mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[rs] Force the wasm32 types to match Send / Sync with the native types
There are several things in this commit: 1) Add `Send` or `Send + Sync` bounds to most of the associated types in `Context`. 2) Force most of the handle types and future types returned by the web backend to be Send / Sync 3) Make `BufferReadMapping` and `BufferWriteMapping` `Send` again on native by making the associated detail types implement `Send`.
This commit is contained in:
@@ -906,6 +906,12 @@ pub(crate) struct BufferWriteMappingDetail {
|
||||
size: usize,
|
||||
}
|
||||
|
||||
// SAFETY: It is safe to implement Send for `BufferReadMappingDetail` and `BufferWriteMappingDetail`
|
||||
// because the only !Send field is `data`, and it is used similarly to `&[u8]` or `&mut [u8]`.
|
||||
|
||||
unsafe impl Send for BufferReadMappingDetail {}
|
||||
unsafe impl Send for BufferWriteMappingDetail {}
|
||||
|
||||
impl BufferWriteMappingDetail {
|
||||
pub(crate) fn as_slice(&mut self) -> &mut [u8] {
|
||||
unsafe { slice::from_raw_parts_mut(self.data as *mut u8, self.size) }
|
||||
|
||||
@@ -6,27 +6,66 @@ use crate::{
|
||||
};
|
||||
|
||||
use futures::FutureExt;
|
||||
use std::{marker::PhantomData, ops::Range};
|
||||
use std::{
|
||||
future::Future,
|
||||
marker::PhantomData,
|
||||
ops::Range,
|
||||
pin::Pin,
|
||||
task::{self, Poll},
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
pub type Context = web_sys::Gpu;
|
||||
// We need to make a wrapper for some of the handle types returned by the web backend to make them
|
||||
// implement `Send` and `Sync` to match native.
|
||||
//
|
||||
// SAFETY: All webgpu handle types in wasm32 are internally a `JsValue`, and `JsValue` is neither
|
||||
// Send nor Sync. Currently, wasm32 has no threading support so implementing `Send` or `Sync` for a
|
||||
// type is (for now) harmless. Eventually wasm32 will support threading, and depending on how this
|
||||
// is integrated (or not integrated) with values like those in webgpu, this may become unsound.
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Sendable<T>(T);
|
||||
unsafe impl<T> Send for Sendable<T> {}
|
||||
unsafe impl<T> Sync for Sendable<T> {}
|
||||
|
||||
pub(crate) type Context = Sendable<web_sys::Gpu>;
|
||||
|
||||
pub(crate) struct ComputePass(web_sys::GpuComputePassEncoder);
|
||||
pub(crate) struct RenderPass(web_sys::GpuRenderPassEncoder);
|
||||
|
||||
// We need to assert that any future we return is Send to match the native API.
|
||||
//
|
||||
// This is safe on wasm32 *for now*, but similarly to the unsafe Send impls for the handle type
|
||||
// wrappers, the full story for threading on wasm32 is still unfolding.
|
||||
|
||||
pub(crate) struct MakeSendFuture<F>(F);
|
||||
|
||||
impl<F: Future> Future for MakeSendFuture<F> {
|
||||
type Output = F::Output;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Self::Output> {
|
||||
// This is safe because we have no Drop implementation to violate the Pin requirements and
|
||||
// do not provide any means of moving the inner future.
|
||||
unsafe { self.map_unchecked_mut(|s| &mut s.0) }.poll(cx)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<F> Send for MakeSendFuture<F> {}
|
||||
|
||||
impl crate::ComputePassInner<Context> for ComputePass {
|
||||
fn set_pipeline(&mut self, pipeline: &web_sys::GpuComputePipeline) {
|
||||
self.0.set_pipeline(pipeline);
|
||||
fn set_pipeline(&mut self, pipeline: &Sendable<web_sys::GpuComputePipeline>) {
|
||||
self.0.set_pipeline(&pipeline.0);
|
||||
}
|
||||
fn set_bind_group(
|
||||
&mut self,
|
||||
index: u32,
|
||||
bind_group: &web_sys::GpuBindGroup,
|
||||
bind_group: &Sendable<web_sys::GpuBindGroup>,
|
||||
offsets: &[wgt::DynamicOffset],
|
||||
) {
|
||||
self.0
|
||||
.set_bind_group_with_u32_array_and_f64_and_dynamic_offsets_data_length(
|
||||
index,
|
||||
bind_group,
|
||||
&bind_group.0,
|
||||
offsets,
|
||||
0f64,
|
||||
offsets.len() as u32,
|
||||
@@ -37,28 +76,28 @@ impl crate::ComputePassInner<Context> for ComputePass {
|
||||
}
|
||||
fn dispatch_indirect(
|
||||
&mut self,
|
||||
indirect_buffer: &web_sys::GpuBuffer,
|
||||
indirect_buffer: &Sendable<web_sys::GpuBuffer>,
|
||||
indirect_offset: wgt::BufferAddress,
|
||||
) {
|
||||
self.0
|
||||
.dispatch_indirect_with_f64(indirect_buffer, indirect_offset as f64);
|
||||
.dispatch_indirect_with_f64(&indirect_buffer.0, indirect_offset as f64);
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::RenderPassInner<Context> for RenderPass {
|
||||
fn set_pipeline(&mut self, pipeline: &web_sys::GpuRenderPipeline) {
|
||||
self.0.set_pipeline(pipeline);
|
||||
fn set_pipeline(&mut self, pipeline: &Sendable<web_sys::GpuRenderPipeline>) {
|
||||
self.0.set_pipeline(&pipeline.0);
|
||||
}
|
||||
fn set_bind_group(
|
||||
&mut self,
|
||||
index: u32,
|
||||
bind_group: &web_sys::GpuBindGroup,
|
||||
bind_group: &Sendable<web_sys::GpuBindGroup>,
|
||||
offsets: &[wgt::DynamicOffset],
|
||||
) {
|
||||
self.0
|
||||
.set_bind_group_with_u32_array_and_f64_and_dynamic_offsets_data_length(
|
||||
index,
|
||||
bind_group,
|
||||
&bind_group.0,
|
||||
offsets,
|
||||
0f64,
|
||||
offsets.len() as u32,
|
||||
@@ -66,22 +105,22 @@ impl crate::RenderPassInner<Context> for RenderPass {
|
||||
}
|
||||
fn set_index_buffer(
|
||||
&mut self,
|
||||
buffer: &web_sys::GpuBuffer,
|
||||
buffer: &Sendable<web_sys::GpuBuffer>,
|
||||
offset: wgt::BufferAddress,
|
||||
size: wgt::BufferAddress,
|
||||
) {
|
||||
self.0
|
||||
.set_index_buffer_with_f64_and_f64(buffer, offset as f64, size as f64);
|
||||
.set_index_buffer_with_f64_and_f64(&buffer.0, offset as f64, size as f64);
|
||||
}
|
||||
fn set_vertex_buffer(
|
||||
&mut self,
|
||||
slot: u32,
|
||||
buffer: &web_sys::GpuBuffer,
|
||||
buffer: &Sendable<web_sys::GpuBuffer>,
|
||||
offset: wgt::BufferAddress,
|
||||
size: wgt::BufferAddress,
|
||||
) {
|
||||
self.0
|
||||
.set_vertex_buffer_with_f64_and_f64(slot, buffer, offset as f64, size as f64);
|
||||
.set_vertex_buffer_with_f64_and_f64(slot, &buffer.0, offset as f64, size as f64);
|
||||
}
|
||||
fn set_blend_color(&mut self, color: wgt::Color) {
|
||||
self.0
|
||||
@@ -126,19 +165,19 @@ impl crate::RenderPassInner<Context> for RenderPass {
|
||||
}
|
||||
fn draw_indirect(
|
||||
&mut self,
|
||||
indirect_buffer: &web_sys::GpuBuffer,
|
||||
indirect_buffer: &Sendable<web_sys::GpuBuffer>,
|
||||
indirect_offset: wgt::BufferAddress,
|
||||
) {
|
||||
self.0
|
||||
.draw_indirect_with_f64(indirect_buffer, indirect_offset as f64);
|
||||
.draw_indirect_with_f64(&indirect_buffer.0, indirect_offset as f64);
|
||||
}
|
||||
fn draw_indexed_indirect(
|
||||
&mut self,
|
||||
indirect_buffer: &web_sys::GpuBuffer,
|
||||
indirect_buffer: &Sendable<web_sys::GpuBuffer>,
|
||||
indirect_offset: wgt::BufferAddress,
|
||||
) {
|
||||
self.0
|
||||
.draw_indexed_indirect_with_f64(indirect_buffer, indirect_offset as f64);
|
||||
.draw_indexed_indirect_with_f64(&indirect_buffer.0, indirect_offset as f64);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,7 +239,7 @@ fn map_texture_component_type(
|
||||
fn map_stage_descriptor(
|
||||
desc: &ProgrammableStageDescriptor,
|
||||
) -> web_sys::GpuProgrammableStageDescriptor {
|
||||
web_sys::GpuProgrammableStageDescriptor::new(desc.entry_point, &desc.module.id)
|
||||
web_sys::GpuProgrammableStageDescriptor::new(desc.entry_point, &desc.module.id.0)
|
||||
}
|
||||
|
||||
fn map_cull_mode(cull_mode: wgt::CullMode) -> web_sys::GpuCullMode {
|
||||
@@ -458,14 +497,14 @@ fn map_texture_view_dimension(
|
||||
}
|
||||
|
||||
fn map_buffer_copy_view(view: crate::BufferCopyView<'_>) -> web_sys::GpuBufferCopyView {
|
||||
let mut mapped = web_sys::GpuBufferCopyView::new(&view.buffer.id, view.bytes_per_row);
|
||||
let mut mapped = web_sys::GpuBufferCopyView::new(&view.buffer.id.0, view.bytes_per_row);
|
||||
mapped.rows_per_image(view.rows_per_image);
|
||||
mapped.offset(view.offset as f64);
|
||||
mapped
|
||||
}
|
||||
|
||||
fn map_texture_copy_view<'a>(view: crate::TextureCopyView<'a>) -> web_sys::GpuTextureCopyView {
|
||||
let mut mapped = web_sys::GpuTextureCopyView::new(&view.texture.id);
|
||||
let mut mapped = web_sys::GpuTextureCopyView::new(&view.texture.id.0);
|
||||
mapped.array_layer(view.array_layer);
|
||||
mapped.mip_level(view.mip_level);
|
||||
mapped.origin(&map_origin_3d(view.origin));
|
||||
@@ -509,20 +548,21 @@ fn map_store_op(op: wgt::StoreOp) -> web_sys::GpuStoreOp {
|
||||
type JsFutureResult = Result<wasm_bindgen::JsValue, wasm_bindgen::JsValue>;
|
||||
type FutureMap<T> = futures::future::Map<wasm_bindgen_futures::JsFuture, fn(JsFutureResult) -> T>;
|
||||
|
||||
fn future_request_adapter(result: JsFutureResult) -> Option<web_sys::GpuAdapter> {
|
||||
fn future_request_adapter(result: JsFutureResult) -> Option<Sendable<web_sys::GpuAdapter>> {
|
||||
match result {
|
||||
Ok(js_value) => Some(web_sys::GpuAdapter::from(js_value)),
|
||||
Ok(js_value) => Some(Sendable(web_sys::GpuAdapter::from(js_value))),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
fn future_request_device(
|
||||
result: JsFutureResult,
|
||||
) -> Result<(web_sys::GpuDevice, web_sys::GpuQueue), crate::RequestDeviceError> {
|
||||
) -> Result<(Sendable<web_sys::GpuDevice>, Sendable<web_sys::GpuQueue>), crate::RequestDeviceError>
|
||||
{
|
||||
result
|
||||
.map(|js_value| {
|
||||
let device_id = web_sys::GpuDevice::from(js_value);
|
||||
let queue_id = device_id.default_queue();
|
||||
(device_id, queue_id)
|
||||
(Sendable(device_id), Sendable(queue_id))
|
||||
})
|
||||
.map_err(|_| crate::RequestDeviceError)
|
||||
}
|
||||
@@ -536,12 +576,18 @@ impl<T> Unpin for MapFuture<T> {}
|
||||
type MapData = (web_sys::GpuBuffer, Vec<u8>);
|
||||
impl From<MapData> for BufferReadMappingDetail {
|
||||
fn from((buffer_id, mapped): MapData) -> Self {
|
||||
BufferReadMappingDetail { buffer_id, mapped }
|
||||
BufferReadMappingDetail {
|
||||
buffer_id: Sendable(buffer_id),
|
||||
mapped,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<MapData> for BufferWriteMappingDetail {
|
||||
fn from((buffer_id, mapped): MapData) -> Self {
|
||||
BufferWriteMappingDetail { buffer_id, mapped }
|
||||
BufferWriteMappingDetail {
|
||||
buffer_id: Sendable(buffer_id),
|
||||
mapped,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: From<MapData>> std::future::Future for MapFuture<T> {
|
||||
@@ -568,24 +614,24 @@ impl<T: From<MapData>> std::future::Future for MapFuture<T> {
|
||||
}
|
||||
|
||||
impl crate::Context for Context {
|
||||
type AdapterId = web_sys::GpuAdapter;
|
||||
type DeviceId = web_sys::GpuDevice;
|
||||
type QueueId = web_sys::GpuQueue;
|
||||
type ShaderModuleId = web_sys::GpuShaderModule;
|
||||
type BindGroupLayoutId = web_sys::GpuBindGroupLayout;
|
||||
type BindGroupId = web_sys::GpuBindGroup;
|
||||
type TextureViewId = web_sys::GpuTextureView;
|
||||
type SamplerId = web_sys::GpuSampler;
|
||||
type BufferId = web_sys::GpuBuffer;
|
||||
type TextureId = web_sys::GpuTexture;
|
||||
type PipelineLayoutId = web_sys::GpuPipelineLayout;
|
||||
type RenderPipelineId = web_sys::GpuRenderPipeline;
|
||||
type ComputePipelineId = web_sys::GpuComputePipeline;
|
||||
type AdapterId = Sendable<web_sys::GpuAdapter>;
|
||||
type DeviceId = Sendable<web_sys::GpuDevice>;
|
||||
type QueueId = Sendable<web_sys::GpuQueue>;
|
||||
type ShaderModuleId = Sendable<web_sys::GpuShaderModule>;
|
||||
type BindGroupLayoutId = Sendable<web_sys::GpuBindGroupLayout>;
|
||||
type BindGroupId = Sendable<web_sys::GpuBindGroup>;
|
||||
type TextureViewId = Sendable<web_sys::GpuTextureView>;
|
||||
type SamplerId = Sendable<web_sys::GpuSampler>;
|
||||
type BufferId = Sendable<web_sys::GpuBuffer>;
|
||||
type TextureId = Sendable<web_sys::GpuTexture>;
|
||||
type PipelineLayoutId = Sendable<web_sys::GpuPipelineLayout>;
|
||||
type RenderPipelineId = Sendable<web_sys::GpuRenderPipeline>;
|
||||
type ComputePipelineId = Sendable<web_sys::GpuComputePipeline>;
|
||||
type CommandEncoderId = web_sys::GpuCommandEncoder;
|
||||
type ComputePassId = ComputePass;
|
||||
type CommandBufferId = web_sys::GpuCommandBuffer;
|
||||
type SurfaceId = web_sys::GpuCanvasContext;
|
||||
type SwapChainId = web_sys::GpuSwapChain;
|
||||
type CommandBufferId = Sendable<web_sys::GpuCommandBuffer>;
|
||||
type SurfaceId = Sendable<web_sys::GpuCanvasContext>;
|
||||
type SwapChainId = Sendable<web_sys::GpuSwapChain>;
|
||||
type RenderPassId = RenderPass;
|
||||
|
||||
type CreateBufferMappedDetail = CreateBufferMappedDetail;
|
||||
@@ -593,14 +639,15 @@ impl crate::Context for Context {
|
||||
type BufferWriteMappingDetail = BufferWriteMappingDetail;
|
||||
type SwapChainOutputDetail = SwapChainOutputDetail;
|
||||
|
||||
type RequestAdapterFuture = FutureMap<Option<web_sys::GpuAdapter>>;
|
||||
type RequestDeviceFuture =
|
||||
FutureMap<Result<(Self::DeviceId, Self::QueueId), crate::RequestDeviceError>>;
|
||||
type MapReadFuture = MapFuture<BufferReadMappingDetail>;
|
||||
type MapWriteFuture = MapFuture<BufferWriteMappingDetail>;
|
||||
type RequestAdapterFuture = MakeSendFuture<FutureMap<Option<Self::AdapterId>>>;
|
||||
type RequestDeviceFuture = MakeSendFuture<
|
||||
FutureMap<Result<(Self::DeviceId, Self::QueueId), crate::RequestDeviceError>>,
|
||||
>;
|
||||
type MapReadFuture = MakeSendFuture<MapFuture<BufferReadMappingDetail>>;
|
||||
type MapWriteFuture = MakeSendFuture<MapFuture<BufferWriteMappingDetail>>;
|
||||
|
||||
fn init() -> Self {
|
||||
web_sys::window().unwrap().navigator().gpu()
|
||||
Sendable(web_sys::window().unwrap().navigator().gpu())
|
||||
}
|
||||
|
||||
fn instance_create_surface(
|
||||
@@ -625,7 +672,7 @@ impl crate::Context for Context {
|
||||
Ok(Some(ctx)) => ctx.into(),
|
||||
_ => panic!("expected to get context from canvas"),
|
||||
};
|
||||
context.into()
|
||||
Sendable(context.into())
|
||||
}
|
||||
|
||||
fn instance_request_adapter(
|
||||
@@ -645,8 +692,10 @@ impl crate::Context for Context {
|
||||
}
|
||||
};
|
||||
mapped_options.power_preference(mapped_power_preference);
|
||||
let adapter_promise = self.request_adapter_with_options(&mapped_options);
|
||||
wasm_bindgen_futures::JsFuture::from(adapter_promise).map(future_request_adapter)
|
||||
let adapter_promise = self.0.request_adapter_with_options(&mapped_options);
|
||||
MakeSendFuture(
|
||||
wasm_bindgen_futures::JsFuture::from(adapter_promise).map(future_request_adapter),
|
||||
)
|
||||
}
|
||||
|
||||
fn adapter_request_device(
|
||||
@@ -663,9 +712,11 @@ impl crate::Context for Context {
|
||||
let mut mapped_limits = web_sys::GpuLimits::new();
|
||||
mapped_limits.max_bind_groups(desc.limits.max_bind_groups);
|
||||
mapped_desc.limits(&mapped_limits);
|
||||
let device_promise = adapter.request_device_with_descriptor(&mapped_desc);
|
||||
let device_promise = adapter.0.request_device_with_descriptor(&mapped_desc);
|
||||
|
||||
wasm_bindgen_futures::JsFuture::from(device_promise).map(future_request_device)
|
||||
MakeSendFuture(
|
||||
wasm_bindgen_futures::JsFuture::from(device_promise).map(future_request_device),
|
||||
)
|
||||
}
|
||||
|
||||
fn device_create_swap_chain(
|
||||
@@ -675,9 +726,9 @@ impl crate::Context for Context {
|
||||
desc: &wgt::SwapChainDescriptor,
|
||||
) -> Self::SwapChainId {
|
||||
let mut mapped =
|
||||
web_sys::GpuSwapChainDescriptor::new(device, map_texture_format(desc.format));
|
||||
web_sys::GpuSwapChainDescriptor::new(&device.0, map_texture_format(desc.format));
|
||||
mapped.usage(desc.usage.bits());
|
||||
surface.configure_swap_chain(&mapped)
|
||||
Sendable(surface.0.configure_swap_chain(&mapped))
|
||||
}
|
||||
|
||||
fn device_create_shader_module(
|
||||
@@ -687,7 +738,7 @@ impl crate::Context for Context {
|
||||
) -> Self::ShaderModuleId {
|
||||
let desc = web_sys::GpuShaderModuleDescriptor::new(&js_sys::Uint32Array::from(spv));
|
||||
// TODO: label
|
||||
device.create_shader_module(&desc)
|
||||
Sendable(device.0.create_shader_module(&desc))
|
||||
}
|
||||
|
||||
fn device_create_bind_group_layout(
|
||||
@@ -763,7 +814,7 @@ impl crate::Context for Context {
|
||||
if let Some(label) = desc.label {
|
||||
mapped_desc.label(label);
|
||||
}
|
||||
device.create_bind_group_layout(&mapped_desc)
|
||||
Sendable(device.0.create_bind_group_layout(&mapped_desc))
|
||||
}
|
||||
|
||||
fn device_create_bind_group(
|
||||
@@ -780,14 +831,15 @@ impl crate::Context for Context {
|
||||
ref buffer,
|
||||
ref range,
|
||||
} => {
|
||||
let mut mapped_buffer_binding = web_sys::GpuBufferBinding::new(&buffer.id);
|
||||
let mut mapped_buffer_binding =
|
||||
web_sys::GpuBufferBinding::new(&buffer.id.0);
|
||||
mapped_buffer_binding.offset(range.start as f64);
|
||||
mapped_buffer_binding.size((range.end - range.start) as f64);
|
||||
JsValue::from(mapped_buffer_binding.clone())
|
||||
}
|
||||
BindingResource::Sampler(ref sampler) => JsValue::from(sampler.id.clone()),
|
||||
BindingResource::Sampler(ref sampler) => JsValue::from(sampler.id.0.clone()),
|
||||
BindingResource::TextureView(ref texture_view) => {
|
||||
JsValue::from(texture_view.id.clone())
|
||||
JsValue::from(texture_view.id.0.clone())
|
||||
}
|
||||
};
|
||||
|
||||
@@ -796,11 +848,11 @@ impl crate::Context for Context {
|
||||
.collect::<js_sys::Array>();
|
||||
|
||||
let mut mapped_desc =
|
||||
web_sys::GpuBindGroupDescriptor::new(&mapped_entries, &desc.layout.id);
|
||||
web_sys::GpuBindGroupDescriptor::new(&mapped_entries, &desc.layout.id.0);
|
||||
if let Some(label) = desc.label {
|
||||
mapped_desc.label(label);
|
||||
}
|
||||
device.create_bind_group(&mapped_desc)
|
||||
Sendable(device.0.create_bind_group(&mapped_desc))
|
||||
}
|
||||
|
||||
fn device_create_pipeline_layout(
|
||||
@@ -811,11 +863,11 @@ impl crate::Context for Context {
|
||||
let temp_layouts = desc
|
||||
.bind_group_layouts
|
||||
.iter()
|
||||
.map(|bgl| bgl.id.clone())
|
||||
.map(|bgl| bgl.id.0.clone())
|
||||
.collect::<js_sys::Array>();
|
||||
let mapped_desc = web_sys::GpuPipelineLayoutDescriptor::new(&temp_layouts);
|
||||
// TODO: label
|
||||
device.create_pipeline_layout(&mapped_desc)
|
||||
Sendable(device.0.create_pipeline_layout(&mapped_desc))
|
||||
}
|
||||
|
||||
fn device_create_render_pipeline(
|
||||
@@ -852,7 +904,7 @@ impl crate::Context for Context {
|
||||
let mapped_vertex_stage = map_stage_descriptor(&desc.vertex_stage);
|
||||
|
||||
let mut mapped_desc = web_sys::GpuRenderPipelineDescriptor::new(
|
||||
&desc.layout.id,
|
||||
&desc.layout.id.0,
|
||||
&mapped_color_states,
|
||||
mapped_primitive_topology,
|
||||
&mapped_vertex_stage,
|
||||
@@ -877,7 +929,7 @@ impl crate::Context for Context {
|
||||
mapped_desc.sample_mask(desc.sample_mask);
|
||||
mapped_desc.alpha_to_coverage_enabled(desc.alpha_to_coverage_enabled);
|
||||
|
||||
device.create_render_pipeline(&mapped_desc)
|
||||
Sendable(device.0.create_render_pipeline(&mapped_desc))
|
||||
}
|
||||
|
||||
fn device_create_compute_pipeline(
|
||||
@@ -887,9 +939,9 @@ impl crate::Context for Context {
|
||||
) -> Self::ComputePipelineId {
|
||||
let mapped_compute_stage = map_stage_descriptor(&desc.compute_stage);
|
||||
let mapped_desc =
|
||||
web_sys::GpuComputePipelineDescriptor::new(&desc.layout.id, &mapped_compute_stage);
|
||||
web_sys::GpuComputePipelineDescriptor::new(&desc.layout.id.0, &mapped_compute_stage);
|
||||
// TODO: label
|
||||
device.create_compute_pipeline(&mapped_desc)
|
||||
Sendable(device.0.create_compute_pipeline(&mapped_desc))
|
||||
}
|
||||
|
||||
fn device_create_buffer_mapped<'a>(
|
||||
@@ -903,7 +955,7 @@ impl crate::Context for Context {
|
||||
mapped_desc.label(label);
|
||||
}
|
||||
unsafe {
|
||||
let pair = device.create_buffer_mapped(&mapped_desc);
|
||||
let pair = device.0.create_buffer_mapped(&mapped_desc);
|
||||
let id = pair.get(0).into();
|
||||
let array_buffer = pair.get(1).into();
|
||||
// TODO: Use `Vec::from_raw_parts` once it's stable
|
||||
@@ -912,7 +964,11 @@ impl crate::Context for Context {
|
||||
Box::into_raw(memory) as *mut u8,
|
||||
desc.size as usize,
|
||||
);
|
||||
(id, mapped_data, CreateBufferMappedDetail { array_buffer })
|
||||
(
|
||||
Sendable(id),
|
||||
mapped_data,
|
||||
CreateBufferMappedDetail { array_buffer },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -926,7 +982,7 @@ impl crate::Context for Context {
|
||||
if let Some(label) = desc.label {
|
||||
mapped_desc.label(label);
|
||||
}
|
||||
device.create_buffer(&mapped_desc)
|
||||
Sendable(device.0.create_buffer(&mapped_desc))
|
||||
}
|
||||
|
||||
fn device_create_texture(
|
||||
@@ -945,7 +1001,7 @@ impl crate::Context for Context {
|
||||
mapped_desc.dimension(map_texture_dimension(desc.dimension));
|
||||
mapped_desc.mip_level_count(desc.mip_level_count);
|
||||
mapped_desc.sample_count(desc.sample_count);
|
||||
device.create_texture(&mapped_desc)
|
||||
Sendable(device.0.create_texture(&mapped_desc))
|
||||
}
|
||||
|
||||
fn device_create_sampler(
|
||||
@@ -966,7 +1022,7 @@ impl crate::Context for Context {
|
||||
mapped_desc.mag_filter(map_filter_mode(desc.mag_filter));
|
||||
mapped_desc.min_filter(map_filter_mode(desc.min_filter));
|
||||
mapped_desc.mipmap_filter(map_filter_mode(desc.mipmap_filter));
|
||||
device.create_sampler_with_descriptor(&mapped_desc)
|
||||
Sendable(device.0.create_sampler_with_descriptor(&mapped_desc))
|
||||
}
|
||||
|
||||
fn device_create_command_encoder(
|
||||
@@ -978,7 +1034,9 @@ impl crate::Context for Context {
|
||||
if let Some(label) = desc.label {
|
||||
mapped_desc.label(label);
|
||||
}
|
||||
device.create_command_encoder_with_descriptor(&mapped_desc)
|
||||
device
|
||||
.0
|
||||
.create_command_encoder_with_descriptor(&mapped_desc)
|
||||
}
|
||||
|
||||
fn device_drop(&self, _device: &Self::DeviceId) {
|
||||
@@ -995,11 +1053,11 @@ impl crate::Context for Context {
|
||||
_start: wgt::BufferAddress,
|
||||
_size: wgt::BufferAddress,
|
||||
) -> Self::MapReadFuture {
|
||||
MapFuture {
|
||||
child: wasm_bindgen_futures::JsFuture::from(buffer.map_read_async()),
|
||||
buffer: Some(buffer.clone()),
|
||||
MakeSendFuture(MapFuture {
|
||||
child: wasm_bindgen_futures::JsFuture::from(buffer.0.map_read_async()),
|
||||
buffer: Some(buffer.0.clone()),
|
||||
marker: PhantomData,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn buffer_map_write(
|
||||
@@ -1008,15 +1066,15 @@ impl crate::Context for Context {
|
||||
_start: wgt::BufferAddress,
|
||||
_size: wgt::BufferAddress,
|
||||
) -> Self::MapWriteFuture {
|
||||
MapFuture {
|
||||
child: wasm_bindgen_futures::JsFuture::from(buffer.map_write_async()),
|
||||
buffer: Some(buffer.clone()),
|
||||
MakeSendFuture(MapFuture {
|
||||
child: wasm_bindgen_futures::JsFuture::from(buffer.0.map_write_async()),
|
||||
buffer: Some(buffer.0.clone()),
|
||||
marker: PhantomData,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn buffer_unmap(&self, buffer: &Self::BufferId) {
|
||||
buffer.unmap();
|
||||
buffer.0.unmap();
|
||||
}
|
||||
|
||||
fn swap_chain_get_next_texture(
|
||||
@@ -1025,7 +1083,10 @@ impl crate::Context for Context {
|
||||
) -> Result<(Self::TextureViewId, Self::SwapChainOutputDetail), crate::TimeOut> {
|
||||
// TODO: Should we pass a descriptor here?
|
||||
// Or is the default view always correct?
|
||||
Ok((swap_chain.get_current_texture().create_view(), ()))
|
||||
Ok((
|
||||
Sendable(swap_chain.0.get_current_texture().create_view()),
|
||||
(),
|
||||
))
|
||||
}
|
||||
|
||||
fn swap_chain_present(
|
||||
@@ -1041,7 +1102,7 @@ impl crate::Context for Context {
|
||||
texture: &Self::TextureId,
|
||||
desc: Option<&TextureViewDescriptor>,
|
||||
) -> Self::TextureViewId {
|
||||
match desc {
|
||||
Sendable(match desc {
|
||||
Some(d) => {
|
||||
let mut mapped_desc = web_sys::GpuTextureViewDescriptor::new();
|
||||
mapped_desc.array_layer_count(d.array_layer_count);
|
||||
@@ -1052,10 +1113,10 @@ impl crate::Context for Context {
|
||||
mapped_desc.format(map_texture_format(d.format));
|
||||
mapped_desc.mip_level_count(d.level_count);
|
||||
// TODO: label
|
||||
texture.create_view_with_descriptor(&mapped_desc)
|
||||
texture.0.create_view_with_descriptor(&mapped_desc)
|
||||
}
|
||||
None => texture.create_view(),
|
||||
}
|
||||
None => texture.0.create_view(),
|
||||
})
|
||||
}
|
||||
|
||||
fn texture_drop(&self, _texture: &Self::TextureId) {
|
||||
@@ -1122,9 +1183,9 @@ impl crate::Context for Context {
|
||||
copy_size: wgt::BufferAddress,
|
||||
) {
|
||||
encoder.copy_buffer_to_buffer_with_f64_and_f64_and_f64(
|
||||
source,
|
||||
&source.0,
|
||||
source_offset as f64,
|
||||
destination,
|
||||
&destination.0,
|
||||
destination_offset as f64,
|
||||
copy_size as f64,
|
||||
)
|
||||
@@ -1199,7 +1260,7 @@ impl crate::Context for Context {
|
||||
.map(|ca| {
|
||||
let mut mapped_color_attachment =
|
||||
web_sys::GpuRenderPassColorAttachmentDescriptor::new(
|
||||
&ca.attachment.id,
|
||||
&ca.attachment.id.0,
|
||||
&match ca.load_op {
|
||||
wgt::LoadOp::Clear => {
|
||||
wasm_bindgen::JsValue::from(map_color(ca.clear_color))
|
||||
@@ -1211,7 +1272,7 @@ impl crate::Context for Context {
|
||||
);
|
||||
|
||||
if let Some(rt) = ca.resolve_target {
|
||||
mapped_color_attachment.resolve_target(&rt.id);
|
||||
mapped_color_attachment.resolve_target(&rt.id.0);
|
||||
}
|
||||
|
||||
mapped_color_attachment.store_op(map_store_op(ca.store_op));
|
||||
@@ -1227,7 +1288,7 @@ impl crate::Context for Context {
|
||||
if let Some(dsa) = &desc.depth_stencil_attachment {
|
||||
let mapped_depth_stencil_attachment =
|
||||
web_sys::GpuRenderPassDepthStencilAttachmentDescriptor::new(
|
||||
&dsa.attachment.id,
|
||||
&dsa.attachment.id.0,
|
||||
&match dsa.depth_load_op {
|
||||
wgt::LoadOp::Clear => wasm_bindgen::JsValue::from(dsa.clear_depth),
|
||||
wgt::LoadOp::Load => wasm_bindgen::JsValue::from(web_sys::GpuLoadOp::Load),
|
||||
@@ -1259,7 +1320,7 @@ impl crate::Context for Context {
|
||||
if let Some(ref label) = encoder.label() {
|
||||
mapped_desc.label(label);
|
||||
}
|
||||
encoder.finish_with_descriptor(&mapped_desc)
|
||||
Sendable(encoder.finish_with_descriptor(&mapped_desc))
|
||||
}
|
||||
|
||||
fn queue_submit<I: Iterator<Item = Self::CommandBufferId>>(
|
||||
@@ -1267,9 +1328,9 @@ impl crate::Context for Context {
|
||||
queue: &Self::QueueId,
|
||||
command_buffers: I,
|
||||
) {
|
||||
let temp_command_buffers = command_buffers.collect::<js_sys::Array>();
|
||||
let temp_command_buffers = command_buffers.map(|i| i.0).collect::<js_sys::Array>();
|
||||
|
||||
queue.submit(&temp_command_buffers);
|
||||
queue.0.submit(&temp_command_buffers);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1280,8 +1341,14 @@ pub(crate) struct CreateBufferMappedDetail {
|
||||
array_buffer: js_sys::ArrayBuffer,
|
||||
}
|
||||
|
||||
// `CreateBufferMappedDetail` must be `Send` to match native.
|
||||
//
|
||||
// SAFETY: This is safe on wasm32 *for now*, but similarly to the unsafe Send impls for the handle
|
||||
// type wrappers, the full story for threading on wasm32 is still unfolding.
|
||||
unsafe impl Send for CreateBufferMappedDetail {}
|
||||
|
||||
pub(crate) struct BufferReadMappingDetail {
|
||||
pub(crate) buffer_id: web_sys::GpuBuffer,
|
||||
pub(crate) buffer_id: Sendable<web_sys::GpuBuffer>,
|
||||
mapped: Vec<u8>,
|
||||
}
|
||||
|
||||
@@ -1292,7 +1359,7 @@ impl BufferReadMappingDetail {
|
||||
}
|
||||
|
||||
pub(crate) struct BufferWriteMappingDetail {
|
||||
pub(crate) buffer_id: web_sys::GpuBuffer,
|
||||
pub(crate) buffer_id: Sendable<web_sys::GpuBuffer>,
|
||||
mapped: Vec<u8>,
|
||||
}
|
||||
|
||||
|
||||
@@ -84,37 +84,38 @@ trait RenderPassInner<Ctx: Context> {
|
||||
}
|
||||
|
||||
trait Context: Sized {
|
||||
type AdapterId;
|
||||
type DeviceId;
|
||||
type QueueId;
|
||||
type ShaderModuleId;
|
||||
type BindGroupLayoutId;
|
||||
type BindGroupId;
|
||||
type TextureViewId;
|
||||
type SamplerId;
|
||||
type BufferId;
|
||||
type TextureId;
|
||||
type PipelineLayoutId;
|
||||
type RenderPipelineId;
|
||||
type ComputePipelineId;
|
||||
type AdapterId: Send + Sync;
|
||||
type DeviceId: Send + Sync;
|
||||
type QueueId: Send + Sync;
|
||||
type ShaderModuleId: Send + Sync;
|
||||
type BindGroupLayoutId: Send + Sync;
|
||||
type BindGroupId: Send + Sync;
|
||||
type TextureViewId: Send + Sync;
|
||||
type SamplerId: Send + Sync;
|
||||
type BufferId: Send + Sync;
|
||||
type TextureId: Send + Sync;
|
||||
type PipelineLayoutId: Send + Sync;
|
||||
type RenderPipelineId: Send + Sync;
|
||||
type ComputePipelineId: Send + Sync;
|
||||
type CommandEncoderId;
|
||||
type ComputePassId: ComputePassInner<Self>;
|
||||
type CommandBufferId;
|
||||
type SurfaceId;
|
||||
type SwapChainId;
|
||||
type CommandBufferId: Send + Sync;
|
||||
type SurfaceId: Send + Sync;
|
||||
type SwapChainId: Send + Sync;
|
||||
type RenderPassId: RenderPassInner<Self>;
|
||||
|
||||
type CreateBufferMappedDetail;
|
||||
type BufferReadMappingDetail;
|
||||
type BufferWriteMappingDetail;
|
||||
type SwapChainOutputDetail;
|
||||
type CreateBufferMappedDetail: Send;
|
||||
type BufferReadMappingDetail: Send;
|
||||
type BufferWriteMappingDetail: Send;
|
||||
type SwapChainOutputDetail: Send;
|
||||
|
||||
type RequestAdapterFuture: Future<Output = Option<Self::AdapterId>>;
|
||||
type RequestDeviceFuture: Future<
|
||||
Output = Result<(Self::DeviceId, Self::QueueId), RequestDeviceError>,
|
||||
>;
|
||||
type MapReadFuture: Future<Output = Result<Self::BufferReadMappingDetail, BufferAsyncError>>;
|
||||
type MapWriteFuture: Future<Output = Result<Self::BufferWriteMappingDetail, BufferAsyncError>>;
|
||||
type RequestAdapterFuture: Future<Output = Option<Self::AdapterId>> + Send;
|
||||
type RequestDeviceFuture: Future<Output = Result<(Self::DeviceId, Self::QueueId), RequestDeviceError>>
|
||||
+ Send;
|
||||
type MapReadFuture: Future<Output = Result<Self::BufferReadMappingDetail, BufferAsyncError>>
|
||||
+ Send;
|
||||
type MapWriteFuture: Future<Output = Result<Self::BufferWriteMappingDetail, BufferAsyncError>>
|
||||
+ Send;
|
||||
|
||||
fn init() -> Self;
|
||||
fn instance_create_surface(
|
||||
@@ -940,7 +941,7 @@ impl Instance {
|
||||
&self,
|
||||
options: &RequestAdapterOptions<'_>,
|
||||
backends: BackendBit,
|
||||
) -> impl Future<Output = Option<Adapter>> {
|
||||
) -> impl Future<Output = Option<Adapter>> + Send {
|
||||
let context = Arc::clone(&self.context);
|
||||
self.context
|
||||
.instance_request_adapter(options, backends)
|
||||
@@ -959,7 +960,7 @@ impl Adapter {
|
||||
&self,
|
||||
desc: &DeviceDescriptor,
|
||||
trace_path: Option<&std::path::Path>,
|
||||
) -> impl Future<Output = Result<(Device, Queue), RequestDeviceError>> {
|
||||
) -> impl Future<Output = Result<(Device, Queue), RequestDeviceError>> + Send {
|
||||
let context = Arc::clone(&self.context);
|
||||
Context::adapter_request_device(&*self.context, &self.id, desc, trace_path).map(|result| {
|
||||
result.map(|(device_id, queue_id)| {
|
||||
@@ -1178,7 +1179,7 @@ impl Buffer {
|
||||
&self,
|
||||
start: BufferAddress,
|
||||
size: BufferAddress,
|
||||
) -> impl Future<Output = Result<BufferReadMapping, BufferAsyncError>> {
|
||||
) -> impl Future<Output = Result<BufferReadMapping, BufferAsyncError>> + Send {
|
||||
let context = Arc::clone(&self.context);
|
||||
self.context
|
||||
.buffer_map_read(&self.id, start, size)
|
||||
@@ -1193,7 +1194,7 @@ impl Buffer {
|
||||
&self,
|
||||
start: BufferAddress,
|
||||
size: BufferAddress,
|
||||
) -> impl Future<Output = Result<BufferWriteMapping, BufferAsyncError>> {
|
||||
) -> impl Future<Output = Result<BufferWriteMapping, BufferAsyncError>> + Send {
|
||||
let context = Arc::clone(&self.context);
|
||||
self.context
|
||||
.buffer_map_write(&self.id, start, size)
|
||||
|
||||
Reference in New Issue
Block a user