Bug 1852740: add tests for the `fetchpriority` attribute in Link headers. r=necko...
[gecko.git] / dom / webgpu / RenderPassEncoder.cpp
blob437d999322f336b9e0cb86c6e7006f485566f24e
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 ffi::WGPURenderPass* ScopedFfiRenderTraits::empty() { return nullptr; }
23 void ScopedFfiRenderTraits::release(ffi::WGPURenderPass* raw) {
24 if (raw) {
25 ffi::wgpu_render_pass_destroy(raw);
29 static ffi::WGPULoadOp ConvertLoadOp(const dom::GPULoadOp& aOp) {
30 switch (aOp) {
31 case dom::GPULoadOp::Load:
32 return ffi::WGPULoadOp_Load;
33 case dom::GPULoadOp::Clear:
34 return ffi::WGPULoadOp_Clear;
35 case dom::GPULoadOp::EndGuard_:
36 break;
38 MOZ_CRASH("bad GPULoadOp");
41 static ffi::WGPUStoreOp ConvertStoreOp(const dom::GPUStoreOp& aOp) {
42 switch (aOp) {
43 case dom::GPUStoreOp::Store:
44 return ffi::WGPUStoreOp_Store;
45 case dom::GPUStoreOp::Discard:
46 return ffi::WGPUStoreOp_Discard;
47 case dom::GPUStoreOp::EndGuard_:
48 break;
50 MOZ_CRASH("bad GPUStoreOp");
53 static ffi::WGPUColor ConvertColor(const dom::Sequence<double>& aSeq) {
54 ffi::WGPUColor color;
55 color.r = aSeq.SafeElementAt(0, 0.0);
56 color.g = aSeq.SafeElementAt(1, 0.0);
57 color.b = aSeq.SafeElementAt(2, 0.0);
58 color.a = aSeq.SafeElementAt(3, 1.0);
59 return color;
62 static ffi::WGPUColor ConvertColor(const dom::GPUColorDict& aColor) {
63 ffi::WGPUColor color = {aColor.mR, aColor.mG, aColor.mB, aColor.mA};
64 return color;
67 static ffi::WGPUColor ConvertColor(
68 const dom::DoubleSequenceOrGPUColorDict& aColor) {
69 if (aColor.IsDoubleSequence()) {
70 return ConvertColor(aColor.GetAsDoubleSequence());
72 if (aColor.IsGPUColorDict()) {
73 return ConvertColor(aColor.GetAsGPUColorDict());
75 MOZ_ASSERT_UNREACHABLE(
76 "Unexpected dom::DoubleSequenceOrGPUColorDict variant");
77 return ffi::WGPUColor();
79 static ffi::WGPUColor ConvertColor(
80 const dom::OwningDoubleSequenceOrGPUColorDict& aColor) {
81 if (aColor.IsDoubleSequence()) {
82 return ConvertColor(aColor.GetAsDoubleSequence());
84 if (aColor.IsGPUColorDict()) {
85 return ConvertColor(aColor.GetAsGPUColorDict());
87 MOZ_ASSERT_UNREACHABLE(
88 "Unexpected dom::OwningDoubleSequenceOrGPUColorDict variant");
89 return ffi::WGPUColor();
92 ffi::WGPURenderPass* BeginRenderPass(
93 CommandEncoder* const aParent, const dom::GPURenderPassDescriptor& aDesc) {
94 ffi::WGPURenderPassDescriptor desc = {};
96 webgpu::StringHelper label(aDesc.mLabel);
97 desc.label = label.Get();
99 ffi::WGPURenderPassDepthStencilAttachment dsDesc = {};
100 if (aDesc.mDepthStencilAttachment.WasPassed()) {
101 const auto& dsa = aDesc.mDepthStencilAttachment.Value();
102 dsDesc.view = dsa.mView->mId;
104 // -
106 if (dsa.mDepthClearValue.WasPassed()) {
107 dsDesc.depth.clear_value = dsa.mDepthClearValue.Value();
109 if (dsa.mDepthLoadOp.WasPassed()) {
110 dsDesc.depth.load_op = ConvertLoadOp(dsa.mDepthLoadOp.Value());
112 if (dsa.mDepthStoreOp.WasPassed()) {
113 dsDesc.depth.store_op = ConvertStoreOp(dsa.mDepthStoreOp.Value());
115 dsDesc.depth.read_only = dsa.mDepthReadOnly;
117 // -
119 dsDesc.stencil.clear_value = dsa.mStencilClearValue;
120 if (dsa.mStencilLoadOp.WasPassed()) {
121 dsDesc.stencil.load_op = ConvertLoadOp(dsa.mStencilLoadOp.Value());
123 if (dsa.mStencilStoreOp.WasPassed()) {
124 dsDesc.stencil.store_op = ConvertStoreOp(dsa.mStencilStoreOp.Value());
126 dsDesc.stencil.read_only = dsa.mStencilReadOnly;
128 // -
130 desc.depth_stencil_attachment = &dsDesc;
133 if (aDesc.mColorAttachments.Length() > WGPUMAX_COLOR_ATTACHMENTS) {
134 aParent->GetDevice()->GenerateValidationError(nsLiteralCString(
135 "Too many color attachments in GPURenderPassDescriptor"));
136 return nullptr;
139 std::array<ffi::WGPURenderPassColorAttachment, WGPUMAX_COLOR_ATTACHMENTS>
140 colorDescs = {};
141 desc.color_attachments = colorDescs.data();
142 desc.color_attachments_length = aDesc.mColorAttachments.Length();
144 for (size_t i = 0; i < aDesc.mColorAttachments.Length(); ++i) {
145 const auto& ca = aDesc.mColorAttachments[i];
146 ffi::WGPURenderPassColorAttachment& cd = colorDescs[i];
147 cd.view = ca.mView->mId;
148 cd.channel.store_op = ConvertStoreOp(ca.mStoreOp);
150 if (ca.mResolveTarget.WasPassed()) {
151 cd.resolve_target = ca.mResolveTarget.Value().mId;
154 cd.channel.load_op = ConvertLoadOp(ca.mLoadOp);
155 if (ca.mClearValue.WasPassed()) {
156 cd.channel.clear_value = ConvertColor(ca.mClearValue.Value());
160 return ffi::wgpu_command_encoder_begin_render_pass(aParent->mId, &desc);
163 RenderPassEncoder::RenderPassEncoder(CommandEncoder* const aParent,
164 const dom::GPURenderPassDescriptor& aDesc)
165 : ChildOf(aParent), mPass(BeginRenderPass(aParent, aDesc)) {
166 if (!mPass) {
167 mValid = false;
168 return;
171 for (const auto& at : aDesc.mColorAttachments) {
172 mUsedTextureViews.AppendElement(at.mView);
174 if (aDesc.mDepthStencilAttachment.WasPassed()) {
175 mUsedTextureViews.AppendElement(
176 aDesc.mDepthStencilAttachment.Value().mView);
180 RenderPassEncoder::~RenderPassEncoder() {
181 if (mValid) {
182 mValid = false;
186 void RenderPassEncoder::SetBindGroup(
187 uint32_t aSlot, const BindGroup& aBindGroup,
188 const dom::Sequence<uint32_t>& aDynamicOffsets) {
189 if (mValid) {
190 mUsedBindGroups.AppendElement(&aBindGroup);
191 ffi::wgpu_render_pass_set_bind_group(mPass, aSlot, aBindGroup.mId,
192 aDynamicOffsets.Elements(),
193 aDynamicOffsets.Length());
197 void RenderPassEncoder::SetPipeline(const RenderPipeline& aPipeline) {
198 if (mValid) {
199 mUsedPipelines.AppendElement(&aPipeline);
200 ffi::wgpu_render_pass_set_pipeline(mPass, aPipeline.mId);
204 void RenderPassEncoder::SetIndexBuffer(const Buffer& aBuffer,
205 const dom::GPUIndexFormat& aIndexFormat,
206 uint64_t aOffset, uint64_t aSize) {
207 if (mValid) {
208 mUsedBuffers.AppendElement(&aBuffer);
209 const auto iformat = aIndexFormat == dom::GPUIndexFormat::Uint32
210 ? ffi::WGPUIndexFormat_Uint32
211 : ffi::WGPUIndexFormat_Uint16;
212 ffi::wgpu_render_pass_set_index_buffer(mPass, aBuffer.mId, iformat, aOffset,
213 aSize);
217 void RenderPassEncoder::SetVertexBuffer(uint32_t aSlot, const Buffer& aBuffer,
218 uint64_t aOffset, uint64_t aSize) {
219 if (mValid) {
220 mUsedBuffers.AppendElement(&aBuffer);
221 ffi::wgpu_render_pass_set_vertex_buffer(mPass, aSlot, aBuffer.mId, aOffset,
222 aSize);
226 void RenderPassEncoder::Draw(uint32_t aVertexCount, uint32_t aInstanceCount,
227 uint32_t aFirstVertex, uint32_t aFirstInstance) {
228 if (mValid) {
229 ffi::wgpu_render_pass_draw(mPass, aVertexCount, aInstanceCount,
230 aFirstVertex, aFirstInstance);
234 void RenderPassEncoder::DrawIndexed(uint32_t aIndexCount,
235 uint32_t aInstanceCount,
236 uint32_t aFirstIndex, int32_t aBaseVertex,
237 uint32_t aFirstInstance) {
238 if (mValid) {
239 ffi::wgpu_render_pass_draw_indexed(mPass, aIndexCount, aInstanceCount,
240 aFirstIndex, aBaseVertex,
241 aFirstInstance);
245 void RenderPassEncoder::DrawIndirect(const Buffer& aIndirectBuffer,
246 uint64_t aIndirectOffset) {
247 if (mValid) {
248 ffi::wgpu_render_pass_draw_indirect(mPass, aIndirectBuffer.mId,
249 aIndirectOffset);
253 void RenderPassEncoder::DrawIndexedIndirect(const Buffer& aIndirectBuffer,
254 uint64_t aIndirectOffset) {
255 if (mValid) {
256 ffi::wgpu_render_pass_draw_indexed_indirect(mPass, aIndirectBuffer.mId,
257 aIndirectOffset);
261 void RenderPassEncoder::SetViewport(float x, float y, float width, float height,
262 float minDepth, float maxDepth) {
263 if (mValid) {
264 ffi::wgpu_render_pass_set_viewport(mPass, x, y, width, height, minDepth,
265 maxDepth);
269 void RenderPassEncoder::SetScissorRect(uint32_t x, uint32_t y, uint32_t width,
270 uint32_t height) {
271 if (mValid) {
272 ffi::wgpu_render_pass_set_scissor_rect(mPass, x, y, width, height);
276 void RenderPassEncoder::SetBlendConstant(
277 const dom::DoubleSequenceOrGPUColorDict& color) {
278 if (mValid) {
279 ffi::WGPUColor aColor = ConvertColor(color);
280 ffi::wgpu_render_pass_set_blend_constant(mPass, &aColor);
284 void RenderPassEncoder::SetStencilReference(uint32_t reference) {
285 if (mValid) {
286 ffi::wgpu_render_pass_set_stencil_reference(mPass, reference);
290 void RenderPassEncoder::ExecuteBundles(
291 const dom::Sequence<OwningNonNull<RenderBundle>>& aBundles) {
292 if (mValid) {
293 nsTArray<ffi::WGPURenderBundleId> renderBundles(aBundles.Length());
294 for (const auto& bundle : aBundles) {
295 mUsedRenderBundles.AppendElement(bundle);
296 renderBundles.AppendElement(bundle->mId);
298 ffi::wgpu_render_pass_execute_bundles(mPass, renderBundles.Elements(),
299 renderBundles.Length());
303 void RenderPassEncoder::PushDebugGroup(const nsAString& aString) {
304 if (mValid) {
305 const NS_ConvertUTF16toUTF8 utf8(aString);
306 ffi::wgpu_render_pass_push_debug_group(mPass, utf8.get(), 0);
309 void RenderPassEncoder::PopDebugGroup() {
310 if (mValid) {
311 ffi::wgpu_render_pass_pop_debug_group(mPass);
314 void RenderPassEncoder::InsertDebugMarker(const nsAString& aString) {
315 if (mValid) {
316 const NS_ConvertUTF16toUTF8 utf8(aString);
317 ffi::wgpu_render_pass_insert_debug_marker(mPass, utf8.get(), 0);
321 void RenderPassEncoder::End(ErrorResult& aRv) {
322 if (mValid) {
323 mValid = false;
324 auto* pass = mPass.forget();
325 MOZ_ASSERT(pass);
326 mParent->EndRenderPass(*pass, aRv);
330 } // namespace mozilla::webgpu