No bug - tagging a47fcf8f07f9c3e1b3f5fda7c49634809fed27cc with FIREFOX_BETA_129_BASE...
[gecko.git] / dom / webgpu / CommandEncoder.cpp
blob193f27596dd97f37cba23e084f8ba901959a6d30
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/UnionTypes.h"
7 #include "mozilla/dom/WebGPUBinding.h"
8 #include "CommandEncoder.h"
10 #include "CommandBuffer.h"
11 #include "Buffer.h"
12 #include "ComputePassEncoder.h"
13 #include "Device.h"
14 #include "RenderPassEncoder.h"
15 #include "Utility.h"
16 #include "mozilla/webgpu/CanvasContext.h"
17 #include "mozilla/webgpu/ffi/wgpu.h"
18 #include "ipc/WebGPUChild.h"
20 namespace mozilla::webgpu {
22 GPU_IMPL_CYCLE_COLLECTION(CommandEncoder, mParent, mBridge)
23 GPU_IMPL_JS_WRAP(CommandEncoder)
25 void CommandEncoder::ConvertTextureDataLayoutToFFI(
26 const dom::GPUImageDataLayout& aLayout,
27 ffi::WGPUImageDataLayout* aLayoutFFI) {
28 *aLayoutFFI = {};
29 aLayoutFFI->offset = aLayout.mOffset;
31 if (aLayout.mBytesPerRow.WasPassed()) {
32 aLayoutFFI->bytes_per_row = &aLayout.mBytesPerRow.Value();
33 } else {
34 aLayoutFFI->bytes_per_row = nullptr;
37 if (aLayout.mRowsPerImage.WasPassed()) {
38 aLayoutFFI->rows_per_image = &aLayout.mRowsPerImage.Value();
39 } else {
40 aLayoutFFI->rows_per_image = nullptr;
44 void CommandEncoder::ConvertTextureCopyViewToFFI(
45 const dom::GPUImageCopyTexture& aCopy,
46 ffi::WGPUImageCopyTexture* aViewFFI) {
47 *aViewFFI = {};
48 aViewFFI->texture = aCopy.mTexture->mId;
49 aViewFFI->mip_level = aCopy.mMipLevel;
50 if (aCopy.mOrigin.WasPassed()) {
51 const auto& origin = aCopy.mOrigin.Value();
52 if (origin.IsRangeEnforcedUnsignedLongSequence()) {
53 const auto& seq = origin.GetAsRangeEnforcedUnsignedLongSequence();
54 aViewFFI->origin.x = seq.Length() > 0 ? seq[0] : 0;
55 aViewFFI->origin.y = seq.Length() > 1 ? seq[1] : 0;
56 aViewFFI->origin.z = seq.Length() > 2 ? seq[2] : 0;
57 } else if (origin.IsGPUOrigin3DDict()) {
58 const auto& dict = origin.GetAsGPUOrigin3DDict();
59 aViewFFI->origin.x = dict.mX;
60 aViewFFI->origin.y = dict.mY;
61 aViewFFI->origin.z = dict.mZ;
62 } else {
63 MOZ_CRASH("Unexpected origin type");
68 static ffi::WGPUImageCopyTexture ConvertTextureCopyView(
69 const dom::GPUImageCopyTexture& aCopy) {
70 ffi::WGPUImageCopyTexture view = {};
71 CommandEncoder::ConvertTextureCopyViewToFFI(aCopy, &view);
72 return view;
75 CommandEncoder::CommandEncoder(Device* const aParent,
76 WebGPUChild* const aBridge, RawId aId)
77 : ChildOf(aParent), mId(aId), mBridge(aBridge) {
78 MOZ_RELEASE_ASSERT(aId);
81 CommandEncoder::~CommandEncoder() { Cleanup(); }
83 void CommandEncoder::Cleanup() {
84 if (!mValid) {
85 return;
87 mValid = false;
89 if (!mBridge) {
90 return;
93 if (mBridge->CanSend()) {
94 mBridge->SendCommandEncoderDrop(mId);
97 wgpu_client_free_command_encoder_id(mBridge->GetClient(), mId);
100 void CommandEncoder::TrackPresentationContext(CanvasContext* aTargetContext) {
101 if (aTargetContext) {
102 if (!aTargetContext->IsOffscreenCanvas()) {
103 mPresentationContexts.AppendElement(aTargetContext);
108 void CommandEncoder::CopyBufferToBuffer(const Buffer& aSource,
109 BufferAddress aSourceOffset,
110 const Buffer& aDestination,
111 BufferAddress aDestinationOffset,
112 BufferAddress aSize) {
113 if (!mBridge->CanSend()) {
114 return;
117 ipc::ByteBuf bb;
118 ffi::wgpu_command_encoder_copy_buffer_to_buffer(
119 aSource.mId, aSourceOffset, aDestination.mId, aDestinationOffset, aSize,
120 ToFFI(&bb));
121 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
124 void CommandEncoder::CopyBufferToTexture(
125 const dom::GPUImageCopyBuffer& aSource,
126 const dom::GPUImageCopyTexture& aDestination,
127 const dom::GPUExtent3D& aCopySize) {
128 if (!mBridge->CanSend()) {
129 return;
132 ipc::ByteBuf bb;
133 ffi::WGPUImageDataLayout src_layout = {};
134 CommandEncoder::ConvertTextureDataLayoutToFFI(aSource, &src_layout);
135 ffi::wgpu_command_encoder_copy_buffer_to_texture(
136 aSource.mBuffer->mId, &src_layout, ConvertTextureCopyView(aDestination),
137 ConvertExtent(aCopySize), ToFFI(&bb));
138 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
140 TrackPresentationContext(aDestination.mTexture->mTargetContext);
142 void CommandEncoder::CopyTextureToBuffer(
143 const dom::GPUImageCopyTexture& aSource,
144 const dom::GPUImageCopyBuffer& aDestination,
145 const dom::GPUExtent3D& aCopySize) {
146 if (!mBridge->CanSend()) {
147 return;
150 ipc::ByteBuf bb;
151 ffi::WGPUImageDataLayout dstLayout = {};
152 CommandEncoder::ConvertTextureDataLayoutToFFI(aDestination, &dstLayout);
153 ffi::wgpu_command_encoder_copy_texture_to_buffer(
154 ConvertTextureCopyView(aSource), aDestination.mBuffer->mId, &dstLayout,
155 ConvertExtent(aCopySize), ToFFI(&bb));
156 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
158 void CommandEncoder::CopyTextureToTexture(
159 const dom::GPUImageCopyTexture& aSource,
160 const dom::GPUImageCopyTexture& aDestination,
161 const dom::GPUExtent3D& aCopySize) {
162 if (!mBridge->CanSend()) {
163 return;
166 ipc::ByteBuf bb;
167 ffi::wgpu_command_encoder_copy_texture_to_texture(
168 ConvertTextureCopyView(aSource), ConvertTextureCopyView(aDestination),
169 ConvertExtent(aCopySize), ToFFI(&bb));
170 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
172 TrackPresentationContext(aDestination.mTexture->mTargetContext);
175 void CommandEncoder::ClearBuffer(const Buffer& aBuffer, const uint64_t aOffset,
176 const dom::Optional<uint64_t>& aSize) {
177 uint64_t sizeVal = 0xdeaddead;
178 uint64_t* size = nullptr;
179 if (aSize.WasPassed()) {
180 sizeVal = aSize.Value();
181 size = &sizeVal;
184 ipc::ByteBuf bb;
185 ffi::wgpu_command_encoder_clear_buffer(aBuffer.mId, aOffset, size,
186 ToFFI(&bb));
187 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
190 void CommandEncoder::PushDebugGroup(const nsAString& aString) {
191 if (!mBridge->CanSend()) {
192 return;
195 ipc::ByteBuf bb;
196 NS_ConvertUTF16toUTF8 marker(aString);
197 ffi::wgpu_command_encoder_push_debug_group(&marker, ToFFI(&bb));
198 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
200 void CommandEncoder::PopDebugGroup() {
201 if (!mBridge->CanSend()) {
202 return;
205 ipc::ByteBuf bb;
206 ffi::wgpu_command_encoder_pop_debug_group(ToFFI(&bb));
207 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
209 void CommandEncoder::InsertDebugMarker(const nsAString& aString) {
210 if (!mBridge->CanSend()) {
211 return;
214 ipc::ByteBuf bb;
215 NS_ConvertUTF16toUTF8 marker(aString);
216 ffi::wgpu_command_encoder_insert_debug_marker(&marker, ToFFI(&bb));
217 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
220 already_AddRefed<ComputePassEncoder> CommandEncoder::BeginComputePass(
221 const dom::GPUComputePassDescriptor& aDesc) {
222 RefPtr<ComputePassEncoder> pass = new ComputePassEncoder(this, aDesc);
223 return pass.forget();
226 already_AddRefed<RenderPassEncoder> CommandEncoder::BeginRenderPass(
227 const dom::GPURenderPassDescriptor& aDesc) {
228 for (const auto& at : aDesc.mColorAttachments) {
229 TrackPresentationContext(at.mView->GetTargetContext());
230 if (at.mResolveTarget.WasPassed()) {
231 TrackPresentationContext(at.mResolveTarget.Value().GetTargetContext());
235 RefPtr<RenderPassEncoder> pass = new RenderPassEncoder(this, aDesc);
236 return pass.forget();
239 void CommandEncoder::EndComputePass(ffi::WGPURecordedComputePass& aPass) {
240 // Because this can be called during child Cleanup, we need to check
241 // that the bridge is still alive.
242 if (!mBridge || !mBridge->CanSend()) {
243 return;
246 ipc::ByteBuf byteBuf;
247 ffi::wgpu_compute_pass_finish(&aPass, ToFFI(&byteBuf));
248 mBridge->SendComputePass(mId, mParent->mId, std::move(byteBuf));
251 void CommandEncoder::EndRenderPass(ffi::WGPURecordedRenderPass& aPass) {
252 // Because this can be called during child Cleanup, we need to check
253 // that the bridge is still alive.
254 if (!mBridge || !mBridge->CanSend()) {
255 return;
258 ipc::ByteBuf byteBuf;
259 ffi::wgpu_render_pass_finish(&aPass, ToFFI(&byteBuf));
260 mBridge->SendRenderPass(mId, mParent->mId, std::move(byteBuf));
263 already_AddRefed<CommandBuffer> CommandEncoder::Finish(
264 const dom::GPUCommandBufferDescriptor& aDesc) {
265 // We rely on knowledge that `CommandEncoderId` == `CommandBufferId`
266 // TODO: refactor this to truly behave as if the encoder is being finished,
267 // and a new command buffer ID is being created from it. Resolve the ID
268 // type aliasing at the place that introduces it: `wgpu-core`.
269 RawId deviceId = mParent->mId;
270 if (mBridge->CanSend()) {
271 mBridge->SendCommandEncoderFinish(mId, deviceId, aDesc);
274 RefPtr<CommandEncoder> me(this);
275 RefPtr<CommandBuffer> comb = new CommandBuffer(
276 mParent, mId, std::move(mPresentationContexts), std::move(me));
277 return comb.forget();
280 } // namespace mozilla::webgpu