Auto merge of #27590 - kunalmohan:update-cts, r=kvark

Update wgpu and WebGPU CTS to include copy validation tests

<!-- Please describe your changes on the following line: -->
r?@kvark

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors

<!-- Either: -->
- [X] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
bors-servo 2020-08-16 14:56:34 -04:00 committed by GitHub
commit 62c7cb4c79
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 2402 additions and 389 deletions

4
Cargo.lock generated
View file

@ -6955,7 +6955,7 @@ dependencies = [
[[package]]
name = "wgpu-core"
version = "0.5.0"
source = "git+https://github.com/gfx-rs/wgpu#430b29d781200009ef02839e41136718ff62456a"
source = "git+https://github.com/gfx-rs/wgpu#7e8b51b4286bd9452567eb1a56edb8e9b7c7f684"
dependencies = [
"arrayvec 0.5.1",
"bitflags",
@ -6982,7 +6982,7 @@ dependencies = [
[[package]]
name = "wgpu-types"
version = "0.5.0"
source = "git+https://github.com/gfx-rs/wgpu#430b29d781200009ef02839e41136718ff62456a"
source = "git+https://github.com/gfx-rs/wgpu#7e8b51b4286bd9452567eb1a56edb8e9b7c7f684"
dependencies = [
"bitflags",
"serde",

View file

@ -73,7 +73,7 @@ use std::collections::HashMap;
use std::ptr::NonNull;
use std::rc::Rc;
use webgpu::wgpu::{
binding_model as wgpu_bind, command::RenderBundleEncoder, pipeline as wgpu_pipe,
binding_model as wgpu_bind, command as wgpu_com, pipeline as wgpu_pipe, resource as wgpu_res,
};
use webgpu::{self, identity::WebGPUOpResult, wgt, ErrorScopeId, WebGPU, WebGPURequest};
@ -320,12 +320,17 @@ impl GPUDeviceMethods for GPUDevice {
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbuffer
fn CreateBuffer(&self, descriptor: &GPUBufferDescriptor) -> DomRoot<GPUBuffer> {
let desc = wgt::BufferUsage::from_bits(descriptor.usage).map(|usg| wgt::BufferDescriptor {
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
size: descriptor.size,
usage: usg,
mapped_at_creation: descriptor.mappedAtCreation,
});
let desc =
wgt::BufferUsage::from_bits(descriptor.usage).map(|usg| wgpu_res::BufferDescriptor {
label: descriptor
.parent
.label
.as_ref()
.map(|s| Cow::Owned(s.to_string())),
size: descriptor.size as wgt::BufferAddress,
usage: usg,
mapped_at_creation: descriptor.mappedAtCreation,
});
let id = self
.global()
.wgpu_id_hub()
@ -464,14 +469,19 @@ impl GPUDeviceMethods for GPUDevice {
},
};
wgt::BindGroupLayoutEntry::new(bind.binding, visibility, ty)
wgt::BindGroupLayoutEntry {
binding: bind.binding,
visibility: visibility,
ty,
count: None,
}
})
.collect::<Vec<_>>();
let scope_id = self.use_current_scope();
let desc = if valid {
Some(wgt::BindGroupLayoutDescriptor {
Some(wgpu_bind::BindGroupLayoutDescriptor {
label: descriptor
.parent
.label
@ -518,7 +528,12 @@ impl GPUDeviceMethods for GPUDevice {
&self,
descriptor: &GPUPipelineLayoutDescriptor,
) -> DomRoot<GPUPipelineLayout> {
let desc = wgt::PipelineLayoutDescriptor {
let desc = wgpu_bind::PipelineLayoutDescriptor {
label: descriptor
.parent
.label
.as_ref()
.map(|s| Cow::Owned(s.to_string())),
bind_group_layouts: Cow::Owned(
descriptor
.bindGroupLayouts
@ -673,7 +688,13 @@ impl GPUDeviceMethods for GPUDevice {
let scope_id = self.use_current_scope();
let desc = wgpu_pipe::ComputePipelineDescriptor {
layout: descriptor.parent.layout.id().0,
label: descriptor
.parent
.parent
.label
.as_ref()
.map(|s| Cow::Owned(s.to_string())),
layout: Some(descriptor.parent.layout.id().0),
compute_stage: wgpu_pipe::ProgrammableStageDescriptor {
module: descriptor.computeStage.module.id().0,
entry_point: Cow::Owned(descriptor.computeStage.entryPoint.to_string()),
@ -718,7 +739,11 @@ impl GPUDeviceMethods for GPUDevice {
WebGPURequest::CreateCommandEncoder {
device_id: self.device.0,
command_encoder_id,
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
label: descriptor
.parent
.label
.as_ref()
.map(|l| Cow::Owned(l.to_string())),
},
))
.expect("Failed to create WebGPU command encoder");
@ -739,8 +764,12 @@ impl GPUDeviceMethods for GPUDevice {
fn CreateTexture(&self, descriptor: &GPUTextureDescriptor) -> DomRoot<GPUTexture> {
let size = convert_texture_size_to_dict(&descriptor.size);
let desc =
wgt::TextureUsage::from_bits(descriptor.usage).map(|usg| wgt::TextureDescriptor {
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
wgt::TextureUsage::from_bits(descriptor.usage).map(|usg| wgpu_res::TextureDescriptor {
label: descriptor
.parent
.label
.as_ref()
.map(|l| Cow::Owned(l.to_string())),
size: convert_texture_size_to_wgt(&size),
mip_level_count: descriptor.mipLevelCount,
sample_count: descriptor.sampleCount,
@ -803,11 +832,17 @@ impl GPUDeviceMethods for GPUDevice {
.lock()
.create_sampler_id(self.device.0.backend());
let compare_enable = descriptor.compare.is_some();
let desc = wgt::SamplerDescriptor {
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
address_mode_u: convert_address_mode(descriptor.addressModeU),
address_mode_v: convert_address_mode(descriptor.addressModeV),
address_mode_w: convert_address_mode(descriptor.addressModeW),
let desc = wgpu_res::SamplerDescriptor {
label: descriptor
.parent
.label
.as_ref()
.map(|s| Cow::Owned(s.to_string())),
address_modes: [
convert_address_mode(descriptor.addressModeU),
convert_address_mode(descriptor.addressModeV),
convert_address_mode(descriptor.addressModeW),
],
mag_filter: convert_filter_mode(descriptor.magFilter),
min_filter: convert_filter_mode(descriptor.minFilter),
mipmap_filter: convert_filter_mode(descriptor.mipmapFilter),
@ -872,7 +907,13 @@ impl GPUDeviceMethods for GPUDevice {
let desc = if valid {
Some(wgpu_pipe::RenderPipelineDescriptor {
layout: descriptor.parent.layout.id().0,
label: descriptor
.parent
.parent
.label
.as_ref()
.map(|s| Cow::Owned(s.to_string())),
layout: Some(descriptor.parent.layout.id().0),
vertex_stage: wgpu_pipe::ProgrammableStageDescriptor {
module: descriptor.vertexStage.module.id().0,
entry_point: Cow::Owned(descriptor.vertexStage.entryPoint.to_string()),
@ -911,23 +952,27 @@ impl GPUDeviceMethods for GPUDevice {
format: convert_texture_format(dss_desc.format),
depth_write_enabled: dss_desc.depthWriteEnabled,
depth_compare: convert_compare_function(dss_desc.depthCompare),
stencil_front: wgt::StencilStateFaceDescriptor {
compare: convert_compare_function(dss_desc.stencilFront.compare),
fail_op: convert_stencil_op(dss_desc.stencilFront.failOp),
depth_fail_op: convert_stencil_op(dss_desc.stencilFront.depthFailOp),
pass_op: convert_stencil_op(dss_desc.stencilFront.passOp),
stencil: wgt::StencilStateDescriptor {
front: wgt::StencilStateFaceDescriptor {
compare: convert_compare_function(dss_desc.stencilFront.compare),
fail_op: convert_stencil_op(dss_desc.stencilFront.failOp),
depth_fail_op: convert_stencil_op(
dss_desc.stencilFront.depthFailOp,
),
pass_op: convert_stencil_op(dss_desc.stencilFront.passOp),
},
back: wgt::StencilStateFaceDescriptor {
compare: convert_compare_function(dss_desc.stencilBack.compare),
fail_op: convert_stencil_op(dss_desc.stencilBack.failOp),
depth_fail_op: convert_stencil_op(dss_desc.stencilBack.depthFailOp),
pass_op: convert_stencil_op(dss_desc.stencilBack.passOp),
},
read_mask: dss_desc.stencilReadMask,
write_mask: dss_desc.stencilWriteMask,
},
stencil_back: wgt::StencilStateFaceDescriptor {
compare: convert_compare_function(dss_desc.stencilBack.compare),
fail_op: convert_stencil_op(dss_desc.stencilBack.failOp),
depth_fail_op: convert_stencil_op(dss_desc.stencilBack.depthFailOp),
pass_op: convert_stencil_op(dss_desc.stencilBack.passOp),
},
stencil_read_mask: dss_desc.stencilReadMask,
stencil_write_mask: dss_desc.stencilWriteMask,
}
}),
vertex_state: wgt::VertexStateDescriptor {
vertex_state: wgpu_pipe::VertexStateDescriptor {
index_format: match vs_desc.indexFormat {
GPUIndexFormat::Uint16 => wgt::IndexFormat::Uint16,
GPUIndexFormat::Uint32 => wgt::IndexFormat::Uint32,
@ -936,7 +981,7 @@ impl GPUDeviceMethods for GPUDevice {
vs_desc
.vertexBuffers
.iter()
.map(|buffer| wgt::VertexBufferDescriptor {
.map(|buffer| wgpu_pipe::VertexBufferDescriptor {
stride: buffer.arrayStride,
step_mode: match buffer.stepMode {
GPUInputStepMode::Vertex => wgt::InputStepMode::Vertex,
@ -1002,7 +1047,7 @@ impl GPUDeviceMethods for GPUDevice {
&self,
descriptor: &GPURenderBundleEncoderDescriptor,
) -> DomRoot<GPURenderBundleEncoder> {
let desc = wgt::RenderBundleEncoderDescriptor {
let desc = wgpu_com::RenderBundleEncoderDescriptor {
label: descriptor
.parent
.label
@ -1022,7 +1067,8 @@ impl GPUDeviceMethods for GPUDevice {
};
// Handle error gracefully
let render_bundle_encoder = RenderBundleEncoder::new(&desc, self.device.0, None).unwrap();
let render_bundle_encoder =
wgpu_com::RenderBundleEncoder::new(&desc, self.device.0, None).unwrap();
GPURenderBundleEncoder::new(
&self.global(),

View file

@ -15,6 +15,7 @@ use crate::dom::gpudevice::GPUDevice;
use crate::dom::gpurenderbundle::GPURenderBundle;
use crate::dom::gpurenderpipeline::GPURenderPipeline;
use dom_struct::dom_struct;
use std::borrow::Cow;
use webgpu::{
wgpu::command::{bundle_ffi as wgpu_bundle, RenderBundleEncoder},
wgt, WebGPU, WebGPURenderBundle, WebGPURequest,
@ -184,7 +185,11 @@ impl GPURenderBundleEncoderMethods for GPURenderBundleEncoder {
/// https://gpuweb.github.io/gpuweb/#dom-gpurenderbundleencoder-finish
fn Finish(&self, descriptor: &GPURenderBundleDescriptor) -> DomRoot<GPURenderBundle> {
let desc = wgt::RenderBundleDescriptor {
label: descriptor.parent.label.as_ref().map(|s| s.to_string()),
label: descriptor
.parent
.label
.as_ref()
.map(|l| Cow::Owned(l.to_string())),
};
let encoder = self.render_bundle_encoder.borrow_mut().take().unwrap();
let render_bundle_id = self

View file

@ -7,7 +7,7 @@ use crate::dom::bindings::codegen::Bindings::GPUTextureBinding::{
GPUExtent3DDict, GPUTextureDimension, GPUTextureFormat, GPUTextureMethods,
};
use crate::dom::bindings::codegen::Bindings::GPUTextureViewBinding::{
GPUTextureAspect, GPUTextureViewDescriptor, GPUTextureViewDimension,
GPUTextureAspect, GPUTextureViewDescriptor,
};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
@ -16,10 +16,12 @@ use crate::dom::globalscope::GlobalScope;
use crate::dom::gpudevice::{convert_texture_format, convert_texture_view_dimension, GPUDevice};
use crate::dom::gputextureview::GPUTextureView;
use dom_struct::dom_struct;
use std::borrow::Cow;
use std::num::NonZeroU32;
use std::string::String;
use webgpu::{
identity::WebGPUOpResult, wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView,
identity::WebGPUOpResult, wgpu::resource, wgt, WebGPU, WebGPURequest, WebGPUTexture,
WebGPUTextureView,
};
#[dom_struct]
@ -123,23 +125,6 @@ impl GPUTextureMethods for GPUTexture {
/// https://gpuweb.github.io/gpuweb/#dom-gputexture-createview
fn CreateView(&self, descriptor: &GPUTextureViewDescriptor) -> DomRoot<GPUTextureView> {
let dimension = if let Some(d) = descriptor.dimension {
d
} else {
match self.dimension {
GPUTextureDimension::_1d => GPUTextureViewDimension::_1d,
GPUTextureDimension::_2d => {
if self.texture_size.depth > 1 && descriptor.arrayLayerCount.is_none() {
GPUTextureViewDimension::_2d_array
} else {
GPUTextureViewDimension::_2d
}
},
GPUTextureDimension::_3d => GPUTextureViewDimension::_3d,
}
};
let format = descriptor.format.unwrap_or(self.format);
let scope_id = self.device.use_current_scope();
let mut valid = true;
let level_count = descriptor.mipLevelCount.and_then(|count| {
@ -156,14 +141,16 @@ impl GPUTextureMethods for GPUTexture {
});
let desc = if valid {
Some(wgt::TextureViewDescriptor {
Some(resource::TextureViewDescriptor {
label: descriptor
.parent
.label
.as_ref()
.map(|s| String::from(s.as_ref())),
format: convert_texture_format(format),
dimension: convert_texture_view_dimension(dimension),
.map(|l| Cow::Owned(l.to_string())),
format: descriptor.format.map(|fr| convert_texture_format(fr)),
dimension: descriptor
.dimension
.map(|dm| convert_texture_view_dimension(dm)),
aspect: match descriptor.aspect {
GPUTextureAspect::All => wgt::TextureAspect::All,
GPUTextureAspect::Stencil_only => wgt::TextureAspect::StencilOnly,

View file

@ -21,9 +21,7 @@ use servo_config::pref;
use smallvec::SmallVec;
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::ffi::CString;
use std::num::NonZeroU64;
use std::ptr;
use std::rc::Rc;
use std::slice;
use std::sync::{Arc, Mutex};
@ -33,13 +31,19 @@ use webrender_traits::{
WebrenderImageSource,
};
use wgpu::{
binding_model::BindGroupDescriptor,
command::{BufferCopyView, ComputePass, RenderBundleEncoder, RenderPass, TextureCopyView},
binding_model::{BindGroupDescriptor, BindGroupLayoutDescriptor, PipelineLayoutDescriptor},
command::{
BufferCopyView, ComputePass, RenderBundleDescriptor, RenderBundleEncoder, RenderPass,
TextureCopyView,
},
device::HostMap,
id,
instance::RequestAdapterOptions,
pipeline::{ComputePipelineDescriptor, RenderPipelineDescriptor},
resource::{BufferMapAsyncStatus, BufferMapOperation},
resource::{
BufferDescriptor, BufferMapAsyncStatus, BufferMapOperation, SamplerDescriptor,
TextureDescriptor, TextureViewDescriptor,
},
};
pub type ErrorScopeId = NonZeroU64;
@ -119,19 +123,19 @@ pub enum WebGPURequest {
CreateBindGroupLayout {
device_id: id::DeviceId,
bind_group_layout_id: id::BindGroupLayoutId,
descriptor: Option<wgt::BindGroupLayoutDescriptor<'static>>,
descriptor: Option<BindGroupLayoutDescriptor<'static>>,
},
CreateBuffer {
device_id: id::DeviceId,
buffer_id: id::BufferId,
descriptor: Option<wgt::BufferDescriptor<Option<String>>>,
descriptor: Option<BufferDescriptor<'static>>,
},
CreateCommandEncoder {
device_id: id::DeviceId,
// TODO(zakorgy): Serialize CommandEncoderDescriptor in wgpu-core
// wgpu::command::CommandEncoderDescriptor,
command_encoder_id: id::CommandEncoderId,
label: Option<String>,
label: Option<Cow<'static, str>>,
},
CreateComputePipeline {
device_id: id::DeviceId,
@ -142,7 +146,7 @@ pub enum WebGPURequest {
CreatePipelineLayout {
device_id: id::DeviceId,
pipeline_layout_id: id::PipelineLayoutId,
descriptor: wgt::PipelineLayoutDescriptor<'static, id::BindGroupLayoutId>,
descriptor: PipelineLayoutDescriptor<'static>,
},
CreateRenderPipeline {
device_id: id::DeviceId,
@ -152,7 +156,7 @@ pub enum WebGPURequest {
CreateSampler {
device_id: id::DeviceId,
sampler_id: id::SamplerId,
descriptor: wgt::SamplerDescriptor<Option<String>>,
descriptor: SamplerDescriptor<'static>,
},
CreateShaderModule {
device_id: id::DeviceId,
@ -170,13 +174,13 @@ pub enum WebGPURequest {
CreateTexture {
device_id: id::DeviceId,
texture_id: id::TextureId,
descriptor: Option<wgt::TextureDescriptor<Option<String>>>,
descriptor: Option<TextureDescriptor<'static>>,
},
CreateTextureView {
texture_id: id::TextureId,
texture_view_id: id::TextureViewId,
device_id: id::DeviceId,
descriptor: Option<wgt::TextureViewDescriptor<Option<String>>>,
descriptor: Option<TextureViewDescriptor<'static>>,
},
DestroyBuffer(id::BufferId),
DestroySwapChain {
@ -189,7 +193,7 @@ pub enum WebGPURequest {
FreeDevice(id::DeviceId),
RenderBundleEncoderFinish {
render_bundle_encoder: RenderBundleEncoder,
descriptor: wgt::RenderBundleDescriptor<Option<String>>,
descriptor: RenderBundleDescriptor<'static>,
render_bundle_id: id::RenderBundleId,
device_id: id::DeviceId,
},
@ -579,16 +583,8 @@ impl<'a> WGPU<'a> {
} => {
let global = &self.global;
if let Some(desc) = descriptor {
let st;
let label = match desc.label {
Some(ref s) => {
st = CString::new(s.as_bytes()).unwrap();
st.as_ptr()
},
None => ptr::null(),
};
let result = gfx_select!(buffer_id =>
global.device_create_buffer(device_id, &desc.map_label(|_| label), buffer_id));
global.device_create_buffer(device_id, &desc, buffer_id));
if result.is_err() {
let _ = gfx_select!(buffer_id => global.buffer_error(buffer_id));
}
@ -603,14 +599,6 @@ impl<'a> WGPU<'a> {
label,
} => {
let global = &self.global;
let st;
let label = match label {
Some(ref s) => {
st = CString::new(s.as_bytes()).unwrap();
st.as_ptr()
},
None => ptr::null(),
};
let desc = wgt::CommandEncoderDescriptor { label };
let result = gfx_select!(command_encoder_id =>
global.device_create_command_encoder(device_id, &desc, command_encoder_id));
@ -626,7 +614,7 @@ impl<'a> WGPU<'a> {
} => {
let global = &self.global;
let result = gfx_select!(compute_pipeline_id =>
global.device_create_compute_pipeline(device_id, &descriptor, compute_pipeline_id));
global.device_create_compute_pipeline(device_id, &descriptor, compute_pipeline_id, None));
if result.is_err() {
let _ = gfx_select!(compute_pipeline_id =>
global.compute_pipeline_error(compute_pipeline_id));
@ -664,7 +652,7 @@ impl<'a> WGPU<'a> {
let global = &self.global;
if let Some(desc) = descriptor {
let result = gfx_select!(render_pipeline_id =>
global.device_create_render_pipeline(device_id, &desc, render_pipeline_id));
global.device_create_render_pipeline(device_id, &desc, render_pipeline_id, None));
if result.is_err() {
let _ = gfx_select!(render_pipeline_id =>
global.render_pipeline_error(render_pipeline_id));
@ -680,17 +668,9 @@ impl<'a> WGPU<'a> {
descriptor,
} => {
let global = &self.global;
let st;
let label = match descriptor.label {
Some(ref s) => {
st = CString::new(s.as_bytes()).unwrap();
st.as_ptr()
},
None => ptr::null(),
};
let result = gfx_select!(sampler_id => global.device_create_sampler(
device_id,
&descriptor.map_label(|_| label),
&descriptor,
sampler_id
));
if result.is_err() {
@ -763,17 +743,9 @@ impl<'a> WGPU<'a> {
} => {
let global = &self.global;
if let Some(desc) = descriptor {
let st;
let label = match desc.label {
Some(ref s) => {
st = CString::new(s.as_bytes()).unwrap();
st.as_ptr()
},
None => ptr::null(),
};
let result = gfx_select!(texture_id => global.device_create_texture(
device_id,
&desc.map_label(|_| label),
&desc,
texture_id
));
if result.is_err() {
@ -792,17 +764,9 @@ impl<'a> WGPU<'a> {
} => {
let global = &self.global;
if let Some(desc) = descriptor {
let st;
let label = match desc.label {
Some(ref s) => {
st = CString::new(s.as_bytes()).unwrap();
st.as_ptr()
},
None => ptr::null(),
};
let result = gfx_select!(texture_view_id => global.texture_create_view(
texture_id,
Some(&desc.map_label(|_| label)),
&desc,
texture_view_id
));
if result.is_err() {
@ -877,17 +841,9 @@ impl<'a> WGPU<'a> {
device_id,
} => {
let global = &self.global;
let st;
let label = match descriptor.label {
Some(ref s) => {
st = CString::new(s.as_bytes()).unwrap();
st.as_ptr()
},
None => ptr::null(),
};
let result = gfx_select!(render_bundle_id => global.render_bundle_encoder_finish(
render_bundle_encoder,
&descriptor.map_label(|_| label),
&descriptor,
render_bundle_id
));
if result.is_err() {
@ -1051,7 +1007,7 @@ impl<'a> WGPU<'a> {
let buffer_size =
(buffer_stride * size.height as u32) as wgt::BufferAddress;
let buffer_desc = wgt::BufferDescriptor {
label: ptr::null(),
label: None,
size: buffer_size,
usage: wgt::BufferUsage::MAP_READ |
wgt::BufferUsage::COPY_DST,
@ -1079,7 +1035,7 @@ impl<'a> WGPU<'a> {
let buffer_size =
(size.height as u32 * buffer_stride) as wgt::BufferAddress;
let comm_desc = wgt::CommandEncoderDescriptor { label: ptr::null() };
let comm_desc = wgt::CommandEncoderDescriptor { label: None };
let _ = gfx_select!(encoder_id => global.device_create_command_encoder(
device_id,
&comm_desc,

View file

@ -58,7 +58,7 @@
],
"gpu": {
"device_pool.js": [
"c6be73f9918be979816bf02978e8429ce8b4d63d",
"f72b6b734c671ff0316fadfec49e0a93bd16fd10",
[]
],
"implementation.js": [
@ -102,7 +102,7 @@
[]
],
"json_param_value.js": [
"1bb32d06dfdf95be6953faac150b767585198cf7",
"921b3ddce6aacde8e3b05d4133dc07ffb90842f8",
[]
],
"parseQuery.js": [
@ -161,7 +161,7 @@
]
},
"version.js": [
"4d5e72c0442fdbdd4d5ceeefa14dcbaafae4ffaa",
"794e3cdef44214801f15234a61aaf5af338f97fc",
[]
]
},
@ -229,7 +229,7 @@
],
"render_pass": {
"storeOp.spec.js": [
"c02e99db655933431cf8f310c21eac4febaf380d",
"83ae8657c1c822b6cfc8f511089de88dfd2d8fdc",
[]
]
},
@ -239,18 +239,36 @@
[]
],
"texture_zero_init_test.js": [
"e3c21011bb288492bd137be9e2e43b5efd02aa36",
"381d7dcb0a8e9574834629223308c7ef0e375b4b",
[]
]
}
},
"validation": {
"copyBufferToBuffer.spec.js": [
"5fd4877383a47b1e3ca27af8e0843781dbf5a443",
[]
],
"copy_between_linear_data_and_texture": {
"copyBetweenLinearDataAndTexture.js": [
"0db6e68d4af6e395ba07157fd4b1ed0c567fd182",
[]
],
"copyBetweenLinearDataAndTexture_dataRelated.spec.js": [
"be1395b664276f13a728a60acee835d96753e6e1",
[]
],
"copyBetweenLinearDataAndTexture_textureRelated.spec.js": [
"bef71943fae2bc6f0dcaa4ae53b744190ccdc00c",
[]
]
},
"createBindGroup.spec.js": [
"fa585038e39ff6208787ee89bc177bdb13cdc385",
[]
],
"createBindGroupLayout.spec.js": [
"9c0df538b278aaa38d11f3922b749799f72f4c3f",
"43fd923687b68d9214305b04ea1573e044245928",
[]
],
"createPipelineLayout.spec.js": [
@ -258,7 +276,7 @@
[]
],
"createTexture.spec.js": [
"a9c7a8be01e03bcda1aa2f96374c30c0ce0bbe45",
"ceff54e136ff321bf22a8647790c3263404f6afc",
[]
],
"createView.spec.js": [
@ -266,11 +284,11 @@
[]
],
"error_scope.spec.js": [
"5523237daeba5d0c1c292dd3da8dead86a99f8e4",
"64575540e8bde1545565389108067bf4b078cae9",
[]
],
"fences.spec.js": [
"cc04848410fed9f20b863aadbedf3482787b6de9",
"b50ebae572d9af8f4edd3f82c051877b6068374e",
[]
],
"queue_submit.spec.js": [
@ -293,7 +311,7 @@
],
"resource_usages": {
"textureUsageInRender.spec.js": [
"6322ec25ee537584030c322ab99ec3d69e02b30e",
"12efa65ce2d9e9ed67cb2be398a0466424d38015",
[]
]
},
@ -318,13 +336,13 @@
[]
],
"validation_test.js": [
"d816fd0594bd5097f4a7e3d2de91c3e0aa6e3f7b",
"c6cd14779bbb7b95e37bdb93d3f5be33902be6c2",
[]
]
}
},
"capability_info.js": [
"2e4264fe229c11bb387d300cebce6a4e69780cd1",
"10a8c5aa4b62c05830eabb33734d866939258ade",
[]
],
"examples.spec.js": [
@ -332,23 +350,23 @@
[]
],
"gpu_test.js": [
"92f0e41840bd8e74eda57bbeda60757af798e2f9",
"f350131af3babe9729dec35261f7c445e2bf41d2",
[]
],
"idl": {
"constants": {
"flags.spec.js": [
"1de75c84e5daeaafd3ac47b31b6011223b03e360",
"51b80aa8aa23cb987079f6dd228bb0bb68816624",
[]
]
},
"idl_test.js": [
"231fc0945f87fe6aede03ec7a03c1ecaf7fe04db",
"3943563d2ac2c779e6cfb0ab033b92bca24e5749",
[]
]
},
"listing.js": [
"8736de378a6a02235dfff5796f4fe4a963769001",
"3134cf0dd5693705ed82f0828f4dbd93fedf358e",
[]
],
"util": {
@ -357,12 +375,12 @@
[]
],
"math.js": [
"a76f1a00158ab50df82c74187de859dfbef41d60",
"4761467b586691662834dd0fbf3e86643a5eb823",
[]
],
"texture": {
"layout.js": [
"26d82a7be0aea4483b4b72d6faa2b9233a5f0039",
"c3c610bf0d93ebe66abf81d8f2017deba62641a3",
[]
],
"subresource.js": [
@ -370,7 +388,7 @@
[]
],
"texelData.js": [
"8a827c47d21e1c1a89e081b2e70d1759c9208b0e",
"eadaa09633022e6c82355b07a4798c802c56a8e8",
[]
]
}
@ -383,7 +401,7 @@
]
},
"copyImageBitmapToTexture.spec.js": [
"1432ff05e1daa192d5898bf1c7f42e84008b23b4",
"9df5ff94419baa92ff27f8b39cdc0ee99439dc06",
[]
],
"reftests": {
@ -396,7 +414,7 @@
[]
],
"gpu_ref_test.js": [
"dd58b543b01ec86c1a820d9d661a5c3f9b68b323",
"a45002835df48518eacb8d7887791ee200c3e3c1",
[]
],
"ref": {
@ -417,7 +435,7 @@
"testharness": {
"webgpu": {
"cts.html": [
"e87ceb79a409fc3e3ddcccf38e48b865740e0809",
"28d69b38d20367b4c61e72e834f518a11e8de411",
[
"webgpu/cts.html?q=webgpu:api,operation,buffers,map_detach:*",
{}
@ -446,6 +464,18 @@
"webgpu/cts.html?q=webgpu:api,operation,render_pass,storeOp:*",
{}
],
[
"webgpu/cts.html?q=webgpu:api,validation,copyBufferToBuffer:*",
{}
],
[
"webgpu/cts.html?q=webgpu:api,validation,copy_between_linear_data_and_texture,copyBetweenLinearDataAndTexture_dataRelated:*",
{}
],
[
"webgpu/cts.html?q=webgpu:api,validation,copy_between_linear_data_and_texture,copyBetweenLinearDataAndTexture_textureRelated:*",
{}
],
[
"webgpu/cts.html?q=webgpu:api,validation,createBindGroup:*",
{}

View file

@ -261,7 +261,396 @@
[webgpu:api,validation,render_pass,storeOp:store_op_and_read_only:readonly=true;depthStoreOp="clear"]
expected: FAIL
[webgpu:api,validation,render_pass,storeOp:store_op_and_read_only:readonly="_undef_";depthReadOnly=true]
expected: FAIL
[webgpu:api,validation,render_pass,storeOp:store_op_and_read_only:readonly="_undef_";stencilReadOnly=true]
expected: FAIL
[cts.html?q=webgpu:api,validation,createPipelineLayout:*]
[cts.html?q=webgpu:api,operation,command_buffer,render,basic:*]
[cts.html?q=webgpu:api,validation,copyBufferToBuffer:*]
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=1;dstUsage=32]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_offset_alignment:srcOffset=2;dstOffset=0]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_with_invalid_buffer:]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=8;dstUsage=128]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=16;dstUsage=256]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_overflow:srcOffset=0;dstOffset=9007199254740984;copySize=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=64;dstUsage=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=4;dstUsage=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=1;dstUsage=128]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=64;dstUsage=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=64;dstUsage=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=4;dstUsage=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_within_same_buffer:srcOffset=4;dstOffset=0;copySize=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=16;dstUsage=64]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_overflow:srcOffset=0;dstOffset=16;copySize=9007199254740984]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=64;dstUsage=512]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_out_of_bounds:srcOffset=0;dstOffset=36;copySize=0]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=16;dstUsage=128]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=32;dstUsage=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_out_of_bounds:srcOffset=0;dstOffset=36;copySize=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=512;dstUsage=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=8;dstUsage=256]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=512;dstUsage=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=512;dstUsage=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=128;dstUsage=128]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=512;dstUsage=1]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=16;dstUsage=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=4;dstUsage=32]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=16;dstUsage=1]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=16;dstUsage=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=16;dstUsage=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_overflow:srcOffset=0;dstOffset=9007199254740984;copySize=9007199254740984]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=128;dstUsage=64]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=16;dstUsage=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_out_of_bounds:srcOffset=36;dstOffset=0;copySize=0]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_out_of_bounds:srcOffset=36;dstOffset=0;copySize=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=8;dstUsage=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=1;dstUsage=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=1;dstUsage=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=1;dstUsage=1]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=8;dstUsage=1]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=8;dstUsage=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=8;dstUsage=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=1;dstUsage=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=64;dstUsage=64]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=8;dstUsage=512]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_overflow:srcOffset=9007199254740984;dstOffset=0;copySize=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=512;dstUsage=256]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=1;dstUsage=512]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=32;dstUsage=32]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=256;dstUsage=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=256;dstUsage=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=256;dstUsage=1]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_size_alignment:copySize=5]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_size_alignment:copySize=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=128;dstUsage=256]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=256;dstUsage=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=4;dstUsage=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_within_same_buffer:srcOffset=0;dstOffset=4;copySize=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=2;dstUsage=256]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_overflow:srcOffset=9007199254740984;dstOffset=9007199254740984;copySize=9007199254740984]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=2;dstUsage=512]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_offset_alignment:srcOffset=0;dstOffset=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_offset_alignment:srcOffset=0;dstOffset=5]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_within_same_buffer:srcOffset=0;dstOffset=8;copySize=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=32;dstUsage=128]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=128;dstUsage=32]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=8;dstUsage=32]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=4;dstUsage=512]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=512;dstUsage=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_out_of_bounds:srcOffset=0;dstOffset=20;copySize=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=32;dstUsage=64]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=4;dstUsage=1]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=512;dstUsage=32]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=64;dstUsage=1]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=256;dstUsage=512]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=4;dstUsage=64]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=16;dstUsage=512]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_within_same_buffer:srcOffset=8;dstOffset=0;copySize=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=2;dstUsage=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=2;dstUsage=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=2;dstUsage=1]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_overflow:srcOffset=0;dstOffset=0;copySize=9007199254740984]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=2;dstUsage=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=512;dstUsage=64]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=2;dstUsage=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=128;dstUsage=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=128;dstUsage=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=128;dstUsage=1]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=32;dstUsage=2]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=128;dstUsage=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=1;dstUsage=64]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=256;dstUsage=32]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=64;dstUsage=32]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=512;dstUsage=128]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=8;dstUsage=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=16;dstUsage=32]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=256;dstUsage=128]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=2;dstUsage=64]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=32;dstUsage=256]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=1;dstUsage=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=256;dstUsage=64]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_overflow:srcOffset=9007199254740984;dstOffset=0;copySize=9007199254740984]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=1;dstUsage=256]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=2;dstUsage=128]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=128;dstUsage=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=8;dstUsage=64]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=256;dstUsage=256]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=2;dstUsage=32]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_overflow:srcOffset=16;dstOffset=0;copySize=9007199254740984]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=4;dstUsage=256]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=256;dstUsage=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=64;dstUsage=128]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=512;dstUsage=512]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_out_of_bounds:srcOffset=20;dstOffset=0;copySize=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_out_of_bounds:srcOffset=0;dstOffset=0;copySize=36]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=64;dstUsage=16]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=32;dstUsage=1]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=32;dstUsage=512]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=32;dstUsage=4]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=32;dstUsage=8]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=128;dstUsage=512]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:copy_offset_alignment:srcOffset=5;dstOffset=0]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=4;dstUsage=128]
expected: FAIL
[webgpu:api,validation,copyBufferToBuffer:buffer_usage:srcUsage=64;dstUsage=256]
expected: FAIL
[cts.html?q=webgpu:api,validation,copy_between_linear_data_and_texture,copyBetweenLinearDataAndTexture_textureRelated:*]
expected: CRASH
[cts.html?q=webgpu:api,validation,copy_between_linear_data_and_texture,copyBetweenLinearDataAndTexture_dataRelated:*]
expected: CRASH

View file

@ -91,10 +91,13 @@ export class DevicePool {
static async makeHolder() {
const gpu = getGPU();
const adapter = await gpu.requestAdapter();
assert(adapter !== null);
const device = await adapter.requestDevice();
assert(device !== null);
const holder = {
acquired: false,
device: await adapter.requestDevice(),
device,
lostReason: undefined,
};

View file

@ -3,10 +3,11 @@
**/ import { assert } from '../util/util.js';
// JSON can't represent `undefined` and by default stores it as `null`.
// Instead, store `undefined` as this magic string value in JSON.
const jsUndefinedMagicValue = '✗undefined';
const jsUndefinedMagicValue = '_undef_';
export function stringifyParamValue(value) {
return JSON.stringify(value, (k, v) => {
// Make sure no one actually uses the magic value as a parameter.
assert(v !== jsUndefinedMagicValue);
return v === undefined ? jsUndefinedMagicValue : v;

View file

@ -1,3 +1,3 @@
// AUTO-GENERATED - DO NOT EDIT. See tools/gen_version.
export const version = 'a4499c8ced40640242a40448c4d4258e3fb830d3';
export const version = 'fa4873f0a303566ca6f34744a253d96f5e462d3d';

View file

@ -36,6 +36,9 @@
<meta name=variant content='?q=webgpu:api,operation,fences:*'>
<meta name=variant content='?q=webgpu:api,operation,render_pass,storeOp:*'>
<!--<meta name=variant content='?q=webgpu:api,operation,resource_init,copied_texture_clear:*'>-->
<meta name=variant content='?q=webgpu:api,validation,copyBufferToBuffer:*'>
<meta name=variant content='?q=webgpu:api,validation,copy_between_linear_data_and_texture,copyBetweenLinearDataAndTexture_dataRelated:*'>
<meta name=variant content='?q=webgpu:api,validation,copy_between_linear_data_and_texture,copyBetweenLinearDataAndTexture_textureRelated:*'>
<meta name=variant content='?q=webgpu:api,validation,createBindGroup:*'>
<!--<meta name=variant content='?q=webgpu:api,validation,createBindGroupLayout:*'>-->
<meta name=variant content='?q=webgpu:api,validation,createPipelineLayout:*'>

View file

@ -30,7 +30,11 @@
TODO: test with more interesting loadOp values`;
import { params, poptions } from '../../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { kTextureFormatInfo, kTextureFormats } from '../../../capability_info.js';
import {
kEncodableTextureFormatInfo,
kEncodableTextureFormats,
kSizedDepthStencilFormats,
} from '../../../capability_info.js';
import { GPUTest } from '../../../gpu_test.js';
// Test with a zero and non-zero mip.
@ -140,20 +144,16 @@ g.test('render_pass_store_op,color_attachment_with_depth_stencil_attachment')
g.test('render_pass_store_op,color_attachment_only')
.params(
params()
.combine(poptions('colorFormat', kTextureFormats))
// Filter out any depth/stencil or non-renderable formats
.filter(
({ colorFormat }) =>
kTextureFormatInfo[colorFormat].color && kTextureFormatInfo[colorFormat].renderable
)
.combine(poptions('colorFormat', kEncodableTextureFormats))
// Filter out any non-renderable formats
.filter(({ colorFormat }) => kEncodableTextureFormatInfo[colorFormat].renderable)
.combine(poptions('storeOperation', kStoreOps))
.combine(poptions('mipLevel', kMipLevel))
.combine(poptions('arrayLayer', kArrayLayers))
)
.fn(t => {
const kColorFormat = 'rgba8unorm';
const colorAttachment = t.device.createTexture({
format: kColorFormat,
format: t.params.colorFormat,
size: { width: kWidth, height: kHeight, depth: t.params.arrayLayer + 1 },
mipLevelCount: kMipLevelCount,
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.OUTPUT_ATTACHMENT,
@ -194,7 +194,7 @@ g.test('render_pass_store_op,color_attachment_only')
expectedValue = { R: 1.0, G: 0.0, B: 0.0, A: 1.0 };
}
t.expectSingleColor(colorAttachment, kColorFormat, {
t.expectSingleColor(colorAttachment, t.params.colorFormat, {
size: [kHeight, kWidth, 1],
slice: t.params.arrayLayer,
exp: expectedValue,
@ -266,15 +266,8 @@ g.test('render_pass_store_op,multiple_color_attachments')
g.test('render_pass_store_op,depth_stencil_attachment_only')
.params(
params()
.combine(poptions('depthStencilFormat', kTextureFormats))
// Filter out color and non-renderable formats.
.filter(
({ depthStencilFormat }) =>
(kTextureFormatInfo[depthStencilFormat].depth ||
kTextureFormatInfo[depthStencilFormat].stencil) &&
kTextureFormatInfo[depthStencilFormat].renderable &&
kTextureFormatInfo[depthStencilFormat].copyable
)
// TODO: Also test unsized depth/stencil formats
.combine(poptions('depthStencilFormat', kSizedDepthStencilFormats))
.combine(poptions('storeOperation', kStoreOps))
.combine(poptions('mipLevel', kMipLevel))
.combine(poptions('arrayLayer', kArrayLayers))

View file

@ -15,7 +15,11 @@
}
import { params, poptions, pbool } from '../../../../common/framework/params_builder.js';
import { assert, unreachable } from '../../../../common/framework/util/util.js';
import { kTextureAspects, kTextureFormatInfo, kTextureFormats } from '../../../capability_info.js';
import {
kTextureAspects,
kUncompressedTextureFormatInfo,
kUncompressedTextureFormats,
} from '../../../capability_info.js';
import { GPUTest } from '../../../gpu_test.js';
import { createTextureUploadBuffer } from '../../../util/texture/layout.js';
import { SubresourceRange } from '../../../util/texture/subresource.js';
@ -192,10 +196,10 @@ function getRequiredTextureUsage(format, sampleCount, uninitializeMethod, readMe
usage |= GPUTextureUsage.OUTPUT_ATTACHMENT;
}
if (!kTextureFormatInfo[format].copyable) {
if (!kUncompressedTextureFormatInfo[format].copyDst) {
// Copies are not possible. We need OutputAttachment to initialize
// canary data.
assert(kTextureFormatInfo[format].renderable);
assert(kUncompressedTextureFormatInfo[format].renderable);
usage |= GPUTextureUsage.OUTPUT_ATTACHMENT;
}
@ -306,7 +310,7 @@ export class TextureZeroInitTest extends GPUTest {
this.params.aspect,
subresourceRange
)) {
if (kTextureFormatInfo[this.params.format].color) {
if (kUncompressedTextureFormatInfo[this.params.format].color) {
commandEncoder
.beginRenderPass({
colorAttachments: [
@ -383,10 +387,13 @@ export class TextureZeroInitTest extends GPUTest {
}
initializeTexture(texture, state, subresourceRange) {
if (this.params.sampleCount > 1 || !kTextureFormatInfo[this.params.format].copyable) {
if (
this.params.sampleCount > 1 ||
!kUncompressedTextureFormatInfo[this.params.format].copyDst
) {
// Copies to multisampled textures not yet specified.
// Use a storeOp for now.
assert(kTextureFormatInfo[this.params.format].renderable);
assert(kUncompressedTextureFormatInfo[this.params.format].renderable);
this.initializeWithStoreOp(state, texture, subresourceRange);
} else {
this.initializeWithCopy(texture, state, subresourceRange);
@ -400,7 +407,7 @@ export class TextureZeroInitTest extends GPUTest {
this.params.aspect,
subresourceRange
)) {
if (kTextureFormatInfo[this.params.format].color) {
if (kUncompressedTextureFormatInfo[this.params.format].color) {
commandEncoder
.beginRenderPass({
colorAttachments: [
@ -434,12 +441,12 @@ export class TextureZeroInitTest extends GPUTest {
return (
// TODO: Consider making a list of "valid" texture descriptors in capability_info.
params()
.combine(poptions('format', kTextureFormats))
.combine(poptions('format', kUncompressedTextureFormats))
.combine(poptions('aspect', kTextureAspects))
.unless(
({ format, aspect }) =>
(aspect === 'depth-only' && !kTextureFormatInfo[format].depth) ||
(aspect === 'stencil-only' && !kTextureFormatInfo[format].stencil)
(aspect === 'depth-only' && !kUncompressedTextureFormatInfo[format].depth) ||
(aspect === 'stencil-only' && !kUncompressedTextureFormatInfo[format].stencil)
)
.combine(poptions('mipLevelCount', kMipLevelCounts))
.combine(poptions('sampleCount', kSampleCounts))
@ -456,14 +463,16 @@ export class TextureZeroInitTest extends GPUTest {
(readMethod === ReadMethod.CopyToBuffer || readMethod === ReadMethod.CopyToTexture) &&
(format === 'depth24plus' || format === 'depth24plus-stencil8')
)
.unless(
({ readMethod, format }) =>
(readMethod === ReadMethod.DepthTest && !kTextureFormatInfo[format].depth) ||
(readMethod === ReadMethod.StencilTest && !kTextureFormatInfo[format].stencil) ||
(readMethod === ReadMethod.ColorBlending && !kTextureFormatInfo[format].color) ||
.unless(({ readMethod, format }) => {
const info = kUncompressedTextureFormatInfo[format];
return (
(readMethod === ReadMethod.DepthTest && !info.depth) ||
(readMethod === ReadMethod.StencilTest && !info.stencil) ||
(readMethod === ReadMethod.ColorBlending && !info.color) ||
// TODO: Test with depth sampling
(readMethod === ReadMethod.Sample && kTextureFormatInfo[format].depth)
)
(readMethod === ReadMethod.Sample && info.depth)
);
})
.unless(
({ readMethod, sampleCount }) =>
// We can only read from multisampled textures by sampling.
@ -481,11 +490,13 @@ export class TextureZeroInitTest extends GPUTest {
readMethod
);
if (usage & GPUTextureUsage.OUTPUT_ATTACHMENT && !kTextureFormatInfo[format].renderable) {
const info = kUncompressedTextureFormatInfo[format];
if (usage & GPUTextureUsage.OUTPUT_ATTACHMENT && !info.renderable) {
return false;
}
if (usage & GPUTextureUsage.STORAGE && !kTextureFormatInfo[format].storage) {
if (usage & GPUTextureUsage.STORAGE && !info.storage) {
return false;
}

View file

@ -0,0 +1,271 @@
/**
* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
**/ export const description = `
copyBufferToBuffer tests.
Test Plan:
* Buffer is valid/invalid
- the source buffer is invalid
- the destination buffer is invalid
* Buffer usages
- the source buffer is created without GPUBufferUsage::COPY_SRC
- the destination buffer is created without GPUBufferUsage::COPY_DEST
* CopySize
- copySize is not a multiple of 4
- copySize is 0
* copy offsets
- sourceOffset is not a multiple of 4
- destinationOffset is not a multiple of 4
* Arthimetic overflow
- (sourceOffset + copySize) is overflow
- (destinationOffset + copySize) is overflow
* Out of bounds
- (sourceOffset + copySize) > size of source buffer
- (destinationOffset + copySize) > size of destination buffer
* Source buffer and destination buffer are the same buffer
`;
import { poptions, params } from '../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../common/framework/test_group.js';
import { kBufferUsages } from '../../capability_info.js';
import { kMaxSafeMultipleOf8 } from '../../util/math.js';
import { ValidationTest } from './validation_test.js';
class F extends ValidationTest {
TestCopyBufferToBuffer(options) {
const { srcBuffer, srcOffset, dstBuffer, dstOffset, copySize, isSuccess } = options;
const commandEncoder = this.device.createCommandEncoder();
commandEncoder.copyBufferToBuffer(srcBuffer, srcOffset, dstBuffer, dstOffset, copySize);
this.expectValidationError(() => {
commandEncoder.finish();
}, !isSuccess);
}
}
export const g = makeTestGroup(F);
g.test('copy_with_invalid_buffer').fn(async t => {
const validBuffer = t.device.createBuffer({
size: 16,
usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
});
const errorBuffer = t.getErrorBuffer();
t.TestCopyBufferToBuffer({
srcBuffer: errorBuffer,
srcOffset: 0,
dstBuffer: validBuffer,
dstOffset: 0,
copySize: 8,
isSuccess: false,
});
t.TestCopyBufferToBuffer({
srcBuffer: validBuffer,
srcOffset: 0,
dstBuffer: errorBuffer,
dstOffset: 0,
copySize: 8,
isSuccess: false,
});
});
g.test('buffer_usage')
.params(
params()
.combine(poptions('srcUsage', kBufferUsages))
.combine(poptions('dstUsage', kBufferUsages))
)
.fn(async t => {
const { srcUsage, dstUsage } = t.params;
const srcBuffer = t.device.createBuffer({
size: 16,
usage: srcUsage,
});
const dstBuffer = t.device.createBuffer({
size: 16,
usage: dstUsage,
});
const isSuccess = srcUsage === GPUBufferUsage.COPY_SRC && dstUsage === GPUBufferUsage.COPY_DST;
t.TestCopyBufferToBuffer({
srcBuffer,
srcOffset: 0,
dstBuffer,
dstOffset: 0,
copySize: 8,
isSuccess,
});
});
g.test('copy_size_alignment')
.params([
{ copySize: 0, _isSuccess: true },
{ copySize: 2, _isSuccess: false },
{ copySize: 4, _isSuccess: true },
{ copySize: 5, _isSuccess: false },
{ copySize: 8, _isSuccess: true },
])
.fn(async t => {
const { copySize, _isSuccess: isSuccess } = t.params;
const srcBuffer = t.device.createBuffer({
size: 16,
usage: GPUBufferUsage.COPY_SRC,
});
const dstBuffer = t.device.createBuffer({
size: 16,
usage: GPUBufferUsage.COPY_DST,
});
t.TestCopyBufferToBuffer({
srcBuffer,
srcOffset: 0,
dstBuffer,
dstOffset: 0,
copySize,
isSuccess,
});
});
g.test('copy_offset_alignment')
.params([
{ srcOffset: 0, dstOffset: 0, _isSuccess: true },
{ srcOffset: 2, dstOffset: 0, _isSuccess: false },
{ srcOffset: 4, dstOffset: 0, _isSuccess: true },
{ srcOffset: 5, dstOffset: 0, _isSuccess: false },
{ srcOffset: 8, dstOffset: 0, _isSuccess: true },
{ srcOffset: 0, dstOffset: 2, _isSuccess: false },
{ srcOffset: 0, dstOffset: 4, _isSuccess: true },
{ srcOffset: 0, dstOffset: 5, _isSuccess: false },
{ srcOffset: 0, dstOffset: 8, _isSuccess: true },
{ srcOffset: 4, dstOffset: 4, _isSuccess: true },
])
.fn(async t => {
const { srcOffset, dstOffset, _isSuccess: isSuccess } = t.params;
const srcBuffer = t.device.createBuffer({
size: 16,
usage: GPUBufferUsage.COPY_SRC,
});
const dstBuffer = t.device.createBuffer({
size: 16,
usage: GPUBufferUsage.COPY_DST,
});
t.TestCopyBufferToBuffer({
srcBuffer,
srcOffset,
dstBuffer,
dstOffset,
copySize: 8,
isSuccess,
});
});
g.test('copy_overflow')
.params([
{ srcOffset: 0, dstOffset: 0, copySize: kMaxSafeMultipleOf8 },
{ srcOffset: 16, dstOffset: 0, copySize: kMaxSafeMultipleOf8 },
{ srcOffset: 0, dstOffset: 16, copySize: kMaxSafeMultipleOf8 },
{ srcOffset: kMaxSafeMultipleOf8, dstOffset: 0, copySize: 16 },
{ srcOffset: 0, dstOffset: kMaxSafeMultipleOf8, copySize: 16 },
{ srcOffset: kMaxSafeMultipleOf8, dstOffset: 0, copySize: kMaxSafeMultipleOf8 },
{ srcOffset: 0, dstOffset: kMaxSafeMultipleOf8, copySize: kMaxSafeMultipleOf8 },
{
srcOffset: kMaxSafeMultipleOf8,
dstOffset: kMaxSafeMultipleOf8,
copySize: kMaxSafeMultipleOf8,
},
])
.fn(async t => {
const { srcOffset, dstOffset, copySize } = t.params;
const srcBuffer = t.device.createBuffer({
size: 16,
usage: GPUBufferUsage.COPY_SRC,
});
const dstBuffer = t.device.createBuffer({
size: 16,
usage: GPUBufferUsage.COPY_DST,
});
t.TestCopyBufferToBuffer({
srcBuffer,
srcOffset,
dstBuffer,
dstOffset,
copySize,
isSuccess: false,
});
});
g.test('copy_out_of_bounds')
.params([
{ srcOffset: 0, dstOffset: 0, copySize: 32, _isSuccess: true },
{ srcOffset: 0, dstOffset: 0, copySize: 36 },
{ srcOffset: 36, dstOffset: 0, copySize: 4 },
{ srcOffset: 0, dstOffset: 36, copySize: 4 },
{ srcOffset: 36, dstOffset: 0, copySize: 0 },
{ srcOffset: 0, dstOffset: 36, copySize: 0 },
{ srcOffset: 20, dstOffset: 0, copySize: 16 },
{ srcOffset: 20, dstOffset: 0, copySize: 12, _isSuccess: true },
{ srcOffset: 0, dstOffset: 20, copySize: 16 },
{ srcOffset: 0, dstOffset: 20, copySize: 12, _isSuccess: true },
])
.fn(async t => {
const { srcOffset, dstOffset, copySize, _isSuccess = false } = t.params;
const srcBuffer = t.device.createBuffer({
size: 32,
usage: GPUBufferUsage.COPY_SRC,
});
const dstBuffer = t.device.createBuffer({
size: 32,
usage: GPUBufferUsage.COPY_DST,
});
t.TestCopyBufferToBuffer({
srcBuffer,
srcOffset,
dstBuffer,
dstOffset,
copySize,
isSuccess: _isSuccess,
});
});
g.test('copy_within_same_buffer')
.params([
{ srcOffset: 0, dstOffset: 8, copySize: 4 },
{ srcOffset: 8, dstOffset: 0, copySize: 4 },
{ srcOffset: 0, dstOffset: 4, copySize: 8 },
{ srcOffset: 4, dstOffset: 0, copySize: 8 },
])
.fn(async t => {
const { srcOffset, dstOffset, copySize } = t.params;
const buffer = t.device.createBuffer({
size: 16,
usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
});
t.TestCopyBufferToBuffer({
srcBuffer: buffer,
srcOffset,
dstBuffer: buffer,
dstOffset,
copySize,
isSuccess: false,
});
});

View file

@ -0,0 +1,179 @@
/**
* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
**/ import { poptions } from '../../../../common/framework/params_builder.js';
import { assert } from '../../../../common/framework/util/util.js';
import { kSizedTextureFormatInfo } from '../../../capability_info.js';
import { ValidationTest } from '../validation_test.js';
export const kAllTestMethods = ['WriteTexture', 'CopyBufferToTexture', 'CopyTextureToBuffer'];
export class CopyBetweenLinearDataAndTextureTest extends ValidationTest {
bytesInACompleteRow(copyWidth, format) {
const info = kSizedTextureFormatInfo[format];
assert(copyWidth % info.blockWidth === 0);
return (info.bytesPerBlock * copyWidth) / info.blockWidth;
}
requiredBytesInCopy(layout, format, copyExtent) {
const info = kSizedTextureFormatInfo[format];
assert(layout.rowsPerImage % info.blockHeight === 0);
assert(copyExtent.height % info.blockHeight === 0);
assert(copyExtent.width % info.blockWidth === 0);
if (copyExtent.width === 0 || copyExtent.height === 0 || copyExtent.depth === 0) {
return 0;
} else {
const texelBlockRowsPerImage = layout.rowsPerImage / info.blockHeight;
const bytesPerImage = layout.bytesPerRow * texelBlockRowsPerImage;
const bytesInLastSlice =
layout.bytesPerRow * (copyExtent.height / info.blockHeight - 1) +
(copyExtent.width / info.blockWidth) * info.bytesPerBlock;
return bytesPerImage * (copyExtent.depth - 1) + bytesInLastSlice;
}
}
testRun(
textureCopyView,
textureDataLayout,
size,
{
dataSize,
method,
success,
submit = false, // If submit is true, the validaton error is expected to come from the submit and encoding should succeed.
}
) {
switch (method) {
case 'WriteTexture': {
const data = new Uint8Array(dataSize);
this.expectValidationError(() => {
this.device.defaultQueue.writeTexture(textureCopyView, data, textureDataLayout, size);
}, !success);
break;
}
case 'CopyBufferToTexture': {
const buffer = this.device.createBuffer({
size: dataSize,
usage: GPUBufferUsage.COPY_SRC,
});
const encoder = this.device.createCommandEncoder();
encoder.copyBufferToTexture({ buffer, ...textureDataLayout }, textureCopyView, size);
if (submit) {
const cmd = encoder.finish();
this.expectValidationError(() => {
this.device.defaultQueue.submit([cmd]);
}, !success);
} else {
this.expectValidationError(() => {
encoder.finish();
}, !success);
}
break;
}
case 'CopyTextureToBuffer': {
const buffer = this.device.createBuffer({
size: dataSize,
usage: GPUBufferUsage.COPY_DST,
});
const encoder = this.device.createCommandEncoder();
encoder.copyTextureToBuffer(textureCopyView, { buffer, ...textureDataLayout }, size);
if (submit) {
const cmd = encoder.finish();
this.expectValidationError(() => {
this.device.defaultQueue.submit([cmd]);
}, !success);
} else {
this.expectValidationError(() => {
encoder.finish();
}, !success);
}
break;
}
}
}
// This is a helper function used for creating a texture when we don't have to be very
// precise about its size as long as it's big enough and properly aligned.
createAlignedTexture(
format,
copySize = { width: 1, height: 1, depth: 1 },
origin = { x: 0, y: 0, z: 0 }
) {
const info = kSizedTextureFormatInfo[format];
return this.device.createTexture({
size: {
width: Math.max(1, copySize.width + origin.x) * info.blockWidth,
height: Math.max(1, copySize.height + origin.y) * info.blockHeight,
depth: Math.max(1, copySize.depth + origin.z),
},
format,
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
});
}
}
// For testing divisibility by a number we test all the values returned by this function:
function valuesToTestDivisibilityBy(number) {
const values = [];
for (let i = 0; i <= 2 * number; ++i) {
values.push(i);
}
values.push(3 * number);
return values;
}
// This is a helper function used for expanding test parameters for texel block alignment tests on offset
export function texelBlockAlignmentTestExpanderForOffset({ format }) {
return poptions(
'offset',
valuesToTestDivisibilityBy(kSizedTextureFormatInfo[format].bytesPerBlock)
);
}
// This is a helper function used for expanding test parameters for texel block alignment tests on rowsPerImage
export function texelBlockAlignmentTestExpanderForRowsPerImage({ format }) {
return poptions(
'rowsPerImage',
valuesToTestDivisibilityBy(kSizedTextureFormatInfo[format].blockHeight)
);
}
// This is a helper function used for expanding test parameters for texel block alignment tests on origin and size
export function texelBlockAlignmentTestExpanderForValueToCoordinate({ format, coordinateToTest }) {
switch (coordinateToTest) {
case 'x':
case 'width':
return poptions(
'valueToCoordinate',
valuesToTestDivisibilityBy(kSizedTextureFormatInfo[format].blockWidth)
);
case 'y':
case 'height':
return poptions(
'valueToCoordinate',
valuesToTestDivisibilityBy(kSizedTextureFormatInfo[format].blockHeight)
);
case 'z':
case 'depth':
return poptions('valueToCoordinate', valuesToTestDivisibilityBy(1));
}
}
// This is a helper function used for filtering test parameters
export function formatCopyableWithMethod({ format, method }) {
if (method === 'CopyTextureToBuffer') {
return kSizedTextureFormatInfo[format].copySrc;
} else {
return kSizedTextureFormatInfo[format].copyDst;
}
}

View file

@ -0,0 +1,299 @@
/**
* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
**/ export const description = '';
import { params, poptions } from '../../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../../common/framework/test_group.js';
import {
kUncompressedTextureFormatInfo,
kSizedTextureFormats,
kSizedTextureFormatInfo,
} from '../../../capability_info.js';
import { align } from '../../../util/math.js';
import {
CopyBetweenLinearDataAndTextureTest,
kAllTestMethods,
texelBlockAlignmentTestExpanderForOffset,
texelBlockAlignmentTestExpanderForRowsPerImage,
formatCopyableWithMethod,
} from './copyBetweenLinearDataAndTexture.js';
export const g = makeTestGroup(CopyBetweenLinearDataAndTextureTest);
g.test('bound_on_rows_per_image')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('rowsPerImageInBlocks', [0, 1, 2]))
.combine(poptions('copyHeightInBlocks', [0, 1, 2]))
.combine(poptions('copyDepth', [1, 3]))
)
.fn(async t => {
const { rowsPerImageInBlocks, copyHeightInBlocks, copyDepth, method } = t.params;
const format = 'rgba8unorm';
const rowsPerImage = rowsPerImageInBlocks * kUncompressedTextureFormatInfo[format].blockHeight;
const copyHeight = copyHeightInBlocks * kUncompressedTextureFormatInfo[format].blockHeight;
const texture = t.device.createTexture({
size: { width: 4, height: 4, depth: 3 },
format,
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
});
// The WebGPU spec:
// If layout.rowsPerImage is not 0, it must be greater than or equal to copyExtent.height.
// If copyExtent.depth is greater than 1: layout.rowsPerImage must be greater than or equal to copyExtent.height.
// TODO: Update this if https://github.com/gpuweb/gpuweb/issues/984 changes the spec.
let success = true;
if (rowsPerImage !== 0 && rowsPerImage < copyHeight) {
success = false;
}
if (copyDepth > 1 && rowsPerImage < copyHeight) {
success = false;
}
t.testRun(
{ texture },
{ bytesPerRow: 1024, rowsPerImage },
{ width: 0, height: copyHeight, depth: copyDepth },
{ dataSize: 1, method, success }
);
});
// Test with offset + requiredBytesIsCopy overflowing GPUSize64.
g.test('offset_plus_required_bytes_in_copy_overflow')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine([
{ bytesPerRow: 2 ** 31, rowsPerImage: 2 ** 31, depth: 1, _success: true }, // success case
{ bytesPerRow: 2 ** 31, rowsPerImage: 2 ** 31, depth: 16, _success: false }, // bytesPerRow * rowsPerImage * (depth - 1) overflows.
])
)
.fn(async t => {
const { method, bytesPerRow, rowsPerImage, depth, _success } = t.params;
const texture = t.device.createTexture({
size: [1, 1, depth],
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
});
t.testRun(
{ texture },
{ bytesPerRow, rowsPerImage },
{ width: 1, height: 1, depth },
{
dataSize: 10000,
method,
success: _success,
}
);
});
// Testing that the minimal data size condition is checked correctly.
// In the success case, we test the exact value.
// In the failing case, we test the exact value minus 1.
g.test('required_bytes_in_copy')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine([
{ bytesPerRowPadding: 0, rowsPerImagePaddingInBlocks: 0 }, // no padding
{ bytesPerRowPadding: 0, rowsPerImagePaddingInBlocks: 6 }, // rowsPerImage padding
{ bytesPerRowPadding: 6, rowsPerImagePaddingInBlocks: 0 }, // bytesPerRow padding
{ bytesPerRowPadding: 15, rowsPerImagePaddingInBlocks: 17 }, // both paddings
])
.combine([
{ copyWidthInBlocks: 3, copyHeightInBlocks: 4, copyDepth: 5, offsetInBlocks: 0 }, // standard copy
{ copyWidthInBlocks: 5, copyHeightInBlocks: 4, copyDepth: 3, offsetInBlocks: 11 }, // standard copy, offset > 0
{ copyWidthInBlocks: 256, copyHeightInBlocks: 3, copyDepth: 2, offsetInBlocks: 0 }, // copyWidth is 256-aligned
{ copyWidthInBlocks: 0, copyHeightInBlocks: 4, copyDepth: 5, offsetInBlocks: 0 }, // empty copy because of width
{ copyWidthInBlocks: 3, copyHeightInBlocks: 0, copyDepth: 5, offsetInBlocks: 0 }, // empty copy because of height
{ copyWidthInBlocks: 3, copyHeightInBlocks: 4, copyDepth: 0, offsetInBlocks: 13 }, // empty copy because of depth, offset > 0
{ copyWidthInBlocks: 1, copyHeightInBlocks: 4, copyDepth: 5, offsetInBlocks: 0 }, // copyWidth = 1
{ copyWidthInBlocks: 3, copyHeightInBlocks: 1, copyDepth: 5, offsetInBlocks: 15 }, // copyHeight = 1, offset > 0
{ copyWidthInBlocks: 5, copyHeightInBlocks: 4, copyDepth: 1, offsetInBlocks: 0 }, // copyDepth = 1
{ copyWidthInBlocks: 7, copyHeightInBlocks: 1, copyDepth: 1, offsetInBlocks: 0 }, // copyHeight = 1 and copyDepth = 1
])
.combine(poptions('format', kSizedTextureFormats))
.filter(formatCopyableWithMethod)
)
.fn(async t => {
const {
offsetInBlocks,
bytesPerRowPadding,
rowsPerImagePaddingInBlocks,
copyWidthInBlocks,
copyHeightInBlocks,
copyDepth,
format,
method,
} = t.params;
// In the CopyB2T and CopyT2B cases we need to have bytesPerRow 256-aligned,
// to make this happen we align the bytesInACompleteRow value and multiply
// bytesPerRowPadding by 256.
const bytesPerRowAlignment = method === 'WriteTexture' ? 1 : 256;
const info = kSizedTextureFormatInfo[format];
const copyWidth = copyWidthInBlocks * info.blockWidth;
const copyHeight = copyHeightInBlocks * info.blockHeight;
const offset = offsetInBlocks * info.bytesPerBlock;
const rowsPerImage = copyHeight + rowsPerImagePaddingInBlocks * info.blockHeight;
const bytesPerRow =
align(t.bytesInACompleteRow(copyWidth, format), bytesPerRowAlignment) +
bytesPerRowPadding * bytesPerRowAlignment;
const size = { width: copyWidth, height: copyHeight, depth: copyDepth };
const minDataSize =
offset + t.requiredBytesInCopy({ offset, bytesPerRow, rowsPerImage }, format, size);
const texture = t.createAlignedTexture(format, size);
t.testRun({ texture }, { offset, bytesPerRow, rowsPerImage }, size, {
dataSize: minDataSize,
method,
success: true,
});
if (minDataSize > 0) {
t.testRun({ texture }, { offset, bytesPerRow, rowsPerImage }, size, {
dataSize: minDataSize - 1,
method,
success: false,
});
}
});
g.test('texel_block_alignment_on_rows_per_image')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('format', kSizedTextureFormats))
.filter(formatCopyableWithMethod)
.expand(texelBlockAlignmentTestExpanderForRowsPerImage)
)
.fn(async t => {
const { rowsPerImage, format, method } = t.params;
const size = { width: 0, height: 0, depth: 0 };
const texture = t.createAlignedTexture(format, size);
const success = rowsPerImage % kSizedTextureFormatInfo[format].blockHeight === 0;
t.testRun({ texture }, { bytesPerRow: 0, rowsPerImage }, size, {
dataSize: 1,
method,
success,
});
});
// TODO: Update this if https://github.com/gpuweb/gpuweb/issues/985 changes the spec.
g.test('texel_block_alignment_on_offset')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('format', kSizedTextureFormats))
.filter(formatCopyableWithMethod)
.expand(texelBlockAlignmentTestExpanderForOffset)
)
.fn(async t => {
const { format, offset, method } = t.params;
const size = { width: 0, height: 0, depth: 0 };
const texture = t.createAlignedTexture(format, size);
const success = offset % kSizedTextureFormatInfo[format].bytesPerBlock === 0;
t.testRun({ texture }, { offset, bytesPerRow: 0 }, size, { dataSize: offset, method, success });
});
g.test('bound_on_bytes_per_row')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine([
{ blocksPerRow: 2, additionalPaddingPerRow: 0, copyWidthInBlocks: 2 }, // success
{ blocksPerRow: 2, additionalPaddingPerRow: 5, copyWidthInBlocks: 3 }, // success if bytesPerBlock <= 5
{ blocksPerRow: 1, additionalPaddingPerRow: 0, copyWidthInBlocks: 2 }, // failure, bytesPerRow > 0
{ blocksPerRow: 0, additionalPaddingPerRow: 0, copyWidthInBlocks: 1 }, // failure, bytesPerRow = 0
])
.combine([
{ copyHeightInBlocks: 0, copyDepth: 1 }, // we don't have to check the bound
{ copyHeightInBlocks: 1, copyDepth: 0 }, // we don't have to check the bound
{ copyHeightInBlocks: 2, copyDepth: 1 }, // we have to check the bound
{ copyHeightInBlocks: 0, copyDepth: 2 }, // we have to check the bound
])
.combine(poptions('format', kSizedTextureFormats))
.filter(formatCopyableWithMethod)
)
.fn(async t => {
const {
blocksPerRow,
additionalPaddingPerRow,
copyWidthInBlocks,
copyHeightInBlocks,
copyDepth,
format,
method,
} = t.params;
// In the CopyB2T and CopyT2B cases we need to have bytesPerRow 256-aligned,
// to make this happen we multiply copyWidth and bytesPerRow by 256, so that
// the appropriate inequalities still hold.
const bytesPerRowAlignment = method === 'WriteTexture' ? 1 : 256;
const info = kSizedTextureFormatInfo[format];
const copyWidth = copyWidthInBlocks * info.blockWidth * bytesPerRowAlignment;
const copyHeight = copyHeightInBlocks * info.blockHeight;
const bytesPerRow =
(blocksPerRow * info.bytesPerBlock + additionalPaddingPerRow) * bytesPerRowAlignment;
const size = { width: copyWidth, height: copyHeight, depth: copyDepth };
const texture = t.createAlignedTexture(format, size);
let success = true;
if (copyHeight > 1 || copyDepth > 1) {
success = bytesPerRow >= t.bytesInACompleteRow(copyWidth, format);
}
t.testRun({ texture }, { bytesPerRow, rowsPerImage: copyHeight }, size, {
dataSize: 1024,
method,
success,
});
});
g.test('bound_on_offset')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('offsetInBlocks', [0, 1, 2]))
.combine(poptions('dataSizeInBlocks', [0, 1, 2]))
)
.fn(async t => {
const { offsetInBlocks, dataSizeInBlocks, method } = t.params;
const format = 'rgba8unorm';
const info = kSizedTextureFormatInfo[format];
const offset = offsetInBlocks * info.bytesPerBlock;
const dataSize = dataSizeInBlocks * info.bytesPerBlock;
const texture = t.device.createTexture({
size: { width: 4, height: 4, depth: 1 },
format,
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
});
const success = offset <= dataSize;
t.testRun(
{ texture },
{ offset, bytesPerRow: 0 },
{ width: 0, height: 0, depth: 0 },
{ dataSize, method, success }
);
});

View file

@ -0,0 +1,307 @@
/**
* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
**/ export const description = '';
import { params, poptions } from '../../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { kSizedTextureFormats, kSizedTextureFormatInfo } from '../../../capability_info.js';
import {
CopyBetweenLinearDataAndTextureTest,
kAllTestMethods,
texelBlockAlignmentTestExpanderForValueToCoordinate,
formatCopyableWithMethod,
} from './copyBetweenLinearDataAndTexture.js';
export const g = makeTestGroup(CopyBetweenLinearDataAndTextureTest);
g.test('texture_must_be_valid')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('textureState', ['valid', 'destroyed', 'error']))
)
.fn(async t => {
const { method, textureState } = t.params;
// A valid texture.
let texture = t.device.createTexture({
size: { width: 4, height: 4, depth: 1 },
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
});
switch (textureState) {
case 'destroyed': {
texture.destroy();
break;
}
case 'error': {
texture = t.getErrorTexture();
break;
}
}
const success = textureState === 'valid';
const submit = textureState === 'destroyed';
t.testRun(
{ texture },
{ bytesPerRow: 0 },
{ width: 0, height: 0, depth: 0 },
{ dataSize: 1, method, success, submit }
);
});
g.test('texture_usage_must_be_valid')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(
poptions('usage', [
GPUTextureUsage.COPY_SRC | GPUTextureUsage.SAMPLED,
GPUTextureUsage.COPY_DST | GPUTextureUsage.SAMPLED,
GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
])
)
)
.fn(async t => {
const { usage, method } = t.params;
const texture = t.device.createTexture({
size: { width: 4, height: 4, depth: 1 },
format: 'rgba8unorm',
usage,
});
const success =
method === 'CopyTextureToBuffer'
? (usage & GPUTextureUsage.COPY_SRC) !== 0
: (usage & GPUTextureUsage.COPY_DST) !== 0;
t.testRun(
{ texture },
{ bytesPerRow: 0 },
{ width: 0, height: 0, depth: 0 },
{ dataSize: 1, method, success }
);
});
g.test('sample_count_must_be_1')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('sampleCount', [1, 4]))
)
.fn(async t => {
const { sampleCount, method } = t.params;
const texture = t.device.createTexture({
size: { width: 4, height: 4, depth: 1 },
sampleCount,
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST | GPUTextureUsage.SAMPLED,
});
const success = sampleCount === 1;
t.testRun(
{ texture },
{ bytesPerRow: 0 },
{ width: 0, height: 0, depth: 0 },
{ dataSize: 1, method, success }
);
});
g.test('mip_level_must_be_in_range')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('mipLevelCount', [3, 5]))
.combine(poptions('mipLevel', [3, 4]))
)
.fn(async t => {
const { mipLevelCount, mipLevel, method } = t.params;
const texture = t.device.createTexture({
size: { width: 32, height: 32, depth: 1 },
mipLevelCount,
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
});
const success = mipLevel < mipLevelCount;
t.testRun(
{ texture, mipLevel },
{ bytesPerRow: 0 },
{ width: 0, height: 0, depth: 0 },
{ dataSize: 1, method, success }
);
});
g.test('texel_block_alignments_on_origin')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('coordinateToTest', ['x', 'y', 'z']))
.combine(poptions('format', kSizedTextureFormats))
.filter(formatCopyableWithMethod)
.expand(texelBlockAlignmentTestExpanderForValueToCoordinate)
)
.fn(async t => {
const { valueToCoordinate, coordinateToTest, format, method } = t.params;
const info = kSizedTextureFormatInfo[format];
const origin = { x: 0, y: 0, z: 0 };
const size = { width: 0, height: 0, depth: 0 };
let success = true;
origin[coordinateToTest] = valueToCoordinate;
switch (coordinateToTest) {
case 'x': {
success = origin.x % info.blockWidth === 0;
break;
}
case 'y': {
success = origin.y % info.blockHeight === 0;
break;
}
}
const texture = t.createAlignedTexture(format, size, origin);
t.testRun({ texture, origin }, { bytesPerRow: 0 }, size, {
dataSize: 1,
method,
success,
});
});
g.test('1d_texture')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('width', [0, 1]))
.combine([
{ height: 1, depth: 1 },
{ height: 1, depth: 0 },
{ height: 1, depth: 2 },
{ height: 0, depth: 1 },
{ height: 2, depth: 1 },
])
)
.fn(async t => {
const { method, width, height, depth } = t.params;
const size = { width, height, depth };
const texture = t.device.createTexture({
size: { width: 2, height: 1, depth: 1 },
dimension: '1d',
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
});
// For 1d textures we require copyHeight and copyDepth to be 1,
// copyHeight or copyDepth being 0 should cause a validation error.
const success = size.height === 1 && size.depth === 1;
t.testRun({ texture }, { bytesPerRow: 256, rowsPerImage: 4 }, size, {
dataSize: 16,
method,
success,
});
});
g.test('texel_block_alignments_on_size')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('coordinateToTest', ['width', 'height', 'depth']))
.combine(poptions('format', kSizedTextureFormats))
.filter(formatCopyableWithMethod)
.expand(texelBlockAlignmentTestExpanderForValueToCoordinate)
)
.fn(async t => {
const { valueToCoordinate, coordinateToTest, format, method } = t.params;
const info = kSizedTextureFormatInfo[format];
const origin = { x: 0, y: 0, z: 0 };
const size = { width: 0, height: 0, depth: 0 };
let success = true;
size[coordinateToTest] = valueToCoordinate;
switch (coordinateToTest) {
case 'width': {
success = size.width % info.blockWidth === 0;
break;
}
case 'height': {
success = size.height % info.blockHeight === 0;
break;
}
}
const texture = t.createAlignedTexture(format, size, origin);
t.testRun({ texture, origin }, { bytesPerRow: 0 }, size, {
dataSize: 1,
method,
success,
});
});
g.test('texture_range_conditions')
.params(
params()
.combine(poptions('method', kAllTestMethods))
.combine(poptions('originValue', [7, 8]))
.combine(poptions('copySizeValue', [7, 8]))
.combine(poptions('textureSizeValue', [14, 15]))
.combine(poptions('mipLevel', [0, 2]))
.combine(poptions('coordinateToTest', [0, 1, 2]))
)
.fn(async t => {
const {
originValue,
copySizeValue,
textureSizeValue,
mipLevel,
coordinateToTest,
method,
} = t.params;
const origin = [0, 0, 0];
const copySize = [0, 0, 0];
const textureSize = { width: 16 << mipLevel, height: 16 << mipLevel, depth: 16 };
const success = originValue + copySizeValue <= textureSizeValue;
origin[coordinateToTest] = originValue;
copySize[coordinateToTest] = copySizeValue;
switch (coordinateToTest) {
case 0: {
textureSize.width = textureSizeValue << mipLevel;
break;
}
case 1: {
textureSize.height = textureSizeValue << mipLevel;
break;
}
case 2: {
textureSize.depth = textureSizeValue;
break;
}
}
const texture = t.device.createTexture({
size: textureSize,
mipLevelCount: 3,
format: 'rgba8unorm',
usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.COPY_DST,
});
t.testRun({ texture, origin, mipLevel }, { bytesPerRow: 0 }, copySize, {
dataSize: 1,
method,
success,
});
});

View file

@ -14,10 +14,10 @@ import {
kShaderStageCombinations,
kTextureBindingTypeInfo,
kTextureComponentTypes,
kTextureFormats,
kTextureFormatInfo,
kTextureViewDimensions,
kTextureViewDimensionInfo,
kAllTextureFormats,
kAllTextureFormatInfo,
} from '../../capability_info.js';
import { ValidationTest } from './validation_test.js';
@ -83,7 +83,7 @@ g.test('bindingTypeSpecific_optional_members')
...poptions('textureComponentType', kTextureComponentTypes),
...pbool('multisampled'),
...poptions('viewDimension', kTextureViewDimensions),
...poptions('storageTextureFormat', kTextureFormats),
...poptions('storageTextureFormat', kAllTextureFormats),
])
)
.fn(t => {
@ -115,7 +115,10 @@ g.test('bindingTypeSpecific_optional_members')
if (viewDimension !== undefined && !kTextureViewDimensionInfo[viewDimension].storage) {
success = false;
}
if (storageTextureFormat !== undefined && !kTextureFormatInfo[storageTextureFormat].storage) {
if (
storageTextureFormat !== undefined &&
!kAllTextureFormatInfo[storageTextureFormat].storage
) {
success = false;
}
}

View file

@ -5,7 +5,7 @@ createTexture validation tests.
`;
import { poptions } from '../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../common/framework/test_group.js';
import { kTextureFormatInfo, kTextureFormats } from '../../capability_info.js';
import { kAllTextureFormats, kAllTextureFormatInfo } from '../../capability_info.js';
import { ValidationTest } from './validation_test.js';
@ -130,10 +130,10 @@ g.test('it_is_invalid_to_submit_a_destroyed_texture_before_and_after_encode')
});
g.test('it_is_invalid_to_have_an_output_attachment_texture_with_non_renderable_format')
.params(poptions('format', kTextureFormats))
.params(poptions('format', kAllTextureFormats))
.fn(async t => {
const format = t.params.format;
const info = kTextureFormatInfo[format];
const info = kAllTextureFormatInfo[format];
const descriptor = t.getDescriptor({ width: 1, height: 1, format });

View file

@ -36,7 +36,10 @@ class F extends Fixture {
super.init();
const gpu = getGPU();
const adapter = await gpu.requestAdapter();
this._device = await adapter.requestDevice();
assert(adapter !== null);
const device = await adapter.requestDevice();
assert(device !== null);
this._device = device;
}
createErrorBuffer() {

View file

@ -4,6 +4,7 @@
fences validation tests.
`;
import { makeTestGroup } from '../../../common/framework/test_group.js';
import { assert } from '../../../common/framework/util/util.js';
import { ValidationTest } from './validation_test.js';
@ -60,6 +61,7 @@ g.test('signal_a_fence_on_a_different_device_than_it_was_created_on_is_invalid')
const fence = t.queue.createFence();
const anotherDevice = await t.device.adapter.requestDevice();
assert(anotherDevice !== null);
const anotherQueue = anotherDevice.defaultQueue;
t.expectValidationError(() => {
@ -71,6 +73,7 @@ g.test('signal_a_fence_on_a_different_device_does_not_update_fence_signaled_valu
const fence = t.queue.createFence({ initialValue: 1 });
const anotherDevice = await t.device.adapter.requestDevice();
assert(anotherDevice !== null);
const anotherQueue = anotherDevice.defaultQueue;
t.expectValidationError(() => {

View file

@ -4,15 +4,31 @@
Texture Usages Validation Tests in Render Pass.
Test Coverage:
- Tests that read and write usages upon the same texture subresource, or different subresources
of the same texture. Different subresources of the same texture includes different mip levels,
different array layers, and different aspects.
- When read and write usages are binding to the same texture subresource, an error should be
generated. Otherwise, no error should be generated.
- For each combination of two texture usages:
- For various subresource ranges (different mip levels or array layers) that overlap a given
subresources or not for color formats:
- Check that an error is generated when read-write or write-write usages are binding to the
same texture subresource. Otherwise, no error should be generated. One exception is race
condition upon two writeonly-storage-texture usages, which is valid.
- For each combination of two texture usages:
- For various aspects (all, depth-only, stencil-only) that overlap a given subresources or not
for depth/stencil formats:
- Check that an error is generated when read-write or write-write usages are binding to the
same aspect. Otherwise, no error should be generated.
- Test combinations of two shader stages:
- Texture usages in bindings with invisible shader stages should be tracked. Invisible shader
stages include shader stage with visibility none and compute shader stage in render pass.
`;
import { poptions, params } from '../../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../../common/framework/test_group.js';
import { kTextureFormatInfo, kShaderStages } from '../../../capability_info.js';
import {
kShaderStages,
kDepthStencilFormats,
kDepthStencilFormatInfo,
} from '../../../capability_info.js';
import { ValidationTest } from '../validation_test.js';
class TextureUsageTracking extends ValidationTest {
@ -40,65 +56,183 @@ class TextureUsageTracking extends ValidationTest {
export const g = makeTestGroup(TextureUsageTracking);
const READ_BASE_LEVEL = 3;
const READ_BASE_LAYER = 0;
const BASE_LEVEL = 3;
const BASE_LAYER = 0;
const TOTAL_LEVELS = 6;
const TOTAL_LAYERS = 2;
g.test('readwrite_upon_subresources')
.params([
// read and write usages are binding to the same texture subresource.
{
writeBaseLevel: READ_BASE_LEVEL,
writeBaseLayer: READ_BASE_LAYER,
_success: false,
},
g.test('subresources_and_binding_types_combination_for_color')
.params(
params()
.combine([
// Two texture usages are binding to the same texture subresource.
{
baseLevel: BASE_LEVEL,
baseLayer: BASE_LAYER,
levelCount: 1,
layerCount: 1,
_resourceSuccess: false,
},
// read and write usages are binding to different mip levels of the same texture.
{
writeBaseLevel: READ_BASE_LEVEL + 1,
writeBaseLayer: READ_BASE_LAYER,
_success: true,
},
// Two texture usages are binding to different mip levels of the same texture.
{
baseLevel: BASE_LEVEL + 1,
baseLayer: BASE_LAYER,
levelCount: 1,
layerCount: 1,
_resourceSuccess: true,
},
// read and write usages are binding to different array layers of the same texture.
{
writeBaseLevel: READ_BASE_LEVEL,
writeBaseLayer: READ_BASE_LAYER + 1,
_success: true,
},
])
// Two texture usages are binding to different array layers of the same texture.
{
baseLevel: BASE_LEVEL,
baseLayer: BASE_LAYER + 1,
levelCount: 1,
layerCount: 1,
_resourceSuccess: true,
},
// The second texture usage contains the whole mip chain where the first texture usage is using.
{
baseLevel: 0,
baseLayer: BASE_LAYER,
levelCount: TOTAL_LEVELS,
layerCount: 1,
_resourceSuccess: false,
},
// The second texture usage contains the all layers where the first texture usage is using.
{
baseLevel: BASE_LEVEL,
baseLayer: 0,
levelCount: 1,
layerCount: TOTAL_LAYERS,
_resourceSuccess: false,
},
])
.combine([
{
type0: 'sampled-texture',
type1: 'sampled-texture',
_usageSuccess: true,
},
{
type0: 'sampled-texture',
type1: 'readonly-storage-texture',
_usageSuccess: true,
},
{
type0: 'sampled-texture',
type1: 'writeonly-storage-texture',
_usageSuccess: false,
},
{
type0: 'sampled-texture',
type1: 'render-target',
_usageSuccess: false,
},
{
type0: 'readonly-storage-texture',
type1: 'readonly-storage-texture',
_usageSuccess: true,
},
{
type0: 'readonly-storage-texture',
type1: 'writeonly-storage-texture',
_usageSuccess: false,
},
{
type0: 'readonly-storage-texture',
type1: 'render-target',
_usageSuccess: false,
},
// Race condition upon multiple writable storage texture is valid.
{
type0: 'writeonly-storage-texture',
type1: 'writeonly-storage-texture',
_usageSuccess: true,
},
{
type0: 'writeonly-storage-texture',
type1: 'render-target',
_usageSuccess: false,
},
])
)
.fn(async t => {
const { writeBaseLevel, writeBaseLayer, _success } = t.params;
const {
baseLevel,
baseLayer,
levelCount,
layerCount,
type0,
type1,
_usageSuccess,
_resourceSuccess,
} = t.params;
const texture = t.createTexture({ arrayLayerCount: 2, mipLevelCount: 6 });
const texture = t.createTexture({
arrayLayerCount: TOTAL_LAYERS,
mipLevelCount: TOTAL_LEVELS,
usage: GPUTextureUsage.SAMPLED | GPUTextureUsage.STORAGE | GPUTextureUsage.OUTPUT_ATTACHMENT,
});
const sampleView = texture.createView({
baseMipLevel: READ_BASE_LEVEL,
const view0 = texture.createView({
baseMipLevel: BASE_LEVEL,
mipLevelCount: 1,
baseArrayLayer: READ_BASE_LAYER,
baseArrayLayer: BASE_LAYER,
arrayLayerCount: 1,
});
const renderView = texture.createView({
baseMipLevel: writeBaseLevel,
mipLevelCount: 1,
baseArrayLayer: writeBaseLayer,
arrayLayerCount: 1,
const view1Dimension = layerCount !== 1 ? '2d-array' : '2d';
const view1 = texture.createView({
dimension: view1Dimension,
baseMipLevel: baseLevel,
mipLevelCount: levelCount,
baseArrayLayer: baseLayer,
arrayLayerCount: layerCount,
});
const bindGroupLayout = t.device.createBindGroupLayout({
entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, type: 'sampled-texture' }],
});
// TODO: Add two 'render-target' usages for color attachments.
const bglEntries = [
{
binding: 0,
visibility: GPUShaderStage.FRAGMENT,
type: type0,
storageTextureFormat: type0 === 'sampled-texture' ? undefined : 'rgba8unorm',
},
];
const bgEntries = [{ binding: 0, resource: view0 }];
if (type1 !== 'render-target') {
bglEntries.push({
binding: 1,
visibility: GPUShaderStage.FRAGMENT,
type: type1,
viewDimension: view1Dimension,
storageTextureFormat: type1 === 'sampled-texture' ? undefined : 'rgba8unorm',
});
bgEntries.push({ binding: 1, resource: view1 });
}
const bindGroup = t.device.createBindGroup({
entries: [{ binding: 0, resource: sampleView }],
layout: bindGroupLayout,
entries: bgEntries,
layout: t.device.createBindGroupLayout({ entries: bglEntries }),
});
const encoder = t.device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [
{
attachment: renderView,
attachment: type1 === 'render-target' ? view1 : t.createTexture().createView(),
loadValue: { r: 0.0, g: 1.0, b: 0.0, a: 1.0 },
storeOp: 'store',
},
@ -108,42 +242,72 @@ g.test('readwrite_upon_subresources')
pass.setBindGroup(0, bindGroup);
pass.endPass();
const success = _resourceSuccess || _usageSuccess;
t.expectValidationError(() => {
encoder.finish();
}, !_success);
}, !success);
});
g.test('readwrite_upon_aspects')
g.test('subresources_and_binding_types_combination_for_aspect')
.params(
params()
.combine(poptions('format', ['depth32float', 'depth24plus', 'depth24plus-stencil8']))
.combine(poptions('readAspect', ['all', 'depth-only', 'stencil-only']))
.combine(poptions('writeAspect', ['all', 'depth-only', 'stencil-only']))
.combine(poptions('format', kDepthStencilFormats))
.combine(poptions('aspect0', ['all', 'depth-only', 'stencil-only']))
.combine(poptions('aspect1', ['all', 'depth-only', 'stencil-only']))
.unless(
({ format, readAspect, writeAspect }) =>
// TODO: Exclude depth-only aspect once WebGPU supports stencil-only texture format(s).
(readAspect === 'stencil-only' && !kTextureFormatInfo[format].stencil) ||
(writeAspect === 'stencil-only' && !kTextureFormatInfo[format].stencil)
({ format, aspect0, aspect1 }) =>
(aspect0 === 'stencil-only' && !kDepthStencilFormatInfo[format].stencil) ||
(aspect1 === 'stencil-only' && !kDepthStencilFormatInfo[format].stencil)
)
.unless(
({ format, aspect0, aspect1 }) =>
(aspect0 === 'depth-only' && !kDepthStencilFormatInfo[format].depth) ||
(aspect1 === 'depth-only' && !kDepthStencilFormatInfo[format].depth)
)
.combine([
{
type0: 'sampled-texture',
type1: 'sampled-texture',
_usageSuccess: true,
},
{
type0: 'sampled-texture',
type1: 'render-target',
_usageSuccess: false,
},
])
)
.fn(async t => {
const { format, readAspect, writeAspect } = t.params;
const { format, aspect0, aspect1, type0, type1, _usageSuccess } = t.params;
const view = t.createTexture({ format }).createView();
const texture = t.createTexture({ format });
const view0 = texture.createView({ aspect: aspect0 });
const view1 = texture.createView({ aspect: aspect1 });
const bindGroupLayout = t.device.createBindGroupLayout({
entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, type: 'sampled-texture' }],
});
const bglEntries = [
{
binding: 0,
visibility: GPUShaderStage.FRAGMENT,
type: type0,
},
];
const bgEntries = [{ binding: 0, resource: view0 }];
if (type1 !== 'render-target') {
bglEntries.push({
binding: 1,
visibility: GPUShaderStage.FRAGMENT,
type: type1,
});
bgEntries.push({ binding: 1, resource: view1 });
}
const bindGroup = t.device.createBindGroup({
entries: [{ binding: 0, resource: view }],
layout: bindGroupLayout,
entries: bgEntries,
layout: t.device.createBindGroupLayout({ entries: bglEntries }),
});
const success =
(readAspect === 'depth-only' && writeAspect === 'stencil-only') ||
(readAspect === 'stencil-only' && writeAspect === 'depth-only');
const encoder = t.device.createCommandEncoder();
const pass = encoder.beginRenderPass({
colorAttachments: [
@ -154,18 +318,26 @@ g.test('readwrite_upon_aspects')
},
],
depthStencilAttachment: {
attachment: view,
depthStoreOp: 'clear',
depthLoadValue: 'load',
stencilStoreOp: 'clear',
stencilLoadValue: 'load',
},
depthStencilAttachment:
type1 !== 'render-target'
? undefined
: {
attachment: view1,
depthStoreOp: 'clear',
depthLoadValue: 'load',
stencilStoreOp: 'clear',
stencilLoadValue: 'load',
},
});
pass.setBindGroup(0, bindGroup);
pass.endPass();
const disjointAspects =
(aspect0 === 'depth-only' && aspect1 === 'stencil-only') ||
(aspect0 === 'stencil-only' && aspect1 === 'depth-only');
const success = disjointAspects || _usageSuccess;
t.expectValidationError(() => {
encoder.finish();
}, !success);

View file

@ -53,15 +53,21 @@ export class ValidationTest extends GPUTest {
});
}
getErrorTexture() {
this.device.pushErrorScope('validation');
const texture = this.device.createTexture({
size: { width: 0, height: 0, depth: 0 },
format: 'rgba8unorm',
usage: GPUTextureUsage.SAMPLED,
});
this.device.popErrorScope();
return texture;
}
getErrorTextureView() {
this.device.pushErrorScope('validation');
const view = this.device
.createTexture({
size: { width: 0, height: 0, depth: 0 },
format: 'rgba8unorm',
usage: GPUTextureUsage.SAMPLED,
})
.createView();
const view = this.getErrorTexture().createView();
this.device.popErrorScope();
return view;
}

View file

@ -29,10 +29,7 @@ export const kBufferUsages = numericKeysOf(kBufferUsageInfo);
// Textures
export const kTextureFormatInfo = {
// Try to keep these manually-formatted in a readable grid.
// (Note: this list should always match the one in the spec.)
export const kRegularTextureFormatInfo = {
// 8-bit formats
r8unorm: {
renderable: true,
@ -40,7 +37,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 1,
blockWidth: 1,
blockHeight: 1,
@ -51,7 +49,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 1,
blockWidth: 1,
blockHeight: 1,
@ -62,7 +61,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 1,
blockWidth: 1,
blockHeight: 1,
@ -73,7 +73,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 1,
blockWidth: 1,
blockHeight: 1,
@ -85,7 +86,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 2,
blockWidth: 1,
blockHeight: 1,
@ -96,7 +98,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 2,
blockWidth: 1,
blockHeight: 1,
@ -107,7 +110,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 2,
blockWidth: 1,
blockHeight: 1,
@ -118,7 +122,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 2,
blockWidth: 1,
blockHeight: 1,
@ -129,7 +134,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 2,
blockWidth: 1,
blockHeight: 1,
@ -140,7 +146,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 2,
blockWidth: 1,
blockHeight: 1,
@ -151,7 +158,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 2,
blockWidth: 1,
blockHeight: 1,
@ -163,7 +171,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -174,7 +183,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -185,7 +195,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -196,7 +207,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -207,7 +219,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -218,7 +231,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -229,7 +243,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -240,7 +255,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -251,7 +267,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -262,7 +279,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -273,7 +291,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -284,7 +303,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -295,7 +315,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -307,7 +328,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -318,7 +340,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
@ -330,7 +353,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 8,
blockWidth: 1,
blockHeight: 1,
@ -341,7 +365,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 8,
blockWidth: 1,
blockHeight: 1,
@ -352,7 +377,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 8,
blockWidth: 1,
blockHeight: 1,
@ -363,7 +389,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 8,
blockWidth: 1,
blockHeight: 1,
@ -374,7 +401,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 8,
blockWidth: 1,
blockHeight: 1,
@ -385,7 +413,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 8,
blockWidth: 1,
blockHeight: 1,
@ -397,7 +426,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 1,
blockHeight: 1,
@ -408,7 +438,8 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 1,
blockHeight: 1,
@ -419,30 +450,44 @@ export const kTextureFormatInfo = {
depth: false,
stencil: false,
storage: true,
copyable: true,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 1,
blockHeight: 1,
},
// Depth/stencil formats
};
export const kRegularTextureFormats = keysOf(kRegularTextureFormatInfo);
export const kSizedDepthStencilFormatInfo = {
depth32float: {
renderable: true,
color: false,
depth: true,
stencil: false,
storage: false,
copyable: true,
copySrc: true,
copyDst: false,
bytesPerBlock: 4,
blockWidth: 1,
blockHeight: 1,
},
};
export const kSizedDepthStencilFormats = keysOf(kSizedDepthStencilFormatInfo);
export const kUnsizedDepthStencilFormatInfo = {
depth24plus: {
renderable: true,
color: false,
depth: true,
stencil: false,
storage: false,
copyable: false,
copySrc: false,
copyDst: false,
blockWidth: 1,
blockHeight: 1,
},
'depth24plus-stencil8': {
renderable: true,
@ -450,11 +495,246 @@ export const kTextureFormatInfo = {
depth: true,
stencil: true,
storage: false,
copyable: false,
copySrc: false,
copyDst: false,
blockWidth: 1,
blockHeight: 1,
},
};
export const kTextureFormats = keysOf(kTextureFormatInfo);
export const kUnsizedDepthStencilFormats = keysOf(kUnsizedDepthStencilFormatInfo);
export const kCompressedTextureFormatInfo = {
// BC formats
'bc1-rgba-unorm': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 8,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc1-rgba-unorm-srgb': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 8,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc2-rgba-unorm': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc2-rgba-unorm-srgb': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc3-rgba-unorm': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc3-rgba-unorm-srgb': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc4-r-unorm': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 8,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc4-r-snorm': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 8,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc5-rg-unorm': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc5-rg-snorm': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc6h-rgb-ufloat': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc6h-rgb-sfloat': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc7-rgba-unorm': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
'bc7-rgba-unorm-srgb': {
renderable: false,
color: true,
depth: false,
stencil: false,
storage: false,
copySrc: true,
copyDst: true,
bytesPerBlock: 16,
blockWidth: 4,
blockHeight: 4,
extension: 'texture-compression-bc',
},
};
export const kCompressedTextureFormats = keysOf(kCompressedTextureFormatInfo);
export const kColorTextureFormatInfo = {
...kRegularTextureFormatInfo,
...kCompressedTextureFormatInfo,
};
export const kColorTextureFormats = keysOf(kColorTextureFormatInfo);
export const kEncodableTextureFormatInfo = {
...kRegularTextureFormatInfo,
...kSizedDepthStencilFormatInfo,
};
export const kEncodableTextureFormats = keysOf(kEncodableTextureFormatInfo);
export const kSizedTextureFormatInfo = {
...kRegularTextureFormatInfo,
...kSizedDepthStencilFormatInfo,
...kCompressedTextureFormatInfo,
};
export const kSizedTextureFormats = keysOf(kSizedTextureFormatInfo);
export const kDepthStencilFormatInfo = {
...kSizedDepthStencilFormatInfo,
...kUnsizedDepthStencilFormatInfo,
};
export const kDepthStencilFormats = keysOf(kDepthStencilFormatInfo);
export const kUncompressedTextureFormatInfo = {
...kRegularTextureFormatInfo,
...kSizedDepthStencilFormatInfo,
...kUnsizedDepthStencilFormatInfo,
};
export const kUncompressedTextureFormats = keysOf(kUncompressedTextureFormatInfo);
export const kAllTextureFormatInfo = {
...kUncompressedTextureFormatInfo,
...kCompressedTextureFormatInfo,
};
export const kAllTextureFormats = keysOf(kAllTextureFormatInfo);
export const kTextureDimensionInfo = {
'1d': {},

View file

@ -223,9 +223,6 @@ got [${failedByteActualValues.join(', ')}]`;
let failed = false;
switch (filter) {
case 'none':
failed = error !== null;
break;
case 'out-of-memory':
failed = !(error instanceof GPUOutOfMemoryError);
break;

View file

@ -3,57 +3,83 @@
**/ export const description = `
Test the values of flags interfaces (e.g. GPUTextureUsage).
`;
import { poptions } from '../../../common/framework/params_builder.js';
import { makeTestGroup } from '../../../common/framework/test_group.js';
import { IDLTest } from '../idl_test.js';
export const g = makeTestGroup(IDLTest);
g.test('BufferUsage').fn(t => {
const expected = {
MAP_READ: 0x0001,
MAP_WRITE: 0x0002,
COPY_SRC: 0x0004,
COPY_DST: 0x0008,
INDEX: 0x0010,
VERTEX: 0x0020,
UNIFORM: 0x0040,
STORAGE: 0x0080,
INDIRECT: 0x0100,
};
const kBufferUsageExp = {
MAP_READ: 0x0001,
MAP_WRITE: 0x0002,
COPY_SRC: 0x0004,
COPY_DST: 0x0008,
INDEX: 0x0010,
VERTEX: 0x0020,
UNIFORM: 0x0040,
STORAGE: 0x0080,
INDIRECT: 0x0100,
QUERY_RESOLVE: 0x0200,
};
t.assertMembers(GPUBufferUsage, expected);
g.test('BufferUsage,count').fn(t => {
t.assertMemberCount(GPUBufferUsage, kBufferUsageExp);
});
g.test('BufferUsage,values')
.params(poptions('key', Object.keys(kBufferUsageExp)))
.fn(t => {
const { key } = t.params;
t.assertMember(GPUBufferUsage, kBufferUsageExp, key);
});
g.test('TextureUsage').fn(t => {
const expected = {
COPY_SRC: 0x01,
COPY_DST: 0x02,
SAMPLED: 0x04,
STORAGE: 0x08,
OUTPUT_ATTACHMENT: 0x10,
};
const kTextureUsageExp = {
COPY_SRC: 0x01,
COPY_DST: 0x02,
SAMPLED: 0x04,
STORAGE: 0x08,
OUTPUT_ATTACHMENT: 0x10,
};
t.assertMembers(GPUTextureUsage, expected);
g.test('TextureUsage,count').fn(t => {
t.assertMemberCount(GPUTextureUsage, kTextureUsageExp);
});
g.test('TextureUsage,values')
.params(poptions('key', Object.keys(kTextureUsageExp)))
.fn(t => {
const { key } = t.params;
t.assertMember(GPUTextureUsage, kTextureUsageExp, key);
});
g.test('ColorWrite').fn(t => {
const expected = {
RED: 0x1,
GREEN: 0x2,
BLUE: 0x4,
ALPHA: 0x8,
ALL: 0xf,
};
const kColorWriteExp = {
RED: 0x1,
GREEN: 0x2,
BLUE: 0x4,
ALPHA: 0x8,
ALL: 0xf,
};
t.assertMembers(GPUColorWrite, expected);
g.test('ColorWrite,count').fn(t => {
t.assertMemberCount(GPUColorWrite, kColorWriteExp);
});
g.test('ColorWrite,values')
.params(poptions('key', Object.keys(kColorWriteExp)))
.fn(t => {
const { key } = t.params;
t.assertMember(GPUColorWrite, kColorWriteExp, key);
});
g.test('ShaderStage').fn(t => {
const expected = {
VERTEX: 0x1,
FRAGMENT: 0x2,
COMPUTE: 0x4,
};
const kShaderStageExp = {
VERTEX: 0x1,
FRAGMENT: 0x2,
COMPUTE: 0x4,
};
t.assertMembers(GPUShaderStage, expected);
g.test('ShaderStage,count').fn(t => {
t.assertMemberCount(GPUShaderStage, kShaderStageExp);
});
g.test('ShaderStage,values')
.params(poptions('key', Object.keys(kShaderStageExp)))
.fn(t => {
const { key } = t.params;
t.assertMember(GPUShaderStage, kShaderStageExp, key);
});

View file

@ -4,18 +4,24 @@
import { assert } from '../../common/framework/util/util.js';
export class IDLTest extends Fixture {
// TODO: add a helper to check prototype chains
/**
* Asserts that an IDL interface has the expected members.
* Asserts that a member of an IDL interface has the expected value.
*/
// TODO: exp should allow sentinel markers for unnameable values, such as methods and attributes
// TODO: handle extensions
// TODO: check prototype chains (maybe as separate method)
assertMembers(act, exp) {
assertMember(act, exp, key) {
assert(key in act, () => `Expected key ${key} missing`);
assert(act[key] === exp[key], () => `Value of [${key}] was ${act[key]}, expected ${exp[key]}`);
}
/**
* Asserts that an IDL interface has the same number of keys as the
*
* TODO: add a way to check for the types of keys with unknown values, like methods and attributes
* TODO: handle extensions
*/
assertMemberCount(act, exp) {
const expKeys = Object.keys(exp);
for (const k of expKeys) {
assert(k in act, () => `Expected key ${k} missing`);
assert(act[k] === exp[k], () => `Value of [${k}] was ${act[k]}, expected ${exp[k]}`);
}
const actKeys = Object.keys(act);
assert(
actKeys.length === expKeys.length,

View file

@ -121,6 +121,40 @@ export const listing = [
],
"readme": "Positive and negative tests for all the validation rules of the API."
},
{
"file": [
"api",
"validation",
"copyBufferToBuffer"
],
"description": "copyBufferToBuffer tests.\n\nTest Plan:\n* Buffer is valid/invalid\n - the source buffer is invalid\n - the destination buffer is invalid\n* Buffer usages\n - the source buffer is created without GPUBufferUsage::COPY_SRC\n - the destination buffer is created without GPUBufferUsage::COPY_DEST\n* CopySize\n - copySize is not a multiple of 4\n - copySize is 0\n* copy offsets\n - sourceOffset is not a multiple of 4\n - destinationOffset is not a multiple of 4\n* Arthimetic overflow\n - (sourceOffset + copySize) is overflow\n - (destinationOffset + copySize) is overflow\n* Out of bounds\n - (sourceOffset + copySize) > size of source buffer\n - (destinationOffset + copySize) > size of destination buffer\n* Source buffer and destination buffer are the same buffer"
},
{
"file": [
"api",
"validation",
"copy_between_linear_data_and_texture"
],
"readme": "writeTexture + copyBufferToTexture + copyTextureToBuffer validation tests.\n\nTest coverage:\n* resource usages:\n\t- texture_usage_must_be_valid: for GPUTextureUsage::COPY_SRC, GPUTextureUsage::COPY_DST flags.\n\t- TODO: buffer_usage_must_be_valid\n\n* textureCopyView:\n\t- texture_must_be_valid: for valid, destroyed, error textures.\n\t- sample_count_must_be_1: for sample count 1 and 4.\n\t- mip_level_must_be_in_range: for various combinations of mipLevel and mipLevelCount.\n\t- texel_block_alignment_on_origin: for all formats and coordinates.\n\n* bufferCopyView:\n\t- TODO: buffer_must_be_valid\n\t- TODO: bytes_per_row_alignment\n\n* linear texture data:\n\t- bound_on_rows_per_image: for various combinations of copyDepth (1, >1), copyHeight, rowsPerImage.\n\t- offset_plus_required_bytes_in_copy_overflow\n\t- required_bytes_in_copy: testing minimal data size and data size too small for various combinations of bytesPerRow, rowsPerImage, copyExtent and offset. for the copy method, bytesPerRow is computed as bytesInACompleteRow aligned to be a multiple of 256 + bytesPerRowPadding * 256.\n\t- texel_block_alignment_on_rows_per_image: for all formats.\n\t- texel_block_alignment_on_offset: for all formats.\n\t- bound_on_bytes_per_row: for all formats and various combinations of bytesPerRow and copyExtent. for writeTexture, bytesPerRow is computed as (blocksPerRow * blockWidth * bytesPerBlock + additionalBytesPerRow) and copyExtent.width is computed as copyWidthInBlocks * blockWidth. for the copy methods, both values are mutliplied by 256.\n\t- bound_on_offset: for various combinations of offset and dataSize.\n\n* texture copy range:\n\t- 1d_texture: copyExtent.height isn't 1, copyExtent.depth isn't 1.\n\t- texel_block_alignment_on_size: for all formats and coordinates.\n\t- texture_range_conditons: for all coordinate and various combinations of origin, copyExtent, textureSize and mipLevel.\n\nTODO: more test coverage for 1D and 3D textures."
},
{
"file": [
"api",
"validation",
"copy_between_linear_data_and_texture",
"copyBetweenLinearDataAndTexture_dataRelated"
],
"description": ""
},
{
"file": [
"api",
"validation",
"copy_between_linear_data_and_texture",
"copyBetweenLinearDataAndTexture_textureRelated"
],
"description": ""
},
{
"file": [
"api",
@ -218,7 +252,7 @@ export const listing = [
"resource_usages",
"textureUsageInRender"
],
"description": "Texture Usages Validation Tests in Render Pass.\n\nTest Coverage:\n - Tests that read and write usages upon the same texture subresource, or different subresources\n of the same texture. Different subresources of the same texture includes different mip levels,\n different array layers, and different aspects.\n - When read and write usages are binding to the same texture subresource, an error should be\n generated. Otherwise, no error should be generated."
"description": "Texture Usages Validation Tests in Render Pass.\n\nTest Coverage:\n\n - For each combination of two texture usages:\n - For various subresource ranges (different mip levels or array layers) that overlap a given\n subresources or not for color formats:\n - Check that an error is generated when read-write or write-write usages are binding to the\n same texture subresource. Otherwise, no error should be generated. One exception is race\n condition upon two writeonly-storage-texture usages, which is valid.\n\n - For each combination of two texture usages:\n - For various aspects (all, depth-only, stencil-only) that overlap a given subresources or not\n for depth/stencil formats:\n - Check that an error is generated when read-write or write-write usages are binding to the\n same aspect. Otherwise, no error should be generated.\n\n - Test combinations of two shader stages:\n - Texture usages in bindings with invisible shader stages should be tracked. Invisible shader\n stages include shader stage with visibility none and compute shader stage in render pass."
},
{
"file": [

View file

@ -7,3 +7,5 @@
export function isAligned(n, alignment) {
return n === align(n, alignment);
}
export const kMaxSafeMultipleOf8 = Number.MAX_SAFE_INTEGER - 7;

View file

@ -1,7 +1,7 @@
/**
* AUTO-GENERATED - DO NOT EDIT. Source: https://github.com/gpuweb/cts
**/ import { assert, unreachable } from '../../../common/framework/util/util.js';
import { kTextureFormatInfo } from '../../capability_info.js';
import { kSizedTextureFormatInfo } from '../../capability_info.js';
import { align, isAligned } from '../math.js';
export const kBytesPerRowAlignment = 256;
@ -30,8 +30,7 @@ export function getTextureCopyLayout(format, dimension, size, options = kDefault
const mipSize = getMipSizePassthroughLayers(dimension, size, mipLevel);
const { blockWidth, blockHeight, bytesPerBlock } = kTextureFormatInfo[format];
assert(!!bytesPerBlock && !!blockWidth && !!blockHeight);
const { blockWidth, blockHeight, bytesPerBlock } = kSizedTextureFormatInfo[format];
assert(isAligned(mipSize[0], blockWidth));
const minBytesPerRow = (mipSize[0] / blockWidth) * bytesPerBlock;
@ -73,8 +72,7 @@ export function fillTextureDataWithTexelValue(
size,
options = kDefaultLayoutOptions
) {
const { blockWidth, blockHeight, bytesPerBlock } = kTextureFormatInfo[format];
assert(!!bytesPerBlock && !!blockWidth && !!blockHeight);
const { blockWidth, blockHeight, bytesPerBlock } = kSizedTextureFormatInfo[format];
assert(bytesPerBlock === texelValue.byteLength);
const { byteLength, rowsPerImage, bytesPerRow } = getTextureCopyLayout(

View file

@ -14,7 +14,7 @@
return obj;
}
import { assert, unreachable } from '../../../common/framework/util/util.js';
import { kTextureFormatInfo } from '../../capability_info.js';
import { kUncompressedTextureFormatInfo } from '../../capability_info.js';
import {
assertInIntegerRange,
float32ToFloatBits,
@ -333,7 +333,7 @@ class TexelDataRepresentationImpl {
];
}
const bytesPerBlock = kTextureFormatInfo[this.format].bytesPerBlock;
const bytesPerBlock = kUncompressedTextureFormatInfo[this.format].bytesPerBlock;
assert(!!bytesPerBlock);
const data = new ArrayBuffer(bytesPerBlock);

View file

@ -6,7 +6,7 @@ copy imageBitmap To texture tests.
import { poptions, params } from '../../common/framework/params_builder.js';
import { makeTestGroup } from '../../common/framework/test_group.js';
import { unreachable } from '../../common/framework/util/util.js';
import { kTextureFormatInfo } from '../capability_info.js';
import { kUncompressedTextureFormatInfo } from '../capability_info.js';
import { GPUTest } from '../gpu_test.js';
import { getTexelDataRepresentation } from '../util/texture/texelData.js';
@ -220,13 +220,14 @@ g.test('from_ImageData')
.fn(async t => {
const { width, height, alpha, orientation, dstColorFormat } = t.params;
const srcBytesPerPixel = kTextureFormatInfo['rgba8unorm'].bytesPerBlock;
const format = 'rgba8unorm';
const srcBytesPerPixel = kUncompressedTextureFormatInfo[format].bytesPerBlock;
// Generate input contents by iterating 'Color' enum
const imagePixels = new Uint8ClampedArray(srcBytesPerPixel * width * height);
const startPixel = Color.Red;
for (let i = 0, currentPixel = startPixel; i < width * height; ++i) {
const pixels = t.generatePixel(currentPixel, 'rgba8unorm');
const pixels = t.generatePixel(currentPixel, format);
if (currentPixel === Color.TransparentBlack) {
currentPixel = Color.Red;
} else {
@ -257,7 +258,7 @@ g.test('from_ImageData')
});
// Construct expected value for different dst color format
const dstBytesPerPixel = kTextureFormatInfo[dstColorFormat].bytesPerBlock;
const dstBytesPerPixel = kUncompressedTextureFormatInfo[dstColorFormat].bytesPerBlock;
const dstPixels = new Uint8ClampedArray(dstBytesPerPixel * width * height);
let expectedPixels = new Uint8ClampedArray(dstBytesPerPixel * width * height);
for (let i = 0, currentPixel = startPixel; i < width * height; ++i) {

View file

@ -9,7 +9,9 @@ export async function runRefTest(fn) {
);
const adapter = await navigator.gpu.requestAdapter();
assert(adapter !== null);
const device = await adapter.requestDevice();
assert(device !== null);
const queue = device.defaultQueue;
await fn({ device, queue });