mirror of
https://github.com/servo/servo.git
synced 2025-07-23 07:13:52 +01:00
Auto merge of #26984 - kunalmohan:gpu-bind-group, r=kvark
Add GPUSampler and GPUTextureView to BindingResources and update wgpu-core <!-- Please describe your changes on the following line: --> This also completes validation for `GPUBindGroup` and `GPUBindGroupLayout`. `entry_map` is stored in `GPUBindGroupLayout` for validating `createBindGroup()`. r?@kvark --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [ ] These changes fix #___ (GitHub issue number if applicable) <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because ___ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
commit
77a75403db
20 changed files with 313 additions and 396 deletions
23
Cargo.lock
generated
23
Cargo.lock
generated
|
@ -1787,9 +1787,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gfx-backend-dx12"
|
name = "gfx-backend-dx12"
|
||||||
version = "0.5.4"
|
version = "0.5.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69af46bd4fc5479cc7d90bf77ccee0da5dd88d4d27b87986a582f9eec97d02d4"
|
checksum = "6e1a979a793023717bcaa7511c8cbb449bab550c093737c98674a659a2bbaf73"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"d3d12",
|
"d3d12",
|
||||||
|
@ -1815,9 +1815,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gfx-backend-metal"
|
name = "gfx-backend-metal"
|
||||||
version = "0.5.2"
|
version = "0.5.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "205f3ca8e74ed814ea2c0206d47d8925077673cab2e21f9b12d48ff781cf87ee"
|
checksum = "412a1e0e53e9e325a7c2e0316f1a4e8a14cbe8d8bfb5f030bc3895692f8a8254"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.5.1",
|
"arrayvec 0.5.1",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
@ -1842,9 +1842,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gfx-backend-vulkan"
|
name = "gfx-backend-vulkan"
|
||||||
version = "0.5.6"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "45ff36feae801fa23d29acd74082603a0145a697a23595757dd4e78828ab33da"
|
checksum = "04af900c2597587b35e801e9d3f91fd8078cc06067421a22caa640ad2b1bc53e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.5.1",
|
"arrayvec 0.5.1",
|
||||||
"ash",
|
"ash",
|
||||||
|
@ -1872,9 +1872,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gfx-hal"
|
name = "gfx-hal"
|
||||||
version = "0.5.0"
|
version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc96180204064c9493e0fe4a9efeb721e0ac59fe8e1906d0c659142a93114fb1"
|
checksum = "f13e8fd6aaa8f50146b9519999432e097da43466749d8863c53409322c705339"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
|
@ -1883,8 +1883,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gfx-memory"
|
name = "gfx-memory"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/gfx-rs/gfx-extras?rev=438353c3f75368c12024ad2fc03cbeb15f351fd9#438353c3f75368c12024ad2fc03cbeb15f351fd9"
|
||||||
checksum = "c2eed6cda674d9cd4d92229102dbd544292124533d236904f987e9afab456137"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fxhash",
|
"fxhash",
|
||||||
"gfx-hal",
|
"gfx-hal",
|
||||||
|
@ -6563,7 +6562,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-core"
|
name = "wgpu-core"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/gfx-rs/wgpu#ac9587e9ced5b043abad68e260cb8c9e812cffb5"
|
source = "git+https://github.com/gfx-rs/wgpu#fc2dd481b2713cd0eda6ffa540faeaf7418fd051"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec 0.5.1",
|
"arrayvec 0.5.1",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
|
@ -6592,7 +6591,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wgpu-types"
|
name = "wgpu-types"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/gfx-rs/wgpu#ac9587e9ced5b043abad68e260cb8c9e812cffb5"
|
source = "git+https://github.com/gfx-rs/wgpu#fc2dd481b2713cd0eda6ffa540faeaf7418fd051"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"peek-poke 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"peek-poke 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
|
@ -165,10 +165,10 @@ use tendril::{StrTendril, TendrilSink};
|
||||||
use time::{Duration, Timespec, Tm};
|
use time::{Duration, Timespec, Tm};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use webgpu::{
|
use webgpu::{
|
||||||
wgpu::command::RawPass, WebGPU, WebGPUAdapter, WebGPUBindGroup, WebGPUBindGroupLayout,
|
wgpu::command::RawPass, wgpu::id, WebGPU, WebGPUAdapter, WebGPUBindGroup,
|
||||||
WebGPUBuffer, WebGPUCommandBuffer, WebGPUCommandEncoder, WebGPUComputePipeline, WebGPUDevice,
|
WebGPUBindGroupLayout, WebGPUBuffer, WebGPUCommandBuffer, WebGPUCommandEncoder,
|
||||||
WebGPUPipelineLayout, WebGPUQueue, WebGPURenderPipeline, WebGPUSampler, WebGPUShaderModule,
|
WebGPUComputePipeline, WebGPUDevice, WebGPUPipelineLayout, WebGPUQueue, WebGPURenderPipeline,
|
||||||
WebGPUTexture, WebGPUTextureView,
|
WebGPUSampler, WebGPUShaderModule, WebGPUTexture, WebGPUTextureView,
|
||||||
};
|
};
|
||||||
use webrender_api::{DocumentId, ExternalImageId, ImageKey};
|
use webrender_api::{DocumentId, ExternalImageId, ImageKey};
|
||||||
use webxr_api::SwapChainId as WebXRSwapChainId;
|
use webxr_api::SwapChainId as WebXRSwapChainId;
|
||||||
|
@ -581,7 +581,7 @@ unsafe_no_jsmanaged_fields!(WebGPUContextId);
|
||||||
unsafe_no_jsmanaged_fields!(WebGPUCommandBuffer);
|
unsafe_no_jsmanaged_fields!(WebGPUCommandBuffer);
|
||||||
unsafe_no_jsmanaged_fields!(WebGPUCommandEncoder);
|
unsafe_no_jsmanaged_fields!(WebGPUCommandEncoder);
|
||||||
unsafe_no_jsmanaged_fields!(WebGPUDevice);
|
unsafe_no_jsmanaged_fields!(WebGPUDevice);
|
||||||
unsafe_no_jsmanaged_fields!(Option<RawPass>);
|
unsafe_no_jsmanaged_fields!(Option<RawPass<id::CommandEncoderId>>);
|
||||||
unsafe_no_jsmanaged_fields!(GPUBufferState);
|
unsafe_no_jsmanaged_fields!(GPUBufferState);
|
||||||
unsafe_no_jsmanaged_fields!(GPUCommandEncoderState);
|
unsafe_no_jsmanaged_fields!(GPUCommandEncoderState);
|
||||||
unsafe_no_jsmanaged_fields!(WebXRSwapChainId);
|
unsafe_no_jsmanaged_fields!(WebXRSwapChainId);
|
||||||
|
|
|
@ -84,7 +84,9 @@ impl GPUAdapterMethods for GPUAdapter {
|
||||||
extensions: wgt::Extensions::empty(),
|
extensions: wgt::Extensions::empty(),
|
||||||
limits: wgt::Limits {
|
limits: wgt::Limits {
|
||||||
max_bind_groups: descriptor.limits.maxBindGroups,
|
max_bind_groups: descriptor.limits.maxBindGroups,
|
||||||
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
shader_validation: true,
|
||||||
};
|
};
|
||||||
let id = self
|
let id = self
|
||||||
.global()
|
.global()
|
||||||
|
|
|
@ -5,34 +5,52 @@
|
||||||
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::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 dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use webgpu::WebGPUBindGroup;
|
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>,
|
||||||
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,
|
||||||
|
layout: &GPUBindGroupLayout,
|
||||||
|
) -> 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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope, bind_group: WebGPUBindGroup, valid: bool) -> DomRoot<Self> {
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
|
bind_group: WebGPUBindGroup,
|
||||||
|
device: WebGPUDevice,
|
||||||
|
valid: bool,
|
||||||
|
layout: &GPUBindGroupLayout,
|
||||||
|
) -> 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, layout,
|
||||||
|
)),
|
||||||
global,
|
global,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,60 +3,40 @@
|
||||||
* 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::GPUBindGroupLayoutBinding::{
|
use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::GPUBindGroupLayoutMethods;
|
||||||
GPUBindGroupLayoutEntry, GPUBindGroupLayoutMethods,
|
|
||||||
};
|
|
||||||
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::DomRoot;
|
||||||
use crate::dom::bindings::str::DOMString;
|
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 webgpu::{WebGPU, WebGPUBindGroupLayout};
|
use webgpu::WebGPUBindGroupLayout;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct GPUBindGroupLayout {
|
pub struct GPUBindGroupLayout {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
label: DomRefCell<Option<DOMString>>,
|
label: DomRefCell<Option<DOMString>>,
|
||||||
bind_group_layout: WebGPUBindGroupLayout,
|
bind_group_layout: WebGPUBindGroupLayout,
|
||||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
|
||||||
bindings: Vec<GPUBindGroupLayoutEntry>,
|
|
||||||
#[ignore_malloc_size_of = "defined in webgpu"]
|
|
||||||
channel: WebGPU,
|
|
||||||
valid: Cell<bool>,
|
valid: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUBindGroupLayout {
|
impl GPUBindGroupLayout {
|
||||||
fn new_inherited(
|
fn new_inherited(bind_group_layout: WebGPUBindGroupLayout, valid: bool) -> Self {
|
||||||
channel: WebGPU,
|
|
||||||
bind_group_layout: WebGPUBindGroupLayout,
|
|
||||||
bindings: Vec<GPUBindGroupLayoutEntry>,
|
|
||||||
valid: bool,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
channel,
|
|
||||||
label: DomRefCell::new(None),
|
label: DomRefCell::new(None),
|
||||||
bind_group_layout,
|
bind_group_layout,
|
||||||
bindings,
|
|
||||||
valid: Cell::new(valid),
|
valid: Cell::new(valid),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
global: &GlobalScope,
|
global: &GlobalScope,
|
||||||
channel: WebGPU,
|
|
||||||
bind_group_layout: WebGPUBindGroupLayout,
|
bind_group_layout: WebGPUBindGroupLayout,
|
||||||
bindings: Vec<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(bind_group_layout, valid)),
|
||||||
channel,
|
|
||||||
bind_group_layout,
|
|
||||||
bindings,
|
|
||||||
valid,
|
|
||||||
)),
|
|
||||||
global,
|
global,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -70,10 +50,6 @@ impl GPUBindGroupLayout {
|
||||||
pub fn id(&self) -> WebGPUBindGroupLayout {
|
pub fn id(&self) -> WebGPUBindGroupLayout {
|
||||||
self.bind_group_layout
|
self.bind_group_layout
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bindings(&self) -> &[GPUBindGroupLayoutEntry] {
|
|
||||||
&self.bindings
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUBindGroupLayoutMethods for GPUBindGroupLayout {
|
impl GPUBindGroupLayoutMethods for GPUBindGroupLayout {
|
||||||
|
|
|
@ -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) &
|
||||||
|
|
|
@ -22,6 +22,7 @@ use webgpu::{
|
||||||
},
|
},
|
||||||
RawPass,
|
RawPass,
|
||||||
},
|
},
|
||||||
|
wgpu::id,
|
||||||
WebGPU, WebGPURequest,
|
WebGPU, WebGPURequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -32,7 +33,7 @@ pub struct GPUComputePassEncoder {
|
||||||
channel: WebGPU,
|
channel: WebGPU,
|
||||||
label: DomRefCell<Option<DOMString>>,
|
label: DomRefCell<Option<DOMString>>,
|
||||||
#[ignore_malloc_size_of = "defined in wgpu-core"]
|
#[ignore_malloc_size_of = "defined in wgpu-core"]
|
||||||
raw_pass: DomRefCell<Option<RawPass>>,
|
raw_pass: DomRefCell<Option<RawPass<id::CommandEncoderId>>>,
|
||||||
command_encoder: Dom<GPUCommandEncoder>,
|
command_encoder: Dom<GPUCommandEncoder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::dom::bindings::root::DomRoot;
|
||||||
use crate::dom::bindings::str::DOMString;
|
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 webgpu::WebGPUComputePipeline;
|
use webgpu::WebGPUComputePipeline;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
|
@ -17,20 +18,26 @@ pub struct GPUComputePipeline {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
label: DomRefCell<Option<DOMString>>,
|
label: DomRefCell<Option<DOMString>>,
|
||||||
compute_pipeline: WebGPUComputePipeline,
|
compute_pipeline: WebGPUComputePipeline,
|
||||||
|
valid: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUComputePipeline {
|
impl GPUComputePipeline {
|
||||||
fn new_inherited(compute_pipeline: WebGPUComputePipeline) -> Self {
|
fn new_inherited(compute_pipeline: WebGPUComputePipeline, valid: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
label: DomRefCell::new(None),
|
label: DomRefCell::new(None),
|
||||||
compute_pipeline,
|
compute_pipeline,
|
||||||
|
valid: Cell::new(valid),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(global: &GlobalScope, compute_pipeline: WebGPUComputePipeline) -> DomRoot<Self> {
|
pub fn new(
|
||||||
|
global: &GlobalScope,
|
||||||
|
compute_pipeline: WebGPUComputePipeline,
|
||||||
|
valid: bool,
|
||||||
|
) -> DomRoot<Self> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(GPUComputePipeline::new_inherited(compute_pipeline)),
|
Box::new(GPUComputePipeline::new_inherited(compute_pipeline, valid)),
|
||||||
global,
|
global,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
#![allow(unsafe_code)]
|
#![allow(unsafe_code)]
|
||||||
|
|
||||||
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::GPUBindGroupBinding::{
|
||||||
use crate::dom::bindings::codegen::Bindings::GPUBindGroupBinding::GPUBindGroupDescriptor;
|
GPUBindGroupDescriptor, GPUBindingResource,
|
||||||
|
};
|
||||||
use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{
|
use crate::dom::bindings::codegen::Bindings::GPUBindGroupLayoutBinding::{
|
||||||
GPUBindGroupLayoutDescriptor, GPUBindGroupLayoutEntry, GPUBindingType,
|
GPUBindGroupLayoutDescriptor, GPUBindingType,
|
||||||
};
|
};
|
||||||
use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::GPUBufferDescriptor;
|
use crate::dom::bindings::codegen::Bindings::GPUBufferBinding::GPUBufferDescriptor;
|
||||||
use crate::dom::bindings::codegen::Bindings::GPUComputePipelineBinding::GPUComputePipelineDescriptor;
|
use crate::dom::bindings::codegen::Bindings::GPUComputePipelineBinding::GPUComputePipelineDescriptor;
|
||||||
|
@ -55,12 +56,10 @@ 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::num::NonZeroU64;
|
||||||
use std::ptr::{self, NonNull};
|
use std::ptr::{self, NonNull};
|
||||||
use webgpu::wgpu::binding_model::{
|
use webgpu::wgpu::binding_model::BufferBinding;
|
||||||
BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, BufferBinding,
|
use webgpu::{self, wgt, WebGPU, WebGPUBindings, WebGPURequest};
|
||||||
};
|
|
||||||
use webgpu::{self, wgpu, wgt, WebGPU, WebGPURequest};
|
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct GPUDevice {
|
pub struct GPUDevice {
|
||||||
|
@ -274,149 +273,93 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
&self,
|
&self,
|
||||||
descriptor: &GPUBindGroupLayoutDescriptor,
|
descriptor: &GPUBindGroupLayoutDescriptor,
|
||||||
) -> DomRoot<GPUBindGroupLayout> {
|
) -> DomRoot<GPUBindGroupLayout> {
|
||||||
#[derive(Clone)]
|
let entries = descriptor
|
||||||
struct MaxLimits {
|
|
||||||
max_uniform_buffers_per_shader_stage: i32,
|
|
||||||
max_storage_buffers_per_shader_stage: i32,
|
|
||||||
max_sampled_textures_per_shader_stage: i32,
|
|
||||||
max_storage_textures_per_shader_stage: i32,
|
|
||||||
max_samplers_per_shader_stage: i32,
|
|
||||||
}
|
|
||||||
let mut storeBindings = HashSet::new();
|
|
||||||
// TODO: We should have these limits on device creation
|
|
||||||
let limits = GPULimits::empty();
|
|
||||||
|
|
||||||
let mut validation_map = HashMap::new();
|
|
||||||
let maxLimits = MaxLimits {
|
|
||||||
max_uniform_buffers_per_shader_stage: limits.maxUniformBuffersPerShaderStage as i32,
|
|
||||||
max_storage_buffers_per_shader_stage: limits.maxStorageBuffersPerShaderStage as i32,
|
|
||||||
max_sampled_textures_per_shader_stage: limits.maxSampledTexturesPerShaderStage as i32,
|
|
||||||
max_storage_textures_per_shader_stage: limits.maxStorageTexturesPerShaderStage as i32,
|
|
||||||
max_samplers_per_shader_stage: limits.maxSamplersPerShaderStage as i32,
|
|
||||||
};
|
|
||||||
validation_map.insert(wgt::ShaderStage::VERTEX, maxLimits.clone());
|
|
||||||
validation_map.insert(wgt::ShaderStage::FRAGMENT, maxLimits.clone());
|
|
||||||
validation_map.insert(wgt::ShaderStage::COMPUTE, maxLimits.clone());
|
|
||||||
let mut max_dynamic_uniform_buffers_per_pipeline_layout =
|
|
||||||
limits.maxDynamicUniformBuffersPerPipelineLayout as i32;
|
|
||||||
let mut max_dynamic_storage_buffers_per_pipeline_layout =
|
|
||||||
limits.maxDynamicStorageBuffersPerPipelineLayout as i32;
|
|
||||||
let mut valid = true;
|
|
||||||
|
|
||||||
let bindings = descriptor
|
|
||||||
.entries
|
.entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|bind| {
|
.map(|bind| {
|
||||||
// TODO: binding must be >= 0
|
|
||||||
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,
|
||||||
None => {
|
None => wgt::ShaderStage::from_bits(0).unwrap(),
|
||||||
valid = false;
|
|
||||||
wgt::ShaderStage::from_bits(0).unwrap()
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
let ty = match bind.type_ {
|
let ty = match bind.type_ {
|
||||||
GPUBindingType::Uniform_buffer => {
|
GPUBindingType::Uniform_buffer => wgt::BindingType::UniformBuffer {
|
||||||
if let Some(limit) = validation_map.get_mut(&visibility) {
|
dynamic: bind.hasDynamicOffset,
|
||||||
limit.max_uniform_buffers_per_shader_stage -= 1;
|
min_binding_size: if bind.minBufferBindingSize == 0 {
|
||||||
}
|
None
|
||||||
if bind.hasDynamicOffset {
|
} else {
|
||||||
max_dynamic_uniform_buffers_per_pipeline_layout -= 1;
|
Some(NonZeroU64::new(bind.minBufferBindingSize).unwrap())
|
||||||
};
|
},
|
||||||
BindingType::UniformBuffer
|
|
||||||
},
|
},
|
||||||
GPUBindingType::Storage_buffer => {
|
GPUBindingType::Storage_buffer => wgt::BindingType::StorageBuffer {
|
||||||
if let Some(limit) = validation_map.get_mut(&visibility) {
|
dynamic: bind.hasDynamicOffset,
|
||||||
limit.max_storage_buffers_per_shader_stage -= 1;
|
min_binding_size: if bind.minBufferBindingSize == 0 {
|
||||||
}
|
None
|
||||||
if bind.hasDynamicOffset {
|
} else {
|
||||||
max_dynamic_storage_buffers_per_pipeline_layout -= 1;
|
Some(NonZeroU64::new(bind.minBufferBindingSize).unwrap())
|
||||||
};
|
},
|
||||||
BindingType::StorageBuffer
|
readonly: false,
|
||||||
},
|
},
|
||||||
GPUBindingType::Readonly_storage_buffer => {
|
GPUBindingType::Readonly_storage_buffer => wgt::BindingType::StorageBuffer {
|
||||||
if let Some(limit) = validation_map.get_mut(&visibility) {
|
dynamic: bind.hasDynamicOffset,
|
||||||
limit.max_storage_buffers_per_shader_stage -= 1;
|
min_binding_size: if bind.minBufferBindingSize == 0 {
|
||||||
}
|
None
|
||||||
if bind.hasDynamicOffset {
|
} else {
|
||||||
max_dynamic_storage_buffers_per_pipeline_layout -= 1;
|
Some(NonZeroU64::new(bind.minBufferBindingSize).unwrap())
|
||||||
};
|
},
|
||||||
BindingType::ReadonlyStorageBuffer
|
readonly: true,
|
||||||
},
|
},
|
||||||
GPUBindingType::Sampled_texture => {
|
GPUBindingType::Sampled_texture => wgt::BindingType::SampledTexture {
|
||||||
if let Some(limit) = validation_map.get_mut(&visibility) {
|
dimension: bind
|
||||||
limit.max_sampled_textures_per_shader_stage -= 1;
|
.viewDimension
|
||||||
}
|
.map_or(wgt::TextureViewDimension::D2, |v| {
|
||||||
if bind.hasDynamicOffset {
|
convert_texture_view_dimension(v)
|
||||||
valid = false
|
}),
|
||||||
};
|
component_type: if let Some(c) = bind.textureComponentType {
|
||||||
BindingType::SampledTexture
|
match c {
|
||||||
|
GPUTextureComponentType::Float => wgt::TextureComponentType::Float,
|
||||||
|
GPUTextureComponentType::Sint => wgt::TextureComponentType::Sint,
|
||||||
|
GPUTextureComponentType::Uint => wgt::TextureComponentType::Uint,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wgt::TextureComponentType::Float
|
||||||
|
},
|
||||||
|
multisampled: bind.multisampled,
|
||||||
},
|
},
|
||||||
GPUBindingType::Readonly_storage_texture => {
|
GPUBindingType::Readonly_storage_texture => wgt::BindingType::StorageTexture {
|
||||||
if let Some(limit) = validation_map.get_mut(&visibility) {
|
dimension: bind
|
||||||
limit.max_storage_textures_per_shader_stage -= 1;
|
.viewDimension
|
||||||
}
|
.map_or(wgt::TextureViewDimension::D2, |v| {
|
||||||
if bind.hasDynamicOffset {
|
convert_texture_view_dimension(v)
|
||||||
valid = false
|
}),
|
||||||
};
|
format: bind
|
||||||
BindingType::ReadonlyStorageTexture
|
.storageTextureFormat
|
||||||
|
.map_or(wgt::TextureFormat::Bgra8UnormSrgb, |f| {
|
||||||
|
convert_texture_format(f)
|
||||||
|
}),
|
||||||
|
readonly: true,
|
||||||
},
|
},
|
||||||
GPUBindingType::Writeonly_storage_texture => {
|
GPUBindingType::Writeonly_storage_texture => wgt::BindingType::StorageTexture {
|
||||||
if let Some(limit) = validation_map.get_mut(&visibility) {
|
dimension: bind
|
||||||
limit.max_storage_textures_per_shader_stage -= 1;
|
.viewDimension
|
||||||
}
|
.map_or(wgt::TextureViewDimension::D2, |v| {
|
||||||
if bind.hasDynamicOffset {
|
convert_texture_view_dimension(v)
|
||||||
valid = false
|
}),
|
||||||
};
|
format: bind
|
||||||
BindingType::WriteonlyStorageTexture
|
.storageTextureFormat
|
||||||
|
.map_or(wgt::TextureFormat::Bgra8UnormSrgb, |f| {
|
||||||
|
convert_texture_format(f)
|
||||||
|
}),
|
||||||
|
readonly: true,
|
||||||
},
|
},
|
||||||
GPUBindingType::Sampler => {
|
GPUBindingType::Sampler => wgt::BindingType::Sampler { comparison: false },
|
||||||
if let Some(limit) = validation_map.get_mut(&visibility) {
|
GPUBindingType::Comparison_sampler => {
|
||||||
limit.max_samplers_per_shader_stage -= 1;
|
wgt::BindingType::Sampler { comparison: true }
|
||||||
}
|
|
||||||
if bind.hasDynamicOffset {
|
|
||||||
valid = false
|
|
||||||
};
|
|
||||||
BindingType::Sampler
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
BindGroupLayoutEntry {
|
wgt::BindGroupLayoutEntry::new(bind.binding, visibility, ty)
|
||||||
binding: bind.binding,
|
|
||||||
visibility,
|
|
||||||
ty,
|
|
||||||
has_dynamic_offset: bind.hasDynamicOffset,
|
|
||||||
multisampled: bind.multisampled,
|
|
||||||
texture_component_type: match bind.textureComponentType {
|
|
||||||
GPUTextureComponentType::Float => wgt::TextureComponentType::Float,
|
|
||||||
GPUTextureComponentType::Sint => wgt::TextureComponentType::Sint,
|
|
||||||
GPUTextureComponentType::Uint => wgt::TextureComponentType::Uint,
|
|
||||||
},
|
|
||||||
storage_texture_format: match bind.storageTextureFormat {
|
|
||||||
Some(s) => convert_texture_format(s),
|
|
||||||
None => wgt::TextureFormat::Bgra8UnormSrgb,
|
|
||||||
},
|
|
||||||
view_dimension: convert_texture_view_dimension(bind.viewDimension),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.collect::<Vec<BindGroupLayoutEntry>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// bindings are unique
|
|
||||||
valid &= storeBindings.len() == bindings.len();
|
|
||||||
|
|
||||||
// Ensure that values do not exceed the max limit for each ShaderStage.
|
|
||||||
valid &= validation_map.values().all(|stage| {
|
|
||||||
stage.max_uniform_buffers_per_shader_stage >= 0 &&
|
|
||||||
stage.max_storage_buffers_per_shader_stage >= 0 &&
|
|
||||||
stage.max_sampled_textures_per_shader_stage >= 0 &&
|
|
||||||
stage.max_storage_textures_per_shader_stage >= 0 &&
|
|
||||||
stage.max_samplers_per_shader_stage >= 0
|
|
||||||
});
|
|
||||||
|
|
||||||
// DynamicValues does not exceed the max limit for the pipeline
|
|
||||||
valid &= max_dynamic_uniform_buffers_per_pipeline_layout >= 0 &&
|
|
||||||
max_dynamic_storage_buffers_per_pipeline_layout >= 0;
|
|
||||||
|
|
||||||
let bind_group_layout_id = self
|
let bind_group_layout_id = self
|
||||||
.global()
|
.global()
|
||||||
|
@ -428,28 +371,13 @@ 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,
|
||||||
})
|
})
|
||||||
.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
|
GPUBindGroupLayout::new(&self.global(), bgl, true)
|
||||||
.entries
|
|
||||||
.iter()
|
|
||||||
.map(|bind| GPUBindGroupLayoutEntry {
|
|
||||||
binding: bind.binding,
|
|
||||||
hasDynamicOffset: bind.hasDynamicOffset,
|
|
||||||
multisampled: bind.multisampled,
|
|
||||||
type_: bind.type_,
|
|
||||||
visibility: bind.visibility,
|
|
||||||
viewDimension: bind.viewDimension,
|
|
||||||
textureComponentType: bind.textureComponentType,
|
|
||||||
storageTextureFormat: bind.storageTextureFormat,
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
GPUBindGroupLayout::new(&self.global(), self.channel.clone(), bgl, binds, valid)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createpipelinelayout
|
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createpipelinelayout
|
||||||
|
@ -457,47 +385,13 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
&self,
|
&self,
|
||||||
descriptor: &GPUPipelineLayoutDescriptor,
|
descriptor: &GPUPipelineLayoutDescriptor,
|
||||||
) -> DomRoot<GPUPipelineLayout> {
|
) -> DomRoot<GPUPipelineLayout> {
|
||||||
// TODO: We should have these limits on device creation
|
|
||||||
let limits = GPULimits::empty();
|
|
||||||
let mut bind_group_layouts = Vec::new();
|
|
||||||
let mut bgl_ids = Vec::new();
|
let mut bgl_ids = Vec::new();
|
||||||
let mut max_dynamic_uniform_buffers_per_pipeline_layout =
|
|
||||||
limits.maxDynamicUniformBuffersPerPipelineLayout as i32;
|
|
||||||
let mut max_dynamic_storage_buffers_per_pipeline_layout =
|
|
||||||
limits.maxDynamicStorageBuffersPerPipelineLayout as i32;
|
|
||||||
descriptor.bindGroupLayouts.iter().for_each(|each| {
|
descriptor.bindGroupLayouts.iter().for_each(|each| {
|
||||||
if each.is_valid() {
|
if each.is_valid() {
|
||||||
let id = each.id();
|
bgl_ids.push(each.id().0);
|
||||||
bind_group_layouts.push(id);
|
|
||||||
bgl_ids.push(id.0);
|
|
||||||
}
|
}
|
||||||
each.bindings().iter().for_each(|bind| {
|
|
||||||
match bind.type_ {
|
|
||||||
GPUBindingType::Uniform_buffer => {
|
|
||||||
if bind.hasDynamicOffset {
|
|
||||||
max_dynamic_uniform_buffers_per_pipeline_layout -= 1;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
GPUBindingType::Storage_buffer => {
|
|
||||||
if bind.hasDynamicOffset {
|
|
||||||
max_dynamic_storage_buffers_per_pipeline_layout -= 1;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
GPUBindingType::Readonly_storage_buffer => {
|
|
||||||
if bind.hasDynamicOffset {
|
|
||||||
max_dynamic_storage_buffers_per_pipeline_layout -= 1;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let valid = descriptor.bindGroupLayouts.len() <= limits.maxBindGroups as usize &&
|
|
||||||
descriptor.bindGroupLayouts.len() == bind_group_layouts.len() &&
|
|
||||||
max_dynamic_uniform_buffers_per_pipeline_layout >= 0 &&
|
|
||||||
max_dynamic_storage_buffers_per_pipeline_layout >= 0;
|
|
||||||
|
|
||||||
let pipeline_layout_id = self
|
let pipeline_layout_id = self
|
||||||
.global()
|
.global()
|
||||||
.wgpu_id_hub()
|
.wgpu_id_hub()
|
||||||
|
@ -513,50 +407,41 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
.expect("Failed to create WebGPU PipelineLayout");
|
.expect("Failed to create WebGPU PipelineLayout");
|
||||||
|
|
||||||
let pipeline_layout = webgpu::WebGPUPipelineLayout(pipeline_layout_id);
|
let pipeline_layout = webgpu::WebGPUPipelineLayout(pipeline_layout_id);
|
||||||
GPUPipelineLayout::new(&self.global(), bind_group_layouts, pipeline_layout, valid)
|
GPUPipelineLayout::new(&self.global(), pipeline_layout, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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 mut valid = descriptor.layout.is_valid();
|
||||||
let mut valid = descriptor.layout.bindings().len() == descriptor.entries.len();
|
let entries = descriptor
|
||||||
|
|
||||||
valid &= descriptor.entries.iter().all(|bind| {
|
|
||||||
let buffer_size = bind.resource.buffer.size();
|
|
||||||
let resource_size = bind.resource.size.unwrap_or(buffer_size);
|
|
||||||
let length = bind.resource.offset.checked_add(resource_size);
|
|
||||||
let usage = wgt::BufferUsage::from_bits(bind.resource.buffer.usage()).unwrap();
|
|
||||||
|
|
||||||
length.is_some() &&
|
|
||||||
buffer_size >= length.unwrap() && // check buffer OOB
|
|
||||||
bind.resource.offset % alignment == 0 && // check alignment
|
|
||||||
bind.resource.offset < buffer_size && // on Vulkan offset must be less than size of buffer
|
|
||||||
descriptor.layout.bindings().iter().any(|layout_bind| {
|
|
||||||
let ty = match layout_bind.type_ {
|
|
||||||
GPUBindingType::Storage_buffer => wgt::BufferUsage::STORAGE,
|
|
||||||
// GPUBindingType::Readonly_storage_buffer => BufferUsage::STORAGE_READ,
|
|
||||||
GPUBindingType::Uniform_buffer => wgt::BufferUsage::UNIFORM,
|
|
||||||
_ => unimplemented!(),
|
|
||||||
};
|
|
||||||
// binding must be present in layout
|
|
||||||
layout_bind.binding == bind.binding &&
|
|
||||||
// binding must contain one buffer of its type
|
|
||||||
usage.contains(ty)
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
let bindings = descriptor
|
|
||||||
.entries
|
.entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|bind| BindGroupEntry {
|
.map(|bind| {
|
||||||
binding: bind.binding,
|
(
|
||||||
resource: BindingResource::Buffer(BufferBinding {
|
bind.binding,
|
||||||
buffer: bind.resource.buffer.id().0,
|
match bind.resource {
|
||||||
offset: bind.resource.offset,
|
GPUBindingResource::GPUSampler(ref s) => {
|
||||||
size: wgt::BufferSize(
|
valid &= s.is_valid();
|
||||||
bind.resource.size.unwrap_or(bind.resource.buffer.size()),
|
WebGPUBindings::Sampler(s.id().0)
|
||||||
),
|
},
|
||||||
}),
|
GPUBindingResource::GPUTextureView(ref t) => {
|
||||||
|
valid &= t.is_valid();
|
||||||
|
WebGPUBindings::TextureView(t.id().0)
|
||||||
|
},
|
||||||
|
GPUBindingResource::GPUBufferBindings(ref b) => {
|
||||||
|
valid &= b.buffer.is_valid();
|
||||||
|
WebGPUBindings::Buffer(BufferBinding {
|
||||||
|
buffer_id: 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 +456,18 @@ 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 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,
|
||||||
|
&*descriptor.layout,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createshadermodule
|
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createshadermodule
|
||||||
|
@ -611,6 +502,7 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
&self,
|
&self,
|
||||||
descriptor: &GPUComputePipelineDescriptor,
|
descriptor: &GPUComputePipelineDescriptor,
|
||||||
) -> DomRoot<GPUComputePipeline> {
|
) -> DomRoot<GPUComputePipeline> {
|
||||||
|
let valid = descriptor.parent.layout.is_valid();
|
||||||
let pipeline = descriptor.parent.layout.id();
|
let pipeline = descriptor.parent.layout.id();
|
||||||
let program = descriptor.computeStage.module.id();
|
let program = descriptor.computeStage.module.id();
|
||||||
let entry_point = descriptor.computeStage.entryPoint.to_string();
|
let entry_point = descriptor.computeStage.entryPoint.to_string();
|
||||||
|
@ -632,7 +524,7 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
.expect("Failed to create WebGPU ComputePipeline");
|
.expect("Failed to create WebGPU ComputePipeline");
|
||||||
|
|
||||||
let compute_pipeline = webgpu::WebGPUComputePipeline(compute_pipeline_id);
|
let compute_pipeline = webgpu::WebGPUComputePipeline(compute_pipeline_id);
|
||||||
GPUComputePipeline::new(&self.global(), compute_pipeline)
|
GPUComputePipeline::new(&self.global(), compute_pipeline, valid)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcommandencoder
|
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcommandencoder
|
||||||
|
@ -740,6 +632,7 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
lod_max_clamp: *descriptor.lodMaxClamp,
|
lod_max_clamp: *descriptor.lodMaxClamp,
|
||||||
compare: descriptor.compare.map(|c| convert_compare_function(c)),
|
compare: descriptor.compare.map(|c| convert_compare_function(c)),
|
||||||
anisotropy_clamp: None,
|
anisotropy_clamp: None,
|
||||||
|
..Default::default()
|
||||||
};
|
};
|
||||||
self.channel
|
self.channel
|
||||||
.0
|
.0
|
||||||
|
@ -752,14 +645,7 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
|
|
||||||
let sampler = webgpu::WebGPUSampler(sampler_id);
|
let sampler = webgpu::WebGPUSampler(sampler_id);
|
||||||
|
|
||||||
GPUSampler::new(
|
GPUSampler::new(&self.global(), self.device, compare_enable, sampler, true)
|
||||||
&self.global(),
|
|
||||||
self.channel.clone(),
|
|
||||||
self.device,
|
|
||||||
compare_enable,
|
|
||||||
sampler,
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderpipeline
|
/// https://gpuweb.github.io/gpuweb/#dom-gpudevice-createrenderpipeline
|
||||||
|
@ -767,12 +653,7 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
&self,
|
&self,
|
||||||
descriptor: &GPURenderPipelineDescriptor,
|
descriptor: &GPURenderPipelineDescriptor,
|
||||||
) -> DomRoot<GPURenderPipeline> {
|
) -> DomRoot<GPURenderPipeline> {
|
||||||
let mut valid = descriptor.parent.layout.is_valid();
|
let valid = descriptor.parent.layout.is_valid();
|
||||||
valid &= descriptor.colorStates.len() <= wgpu::device::MAX_COLOR_TARGETS;
|
|
||||||
if descriptor.alphaToCoverageEnabled {
|
|
||||||
valid &= descriptor.sampleCount > 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let vertex_module = descriptor.vertexStage.module.id().0;
|
let vertex_module = descriptor.vertexStage.module.id().0;
|
||||||
let vertex_entry_point = descriptor.vertexStage.entryPoint.to_string();
|
let vertex_entry_point = descriptor.vertexStage.entryPoint.to_string();
|
||||||
let (fragment_module, fragment_entry_point) = match descriptor.fragmentStage {
|
let (fragment_module, fragment_entry_point) = match descriptor.fragmentStage {
|
||||||
|
@ -813,10 +694,7 @@ impl GPUDeviceMethods for GPUDevice {
|
||||||
color_blend: convert_blend_descriptor(&state.colorBlend),
|
color_blend: convert_blend_descriptor(&state.colorBlend),
|
||||||
write_mask: match wgt::ColorWrite::from_bits(state.writeMask) {
|
write_mask: match wgt::ColorWrite::from_bits(state.writeMask) {
|
||||||
Some(mask) => mask,
|
Some(mask) => mask,
|
||||||
None => {
|
None => wgt::ColorWrite::empty(),
|
||||||
valid = false;
|
|
||||||
wgt::ColorWrite::empty()
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
.collect::<ArrayVec<_>>();
|
.collect::<ArrayVec<_>>();
|
||||||
|
|
|
@ -10,26 +10,20 @@ 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 webgpu::{WebGPUBindGroupLayout, WebGPUPipelineLayout};
|
use webgpu::WebGPUPipelineLayout;
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct GPUPipelineLayout {
|
pub struct GPUPipelineLayout {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
bind_group_layouts: Vec<WebGPUBindGroupLayout>,
|
|
||||||
label: DomRefCell<Option<DOMString>>,
|
label: DomRefCell<Option<DOMString>>,
|
||||||
pipeline_layout: WebGPUPipelineLayout,
|
pipeline_layout: WebGPUPipelineLayout,
|
||||||
valid: Cell<bool>,
|
valid: Cell<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPUPipelineLayout {
|
impl GPUPipelineLayout {
|
||||||
fn new_inherited(
|
fn new_inherited(pipeline_layout: WebGPUPipelineLayout, valid: bool) -> Self {
|
||||||
bind_group_layouts: Vec<WebGPUBindGroupLayout>,
|
|
||||||
pipeline_layout: WebGPUPipelineLayout,
|
|
||||||
valid: bool,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
Self {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
bind_group_layouts,
|
|
||||||
label: DomRefCell::new(None),
|
label: DomRefCell::new(None),
|
||||||
pipeline_layout,
|
pipeline_layout,
|
||||||
valid: Cell::new(valid),
|
valid: Cell::new(valid),
|
||||||
|
@ -38,16 +32,11 @@ impl GPUPipelineLayout {
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
global: &GlobalScope,
|
global: &GlobalScope,
|
||||||
bind_group_layouts: Vec<WebGPUBindGroupLayout>,
|
|
||||||
pipeline_layout: WebGPUPipelineLayout,
|
pipeline_layout: WebGPUPipelineLayout,
|
||||||
valid: bool,
|
valid: bool,
|
||||||
) -> DomRoot<Self> {
|
) -> DomRoot<Self> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(GPUPipelineLayout::new_inherited(
|
Box::new(GPUPipelineLayout::new_inherited(pipeline_layout, valid)),
|
||||||
bind_group_layouts,
|
|
||||||
pipeline_layout,
|
|
||||||
valid,
|
|
||||||
)),
|
|
||||||
global,
|
global,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ use crate::dom::gpurenderpipeline::GPURenderPipeline;
|
||||||
use dom_struct::dom_struct;
|
use dom_struct::dom_struct;
|
||||||
use webgpu::{
|
use webgpu::{
|
||||||
wgpu::command::{render_ffi as wgpu_render, RawPass},
|
wgpu::command::{render_ffi as wgpu_render, RawPass},
|
||||||
|
wgpu::id,
|
||||||
wgt, WebGPU, WebGPURequest,
|
wgt, WebGPU, WebGPURequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,12 +30,16 @@ pub struct GPURenderPassEncoder {
|
||||||
channel: WebGPU,
|
channel: WebGPU,
|
||||||
label: DomRefCell<Option<DOMString>>,
|
label: DomRefCell<Option<DOMString>>,
|
||||||
#[ignore_malloc_size_of = "defined in wgpu-core"]
|
#[ignore_malloc_size_of = "defined in wgpu-core"]
|
||||||
raw_pass: DomRefCell<Option<RawPass>>,
|
raw_pass: DomRefCell<Option<RawPass<id::CommandEncoderId>>>,
|
||||||
command_encoder: Dom<GPUCommandEncoder>,
|
command_encoder: Dom<GPUCommandEncoder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GPURenderPassEncoder {
|
impl GPURenderPassEncoder {
|
||||||
fn new_inherited(channel: WebGPU, raw_pass: RawPass, parent: &GPUCommandEncoder) -> Self {
|
fn new_inherited(
|
||||||
|
channel: WebGPU,
|
||||||
|
raw_pass: RawPass<id::CommandEncoderId>,
|
||||||
|
parent: &GPUCommandEncoder,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
channel,
|
channel,
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
|
@ -47,7 +52,7 @@ impl GPURenderPassEncoder {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
global: &GlobalScope,
|
global: &GlobalScope,
|
||||||
channel: WebGPU,
|
channel: WebGPU,
|
||||||
raw_pass: RawPass,
|
raw_pass: RawPass<id::CommandEncoderId>,
|
||||||
parent: &GPUCommandEncoder,
|
parent: &GPUCommandEncoder,
|
||||||
) -> DomRoot<Self> {
|
) -> DomRoot<Self> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
|
|
|
@ -10,13 +10,11 @@ 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 webgpu::{WebGPU, WebGPUDevice, WebGPUSampler};
|
use webgpu::{WebGPUDevice, WebGPUSampler};
|
||||||
|
|
||||||
#[dom_struct]
|
#[dom_struct]
|
||||||
pub struct GPUSampler {
|
pub struct GPUSampler {
|
||||||
reflector_: Reflector,
|
reflector_: Reflector,
|
||||||
#[ignore_malloc_size_of = "channels are hard"]
|
|
||||||
channel: WebGPU,
|
|
||||||
label: DomRefCell<Option<DOMString>>,
|
label: DomRefCell<Option<DOMString>>,
|
||||||
device: WebGPUDevice,
|
device: WebGPUDevice,
|
||||||
compare_enable: bool,
|
compare_enable: bool,
|
||||||
|
@ -26,7 +24,6 @@ pub struct GPUSampler {
|
||||||
|
|
||||||
impl GPUSampler {
|
impl GPUSampler {
|
||||||
fn new_inherited(
|
fn new_inherited(
|
||||||
channel: WebGPU,
|
|
||||||
device: WebGPUDevice,
|
device: WebGPUDevice,
|
||||||
compare_enable: bool,
|
compare_enable: bool,
|
||||||
sampler: WebGPUSampler,
|
sampler: WebGPUSampler,
|
||||||
|
@ -34,7 +31,6 @@ impl GPUSampler {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reflector_: Reflector::new(),
|
reflector_: Reflector::new(),
|
||||||
channel,
|
|
||||||
label: DomRefCell::new(None),
|
label: DomRefCell::new(None),
|
||||||
valid: Cell::new(valid),
|
valid: Cell::new(valid),
|
||||||
device,
|
device,
|
||||||
|
@ -45,7 +41,6 @@ impl GPUSampler {
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
global: &GlobalScope,
|
global: &GlobalScope,
|
||||||
channel: WebGPU,
|
|
||||||
device: WebGPUDevice,
|
device: WebGPUDevice,
|
||||||
compare_enable: bool,
|
compare_enable: bool,
|
||||||
sampler: WebGPUSampler,
|
sampler: WebGPUSampler,
|
||||||
|
@ -53,7 +48,6 @@ impl GPUSampler {
|
||||||
) -> DomRoot<Self> {
|
) -> DomRoot<Self> {
|
||||||
reflect_dom_object(
|
reflect_dom_object(
|
||||||
Box::new(GPUSampler::new_inherited(
|
Box::new(GPUSampler::new_inherited(
|
||||||
channel,
|
|
||||||
device,
|
device,
|
||||||
compare_enable,
|
compare_enable,
|
||||||
sampler,
|
sampler,
|
||||||
|
@ -64,6 +58,16 @@ impl GPUSampler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl GPUSampler {
|
||||||
|
pub fn id(&self) -> WebGPUSampler {
|
||||||
|
self.sampler
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_valid(&self) -> bool {
|
||||||
|
self.valid.get()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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> {
|
||||||
|
|
|
@ -7,7 +7,7 @@ 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;
|
||||||
|
@ -122,23 +122,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 +180,7 @@ 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)
|
GPUTextureView::new(&self.global(), texture_view, &self, self.valid.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://gpuweb.github.io/gpuweb/#dom-gputexture-destroy
|
/// https://gpuweb.github.io/gpuweb/#dom-gputexture-destroy
|
||||||
|
|
|
@ -5,27 +5,32 @@
|
||||||
use crate::dom::bindings::cell::DomRefCell;
|
use crate::dom::bindings::cell::DomRefCell;
|
||||||
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 webgpu::WebGPUTextureView;
|
||||||
|
|
||||||
#[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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
||||||
|
) -> 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),
|
||||||
|
@ -35,11 +40,11 @@ impl GPUTextureView {
|
||||||
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> {
|
) -> 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)),
|
||||||
global,
|
global,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -49,6 +54,10 @@ 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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,12 @@ 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";
|
|
||||||
GPUTextureFormat storageTextureFormat;
|
|
||||||
boolean multisampled = false;
|
|
||||||
boolean hasDynamicOffset = false;
|
boolean hasDynamicOffset = false;
|
||||||
|
GPUSize64 minBufferBindingSize = 0;
|
||||||
|
GPUTextureViewDimension viewDimension;
|
||||||
|
GPUTextureComponentType textureComponentType;
|
||||||
|
boolean multisampled = false;
|
||||||
|
GPUTextureFormat storageTextureFormat;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum GPUBindingType {
|
enum GPUBindingType {
|
||||||
|
@ -28,8 +29,8 @@ enum GPUBindingType {
|
||||||
"storage-buffer",
|
"storage-buffer",
|
||||||
"readonly-storage-buffer",
|
"readonly-storage-buffer",
|
||||||
"sampler",
|
"sampler",
|
||||||
|
"comparison-sampler",
|
||||||
"sampled-texture",
|
"sampled-texture",
|
||||||
"readonly-storage-texture",
|
"readonly-storage-texture",
|
||||||
"writeonly-storage-texture",
|
"writeonly-storage-texture"
|
||||||
//"comparison-sampler",
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,8 +8,8 @@ use wgpu::{
|
||||||
hub::{GlobalIdentityHandlerFactory, IdentityHandler, IdentityHandlerFactory},
|
hub::{GlobalIdentityHandlerFactory, IdentityHandler, IdentityHandlerFactory},
|
||||||
id::{
|
id::{
|
||||||
AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, ComputePipelineId,
|
AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, ComputePipelineId,
|
||||||
DeviceId, PipelineLayoutId, RenderPipelineId, SamplerId, ShaderModuleId, SurfaceId,
|
DeviceId, PipelineLayoutId, RenderBundleId, RenderPipelineId, SamplerId, ShaderModuleId,
|
||||||
SwapChainId, TextureId, TextureViewId, TypedId,
|
SurfaceId, SwapChainId, TextureId, TextureViewId, TypedId,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use wgt::Backend;
|
use wgt::Backend;
|
||||||
|
@ -31,6 +31,7 @@ pub enum WebGPUMsg {
|
||||||
FreeSampler(SamplerId),
|
FreeSampler(SamplerId),
|
||||||
FreeSurface(SurfaceId),
|
FreeSurface(SurfaceId),
|
||||||
FreeShaderModule(ShaderModuleId),
|
FreeShaderModule(ShaderModuleId),
|
||||||
|
FreeRenderBundle(RenderBundleId),
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,6 +74,7 @@ impl_identity_handler!(BufferId, "buffer", WebGPUMsg::FreeBuffer);
|
||||||
impl_identity_handler!(BindGroupId, "bind_group", WebGPUMsg::FreeBindGroup);
|
impl_identity_handler!(BindGroupId, "bind_group", WebGPUMsg::FreeBindGroup);
|
||||||
impl_identity_handler!(SwapChainId, "swap_chain", WebGPUMsg::FreeSwapChain);
|
impl_identity_handler!(SwapChainId, "swap_chain", WebGPUMsg::FreeSwapChain);
|
||||||
impl_identity_handler!(ShaderModuleId, "shader_module", WebGPUMsg::FreeShaderModule);
|
impl_identity_handler!(ShaderModuleId, "shader_module", WebGPUMsg::FreeShaderModule);
|
||||||
|
impl_identity_handler!(RenderBundleId, "render_bundle", WebGPUMsg::FreeRenderBundle);
|
||||||
impl_identity_handler!(
|
impl_identity_handler!(
|
||||||
RenderPipelineId,
|
RenderPipelineId,
|
||||||
"render_pipeline",
|
"render_pipeline",
|
||||||
|
|
|
@ -28,9 +28,7 @@ use webrender_traits::{
|
||||||
WebrenderImageSource,
|
WebrenderImageSource,
|
||||||
};
|
};
|
||||||
use wgpu::{
|
use wgpu::{
|
||||||
binding_model::{
|
binding_model::{BindGroupDescriptor, BindGroupEntry, BindingResource, BufferBinding},
|
||||||
BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
|
|
||||||
},
|
|
||||||
command::{BufferCopyView, TextureCopyView},
|
command::{BufferCopyView, TextureCopyView},
|
||||||
device::HostMap,
|
device::HostMap,
|
||||||
id,
|
id,
|
||||||
|
@ -73,12 +71,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<(u32, WebGPUBindings)>,
|
||||||
},
|
},
|
||||||
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<wgt::BindGroupLayoutEntry>,
|
||||||
},
|
},
|
||||||
CreateBuffer {
|
CreateBuffer {
|
||||||
device_id: id::DeviceId,
|
device_id: id::DeviceId,
|
||||||
|
@ -195,6 +193,13 @@ pub enum WebGPURequest {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize)]
|
||||||
|
pub enum WebGPUBindings {
|
||||||
|
Buffer(BufferBinding),
|
||||||
|
Sampler(id::SamplerId),
|
||||||
|
TextureView(id::TextureViewId),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct WebGPU(pub IpcSender<WebGPURequest>);
|
pub struct WebGPU(pub IpcSender<WebGPURequest>);
|
||||||
|
|
||||||
|
@ -334,14 +339,27 @@ impl WGPU {
|
||||||
device_id,
|
device_id,
|
||||||
bind_group_id,
|
bind_group_id,
|
||||||
bind_group_layout_id,
|
bind_group_layout_id,
|
||||||
bindings,
|
mut entries,
|
||||||
} => {
|
} => {
|
||||||
let global = &self.global;
|
let global = &self.global;
|
||||||
|
let bindings = entries
|
||||||
|
.drain(..)
|
||||||
|
.map(|(bind, res)| {
|
||||||
|
let resource = match res {
|
||||||
|
WebGPUBindings::Sampler(s) => BindingResource::Sampler(s),
|
||||||
|
WebGPUBindings::TextureView(t) => BindingResource::TextureView(t),
|
||||||
|
WebGPUBindings::Buffer(b) => BindingResource::Buffer(b),
|
||||||
|
};
|
||||||
|
BindGroupEntry {
|
||||||
|
binding: bind,
|
||||||
|
resource,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let descriptor = BindGroupDescriptor {
|
let descriptor = BindGroupDescriptor {
|
||||||
|
label: None,
|
||||||
layout: bind_group_layout_id,
|
layout: bind_group_layout_id,
|
||||||
entries: bindings.as_ptr(),
|
bindings: bindings.as_slice(),
|
||||||
entries_length: bindings.len(),
|
|
||||||
label: ptr::null(),
|
|
||||||
};
|
};
|
||||||
let _ = gfx_select!(bind_group_id =>
|
let _ = gfx_select!(bind_group_id =>
|
||||||
global.device_create_bind_group(device_id, &descriptor, bind_group_id));
|
global.device_create_bind_group(device_id, &descriptor, bind_group_id));
|
||||||
|
@ -349,13 +367,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 = wgt::BindGroupLayoutDescriptor {
|
||||||
entries: bindings.as_ptr(),
|
bindings: entries.as_slice(),
|
||||||
entries_length: bindings.len(),
|
label: None,
|
||||||
label: ptr::null(),
|
|
||||||
};
|
};
|
||||||
let _ = gfx_select!(bind_group_layout_id =>
|
let _ = gfx_select!(bind_group_layout_id =>
|
||||||
global.device_create_bind_group_layout(device_id, &descriptor, bind_group_layout_id));
|
global.device_create_bind_group_layout(device_id, &descriptor, bind_group_layout_id));
|
||||||
|
@ -375,18 +392,9 @@ impl WGPU {
|
||||||
command_encoder_id,
|
command_encoder_id,
|
||||||
} => {
|
} => {
|
||||||
let global = &self.global;
|
let global = &self.global;
|
||||||
|
let desc = wgt::CommandEncoderDescriptor { label: ptr::null() };
|
||||||
let _ = gfx_select!(command_encoder_id =>
|
let _ = gfx_select!(command_encoder_id =>
|
||||||
global.device_create_command_encoder(device_id, &Default::default(), command_encoder_id));
|
global.device_create_command_encoder(device_id, &desc, command_encoder_id));
|
||||||
},
|
|
||||||
WebGPURequest::CreateContext(sender) => {
|
|
||||||
let id = self
|
|
||||||
.external_images
|
|
||||||
.lock()
|
|
||||||
.expect("Lock poisoned?")
|
|
||||||
.next_id(WebrenderImageHandlerType::WebGPU);
|
|
||||||
if let Err(e) = sender.send(id) {
|
|
||||||
warn!("Failed to send ExternalImageId to new context ({})", e);
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
WebGPURequest::CreateComputePipeline {
|
WebGPURequest::CreateComputePipeline {
|
||||||
device_id,
|
device_id,
|
||||||
|
@ -407,6 +415,16 @@ impl WGPU {
|
||||||
let _ = gfx_select!(compute_pipeline_id =>
|
let _ = gfx_select!(compute_pipeline_id =>
|
||||||
global.device_create_compute_pipeline(device_id, &descriptor, compute_pipeline_id));
|
global.device_create_compute_pipeline(device_id, &descriptor, compute_pipeline_id));
|
||||||
},
|
},
|
||||||
|
WebGPURequest::CreateContext(sender) => {
|
||||||
|
let id = self
|
||||||
|
.external_images
|
||||||
|
.lock()
|
||||||
|
.expect("Lock poisoned?")
|
||||||
|
.next_id(WebrenderImageHandlerType::WebGPU);
|
||||||
|
if let Err(e) = sender.send(id) {
|
||||||
|
warn!("Failed to send ExternalImageId to new context ({})", e);
|
||||||
|
};
|
||||||
|
},
|
||||||
WebGPURequest::CreatePipelineLayout {
|
WebGPURequest::CreatePipelineLayout {
|
||||||
device_id,
|
device_id,
|
||||||
pipeline_layout_id,
|
pipeline_layout_id,
|
||||||
|
@ -631,6 +649,7 @@ impl WGPU {
|
||||||
} => {
|
} => {
|
||||||
let adapter_id = match self.global.pick_adapter(
|
let adapter_id = match self.global.pick_adapter(
|
||||||
&options,
|
&options,
|
||||||
|
wgt::UnsafeExtensions::disallow(),
|
||||||
wgpu::instance::AdapterInputs::IdSet(&ids, |id| id.backend()),
|
wgpu::instance::AdapterInputs::IdSet(&ids, |id| id.backend()),
|
||||||
) {
|
) {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
|
@ -749,9 +768,10 @@ impl WGPU {
|
||||||
}
|
}
|
||||||
|
|
||||||
let buffer_size = (size.height as u32 * buffer_stride) as wgt::BufferAddress;
|
let buffer_size = (size.height as u32 * buffer_stride) as wgt::BufferAddress;
|
||||||
|
let comm_desc = wgt::CommandEncoderDescriptor { label: ptr::null() };
|
||||||
let _ = gfx_select!(encoder_id => global.device_create_command_encoder(
|
let _ = gfx_select!(encoder_id => global.device_create_command_encoder(
|
||||||
device_id,
|
device_id,
|
||||||
&wgt::CommandEncoderDescriptor::default(),
|
&comm_desc,
|
||||||
encoder_id
|
encoder_id
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue