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 base::generic_channel::{GenericOneshotSender, GenericSender, GenericSharedMemory};
13use malloc_size_of_derive::MallocSizeOf;
14use serde::{Deserialize, Serialize};
15use webrender_api::euclid::default::Size2D;
16use webrender_api::{ImageDescriptor, ImageDescriptorFlags, ImageFormat};
17use wgpu_core::device::HostMap;
18pub use wgpu_core::id::markers::{
19    ComputePassEncoder as ComputePass, RenderPassEncoder as RenderPass,
20};
21pub use wgpu_core::id::{
22    ComputePassEncoderId as ComputePassId, RenderPassEncoderId as RenderPassId,
23};
24use wgpu_core::id::{ComputePipelineId, DeviceId, QueueId, RenderPipelineId};
25use wgpu_core::instance::FailedLimit;
26use wgpu_core::pipeline::CreateShaderModuleError;
27use wgpu_types::{AdapterInfo, COPY_BYTES_PER_ROW_ALIGNMENT, DeviceDescriptor, Features, Limits};
28
29pub use crate::error::*;
30pub use crate::ids::*;
31pub use crate::messages::*;
32pub use crate::render_commands::*;
33
34pub const PRESENTATION_BUFFER_COUNT: usize = 10;
35
36pub type WebGPUAdapterResponse = Option<Result<Adapter, String>>;
37pub type WebGPUComputePipelineResponse = Result<Pipeline<ComputePipelineId>, Error>;
38pub type WebGPUPoppedErrorScopeResponse = Result<Option<Error>, PopError>;
39pub type WebGPURenderPipelineResponse = Result<Pipeline<RenderPipelineId>, Error>;
40
41#[derive(Clone, Debug, Deserialize, Serialize, MallocSizeOf)]
42pub struct WebGPU(pub GenericSender<WebGPURequest>);
43
44impl WebGPU {
45    pub fn exit(&self, sender: GenericOneshotSender<()>) -> Result<(), &'static str> {
46        self.0
47            .send(WebGPURequest::Exit(sender))
48            .map_err(|_| "Failed to send Exit message")
49    }
50}
51
52#[derive(Debug, Deserialize, Serialize)]
53pub struct Adapter {
54    pub adapter_info: AdapterInfo,
55    pub adapter_id: WebGPUAdapter,
56    pub features: Features,
57    pub limits: Limits,
58    pub channel: WebGPU,
59}
60
61#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
62pub struct ContextConfiguration {
63    pub device_id: DeviceId,
64    pub queue_id: QueueId,
65    pub format: ImageFormat,
66    pub is_opaque: bool,
67    pub size: Size2D<u32>,
68}
69
70impl ContextConfiguration {
71    pub fn stride(&self) -> u32 {
72        (self.size.width * self.format.bytes_per_pixel() as u32)
73            .next_multiple_of(COPY_BYTES_PER_ROW_ALIGNMENT)
74    }
75
76    pub fn buffer_size(&self) -> u64 {
77        self.stride() as u64 * self.size.height as u64
78    }
79}
80
81impl From<ContextConfiguration> for ImageDescriptor {
82    fn from(config: ContextConfiguration) -> Self {
83        ImageDescriptor {
84            format: config.format,
85            size: config.size.cast().cast_unit(),
86            stride: Some(config.stride() as i32),
87            offset: 0,
88            flags: if config.is_opaque {
89                ImageDescriptorFlags::IS_OPAQUE
90            } else {
91                ImageDescriptorFlags::empty()
92            },
93        }
94    }
95}
96
97/// <https://gpuweb.github.io/gpuweb/#enumdef-gpudevicelostreason>
98#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
99pub enum DeviceLostReason {
100    Unknown,
101    Destroyed,
102}
103
104#[derive(Clone, Debug, Default, Deserialize, Serialize)]
105pub struct ShaderCompilationInfo {
106    pub line_number: u64,
107    pub line_pos: u64,
108    pub offset: u64,
109    pub length: u64,
110    pub message: String,
111}
112
113impl ShaderCompilationInfo {
114    pub fn from(error: &CreateShaderModuleError, source: &str) -> Self {
115        let location = match error {
116            CreateShaderModuleError::Parsing(e) => e.inner.location(source),
117            CreateShaderModuleError::Validation(e) => e.inner.location(source),
118            _ => None,
119        };
120
121        if let Some(location) = location {
122            // Naga reports locations in UTF-8 code units, but spec requires location in UTF-16 code units
123            // Based on https://searchfox.org/mozilla-central/rev/5b037d9c6ecdb0729f39ad519f0b867d80a92aad/gfx/wgpu_bindings/src/server.rs#353
124            fn len_utf16(s: &str) -> u64 {
125                s.chars().map(|c| c.len_utf16() as u64).sum()
126            }
127            let start = location.offset as usize;
128            let end = start + location.length as usize;
129            let line_start = source[0..start].rfind('\n').map(|pos| pos + 1).unwrap_or(0);
130            Self {
131                line_number: location.line_number as u64,
132                line_pos: len_utf16(&source[line_start..start]) + 1,
133                offset: len_utf16(&source[0..start]),
134                length: len_utf16(&source[start..end]),
135                message: error.to_string(),
136            }
137        } else {
138            Self {
139                message: error.to_string(),
140                ..Default::default()
141            }
142        }
143    }
144}
145
146#[derive(Debug, Deserialize, Serialize)]
147pub struct Pipeline<T: std::fmt::Debug + Serialize> {
148    pub id: T,
149    pub label: String,
150}
151
152#[derive(Debug, Deserialize, Serialize)]
153pub struct Mapping {
154    pub data: GenericSharedMemory,
155    pub mode: HostMap,
156    pub range: Range<u64>,
157}
158
159pub type WebGPUDeviceResponse = (
160    WebGPUDevice,
161    WebGPUQueue,
162    Result<DeviceDescriptor<Option<String>>, RequestDeviceError>,
163);
164
165#[derive(Clone, Debug, Deserialize, Serialize)]
166pub enum RequestDeviceError {
167    LimitsExceeded(FailedLimit),
168    UnsupportedFeature(Features),
169    Other(String),
170}
171
172impl From<wgpu_core::instance::RequestDeviceError> for RequestDeviceError {
173    fn from(value: wgpu_core::instance::RequestDeviceError) -> Self {
174        match value {
175            wgpu_core::instance::RequestDeviceError::LimitsExceeded(failed_limit) => {
176                RequestDeviceError::LimitsExceeded(failed_limit)
177            },
178            wgpu_core::instance::RequestDeviceError::UnsupportedFeature(features) => {
179                RequestDeviceError::UnsupportedFeature(features)
180            },
181            e => RequestDeviceError::Other(e.to_string()),
182        }
183    }
184}