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"
11 #include "ComputePassEncoder.h"
13 #include "RenderPassEncoder.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
) {
28 aLayoutFFI
->offset
= aLayout
.mOffset
;
30 if (aLayout
.mBytesPerRow
.WasPassed()) {
31 aLayoutFFI
->bytes_per_row
= &aLayout
.mBytesPerRow
.Value();
33 aLayoutFFI
->bytes_per_row
= nullptr;
36 if (aLayout
.mRowsPerImage
.WasPassed()) {
37 aLayoutFFI
->rows_per_image
= &aLayout
.mRowsPerImage
.Value();
39 aLayoutFFI
->rows_per_image
= nullptr;
43 void CommandEncoder::ConvertTextureCopyViewToFFI(
44 const dom::GPUImageCopyTexture
& aCopy
,
45 ffi::WGPUImageCopyTexture
* 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
;
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
);
74 CommandEncoder::CommandEncoder(Device
* const aParent
,
75 WebGPUChild
* const aBridge
, RawId aId
)
76 : ChildOf(aParent
), mId(aId
), mBridge(aBridge
) {}
78 CommandEncoder::~CommandEncoder() { Cleanup(); }
80 void CommandEncoder::Cleanup() {
83 if (mBridge
->IsOpen()) {
84 mBridge
->SendCommandEncoderDestroy(mId
);
89 void CommandEncoder::CopyBufferToBuffer(const Buffer
& aSource
,
90 BufferAddress aSourceOffset
,
91 const Buffer
& aDestination
,
92 BufferAddress aDestinationOffset
,
93 BufferAddress aSize
) {
94 if (mValid
&& mBridge
->IsOpen()) {
96 ffi::wgpu_command_encoder_copy_buffer_to_buffer(
97 aSource
.mId
, aSourceOffset
, aDestination
.mId
, aDestinationOffset
, aSize
,
99 mBridge
->SendCommandEncoderAction(mId
, mParent
->mId
, std::move(bb
));
103 void CommandEncoder::CopyBufferToTexture(
104 const dom::GPUImageCopyBuffer
& aSource
,
105 const dom::GPUImageCopyTexture
& aDestination
,
106 const dom::GPUExtent3D
& aCopySize
) {
107 if (mValid
&& mBridge
->IsOpen()) {
109 ffi::WGPUImageDataLayout src_layout
= {};
110 CommandEncoder::ConvertTextureDataLayoutToFFI(aSource
, &src_layout
);
111 ffi::wgpu_command_encoder_copy_buffer_to_texture(
112 aSource
.mBuffer
->mId
, &src_layout
, ConvertTextureCopyView(aDestination
),
113 ConvertExtent(aCopySize
), ToFFI(&bb
));
114 mBridge
->SendCommandEncoderAction(mId
, mParent
->mId
, std::move(bb
));
116 const auto& targetContext
= aDestination
.mTexture
->mTargetContext
;
118 mTargetContexts
.AppendElement(targetContext
);
122 void CommandEncoder::CopyTextureToBuffer(
123 const dom::GPUImageCopyTexture
& aSource
,
124 const dom::GPUImageCopyBuffer
& aDestination
,
125 const dom::GPUExtent3D
& aCopySize
) {
126 if (mValid
&& mBridge
->IsOpen()) {
128 ffi::WGPUImageDataLayout dstLayout
= {};
129 CommandEncoder::ConvertTextureDataLayoutToFFI(aDestination
, &dstLayout
);
130 ffi::wgpu_command_encoder_copy_texture_to_buffer(
131 ConvertTextureCopyView(aSource
), aDestination
.mBuffer
->mId
, &dstLayout
,
132 ConvertExtent(aCopySize
), ToFFI(&bb
));
133 mBridge
->SendCommandEncoderAction(mId
, mParent
->mId
, std::move(bb
));
136 void CommandEncoder::CopyTextureToTexture(
137 const dom::GPUImageCopyTexture
& aSource
,
138 const dom::GPUImageCopyTexture
& aDestination
,
139 const dom::GPUExtent3D
& aCopySize
) {
140 if (mValid
&& mBridge
->IsOpen()) {
142 ffi::wgpu_command_encoder_copy_texture_to_texture(
143 ConvertTextureCopyView(aSource
), ConvertTextureCopyView(aDestination
),
144 ConvertExtent(aCopySize
), ToFFI(&bb
));
145 mBridge
->SendCommandEncoderAction(mId
, mParent
->mId
, std::move(bb
));
147 const auto& targetContext
= aDestination
.mTexture
->mTargetContext
;
149 mTargetContexts
.AppendElement(targetContext
);
154 void CommandEncoder::PushDebugGroup(const nsAString
& aString
) {
155 if (mValid
&& mBridge
->IsOpen()) {
157 NS_ConvertUTF16toUTF8
marker(aString
);
158 ffi::wgpu_command_encoder_push_debug_group(&marker
, ToFFI(&bb
));
159 mBridge
->SendCommandEncoderAction(mId
, mParent
->mId
, std::move(bb
));
162 void CommandEncoder::PopDebugGroup() {
163 if (mValid
&& mBridge
->IsOpen()) {
165 ffi::wgpu_command_encoder_pop_debug_group(ToFFI(&bb
));
166 mBridge
->SendCommandEncoderAction(mId
, mParent
->mId
, std::move(bb
));
169 void CommandEncoder::InsertDebugMarker(const nsAString
& aString
) {
170 if (mValid
&& mBridge
->IsOpen()) {
172 NS_ConvertUTF16toUTF8
marker(aString
);
173 ffi::wgpu_command_encoder_insert_debug_marker(&marker
, ToFFI(&bb
));
174 mBridge
->SendCommandEncoderAction(mId
, mParent
->mId
, std::move(bb
));
178 already_AddRefed
<ComputePassEncoder
> CommandEncoder::BeginComputePass(
179 const dom::GPUComputePassDescriptor
& aDesc
) {
180 RefPtr
<ComputePassEncoder
> pass
= new ComputePassEncoder(this, aDesc
);
181 return pass
.forget();
184 already_AddRefed
<RenderPassEncoder
> CommandEncoder::BeginRenderPass(
185 const dom::GPURenderPassDescriptor
& aDesc
) {
186 for (const auto& at
: aDesc
.mColorAttachments
) {
187 auto* targetContext
= at
.mView
->GetTargetContext();
189 mTargetContexts
.AppendElement(targetContext
);
191 if (at
.mResolveTarget
.WasPassed()) {
192 targetContext
= at
.mResolveTarget
.Value().GetTargetContext();
193 mTargetContexts
.AppendElement(targetContext
);
197 RefPtr
<RenderPassEncoder
> pass
= new RenderPassEncoder(this, aDesc
);
198 return pass
.forget();
201 void CommandEncoder::EndComputePass(ffi::WGPUComputePass
& aPass
,
203 if (!mValid
|| !mBridge
->IsOpen()) {
204 return aRv
.ThrowInvalidStateError("Command encoder is not valid");
207 ipc::ByteBuf byteBuf
;
208 ffi::wgpu_compute_pass_finish(&aPass
, ToFFI(&byteBuf
));
209 mBridge
->SendCommandEncoderAction(mId
, mParent
->mId
, std::move(byteBuf
));
212 void CommandEncoder::EndRenderPass(ffi::WGPURenderPass
& aPass
,
214 if (!mValid
|| !mBridge
->IsOpen()) {
215 return aRv
.ThrowInvalidStateError("Command encoder is not valid");
218 ipc::ByteBuf byteBuf
;
219 ffi::wgpu_render_pass_finish(&aPass
, ToFFI(&byteBuf
));
220 mBridge
->SendCommandEncoderAction(mId
, mParent
->mId
, std::move(byteBuf
));
223 already_AddRefed
<CommandBuffer
> CommandEncoder::Finish(
224 const dom::GPUCommandBufferDescriptor
& aDesc
) {
226 if (mValid
&& mBridge
->IsOpen()) {
228 id
= mBridge
->CommandEncoderFinish(mId
, mParent
->mId
, aDesc
);
230 RefPtr
<CommandBuffer
> comb
=
231 new CommandBuffer(mParent
, id
, std::move(mTargetContexts
));
232 return comb
.forget();
235 } // namespace mozilla::webgpu