Bug 1941128 - Turn off network.dns.native_https_query on Mac again
[gecko.git] / dom / webgpu / CommandEncoder.cpp
blob4b499de891f2d271b77625f00dc0ebf5674b3619
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::GPUTexelCopyBufferLayout& aLayout,
27 ffi::WGPUTexelCopyBufferLayout* 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::GPUTexelCopyTextureInfo& aCopy,
46 ffi::WGPUTexelCopyTextureInfo* aViewFFI) {
47 *aViewFFI = {};
48 aViewFFI->texture = aCopy.mTexture->mId;
49 aViewFFI->mip_level = aCopy.mMipLevel;
50 const auto& origin = aCopy.mOrigin;
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");
66 static ffi::WGPUTexelCopyTextureInfo ConvertTextureCopyView(
67 const dom::GPUTexelCopyTextureInfo& aCopy) {
68 ffi::WGPUTexelCopyTextureInfo view = {};
69 CommandEncoder::ConvertTextureCopyViewToFFI(aCopy, &view);
70 return view;
73 CommandEncoder::CommandEncoder(Device* const aParent,
74 WebGPUChild* const aBridge, RawId aId)
75 : ChildOf(aParent), mId(aId), mBridge(aBridge) {
76 MOZ_RELEASE_ASSERT(aId);
79 CommandEncoder::~CommandEncoder() { Cleanup(); }
81 void CommandEncoder::Cleanup() {
82 if (!mValid) {
83 return;
85 mValid = false;
87 if (!mBridge) {
88 return;
91 if (mBridge->CanSend()) {
92 mBridge->SendCommandEncoderDrop(mId);
95 wgpu_client_free_command_encoder_id(mBridge->GetClient(), mId);
98 void CommandEncoder::TrackPresentationContext(CanvasContext* aTargetContext) {
99 if (aTargetContext) {
100 mPresentationContexts.AppendElement(aTargetContext);
104 void CommandEncoder::CopyBufferToBuffer(const Buffer& aSource,
105 BufferAddress aSourceOffset,
106 const Buffer& aDestination,
107 BufferAddress aDestinationOffset,
108 BufferAddress aSize) {
109 if (!mBridge->CanSend()) {
110 return;
113 ipc::ByteBuf bb;
114 ffi::wgpu_command_encoder_copy_buffer_to_buffer(
115 aSource.mId, aSourceOffset, aDestination.mId, aDestinationOffset, aSize,
116 ToFFI(&bb));
117 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
120 void CommandEncoder::CopyBufferToTexture(
121 const dom::GPUTexelCopyBufferInfo& aSource,
122 const dom::GPUTexelCopyTextureInfo& aDestination,
123 const dom::GPUExtent3D& aCopySize) {
124 if (!mBridge->CanSend()) {
125 return;
128 ipc::ByteBuf bb;
129 ffi::WGPUTexelCopyBufferLayout src_layout = {};
130 CommandEncoder::ConvertTextureDataLayoutToFFI(aSource, &src_layout);
131 ffi::wgpu_command_encoder_copy_buffer_to_texture(
132 aSource.mBuffer->mId, &src_layout, ConvertTextureCopyView(aDestination),
133 ConvertExtent(aCopySize), ToFFI(&bb));
134 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
136 TrackPresentationContext(aDestination.mTexture->mTargetContext);
138 void CommandEncoder::CopyTextureToBuffer(
139 const dom::GPUTexelCopyTextureInfo& aSource,
140 const dom::GPUTexelCopyBufferInfo& aDestination,
141 const dom::GPUExtent3D& aCopySize) {
142 if (!mBridge->CanSend()) {
143 return;
146 ipc::ByteBuf bb;
147 ffi::WGPUTexelCopyBufferLayout dstLayout = {};
148 CommandEncoder::ConvertTextureDataLayoutToFFI(aDestination, &dstLayout);
149 ffi::wgpu_command_encoder_copy_texture_to_buffer(
150 ConvertTextureCopyView(aSource), aDestination.mBuffer->mId, &dstLayout,
151 ConvertExtent(aCopySize), ToFFI(&bb));
152 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
154 void CommandEncoder::CopyTextureToTexture(
155 const dom::GPUTexelCopyTextureInfo& aSource,
156 const dom::GPUTexelCopyTextureInfo& aDestination,
157 const dom::GPUExtent3D& aCopySize) {
158 if (!mBridge->CanSend()) {
159 return;
162 ipc::ByteBuf bb;
163 ffi::wgpu_command_encoder_copy_texture_to_texture(
164 ConvertTextureCopyView(aSource), ConvertTextureCopyView(aDestination),
165 ConvertExtent(aCopySize), ToFFI(&bb));
166 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
168 TrackPresentationContext(aDestination.mTexture->mTargetContext);
171 void CommandEncoder::ClearBuffer(const Buffer& aBuffer, const uint64_t aOffset,
172 const dom::Optional<uint64_t>& aSize) {
173 uint64_t sizeVal = 0xdeaddead;
174 uint64_t* size = nullptr;
175 if (aSize.WasPassed()) {
176 sizeVal = aSize.Value();
177 size = &sizeVal;
180 ipc::ByteBuf bb;
181 ffi::wgpu_command_encoder_clear_buffer(aBuffer.mId, aOffset, size,
182 ToFFI(&bb));
183 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
186 void CommandEncoder::PushDebugGroup(const nsAString& aString) {
187 if (!mBridge->CanSend()) {
188 return;
191 ipc::ByteBuf bb;
192 NS_ConvertUTF16toUTF8 marker(aString);
193 ffi::wgpu_command_encoder_push_debug_group(&marker, ToFFI(&bb));
194 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
196 void CommandEncoder::PopDebugGroup() {
197 if (!mBridge->CanSend()) {
198 return;
201 ipc::ByteBuf bb;
202 ffi::wgpu_command_encoder_pop_debug_group(ToFFI(&bb));
203 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
205 void CommandEncoder::InsertDebugMarker(const nsAString& aString) {
206 if (!mBridge->CanSend()) {
207 return;
210 ipc::ByteBuf bb;
211 NS_ConvertUTF16toUTF8 marker(aString);
212 ffi::wgpu_command_encoder_insert_debug_marker(&marker, ToFFI(&bb));
213 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
216 already_AddRefed<ComputePassEncoder> CommandEncoder::BeginComputePass(
217 const dom::GPUComputePassDescriptor& aDesc) {
218 RefPtr<ComputePassEncoder> pass = new ComputePassEncoder(this, aDesc);
219 return pass.forget();
222 already_AddRefed<RenderPassEncoder> CommandEncoder::BeginRenderPass(
223 const dom::GPURenderPassDescriptor& aDesc) {
224 for (const auto& at : aDesc.mColorAttachments) {
225 TrackPresentationContext(at.mView->GetTargetContext());
226 if (at.mResolveTarget.WasPassed()) {
227 TrackPresentationContext(at.mResolveTarget.Value().GetTargetContext());
231 RefPtr<RenderPassEncoder> pass = new RenderPassEncoder(this, aDesc);
232 return pass.forget();
235 void CommandEncoder::ResolveQuerySet(QuerySet& aQuerySet, uint32_t aFirstQuery,
236 uint32_t aQueryCount,
237 webgpu::Buffer& aDestination,
238 uint64_t aDestinationOffset) {
239 if (!mBridge->CanSend()) {
240 return;
243 ipc::ByteBuf bb;
244 ffi::wgpu_command_encoder_resolve_query_set(aQuerySet.mId, aFirstQuery,
245 aQueryCount, aDestination.mId,
246 aDestinationOffset, ToFFI(&bb));
247 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
250 void CommandEncoder::EndComputePass(ffi::WGPURecordedComputePass& aPass) {
251 // Because this can be called during child Cleanup, we need to check
252 // that the bridge is still alive.
253 if (!mBridge || !mBridge->CanSend()) {
254 return;
257 ipc::ByteBuf byteBuf;
258 ffi::wgpu_compute_pass_finish(&aPass, ToFFI(&byteBuf));
259 mBridge->SendComputePass(mId, mParent->mId, std::move(byteBuf));
262 void CommandEncoder::EndRenderPass(ffi::WGPURecordedRenderPass& aPass) {
263 // Because this can be called during child Cleanup, we need to check
264 // that the bridge is still alive.
265 if (!mBridge || !mBridge->CanSend()) {
266 return;
269 ipc::ByteBuf byteBuf;
270 ffi::wgpu_render_pass_finish(&aPass, ToFFI(&byteBuf));
271 mBridge->SendRenderPass(mId, mParent->mId, std::move(byteBuf));
274 already_AddRefed<CommandBuffer> CommandEncoder::Finish(
275 const dom::GPUCommandBufferDescriptor& aDesc) {
276 // We rely on knowledge that `CommandEncoderId` == `CommandBufferId`
277 // TODO: refactor this to truly behave as if the encoder is being finished,
278 // and a new command buffer ID is being created from it. Resolve the ID
279 // type aliasing at the place that introduces it: `wgpu-core`.
280 RawId deviceId = mParent->mId;
281 if (mBridge->CanSend()) {
282 mBridge->SendCommandEncoderFinish(mId, deviceId, aDesc);
285 RefPtr<CommandEncoder> me(this);
286 RefPtr<CommandBuffer> comb = new CommandBuffer(
287 mParent, mId, std::move(mPresentationContexts), std::move(me));
288 return comb.forget();
291 } // namespace mozilla::webgpu