mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
webgpu: renovate gpucanvascontext and webgpu presentation to match the spec (#33521)
* Reimpl gpucanvascontext Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * ValidateTextureDescriptorAndCreateSwapChain Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * reconfigure Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * resize Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * work around deadlocks in wgpu core Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * match spec even more by moving all swapchain operations into one updatecontext Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * error handling Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * enable one test Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * label dummy texture Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * update expect Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * clean some expectation (they are not flaky anymore) Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * one more Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * change for configuration change in update_wr_image Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * DEFAULT_IMAGE_FORMAT Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * fixup Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> * introduce WebGPUImageDescriptor Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com> --------- Signed-off-by: sagudev <16504129+sagudev@users.noreply.github.com>
This commit is contained in:
parent
0b2549f4cb
commit
05ecb8eddb
30 changed files with 795 additions and 483 deletions
|
@ -2951,7 +2951,7 @@ impl Document {
|
||||||
self.dirty_webgpu_contexts
|
self.dirty_webgpu_contexts
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.drain()
|
.drain()
|
||||||
.for_each(|(_, context)| context.send_swap_chain_present());
|
.for_each(|(_, context)| context.update_rendering_of_webgpu_canvas());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id_map(&self) -> Ref<HashMapTracedValues<Atom, Vec<Dom<Element>>>> {
|
pub fn id_map(&self) -> Ref<HashMapTracedValues<Atom, Vec<Dom<Element>>>> {
|
||||||
|
|
|
@ -2,6 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::borrow::Cow;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
|
@ -9,20 +12,25 @@ use ipc_channel::ipc;
|
||||||
use script_layout_interface::HTMLCanvasDataSource;
|
use script_layout_interface::HTMLCanvasDataSource;
|
||||||
use webgpu::swapchain::WebGPUContextId;
|
use webgpu::swapchain::WebGPUContextId;
|
||||||
use webgpu::wgc::id;
|
use webgpu::wgc::id;
|
||||||
use webgpu::{WebGPU, WebGPURequest, WebGPUTexture, PRESENTATION_BUFFER_COUNT};
|
use webgpu::{
|
||||||
use webrender_api::{units, ImageFormat, ImageKey};
|
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::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas;
|
||||||
use super::bindings::error::{Error, Fallible};
|
use super::bindings::error::{Error, Fallible};
|
||||||
use super::bindings::root::MutNullableDom;
|
use super::bindings::root::MutNullableDom;
|
||||||
use super::bindings::str::USVString;
|
use super::bindings::str::USVString;
|
||||||
|
use super::gpuconvert::convert_texture_descriptor;
|
||||||
use super::gputexture::GPUTexture;
|
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::{
|
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||||
GPUCanvasConfiguration, GPUCanvasContextMethods, GPUDeviceMethods, GPUExtent3D,
|
GPUCanvasConfiguration, GPUCanvasContextMethods, GPUDeviceMethods, GPUExtent3D,
|
||||||
GPUExtent3DDict, GPUObjectDescriptorBase, GPUTextureDescriptor, GPUTextureDimension,
|
GPUExtent3DDict, GPUObjectDescriptorBase, GPUTextureDescriptor, GPUTextureDimension,
|
||||||
GPUTextureFormat,
|
|
||||||
};
|
};
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
|
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<u64> {
|
||||||
|
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<ContextConfiguration>,
|
||||||
|
}
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct GPUCanvasContext {
|
pub struct GPUCanvasContext {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
|
@ -99,14 +130,34 @@ pub struct GPUCanvasContext {
|
||||||
webrender_image: ImageKey,
|
webrender_image: ImageKey,
|
||||||
#[no_trace]
|
#[no_trace]
|
||||||
context_id: WebGPUContextId,
|
context_id: WebGPUContextId,
|
||||||
|
#[ignore_malloc_size_of = "manual writing is hard"]
|
||||||
|
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-configuration-slot>
|
||||||
|
configuration: RefCell<Option<GPUCanvasConfiguration>>,
|
||||||
|
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-texturedescriptor-slot>
|
||||||
|
texture_descriptor: RefCell<Option<GPUTextureDescriptor>>,
|
||||||
|
/// Conceptually <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-drawingbuffer-slot>
|
||||||
|
drawing_buffer: RefCell<DrawingBuffer>,
|
||||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-currenttexture-slot>
|
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-currenttexture-slot>
|
||||||
texture: MutNullableDom<GPUTexture>,
|
current_texture: MutNullableDom<GPUTexture>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUCanvasContext {
|
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();
|
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::<id::BufferId, PRESENTATION_BUFFER_COUNT>::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);
|
warn!("Failed to send CreateContext ({:?})", e);
|
||||||
}
|
}
|
||||||
let (external_id, webrender_image) = receiver.recv().unwrap();
|
let (external_id, webrender_image) = receiver.recv().unwrap();
|
||||||
|
@ -116,13 +167,21 @@ impl GPUCanvasContext {
|
||||||
canvas,
|
canvas,
|
||||||
webrender_image,
|
webrender_image,
|
||||||
context_id: WebGPUContextId(external_id.0),
|
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<Self> {
|
pub fn new(global: &GlobalScope, canvas: &HTMLCanvasElement, channel: WebGPU) -> DomRoot<Self> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(GPUCanvasContext::new_inherited(
|
Box::new(GPUCanvasContext::new_inherited(
|
||||||
|
global,
|
||||||
HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(DomRoot::from_ref(canvas)),
|
HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(DomRoot::from_ref(canvas)),
|
||||||
channel,
|
channel,
|
||||||
)),
|
)),
|
||||||
|
@ -131,17 +190,93 @@ impl GPUCanvasContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Abstract ops from spec
|
||||||
impl GPUCanvasContext {
|
impl GPUCanvasContext {
|
||||||
fn layout_handle(&self) -> HTMLCanvasDataSource {
|
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-gputexturedescriptor-for-the-canvas-and-configuration>
|
||||||
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) {
|
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-expire-the-current-texture>
|
||||||
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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-replace-the-drawing-buffer>
|
||||||
|
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();
|
let encoder_id = self.global().wgpu_id_hub().create_command_encoder_id();
|
||||||
if let Err(e) = self.channel.0.send(WebGPURequest::SwapChainPresent {
|
if let Err(e) = self.channel.0.send(WebGPURequest::SwapChainPresent {
|
||||||
context_id: self.context_id,
|
context_id: self.context_id,
|
||||||
texture_id,
|
texture_id: texture_id.0,
|
||||||
encoder_id,
|
encoder_id,
|
||||||
}) {
|
}) {
|
||||||
warn!(
|
warn!(
|
||||||
|
@ -151,29 +286,42 @@ impl GPUCanvasContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn context_id(&self) -> WebGPUContextId {
|
fn size(&self) -> Size2D<u64> {
|
||||||
|
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
|
self.context_id
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn texture_id(&self) -> Option<WebGPUTexture> {
|
pub(crate) fn mark_as_dirty(&self) {
|
||||||
self.texture.get().map(|t| t.id())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mark_as_dirty(&self) {
|
|
||||||
if let HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) = &self.canvas {
|
if let HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) = &self.canvas {
|
||||||
canvas.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
canvas.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
||||||
let document = document_from_node(&**canvas);
|
let document = document_from_node(&**canvas);
|
||||||
document.add_dirty_webgpu_canvas(self);
|
document.add_dirty_webgpu_canvas(self);
|
||||||
}
|
}
|
||||||
// TODO(sagudev): offscreen canvas also dirty?
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> Size2D<u64> {
|
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-updating-the-rendering-of-a-webgpu-canvas>
|
||||||
match &self.canvas {
|
pub(crate) fn update_rendering_of_webgpu_canvas(&self) {
|
||||||
HTMLCanvasElementOrOffscreenCanvas::HTMLCanvasElement(canvas) => {
|
// Step 1
|
||||||
Size2D::new(canvas.Width() as u64, canvas.Height() as u64)
|
self.expire_current_texture();
|
||||||
},
|
}
|
||||||
HTMLCanvasElementOrOffscreenCanvas::OffscreenCanvas(canvas) => canvas.get_size(),
|
|
||||||
|
/// <https://gpuweb.github.io/gpuweb/#abstract-opdef-update-the-canvas-size>
|
||||||
|
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 {
|
||||||
|
|
||||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-configure>
|
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-configure>
|
||||||
fn Configure(&self, configuration: &GPUCanvasConfiguration) -> Fallible<()> {
|
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
|
// Step 4
|
||||||
let size = self.size();
|
let descriptor = self.texture_descriptor_for_canvas(configuration);
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Step 8
|
// Step 2&3
|
||||||
let mut buffer_ids = ArrayVec::<id::BufferId, PRESENTATION_BUFFER_COUNT>::new();
|
let (mut desc, _) = convert_texture_descriptor(&descriptor, &configuration.device)?;
|
||||||
for _ in 0..PRESENTATION_BUFFER_COUNT {
|
desc.label = Some(Cow::Borrowed(
|
||||||
buffer_ids.push(self.global().wgpu_id_hub().create_buffer_id());
|
"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
|
self.channel
|
||||||
.0
|
.0
|
||||||
.send(WebGPURequest::CreateSwapChain {
|
.send(WebGPURequest::ValidateTextureDescriptor {
|
||||||
device_id: configuration.device.id().0,
|
device_id: configuration.device.id().0,
|
||||||
queue_id: configuration.device.GetQueue().id().0,
|
texture_id,
|
||||||
buffer_ids,
|
descriptor: desc,
|
||||||
context_id: self.context_id,
|
|
||||||
image_key: self.webrender_image,
|
|
||||||
format,
|
|
||||||
size: units::DeviceIntSize::new(size.width as i32, size.height as i32),
|
|
||||||
})
|
})
|
||||||
.expect("Failed to create WebGPU SwapChain");
|
.expect("Failed to create WebGPU SwapChain");
|
||||||
|
|
||||||
self.texture.set(Some(
|
|
||||||
&configuration.device.CreateTexture(&text_desc).unwrap(),
|
|
||||||
));
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-unconfigure>
|
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-unconfigure>
|
||||||
fn Unconfigure(&self) {
|
fn Unconfigure(&self) {
|
||||||
if let Some(texture) = self.texture.take() {
|
// Step 1
|
||||||
if let Err(e) = self.channel.0.send(WebGPURequest::DestroySwapChain {
|
self.configuration.take();
|
||||||
context_id: self.context_id,
|
// Step 2
|
||||||
image_key: self.webrender_image,
|
self.current_texture.take();
|
||||||
}) {
|
// Step 3
|
||||||
warn!(
|
self.replace_drawing_buffer();
|
||||||
"Failed to send DestroySwapChain-ImageKey({:?}) ({})",
|
|
||||||
self.webrender_image, e
|
|
||||||
);
|
|
||||||
}
|
|
||||||
drop(texture);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-getcurrenttexture>
|
/// <https://gpuweb.github.io/gpuweb/#dom-gpucanvascontext-getcurrenttexture>
|
||||||
fn GetCurrentTexture(&self) -> Fallible<DomRoot<GPUTexture>> {
|
fn GetCurrentTexture(&self) -> Fallible<DomRoot<GPUTexture>> {
|
||||||
// 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();
|
self.mark_as_dirty();
|
||||||
// Step 6.
|
// Step 6
|
||||||
self.texture.get().ok_or(Error::InvalidState)
|
Ok(current_texture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for GPUCanvasContext {
|
impl Drop for GPUCanvasContext {
|
||||||
fn drop(&mut self) {
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,11 @@ use std::num::NonZeroU64;
|
||||||
use webgpu::wgc::binding_model::{BindGroupEntry, BindingResource, BufferBinding};
|
use webgpu::wgc::binding_model::{BindGroupEntry, BindingResource, BufferBinding};
|
||||||
use webgpu::wgc::command as wgpu_com;
|
use webgpu::wgc::command as wgpu_com;
|
||||||
use webgpu::wgc::pipeline::ProgrammableStageDescriptor;
|
use webgpu::wgc::pipeline::ProgrammableStageDescriptor;
|
||||||
|
use webgpu::wgc::resource::TextureDescriptor;
|
||||||
use webgpu::wgt::{self, AstcBlock, AstcChannel};
|
use webgpu::wgt::{self, AstcBlock, AstcChannel};
|
||||||
|
|
||||||
use super::bindings::codegen::Bindings::WebGPUBinding::{
|
use super::bindings::codegen::Bindings::WebGPUBinding::{
|
||||||
GPUProgrammableStage, GPUTextureDimension,
|
GPUProgrammableStage, GPUTextureDescriptor, GPUTextureDimension,
|
||||||
};
|
};
|
||||||
use super::bindings::error::Error;
|
use super::bindings::error::Error;
|
||||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||||
|
@ -506,6 +507,7 @@ impl<'a> From<&GPUObjectDescriptorBase> for Option<Cow<'a, str>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn convert_bind_group_layout_entry(
|
pub fn convert_bind_group_layout_entry(
|
||||||
bgle: &GPUBindGroupLayoutEntry,
|
bgle: &GPUBindGroupLayoutEntry,
|
||||||
device: &GPUDevice,
|
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::<Fallible<_>>()?,
|
||||||
|
};
|
||||||
|
Ok((desc, size))
|
||||||
|
}
|
||||||
|
|
||||||
impl TryFrom<&GPUColor> for wgt::Color {
|
impl TryFrom<&GPUColor> for wgt::Color {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
|
|
|
@ -153,6 +153,10 @@ impl GPUDevice {
|
||||||
self.device
|
self.device
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn queue_id(&self) -> webgpu::WebGPUQueue {
|
||||||
|
self.default_queue.id()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn channel(&self) -> WebGPU {
|
pub fn channel(&self) -> WebGPU {
|
||||||
self.channel.clone()
|
self.channel.clone()
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ use webgpu::wgc::resource;
|
||||||
use webgpu::{wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView};
|
use webgpu::{wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView};
|
||||||
|
|
||||||
use super::bindings::error::Fallible;
|
use super::bindings::error::Fallible;
|
||||||
|
use super::gpuconvert::convert_texture_descriptor;
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
|
||||||
GPUTextureAspect, GPUTextureDescriptor, GPUTextureDimension, GPUTextureFormat,
|
GPUTextureAspect, GPUTextureDescriptor, GPUTextureDimension, GPUTextureFormat,
|
||||||
|
@ -127,21 +128,7 @@ impl GPUTexture {
|
||||||
device: &GPUDevice,
|
device: &GPUDevice,
|
||||||
descriptor: &GPUTextureDescriptor,
|
descriptor: &GPUTextureDescriptor,
|
||||||
) -> Fallible<DomRoot<GPUTexture>> {
|
) -> Fallible<DomRoot<GPUTexture>> {
|
||||||
let size = (&descriptor.size).try_into()?;
|
let (desc, size) = convert_texture_descriptor(descriptor, device)?;
|
||||||
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::<Fallible<_>>()?,
|
|
||||||
};
|
|
||||||
|
|
||||||
let texture_id = device.global().wgpu_id_hub().create_texture_id();
|
let texture_id = device.global().wgpu_id_hub().create_texture_id();
|
||||||
|
|
||||||
|
|
|
@ -105,7 +105,7 @@ impl HTMLCanvasElement {
|
||||||
},
|
},
|
||||||
CanvasContext::WebGL(ref context) => context.recreate(size),
|
CanvasContext::WebGL(ref context) => context.recreate(size),
|
||||||
CanvasContext::WebGL2(ref context) => context.recreate(size),
|
CanvasContext::WebGL2(ref context) => context.recreate(size),
|
||||||
CanvasContext::WebGPU(_) => unimplemented!(),
|
CanvasContext::WebGPU(ref context) => context.resize(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ use base::id::PipelineId;
|
||||||
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
|
use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use webrender_api::units::DeviceIntSize;
|
use webrender_api::units::DeviceIntSize;
|
||||||
use webrender_api::{ImageFormat, ImageKey};
|
use webrender_api::ImageKey;
|
||||||
use wgc::binding_model::{
|
use wgc::binding_model::{
|
||||||
BindGroupDescriptor, BindGroupLayoutDescriptor, PipelineLayoutDescriptor,
|
BindGroupDescriptor, BindGroupLayoutDescriptor, PipelineLayoutDescriptor,
|
||||||
};
|
};
|
||||||
|
@ -34,6 +34,14 @@ use crate::render_commands::RenderCommand;
|
||||||
use crate::swapchain::WebGPUContextId;
|
use crate::swapchain::WebGPUContextId;
|
||||||
use crate::{Error, ErrorFilter, WebGPUResponse, PRESENTATION_BUFFER_COUNT};
|
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)]
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
pub enum WebGPURequest {
|
pub enum WebGPURequest {
|
||||||
BufferMapAsync {
|
BufferMapAsync {
|
||||||
|
@ -103,7 +111,6 @@ pub enum WebGPURequest {
|
||||||
/// present only on ASYNC versions
|
/// present only on ASYNC versions
|
||||||
async_sender: Option<IpcSender<WebGPUResponse>>,
|
async_sender: Option<IpcSender<WebGPUResponse>>,
|
||||||
},
|
},
|
||||||
CreateContext(IpcSender<(WebGPUContextId, ImageKey)>),
|
|
||||||
CreatePipelineLayout {
|
CreatePipelineLayout {
|
||||||
device_id: id::DeviceId,
|
device_id: id::DeviceId,
|
||||||
pipeline_layout_id: id::PipelineLayoutId,
|
pipeline_layout_id: id::PipelineLayoutId,
|
||||||
|
@ -129,14 +136,31 @@ pub enum WebGPURequest {
|
||||||
label: Option<String>,
|
label: Option<String>,
|
||||||
sender: IpcSender<WebGPUResponse>,
|
sender: IpcSender<WebGPUResponse>,
|
||||||
},
|
},
|
||||||
CreateSwapChain {
|
/// Creates context
|
||||||
device_id: id::DeviceId,
|
CreateContext {
|
||||||
queue_id: id::QueueId,
|
|
||||||
buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
||||||
context_id: WebGPUContextId,
|
|
||||||
image_key: ImageKey,
|
|
||||||
format: ImageFormat,
|
|
||||||
size: DeviceIntSize,
|
size: DeviceIntSize,
|
||||||
|
sender: IpcSender<(WebGPUContextId, ImageKey)>,
|
||||||
|
},
|
||||||
|
/// Recreates swapchain (if needed)
|
||||||
|
UpdateContext {
|
||||||
|
context_id: WebGPUContextId,
|
||||||
|
size: DeviceIntSize,
|
||||||
|
configuration: Option<ContextConfiguration>,
|
||||||
|
},
|
||||||
|
/// 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 {
|
CreateTexture {
|
||||||
device_id: id::DeviceId,
|
device_id: id::DeviceId,
|
||||||
|
@ -152,10 +176,6 @@ pub enum WebGPURequest {
|
||||||
DestroyBuffer(id::BufferId),
|
DestroyBuffer(id::BufferId),
|
||||||
DestroyDevice(id::DeviceId),
|
DestroyDevice(id::DeviceId),
|
||||||
DestroyTexture(id::TextureId),
|
DestroyTexture(id::TextureId),
|
||||||
DestroySwapChain {
|
|
||||||
context_id: WebGPUContextId,
|
|
||||||
image_key: ImageKey,
|
|
||||||
},
|
|
||||||
DropTexture(id::TextureId),
|
DropTexture(id::TextureId),
|
||||||
DropAdapter(id::AdapterId),
|
DropAdapter(id::AdapterId),
|
||||||
DropDevice(id::DeviceId),
|
DropDevice(id::DeviceId),
|
||||||
|
@ -254,11 +274,6 @@ pub enum WebGPURequest {
|
||||||
queue_id: id::QueueId,
|
queue_id: id::QueueId,
|
||||||
command_buffers: Vec<id::CommandBufferId>,
|
command_buffers: Vec<id::CommandBufferId>,
|
||||||
},
|
},
|
||||||
SwapChainPresent {
|
|
||||||
context_id: WebGPUContextId,
|
|
||||||
texture_id: id::TextureId,
|
|
||||||
encoder_id: id::CommandEncoderId,
|
|
||||||
},
|
|
||||||
UnmapBuffer {
|
UnmapBuffer {
|
||||||
buffer_id: id::BufferId,
|
buffer_id: id::BufferId,
|
||||||
array_buffer: IpcSharedMemory,
|
array_buffer: IpcSharedMemory,
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use swapchain::WGPUImageMap;
|
use swapchain::WGPUImageMap;
|
||||||
pub use swapchain::{PresentationData, WGPUExternalImages};
|
pub use swapchain::{ContextData, WGPUExternalImages};
|
||||||
use webrender::RenderApiSender;
|
use webrender::RenderApiSender;
|
||||||
use wgpu_thread::WGPU;
|
use wgpu_thread::WGPU;
|
||||||
pub use {wgpu_core as wgc, wgpu_types as wgt};
|
pub use {wgpu_core as wgc, wgpu_types as wgt};
|
||||||
|
|
|
@ -3,21 +3,21 @@
|
||||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::ControlFlow;
|
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use arrayvec::ArrayVec;
|
use arrayvec::ArrayVec;
|
||||||
use euclid::default::Size2D;
|
use euclid::default::Size2D;
|
||||||
|
use ipc_channel::ipc::IpcSender;
|
||||||
use log::{error, warn};
|
use log::{error, warn};
|
||||||
use malloc_size_of::MallocSizeOf;
|
use malloc_size_of::MallocSizeOf;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use webrender::{RenderApi, Transaction};
|
use webrender::{RenderApi, Transaction};
|
||||||
use webrender_api::units::DeviceIntSize;
|
use webrender_api::units::DeviceIntSize;
|
||||||
use webrender_api::{
|
use webrender_api::{
|
||||||
DirtyRect, ExternalImageData, ExternalImageId, ExternalImageType, ImageData, ImageDescriptor,
|
DirtyRect, DocumentId, ExternalImageData, ExternalImageId, ExternalImageType, ImageData,
|
||||||
ImageDescriptorFlags, ImageFormat, ImageKey,
|
ImageDescriptor, ImageDescriptorFlags, ImageFormat, ImageKey,
|
||||||
};
|
};
|
||||||
use webrender_traits::{WebrenderExternalImageApi, WebrenderImageSource};
|
use webrender_traits::{WebrenderExternalImageApi, WebrenderImageSource};
|
||||||
use wgpu_core::device::HostMap;
|
use wgpu_core::device::HostMap;
|
||||||
|
@ -25,9 +25,10 @@ use wgpu_core::global::Global;
|
||||||
use wgpu_core::id;
|
use wgpu_core::id;
|
||||||
use wgpu_core::resource::{BufferAccessError, BufferMapCallback, BufferMapOperation};
|
use wgpu_core::resource::{BufferAccessError, BufferMapCallback, BufferMapOperation};
|
||||||
|
|
||||||
use crate::{wgt, WebGPUMsg};
|
use crate::{wgt, ContextConfiguration, Error, WebGPUMsg};
|
||||||
|
|
||||||
pub const PRESENTATION_BUFFER_COUNT: usize = 10;
|
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)]
|
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
|
||||||
pub struct WebGPUContextId(pub u64);
|
pub struct WebGPUContextId(pub u64);
|
||||||
|
@ -38,7 +39,7 @@ impl MallocSizeOf for WebGPUContextId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type WGPUImageMap = Arc<Mutex<HashMap<WebGPUContextId, PresentationData>>>;
|
pub type WGPUImageMap = Arc<Mutex<HashMap<WebGPUContextId, ContextData>>>;
|
||||||
|
|
||||||
struct GPUPresentationBuffer {
|
struct GPUPresentationBuffer {
|
||||||
global: Arc<Global>,
|
global: Arc<Global>,
|
||||||
|
@ -84,20 +85,20 @@ pub struct WGPUExternalImages {
|
||||||
impl WebrenderExternalImageApi for WGPUExternalImages {
|
impl WebrenderExternalImageApi for WGPUExternalImages {
|
||||||
fn lock(&mut self, id: u64) -> (WebrenderImageSource, Size2D<i32>) {
|
fn lock(&mut self, id: u64) -> (WebrenderImageSource, Size2D<i32>) {
|
||||||
let id = WebGPUContextId(id);
|
let id = WebGPUContextId(id);
|
||||||
let size;
|
let webgpu_contexts = self.images.lock().unwrap();
|
||||||
let data;
|
let context_data = webgpu_contexts.get(&id).unwrap();
|
||||||
if let Some(present_data) = self.images.lock().unwrap().get(&id) {
|
let size = context_data.image_desc.size().cast_unit();
|
||||||
size = present_data.image_desc.size.cast_unit();
|
let data = if let Some(present_buffer) = context_data
|
||||||
data = if let Some(present_data) = &present_data.data {
|
.swap_chain
|
||||||
present_data.slice().to_vec()
|
.as_ref()
|
||||||
} else {
|
.map(|swap_chain| swap_chain.data.as_ref())
|
||||||
present_data.dummy_data()
|
.flatten()
|
||||||
};
|
{
|
||||||
|
present_buffer.slice().to_vec()
|
||||||
} else {
|
} else {
|
||||||
size = Size2D::new(0, 0);
|
context_data.dummy_data()
|
||||||
data = Vec::new();
|
};
|
||||||
}
|
self.locked_ids.insert(id, data);
|
||||||
let _ = self.locked_ids.insert(id, data);
|
|
||||||
(
|
(
|
||||||
WebrenderImageSource::Raw(self.locked_ids.get(&id).unwrap().as_slice()),
|
WebrenderImageSource::Raw(self.locked_ids.get(&id).unwrap().as_slice()),
|
||||||
size,
|
size,
|
||||||
|
@ -106,13 +107,13 @@ impl WebrenderExternalImageApi for WGPUExternalImages {
|
||||||
|
|
||||||
fn unlock(&mut self, id: u64) {
|
fn unlock(&mut self, id: u64) {
|
||||||
let id = WebGPUContextId(id);
|
let id = WebGPUContextId(id);
|
||||||
let _ = self.locked_ids.remove(&id);
|
self.locked_ids.remove(&id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// States of presentation buffer
|
/// States of presentation buffer
|
||||||
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)]
|
||||||
pub enum PresentationBufferState {
|
enum PresentationBufferState {
|
||||||
/// Initial state, buffer has yet to be created,
|
/// Initial state, buffer has yet to be created,
|
||||||
/// only its id is reserved
|
/// only its id is reserved
|
||||||
#[default]
|
#[default]
|
||||||
|
@ -125,61 +126,105 @@ pub enum PresentationBufferState {
|
||||||
Mapped,
|
Mapped,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PresentationData {
|
struct SwapChain {
|
||||||
device_id: id::DeviceId,
|
device_id: id::DeviceId,
|
||||||
queue_id: id::QueueId,
|
queue_id: id::QueueId,
|
||||||
data: Option<GPUPresentationBuffer>,
|
data: Option<GPUPresentationBuffer>,
|
||||||
buffer_ids: ArrayVec<(id::BufferId, PresentationBufferState), PRESENTATION_BUFFER_COUNT>,
|
|
||||||
image_key: ImageKey,
|
|
||||||
image_desc: ImageDescriptor,
|
|
||||||
image_data: ImageData,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PresentationData {
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
pub fn new(
|
pub struct WebGPUImageDescriptor(pub ImageDescriptor);
|
||||||
device_id: id::DeviceId,
|
|
||||||
queue_id: id::QueueId,
|
impl WebGPUImageDescriptor {
|
||||||
buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
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<SwapChain>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContextData {
|
||||||
|
/// Init ContextData as dummy (transparent black)
|
||||||
|
fn new(
|
||||||
|
context_id: WebGPUContextId,
|
||||||
image_key: ImageKey,
|
image_key: ImageKey,
|
||||||
image_desc: ImageDescriptor,
|
size: DeviceIntSize,
|
||||||
image_data: ImageData,
|
buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let image_data = ImageData::External(ExternalImageData {
|
||||||
|
id: ExternalImageId(context_id.0),
|
||||||
|
channel_index: 0,
|
||||||
|
image_type: ExternalImageType::Buffer,
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
device_id,
|
image_key,
|
||||||
queue_id,
|
image_desc: WebGPUImageDescriptor::default(size),
|
||||||
data: None,
|
image_data,
|
||||||
|
swap_chain: None,
|
||||||
buffer_ids: buffer_ids
|
buffer_ids: buffer_ids
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&id| (id, PresentationBufferState::Unassigned))
|
.map(|&buffer_id| (buffer_id, PresentationBufferState::Unassigned))
|
||||||
.collect(),
|
.collect(),
|
||||||
image_key,
|
|
||||||
image_desc,
|
|
||||||
image_data,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dummy_data(&self) -> Vec<u8> {
|
fn dummy_data(&self) -> Vec<u8> {
|
||||||
let size = (self
|
vec![0; self.image_desc.buffer_size() as usize]
|
||||||
.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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns id of available buffer
|
/// Returns id of available buffer
|
||||||
/// and sets state to PresentationBufferState::Mapping
|
/// and sets state to PresentationBufferState::Mapping
|
||||||
fn get_available_buffer(&'_ mut self, global: &Arc<Global>) -> Option<id::BufferId> {
|
fn get_available_buffer(&'_ mut self, global: &Arc<Global>) -> Option<id::BufferId> {
|
||||||
|
assert!(self.swap_chain.is_some());
|
||||||
if let Some((buffer_id, buffer_state)) = self
|
if let Some((buffer_id, buffer_state)) = self
|
||||||
.buffer_ids
|
.buffer_ids
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
@ -196,11 +241,15 @@ impl PresentationData {
|
||||||
let buffer_id = *buffer_id;
|
let buffer_id = *buffer_id;
|
||||||
let buffer_desc = wgt::BufferDescriptor {
|
let buffer_desc = wgt::BufferDescriptor {
|
||||||
label: None,
|
label: None,
|
||||||
size: self.buffer_size(),
|
size: self.image_desc.buffer_size(),
|
||||||
usage: wgt::BufferUsages::MAP_READ | wgt::BufferUsages::COPY_DST,
|
usage: wgt::BufferUsages::MAP_READ | wgt::BufferUsages::COPY_DST,
|
||||||
mapped_at_creation: false,
|
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)
|
Some(buffer_id)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -217,57 +266,135 @@ impl PresentationData {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmap_old_buffer(&mut self, presentation_buffer: GPUPresentationBuffer) {
|
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);
|
let buffer_state = self.get_buffer_state(presentation_buffer.buffer_id);
|
||||||
assert_eq!(*buffer_state, PresentationBufferState::Mapped);
|
assert_eq!(*buffer_state, PresentationBufferState::Mapped);
|
||||||
*buffer_state = PresentationBufferState::Available;
|
*buffer_state = PresentationBufferState::Available;
|
||||||
drop(presentation_buffer);
|
drop(presentation_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn destroy_swapchain(&mut self, global: &Arc<Global>) {
|
||||||
|
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<Global>,
|
||||||
|
script_sender: &IpcSender<WebGPUMsg>,
|
||||||
|
webrender_api: &Arc<Mutex<RenderApi>>,
|
||||||
|
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 {
|
impl crate::WGPU {
|
||||||
pub(crate) fn create_swapchain(
|
pub(crate) fn create_context(
|
||||||
&self,
|
&self,
|
||||||
device_id: id::DeviceId,
|
|
||||||
queue_id: id::QueueId,
|
|
||||||
buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
|
||||||
context_id: WebGPUContextId,
|
context_id: WebGPUContextId,
|
||||||
format: ImageFormat,
|
|
||||||
size: DeviceIntSize,
|
|
||||||
image_key: ImageKey,
|
image_key: ImageKey,
|
||||||
|
size: DeviceIntSize,
|
||||||
|
buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
|
||||||
) {
|
) {
|
||||||
let image_desc = ImageDescriptor {
|
let context_data = ContextData::new(context_id, image_key, size, buffer_ids);
|
||||||
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 mut txn = Transaction::new();
|
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
|
self.webrender_api
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.send_transaction(self.webrender_document, txn);
|
.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<ContextConfiguration>,
|
||||||
|
) {
|
||||||
|
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
|
/// Copies data async from provided texture using encoder_id to available staging presentation buffer
|
||||||
|
@ -276,39 +403,42 @@ impl crate::WGPU {
|
||||||
context_id: WebGPUContextId,
|
context_id: WebGPUContextId,
|
||||||
encoder_id: id::Id<id::markers::CommandEncoder>,
|
encoder_id: id::Id<id::markers::CommandEncoder>,
|
||||||
texture_id: id::Id<id::markers::Texture>,
|
texture_id: id::Id<id::markers::Texture>,
|
||||||
) -> ControlFlow<()> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
fn err<T: std::error::Error + 'static>(e: Option<T>) -> Result<(), T> {
|
||||||
|
if let Some(error) = e {
|
||||||
|
Err(error)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let global = &self.global;
|
let global = &self.global;
|
||||||
let device_id;
|
let device_id;
|
||||||
let queue_id;
|
let queue_id;
|
||||||
let size;
|
|
||||||
let buffer_id;
|
let buffer_id;
|
||||||
let buffer_stride;
|
let image_desc;
|
||||||
let buffer_size;
|
|
||||||
{
|
{
|
||||||
if let Some(present_data) = self.wgpu_image_map.lock().unwrap().get_mut(&context_id) {
|
if let Some(context_data) = self.wgpu_image_map.lock().unwrap().get_mut(&context_id) {
|
||||||
size = present_data.image_desc.size;
|
let Some(swap_chain) = context_data.swap_chain.as_ref() else {
|
||||||
device_id = present_data.device_id;
|
return Ok(());
|
||||||
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(());
|
|
||||||
};
|
};
|
||||||
|
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 {
|
} else {
|
||||||
error!("Data not found for {:?}", context_id);
|
return Ok(());
|
||||||
return ControlFlow::Break(());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let comm_desc = wgt::CommandEncoderDescriptor { label: None };
|
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 {
|
let buffer_cv = wgt::ImageCopyBuffer {
|
||||||
buffer: buffer_id,
|
buffer: buffer_id,
|
||||||
layout: wgt::ImageDataLayout {
|
layout: wgt::ImageDataLayout {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
bytes_per_row: Some(buffer_stride as u32),
|
bytes_per_row: Some(image_desc.buffer_stride() as u32),
|
||||||
rows_per_image: None,
|
rows_per_image: None,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -319,18 +449,25 @@ impl crate::WGPU {
|
||||||
aspect: wgt::TextureAspect::All,
|
aspect: wgt::TextureAspect::All,
|
||||||
};
|
};
|
||||||
let copy_size = wgt::Extent3d {
|
let copy_size = wgt::Extent3d {
|
||||||
width: size.width as u32,
|
width: image_desc.size().width as u32,
|
||||||
height: size.height as u32,
|
height: image_desc.size().height as u32,
|
||||||
depth_or_array_layers: 1,
|
depth_or_array_layers: 1,
|
||||||
};
|
};
|
||||||
let _ = global.command_encoder_copy_texture_to_buffer(
|
global.command_encoder_copy_texture_to_buffer(
|
||||||
encoder_id,
|
encoder_id,
|
||||||
&texture_cv,
|
&texture_cv,
|
||||||
&buffer_cv,
|
&buffer_cv,
|
||||||
©_size,
|
©_size,
|
||||||
);
|
)?;
|
||||||
let _ = global.command_encoder_finish(encoder_id, &wgt::CommandBufferDescriptor::default());
|
let (command_buffer_id, error) =
|
||||||
let _ = global.queue_submit(queue_id, &[encoder_id.into_command_buffer_id()]);
|
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 callback = {
|
||||||
let global = Arc::clone(&self.global);
|
let global = Arc::clone(&self.global);
|
||||||
let wgpu_image_map = Arc::clone(&self.wgpu_image_map);
|
let wgpu_image_map = Arc::clone(&self.wgpu_image_map);
|
||||||
|
@ -343,11 +480,11 @@ impl crate::WGPU {
|
||||||
result,
|
result,
|
||||||
global,
|
global,
|
||||||
buffer_id,
|
buffer_id,
|
||||||
buffer_size,
|
|
||||||
wgpu_image_map,
|
wgpu_image_map,
|
||||||
context_id,
|
context_id,
|
||||||
webrender_api,
|
webrender_api,
|
||||||
webrender_document,
|
webrender_document,
|
||||||
|
image_desc,
|
||||||
);
|
);
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
@ -355,42 +492,23 @@ impl crate::WGPU {
|
||||||
host: HostMap::Read,
|
host: HostMap::Read,
|
||||||
callback: Some(callback),
|
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();
|
self.poller.wake();
|
||||||
|
Ok(())
|
||||||
ControlFlow::Continue(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn destroy_swapchain(
|
pub(crate) fn destroy_context(&mut self, context_id: WebGPUContextId) {
|
||||||
&mut self,
|
self.wgpu_image_map
|
||||||
context_id: WebGPUContextId,
|
|
||||||
image_key: webrender_api::ImageKey,
|
|
||||||
) {
|
|
||||||
let present_data = self
|
|
||||||
.wgpu_image_map
|
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.remove(&context_id)
|
.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()
|
.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>,
|
result: Result<(), BufferAccessError>,
|
||||||
global: Arc<Global>,
|
global: Arc<Global>,
|
||||||
buffer_id: id::BufferId,
|
buffer_id: id::BufferId,
|
||||||
buffer_size: u64,
|
|
||||||
wgpu_image_map: WGPUImageMap,
|
wgpu_image_map: WGPUImageMap,
|
||||||
context_id: WebGPUContextId,
|
context_id: WebGPUContextId,
|
||||||
webrender_api: Arc<Mutex<RenderApi>>,
|
webrender_api: Arc<Mutex<RenderApi>>,
|
||||||
webrender_document: webrender_api::DocumentId,
|
webrender_document: webrender_api::DocumentId,
|
||||||
|
image_desc: WebGPUImageDescriptor,
|
||||||
) {
|
) {
|
||||||
match result {
|
match result {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
if let Some(present_data) = wgpu_image_map.lock().unwrap().get_mut(&context_id) {
|
if let Some(context_data) = wgpu_image_map.lock().unwrap().get_mut(&context_id) {
|
||||||
let buffer_state = present_data.get_buffer_state(buffer_id);
|
let config_changed = image_desc != context_data.image_desc;
|
||||||
assert_eq!(*buffer_state, PresentationBufferState::Mapping);
|
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;
|
*buffer_state = PresentationBufferState::Mapped;
|
||||||
let presentation_buffer =
|
let presentation_buffer =
|
||||||
GPUPresentationBuffer::new(global, buffer_id, buffer_size);
|
GPUPresentationBuffer::new(global, buffer_id, image_desc.buffer_size());
|
||||||
let old_presentation_buffer = present_data.data.replace(presentation_buffer);
|
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();
|
let mut txn = Transaction::new();
|
||||||
txn.update_image(
|
txn.update_image(
|
||||||
present_data.image_key,
|
context_data.image_key,
|
||||||
present_data.image_desc,
|
context_data.image_desc.0,
|
||||||
present_data.image_data.clone(),
|
context_data.image_data.clone(),
|
||||||
&DirtyRect::All,
|
&DirtyRect::All,
|
||||||
);
|
);
|
||||||
webrender_api
|
webrender_api
|
||||||
|
@ -425,10 +577,10 @@ fn update_wr_image(
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.send_transaction(webrender_document, txn);
|
.send_transaction(webrender_document, txn);
|
||||||
if let Some(old_presentation_buffer) = old_presentation_buffer {
|
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 {
|
} else {
|
||||||
error!("Data not found for {:?}", context_id);
|
error!("WebGPU Context {:?} is destroyed", context_id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => error!("Could not map buffer({:?})", buffer_id),
|
_ => error!("Could not map buffer({:?})", buffer_id),
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::ops::ControlFlow;
|
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
@ -15,7 +14,7 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender, IpcSharedMemory};
|
||||||
use log::{info, warn};
|
use log::{info, warn};
|
||||||
use servo_config::pref;
|
use servo_config::pref;
|
||||||
use webrender::{RenderApi, RenderApiSender};
|
use webrender::{RenderApi, RenderApiSender};
|
||||||
use webrender_api::DocumentId;
|
use webrender_api::{DocumentId, ExternalImageId};
|
||||||
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
|
use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
|
||||||
use wgc::command::{ComputePass, ComputePassDescriptor, RenderPass};
|
use wgc::command::{ComputePass, ComputePassDescriptor, RenderPass};
|
||||||
use wgc::device::queue::SubmittedWorkDoneClosure;
|
use wgc::device::queue::SubmittedWorkDoneClosure;
|
||||||
|
@ -404,17 +403,6 @@ impl WGPU {
|
||||||
self.maybe_dispatch_wgpu_error(device_id, error);
|
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 {
|
WebGPURequest::CreatePipelineLayout {
|
||||||
device_id,
|
device_id,
|
||||||
pipeline_layout_id,
|
pipeline_layout_id,
|
||||||
|
@ -513,17 +501,79 @@ impl WGPU {
|
||||||
}
|
}
|
||||||
self.maybe_dispatch_wgpu_error(device_id, error);
|
self.maybe_dispatch_wgpu_error(device_id, error);
|
||||||
},
|
},
|
||||||
WebGPURequest::CreateSwapChain {
|
WebGPURequest::CreateContext {
|
||||||
device_id,
|
|
||||||
queue_id,
|
|
||||||
buffer_ids,
|
buffer_ids,
|
||||||
context_id,
|
|
||||||
image_key,
|
|
||||||
size,
|
size,
|
||||||
format,
|
sender,
|
||||||
} => self.create_swapchain(
|
} => {
|
||||||
device_id, queue_id, buffer_ids, context_id, format, size, image_key,
|
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 {
|
WebGPURequest::CreateTexture {
|
||||||
device_id,
|
device_id,
|
||||||
texture_id,
|
texture_id,
|
||||||
|
@ -561,12 +611,6 @@ impl WGPU {
|
||||||
// Wake poller thread to trigger DeviceLostClosure
|
// Wake poller thread to trigger DeviceLostClosure
|
||||||
self.poller.wake();
|
self.poller.wake();
|
||||||
},
|
},
|
||||||
WebGPURequest::DestroySwapChain {
|
|
||||||
context_id,
|
|
||||||
image_key,
|
|
||||||
} => {
|
|
||||||
self.destroy_swapchain(context_id, image_key);
|
|
||||||
},
|
|
||||||
WebGPURequest::DestroyTexture(texture_id) => {
|
WebGPURequest::DestroyTexture(texture_id) => {
|
||||||
let global = &self.global;
|
let global = &self.global;
|
||||||
let _ = global.texture_destroy(texture_id);
|
let _ = global.texture_destroy(texture_id);
|
||||||
|
@ -965,17 +1009,6 @@ impl WGPU {
|
||||||
};
|
};
|
||||||
self.maybe_dispatch_error(device_id, result.err());
|
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 {
|
WebGPURequest::UnmapBuffer {
|
||||||
buffer_id,
|
buffer_id,
|
||||||
array_buffer,
|
array_buffer,
|
||||||
|
|
195
tests/wpt/webgpu/meta/webgpu/cts.https.html.ini
vendored
195
tests/wpt/webgpu/meta/webgpu/cts.https.html.ini
vendored
|
@ -9741,8 +9741,6 @@
|
||||||
[:format="bc1-rgba-unorm";canvasType="onscreen";enable_required_feature=false]
|
[:format="bc1-rgba-unorm";canvasType="onscreen";enable_required_feature=false]
|
||||||
|
|
||||||
[:format="bc1-rgba-unorm";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc1-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc2-rgba-unorm";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc2-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc3-rgba-unorm";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc3-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc4-r-snorm";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc4-r-unorm";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc5-rg-snorm";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc5-rg-unorm";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc6h-rgb-float";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc6h-rgb-ufloat";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc7-rgba-unorm";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="bc7-rgba-unorm-srgb";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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=false]
|
||||||
|
|
||||||
[:format="depth32float-stencil8";canvasType="onscreen";enable_required_feature=true]
|
[: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]
|
[: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:*]
|
[cts.https.html?q=webgpu:api,validation,capability_checks,limits,maxTextureDimension2D:configure,at_over:*]
|
||||||
disabled: true
|
[:limitTest="atDefault";testValueName="atLimit";canvasType="offscreen"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: SKIP
|
[: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:*]
|
[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:*]
|
[cts.https.html?q=webgpu:api,validation,capability_checks,limits,maxTextureDimension2D:getCurrentTexture,at_over:*]
|
||||||
expected:
|
[:limitTest="atDefault";testValueName="atLimit";canvasType="offscreen"]
|
||||||
if os == "linux" and not debug: CRASH
|
|
||||||
|
[: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:*]
|
[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="astc-8x8-unorm-srgb"]
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc1-rgba-unorm"]
|
[:canvasType="onscreen";format="bc1-rgba-unorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc1-rgba-unorm-srgb"]
|
[:canvasType="onscreen";format="bc1-rgba-unorm-srgb"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc2-rgba-unorm"]
|
[:canvasType="onscreen";format="bc2-rgba-unorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc2-rgba-unorm-srgb"]
|
[:canvasType="onscreen";format="bc2-rgba-unorm-srgb"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc3-rgba-unorm"]
|
[:canvasType="onscreen";format="bc3-rgba-unorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc3-rgba-unorm-srgb"]
|
[:canvasType="onscreen";format="bc3-rgba-unorm-srgb"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc4-r-snorm"]
|
[:canvasType="onscreen";format="bc4-r-snorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc4-r-unorm"]
|
[:canvasType="onscreen";format="bc4-r-unorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc5-rg-snorm"]
|
[:canvasType="onscreen";format="bc5-rg-snorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc5-rg-unorm"]
|
[:canvasType="onscreen";format="bc5-rg-unorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc6h-rgb-float"]
|
[:canvasType="onscreen";format="bc6h-rgb-float"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc6h-rgb-ufloat"]
|
[:canvasType="onscreen";format="bc6h-rgb-ufloat"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc7-rgba-unorm"]
|
[:canvasType="onscreen";format="bc7-rgba-unorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bc7-rgba-unorm-srgb"]
|
[:canvasType="onscreen";format="bc7-rgba-unorm-srgb"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bgra8unorm"]
|
[:canvasType="onscreen";format="bgra8unorm"]
|
||||||
|
|
||||||
|
@ -185863,8 +185878,6 @@
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:canvasType="onscreen";format="r8snorm"]
|
[:canvasType="onscreen";format="r8snorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="r8uint"]
|
[:canvasType="onscreen";format="r8uint"]
|
||||||
expected:
|
expected:
|
||||||
|
@ -185875,8 +185888,6 @@
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rg11b10ufloat"]
|
[:canvasType="onscreen";format="rg11b10ufloat"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rg16float"]
|
[:canvasType="onscreen";format="rg16float"]
|
||||||
expected:
|
expected:
|
||||||
|
@ -185907,8 +185918,6 @@
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rg8snorm"]
|
[:canvasType="onscreen";format="rg8snorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rg8uint"]
|
[:canvasType="onscreen";format="rg8uint"]
|
||||||
expected:
|
expected:
|
||||||
|
@ -185927,8 +185936,6 @@
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rgb9e5ufloat"]
|
[:canvasType="onscreen";format="rgb9e5ufloat"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rgba16float"]
|
[:canvasType="onscreen";format="rgba16float"]
|
||||||
expected:
|
expected:
|
||||||
|
@ -185959,8 +185966,6 @@
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rgba8snorm"]
|
[:canvasType="onscreen";format="rgba8snorm"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rgba8uint"]
|
[:canvasType="onscreen";format="rgba8uint"]
|
||||||
expected:
|
expected:
|
||||||
|
@ -185978,13 +185983,23 @@
|
||||||
|
|
||||||
|
|
||||||
[cts.https.html?q=webgpu:web_platform,canvas,configure:size_zero_after_configure:*]
|
[cts.https.html?q=webgpu:web_platform,canvas,configure:size_zero_after_configure:*]
|
||||||
expected:
|
[:canvasType="offscreen";zeroDimension="height"]
|
||||||
if os == "linux" and not debug: CRASH
|
|
||||||
|
[: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:*]
|
[cts.https.html?q=webgpu:web_platform,canvas,configure:size_zero_before_configure:*]
|
||||||
expected:
|
[:canvasType="offscreen";zeroDimension="height"]
|
||||||
if os == "linux" and not debug: CRASH
|
|
||||||
|
[:canvasType="offscreen";zeroDimension="width"]
|
||||||
|
|
||||||
|
[:canvasType="onscreen";zeroDimension="height"]
|
||||||
|
|
||||||
|
[:canvasType="onscreen";zeroDimension="width"]
|
||||||
|
|
||||||
|
|
||||||
[cts.https.html?q=webgpu:web_platform,canvas,configure:usage:*]
|
[cts.https.html?q=webgpu:web_platform,canvas,configure:usage:*]
|
||||||
|
@ -186027,18 +186042,12 @@
|
||||||
[:canvasType="offscreen";format="rgba8unorm";viewFormatFeature="texture-compression-etc2"]
|
[:canvasType="offscreen";format="rgba8unorm";viewFormatFeature="texture-compression-etc2"]
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="_undef_"]
|
[:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="_undef_"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="depth32float-stencil8"]
|
[: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-astc"]
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="texture-compression-bc"]
|
[:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="texture-compression-bc"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="texture-compression-etc2"]
|
[:canvasType="onscreen";format="bgra8unorm";viewFormatFeature="texture-compression-etc2"]
|
||||||
|
|
||||||
|
@ -186047,30 +186056,20 @@
|
||||||
if os == "linux" and not debug: FAIL
|
if os == "linux" and not debug: FAIL
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rgba16float";viewFormatFeature="depth32float-stencil8"]
|
[: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-astc"]
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rgba16float";viewFormatFeature="texture-compression-bc"]
|
[: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="rgba16float";viewFormatFeature="texture-compression-etc2"]
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="_undef_"]
|
[:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="_undef_"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="depth32float-stencil8"]
|
[: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-astc"]
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="texture-compression-bc"]
|
[:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="texture-compression-bc"]
|
||||||
expected:
|
|
||||||
if os == "linux" and not debug: FAIL
|
|
||||||
|
|
||||||
[:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="texture-compression-etc2"]
|
[:canvasType="onscreen";format="rgba8unorm";viewFormatFeature="texture-compression-etc2"]
|
||||||
|
|
||||||
|
@ -186082,8 +186081,9 @@
|
||||||
|
|
||||||
|
|
||||||
[cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:configured:*]
|
[cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:configured:*]
|
||||||
expected:
|
[:canvasType="offscreen"]
|
||||||
if os == "linux" and not debug: CRASH
|
|
||||||
|
[:canvasType="onscreen"]
|
||||||
|
|
||||||
|
|
||||||
[cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:expiry:*]
|
[cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:expiry:*]
|
||||||
|
@ -186119,8 +186119,9 @@
|
||||||
|
|
||||||
|
|
||||||
[cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:resize:*]
|
[cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:resize:*]
|
||||||
expected:
|
[:canvasType="offscreen"]
|
||||||
if os == "linux" and not debug: CRASH
|
|
||||||
|
[:canvasType="onscreen"]
|
||||||
|
|
||||||
|
|
||||||
[cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:single_frames:*]
|
[cts.https.html?q=webgpu:web_platform,canvas,getCurrentTexture:single_frames:*]
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[canvas_clear.https.html]
|
[canvas_clear.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "win": CRASH
|
if os == "linux" and not debug: FAIL
|
||||||
if os == "linux" and debug: CRASH
|
|
||||||
if os == "linux" and not debug: TIMEOUT
|
|
||||||
if os == "mac": CRASH
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[canvas_colorspace_rgba16float.https.html]
|
[canvas_colorspace_rgba16float.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "win": CRASH
|
|
||||||
if os == "linux" and debug: CRASH
|
|
||||||
if os == "linux" and not debug: TIMEOUT
|
if os == "linux" and not debug: TIMEOUT
|
||||||
if os == "mac": CRASH
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[canvas_complex_rgba16float_copy.https.html]
|
[canvas_complex_rgba16float_copy.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "win": CRASH
|
|
||||||
if os == "linux" and debug: CRASH
|
|
||||||
if os == "linux" and not debug: TIMEOUT
|
if os == "linux" and not debug: TIMEOUT
|
||||||
if os == "mac": CRASH
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[canvas_complex_rgba16float_draw.https.html]
|
[canvas_complex_rgba16float_draw.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "win": CRASH
|
|
||||||
if os == "linux" and debug: CRASH
|
|
||||||
if os == "linux" and not debug: TIMEOUT
|
if os == "linux" and not debug: TIMEOUT
|
||||||
if os == "mac": CRASH
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[canvas_complex_rgba16float_store.https.html]
|
[canvas_complex_rgba16float_store.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "win": CRASH
|
if os == "linux" and not debug: FAIL
|
||||||
if os == "linux" and debug: CRASH
|
|
||||||
if os == "linux" and not debug: TIMEOUT
|
|
||||||
if os == "mac": CRASH
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[canvas_complex_rgba8unorm_store.https.html]
|
[canvas_complex_rgba8unorm_store.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "linux" and not debug: [PASS, FAIL]
|
if os == "linux" and not debug: PASS
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[canvas_composite_alpha_bgra8unorm_opaque_copy.https.html]
|
[canvas_composite_alpha_bgra8unorm_opaque_copy.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "linux" and not debug: [CRASH, PASS, FAIL]
|
if os == "linux" and not debug: PASS
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
[canvas_composite_alpha_bgra8unorm_opaque_draw.https.html]
|
[canvas_composite_alpha_bgra8unorm_opaque_draw.https.html]
|
||||||
expected: [CRASH, PASS, FAIL]
|
expected: PASS
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
[canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html]
|
[canvas_composite_alpha_bgra8unorm_premultiplied_copy.https.html]
|
||||||
expected: FAIL
|
expected:
|
||||||
|
if os == "linux" and not debug: PASS
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
[canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html]
|
[canvas_composite_alpha_bgra8unorm_premultiplied_draw.https.html]
|
||||||
expected: FAIL
|
expected:
|
||||||
|
if os == "linux" and not debug: PASS
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[canvas_composite_alpha_rgba16float_opaque_copy.https.html]
|
[canvas_composite_alpha_rgba16float_opaque_copy.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "win": CRASH
|
if os == "linux" and not debug: FAIL
|
||||||
if os == "linux" and debug: CRASH
|
|
||||||
if os == "linux" and not debug: TIMEOUT
|
|
||||||
if os == "mac": CRASH
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[canvas_composite_alpha_rgba16float_opaque_draw.https.html]
|
[canvas_composite_alpha_rgba16float_opaque_draw.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "win": CRASH
|
if os == "linux" and not debug: FAIL
|
||||||
if os == "linux" and debug: CRASH
|
|
||||||
if os == "linux" and not debug: TIMEOUT
|
|
||||||
if os == "mac": CRASH
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[canvas_composite_alpha_rgba16float_premultiplied_copy.https.html]
|
[canvas_composite_alpha_rgba16float_premultiplied_copy.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "win": CRASH
|
if os == "linux" and not debug: FAIL
|
||||||
if os == "linux" and debug: CRASH
|
|
||||||
if os == "linux" and not debug: TIMEOUT
|
|
||||||
if os == "mac": CRASH
|
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[canvas_composite_alpha_rgba16float_premultiplied_draw.https.html]
|
[canvas_composite_alpha_rgba16float_premultiplied_draw.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "win": CRASH
|
if os == "linux" and not debug: FAIL
|
||||||
if os == "linux" and debug: CRASH
|
|
||||||
if os == "linux" and not debug: TIMEOUT
|
|
||||||
if os == "mac": CRASH
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[canvas_composite_alpha_rgba8unorm_opaque_copy.https.html]
|
[canvas_composite_alpha_rgba8unorm_opaque_copy.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "linux" and not debug: [CRASH, PASS, FAIL]
|
if os == "linux" and not debug: PASS
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
[canvas_composite_alpha_rgba8unorm_opaque_draw.https.html]
|
[canvas_composite_alpha_rgba8unorm_opaque_draw.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "linux" and not debug: [PASS, FAIL]
|
if os == "linux" and not debug: PASS
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
[canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html]
|
[canvas_composite_alpha_rgba8unorm_premultiplied_copy.https.html]
|
||||||
expected: FAIL
|
expected:
|
||||||
|
if os == "linux" and not debug: PASS
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
[canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html]
|
[canvas_composite_alpha_rgba8unorm_premultiplied_draw.https.html]
|
||||||
expected: [CRASH, FAIL]
|
expected:
|
||||||
|
if os == "linux" and not debug: PASS
|
||||||
|
|
|
@ -1,6 +1,3 @@
|
||||||
[delay_get_texture.https.html]
|
[delay_get_texture.https.html]
|
||||||
expected:
|
expected:
|
||||||
if os == "win": FAIL
|
if os == "linux" and not debug: PASS
|
||||||
if os == "linux" and debug: FAIL
|
|
||||||
if os == "linux" and not debug: [PASS, FAIL]
|
|
||||||
if os == "mac": FAIL
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue