forked from mirrors/gecko-dev
This makes sure we never create an invalid (zero) ID after incorrect usage of a command encoder. It also simplifies the code. The JS object should not do any validaion (per spec) and simply forward the commands to the parent process where all of the validation is done. Differential Revision: https://phabricator.services.mozilla.com/D192839
248 lines
7.9 KiB
C++
248 lines
7.9 KiB
C++
/* -*- 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 "Utility.h"
|
|
#include "mozilla/webgpu/CanvasContext.h"
|
|
#include "mozilla/webgpu/ffi/wgpu.h"
|
|
#include "ipc/WebGPUChild.h"
|
|
|
|
namespace mozilla::webgpu {
|
|
|
|
GPU_IMPL_CYCLE_COLLECTION(CommandEncoder, mParent, mBridge)
|
|
GPU_IMPL_JS_WRAP(CommandEncoder)
|
|
|
|
void CommandEncoder::ConvertTextureDataLayoutToFFI(
|
|
const dom::GPUImageDataLayout& aLayout,
|
|
ffi::WGPUImageDataLayout* aLayoutFFI) {
|
|
*aLayoutFFI = {};
|
|
aLayoutFFI->offset = aLayout.mOffset;
|
|
|
|
if (aLayout.mBytesPerRow.WasPassed()) {
|
|
aLayoutFFI->bytes_per_row = &aLayout.mBytesPerRow.Value();
|
|
} else {
|
|
aLayoutFFI->bytes_per_row = nullptr;
|
|
}
|
|
|
|
if (aLayout.mRowsPerImage.WasPassed()) {
|
|
aLayoutFFI->rows_per_image = &aLayout.mRowsPerImage.Value();
|
|
} else {
|
|
aLayoutFFI->rows_per_image = nullptr;
|
|
}
|
|
}
|
|
|
|
void CommandEncoder::ConvertTextureCopyViewToFFI(
|
|
const dom::GPUImageCopyTexture& aCopy,
|
|
ffi::WGPUImageCopyTexture* aViewFFI) {
|
|
*aViewFFI = {};
|
|
aViewFFI->texture = aCopy.mTexture->mId;
|
|
aViewFFI->mip_level = aCopy.mMipLevel;
|
|
if (aCopy.mOrigin.WasPassed()) {
|
|
const auto& origin = aCopy.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");
|
|
}
|
|
}
|
|
}
|
|
|
|
static ffi::WGPUImageCopyTexture ConvertTextureCopyView(
|
|
const dom::GPUImageCopyTexture& aCopy) {
|
|
ffi::WGPUImageCopyTexture view = {};
|
|
CommandEncoder::ConvertTextureCopyViewToFFI(aCopy, &view);
|
|
return view;
|
|
}
|
|
|
|
CommandEncoder::CommandEncoder(Device* const aParent,
|
|
WebGPUChild* const aBridge, RawId aId)
|
|
: ChildOf(aParent), mId(aId), mBridge(aBridge) {
|
|
MOZ_RELEASE_ASSERT(aId);
|
|
}
|
|
|
|
CommandEncoder::~CommandEncoder() { Cleanup(); }
|
|
|
|
void CommandEncoder::Cleanup() {
|
|
if (!mValid) {
|
|
return;
|
|
}
|
|
mValid = false;
|
|
if (mBridge->IsOpen()) {
|
|
mBridge->SendCommandEncoderDrop(mId);
|
|
}
|
|
}
|
|
|
|
void CommandEncoder::CopyBufferToBuffer(const Buffer& aSource,
|
|
BufferAddress aSourceOffset,
|
|
const Buffer& aDestination,
|
|
BufferAddress aDestinationOffset,
|
|
BufferAddress aSize) {
|
|
if (!mBridge->IsOpen()) {
|
|
return;
|
|
}
|
|
|
|
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::GPUImageCopyBuffer& aSource,
|
|
const dom::GPUImageCopyTexture& aDestination,
|
|
const dom::GPUExtent3D& aCopySize) {
|
|
if (!mBridge->IsOpen()) {
|
|
return;
|
|
}
|
|
|
|
ipc::ByteBuf bb;
|
|
ffi::WGPUImageDataLayout src_layout = {};
|
|
CommandEncoder::ConvertTextureDataLayoutToFFI(aSource, &src_layout);
|
|
ffi::wgpu_command_encoder_copy_buffer_to_texture(
|
|
aSource.mBuffer->mId, &src_layout, ConvertTextureCopyView(aDestination),
|
|
ConvertExtent(aCopySize), ToFFI(&bb));
|
|
mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
|
|
|
|
const auto& targetContext = aDestination.mTexture->mTargetContext;
|
|
if (targetContext) {
|
|
mTargetContexts.AppendElement(targetContext);
|
|
}
|
|
}
|
|
void CommandEncoder::CopyTextureToBuffer(
|
|
const dom::GPUImageCopyTexture& aSource,
|
|
const dom::GPUImageCopyBuffer& aDestination,
|
|
const dom::GPUExtent3D& aCopySize) {
|
|
if (!mBridge->IsOpen()) {
|
|
return;
|
|
}
|
|
|
|
ipc::ByteBuf bb;
|
|
ffi::WGPUImageDataLayout dstLayout = {};
|
|
CommandEncoder::ConvertTextureDataLayoutToFFI(aDestination, &dstLayout);
|
|
ffi::wgpu_command_encoder_copy_texture_to_buffer(
|
|
ConvertTextureCopyView(aSource), aDestination.mBuffer->mId, &dstLayout,
|
|
ConvertExtent(aCopySize), ToFFI(&bb));
|
|
mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
|
|
}
|
|
void CommandEncoder::CopyTextureToTexture(
|
|
const dom::GPUImageCopyTexture& aSource,
|
|
const dom::GPUImageCopyTexture& aDestination,
|
|
const dom::GPUExtent3D& aCopySize) {
|
|
if (!mBridge->IsOpen()) {
|
|
return;
|
|
}
|
|
|
|
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));
|
|
|
|
const auto& targetContext = aDestination.mTexture->mTargetContext;
|
|
if (targetContext) {
|
|
mTargetContexts.AppendElement(targetContext);
|
|
}
|
|
}
|
|
|
|
void CommandEncoder::PushDebugGroup(const nsAString& aString) {
|
|
if (!mBridge->IsOpen()) {
|
|
return;
|
|
}
|
|
|
|
ipc::ByteBuf bb;
|
|
NS_ConvertUTF16toUTF8 marker(aString);
|
|
ffi::wgpu_command_encoder_push_debug_group(&marker, ToFFI(&bb));
|
|
mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
|
|
}
|
|
void CommandEncoder::PopDebugGroup() {
|
|
if (!mBridge->IsOpen()) {
|
|
return;
|
|
}
|
|
|
|
ipc::ByteBuf bb;
|
|
ffi::wgpu_command_encoder_pop_debug_group(ToFFI(&bb));
|
|
mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
|
|
}
|
|
void CommandEncoder::InsertDebugMarker(const nsAString& aString) {
|
|
if (!mBridge->IsOpen()) {
|
|
return;
|
|
}
|
|
|
|
ipc::ByteBuf bb;
|
|
NS_ConvertUTF16toUTF8 marker(aString);
|
|
ffi::wgpu_command_encoder_insert_debug_marker(&marker, 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* targetContext = at.mView->GetTargetContext();
|
|
if (targetContext) {
|
|
mTargetContexts.AppendElement(targetContext);
|
|
}
|
|
if (at.mResolveTarget.WasPassed()) {
|
|
targetContext = at.mResolveTarget.Value().GetTargetContext();
|
|
mTargetContexts.AppendElement(targetContext);
|
|
}
|
|
}
|
|
|
|
RefPtr<RenderPassEncoder> pass = new RenderPassEncoder(this, aDesc);
|
|
return pass.forget();
|
|
}
|
|
|
|
void CommandEncoder::EndComputePass(ffi::WGPUComputePass& aPass) {
|
|
if (!mBridge->IsOpen()) {
|
|
return;
|
|
}
|
|
|
|
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) {
|
|
if (!mBridge->IsOpen()) {
|
|
return;
|
|
}
|
|
|
|
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) {
|
|
// WebGPUChild::CommandEncoderFinish handles the case where the IPC channel
|
|
// closed.
|
|
RawId id = mBridge->CommandEncoderFinish(mId, mParent->mId, aDesc);
|
|
RefPtr<CommandBuffer> comb =
|
|
new CommandBuffer(mParent, id, std::move(mTargetContexts));
|
|
return comb.forget();
|
|
}
|
|
|
|
} // namespace mozilla::webgpu
|