mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Add GPUSampler and GPUTextureView to BindingResource
Add validation for BindGroups
This commit is contained in:
parent
abc3ed40c9
commit
00b3f785c4
12 changed files with 591 additions and 123 deletions
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) &
|
||||||
|
|
|
@ -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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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",
|
||||||
};
|
};
|
||||||
|
|
|
@ -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 =>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue