aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamson <16504129+sagudev@users.noreply.github.com>2024-05-08 15:53:39 +0200
committerGitHub <noreply@github.com>2024-05-08 13:53:39 +0000
commit168d43f24a18184afadc6aa8646537289c85860a (patch)
tree138629b4b003141fbb5c6cb8fcf8cee3272664c2
parentc4f8599404e52da58e9e4e8f8aef3e7efa4996c9 (diff)
downloadservo-168d43f24a18184afadc6aa8646537289c85860a.tar.gz
servo-168d43f24a18184afadc6aa8646537289c85860a.zip
webgpu: Refactor webgpu crate (#32255)
* wgpu(_core) -> wgc * Refactor webgpu crate split lib.rs into multiple modules
-rw-r--r--components/script/dom/globalscope.rs3
-rw-r--r--components/script/dom/gpu.rs4
-rw-r--r--components/script/dom/gpubuffer.rs7
-rw-r--r--components/script/dom/gpucanvascontext.rs2
-rw-r--r--components/script/dom/gpucommandencoder.rs2
-rw-r--r--components/script/dom/gpucomputepassencoder.rs2
-rw-r--r--components/script/dom/gpuconvert.rs2
-rw-r--r--components/script/dom/gpudevice.rs7
-rw-r--r--components/script/dom/gpuqueue.rs3
-rw-r--r--components/script/dom/gpurenderbundleencoder.rs2
-rw-r--r--components/script/dom/gpurenderpassencoder.rs2
-rw-r--r--components/script/dom/gputexture.rs5
-rw-r--r--components/script/dom/identityhub.rs6
-rw-r--r--components/script/script_thread.rs2
-rw-r--r--components/shared/script/lib.rs2
-rw-r--r--components/shared/script/script_msg.rs6
-rw-r--r--components/webgpu/dom_messages.rs254
-rw-r--r--components/webgpu/identity.rs77
-rw-r--r--components/webgpu/lib.rs1357
-rw-r--r--components/webgpu/script_messages.rs55
-rw-r--r--components/webgpu/wgpu_thread.rs1088
21 files changed, 1475 insertions, 1413 deletions
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 5948ee302cf..32febf8ab8e 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -56,8 +56,7 @@ use script_traits::{
};
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
use uuid::Uuid;
-use webgpu::identity::WebGPUOpResult;
-use webgpu::{ErrorScopeId, WebGPUDevice};
+use webgpu::{ErrorScopeId, WebGPUDevice, WebGPUOpResult};
use super::bindings::trace::HashMapTracedValues;
use crate::dom::bindings::cell::{DomRefCell, RefMut};
diff --git a/components/script/dom/gpu.rs b/components/script/dom/gpu.rs
index d3babad3850..1dbd852f0f3 100644
--- a/components/script/dom/gpu.rs
+++ b/components/script/dom/gpu.rs
@@ -10,7 +10,7 @@ use ipc_channel::router::ROUTER;
use js::jsapi::Heap;
use script_traits::ScriptMsg;
use webgpu::wgt::PowerPreference;
-use webgpu::{wgpu, WebGPUResponse, WebGPUResponseResult};
+use webgpu::{wgc, WebGPUResponse, WebGPUResponseResult};
use super::bindings::codegen::Bindings::WebGPUBinding::GPUTextureFormat;
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
@@ -117,7 +117,7 @@ impl GPUMethods for GPU {
if script_to_constellation_chan
.send(ScriptMsg::RequestAdapter(
sender,
- wgpu::instance::RequestAdapterOptions {
+ wgc::instance::RequestAdapterOptions {
power_preference,
compatible_surface: None,
force_fallback_adapter: options.forceFallbackAdapter,
diff --git a/components/script/dom/gpubuffer.rs b/components/script/dom/gpubuffer.rs
index 400bfa3c57d..bb747a998cc 100644
--- a/components/script/dom/gpubuffer.rs
+++ b/components/script/dom/gpubuffer.rs
@@ -11,9 +11,10 @@ use std::sync::{Arc, Mutex};
use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSharedMemory;
use js::typedarray::{ArrayBuffer, ArrayBufferU8};
-use webgpu::identity::WebGPUOpResult;
-use webgpu::wgpu::device::HostMap;
-use webgpu::{WebGPU, WebGPUBuffer, WebGPURequest, WebGPUResponse, WebGPUResponseResult};
+use webgpu::wgc::device::HostMap;
+use webgpu::{
+ WebGPU, WebGPUBuffer, WebGPUOpResult, WebGPURequest, WebGPUResponse, WebGPUResponseResult,
+};
use super::bindings::buffer_source::{create_new_external_array_buffer, HeapBufferSource};
use crate::dom::bindings::cell::DomRefCell;
diff --git a/components/script/dom/gpucanvascontext.rs b/components/script/dom/gpucanvascontext.rs
index 775b21530ab..0aa45648f8e 100644
--- a/components/script/dom/gpucanvascontext.rs
+++ b/components/script/dom/gpucanvascontext.rs
@@ -9,7 +9,7 @@ use dom_struct::dom_struct;
use euclid::default::Size2D;
use ipc_channel::ipc;
use script_layout_interface::HTMLCanvasDataSource;
-use webgpu::wgpu::id;
+use webgpu::wgc::id;
use webgpu::{wgt, WebGPU, WebGPURequest, WebGPUTexture, PRESENTATION_BUFFER_COUNT};
use webrender_api::{
units, ExternalImageData, ExternalImageId, ExternalImageType, ImageData, ImageDescriptor,
diff --git a/components/script/dom/gpucommandencoder.rs b/components/script/dom/gpucommandencoder.rs
index 7bd5de4af94..8f26601b122 100644
--- a/components/script/dom/gpucommandencoder.rs
+++ b/components/script/dom/gpucommandencoder.rs
@@ -7,7 +7,7 @@ use std::cell::Cell;
use std::collections::HashSet;
use dom_struct::dom_struct;
-use webgpu::wgpu::command as wgpu_com;
+use webgpu::wgc::command as wgpu_com;
use webgpu::{self, wgt, WebGPU, WebGPURequest};
use crate::dom::bindings::cell::DomRefCell;
diff --git a/components/script/dom/gpucomputepassencoder.rs b/components/script/dom/gpucomputepassencoder.rs
index 40264947eb5..cb0153b3c22 100644
--- a/components/script/dom/gpucomputepassencoder.rs
+++ b/components/script/dom/gpucomputepassencoder.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use webgpu::wgpu::command::{compute_commands as wgpu_comp, ComputePass};
+use webgpu::wgc::command::{compute_commands as wgpu_comp, ComputePass};
use webgpu::{WebGPU, WebGPURequest};
use super::bindings::error::Fallible;
diff --git a/components/script/dom/gpuconvert.rs b/components/script/dom/gpuconvert.rs
index 82b6b1dc2f0..bdfa9b8dd35 100644
--- a/components/script/dom/gpuconvert.rs
+++ b/components/script/dom/gpuconvert.rs
@@ -4,7 +4,7 @@
use std::borrow::Cow;
-use webgpu::wgpu::command as wgpu_com;
+use webgpu::wgc::command as wgpu_com;
use webgpu::wgt;
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
diff --git a/components/script/dom/gpudevice.rs b/components/script/dom/gpudevice.rs
index b7a705261ef..f208ee37c47 100644
--- a/components/script/dom/gpudevice.rs
+++ b/components/script/dom/gpudevice.rs
@@ -13,12 +13,11 @@ use std::sync::{Arc, Mutex};
use dom_struct::dom_struct;
use js::jsapi::{Heap, JSObject};
-use webgpu::identity::WebGPUOpResult;
-use webgpu::wgpu::id::{BindGroupLayoutId, PipelineLayoutId};
-use webgpu::wgpu::{
+use webgpu::wgc::id::{BindGroupLayoutId, PipelineLayoutId};
+use webgpu::wgc::{
binding_model as wgpu_bind, command as wgpu_com, pipeline as wgpu_pipe, resource as wgpu_res,
};
-use webgpu::{self, wgt, ErrorScopeId, WebGPU, WebGPURequest};
+use webgpu::{self, wgt, ErrorScopeId, WebGPU, WebGPUOpResult, WebGPURequest};
use super::bindings::codegen::UnionTypes::GPUPipelineLayoutOrGPUAutoLayoutMode;
use super::bindings::error::Fallible;
diff --git a/components/script/dom/gpuqueue.rs b/components/script/dom/gpuqueue.rs
index bcc60eb5dd2..4a2fef174b3 100644
--- a/components/script/dom/gpuqueue.rs
+++ b/components/script/dom/gpuqueue.rs
@@ -6,8 +6,7 @@ use std::rc::Rc;
use dom_struct::dom_struct;
use ipc_channel::ipc::IpcSharedMemory;
-use webgpu::identity::WebGPUOpResult;
-use webgpu::{wgt, WebGPU, WebGPUQueue, WebGPURequest, WebGPUResponse};
+use webgpu::{wgt, WebGPU, WebGPUOpResult, WebGPUQueue, WebGPURequest, WebGPUResponse};
use super::bindings::codegen::Bindings::WebGPUBinding::{GPUImageCopyTexture, GPUImageDataLayout};
use super::gpu::{response_async, AsyncWGPUListener};
diff --git a/components/script/dom/gpurenderbundleencoder.rs b/components/script/dom/gpurenderbundleencoder.rs
index 6287b8233d7..7fb3de9c489 100644
--- a/components/script/dom/gpurenderbundleencoder.rs
+++ b/components/script/dom/gpurenderbundleencoder.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use webgpu::wgpu::command::{bundle_ffi as wgpu_bundle, RenderBundleEncoder};
+use webgpu::wgc::command::{bundle_ffi as wgpu_bundle, RenderBundleEncoder};
use webgpu::{wgt, WebGPU, WebGPURenderBundle, WebGPURequest};
use super::bindings::codegen::Bindings::WebGPUBinding::GPUIndexFormat;
diff --git a/components/script/dom/gpurenderpassencoder.rs b/components/script/dom/gpurenderpassencoder.rs
index ee3d1621ba3..a0a87ad4f4d 100644
--- a/components/script/dom/gpurenderpassencoder.rs
+++ b/components/script/dom/gpurenderpassencoder.rs
@@ -3,7 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use webgpu::wgpu::command::{render_commands as wgpu_render, RenderPass};
+use webgpu::wgc::command::{render_commands as wgpu_render, RenderPass};
use webgpu::{wgt, WebGPU, WebGPURequest};
use super::bindings::codegen::Bindings::WebGPUBinding::GPUIndexFormat;
diff --git a/components/script/dom/gputexture.rs b/components/script/dom/gputexture.rs
index 0b7db7a16fd..4f97024f774 100644
--- a/components/script/dom/gputexture.rs
+++ b/components/script/dom/gputexture.rs
@@ -6,9 +6,8 @@ use std::cell::Cell;
use std::string::String;
use dom_struct::dom_struct;
-use webgpu::identity::WebGPUOpResult;
-use webgpu::wgpu::resource;
-use webgpu::{wgt, WebGPU, WebGPURequest, WebGPUTexture, WebGPUTextureView};
+use webgpu::wgc::resource;
+use webgpu::{wgt, WebGPU, WebGPUOpResult, WebGPURequest, WebGPUTexture, WebGPUTextureView};
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::WebGPUBinding::{
diff --git a/components/script/dom/identityhub.rs b/components/script/dom/identityhub.rs
index 976637dac51..391afa641c9 100644
--- a/components/script/dom/identityhub.rs
+++ b/components/script/dom/identityhub.rs
@@ -3,16 +3,16 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use smallvec::SmallVec;
-use webgpu::wgpu::id::markers::{
+use webgpu::wgc::id::markers::{
Adapter, BindGroup, BindGroupLayout, Buffer, CommandEncoder, ComputePipeline, Device,
PipelineLayout, RenderBundle, RenderPipeline, Sampler, ShaderModule, Texture, TextureView,
};
-use webgpu::wgpu::id::{
+use webgpu::wgc::id::{
AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandEncoderId, ComputePipelineId,
DeviceId, PipelineLayoutId, RenderBundleId, RenderPipelineId, SamplerId, ShaderModuleId,
TextureId, TextureViewId,
};
-use webgpu::wgpu::identity::IdentityManager;
+use webgpu::wgc::identity::IdentityManager;
use webgpu::wgt::Backend;
#[derive(Debug)]
diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs
index 36914a21507..e5af478a5c9 100644
--- a/components/script/script_thread.rs
+++ b/components/script/script_thread.rs
@@ -95,7 +95,7 @@ use style::dom::OpaqueNode;
use style::thread_state::{self, ThreadState};
use time::precise_time_ns;
use url::Position;
-use webgpu::identity::WebGPUMsg;
+use webgpu::WebGPUMsg;
use webrender_api::units::LayoutPixel;
use webrender_api::DocumentId;
diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs
index 76d0e74bd31..43010955aff 100644
--- a/components/shared/script/lib.rs
+++ b/components/shared/script/lib.rs
@@ -55,7 +55,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer};
use servo_atoms::Atom;
use servo_url::{ImmutableOrigin, ServoUrl};
use style_traits::{CSSPixel, SpeculativePainter};
-use webgpu::identity::WebGPUMsg;
+use webgpu::WebGPUMsg;
use webrender_api::units::{DeviceIntSize, DevicePixel, DevicePoint, LayoutPixel, LayoutPoint};
use webrender_api::{
BuiltDisplayList, BuiltDisplayListDescriptor, DocumentId, ExternalImageData, ExternalScrollId,
diff --git a/components/shared/script/script_msg.rs b/components/shared/script/script_msg.rs
index ff854b8d26f..a51859231ba 100644
--- a/components/shared/script/script_msg.rs
+++ b/components/shared/script/script_msg.rs
@@ -24,7 +24,7 @@ use serde::{Deserialize, Serialize};
use servo_url::{ImmutableOrigin, ServoUrl};
use smallvec::SmallVec;
use style_traits::CSSPixel;
-use webgpu::{wgpu, WebGPU, WebGPUResponseResult};
+use webgpu::{wgc, WebGPU, WebGPUResponseResult};
use webrender_api::units::{DeviceIntPoint, DeviceIntSize};
use crate::{
@@ -258,8 +258,8 @@ pub enum ScriptMsg {
/// Create a WebGPU Adapter instance
RequestAdapter(
IpcSender<Option<WebGPUResponseResult>>,
- wgpu::instance::RequestAdapterOptions,
- SmallVec<[wgpu::id::AdapterId; 4]>,
+ wgc::instance::RequestAdapterOptions,
+ SmallVec<[wgc::id::AdapterId; 4]>,
),
/// Get WebGPU channel
GetWebGPUChan(IpcSender<Option<WebGPU>>),
diff --git a/components/webgpu/dom_messages.rs b/components/webgpu/dom_messages.rs
new file mode 100644
index 00000000000..6edd6f93e88
--- /dev/null
+++ b/components/webgpu/dom_messages.rs
@@ -0,0 +1,254 @@
+/* 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/. */
+
+//! IPC massages that are send/received from GPU DOM objects.
+
+use std::borrow::Cow;
+
+use arrayvec::ArrayVec;
+use ipc_channel::ipc::{IpcSender, IpcSharedMemory};
+use msg::constellation_msg::PipelineId;
+use serde::{Deserialize, Serialize};
+use smallvec::SmallVec;
+use webrender_api::{ExternalImageId, ImageData, ImageDescriptor, ImageKey};
+use wgc::binding_model::{
+ BindGroupDescriptor, BindGroupLayoutDescriptor, PipelineLayoutDescriptor,
+};
+use wgc::command::{
+ ComputePass, ImageCopyBuffer, ImageCopyTexture, RenderBundleDescriptor, RenderBundleEncoder,
+ RenderPass,
+};
+use wgc::device::HostMap;
+use wgc::id;
+use wgc::instance::RequestAdapterOptions;
+use wgc::pipeline::{ComputePipelineDescriptor, RenderPipelineDescriptor};
+use wgc::resource::{
+ BufferDescriptor, SamplerDescriptor, TextureDescriptor, TextureViewDescriptor,
+};
+pub use {wgpu_core as wgc, wgpu_types as wgt};
+
+use crate::identity::*;
+use crate::{WebGPU, PRESENTATION_BUFFER_COUNT};
+
+#[derive(Debug, Deserialize, Serialize)]
+#[allow(clippy::large_enum_variant)]
+pub enum WebGPUResponse {
+ RequestAdapter {
+ adapter_info: wgt::AdapterInfo,
+ adapter_id: WebGPUAdapter,
+ features: wgt::Features,
+ limits: wgt::Limits,
+ channel: WebGPU,
+ },
+ RequestDevice {
+ device_id: WebGPUDevice,
+ queue_id: WebGPUQueue,
+ descriptor: wgt::DeviceDescriptor<Option<String>>,
+ },
+ BufferMapAsync(IpcSharedMemory),
+ SubmittedWorkDone,
+}
+
+pub type WebGPUResponseResult = Result<WebGPUResponse, String>;
+
+#[derive(Debug, Deserialize, Serialize)]
+pub enum WebGPURequest {
+ BufferMapAsync {
+ sender: IpcSender<Option<WebGPUResponseResult>>,
+ buffer_id: id::BufferId,
+ device_id: id::DeviceId,
+ host_map: HostMap,
+ offset: u64,
+ size: Option<u64>,
+ },
+ CommandEncoderFinish {
+ command_encoder_id: id::CommandEncoderId,
+ device_id: id::DeviceId,
+ is_error: bool,
+ // TODO(zakorgy): Serialize CommandBufferDescriptor in wgpu-core
+ // wgc::command::CommandBufferDescriptor,
+ },
+ CopyBufferToBuffer {
+ command_encoder_id: id::CommandEncoderId,
+ source_id: id::BufferId,
+ source_offset: wgt::BufferAddress,
+ destination_id: id::BufferId,
+ destination_offset: wgt::BufferAddress,
+ size: wgt::BufferAddress,
+ },
+ CopyBufferToTexture {
+ command_encoder_id: id::CommandEncoderId,
+ source: ImageCopyBuffer,
+ destination: ImageCopyTexture,
+ copy_size: wgt::Extent3d,
+ },
+ CopyTextureToBuffer {
+ command_encoder_id: id::CommandEncoderId,
+ source: ImageCopyTexture,
+ destination: ImageCopyBuffer,
+ copy_size: wgt::Extent3d,
+ },
+ CopyTextureToTexture {
+ command_encoder_id: id::CommandEncoderId,
+ source: ImageCopyTexture,
+ destination: ImageCopyTexture,
+ copy_size: wgt::Extent3d,
+ },
+ CreateBindGroup {
+ device_id: id::DeviceId,
+ bind_group_id: id::BindGroupId,
+ descriptor: BindGroupDescriptor<'static>,
+ },
+ CreateBindGroupLayout {
+ device_id: id::DeviceId,
+ bind_group_layout_id: id::BindGroupLayoutId,
+ descriptor: Option<BindGroupLayoutDescriptor<'static>>,
+ },
+ CreateBuffer {
+ device_id: id::DeviceId,
+ buffer_id: id::BufferId,
+ descriptor: Option<BufferDescriptor<'static>>,
+ },
+ CreateCommandEncoder {
+ device_id: id::DeviceId,
+ // TODO(zakorgy): Serialize CommandEncoderDescriptor in wgpu-core
+ // wgc::command::CommandEncoderDescriptor,
+ command_encoder_id: id::CommandEncoderId,
+ label: Option<Cow<'static, str>>,
+ },
+ CreateComputePipeline {
+ device_id: id::DeviceId,
+ compute_pipeline_id: id::ComputePipelineId,
+ descriptor: ComputePipelineDescriptor<'static>,
+ implicit_ids: Option<(id::PipelineLayoutId, Vec<id::BindGroupLayoutId>)>,
+ },
+ CreateContext(IpcSender<ExternalImageId>),
+ CreatePipelineLayout {
+ device_id: id::DeviceId,
+ pipeline_layout_id: id::PipelineLayoutId,
+ descriptor: PipelineLayoutDescriptor<'static>,
+ },
+ CreateRenderPipeline {
+ device_id: id::DeviceId,
+ render_pipeline_id: id::RenderPipelineId,
+ descriptor: Option<RenderPipelineDescriptor<'static>>,
+ implicit_ids: Option<(id::PipelineLayoutId, Vec<id::BindGroupLayoutId>)>,
+ },
+ CreateSampler {
+ device_id: id::DeviceId,
+ sampler_id: id::SamplerId,
+ descriptor: SamplerDescriptor<'static>,
+ },
+ CreateShaderModule {
+ device_id: id::DeviceId,
+ program_id: id::ShaderModuleId,
+ program: String,
+ label: Option<String>,
+ },
+ CreateSwapChain {
+ device_id: id::DeviceId,
+ buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
+ external_id: u64,
+ sender: IpcSender<ImageKey>,
+ image_desc: ImageDescriptor,
+ image_data: ImageData,
+ },
+ CreateTexture {
+ device_id: id::DeviceId,
+ texture_id: id::TextureId,
+ descriptor: Option<TextureDescriptor<'static>>,
+ },
+ CreateTextureView {
+ texture_id: id::TextureId,
+ texture_view_id: id::TextureViewId,
+ device_id: id::DeviceId,
+ descriptor: Option<TextureViewDescriptor<'static>>,
+ },
+ DestroyBuffer(id::BufferId),
+ DestroyDevice(id::DeviceId),
+ DestroyTexture {
+ device_id: id::DeviceId,
+ texture_id: id::TextureId,
+ },
+ DestroySwapChain {
+ external_id: u64,
+ image_key: ImageKey,
+ },
+ DropTexture(id::TextureId),
+ DropAdapter(id::AdapterId),
+ DropDevice(id::DeviceId),
+ DropBuffer(id::BufferId),
+ DropPipelineLayout(id::PipelineLayoutId),
+ DropComputePipeline(id::ComputePipelineId),
+ DropRenderPipeline(id::RenderPipelineId),
+ DropBindGroup(id::BindGroupId),
+ DropBindGroupLayout(id::BindGroupLayoutId),
+ DropCommandBuffer(id::CommandBufferId),
+ DropTextureView(id::TextureViewId),
+ DropSampler(id::SamplerId),
+ DropShaderModule(id::ShaderModuleId),
+ DropRenderBundle(id::RenderBundleId),
+ DropQuerySet(id::QuerySetId),
+ Exit(IpcSender<()>),
+ RenderBundleEncoderFinish {
+ render_bundle_encoder: RenderBundleEncoder,
+ descriptor: RenderBundleDescriptor<'static>,
+ render_bundle_id: id::RenderBundleId,
+ device_id: id::DeviceId,
+ },
+ RequestAdapter {
+ sender: IpcSender<Option<WebGPUResponseResult>>,
+ options: RequestAdapterOptions,
+ ids: SmallVec<[id::AdapterId; 4]>,
+ },
+ RequestDevice {
+ sender: IpcSender<Option<WebGPUResponseResult>>,
+ adapter_id: WebGPUAdapter,
+ descriptor: wgt::DeviceDescriptor<Option<String>>,
+ device_id: id::DeviceId,
+ pipeline_id: PipelineId,
+ },
+ RunComputePass {
+ command_encoder_id: id::CommandEncoderId,
+ compute_pass: Option<ComputePass>,
+ },
+ RunRenderPass {
+ command_encoder_id: id::CommandEncoderId,
+ render_pass: Option<RenderPass>,
+ },
+ Submit {
+ queue_id: id::QueueId,
+ command_buffers: Vec<id::CommandBufferId>,
+ },
+ SwapChainPresent {
+ external_id: u64,
+ texture_id: id::TextureId,
+ encoder_id: id::CommandEncoderId,
+ },
+ UnmapBuffer {
+ buffer_id: id::BufferId,
+ device_id: id::DeviceId,
+ array_buffer: IpcSharedMemory,
+ is_map_read: bool,
+ offset: u64,
+ size: u64,
+ },
+ WriteBuffer {
+ queue_id: id::QueueId,
+ buffer_id: id::BufferId,
+ buffer_offset: u64,
+ data: IpcSharedMemory,
+ },
+ WriteTexture {
+ queue_id: id::QueueId,
+ texture_cv: ImageCopyTexture,
+ data_layout: wgt::ImageDataLayout,
+ size: wgt::Extent3d,
+ data: IpcSharedMemory,
+ },
+ QueueOnSubmittedWorkDone {
+ sender: IpcSender<Option<WebGPUResponseResult>>,
+ queue_id: id::QueueId,
+ },
+}
diff --git a/components/webgpu/identity.rs b/components/webgpu/identity.rs
index 019428fe9c7..86ea497f67d 100644
--- a/components/webgpu/identity.rs
+++ b/components/webgpu/identity.rs
@@ -2,51 +2,44 @@
* 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 msg::constellation_msg::PipelineId;
+use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
use serde::{Deserialize, Serialize};
-use crate::wgpu::id::{
- AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, ComputePipelineId,
- DeviceId, PipelineLayoutId, QuerySetId, RenderBundleId, RenderPipelineId, SamplerId,
- ShaderModuleId, StagingBufferId, SurfaceId, TextureId, TextureViewId,
+use crate::wgc::id::{
+ AdapterId, BindGroupId, BindGroupLayoutId, BufferId, CommandBufferId, CommandEncoderId,
+ ComputePipelineId, DeviceId, PipelineLayoutId, QueueId, RenderBundleId, RenderPipelineId,
+ SamplerId, ShaderModuleId, SurfaceId, TextureId, TextureViewId,
};
-use crate::{ErrorScopeId, WebGPUDevice};
-#[derive(Clone, Debug, Deserialize, Serialize)]
-pub enum WebGPUOpResult {
- ValidationError(String),
- OutOfMemoryError,
- Success,
-}
+macro_rules! webgpu_resource {
+ ($name:ident, $id:ty) => {
+ #[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
+ pub struct $name(pub $id);
+
+ impl MallocSizeOf for $name {
+ fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
+ 0
+ }
+ }
-#[derive(Clone, Debug, Deserialize, Serialize)]
-pub enum WebGPUMsg {
- FreeAdapter(AdapterId),
- FreeDevice(DeviceId),
- FreeBuffer(BufferId),
- FreePipelineLayout(PipelineLayoutId),
- FreeComputePipeline(ComputePipelineId),
- FreeRenderPipeline(RenderPipelineId),
- FreeBindGroup(BindGroupId),
- FreeBindGroupLayout(BindGroupLayoutId),
- FreeCommandBuffer(CommandBufferId),
- FreeTexture(TextureId),
- FreeTextureView(TextureViewId),
- FreeSampler(SamplerId),
- FreeSurface(SurfaceId),
- FreeShaderModule(ShaderModuleId),
- FreeRenderBundle(RenderBundleId),
- FreeStagingBuffer(StagingBufferId),
- FreeQuerySet(QuerySetId),
- WebGPUOpResult {
- device: WebGPUDevice,
- scope_id: Option<ErrorScopeId>,
- pipeline_id: PipelineId,
- result: WebGPUOpResult,
- },
- CleanDevice {
- device: WebGPUDevice,
- pipeline_id: PipelineId,
- },
- Exit,
+ impl Eq for $name {}
+ };
}
+
+webgpu_resource!(WebGPUAdapter, AdapterId);
+webgpu_resource!(WebGPUBindGroup, BindGroupId);
+webgpu_resource!(WebGPUBindGroupLayout, BindGroupLayoutId);
+webgpu_resource!(WebGPUBuffer, BufferId);
+webgpu_resource!(WebGPUCommandBuffer, CommandBufferId);
+webgpu_resource!(WebGPUCommandEncoder, CommandEncoderId);
+webgpu_resource!(WebGPUComputePipeline, ComputePipelineId);
+webgpu_resource!(WebGPUDevice, DeviceId);
+webgpu_resource!(WebGPUPipelineLayout, PipelineLayoutId);
+webgpu_resource!(WebGPUQueue, QueueId);
+webgpu_resource!(WebGPURenderBundle, RenderBundleId);
+webgpu_resource!(WebGPURenderPipeline, RenderPipelineId);
+webgpu_resource!(WebGPUSampler, SamplerId);
+webgpu_resource!(WebGPUShaderModule, ShaderModuleId);
+webgpu_resource!(WebGPUSurface, SurfaceId);
+webgpu_resource!(WebGPUTexture, TextureId);
+webgpu_resource!(WebGPUTextureView, TextureViewId);
diff --git a/components/webgpu/lib.rs b/components/webgpu/lib.rs
index cfe2d9c1689..97bcb137267 100644
--- a/components/webgpu/lib.rs
+++ b/components/webgpu/lib.rs
@@ -2,278 +2,38 @@
* 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 log::{error, warn};
-use wgpu::device::queue::SubmittedWorkDoneClosure;
-use wgpu::gfx_select;
-pub use {wgpu_core as wgpu, wgpu_types as wgt};
+use log::warn;
+use webrender::RenderApiSender;
+use wgpu_thread::WGPU;
+pub use {wgpu_core as wgc, wgpu_types as wgt};
pub mod identity;
+mod wgpu_thread;
use std::borrow::Cow;
-use std::cell::RefCell;
use std::collections::HashMap;
use std::num::NonZeroU64;
-use std::slice;
use std::sync::{Arc, Mutex};
-use std::time::{Duration, Instant};
use arrayvec::ArrayVec;
use euclid::default::Size2D;
-use identity::{WebGPUMsg, WebGPUOpResult};
-use ipc_channel::ipc::{self, IpcReceiver, IpcSender, IpcSharedMemory};
-use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
-use msg::constellation_msg::PipelineId;
+use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use serde::{Deserialize, Serialize};
use servo_config::pref;
-use smallvec::SmallVec;
-use webrender::{RenderApi, RenderApiSender, Transaction};
-use webrender_api::{DirtyRect, DocumentId, ExternalImageId, ImageData, ImageDescriptor, ImageKey};
+use webrender_api::{DocumentId, ImageData, ImageDescriptor, ImageKey};
use webrender_traits::{
- WebrenderExternalImageApi, WebrenderExternalImageRegistry, WebrenderImageHandlerType,
- WebrenderImageSource,
+ WebrenderExternalImageApi, WebrenderExternalImageRegistry, WebrenderImageSource,
};
-use wgpu::binding_model::{
- BindGroupDescriptor, BindGroupLayoutDescriptor, PipelineLayoutDescriptor,
-};
-use wgpu::command::{
- ComputePass, ImageCopyBuffer, ImageCopyTexture, RenderBundleDescriptor, RenderBundleEncoder,
- RenderPass,
-};
-use wgpu::device::{DeviceDescriptor, HostMap, ImplicitPipelineIds};
-use wgpu::id;
-use wgpu::instance::RequestAdapterOptions;
-use wgpu::pipeline::{ComputePipelineDescriptor, RenderPipelineDescriptor, ShaderModuleDescriptor};
-use wgpu::resource::{
- BufferDescriptor, BufferMapCallback, BufferMapOperation, SamplerDescriptor, TextureDescriptor,
- TextureViewDescriptor,
-};
-use wgt::InstanceDescriptor;
-
-pub type ErrorScopeId = NonZeroU64;
-const DEVICE_POLL_INTERVAL: Duration = Duration::from_millis(50);
-pub const PRESENTATION_BUFFER_COUNT: usize = 10;
-
-#[derive(Debug, Deserialize, Serialize)]
-#[allow(clippy::large_enum_variant)]
-pub enum WebGPUResponse {
- RequestAdapter {
- adapter_info: wgt::AdapterInfo,
- adapter_id: WebGPUAdapter,
- features: wgt::Features,
- limits: wgt::Limits,
- channel: WebGPU,
- },
- RequestDevice {
- device_id: WebGPUDevice,
- queue_id: WebGPUQueue,
- descriptor: wgt::DeviceDescriptor<Option<String>>,
- },
- BufferMapAsync(IpcSharedMemory),
- SubmittedWorkDone,
-}
+use wgc::id;
-pub type WebGPUResponseResult = Result<WebGPUResponse, String>;
+mod dom_messages;
+mod script_messages;
+pub use dom_messages::*;
+pub use identity::*;
+pub use script_messages::*;
-#[derive(Debug, Deserialize, Serialize)]
-pub enum WebGPURequest {
- BufferMapAsync {
- sender: IpcSender<Option<WebGPUResponseResult>>,
- buffer_id: id::BufferId,
- device_id: id::DeviceId,
- host_map: HostMap,
- offset: u64,
- size: Option<u64>,
- },
- CommandEncoderFinish {
- command_encoder_id: id::CommandEncoderId,
- device_id: id::DeviceId,
- is_error: bool,
- // TODO(zakorgy): Serialize CommandBufferDescriptor in wgpu-core
- // wgpu::command::CommandBufferDescriptor,
- },
- CopyBufferToBuffer {
- command_encoder_id: id::CommandEncoderId,
- source_id: id::BufferId,
- source_offset: wgt::BufferAddress,
- destination_id: id::BufferId,
- destination_offset: wgt::BufferAddress,
- size: wgt::BufferAddress,
- },
- CopyBufferToTexture {
- command_encoder_id: id::CommandEncoderId,
- source: ImageCopyBuffer,
- destination: ImageCopyTexture,
- copy_size: wgt::Extent3d,
- },
- CopyTextureToBuffer {
- command_encoder_id: id::CommandEncoderId,
- source: ImageCopyTexture,
- destination: ImageCopyBuffer,
- copy_size: wgt::Extent3d,
- },
- CopyTextureToTexture {
- command_encoder_id: id::CommandEncoderId,
- source: ImageCopyTexture,
- destination: ImageCopyTexture,
- copy_size: wgt::Extent3d,
- },
- CreateBindGroup {
- device_id: id::DeviceId,
- bind_group_id: id::BindGroupId,
- descriptor: BindGroupDescriptor<'static>,
- },
- CreateBindGroupLayout {
- device_id: id::DeviceId,
- bind_group_layout_id: id::BindGroupLayoutId,
- descriptor: Option<BindGroupLayoutDescriptor<'static>>,
- },
- CreateBuffer {
- device_id: id::DeviceId,
- buffer_id: id::BufferId,
- descriptor: Option<BufferDescriptor<'static>>,
- },
- CreateCommandEncoder {
- device_id: id::DeviceId,
- // TODO(zakorgy): Serialize CommandEncoderDescriptor in wgpu-core
- // wgpu::command::CommandEncoderDescriptor,
- command_encoder_id: id::CommandEncoderId,
- label: Option<Cow<'static, str>>,
- },
- CreateComputePipeline {
- device_id: id::DeviceId,
- compute_pipeline_id: id::ComputePipelineId,
- descriptor: ComputePipelineDescriptor<'static>,
- implicit_ids: Option<(id::PipelineLayoutId, Vec<id::BindGroupLayoutId>)>,
- },
- CreateContext(IpcSender<ExternalImageId>),
- CreatePipelineLayout {
- device_id: id::DeviceId,
- pipeline_layout_id: id::PipelineLayoutId,
- descriptor: PipelineLayoutDescriptor<'static>,
- },
- CreateRenderPipeline {
- device_id: id::DeviceId,
- render_pipeline_id: id::RenderPipelineId,
- descriptor: Option<RenderPipelineDescriptor<'static>>,
- implicit_ids: Option<(id::PipelineLayoutId, Vec<id::BindGroupLayoutId>)>,
- },
- CreateSampler {
- device_id: id::DeviceId,
- sampler_id: id::SamplerId,
- descriptor: SamplerDescriptor<'static>,
- },
- CreateShaderModule {
- device_id: id::DeviceId,
- program_id: id::ShaderModuleId,
- program: String,
- label: Option<String>,
- },
- CreateSwapChain {
- device_id: id::DeviceId,
- buffer_ids: ArrayVec<id::BufferId, PRESENTATION_BUFFER_COUNT>,
- external_id: u64,
- sender: IpcSender<ImageKey>,
- image_desc: ImageDescriptor,
- image_data: ImageData,
- },
- CreateTexture {
- device_id: id::DeviceId,
- texture_id: id::TextureId,
- descriptor: Option<TextureDescriptor<'static>>,
- },
- CreateTextureView {
- texture_id: id::TextureId,
- texture_view_id: id::TextureViewId,
- device_id: id::DeviceId,
- descriptor: Option<TextureViewDescriptor<'static>>,
- },
- DestroyBuffer(id::BufferId),
- DestroyDevice(id::DeviceId),
- DestroyTexture {
- device_id: id::DeviceId,
- texture_id: id::TextureId,
- },
- DestroySwapChain {
- external_id: u64,
- image_key: ImageKey,
- },
- DropTexture(id::TextureId),
- DropAdapter(id::AdapterId),
- DropDevice(id::DeviceId),
- DropBuffer(id::BufferId),
- DropPipelineLayout(id::PipelineLayoutId),
- DropComputePipeline(id::ComputePipelineId),
- DropRenderPipeline(id::RenderPipelineId),
- DropBindGroup(id::BindGroupId),
- DropBindGroupLayout(id::BindGroupLayoutId),
- DropCommandBuffer(id::CommandBufferId),
- DropTextureView(id::TextureViewId),
- DropSampler(id::SamplerId),
- DropShaderModule(id::ShaderModuleId),
- DropRenderBundle(id::RenderBundleId),
- DropQuerySet(id::QuerySetId),
- Exit(IpcSender<()>),
- RenderBundleEncoderFinish {
- render_bundle_encoder: RenderBundleEncoder,
- descriptor: RenderBundleDescriptor<'static>,
- render_bundle_id: id::RenderBundleId,
- device_id: id::DeviceId,
- },
- RequestAdapter {
- sender: IpcSender<Option<WebGPUResponseResult>>,
- options: RequestAdapterOptions,
- ids: SmallVec<[id::AdapterId; 4]>,
- },
- RequestDevice {
- sender: IpcSender<Option<WebGPUResponseResult>>,
- adapter_id: WebGPUAdapter,
- descriptor: wgt::DeviceDescriptor<Option<String>>,
- device_id: id::DeviceId,
- pipeline_id: PipelineId,
- },
- RunComputePass {
- command_encoder_id: id::CommandEncoderId,
- compute_pass: Option<ComputePass>,
- },
- RunRenderPass {
- command_encoder_id: id::CommandEncoderId,
- render_pass: Option<RenderPass>,
- },
- Submit {
- queue_id: id::QueueId,
- command_buffers: Vec<id::CommandBufferId>,
- },
- SwapChainPresent {
- external_id: u64,
- texture_id: id::TextureId,
- encoder_id: id::CommandEncoderId,
- },
- UnmapBuffer {
- buffer_id: id::BufferId,
- device_id: id::DeviceId,
- array_buffer: IpcSharedMemory,
- is_map_read: bool,
- offset: u64,
- size: u64,
- },
- WriteBuffer {
- queue_id: id::QueueId,
- buffer_id: id::BufferId,
- buffer_offset: u64,
- data: IpcSharedMemory,
- },
- WriteTexture {
- queue_id: id::QueueId,
- texture_cv: ImageCopyTexture,
- data_layout: wgt::ImageDataLayout,
- size: wgt::Extent3d,
- data: IpcSharedMemory,
- },
- QueueOnSubmittedWorkDone {
- sender: IpcSender<Option<WebGPUResponseResult>>,
- queue_id: id::QueueId,
- },
-}
+pub type ErrorScopeId = NonZeroU64;
+pub use wgpu_thread::PRESENTATION_BUFFER_COUNT;
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct WebGPU(pub IpcSender<(Option<ErrorScopeId>, WebGPURequest)>);
@@ -339,1091 +99,6 @@ impl WebGPU {
}
}
-#[allow(clippy::upper_case_acronyms)] // Name of the library
-struct WGPU {
- receiver: IpcReceiver<(Option<ErrorScopeId>, WebGPURequest)>,
- sender: IpcSender<(Option<ErrorScopeId>, WebGPURequest)>,
- script_sender: IpcSender<WebGPUMsg>,
- global: Arc<wgpu::global::Global>,
- adapters: Vec<WebGPUAdapter>,
- devices: HashMap<WebGPUDevice, PipelineId>,
- // 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>>,
- webrender_api: Arc<Mutex<RenderApi>>,
- webrender_document: DocumentId,
- external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
- wgpu_image_map: Arc<Mutex<HashMap<u64, PresentationData>>>,
- last_poll: Instant,
-}
-
-impl WGPU {
- fn new(
- receiver: IpcReceiver<(Option<ErrorScopeId>, WebGPURequest)>,
- sender: IpcSender<(Option<ErrorScopeId>, WebGPURequest)>,
- script_sender: IpcSender<WebGPUMsg>,
- webrender_api_sender: RenderApiSender,
- webrender_document: DocumentId,
- external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
- wgpu_image_map: Arc<Mutex<HashMap<u64, PresentationData>>>,
- ) -> Self {
- WGPU {
- receiver,
- sender,
- script_sender,
- global: Arc::new(wgpu::global::Global::new(
- "wgpu-core",
- InstanceDescriptor {
- backends: wgt::Backends::PRIMARY,
- ..Default::default()
- },
- )),
- adapters: Vec::new(),
- devices: HashMap::new(),
- _invalid_adapters: Vec::new(),
- error_command_encoders: RefCell::new(HashMap::new()),
- webrender_api: Arc::new(Mutex::new(webrender_api_sender.create_api())),
- webrender_document,
- external_images,
- wgpu_image_map,
- last_poll: Instant::now(),
- }
- }
-
- fn run(&mut self) {
- loop {
- let diff = DEVICE_POLL_INTERVAL.checked_sub(self.last_poll.elapsed());
- if diff.is_none() {
- let _ = self.global.poll_all_devices(false);
- self.last_poll = Instant::now();
- }
- if let Ok((scope_id, msg)) = self
- .receiver
- .try_recv_timeout(diff.unwrap_or(DEVICE_POLL_INTERVAL))
- {
- match msg {
- WebGPURequest::BufferMapAsync {
- sender,
- buffer_id,
- device_id,
- host_map,
- offset,
- size,
- } => {
- let glob = Arc::clone(&self.global);
- let resp_sender = sender.clone();
- let callback = BufferMapCallback::from_rust(Box::from(move |result| {
- match result {
- Ok(()) => {
- let global = &glob;
- let (slice_pointer, range_size) = gfx_select!(buffer_id =>
- global.buffer_get_mapped_range(buffer_id, 0, None))
- .unwrap();
- // SAFETY: guarantee to be safe from wgpu
- let data = unsafe {
- slice::from_raw_parts(slice_pointer, range_size as usize)
- };
-
- if let Err(e) =
- resp_sender.send(Some(Ok(WebGPUResponse::BufferMapAsync(
- IpcSharedMemory::from_bytes(data),
- ))))
- {
- warn!("Could not send BufferMapAsync Response ({})", e);
- }
- },
- Err(_) => {
- warn!("Could not map buffer({:?})", buffer_id);
- if let Err(e) = resp_sender
- .send(Some(Err(String::from("Failed to map Buffer"))))
- {
- warn!("Could not send BufferMapAsync Response ({})", e);
- }
- },
- };
- }));
-
- let operation = BufferMapOperation {
- host: host_map,
- callback: Some(callback),
- };
- let global = &self.global;
- let result = gfx_select!(buffer_id => global.buffer_map_async(
- buffer_id,
- offset,
- size,
- operation
- ));
- if let Err(ref e) = result {
- if let Err(w) = sender.send(Some(Err(format!("{:?}", e)))) {
- warn!("Failed to send BufferMapAsync Response ({:?})", w);
- }
- }
- self.send_result(device_id, scope_id, result);
- },
- WebGPURequest::CommandEncoderFinish {
- command_encoder_id,
- device_id,
- is_error,
- } => {
- let global = &self.global;
- let result = if is_error {
- Err(String::from("Invalid GPUCommandEncoder"))
- } else if let Some(err) = self
- .error_command_encoders
- .borrow()
- .get(&command_encoder_id)
- {
- Err(err.clone())
- } else {
- tuple_to_result(
- gfx_select!(command_encoder_id => global.command_encoder_finish(
- command_encoder_id,
- &wgt::CommandBufferDescriptor::default()
- )),
- )
- .map_err(|e| format!("{:?}", e))
- };
- self.encoder_record_error(command_encoder_id, &result);
- self.send_result(device_id, scope_id, result);
- },
- WebGPURequest::CopyBufferToBuffer {
- command_encoder_id,
- source_id,
- source_offset,
- destination_id,
- destination_offset,
- size,
- } => {
- let global = &self.global;
- let result = gfx_select!(command_encoder_id => global.command_encoder_copy_buffer_to_buffer(
- command_encoder_id,
- source_id,
- source_offset,
- destination_id,
- destination_offset,
- size
- ));
- self.encoder_record_error(command_encoder_id, &result);
- },
- WebGPURequest::CopyBufferToTexture {
- command_encoder_id,
- source,
- destination,
- copy_size,
- } => {
- let global = &self.global;
- let result = gfx_select!(command_encoder_id => global.command_encoder_copy_buffer_to_texture(
- command_encoder_id,
- &source,
- &destination,
- &copy_size
- ));
- self.encoder_record_error(command_encoder_id, &result);
- },
- WebGPURequest::CopyTextureToBuffer {
- command_encoder_id,
- source,
- destination,
- copy_size,
- } => {
- let global = &self.global;
- let result = gfx_select!(command_encoder_id => global.command_encoder_copy_texture_to_buffer(
- command_encoder_id,
- &source,
- &destination,
- &copy_size
- ));
- self.encoder_record_error(command_encoder_id, &result);
- },
- WebGPURequest::CopyTextureToTexture {
- command_encoder_id,
- source,
- destination,
- copy_size,
- } => {
- let global = &self.global;
- let result = gfx_select!(command_encoder_id => global.command_encoder_copy_texture_to_texture(
- command_encoder_id,
- &source,
- &destination,
- &copy_size
- ));
- self.encoder_record_error(command_encoder_id, &result);
- },
- WebGPURequest::CreateBindGroup {
- device_id,
- bind_group_id,
- descriptor,
- } => {
- let global = &self.global;
- let result = tuple_to_result(gfx_select!(bind_group_id =>
- global.device_create_bind_group(device_id, &descriptor, Some(bind_group_id))));
- self.send_result(device_id, scope_id, result);
- },
- WebGPURequest::CreateBindGroupLayout {
- device_id,
- bind_group_layout_id,
- descriptor,
- } => {
- let global = &self.global;
- if let Some(desc) = descriptor {
- let result = tuple_to_result(gfx_select!(bind_group_layout_id =>
- global.device_create_bind_group_layout(device_id, &desc, Some(bind_group_layout_id))));
-
- self.send_result(device_id, scope_id, result);
- }
- },
- WebGPURequest::CreateBuffer {
- device_id,
- buffer_id,
- descriptor,
- } => {
- let global = &self.global;
- if let Some(desc) = descriptor {
- let result = tuple_to_result(gfx_select!(buffer_id =>
- global.device_create_buffer(device_id, &desc, Some(buffer_id))));
-
- self.send_result(device_id, scope_id, result);
- }
- },
- WebGPURequest::CreateCommandEncoder {
- device_id,
- command_encoder_id,
- label,
- } => {
- let global = &self.global;
- let desc = wgt::CommandEncoderDescriptor { label };
- let result = tuple_to_result(gfx_select!(command_encoder_id =>
- global.device_create_command_encoder(device_id, &desc, Some(command_encoder_id))));
-
- self.send_result(device_id, scope_id, result);
- },
- WebGPURequest::CreateComputePipeline {
- device_id,
- compute_pipeline_id,
- descriptor,
- implicit_ids,
- } => {
- let global = &self.global;
- let bgls = implicit_ids
- .as_ref()
- .map_or(Vec::with_capacity(0), |(_, bgls)| {
- bgls.iter().map(|x| Some(x.to_owned())).collect()
- });
- let implicit =
- implicit_ids
- .as_ref()
- .map(|(layout, _)| ImplicitPipelineIds {
- root_id: Some(*layout),
- group_ids: bgls.as_slice(),
- });
- let result = tuple_to_result(
- gfx_select!(compute_pipeline_id => global.device_create_compute_pipeline(
- device_id,
- &descriptor,
- Some(compute_pipeline_id),
- implicit
- )),
- );
- self.send_result(device_id, scope_id, result);
- },
- 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 {
- device_id,
- pipeline_layout_id,
- descriptor,
- } => {
- let global = &self.global;
- let result = tuple_to_result(gfx_select!(pipeline_layout_id =>
- global.device_create_pipeline_layout(device_id, &descriptor, Some(pipeline_layout_id))));
- self.send_result(device_id, scope_id, result);
- },
- WebGPURequest::CreateRenderPipeline {
- device_id,
- render_pipeline_id,
- descriptor,
- implicit_ids,
- } => {
- let global = &self.global;
- let bgls = implicit_ids
- .as_ref()
- .map_or(Vec::with_capacity(0), |(_, bgls)| {
- bgls.iter().map(|x| Some(x.to_owned())).collect()
- });
- let implicit =
- implicit_ids
- .as_ref()
- .map(|(layout, _)| ImplicitPipelineIds {
- root_id: Some(*layout),
- group_ids: bgls.as_slice(),
- });
- if let Some(desc) = descriptor {
- let result = tuple_to_result(gfx_select!(render_pipeline_id =>
- global.device_create_render_pipeline(
- device_id,
- &desc,
- Some(render_pipeline_id),
- implicit)
- ));
- self.send_result(device_id, scope_id, result);
- }
- },
- WebGPURequest::CreateSampler {
- device_id,
- sampler_id,
- descriptor,
- } => {
- let global = &self.global;
- let result = tuple_to_result(
- gfx_select!(sampler_id => global.device_create_sampler(
- device_id,
- &descriptor,
- Some(sampler_id)
- )),
- );
- self.send_result(device_id, scope_id, result);
- },
- WebGPURequest::CreateShaderModule {
- device_id,
- program_id,
- program,
- label,
- } => {
- let global = &self.global;
- let source = wgpu_core::pipeline::ShaderModuleSource::Wgsl(
- crate::Cow::Owned(program),
- );
- let desc = ShaderModuleDescriptor {
- label: label.map(|s| s.into()),
- shader_bound_checks: wgt::ShaderBoundChecks::default(),
- };
- let result = tuple_to_result(gfx_select!(program_id =>
- global.device_create_shader_module(device_id, &desc, source, Some(program_id))));
- self.send_result(device_id, scope_id, result);
- },
- WebGPURequest::CreateSwapChain {
- device_id,
- buffer_ids,
- external_id,
- sender,
- image_desc,
- image_data,
- } => {
- let height = image_desc.size.height;
- let width = image_desc.size.width;
- let buffer_stride =
- ((width * 4) as u32 | (wgt::COPY_BYTES_PER_ROW_ALIGNMENT - 1)) + 1;
- let mut wr = self.webrender_api.lock().unwrap();
- let image_key = wr.generate_image_key();
- if let Err(e) = sender.send(image_key) {
- warn!("Failed to send ImageKey ({})", e);
- }
- let _ = self.wgpu_image_map.lock().unwrap().insert(
- external_id,
- PresentationData {
- device_id,
- queue_id: device_id.transmute(),
- data: vec![255; (buffer_stride * height as u32) as usize],
- size: Size2D::new(width, height),
- unassigned_buffer_ids: buffer_ids,
- available_buffer_ids: ArrayVec::<
- id::BufferId,
- PRESENTATION_BUFFER_COUNT,
- >::new(),
- queued_buffer_ids: ArrayVec::<
- id::BufferId,
- PRESENTATION_BUFFER_COUNT,
- >::new(),
- buffer_stride,
- image_key,
- image_desc,
- image_data: image_data.clone(),
- },
- );
-
- let mut txn = Transaction::new();
- txn.add_image(image_key, image_desc, image_data, None);
- wr.send_transaction(self.webrender_document, txn);
- },
- WebGPURequest::CreateTexture {
- device_id,
- texture_id,
- descriptor,
- } => {
- let global = &self.global;
- if let Some(desc) = descriptor {
- let result = tuple_to_result(
- gfx_select!(texture_id => global.device_create_texture(
- device_id,
- &desc,
- Some(texture_id)
- )),
- );
- self.send_result(device_id, scope_id, result);
- }
- },
- WebGPURequest::CreateTextureView {
- texture_id,
- texture_view_id,
- device_id,
- descriptor,
- } => {
- let global = &self.global;
- if let Some(desc) = descriptor {
- let result = tuple_to_result(
- gfx_select!(texture_view_id => global.texture_create_view(
- texture_id,
- &desc,
- Some(texture_view_id)
- )),
- );
-
- self.send_result(device_id, scope_id, result);
- }
- },
- WebGPURequest::DestroyBuffer(buffer) => {
- let global = &self.global;
- let _result = gfx_select!(buffer => global.buffer_destroy(buffer));
- },
- WebGPURequest::DestroyDevice(device) => {
- let global = &self.global;
- gfx_select!(device => global.device_destroy(device));
- },
- WebGPURequest::DestroySwapChain {
- external_id,
- image_key,
- } => {
- let data = self
- .wgpu_image_map
- .lock()
- .unwrap()
- .remove(&external_id)
- .unwrap();
- let global = &self.global;
- for b_id in data.available_buffer_ids.iter() {
- gfx_select!(b_id => global.buffer_drop(*b_id, false));
- }
- for b_id in data.queued_buffer_ids.iter() {
- gfx_select!(b_id => global.buffer_drop(*b_id, false));
- }
- for b_id in data.unassigned_buffer_ids.iter() {
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBuffer(*b_id)) {
- warn!("Unable to send FreeBuffer({:?}) ({:?})", *b_id, e);
- };
- }
- let mut txn = Transaction::new();
- txn.delete_image(image_key);
- self.webrender_api
- .lock()
- .unwrap()
- .send_transaction(self.webrender_document, txn);
- },
- WebGPURequest::DestroyTexture {
- device_id,
- texture_id,
- } => {
- let global = &self.global;
- let result = gfx_select!(texture_id => global.texture_destroy(texture_id));
- self.send_result(device_id, scope_id, result);
- },
- WebGPURequest::Exit(sender) => {
- if let Err(e) = sender.send(()) {
- warn!("Failed to send response to WebGPURequest::Exit ({})", e)
- }
- break;
- },
- 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));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeCommandBuffer(id)) {
- warn!("Unable to send FreeCommandBuffer({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropDevice(device_id) => {
- let device = WebGPUDevice(device_id);
- let pipeline_id = self.devices.remove(&device).unwrap();
- if let Err(e) = self.script_sender.send(WebGPUMsg::CleanDevice {
- device,
- pipeline_id,
- }) {
- warn!("Unable to send CleanDevice({:?}) ({:?})", device_id, e);
- }
- let global = &self.global;
- gfx_select!(device_id => global.device_drop(device_id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeDevice(device_id)) {
- warn!("Unable to send FreeDevice({:?}) ({:?})", device_id, e);
- };
- },
- WebGPURequest::RenderBundleEncoderFinish {
- render_bundle_encoder,
- descriptor,
- render_bundle_id,
- device_id,
- } => {
- let global = &self.global;
- let result = tuple_to_result(
- gfx_select!(render_bundle_id => global.render_bundle_encoder_finish(
- render_bundle_encoder,
- &descriptor,
- Some(render_bundle_id)
- )),
- );
-
- self.send_result(device_id, scope_id, result);
- },
- WebGPURequest::RequestAdapter {
- sender,
- options,
- ids,
- } => {
- let adapter_id = match self
- .global
- .request_adapter(&options, wgpu::instance::AdapterInputs::IdSet(&ids))
- {
- Ok(id) => id,
- Err(w) => {
- if let Err(e) = sender.send(Some(Err(format!("{:?}", w)))) {
- warn!(
- "Failed to send response to WebGPURequest::RequestAdapter ({})",
- e
- )
- }
- break;
- },
- };
- let adapter = WebGPUAdapter(adapter_id);
- self.adapters.push(adapter);
- let global = &self.global;
- // TODO: can we do this lazily
- let info =
- gfx_select!(adapter_id => global.adapter_get_info(adapter_id)).unwrap();
- let limits =
- gfx_select!(adapter_id => global.adapter_limits(adapter_id)).unwrap();
- let features =
- gfx_select!(adapter_id => global.adapter_features(adapter_id)).unwrap();
- if let Err(e) = sender.send(Some(Ok(WebGPUResponse::RequestAdapter {
- adapter_info: info,
- adapter_id: adapter,
- features,
- limits,
- channel: WebGPU(self.sender.clone()),
- }))) {
- warn!(
- "Failed to send response to WebGPURequest::RequestAdapter ({})",
- e
- )
- }
- },
- WebGPURequest::RequestDevice {
- sender,
- adapter_id,
- descriptor,
- device_id,
- pipeline_id,
- } => {
- let desc = DeviceDescriptor {
- label: descriptor.label.as_ref().map(crate::Cow::from),
- required_features: descriptor.required_features,
- required_limits: descriptor.required_limits.clone(),
- };
- let global = &self.global;
- let (device_id, queue_id) = match gfx_select!(device_id => global.adapter_request_device(
- adapter_id.0,
- &desc,
- None,
- Some(device_id),
- Some(device_id.transmute()),
- )) {
- (_, _, Some(e)) => {
- if let Err(w) = sender.send(Some(Err(format!("{:?}", e)))) {
- warn!(
- "Failed to send response to WebGPURequest::RequestDevice ({})",
- w
- )
- }
- break;
- },
- (device_id, queue_id, None) => (device_id, queue_id),
- };
- let device = WebGPUDevice(device_id);
- let queue = WebGPUQueue(queue_id);
- self.devices.insert(device, pipeline_id);
- if let Err(e) = sender.send(Some(Ok(WebGPUResponse::RequestDevice {
- device_id: device,
- queue_id: queue,
- descriptor,
- }))) {
- warn!(
- "Failed to send response to WebGPURequest::RequestDevice ({})",
- e
- )
- }
- },
- WebGPURequest::RunComputePass {
- command_encoder_id,
- compute_pass,
- } => {
- let global = &self.global;
- let result = if let Some(pass) = compute_pass {
- gfx_select!(command_encoder_id => global.command_encoder_run_compute_pass(
- command_encoder_id,
- &pass
- )).map_err(|e| format!("{:?}", e))
- } else {
- Err(String::from("Invalid ComputePass"))
- };
- self.encoder_record_error(command_encoder_id, &result);
- },
- WebGPURequest::RunRenderPass {
- 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))
- } else {
- Err(String::from("Invalid RenderPass"))
- };
- self.encoder_record_error(command_encoder_id, &result);
- },
- WebGPURequest::Submit {
- queue_id,
- command_buffers,
- } => {
- 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(String::from("Invalid command buffer submitted"))
- } else {
- gfx_select!(queue_id => global.queue_submit(queue_id, &command_buffers))
- .map_err(|e| format!("{:?}", e))
- };
- self.send_result(queue_id.transmute(), scope_id, result);
- },
- WebGPURequest::SwapChainPresent {
- external_id,
- texture_id,
- encoder_id,
- } => {
- let global = &self.global;
- let device_id;
- let queue_id;
- let size;
- let buffer_id;
- let buffer_stride;
- {
- if let Some(present_data) =
- self.wgpu_image_map.lock().unwrap().get_mut(&external_id)
- {
- size = present_data.size;
- device_id = present_data.device_id;
- queue_id = present_data.queue_id;
- buffer_stride = present_data.buffer_stride;
- buffer_id = if let Some(b_id) =
- present_data.available_buffer_ids.pop()
- {
- b_id
- } else if let Some(b_id) = present_data.unassigned_buffer_ids.pop()
- {
- let buffer_size =
- (buffer_stride * size.height as u32) as wgt::BufferAddress;
- let buffer_desc = wgt::BufferDescriptor {
- label: None,
- size: buffer_size,
- usage: wgt::BufferUsages::MAP_READ |
- wgt::BufferUsages::COPY_DST,
- mapped_at_creation: false,
- };
- let _ = gfx_select!(b_id => global.device_create_buffer(
- device_id,
- &buffer_desc,
- Some(b_id)
- ));
- b_id
- } else {
- warn!(
- "No staging buffer available for ExternalImageId({:?})",
- external_id
- );
- continue;
- };
- present_data.queued_buffer_ids.push(buffer_id);
- } else {
- warn!("Data not found for ExternalImageId({:?})", external_id);
- continue;
- }
- }
-
- let buffer_size =
- (size.height as u32 * buffer_stride) as wgt::BufferAddress;
- let comm_desc = wgt::CommandEncoderDescriptor { label: None };
- let _ = gfx_select!(encoder_id => global.device_create_command_encoder(
- device_id,
- &comm_desc,
- Some(encoder_id)
- ));
-
- let buffer_cv = ImageCopyBuffer {
- buffer: buffer_id,
- layout: wgt::ImageDataLayout {
- offset: 0,
- bytes_per_row: Some(buffer_stride),
- rows_per_image: None,
- },
- };
- let texture_cv = ImageCopyTexture {
- texture: texture_id,
- mip_level: 0,
- origin: wgt::Origin3d::ZERO,
- aspect: wgt::TextureAspect::All,
- };
- let copy_size = wgt::Extent3d {
- width: size.width as u32,
- height: size.height as u32,
- depth_or_array_layers: 1,
- };
- let _ = gfx_select!(encoder_id => global.command_encoder_copy_texture_to_buffer(
- encoder_id,
- &texture_cv,
- &buffer_cv,
- &copy_size
- ));
- let _ = gfx_select!(encoder_id => global.command_encoder_finish(
- encoder_id,
- &wgt::CommandBufferDescriptor::default()
- ));
- let _ = gfx_select!(queue_id => global.queue_submit(
- queue_id,
- &[encoder_id.into_command_buffer_id()]
- ));
-
- let glob = Arc::clone(&self.global);
- let wgpu_image_map = Arc::clone(&self.wgpu_image_map);
- let webrender_api = Arc::clone(&self.webrender_api);
- let webrender_document = self.webrender_document;
- let callback = BufferMapCallback::from_rust(Box::from(move |result| {
- match result {
- Ok(()) => {
- let global = &glob;
- let (slice_pointer, range_size) = gfx_select!(buffer_id =>
- global.buffer_get_mapped_range(buffer_id, 0, Some(buffer_size as u64)))
- .unwrap();
- let data = unsafe {
- slice::from_raw_parts(slice_pointer, range_size as usize)
- }
- .to_vec();
- if let Some(present_data) =
- wgpu_image_map.lock().unwrap().get_mut(&external_id)
- {
- present_data.data = data;
- let mut txn = Transaction::new();
- txn.update_image(
- present_data.image_key,
- present_data.image_desc,
- present_data.image_data.clone(),
- &DirtyRect::All,
- );
- webrender_api
- .lock()
- .unwrap()
- .send_transaction(webrender_document, txn);
- present_data
- .queued_buffer_ids
- .retain(|b_id| *b_id != buffer_id);
- present_data.available_buffer_ids.push(buffer_id);
- } else {
- warn!(
- "Data not found for ExternalImageId({:?})",
- external_id
- );
- }
- let _ =
- gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
- },
- _ => error!("Could not map buffer({:?})", buffer_id),
- }
- }));
- let map_op = BufferMapOperation {
- host: HostMap::Read,
- callback: Some(callback),
- };
- let _ = gfx_select!(buffer_id
- => global.buffer_map_async(buffer_id, 0, Some(buffer_size), map_op));
- },
- WebGPURequest::UnmapBuffer {
- buffer_id,
- device_id,
- array_buffer,
- is_map_read,
- offset,
- size,
- } => {
- let global = &self.global;
- if !is_map_read {
- let (slice_pointer, range_size) =
- gfx_select!(buffer_id => global.buffer_get_mapped_range(
- buffer_id,
- offset,
- Some(size)
- ))
- .unwrap();
- unsafe {
- slice::from_raw_parts_mut(slice_pointer, range_size as usize)
- }
- .copy_from_slice(&array_buffer);
- }
- let result = gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
- self.send_result(device_id, scope_id, result);
- },
- WebGPURequest::WriteBuffer {
- queue_id,
- buffer_id,
- buffer_offset,
- data,
- } => {
- let global = &self.global;
- //TODO: Report result to content process
- let result = gfx_select!(queue_id => global.queue_write_buffer(
- queue_id,
- buffer_id,
- buffer_offset as wgt::BufferAddress,
- &data
- ));
- self.send_result(queue_id.transmute(), scope_id, result);
- },
- WebGPURequest::WriteTexture {
- queue_id,
- texture_cv,
- data_layout,
- size,
- data,
- } => {
- let global = &self.global;
- //TODO: Report result to content process
- let result = gfx_select!(queue_id => global.queue_write_texture(
- queue_id,
- &texture_cv,
- &data,
- &data_layout,
- &size
- ));
- self.send_result(queue_id.transmute(), scope_id, result);
- },
- WebGPURequest::QueueOnSubmittedWorkDone { sender, queue_id } => {
- let global = &self.global;
-
- let callback = SubmittedWorkDoneClosure::from_rust(Box::from(move || {
- if let Err(e) = sender.send(Some(Ok(WebGPUResponse::SubmittedWorkDone)))
- {
- warn!("Could not send SubmittedWorkDone Response ({})", e);
- }
- }));
- let result = gfx_select!(queue_id => global.queue_on_submitted_work_done(queue_id, callback));
- self.send_result(queue_id.transmute(), scope_id, result);
- },
- WebGPURequest::DropTexture(id) => {
- let global = &self.global;
- gfx_select!(id => global.texture_drop(id, true));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTexture(id)) {
- warn!("Unable to send FreeTexture({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropAdapter(id) => {
- let global = &self.global;
- gfx_select!(id => global.adapter_drop(id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeAdapter(id)) {
- warn!("Unable to send FreeAdapter({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropBuffer(id) => {
- let global = &self.global;
- gfx_select!(id => global.buffer_drop(id, true));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBuffer(id)) {
- warn!("Unable to send FreeBuffer({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropPipelineLayout(id) => {
- let global = &self.global;
- gfx_select!(id => global.pipeline_layout_drop(id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreePipelineLayout(id)) {
- warn!("Unable to send FreePipelineLayout({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropComputePipeline(id) => {
- let global = &self.global;
- gfx_select!(id => global.compute_pipeline_drop(id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeComputePipeline(id))
- {
- warn!("Unable to send FreeComputePipeline({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropRenderPipeline(id) => {
- let global = &self.global;
- gfx_select!(id => global.render_pipeline_drop(id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeRenderPipeline(id)) {
- warn!("Unable to send FreeRenderPipeline({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropBindGroup(id) => {
- let global = &self.global;
- gfx_select!(id => global.bind_group_drop(id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBindGroup(id)) {
- warn!("Unable to send FreeBindGroup({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropBindGroupLayout(id) => {
- let global = &self.global;
- gfx_select!(id => global.bind_group_layout_drop(id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBindGroupLayout(id))
- {
- warn!("Unable to send FreeBindGroupLayout({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropTextureView(id) => {
- let global = &self.global;
- let _result = gfx_select!(id => global.texture_view_drop(id, true));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTextureView(id)) {
- warn!("Unable to send FreeTextureView({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropSampler(id) => {
- let global = &self.global;
- gfx_select!(id => global.sampler_drop(id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeSampler(id)) {
- warn!("Unable to send FreeSampler({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropShaderModule(id) => {
- let global = &self.global;
- gfx_select!(id => global.shader_module_drop(id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeShaderModule(id)) {
- warn!("Unable to send FreeShaderModule({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropRenderBundle(id) => {
- let global = &self.global;
- gfx_select!(id => global.render_bundle_drop(id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeRenderBundle(id)) {
- warn!("Unable to send FreeRenderBundle({:?}) ({:?})", id, e);
- };
- },
- WebGPURequest::DropQuerySet(id) => {
- let global = &self.global;
- gfx_select!(id => global.query_set_drop(id));
- if let Err(e) = self.script_sender.send(WebGPUMsg::FreeQuerySet(id)) {
- warn!("Unable to send FreeQuerySet({:?}) ({:?})", id, e);
- };
- },
- }
- }
- }
- if let Err(e) = self.script_sender.send(WebGPUMsg::Exit) {
- warn!("Failed to send WebGPUMsg::Exit to script ({})", e);
- }
- }
-
- fn send_result<U, T: std::fmt::Debug>(
- &self,
- device_id: id::DeviceId,
- scope_id: Option<ErrorScopeId>,
- result: Result<U, T>,
- ) {
- let &pipeline_id = self.devices.get(&WebGPUDevice(device_id)).unwrap();
- if let Err(w) = self.script_sender.send(WebGPUMsg::WebGPUOpResult {
- device: WebGPUDevice(device_id),
- scope_id,
- pipeline_id,
- result: if let Err(e) = result {
- let err = format!("{:?}", e);
- if err.contains("OutOfMemory") {
- WebGPUOpResult::OutOfMemoryError
- } else {
- WebGPUOpResult::ValidationError(err)
- }
- } else {
- WebGPUOpResult::Success
- },
- }) {
- warn!("Failed to send WebGPUOpResult ({})", w);
- }
- }
-
- fn encoder_record_error<U, T: std::fmt::Debug>(
- &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));
- }
- }
-}
-
-fn tuple_to_result<T, E>(res: (T, Option<E>)) -> Result<T, E> {
- if let Some(err) = res.1 {
- Err(err)
- } else {
- Ok(res.0)
- }
-}
-
-macro_rules! webgpu_resource {
- ($name:ident, $id:ty) => {
- #[derive(Clone, Copy, Debug, Deserialize, Hash, PartialEq, Serialize)]
- pub struct $name(pub $id);
-
- impl MallocSizeOf for $name {
- fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize {
- 0
- }
- }
-
- impl Eq for $name {}
- };
-}
-
-webgpu_resource!(WebGPUAdapter, id::AdapterId);
-webgpu_resource!(WebGPUBindGroup, id::BindGroupId);
-webgpu_resource!(WebGPUBindGroupLayout, id::BindGroupLayoutId);
-webgpu_resource!(WebGPUBuffer, id::BufferId);
-webgpu_resource!(WebGPUCommandBuffer, id::CommandBufferId);
-webgpu_resource!(WebGPUCommandEncoder, id::CommandEncoderId);
-webgpu_resource!(WebGPUComputePipeline, id::ComputePipelineId);
-webgpu_resource!(WebGPUDevice, id::DeviceId);
-webgpu_resource!(WebGPUPipelineLayout, id::PipelineLayoutId);
-webgpu_resource!(WebGPUQueue, id::QueueId);
-webgpu_resource!(WebGPURenderBundle, id::RenderBundleId);
-webgpu_resource!(WebGPURenderPipeline, id::RenderPipelineId);
-webgpu_resource!(WebGPUSampler, id::SamplerId);
-webgpu_resource!(WebGPUShaderModule, id::ShaderModuleId);
-webgpu_resource!(WebGPUSurface, id::SurfaceId);
-webgpu_resource!(WebGPUTexture, id::TextureId);
-webgpu_resource!(WebGPUTextureView, id::TextureViewId);
-
#[derive(Default)]
pub struct WGPUExternalImages {
pub images: Arc<Mutex<HashMap<u64, PresentationData>>>,
diff --git a/components/webgpu/script_messages.rs b/components/webgpu/script_messages.rs
new file mode 100644
index 00000000000..08e2269d39c
--- /dev/null
+++ b/components/webgpu/script_messages.rs
@@ -0,0 +1,55 @@
+/* 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/. */
+
+//! IPC massages that are send to script thread (global scope).
+
+use msg::constellation_msg::PipelineId;
+use serde::{Deserialize, Serialize};
+
+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,
+};
+use crate::ErrorScopeId;
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub enum WebGPUOpResult {
+ ValidationError(String),
+ OutOfMemoryError,
+ Success,
+}
+
+#[derive(Clone, Debug, Deserialize, Serialize)]
+pub enum WebGPUMsg {
+ FreeAdapter(AdapterId),
+ FreeDevice(DeviceId),
+ FreeBuffer(BufferId),
+ FreePipelineLayout(PipelineLayoutId),
+ FreeComputePipeline(ComputePipelineId),
+ FreeRenderPipeline(RenderPipelineId),
+ FreeBindGroup(BindGroupId),
+ FreeBindGroupLayout(BindGroupLayoutId),
+ FreeCommandBuffer(CommandBufferId),
+ FreeTexture(TextureId),
+ FreeTextureView(TextureViewId),
+ FreeSampler(SamplerId),
+ FreeSurface(SurfaceId),
+ FreeShaderModule(ShaderModuleId),
+ FreeRenderBundle(RenderBundleId),
+ FreeStagingBuffer(StagingBufferId),
+ FreeQuerySet(QuerySetId),
+ WebGPUOpResult {
+ device: WebGPUDevice,
+ scope_id: Option<ErrorScopeId>,
+ pipeline_id: PipelineId,
+ result: WebGPUOpResult,
+ },
+ CleanDevice {
+ device: WebGPUDevice,
+ pipeline_id: PipelineId,
+ },
+ Exit,
+}
diff --git a/components/webgpu/wgpu_thread.rs b/components/webgpu/wgpu_thread.rs
new file mode 100644
index 00000000000..16bda74634e
--- /dev/null
+++ b/components/webgpu/wgpu_thread.rs
@@ -0,0 +1,1088 @@
+/* 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/. */
+
+//! Data and main loop of WebGPU thread.
+
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::slice;
+use std::sync::{Arc, Mutex};
+use std::time::{Duration, Instant};
+
+use arrayvec::ArrayVec;
+use euclid::default::Size2D;
+use ipc_channel::ipc::{IpcReceiver, IpcSender, IpcSharedMemory};
+use log::{error, warn};
+use msg::constellation_msg::PipelineId;
+use webrender::{RenderApi, RenderApiSender, Transaction};
+use webrender_api::{DirtyRect, DocumentId};
+use webrender_traits::{WebrenderExternalImageRegistry, WebrenderImageHandlerType};
+use wgc::command::{ImageCopyBuffer, ImageCopyTexture};
+use wgc::device::queue::SubmittedWorkDoneClosure;
+use wgc::device::{DeviceDescriptor, HostMap, ImplicitPipelineIds};
+use wgc::pipeline::ShaderModuleDescriptor;
+use wgc::resource::{BufferMapCallback, BufferMapOperation};
+use wgc::{gfx_select, id};
+use wgt::InstanceDescriptor;
+pub use {wgpu_core as wgc, wgpu_types as wgt};
+
+use crate::{
+ ErrorScopeId, PresentationData, Transmute, WebGPU, WebGPUAdapter, WebGPUDevice, WebGPUMsg,
+ WebGPUOpResult, WebGPUQueue, WebGPURequest, WebGPUResponse,
+};
+
+const DEVICE_POLL_INTERVAL: Duration = Duration::from_millis(50);
+pub const PRESENTATION_BUFFER_COUNT: usize = 10;
+
+#[allow(clippy::upper_case_acronyms)] // Name of the library
+pub(crate) struct WGPU {
+ receiver: IpcReceiver<(Option<ErrorScopeId>, WebGPURequest)>,
+ sender: IpcSender<(Option<ErrorScopeId>, WebGPURequest)>,
+ script_sender: IpcSender<WebGPUMsg>,
+ global: Arc<wgc::global::Global>,
+ adapters: Vec<WebGPUAdapter>,
+ devices: HashMap<WebGPUDevice, PipelineId>,
+ // 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>>,
+ webrender_api: Arc<Mutex<RenderApi>>,
+ webrender_document: DocumentId,
+ external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
+ wgpu_image_map: Arc<Mutex<HashMap<u64, PresentationData>>>,
+ last_poll: Instant,
+}
+
+impl WGPU {
+ pub(crate) fn new(
+ receiver: IpcReceiver<(Option<ErrorScopeId>, WebGPURequest)>,
+ sender: IpcSender<(Option<ErrorScopeId>, WebGPURequest)>,
+ script_sender: IpcSender<WebGPUMsg>,
+ webrender_api_sender: RenderApiSender,
+ webrender_document: DocumentId,
+ external_images: Arc<Mutex<WebrenderExternalImageRegistry>>,
+ wgpu_image_map: Arc<Mutex<HashMap<u64, PresentationData>>>,
+ ) -> Self {
+ WGPU {
+ receiver,
+ sender,
+ script_sender,
+ global: Arc::new(wgc::global::Global::new(
+ "wgpu-core",
+ InstanceDescriptor {
+ backends: wgt::Backends::PRIMARY,
+ ..Default::default()
+ },
+ )),
+ adapters: Vec::new(),
+ devices: HashMap::new(),
+ _invalid_adapters: Vec::new(),
+ error_command_encoders: RefCell::new(HashMap::new()),
+ webrender_api: Arc::new(Mutex::new(webrender_api_sender.create_api())),
+ webrender_document,
+ external_images,
+ wgpu_image_map,
+ last_poll: Instant::now(),
+ }
+ }
+
+ pub(crate) fn run(&mut self) {
+ loop {
+ let diff = DEVICE_POLL_INTERVAL.checked_sub(self.last_poll.elapsed());
+ if diff.is_none() {
+ let _ = self.global.poll_all_devices(false);
+ self.last_poll = Instant::now();
+ }
+ if let Ok((scope_id, msg)) = self
+ .receiver
+ .try_recv_timeout(diff.unwrap_or(DEVICE_POLL_INTERVAL))
+ {
+ match msg {
+ WebGPURequest::BufferMapAsync {
+ sender,
+ buffer_id,
+ device_id,
+ host_map,
+ offset,
+ size,
+ } => {
+ let glob = Arc::clone(&self.global);
+ let resp_sender = sender.clone();
+ let callback = BufferMapCallback::from_rust(Box::from(move |result| {
+ match result {
+ Ok(()) => {
+ let global = &glob;
+ let (slice_pointer, range_size) = gfx_select!(buffer_id =>
+ global.buffer_get_mapped_range(buffer_id, 0, None))
+ .unwrap();
+ // SAFETY: guarantee to be safe from wgpu
+ let data = unsafe {
+ slice::from_raw_parts(slice_pointer, range_size as usize)
+ };
+
+ if let Err(e) =
+ resp_sender.send(Some(Ok(WebGPUResponse::BufferMapAsync(
+ IpcSharedMemory::from_bytes(data),
+ ))))
+ {
+ warn!("Could not send BufferMapAsync Response ({})", e);
+ }
+ },
+ Err(_) => {
+ warn!("Could not map buffer({:?})", buffer_id);
+ if let Err(e) = resp_sender
+ .send(Some(Err(String::from("Failed to map Buffer"))))
+ {
+ warn!("Could not send BufferMapAsync Response ({})", e);
+ }
+ },
+ };
+ }));
+
+ let operation = BufferMapOperation {
+ host: host_map,
+ callback: Some(callback),
+ };
+ let global = &self.global;
+ let result = gfx_select!(buffer_id => global.buffer_map_async(
+ buffer_id,
+ offset,
+ size,
+ operation
+ ));
+ if let Err(ref e) = result {
+ if let Err(w) = sender.send(Some(Err(format!("{:?}", e)))) {
+ warn!("Failed to send BufferMapAsync Response ({:?})", w);
+ }
+ }
+ self.send_result(device_id, scope_id, result);
+ },
+ WebGPURequest::CommandEncoderFinish {
+ command_encoder_id,
+ device_id,
+ is_error,
+ } => {
+ let global = &self.global;
+ let result = if is_error {
+ Err(String::from("Invalid GPUCommandEncoder"))
+ } else if let Some(err) = self
+ .error_command_encoders
+ .borrow()
+ .get(&command_encoder_id)
+ {
+ Err(err.clone())
+ } else {
+ tuple_to_result(
+ gfx_select!(command_encoder_id => global.command_encoder_finish(
+ command_encoder_id,
+ &wgt::CommandBufferDescriptor::default()
+ )),
+ )
+ .map_err(|e| format!("{:?}", e))
+ };
+ self.encoder_record_error(command_encoder_id, &result);
+ self.send_result(device_id, scope_id, result);
+ },
+ WebGPURequest::CopyBufferToBuffer {
+ command_encoder_id,
+ source_id,
+ source_offset,
+ destination_id,
+ destination_offset,
+ size,
+ } => {
+ let global = &self.global;
+ let result = gfx_select!(command_encoder_id => global.command_encoder_copy_buffer_to_buffer(
+ command_encoder_id,
+ source_id,
+ source_offset,
+ destination_id,
+ destination_offset,
+ size
+ ));
+ self.encoder_record_error(command_encoder_id, &result);
+ },
+ WebGPURequest::CopyBufferToTexture {
+ command_encoder_id,
+ source,
+ destination,
+ copy_size,
+ } => {
+ let global = &self.global;
+ let result = gfx_select!(command_encoder_id => global.command_encoder_copy_buffer_to_texture(
+ command_encoder_id,
+ &source,
+ &destination,
+ &copy_size
+ ));
+ self.encoder_record_error(command_encoder_id, &result);
+ },
+ WebGPURequest::CopyTextureToBuffer {
+ command_encoder_id,
+ source,
+ destination,
+ copy_size,
+ } => {
+ let global = &self.global;
+ let result = gfx_select!(command_encoder_id => global.command_encoder_copy_texture_to_buffer(
+ command_encoder_id,
+ &source,
+ &destination,
+ &copy_size
+ ));
+ self.encoder_record_error(command_encoder_id, &result);
+ },
+ WebGPURequest::CopyTextureToTexture {
+ command_encoder_id,
+ source,
+ destination,
+ copy_size,
+ } => {
+ let global = &self.global;
+ let result = gfx_select!(command_encoder_id => global.command_encoder_copy_texture_to_texture(
+ command_encoder_id,
+ &source,
+ &destination,
+ &copy_size
+ ));
+ self.encoder_record_error(command_encoder_id, &result);
+ },
+ WebGPURequest::CreateBindGroup {
+ device_id,
+ bind_group_id,
+ descriptor,
+ } => {
+ let global = &self.global;
+ let result = tuple_to_result(gfx_select!(bind_group_id =>
+ global.device_create_bind_group(device_id, &descriptor, Some(bind_group_id))));
+ self.send_result(device_id, scope_id, result);
+ },
+ WebGPURequest::CreateBindGroupLayout {
+ device_id,
+ bind_group_layout_id,
+ descriptor,
+ } => {
+ let global = &self.global;
+ if let Some(desc) = descriptor {
+ let result = tuple_to_result(gfx_select!(bind_group_layout_id =>
+ global.device_create_bind_group_layout(device_id, &desc, Some(bind_group_layout_id))));
+
+ self.send_result(device_id, scope_id, result);
+ }
+ },
+ WebGPURequest::CreateBuffer {
+ device_id,
+ buffer_id,
+ descriptor,
+ } => {
+ let global = &self.global;
+ if let Some(desc) = descriptor {
+ let result = tuple_to_result(gfx_select!(buffer_id =>
+ global.device_create_buffer(device_id, &desc, Some(buffer_id))));
+
+ self.send_result(device_id, scope_id, result);
+ }
+ },
+ WebGPURequest::CreateCommandEncoder {
+ device_id,
+ command_encoder_id,
+ label,
+ } => {
+ let global = &self.global;
+ let desc = wgt::CommandEncoderDescriptor { label };
+ let result = tuple_to_result(gfx_select!(command_encoder_id =>
+ global.device_create_command_encoder(device_id, &desc, Some(command_encoder_id))));
+
+ self.send_result(device_id, scope_id, result);
+ },
+ WebGPURequest::CreateComputePipeline {
+ device_id,
+ compute_pipeline_id,
+ descriptor,
+ implicit_ids,
+ } => {
+ let global = &self.global;
+ let bgls = implicit_ids
+ .as_ref()
+ .map_or(Vec::with_capacity(0), |(_, bgls)| {
+ bgls.iter().map(|x| Some(x.to_owned())).collect()
+ });
+ let implicit =
+ implicit_ids
+ .as_ref()
+ .map(|(layout, _)| ImplicitPipelineIds {
+ root_id: Some(*layout),
+ group_ids: bgls.as_slice(),
+ });
+ let result = tuple_to_result(
+ gfx_select!(compute_pipeline_id => global.device_create_compute_pipeline(
+ device_id,
+ &descriptor,
+ Some(compute_pipeline_id),
+ implicit
+ )),
+ );
+ self.send_result(device_id, scope_id, result);
+ },
+ 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 {
+ device_id,
+ pipeline_layout_id,
+ descriptor,
+ } => {
+ let global = &self.global;
+ let result = tuple_to_result(gfx_select!(pipeline_layout_id =>
+ global.device_create_pipeline_layout(device_id, &descriptor, Some(pipeline_layout_id))));
+ self.send_result(device_id, scope_id, result);
+ },
+ WebGPURequest::CreateRenderPipeline {
+ device_id,
+ render_pipeline_id,
+ descriptor,
+ implicit_ids,
+ } => {
+ let global = &self.global;
+ let bgls = implicit_ids
+ .as_ref()
+ .map_or(Vec::with_capacity(0), |(_, bgls)| {
+ bgls.iter().map(|x| Some(x.to_owned())).collect()
+ });
+ let implicit =
+ implicit_ids
+ .as_ref()
+ .map(|(layout, _)| ImplicitPipelineIds {
+ root_id: Some(*layout),
+ group_ids: bgls.as_slice(),
+ });
+ if let Some(desc) = descriptor {
+ let result = tuple_to_result(gfx_select!(render_pipeline_id =>
+ global.device_create_render_pipeline(
+ device_id,
+ &desc,
+ Some(render_pipeline_id),
+ implicit)
+ ));
+ self.send_result(device_id, scope_id, result);
+ }
+ },
+ WebGPURequest::CreateSampler {
+ device_id,
+ sampler_id,
+ descriptor,
+ } => {
+ let global = &self.global;
+ let result = tuple_to_result(
+ gfx_select!(sampler_id => global.device_create_sampler(
+ device_id,
+ &descriptor,
+ Some(sampler_id)
+ )),
+ );
+ self.send_result(device_id, scope_id, result);
+ },
+ WebGPURequest::CreateShaderModule {
+ device_id,
+ program_id,
+ program,
+ label,
+ } => {
+ let global = &self.global;
+ let source = wgpu_core::pipeline::ShaderModuleSource::Wgsl(
+ crate::Cow::Owned(program),
+ );
+ let desc = ShaderModuleDescriptor {
+ label: label.map(|s| s.into()),
+ shader_bound_checks: wgt::ShaderBoundChecks::default(),
+ };
+ let result = tuple_to_result(gfx_select!(program_id =>
+ global.device_create_shader_module(device_id, &desc, source, Some(program_id))));
+ self.send_result(device_id, scope_id, result);
+ },
+ WebGPURequest::CreateSwapChain {
+ device_id,
+ buffer_ids,
+ external_id,
+ sender,
+ image_desc,
+ image_data,
+ } => {
+ let height = image_desc.size.height;
+ let width = image_desc.size.width;
+ let buffer_stride =
+ ((width * 4) as u32 | (wgt::COPY_BYTES_PER_ROW_ALIGNMENT - 1)) + 1;
+ let mut wr = self.webrender_api.lock().unwrap();
+ let image_key = wr.generate_image_key();
+ if let Err(e) = sender.send(image_key) {
+ warn!("Failed to send ImageKey ({})", e);
+ }
+ let _ = self.wgpu_image_map.lock().unwrap().insert(
+ external_id,
+ PresentationData {
+ device_id,
+ queue_id: device_id.transmute(),
+ data: vec![255; (buffer_stride * height as u32) as usize],
+ size: Size2D::new(width, height),
+ unassigned_buffer_ids: buffer_ids,
+ available_buffer_ids: ArrayVec::<
+ id::BufferId,
+ PRESENTATION_BUFFER_COUNT,
+ >::new(),
+ queued_buffer_ids: ArrayVec::<
+ id::BufferId,
+ PRESENTATION_BUFFER_COUNT,
+ >::new(),
+ buffer_stride,
+ image_key,
+ image_desc,
+ image_data: image_data.clone(),
+ },
+ );
+
+ let mut txn = Transaction::new();
+ txn.add_image(image_key, image_desc, image_data, None);
+ wr.send_transaction(self.webrender_document, txn);
+ },
+ WebGPURequest::CreateTexture {
+ device_id,
+ texture_id,
+ descriptor,
+ } => {
+ let global = &self.global;
+ if let Some(desc) = descriptor {
+ let result = tuple_to_result(
+ gfx_select!(texture_id => global.device_create_texture(
+ device_id,
+ &desc,
+ Some(texture_id)
+ )),
+ );
+ self.send_result(device_id, scope_id, result);
+ }
+ },
+ WebGPURequest::CreateTextureView {
+ texture_id,
+ texture_view_id,
+ device_id,
+ descriptor,
+ } => {
+ let global = &self.global;
+ if let Some(desc) = descriptor {
+ let result = tuple_to_result(
+ gfx_select!(texture_view_id => global.texture_create_view(
+ texture_id,
+ &desc,
+ Some(texture_view_id)
+ )),
+ );
+
+ self.send_result(device_id, scope_id, result);
+ }
+ },
+ WebGPURequest::DestroyBuffer(buffer) => {
+ let global = &self.global;
+ let _result = gfx_select!(buffer => global.buffer_destroy(buffer));
+ },
+ WebGPURequest::DestroyDevice(device) => {
+ let global = &self.global;
+ gfx_select!(device => global.device_destroy(device));
+ },
+ WebGPURequest::DestroySwapChain {
+ external_id,
+ image_key,
+ } => {
+ let data = self
+ .wgpu_image_map
+ .lock()
+ .unwrap()
+ .remove(&external_id)
+ .unwrap();
+ let global = &self.global;
+ for b_id in data.available_buffer_ids.iter() {
+ gfx_select!(b_id => global.buffer_drop(*b_id, false));
+ }
+ for b_id in data.queued_buffer_ids.iter() {
+ gfx_select!(b_id => global.buffer_drop(*b_id, false));
+ }
+ for b_id in data.unassigned_buffer_ids.iter() {
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBuffer(*b_id)) {
+ warn!("Unable to send FreeBuffer({:?}) ({:?})", *b_id, e);
+ };
+ }
+ let mut txn = Transaction::new();
+ txn.delete_image(image_key);
+ self.webrender_api
+ .lock()
+ .unwrap()
+ .send_transaction(self.webrender_document, txn);
+ },
+ WebGPURequest::DestroyTexture {
+ device_id,
+ texture_id,
+ } => {
+ let global = &self.global;
+ let result = gfx_select!(texture_id => global.texture_destroy(texture_id));
+ self.send_result(device_id, scope_id, result);
+ },
+ WebGPURequest::Exit(sender) => {
+ if let Err(e) = sender.send(()) {
+ warn!("Failed to send response to WebGPURequest::Exit ({})", e)
+ }
+ break;
+ },
+ 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));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeCommandBuffer(id)) {
+ warn!("Unable to send FreeCommandBuffer({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropDevice(device_id) => {
+ let device = WebGPUDevice(device_id);
+ let pipeline_id = self.devices.remove(&device).unwrap();
+ if let Err(e) = self.script_sender.send(WebGPUMsg::CleanDevice {
+ device,
+ pipeline_id,
+ }) {
+ warn!("Unable to send CleanDevice({:?}) ({:?})", device_id, e);
+ }
+ let global = &self.global;
+ gfx_select!(device_id => global.device_drop(device_id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeDevice(device_id)) {
+ warn!("Unable to send FreeDevice({:?}) ({:?})", device_id, e);
+ };
+ },
+ WebGPURequest::RenderBundleEncoderFinish {
+ render_bundle_encoder,
+ descriptor,
+ render_bundle_id,
+ device_id,
+ } => {
+ let global = &self.global;
+ let result = tuple_to_result(
+ gfx_select!(render_bundle_id => global.render_bundle_encoder_finish(
+ render_bundle_encoder,
+ &descriptor,
+ Some(render_bundle_id)
+ )),
+ );
+
+ self.send_result(device_id, scope_id, result);
+ },
+ WebGPURequest::RequestAdapter {
+ sender,
+ options,
+ ids,
+ } => {
+ let adapter_id = match self
+ .global
+ .request_adapter(&options, wgc::instance::AdapterInputs::IdSet(&ids))
+ {
+ Ok(id) => id,
+ Err(w) => {
+ if let Err(e) = sender.send(Some(Err(format!("{:?}", w)))) {
+ warn!(
+ "Failed to send response to WebGPURequest::RequestAdapter ({})",
+ e
+ )
+ }
+ break;
+ },
+ };
+ let adapter = WebGPUAdapter(adapter_id);
+ self.adapters.push(adapter);
+ let global = &self.global;
+ // TODO: can we do this lazily
+ let info =
+ gfx_select!(adapter_id => global.adapter_get_info(adapter_id)).unwrap();
+ let limits =
+ gfx_select!(adapter_id => global.adapter_limits(adapter_id)).unwrap();
+ let features =
+ gfx_select!(adapter_id => global.adapter_features(adapter_id)).unwrap();
+ if let Err(e) = sender.send(Some(Ok(WebGPUResponse::RequestAdapter {
+ adapter_info: info,
+ adapter_id: adapter,
+ features,
+ limits,
+ channel: WebGPU(self.sender.clone()),
+ }))) {
+ warn!(
+ "Failed to send response to WebGPURequest::RequestAdapter ({})",
+ e
+ )
+ }
+ },
+ WebGPURequest::RequestDevice {
+ sender,
+ adapter_id,
+ descriptor,
+ device_id,
+ pipeline_id,
+ } => {
+ let desc = DeviceDescriptor {
+ label: descriptor.label.as_ref().map(crate::Cow::from),
+ required_features: descriptor.required_features,
+ required_limits: descriptor.required_limits.clone(),
+ };
+ let global = &self.global;
+ let (device_id, queue_id) = match gfx_select!(device_id => global.adapter_request_device(
+ adapter_id.0,
+ &desc,
+ None,
+ Some(device_id),
+ Some(device_id.transmute()),
+ )) {
+ (_, _, Some(e)) => {
+ if let Err(w) = sender.send(Some(Err(format!("{:?}", e)))) {
+ warn!(
+ "Failed to send response to WebGPURequest::RequestDevice ({})",
+ w
+ )
+ }
+ break;
+ },
+ (device_id, queue_id, None) => (device_id, queue_id),
+ };
+ let device = WebGPUDevice(device_id);
+ let queue = WebGPUQueue(queue_id);
+ self.devices.insert(device, pipeline_id);
+ if let Err(e) = sender.send(Some(Ok(WebGPUResponse::RequestDevice {
+ device_id: device,
+ queue_id: queue,
+ descriptor,
+ }))) {
+ warn!(
+ "Failed to send response to WebGPURequest::RequestDevice ({})",
+ e
+ )
+ }
+ },
+ WebGPURequest::RunComputePass {
+ command_encoder_id,
+ compute_pass,
+ } => {
+ let global = &self.global;
+ let result = if let Some(pass) = compute_pass {
+ gfx_select!(command_encoder_id => global.command_encoder_run_compute_pass(
+ command_encoder_id,
+ &pass
+ )).map_err(|e| format!("{:?}", e))
+ } else {
+ Err(String::from("Invalid ComputePass"))
+ };
+ self.encoder_record_error(command_encoder_id, &result);
+ },
+ WebGPURequest::RunRenderPass {
+ 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))
+ } else {
+ Err(String::from("Invalid RenderPass"))
+ };
+ self.encoder_record_error(command_encoder_id, &result);
+ },
+ WebGPURequest::Submit {
+ queue_id,
+ command_buffers,
+ } => {
+ 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(String::from("Invalid command buffer submitted"))
+ } else {
+ gfx_select!(queue_id => global.queue_submit(queue_id, &command_buffers))
+ .map_err(|e| format!("{:?}", e))
+ };
+ self.send_result(queue_id.transmute(), scope_id, result);
+ },
+ WebGPURequest::SwapChainPresent {
+ external_id,
+ texture_id,
+ encoder_id,
+ } => {
+ let global = &self.global;
+ let device_id;
+ let queue_id;
+ let size;
+ let buffer_id;
+ let buffer_stride;
+ {
+ if let Some(present_data) =
+ self.wgpu_image_map.lock().unwrap().get_mut(&external_id)
+ {
+ size = present_data.size;
+ device_id = present_data.device_id;
+ queue_id = present_data.queue_id;
+ buffer_stride = present_data.buffer_stride;
+ buffer_id = if let Some(b_id) =
+ present_data.available_buffer_ids.pop()
+ {
+ b_id
+ } else if let Some(b_id) = present_data.unassigned_buffer_ids.pop()
+ {
+ let buffer_size =
+ (buffer_stride * size.height as u32) as wgt::BufferAddress;
+ let buffer_desc = wgt::BufferDescriptor {
+ label: None,
+ size: buffer_size,
+ usage: wgt::BufferUsages::MAP_READ |
+ wgt::BufferUsages::COPY_DST,
+ mapped_at_creation: false,
+ };
+ let _ = gfx_select!(b_id => global.device_create_buffer(
+ device_id,
+ &buffer_desc,
+ Some(b_id)
+ ));
+ b_id
+ } else {
+ warn!(
+ "No staging buffer available for ExternalImageId({:?})",
+ external_id
+ );
+ continue;
+ };
+ present_data.queued_buffer_ids.push(buffer_id);
+ } else {
+ warn!("Data not found for ExternalImageId({:?})", external_id);
+ continue;
+ }
+ }
+
+ let buffer_size =
+ (size.height as u32 * buffer_stride) as wgt::BufferAddress;
+ let comm_desc = wgt::CommandEncoderDescriptor { label: None };
+ let _ = gfx_select!(encoder_id => global.device_create_command_encoder(
+ device_id,
+ &comm_desc,
+ Some(encoder_id)
+ ));
+
+ let buffer_cv = ImageCopyBuffer {
+ buffer: buffer_id,
+ layout: wgt::ImageDataLayout {
+ offset: 0,
+ bytes_per_row: Some(buffer_stride),
+ rows_per_image: None,
+ },
+ };
+ let texture_cv = ImageCopyTexture {
+ texture: texture_id,
+ mip_level: 0,
+ origin: wgt::Origin3d::ZERO,
+ aspect: wgt::TextureAspect::All,
+ };
+ let copy_size = wgt::Extent3d {
+ width: size.width as u32,
+ height: size.height as u32,
+ depth_or_array_layers: 1,
+ };
+ let _ = gfx_select!(encoder_id => global.command_encoder_copy_texture_to_buffer(
+ encoder_id,
+ &texture_cv,
+ &buffer_cv,
+ &copy_size
+ ));
+ let _ = gfx_select!(encoder_id => global.command_encoder_finish(
+ encoder_id,
+ &wgt::CommandBufferDescriptor::default()
+ ));
+ let _ = gfx_select!(queue_id => global.queue_submit(
+ queue_id,
+ &[encoder_id.into_command_buffer_id()]
+ ));
+
+ let glob = Arc::clone(&self.global);
+ let wgpu_image_map = Arc::clone(&self.wgpu_image_map);
+ let webrender_api = Arc::clone(&self.webrender_api);
+ let webrender_document = self.webrender_document;
+ let callback = BufferMapCallback::from_rust(Box::from(move |result| {
+ match result {
+ Ok(()) => {
+ let global = &glob;
+ let (slice_pointer, range_size) = gfx_select!(buffer_id =>
+ global.buffer_get_mapped_range(buffer_id, 0, Some(buffer_size as u64)))
+ .unwrap();
+ let data = unsafe {
+ slice::from_raw_parts(slice_pointer, range_size as usize)
+ }
+ .to_vec();
+ if let Some(present_data) =
+ wgpu_image_map.lock().unwrap().get_mut(&external_id)
+ {
+ present_data.data = data;
+ let mut txn = Transaction::new();
+ txn.update_image(
+ present_data.image_key,
+ present_data.image_desc,
+ present_data.image_data.clone(),
+ &DirtyRect::All,
+ );
+ webrender_api
+ .lock()
+ .unwrap()
+ .send_transaction(webrender_document, txn);
+ present_data
+ .queued_buffer_ids
+ .retain(|b_id| *b_id != buffer_id);
+ present_data.available_buffer_ids.push(buffer_id);
+ } else {
+ warn!(
+ "Data not found for ExternalImageId({:?})",
+ external_id
+ );
+ }
+ let _ =
+ gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
+ },
+ _ => error!("Could not map buffer({:?})", buffer_id),
+ }
+ }));
+ let map_op = BufferMapOperation {
+ host: HostMap::Read,
+ callback: Some(callback),
+ };
+ let _ = gfx_select!(buffer_id
+ => global.buffer_map_async(buffer_id, 0, Some(buffer_size), map_op));
+ },
+ WebGPURequest::UnmapBuffer {
+ buffer_id,
+ device_id,
+ array_buffer,
+ is_map_read,
+ offset,
+ size,
+ } => {
+ let global = &self.global;
+ if !is_map_read {
+ let (slice_pointer, range_size) =
+ gfx_select!(buffer_id => global.buffer_get_mapped_range(
+ buffer_id,
+ offset,
+ Some(size)
+ ))
+ .unwrap();
+ unsafe {
+ slice::from_raw_parts_mut(slice_pointer, range_size as usize)
+ }
+ .copy_from_slice(&array_buffer);
+ }
+ let result = gfx_select!(buffer_id => global.buffer_unmap(buffer_id));
+ self.send_result(device_id, scope_id, result);
+ },
+ WebGPURequest::WriteBuffer {
+ queue_id,
+ buffer_id,
+ buffer_offset,
+ data,
+ } => {
+ let global = &self.global;
+ //TODO: Report result to content process
+ let result = gfx_select!(queue_id => global.queue_write_buffer(
+ queue_id,
+ buffer_id,
+ buffer_offset as wgt::BufferAddress,
+ &data
+ ));
+ self.send_result(queue_id.transmute(), scope_id, result);
+ },
+ WebGPURequest::WriteTexture {
+ queue_id,
+ texture_cv,
+ data_layout,
+ size,
+ data,
+ } => {
+ let global = &self.global;
+ //TODO: Report result to content process
+ let result = gfx_select!(queue_id => global.queue_write_texture(
+ queue_id,
+ &texture_cv,
+ &data,
+ &data_layout,
+ &size
+ ));
+ self.send_result(queue_id.transmute(), scope_id, result);
+ },
+ WebGPURequest::QueueOnSubmittedWorkDone { sender, queue_id } => {
+ let global = &self.global;
+
+ let callback = SubmittedWorkDoneClosure::from_rust(Box::from(move || {
+ if let Err(e) = sender.send(Some(Ok(WebGPUResponse::SubmittedWorkDone)))
+ {
+ warn!("Could not send SubmittedWorkDone Response ({})", e);
+ }
+ }));
+ let result = gfx_select!(queue_id => global.queue_on_submitted_work_done(queue_id, callback));
+ self.send_result(queue_id.transmute(), scope_id, result);
+ },
+ WebGPURequest::DropTexture(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.texture_drop(id, true));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTexture(id)) {
+ warn!("Unable to send FreeTexture({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropAdapter(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.adapter_drop(id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeAdapter(id)) {
+ warn!("Unable to send FreeAdapter({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropBuffer(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.buffer_drop(id, true));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBuffer(id)) {
+ warn!("Unable to send FreeBuffer({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropPipelineLayout(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.pipeline_layout_drop(id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreePipelineLayout(id)) {
+ warn!("Unable to send FreePipelineLayout({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropComputePipeline(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.compute_pipeline_drop(id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeComputePipeline(id))
+ {
+ warn!("Unable to send FreeComputePipeline({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropRenderPipeline(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.render_pipeline_drop(id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeRenderPipeline(id)) {
+ warn!("Unable to send FreeRenderPipeline({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropBindGroup(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.bind_group_drop(id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBindGroup(id)) {
+ warn!("Unable to send FreeBindGroup({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropBindGroupLayout(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.bind_group_layout_drop(id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeBindGroupLayout(id))
+ {
+ warn!("Unable to send FreeBindGroupLayout({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropTextureView(id) => {
+ let global = &self.global;
+ let _result = gfx_select!(id => global.texture_view_drop(id, true));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeTextureView(id)) {
+ warn!("Unable to send FreeTextureView({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropSampler(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.sampler_drop(id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeSampler(id)) {
+ warn!("Unable to send FreeSampler({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropShaderModule(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.shader_module_drop(id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeShaderModule(id)) {
+ warn!("Unable to send FreeShaderModule({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropRenderBundle(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.render_bundle_drop(id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeRenderBundle(id)) {
+ warn!("Unable to send FreeRenderBundle({:?}) ({:?})", id, e);
+ };
+ },
+ WebGPURequest::DropQuerySet(id) => {
+ let global = &self.global;
+ gfx_select!(id => global.query_set_drop(id));
+ if let Err(e) = self.script_sender.send(WebGPUMsg::FreeQuerySet(id)) {
+ warn!("Unable to send FreeQuerySet({:?}) ({:?})", id, e);
+ };
+ },
+ }
+ }
+ }
+ if let Err(e) = self.script_sender.send(WebGPUMsg::Exit) {
+ warn!("Failed to send WebGPUMsg::Exit to script ({})", e);
+ }
+ }
+
+ fn send_result<U, T: std::fmt::Debug>(
+ &self,
+ device_id: id::DeviceId,
+ scope_id: Option<ErrorScopeId>,
+ result: Result<U, T>,
+ ) {
+ let &pipeline_id = self.devices.get(&WebGPUDevice(device_id)).unwrap();
+ if let Err(w) = self.script_sender.send(WebGPUMsg::WebGPUOpResult {
+ device: WebGPUDevice(device_id),
+ scope_id,
+ pipeline_id,
+ result: if let Err(e) = result {
+ let err = format!("{:?}", e);
+ if err.contains("OutOfMemory") {
+ WebGPUOpResult::OutOfMemoryError
+ } else {
+ WebGPUOpResult::ValidationError(err)
+ }
+ } else {
+ WebGPUOpResult::Success
+ },
+ }) {
+ warn!("Failed to send WebGPUOpResult ({})", w);
+ }
+ }
+
+ fn encoder_record_error<U, T: std::fmt::Debug>(
+ &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));
+ }
+ }
+}
+
+fn tuple_to_result<T, E>(res: (T, Option<E>)) -> Result<T, E> {
+ if let Some(err) = res.1 {
+ Err(err)
+ } else {
+ Ok(res.0)
+ }
+}