Bug 1609175 - WebGPU bind groups and compute pipelines r=jgilbert,webidl,smaug,bzbarsky

Adds support for bind groups and compute pipelines
The end goal of this PR is to run the compute example.

Differential Revision: https://phabricator.services.mozilla.com/D60746

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Dzmitry Malyshau 2020-01-24 05:05:34 +00:00
parent 9e3c203f89
commit 73eff15f2c
50 changed files with 949 additions and 111 deletions

View File

@ -18,7 +18,7 @@ GPU_IMPL_CYCLE_COLLECTION(Adapter, mParent, mBridge)
GPU_IMPL_JS_WRAP(Adapter)
Adapter::Adapter(Instance* const aParent, RawId aId)
: ChildOf(aParent), mBridge(aParent->GetBridge()), mId(aId) {}
: ChildOf(aParent), mBridge(aParent->mBridge), mId(aId) {}
Adapter::~Adapter() { Cleanup(); }
@ -29,8 +29,6 @@ void Adapter::Cleanup() {
}
}
WebGPUChild* Adapter::GetBridge() const { return mBridge; }
already_AddRefed<dom::Promise> Adapter::RequestDevice(
const dom::GPUDeviceDescriptor& aDesc, ErrorResult& aRv) {
RefPtr<dom::Promise> promise = dom::Promise::Create(GetParentObject(), aRv);

View File

@ -29,19 +29,19 @@ class Adapter final : public ObjectBase, public ChildOf<Instance> {
GPU_DECL_CYCLE_COLLECTION(Adapter)
GPU_DECL_JS_WRAP(Adapter)
const RefPtr<WebGPUChild> mBridge;
private:
Adapter() = delete;
~Adapter();
void Cleanup();
const RefPtr<WebGPUChild> mBridge;
const RawId mId;
const nsString mName;
public:
explicit Adapter(Instance* const aParent, RawId aId);
void GetName(nsString& out) const { out = mName; }
WebGPUChild* GetBridge() const;
already_AddRefed<dom::Promise> RequestDevice(
const dom::GPUDeviceDescriptor& aDesc, ErrorResult& aRv);

View File

@ -14,7 +14,20 @@ namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(BindGroup, mParent)
GPU_IMPL_JS_WRAP(BindGroup)
void BindGroup::Cleanup() {}
BindGroup::BindGroup(Device* const aParent, RawId aId)
: ChildOf(aParent), mId(aId) {}
BindGroup::~BindGroup() { Cleanup(); }
void BindGroup::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
if (bridge && bridge->IsOpen()) {
bridge->DestroyBindGroup(mId);
}
}
}
} // namespace webgpu
} // namespace mozilla

View File

@ -8,6 +8,7 @@
#include "nsWrapperCache.h"
#include "ObjectModel.h"
#include "mozilla/webgpu/WebGPUTypes.h"
namespace mozilla {
namespace webgpu {
@ -19,9 +20,12 @@ class BindGroup final : public ObjectBase, public ChildOf<Device> {
GPU_DECL_CYCLE_COLLECTION(BindGroup)
GPU_DECL_JS_WRAP(BindGroup)
BindGroup(Device* const aParent, RawId aId);
const RawId mId;
private:
BindGroup() = delete;
~BindGroup() = default;
~BindGroup();
void Cleanup();
};

View File

@ -14,7 +14,20 @@ namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(BindGroupLayout, mParent)
GPU_IMPL_JS_WRAP(BindGroupLayout)
void BindGroupLayout::Cleanup() {}
BindGroupLayout::BindGroupLayout(Device* const aParent, RawId aId)
: ChildOf(aParent), mId(aId) {}
BindGroupLayout::~BindGroupLayout() { Cleanup(); }
void BindGroupLayout::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
if (bridge && bridge->IsOpen()) {
bridge->DestroyBindGroupLayout(mId);
}
}
}
} // namespace webgpu
} // namespace mozilla

View File

@ -8,6 +8,7 @@
#include "nsWrapperCache.h"
#include "ObjectModel.h"
#include "mozilla/webgpu/WebGPUTypes.h"
namespace mozilla {
namespace webgpu {
@ -19,9 +20,12 @@ class BindGroupLayout final : public ObjectBase, public ChildOf<Device> {
GPU_DECL_CYCLE_COLLECTION(BindGroupLayout)
GPU_DECL_JS_WRAP(BindGroupLayout)
BindGroupLayout(Device* const aParent, RawId aId);
const RawId mId;
private:
BindGroupLayout() = delete;
~BindGroupLayout() = default;
~BindGroupLayout();
void Cleanup();
};

View File

@ -51,7 +51,10 @@ Buffer::~Buffer() {
void Buffer::Cleanup() {
if (mParent) {
mParent->DestroyBuffer(mId);
WebGPUChild* bridge = mParent->mBridge;
if (bridge && bridge->IsOpen()) {
bridge->DestroyBuffer(mId);
}
}
mMapping.reset();
}

View File

@ -34,11 +34,12 @@ class Buffer final : public ObjectBase, public ChildOf<Device> {
Buffer(Device* const aParent, RawId aId, BufferAddress aSize);
void InitMapping(ipc::Shmem&& aShmem, JSObject* aArrayBuffer);
const RawId mId;
private:
virtual ~Buffer();
void Cleanup();
const RawId mId;
// Note: we can't map a buffer with the size that don't fit into `size_t`
// (which may be smaller than `BufferAddress`), but general not all buffers
// are mapped.

View File

@ -26,7 +26,10 @@ CommandBuffer::~CommandBuffer() { Cleanup(); }
void CommandBuffer::Cleanup() {
if (mValid && mParent) {
mValid = false;
mParent->DestroyCommandBuffer(mId);
WebGPUChild* bridge = mParent->mBridge;
if (bridge && bridge->IsOpen()) {
bridge->DestroyCommandBuffer(mId);
}
}
}

View File

@ -7,6 +7,7 @@
#include "CommandEncoder.h"
#include "CommandBuffer.h"
#include "Buffer.h"
#include "ComputePassEncoder.h"
#include "Device.h"
@ -18,14 +19,29 @@ GPU_IMPL_JS_WRAP(CommandEncoder)
CommandEncoder::CommandEncoder(Device* const aParent,
WebGPUChild* const aBridge, RawId aId)
: ChildOf(aParent), mBridge(aBridge), mId(aId) {}
: ChildOf(aParent), mId(aId), mBridge(aBridge) {}
CommandEncoder::~CommandEncoder() { Cleanup(); }
void CommandEncoder::Cleanup() {
if (mValid && mParent) {
mValid = false;
mParent->DestroyCommandEncoder(mId);
WebGPUChild* bridge = mParent->mBridge;
if (bridge && bridge->IsOpen()) {
bridge->DestroyCommandEncoder(mId);
}
}
}
void CommandEncoder::CopyBufferToBuffer(const Buffer& aSource,
BufferAddress aSourceOffset,
const Buffer& aDestination,
BufferAddress aDestinationOffset,
BufferAddress aSize) {
if (mValid) {
mBridge->SendCommandEncoderCopyBufferToBuffer(
mId, aSource.mId, aSourceOffset, aDestination.mId, aDestinationOffset,
aSize);
}
}

View File

@ -38,20 +38,26 @@ class CommandEncoder final : public ObjectBase, public ChildOf<Device> {
GPU_DECL_JS_WRAP(CommandEncoder)
CommandEncoder(Device* const aParent, WebGPUChild* const aBridge, RawId aId);
RawId GetId() const { return mId; }
void EndComputePass(Span<const uint8_t> aData, ErrorResult& aRv);
already_AddRefed<ComputePassEncoder> BeginComputePass(
const dom::GPUComputePassDescriptor& aDesc);
already_AddRefed<CommandBuffer> Finish(
const dom::GPUCommandBufferDescriptor& aDesc);
const RawId mId;
private:
~CommandEncoder();
void Cleanup();
const RefPtr<WebGPUChild> mBridge;
const RawId mId;
public:
void EndComputePass(Span<const uint8_t> aData, ErrorResult& aRv);
void CopyBufferToBuffer(const Buffer& aSource, BufferAddress aSourceOffset,
const Buffer& aDestination,
BufferAddress aDestinationOffset,
BufferAddress aSize);
already_AddRefed<ComputePassEncoder> BeginComputePass(
const dom::GPUComputePassDescriptor& aDesc);
already_AddRefed<CommandBuffer> Finish(
const dom::GPUCommandBufferDescriptor& aDesc);
};
} // namespace webgpu

View File

@ -5,6 +5,8 @@
#include "mozilla/dom/WebGPUBinding.h"
#include "ComputePassEncoder.h"
#include "BindGroup.h"
#include "ComputePipeline.h"
#include "mozilla/webgpu/ffi/wgpu.h"
@ -29,7 +31,7 @@ ffi::WGPURawPass BeginComputePass(RawId aEncoderId,
ComputePassEncoder::ComputePassEncoder(
CommandEncoder* const aParent, const dom::GPUComputePassDescriptor& aDesc)
: ChildOf(aParent), mRaw(BeginComputePass(aParent->GetId(), aDesc)) {}
: ChildOf(aParent), mRaw(BeginComputePass(aParent->mId, aDesc)) {}
ComputePassEncoder::~ComputePassEncoder() {
if (mValid) {
@ -38,6 +40,22 @@ ComputePassEncoder::~ComputePassEncoder() {
}
}
void ComputePassEncoder::SetBindGroup(
uint32_t aSlot, const BindGroup& aBindGroup,
const dom::Sequence<uint32_t>& aDynamicOffsets) {
if (mValid) {
ffi::wgpu_compute_pass_set_bind_group(&mRaw, aSlot, aBindGroup.mId,
aDynamicOffsets.Elements(),
aDynamicOffsets.Length());
}
}
void ComputePassEncoder::SetPipeline(const ComputePipeline& aPipeline) {
if (mValid) {
ffi::wgpu_compute_pass_set_pipeline(&mRaw, aPipeline.mId);
}
}
void ComputePassEncoder::Dispatch(uint32_t x, uint32_t y, uint32_t z) {
if (mValid) {
ffi::wgpu_compute_pass_dispatch(&mRaw, x, y, z);

View File

@ -37,6 +37,9 @@ class ComputePassEncoder final : public ProgrammablePassEncoder,
ffi::WGPURawPass mRaw;
public:
void SetBindGroup(uint32_t aSlot, const BindGroup& aBindGroup,
const dom::Sequence<uint32_t>& aDynamicOffsets) override;
void SetPipeline(const ComputePipeline& aPipeline);
void Dispatch(uint32_t x, uint32_t y, uint32_t z);
void EndPass(ErrorResult& aRv);
};

View File

@ -13,5 +13,20 @@ namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(ComputePipeline, mParent)
GPU_IMPL_JS_WRAP(ComputePipeline)
ComputePipeline::ComputePipeline(Device* const aParent, RawId aId)
: ChildOf(aParent), mId(aId) {}
ComputePipeline::~ComputePipeline() { Cleanup(); }
void ComputePipeline::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
if (bridge && bridge->IsOpen()) {
bridge->DestroyComputePipeline(mId);
}
}
}
} // namespace webgpu
} // namespace mozilla

View File

@ -19,10 +19,13 @@ class ComputePipeline final : public ObjectBase, public ChildOf<Device> {
GPU_DECL_CYCLE_COLLECTION(ComputePipeline)
GPU_DECL_JS_WRAP(ComputePipeline)
ComputePipeline(Device* const aParent, RawId aId);
const RawId mId;
private:
ComputePipeline() = delete;
~ComputePipeline() = default;
void Cleanup() {}
~ComputePipeline();
void Cleanup();
};
} // namespace webgpu

View File

@ -38,9 +38,9 @@ JSObject* Device::CreateExternalArrayBuffer(JSContext* aCx, size_t aSize,
Device::Device(Adapter* const aParent, RawId aId)
: DOMEventTargetHelper(aParent->GetParentObject()),
mBridge(aParent->GetBridge()),
mBridge(aParent->mBridge),
mId(aId),
mQueue(new Queue(this, aParent->GetBridge(), aId)) {}
mQueue(new Queue(this, aParent->mBridge, aId)) {}
Device::~Device() { Cleanup(); }
@ -129,12 +129,6 @@ void Device::UnmapBuffer(RawId aId, UniquePtr<ipc::Shmem> aShmem) {
mBridge->SendDeviceUnmapBuffer(mId, aId, std::move(*aShmem));
}
void Device::DestroyBuffer(RawId aId) {
if (mBridge && mBridge->IsOpen()) {
mBridge->DestroyBuffer(aId);
}
}
already_AddRefed<CommandEncoder> Device::CreateCommandEncoder(
const dom::GPUCommandEncoderDescriptor& aDesc) {
RawId id = mBridge->DeviceCreateCommandEncoder(mId, aDesc);
@ -142,16 +136,37 @@ already_AddRefed<CommandEncoder> Device::CreateCommandEncoder(
return encoder.forget();
}
void Device::DestroyCommandEncoder(RawId aId) {
if (mBridge && mBridge->IsOpen()) {
mBridge->DestroyCommandEncoder(aId);
}
already_AddRefed<BindGroupLayout> Device::CreateBindGroupLayout(
const dom::GPUBindGroupLayoutDescriptor& aDesc) {
RawId id = mBridge->DeviceCreateBindGroupLayout(mId, aDesc);
RefPtr<BindGroupLayout> object = new BindGroupLayout(this, id);
return object.forget();
}
already_AddRefed<PipelineLayout> Device::CreatePipelineLayout(
const dom::GPUPipelineLayoutDescriptor& aDesc) {
RawId id = mBridge->DeviceCreatePipelineLayout(mId, aDesc);
RefPtr<PipelineLayout> object = new PipelineLayout(this, id);
return object.forget();
}
already_AddRefed<BindGroup> Device::CreateBindGroup(
const dom::GPUBindGroupDescriptor& aDesc) {
RawId id = mBridge->DeviceCreateBindGroup(mId, aDesc);
RefPtr<BindGroup> object = new BindGroup(this, id);
return object.forget();
}
void Device::DestroyCommandBuffer(RawId aId) {
if (mBridge && mBridge->IsOpen()) {
mBridge->DestroyCommandBuffer(aId);
}
already_AddRefed<ShaderModule> Device::CreateShaderModule(
const dom::GPUShaderModuleDescriptor& aDesc) {
RawId id = mBridge->DeviceCreateShaderModule(mId, aDesc);
RefPtr<ShaderModule> object = new ShaderModule(this, id);
return object.forget();
}
already_AddRefed<ComputePipeline> Device::CreateComputePipeline(
const dom::GPUComputePipelineDescriptor& aDesc) {
RawId id = mBridge->DeviceCreateComputePipeline(mId, aDesc);
RefPtr<ComputePipeline> object = new ComputePipeline(this, id);
return object.forget();
}
} // namespace webgpu

View File

@ -79,15 +79,13 @@ class Device final : public DOMEventTargetHelper {
RefPtr<MappingPromise> MapBufferForReadAsync(RawId aId, size_t aSize,
ErrorResult& aRv);
void UnmapBuffer(RawId aId, UniquePtr<ipc::Shmem> aShmem);
void DestroyBuffer(RawId aId);
void DestroyCommandEncoder(RawId aId);
void DestroyCommandBuffer(RawId aId);
const RefPtr<WebGPUChild> mBridge;
private:
~Device();
void Cleanup();
const RefPtr<WebGPUChild> mBridge;
const RawId mId;
bool mValid = true;
nsString mLabel;
@ -105,6 +103,19 @@ class Device final : public DOMEventTargetHelper {
already_AddRefed<CommandEncoder> CreateCommandEncoder(
const dom::GPUCommandEncoderDescriptor& aDesc);
already_AddRefed<BindGroupLayout> CreateBindGroupLayout(
const dom::GPUBindGroupLayoutDescriptor& aDesc);
already_AddRefed<PipelineLayout> CreatePipelineLayout(
const dom::GPUPipelineLayoutDescriptor& aDesc);
already_AddRefed<BindGroup> CreateBindGroup(
const dom::GPUBindGroupDescriptor& aDesc);
already_AddRefed<ShaderModule> CreateShaderModule(
const dom::GPUShaderModuleDescriptor& aDesc);
already_AddRefed<ComputePipeline> CreateComputePipeline(
const dom::GPUComputePipelineDescriptor& aDesc);
// IMPL_EVENT_HANDLER(uncapturederror)
};

View File

@ -15,7 +15,7 @@
namespace mozilla {
namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(Instance, mOwner, mBridge)
GPU_IMPL_CYCLE_COLLECTION(Instance, mBridge, mOwner)
/*static*/
already_AddRefed<Instance> Instance::Create(nsIGlobalObject* aOwner) {
@ -34,7 +34,7 @@ already_AddRefed<Instance> Instance::Create(nsIGlobalObject* aOwner) {
}
Instance::Instance(nsIGlobalObject* aOwner, WebGPUChild* aBridge)
: mOwner(aOwner), mBridge(aBridge) {}
: mBridge(aBridge), mOwner(aOwner) {}
Instance::~Instance() { Cleanup(); }
@ -45,8 +45,6 @@ JSObject* Instance::WrapObject(JSContext* cx,
return dom::GPU_Binding::Wrap(cx, this, givenProto);
}
WebGPUChild* Instance::GetBridge() const { return mBridge; }
already_AddRefed<dom::Promise> Instance::RequestAdapter(
const dom::GPURequestAdapterOptions& aOptions, ErrorResult& aRv) {
RefPtr<dom::Promise> promise = dom::Promise::Create(mOwner, aRv);

View File

@ -27,22 +27,23 @@ class Instance final : public nsWrapperCache {
GPU_DECL_CYCLE_COLLECTION(Instance)
GPU_DECL_JS_WRAP(Instance)
nsIGlobalObject* GetParentObject() const { return mOwner; }
static already_AddRefed<Instance> Create(nsIGlobalObject* aOwner);
already_AddRefed<dom::Promise> RequestAdapter(
const dom::GPURequestAdapterOptions& aOptions, ErrorResult& aRv);
const RefPtr<WebGPUChild> mBridge;
private:
explicit Instance(nsIGlobalObject* aOwner, WebGPUChild* aBridge);
virtual ~Instance();
void Cleanup();
nsCOMPtr<nsIGlobalObject> mOwner;
const RefPtr<WebGPUChild> mBridge;
public:
nsIGlobalObject* GetParentObject() const { return mOwner; }
WebGPUChild* GetBridge() const;
};
} // namespace webgpu

View File

@ -14,7 +14,20 @@ namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(PipelineLayout, mParent)
GPU_IMPL_JS_WRAP(PipelineLayout)
PipelineLayout::~PipelineLayout() = default;
PipelineLayout::PipelineLayout(Device* const aParent, RawId aId)
: ChildOf(aParent), mId(aId) {}
PipelineLayout::~PipelineLayout() { Cleanup(); }
void PipelineLayout::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
if (bridge && bridge->IsOpen()) {
bridge->DestroyPipelineLayout(mId);
}
}
}
} // namespace webgpu
} // namespace mozilla

View File

@ -8,6 +8,7 @@
#include "nsWrapperCache.h"
#include "ObjectModel.h"
#include "mozilla/webgpu/WebGPUTypes.h"
namespace mozilla {
namespace webgpu {
@ -19,10 +20,13 @@ class PipelineLayout final : public ObjectBase, public ChildOf<Device> {
GPU_DECL_CYCLE_COLLECTION(PipelineLayout)
GPU_DECL_JS_WRAP(PipelineLayout)
PipelineLayout(Device* const aParent, RawId aId);
const RawId mId;
private:
PipelineLayout() = delete;
virtual ~PipelineLayout();
void Cleanup() {}
void Cleanup();
};
} // namespace webgpu

View File

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "ProgrammablePassEncoder.h"
#include "BindGroup.h"
namespace mozilla {
namespace webgpu {

View File

@ -13,8 +13,6 @@ namespace mozilla {
namespace dom {
template <typename T>
class Sequence;
template <typename T>
class Optional;
} // namespace dom
namespace webgpu {
@ -34,6 +32,12 @@ class ProgrammablePassEncoder : public nsISupports, public ObjectBase {
protected:
~ProgrammablePassEncoder() = default;
void Cleanup() {}
public:
// TODO: remove all of this, see
// https://bugzilla.mozilla.org/show_bug.cgi?id=1611024
virtual void SetBindGroup(uint32_t aSlot, const BindGroup& aBindGroup,
const dom::Sequence<uint32_t>& aDynamicOffsets) = 0;
};
} // namespace webgpu

View File

@ -20,5 +20,13 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(RenderBundleEncoder,
NS_IMPL_CYCLE_COLLECTION_TRACE_END
GPU_IMPL_JS_WRAP(RenderBundleEncoder)
void RenderBundleEncoder::SetBindGroup(
uint32_t aSlot, const BindGroup& aBindGroup,
const dom::Sequence<uint32_t>& aDynamicOffsets) {
if (mValid) {
MOZ_CRASH("TODO");
}
}
} // namespace webgpu
} // namespace mozilla

View File

@ -29,6 +29,8 @@ class RenderBundleEncoder final : public RenderEncoderBase,
~RenderBundleEncoder() = default;
public:
void SetBindGroup(uint32_t aSlot, const BindGroup& aBindGroup,
const dom::Sequence<uint32_t>& aDynamicOffsets) override;
};
} // namespace webgpu

View File

@ -21,5 +21,13 @@ GPU_IMPL_JS_WRAP(RenderPassEncoder)
RenderPassEncoder::~RenderPassEncoder() = default;
void RenderPassEncoder::SetBindGroup(
uint32_t aSlot, const BindGroup& aBindGroup,
const dom::Sequence<uint32_t>& aDynamicOffsets) {
if (mValid) {
MOZ_CRASH("TODO");
}
}
} // namespace webgpu
} // namespace mozilla

View File

@ -39,6 +39,8 @@ class RenderPassEncoder final : public RenderEncoderBase,
void Cleanup() {}
public:
void SetBindGroup(uint32_t aSlot, const BindGroup& aBindGroup,
const dom::Sequence<uint32_t>& aDynamicOffsets) override;
};
} // namespace webgpu

View File

@ -19,6 +19,8 @@ class Sampler final : public ObjectBase, public ChildOf<Device> {
GPU_DECL_CYCLE_COLLECTION(Sampler)
GPU_DECL_JS_WRAP(Sampler)
const RawId mId;
private:
Sampler() = delete;
virtual ~Sampler();

View File

@ -14,7 +14,20 @@ namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(ShaderModule, mParent)
GPU_IMPL_JS_WRAP(ShaderModule)
ShaderModule::~ShaderModule() = default;
ShaderModule::ShaderModule(Device* const aParent, RawId aId)
: ChildOf(aParent), mId(aId) {}
ShaderModule::~ShaderModule() { Cleanup(); }
void ShaderModule::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
if (bridge && bridge->IsOpen()) {
bridge->DestroyShaderModule(mId);
}
}
}
} // namespace webgpu
} // namespace mozilla

View File

@ -19,10 +19,13 @@ class ShaderModule final : public ObjectBase, public ChildOf<Device> {
GPU_DECL_CYCLE_COLLECTION(ShaderModule)
GPU_DECL_JS_WRAP(ShaderModule)
ShaderModule(Device* const aParent, RawId aId);
const RawId mId;
private:
ShaderModule() = delete;
virtual ~ShaderModule();
void Cleanup() {}
void Cleanup();
};
} // namespace webgpu

View File

