Auto merge of #26564 - kunalmohan:gpu-id-rotation, r=jdm

Upgrade wgpu version to "0.5.0" and add server-side code for id recycling for WebGPU

<!-- Please describe your changes on the following line: -->
I have updated the cargo.lock to use a wgpu-core at a more recent commit where IdentityHandlerFactory was introduced.
r?@kvark

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [ ] `./mach build -d` does not report any errors
- [ ] `./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:
bors-servo 2020-05-21 13:24:55 -04:00 committed by GitHub
commit 94063d67a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 509 additions and 344 deletions

View file

@ -455,7 +455,7 @@ impl<'a> CanvasData<'a> {
pub fn restore_context_state(&mut self) {
if let Some(state) = self.saved_states.pop() {
mem::replace(&mut self.state, state);
let _ = mem::replace(&mut self.state, state);
self.drawtarget.set_transform(&self.state.transform);
self.drawtarget.pop_clip();
}

View file

@ -20,8 +20,8 @@ use ipc_channel::router::ROUTER;
use js::jsapi::Heap;
use script_traits::ScriptMsg;
use std::rc::Rc;
use webgpu::wgpu;
use webgpu::{WebGPUResponse, WebGPUResponseResult};
use webgpu::wgt::PowerPreference;
use webgpu::{wgpu, WebGPUResponse, WebGPUResponseResult};
#[dom_struct]
pub struct GPU {
@ -109,11 +109,9 @@ impl GPUMethods for GPU {
let promise = Promise::new_in_current_realm(global, comp);
let sender = response_async(&promise, self);
let power_preference = match options.powerPreference {
Some(GPUPowerPreference::Low_power) => wgpu::instance::PowerPreference::LowPower,
Some(GPUPowerPreference::High_performance) => {
wgpu::instance::PowerPreference::HighPerformance
},
None => wgpu::instance::PowerPreference::Default,
Some(GPUPowerPreference::Low_power) => PowerPreference::LowPower,
Some(GPUPowerPreference::High_performance) => PowerPreference::HighPerformance,
None => PowerPreference::Default,
};
let ids = global.wgpu_id_hub().lock().create_adapter_ids();
@ -121,7 +119,10 @@ impl GPUMethods for GPU {
if script_to_constellation_chan
.send(ScriptMsg::RequestAdapter(
sender,
wgpu::instance::RequestAdapterOptions { power_preference },
wgpu::instance::RequestAdapterOptions {
power_preference,
compatible_surface: None,
},
ids,
))
.is_err()

View file

@ -20,7 +20,7 @@ use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use std::ptr::NonNull;
use std::rc::Rc;
use webgpu::{wgpu, WebGPU, WebGPUAdapter, WebGPURequest, WebGPUResponse};
use webgpu::{wgt, WebGPU, WebGPUAdapter, WebGPURequest, WebGPUResponse};
#[dom_struct]
pub struct GPUAdapter {
@ -80,11 +80,11 @@ impl GPUAdapterMethods for GPUAdapter {
fn RequestDevice(&self, descriptor: &GPUDeviceDescriptor, comp: InRealm) -> Rc<Promise> {
let promise = Promise::new_in_current_realm(&self.global(), comp);
let sender = response_async(&promise, self);
let desc = wgpu::instance::DeviceDescriptor {
extensions: wgpu::instance::Extensions {
let desc = wgt::DeviceDescriptor {
extensions: wgt::Extensions {
anisotropic_filtering: descriptor.extensions.anisotropicFiltering,
},
limits: wgpu::instance::Limits {
limits: wgt::Limits {
max_bind_groups: descriptor.limits.maxBindGroups,
},
};

View file

@ -11,21 +11,14 @@ use crate::dom::bindings::root::DomRoot;
use crate::dom::bindings::str::DOMString;
use crate::dom::bindings::trace::RootedTraceableBox;
use crate::dom::globalscope::GlobalScope;
use crate::dom::gpu::{response_async, AsyncWGPUListener};
use crate::dom::promise::Promise;
use crate::realms::InRealm;
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
use js::jsval::UndefinedValue;
use js::rust::jsapi_wrapped::{DetachArrayBuffer, IsPromiseObject, RejectPromise};
use js::rust::MutableHandle;
use js::typedarray::{ArrayBuffer, CreateWith};
use js::typedarray::ArrayBuffer;
use std::cell::Cell;
use std::ptr;
use std::rc::Rc;
use webgpu::{
wgpu::resource::BufferUsage, WebGPU, WebGPUBuffer, WebGPUDevice, WebGPURequest, WebGPUResponse,
};
use webgpu::{WebGPU, WebGPUBuffer, WebGPUDevice, WebGPURequest};
// https://gpuweb.github.io/gpuweb/#buffer-state
#[derive(Clone, MallocSizeOf)]
@ -193,72 +186,6 @@ impl GPUBufferMethods for GPUBuffer {
*self.state.borrow_mut() = GPUBufferState::Destroyed;
}
#[allow(unsafe_code)]
/// https://gpuweb.github.io/gpuweb/#dom-gpubuffer-mapreadasync
fn MapReadAsync(&self, comp: InRealm) -> Rc<Promise> {
// Step 1 & 2
let promise = Promise::new_in_current_realm(&self.global(), comp);
match *self.state.borrow() {
GPUBufferState::Unmapped => {
match BufferUsage::from_bits(self.usage) {
Some(usage) => {
if !usage.contains(BufferUsage::MAP_READ) {
// TODO: Record validation error on the current scope
promise.reject_error(Error::Abort);
return promise;
};
},
None => {
promise.reject_error(Error::Abort);
return promise;
},
}
},
_ => {
promise.reject_error(Error::Abort);
return promise;
},
}
// Step 3
self.mapping.set(*promise.promise_obj());
// Step 4
*self.state.borrow_mut() = GPUBufferState::MappedPendingForReading;
// Step 5.1
if unsafe {
ArrayBuffer::create(
*self.global().get_cx(),
CreateWith::Length(self.size as u32),
MutableHandle::from_raw(self.mapping.handle_mut()),
)
}
.is_err()
{
promise.reject_error(Error::Operation);
return promise;
}
let sender = response_async(&promise, self);
if self
.channel
.0
.send(WebGPURequest::MapReadAsync {
sender,
buffer_id: self.buffer.0,
device_id: self.device.0,
usage: self.usage,
size: self.size,
})
.is_err()
{
promise.reject_error(Error::Operation);
return promise;
}
// Step 6
promise
}
/// https://gpuweb.github.io/gpuweb/#dom-gpuobjectbase-label
fn GetLabel(&self) -> Option<DOMString> {
self.label.borrow().clone()
@ -269,25 +196,3 @@ impl GPUBufferMethods for GPUBuffer {
*self.label.borrow_mut() = value;
}
}
impl AsyncWGPUListener for GPUBuffer {
#[allow(unsafe_code)]
fn handle_response(&self, response: WebGPUResponse, promise: &Rc<Promise>) {
match response {
WebGPUResponse::MapReadAsync(bytes) => unsafe {
match ArrayBuffer::from(self.mapping.get()) {
Ok(mut array_buffer) => {
// Step 5.2
array_buffer.update(&bytes);
// Step 5.3
*self.state.borrow_mut() = GPUBufferState::MappedForReading;
// Step 5.4
promise.resolve_native(&array_buffer);
},
_ => promise.reject_error(Error::Operation),
};
},
_ => promise.reject_error(Error::Operation),
}
}
}

View file

@ -19,7 +19,7 @@ use dom_struct::dom_struct;
use ipc_channel::ipc;
use std::cell::Cell;
use std::collections::HashSet;
use webgpu::wgpu::resource::BufferUsage;
use webgpu::wgt::BufferUsage;
use webgpu::{WebGPU, WebGPUCommandEncoder, WebGPURequest};
const BUFFER_COPY_ALIGN_MASK: u64 = 3;

View file

@ -36,12 +36,13 @@ pub struct GPUComputePassEncoder {
}
impl GPUComputePassEncoder {
#[allow(unsafe_code)]
fn new_inherited(channel: WebGPU, parent: &GPUCommandEncoder) -> GPUComputePassEncoder {
GPUComputePassEncoder {
channel,
reflector_: Reflector::new(),
label: DomRefCell::new(None),
raw_pass: RefCell::new(Some(RawPass::new_compute(parent.id().0))),
raw_pass: RefCell::new(Some(unsafe { RawPass::new_compute(parent.id().0) })),
command_encoder: Dom::from_ref(parent),
}
}

View file

@ -42,10 +42,12 @@ use js::typedarray::{ArrayBuffer, CreateWith};
use std::collections::{HashMap, HashSet};
use std::ptr::{self, NonNull};
use webgpu::wgpu::binding_model::{
BindGroupBinding, BindGroupLayoutBinding, BindingResource, BindingType, BufferBinding,
ShaderStage,
BindGroupEntry, BindGroupLayoutEntry, BindingResource, BindingType, BufferBinding,
};
use webgpu::wgt::{
BufferDescriptor, BufferUsage, ShaderStage, TextureComponentType, TextureFormat,
TextureViewDimension,
};
use webgpu::wgpu::resource::{BufferDescriptor, BufferUsage};
use webgpu::{WebGPU, WebGPUDevice, WebGPUQueue, WebGPURequest};
#[dom_struct]
@ -108,7 +110,7 @@ impl GPUDevice {
fn validate_buffer_descriptor(
&self,
descriptor: &GPUBufferDescriptor,
) -> (bool, BufferDescriptor) {
) -> (bool, BufferDescriptor<std::string::String>) {
// TODO: Record a validation error in the current scope if the descriptor is invalid.
let wgpu_usage = BufferUsage::from_bits(descriptor.usage);
let valid = wgpu_usage.is_some() && descriptor.size > 0;
@ -119,6 +121,7 @@ impl GPUDevice {
BufferDescriptor {
size: descriptor.size,
usage: wgpu_usage.unwrap(),
label: Default::default(),
},
)
} else {
@ -127,6 +130,7 @@ impl GPUDevice {
BufferDescriptor {
size: 0,
usage: BufferUsage::STORAGE,
label: Default::default(),
},
)
}
@ -276,18 +280,9 @@ impl GPUDeviceMethods for GPUDevice {
max_storage_textures_per_shader_stage: limits.maxStorageTexturesPerShaderStage as i32,
max_samplers_per_shader_stage: limits.maxSamplersPerShaderStage as i32,
};
validation_map.insert(
webgpu::wgpu::binding_model::ShaderStage::VERTEX,
maxLimits.clone(),
);
validation_map.insert(
webgpu::wgpu::binding_model::ShaderStage::FRAGMENT,
maxLimits.clone(),
);
validation_map.insert(
webgpu::wgpu::binding_model::ShaderStage::COMPUTE,
maxLimits.clone(),
);
validation_map.insert(ShaderStage::VERTEX, maxLimits.clone());
validation_map.insert(ShaderStage::FRAGMENT, maxLimits.clone());
validation_map.insert(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 =
@ -344,14 +339,23 @@ impl GPUDeviceMethods for GPUDevice {
};
BindingType::SampledTexture
},
GPUBindingType::Storage_texture => {
GPUBindingType::Readonly_storage_texture => {
if let Some(limit) = validation_map.get_mut(&visibility) {
limit.max_storage_textures_per_shader_stage -= 1;
}
if bind.hasDynamicOffset {
valid = false
};
BindingType::StorageTexture
BindingType::ReadonlyStorageTexture
},
GPUBindingType::Writeonly_storage_texture => {
if let Some(limit) = validation_map.get_mut(&visibility) {
limit.max_storage_textures_per_shader_stage -= 1;
}
if bind.hasDynamicOffset {
valid = false
};
BindingType::WriteonlyStorageTexture
},
GPUBindingType::Sampler => {
if let Some(limit) = validation_map.get_mut(&visibility) {
@ -364,16 +368,19 @@ impl GPUDeviceMethods for GPUDevice {
},
};
BindGroupLayoutBinding {
BindGroupLayoutEntry {
binding: bind.binding,
visibility,
ty,
dynamic: bind.hasDynamicOffset,
has_dynamic_offset: bind.hasDynamicOffset,
multisampled: bind.multisampled,
texture_dimension: webgpu::wgpu::resource::TextureViewDimension::D2, // Use as default for now
// Use as default for now
texture_component_type: TextureComponentType::Float,
storage_texture_format: TextureFormat::Rgba8UnormSrgb,
view_dimension: TextureViewDimension::D2,
}
})
.collect::<Vec<BindGroupLayoutBinding>>();
.collect::<Vec<BindGroupLayoutEntry>>();
// bindings are unique
valid &= storeBindings.len() == bindings.len();
@ -523,7 +530,7 @@ impl GPUDeviceMethods for GPUDevice {
let bindings = descriptor
.entries
.iter()
.map(|bind| BindGroupBinding {
.map(|bind| BindGroupEntry {
binding: bind.binding,
resource: BindingResource::Buffer(BufferBinding {
buffer: bind.resource.buffer.id().0,

View file

@ -9,8 +9,8 @@ use webgpu::wgpu::{
AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandEncoderId, ComputePipelineId,
DeviceId, PipelineLayoutId, ShaderModuleId,
},
Backend,
};
use webgpu::wgt::Backend;
#[derive(Debug)]
pub struct IdentityHub {

View file

@ -239,7 +239,7 @@ impl BodyOperations for Response {
match body {
NetTraitsResponseBody::Done(bytes) => Some(bytes),
body => {
mem::replace(&mut *self.body.borrow_mut(), body);
let _ = mem::replace(&mut *self.body.borrow_mut(), body);
None
},
}

View file

@ -28,5 +28,7 @@ enum GPUBindingType {
"readonly-storage-buffer",
"sampler",
"sampled-texture",
"storage-texture"
"readonly-storage-texture",
"writeonly-storage-texture",
//"comparison-sampler",
};

View file

@ -5,7 +5,7 @@
// https://gpuweb.github.io/gpuweb/#gpubuffer
[Exposed=(Window, DedicatedWorker), Serializable, Pref="dom.webgpu.enabled"]
interface GPUBuffer {
Promise<ArrayBuffer> mapReadAsync();
//Promise<ArrayBuffer> mapReadAsync();
// Promise<ArrayBuffer> mapWriteAsync();
void unmap();

View file

@ -337,7 +337,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
($slot:expr) => {{
let dummy = Self::MinMax(Default::default(), MinMaxOp::Max);
let result = mem::replace($slot, dummy);
mem::replace(self, result);
let _ = mem::replace(self, result);
}};
}
match *self {
@ -464,7 +464,7 @@ impl<L: CalcNodeLeaf> CalcNode<L> {
replace_self_with!(&mut children[0]);
} else {
// Else put our simplified children back.
mem::replace(children_slot, children.into_boxed_slice().into());
let _ = mem::replace(children_slot, children.into_boxed_slice().into());
}
},
Self::Leaf(ref mut l) => {

View file

@ -15,7 +15,8 @@ embedder_traits = {path = "../embedder_traits"}
ipc-channel = "0.14"
log = "0.4"
malloc_size_of = { path = "../malloc_size_of" }
serde = "1.0"
serde = { version = "1.0", features = ["serde_derive"] }
servo_config = {path = "../config"}
smallvec = { version = "0.6", features = ["serde"] }
wgpu-core = { version = "0.1.0", git = "https://github.com/gfx-rs/wgpu", features = ["serde"] }
wgpu-core = { version = "0.5.0", git = "https://github.com/gfx-rs/wgpu", features = ["trace", "replay"] }
wgpu-types = { version = "0.5.0", git = "https://github.com/gfx-rs/wgpu", features = ["trace", "replay"] }

View file

@ -0,0 +1,114 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use ipc_channel::ipc::IpcSender;
use serde::{Deserialize, Serialize};
use wgpu::{
hub::{GlobalIdentityHandlerFactory, IdentityHandler, IdentityHandlerFactory},
id::{
AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, ComputePipelineId,
DeviceId, PipelineLayoutId, RenderPipelineId, SamplerId, ShaderModuleId, SurfaceId,
SwapChainId, TextureId, TextureViewId, TypedId,
},
};
use wgt::Backend;
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub enum WebGPUMsg {
FreeAdapter(AdapterId),
FreeDevice(DeviceId),
FreeBuffer(BufferId),
FreeSwapChain(SwapChainId),
FreePipelineLayout(PipelineLayoutId),
FreeComputePipeline(ComputePipelineId),
FreeRenderPipeline(RenderPipelineId),
FreeBindGroup(BindGroupId),
FreeBindGroupLayout(BindGroupLayoutId),
FreeCommandBuffer(CommandBufferId),
FreeTexture(TextureId),
FreeTextureView(TextureViewId),
FreeSampler(SamplerId),
FreeSurface(SurfaceId),
FreeShaderModule(ShaderModuleId),
}
#[derive(Debug)]
pub struct IdentityRecycler {
sender: IpcSender<WebGPUMsg>,
}
pub struct IdentityRecyclerFactory {
pub sender: IpcSender<WebGPUMsg>,
}
macro_rules! impl_identity_handler {
($id:ty, $st:tt, $($var:tt)*) => {
impl IdentityHandler<$id> for IdentityRecycler {
type Input = $id;
fn process(&self, id: $id, _backend: Backend) -> $id {
log::debug!("process {} {:?}", $st, id);
//debug_assert_eq!(id.unzip().2, backend);
id
}
fn free(&self, id: $id) {
log::debug!("free {} {:?}", $st, id);
let msg = $($var)*(id);
if self.sender.send(msg).is_err() {
log::error!("Failed to send {:?}", msg);
}
}
}
};
}
impl_identity_handler!(AdapterId, "adapter", WebGPUMsg::FreeAdapter);
impl_identity_handler!(DeviceId, "device", WebGPUMsg::FreeDevice);
impl_identity_handler!(SurfaceId, "surface", WebGPUMsg::FreeSurface);
impl_identity_handler!(SamplerId, "sampler", WebGPUMsg::FreeSampler);
impl_identity_handler!(TextureId, "texture", WebGPUMsg::FreeTexture);
impl_identity_handler!(TextureViewId, "texture_view", WebGPUMsg::FreeTextureView);
impl_identity_handler!(BufferId, "buffer", WebGPUMsg::FreeBuffer);
impl_identity_handler!(BindGroupId, "bind_group", WebGPUMsg::FreeBindGroup);
impl_identity_handler!(SwapChainId, "swap_chain", WebGPUMsg::FreeSwapChain);
impl_identity_handler!(ShaderModuleId, "shader_module", WebGPUMsg::FreeShaderModule);
impl_identity_handler!(
RenderPipelineId,
"render_pipeline",
WebGPUMsg::FreeRenderPipeline
);
impl_identity_handler!(
ComputePipelineId,
"compute_pipeline",
WebGPUMsg::FreeComputePipeline
);
impl_identity_handler!(
CommandBufferId,
"command_buffer",
WebGPUMsg::FreeCommandBuffer
);
impl_identity_handler!(
BindGroupLayoutId,
"bind_group_layout",
WebGPUMsg::FreeBindGroupLayout
);
impl_identity_handler!(
PipelineLayoutId,
"pipeline_layout",
WebGPUMsg::FreePipelineLayout
);
impl<I: TypedId + Clone + std::fmt::Debug> IdentityHandlerFactory<I> for IdentityRecyclerFactory
where
I: TypedId + Clone + std::fmt::Debug,
IdentityRecycler: IdentityHandler<I>,
{
type Filter = IdentityRecycler;
fn spawn(&self, _min_index: u32) -> Self::Filter {
IdentityRecycler {
sender: self.sender.clone(),
}
}
}
impl GlobalIdentityHandlerFactory for IdentityRecyclerFactory {}

View file

@ -6,21 +6,28 @@
extern crate log;
#[macro_use]
pub extern crate wgpu_core as wgpu;
pub extern crate wgpu_types as wgt;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender, IpcSharedMemory};
mod identity;
use identity::{IdentityRecyclerFactory, WebGPUMsg};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use serde::{Deserialize, Serialize};
use servo_config::pref;
use smallvec::SmallVec;
use std::ptr;
use wgpu::{
binding_model::{BindGroupBinding, BindGroupLayoutBinding},
binding_model::{
BindGroupDescriptor, BindGroupEntry, BindGroupLayoutDescriptor, BindGroupLayoutEntry,
},
id::{
AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, CommandEncoderId,
ComputePipelineId, DeviceId, PipelineLayoutId, QueueId, ShaderModuleId,
},
instance::{DeviceDescriptor, RequestAdapterOptions},
resource::BufferDescriptor,
BufferAddress,
instance::RequestAdapterOptions,
};
use wgt::{BufferAddress, BufferDescriptor, CommandBufferDescriptor, DeviceDescriptor};
#[derive(Debug, Deserialize, Serialize)]
pub enum WebGPUResponse {
@ -34,7 +41,6 @@ pub enum WebGPUResponse {
queue_id: WebGPUQueue,
_descriptor: DeviceDescriptor,
},
MapReadAsync(IpcSharedMemory),
}
pub type WebGPUResponseResult = Result<WebGPUResponse, String>;
@ -60,25 +66,25 @@ pub enum WebGPURequest {
device_id: DeviceId,
bind_group_id: BindGroupId,
bind_group_layout_id: BindGroupLayoutId,
bindings: Vec<BindGroupBinding>,
bindings: Vec<BindGroupEntry>,
},
CreateBindGroupLayout {
sender: IpcSender<WebGPUBindGroupLayout>,
device_id: DeviceId,
bind_group_layout_id: BindGroupLayoutId,
bindings: Vec<BindGroupLayoutBinding>,
bindings: Vec<BindGroupLayoutEntry>,
},
CreateBuffer {
sender: IpcSender<WebGPUBuffer>,
device_id: DeviceId,
buffer_id: BufferId,
descriptor: BufferDescriptor,
descriptor: BufferDescriptor<String>,
},
CreateBufferMapped {
sender: IpcSender<WebGPUBuffer>,
device_id: DeviceId,
buffer_id: BufferId,
descriptor: BufferDescriptor,
descriptor: BufferDescriptor<String>,
},
CreateCommandEncoder {
sender: IpcSender<WebGPUCommandEncoder>,
@ -109,13 +115,6 @@ pub enum WebGPURequest {
},
DestroyBuffer(BufferId),
Exit(IpcSender<()>),
MapReadAsync {
sender: IpcSender<WebGPUResponseResult>,
buffer_id: BufferId,
device_id: DeviceId,
usage: u32,
size: u64,
},
RequestAdapter {
sender: IpcSender<WebGPUResponseResult>,
options: RequestAdapterOptions,
@ -154,7 +153,7 @@ impl WebGPU {
Ok(sender_and_receiver) => sender_and_receiver,
Err(e) => {
warn!(
"Failed to create sender and receiciver for WGPU thread ({})",
"Failed to create sender and receiver for WGPU thread ({})",
e
);
return None;
@ -162,10 +161,21 @@ impl WebGPU {
};
let sender_clone = sender.clone();
let (script_sender, _script_recv) = match ipc::channel() {
Ok(sender_and_receiver) => sender_and_receiver,
Err(e) => {
warn!(
"Failed to create receiver and sender for WGPU thread ({})",
e
);
return None;
},
};
if let Err(e) = std::thread::Builder::new()
.name("WGPU".to_owned())
.spawn(move || {
WGPU::new(receiver, sender_clone).run();
WGPU::new(receiver, sender_clone, script_sender).run();
})
{
warn!("Failed to spwan WGPU thread ({})", e);
@ -184,7 +194,7 @@ impl WebGPU {
struct WGPU {
receiver: IpcReceiver<WebGPURequest>,
sender: IpcSender<WebGPURequest>,
global: wgpu::hub::Global<()>,
global: wgpu::hub::Global<IdentityRecyclerFactory>,
adapters: Vec<WebGPUAdapter>,
devices: Vec<WebGPUDevice>,
// Track invalid adapters https://gpuweb.github.io/gpuweb/#invalid
@ -192,21 +202,24 @@ struct WGPU {
}
impl WGPU {
fn new(receiver: IpcReceiver<WebGPURequest>, sender: IpcSender<WebGPURequest>) -> Self {
fn new(
receiver: IpcReceiver<WebGPURequest>,
sender: IpcSender<WebGPURequest>,
script_sender: IpcSender<WebGPUMsg>,
) -> Self {
let factory = IdentityRecyclerFactory {
sender: script_sender,
};
WGPU {
receiver,
sender,
global: wgpu::hub::Global::new("wgpu-core"),
global: wgpu::hub::Global::new("wgpu-core", factory),
adapters: Vec::new(),
devices: Vec::new(),
_invalid_adapters: Vec::new(),
}
}
fn deinit(self) {
self.global.delete()
}
fn run(mut self) {
while let Ok(msg) = self.receiver.recv() {
match msg {
@ -217,7 +230,7 @@ impl WGPU {
let global = &self.global;
let command_buffer_id = gfx_select!(command_encoder_id => global.command_encoder_finish(
command_encoder_id,
&wgpu::command::CommandBufferDescriptor::default()
&CommandBufferDescriptor::default()
));
if let Err(e) = sender.send(WebGPUCommandBuffer(command_buffer_id)) {
warn!(
@ -252,10 +265,11 @@ impl WGPU {
bindings,
} => {
let global = &self.global;
let descriptor = wgpu_core::binding_model::BindGroupDescriptor {
let descriptor = BindGroupDescriptor {
layout: bind_group_layout_id,
bindings: bindings.as_ptr(),
bindings_length: bindings.len(),
entries: bindings.as_ptr(),
entries_length: bindings.len(),
label: ptr::null(),
};
let bg_id = gfx_select!(bind_group_id =>
global.device_create_bind_group(device_id, &descriptor, bind_group_id));
@ -275,9 +289,10 @@ impl WGPU {
bindings,
} => {
let global = &self.global;
let descriptor = wgpu_core::binding_model::BindGroupLayoutDescriptor {
bindings: bindings.as_ptr(),
bindings_length: bindings.len(),
let descriptor = BindGroupLayoutDescriptor {
entries: bindings.as_ptr(),
entries_length: bindings.len(),
label: ptr::null(),
};
let bgl_id = gfx_select!(bind_group_layout_id =>
global.device_create_bind_group_layout(device_id, &descriptor, bind_group_layout_id));
@ -297,7 +312,12 @@ impl WGPU {
descriptor,
} => {
let global = &self.global;
let id = gfx_select!(buffer_id => global.device_create_buffer(device_id, &descriptor, buffer_id));
let desc = BufferDescriptor {
size: descriptor.size,
usage: descriptor.usage,
label: ptr::null(),
};
let id = gfx_select!(buffer_id => global.device_create_buffer(device_id, &desc, buffer_id));
let buffer = WebGPUBuffer(id);
if let Err(e) = sender.send(buffer) {
warn!(
@ -313,8 +333,13 @@ impl WGPU {
descriptor,
} => {
let global = &self.global;
let desc = BufferDescriptor {
size: descriptor.size,
usage: descriptor.usage,
label: ptr::null(),
};
let (buffer_id, _arr_buff_ptr) = gfx_select!(buffer_id =>
global.device_create_buffer_mapped(device_id, &descriptor, buffer_id));
global.device_create_buffer_mapped(device_id, &desc, buffer_id));
let buffer = WebGPUBuffer(buffer_id);
if let Err(e) = sender.send(buffer) {
@ -418,55 +443,12 @@ impl WGPU {
gfx_select!(buffer => global.buffer_destroy(buffer));
},
WebGPURequest::Exit(sender) => {
self.deinit();
drop(self.global);
if let Err(e) = sender.send(()) {
warn!("Failed to send response to WebGPURequest::Exit ({})", e)
}
return;
},
WebGPURequest::MapReadAsync {
sender,
buffer_id,
device_id,
usage,
size,
} => {
let global = &self.global;
let on_read = move |status: wgpu::resource::BufferMapAsyncStatus,
ptr: *const u8| {
match status {
wgpu::resource::BufferMapAsyncStatus::Success => {
let array_buffer =
unsafe { std::slice::from_raw_parts(ptr, size as usize) };
if let Err(e) = sender.send(Ok(WebGPUResponse::MapReadAsync(
IpcSharedMemory::from_bytes(array_buffer),
))) {
warn!(
"Failed to send response to WebGPURequest::MapReadAsync ({})",
e
)
}
},
_ => {
if let Err(e) = sender
.send(Err("MapReadAsync: Failed to map buffer".to_owned()))
{
warn!(
"Failed to send response to WebGPURequest::MapReadAsync ({})",
e
)
}
},
}
};
gfx_select!(buffer_id => global.buffer_map_async(
buffer_id,
wgpu::resource::BufferUsage::from_bits(usage).unwrap(),
0..size,
wgpu::resource::BufferMapOperation::Read(Box::new(on_read))
));
gfx_select!(device_id => global.device_poll(device_id, true));
},
WebGPURequest::RequestAdapter {
sender,
options,
@ -523,6 +505,7 @@ impl WGPU {
let id = gfx_select!(device_id => global.adapter_request_device(
adapter_id.0,
&descriptor,
None,
device_id
));