Bug 1857841 - pt 3. Add a new page kind named "fresh" r=glandium
[gecko.git] / dom / webgpu / CommandEncoder.cpp
blobf254c9d8b9a525a411a844d48bc32f4375805dd2
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;
88 if (mBridge->IsOpen()) {
89 mBridge->SendCommandEncoderDrop(mId);
93 void CommandEncoder::TrackPresentationContext(CanvasContext* aTargetContext) {
94 if (aTargetContext) {
95 if (!aTargetContext->IsOffscreenCanvas()) {
96 mPresentationContexts.AppendElement(aTargetContext);
101 void CommandEncoder::CopyBufferToBuffer(const Buffer& aSource,
102 BufferAddress aSourceOffset,
103 const Buffer& aDestination,
104 BufferAddress aDestinationOffset,
105 BufferAddress aSize) {
106 if (!mBridge->IsOpen()) {
107 return;
110 ipc::ByteBuf bb;
111 ffi::wgpu_command_encoder_copy_buffer_to_buffer(
112 aSource.mId, aSourceOffset, aDestination.mId, aDestinationOffset, aSize,
113 ToFFI(&bb));
114 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
117 void CommandEncoder::CopyBufferToTexture(
118 const dom::GPUImageCopyBuffer& aSource,
119 const dom::GPUImageCopyTexture& aDestination,
120 const dom::GPUExtent3D& aCopySize) {
121 if (!mBridge->IsOpen()) {
122 return;
125 ipc::ByteBuf bb;
126 ffi::WGPUImageDataLayout src_layout = {};
127 CommandEncoder::ConvertTextureDataLayoutToFFI(aSource, &src_layout);
128 ffi::wgpu_command_encoder_copy_buffer_to_texture(
129 aSource.mBuffer->mId, &src_layout, ConvertTextureCopyView(aDestination),
130 ConvertExtent(aCopySize), ToFFI(&bb));
131 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
133 TrackPresentationContext(aDestination.mTexture->mTargetContext);
135 void CommandEncoder::CopyTextureToBuffer(
136 const dom::GPUImageCopyTexture& aSource,
137 const dom::GPUImageCopyBuffer& aDestination,
138 const dom::GPUExtent3D& aCopySize) {
139 if (!mBridge->IsOpen()) {
140 return;
143 ipc::ByteBuf bb;
144 ffi::WGPUImageDataLayout dstLayout = {};
145 CommandEncoder::ConvertTextureDataLayoutToFFI(aDestination, &dstLayout);
146 ffi::wgpu_command_encoder_copy_texture_to_buffer(
147 ConvertTextureCopyView(aSource), aDestination.mBuffer->mId, &dstLayout,
148 ConvertExtent(aCopySize), ToFFI(&bb));
149 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
151 void CommandEncoder::CopyTextureToTexture(
152 const dom::GPUImageCopyTexture& aSource,
153 const dom::GPUImageCopyTexture& aDestination,
154 const dom::GPUExtent3D& aCopySize) {
155 if (!mBridge->IsOpen()) {
156 return;
159 ipc::ByteBuf bb;
160 ffi::wgpu_command_encoder_copy_texture_to_texture(
161 ConvertTextureCopyView(aSource), ConvertTextureCopyView(aDestination),
162 ConvertExtent(aCopySize), ToFFI(&bb));
163 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
165 TrackPresentationContext(aDestination.mTexture->mTargetContext);
168 void CommandEncoder::ClearBuffer(const Buffer& aBuffer, const uint64_t aOffset,
169 const dom::Optional<uint64_t>& aSize) {
170 uint64_t sizeVal = 0xdeaddead;
171 uint64_t* size = nullptr;
172 if (aSize.WasPassed()) {
173 sizeVal = aSize.Value();
174 size = &sizeVal;
177 ipc::ByteBuf bb;
178 ffi::wgpu_command_encoder_clear_buffer(aBuffer.mId, aOffset, size,
179 ToFFI(&bb));
180 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
183 void CommandEncoder::PushDebugGroup(const nsAString& aString) {
184 if (!mBridge->IsOpen()) {
185 return;
188 ipc::ByteBuf bb;
189 NS_ConvertUTF16toUTF8 marker(aString);
190 ffi::wgpu_command_encoder_push_debug_group(&marker, ToFFI(&bb));
191 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
193 void CommandEncoder::PopDebugGroup() {
194 if (!mBridge->IsOpen()) {
195 return;
198 ipc::ByteBuf bb;
199 ffi::wgpu_command_encoder_pop_debug_group(ToFFI(&bb));
200 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
202 void CommandEncoder::InsertDebugMarker(const nsAString& aString) {
203 if (!mBridge->IsOpen()) {
204 return;
207 ipc::ByteBuf bb;
208 NS_ConvertUTF16toUTF8 marker(aString);
209 ffi::wgpu_command_encoder_insert_debug_marker(&marker, ToFFI(&bb));
210 mBridge->SendCommandEncoderAction(mId, mParent->mId, std::move(bb));
213 already_AddRefed<ComputePassEncoder> CommandEncoder::BeginComputePass(
214 const dom::GPUComputePassDescriptor& aDesc) {
215 RefPtr<ComputePassEncoder> pass = new ComputePassEncoder(this, aDesc);
216 return pass.forget();
219 already_AddRefed<RenderPassEncoder> CommandEncoder::BeginRenderPass(
220 const dom::GPURenderPassDescriptor& aDesc) {
221 for (const auto& at : aDesc.mColorAttachments) {
222 TrackPresentationContext(at.mView->GetTargetContext());
223 if (at.mResolveTarget.WasPassed()) {
224 TrackPresentationContext(at.mResolveTarget.Value().GetTargetContext());
228 RefPtr<RenderPassEncoder> pass = new RenderPassEncoder(this, aDesc);
229 return pass.forget();
232 void CommandEncoder::EndComputePass(ffi::WGPURecordedComputePass& aPass) {
233 if (!mBridge->IsOpen()) {
234 return;
237 ipc::ByteBuf byteBuf;
238 ffi::wgpu_compute_pass_finish(&aPass, ToFFI(&byteBuf));
239 mBridge->SendComputePass(mId, mParent->mId, std::move(byteBuf));
242 void CommandEncoder::EndRenderPass(ffi::WGPURecordedRenderPass& aPass) {
243 if (!mBridge->IsOpen()) {
244 return;
247 ipc::ByteBuf byteBuf;
248 ffi::wgpu_render_pass_finish(&aPass, ToFFI(&byteBuf));
249 mBridge->SendRenderPass(mId, mParent->mId, std::move(byteBuf));
252 already_AddRefed<CommandBuffer> CommandEncoder::Finish(
253 const dom::GPUCommandBufferDescriptor& aDesc) {
254 // We rely on knowledge that `CommandEncoderId` == `CommandBufferId`
255 // TODO: refactor this to truly behave as if the encoder is being finished,
256 // and a new command buffer ID is being created from it. Resolve the ID
257 // type aliasing at the place that introduces it: `wgpu-core`.
258 RawId deviceId = mParent->mId;
259 if (mBridge->CanSend()) {
260 mBridge->SendCommandEncoderFinish(mId, deviceId, aDesc);
263 RefPtr<CommandEncoder> me(this);
264 RefPtr<CommandBuffer> comb = new CommandBuffer(
265 mParent, mId, std::move(mPresentationContexts), std::move(me));
266 return comb.forget();
269 } // namespace mozilla::webgpu