@ -19,6 +19,8 @@ class TextureView final : public ObjectBase, public ChildOf<Device> {
GPU_DECL_CYCLE_COLLECTION(TextureView)
GPU_DECL_JS_WRAP(TextureView)
const RawId mId;
private:
TextureView() = delete;
virtual ~TextureView();

View File

@ -15,7 +15,9 @@ if CONFIG['COMPILE_ENVIRONMENT']:
GeneratedFile('wgpu_ffi_generated.h',
script='/layout/style/RunCbindgen.py',
entry_point='generate',
inputs=['/gfx/wgpu/wgpu-remote'])
inputs=[
'/gfx/wgpu/wgpu-remote',
])
EXPORTS.mozilla.webgpu.ffi += [
'!wgpu_ffi_generated.h',

View File

@ -6,11 +6,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
using RawId from "mozilla/webgpu/WebGPUTypes.h";
using BufferAddress from "mozilla/webgpu/WebGPUTypes.h";
using SerialBindGroupLayoutDescriptor from "mozilla/webgpu/WebGPUTypes.h";
using SerialPipelineLayoutDescriptor from "mozilla/webgpu/WebGPUTypes.h";
using SerialBindGroupDescriptor from "mozilla/webgpu/WebGPUTypes.h";
using SerialComputePipelineDescriptor from "mozilla/webgpu/WebGPUTypes.h";
using dom::GPURequestAdapterOptions from "mozilla/dom/WebGPUBinding.h";
using dom::GPUDeviceDescriptor from "mozilla/dom/WebGPUBinding.h";
using dom::GPUBufferDescriptor from "mozilla/dom/WebGPUBinding.h";
using dom::GPUCommandEncoderDescriptor from "mozilla/dom/WebGPUBinding.h";
using dom::GPUCommandBufferDescriptor from "mozilla/dom/WebGPUBinding.h";
using dom::GPUPipelineLayoutDescriptor from "mozilla/dom/WebGPUBinding.h";
include "mozilla/webgpu/WebGPUSerialize.h";
include protocol PCompositorBridge;
@ -37,11 +43,22 @@ parent:
async BufferMapRead(RawId selfId, Shmem shmem) returns (Shmem sm);
async BufferDestroy(RawId selfId);
async DeviceCreateCommandEncoder(RawId selfId, GPUCommandEncoderDescriptor desc, RawId newId);
async CommandEncoderCopyBufferToBuffer(RawId selfId, RawId sourceId, BufferAddress sourceOffset, RawId destinationId, BufferAddress destinationOffset, BufferAddress size);
async CommandEncoderRunComputePass(RawId selfId, Shmem shmem);
async CommandEncoderFinish(RawId selfId, GPUCommandBufferDescriptor desc);
async CommandEncoderDestroy(RawId selfId);
async CommandBufferDestroy(RawId selfId);
async QueueSubmit(RawId selfId, RawId[] commandBuffers);
async DeviceCreateBindGroupLayout(RawId selfId, SerialBindGroupLayoutDescriptor desc, RawId newId);
async BindGroupLayoutDestroy(RawId selfId);
async DeviceCreatePipelineLayout(RawId selfId, SerialPipelineLayoutDescriptor desc, RawId newId);
async PipelineLayoutDestroy(RawId selfId);
async DeviceCreateBindGroup(RawId selfId, SerialBindGroupDescriptor desc, RawId newId);
async BindGroupDestroy(RawId selfId);
async DeviceCreateShaderModule(RawId selfId, uint32_t[] data, RawId newId);
async ShaderModuleDestroy(RawId selfId);
async DeviceCreateComputePipeline(RawId selfId, SerialComputePipelineDescriptor desc, RawId newId);
async ComputePipelineDestroy(RawId selfId);
async Shutdown();
child:

View File

@ -110,6 +110,100 @@ RawId WebGPUChild::CommandEncoderFinish(
return aSelfId;
}
RawId WebGPUChild::DeviceCreateBindGroupLayout(
RawId aSelfId, const dom::GPUBindGroupLayoutDescriptor& aDesc) {
RawId id = ffi::wgpu_client_make_bind_group_layout_id(mClient, aSelfId);
nsTArray<ffi::WGPUBindGroupLayoutBinding> bindings(aDesc.mBindings.Length());
for (const auto& binding : aDesc.mBindings) {
ffi::WGPUBindGroupLayoutBinding b = {};
b.binding = binding.mBinding;
b.visibility = binding.mVisibility;
b.ty = ffi::WGPUBindingType(binding.mType);
Unused << binding.mTextureComponentType; // TODO
b.texture_dimension =
ffi::WGPUTextureViewDimension(binding.mTextureDimension);
b.multisampled = binding.mMultisampled;
b.dynamic = binding.mDynamic;
bindings.AppendElement(b);
}
SerialBindGroupLayoutDescriptor desc = {std::move(bindings)};
if (!SendDeviceCreateBindGroupLayout(aSelfId, desc, id)) {
MOZ_CRASH("IPC failure");
}
return id;
}
RawId WebGPUChild::DeviceCreatePipelineLayout(
RawId aSelfId, const dom::GPUPipelineLayoutDescriptor& aDesc) {
RawId id = ffi::wgpu_client_make_pipeline_layout_id(mClient, aSelfId);
SerialPipelineLayoutDescriptor desc = {};
for (const auto& layouts : aDesc.mBindGroupLayouts) {
desc.mBindGroupLayouts.AppendElement(layouts->mId);
}
if (!SendDeviceCreatePipelineLayout(aSelfId, desc, id)) {
MOZ_CRASH("IPC failure");
}
return id;
}
RawId WebGPUChild::DeviceCreateBindGroup(
RawId aSelfId, const dom::GPUBindGroupDescriptor& aDesc) {
RawId id = ffi::wgpu_client_make_bind_group_id(mClient, aSelfId);
SerialBindGroupDescriptor desc = {};
desc.mLayout = aDesc.mLayout->mId;
for (const auto& binding : aDesc.mBindings) {
SerialBindGroupBinding bd = {};
bd.mBinding = binding.mBinding;
if (binding.mResource.IsGPUBufferBinding()) {
bd.mType = SerialBindGroupBindingType::Buffer;
const auto& bufBinding = binding.mResource.GetAsGPUBufferBinding();
bd.mValue = bufBinding.mBuffer->mId;
bd.mBufferOffset = bufBinding.mOffset;
bd.mBufferSize =
bufBinding.mSize.WasPassed() ? bufBinding.mSize.Value() : 0;
}
if (binding.mResource.IsGPUTextureView()) {
bd.mType = SerialBindGroupBindingType::Texture;
bd.mValue = binding.mResource.GetAsGPUTextureView()->mId;
}
if (binding.mResource.IsGPUSampler()) {
bd.mType = SerialBindGroupBindingType::Sampler;
bd.mValue = binding.mResource.GetAsGPUSampler()->mId;
}
desc.mBindings.AppendElement(bd);
}
if (!SendDeviceCreateBindGroup(aSelfId, desc, id)) {
MOZ_CRASH("IPC failure");
}
return id;
}
RawId WebGPUChild::DeviceCreateShaderModule(
RawId aSelfId, const dom::GPUShaderModuleDescriptor& aDesc) {
RawId id = ffi::wgpu_client_make_shader_module_id(mClient, aSelfId);
MOZ_ASSERT(aDesc.mCode.IsUint32Array());
const auto& code = aDesc.mCode.GetAsUint32Array();
code.ComputeLengthAndData();
nsTArray<uint32_t> data(code.Length());
data.AppendElements(code.Data(), code.Length());
if (!SendDeviceCreateShaderModule(aSelfId, data, id)) {
MOZ_CRASH("IPC failure");
}
return id;
}
RawId WebGPUChild::DeviceCreateComputePipeline(
RawId aSelfId, const dom::GPUComputePipelineDescriptor& aDesc) {
RawId id = ffi::wgpu_client_make_compute_pipeline_id(mClient, aSelfId);
SerialProgrammableStageDescriptor stage = {};
stage.mModule = aDesc.mComputeStage.mModule->mId;
stage.mEntryPoint = aDesc.mComputeStage.mEntryPoint;
SerialComputePipelineDescriptor desc = {aDesc.mLayout->mId, stage};
if (!SendDeviceCreateComputePipeline(aSelfId, desc, id)) {
MOZ_CRASH("IPC failure");
}
return id;
}
void WebGPUChild::QueueSubmit(RawId aSelfId,
const nsTArray<RawId>& aCommandBufferIds) {
SendQueueSubmit(aSelfId, aCommandBufferIds);
@ -134,6 +228,26 @@ void WebGPUChild::DestroyCommandBuffer(RawId aId) {
SendCommandBufferDestroy(aId);
ffi::wgpu_client_kill_encoder_id(mClient, aId);
}
void WebGPUChild::DestroyBindGroupLayout(RawId aId) {
SendBindGroupLayoutDestroy(aId);
ffi::wgpu_client_kill_bind_group_layout_id(mClient, aId);
}
void WebGPUChild::DestroyPipelineLayout(RawId aId) {
SendPipelineLayoutDestroy(aId);
ffi::wgpu_client_kill_pipeline_layout_id(mClient, aId);
}
void WebGPUChild::DestroyBindGroup(RawId aId) {
SendBindGroupDestroy(aId);
ffi::wgpu_client_kill_bind_group_id(mClient, aId);
}
void WebGPUChild::DestroyShaderModule(RawId aId) {
SendShaderModuleDestroy(aId);
ffi::wgpu_client_kill_shader_module_id(mClient, aId);
}
void WebGPUChild::DestroyComputePipeline(RawId aId) {
SendComputePipelineDestroy(aId);
ffi::wgpu_client_kill_compute_pipeline_id(mClient, aId);
}
} // namespace webgpu
} // namespace mozilla

View File

@ -44,12 +44,28 @@ class WebGPUChild final : public PWebGPUChild {
RawId aSelfId, const dom::GPUCommandEncoderDescriptor& aDesc);
RawId CommandEncoderFinish(RawId aSelfId,
const dom::GPUCommandBufferDescriptor& aDesc);
RawId DeviceCreateBindGroupLayout(
RawId aSelfId, const dom::GPUBindGroupLayoutDescriptor& aDesc);
RawId DeviceCreatePipelineLayout(
RawId aSelfId, const dom::GPUPipelineLayoutDescriptor& aDesc);
RawId DeviceCreateBindGroup(RawId aSelfId,
const dom::GPUBindGroupDescriptor& aDesc);
RawId DeviceCreateShaderModule(RawId aSelfId,
const dom::GPUShaderModuleDescriptor& aDesc);
RawId DeviceCreateComputePipeline(
RawId aSelfId, const dom::GPUComputePipelineDescriptor& aDesc);
void QueueSubmit(RawId aSelfId, const nsTArray<RawId>& aCommandBufferIds);
void DestroyAdapter(RawId aId);
void DestroyBuffer(RawId aId);
void DestroyCommandEncoder(RawId aId);
void DestroyCommandBuffer(RawId aId);
void DestroyBindGroupLayout(RawId aId);
void DestroyPipelineLayout(RawId aId);
void DestroyBindGroup(RawId aId);
void DestroyShaderModule(RawId aId);
void DestroyComputePipeline(RawId aId);
private:
virtual ~WebGPUChild();

View File

