mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
webgpu: Implement ShaderCompilationInfo (#32642)
* ShaderCompilationInfo * expectations * Handle CompilationInfo promise in GPUShaderModule * Fix my english
This commit is contained in:
parent
bd0a5eb4b7
commit
c0105de82b
9 changed files with 22103 additions and 682 deletions
|
@ -170,7 +170,12 @@ DOMInterfaces = {
|
||||||
|
|
||||||
'GPUDevice': {
|
'GPUDevice': {
|
||||||
'weakReferenceable': True, # for usage in GlobalScope https://github.com/servo/servo/issues/32519
|
'weakReferenceable': True, # for usage in GlobalScope https://github.com/servo/servo/issues/32519
|
||||||
'inRealms': ['PopErrorScope', 'CreateComputePipelineAsync', 'CreateRenderPipelineAsync'],
|
'inRealms': [
|
||||||
|
'PopErrorScope',
|
||||||
|
'CreateComputePipelineAsync',
|
||||||
|
'CreateRenderPipelineAsync',
|
||||||
|
'CreateShaderModule' # Creates promise for compilation info
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,23 +4,52 @@
|
||||||
|
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use js::jsval::JSVal;
|
use js::jsval::JSVal;
|
||||||
|
use webgpu::ShaderCompilationInfo;
|
||||||
|
|
||||||
use super::bindings::codegen::Bindings::WebGPUBinding::GPUCompilationInfoMethods;
|
use super::bindings::codegen::Bindings::WebGPUBinding::GPUCompilationInfoMethods;
|
||||||
use super::bindings::root::Dom;
|
use super::bindings::import::module::DomRoot;
|
||||||
|
use super::bindings::reflector::reflect_dom_object_with_proto;
|
||||||
|
use super::bindings::utils::to_frozen_array;
|
||||||
use super::types::GPUCompilationMessage;
|
use super::types::GPUCompilationMessage;
|
||||||
use crate::dom::bindings::reflector::Reflector;
|
use crate::dom::bindings::reflector::Reflector;
|
||||||
|
use crate::dom::globalscope::GlobalScope;
|
||||||
use crate::script_runtime::JSContext;
|
use crate::script_runtime::JSContext;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct GPUCompilationInfo {
|
pub struct GPUCompilationInfo {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
msg: Dom<GPUCompilationMessage>,
|
// currently we only get one message from wgpu
|
||||||
|
msg: Vec<DomRoot<GPUCompilationMessage>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: wgpu does not expose right fields right now
|
impl GPUCompilationInfo {
|
||||||
impl GPUCompilationInfoMethods for GPUCompilationInfo {
|
pub fn new_inherited(msg: Vec<DomRoot<GPUCompilationMessage>>) -> Self {
|
||||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationinfo-messages>
|
Self {
|
||||||
fn Messages(&self, _cx: JSContext) -> JSVal {
|
reflector_: Reflector::new(),
|
||||||
todo!()
|
msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn new(global: &GlobalScope, msg: Vec<DomRoot<GPUCompilationMessage>>) -> DomRoot<Self> {
|
||||||
|
reflect_dom_object_with_proto(Box::new(Self::new_inherited(msg)), global, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from(global: &GlobalScope, error: Option<ShaderCompilationInfo>) -> DomRoot<Self> {
|
||||||
|
Self::new(
|
||||||
|
global,
|
||||||
|
if let Some(error) = error {
|
||||||
|
vec![GPUCompilationMessage::from(global, error)]
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GPUCompilationInfoMethods for GPUCompilationInfo {
|
||||||
|
/// <https://gpuweb.github.io/gpuweb/#dom-gpucompilationinfo-messages>
|
||||||
|
fn Messages(&self, cx: JSContext) -> JSVal {
|
||||||
|
to_frozen_array(self.msg.as_slice(), cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#![allow(dead_code)] // this file is stub as wgpu does not provide info
|
#![allow(dead_code)] // this file is stub as wgpu does not provide info
|
||||||
|
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
|
use webgpu::ShaderCompilationInfo;
|
||||||
|
|
||||||
use super::bindings::codegen::Bindings::WebGPUBinding::{
|
use super::bindings::codegen::Bindings::WebGPUBinding::{
|
||||||
GPUCompilationMessageMethods, GPUCompilationMessageType,
|
GPUCompilationMessageMethods, GPUCompilationMessageType,
|
||||||
|
@ -62,6 +63,18 @@ impl GPUCompilationMessage {
|
||||||
global,
|
global,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from(global: &GlobalScope, info: ShaderCompilationInfo) -> DomRoot<Self> {
|
||||||
|
GPUCompilationMessage::new(
|
||||||
|
global,
|
||||||
|
info.message.into(),
|
||||||
|
GPUCompilationMessageType::Error,
|
||||||
|
info.line_number as u64,
|
||||||
|
info.line_pos as u64,
|
||||||
|
info.offset as u64,
|
||||||
|
info.length as u64,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUCompilationMessageMethods for GPUCompilationMessage {
|
impl GPUCompilationMessageMethods for GPUCompilationMessage {
|
||||||
|
|
|
@ -539,13 +539,22 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
fn CreateShaderModule(
|
fn CreateShaderModule(
|
||||||
&self,
|
&self,
|
||||||
descriptor: RootedTraceableBox<GPUShaderModuleDescriptor>,
|
descriptor: RootedTraceableBox<GPUShaderModuleDescriptor>,
|
||||||
|
comp: InRealm,
|
||||||
) -> DomRoot<GPUShaderModule> {
|
) -> DomRoot<GPUShaderModule> {
|
||||||
let program_id = self
|
let program_id = self
|
||||||
.global()
|
.global()
|
||||||
.wgpu_id_hub()
|
.wgpu_id_hub()
|
||||||
.lock()
|
.lock()
|
||||||
.create_shader_module_id(self.device.0.backend());
|
.create_shader_module_id(self.device.0.backend());
|
||||||
|
let promise = Promise::new_in_current_realm(comp);
|
||||||
|
let shader_module = GPUShaderModule::new(
|
||||||
|
&self.global(),
|
||||||
|
self.channel.clone(),
|
||||||
|
webgpu::WebGPUShaderModule(program_id),
|
||||||
|
descriptor.parent.label.clone().unwrap_or_default(),
|
||||||
|
promise.clone(),
|
||||||
|
);
|
||||||
|
let sender = response_async(&promise, &*shader_module);
|
||||||
self.channel
|
self.channel
|
||||||
.0
|
.0
|
||||||
.send(WebGPURequest::CreateShaderModule {
|
.send(WebGPURequest::CreateShaderModule {
|
||||||
|
@ -553,16 +562,10 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
program_id,
|
program_id,
|
||||||
program: descriptor.code.0.clone(),
|
program: descriptor.code.0.clone(),
|
||||||
label: None,
|
label: None,
|
||||||
|
sender,
|
||||||
})
|
})
|
||||||
.expect("Failed to create WebGPU ShaderModule");
|
.expect("Failed to create WebGPU ShaderModule");
|
||||||
|
shader_module
|
||||||
let shader_module = webgpu::WebGPUShaderModule(program_id);
|
|
||||||
GPUShaderModule::new(
|
|
||||||
&self.global(),
|
|
||||||
self.channel.clone(),
|
|
||||||
shader_module,
|
|
||||||
descriptor.parent.label.clone().unwrap_or_default(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcomputepipeline>
|
/// <https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcomputepipeline>
|
||||||
|
@ -1029,7 +1032,7 @@ impl AsyncWGPUListener for GPUDevice {
|
||||||
promise.resolve_native(&error);
|
promise.resolve_native(&error);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
_ => unreachable!("Wrong response recived on AsyncWGPUListener for GPUDevice"),
|
_ => unreachable!("Wrong response received on AsyncWGPUListener for GPUDevice"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,14 @@
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use webgpu::{WebGPU, WebGPURequest, WebGPUShaderModule};
|
use webgpu::{WebGPU, WebGPURequest, WebGPUResponse, WebGPUResponseResult, WebGPUShaderModule};
|
||||||
|
|
||||||
use super::bindings::error::Fallible;
|
use super::gpu::AsyncWGPUListener;
|
||||||
|
use super::gpucompilationinfo::GPUCompilationInfo;
|
||||||
use super::promise::Promise;
|
use super::promise::Promise;
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUShaderModuleMethods;
|
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUShaderModuleMethods;
|
||||||
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
|
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
||||||
use crate::dom::bindings::root::DomRoot;
|
use crate::dom::bindings::root::DomRoot;
|
||||||
use crate::dom::bindings::str::USVString;
|
use crate::dom::bindings::str::USVString;
|
||||||
use crate::dom::globalscope::GlobalScope;
|
use crate::dom::globalscope::GlobalScope;
|
||||||
|
@ -25,15 +26,23 @@ pub struct GPUShaderModule {
|
||||||
label: DomRefCell<USVString>,
|
label: DomRefCell<USVString>,
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
shader_module: WebGPUShaderModule,
|
shader_module: WebGPUShaderModule,
|
||||||
|
#[ignore_malloc_size_of = "promise"]
|
||||||
|
compilation_info_promise: Rc<Promise>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUShaderModule {
|
impl GPUShaderModule {
|
||||||
fn new_inherited(channel: WebGPU, shader_module: WebGPUShaderModule, label: USVString) -> Self {
|
fn new_inherited(
|
||||||
|
channel: WebGPU,
|
||||||
|
shader_module: WebGPUShaderModule,
|
||||||
|
label: USVString,
|
||||||
|
promise: Rc<Promise>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
channel,
|
channel,
|
||||||
label: DomRefCell::new(label),
|
label: DomRefCell::new(label),
|
||||||
shader_module,
|
shader_module,
|
||||||
|
compilation_info_promise: promise,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,12 +51,14 @@ impl GPUShaderModule {
|
||||||
channel: WebGPU,
|
channel: WebGPU,
|
||||||
shader_module: WebGPUShaderModule,
|
shader_module: WebGPUShaderModule,
|
||||||
label: USVString,
|
label: USVString,
|
||||||
|
promise: Rc<Promise>,
|
||||||
) -> DomRoot<Self> {
|
) -> DomRoot<Self> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(GPUShaderModule::new_inherited(
|
Box::new(GPUShaderModule::new_inherited(
|
||||||
channel,
|
channel,
|
||||||
shader_module,
|
shader_module,
|
||||||
label,
|
label,
|
||||||
|
promise,
|
||||||
)),
|
)),
|
||||||
global,
|
global,
|
||||||
)
|
)
|
||||||
|
@ -72,8 +83,20 @@ impl GPUShaderModuleMethods for GPUShaderModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpushadermodule-getcompilationinfo>
|
/// <https://gpuweb.github.io/gpuweb/#dom-gpushadermodule-getcompilationinfo>
|
||||||
fn GetCompilationInfo(&self) -> Fallible<Rc<Promise>> {
|
fn GetCompilationInfo(&self) -> Rc<Promise> {
|
||||||
todo!("Missing in wgpu: https://github.com/gfx-rs/wgpu/issues/2170")
|
self.compilation_info_promise.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncWGPUListener for GPUShaderModule {
|
||||||
|
fn handle_response(&self, response: Option<WebGPUResponseResult>, promise: &Rc<Promise>) {
|
||||||
|
match response {
|
||||||
|
Some(Ok(WebGPUResponse::CompilationInfo(info))) => {
|
||||||
|
let info = GPUCompilationInfo::from(&self.global(), info);
|
||||||
|
promise.resolve_native(&info);
|
||||||
|
},
|
||||||
|
_ => unreachable!("Wrong response received on AsyncWGPUListener for GPUShaderModule"),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -486,7 +486,6 @@ dictionary GPUPipelineLayoutDescriptor : GPUObjectDescriptorBase {
|
||||||
|
|
||||||
[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
|
[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
|
||||||
interface GPUShaderModule {
|
interface GPUShaderModule {
|
||||||
[Throws]
|
|
||||||
Promise<GPUCompilationInfo> getCompilationInfo();
|
Promise<GPUCompilationInfo> getCompilationInfo();
|
||||||
};
|
};
|
||||||
GPUShaderModule includes GPUObjectBase;
|
GPUShaderModule includes GPUObjectBase;
|
||||||
|
@ -515,9 +514,8 @@ interface GPUCompilationMessage {
|
||||||
|
|
||||||
[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"]
|
[Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"]
|
||||||
interface GPUCompilationInfo {
|
interface GPUCompilationInfo {
|
||||||
// codegen hates it
|
//readonly attribute FrozenArray<GPUCompilationMessage> messages;
|
||||||
//[Cached, Frozen, Pure]
|
readonly attribute any messages;
|
||||||
readonly attribute /*sequence<GPUCompilationMessage>*/ any messages;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GPUAutoLayoutMode {
|
enum GPUAutoLayoutMode {
|
||||||
|
|
|
@ -25,11 +25,54 @@ use wgc::pipeline::{ComputePipelineDescriptor, RenderPipelineDescriptor};
|
||||||
use wgc::resource::{
|
use wgc::resource::{
|
||||||
BufferDescriptor, SamplerDescriptor, TextureDescriptor, TextureViewDescriptor,
|
BufferDescriptor, SamplerDescriptor, TextureDescriptor, TextureViewDescriptor,
|
||||||
};
|
};
|
||||||
|
use wgpu_core::pipeline::CreateShaderModuleError;
|
||||||
pub use {wgpu_core as wgc, wgpu_types as wgt};
|
pub use {wgpu_core as wgc, wgpu_types as wgt};
|
||||||
|
|
||||||
use crate::identity::*;
|
use crate::identity::*;
|
||||||
use crate::{Error, ErrorFilter, PopError, WebGPU, PRESENTATION_BUFFER_COUNT};
|
use crate::{Error, ErrorFilter, PopError, WebGPU, PRESENTATION_BUFFER_COUNT};
|
||||||
|
|
||||||
|
#[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)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
pub enum WebGPUResponse {
|
pub enum WebGPUResponse {
|
||||||
|
@ -48,6 +91,7 @@ pub enum WebGPUResponse {
|
||||||
BufferMapAsync(IpcSharedMemory),
|
BufferMapAsync(IpcSharedMemory),
|
||||||
SubmittedWorkDone,
|
SubmittedWorkDone,
|
||||||
PoppedErrorScope(Result<Option<Error>, PopError>),
|
PoppedErrorScope(Result<Option<Error>, PopError>),
|
||||||
|
CompilationInfo(Option<ShaderCompilationInfo>),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type WebGPUResponseResult = Result<WebGPUResponse, String>;
|
pub type WebGPUResponseResult = Result<WebGPUResponse, String>;
|
||||||
|
@ -145,6 +189,7 @@ pub enum WebGPURequest {
|
||||||
program_id: id::ShaderModuleId,
|
program_id: id::ShaderModuleId,
|
||||||
program: String,
|
program: String,
|
||||||
label: Option<String>,
|
label: Option<String>,
|
||||||
|
sender: IpcSender<Option<WebGPUResponseResult>>,
|
||||||
},
|
},
|
||||||
CreateSwapChain {
|
CreateSwapChain {
|
||||||
device_id: id::DeviceId,
|
device_id: id::DeviceId,
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
//! Data and main loop of WebGPU thread.
|
//! Data and main loop of WebGPU thread.
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
@ -437,17 +438,24 @@ impl WGPU {
|
||||||
program_id,
|
program_id,
|
||||||
program,
|
program,
|
||||||
label,
|
label,
|
||||||
|
sender,
|
||||||
} => {
|
} => {
|
||||||
let global = &self.global;
|
let global = &self.global;
|
||||||
let source = wgpu_core::pipeline::ShaderModuleSource::Wgsl(
|
let source =
|
||||||
crate::Cow::Owned(program),
|
wgpu_core::pipeline::ShaderModuleSource::Wgsl(Cow::Borrowed(&program));
|
||||||
);
|
|
||||||
let desc = ShaderModuleDescriptor {
|
let desc = ShaderModuleDescriptor {
|
||||||
label: label.map(|s| s.into()),
|
label: label.map(|s| s.into()),
|
||||||
shader_bound_checks: wgt::ShaderBoundChecks::default(),
|
shader_bound_checks: wgt::ShaderBoundChecks::default(),
|
||||||
};
|
};
|
||||||
let (_, error) = gfx_select!(program_id =>
|
let (_, error) = gfx_select!(program_id =>
|
||||||
global.device_create_shader_module(device_id, &desc, source, Some(program_id)));
|
global.device_create_shader_module(device_id, &desc, source, Some(program_id)));
|
||||||
|
if let Err(e) = sender.send(Some(Ok(WebGPUResponse::CompilationInfo(
|
||||||
|
error
|
||||||
|
.as_ref()
|
||||||
|
.map(|e| crate::ShaderCompilationInfo::from(e, &program)),
|
||||||
|
)))) {
|
||||||
|
warn!("Failed to send WebGPUResponse::CompilationInfo {e:?}");
|
||||||
|
}
|
||||||
self.maybe_dispatch_wgpu_error(device_id, error);
|
self.maybe_dispatch_wgpu_error(device_id, error);
|
||||||
},
|
},
|
||||||
WebGPURequest::CreateSwapChain {
|
WebGPURequest::CreateSwapChain {
|
||||||
|
|
22319
tests/wpt/webgpu/meta/webgpu/cts.https.html.ini
vendored
22319
tests/wpt/webgpu/meta/webgpu/cts.https.html.ini
vendored
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue