Add GPUSampler and GPUTextureView to BindingResource

Add validation for BindGroups
This commit is contained in:
Kunal Mohan 2020-06-02 15:36:08 +05:30
parent abc3ed40c9
commit 00b3f785c4
12 changed files with 591 additions and 123 deletions

View file

@ -3,36 +3,81 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::GPUBindGroupBinding::GPUBindGroupMethods; use crate::dom::bindings::codegen::Bindings::GPUBindGroupBinding::{
GPUBindGroupEntry, GPUBindGroupMethods,
};
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gpubindgrouplayout::GPUBindGroupLayout;
use crate::dom::gpubuffer::GPUBuffer;
use crate::dom::gputextureview::TextureSubresource;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use std::cell::Cell; use std::cell::Cell;
use webgpu::WebGPUBindGroup; use std::collections::HashMap;
use webgpu::{WebGPUBindGroup, WebGPUDevice};
#[dom_struct] #[dom_struct]
pub struct GPUBindGroup { pub struct GPUBindGroup {
reflector_: Reflector, reflector_: Reflector,
label: DomRefCell<Option<DOMString>>, label: DomRefCell<Option<DOMString>>,
bind_group: WebGPUBindGroup, bind_group: WebGPUBindGroup,
device: WebGPUDevice,
layout: Dom<GPUBindGroupLayout>,
#[ignore_malloc_size_of = "defined in webgpu"]
entries: Vec<GPUBindGroupEntry>,
used_buffers: HashMap<Dom<GPUBuffer>, u32>,
used_textures: HashMap<TextureSubresource, u32>,
valid: Cell<bool>, valid: Cell<bool>,
} }
impl GPUBindGroup { impl GPUBindGroup {
fn new_inherited(bind_group: WebGPUBindGroup, valid: bool) -> Self { fn new_inherited(
bind_group: WebGPUBindGroup,
device: WebGPUDevice,
valid: bool,
entries: Vec<GPUBindGroupEntry>,
layout: &GPUBindGroupLayout,
used_buffers: HashMap<DomRoot<GPUBuffer>, u32>,
used_textures: HashMap<TextureSubresource, u32>,
) -> Self {
Self { Self {
reflector_: Reflector::new(), reflector_: Reflector::new(),
label: DomRefCell::new(None), label: DomRefCell::new(None),
bind_group, bind_group,
device,
valid: Cell::new(valid), valid: Cell::new(valid),
layout: Dom::from_ref(layout),
entries,
used_buffers: used_buffers
.into_iter()
.map(|(key, value)| (Dom::from_ref(&*key), value))
.collect(),
used_textures,
} }
} }
pub fn new(global: &GlobalScope, bind_group: WebGPUBindGroup, valid: bool) -> DomRoot<Self> { pub fn new(
global: &GlobalScope,
bind_group: WebGPUBindGroup,
device: WebGPUDevice,
valid: bool,
entries: Vec<GPUBindGroupEntry>,
layout: &GPUBindGroupLayout,
used_buffers: HashMap<DomRoot<GPUBuffer>, u32>,
used_textures: HashMap<TextureSubresource, u32>,
) -> DomRoot<Self> {
reflect_dom_object( reflect_dom_object(
Box::new(GPUBindGroup::new_inherited(bind_group, valid)), Box::new(GPUBindGroup::new_inherited(
bind_group,
device,
valid,
entries,
layout,
used_buffers,
used_textures,
)),
global, global,
) )
} }

View file

@ -12,6 +12,7 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use std::cell::Cell; use std::cell::Cell;
use std::collections::HashMap;
use webgpu::{WebGPU, WebGPUBindGroupLayout}; use webgpu::{WebGPU, WebGPUBindGroupLayout};
#[dom_struct] #[dom_struct]
@ -20,7 +21,7 @@ pub struct GPUBindGroupLayout {
label: DomRefCell<Option<DOMString>>, label: DomRefCell<Option<DOMString>>,
bind_group_layout: WebGPUBindGroupLayout, bind_group_layout: WebGPUBindGroupLayout,
#[ignore_malloc_size_of = "defined in webgpu"] #[ignore_malloc_size_of = "defined in webgpu"]
bindings: Vec<GPUBindGroupLayoutEntry>, entry_map: HashMap<u32, GPUBindGroupLayoutEntry>,
#[ignore_malloc_size_of = "defined in webgpu"] #[ignore_malloc_size_of = "defined in webgpu"]
channel: WebGPU, channel: WebGPU,
valid: Cell<bool>, valid: Cell<bool>,
@ -30,7 +31,7 @@ impl GPUBindGroupLayout {
fn new_inherited( fn new_inherited(
channel: WebGPU, channel: WebGPU,
bind_group_layout: WebGPUBindGroupLayout, bind_group_layout: WebGPUBindGroupLayout,
bindings: Vec<GPUBindGroupLayoutEntry>, entry_map: HashMap<u32, GPUBindGroupLayoutEntry>,
valid: bool, valid: bool,
) -> Self { ) -> Self {
Self { Self {
@ -38,7 +39,7 @@ impl GPUBindGroupLayout {
channel, channel,
label: DomRefCell::new(None), label: DomRefCell::new(None),
bind_group_layout, bind_group_layout,
bindings, entry_map,
valid: Cell::new(valid), valid: Cell::new(valid),
} }
} }
@ -47,14 +48,14 @@ impl GPUBindGroupLayout {
global: &GlobalScope, global: &GlobalScope,
channel: WebGPU, channel: WebGPU,
bind_group_layout: WebGPUBindGroupLayout, bind_group_layout: WebGPUBindGroupLayout,
bindings: Vec<GPUBindGroupLayoutEntry>, entry_map: HashMap<u32, GPUBindGroupLayoutEntry>,
valid: bool, valid: bool,
) -> DomRoot<Self> { ) -> DomRoot<Self> {
reflect_dom_object( reflect_dom_object(
Box::new(GPUBindGroupLayout::new_inherited( Box::new(GPUBindGroupLayout::new_inherited(
channel, channel,
bind_group_layout, bind_group_layout,
bindings, entry_map,
valid, valid,
)), )),
global, global,
@ -71,8 +72,8 @@ impl GPUBindGroupLayout {
self.bind_group_layout self.bind_group_layout
} }
pub fn bindings(&self) -> &[GPUBindGroupLayoutEntry] { pub fn entries(&self) -> &HashMap<u32, GPUBindGroupLayoutEntry> {
&self.bindings &self.entry_map
} }
} }

View file

@ -110,7 +110,7 @@ impl GPUBuffer {
self.state.borrow() self.state.borrow()
} }
pub fn valid(&self) -> bool { pub fn is_valid(&self) -> bool {
self.valid.get() self.valid.get()
} }
} }

View file

@ -240,8 +240,8 @@ impl GPUCommandEncoderMethods for GPUCommandEncoder {
None => false, None => false,
}; };
valid &= (*self.state.borrow() == GPUCommandEncoderState::Open) && valid &= (*self.state.borrow() == GPUCommandEncoderState::Open) &&
source.valid() && source.is_valid() &&
destination.valid() & destination.is_valid() &
!(size & BUFFER_COPY_ALIGN_MASK == 0) & !(size & BUFFER_COPY_ALIGN_MASK == 0) &
!(source_offset & BUFFER_COPY_ALIGN_MASK == 0) & !(source_offset & BUFFER_COPY_ALIGN_MASK == 0) &
!(destination_offset & BUFFER_COPY_ALIGN_MASK == 0) & !(destination_offset & BUFFER_COPY_ALIGN_MASK == 0) &

View file

@ -6,11 +6,14 @@
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::GPULimits; use crate::dom::bindings::codegen::Bindings::GPUAdapterBinding::GPULimits;
use crate::dom::bindings::codegen::Bindings::GPUBindGroupBinding::GPUBindGroupDescriptor; use crate::dom::bindings::codegen::Bindings::GPUBindGroupBinding::{
GPUBindGroupDescriptor, GPUBindGroupEntry, GPUBindingResource, GPUBufferBindings,
};
use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{ use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{
GPUBindGroupLayoutDescriptor, GPUBindGroupLayoutEntry, GPUBindingType, GPUBindGroupLayoutDescriptor, GPUBindGroupLayoutEntry, GPUBindingType,
}; };
use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::GPUBufferDescriptor; use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::GPUBufferDescriptor;
use crate::dom::bindings::codegen::Bindings::GPUBufferUsageBinding::GPUBufferUsageConstants;
use crate::dom::bindings::codegen::Bindings::GPUComputePipelineBinding::GPUComputePipelineDescriptor; use crate::dom::bindings::codegen::Bindings::GPUComputePipelineBinding::GPUComputePipelineDescriptor;
use crate::dom::bindings::codegen::Bindings::GPUDeviceBinding::{ use crate::dom::bindings::codegen::Bindings::GPUDeviceBinding::{
GPUCommandEncoderDescriptor, GPUDeviceMethods, GPUCommandEncoderDescriptor, GPUDeviceMethods,
@ -29,6 +32,7 @@ use crate::dom::bindings::codegen::Bindings::GPUTextureBinding::{
GPUExtent3D, GPUExtent3DDict, GPUTextureComponentType, GPUTextureDescriptor, GPUExtent3D, GPUExtent3DDict, GPUTextureComponentType, GPUTextureDescriptor,
GPUTextureDimension, GPUTextureFormat, GPUTextureDimension, GPUTextureFormat,
}; };
use crate::dom::bindings::codegen::Bindings::GPUTextureUsageBinding::GPUTextureUsageConstants;
use crate::dom::bindings::codegen::Bindings::GPUTextureViewBinding::GPUTextureViewDimension; use crate::dom::bindings::codegen::Bindings::GPUTextureViewBinding::GPUTextureViewDimension;
use crate::dom::bindings::codegen::UnionTypes::Uint32ArrayOrString::{String, Uint32Array}; use crate::dom::bindings::codegen::UnionTypes::Uint32ArrayOrString::{String, Uint32Array};
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
@ -49,13 +53,14 @@ use crate::dom::gpurenderpipeline::GPURenderPipeline;
use crate::dom::gpusampler::GPUSampler; use crate::dom::gpusampler::GPUSampler;
use crate::dom::gpushadermodule::GPUShaderModule; use crate::dom::gpushadermodule::GPUShaderModule;
use crate::dom::gputexture::GPUTexture; use crate::dom::gputexture::GPUTexture;
use crate::dom::gputextureview::{GPUTextureView, TextureSubresource};
use crate::script_runtime::JSContext as SafeJSContext; use crate::script_runtime::JSContext as SafeJSContext;
use arrayvec::ArrayVec; use arrayvec::ArrayVec;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject}; use js::jsapi::{Heap, JSObject};
use js::jsval::{JSVal, ObjectValue}; use js::jsval::{JSVal, ObjectValue};
use js::typedarray::{ArrayBuffer, CreateWith}; use js::typedarray::{ArrayBuffer, CreateWith};
use std::collections::{HashMap, HashSet}; use std::collections::{hash_map::Entry, HashMap, HashSet};
use std::ptr::{self, NonNull}; use std::ptr::{self, NonNull};
use webgpu::wgpu::binding_model::{ use webgpu::wgpu::binding_model::{
BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, BufferBinding, BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, BufferBinding,
@ -153,6 +158,81 @@ impl GPUDevice {
) )
} }
} }
fn validate_texture_view_binding(
&self,
texture_view: &GPUTextureView,
binding: &GPUBindGroupLayoutEntry,
) -> bool {
let mut valid = if let Some(d) = binding.viewDimension {
texture_view.descriptor().dimension.unwrap() == d
} else {
false
};
let view_component = get_component_from_format(texture_view.descriptor().format.unwrap());
valid &= if let Some(c) = binding.textureComponentType {
view_component == c
} else {
false
};
valid &= if binding.multisampled {
texture_view.texture().sample_count() > 1
} else {
texture_view.texture().sample_count() == 1
};
valid &= match binding.type_ {
GPUBindingType::Sampled_texture => {
match wgt::TextureUsage::from_bits(texture_view.texture().usage()) {
Some(u) => u.contains(wgt::TextureUsage::SAMPLED),
None => false,
}
},
GPUBindingType::Readonly_storage_texture |
GPUBindingType::Writeonly_storage_texture => {
match wgt::TextureUsage::from_bits(texture_view.texture().usage()) {
Some(u) => u.contains(wgt::TextureUsage::STORAGE),
None => false,
}
},
_ => false,
};
valid
}
fn validate_buffer_binding(
&self,
buffer_bind: &GPUBufferBindings,
binding: &GPUBindGroupLayoutEntry,
) -> bool {
let mut valid = match binding.type_ {
GPUBindingType::Uniform_buffer => {
match wgt::BufferUsage::from_bits(buffer_bind.buffer.usage()) {
Some(u) => {
let v = if let Some(s) = buffer_bind.size {
s <= GPULimits::empty().maxUniformBufferBindingSize.into()
} else {
true
};
v && u.contains(wgt::BufferUsage::UNIFORM)
},
None => false,
}
},
GPUBindingType::Storage_buffer | GPUBindingType::Readonly_storage_buffer => {
match wgt::BufferUsage::from_bits(buffer_bind.buffer.usage()) {
Some(u) => u.contains(wgt::BufferUsage::STORAGE),
None => false,
}
},
_ => false,
};
valid &= if let Some(s) = buffer_bind.size {
buffer_bind.offset + s <= buffer_bind.buffer.size() && buffer_bind.offset > 0
} else {
buffer_bind.offset > 0 && buffer_bind.offset < buffer_bind.buffer.size()
};
valid
}
} }
impl GPUDeviceMethods for GPUDevice { impl GPUDeviceMethods for GPUDevice {
@ -303,11 +383,10 @@ impl GPUDeviceMethods for GPUDevice {
limits.maxDynamicStorageBuffersPerPipelineLayout as i32; limits.maxDynamicStorageBuffersPerPipelineLayout as i32;
let mut valid = true; let mut valid = true;
let bindings = descriptor let entries = descriptor
.entries .entries
.iter() .iter()
.map(|bind| { .map(|bind| {
// TODO: binding must be >= 0
storeBindings.insert(bind.binding); storeBindings.insert(bind.binding);
let visibility = match wgt::ShaderStage::from_bits(bind.visibility) { let visibility = match wgt::ShaderStage::from_bits(bind.visibility) {
Some(visibility) => visibility, Some(visibility) => visibility,
@ -324,6 +403,10 @@ impl GPUDeviceMethods for GPUDevice {
if bind.hasDynamicOffset { if bind.hasDynamicOffset {
max_dynamic_uniform_buffers_per_pipeline_layout -= 1; max_dynamic_uniform_buffers_per_pipeline_layout -= 1;
}; };
valid &= bind.viewDimension.is_none() &&
bind.textureComponentType.is_none() &&
!bind.multisampled &&
bind.storageTextureFormat.is_none();
BindingType::UniformBuffer BindingType::UniformBuffer
}, },
GPUBindingType::Storage_buffer => { GPUBindingType::Storage_buffer => {
@ -333,6 +416,11 @@ impl GPUDeviceMethods for GPUDevice {
if bind.hasDynamicOffset { if bind.hasDynamicOffset {
max_dynamic_storage_buffers_per_pipeline_layout -= 1; max_dynamic_storage_buffers_per_pipeline_layout -= 1;
}; };
valid &= bind.viewDimension.is_none() &&
!visibility.contains(wgt::ShaderStage::VERTEX) &&
bind.textureComponentType.is_none() &&
!bind.multisampled &&
bind.storageTextureFormat.is_none();
BindingType::StorageBuffer BindingType::StorageBuffer
}, },
GPUBindingType::Readonly_storage_buffer => { GPUBindingType::Readonly_storage_buffer => {
@ -342,44 +430,59 @@ impl GPUDeviceMethods for GPUDevice {
if bind.hasDynamicOffset { if bind.hasDynamicOffset {
max_dynamic_storage_buffers_per_pipeline_layout -= 1; max_dynamic_storage_buffers_per_pipeline_layout -= 1;
}; };
valid &= bind.viewDimension.is_none() &&
bind.textureComponentType.is_none() &&
!bind.multisampled &&
bind.storageTextureFormat.is_none();
BindingType::ReadonlyStorageBuffer BindingType::ReadonlyStorageBuffer
}, },
GPUBindingType::Sampled_texture => { GPUBindingType::Sampled_texture => {
if let Some(limit) = validation_map.get_mut(&visibility) { if let Some(limit) = validation_map.get_mut(&visibility) {
limit.max_sampled_textures_per_shader_stage -= 1; limit.max_sampled_textures_per_shader_stage -= 1;
} }
if bind.hasDynamicOffset { valid &= !bind.hasDynamicOffset && bind.storageTextureFormat.is_none();
valid = false
};
BindingType::SampledTexture BindingType::SampledTexture
}, },
GPUBindingType::Readonly_storage_texture => { GPUBindingType::Readonly_storage_texture => {
if let Some(limit) = validation_map.get_mut(&visibility) { if let Some(limit) = validation_map.get_mut(&visibility) {
limit.max_storage_textures_per_shader_stage -= 1; limit.max_storage_textures_per_shader_stage -= 1;
} }
if bind.hasDynamicOffset { valid &= !bind.hasDynamicOffset &&
valid = false bind.textureComponentType.is_none() &&
}; !bind.multisampled;
BindingType::ReadonlyStorageTexture BindingType::ReadonlyStorageTexture
}, },
GPUBindingType::Writeonly_storage_texture => { GPUBindingType::Writeonly_storage_texture => {
if let Some(limit) = validation_map.get_mut(&visibility) { if let Some(limit) = validation_map.get_mut(&visibility) {
limit.max_storage_textures_per_shader_stage -= 1; limit.max_storage_textures_per_shader_stage -= 1;
} }
if bind.hasDynamicOffset { valid &= !bind.hasDynamicOffset &&
valid = false bind.textureComponentType.is_none() &&
}; !bind.multisampled;
BindingType::WriteonlyStorageTexture BindingType::WriteonlyStorageTexture
}, },
GPUBindingType::Sampler => { GPUBindingType::Sampler => {
if let Some(limit) = validation_map.get_mut(&visibility) { if let Some(limit) = validation_map.get_mut(&visibility) {
limit.max_samplers_per_shader_stage -= 1; limit.max_samplers_per_shader_stage -= 1;
} }
if bind.hasDynamicOffset { valid &= !bind.hasDynamicOffset &&
valid = false bind.viewDimension.is_none() &&
}; bind.textureComponentType.is_none() &&
!bind.multisampled &&
bind.storageTextureFormat.is_none();
BindingType::Sampler BindingType::Sampler
}, },
GPUBindingType::Comparison_sampler => {
if let Some(limit) = validation_map.get_mut(&visibility) {
limit.max_samplers_per_shader_stage -= 1;
}
valid &= !bind.hasDynamicOffset &&
bind.viewDimension.is_none() &&
bind.textureComponentType.is_none() &&
!bind.multisampled &&
bind.storageTextureFormat.is_none();
BindingType::ComparisonSampler
},
}; };
BindGroupLayoutEntry { BindGroupLayoutEntry {
@ -388,22 +491,30 @@ impl GPUDeviceMethods for GPUDevice {
ty, ty,
has_dynamic_offset: bind.hasDynamicOffset, has_dynamic_offset: bind.hasDynamicOffset,
multisampled: bind.multisampled, multisampled: bind.multisampled,
texture_component_type: match bind.textureComponentType { texture_component_type: if let Some(c) = bind.textureComponentType {
GPUTextureComponentType::Float => wgt::TextureComponentType::Float, match c {
GPUTextureComponentType::Sint => wgt::TextureComponentType::Sint, GPUTextureComponentType::Float => wgt::TextureComponentType::Float,
GPUTextureComponentType::Uint => wgt::TextureComponentType::Uint, GPUTextureComponentType::Sint => wgt::TextureComponentType::Sint,
GPUTextureComponentType::Uint => wgt::TextureComponentType::Uint,
}
} else {
wgt::TextureComponentType::Float
}, },
storage_texture_format: match bind.storageTextureFormat { storage_texture_format: match bind.storageTextureFormat {
Some(s) => convert_texture_format(s), Some(s) => convert_texture_format(s),
None => wgt::TextureFormat::Bgra8UnormSrgb, None => wgt::TextureFormat::Bgra8UnormSrgb,
}, },
view_dimension: convert_texture_view_dimension(bind.viewDimension), view_dimension: bind
.viewDimension
.map_or(wgt::TextureViewDimension::D2, |v| {
convert_texture_view_dimension(v)
}),
} }
}) })
.collect::<Vec<BindGroupLayoutEntry>>(); .collect::<Vec<BindGroupLayoutEntry>>();
// bindings are unique // bindings are unique
valid &= storeBindings.len() == bindings.len(); valid &= storeBindings.len() == entries.len();
// Ensure that values do not exceed the max limit for each ShaderStage. // Ensure that values do not exceed the max limit for each ShaderStage.
valid &= validation_map.values().all(|stage| { valid &= validation_map.values().all(|stage| {
@ -428,26 +539,28 @@ impl GPUDeviceMethods for GPUDevice {
.send(WebGPURequest::CreateBindGroupLayout { .send(WebGPURequest::CreateBindGroupLayout {
device_id: self.device.0, device_id: self.device.0,
bind_group_layout_id, bind_group_layout_id,
bindings: bindings.clone(), entries: entries.clone(),
}) })
.expect("Failed to create WebGPU BindGroupLayout"); .expect("Failed to create WebGPU BindGroupLayout");
let bgl = webgpu::WebGPUBindGroupLayout(bind_group_layout_id); let bgl = webgpu::WebGPUBindGroupLayout(bind_group_layout_id);
let binds = descriptor let mut binds = HashMap::new();
.entries descriptor.entries.iter().for_each(|bind| {
.iter() binds.insert(
.map(|bind| GPUBindGroupLayoutEntry { bind.binding,
binding: bind.binding, GPUBindGroupLayoutEntry {
hasDynamicOffset: bind.hasDynamicOffset, binding: bind.binding,
multisampled: bind.multisampled, hasDynamicOffset: bind.hasDynamicOffset,
type_: bind.type_, multisampled: bind.multisampled,
visibility: bind.visibility, type_: bind.type_,
viewDimension: bind.viewDimension, visibility: bind.visibility,
textureComponentType: bind.textureComponentType, viewDimension: bind.viewDimension,
storageTextureFormat: bind.storageTextureFormat, textureComponentType: bind.textureComponentType,
}) storageTextureFormat: bind.storageTextureFormat,
.collect::<Vec<_>>(); },
);
});
GPUBindGroupLayout::new(&self.global(), self.channel.clone(), bgl, binds, valid) GPUBindGroupLayout::new(&self.global(), self.channel.clone(), bgl, binds, valid)
} }
@ -471,7 +584,7 @@ impl GPUDeviceMethods for GPUDevice {
bind_group_layouts.push(id); bind_group_layouts.push(id);
bgl_ids.push(id.0); bgl_ids.push(id.0);
} }
each.bindings().iter().for_each(|bind| { each.entries().values().for_each(|bind| {
match bind.type_ { match bind.type_ {
GPUBindingType::Uniform_buffer => { GPUBindingType::Uniform_buffer => {
if bind.hasDynamicOffset { if bind.hasDynamicOffset {
@ -518,10 +631,11 @@ impl GPUDeviceMethods for GPUDevice {
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbindgroup /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createbindgroup
fn CreateBindGroup(&self, descriptor: &GPUBindGroupDescriptor) -> DomRoot<GPUBindGroup> { fn CreateBindGroup(&self, descriptor: &GPUBindGroupDescriptor) -> DomRoot<GPUBindGroup> {
let alignment: u64 = 256; //let alignment: u64 = 256;
let mut valid = descriptor.layout.bindings().len() == descriptor.entries.len(); let mut valid = descriptor.layout.is_valid() &&
descriptor.layout.entries().len() == descriptor.entries.len();
valid &= descriptor.entries.iter().all(|bind| { /*valid &= descriptor.entries.iter().all(|bind| {
let buffer_size = bind.resource.buffer.size(); let buffer_size = bind.resource.buffer.size();
let resource_size = bind.resource.size.unwrap_or(buffer_size); let resource_size = bind.resource.size.unwrap_or(buffer_size);
let length = bind.resource.offset.checked_add(resource_size); let length = bind.resource.offset.checked_add(resource_size);
@ -531,32 +645,149 @@ impl GPUDeviceMethods for GPUDevice {
buffer_size >= length.unwrap() && // check buffer OOB buffer_size >= length.unwrap() && // check buffer OOB
bind.resource.offset % alignment == 0 && // check alignment bind.resource.offset % alignment == 0 && // check alignment
bind.resource.offset < buffer_size && // on Vulkan offset must be less than size of buffer bind.resource.offset < buffer_size && // on Vulkan offset must be less than size of buffer
descriptor.layout.bindings().iter().any(|layout_bind| { descriptor.layout.entries().iter().any(|layout_bind| {
let ty = match layout_bind.type_ { match layout_bind.type_ {
GPUBindingType::Storage_buffer => wgt::BufferUsage::STORAGE, GPUBindingType::Storage_buffer => usage.contains(wgt::BufferUsage::STORAGE),
// GPUBindingType::Readonly_storage_buffer => BufferUsage::STORAGE_READ, // GPUBindingType::Readonly_storage_buffer => BufferUsage::STORAGE_READ,
GPUBindingType::Uniform_buffer => wgt::BufferUsage::UNIFORM, GPUBindingType::Uniform_buffer => usage.contains(wgt::BufferUsage::UNIFORM),
GPUBindingType::Sampler => bind.resource
_ => unimplemented!(), _ => unimplemented!(),
}; };
// binding must be present in layout // binding must be present in layout
layout_bind.binding == bind.binding && layout_bind.binding == bind.binding
// binding must contain one buffer of its type
usage.contains(ty)
}) })
});*/
let mut bindings = HashSet::new();
let mut used_buffers = HashMap::new();
let mut used_textures = HashMap::new();
valid &= descriptor.entries.iter().all(|bind| {
bindings.insert(bind.binding);
if let Some(layout_bind) = descriptor
.layout
.entries()
.values()
.find(|lb| lb.binding == bind.binding)
{
match layout_bind.type_ {
GPUBindingType::Sampler => match bind.resource {
GPUBindingResource::GPUSampler(ref s) => s.is_valid() && !s.compare(),
_ => false,
},
GPUBindingType::Comparison_sampler => match bind.resource {
GPUBindingResource::GPUSampler(ref s) => s.is_valid() && s.compare(),
_ => false,
},
GPUBindingType::Sampled_texture => match bind.resource {
GPUBindingResource::GPUTextureView(ref t) => {
let desc = t.descriptor();
for i in desc.baseMipLevel..desc.mipLevelCount {
for j in desc.baseArrayLayer..desc.arrayLayerCount {
let subresource = TextureSubresource {
texture: DomRoot::from_ref(t.texture()),
mipmap_level: i,
array_layer: j,
};
match used_textures.entry(subresource) {
Entry::Vacant(v) => {
v.insert(GPUTextureUsageConstants::SAMPLED);
},
Entry::Occupied(mut o) => {
*o.get_mut() += GPUTextureUsageConstants::SAMPLED;
},
}
}
}
t.is_valid() && self.validate_texture_view_binding(t, layout_bind)
},
_ => false,
},
GPUBindingType::Readonly_storage_texture |
GPUBindingType::Writeonly_storage_texture => match bind.resource {
GPUBindingResource::GPUTextureView(ref t) => {
let desc = t.descriptor();
for i in desc.baseMipLevel..desc.mipLevelCount {
for j in desc.baseArrayLayer..desc.arrayLayerCount {
let subresource = TextureSubresource {
texture: DomRoot::from_ref(t.texture()),
mipmap_level: i,
array_layer: j,
};
match used_textures.entry(subresource) {
Entry::Vacant(v) => {
v.insert(GPUTextureUsageConstants::STORAGE);
},
Entry::Occupied(mut o) => {
*o.get_mut() += GPUTextureUsageConstants::STORAGE;
},
}
}
}
t.is_valid() &&
self.validate_texture_view_binding(t, layout_bind) &&
t.descriptor().format == layout_bind.storageTextureFormat
},
_ => false,
},
GPUBindingType::Uniform_buffer => match bind.resource {
GPUBindingResource::GPUBufferBindings(ref b) => {
match used_buffers.entry(DomRoot::from_ref(&*b.buffer)) {
Entry::Vacant(v) => {
v.insert(GPUBufferUsageConstants::UNIFORM);
},
Entry::Occupied(mut o) => {
*o.get_mut() += GPUBufferUsageConstants::UNIFORM;
},
}
b.buffer.is_valid() && self.validate_buffer_binding(b, layout_bind)
},
_ => false,
},
GPUBindingType::Storage_buffer | GPUBindingType::Readonly_storage_buffer => {
match bind.resource {
GPUBindingResource::GPUBufferBindings(ref b) => {
match used_buffers.entry(DomRoot::from_ref(&*b.buffer)) {
Entry::Vacant(v) => {
v.insert(GPUBufferUsageConstants::STORAGE);
},
Entry::Occupied(mut o) => {
*o.get_mut() += GPUBufferUsageConstants::STORAGE;
},
}
b.buffer.is_valid() && self.validate_buffer_binding(b, layout_bind)
},
_ => false,
}
},
}
} else {
false
}
}); });
let bindings = descriptor valid &= bindings.len() == descriptor.entries.len();
let entries = descriptor
.entries .entries
.iter() .iter()
.map(|bind| BindGroupEntry { .map(|bind| BindGroupEntry {
binding: bind.binding, binding: bind.binding,
resource: BindingResource::Buffer(BufferBinding { resource: match bind.resource {
buffer: bind.resource.buffer.id().0, GPUBindingResource::GPUSampler(ref s) => BindingResource::Sampler(s.id().0),
offset: bind.resource.offset, GPUBindingResource::GPUTextureView(ref t) => {
size: wgt::BufferSize( BindingResource::TextureView(t.id().0)
bind.resource.size.unwrap_or(bind.resource.buffer.size()), },
), GPUBindingResource::GPUBufferBindings(ref b) => {
}), BindingResource::Buffer(BufferBinding {
buffer: b.buffer.id().0,
offset: b.offset,
size: if let Some(s) = b.size {
wgt::BufferSize(s)
} else {
wgt::BufferSize::WHOLE
},
})
},
},
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
@ -571,12 +802,44 @@ impl GPUDeviceMethods for GPUDevice {
device_id: self.device.0, device_id: self.device.0,
bind_group_id, bind_group_id,
bind_group_layout_id: descriptor.layout.id().0, bind_group_layout_id: descriptor.layout.id().0,
bindings, entries,
}) })
.expect("Failed to create WebGPU BindGroup"); .expect("Failed to create WebGPU BindGroup");
let desc_entries = descriptor
.entries
.iter()
.map(|bind| GPUBindGroupEntry {
binding: bind.binding,
resource: match bind.resource {
GPUBindingResource::GPUSampler(ref s) => {
GPUBindingResource::GPUSampler(DomRoot::from_ref(&*s))
},
GPUBindingResource::GPUTextureView(ref t) => {
GPUBindingResource::GPUTextureView(DomRoot::from_ref(&*t))
},
GPUBindingResource::GPUBufferBindings(ref b) => {
GPUBindingResource::GPUBufferBindings(GPUBufferBindings {
buffer: DomRoot::from_ref(&*b.buffer),
offset: b.offset,
size: b.size,
})
},
},
})
.collect::<Vec<_>>();
let bind_group = webgpu::WebGPUBindGroup(bind_group_id); let bind_group = webgpu::WebGPUBindGroup(bind_group_id);
GPUBindGroup::new(&self.global(), bind_group, valid) GPUBindGroup::new(
&self.global(),
bind_group,
self.device,
valid,
desc_entries,
&*descriptor.layout,
used_buffers,
used_textures,
)
} }
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createshadermodule /// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createshadermodule
@ -1094,3 +1357,46 @@ fn convert_texture_size_to_wgt(size: &GPUExtent3DDict) -> wgt::Extent3d {
depth: size.depth, depth: size.depth,
} }
} }
fn get_component_from_format(format: GPUTextureFormat) -> GPUTextureComponentType {
match format {
GPUTextureFormat::R8unorm |
GPUTextureFormat::R8snorm |
GPUTextureFormat::R16float |
GPUTextureFormat::Rg8unorm |
GPUTextureFormat::Rg8snorm |
GPUTextureFormat::R32float |
GPUTextureFormat::Rg16float |
GPUTextureFormat::Rgba8unorm |
GPUTextureFormat::Rgba8unorm_srgb |
GPUTextureFormat::Rgba8snorm |
GPUTextureFormat::Bgra8unorm |
GPUTextureFormat::Bgra8unorm_srgb |
GPUTextureFormat::Rgb10a2unorm |
GPUTextureFormat::Rg11b10float |
GPUTextureFormat::Rg32float |
GPUTextureFormat::Rgba16float |
GPUTextureFormat::Rgba32float |
GPUTextureFormat::Depth32float |
GPUTextureFormat::Depth24plus |
GPUTextureFormat::Depth24plus_stencil8 => GPUTextureComponentType::Float,
GPUTextureFormat::R8uint |
GPUTextureFormat::R16uint |
GPUTextureFormat::Rg8uint |
GPUTextureFormat::R32uint |
GPUTextureFormat::Rg16uint |
GPUTextureFormat::Rgba8uint |
GPUTextureFormat::Rg32uint |
GPUTextureFormat::Rgba16uint |
GPUTextureFormat::Rgba32uint => GPUTextureComponentType::Uint,
GPUTextureFormat::R8sint |
GPUTextureFormat::R16sint |
GPUTextureFormat::Rg8sint |
GPUTextureFormat::R32sint |
GPUTextureFormat::Rg16sint |
GPUTextureFormat::Rgba8sint |
GPUTextureFormat::Rg32sint |
GPUTextureFormat::Rgba16sint |
GPUTextureFormat::Rgba32sint => GPUTextureComponentType::Sint,
}
}

View file

@ -64,6 +64,20 @@ impl GPUSampler {
} }
} }
impl GPUSampler {
pub fn id(&self) -> WebGPUSampler {
self.sampler
}
pub fn is_valid(&self) -> bool {
self.valid.get()
}
pub fn compare(&self) -> bool {
self.compare_enable
}
}
impl GPUSamplerMethods for GPUSampler { impl GPUSamplerMethods for GPUSampler {
/// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label /// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
fn GetLabel(&self) -> Option<DOMString> { fn GetLabel(&self) -> Option<DOMString> {

View file

@ -3,11 +3,12 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::GPUObjectBaseBinding::GPUObjectDescriptorBase;
use crate::dom::bindings::codegen::Bindings::GPUTextureBinding::{ use crate::dom::bindings::codegen::Bindings::GPUTextureBinding::{
GPUExtent3DDict, GPUTextureDimension, GPUTextureFormat, GPUTextureMethods, GPUExtent3DDict, GPUTextureDimension, GPUTextureFormat, GPUTextureMethods,
}; };
use crate::dom::bindings::codegen::Bindings::GPUTextureViewBinding::{ use crate::dom::bindings::codegen::Bindings::GPUTextureViewBinding::{
GPUTextureAspect, GPUTextureViewDescriptor, GPUTextureAspect, GPUTextureViewDescriptor, GPUTextureViewDimension,
}; };
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector}; use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::DomRoot;
@ -107,6 +108,14 @@ impl GPUTexture {
pub fn id(&self) -> WebGPUTexture { pub fn id(&self) -> WebGPUTexture {
self.texture self.texture
} }
pub fn sample_count(&self) -> u32 {
self.sample_count
}
pub fn usage(&self) -> u32 {
self.texture_usage
}
} }
impl GPUTextureMethods for GPUTexture { impl GPUTextureMethods for GPUTexture {
@ -122,23 +131,28 @@ impl GPUTextureMethods for GPUTexture {
/// https://gpuweb.github.io/gpuweb/#dom-gputexture-createview /// https://gpuweb.github.io/gpuweb/#dom-gputexture-createview
fn CreateView(&self, descriptor: &GPUTextureViewDescriptor) -> DomRoot<GPUTextureView> { 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 == 0 {
GPUTextureViewDimension::_2d_array
} else {
GPUTextureViewDimension::_2d
}
},
GPUTextureDimension::_3d => GPUTextureViewDimension::_3d,
}
};
let format = descriptor.format.unwrap_or(self.format);
let desc = wgt::TextureViewDescriptor { let desc = wgt::TextureViewDescriptor {
label: Default::default(), label: Default::default(),
format: convert_texture_format(descriptor.format.unwrap_or(self.format)), format: convert_texture_format(format),
dimension: match descriptor.dimension { dimension: convert_texture_view_dimension(dimension),
Some(d) => convert_texture_view_dimension(d),
None => match self.dimension {
GPUTextureDimension::_1d => wgt::TextureViewDimension::D1,
GPUTextureDimension::_2d => {
if self.texture_size.depth > 1 && descriptor.arrayLayerCount == 0 {
wgt::TextureViewDimension::D2Array
} else {
wgt::TextureViewDimension::D2
}
},
GPUTextureDimension::_3d => wgt::TextureViewDimension::D3,
},
},
aspect: match descriptor.aspect { aspect: match descriptor.aspect {
GPUTextureAspect::All => wgt::TextureAspect::All, GPUTextureAspect::All => wgt::TextureAspect::All,
GPUTextureAspect::Stencil_only => wgt::TextureAspect::StencilOnly, GPUTextureAspect::Stencil_only => wgt::TextureAspect::StencilOnly,
@ -175,7 +189,32 @@ impl GPUTextureMethods for GPUTexture {
let texture_view = WebGPUTextureView(texture_view_id); let texture_view = WebGPUTextureView(texture_view_id);
GPUTextureView::new(&self.global(), texture_view, self.device, true) let desc = GPUTextureViewDescriptor {
parent: GPUObjectDescriptorBase {
label: descriptor
.parent
.label
.as_ref()
.map(|l| l.as_ref().map(|u| u.clone())),
},
arrayLayerCount: if descriptor.arrayLayerCount == 0 {
self.texture_size.depth - descriptor.baseArrayLayer
} else {
descriptor.arrayLayerCount
},
aspect: descriptor.aspect,
baseArrayLayer: descriptor.baseArrayLayer,
baseMipLevel: descriptor.baseMipLevel,
dimension: Some(dimension),
format: Some(descriptor.format.unwrap_or(self.format)),
mipLevelCount: if descriptor.mipLevelCount == 0 {
self.mip_level_count - descriptor.baseMipLevel
} else {
descriptor.mipLevelCount
},
};
GPUTextureView::new(&self.global(), texture_view, &self, true, desc)
} }
/// https://gpuweb.github.io/gpuweb/#dom-gputexture-destroy /// https://gpuweb.github.io/gpuweb/#dom-gputexture-destroy

View file

@ -3,43 +3,85 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::GPUTextureViewBinding::GPUTextureViewDescriptor;
use crate::dom::bindings::codegen::Bindings::GPUTextureViewBinding::GPUTextureViewMethods; use crate::dom::bindings::codegen::Bindings::GPUTextureViewBinding::GPUTextureViewMethods;
use crate::dom::bindings::reflector::{reflect_dom_object, Reflector}; use crate::dom::bindings::reflector::{reflect_dom_object, Reflector};
use crate::dom::bindings::root::DomRoot; use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::bindings::str::DOMString; use crate::dom::bindings::str::DOMString;
use crate::dom::globalscope::GlobalScope; use crate::dom::globalscope::GlobalScope;
use crate::dom::gputexture::GPUTexture;
use dom_struct::dom_struct; use dom_struct::dom_struct;
use std::cell::Cell; use std::cell::Cell;
use webgpu::{WebGPUDevice, WebGPUTextureView}; use std::hash::{Hash, Hasher};
use webgpu::WebGPUTextureView;
#[derive(MallocSizeOf, JSTraceable)]
pub struct TextureSubresource {
pub texture: DomRoot<GPUTexture>,
pub mipmap_level: u32,
pub array_layer: u32,
}
impl PartialEq for TextureSubresource {
fn eq(&self, other: &Self) -> bool {
self.texture.id().0 == other.texture.id().0 &&
self.mipmap_level == other.mipmap_level &&
self.array_layer == other.array_layer
}
}
impl Eq for TextureSubresource {}
impl Hash for TextureSubresource {
fn hash<H: Hasher>(&self, state: &mut H) {
self.texture.id().0.hash(state);
self.mipmap_level.hash(state);
self.array_layer.hash(state);
}
}
#[dom_struct] #[dom_struct]
pub struct GPUTextureView { pub struct GPUTextureView {
reflector_: Reflector, reflector_: Reflector,
label: DomRefCell<Option<DOMString>>, label: DomRefCell<Option<DOMString>>,
texture_view: WebGPUTextureView, texture_view: WebGPUTextureView,
device: WebGPUDevice, texture: Dom<GPUTexture>,
valid: Cell<bool>, valid: Cell<bool>,
#[ignore_malloc_size_of = "defined in webgpu"]
descriptor: GPUTextureViewDescriptor,
} }
impl GPUTextureView { impl GPUTextureView {
fn new_inherited(texture_view: WebGPUTextureView, device: WebGPUDevice, valid: bool) -> Self { fn new_inherited(
texture_view: WebGPUTextureView,
texture: &GPUTexture,
valid: bool,
descriptor: GPUTextureViewDescriptor,
) -> GPUTextureView {
Self { Self {
reflector_: Reflector::new(), reflector_: Reflector::new(),
device, texture: Dom::from_ref(texture),
label: DomRefCell::new(None), label: DomRefCell::new(None),
texture_view, texture_view,
valid: Cell::new(valid), valid: Cell::new(valid),
descriptor,
} }
} }
pub fn new( pub fn new(
global: &GlobalScope, global: &GlobalScope,
texture_view: WebGPUTextureView, texture_view: WebGPUTextureView,
device: WebGPUDevice, texture: &GPUTexture,
valid: bool, valid: bool,
) -> DomRoot<Self> { descriptor: GPUTextureViewDescriptor,
) -> DomRoot<GPUTextureView> {
reflect_dom_object( reflect_dom_object(
Box::new(GPUTextureView::new_inherited(texture_view, device, valid)), Box::new(GPUTextureView::new_inherited(
texture_view,
texture,
valid,
descriptor,
)),
global, global,
) )
} }
@ -49,6 +91,18 @@ impl GPUTextureView {
pub fn id(&self) -> WebGPUTextureView { pub fn id(&self) -> WebGPUTextureView {
self.texture_view self.texture_view
} }
pub fn is_valid(&self) -> bool {
self.valid.get()
}
pub fn descriptor(&self) -> &GPUTextureViewDescriptor {
&self.descriptor
}
pub fn texture(&self) -> &GPUTexture {
&*self.texture
}
} }
impl GPUTextureViewMethods for GPUTextureView { impl GPUTextureViewMethods for GPUTextureView {

View file

@ -24,12 +24,13 @@ enum GPUExtensionName {
}; };
dictionary GPULimits { dictionary GPULimits {
unsigned long maxBindGroups = 4; GPUSize32 maxBindGroups = 4;
unsigned long maxDynamicUniformBuffersPerPipelineLayout = 8; GPUSize32 maxDynamicUniformBuffersPerPipelineLayout = 8;
unsigned long maxDynamicStorageBuffersPerPipelineLayout = 4; GPUSize32 maxDynamicStorageBuffersPerPipelineLayout = 4;
unsigned long maxSampledTexturesPerShaderStage = 16; GPUSize32 maxSampledTexturesPerShaderStage = 16;
unsigned long maxSamplersPerShaderStage = 16; GPUSize32 maxSamplersPerShaderStage = 16;
unsigned long maxStorageBuffersPerShaderStage = 4; GPUSize32 maxStorageBuffersPerShaderStage = 4;
unsigned long maxStorageTexturesPerShaderStage = 4; GPUSize32 maxStorageTexturesPerShaderStage = 4;
unsigned long maxUniformBuffersPerShaderStage = 12; GPUSize32 maxUniformBuffersPerShaderStage = 12;
GPUSize32 maxUniformBufferBindingSize = 16384;
}; };

View file

@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
// https://gpuweb.github.io/gpuweb/#gpubindgrouplayout // https://gpuweb.github.io/gpuweb/#gpubindgrouplayout
[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"] [Exposed=(Window, DedicatedWorker), Pref="dom.webgpu.enabled"]
interface GPUBindGroup { interface GPUBindGroup {
}; };
GPUBindGroup includes GPUObjectBase; GPUBindGroup includes GPUObjectBase;
@ -13,10 +13,10 @@ dictionary GPUBindGroupDescriptor : GPUObjectDescriptorBase {
required sequence<GPUBindGroupEntry> entries; required sequence<GPUBindGroupEntry> entries;
}; };
typedef /*(GPUSampler or GPUTextureView or*/ GPUBufferBindings/*)*/ GPUBindingResource; typedef (GPUSampler or GPUTextureView or GPUBufferBindings) GPUBindingResource;
dictionary GPUBindGroupEntry { dictionary GPUBindGroupEntry {
required unsigned long binding; required GPUIndex32 binding;
required GPUBindingResource resource; required GPUBindingResource resource;
}; };

View file

@ -16,11 +16,19 @@ dictionary GPUBindGroupLayoutEntry {
required GPUIndex32 binding; required GPUIndex32 binding;
required GPUShaderStageFlags visibility; required GPUShaderStageFlags visibility;
required GPUBindingType type; required GPUBindingType type;
GPUTextureViewDimension viewDimension = "2d";
GPUTextureComponentType textureComponentType = "float"; // Used for uniform buffer and storage buffer bindings.
GPUTextureFormat storageTextureFormat;
boolean multisampled = false;
boolean hasDynamicOffset = false; boolean hasDynamicOffset = false;
// Used for sampled texture and storage texture bindings.
GPUTextureViewDimension viewDimension;
// Used for sampled texture bindings.
GPUTextureComponentType textureComponentType;
boolean multisampled = false;
// Used for storage texture bindings.
GPUTextureFormat storageTextureFormat;
}; };
enum GPUBindingType { enum GPUBindingType {
@ -31,5 +39,5 @@ enum GPUBindingType {
"sampled-texture", "sampled-texture",
"readonly-storage-texture", "readonly-storage-texture",
"writeonly-storage-texture", "writeonly-storage-texture",
//"comparison-sampler", "comparison-sampler",
}; };

View file

@ -73,12 +73,12 @@ pub enum WebGPURequest {
device_id: id::DeviceId, device_id: id::DeviceId,
bind_group_id: id::BindGroupId, bind_group_id: id::BindGroupId,
bind_group_layout_id: id::BindGroupLayoutId, bind_group_layout_id: id::BindGroupLayoutId,
bindings: Vec<BindGroupEntry>, entries: Vec<BindGroupEntry>,
}, },
CreateBindGroupLayout { CreateBindGroupLayout {
device_id: id::DeviceId, device_id: id::DeviceId,
bind_group_layout_id: id::BindGroupLayoutId, bind_group_layout_id: id::BindGroupLayoutId,
bindings: Vec<BindGroupLayoutEntry>, entries: Vec<BindGroupLayoutEntry>,
}, },
CreateBuffer { CreateBuffer {
device_id: id::DeviceId, device_id: id::DeviceId,
@ -334,13 +334,13 @@ impl WGPU {
device_id, device_id,
bind_group_id, bind_group_id,
bind_group_layout_id, bind_group_layout_id,
bindings, entries,
} => { } => {
let global = &self.global; let global = &self.global;
let descriptor = BindGroupDescriptor { let descriptor = BindGroupDescriptor {
layout: bind_group_layout_id, layout: bind_group_layout_id,
entries: bindings.as_ptr(), entries: entries.as_ptr(),
entries_length: bindings.len(), entries_length: entries.len(),
label: ptr::null(), label: ptr::null(),
}; };
let _ = gfx_select!(bind_group_id => let _ = gfx_select!(bind_group_id =>
@ -349,12 +349,12 @@ impl WGPU {
WebGPURequest::CreateBindGroupLayout { WebGPURequest::CreateBindGroupLayout {
device_id, device_id,
bind_group_layout_id, bind_group_layout_id,
bindings, entries,
} => { } => {
let global = &self.global; let global = &self.global;
let descriptor = BindGroupLayoutDescriptor { let descriptor = BindGroupLayoutDescriptor {
entries: bindings.as_ptr(), entries: entries.as_ptr(),
entries_length: bindings.len(), entries_length: entries.len(),
label: ptr::null(), label: ptr::null(),
}; };
let _ = gfx_select!(bind_group_layout_id => let _ = gfx_select!(bind_group_layout_id =>