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/. */
5
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"
13
14 namespace mozilla {
15 namespace webgpu {
16
GPU_IMPL_CYCLE_COLLECTION(RenderPassEncoder,mParent,mUsedBindGroups,mUsedBuffers,mUsedPipelines,mUsedTextureViews,mUsedRenderBundles)17 GPU_IMPL_CYCLE_COLLECTION(RenderPassEncoder, mParent, mUsedBindGroups,
18 mUsedBuffers, mUsedPipelines, mUsedTextureViews,
19 mUsedRenderBundles)
20 GPU_IMPL_JS_WRAP(RenderPassEncoder)
21
22 ffi::WGPURenderPass* ScopedFfiRenderTraits::empty() { return nullptr; }
23
release(ffi::WGPURenderPass * raw)24 void ScopedFfiRenderTraits::release(ffi::WGPURenderPass* raw) {
25 if (raw) {
26 ffi::wgpu_render_pass_destroy(raw);
27 }
28 }
29
ConvertLoadOp(const dom::GPULoadOp & aOp)30 ffi::WGPULoadOp ConvertLoadOp(const dom::GPULoadOp& aOp) {
31 switch (aOp) {
32 case dom::GPULoadOp::Load:
33 return ffi::WGPULoadOp_Load;
34 default:
35 MOZ_CRASH("Unexpected load op");
36 }
37 }
38
ConvertStoreOp(const dom::GPUStoreOp & aOp)39 ffi::WGPUStoreOp ConvertStoreOp(const dom::GPUStoreOp& aOp) {
40 switch (aOp) {
41 case dom::GPUStoreOp::Store:
42 return ffi::WGPUStoreOp_Store;
43 case dom::GPUStoreOp::Clear:
44 return ffi::WGPUStoreOp_Clear;
45 default:
46 MOZ_CRASH("Unexpected load op");
47 }
48 }
49
ConvertColor(const dom::GPUColorDict & aColor)50 ffi::WGPUColor ConvertColor(const dom::GPUColorDict& aColor) {
51 ffi::WGPUColor color = {aColor.mR, aColor.mG, aColor.mB, aColor.mA};
52 return color;
53 }
54
BeginRenderPass(RawId aEncoderId,const dom::GPURenderPassDescriptor & aDesc)55 ffi::WGPURenderPass* BeginRenderPass(
56 RawId aEncoderId, const dom::GPURenderPassDescriptor& aDesc) {
57 ffi::WGPURenderPassDescriptor desc = {};
58
59 ffi::WGPURenderPassDepthStencilAttachment dsDesc = {};
60 if (aDesc.mDepthStencilAttachment.WasPassed()) {
61 const auto& dsa = aDesc.mDepthStencilAttachment.Value();
62 dsDesc.view = dsa.mView->mId;
63
64 if (dsa.mDepthLoadValue.IsFloat()) {
65 dsDesc.depth.load_op = ffi::WGPULoadOp_Clear;
66 dsDesc.depth.clear_value = dsa.mDepthLoadValue.GetAsFloat();
67 }
68 if (dsa.mDepthLoadValue.IsGPULoadOp()) {
69 dsDesc.depth.load_op =
70 ConvertLoadOp(dsa.mDepthLoadValue.GetAsGPULoadOp());
71 }
72 dsDesc.depth.store_op = ConvertStoreOp(dsa.mDepthStoreOp);
73
74 if (dsa.mStencilLoadValue.IsRangeEnforcedUnsignedLong()) {
75 dsDesc.stencil.load_op = ffi::WGPULoadOp_Clear;
76 dsDesc.stencil.clear_value =
77 dsa.mStencilLoadValue.GetAsRangeEnforcedUnsignedLong();
78 }
79 if (dsa.mStencilLoadValue.IsGPULoadOp()) {
80 dsDesc.stencil.load_op =
81 ConvertLoadOp(dsa.mStencilLoadValue.GetAsGPULoadOp());
82 }
83 dsDesc.stencil.store_op = ConvertStoreOp(dsa.mStencilStoreOp);
84
85 desc.depth_stencil_attachment = &dsDesc;
86 }
87
88 std::array<ffi::WGPURenderPassColorAttachment, WGPUMAX_COLOR_TARGETS>
89 colorDescs = {};
90 desc.color_attachments = colorDescs.data();
91 desc.color_attachments_length = aDesc.mColorAttachments.Length();
92
93 for (size_t i = 0; i < aDesc.mColorAttachments.Length(); ++i) {
94 const auto& ca = aDesc.mColorAttachments[i];
95 ffi::WGPURenderPassColorAttachment& cd = colorDescs[i];
96 cd.view = ca.mView->mId;
97 cd.channel.store_op = ConvertStoreOp(ca.mStoreOp);
98
99 if (ca.mResolveTarget.WasPassed()) {
100 cd.resolve_target = ca.mResolveTarget.Value().mId;
101 }
102 if (ca.mLoadValue.IsGPULoadOp()) {
103 cd.channel.load_op = ConvertLoadOp(ca.mLoadValue.GetAsGPULoadOp());
104 } else {
105 cd.channel.load_op = ffi::WGPULoadOp_Clear;
106 if (ca.mLoadValue.IsDoubleSequence()) {
107 const auto& seq = ca.mLoadValue.GetAsDoubleSequence();
108 if (seq.Length() >= 1) {
109 cd.channel.clear_value.r = seq[0];
110 }
111 if (seq.Length() >= 2) {
112 cd.channel.clear_value.g = seq[1];
113 }
114 if (seq.Length() >= 3) {
115 cd.channel.clear_value.b = seq[2];
116 }
117 if (seq.Length() >= 4) {
118 cd.channel.clear_value.a = seq[3];
119 }
120 }
121 if (ca.mLoadValue.IsGPUColorDict()) {
122 cd.channel.clear_value =
123 ConvertColor(ca.mLoadValue.GetAsGPUColorDict());
124 }
125 }
126 }
127
128 return ffi::wgpu_command_encoder_begin_render_pass(aEncoderId, &desc);
129 }
130
RenderPassEncoder(CommandEncoder * const aParent,const dom::GPURenderPassDescriptor & aDesc)131 RenderPassEncoder::RenderPassEncoder(CommandEncoder* const aParent,
132 const dom::GPURenderPassDescriptor& aDesc)
133 : ChildOf(aParent), mPass(BeginRenderPass(aParent->mId, aDesc)) {
134 for (const auto& at : aDesc.mColorAttachments) {
135 mUsedTextureViews.AppendElement(at.mView);
136 }
137 if (aDesc.mDepthStencilAttachment.WasPassed()) {
138 mUsedTextureViews.AppendElement(
139 aDesc.mDepthStencilAttachment.Value().mView);
140 }
141 }
142
~RenderPassEncoder()143 RenderPassEncoder::~RenderPassEncoder() {
144 if (mValid) {
145 mValid = false;
146 }
147 }
148
SetBindGroup(uint32_t aSlot,const BindGroup & aBindGroup,const dom::Sequence<uint32_t> & aDynamicOffsets)149 void RenderPassEncoder::SetBindGroup(
150 uint32_t aSlot, const BindGroup& aBindGroup,
151 const dom::Sequence<uint32_t>& aDynamicOffsets) {
152 if (mValid) {
153 mUsedBindGroups.AppendElement(&aBindGroup);
154 ffi::wgpu_render_pass_set_bind_group(mPass, aSlot, aBindGroup.mId,
155 aDynamicOffsets.Elements(),
156 aDynamicOffsets.Length());
157 }
158 }
159
SetPipeline(const RenderPipeline & aPipeline)160 void RenderPassEncoder::SetPipeline(const RenderPipeline& aPipeline) {
161 if (mValid) {
162 mUsedPipelines.AppendElement(&aPipeline);
163 ffi::wgpu_render_pass_set_pipeline(mPass, aPipeline.mId);
164 }
165 }
166
SetIndexBuffer(const Buffer & aBuffer,const dom::GPUIndexFormat & aIndexFormat,uint64_t aOffset,uint64_t aSize)167 void RenderPassEncoder::SetIndexBuffer(const Buffer& aBuffer,
168 const dom::GPUIndexFormat& aIndexFormat,
169 uint64_t aOffset, uint64_t aSize) {
170 if (mValid) {
171 mUsedBuffers.AppendElement(&aBuffer);
172 const auto iformat = aIndexFormat == dom::GPUIndexFormat::Uint32
173 ? ffi::WGPUIndexFormat_Uint32
174 : ffi::WGPUIndexFormat_Uint16;
175 ffi::wgpu_render_pass_set_index_buffer(mPass, aBuffer.mId, iformat, aOffset,
176 aSize);
177 }
178 }
179
SetVertexBuffer(uint32_t aSlot,const Buffer & aBuffer,uint64_t aOffset,uint64_t aSize)180 void RenderPassEncoder::SetVertexBuffer(uint32_t aSlot, const Buffer& aBuffer,
181 uint64_t aOffset, uint64_t aSize) {
182 if (mValid) {
183 mUsedBuffers.AppendElement(&aBuffer);
184 ffi::wgpu_render_pass_set_vertex_buffer(mPass, aSlot, aBuffer.mId, aOffset,
185 aSize);
186 }
187 }
188
Draw(uint32_t aVertexCount,uint32_t aInstanceCount,uint32_t aFirstVertex,uint32_t aFirstInstance)189 void RenderPassEncoder::Draw(uint32_t aVertexCount, uint32_t aInstanceCount,
190 uint32_t aFirstVertex, uint32_t aFirstInstance) {
191 if (mValid) {
192 ffi::wgpu_render_pass_draw(mPass, aVertexCount, aInstanceCount,
193 aFirstVertex, aFirstInstance);
194 }
195 }
196
DrawIndexed(uint32_t aIndexCount,uint32_t aInstanceCount,uint32_t aFirstIndex,int32_t aBaseVertex,uint32_t aFirstInstance)197 void RenderPassEncoder::DrawIndexed(uint32_t aIndexCount,
198 uint32_t aInstanceCount,
199 uint32_t aFirstIndex, int32_t aBaseVertex,
200 uint32_t aFirstInstance) {
201 if (mValid) {
202 ffi::wgpu_render_pass_draw_indexed(mPass, aIndexCount, aInstanceCount,
203 aFirstIndex, aBaseVertex,
204 aFirstInstance);
205 }
206 }
207
DrawIndirect(const Buffer & aIndirectBuffer,uint64_t aIndirectOffset)208 void RenderPassEncoder::DrawIndirect(const Buffer& aIndirectBuffer,
209 uint64_t aIndirectOffset) {
210 if (mValid) {
211 ffi::wgpu_render_pass_draw_indirect(mPass, aIndirectBuffer.mId,
212 aIndirectOffset);
213 }
214 }
215
DrawIndexedIndirect(const Buffer & aIndirectBuffer,uint64_t aIndirectOffset)216 void RenderPassEncoder::DrawIndexedIndirect(const Buffer& aIndirectBuffer,
217 uint64_t aIndirectOffset) {
218 if (mValid) {
219 ffi::wgpu_render_pass_draw_indexed_indirect(mPass, aIndirectBuffer.mId,
220 aIndirectOffset);
221 }
222 }
223
SetViewport(float x,float y,float width,float height,float minDepth,float maxDepth)224 void RenderPassEncoder::SetViewport(float x, float y, float width, float height,
225 float minDepth, float maxDepth) {
226 if (mValid) {
227 ffi::wgpu_render_pass_set_viewport(mPass, x, y, width, height, minDepth,
228 maxDepth);
229 }
230 }
231
SetScissorRect(uint32_t x,uint32_t y,uint32_t width,uint32_t height)232 void RenderPassEncoder::SetScissorRect(uint32_t x, uint32_t y, uint32_t width,
233 uint32_t height) {
234 if (mValid) {
235 ffi::wgpu_render_pass_set_scissor_rect(mPass, x, y, width, height);
236 }
237 }
238
SetBlendConstant(const dom::DoubleSequenceOrGPUColorDict & color)239 void RenderPassEncoder::SetBlendConstant(
240 const dom::DoubleSequenceOrGPUColorDict& color) {
241 if (mValid) {
242 ffi::WGPUColor aColor = ConvertColor(color.GetAsGPUColorDict());
243 ffi::wgpu_render_pass_set_blend_constant(mPass, &aColor);
244 }
245 }
246
SetStencilReference(uint32_t reference)247 void RenderPassEncoder::SetStencilReference(uint32_t reference) {
248 if (mValid) {
249 ffi::wgpu_render_pass_set_stencil_reference(mPass, reference);
250 }
251 }
252
ExecuteBundles(const dom::Sequence<OwningNonNull<RenderBundle>> & aBundles)253 void RenderPassEncoder::ExecuteBundles(
254 const dom::Sequence<OwningNonNull<RenderBundle>>& aBundles) {
255 if (mValid) {
256 nsTArray<ffi::WGPURenderBundleId> renderBundles(aBundles.Length());
257 for (const auto& bundle : aBundles) {
258 mUsedRenderBundles.AppendElement(bundle);
259 renderBundles.AppendElement(bundle->mId);
260 }
261 ffi::wgpu_render_pass_execute_bundles(mPass, renderBundles.Elements(),
262 renderBundles.Length());
263 }
264 }
265
EndPass(ErrorResult & aRv)266 void RenderPassEncoder::EndPass(ErrorResult& aRv) {
267 if (mValid) {
268 mValid = false;
269 auto* pass = mPass.forget();
270 MOZ_ASSERT(pass);
271 mParent->EndRenderPass(*pass, aRv);
272 }
273 }
274
275 } // namespace webgpu
276 } // namespace mozilla
277