diff --git a/crates/wasi-webgpu-wasmtime/src/lib.rs b/crates/wasi-webgpu-wasmtime/src/lib.rs index b558070..cf9f01d 100644 --- a/crates/wasi-webgpu-wasmtime/src/lib.rs +++ b/crates/wasi-webgpu-wasmtime/src/lib.rs @@ -59,8 +59,8 @@ wasmtime::component::bindgen!({ "wasi:webgpu/webgpu/gpu-device": wrapper_types::Device, "wasi:webgpu/webgpu/gpu-queue": wgpu_core::id::QueueId, "wasi:webgpu/webgpu/gpu-command-encoder": wgpu_core::id::CommandEncoderId, - "wasi:webgpu/webgpu/gpu-render-pass-encoder": wrapper_types::RenderPass, - "wasi:webgpu/webgpu/gpu-compute-pass-encoder": wrapper_types::ComputePass, + "wasi:webgpu/webgpu/gpu-render-pass-encoder": wrapper_types::RenderPassEncoder, + "wasi:webgpu/webgpu/gpu-compute-pass-encoder": wrapper_types::ComputePassEncoder, "wasi:webgpu/webgpu/gpu-shader-module": wgpu_core::id::ShaderModuleId, "wasi:webgpu/webgpu/gpu-render-pipeline": wgpu_core::id::RenderPipelineId, "wasi:webgpu/webgpu/gpu-render-bundle-encoder": wgpu_core::command::RenderBundleEncoder, diff --git a/crates/wasi-webgpu-wasmtime/src/trait_impls.rs b/crates/wasi-webgpu-wasmtime/src/trait_impls.rs index b011567..a9b39bb 100644 --- a/crates/wasi-webgpu-wasmtime/src/trait_impls.rs +++ b/crates/wasi-webgpu-wasmtime/src/trait_impls.rs @@ -9,7 +9,7 @@ use wasmtime_wasi::WasiView; use crate::{ to_core_conversions::ToCore, wasi::webgpu::webgpu, - wrapper_types::{Buffer, BufferPtr, Device}, + wrapper_types::{Buffer, BufferPtr, ComputePassEncoder, Device, RenderPassEncoder}, AbstractBuffer, MainThreadSpawner, WasiWebGpuImpl, WasiWebGpuView, WebGpuSurface, }; @@ -756,11 +756,11 @@ impl webgpu::HostGpuTextureView for WasiWebGpuImpl { } impl webgpu::HostGpuCommandBuffer for WasiWebGpuImpl { - fn label(&mut self, _self_: Resource) -> String { + fn label(&mut self, _self_: Resource) -> String { todo!() } - fn set_label(&mut self, _self_: Resource, _label: String) { + fn set_label(&mut self, _self_: Resource, _label: String) { todo!() } @@ -1024,7 +1024,10 @@ impl webgpu::HostGpuCommandEncoder for WasiWebGpuImpl { ) .unwrap(); - self.0.table().push(render_pass).unwrap() + self.0 + .table() + .push(RenderPassEncoder::new(render_pass)) + .unwrap() } fn finish( @@ -1071,7 +1074,10 @@ impl webgpu::HostGpuCommandEncoder for WasiWebGpuImpl { ), ) .unwrap(); - self.0.table().push(compute_pass).unwrap() + self.0 + .table() + .push(ComputePassEncoder::new(compute_pass)) + .unwrap() } fn copy_buffer_to_buffer( @@ -1218,12 +1224,13 @@ impl webgpu::HostGpuCommandEncoder for WasiWebGpuImpl { impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn set_pipeline( &mut self, - render_pass: Resource>, + render_pass: Resource, pipeline: Resource, ) { let instance = self.0.instance(); let pipeline = pipeline.to_core(&self.0.table()); - let render_pass = self.0.table().get_mut(&render_pass).unwrap(); + let mut render_pass = self.0.table().get_mut(&render_pass).unwrap().lock(); + let render_pass = render_pass.as_mut().unwrap(); instance .render_pass_set_pipeline(render_pass, pipeline) .unwrap() @@ -1231,17 +1238,18 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn draw( &mut self, - rpass: Resource>, + render_pass: Resource, vertex_count: webgpu::GpuSize32, instance_count: Option, first_vertex: Option, first_instance: Option, ) { let instance = self.0.instance(); - let rpass = self.0.table().get_mut(&rpass).unwrap(); + let mut render_pass = self.0.table().get_mut(&render_pass).unwrap().lock(); + let render_pass = render_pass.as_mut().unwrap(); instance .render_pass_draw( - rpass, + render_pass, vertex_count, instance_count.unwrap_or(1), first_vertex.unwrap_or(0), @@ -1250,17 +1258,18 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { .unwrap() } - fn end(&mut self, rpass: Resource>) { + fn end(&mut self, render_pass: Resource) { let instance = self.0.instance(); - let mut rpass = self.0.table().get_mut(&rpass).unwrap(); + let mut render_pass = self.0.table().get_mut(&render_pass).unwrap().lock(); + let mut render_pass = render_pass.take().unwrap(); instance - .render_pass_end::(&mut rpass) + .render_pass_end::(&mut render_pass) .unwrap(); } fn set_viewport( &mut self, - render_pass: Resource>, + render_pass: Resource, x: f32, y: f32, width: f32, @@ -1269,7 +1278,8 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { max_depth: f32, ) { let instance = self.0.instance(); - let render_pass = self.0.table().get_mut(&render_pass).unwrap(); + let mut render_pass = self.0.table().get_mut(&render_pass).unwrap().lock(); + let render_pass = render_pass.as_mut().unwrap(); instance .render_pass_set_viewport(render_pass, x, y, width, height, min_depth, max_depth) .unwrap(); @@ -1277,14 +1287,15 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn set_scissor_rect( &mut self, - render_pass: Resource>, + render_pass: Resource, x: webgpu::GpuIntegerCoordinate, y: webgpu::GpuIntegerCoordinate, width: webgpu::GpuIntegerCoordinate, height: webgpu::GpuIntegerCoordinate, ) { let instance = self.0.instance(); - let render_pass = self.0.table().get_mut(&render_pass).unwrap(); + let mut render_pass = self.0.table().get_mut(&render_pass).unwrap().lock(); + let render_pass = render_pass.as_mut().unwrap(); instance .render_pass_set_scissor_rect(render_pass, x, y, width, height) .unwrap(); @@ -1292,7 +1303,7 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn set_blend_constant( &mut self, - _self_: Resource>, + _self_: Resource, _color: webgpu::GpuColor, ) { todo!() @@ -1300,7 +1311,7 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn set_stencil_reference( &mut self, - _self_: Resource>, + _self_: Resource, _reference: webgpu::GpuStencilValue, ) { todo!() @@ -1308,68 +1319,47 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn begin_occlusion_query( &mut self, - _self_: Resource>, + _self_: Resource, _query_index: webgpu::GpuSize32, ) { todo!() } - fn end_occlusion_query( - &mut self, - _self_: Resource>, - ) { + fn end_occlusion_query(&mut self, _self_: Resource) { todo!() } fn execute_bundles( &mut self, - _self_: Resource>, + _self_: Resource, _bundles: Vec>, ) { todo!() } - fn label( - &mut self, - _self_: Resource>, - ) -> String { + fn label(&mut self, _self_: Resource) -> String { todo!() } - fn set_label( - &mut self, - _self_: Resource>, - _label: String, - ) { + fn set_label(&mut self, _self_: Resource, _label: String) { todo!() } - fn push_debug_group( - &mut self, - _self_: Resource>, - _group_label: String, - ) { + fn push_debug_group(&mut self, _self_: Resource, _group_label: String) { todo!() } - fn pop_debug_group( - &mut self, - _self_: Resource>, - ) { + fn pop_debug_group(&mut self, _self_: Resource) { todo!() } - fn insert_debug_marker( - &mut self, - _self_: Resource>, - _marker_label: String, - ) { + fn insert_debug_marker(&mut self, _self_: Resource, _marker_label: String) { todo!() } fn set_bind_group( &mut self, - render_pass: Resource>, + render_pass: Resource, index: webgpu::GpuIndex32, bind_group: Option>, dynamic_offsets: Option>, @@ -1380,7 +1370,8 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { .table() .get(&bind_group.expect("TODO: deal with null bind_groups")) .unwrap(); - let mut render_pass = self.0.table().get_mut(&render_pass).unwrap(); + let mut render_pass = self.0.table().get_mut(&render_pass).unwrap().lock(); + let mut render_pass = render_pass.as_mut().unwrap(); let dynamic_offsets = dynamic_offsets.unwrap(); instance .render_pass_set_bind_group(&mut render_pass, index, bind_group, &dynamic_offsets) @@ -1389,7 +1380,7 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn set_index_buffer( &mut self, - render_pass: Resource>, + render_pass: Resource, buffer: Resource, index_format: webgpu::GpuIndexFormat, offset: Option, @@ -1400,7 +1391,8 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { let buffer = self.table().get(&buffer).unwrap(); (buffer.buffer_id, buffer.size) }; - let render_pass = self.table().get_mut(&render_pass).unwrap(); + let mut render_pass = self.0.table().get_mut(&render_pass).unwrap().lock(); + let render_pass = render_pass.as_mut().unwrap(); instance .render_pass_set_index_buffer( render_pass, @@ -1414,7 +1406,7 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn set_vertex_buffer( &mut self, - render_pass: Resource>, + render_pass: Resource, slot: webgpu::GpuIndex32, buffer: Option>, offset: Option, @@ -1428,7 +1420,8 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { .unwrap(); (buffer.buffer_id, buffer.size) }; - let mut render_pass = self.0.table().get_mut(&render_pass).unwrap(); + let mut render_pass = self.0.table().get_mut(&render_pass).unwrap().lock(); + let mut render_pass = render_pass.as_mut().unwrap(); instance .render_pass_set_vertex_buffer( &mut render_pass, @@ -1442,7 +1435,7 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn draw_indexed( &mut self, - render_pass: Resource>, + render_pass: Resource, index_count: webgpu::GpuSize32, instance_count: Option, first_index: Option, @@ -1450,7 +1443,8 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { first_instance: Option, ) { let instance = self.0.instance(); - let render_pass = self.table().get_mut(&render_pass).unwrap(); + let mut render_pass = self.0.table().get_mut(&render_pass).unwrap().lock(); + let render_pass = render_pass.as_mut().unwrap(); instance .render_pass_draw_indexed( render_pass, @@ -1465,7 +1459,7 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn draw_indirect( &mut self, - _self_: Resource>, + _self_: Resource, _indirect_buffer: Resource, _indirect_offset: webgpu::GpuSize64, ) { @@ -1474,17 +1468,14 @@ impl webgpu::HostGpuRenderPassEncoder for WasiWebGpuImpl { fn draw_indexed_indirect( &mut self, - _self_: Resource>, + _self_: Resource, _indirect_buffer: Resource, _indirect_offset: webgpu::GpuSize64, ) { todo!() } - fn drop( - &mut self, - render_pass: Resource>, - ) -> wasmtime::Result<()> { + fn drop(&mut self, render_pass: Resource) -> wasmtime::Result<()> { self.table().delete(render_pass).unwrap(); Ok(()) } @@ -1621,29 +1612,31 @@ impl webgpu::HostGpuRenderBundle for WasiWebGpuImpl { impl webgpu::HostGpuComputePassEncoder for WasiWebGpuImpl { fn set_pipeline( &mut self, - encoder: Resource, + compute_pass: Resource, pipeline: Resource, ) { let instance = self.0.instance(); let pipeline = *self.0.table().get(&pipeline).unwrap(); - let encoder = self.0.table().get_mut(&encoder).unwrap(); + let mut compute_pass = self.0.table().get_mut(&compute_pass).unwrap().lock(); + let compute_pass = compute_pass.as_mut().unwrap(); instance - .compute_pass_set_pipeline(encoder, pipeline) + .compute_pass_set_pipeline(compute_pass, pipeline) .unwrap(); } fn dispatch_workgroups( &mut self, - encoder: Resource, + compute_pass: Resource, workgroup_count_x: webgpu::GpuSize32, workgroup_count_y: Option, workgroup_count_z: Option, ) { let instance = self.0.instance(); - let encoder = self.0.table().get_mut(&encoder).unwrap(); + let mut compute_pass = self.0.table().get_mut(&compute_pass).unwrap().lock(); + let compute_pass = compute_pass.as_mut().unwrap(); instance .compute_pass_dispatch_workgroups( - encoder, + compute_pass, workgroup_count_x, workgroup_count_y.unwrap(), workgroup_count_z.unwrap(), @@ -1653,23 +1646,29 @@ impl webgpu::HostGpuComputePassEncoder for WasiWebGpuImpl fn dispatch_workgroups_indirect( &mut self, - encoder: Resource, + compute_pass: Resource, indirect_buffer: Resource, indirect_offset: webgpu::GpuSize64, ) { let instance = self.instance(); let indirect_buffer = self.0.table().get(&indirect_buffer).unwrap().buffer_id; - let encoder = self.0.table().get_mut(&encoder).unwrap(); + let mut compute_pass = self.0.table().get_mut(&compute_pass).unwrap().lock(); + let compute_pass = compute_pass.as_mut().unwrap(); instance - .compute_pass_dispatch_workgroups_indirect(encoder, indirect_buffer, indirect_offset) + .compute_pass_dispatch_workgroups_indirect( + compute_pass, + indirect_buffer, + indirect_offset, + ) .unwrap(); } - fn end(&mut self, cpass: Resource>) { + fn end(&mut self, compute_pass: Resource) { let instance = self.0.instance(); - let mut cpass = self.0.table().get_mut(&cpass).unwrap(); + let mut compute_pass = self.0.table().get_mut(&compute_pass).unwrap().lock(); + let mut compute_pass = compute_pass.take().unwrap(); instance - .compute_pass_end::(&mut cpass) + .compute_pass_end::(&mut compute_pass) .unwrap(); } @@ -1683,37 +1682,40 @@ impl webgpu::HostGpuComputePassEncoder for WasiWebGpuImpl fn push_debug_group( &mut self, - cpass: Resource, + compute_pass: Resource, group_label: String, ) { let instance = self.instance(); - let cpass = self.table().get_mut(&cpass).unwrap(); + let mut compute_pass = self.0.table().get_mut(&compute_pass).unwrap().lock(); + let compute_pass = compute_pass.as_mut().unwrap(); instance - .compute_pass_push_debug_group(cpass, &group_label, 0) + .compute_pass_push_debug_group(compute_pass, &group_label, 0) .unwrap(); } - fn pop_debug_group(&mut self, cpass: Resource) { + fn pop_debug_group(&mut self, compute_pass: Resource) { let instance = self.instance(); - let cpass = self.table().get_mut(&cpass).unwrap(); - instance.compute_pass_pop_debug_group(cpass).unwrap(); + let mut compute_pass = self.0.table().get_mut(&compute_pass).unwrap().lock(); + let compute_pass = compute_pass.as_mut().unwrap(); + instance.compute_pass_pop_debug_group(compute_pass).unwrap(); } fn insert_debug_marker( &mut self, - cpass: Resource, + compute_pass: Resource, label: String, ) { let instance = self.0.instance(); - let cpass = self.0.table().get_mut(&cpass).unwrap(); + let mut compute_pass = self.0.table().get_mut(&compute_pass).unwrap().lock(); + let compute_pass = compute_pass.as_mut().unwrap(); instance - .compute_pass_insert_debug_marker(cpass, &label, 0) + .compute_pass_insert_debug_marker(compute_pass, &label, 0) .unwrap() } fn set_bind_group( &mut self, - encoder: Resource, + compute_pass: Resource, index: webgpu::GpuIndex32, bind_group: Option>, dynamic_offsets: Option>, @@ -1724,15 +1726,19 @@ impl webgpu::HostGpuComputePassEncoder for WasiWebGpuImpl .table() .get(&bind_group.expect("TODO: deal with null bind_groups")) .unwrap(); - let encoder = self.0.table().get_mut(&encoder).unwrap(); + let mut compute_pass = self.0.table().get_mut(&compute_pass).unwrap().lock(); + let compute_pass = compute_pass.as_mut().unwrap(); let dynamic_offsets = dynamic_offsets.unwrap(); instance - .compute_pass_set_bind_group(encoder, index, bind_group, &dynamic_offsets) + .compute_pass_set_bind_group(compute_pass, index, bind_group, &dynamic_offsets) .unwrap() } - fn drop(&mut self, encoder: Resource) -> wasmtime::Result<()> { - self.table().delete(encoder).unwrap(); + fn drop( + &mut self, + compute_pass: Resource, + ) -> wasmtime::Result<()> { + self.table().delete(compute_pass).unwrap(); Ok(()) } } diff --git a/crates/wasi-webgpu-wasmtime/src/wrapper_types.rs b/crates/wasi-webgpu-wasmtime/src/wrapper_types.rs index 544bc5e..3363b66 100644 --- a/crates/wasi-webgpu-wasmtime/src/wrapper_types.rs +++ b/crates/wasi-webgpu-wasmtime/src/wrapper_types.rs @@ -1,15 +1,35 @@ // Wrappers around `wgpu_*` types // Every type here should have an explanation as to why we can't use the type directly. -use std::{collections::HashMap, ptr::NonNull, slice}; +use std::{collections::HashMap, ptr::NonNull, slice, sync::Arc}; use crate::wasi::webgpu::webgpu; // can't pass generics to `wasmtime::component::bindgen` -pub type RenderPass = wgpu_core::command::RenderPass; -pub type ComputePass = wgpu_core::command::ComputePass; pub type RecordGpuPipelineConstantValue = HashMap; +// RenderPassEncoder and ComputePassEncoder need to be dropped when calling .end on them, but we can't guerenty that they'll be dropped in time in some languages. Removeable let's you take the value and leaves None in place, so that RenderPass/ComputePass technicly get's dropped, but he wasm can keep it's reference. +// this is caused by the same underlying issue as this one https://github.com/gfx-rs/wgpu-native/issues/412 +pub type RenderPassEncoder = Takeable>; +pub type ComputePassEncoder = Takeable>; + +#[derive(Clone, Debug)] +pub struct Takeable(Arc>>); +impl Takeable +where + T: std::fmt::Debug, +{ + pub fn new(id: T) -> Self { + Takeable(Arc::new(std::sync::Mutex::new(Some(id)))) + } + pub fn lock<'a>(&'a self) -> std::sync::MutexGuard<'a, Option> { + self.0.lock().unwrap() + } + pub fn take(&self) -> Option { + self.0.lock().unwrap().take() + } +} + // needed just to group the pointer and length together pub struct BufferPtr { // See https://bytecodealliance.zulipchat.com/#narrow/stream/206238-general/topic/Should.20wasi.20resources.20be.20stored.20behind.20a.20mutex.3F