diff options
Diffstat (limited to 'dom/webgpu/CommandEncoder.cpp')
-rw-r--r-- | dom/webgpu/CommandEncoder.cpp | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/dom/webgpu/CommandEncoder.cpp b/dom/webgpu/CommandEncoder.cpp new file mode 100644 index 0000000000..c10e80580d --- /dev/null +++ b/dom/webgpu/CommandEncoder.cpp @@ -0,0 +1,220 @@ +/* -*- Mode: C++; tab-width: 4; 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 "mozilla/dom/WebGPUBinding.h" +#include "CommandEncoder.h" + +#include "CommandBuffer.h" +#include "Buffer.h" +#include "ComputePassEncoder.h" +#include "Device.h" +#include "RenderPassEncoder.h" +#include "mozilla/dom/HTMLCanvasElement.h" +#include "mozilla/webgpu/ffi/wgpu.h" +#include "ipc/WebGPUChild.h" + +namespace mozilla { +namespace webgpu { + +GPU_IMPL_CYCLE_COLLECTION(CommandEncoder, mParent, mBridge) +GPU_IMPL_JS_WRAP(CommandEncoder) + +void CommandEncoder::ConvertTextureDataLayoutToFFI( + const dom::GPUTextureDataLayout& aLayout, + ffi::WGPUTextureDataLayout* aLayoutFFI) { + *aLayoutFFI = {}; + aLayoutFFI->offset = aLayout.mOffset; + aLayoutFFI->bytes_per_row = aLayout.mBytesPerRow; + aLayoutFFI->rows_per_image = aLayout.mRowsPerImage; +} + +void CommandEncoder::ConvertTextureCopyViewToFFI( + const dom::GPUTextureCopyView& aView, ffi::WGPUTextureCopyView* aViewFFI) { + *aViewFFI = {}; + aViewFFI->texture = aView.mTexture->mId; + aViewFFI->mip_level = aView.mMipLevel; + if (aView.mOrigin.WasPassed()) { + const auto& origin = aView.mOrigin.Value(); + if (origin.IsRangeEnforcedUnsignedLongSequence()) { + const auto& seq = origin.GetAsRangeEnforcedUnsignedLongSequence(); + aViewFFI->origin.x = seq.Length() > 0 ? seq[0] : 0; + aViewFFI->origin.y = seq.Length() > 1 ? seq[1] : 0; + aViewFFI->origin.z = seq.Length() > 2 ? seq[2] : 0; + } else if (origin.IsGPUOrigin3DDict()) { + const auto& dict = origin.GetAsGPUOrigin3DDict(); + aViewFFI->origin.x = dict.mX; + aViewFFI->origin.y = dict.mY; + aViewFFI->origin.z = dict.mZ; + } else { + MOZ_CRASH("Unexpected origin type"); + } + } +} + +void CommandEncoder::ConvertExtent3DToFFI(const dom::GPUExtent3D& aExtent, + ffi::WGPUExtent3d* aExtentFFI) { + *aExtentFFI = {}; + if (aExtent.IsRangeEnforcedUnsignedLongSequence()) { + const auto& seq = aExtent.GetAsRangeEnforcedUnsignedLongSequence(); + aExtentFFI->width = seq.Length() > 0 ? seq[0] : 0; + aExtentFFI->height = seq.Length() > 1 ? seq[1] : 0; + aExtentFFI->depth = seq.Length() > 2 ? seq[2] : 0; + } else if (aExtent.IsGPUExtent3DDict()) { + const auto& dict = aExtent.GetAsGPUExtent3DDict(); + aExtentFFI->width = dict.mWidth; + aExtentFFI->height = dict.mHeight; + aExtentFFI->depth = dict.mDepth; + } else { + MOZ_CRASH("Unexptected extent type"); + } +} + +static ffi::WGPUBufferCopyView ConvertBufferCopyView( + const dom::GPUBufferCopyView& aView) { + ffi::WGPUBufferCopyView view = {}; + view.buffer = aView.mBuffer->mId; + CommandEncoder::ConvertTextureDataLayoutToFFI(aView, &view.layout); + return view; +} + +static ffi::WGPUTextureCopyView ConvertTextureCopyView( + const dom::GPUTextureCopyView& aView) { + ffi::WGPUTextureCopyView view = {}; + CommandEncoder::ConvertTextureCopyViewToFFI(aView, &view); + return view; +} + +static ffi::WGPUExtent3d ConvertExtent(const dom::GPUExtent3D& aExtent) { + ffi::WGPUExtent3d extent = {}; + CommandEncoder::ConvertExtent3DToFFI(aExtent, &extent); + return extent; +} + +CommandEncoder::CommandEncoder(Device* const aParent, + WebGPUChild* const aBridge, RawId aId) + : ChildOf(aParent), mId(aId), mBridge(aBridge) {} + +CommandEncoder::~CommandEncoder() { Cleanup(); } + +void CommandEncoder::Cleanup() { + if (mValid && mParent) { + mValid = false; + auto bridge = mParent->GetBridge(); + if (bridge && bridge->IsOpen()) { + bridge->SendCommandEncoderDestroy(mId); + } + } +} + +void CommandEncoder::CopyBufferToBuffer(const Buffer& aSource, + BufferAddress aSourceOffset, + const Buffer& aDestination, + BufferAddress aDestinationOffset, + BufferAddress aSize) { + if (mValid) { + ipc::ByteBuf bb; + ffi::wgpu_command_encoder_copy_buffer_to_buffer( + aSource.mId, aSourceOffset, aDestination.mId, aDestinationOffset, aSize, + ToFFI(&bb)); + mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb)); + } +} + +void CommandEncoder::CopyBufferToTexture( + const dom::GPUBufferCopyView& aSource, + const dom::GPUTextureCopyView& aDestination, + const dom::GPUExtent3D& aCopySize) { + if (mValid) { + ipc::ByteBuf bb; + ffi::wgpu_command_encoder_copy_buffer_to_texture( + ConvertBufferCopyView(aSource), ConvertTextureCopyView(aDestination), + ConvertExtent(aCopySize), ToFFI(&bb)); + mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb)); + } +} +void CommandEncoder::CopyTextureToBuffer( + const dom::GPUTextureCopyView& aSource, + const dom::GPUBufferCopyView& aDestination, + const dom::GPUExtent3D& aCopySize) { + if (mValid) { + ipc::ByteBuf bb; + ffi::wgpu_command_encoder_copy_texture_to_buffer( + ConvertTextureCopyView(aSource), ConvertBufferCopyView(aDestination), + ConvertExtent(aCopySize), ToFFI(&bb)); + mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb)); + } +} +void CommandEncoder::CopyTextureToTexture( + const dom::GPUTextureCopyView& aSource, + const dom::GPUTextureCopyView& aDestination, + const dom::GPUExtent3D& aCopySize) { + if (mValid) { + ipc::ByteBuf bb; + ffi::wgpu_command_encoder_copy_texture_to_texture( + ConvertTextureCopyView(aSource), ConvertTextureCopyView(aDestination), + ConvertExtent(aCopySize), ToFFI(&bb)); + mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb)); + } +} + +already_AddRefed<ComputePassEncoder> CommandEncoder::BeginComputePass( + const dom::GPUComputePassDescriptor& aDesc) { + RefPtr<ComputePassEncoder> pass = new ComputePassEncoder(this, aDesc); + return pass.forget(); +} + +already_AddRefed<RenderPassEncoder> CommandEncoder::BeginRenderPass( + const dom::GPURenderPassDescriptor& aDesc) { + for (const auto& at : aDesc.mColorAttachments) { + auto* targetCanvasElement = at.mAttachment->GetTargetCanvasElement(); + if (targetCanvasElement) { + if (mTargetCanvasElement) { + NS_WARNING("Command encoder touches more than one canvas"); + } else { + mTargetCanvasElement = targetCanvasElement; + } + } + } + + RefPtr<RenderPassEncoder> pass = new RenderPassEncoder(this, aDesc); + return pass.forget(); +} + +void CommandEncoder::EndComputePass(ffi::WGPUComputePass& aPass, + ErrorResult& aRv) { + if (!mValid) { + return aRv.ThrowInvalidStateError("Command encoder is not valid"); + } + + ipc::ByteBuf byteBuf; + ffi::wgpu_compute_pass_finish(&aPass, ToFFI(&byteBuf)); + mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(byteBuf)); +} + +void CommandEncoder::EndRenderPass(ffi::WGPURenderPass& aPass, + ErrorResult& aRv) { + if (!mValid) { + return aRv.ThrowInvalidStateError("Command encoder is not valid"); + } + + ipc::ByteBuf byteBuf; + ffi::wgpu_render_pass_finish(&aPass, ToFFI(&byteBuf)); + mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(byteBuf)); +} + +already_AddRefed<CommandBuffer> CommandEncoder::Finish( + const dom::GPUCommandBufferDescriptor& aDesc) { + RawId id = 0; + if (mValid) { + mValid = false; + id = mBridge->CommandEncoderFinish(mId, mParent->mId, aDesc); + } + RefPtr<CommandBuffer> comb = + new CommandBuffer(mParent, id, mTargetCanvasElement); + return comb.forget(); +} + +} // namespace webgpu +} // namespace mozilla |