diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index 021f747c8f5..488ed65989a 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -2951,7 +2951,7 @@ impl Document { self.dirty_webgpu_contexts .borrow_mut() .drain() - .for_each(|(_, context)| context.send_swap_chain_present()); + .for_each(|(_, context)| context.update_rendering_of_webgpu_canvas()); } pub fn id_map(&self) -> Ref>>> { diff --git a/components/script/dom/gpucanvascontext.rs b/components/script/dom/gpucanvascontext.rs index 7282cac5ba9..cc8c5ca3e25 100644 --- a/components/script/dom/gpucanvascontext.rs +++ b/components/script/dom/gpucanvascontext.rs @@ -2,6 +2,9 @@ * 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/. */ +use std::borrow::Cow; +use std::cell::RefCell; + use arrayvec::ArrayVec; use dom_struct::dom_struct; use euclid::default::Size2D; @@ -9,20 +12,25 @@ use ipc_channel::ipc; use script_layout_interface::HTMLCanvasDataSource; use webgpu::swapchain::WebGPUContextId; use webgpu::wgc::id; -use webgpu::{WebGPU, WebGPURequest, WebGPUTexture, PRESENTATION_BUFFER_COUNT}; -use webrender_api::{units, ImageFormat, ImageKey}; +use webgpu::{ + ContextConfiguration, WebGPU, WebGPURequest, WebGPUTexture, PRESENTATION_BUFFER_COUNT, +}; +use webrender_api::units::DeviceIntSize; +use webrender_api::ImageKey; -use super::bindings::codegen::Bindings::WebGPUBinding::GPUTextureUsageConstants; +use super::bindings::codegen::Bindings::WebGPUBinding::{ + GPUCanvasAlphaMode, GPUTextureUsageConstants, +}; use super::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas; use super::bindings::error::{Error, Fallible}; use super::bindings::root::MutNullableDom; use super::bindings::str::USVString; +use super::gpuconvert::convert_texture_descriptor; use super::gputexture::GPUTexture; -use crate::dom::bindings::codegen::Bindings::HTMLCanvasElementBinding::HTMLCanvasElement_Binding::HTMLCanvasElementMethods; +use crate::dom::bindings::codegen::Bindings::WebGPUBinding::GPUTexture_Binding::GPUTextureMethods; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ GPUCanvasConfiguration, GPUCanvasContextMethods, GPUDeviceMethods, GPUExtent3D, GPUExtent3DDict, GPUObjectDescriptorBase, GPUTextureDescriptor, GPUTextureDimension, - GPUTextureFormat, }; use crate::dom::bindings::inheritance::Castable; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; @@ -85,6 +93,29 @@ impl malloc_size_of::MallocSizeOf for HTMLCanvasElementOrOffscreenCanvas { } } +impl HTMLCanvasElementOrOffscreenCanvas { + fn size(&self) -> Size2D { + match self { + HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) => { + canvas.get_size().cast() + }, + HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(canvas) => canvas.get_size(), + } + } +} + +#[derive(Clone, Debug, Default, JSTraceable, MallocSizeOf)] +/// Helps observe changes on swapchain +struct DrawingBuffer { + #[no_trace] + size: DeviceIntSize, + /// image is transparent black + cleared: bool, + #[ignore_malloc_size_of = "Defined in wgpu"] + #[no_trace] + config: Option, +} + #[dom_struct] pub struct GPUCanvasContext { reflector_: Reflector, @@ -99,14 +130,34 @@ pub struct GPUCanvasContext { webrender_image: ImageKey, #[no_trace] context_id: WebGPUContextId, + #[ignore_malloc_size_of = "manual writing is hard"] + /// + configuration: RefCell>, + /// + texture_descriptor: RefCell>, + /// Conceptually + drawing_buffer: RefCell, /// - texture: MutNullableDom, + current_texture: MutNullableDom, } impl GPUCanvasContext { - fn new_inherited(canvas: HTMLCanvasElementOrOffscreenCanvas, channel: WebGPU) -> Self { + fn new_inherited( + global: &GlobalScope, + canvas: HTMLCanvasElementOrOffscreenCanvas, + channel: WebGPU, + ) -> Self { let (sender, receiver) = ipc::channel().unwrap(); - if let Err(e) = channel.0.send(WebGPURequest::CreateContext(sender)) { + let size = canvas.size().cast().cast_unit(); + let mut buffer_ids = ArrayVec::::new(); + for _ in 0..PRESENTATION_BUFFER_COUNT { + buffer_ids.push(global.wgpu_id_hub().create_buffer_id()); + } + if let Err(e) = channel.0.send(WebGPURequest::CreateContext { + buffer_ids, + size, + sender, + }) { warn!("Failed to send CreateContext ({:?})", e); } let (external_id, webrender_image) = receiver.recv().unwrap(); @@ -116,13 +167,21 @@ impl GPUCanvasContext { canvas, webrender_image, context_id: WebGPUContextId(external_id.0), - texture: MutNullableDom::default(), + drawing_buffer: RefCell::new(DrawingBuffer { + size, + cleared: true, + ..Default::default() + }), + configuration: RefCell::new(None), + texture_descriptor: RefCell::new(None), + current_texture: MutNullableDom::default(), } } pub fn new(global: &GlobalScope, canvas: &HTMLCanvasElement, channel: WebGPU) -> DomRoot { reflect_dom_object( Box::new(GPUCanvasContext::new_inherited( + global, HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(DomRoot::from_ref(canvas)), channel, )), @@ -131,17 +190,93 @@ impl GPUCanvasContext { } } +// Abstract ops from spec impl GPUCanvasContext { - fn layout_handle(&self) -> HTMLCanvasDataSource { - HTMLCanvasDataSource::WebGPU(self.webrender_image) + /// + fn texture_descriptor_for_canvas( + &self, + configuration: &GPUCanvasConfiguration, + ) -> GPUTextureDescriptor { + let size = self.size(); + GPUTextureDescriptor { + format: configuration.format, + // We need to add `COPY_SRC` so we can copy texture to presentation buffer + // causes FAIL on webgpu:web_platform,canvas,configure:usage:* + usage: configuration.usage | GPUTextureUsageConstants::COPY_SRC, + size: GPUExtent3D::GPUExtent3DDict(GPUExtent3DDict { + width: size.width as u32, + height: size.height as u32, + depthOrArrayLayers: 1, + }), + viewFormats: configuration.viewFormats.clone(), + // other members to default + mipLevelCount: 1, + sampleCount: 1, + parent: GPUObjectDescriptorBase { + label: USVString::default(), + }, + dimension: GPUTextureDimension::_2d, + } } - pub fn send_swap_chain_present(&self) { - let texture_id = self.texture_id().unwrap().0; + /// + fn expire_current_texture(&self) { + if let Some(current_texture) = self.current_texture.take() { + // Make copy of texture content + self.send_swap_chain_present(current_texture.id()); + // Step 1 + current_texture.Destroy() + } + } + + /// + fn replace_drawing_buffer(&self) { + // Step 1 + self.expire_current_texture(); + // Step 2 + let configuration = self.configuration.borrow(); + // Step 3 + let mut drawing_buffer = self.drawing_buffer.borrow_mut(); + drawing_buffer.size = self.size().cast().cast_unit(); + drawing_buffer.cleared = true; + if let Some(configuration) = configuration.as_ref() { + drawing_buffer.config = Some(ContextConfiguration { + device_id: configuration.device.id().0, + queue_id: configuration.device.queue_id().0, + format: configuration.format.into(), + is_opaque: matches!(configuration.alphaMode, GPUCanvasAlphaMode::Opaque), + }); + } else { + drawing_buffer.config.take(); + }; + // TODO: send less + self.channel + .0 + .send(WebGPURequest::UpdateContext { + context_id: self.context_id, + size: drawing_buffer.size, + configuration: drawing_buffer.config.clone(), + }) + .expect("Failed to update webgpu context"); + } +} + +// Internal helper methods +impl GPUCanvasContext { + fn layout_handle(&self) -> HTMLCanvasDataSource { + if self.drawing_buffer.borrow().cleared { + HTMLCanvasDataSource::Empty + } else { + HTMLCanvasDataSource::WebGPU(self.webrender_image) + } + } + + fn send_swap_chain_present(&self, texture_id: WebGPUTexture) { + self.drawing_buffer.borrow_mut().cleared = false; let encoder_id = self.global().wgpu_id_hub().create_command_encoder_id(); if let Err(e) = self.channel.0.send(WebGPURequest::SwapChainPresent { context_id: self.context_id, - texture_id, + texture_id: texture_id.0, encoder_id, }) { warn!( @@ -151,29 +286,42 @@ impl GPUCanvasContext { } } - pub fn context_id(&self) -> WebGPUContextId { + fn size(&self) -> Size2D { + self.canvas.size() + } +} + +// public methods for canvas handling +// these methods should probably be behind trait for all canvases +impl GPUCanvasContext { + pub(crate) fn context_id(&self) -> WebGPUContextId { self.context_id } - pub fn texture_id(&self) -> Option { - self.texture.get().map(|t| t.id()) - } - - pub fn mark_as_dirty(&self) { + pub(crate) fn mark_as_dirty(&self) { if let HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) = &self.canvas { canvas.upcast::().dirty(NodeDamage::OtherNodeDamage); let document = document_from_node(&**canvas); document.add_dirty_webgpu_canvas(self); } - // TODO(sagudev): offscreen canvas also dirty? } - fn size(&self) -> Size2D { - match &self.canvas { - HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) => { - Size2D::new(canvas.Width() as u64, canvas.Height() as u64) - }, - HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(canvas) => canvas.get_size(), + /// + pub(crate) fn update_rendering_of_webgpu_canvas(&self) { + // Step 1 + self.expire_current_texture(); + } + + /// + pub(crate) fn resize(&self) { + // Step 1 + self.replace_drawing_buffer(); + // Step 2 + let configuration = self.configuration.borrow(); + // Step 3 + if let Some(configuration) = configuration.as_ref() { + self.texture_descriptor + .replace(Some(self.texture_descriptor_for_canvas(configuration))); } } } @@ -192,110 +340,84 @@ impl GPUCanvasContextMethods for GPUCanvasContext { /// fn Configure(&self, configuration: &GPUCanvasConfiguration) -> Fallible<()> { - // Step 1 is let - // Step 2 - configuration - .device - .validate_texture_format_required_features(&configuration.format)?; - // Mapping between wr and wgpu can be determined by inspecting - // https://github.com/gfx-rs/wgpu/blob/9b36a3e129da04b018257564d5129caff240cb75/wgpu-hal/src/gles/conv.rs#L10 - // https://github.com/servo/webrender/blob/1e73f384a7a86e413f91e9e430436a9bd83381cd/webrender/src/device/gl.rs#L4064 - let format = match configuration.format { - GPUTextureFormat::R8unorm => ImageFormat::R8, - GPUTextureFormat::Bgra8unorm | GPUTextureFormat::Bgra8unorm_srgb => ImageFormat::BGRA8, - GPUTextureFormat::Rgba8unorm | GPUTextureFormat::Rgba8unorm_srgb => ImageFormat::RGBA8, - GPUTextureFormat::Rgba32float => ImageFormat::RGBAF32, - GPUTextureFormat::Rgba32sint => ImageFormat::RGBAI32, - GPUTextureFormat::Rg8unorm => ImageFormat::RG8, - _ => { - return Err(Error::Type(format!( - "SwapChain format({:?}) not supported", - configuration.format - ))) - }, - }; - - // Step 3 - for view_format in &configuration.viewFormats { - configuration - .device - .validate_texture_format_required_features(view_format)?; - } - // Step 4 - let size = self.size(); - let text_desc = GPUTextureDescriptor { - format: configuration.format, - mipLevelCount: 1, - sampleCount: 1, - // We need to add `COPY_SRC` so we can copy texture to presentation buffer - usage: configuration.usage | GPUTextureUsageConstants::COPY_SRC, - size: GPUExtent3D::GPUExtent3DDict(GPUExtent3DDict { - width: size.width as u32, - height: size.height as u32, - depthOrArrayLayers: 1, - }), - viewFormats: configuration.viewFormats.clone(), - // other members to default - parent: GPUObjectDescriptorBase { - label: USVString::default(), - }, - dimension: GPUTextureDimension::_2d, - }; + let descriptor = self.texture_descriptor_for_canvas(configuration); - // Step 8 - let mut buffer_ids = ArrayVec::::new(); - for _ in 0..PRESENTATION_BUFFER_COUNT { - buffer_ids.push(self.global().wgpu_id_hub().create_buffer_id()); - } + // Step 2&3 + let (mut desc, _) = convert_texture_descriptor(&descriptor, &configuration.device)?; + desc.label = Some(Cow::Borrowed( + "dummy texture for texture descriptor validation", + )); + // Step 5 + self.configuration.replace(Some(configuration.clone())); + + // Step 6 + self.texture_descriptor.replace(Some(descriptor)); + + // Step 7 + self.replace_drawing_buffer(); + + // Step 8: Validate texture descriptor + let texture_id = self.global().wgpu_id_hub().create_texture_id(); self.channel .0 - .send(WebGPURequest::CreateSwapChain { + .send(WebGPURequest::ValidateTextureDescriptor { device_id: configuration.device.id().0, - queue_id: configuration.device.GetQueue().id().0, - buffer_ids, - context_id: self.context_id, - image_key: self.webrender_image, - format, - size: units::DeviceIntSize::new(size.width as i32, size.height as i32), + texture_id, + descriptor: desc, }) .expect("Failed to create WebGPU SwapChain"); - self.texture.set(Some( - &configuration.device.CreateTexture(&text_desc).unwrap(), - )); - Ok(()) } /// fn Unconfigure(&self) { - if let Some(texture) = self.texture.take() { - if let Err(e) = self.channel.0.send(WebGPURequest::DestroySwapChain { - context_id: self.context_id, - image_key: self.webrender_image, - }) { - warn!( - "Failed to send DestroySwapChain-ImageKey({:?}) ({})", - self.webrender_image, e - ); - } - drop(texture); - } + // Step 1 + self.configuration.take(); + // Step 2 + self.current_texture.take(); + // Step 3 + self.replace_drawing_buffer(); } /// fn GetCurrentTexture(&self) -> Fallible> { - // Step 5. + // Step 1 + let configuration = self.configuration.borrow(); + let Some(configuration) = configuration.as_ref() else { + return Err(Error::InvalidState); + }; + // Step 2 + let texture_descriptor = self.texture_descriptor.borrow(); + let texture_descriptor = texture_descriptor.as_ref().unwrap(); + // Step 6 + let current_texture = if let Some(current_texture) = self.current_texture.get() { + current_texture + } else { + // Step 3&4 + self.replace_drawing_buffer(); + let current_texture = configuration.device.CreateTexture(&texture_descriptor)?; + self.current_texture.set(Some(¤t_texture)); + current_texture + }; + // Step 5 self.mark_as_dirty(); - // Step 6. - self.texture.get().ok_or(Error::InvalidState) + // Step 6 + Ok(current_texture) } } impl Drop for GPUCanvasContext { fn drop(&mut self) { - self.Unconfigure() + if let Err(e) = self.channel.0.send(WebGPURequest::DestroyContext { + context_id: self.context_id, + }) { + warn!( + "Failed to send DestroySwapChain-ImageKey({:?}) ({})", + self.webrender_image, e + ); + } } } diff --git a/components/script/dom/gpuconvert.rs b/components/script/dom/gpuconvert.rs index 4bd53573d43..c3817c75ea1 100644 --- a/components/script/dom/gpuconvert.rs +++ b/components/script/dom/gpuconvert.rs @@ -8,10 +8,11 @@ use std::num::NonZeroU64; use webgpu::wgc::binding_model::{BindGroupEntry, BindingResource, BufferBinding}; use webgpu::wgc::command as wgpu_com; use webgpu::wgc::pipeline::ProgrammableStageDescriptor; +use webgpu::wgc::resource::TextureDescriptor; use webgpu::wgt::{self, AstcBlock, AstcChannel}; use super::bindings::codegen::Bindings::WebGPUBinding::{ - GPUProgrammableStage, GPUTextureDimension, + GPUProgrammableStage, GPUTextureDescriptor, GPUTextureDimension, }; use super::bindings::error::Error; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ @@ -506,6 +507,7 @@ impl<'a> From<&GPUObjectDescriptorBase> for Option> { } } } + pub fn convert_bind_group_layout_entry( bgle: &GPUBindGroupLayoutEntry, device: &GPUDevice, @@ -581,6 +583,28 @@ pub fn convert_bind_group_layout_entry( })) } +pub fn convert_texture_descriptor( + descriptor: &GPUTextureDescriptor, + device: &GPUDevice, +) -> Fallible<(TextureDescriptor<'static>, wgt::Extent3d)> { + let size = (&descriptor.size).try_into()?; + let desc = TextureDescriptor { + label: (&descriptor.parent).into(), + size, + mip_level_count: descriptor.mipLevelCount, + sample_count: descriptor.sampleCount, + dimension: descriptor.dimension.into(), + format: device.validate_texture_format_required_features(&descriptor.format)?, + usage: wgt::TextureUsages::from_bits_retain(descriptor.usage), + view_formats: descriptor + .viewFormats + .iter() + .map(|tf| device.validate_texture_format_required_features(tf)) + .collect::>()?, + }; + Ok((desc, size)) +} + impl TryFrom<&GPUColor> for wgt::Color { type Error = Error; diff --git a/components/script/dom/gpudevice.rs b/components/script/dom/gpudevice.rs index c075894f374..780febc146d 100644 --- a/components/script/dom/gpudevice.rs +++ b/components/script/dom/gpudevice.rs @@ -153,6 +153,10 @@ impl GPUDevice { self.device } + pub fn queue_id(&self) -> webgpu::WebGPUQueue { + self.default_queue.id() + } + pub fn channel(&self) -> WebGPU { self.channel.clone() } diff --git a/components/script/dom/gputexture.rs b/components/script/dom/gputexture.rs index 76f2bf8a71c..530af51666d 100644 --- a/components/script/dom/gputexture.rs +++ b/components/script/dom/gputexture.rs @@ -9,6 +9,7 @@ use webgpu::wgc::resource; use webgpu::{wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView}; use super::bindings::error::Fallible; +use super::gpuconvert::convert_texture_descriptor; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{ GPUTextureAspect, GPUTextureDescriptor, GPUTextureDimension, GPUTextureFormat, @@ -127,21 +128,7 @@ impl GPUTexture { device: &GPUDevice, descriptor: &GPUTextureDescriptor, ) -> Fallible> { - let size = (&descriptor.size).try_into()?; - let desc = wgt::TextureDescriptor { - label: (&descriptor.parent).into(), - size, - mip_level_count: descriptor.mipLevelCount, - sample_count: descriptor.sampleCount, - dimension: descriptor.dimension.into(), - format: device.validate_texture_format_required_features(&descriptor.format)?, - usage: wgt::TextureUsages::from_bits_retain(descriptor.usage), - view_formats: descriptor - .viewFormats - .iter() - .map(|tf| device.validate_texture_format_required_features(tf)) - .collect::>()?, - }; + let (desc, size) = convert_texture_descriptor(descriptor, device)?; let texture_id = device.global().wgpu_id_hub().create_texture_id(); diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs index 839c233cb1e..b8fb33d07fc 100644 --- a/components/script/dom/htmlcanvaselement.rs +++ b/components/script/dom/htmlcanvaselement.rs @@ -105,7 +105,7 @@ impl HTMLCanvasElement { }, CanvasContext::WebGL(ref context) => context.recreate(size), CanvasContext::WebGL2(ref context) => context.recreate(size), - CanvasContext::WebGPU(_) => unimplemented!(), + CanvasContext::WebGPU(ref context) => context.resize(), } } } diff --git a/components/webgpu/ipc_messages/recv.rs b/components/webgpu/ipc_messages/recv.rs index 4328a384107..bc907c497a1 100644 --- a/components/webgpu/ipc_messages/recv.rs +++ b/components/webgpu/ipc_messages/recv.rs @@ -10,7 +10,7 @@ use base::id::PipelineId; use ipc_channel::ipc::{IpcSender, IpcSharedMemory}; use serde::{Deserialize, Serialize}; use webrender_api::units::DeviceIntSize; -use webrender_api::{ImageFormat, ImageKey}; +use webrender_api::ImageKey; use wgc::binding_model::{ BindGroupDescriptor, BindGroupLayoutDescriptor, PipelineLayoutDescriptor, }; @@ -34,6 +34,14 @@ use crate::render_commands::RenderCommand; use crate::swapchain::WebGPUContextId; use crate::{Error, ErrorFilter, WebGPUResponse, PRESENTATION_BUFFER_COUNT}; +#[derive(Clone, Copy, Debug, Deserialize, Serialize)] +pub struct ContextConfiguration { + pub device_id: id::DeviceId, + pub queue_id: id::QueueId, + pub format: wgt::TextureFormat, + pub is_opaque: bool, +} + #[derive(Debug, Deserialize, Serialize)] pub enum WebGPURequest { BufferMapAsync { @@ -103,7 +111,6 @@ pub enum WebGPURequest { /// present only on ASYNC versions async_sender: Option>, }, - CreateContext(IpcSender<(WebGPUContextId, ImageKey)>), CreatePipelineLayout { device_id: id::DeviceId, pipeline_layout_id: id::PipelineLayoutId, @@ -129,14 +136,31 @@ pub enum WebGPURequest { label: Option, sender: IpcSender, }, - CreateSwapChain { - device_id: id::DeviceId, - queue_id: id::QueueId, + /// Creates context + CreateContext { buffer_ids: ArrayVec, - context_id: WebGPUContextId, - image_key: ImageKey, - format: ImageFormat, size: DeviceIntSize, + sender: IpcSender<(WebGPUContextId, ImageKey)>, + }, + /// Recreates swapchain (if needed) + UpdateContext { + context_id: WebGPUContextId, + size: DeviceIntSize, + configuration: Option, + }, + /// Reads texture to swapchains buffer and maps it + SwapChainPresent { + context_id: WebGPUContextId, + texture_id: id::TextureId, + encoder_id: id::CommandEncoderId, + }, + ValidateTextureDescriptor { + device_id: id::DeviceId, + texture_id: id::TextureId, + descriptor: TextureDescriptor<'static>, + }, + DestroyContext { + context_id: WebGPUContextId, }, CreateTexture { device_id: id::DeviceId, @@ -152,10 +176,6 @@ pub enum WebGPURequest { DestroyBuffer(id::BufferId), DestroyDevice(id::DeviceId), DestroyTexture(id::TextureId), - DestroySwapChain { - context_id: WebGPUContextId, - image_key: ImageKey, - }, DropTexture(id::TextureId), DropAdapter(id::AdapterId), DropDevice(id::DeviceId), @@ -254,11 +274,6 @@ pub enum WebGPURequest { queue_id: id::QueueId, command_buffers: Vec, }, - SwapChainPresent { - context_id: WebGPUContextId, - texture_id: id::TextureId, - encoder_id: id::CommandEncoderId, - }, UnmapBuffer { buffer_id: id::BufferId, array_buffer: IpcSharedMemory, diff --git a/components/webgpu/lib.rs b/components/webgpu/lib.rs index f6c00b80bea..7d953d0ca6c 100644 --- a/components/webgpu/lib.rs +++ b/components/webgpu/lib.rs @@ -4,7 +4,7 @@ use log::warn; use swapchain::WGPUImageMap; -pub use swapchain::{PresentationData, WGPUExternalImages}; +pub use swapchain::{ContextData, WGPUExternalImages}; use webrender::RenderApiSender; use wgpu_thread::WGPU; pub use {wgpu_core as wgc, wgpu_types as wgt}; diff --git a/components/webgpu/swapchain.rs b/components/webgpu/swapchain.rs index 006ff993be8..d6fcfefa734 100644 --- a/components/webgpu/swapchain.rs +++ b/components/webgpu/swapchain.rs @@ -3,21 +3,21 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::collections::HashMap; -use std::ops::ControlFlow; use std::ptr::NonNull; use std::slice; use std::sync::{Arc, Mutex}; use arrayvec::ArrayVec; use euclid::default::Size2D; +use ipc_channel::ipc::IpcSender; use log::{error, warn}; use malloc_size_of::MallocSizeOf; use serde::{Deserialize, Serialize}; use webrender::{RenderApi, Transaction}; use webrender_api::units::DeviceIntSize; use webrender_api::{ - DirtyRect, ExternalImageData, ExternalImageId, ExternalImageType, ImageData, ImageDescriptor, - ImageDescriptorFlags, ImageFormat, ImageKey, + DirtyRect, DocumentId, ExternalImageData, ExternalImageId, ExternalImageType, ImageData, + ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey, }; use webrender_traits::{WebrenderExternalImageApi, WebrenderImageSource}; use wgpu_core::device::HostMap; @@ -25,9 +25,10 @@ use wgpu_core::global::Global; use wgpu_core::id; use wgpu_core::resource::{BufferAccessError, BufferMapCallback, BufferMapOperation}; -use crate::{wgt, WebGPUMsg}; +use crate::{wgt, ContextConfiguration, Error, WebGPUMsg}; pub const PRESENTATION_BUFFER_COUNT: usize = 10; +const DEFAULT_IMAGE_FORMAT: ImageFormat = ImageFormat::RGBA8; #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)] pub struct WebGPUContextId(pub u64); @@ -38,7 +39,7 @@ impl MallocSizeOf for WebGPUContextId { } } -pub type WGPUImageMap = Arc>>; +pub type WGPUImageMap = Arc>>; struct GPUPresentationBuffer { global: Arc, @@ -84,20 +85,20 @@ pub struct WGPUExternalImages { impl WebrenderExternalImageApi for WGPUExternalImages { fn lock(&mut self, id: u64) -> (WebrenderImageSource, Size2D) { let id = WebGPUContextId(id); - let size; - let data; - if let Some(present_data) = self.images.lock().unwrap().get(&id) { - size = present_data.image_desc.size.cast_unit(); - data = if let Some(present_data) = &present_data.data { - present_data.slice().to_vec() - } else { - present_data.dummy_data() - }; + let webgpu_contexts = self.images.lock().unwrap(); + let context_data = webgpu_contexts.get(&id).unwrap(); + let size = context_data.image_desc.size().cast_unit(); + let data = if let Some(present_buffer) = context_data + .swap_chain + .as_ref() + .map(|swap_chain| swap_chain.data.as_ref()) + .flatten() + { + present_buffer.slice().to_vec() } else { - size = Size2D::new(0, 0); - data = Vec::new(); - } - let _ = self.locked_ids.insert(id, data); + context_data.dummy_data() + }; + self.locked_ids.insert(id, data); ( WebrenderImageSource::Raw(self.locked_ids.get(&id).unwrap().as_slice()), size, @@ -106,13 +107,13 @@ impl WebrenderExternalImageApi for WGPUExternalImages { fn unlock(&mut self, id: u64) { let id = WebGPUContextId(id); - let _ = self.locked_ids.remove(&id); + self.locked_ids.remove(&id); } } /// States of presentation buffer #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] -pub enum PresentationBufferState { +enum PresentationBufferState { /// Initial state, buffer has yet to be created, /// only its id is reserved #[default] @@ -125,61 +126,105 @@ pub enum PresentationBufferState { Mapped, } -pub struct PresentationData { +struct SwapChain { device_id: id::DeviceId, queue_id: id::QueueId, data: Option, - buffer_ids: ArrayVec<(id::BufferId, PresentationBufferState), PRESENTATION_BUFFER_COUNT>, - image_key: ImageKey, - image_desc: ImageDescriptor, - image_data: ImageData, } -impl PresentationData { - pub fn new( - device_id: id::DeviceId, - queue_id: id::QueueId, - buffer_ids: ArrayVec, +#[derive(Clone, Copy, Debug, PartialEq)] +pub struct WebGPUImageDescriptor(pub ImageDescriptor); + +impl WebGPUImageDescriptor { + fn new(format: ImageFormat, size: DeviceIntSize, is_opaque: bool) -> Self { + let stride = (((size.width * format.bytes_per_pixel()) | + (wgt::COPY_BYTES_PER_ROW_ALIGNMENT as i32 - 1)) + + 1) as i32; + Self(ImageDescriptor { + format, + size, + stride: Some(stride), + offset: 0, + flags: if is_opaque { + ImageDescriptorFlags::IS_OPAQUE + } else { + ImageDescriptorFlags::empty() + }, + }) + } + + fn default(size: DeviceIntSize) -> Self { + Self::new(DEFAULT_IMAGE_FORMAT, size, false) + } + + /// Returns true if needs image update (if it's changed) + fn update(&mut self, new: Self) -> bool { + if self.0 != new.0 { + self.0 = new.0; + true + } else { + false + } + } + + fn buffer_stride(&self) -> i32 { + self.0 + .stride + .expect("Stride should be set by WebGPUImageDescriptor") + } + + fn buffer_size(&self) -> wgt::BufferAddress { + (self.buffer_stride() * self.0.size.height) as wgt::BufferAddress + } + + fn size(&self) -> DeviceIntSize { + self.0.size + } +} + +pub struct ContextData { + image_key: ImageKey, + image_desc: WebGPUImageDescriptor, + image_data: ImageData, + buffer_ids: ArrayVec<(id::BufferId, PresentationBufferState), PRESENTATION_BUFFER_COUNT>, + /// If there is no associated swapchain the context is dummy (transparent black) + swap_chain: Option, +} + +impl ContextData { + /// Init ContextData as dummy (transparent black) + fn new( + context_id: WebGPUContextId, image_key: ImageKey, - image_desc: ImageDescriptor, - image_data: ImageData, + size: DeviceIntSize, + buffer_ids: ArrayVec, ) -> Self { + let image_data = ImageData::External(ExternalImageData { + id: ExternalImageId(context_id.0), + channel_index: 0, + image_type: ExternalImageType::Buffer, + }); + Self { - device_id, - queue_id, - data: None, + image_key, + image_desc: WebGPUImageDescriptor::default(size), + image_data, + swap_chain: None, buffer_ids: buffer_ids .iter() - .map(|&id| (id, PresentationBufferState::Unassigned)) + .map(|&buffer_id| (buffer_id, PresentationBufferState::Unassigned)) .collect(), - image_key, - image_desc, - image_data, } } fn dummy_data(&self) -> Vec { - let size = (self - .image_desc - .stride - .expect("Stride should be set when creating swapchain") * - self.image_desc.size.height) as usize; - vec![0; size] - } - - fn buffer_stride(&self) -> i32 { - self.image_desc - .stride - .expect("Stride should be set when creating swapchain") - } - - fn buffer_size(&self) -> wgt::BufferAddress { - (self.buffer_stride() * self.image_desc.size.height) as wgt::BufferAddress + vec![0; self.image_desc.buffer_size() as usize] } /// Returns id of available buffer /// and sets state to PresentationBufferState::Mapping fn get_available_buffer(&'_ mut self, global: &Arc) -> Option { + assert!(self.swap_chain.is_some()); if let Some((buffer_id, buffer_state)) = self .buffer_ids .iter_mut() @@ -196,11 +241,15 @@ impl PresentationData { let buffer_id = *buffer_id; let buffer_desc = wgt::BufferDescriptor { label: None, - size: self.buffer_size(), + size: self.image_desc.buffer_size(), usage: wgt::BufferUsages::MAP_READ | wgt::BufferUsages::COPY_DST, mapped_at_creation: false, }; - let _ = global.device_create_buffer(self.device_id, &buffer_desc, Some(buffer_id)); + let _ = global.device_create_buffer( + self.swap_chain.as_ref().unwrap().device_id, + &buffer_desc, + Some(buffer_id), + ); Some(buffer_id) } else { None @@ -217,57 +266,135 @@ impl PresentationData { } fn unmap_old_buffer(&mut self, presentation_buffer: GPUPresentationBuffer) { + assert!(self.swap_chain.is_some()); let buffer_state = self.get_buffer_state(presentation_buffer.buffer_id); assert_eq!(*buffer_state, PresentationBufferState::Mapped); *buffer_state = PresentationBufferState::Available; drop(presentation_buffer); } + + fn destroy_swapchain(&mut self, global: &Arc) { + drop(self.swap_chain.take()); + // free all buffers + for (buffer_id, buffer_state) in &mut self.buffer_ids { + match buffer_state { + PresentationBufferState::Unassigned => { + /* These buffer were not yet created in wgpu */ + }, + _ => { + global.buffer_drop(*buffer_id); + }, + } + *buffer_state = PresentationBufferState::Unassigned; + } + } + + fn destroy( + mut self, + global: &Arc, + script_sender: &IpcSender, + webrender_api: &Arc>, + webrender_document: DocumentId, + ) { + self.destroy_swapchain(global); + for (buffer_id, _) in self.buffer_ids { + if let Err(e) = script_sender.send(WebGPUMsg::FreeBuffer(buffer_id)) { + warn!("Unable to send FreeBuffer({:?}) ({:?})", buffer_id, e); + }; + } + let mut txn = Transaction::new(); + txn.delete_image(self.image_key); + webrender_api + .lock() + .unwrap() + .send_transaction(webrender_document, txn); + } } impl crate::WGPU { - pub(crate) fn create_swapchain( + pub(crate) fn create_context( &self, - device_id: id::DeviceId, - queue_id: id::QueueId, - buffer_ids: ArrayVec, context_id: WebGPUContextId, - format: ImageFormat, - size: DeviceIntSize, image_key: ImageKey, + size: DeviceIntSize, + buffer_ids: ArrayVec, ) { - let image_desc = ImageDescriptor { - format, - size, - stride: Some( - (((size.width as u32 * 4) | (wgt::COPY_BYTES_PER_ROW_ALIGNMENT - 1)) + 1) as i32, - ), - offset: 0, - flags: ImageDescriptorFlags::IS_OPAQUE, - }; - - let image_data = ImageData::External(ExternalImageData { - id: ExternalImageId(context_id.0), - channel_index: 0, - image_type: ExternalImageType::Buffer, - }); - let _ = self.wgpu_image_map.lock().unwrap().insert( - context_id, - PresentationData::new( - device_id, - queue_id, - buffer_ids, - image_key, - image_desc, - image_data.clone(), - ), - ); - + let context_data = ContextData::new(context_id, image_key, size, buffer_ids); let mut txn = Transaction::new(); - txn.add_image(image_key, image_desc, image_data, None); + txn.add_image( + image_key, + context_data.image_desc.0, + context_data.image_data.clone(), + None, + ); self.webrender_api .lock() .unwrap() .send_transaction(self.webrender_document, txn); + assert!( + self.wgpu_image_map + .lock() + .unwrap() + .insert(context_id, context_data) + .is_none(), + "Context should be created only once!" + ); + } + + pub(crate) fn update_context( + &self, + context_id: WebGPUContextId, + size: DeviceIntSize, + config: Option, + ) { + let mut webgpu_contexts = self.wgpu_image_map.lock().unwrap(); + let context_data = webgpu_contexts.get_mut(&context_id).unwrap(); + + // If configuration is not provided or presentation format is not valid + // the context will be dummy until recreation + let format = config + .as_ref() + .map(|config| match config.format { + wgt::TextureFormat::Rgba8Unorm => Some(ImageFormat::RGBA8), + wgt::TextureFormat::Bgra8Unorm => Some(ImageFormat::BGRA8), + _ => None, + }) + .flatten(); + + let needs_image_update = if let Some(format) = format { + let config = config.expect("Config should exist when valid format is available"); + let new_image_desc = WebGPUImageDescriptor::new(format, size, config.is_opaque); + let needs_swapchain_rebuild = context_data.swap_chain.is_none() || + new_image_desc.buffer_size() != context_data.image_desc.buffer_size(); + if needs_swapchain_rebuild { + context_data.destroy_swapchain(&self.global); + context_data.swap_chain = Some(SwapChain { + device_id: config.device_id, + queue_id: config.queue_id, + data: None, + }); + } + context_data.image_desc.update(new_image_desc) + } else { + context_data.destroy_swapchain(&self.global); + context_data + .image_desc + .update(WebGPUImageDescriptor::default(size)) + }; + + if needs_image_update { + let mut txn = Transaction::new(); + txn.update_image( + context_data.image_key, + context_data.image_desc.0, + context_data.image_data.clone(), + &DirtyRect::All, + ); + self.webrender_api + .lock() + .unwrap() + .send_transaction(self.webrender_document, txn); + } } /// Copies data async from provided texture using encoder_id to available staging presentation buffer @@ -276,39 +403,42 @@ impl crate::WGPU { context_id: WebGPUContextId, encoder_id: id::Id, texture_id: id::Id, - ) -> ControlFlow<()> { + ) -> Result<(), Box> { + fn err(e: Option) -> Result<(), T> { + if let Some(error) = e { + Err(error) + } else { + Ok(()) + } + } + let global = &self.global; let device_id; let queue_id; - let size; let buffer_id; - let buffer_stride; - let buffer_size; + let image_desc; { - if let Some(present_data) = self.wgpu_image_map.lock().unwrap().get_mut(&context_id) { - size = present_data.image_desc.size; - device_id = present_data.device_id; - queue_id = present_data.queue_id; - buffer_stride = present_data.buffer_stride(); - buffer_size = present_data.buffer_size(); - buffer_id = if let Some(buffer_id) = present_data.get_available_buffer(global) { - buffer_id - } else { - error!("No staging buffer available for {:?}", context_id); - return ControlFlow::Break(()); + if let Some(context_data) = self.wgpu_image_map.lock().unwrap().get_mut(&context_id) { + let Some(swap_chain) = context_data.swap_chain.as_ref() else { + return Ok(()); }; + device_id = swap_chain.device_id; + queue_id = swap_chain.queue_id; + buffer_id = context_data.get_available_buffer(global).unwrap(); + image_desc = context_data.image_desc; } else { - error!("Data not found for {:?}", context_id); - return ControlFlow::Break(()); + return Ok(()); } } let comm_desc = wgt::CommandEncoderDescriptor { label: None }; - let _ = global.device_create_command_encoder(device_id, &comm_desc, Some(encoder_id)); + let (encoder_id, error) = + global.device_create_command_encoder(device_id, &comm_desc, Some(encoder_id)); + err(error)?; let buffer_cv = wgt::ImageCopyBuffer { buffer: buffer_id, layout: wgt::ImageDataLayout { offset: 0, - bytes_per_row: Some(buffer_stride as u32), + bytes_per_row: Some(image_desc.buffer_stride() as u32), rows_per_image: None, }, }; @@ -319,18 +449,25 @@ impl crate::WGPU { aspect: wgt::TextureAspect::All, }; let copy_size = wgt::Extent3d { - width: size.width as u32, - height: size.height as u32, + width: image_desc.size().width as u32, + height: image_desc.size().height as u32, depth_or_array_layers: 1, }; - let _ = global.command_encoder_copy_texture_to_buffer( + global.command_encoder_copy_texture_to_buffer( encoder_id, &texture_cv, &buffer_cv, ©_size, - ); - let _ = global.command_encoder_finish(encoder_id, &wgt::CommandBufferDescriptor::default()); - let _ = global.queue_submit(queue_id, &[encoder_id.into_command_buffer_id()]); + )?; + let (command_buffer_id, error) = + global.command_encoder_finish(encoder_id, &wgt::CommandBufferDescriptor::default()); + err(error)?; + { + let _guard = self.poller.lock(); + global + .queue_submit(queue_id, &[command_buffer_id]) + .map_err(Error::from_error)?; + } let callback = { let global = Arc::clone(&self.global); let wgpu_image_map = Arc::clone(&self.wgpu_image_map); @@ -343,11 +480,11 @@ impl crate::WGPU { result, global, buffer_id, - buffer_size, wgpu_image_map, context_id, webrender_api, webrender_document, + image_desc, ); })) }; @@ -355,42 +492,23 @@ impl crate::WGPU { host: HostMap::Read, callback: Some(callback), }; - let _ = global.buffer_map_async(buffer_id, 0, Some(buffer_size), map_op); + global.buffer_map_async(buffer_id, 0, Some(image_desc.buffer_size()), map_op)?; self.poller.wake(); - - ControlFlow::Continue(()) + Ok(()) } - pub(crate) fn destroy_swapchain( - &mut self, - context_id: WebGPUContextId, - image_key: webrender_api::ImageKey, - ) { - let present_data = self - .wgpu_image_map + pub(crate) fn destroy_context(&mut self, context_id: WebGPUContextId) { + self.wgpu_image_map .lock() .unwrap() .remove(&context_id) - .unwrap(); - for (buffer_id, buffer_state) in present_data.buffer_ids { - match buffer_state { - PresentationBufferState::Unassigned => { - /* These buffer were not yet created in wgpu */ - }, - _ => { - self.global.buffer_drop(buffer_id); - }, - } - if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBuffer(buffer_id)) { - warn!("Unable to send FreeBuffer({:?}) ({:?})", buffer_id, e); - }; - } - let mut txn = Transaction::new(); - txn.delete_image(image_key); - self.webrender_api - .lock() .unwrap() - .send_transaction(self.webrender_document, txn); + .destroy( + &self.global, + &self.script_sender, + &self.webrender_api, + self.webrender_document, + ); } } @@ -398,26 +516,60 @@ fn update_wr_image( result: Result<(), BufferAccessError>, global: Arc, buffer_id: id::BufferId, - buffer_size: u64, wgpu_image_map: WGPUImageMap, context_id: WebGPUContextId, webrender_api: Arc>, webrender_document: webrender_api::DocumentId, + image_desc: WebGPUImageDescriptor, ) { match result { Ok(()) => { - if let Some(present_data) = wgpu_image_map.lock().unwrap().get_mut(&context_id) { - let buffer_state = present_data.get_buffer_state(buffer_id); - assert_eq!(*buffer_state, PresentationBufferState::Mapping); + if let Some(context_data) = wgpu_image_map.lock().unwrap().get_mut(&context_id) { + let config_changed = image_desc != context_data.image_desc; + let buffer_state = context_data.get_buffer_state(buffer_id); + match buffer_state { + PresentationBufferState::Unassigned => { + // throw away all work, because we are from old swapchain + return; + }, + PresentationBufferState::Mapping => {}, + _ => panic!("Unexpected presentation buffer state"), + } + if config_changed { + /* + This means that while mapasync was running, context got recreated + so we need to throw all out work away. + + It is also possible that we got recreated with same config, + so canvas should be cleared, but we handle such case in gpucanvascontext + with drawing_buffer.cleared + + One more case is that we already have newer map async done, + so we can replace new image with old image but that should happen very rarely + + One possible solution to all problems is blocking device timeline + (wgpu thread or introduce new timeline/thread for presentation) + something like this is also mentioned in spec: + + 2. Ensure that all submitted work items (e.g. queue submissions) have completed writing to the image + https://gpuweb.github.io/gpuweb/#abstract-opdef-get-a-copy-of-the-image-contents-of-a-context + */ + let _ = global.buffer_unmap(buffer_id); + *buffer_state = PresentationBufferState::Available; + return; + } *buffer_state = PresentationBufferState::Mapped; let presentation_buffer = - GPUPresentationBuffer::new(global, buffer_id, buffer_size); - let old_presentation_buffer = present_data.data.replace(presentation_buffer); + GPUPresentationBuffer::new(global, buffer_id, image_desc.buffer_size()); + let Some(swap_chain) = context_data.swap_chain.as_mut() else { + return; + }; + let old_presentation_buffer = swap_chain.data.replace(presentation_buffer); let mut txn = Transaction::new(); txn.update_image( - present_data.image_key, - present_data.image_desc, - present_data.image_data.clone(), + context_data.image_key, + context_data.image_desc.0, + context_data.image_data.clone(), &DirtyRect::All, ); webrender_api @@ -425,10 +577,10 @@ fn update_wr_image( .unwrap() .send_transaction(webrender_document, txn); if let Some(old_presentation_buffer) = old_presentation_buffer { - present_data.unmap_old_buffer(old_presentation_buffer) + context_data.unmap_old_buffer(old_presentation_buffer) } } else { - error!("Data not found for {:?}", context_id); + error!("WebGPU Context {:?} is destroyed", context_id); } }, _ => error!("Could not map buffer({:?})", buffer_id), diff --git a/components/webgpu/wgpu_thread.rs b/components/webgpu/wgpu_thread.rs index 99dbd4326bb..256be53d68c 100644 --- a/components/webgpu/wgpu_thread.rs +++ b/components/webgpu/wgpu_thread.rs @@ -6,7 +6,6 @@ use std::borrow::Cow; use std::collections::HashMap; -use std::ops::ControlFlow; use std::slice; use std::sync::{Arc, Mutex}; @@ -15,7 +14,7 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender, IpcSharedMemory}; use log::{info, warn}; use servo_config::pref; use webrender::{RenderApi, RenderApiSender}; -use webrender_api::DocumentId; +use webrender_api::{DocumentId, ExternalImageId}; use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType}; use wgc::command::{ComputePass, ComputePassDescriptor, RenderPass}; use wgc::device::queue::SubmittedWorkDoneClosure; @@ -404,17 +403,6 @@ impl WGPU { self.maybe_dispatch_wgpu_error(device_id, error); } }, - WebGPURequest::CreateContext(sender) => { - let id = self - .external_images - .lock() - .expect("Lock poisoned?") - .next_id(WebrenderImageHandlerType::WebGPU); - let image_key = self.webrender_api.lock().unwrap().generate_image_key(); - if let Err(e) = sender.send((WebGPUContextId(id.0), image_key)) { - warn!("Failed to send ExternalImageId to new context ({})", e); - }; - }, WebGPURequest::CreatePipelineLayout { device_id, pipeline_layout_id, @@ -513,17 +501,79 @@ impl WGPU { } self.maybe_dispatch_wgpu_error(device_id, error); }, - WebGPURequest::CreateSwapChain { - device_id, - queue_id, + WebGPURequest::CreateContext { buffer_ids, - context_id, - image_key, size, - format, - } => self.create_swapchain( - device_id, queue_id, buffer_ids, context_id, format, size, image_key, - ), + sender, + } => { + let id = self + .external_images + .lock() + .expect("Lock poisoned?") + .next_id(WebrenderImageHandlerType::WebGPU); + let image_key = self.webrender_api.lock().unwrap().generate_image_key(); + let context_id = WebGPUContextId(id.0); + if let Err(e) = sender.send((context_id, image_key)) { + warn!("Failed to send ExternalImageId to new context ({})", e); + }; + self.create_context(context_id, image_key, size, buffer_ids); + }, + WebGPURequest::UpdateContext { + context_id, + size, + configuration, + } => { + self.update_context(context_id, size, configuration); + }, + WebGPURequest::SwapChainPresent { + context_id, + texture_id, + encoder_id, + } => { + let result = self.swapchain_present(context_id, encoder_id, texture_id); + if let Err(e) = result { + log::error!("Error occured in SwapChainPresent: {e:?}"); + } + }, + WebGPURequest::ValidateTextureDescriptor { + device_id, + texture_id, + descriptor, + } => { + // https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-configure + // validating TextureDescriptor by creating dummy texture + let global = &self.global; + let (_, error) = + global.device_create_texture(device_id, &descriptor, Some(texture_id)); + global.texture_drop(texture_id); + self.poller.wake(); + if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTexture(texture_id)) + { + warn!("Unable to send FreeTexture({:?}) ({:?})", texture_id, e); + }; + if let Some(error) = error { + self.dispatch_error(device_id, Error::from_error(error)); + continue; + } + // Supported context formats + // TODO: wgt::TextureFormat::Rgba16Float, when wr supports HDR + if !matches!( + descriptor.format, + wgt::TextureFormat::Bgra8Unorm | wgt::TextureFormat::Rgba8Unorm + ) { + self.dispatch_error( + device_id, + Error::Validation("Unsupported context format".to_string()), + ); + } + }, + WebGPURequest::DestroyContext { context_id } => { + self.destroy_context(context_id); + self.external_images + .lock() + .expect("Lock poisoned?") + .remove(&ExternalImageId(context_id.0)); + }, WebGPURequest::CreateTexture { device_id, texture_id, @@ -561,12 +611,6 @@ impl WGPU { // Wake poller thread to trigger DeviceLostClosure self.poller.wake(); }, - WebGPURequest::DestroySwapChain { - context_id, - image_key, - } => { - self.destroy_swapchain(context_id, image_key); - }, WebGPURequest::DestroyTexture(texture_id) => { let global = &self.global; let _ = global.texture_destroy(texture_id); @@ -965,17 +1009,6 @@ impl WGPU { }; self.maybe_dispatch_error(device_id, result.err()); }, - WebGPURequest::SwapChainPresent { - context_id, - texture_id, - encoder_id, - } => { - if let ControlFlow::Break(_) = - self.swapchain_present(context_id, encoder_id, texture_id) - { - continue; - } - }, WebGPURequest::UnmapBuffer { buffer_id, array_buffer, diff --git a/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini b/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini index a14959d0d29..00caf2152bf 100644 --- a/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/cts.https.html.ini @@ -9741,8 +9741,6 @@ [:format="bc1-rgba-unorm";canvasType="onscreen";enable_required_feature=false] [:format="bc1-rgba-unorm";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc1-rgba-unorm-srgb";canvasType="offscreen";enable_required_feature=false] @@ -9751,8 +9749,6 @@ [:format="bc1-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=false] [:format="bc1-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc2-rgba-unorm";canvasType="offscreen";enable_required_feature=false] @@ -9761,8 +9757,6 @@ [:format="bc2-rgba-unorm";canvasType="onscreen";enable_required_feature=false] [:format="bc2-rgba-unorm";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc2-rgba-unorm-srgb";canvasType="offscreen";enable_required_feature=false] @@ -9771,8 +9765,6 @@ [:format="bc2-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=false] [:format="bc2-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc3-rgba-unorm";canvasType="offscreen";enable_required_feature=false] @@ -9781,8 +9773,6 @@ [:format="bc3-rgba-unorm";canvasType="onscreen";enable_required_feature=false] [:format="bc3-rgba-unorm";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc3-rgba-unorm-srgb";canvasType="offscreen";enable_required_feature=false] @@ -9791,8 +9781,6 @@ [:format="bc3-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=false] [:format="bc3-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc4-r-snorm";canvasType="offscreen";enable_required_feature=false] @@ -9801,8 +9789,6 @@ [:format="bc4-r-snorm";canvasType="onscreen";enable_required_feature=false] [:format="bc4-r-snorm";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc4-r-unorm";canvasType="offscreen";enable_required_feature=false] @@ -9811,8 +9797,6 @@ [:format="bc4-r-unorm";canvasType="onscreen";enable_required_feature=false] [:format="bc4-r-unorm";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc5-rg-snorm";canvasType="offscreen";enable_required_feature=false] @@ -9821,8 +9805,6 @@ [:format="bc5-rg-snorm";canvasType="onscreen";enable_required_feature=false] [:format="bc5-rg-snorm";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc5-rg-unorm";canvasType="offscreen";enable_required_feature=false] @@ -9831,8 +9813,6 @@ [:format="bc5-rg-unorm";canvasType="onscreen";enable_required_feature=false] [:format="bc5-rg-unorm";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc6h-rgb-float";canvasType="offscreen";enable_required_feature=false] @@ -9841,8 +9821,6 @@ [:format="bc6h-rgb-float";canvasType="onscreen";enable_required_feature=false] [:format="bc6h-rgb-float";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc6h-rgb-ufloat";canvasType="offscreen";enable_required_feature=false] @@ -9851,8 +9829,6 @@ [:format="bc6h-rgb-ufloat";canvasType="onscreen";enable_required_feature=false] [:format="bc6h-rgb-ufloat";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc7-rgba-unorm";canvasType="offscreen";enable_required_feature=false] @@ -9861,8 +9837,6 @@ [:format="bc7-rgba-unorm";canvasType="onscreen";enable_required_feature=false] [:format="bc7-rgba-unorm";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="bc7-rgba-unorm-srgb";canvasType="offscreen";enable_required_feature=false] @@ -9871,8 +9845,6 @@ [:format="bc7-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=false] [:format="bc7-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="depth32float-stencil8";canvasType="offscreen";enable_required_feature=false] @@ -9881,8 +9853,6 @@ [:format="depth32float-stencil8";canvasType="onscreen";enable_required_feature=false] [:format="depth32float-stencil8";canvasType="onscreen";enable_required_feature=true] - expected: - if os == "linux" and not debug: FAIL [:format="eac-r11snorm";canvasType="offscreen";enable_required_feature=false] @@ -16934,9 +16904,45 @@ [cts.https.html?q=webgpu:api,validation,capability_checks,limits,maxTextureDimension2D:configure,at_over:*] - disabled: true - expected: - if os == "linux" and not debug: SKIP + [:limitTest="atDefault";testValueName="atLimit";canvasType="offscreen"] + + [:limitTest="atDefault";testValueName="atLimit";canvasType="onscreen"] + + [:limitTest="atDefault";testValueName="overLimit";canvasType="offscreen"] + + [:limitTest="atDefault";testValueName="overLimit";canvasType="onscreen"] + + [:limitTest="atMaximum";testValueName="atLimit";canvasType="offscreen"] + + [:limitTest="atMaximum";testValueName="atLimit";canvasType="onscreen"] + + [:limitTest="atMaximum";testValueName="overLimit";canvasType="offscreen"] + + [:limitTest="atMaximum";testValueName="overLimit";canvasType="onscreen"] + + [:limitTest="betweenDefaultAndMaximum";testValueName="atLimit";canvasType="offscreen"] + + [:limitTest="betweenDefaultAndMaximum";testValueName="atLimit";canvasType="onscreen"] + + [:limitTest="betweenDefaultAndMaximum";testValueName="overLimit";canvasType="offscreen"] + + [:limitTest="betweenDefaultAndMaximum";testValueName="overLimit";canvasType="onscreen"] + + [:limitTest="overMaximum";testValueName="atLimit";canvasType="offscreen"] + + [:limitTest="overMaximum";testValueName="atLimit";canvasType="onscreen"] + + [:limitTest="overMaximum";testValueName="overLimit";canvasType="offscreen"] + + [:limitTest="overMaximum";testValueName="overLimit";canvasType="onscreen"] + + [:limitTest="underDefault";testValueName="atLimit";canvasType="offscreen"] + + [:limitTest="underDefault";testValueName="atLimit";canvasType="onscreen"] + + [:limitTest="underDefault";testValueName="overLimit";canvasType="offscreen"] + + [:limitTest="underDefault";testValueName="overLimit";canvasType="onscreen"] [cts.https.html?q=webgpu:api,validation,capability_checks,limits,maxTextureDimension2D:createTexture,at_over:*] @@ -16962,8 +16968,45 @@ [cts.https.html?q=webgpu:api,validation,capability_checks,limits,maxTextureDimension2D:getCurrentTexture,at_over:*] - expected: - if os == "linux" and not debug: CRASH + [:limitTest="atDefault";testValueName="atLimit";canvasType="offscreen"] + + [:limitTest="atDefault";testValueName="atLimit";canvasType="onscreen"] + + [:limitTest="atDefault";testValueName="overLimit";canvasType="offscreen"] + + [:limitTest="atDefault";testValueName="overLimit";canvasType="onscreen"] + + [:limitTest="atMaximum";testValueName="atLimit";canvasType="offscreen"] + + [:limitTest="atMaximum";testValueName="atLimit";canvasType="onscreen"] + + [:limitTest="atMaximum";testValueName="overLimit";canvasType="offscreen"] + + [:limitTest="atMaximum";testValueName="overLimit";canvasType="onscreen"] + + [:limitTest="betweenDefaultAndMaximum";testValueName="atLimit";canvasType="offscreen"] + + [:limitTest="betweenDefaultAndMaximum";testValueName="atLimit";canvasType="onscreen"] + + [:limitTest="betweenDefaultAndMaximum";testValueName="overLimit";canvasType="offscreen"] + + [:limitTest="betweenDefaultAndMaximum";testValueName="overLimit";canvasType="onscreen"] + + [:limitTest="overMaximum";testValueName="atLimit";canvasType="offscreen"] + + [:limitTest="overMaximum";testValueName="atLimit";canvasType="onscreen"] + + [:limitTest="overMaximum";testValueName="overLimit";canvasType="offscreen"] + + [:limitTest="overMaximum";testValueName="overLimit";canvasType="onscreen"] + + [:limitTest="underDefault";testValueName="atLimit";canvasType="offscreen"] + + [:limitTest="underDefault";testValueName="atLimit";canvasType="onscreen"] + + [:limitTest="underDefault";testValueName="overLimit";canvasType="offscreen"] + + [:limitTest="underDefault";testValueName="overLimit";canvasType="onscreen"] [cts.https.html?q=webgpu:api,validation,capability_checks,limits,maxTextureDimension3D:createTexture,at_over:*] @@ -185733,60 +185776,32 @@ [:canvasType="onscreen";format="astc-8x8-unorm-srgb"] [:canvasType="onscreen";format="bc1-rgba-unorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc1-rgba-unorm-srgb"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc2-rgba-unorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc2-rgba-unorm-srgb"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc3-rgba-unorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc3-rgba-unorm-srgb"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc4-r-snorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc4-r-unorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc5-rg-snorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc5-rg-unorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc6h-rgb-float"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc6h-rgb-ufloat"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc7-rgba-unorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bc7-rgba-unorm-srgb"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bgra8unorm"] @@ -185863,8 +185878,6 @@ if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="r8snorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="r8uint"] expected: @@ -185875,8 +185888,6 @@ if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rg11b10ufloat"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rg16float"] expected: @@ -185907,8 +185918,6 @@ if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rg8snorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rg8uint"] expected: @@ -185927,8 +185936,6 @@ if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rgb9e5ufloat"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rgba16float"] expected: @@ -185959,8 +185966,6 @@ if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rgba8snorm"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rgba8uint"] expected: @@ -185978,13 +185983,23 @@ [cts.https.html?q=webgpu:web_platform,canvas,configure:size_zero_after_configure:*] - expected: - if os == "linux" and not debug: CRASH + [:canvasType="offscreen";zeroDimension="height"] + + [:canvasType="offscreen";zeroDimension="width"] + + [:canvasType="onscreen";zeroDimension="height"] + + [:canvasType="onscreen";zeroDimension="width"] [cts.https.html?q=webgpu:web_platform,canvas,configure:size_zero_before_configure:*] - expected: - if os == "linux" and not debug: CRASH + [:canvasType="offscreen";zeroDimension="height"] + + [:canvasType="offscreen";zeroDimension="width"] + + [:canvasType="onscreen";zeroDimension="height"] + + [:canvasType="onscreen";zeroDimension="width"] [cts.https.html?q=webgpu:web_platform,canvas,configure:usage:*] @@ -186027,18 +186042,12 @@ [:canvasType="offscreen";format="rgba8unorm";viewFormatFeature="texture-compression-etc2"] [:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="_undef_"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="depth32float-stencil8"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="texture-compression-astc"] [:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="texture-compression-bc"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="texture-compression-etc2"] @@ -186047,30 +186056,20 @@ if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rgba16float";viewFormatFeature="depth32float-stencil8"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rgba16float";viewFormatFeature="texture-compression-astc"] [:canvasType="onscreen";format="rgba16float";viewFormatFeature="texture-compression-bc"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rgba16float";viewFormatFeature="texture-compression-etc2"] [:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="_undef_"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="depth32float-stencil8"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="texture-compression-astc"] [:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="texture-compression-bc"] - expected: - if os == "linux" and not debug: FAIL [:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="texture-compression-etc2"] @@ -186082,8 +186081,9 @@ [cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:configured:*] - expected: - if os == "linux" and not debug: CRASH + [:canvasType="offscreen"] + + [:canvasType="onscreen"] [cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:expiry:*] @@ -186119,8 +186119,9 @@ [cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:resize:*] - expected: - if os == "linux" and not debug: CRASH + [:canvasType="offscreen"] + + [:canvasType="onscreen"] [cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:single_frames:*] diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_clear.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_clear.https.html.ini index e095c622110..e5370945fd7 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_clear.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_clear.https.html.ini @@ -1,6 +1,3 @@ [canvas_clear.https.html] expected: - if os == "win": CRASH - if os == "linux" and debug: CRASH - if os == "linux" and not debug: TIMEOUT - if os == "mac": CRASH + if os == "linux" and not debug: FAIL diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html.ini index d3a34795a48..95d0719fd6f 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_colorspace_rgba16float.https.html.ini @@ -1,6 +1,3 @@ [canvas_colorspace_rgba16float.https.html] expected: - if os == "win": CRASH - if os == "linux" and debug: CRASH if os == "linux" and not debug: TIMEOUT - if os == "mac": CRASH diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_copy.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_copy.https.html.ini index f5d7701c25f..a74b8034a45 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_copy.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_copy.https.html.ini @@ -1,6 +1,3 @@ [canvas_complex_rgba16float_copy.https.html] expected: - if os == "win": CRASH - if os == "linux" and debug: CRASH if os == "linux" and not debug: TIMEOUT - if os == "mac": CRASH diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_draw.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_draw.https.html.ini index bda949170f6..2454f43c393 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_draw.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_draw.https.html.ini @@ -1,6 +1,3 @@ [canvas_complex_rgba16float_draw.https.html] expected: - if os == "win": CRASH - if os == "linux" and debug: CRASH if os == "linux" and not debug: TIMEOUT - if os == "mac": CRASH diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_store.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_store.https.html.ini index 393275d96f5..54575862892 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_store.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba16float_store.https.html.ini @@ -1,6 +1,3 @@ [canvas_complex_rgba16float_store.https.html] expected: - if os == "win": CRASH - if os == "linux" and debug: CRASH - if os == "linux" and not debug: TIMEOUT - if os == "mac": CRASH + if os == "linux" and not debug: FAIL diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba8unorm_store.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba8unorm_store.https.html.ini index f58c35f5777..3848337c5b5 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba8unorm_store.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_complex_rgba8unorm_store.https.html.ini @@ -1,3 +1,3 @@ [canvas_complex_rgba8unorm_store.https.html] expected: - if os == "linux" and not debug: [PASS, FAIL] + if os == "linux" and not debug: PASS diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque_copy.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque_copy.https.html.ini index 6e592d5d2f6..51d6acd04b6 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque_copy.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque_copy.https.html.ini @@ -1,3 +1,3 @@ [canvas_composite_alpha_bgra8unorm_opaque_copy.https.html] expected: - if os == "linux" and not debug: [CRASH, PASS, FAIL] + if os == "linux" and not debug: PASS diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque_draw.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque_draw.https.html.ini index cf7bb53cb85..f1d70f52d28 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque_draw.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_opaque_draw.https.html.ini @@ -1,2 +1,2 @@ [canvas_composite_alpha_bgra8unorm_opaque_draw.https.html] - expected: [CRASH, PASS, FAIL] + expected: PASS diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html.ini index 1c45c99997c..3a56987d61d 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html.ini @@ -1,2 +1,3 @@ [canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html] - expected: FAIL + expected: + if os == "linux" and not debug: PASS diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html.ini index 7737a53cff1..db825da0175 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html.ini @@ -1,2 +1,3 @@ [canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html] - expected: FAIL + expected: + if os == "linux" and not debug: PASS diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_opaque_copy.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_opaque_copy.https.html.ini index 8bc934e79bd..adf70d0cd5e 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_opaque_copy.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_opaque_copy.https.html.ini @@ -1,6 +1,3 @@ [canvas_composite_alpha_rgba16float_opaque_copy.https.html] expected: - if os == "win": CRASH - if os == "linux" and debug: CRASH - if os == "linux" and not debug: TIMEOUT - if os == "mac": CRASH + if os == "linux" and not debug: FAIL diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_opaque_draw.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_opaque_draw.https.html.ini index 3d0b65f85e7..180a1e1073a 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_opaque_draw.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_opaque_draw.https.html.ini @@ -1,6 +1,3 @@ [canvas_composite_alpha_rgba16float_opaque_draw.https.html] expected: - if os == "win": CRASH - if os == "linux" and debug: CRASH - if os == "linux" and not debug: TIMEOUT - if os == "mac": CRASH + if os == "linux" and not debug: FAIL diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_copy.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_copy.https.html.ini index db7839f9bfc..ec3edf5b629 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_copy.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_copy.https.html.ini @@ -1,6 +1,3 @@ [canvas_composite_alpha_rgba16float_premultiplied_copy.https.html] expected: - if os == "win": CRASH - if os == "linux" and debug: CRASH - if os == "linux" and not debug: TIMEOUT - if os == "mac": CRASH + if os == "linux" and not debug: FAIL diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_draw.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_draw.https.html.ini index a5161dbd9f7..885629d4425 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_draw.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba16float_premultiplied_draw.https.html.ini @@ -1,6 +1,3 @@ [canvas_composite_alpha_rgba16float_premultiplied_draw.https.html] expected: - if os == "win": CRASH - if os == "linux" and debug: CRASH - if os == "linux" and not debug: TIMEOUT - if os == "mac": CRASH + if os == "linux" and not debug: FAIL diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_copy.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_copy.https.html.ini index b409401c33d..4e3391e6669 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_copy.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_copy.https.html.ini @@ -1,3 +1,3 @@ [canvas_composite_alpha_rgba8unorm_opaque_copy.https.html] expected: - if os == "linux" and not debug: [CRASH, PASS, FAIL] + if os == "linux" and not debug: PASS diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_draw.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_draw.https.html.ini index 3684ca84a50..5c94c840149 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_draw.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_opaque_draw.https.html.ini @@ -1,3 +1,3 @@ [canvas_composite_alpha_rgba8unorm_opaque_draw.https.html] expected: - if os == "linux" and not debug: [PASS, FAIL] + if os == "linux" and not debug: PASS diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html.ini index 2e826246236..87632985610 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html.ini @@ -1,2 +1,3 @@ [canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html] - expected: FAIL + expected: + if os == "linux" and not debug: PASS diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html.ini index 426c1fc499e..7c5b6119847 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html.ini @@ -1,2 +1,3 @@ [canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html] - expected: [CRASH, FAIL] + expected: + if os == "linux" and not debug: PASS diff --git a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/delay_get_texture.https.html.ini b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/delay_get_texture.https.html.ini index f892aa1dcf9..5d76752c7ac 100644 --- a/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/delay_get_texture.https.html.ini +++ b/tests/wpt/webgpu/meta/webgpu/webgpu/web_platform/reftests/delay_get_texture.https.html.ini @@ -1,6 +1,3 @@ [delay_get_texture.https.html] expected: - if os == "win": FAIL - if os == "linux" and debug: FAIL - if os == "linux" and not debug: [PASS, FAIL] - if os == "mac": FAIL + if os == "linux" and not debug: PASS