@ -46,6 +46,9 @@ ipc::IPCResult WebGPUParent::RecvInstanceRequestAdapter(
ipc::IPCResult WebGPUParent::RecvAdapterRequestDevice(
RawId aSelfId, const dom::GPUDeviceDescriptor& aDesc, RawId aNewId) {
ffi::WGPUDeviceDescriptor desc = {};
desc.limits.max_bind_groups = aDesc.mLimits.WasPassed()
? aDesc.mLimits.Value().mMaxBindGroups
: WGPUDEFAULT_BIND_GROUPS;
Unused << aDesc; // no useful fields
// TODO: fill up the descriptor
ffi::wgpu_server_adapter_request_device(mContext, aSelfId, &desc, aNewId);
@ -67,6 +70,11 @@ ipc::IPCResult WebGPUParent::RecvDeviceCreateBuffer(
ffi::WGPUBufferDescriptor desc = {};
desc.usage = aDesc.mUsage;
desc.size = aDesc.mSize;
// tweak: imply STORAGE_READ. This is yet to be figured out by the spec,
// see https://github.com/gpuweb/gpuweb/issues/541
if (desc.usage & WGPUBufferUsage_STORAGE) {
desc.usage |= WGPUBufferUsage_STORAGE_READ;
}
ffi::wgpu_server_device_create_buffer(mContext, aSelfId, &desc, aNewId);
return IPC_OK();
}
@ -121,6 +129,16 @@ ipc::IPCResult WebGPUParent::RecvDeviceCreateCommandEncoder(
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvCommandEncoderCopyBufferToBuffer(
RawId aSelfId, RawId aSourceId, BufferAddress aSourceOffset,
RawId aDestinationId, BufferAddress aDestinationOffset,
BufferAddress aSize) {
ffi::wgpu_server_encoder_copy_buffer_to_buffer(mContext, aSelfId, aSourceId,
aSourceOffset, aDestinationId,
aDestinationOffset, aSize);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvCommandEncoderRunComputePass(RawId aSelfId,
Shmem&& shmem) {
ffi::wgpu_server_encode_compute_pass(mContext, aSelfId, shmem.get<uint8_t>(),
@ -153,6 +171,107 @@ ipc::IPCResult WebGPUParent::RecvQueueSubmit(
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvDeviceCreateBindGroupLayout(
RawId aSelfId, const SerialBindGroupLayoutDescriptor& aDesc, RawId aNewId) {
ffi::WGPUBindGroupLayoutDescriptor desc = {};
desc.bindings = aDesc.mBindings.Elements();
desc.bindings_length = aDesc.mBindings.Length();
ffi::wgpu_server_device_create_bind_group_layout(mContext, aSelfId, &desc,
aNewId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvBindGroupLayoutDestroy(RawId aSelfId) {
ffi::wgpu_server_bind_group_layout_destroy(mContext, aSelfId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvDeviceCreatePipelineLayout(
RawId aSelfId, const SerialPipelineLayoutDescriptor& aDesc, RawId aNewId) {
ffi::WGPUPipelineLayoutDescriptor desc = {};
desc.bind_group_layouts = aDesc.mBindGroupLayouts.Elements();
desc.bind_group_layouts_length = aDesc.mBindGroupLayouts.Length();
ffi::wgpu_server_device_create_pipeline_layout(mContext, aSelfId, &desc,
aNewId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvPipelineLayoutDestroy(RawId aSelfId) {
ffi::wgpu_server_pipeline_layout_destroy(mContext, aSelfId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvDeviceCreateBindGroup(
RawId aSelfId, const SerialBindGroupDescriptor& aDesc, RawId aNewId) {
nsTArray<ffi::WGPUBindGroupBinding> ffiBindings(aDesc.mBindings.Length());
for (const auto& binding : aDesc.mBindings) {
ffi::WGPUBindGroupBinding bgb = {};
bgb.binding = binding.mBinding;
switch (binding.mType) {
case SerialBindGroupBindingType::Buffer:
bgb.resource.tag = ffi::WGPUBindingResource_Buffer;
bgb.resource.buffer._0.buffer = binding.mValue;
bgb.resource.buffer._0.offset = binding.mBufferOffset;
bgb.resource.buffer._0.size = binding.mBufferSize;
break;
case SerialBindGroupBindingType::Texture:
bgb.resource.tag = ffi::WGPUBindingResource_TextureView;
bgb.resource.texture_view._0 = binding.mValue;
break;
case SerialBindGroupBindingType::Sampler:
bgb.resource.tag = ffi::WGPUBindingResource_Sampler;
bgb.resource.sampler._0 = binding.mValue;
break;
default:
MOZ_CRASH("unreachable");
}
ffiBindings.AppendElement(bgb);
}
ffi::WGPUBindGroupDescriptor desc = {};
desc.layout = aDesc.mLayout;
desc.bindings = ffiBindings.Elements();
desc.bindings_length = ffiBindings.Length();
ffi::wgpu_server_device_create_bind_group(mContext, aSelfId, &desc, aNewId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvBindGroupDestroy(RawId aSelfId) {
ffi::wgpu_server_bind_group_destroy(mContext, aSelfId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvDeviceCreateShaderModule(
RawId aSelfId, const nsTArray<uint32_t>& aData, RawId aNewId) {
ffi::WGPUShaderModuleDescriptor desc = {};
desc.code.bytes = aData.Elements();
desc.code.length = aData.Length();
ffi::wgpu_server_device_create_shader_module(mContext, aSelfId, &desc,
aNewId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvShaderModuleDestroy(RawId aSelfId) {
ffi::wgpu_server_shader_module_destroy(mContext, aSelfId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvDeviceCreateComputePipeline(
RawId aSelfId, const SerialComputePipelineDescriptor& aDesc, RawId aNewId) {
NS_LossyConvertUTF16toASCII entryPoint(aDesc.mComputeStage.mEntryPoint);
ffi::WGPUComputePipelineDescriptor desc = {};
desc.layout = aDesc.mLayout;
desc.compute_stage.module = aDesc.mComputeStage.mModule;
desc.compute_stage.entry_point = entryPoint.get();
ffi::wgpu_server_device_create_compute_pipeline(mContext, aSelfId, &desc,
aNewId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvComputePipelineDestroy(RawId aSelfId) {
ffi::wgpu_server_compute_pipeline_destroy(mContext, aSelfId);
return IPC_OK();
}
ipc::IPCResult WebGPUParent::RecvShutdown() {
mTimer.Stop();
ffi::wgpu_server_poll_all_devices(mContext, true);

View File

@ -42,6 +42,10 @@ class WebGPUParent final : public PWebGPUParent {
ipc::IPCResult RecvDeviceCreateCommandEncoder(
RawId aSelfId, const dom::GPUCommandEncoderDescriptor& aDesc,
RawId aNewId);
ipc::IPCResult RecvCommandEncoderCopyBufferToBuffer(
RawId aSelfId, RawId aSourceId, BufferAddress aSourceOffset,
RawId aDestinationId, BufferAddress aDestinationOffset,
BufferAddress aSize);
ipc::IPCResult RecvCommandEncoderRunComputePass(RawId aSelfId, Shmem&& shmem);
ipc::IPCResult RecvCommandEncoderFinish(
RawId aSelfId, const dom::GPUCommandBufferDescriptor& aDesc);
@ -49,6 +53,24 @@ class WebGPUParent final : public PWebGPUParent {
ipc::IPCResult RecvCommandBufferDestroy(RawId aSelfId);
ipc::IPCResult RecvQueueSubmit(RawId aSelfId,
const nsTArray<RawId>& aCommandBuffers);
ipc::IPCResult RecvDeviceCreateBindGroupLayout(
RawId aSelfId, const SerialBindGroupLayoutDescriptor& aDesc,
RawId aNewId);
ipc::IPCResult RecvBindGroupLayoutDestroy(RawId aSelfId);
ipc::IPCResult RecvDeviceCreatePipelineLayout(
RawId aSelfId, const SerialPipelineLayoutDescriptor& aDesc, RawId aNewId);
ipc::IPCResult RecvPipelineLayoutDestroy(RawId aSelfId);
ipc::IPCResult RecvDeviceCreateBindGroup(
RawId aSelfId, const SerialBindGroupDescriptor& aDesc, RawId aNewId);
ipc::IPCResult RecvBindGroupDestroy(RawId aSelfId);
ipc::IPCResult RecvDeviceCreateShaderModule(RawId aSelfId,
const nsTArray<uint32_t>& aData,
RawId aNewId);
ipc::IPCResult RecvShaderModuleDestroy(RawId aSelfId);
ipc::IPCResult RecvDeviceCreateComputePipeline(
RawId aSelfId, const SerialComputePipelineDescriptor& aDesc,
RawId aNewId);
ipc::IPCResult RecvComputePipelineDestroy(RawId aSelfId);
ipc::IPCResult RecvShutdown();
private:

View File

@ -9,14 +9,17 @@
#include "WebGPUTypes.h"
#include "ipc/IPCMessageUtils.h"
#include "mozilla/dom/WebGPUBinding.h"
#include "mozilla/webgpu/ffi/wgpu.h"
namespace IPC {
#define DEFINE_IPC_SERIALIZER_ENUM(something) \
template <> \
struct ParamTraits<something> \
: public ContiguousEnumSerializer<something, something(0), \
something::EndGuard_> {}
#define DEFINE_IPC_SERIALIZER_ENUM_GUARD(something, guard) \
template <> \
struct ParamTraits<something> \
: public ContiguousEnumSerializer<something, something(0), guard> {}
#define DEFINE_IPC_SERIALIZER_ENUM(something) \
DEFINE_IPC_SERIALIZER_ENUM_GUARD(something, something::EndGuard_)
DEFINE_IPC_SERIALIZER_ENUM(mozilla::dom::GPUPowerPreference);
@ -32,7 +35,35 @@ DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::dom::GPUBufferDescriptor, mSize,
DEFINE_IPC_SERIALIZER_WITHOUT_FIELDS(mozilla::dom::GPUCommandEncoderDescriptor);
DEFINE_IPC_SERIALIZER_WITHOUT_FIELDS(mozilla::dom::GPUCommandBufferDescriptor);
// TODO: have the enum sentinels generated by `cbindgen` when it supports them
// see https://github.com/eqrion/cbindgen/issues/458
DEFINE_IPC_SERIALIZER_ENUM_GUARD(
mozilla::webgpu::ffi::WGPUBindingType,
mozilla::webgpu::ffi::WGPUBindingType_StorageTexture);
DEFINE_IPC_SERIALIZER_ENUM_GUARD(
mozilla::webgpu::ffi::WGPUTextureViewDimension,
mozilla::webgpu::ffi::WGPUTextureViewDimension_D3);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(
mozilla::webgpu::ffi::WGPUBindGroupLayoutBinding, binding, visibility, ty,
texture_dimension, multisampled, dynamic);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(
mozilla::webgpu::SerialBindGroupLayoutDescriptor, mBindings);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(
mozilla::webgpu::SerialPipelineLayoutDescriptor, mBindGroupLayouts);
DEFINE_IPC_SERIALIZER_ENUM(mozilla::webgpu::SerialBindGroupBindingType);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::webgpu::SerialBindGroupBinding,
mBinding, mType, mValue, mBufferOffset,
mBufferSize);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(mozilla::webgpu::SerialBindGroupDescriptor,
mLayout, mBindings);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(
mozilla::webgpu::SerialProgrammableStageDescriptor, mModule, mEntryPoint);
DEFINE_IPC_SERIALIZER_WITH_FIELDS(
mozilla::webgpu::SerialComputePipelineDescriptor, mLayout, mComputeStage);
#undef DEFINE_IPC_SERIALIZER_ENUM
#undef DEFINE_IPC_SERIALIZER_ENUM_GUARD
} // namespace IPC
#endif // WEBGPU_SERIALIZE_H_

View File

@ -7,15 +7,56 @@
#define WEBGPU_TYPES_H_
#include <cstdint>
#include "nsTArray.h"
namespace mozilla {
namespace webgpu {
namespace ffi {
struct WGPUBindGroupLayoutBinding;
} // namespace ffi
typedef uint64_t RawId;
typedef uint64_t BufferAddress;
} // namespace webgpu
struct SerialBindGroupLayoutDescriptor {
nsTArray<ffi::WGPUBindGroupLayoutBinding> mBindings;
};
struct SerialPipelineLayoutDescriptor {
nsTArray<RawId> mBindGroupLayouts;
};
enum class SerialBindGroupBindingType : uint8_t {
Buffer,
Texture,
Sampler,
EndGuard_
};
struct SerialBindGroupBinding {
uint32_t mBinding;
SerialBindGroupBindingType mType;
RawId mValue;
BufferAddress mBufferOffset;
BufferAddress mBufferSize;
};
struct SerialBindGroupDescriptor {
RawId mLayout;
nsTArray<SerialBindGroupBinding> mBindings;
};
struct SerialProgrammableStageDescriptor {
RawId mModule;
nsString mEntryPoint;
};
struct SerialComputePipelineDescriptor {
RawId mLayout;
SerialProgrammableStageDescriptor mComputeStage;
};
} // namespace webgpu
} // namespace mozilla
#endif // WEBGPU_TYPES_H_

View File

@ -115,12 +115,12 @@ interface GPUDevice {
//GPUTexture createTexture(GPUTextureDescriptor descriptor);
//GPUSampler createSampler(optional GPUSamplerDescriptor descriptor = {});
//GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
//GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
//GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
GPUBindGroupLayout createBindGroupLayout(GPUBindGroupLayoutDescriptor descriptor);
GPUPipelineLayout createPipelineLayout(GPUPipelineLayoutDescriptor descriptor);
GPUBindGroup createBindGroup(GPUBindGroupDescriptor descriptor);
//GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
//GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
GPUShaderModule createShaderModule(GPUShaderModuleDescriptor descriptor);
GPUComputePipeline createComputePipeline(GPUComputePipelineDescriptor descriptor);
//GPURenderPipeline createRenderPipeline(GPURenderPipelineDescriptor descriptor);
[NewObject]
@ -634,7 +634,7 @@ dictionary GPUPipelineDescriptorBase : GPUObjectDescriptorBase {
};
dictionary GPUProgrammableStageDescriptor {
required GPUShaderModule module_;
required GPUShaderModule module;
required DOMString entryPoint;
};
@ -764,7 +764,6 @@ interface GPUCommandEncoder {
[NewObject]
GPUComputePassEncoder beginComputePass(optional GPUComputePassDescriptor descriptor = {});
/*
void copyBufferToBuffer(
GPUBuffer source,
u64 sourceOffset,
@ -772,6 +771,7 @@ interface GPUCommandEncoder {
u64 destinationOffset,
u64 size);
/*
void copyBufferToTexture(
GPUBufferCopyView source,
GPUTextureCopyView destination,
@ -805,8 +805,8 @@ GPUCommandEncoder includes GPUObjectBase;
[Pref="dom.webgpu.enabled",
Exposed=Window]
interface GPUProgrammablePassEncoder {
//void setBindGroup(u32 index, GPUBindGroup bindGroup,
// optional sequence<u64> dynamicOffsets);
void setBindGroup(unsigned long index, GPUBindGroup bindGroup,
optional sequence<unsigned long> dynamicOffsets = []);
//void pushDebugGroup(DOMString groupLabel);
//void popDebugGroup();
@ -856,7 +856,7 @@ dictionary GPUComputePassDescriptor : GPUObjectDescriptorBase {
[Pref="dom.webgpu.enabled",
Exposed=Window]
interface GPUComputePassEncoder : GPUProgrammablePassEncoder {
//void setPipeline(GPUComputePipeline pipeline);
void setPipeline(GPUComputePipeline pipeline);
void dispatch(u32 x, optional u32 y = 1, optional u32 z = 1);
//void dispatchIndirect(GPUBuffer indirectBuffer, u64 indirectOffset);

View File

@ -413,6 +413,8 @@ typedef WGPURawPass *WGPUComputePassId;
typedef const char *WGPURawString;
typedef uint32_t WGPUDynamicOffset;
typedef uint64_t WGPUId_ComputePipeline_Dummy;
typedef WGPUId_ComputePipeline_Dummy WGPUComputePipelineId;
@ -502,8 +504,8 @@ typedef uint32_t WGPUBufferUsage;
#define WGPUBufferUsage_VERTEX 32
#define WGPUBufferUsage_UNIFORM 64
#define WGPUBufferUsage_STORAGE 128
#define WGPUBufferUsage_STORAGE_READ 256
#define WGPUBufferUsage_INDIRECT 512
#define WGPUBufferUsage_INDIRECT 256
#define WGPUBufferUsage_STORAGE_READ 512
#define WGPUBufferUsage_NONE 0
typedef struct {
@ -788,7 +790,7 @@ void wgpu_compute_pass_push_debug_group(WGPURawPass *_pass, WGPURawString _label
void wgpu_compute_pass_set_bind_group(WGPURawPass *pass,
uint32_t index,
WGPUBindGroupId bind_group_id,
const WGPUBufferAddress *offsets,
const WGPUDynamicOffset *offsets,
uintptr_t offset_length);
void wgpu_compute_pass_set_pipeline(WGPURawPass *pass, WGPUComputePipelineId pipeline_id);
@ -888,7 +890,7 @@ void wgpu_render_pass_push_debug_group(WGPURawRenderPass *_pass, WGPURawString _
void wgpu_render_pass_set_bind_group(WGPURawRenderPass *pass,
uint32_t index,
WGPUBindGroupId bind_group_id,
const WGPUBufferAddress *offsets,
const WGPUDynamicOffset *offsets,
uintptr_t offset_length);
void wgpu_render_pass_set_blend_color(WGPURawRenderPass *pass, const WGPUColor *color);

View File

@ -6,7 +6,7 @@ use crate::{
binding_model::BindGroup,
hub::GfxBackend,
id::{BindGroupId, BindGroupLayoutId, PipelineLayoutId},
BufferAddress,
DynamicOffset,
Stored,
};
@ -26,7 +26,7 @@ pub struct BindGroupPair {
#[derive(Debug)]
pub enum LayoutChange<'a> {
Unchanged,
Match(BindGroupId, &'a [BufferAddress]),
Match(BindGroupId, &'a [DynamicOffset]),
Mismatch,
}
@ -41,7 +41,7 @@ pub struct FollowUpIter<'a> {
iter: slice::Iter<'a, BindGroupEntry>,
}
impl<'a> Iterator for FollowUpIter<'a> {
type Item = (BindGroupId, &'a [BufferAddress]);
type Item = (BindGroupId, &'a [DynamicOffset]);
fn next(&mut self) -> Option<Self::Item> {
self.iter
.next()
@ -58,7 +58,7 @@ impl<'a> Iterator for FollowUpIter<'a> {
pub struct BindGroupEntry {
expected_layout_id: Option<BindGroupLayoutId>,
provided: Option<BindGroupPair>,
dynamic_offsets: Vec<BufferAddress>,
dynamic_offsets: Vec<DynamicOffset>,
}
impl BindGroupEntry {
@ -66,7 +66,7 @@ impl BindGroupEntry {
&mut self,
bind_group_id: BindGroupId,
bind_group: &BindGroup<B>,
offsets: &[BufferAddress],
offsets: &[DynamicOffset],
) -> Provision {
debug_assert_eq!(B::VARIANT, bind_group_id.backend());
@ -167,7 +167,7 @@ impl Binder {
index: usize,
bind_group_id: BindGroupId,
bind_group: &BindGroup<B>,
offsets: &[BufferAddress],
offsets: &[DynamicOffset],
) -> Option<(PipelineLayoutId, FollowUpIter<'a>)> {
log::trace!("\tBinding [{}] = group {:?}", index, bind_group_id);
debug_assert_eq!(B::VARIANT, bind_group_id.backend());

View File

@ -13,6 +13,7 @@ use crate::{
id,
resource::BufferUsage,
BufferAddress,
DynamicOffset,
};
use hal::command::CommandBuffer as _;
@ -27,7 +28,7 @@ enum ComputeCommand {
index: u8,
num_dynamic_offsets: u8,
bind_group_id: id::BindGroupId,
phantom_offsets: PhantomSlice<BufferAddress>,
phantom_offsets: PhantomSlice<DynamicOffset>,
},
SetPipeline(id::ComputePipelineId),
Dispatch([u32; 3]),
@ -95,7 +96,7 @@ impl<F> Global<F> {
if cfg!(debug_assertions) {
for off in offsets {
assert_eq!(
*off % BIND_BUFFER_ALIGNMENT,
*off as BufferAddress % BIND_BUFFER_ALIGNMENT,
0,
"Misaligned dynamic buffer offset: {} does not align with {}",
off,
@ -222,6 +223,7 @@ pub mod compute_ffi {
use crate::{
id,
BufferAddress,
DynamicOffset,
RawString,
};
use std::{convert::TryInto, slice};
@ -231,7 +233,7 @@ pub mod compute_ffi {
pass: &mut RawPass,
index: u32,
bind_group_id: id::BindGroupId,
offsets: *const BufferAddress,
offsets: *const DynamicOffset,
offset_length: usize,
) {
pass.encode(&ComputeCommand::SetBindGroup {

View File

@ -24,6 +24,7 @@ use crate::{
track::TrackerSet,
BufferAddress,
Color,
DynamicOffset,
Stored,
};
@ -106,7 +107,7 @@ enum RenderCommand {
index: u8,
num_dynamic_offsets: u8,
bind_group_id: id::BindGroupId,
phantom_offsets: PhantomSlice<BufferAddress>,
phantom_offsets: PhantomSlice<DynamicOffset>,
},
SetPipeline(id::RenderPipelineId),
SetIndexBuffer {
@ -798,7 +799,7 @@ impl<F> Global<F> {
if cfg!(debug_assertions) {
for off in offsets {
assert_eq!(
*off % BIND_BUFFER_ALIGNMENT,
*off as BufferAddress % BIND_BUFFER_ALIGNMENT,
0,
"Misaligned dynamic buffer offset: {} does not align with {}",
off,
@ -1124,6 +1125,7 @@ pub mod render_ffi {
id,
BufferAddress,
Color,
DynamicOffset,
RawString,
};
use std::{convert::TryInto, slice};
@ -1133,7 +1135,7 @@ pub mod render_ffi {
pass: &mut RawRenderPass,
index: u32,
bind_group_id: id::BindGroupId,
offsets: *const BufferAddress,
offsets: *const DynamicOffset,
offset_length: usize,
) {
pass.raw.encode(&RenderCommand::SetBindGroup {

View File

@ -498,6 +498,8 @@ impl<F: IdentityFilter<id::BufferId>> Global<F> {
let hub = B::hub(self);
let mut token = Token::root();
log::info!("Create buffer {:?} with ID {:?}", desc, id_in);
let (device_guard, mut token) = hub.devices.read(&mut token);
let device = &device_guard[device_id];
let buffer = device.create_buffer(device_id, desc);
@ -884,14 +886,16 @@ impl<F: IdentityFilter<id::BindGroupLayoutId>> Global<F> {
.map(|b| (b.binding, b))
.collect();
{
let (bind_group_layout_guard, _) = hub.bind_group_layouts.read(&mut token);
let bind_group_layout =
bind_group_layout_guard
.iter(device_id.backend())
.find(|(_, bgl)| bgl.bindings == bindings_map);
// TODO: deduplicate the bind group layouts at some level.
// We can't do it right here, because in the remote scenario
// the client need to know if the same ID can be used, or not.
if false {
let (bgl_guard, _) = hub.bind_group_layouts.read(&mut token);
let bind_group_layout_id = bgl_guard
.iter(device_id.backend())
.find(|(_, bgl)| bgl.bindings == bindings_map);
if let Some((id, _)) = bind_group_layout {
if let Some((id, _)) = bind_group_layout_id {
return id;
}
}
@ -925,6 +929,13 @@ impl<F: IdentityFilter<id::BindGroupLayoutId>> Global<F> {
hub.bind_group_layouts
.register_identity(id_in, layout, &mut token)
}
pub fn bind_group_layout_destroy<B: GfxBackend>(&self, bind_group_layout_id: id::BindGroupLayoutId) {
let hub = B::hub(self);
let mut token = Token::root();
//TODO: track usage by GPU
hub.bind_group_layouts.unregister(bind_group_layout_id, &mut token);
}
}
impl<F: IdentityFilter<id::PipelineLayoutId>> Global<F> {
@ -967,6 +978,13 @@ impl<F: IdentityFilter<id::PipelineLayoutId>> Global<F> {
hub.pipeline_layouts
.register_identity(id_in, layout, &mut token)
}
pub fn pipeline_layout_destroy<B: GfxBackend>(&self, pipeline_layout_id: id::PipelineLayoutId) {
let hub = B::hub(self);
let mut token = Token::root();
//TODO: track usage by GPU
hub.pipeline_layouts.unregister(pipeline_layout_id, &mut token);
}
}
impl<F: IdentityFilter<id::BindGroupId>> Global<F> {
@ -1200,6 +1218,13 @@ impl<F: IdentityFilter<id::ShaderModuleId>> Global<F> {
hub.shader_modules
.register_identity(id_in, shader, &mut token)
}
pub fn shader_module_destroy<B: GfxBackend>(&self, shader_module_id: id::ShaderModuleId) {
let hub = B::hub(self);
let mut token = Token::root();
//TODO: track usage by GPU
hub.shader_modules.unregister(shader_module_id, &mut token);
}
}
impl<F: IdentityFilter<id::CommandEncoderId>> Global<F> {
@ -1718,6 +1743,13 @@ impl<F: IdentityFilter<id::RenderPipelineId>> Global<F> {
hub.render_pipelines
.register_identity(id_in, pipeline, &mut token)
}
pub fn render_pipeline_destroy<B: GfxBackend>(&self, render_pipeline_id: id::RenderPipelineId) {
let hub = B::hub(self);
let mut token = Token::root();
//TODO: track usage by GPU
hub.render_pipelines.unregister(render_pipeline_id, &mut token);
}
}
impl<F: IdentityFilter<id::ComputePipelineId>> Global<F> {
@ -1773,6 +1805,13 @@ impl<F: IdentityFilter<id::ComputePipelineId>> Global<F> {
hub.compute_pipelines
.register_identity(id_in, pipeline, &mut token)
}
pub fn compute_pipeline_destroy<B: GfxBackend>(&self, compute_pipeline_id: id::ComputePipelineId) {
let hub = B::hub(self);
let mut token = Token::root();
//TODO: track usage by GPU
hub.compute_pipelines.unregister(compute_pipeline_id, &mut token);
}
}
fn validate_swap_chain_descriptor(

View File

@ -39,7 +39,7 @@ use vec_map::VecMap;
#[cfg(debug_assertions)]
use std::cell::Cell;
use std::{marker::PhantomData, ops};
use std::{fmt::Debug, marker::PhantomData, ops};
/// A simple structure to manage identities of objects.
@ -251,13 +251,13 @@ impl<'a, T> Drop for Token<'a, T> {
}
pub trait IdentityFilter<I> {
type Input: Clone;
pub trait IdentityFilter<I>: Debug {
type Input: Clone + Debug;
fn process(&self, id: Self::Input, backend: Backend) -> I;
fn free(&self, id: I);
}
impl<I: TypedId + Clone> IdentityFilter<I> for () {
impl<I: TypedId + Clone + Debug> IdentityFilter<I> for () {
type Input = I;
fn process(&self, id: I, _backend: Backend) -> I {
//debug_assert_eq!(id.unzip().2, backend);
@ -266,7 +266,7 @@ impl<I: TypedId + Clone> IdentityFilter<I> for () {
fn free(&self, _id: I) {}
}
impl<I: TypedId> IdentityFilter<I> for Mutex<IdentityManager> {
impl<I: TypedId + Debug> IdentityFilter<I> for Mutex<IdentityManager> {
type Input = PhantomData<I>;
fn process(&self, _id: Self::Input, backend: Backend) -> I {
self.lock().alloc(backend)

View File

@ -55,6 +55,7 @@ pub enum Backend {
}
pub type BufferAddress = u64;
pub type DynamicOffset = u32;
pub type RawString = *const c_char;
//TODO: make it private. Currently used for swapchain creation impl.

View File

@ -32,8 +32,8 @@ bitflags::bitflags! {
const VERTEX = 32;
const UNIFORM = 64;
const STORAGE = 128;
const STORAGE_READ = 256;
const INDIRECT = 512;
const INDIRECT = 256;
const STORAGE_READ = 512;
const NONE = 0;
/// The combination of all read-only usages.
const READ_ALL = Self::MAP_READ.bits | Self::COPY_SRC.bits |

View File

@ -27,6 +27,11 @@ struct IdentityHub {
devices: IdentityManager,
buffers: IdentityManager,
command_buffers: IdentityManager,
bind_group_layouts: IdentityManager,
pipeline_layouts: IdentityManager,
bind_groups: IdentityManager,
shader_modules: IdentityManager,
compute_pipelines: IdentityManager,
}
#[derive(Debug, Default)]
@ -200,3 +205,138 @@ pub unsafe extern "C" fn wgpu_command_encoder_begin_compute_pass(
pub unsafe extern "C" fn wgpu_compute_pass_destroy(pass: core::command::RawPass) {
let _ = pass.into_vec();
}
#[no_mangle]
pub extern "C" fn wgpu_client_make_bind_group_layout_id(
client: &Client,
device_id: id::DeviceId,
) -> id::BindGroupLayoutId {
let backend = device_id.backend();
client
.identities
.lock()
.select(backend)
.bind_group_layouts
.alloc(backend)
}
#[no_mangle]
pub extern "C" fn wgpu_client_kill_bind_group_layout_id(
client: &Client,
id: id::BindGroupLayoutId,
) {
client
.identities
.lock()
.select(id.backend())
.bind_group_layouts
.free(id)
}
#[no_mangle]
pub extern "C" fn wgpu_client_make_pipeline_layout_id(
client: &Client,
device_id: id::DeviceId,
) -> id::PipelineLayoutId {
let backend = device_id.backend();
client
.identities
.lock()
.select(backend)
.pipeline_layouts
.alloc(backend)
}
#[no_mangle]
pub extern "C" fn wgpu_client_kill_pipeline_layout_id(
client: &Client,
id: id::PipelineLayoutId,
) {
client
.identities
.lock()
.select(id.backend())
.pipeline_layouts
.free(id)
}
#[no_mangle]
pub extern "C" fn wgpu_client_make_bind_group_id(
client: &Client,
device_id: id::DeviceId,
) -> id::BindGroupId {
let backend = device_id.backend();
client
.identities
.lock()
.select(backend)
.bind_groups
.alloc(backend)
}
#[no_mangle]
pub extern "C" fn wgpu_client_kill_bind_group_id(
client: &Client,
id: id::BindGroupId,
) {
client
.identities
.lock()
.select(id.backend())
.bind_groups
.free(id)
}
#[no_mangle]
pub extern "C" fn wgpu_client_make_shader_module_id(
client: &Client,
device_id: id::DeviceId,
) -> id::ShaderModuleId {
let backend = device_id.backend();
client
.identities
.lock()
.select(backend)
.shader_modules
.alloc(backend)
}
#[no_mangle]
pub extern "C" fn wgpu_client_kill_shader_module_id(
client: &Client,
id: id::ShaderModuleId,
) {
client
.identities
.lock()
.select(id.backend())
.shader_modules
.free(id)
}
#[no_mangle]
pub extern "C" fn wgpu_client_make_compute_pipeline_id(
client: &Client,
device_id: id::DeviceId,
) -> id::ComputePipelineId {
let backend = device_id.backend();
client
.identities
.lock()
.select(backend)
.compute_pipelines
.alloc(backend)
}
#[no_mangle]
pub extern "C" fn wgpu_client_kill_compute_pipeline_id(
client: &Client,
id: id::ComputePipelineId,
) {
client
.identities
.lock()
.select(id.backend())
.compute_pipelines
.free(id)
}

View File

@ -127,9 +127,9 @@ pub extern "C" fn wgpu_server_device_create_encoder(
global: &Global,
self_id: id::DeviceId,
desc: &core::command::CommandEncoderDescriptor,
encoder_id: id::CommandEncoderId,
new_id: id::CommandEncoderId,
) {
gfx_select!(self_id => global.device_create_command_encoder(self_id, &desc, encoder_id));
gfx_select!(self_id => global.device_create_command_encoder(self_id, &desc, new_id));
}
#[no_mangle]
@ -157,6 +157,19 @@ pub extern "C" fn wgpu_server_command_buffer_destroy(
gfx_select!(self_id => global.command_buffer_destroy(self_id));
}
#[no_mangle]
pub unsafe extern "C" fn wgpu_server_encoder_copy_buffer_to_buffer(
global: &Global,
self_id: id::CommandEncoderId,
source_id: id::BufferId,
source_offset: core::BufferAddress,
destination_id: id::BufferId,
destination_offset: core::BufferAddress,
size: core::BufferAddress,
) {
gfx_select!(self_id => global.command_encoder_copy_buffer_to_buffer(self_id, source_id, source_offset, destination_id, destination_offset, size));
}
#[no_mangle]
pub unsafe extern "C" fn wgpu_server_encode_compute_pass(
global: &Global,
@ -193,3 +206,93 @@ pub unsafe extern "C" fn wgpu_server_queue_submit(
let command_buffers = slice::from_raw_parts(command_buffer_ids, command_buffer_id_length);
gfx_select!(self_id => global.queue_submit(self_id, command_buffers));
}
#[no_mangle]
pub extern "C" fn wgpu_server_device_create_bind_group_layout(
global: &Global,
self_id: id::DeviceId,
desc: &core::binding_model::BindGroupLayoutDescriptor,
new_id: id::BindGroupLayoutId,
) {
gfx_select!(self_id => global.device_create_bind_group_layout(self_id, desc, new_id));
}
#[no_mangle]
pub extern "C" fn wgpu_server_bind_group_layout_destroy(
global: &Global,
self_id: id::BindGroupLayoutId,
) {
gfx_select!(self_id => global.bind_group_layout_destroy(self_id));
}
#[no_mangle]
pub extern "C" fn wgpu_server_device_create_pipeline_layout(
global: &Global,
self_id: id::DeviceId,
desc: &core::binding_model::PipelineLayoutDescriptor,
new_id: id::PipelineLayoutId,
) {
gfx_select!(self_id => global.device_create_pipeline_layout(self_id, desc, new_id));
}
#[no_mangle]
pub extern "C" fn wgpu_server_pipeline_layout_destroy(
global: &Global,
self_id: id::PipelineLayoutId,
) {
gfx_select!(self_id => global.pipeline_layout_destroy(self_id));
}
#[no_mangle]
pub extern "C" fn wgpu_server_device_create_bind_group(
global: &Global,
self_id: id::DeviceId,
desc: &core::binding_model::BindGroupDescriptor,
new_id: id::BindGroupId,
) {
gfx_select!(self_id => global.device_create_bind_group(self_id, desc, new_id));
}
#[no_mangle]
pub extern "C" fn wgpu_server_bind_group_destroy(
global: &Global,
self_id: id::BindGroupId,
) {
gfx_select!(self_id => global.bind_group_destroy(self_id));
}
#[no_mangle]
pub extern "C" fn wgpu_server_device_create_shader_module(
global: &Global,
self_id: id::DeviceId,
desc: &core::pipeline::ShaderModuleDescriptor,
new_id: id::ShaderModuleId,
) {
gfx_select!(self_id => global.device_create_shader_module(self_id, desc, new_id));
}
#[no_mangle]
pub extern "C" fn wgpu_server_shader_module_destroy(
global: &Global,
self_id: id::ShaderModuleId,
) {
gfx_select!(self_id => global.shader_module_destroy(self_id));
}
#[no_mangle]
pub extern "C" fn wgpu_server_device_create_compute_pipeline(
global: &Global,
self_id: id::DeviceId,
desc: &core::pipeline::ComputePipelineDescriptor,
new_id: id::ComputePipelineId,
) {
gfx_select!(self_id => global.device_create_compute_pipeline(self_id, desc, new_id));
}
#[no_mangle]
pub extern "C" fn wgpu_server_compute_pipeline_destroy(
global: &Global,
self_id: id::ComputePipelineId,
) {
gfx_select!(self_id => global.compute_pipeline_destroy(self_id));
}