Bug 1863873 - Block ability to perform audio decoding outside of Utility on release...
[gecko.git] / dom / webgpu / CommandEncoder.cpp
blob15d95401d41fa773c55619eaf483442f51e2bbd6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/dom/WebGPUBinding.h"
7 #include "CommandEncoder.h"
9 #include "CommandBuffer.h"
10 #include "Buffer.h"
11 #include "ComputePassEncoder.h"
12 #include "Device.h"
13 #include "RenderPassEncoder.h"
14 #include "Utility.h"
15 #include "mozilla/webgpu/CanvasContext.h"
16 #include "mozilla/webgpu/ffi/wgpu.h"
17 #include "ipc/WebGPUChild.h"
19 namespace mozilla::webgpu {
21 GPU_IMPL_CYCLE_COLLECTION(CommandEncoder, mParent, mBridge)
22 GPU_IMPL_JS_WRAP(CommandEncoder)
24 void CommandEncoder::ConvertTextureDataLayoutToFFI(
25 const dom::GPUImageDataLayout& aLayout,
26 ffi::WGPUImageDataLayout* aLayoutFFI) {
27 *aLayoutFFI = {};
28 aLayoutFFI->offset = aLayout.mOffset;
30 if (aLayout.mBytesPerRow.WasPassed()) {
31 aLayoutFFI->bytes_per_row = &aLayout.mBytesPerRow.Value();
32 } else {
33 aLayoutFFI->bytes_per_row = nullptr;
36 if (aLayout.mRowsPerImage.WasPassed()) {
37 aLayoutFFI->rows_per_image = &aLayout.mRowsPerImage.Value();
38 } else {
39 aLayoutFFI->rows_per_image = nullptr;
43 void CommandEncoder::ConvertTextureCopyViewToFFI(
44 const dom::GPUImageCopyTexture& aCopy,
45 ffi::WGPUImageCopyTexture* aViewFFI) {
46 *aViewFFI = {};
47 aViewFFI->texture = aCopy.mTexture->mId;
48 aViewFFI->mip_level = aCopy.mMipLevel;
49 if (aCopy.mOrigin.WasPassed()) {
50 const auto& origin = aCopy.mOrigin.Value();
51 if (origin.IsRangeEnforcedUnsignedLongSequence()) {
52 const auto& seq = origin.GetAsRangeEnforcedUnsignedLongSequence();
53 aViewFFI->origin.x = seq.Length() > 0 ? seq[0] : 0;
54 aViewFFI->origin.y = seq.Length() > 1 ? seq[1] : 0;
55 aViewFFI->origin.z = seq.Length() > 2 ? seq[2] : 0;
56 } else if (origin.IsGPUOrigin3DDict()) {
57 const auto& dict = origin.GetAsGPUOrigin3DDict();
58 aViewFFI->origin.x = dict.mX;
59 aViewFFI->origin.y = dict.mY;
60 aViewFFI->origin.z = dict.mZ;
61 } else {
62 MOZ_CRASH("Unexpected origin type");
67 static ffi::WGPUImageCopyTexture ConvertTextureCopyView(
68 const dom::GPUImageCopyTexture& aCopy) {
69 ffi::WGPUImageCopyTexture view = {};
70 CommandEncoder::ConvertTextureCopyViewToFFI(aCopy, &view);
71 return view;
74 CommandEncoder::CommandEncoder(Device* const aParent,
75 WebGPUChild* const aBridge, RawId aId)
76 : ChildOf(aParent), mId(aId), mBridge(aBridge) {
77 MOZ_RELEASE_ASSERT(aId);
80 CommandEncoder::~CommandEncoder() { Cleanup(); }
82 void CommandEncoder::Cleanup() {
83 if (!mValid) {
84 return;
86 mValid = false;
87 if (mBridge->IsOpen()) {
88 mBridge->SendCommandEncoderDrop(mId);
92 void CommandEncoder::CopyBufferToBuffer(const Buffer& aSource,
93 BufferAddress aSourceOffset,
94 const Buffer& aDestination,
95 BufferAddress aDestinationOffset,
96 BufferAddress aSize) {
97 if (!mBridge->IsOpen()) {
98 return;
101 ipc::ByteBuf bb;
102 ffi::wgpu_command_encoder_copy_buffer_to_buffer(
103 aSource.mId, aSourceOffset, aDestination.mId, aDestinationOffset, aSize,
104 ToFFI(&bb));
105 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
108 void CommandEncoder::CopyBufferToTexture(
109 const dom::GPUImageCopyBuffer& aSource,
110 const dom::GPUImageCopyTexture& aDestination,
111 const dom::GPUExtent3D& aCopySize) {
112 if (!mBridge->IsOpen()) {
113 return;
116 ipc::ByteBuf bb;
117 ffi::WGPUImageDataLayout src_layout = {};
118 CommandEncoder::ConvertTextureDataLayoutToFFI(aSource, &src_layout);
119 ffi::wgpu_command_encoder_copy_buffer_to_texture(
120 aSource.mBuffer->mId, &src_layout, ConvertTextureCopyView(aDestination),
121 ConvertExtent(aCopySize), ToFFI(&bb));
122 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
124 const auto& targetContext = aDestination.mTexture->mTargetContext;
125 if (targetContext) {
126 mTargetContexts.AppendElement(targetContext);
129 void CommandEncoder::CopyTextureToBuffer(
130 const dom::GPUImageCopyTexture& aSource,
131 const dom::GPUImageCopyBuffer& aDestination,
132 const dom::GPUExtent3D& aCopySize) {
133 if (!mBridge->IsOpen()) {
134 return;
137 ipc::ByteBuf bb;
138 ffi::WGPUImageDataLayout dstLayout = {};
139 CommandEncoder::ConvertTextureDataLayoutToFFI(aDestination, &dstLayout);
140 ffi::wgpu_command_encoder_copy_texture_to_buffer(
141 ConvertTextureCopyView(aSource), aDestination.mBuffer->mId, &dstLayout,
142 ConvertExtent(aCopySize), ToFFI(&bb));
143 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
145 void CommandEncoder::CopyTextureToTexture(
146 const dom::GPUImageCopyTexture& aSource,
147 const dom::GPUImageCopyTexture& aDestination,
148 const dom::GPUExtent3D& aCopySize) {
149 if (!mBridge->IsOpen()) {
150 return;
153 ipc::ByteBuf bb;
154 ffi::wgpu_command_encoder_copy_texture_to_texture(
155 ConvertTextureCopyView(aSource), ConvertTextureCopyView(aDestination),
156 ConvertExtent(aCopySize), ToFFI(&bb));
157 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
159 const auto& targetContext = aDestination.mTexture->mTargetContext;
160 if (targetContext) {
161 mTargetContexts.AppendElement(targetContext);
165 void CommandEncoder::ClearBuffer(const Buffer& aBuffer, const uint64_t aOffset,
166 const dom::Optional<uint64_t>& aSize) {
167 uint64_t sizeVal = 0xdeaddead;
168 uint64_t* size = nullptr;
169 if (aSize.WasPassed()) {
170 sizeVal = aSize.Value();
171 size = &sizeVal;
174 ipc::ByteBuf bb;
175 ffi::wgpu_command_encoder_clear_buffer(aBuffer.mId, aOffset, size,
176 ToFFI(&bb));
177 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
180 void CommandEncoder::PushDebugGroup(const nsAString& aString) {
181 if (!mBridge->IsOpen()) {
182 return;
185 ipc::ByteBuf bb;
186 NS_ConvertUTF16toUTF8 marker(aString);
187 ffi::wgpu_command_encoder_push_debug_group(&marker, ToFFI(&bb));
188 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
190 void CommandEncoder::PopDebugGroup() {
191 if (!mBridge->IsOpen()) {
192 return;
195 ipc::ByteBuf bb;
196 ffi::wgpu_command_encoder_pop_debug_group(ToFFI(&bb));
197 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
199 void CommandEncoder::InsertDebugMarker(const nsAString& aString) {
200 if (!mBridge->IsOpen()) {
201 return;
204 ipc::ByteBuf bb;
205 NS_ConvertUTF16toUTF8 marker(aString);
206 ffi::wgpu_command_encoder_insert_debug_marker(&marker, ToFFI(&bb));
207 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
210 already_AddRefed<ComputePassEncoder> CommandEncoder::BeginComputePass(
211 const dom::GPUComputePassDescriptor& aDesc) {
212 RefPtr<ComputePassEncoder> pass = new ComputePassEncoder(this, aDesc);
213 return pass.forget();
216 already_AddRefed<RenderPassEncoder> CommandEncoder::BeginRenderPass(
217 const dom::GPURenderPassDescriptor& aDesc) {
218 for (const auto& at : aDesc.mColorAttachments) {
219 auto* targetContext = at.mView->GetTargetContext();
220 if (targetContext) {
221 mTargetContexts.AppendElement(targetContext);
223 if (at.mResolveTarget.WasPassed()) {
224 targetContext = at.mResolveTarget.Value().GetTargetContext();
225 mTargetContexts.AppendElement(targetContext);
229 RefPtr<RenderPassEncoder> pass = new RenderPassEncoder(this, aDesc);
230 return pass.forget();
233 void CommandEncoder::EndComputePass(ffi::WGPUComputePass& aPass) {
234 if (!mBridge->IsOpen()) {
235 return;
238 ipc::ByteBuf byteBuf;
239 ffi::wgpu_compute_pass_finish(&aPass, ToFFI(&byteBuf));
240 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(byteBuf));
243 void CommandEncoder::EndRenderPass(ffi::WGPURenderPass& aPass) {
244 if (!mBridge->IsOpen()) {
245 return;
248 ipc::ByteBuf byteBuf;
249 ffi::wgpu_render_pass_finish(&aPass, ToFFI(&byteBuf));
250 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(byteBuf));
253 already_AddRefed<CommandBuffer> CommandEncoder::Finish(
254 const dom::GPUCommandBufferDescriptor& aDesc) {
255 // We rely on knowledge that `CommandEncoderId` == `CommandBufferId`
256 // TODO: refactor this to truly behave as if the encoder is being finished,
257 // and a new command buffer ID is being created from it. Resolve the ID
258 // type aliasing at the place that introduces it: `wgpu-core`.
259 RawId deviceId = mParent->mId;
260 if (mBridge->CanSend()) {
261 mBridge->SendCommandEncoderFinish(mId, deviceId, aDesc);
264 RefPtr<CommandEncoder> me(this);
265 RefPtr<CommandBuffer> comb = new CommandBuffer(
266 mParent, mId, std::move(mTargetContexts), std::move(me));
267 return comb.forget();
270 } // namespace mozilla::webgpu