webgpu_traits/
lib.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5pub mod error;
6pub mod ids;
7pub mod messages;
8pub mod render_commands;
9
10use std::ops::Range;
11
12use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
13use serde::{Deserialize, Serialize};
14use webrender_api::ImageFormat;
15use wgpu_core::device::HostMap;
16pub use wgpu_core::id::markers::{
17    ComputePassEncoder as ComputePass, RenderPassEncoder as RenderPass,
18};
19pub use wgpu_core::id::{
20    ComputePassEncoderId as ComputePassId, RenderPassEncoderId as RenderPassId,
21};
22use wgpu_core::id::{ComputePipelineId, DeviceId, QueueId, RenderPipelineId};
23use wgpu_core::instance::FailedLimit;
24use wgpu_core::pipeline::CreateShaderModuleError;
25use wgpu_types::{AdapterInfo, DeviceDescriptor, Features, Limits, TextureFormat};
26
27pub use crate::error::*;
28pub use crate::ids::*;
29pub use crate::messages::*;
30pub use crate::render_commands::*;
31
32pub const PRESENTATION_BUFFER_COUNT: usize = 10;
33
34pub type WebGPUAdapterResponse = Option<Result<Adapter, String>>;
35pub type WebGPUComputePipelineResponse = Result<Pipeline<ComputePipelineId>, Error>;
36pub type WebGPUPoppedErrorScopeResponse = Result<Option<Error>, PopError>;
37pub type WebGPURenderPipelineResponse = Result<Pipeline<RenderPipelineId>, Error>;
38
39#[derive(Clone, Debug, Deserialize, Serialize)]
40pub struct WebGPU(pub IpcSender<WebGPURequest>);
41
42impl WebGPU {
43    pub fn exit(&self, sender: IpcSender<()>) -> Result<(), &'static str> {
44        self.0
45            .send(WebGPURequest::Exit(sender))
46            .map_err(|_| "Failed to send Exit message")
47    }
48}
49
50#[derive(Debug, Deserialize, Serialize)]
51pub struct Adapter {
52    pub adapter_info: AdapterInfo,
53    pub adapter_id: WebGPUAdapter,
54    pub features: Features,
55    pub limits: Limits,
56    pub channel: WebGPU,
57}
58
59#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
60pub struct ContextConfiguration {
61    pub device_id: DeviceId,
62    pub queue_id: QueueId,
63    pub format: TextureFormat,
64    pub is_opaque: bool,
65}
66
67impl ContextConfiguration {
68    pub fn format(&self) -> ImageFormat {
69        match self.format {
70            TextureFormat::Rgba8Unorm => ImageFormat::RGBA8,
71            TextureFormat::Bgra8Unorm => ImageFormat::BGRA8,
72            // TODO: wgt::TextureFormat::Rgba16Float
73            _ => unreachable!("Unsupported canvas context format in configuration"),
74        }
75    }
76}
77
78/// <https://gpuweb.github.io/gpuweb/#enumdef-gpudevicelostreason>
79#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
80pub enum DeviceLostReason {
81    Unknown,
82    Destroyed,
83}
84
85#[derive(Clone, Debug, Default, Deserialize, Serialize)]
86pub struct ShaderCompilationInfo {
87    pub line_number: u64,
88    pub line_pos: u64,
89    pub offset: u64,
90    pub length: u64,
91    pub message: String,
92}
93
94impl ShaderCompilationInfo {
95    pub fn from(error: &CreateShaderModuleError, source: &str) -> Self {
96        let location = match error {
97            CreateShaderModuleError::Parsing(e) => e.inner.location(source),
98            CreateShaderModuleError::Validation(e) => e.inner.location(source),
99            _ => None,
100        };
101
102        if let Some(location) = location {
103            // Naga reports locations in UTF-8 code units, but spec requires location in UTF-16 code units
104            // Based on https://searchfox.org/mozilla-central/rev/5b037d9c6ecdb0729f39ad519f0b867d80a92aad/gfx/wgpu_bindings/src/server.rs#353
105            fn len_utf16(s: &str) -> u64 {
106                s.chars().map(|c| c.len_utf16() as u64).sum()
107            }
108            let start = location.offset as usize;
109            let end = start + location.length as usize;
110            let line_start = source[0..start].rfind('\n').map(|pos| pos + 1).unwrap_or(0);
111            Self {
112                line_number: location.line_number as u64,
113                line_pos: len_utf16(&source[line_start..start]) + 1,
114                offset: len_utf16(&source[0..start]),
115                length: len_utf16(&source[start..end]),
116                message: error.to_string(),
117            }
118        } else {
119            Self {
120                message: error.to_string(),
121                ..Default::default()
122            }
123        }
124    }
125}
126
127#[derive(Debug, Deserialize, Serialize)]
128pub struct Pipeline<T: std::fmt::Debug + Serialize> {
129    pub id: T,
130    pub label: String,
131}
132
133#[derive(Debug, Deserialize, Serialize)]
134pub struct Mapping {
135    pub data: IpcSharedMemory,
136    pub mode: HostMap,
137    pub range: Range<u64>,
138}
139
140pub type WebGPUDeviceResponse = (
141    WebGPUDevice,
142    WebGPUQueue,
143    Result<DeviceDescriptor<Option<String>>, RequestDeviceError>,
144);
145
146#[derive(Clone, Debug, Deserialize, Serialize)]
147pub enum RequestDeviceError {
148    LimitsExceeded(FailedLimit),
149    UnsupportedFeature(Features),
150    Other(String),
151}
152
153impl From<wgpu_core::instance::RequestDeviceError> for RequestDeviceError {
154    fn from(value: wgpu_core::instance::RequestDeviceError) -> Self {
155        match value {
156            wgpu_core::instance::RequestDeviceError::LimitsExceeded(failed_limit) => {
157                RequestDeviceError::LimitsExceeded(failed_limit)
158            },
159            wgpu_core::instance::RequestDeviceError::UnsupportedFeature(features) => {
160                RequestDeviceError::UnsupportedFeature(features)
161            },
162            e => RequestDeviceError::Other(e.to_string()),
163        }
164    }
165}