summaryrefslogtreecommitdiffstats
path: root/dom/webgpu/ipc/WebGPUChild.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /dom/webgpu/ipc/WebGPUChild.cpp
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/webgpu/ipc/WebGPUChild.cpp')
-rw-r--r--dom/webgpu/ipc/WebGPUChild.cpp697
1 files changed, 697 insertions, 0 deletions
diff --git a/dom/webgpu/ipc/WebGPUChild.cpp b/dom/webgpu/ipc/WebGPUChild.cpp
new file mode 100644
index 0000000000..3ba2f84eb0
--- /dev/null
+++ b/dom/webgpu/ipc/WebGPUChild.cpp
@@ -0,0 +1,697 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 http://mozilla.org/MPL/2.0/. */
+
+#include "WebGPUChild.h"
+#include "mozilla/EnumTypeTraits.h"
+#include "mozilla/dom/WebGPUBinding.h"
+#include "mozilla/dom/GPUUncapturedErrorEvent.h"
+#include "mozilla/webgpu/ValidationError.h"
+#include "mozilla/webgpu/ffi/wgpu.h"
+#include "Sampler.h"
+
+namespace mozilla {
+namespace webgpu {
+
+NS_IMPL_CYCLE_COLLECTION(WebGPUChild)
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGPUChild, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGPUChild, Release)
+
+static ffi::WGPUCompareFunction ConvertCompareFunction(
+ const dom::GPUCompareFunction& aCompare) {
+ // Value of 0 = Undefined is reserved on the C side for "null" semantics.
+ return ffi::WGPUCompareFunction(UnderlyingValue(aCompare) + 1);
+}
+
+static ffi::WGPUClient* initialize() {
+ ffi::WGPUInfrastructure infra = ffi::wgpu_client_new();
+ return infra.client;
+}
+
+WebGPUChild::WebGPUChild() : mClient(initialize()), mIPCOpen(false) {}
+
+WebGPUChild::~WebGPUChild() {
+ if (mClient) {
+ ffi::wgpu_client_delete(mClient);
+ }
+}
+
+RefPtr<RawIdPromise> WebGPUChild::InstanceRequestAdapter(
+ const dom::GPURequestAdapterOptions& aOptions) {
+ const int max_ids = 10;
+ RawId ids[max_ids] = {0};
+ unsigned long count =
+ ffi::wgpu_client_make_adapter_ids(mClient, ids, max_ids);
+
+ nsTArray<RawId> sharedIds(count);
+ for (unsigned long i = 0; i != count; ++i) {
+ sharedIds.AppendElement(ids[i]);
+ }
+
+ return SendInstanceRequestAdapter(aOptions, sharedIds)
+ ->Then(
+ GetCurrentSerialEventTarget(), __func__,
+ [](const RawId& aId) {
+ return aId == 0 ? RawIdPromise::CreateAndReject(Nothing(), __func__)
+ : RawIdPromise::CreateAndResolve(aId, __func__);
+ },
+ [](const ipc::ResponseRejectReason& aReason) {
+ return RawIdPromise::CreateAndReject(Some(aReason), __func__);
+ });
+}
+
+Maybe<RawId> WebGPUChild::AdapterRequestDevice(
+ RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc) {
+ RawId id = ffi::wgpu_client_make_device_id(mClient, aSelfId);
+ if (SendAdapterRequestDevice(aSelfId, aDesc, id)) {
+ return Some(id);
+ }
+ ffi::wgpu_client_kill_device_id(mClient, id);
+ return Nothing();
+}
+
+RawId WebGPUChild::DeviceCreateBuffer(RawId aSelfId,
+ const dom::GPUBufferDescriptor& aDesc) {
+ ffi::WGPUBufferDescriptor desc = {};
+ nsCString label;
+ if (aDesc.mLabel.WasPassed()) {
+ LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
+ desc.label = label.get();
+ }
+ desc.size = aDesc.mSize;
+ desc.usage = aDesc.mUsage;
+ desc.mapped_at_creation = aDesc.mMappedAtCreation;
+
+ ByteBuf bb;
+ RawId id =
+ ffi::wgpu_client_create_buffer(mClient, aSelfId, &desc, ToFFI(&bb));
+ if (!SendDeviceAction(aSelfId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+RawId WebGPUChild::DeviceCreateTexture(RawId aSelfId,
+ const dom::GPUTextureDescriptor& aDesc) {
+ ffi::WGPUTextureDescriptor desc = {};
+ nsCString label;
+ if (aDesc.mLabel.WasPassed()) {
+ LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
+ desc.label = label.get();
+ }
+ if (aDesc.mSize.IsRangeEnforcedUnsignedLongSequence()) {
+ const auto& seq = aDesc.mSize.GetAsRangeEnforcedUnsignedLongSequence();
+ desc.size.width = seq.Length() > 0 ? seq[0] : 1;
+ desc.size.height = seq.Length() > 1 ? seq[1] : 1;
+ desc.size.depth = seq.Length() > 2 ? seq[2] : 1;
+ } else if (aDesc.mSize.IsGPUExtent3DDict()) {
+ const auto& dict = aDesc.mSize.GetAsGPUExtent3DDict();
+ desc.size.width = dict.mWidth;
+ desc.size.height = dict.mHeight;
+ desc.size.depth = dict.mDepth;
+ } else {
+ MOZ_CRASH("Unexpected union");
+ }
+ desc.mip_level_count = aDesc.mMipLevelCount;
+ desc.sample_count = aDesc.mSampleCount;
+ desc.dimension = ffi::WGPUTextureDimension(aDesc.mDimension);
+ desc.format = ffi::WGPUTextureFormat(aDesc.mFormat);
+ desc.usage = aDesc.mUsage;
+
+ ByteBuf bb;
+ RawId id =
+ ffi::wgpu_client_create_texture(mClient, aSelfId, &desc, ToFFI(&bb));
+ if (!SendDeviceAction(aSelfId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+RawId WebGPUChild::TextureCreateView(
+ RawId aSelfId, RawId aDeviceId,
+ const dom::GPUTextureViewDescriptor& aDesc) {
+ ffi::WGPUTextureViewDescriptor desc = {};
+ nsCString label;
+ if (aDesc.mLabel.WasPassed()) {
+ LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
+ desc.label = label.get();
+ }
+
+ ffi::WGPUTextureFormat format = ffi::WGPUTextureFormat_Sentinel;
+ if (aDesc.mFormat.WasPassed()) {
+ format = ffi::WGPUTextureFormat(aDesc.mFormat.Value());
+ desc.format = &format;
+ }
+ ffi::WGPUTextureViewDimension dimension =
+ ffi::WGPUTextureViewDimension_Sentinel;
+ if (aDesc.mDimension.WasPassed()) {
+ dimension = ffi::WGPUTextureViewDimension(aDesc.mDimension.Value());
+ desc.dimension = &dimension;
+ }
+
+ desc.aspect = ffi::WGPUTextureAspect(aDesc.mAspect);
+ desc.base_mip_level = aDesc.mBaseMipLevel;
+ desc.level_count =
+ aDesc.mMipLevelCount.WasPassed() ? aDesc.mMipLevelCount.Value() : 0;
+ desc.base_array_layer = aDesc.mBaseArrayLayer;
+ desc.array_layer_count =
+ aDesc.mArrayLayerCount.WasPassed() ? aDesc.mArrayLayerCount.Value() : 0;
+
+ ByteBuf bb;
+ RawId id =
+ ffi::wgpu_client_create_texture_view(mClient, aSelfId, &desc, ToFFI(&bb));
+ if (!SendTextureAction(aSelfId, aDeviceId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+RawId WebGPUChild::DeviceCreateSampler(RawId aSelfId,
+ const dom::GPUSamplerDescriptor& aDesc) {
+ ffi::WGPUSamplerDescriptor desc = {};
+ nsCString label;
+ if (aDesc.mLabel.WasPassed()) {
+ LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
+ desc.label = label.get();
+ }
+
+ desc.address_modes[0] = ffi::WGPUAddressMode(aDesc.mAddressModeU);
+ desc.address_modes[1] = ffi::WGPUAddressMode(aDesc.mAddressModeV);
+ desc.address_modes[2] = ffi::WGPUAddressMode(aDesc.mAddressModeW);
+ desc.mag_filter = ffi::WGPUFilterMode(aDesc.mMagFilter);
+ desc.min_filter = ffi::WGPUFilterMode(aDesc.mMinFilter);
+ desc.mipmap_filter = ffi::WGPUFilterMode(aDesc.mMipmapFilter);
+ desc.lod_min_clamp = aDesc.mLodMinClamp;
+ desc.lod_max_clamp = aDesc.mLodMaxClamp;
+
+ ffi::WGPUCompareFunction comparison = ffi::WGPUCompareFunction_Sentinel;
+ if (aDesc.mCompare.WasPassed()) {
+ comparison = ConvertCompareFunction(aDesc.mCompare.Value());
+ desc.compare = &comparison;
+ }
+
+ ByteBuf bb;
+ RawId id =
+ ffi::wgpu_client_create_sampler(mClient, aSelfId, &desc, ToFFI(&bb));
+ if (!SendDeviceAction(aSelfId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+RawId WebGPUChild::DeviceCreateCommandEncoder(
+ RawId aSelfId, const dom::GPUCommandEncoderDescriptor& aDesc) {
+ ffi::WGPUCommandEncoderDescriptor desc = {};
+ nsCString label;
+ if (aDesc.mLabel.WasPassed()) {
+ LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
+ desc.label = label.get();
+ }
+
+ ByteBuf bb;
+ RawId id = ffi::wgpu_client_create_command_encoder(mClient, aSelfId, &desc,
+ ToFFI(&bb));
+ if (!SendDeviceAction(aSelfId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+RawId WebGPUChild::CommandEncoderFinish(
+ RawId aSelfId, RawId aDeviceId,
+ const dom::GPUCommandBufferDescriptor& aDesc) {
+ if (!SendCommandEncoderFinish(aSelfId, aDeviceId, aDesc)) {
+ MOZ_CRASH("IPC failure");
+ }
+ // We rely on knowledge that `CommandEncoderId` == `CommandBufferId`
+ // TODO: refactor this to truly behave as if the encoder is being finished,
+ // and a new command buffer ID is being created from it. Resolve the ID
+ // type aliasing at the place that introduces it: `wgpu-core`.
+ return aSelfId;
+}
+
+RawId WebGPUChild::DeviceCreateBindGroupLayout(
+ RawId aSelfId, const dom::GPUBindGroupLayoutDescriptor& aDesc) {
+ struct OptionalData {
+ ffi::WGPUTextureViewDimension dim;
+ ffi::WGPURawTextureSampleType type;
+ ffi::WGPUTextureFormat format;
+ };
+ nsTArray<OptionalData> optional(aDesc.mEntries.Length());
+ for (const auto& entry : aDesc.mEntries) {
+ OptionalData data = {};
+ if (entry.mViewDimension.WasPassed()) {
+ data.dim = ffi::WGPUTextureViewDimension(entry.mViewDimension.Value());
+ }
+ if (entry.mTextureComponentType.WasPassed()) {
+ switch (entry.mTextureComponentType.Value()) {
+ case dom::GPUTextureComponentType::Float:
+ data.type = ffi::WGPURawTextureSampleType_Float;
+ break;
+ case dom::GPUTextureComponentType::Uint:
+ data.type = ffi::WGPURawTextureSampleType_Uint;
+ break;
+ case dom::GPUTextureComponentType::Sint:
+ data.type = ffi::WGPURawTextureSampleType_Sint;
+ break;
+ case dom::GPUTextureComponentType::Depth_comparison:
+ data.type = ffi::WGPURawTextureSampleType_Depth;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE();
+ break;
+ }
+ }
+ if (entry.mStorageTextureFormat.WasPassed()) {
+ data.format = ffi::WGPUTextureFormat(entry.mStorageTextureFormat.Value());
+ }
+ optional.AppendElement(data);
+ }
+
+ nsTArray<ffi::WGPUBindGroupLayoutEntry> entries(aDesc.mEntries.Length());
+ for (size_t i = 0; i < aDesc.mEntries.Length(); ++i) {
+ const auto& entry = aDesc.mEntries[i];
+ ffi::WGPUBindGroupLayoutEntry e = {};
+ e.binding = entry.mBinding;
+ e.visibility = entry.mVisibility;
+ e.ty = ffi::WGPURawBindingType(entry.mType);
+ e.multisampled = entry.mMultisampled;
+ e.has_dynamic_offset = entry.mHasDynamicOffset;
+ if (entry.mViewDimension.WasPassed()) {
+ e.view_dimension = &optional[i].dim;
+ }
+ if (entry.mTextureComponentType.WasPassed()) {
+ e.texture_sample_type = &optional[i].type;
+ }
+ if (entry.mStorageTextureFormat.WasPassed()) {
+ e.storage_texture_format = &optional[i].format;
+ }
+ entries.AppendElement(e);
+ }
+
+ ffi::WGPUBindGroupLayoutDescriptor desc = {};
+ nsCString label;
+ if (aDesc.mLabel.WasPassed()) {
+ LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
+ desc.label = label.get();
+ }
+ desc.entries = entries.Elements();
+ desc.entries_length = entries.Length();
+
+ ByteBuf bb;
+ RawId id = ffi::wgpu_client_create_bind_group_layout(mClient, aSelfId, &desc,
+ ToFFI(&bb));
+ if (!SendDeviceAction(aSelfId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+RawId WebGPUChild::DeviceCreatePipelineLayout(
+ RawId aSelfId, const dom::GPUPipelineLayoutDescriptor& aDesc) {
+ nsTArray<ffi::WGPUBindGroupLayoutId> bindGroupLayouts(
+ aDesc.mBindGroupLayouts.Length());
+ for (const auto& layout : aDesc.mBindGroupLayouts) {
+ bindGroupLayouts.AppendElement(layout->mId);
+ }
+
+ ffi::WGPUPipelineLayoutDescriptor desc = {};
+ nsCString label;
+ if (aDesc.mLabel.WasPassed()) {
+ LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
+ desc.label = label.get();
+ }
+ desc.bind_group_layouts = bindGroupLayouts.Elements();
+ desc.bind_group_layouts_length = bindGroupLayouts.Length();
+
+ ByteBuf bb;
+ RawId id = ffi::wgpu_client_create_pipeline_layout(mClient, aSelfId, &desc,
+ ToFFI(&bb));
+ if (!SendDeviceAction(aSelfId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+RawId WebGPUChild::DeviceCreateBindGroup(
+ RawId aSelfId, const dom::GPUBindGroupDescriptor& aDesc) {
+ nsTArray<ffi::WGPUBindGroupEntry> entries(aDesc.mEntries.Length());
+ for (const auto& entry : aDesc.mEntries) {
+ ffi::WGPUBindGroupEntry e = {};
+ e.binding = entry.mBinding;
+ if (entry.mResource.IsGPUBufferBinding()) {
+ const auto& bufBinding = entry.mResource.GetAsGPUBufferBinding();
+ e.buffer = bufBinding.mBuffer->mId;
+ e.offset = bufBinding.mOffset;
+ e.size = bufBinding.mSize.WasPassed() ? bufBinding.mSize.Value() : 0;
+ }
+ if (entry.mResource.IsGPUTextureView()) {
+ e.texture_view = entry.mResource.GetAsGPUTextureView()->mId;
+ }
+ if (entry.mResource.IsGPUSampler()) {
+ e.sampler = entry.mResource.GetAsGPUSampler()->mId;
+ }
+ entries.AppendElement(e);
+ }
+
+ ffi::WGPUBindGroupDescriptor desc = {};
+ nsCString label;
+ if (aDesc.mLabel.WasPassed()) {
+ LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
+ desc.label = label.get();
+ }
+ desc.layout = aDesc.mLayout->mId;
+ desc.entries = entries.Elements();
+ desc.entries_length = entries.Length();
+
+ ByteBuf bb;
+ RawId id =
+ ffi::wgpu_client_create_bind_group(mClient, aSelfId, &desc, ToFFI(&bb));
+ if (!SendDeviceAction(aSelfId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+RawId WebGPUChild::DeviceCreateShaderModule(
+ RawId aSelfId, const dom::GPUShaderModuleDescriptor& aDesc) {
+ ffi::WGPUShaderModuleDescriptor desc = {};
+
+ nsCString wgsl;
+ if (aDesc.mCode.IsString()) {
+ LossyCopyUTF16toASCII(aDesc.mCode.GetAsString(), wgsl);
+ desc.wgsl_chars = wgsl.get();
+ } else {
+ const auto& code = aDesc.mCode.GetAsUint32Array();
+ code.ComputeState();
+ desc.spirv_words = code.Data();
+ desc.spirv_words_length = code.Length();
+ }
+
+ ByteBuf bb;
+ RawId id = ffi::wgpu_client_create_shader_module(mClient, aSelfId, &desc,
+ ToFFI(&bb));
+ if (!SendDeviceAction(aSelfId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+RawId WebGPUChild::DeviceCreateComputePipeline(
+ RawId aSelfId, const dom::GPUComputePipelineDescriptor& aDesc,
+ nsTArray<RawId>* const aImplicitBindGroupLayoutIds) {
+ ffi::WGPUComputePipelineDescriptor desc = {};
+ nsCString label, entryPoint;
+ if (aDesc.mLabel.WasPassed()) {
+ LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
+ desc.label = label.get();
+ }
+ if (aDesc.mLayout.WasPassed()) {
+ desc.layout = aDesc.mLayout.Value().mId;
+ }
+ desc.compute_stage.module = aDesc.mComputeStage.mModule->mId;
+ LossyCopyUTF16toASCII(aDesc.mComputeStage.mEntryPoint, entryPoint);
+ desc.compute_stage.entry_point = entryPoint.get();
+
+ ByteBuf bb;
+ RawId implicit_bgl_ids[WGPUMAX_BIND_GROUPS] = {};
+ RawId id = ffi::wgpu_client_create_compute_pipeline(
+ mClient, aSelfId, &desc, ToFFI(&bb), implicit_bgl_ids);
+
+ for (const auto& cur : implicit_bgl_ids) {
+ if (!cur) break;
+ aImplicitBindGroupLayoutIds->AppendElement(cur);
+ }
+ if (!SendDeviceAction(aSelfId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+static ffi::WGPURasterizationStateDescriptor ConvertRasterizationDescriptor(
+ const dom::GPURasterizationStateDescriptor& aDesc) {
+ ffi::WGPURasterizationStateDescriptor desc = {};
+ desc.front_face = ffi::WGPUFrontFace(aDesc.mFrontFace);
+ desc.cull_mode = ffi::WGPUCullMode(aDesc.mCullMode);
+ desc.depth_bias = aDesc.mDepthBias;
+ desc.depth_bias_slope_scale = aDesc.mDepthBiasSlopeScale;
+ desc.depth_bias_clamp = aDesc.mDepthBiasClamp;
+ return desc;
+}
+
+static ffi::WGPUBlendDescriptor ConvertBlendDescriptor(
+ const dom::GPUBlendDescriptor& aDesc) {
+ ffi::WGPUBlendDescriptor desc = {};
+ desc.src_factor = ffi::WGPUBlendFactor(aDesc.mSrcFactor);
+ desc.dst_factor = ffi::WGPUBlendFactor(aDesc.mDstFactor);
+ desc.operation = ffi::WGPUBlendOperation(aDesc.mOperation);
+ return desc;
+}
+
+static ffi::WGPUColorStateDescriptor ConvertColorDescriptor(
+ const dom::GPUColorStateDescriptor& aDesc) {
+ ffi::WGPUColorStateDescriptor desc = {};
+ desc.format = ffi::WGPUTextureFormat(aDesc.mFormat);
+ desc.alpha_blend = ConvertBlendDescriptor(aDesc.mAlphaBlend);
+ desc.color_blend = ConvertBlendDescriptor(aDesc.mColorBlend);
+ desc.write_mask = aDesc.mWriteMask;
+ return desc;
+}
+
+static ffi::WGPUStencilStateFaceDescriptor ConvertStencilFaceDescriptor(
+ const dom::GPUStencilStateFaceDescriptor& aDesc) {
+ ffi::WGPUStencilStateFaceDescriptor desc = {};
+ desc.compare = ConvertCompareFunction(aDesc.mCompare);
+ desc.fail_op = ffi::WGPUStencilOperation(aDesc.mFailOp);
+ desc.depth_fail_op = ffi::WGPUStencilOperation(aDesc.mDepthFailOp);
+ desc.pass_op = ffi::WGPUStencilOperation(aDesc.mPassOp);
+ return desc;
+}
+
+static ffi::WGPUDepthStencilStateDescriptor ConvertDepthStencilDescriptor(
+ const dom::GPUDepthStencilStateDescriptor& aDesc) {
+ ffi::WGPUDepthStencilStateDescriptor desc = {};
+ desc.format = ffi::WGPUTextureFormat(aDesc.mFormat);
+ desc.depth_write_enabled = aDesc.mDepthWriteEnabled;
+ desc.depth_compare = ConvertCompareFunction(aDesc.mDepthCompare);
+ desc.stencil.front = ConvertStencilFaceDescriptor(aDesc.mStencilFront);
+ desc.stencil.back = ConvertStencilFaceDescriptor(aDesc.mStencilBack);
+ desc.stencil.read_mask = aDesc.mStencilReadMask;
+ desc.stencil.write_mask = aDesc.mStencilWriteMask;
+ return desc;
+}
+
+RawId WebGPUChild::DeviceCreateRenderPipeline(
+ RawId aSelfId, const dom::GPURenderPipelineDescriptor& aDesc,
+ nsTArray<RawId>* const aImplicitBindGroupLayoutIds) {
+ ffi::WGPURenderPipelineDescriptor desc = {};
+ nsCString label, vsEntry, fsEntry;
+ ffi::WGPUProgrammableStageDescriptor vertexStage = {};
+ ffi::WGPUProgrammableStageDescriptor fragmentStage = {};
+
+ if (aDesc.mLabel.WasPassed()) {
+ LossyCopyUTF16toASCII(aDesc.mLabel.Value(), label);
+ desc.label = label.get();
+ }
+ if (aDesc.mLayout.WasPassed()) {
+ desc.layout = aDesc.mLayout.Value().mId;
+ }
+
+ vertexStage.module = aDesc.mVertexStage.mModule->mId;
+ LossyCopyUTF16toASCII(aDesc.mVertexStage.mEntryPoint, vsEntry);
+ vertexStage.entry_point = vsEntry.get();
+ desc.vertex_stage = &vertexStage;
+
+ if (aDesc.mFragmentStage.WasPassed()) {
+ const auto& stage = aDesc.mFragmentStage.Value();
+ fragmentStage.module = stage.mModule->mId;
+ LossyCopyUTF16toASCII(stage.mEntryPoint, fsEntry);
+ fragmentStage.entry_point = fsEntry.get();
+ desc.fragment_stage = &fragmentStage;
+ }
+
+ desc.primitive_topology =
+ ffi::WGPUPrimitiveTopology(aDesc.mPrimitiveTopology);
+ const auto rasterization =
+ ConvertRasterizationDescriptor(aDesc.mRasterizationState);
+ desc.rasterization_state = &rasterization;
+
+ nsTArray<ffi::WGPUColorStateDescriptor> colorStates;
+ for (const auto& colorState : aDesc.mColorStates) {
+ colorStates.AppendElement(ConvertColorDescriptor(colorState));
+ }
+ desc.color_states = colorStates.Elements();
+ desc.color_states_length = colorStates.Length();
+
+ ffi::WGPUDepthStencilStateDescriptor depthStencilState = {};
+ if (aDesc.mDepthStencilState.WasPassed()) {
+ depthStencilState =
+ ConvertDepthStencilDescriptor(aDesc.mDepthStencilState.Value());
+ desc.depth_stencil_state = &depthStencilState;
+ }
+
+ desc.vertex_state.index_format =
+ ffi::WGPUIndexFormat(aDesc.mVertexState.mIndexFormat);
+ nsTArray<ffi::WGPUVertexBufferDescriptor> vertexBuffers;
+ nsTArray<ffi::WGPUVertexAttributeDescriptor> vertexAttributes;
+ for (const auto& vertex_desc : aDesc.mVertexState.mVertexBuffers) {
+ ffi::WGPUVertexBufferDescriptor vb_desc = {};
+ if (!vertex_desc.IsNull()) {
+ const auto& vd = vertex_desc.Value();
+ vb_desc.stride = vd.mArrayStride;
+ vb_desc.step_mode = ffi::WGPUInputStepMode(vd.mStepMode);
+ // Note: we are setting the length but not the pointer
+ vb_desc.attributes_length = vd.mAttributes.Length();
+ for (const auto& vat : vd.mAttributes) {
+ ffi::WGPUVertexAttributeDescriptor ad = {};
+ ad.offset = vat.mOffset;
+ ad.format = ffi::WGPUVertexFormat(vat.mFormat);
+ ad.shader_location = vat.mShaderLocation;
+ vertexAttributes.AppendElement(ad);
+ }
+ }
+ vertexBuffers.AppendElement(vb_desc);
+ }
+ // Now patch up all the pointers to attribute lists.
+ size_t numAttributes = 0;
+ for (auto& vb_desc : vertexBuffers) {
+ vb_desc.attributes = vertexAttributes.Elements() + numAttributes;
+ numAttributes += vb_desc.attributes_length;
+ }
+
+ desc.vertex_state.vertex_buffers = vertexBuffers.Elements();
+ desc.vertex_state.vertex_buffers_length = vertexBuffers.Length();
+ desc.sample_count = aDesc.mSampleCount;
+ desc.sample_mask = aDesc.mSampleMask;
+ desc.alpha_to_coverage_enabled = aDesc.mAlphaToCoverageEnabled;
+
+ ByteBuf bb;
+ RawId implicit_bgl_ids[WGPUMAX_BIND_GROUPS] = {};
+ RawId id = ffi::wgpu_client_create_render_pipeline(
+ mClient, aSelfId, &desc, ToFFI(&bb), implicit_bgl_ids);
+
+ for (const auto& cur : implicit_bgl_ids) {
+ if (!cur) break;
+ aImplicitBindGroupLayoutIds->AppendElement(cur);
+ }
+ if (!SendDeviceAction(aSelfId, std::move(bb))) {
+ MOZ_CRASH("IPC failure");
+ }
+ return id;
+}
+
+ipc::IPCResult WebGPUChild::RecvError(RawId aDeviceId,
+ const nsACString& aMessage) {
+ if (!aDeviceId) {
+ // TODO: figure out how to report these kinds of errors
+ printf_stderr("Validation error without device target: %s\n",
+ PromiseFlatCString(aMessage).get());
+ } else if (mDeviceMap.find(aDeviceId) == mDeviceMap.end()) {
+ printf_stderr("Validation error on a dropped device: %s\n",
+ PromiseFlatCString(aMessage).get());
+ } else {
+ auto* target = mDeviceMap[aDeviceId];
+ MOZ_ASSERT(target);
+ dom::GPUUncapturedErrorEventInit init;
+ init.mError.SetAsGPUValidationError() =
+ new ValidationError(target, aMessage);
+ RefPtr<mozilla::dom::GPUUncapturedErrorEvent> event =
+ dom::GPUUncapturedErrorEvent::Constructor(target, u"uncapturederror"_ns,
+ init);
+ target->DispatchEvent(*event);
+ }
+ return IPC_OK();
+}
+
+ipc::IPCResult WebGPUChild::RecvDropAction(const ipc::ByteBuf& aByteBuf) {
+ const auto* byteBuf = ToFFI(&aByteBuf);
+ ffi::wgpu_client_drop_action(mClient, byteBuf);
+ return IPC_OK();
+}
+
+ipc::IPCResult WebGPUChild::RecvFreeAdapter(RawId id) {
+ ffi::wgpu_client_kill_adapter_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeDevice(RawId id) {
+ ffi::wgpu_client_kill_device_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreePipelineLayout(RawId id) {
+ ffi::wgpu_client_kill_pipeline_layout_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeShaderModule(RawId id) {
+ ffi::wgpu_client_kill_shader_module_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeBindGroupLayout(RawId id) {
+ ffi::wgpu_client_kill_bind_group_layout_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeBindGroup(RawId id) {
+ ffi::wgpu_client_kill_bind_group_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeCommandBuffer(RawId id) {
+ ffi::wgpu_client_kill_encoder_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeRenderPipeline(RawId id) {
+ ffi::wgpu_client_kill_render_pipeline_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeComputePipeline(RawId id) {
+ ffi::wgpu_client_kill_compute_pipeline_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeBuffer(RawId id) {
+ ffi::wgpu_client_kill_buffer_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeTexture(RawId id) {
+ ffi::wgpu_client_kill_texture_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeTextureView(RawId id) {
+ ffi::wgpu_client_kill_texture_view_id(mClient, id);
+ return IPC_OK();
+}
+ipc::IPCResult WebGPUChild::RecvFreeSampler(RawId id) {
+ ffi::wgpu_client_kill_sampler_id(mClient, id);
+ return IPC_OK();
+}
+
+void WebGPUChild::DeviceCreateSwapChain(RawId aSelfId,
+ const RGBDescriptor& aRgbDesc,
+ size_t maxBufferCount,
+ wr::ExternalImageId aExternalImageId) {
+ RawId queueId = aSelfId; // TODO: multiple queues
+ nsTArray<RawId> bufferIds(maxBufferCount);
+ for (size_t i = 0; i < maxBufferCount; ++i) {
+ bufferIds.AppendElement(ffi::wgpu_client_make_buffer_id(mClient, aSelfId));
+ }
+ SendDeviceCreateSwapChain(aSelfId, queueId, aRgbDesc, bufferIds,
+ aExternalImageId);
+}
+
+void WebGPUChild::SwapChainPresent(wr::ExternalImageId aExternalImageId,
+ RawId aTextureId) {
+ // Hack: the function expects `DeviceId`, but it only uses it for `backend()`
+ // selection.
+ RawId encoderId = ffi::wgpu_client_make_encoder_id(mClient, aTextureId);
+ SendSwapChainPresent(aExternalImageId, aTextureId, encoderId);
+}
+
+void WebGPUChild::RegisterDevice(RawId aId, Device* aDevice) {
+ mDeviceMap.insert({aId, aDevice});
+}
+
+void WebGPUChild::UnregisterDevice(RawId aId) {
+ mDeviceMap.erase(aId);
+ SendDeviceDestroy(aId);
+}
+
+} // namespace webgpu
+} // namespace mozilla