webgpu_traits/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

pub mod error;
pub mod ids;
pub mod messages;
pub mod render_commands;

use std::ops::Range;

use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
use serde::{Deserialize, Serialize};
use webrender_api::ImageFormat;
use wgpu_core::device::HostMap;
pub use wgpu_core::id::markers::{
    ComputePassEncoder as ComputePass, RenderPassEncoder as RenderPass,
};
pub use wgpu_core::id::{
    ComputePassEncoderId as ComputePassId, RenderPassEncoderId as RenderPassId,
};
use wgpu_core::id::{ComputePipelineId, DeviceId, QueueId, RenderPipelineId};
use wgpu_core::instance::{RequestAdapterError, RequestDeviceError};
use wgpu_core::pipeline::CreateShaderModuleError;
use wgpu_types::{AdapterInfo, DeviceDescriptor, Features, Limits, TextureFormat};

pub use crate::error::*;
pub use crate::ids::*;
pub use crate::messages::*;
pub use crate::render_commands::*;

pub const PRESENTATION_BUFFER_COUNT: usize = 10;

pub type WebGPUAdapterResponse = Option<Result<Adapter, RequestAdapterError>>;
pub type WebGPUComputePipelineResponse = Result<Pipeline<ComputePipelineId>, Error>;
pub type WebGPUPoppedErrorScopeResponse = Result<Option<Error>, PopError>;
pub type WebGPURenderPipelineResponse = Result<Pipeline<RenderPipelineId>, Error>;

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WebGPU(pub IpcSender<WebGPURequest>);

impl WebGPU {
    pub fn exit(&self, sender: IpcSender<()>) -> Result<(), &'static str> {
        self.0
            .send(WebGPURequest::Exit(sender))
            .map_err(|_| "Failed to send Exit message")
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Adapter {
    pub adapter_info: AdapterInfo,
    pub adapter_id: WebGPUAdapter,
    pub features: Features,
    pub limits: Limits,
    pub channel: WebGPU,
}

#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct ContextConfiguration {
    pub device_id: DeviceId,
    pub queue_id: QueueId,
    pub format: TextureFormat,
    pub is_opaque: bool,
}

impl ContextConfiguration {
    pub fn format(&self) -> ImageFormat {
        match self.format {
            TextureFormat::Rgba8Unorm => ImageFormat::RGBA8,
            TextureFormat::Bgra8Unorm => ImageFormat::BGRA8,
            // TODO: wgt::TextureFormat::Rgba16Float
            _ => unreachable!("Unsupported canvas context format in configuration"),
        }
    }
}

/// <https://gpuweb.github.io/gpuweb/#enumdef-gpudevicelostreason>
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum DeviceLostReason {
    Unknown,
    Destroyed,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct ShaderCompilationInfo {
    pub line_number: u64,
    pub line_pos: u64,
    pub offset: u64,
    pub length: u64,
    pub message: String,
}

impl ShaderCompilationInfo {
    pub fn from(error: &CreateShaderModuleError, source: &str) -> Self {
        let location = match error {
            CreateShaderModuleError::Parsing(e) => e.inner.location(source),
            CreateShaderModuleError::Validation(e) => e.inner.location(source),
            _ => None,
        };

        if let Some(location) = location {
            // Naga reports locations in UTF-8 code units, but spec requires location in UTF-16 code units
            // Based on https://searchfox.org/mozilla-central/rev/5b037d9c6ecdb0729f39ad519f0b867d80a92aad/gfx/wgpu_bindings/src/server.rs#353
            fn len_utf16(s: &str) -> u64 {
                s.chars().map(|c| c.len_utf16() as u64).sum()
            }
            let start = location.offset as usize;
            let end = start + location.length as usize;
            let line_start = source[0..start].rfind('\n').map(|pos| pos + 1).unwrap_or(0);
            Self {
                line_number: location.line_number as u64,
                line_pos: len_utf16(&source[line_start..start]) + 1,
                offset: len_utf16(&source[0..start]),
                length: len_utf16(&source[start..end]),
                message: error.to_string(),
            }
        } else {
            Self {
                message: error.to_string(),
                ..Default::default()
            }
        }
    }
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Pipeline<T: std::fmt::Debug + Serialize> {
    pub id: T,
    pub label: String,
}

#[derive(Debug, Deserialize, Serialize)]
pub struct Mapping {
    pub data: IpcSharedMemory,
    pub mode: HostMap,
    pub range: Range<u64>,
}

pub type WebGPUDeviceResponse = (
    WebGPUDevice,
    WebGPUQueue,
    Result<DeviceDescriptor<Option<String>>, RequestDeviceError>,
);