aboutsummaryrefslogtreecommitdiffstats
path: root/components/webgpu
diff options
context:
space:
mode:
Diffstat (limited to 'components/webgpu')
-rw-r--r--components/webgpu/dom_messages.rs42
-rw-r--r--components/webgpu/identity.rs3
-rw-r--r--components/webgpu/script_messages.rs7
-rw-r--r--components/webgpu/wgpu_thread.rs185
4 files changed, 191 insertions, 46 deletions
diff --git a/components/webgpu/dom_messages.rs b/components/webgpu/dom_messages.rs
index f9f0fc0ffe5..78bde1c91b2 100644
--- a/components/webgpu/dom_messages.rs
+++ b/components/webgpu/dom_messages.rs
@@ -16,8 +16,7 @@ use wgc::binding_model::{
BindGroupDescriptor, BindGroupLayoutDescriptor, PipelineLayoutDescriptor,
};
use wgc::command::{
- ComputePass, ImageCopyBuffer, ImageCopyTexture, RenderBundleDescriptor, RenderBundleEncoder,
- RenderPass,
+ ImageCopyBuffer, ImageCopyTexture, RenderBundleDescriptor, RenderBundleEncoder, RenderPass,
};
use wgc::device::HostMap;
use wgc::id;
@@ -191,6 +190,7 @@ pub enum WebGPURequest {
DropShaderModule(id::ShaderModuleId),
DropRenderBundle(id::RenderBundleId),
DropQuerySet(id::QuerySetId),
+ DropComputePass(id::ComputePassEncoderId),
Exit(IpcSender<()>),
RenderBundleEncoderFinish {
render_bundle_encoder: RenderBundleEncoder,
@@ -210,13 +210,45 @@ pub enum WebGPURequest {
device_id: id::DeviceId,
pipeline_id: PipelineId,
},
- RunComputePass {
+ BeginComputePass {
command_encoder_id: id::CommandEncoderId,
- compute_pass: Option<ComputePass>,
+ compute_pass_id: ComputePassId,
+ label: Option<Cow<'static, str>>,
+ device_id: id::DeviceId,
+ },
+ ComputePassSetPipeline {
+ compute_pass_id: ComputePassId,
+ pipeline_id: id::ComputePipelineId,
+ device_id: id::DeviceId,
+ },
+ ComputePassSetBindGroup {
+ compute_pass_id: ComputePassId,
+ index: u32,
+ bind_group_id: id::BindGroupId,
+ offsets: Vec<u32>,
+ device_id: id::DeviceId,
+ },
+ ComputePassDispatchWorkgroups {
+ compute_pass_id: ComputePassId,
+ x: u32,
+ y: u32,
+ z: u32,
+ device_id: id::DeviceId,
+ },
+ ComputePassDispatchWorkgroupsIndirect {
+ compute_pass_id: ComputePassId,
+ buffer_id: id::BufferId,
+ offset: u64,
+ device_id: id::DeviceId,
},
- RunRenderPass {
+ EndComputePass {
+ compute_pass_id: ComputePassId,
+ device_id: id::DeviceId,
command_encoder_id: id::CommandEncoderId,
+ },
+ EndRenderPass {
render_pass: Option<RenderPass>,
+ device_id: id::DeviceId,
},
Submit {
queue_id: id::QueueId,
diff --git a/components/webgpu/identity.rs b/components/webgpu/identity.rs
index 86ea497f67d..bb1cb1ca4a0 100644
--- a/components/webgpu/identity.rs
+++ b/components/webgpu/identity.rs
@@ -5,6 +5,8 @@
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use serde::{Deserialize, Serialize};
+pub use crate::wgc::id::markers::ComputePassEncoder as ComputePass;
+pub use crate::wgc::id::ComputePassEncoderId as ComputePassId;
use crate::wgc::id::{
AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, CommandEncoderId,
ComputePipelineId, DeviceId, PipelineLayoutId, QueueId, RenderBundleId, RenderPipelineId,
@@ -43,3 +45,4 @@ webgpu_resource!(WebGPUShaderModule, ShaderModuleId);
webgpu_resource!(WebGPUSurface, SurfaceId);
webgpu_resource!(WebGPUTexture, TextureId);
webgpu_resource!(WebGPUTextureView, TextureViewId);
+webgpu_resource!(WebGPUComputePass, ComputePassId);
diff --git a/components/webgpu/script_messages.rs b/components/webgpu/script_messages.rs
index 15fe198386d..774bfd6cb7c 100644
--- a/components/webgpu/script_messages.rs
+++ b/components/webgpu/script_messages.rs
@@ -10,9 +10,9 @@ use serde::{Deserialize, Serialize};
use crate::gpu_error::Error;
use crate::identity::WebGPUDevice;
use crate::wgc::id::{
- AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, ComputePipelineId,
- DeviceId, PipelineLayoutId, QuerySetId, RenderBundleId, RenderPipelineId, SamplerId,
- ShaderModuleId, StagingBufferId, SurfaceId, TextureId, TextureViewId,
+ AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, ComputePassEncoderId,
+ ComputePipelineId, DeviceId, PipelineLayoutId, QuerySetId, RenderBundleId, RenderPipelineId,
+ SamplerId, ShaderModuleId, StagingBufferId, SurfaceId, TextureId, TextureViewId,
};
/// <https://gpuweb.github.io/gpuweb/#enumdef-gpudevicelostreason>
@@ -44,6 +44,7 @@ pub enum WebGPUMsg {
FreeRenderBundle(RenderBundleId),
FreeStagingBuffer(StagingBufferId),
FreeQuerySet(QuerySetId),
+ FreeComputePass(ComputePassEncoderId),
UncapturedError {
device: WebGPUDevice,
pipeline_id: PipelineId,
diff --git a/components/webgpu/wgpu_thread.rs b/components/webgpu/wgpu_thread.rs
index f98fd2869a3..9688bb0726a 100644
--- a/components/webgpu/wgpu_thread.rs
+++ b/components/webgpu/wgpu_thread.rs
@@ -4,7 +4,6 @@
//! Data and main loop of WebGPU thread.
-use std::cell::RefCell;
use std::collections::HashMap;
use std::slice;
use std::sync::{Arc, Mutex};
@@ -26,14 +25,15 @@ use wgc::instance::parse_backends_from_comma_list;
use wgc::pipeline::ShaderModuleDescriptor;
use wgc::resource::{BufferMapCallback, BufferMapOperation};
use wgc::{gfx_select, id};
+use wgpu_core::command::{ComputePassDescriptor, DynComputePass};
use wgt::InstanceDescriptor;
pub use {wgpu_core as wgc, wgpu_types as wgt};
use crate::gpu_error::ErrorScope;
use crate::poll_thread::Poller;
use crate::{
- Error, PopError, PresentationData, Transmute, WebGPU, WebGPUAdapter, WebGPUDevice, WebGPUMsg,
- WebGPUQueue, WebGPURequest, WebGPUResponse,
+ ComputePassId, Error, PopError, PresentationData, Transmute, WebGPU, WebGPUAdapter,
+ WebGPUDevice, WebGPUMsg, WebGPUQueue, WebGPURequest, WebGPUResponse,
};
pub const PRESENTATION_BUFFER_COUNT: usize = 10;
@@ -73,13 +73,20 @@ pub(crate) struct WGPU {
devices: Arc<Mutex<HashMap<DeviceId, DeviceScope>>>,
// Track invalid adapters https://gpuweb.github.io/gpuweb/#invalid
_invalid_adapters: Vec<WebGPUAdapter>,
- //TODO: Remove this (https://github.com/gfx-rs/wgpu/issues/867)
- error_command_encoders: RefCell<HashMap<id::CommandEncoderId, String>>,
+ // TODO: Remove this (https://github.com/gfx-rs/wgpu/issues/867)
+ /// This stores first error on command encoder,
+ /// because wgpu does not invalidate command encoder object
+ /// (this is also reused for invalidation of command buffers)
+ error_command_encoders: HashMap<id::CommandEncoderId, String>,
webrender_api: Arc<Mutex<RenderApi>>,
webrender_document: DocumentId,
external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
wgpu_image_map: Arc<Mutex<HashMap<u64, PresentationData>>>,
+ /// Provides access to poller thread
poller: Poller,
+ /// Store compute passes (that have not ended yet) and their validity
+ compute_passes: HashMap<ComputePassId, (Box<dyn DynComputePass>, bool)>,
+ //render_passes: HashMap<RenderPassId, Box<dyn DynRenderPass>>,
}
impl WGPU {
@@ -118,11 +125,12 @@ impl WGPU {
adapters: Vec::new(),
devices: Arc::new(Mutex::new(HashMap::new())),
_invalid_adapters: Vec::new(),
- error_command_encoders: RefCell::new(HashMap::new()),
+ error_command_encoders: HashMap::new(),
webrender_api: Arc::new(Mutex::new(webrender_api_sender.create_api())),
webrender_document,
external_images,
wgpu_image_map,
+ compute_passes: HashMap::new(),
}
}
@@ -199,13 +207,11 @@ impl WGPU {
} => {
let global = &self.global;
let result = if is_error {
- Err(Error::Internal(String::from("Invalid GPUCommandEncoder")))
- } else if let Some(err) = self
- .error_command_encoders
- .borrow()
- .get(&command_encoder_id)
+ Err(Error::Validation(String::from("Invalid GPUCommandEncoder")))
+ } else if let Some(err) =
+ self.error_command_encoders.get(&command_encoder_id)
{
- Err(Error::Internal(err.clone()))
+ Err(Error::Validation(err.clone()))
} else if let Some(error) =
gfx_select!(command_encoder_id => global.command_encoder_finish(
command_encoder_id,
@@ -218,7 +224,9 @@ impl WGPU {
Ok(())
};
+ // invalidate command buffer too
self.encoder_record_error(command_encoder_id, &result);
+ // dispatch validation error
self.maybe_dispatch_error(device_id, result.err());
},
WebGPURequest::CopyBufferToBuffer {
@@ -575,7 +583,6 @@ impl WGPU {
},
WebGPURequest::DropCommandBuffer(id) => {
self.error_command_encoders
- .borrow_mut()
.remove(&id.into_command_encoder_id());
let global = &self.global;
gfx_select!(id => global.command_buffer_drop(id));
@@ -745,35 +752,129 @@ impl WGPU {
)
}
},
- WebGPURequest::RunComputePass {
+ WebGPURequest::BeginComputePass {
command_encoder_id,
- compute_pass,
+ compute_pass_id,
+ label,
+ device_id: _device_id,
} => {
let global = &self.global;
- let result = if let Some(pass) = compute_pass {
- gfx_select!(command_encoder_id => global.command_encoder_run_compute_pass(
+ let (pass, error) = gfx_select!(
+ command_encoder_id => global.command_encoder_create_compute_pass_dyn(
command_encoder_id,
- &pass
- )).map_err(|e| format!("{:?}", e))
+ &ComputePassDescriptor { label, timestamp_writes: None }
+ ));
+ assert!(
+ self.compute_passes
+ .insert(compute_pass_id, (pass, error.is_none()))
+ .is_none(),
+ "ComputePass should not exist yet."
+ );
+ // TODO: Command encoder state errors
+ // self.maybe_dispatch_wgpu_error(device_id, error);
+ },
+ WebGPURequest::ComputePassSetPipeline {
+ compute_pass_id,
+ pipeline_id,
+ device_id,
+ } => {
+ if let Some((pass, valid)) = self.compute_passes.get_mut(&compute_pass_id) {
+ *valid &= pass.set_pipeline(&self.global, pipeline_id).is_ok();
} else {
- Err(String::from("Invalid ComputePass"))
+ self.maybe_dispatch_error(
+ device_id,
+ Some(Error::Validation("pass already ended".to_string())),
+ );
};
- self.encoder_record_error(command_encoder_id, &result);
},
- WebGPURequest::RunRenderPass {
+ WebGPURequest::ComputePassSetBindGroup {
+ compute_pass_id,
+ index,
+ bind_group_id,
+ offsets,
+ device_id,
+ } => {
+ if let Some((pass, valid)) = self.compute_passes.get_mut(&compute_pass_id) {
+ *valid &= pass
+ .set_bind_group(&self.global, index, bind_group_id, &offsets)
+ .is_ok();
+ } else {
+ self.maybe_dispatch_error(
+ device_id,
+ Some(Error::Validation("pass already ended".to_string())),
+ );
+ };
+ },
+ WebGPURequest::ComputePassDispatchWorkgroups {
+ compute_pass_id,
+ x,
+ y,
+ z,
+ device_id,
+ } => {
+ if let Some((pass, valid)) = self.compute_passes.get_mut(&compute_pass_id) {
+ *valid &= pass.dispatch_workgroups(&self.global, x, y, z).is_ok();
+ } else {
+ self.maybe_dispatch_error(
+ device_id,
+ Some(Error::Validation("pass already ended".to_string())),
+ );
+ };
+ },
+ WebGPURequest::ComputePassDispatchWorkgroupsIndirect {
+ compute_pass_id,
+ buffer_id,
+ offset,
+ device_id,
+ } => {
+ if let Some((pass, valid)) = self.compute_passes.get_mut(&compute_pass_id) {
+ *valid &= pass
+ .dispatch_workgroups_indirect(&self.global, buffer_id, offset)
+ .is_ok();
+ } else {
+ self.maybe_dispatch_error(
+ device_id,
+ Some(Error::Validation("pass already ended".to_string())),
+ );
+ };
+ },
+ WebGPURequest::EndComputePass {
+ compute_pass_id,
+ device_id,
command_encoder_id,
- render_pass,
} => {
- let global = &self.global;
- let result = if let Some(pass) = render_pass {
- gfx_select!(command_encoder_id => global.command_encoder_run_render_pass(
- command_encoder_id,
- &pass
- )).map_err(|e| format!("{:?}", e))
+ // TODO: Command encoder state error
+ if let Some((mut pass, valid)) =
+ self.compute_passes.remove(&compute_pass_id)
+ {
+ if pass.end(&self.global).is_ok() && !valid {
+ self.encoder_record_error(
+ command_encoder_id,
+ &Err::<(), _>("Pass is invalid".to_string()),
+ );
+ }
} else {
- Err(String::from("Invalid RenderPass"))
+ self.dispatch_error(
+ device_id,
+ Error::Validation("pass already ended".to_string()),
+ );
};
- self.encoder_record_error(command_encoder_id, &result);
+ },
+ WebGPURequest::EndRenderPass {
+ render_pass,
+ device_id,
+ } => {
+ if let Some(render_pass) = render_pass {
+ let command_encoder_id = render_pass.parent_id();
+ let global = &self.global;
+ let result = gfx_select!(command_encoder_id => global.render_pass_end(&render_pass));
+ self.maybe_dispatch_wgpu_error(device_id, result.err())
+ } else {
+ self.dispatch_error(
+ device_id,
+ Error::Validation("Render pass already ended".to_string()),
+ )
+ }
},
WebGPURequest::Submit {
queue_id,
@@ -782,11 +883,10 @@ impl WGPU {
let global = &self.global;
let cmd_id = command_buffers.iter().find(|id| {
self.error_command_encoders
- .borrow()
.contains_key(&id.into_command_encoder_id())
});
let result = if cmd_id.is_some() {
- Err(Error::Internal(String::from(
+ Err(Error::Validation(String::from(
"Invalid command buffer submitted",
)))
} else {
@@ -1026,7 +1126,8 @@ impl WGPU {
},
WebGPURequest::DropTexture(id) => {
let global = &self.global;
- gfx_select!(id => global.texture_drop(id, true));
+ gfx_select!(id => global.texture_drop(id, false));
+ self.poller.wake();
if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTexture(id)) {
warn!("Unable to send FreeTexture({:?}) ({:?})", id, e);
};
@@ -1040,7 +1141,8 @@ impl WGPU {
},
WebGPURequest::DropBuffer(id) => {
let global = &self.global;
- gfx_select!(id => global.buffer_drop(id, true));
+ gfx_select!(id => global.buffer_drop(id, false));
+ self.poller.wake();
if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBuffer(id)) {
warn!("Unable to send FreeBuffer({:?}) ({:?})", id, e);
};
@@ -1060,6 +1162,13 @@ impl WGPU {
warn!("Unable to send FreeComputePipeline({:?}) ({:?})", id, e);
};
},
+ WebGPURequest::DropComputePass(id) => {
+ // Compute pass might have already ended
+ self.compute_passes.remove(&id);
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeComputePass(id)) {
+ warn!("Unable to send FreeComputePass({:?}) ({:?})", id, e);
+ };
+ },
WebGPURequest::DropRenderPipeline(id) => {
let global = &self.global;
gfx_select!(id => global.render_pipeline_drop(id));
@@ -1084,7 +1193,8 @@ impl WGPU {
},
WebGPURequest::DropTextureView(id) => {
let global = &self.global;
- let _result = gfx_select!(id => global.texture_view_drop(id, true));
+ let _result = gfx_select!(id => global.texture_view_drop(id, false));
+ self.poller.wake();
if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTextureView(id)) {
warn!("Unable to send FreeTextureView({:?}) ({:?})", id, e);
};
@@ -1214,13 +1324,12 @@ impl WGPU {
}
fn encoder_record_error<U, T: std::fmt::Debug>(
- &self,
+ &mut self,
encoder_id: id::CommandEncoderId,
result: &Result<U, T>,
) {
if let Err(ref e) = result {
self.error_command_encoders
- .borrow_mut()
.entry(encoder_id)
.or_insert_with(|| format!("{:?}", e));
}