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