Backed out 4 changesets (bug 1825722) for causing reftest failures CLOSED TREE
[gecko.git] / dom / webgpu / RenderPassEncoder.cpp
blobbd3503ea772a8c511434c8d333b1ed5f5541017e
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 "RenderPassEncoder.h"
8 #include "BindGroup.h"
9 #include "CommandEncoder.h"
10 #include "RenderBundle.h"
11 #include "RenderPipeline.h"
12 #include "mozilla/webgpu/ffi/wgpu.h"
14 namespace mozilla::webgpu {
16 GPU_IMPL_CYCLE_COLLECTION(RenderPassEncoder, mParent, mUsedBindGroups,
17 mUsedBuffers, mUsedPipelines, mUsedTextureViews,
18 mUsedRenderBundles)
19 GPU_IMPL_JS_WRAP(RenderPassEncoder)
21 void ffiWGPURenderPassDeleter::operator()(ffi::WGPURecordedRenderPass* raw) {
22 if (raw) {
23 ffi::wgpu_render_pass_destroy(raw);
27 static ffi::WGPULoadOp ConvertLoadOp(const dom::GPULoadOp& aOp) {
28 switch (aOp) {
29 case dom::GPULoadOp::Load:
30 return ffi::WGPULoadOp_Load;
31 case dom::GPULoadOp::Clear:
32 return ffi::WGPULoadOp_Clear;
33 case dom::GPULoadOp::EndGuard_:
34 break;
36 MOZ_CRASH("bad GPULoadOp");
39 static ffi::WGPUStoreOp ConvertStoreOp(const dom::GPUStoreOp& aOp) {
40 switch (aOp) {
41 case dom::GPUStoreOp::Store:
42 return ffi::WGPUStoreOp_Store;
43 case dom::GPUStoreOp::Discard:
44 return ffi::WGPUStoreOp_Discard;
45 case dom::GPUStoreOp::EndGuard_:
46 break;
48 MOZ_CRASH("bad GPUStoreOp");
51 static ffi::WGPUColor ConvertColor(const dom::Sequence<double>& aSeq) {
52 ffi::WGPUColor color;
53 color.r = aSeq.SafeElementAt(0, 0.0);
54 color.g = aSeq.SafeElementAt(1, 0.0);
55 color.b = aSeq.SafeElementAt(2, 0.0);
56 color.a = aSeq.SafeElementAt(3, 1.0);
57 return color;
60 static ffi::WGPUColor ConvertColor(const dom::GPUColorDict& aColor) {
61 ffi::WGPUColor color = {aColor.mR, aColor.mG, aColor.mB, aColor.mA};
62 return color;
65 static ffi::WGPUColor ConvertColor(
66 const dom::DoubleSequenceOrGPUColorDict& aColor) {
67 if (aColor.IsDoubleSequence()) {
68 return ConvertColor(aColor.GetAsDoubleSequence());
70 if (aColor.IsGPUColorDict()) {
71 return ConvertColor(aColor.GetAsGPUColorDict());
73 MOZ_ASSERT_UNREACHABLE(
74 "Unexpected dom::DoubleSequenceOrGPUColorDict variant");
75 return ffi::WGPUColor();
77 static ffi::WGPUColor ConvertColor(
78 const dom::OwningDoubleSequenceOrGPUColorDict& aColor) {
79 if (aColor.IsDoubleSequence()) {
80 return ConvertColor(aColor.GetAsDoubleSequence());
82 if (aColor.IsGPUColorDict()) {
83 return ConvertColor(aColor.GetAsGPUColorDict());
85 MOZ_ASSERT_UNREACHABLE(
86 "Unexpected dom::OwningDoubleSequenceOrGPUColorDict variant");
87 return ffi::WGPUColor();
90 ffi::WGPURecordedRenderPass* BeginRenderPass(
91 CommandEncoder* const aParent, const dom::GPURenderPassDescriptor& aDesc) {
92 ffi::WGPURenderPassDescriptor desc = {};
94 webgpu::StringHelper label(aDesc.mLabel);
95 desc.label = label.Get();
97 ffi::WGPURenderPassDepthStencilAttachment dsDesc = {};
98 if (aDesc.mDepthStencilAttachment.WasPassed()) {
99 const auto& dsa = aDesc.mDepthStencilAttachment.Value();
100 dsDesc.view = dsa.mView->mId;
102 // -
104 if (dsa.mDepthClearValue.WasPassed()) {
105 dsDesc.depth.clear_value = dsa.mDepthClearValue.Value();
107 if (dsa.mDepthLoadOp.WasPassed()) {
108 dsDesc.depth.load_op = ConvertLoadOp(dsa.mDepthLoadOp.Value());
110 if (dsa.mDepthStoreOp.WasPassed()) {
111 dsDesc.depth.store_op = ConvertStoreOp(dsa.mDepthStoreOp.Value());
113 dsDesc.depth.read_only = dsa.mDepthReadOnly;
115 // -
117 dsDesc.stencil.clear_value = dsa.mStencilClearValue;
118 if (dsa.mStencilLoadOp.WasPassed()) {
119 dsDesc.stencil.load_op = ConvertLoadOp(dsa.mStencilLoadOp.Value());
121 if (dsa.mStencilStoreOp.WasPassed()) {
122 dsDesc.stencil.store_op = ConvertStoreOp(dsa.mStencilStoreOp.Value());
124 dsDesc.stencil.read_only = dsa.mStencilReadOnly;
126 // -
128 desc.depth_stencil_attachment = &dsDesc;
131 if (aDesc.mColorAttachments.Length() > WGPUMAX_COLOR_ATTACHMENTS) {
132 aParent->GetDevice()->GenerateValidationError(nsLiteralCString(
133 "Too many color attachments in GPURenderPassDescriptor"));
134 return nullptr;
137 std::array<ffi::WGPURenderPassColorAttachment, WGPUMAX_COLOR_ATTACHMENTS>
138 colorDescs = {};
139 desc.color_attachments = colorDescs.data();
140 desc.color_attachments_length = aDesc.mColorAttachments.Length();
142 for (size_t i = 0; i < aDesc.mColorAttachments.Length(); ++i) {
143 const auto& ca = aDesc.mColorAttachments[i];
144 ffi::WGPURenderPassColorAttachment& cd = colorDescs[i];
145 cd.view = ca.mView->mId;
146 cd.channel.store_op = ConvertStoreOp(ca.mStoreOp);
148 if (ca.mResolveTarget.WasPassed()) {
149 cd.resolve_target = ca.mResolveTarget.Value().mId;
152 cd.channel.load_op = ConvertLoadOp(ca.mLoadOp);
153 if (ca.mClearValue.WasPassed()) {
154 cd.channel.clear_value = ConvertColor(ca.mClearValue.Value());
158 return ffi::wgpu_command_encoder_begin_render_pass(&desc);
161 RenderPassEncoder::RenderPassEncoder(CommandEncoder* const aParent,
162 const dom::GPURenderPassDescriptor& aDesc)
163 : ChildOf(aParent), mPass(BeginRenderPass(aParent, aDesc)) {
164 if (!mPass) {
165 mValid = false;
166 return;
169 for (const auto& at : aDesc.mColorAttachments) {
170 mUsedTextureViews.AppendElement(at.mView);
172 if (aDesc.mDepthStencilAttachment.WasPassed()) {
173 mUsedTextureViews.AppendElement(
174 aDesc.mDepthStencilAttachment.Value().mView);
178 RenderPassEncoder::~RenderPassEncoder() {
179 if (mValid) {
180 mValid = false;
184 void RenderPassEncoder::SetBindGroup(
185 uint32_t aSlot, const BindGroup& aBindGroup,
186 const dom::Sequence<uint32_t>& aDynamicOffsets) {
187 if (mValid) {
188 mUsedBindGroups.AppendElement(&aBindGroup);
189 ffi::wgpu_recorded_render_pass_set_bind_group(
190 mPass.get(), aSlot, aBindGroup.mId, aDynamicOffsets.Elements(),
191 aDynamicOffsets.Length());
195 void RenderPassEncoder::SetPipeline(const RenderPipeline& aPipeline) {
196 if (mValid) {
197 mUsedPipelines.AppendElement(&aPipeline);
198 ffi::wgpu_recorded_render_pass_set_pipeline(mPass.get(), aPipeline.mId);
202 void RenderPassEncoder::SetIndexBuffer(const Buffer& aBuffer,
203 const dom::GPUIndexFormat& aIndexFormat,
204 uint64_t aOffset, uint64_t aSize) {
205 if (mValid) {
206 mUsedBuffers.AppendElement(&aBuffer);
207 const auto iformat = aIndexFormat == dom::GPUIndexFormat::Uint32
208 ? ffi::WGPUIndexFormat_Uint32
209 : ffi::WGPUIndexFormat_Uint16;
210 ffi::wgpu_recorded_render_pass_set_index_buffer(mPass.get(), aBuffer.mId,
211 iformat, aOffset, aSize);
215 void RenderPassEncoder::SetVertexBuffer(uint32_t aSlot, const Buffer& aBuffer,
216 uint64_t aOffset, uint64_t aSize) {
217 if (mValid) {
218 mUsedBuffers.AppendElement(&aBuffer);
219 ffi::wgpu_recorded_render_pass_set_vertex_buffer(
220 mPass.get(), aSlot, aBuffer.mId, aOffset, aSize);
224 void RenderPassEncoder::Draw(uint32_t aVertexCount, uint32_t aInstanceCount,
225 uint32_t aFirstVertex, uint32_t aFirstInstance) {
226 if (mValid) {
227 ffi::wgpu_recorded_render_pass_draw(mPass.get(), aVertexCount,
228 aInstanceCount, aFirstVertex,
229 aFirstInstance);
233 void RenderPassEncoder::DrawIndexed(uint32_t aIndexCount,
234 uint32_t aInstanceCount,
235 uint32_t aFirstIndex, int32_t aBaseVertex,
236 uint32_t aFirstInstance) {
237 if (mValid) {
238 ffi::wgpu_recorded_render_pass_draw_indexed(mPass.get(), aIndexCount,
239 aInstanceCount, aFirstIndex,
240 aBaseVertex, aFirstInstance);
244 void RenderPassEncoder::DrawIndirect(const Buffer& aIndirectBuffer,
245 uint64_t aIndirectOffset) {
246 if (mValid) {
247 ffi::wgpu_recorded_render_pass_draw_indirect(
248 mPass.get(), aIndirectBuffer.mId, aIndirectOffset);
252 void RenderPassEncoder::DrawIndexedIndirect(const Buffer& aIndirectBuffer,
253 uint64_t aIndirectOffset) {
254 if (mValid) {
255 ffi::wgpu_recorded_render_pass_draw_indexed_indirect(
256 mPass.get(), aIndirectBuffer.mId, aIndirectOffset);
260 void RenderPassEncoder::SetViewport(float x, float y, float width, float height,
261 float minDepth, float maxDepth) {
262 if (mValid) {
263 ffi::wgpu_recorded_render_pass_set_viewport(mPass.get(), x, y, width,
264 height, minDepth, maxDepth);
268 void RenderPassEncoder::SetScissorRect(uint32_t x, uint32_t y, uint32_t width,
269 uint32_t height) {
270 if (mValid) {
271 ffi::wgpu_recorded_render_pass_set_scissor_rect(mPass.get(), x, y, width,
272 height);
276 void RenderPassEncoder::SetBlendConstant(
277 const dom::DoubleSequenceOrGPUColorDict& color) {
278 if (mValid) {
279 ffi::WGPUColor aColor = ConvertColor(color);
280 ffi::wgpu_recorded_render_pass_set_blend_constant(mPass.get(), &aColor);
284 void RenderPassEncoder::SetStencilReference(uint32_t reference) {
285 if (mValid) {
286 ffi::wgpu_recorded_render_pass_set_stencil_reference(mPass.get(),
287 reference);
291 void RenderPassEncoder::ExecuteBundles(
292 const dom::Sequence<OwningNonNull<RenderBundle>>& aBundles) {
293 if (mValid) {
294 nsTArray<ffi::WGPURenderBundleId> renderBundles(aBundles.Length());
295 for (const auto& bundle : aBundles) {
296 mUsedRenderBundles.AppendElement(bundle);
297 renderBundles.AppendElement(bundle->mId);
299 ffi::wgpu_recorded_render_pass_execute_bundles(
300 mPass.get(), renderBundles.Elements(), renderBundles.Length());
304 void RenderPassEncoder::PushDebugGroup(const nsAString& aString) {
305 if (mValid) {
306 const NS_ConvertUTF16toUTF8 utf8(aString);
307 ffi::wgpu_recorded_render_pass_push_debug_group(mPass.get(), utf8.get(), 0);
310 void RenderPassEncoder::PopDebugGroup() {
311 if (mValid) {
312 ffi::wgpu_recorded_render_pass_pop_debug_group(mPass.get());
315 void RenderPassEncoder::InsertDebugMarker(const nsAString& aString) {
316 if (mValid) {
317 const NS_ConvertUTF16toUTF8 utf8(aString);
318 ffi::wgpu_recorded_render_pass_insert_debug_marker(mPass.get(), utf8.get(),
323 void RenderPassEncoder::End() {
324 if (mValid) {
325 mValid = false;
326 auto* pass = mPass.release();
327 MOZ_ASSERT(pass);
328 mParent->EndRenderPass(*pass);
332 } // namespace mozilla::webgpu