Skip to content

Commit

Permalink
Bug 1602131 - WebGPU render passes r=jgilbert,webidl,smaug
Browse files Browse the repository at this point in the history
Adds support for recording render passes in WebGPU.
The `wgpu` logo is also added to the repository ("gfx/wgpu/logo.png") under [CC-BY-SA](https://creativecommons.org/licenses/by-sa/3.0/) license.

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

--HG--
extra : moz-landing-system : lando
  • Loading branch information
kvark committed Feb 19, 2020
1 parent c9f1371 commit 199a362
Show file tree
Hide file tree
Showing 29 changed files with 653 additions and 219 deletions.
23 changes: 23 additions & 0 deletions dom/webgpu/CommandEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "Buffer.h"
#include "ComputePassEncoder.h"
#include "Device.h"
#include "RenderPassEncoder.h"

namespace mozilla {
namespace webgpu {
Expand Down Expand Up @@ -51,6 +52,12 @@ already_AddRefed<ComputePassEncoder> CommandEncoder::BeginComputePass(
return pass.forget();
}

already_AddRefed<RenderPassEncoder> CommandEncoder::BeginRenderPass(
const dom::GPURenderPassDescriptor& aDesc) {
RefPtr<RenderPassEncoder> pass = new RenderPassEncoder(this, aDesc);
return pass.forget();
}

void CommandEncoder::EndComputePass(Span<const uint8_t> aData,
ErrorResult& aRv) {
if (!mValid) {
Expand All @@ -67,6 +74,22 @@ void CommandEncoder::EndComputePass(Span<const uint8_t> aData,
mBridge->SendCommandEncoderRunComputePass(mId, std::move(shmem));
}

void CommandEncoder::EndRenderPass(Span<const uint8_t> aData,
ErrorResult& aRv) {
if (!mValid) {
return aRv.ThrowInvalidStateError("Command encoder is not valid");
}
ipc::Shmem shmem;
if (!mBridge->AllocShmem(aData.Length(), ipc::Shmem::SharedMemory::TYPE_BASIC,
&shmem)) {
return aRv.ThrowAbortError(nsPrintfCString(
"Unable to allocate shmem of size %zu", aData.Length()));
}

memcpy(shmem.get<uint8_t>(), aData.data(), aData.Length());
mBridge->SendCommandEncoderRunRenderPass(mId, std::move(shmem));
}

already_AddRefed<CommandBuffer> CommandEncoder::Finish(
const dom::GPUCommandBufferDescriptor& aDesc) {
RawId id = 0;
Expand Down
3 changes: 3 additions & 0 deletions dom/webgpu/CommandEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,16 @@ class CommandEncoder final : public ObjectBase, public ChildOf<Device> {

public:
void EndComputePass(Span<const uint8_t> aData, ErrorResult& aRv);
void EndRenderPass(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<RenderPassEncoder> BeginRenderPass(
const dom::GPURenderPassDescriptor& aDesc);
already_AddRefed<CommandBuffer> Finish(
const dom::GPUCommandBufferDescriptor& aDesc);
};
Expand Down
167 changes: 165 additions & 2 deletions dom/webgpu/RenderPassEncoder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,184 @@

#include "mozilla/dom/WebGPUBinding.h"
#include "RenderPassEncoder.h"
#include "BindGroup.h"
#include "CommandEncoder.h"
#include "RenderPipeline.h"

namespace mozilla {
namespace webgpu {

GPU_IMPL_CYCLE_COLLECTION(RenderPassEncoder, mParent)
GPU_IMPL_JS_WRAP(RenderPassEncoder)

RenderPassEncoder::~RenderPassEncoder() = default;
ffi::WGPULoadOp ConvertLoadOp(const dom::GPULoadOp& aOp) {
switch (aOp) {
case dom::GPULoadOp::Load:
return ffi::WGPULoadOp_Load;
default:
MOZ_CRASH("Unexpected load op");
}
}

ffi::WGPUStoreOp ConvertStoreOp(const dom::GPUStoreOp& aOp) {
switch (aOp) {
case dom::GPUStoreOp::Store:
return ffi::WGPUStoreOp_Store;
case dom::GPUStoreOp::Clear:
return ffi::WGPUStoreOp_Clear;
default:
MOZ_CRASH("Unexpected load op");
}
}

ffi::WGPUColor ConvertColor(const dom::GPUColorDict& aColor) {
ffi::WGPUColor color = {aColor.mR, aColor.mG, aColor.mB, aColor.mA};
return color;
}

ffi::WGPURawPass BeginRenderPass(RawId aEncoderId,
const dom::GPURenderPassDescriptor& aDesc) {
ffi::WGPURenderPassDescriptor desc = {};

ffi::WGPURenderPassDepthStencilAttachmentDescriptor dsDesc = {};
if (aDesc.mDepthStencilAttachment.WasPassed()) {
const auto& dsa = aDesc.mDepthStencilAttachment.Value();
dsDesc.attachment = dsa.mAttachment->mId;

if (dsa.mDepthLoadValue.IsFloat()) {
dsDesc.depth_load_op = ffi::WGPULoadOp_Clear;
dsDesc.clear_depth = dsa.mDepthLoadValue.GetAsFloat();
}
if (dsa.mDepthLoadValue.IsGPULoadOp()) {
dsDesc.depth_load_op =
ConvertLoadOp(dsa.mDepthLoadValue.GetAsGPULoadOp());
}
dsDesc.depth_store_op = ConvertStoreOp(dsa.mDepthStoreOp);

if (dsa.mStencilLoadValue.IsUnsignedLong()) {
dsDesc.stencil_load_op = ffi::WGPULoadOp_Clear;
dsDesc.clear_stencil = dsa.mStencilLoadValue.GetAsUnsignedLong();
}
if (dsa.mStencilLoadValue.IsGPULoadOp()) {
dsDesc.stencil_load_op =
ConvertLoadOp(dsa.mStencilLoadValue.GetAsGPULoadOp());
}
dsDesc.stencil_store_op = ConvertStoreOp(dsa.mStencilStoreOp);

desc.depth_stencil_attachment = &dsDesc;
}

std::array<ffi::WGPURenderPassColorAttachmentDescriptor,
WGPUMAX_COLOR_TARGETS>
colorDescs = {};
desc.color_attachments = colorDescs.data();
for (size_t i = 0; i < aDesc.mColorAttachments.Length(); ++i) {
const auto& ca = aDesc.mColorAttachments[i];
ffi::WGPURenderPassColorAttachmentDescriptor& cd = colorDescs[i];
cd.attachment = ca.mAttachment->mId;
cd.store_op = ConvertStoreOp(ca.mStoreOp);

if (ca.mResolveTarget.WasPassed()) {
cd.resolve_target = &ca.mResolveTarget.Value().mId;
}
if (ca.mLoadValue.IsGPULoadOp()) {
cd.load_op = ConvertLoadOp(ca.mLoadValue.GetAsGPULoadOp());
} else {
cd.load_op = ffi::WGPULoadOp_Clear;
if (ca.mLoadValue.IsDoubleSequence()) {
const auto& seq = ca.mLoadValue.GetAsDoubleSequence();
if (seq.Length() >= 1) {
cd.clear_color.r = seq[0];
}
if (seq.Length() >= 2) {
cd.clear_color.g = seq[1];
}
if (seq.Length() >= 3) {
cd.clear_color.b = seq[2];
}
if (seq.Length() >= 4) {
cd.clear_color.a = seq[3];
}
}
if (ca.mLoadValue.IsGPUColorDict()) {
cd.clear_color =
ConvertColor(ca.mLoadValue.GetAsGPUColorDict());
}
}
}

return ffi::wgpu_command_encoder_begin_render_pass(aEncoderId, &desc);
}

RenderPassEncoder::RenderPassEncoder(CommandEncoder* const aParent,
const dom::GPURenderPassDescriptor& aDesc)
: ChildOf(aParent), mRaw(BeginRenderPass(aParent->mId, aDesc)) {}

RenderPassEncoder::~RenderPassEncoder() {
if (mValid) {
mValid = false;
ffi::wgpu_render_pass_destroy(mRaw);
}
}

void RenderPassEncoder::SetBindGroup(
uint32_t aSlot, const BindGroup& aBindGroup,
const dom::Sequence<uint32_t>& aDynamicOffsets) {
if (mValid) {
MOZ_CRASH("TODO");
ffi::wgpu_render_pass_set_bind_group(&mRaw, aSlot, aBindGroup.mId,
aDynamicOffsets.Elements(),
aDynamicOffsets.Length());
}
}

void RenderPassEncoder::SetPipeline(const RenderPipeline& aPipeline) {
if (mValid) {
ffi::wgpu_render_pass_set_pipeline(&mRaw, aPipeline.mId);
}
}

void RenderPassEncoder::SetIndexBuffer(const Buffer& aBuffer,
uint64_t aOffset) {
if (mValid) {
ffi::wgpu_render_pass_set_index_buffer(&mRaw, aBuffer.mId, aOffset);
}
}

void RenderPassEncoder::SetVertexBuffer(uint32_t aSlot, const Buffer& aBuffer,
uint64_t aOffset) {
if (mValid) {
// TODO: change the Rust API to use a single vertex buffer?
ffi::wgpu_render_pass_set_vertex_buffers(&mRaw, aSlot, &aBuffer.mId,
&aOffset, 1);
}
}

void RenderPassEncoder::Draw(uint32_t aVertexCount, uint32_t aInstanceCount,
uint32_t aFirstVertex, uint32_t aFirstInstance) {
if (mValid) {
ffi::wgpu_render_pass_draw(&mRaw, aVertexCount, aInstanceCount,
aFirstVertex, aFirstInstance);
}
}

void RenderPassEncoder::DrawIndexed(uint32_t aIndexCount,
uint32_t aInstanceCount,
uint32_t aFirstIndex, int32_t aBaseVertex,
uint32_t aFirstInstance) {
if (mValid) {
ffi::wgpu_render_pass_draw_indexed(&mRaw, aIndexCount, aInstanceCount,
aFirstIndex, aBaseVertex,
aFirstInstance);
}
}

void RenderPassEncoder::EndPass(ErrorResult& aRv) {
if (mValid) {
mValid = false;
uintptr_t length = 0;
const uint8_t* pass_data = ffi::wgpu_render_pass_finish(&mRaw, &length);
mParent->EndRenderPass(Span(pass_data, length), aRv);
ffi::wgpu_render_pass_destroy(mRaw);
}
}

Expand Down
15 changes: 14 additions & 1 deletion dom/webgpu/RenderPassEncoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,35 @@ namespace webgpu {

class CommandEncoder;
class RenderBundle;
class RenderPipeline;

class RenderPassEncoder final : public ObjectBase,
public ChildOf<CommandEncoder> {
public:
GPU_DECL_CYCLE_COLLECTION(RenderPassEncoder)
GPU_DECL_JS_WRAP(RenderPassEncoder)

RenderPassEncoder() = delete;
RenderPassEncoder(CommandEncoder* const aParent,
const dom::GPURenderPassDescriptor& aDesc);

protected:
virtual ~RenderPassEncoder();
void Cleanup() {}

ffi::WGPURawPass mRaw;

public:
void SetBindGroup(uint32_t aSlot, const BindGroup& aBindGroup,
const dom::Sequence<uint32_t>& aDynamicOffsets);
void SetPipeline(const RenderPipeline& aPipeline);
void SetIndexBuffer(const Buffer& aBuffer, uint64_t aOffset);
void SetVertexBuffer(uint32_t aSlot, const Buffer& aBuffer, uint64_t aOffset);
void Draw(uint32_t aVertexCount, uint32_t aInstanceCount,
uint32_t aFirstVertex, uint32_t aFirstInstance);
void DrawIndexed(uint32_t aIndexCount, uint32_t aInstanceCount,
uint32_t aFirstIndex, int32_t aBaseVertex,
uint32_t aFirstInstance);
void EndPass(ErrorResult& aRv);
};

} // namespace webgpu
Expand Down
15 changes: 14 additions & 1 deletion dom/webgpu/RenderPipeline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,20 @@ namespace webgpu {
GPU_IMPL_CYCLE_COLLECTION(RenderPipeline, mParent)
GPU_IMPL_JS_WRAP(RenderPipeline)

RenderPipeline::~RenderPipeline() = default;
RenderPipeline::RenderPipeline(Device* const aParent, RawId aId)
: ChildOf(aParent), mId(aId) {}

RenderPipeline::~RenderPipeline() { Cleanup(); }

void RenderPipeline::Cleanup() {
if (mValid && mParent) {
mValid = false;
WebGPUChild* bridge = mParent->mBridge;
if (bridge && bridge->IsOpen()) {
bridge->DestroyRenderPipeline(mId);
}
}
}

} // namespace webgpu
} // namespace mozilla
7 changes: 5 additions & 2 deletions dom/webgpu/RenderPipeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ class RenderPipeline final : public ObjectBase, public ChildOf<Device> {
GPU_DECL_CYCLE_COLLECTION(RenderPipeline)
GPU_DECL_JS_WRAP(RenderPipeline)

RenderPipeline(Device* const aParent, RawId aId);

const RawId mId;

private:
RenderPipeline() = delete;
virtual ~RenderPipeline();
void Cleanup() {}
void Cleanup();
};

} // namespace webgpu
Expand Down
2 changes: 2 additions & 0 deletions dom/webgpu/ipc/PWebGPU.ipdl
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ parent:
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 CommandEncoderRunRenderPass(RawId selfId, Shmem shmem);
async CommandEncoderFinish(RawId selfId, GPUCommandBufferDescriptor desc);
async CommandEncoderDestroy(RawId selfId);
async CommandBufferDestroy(RawId selfId);
Expand All @@ -59,6 +60,7 @@ parent:
async ShaderModuleDestroy(RawId selfId);
async DeviceCreateComputePipeline(RawId selfId, SerialComputePipelineDescriptor desc, RawId newId);
async ComputePipelineDestroy(RawId selfId);
async RenderPipelineDestroy(RawId selfId);
async Shutdown();

child:
Expand Down
4 changes: 4 additions & 0 deletions dom/webgpu/ipc/WebGPUChild.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ void WebGPUChild::DestroyComputePipeline(RawId aId) {
SendComputePipelineDestroy(aId);
ffi::wgpu_client_kill_compute_pipeline_id(mClient, aId);
}
void WebGPUChild::DestroyRenderPipeline(RawId aId) {
SendRenderPipelineDestroy(aId);
ffi::wgpu_client_kill_render_pipeline_id(mClient, aId);
}

} // namespace webgpu
} // namespace mozilla
1 change: 1 addition & 0 deletions dom/webgpu/ipc/WebGPUChild.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class WebGPUChild final : public PWebGPUChild {
void DestroyBindGroup(RawId aId);
void DestroyShaderModule(RawId aId);
void DestroyComputePipeline(RawId aId);
void DestroyRenderPipeline(RawId aId);

private:
virtual ~WebGPUChild();
Expand Down
12 changes: 12 additions & 0 deletions dom/webgpu/ipc/WebGPUParent.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,13 @@ ipc::IPCResult WebGPUParent::RecvCommandEncoderRunComputePass(RawId aSelfId,
return IPC_OK();
}

ipc::IPCResult WebGPUParent::RecvCommandEncoderRunRenderPass(RawId aSelfId,
Shmem&& shmem) {
ffi::wgpu_server_encode_render_pass(mContext, aSelfId, shmem.get<uint8_t>(),
shmem.Size<uint8_t>());
return IPC_OK();
}

ipc::IPCResult WebGPUParent::RecvCommandEncoderFinish(
RawId aSelfId, const dom::GPUCommandBufferDescriptor& aDesc) {
Unused << aDesc;
Expand Down Expand Up @@ -272,6 +279,11 @@ ipc::IPCResult WebGPUParent::RecvComputePipelineDestroy(RawId aSelfId) {
return IPC_OK();
}

ipc::IPCResult WebGPUParent::RecvRenderPipelineDestroy(RawId aSelfId) {
ffi::wgpu_server_render_pipeline_destroy(mContext, aSelfId);
return IPC_OK();
}

ipc::IPCResult WebGPUParent::RecvShutdown() {
mTimer.Stop();
ffi::wgpu_server_poll_all_devices(mContext, true);
Expand Down
2 changes: 2 additions & 0 deletions dom/webgpu/ipc/WebGPUParent.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class WebGPUParent final : public PWebGPUParent {
RawId aDestinationId, BufferAddress aDestinationOffset,
BufferAddress aSize);
ipc::IPCResult RecvCommandEncoderRunComputePass(RawId aSelfId, Shmem&& shmem);
ipc::IPCResult RecvCommandEncoderRunRenderPass(RawId aSelfId, Shmem&& shmem);
ipc::IPCResult RecvCommandEncoderFinish(
RawId aSelfId, const dom::GPUCommandBufferDescriptor& aDesc);
ipc::IPCResult RecvCommandEncoderDestroy(RawId aSelfId);
Expand All @@ -71,6 +72,7 @@ class WebGPUParent final : public PWebGPUParent {
RawId aSelfId, const SerialComputePipelineDescriptor& aDesc,
RawId aNewId);
ipc::IPCResult RecvComputePipelineDestroy(RawId aSelfId);
ipc::IPCResult RecvRenderPipelineDestroy(RawId aSelfId);
ipc::IPCResult RecvShutdown();

private:
Expand Down
Loading

0 comments on commit 199a362

Please sign in to comment.