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"
12 #include "ComputePassEncoder.h"
14 #include "RenderPassEncoder.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
) {
29 aLayoutFFI
->offset
= aLayout
.mOffset
;
31 if (aLayout
.mBytesPerRow
.WasPassed()) {
32 aLayoutFFI
->bytes_per_row
= &aLayout
.mBytesPerRow
.Value();
34 aLayoutFFI
->bytes_per_row
= nullptr;
37 if (aLayout
.mRowsPerImage
.WasPassed()) {
38 aLayoutFFI
->rows_per_image
= &aLayout
.mRowsPerImage
.Value();
40 aLayoutFFI
->rows_per_image
= nullptr;
44 void CommandEncoder::ConvertTextureCopyViewToFFI(
45 const dom::GPUTexelCopyTextureInfo
& aCopy
,
46 ffi::WGPUTexelCopyTextureInfo
* 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
;
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
);
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() {
91 if (mBridge
->CanSend()) {
92 mBridge
->SendCommandEncoderDrop(mId
);
95 wgpu_client_free_command_encoder_id(mBridge
->GetClient(), mId
);
98 void CommandEncoder::TrackPresentationContext(CanvasContext
* 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()) {
114 ffi::wgpu_command_encoder_copy_buffer_to_buffer(
115 aSource
.mId
, aSourceOffset
, aDestination
.mId
, aDestinationOffset
, aSize
,
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()) {
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()) {
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()) {
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();
181 ffi::wgpu_command_encoder_clear_buffer(aBuffer
.mId
, aOffset
, size
,
183 mBridge
->SendCommandEncoderAction(mId
, mParent
->mId
, std::move(bb
));
186 void CommandEncoder::PushDebugGroup(const nsAString
& aString
) {
187 if (!mBridge
->CanSend()) {
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()) {
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()) {
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()) {
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()) {
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()) {
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