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"
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
,
19 GPU_IMPL_JS_WRAP(RenderPassEncoder
)
21 void ffiWGPURenderPassDeleter::operator()(ffi::WGPURecordedRenderPass
* raw
) {
23 ffi::wgpu_render_pass_destroy(raw
);
27 static ffi::WGPULoadOp
ConvertLoadOp(const dom::GPULoadOp
& 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_
:
36 MOZ_CRASH("bad GPULoadOp");
39 static ffi::WGPUStoreOp
ConvertStoreOp(const dom::GPUStoreOp
& 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_
:
48 MOZ_CRASH("bad GPUStoreOp");
51 static ffi::WGPUColor
ConvertColor(const dom::Sequence
<double>& aSeq
) {
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);
60 static ffi::WGPUColor
ConvertColor(const dom::GPUColorDict
& aColor
) {
61 ffi::WGPUColor color
= {aColor
.mR
, aColor
.mG
, aColor
.mB
, aColor
.mA
};
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
;
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
;
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
;
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"));
137 std::array
<ffi::WGPURenderPassColorAttachment
, WGPUMAX_COLOR_ATTACHMENTS
>
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
)) {
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() {
184 void RenderPassEncoder::SetBindGroup(
185 uint32_t aSlot
, const BindGroup
& aBindGroup
,
186 const dom::Sequence
<uint32_t>& aDynamicOffsets
) {
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
) {
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
) {
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
) {
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
) {
227 ffi::wgpu_recorded_render_pass_draw(mPass
.get(), aVertexCount
,
228 aInstanceCount
, aFirstVertex
,
233 void RenderPassEncoder::DrawIndexed(uint32_t aIndexCount
,
234 uint32_t aInstanceCount
,
235 uint32_t aFirstIndex
, int32_t aBaseVertex
,
236 uint32_t aFirstInstance
) {
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
) {
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
) {
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
) {
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
,
271 ffi::wgpu_recorded_render_pass_set_scissor_rect(mPass
.get(), x
, y
, width
,
276 void RenderPassEncoder::SetBlendConstant(
277 const dom::DoubleSequenceOrGPUColorDict
& color
) {
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
) {
286 ffi::wgpu_recorded_render_pass_set_stencil_reference(mPass
.get(),
291 void RenderPassEncoder::ExecuteBundles(
292 const dom::Sequence
<OwningNonNull
<RenderBundle
>>& aBundles
) {
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
) {
306 const NS_ConvertUTF16toUTF8
utf8(aString
);
307 ffi::wgpu_recorded_render_pass_push_debug_group(mPass
.get(), utf8
.get(), 0);
310 void RenderPassEncoder::PopDebugGroup() {
312 ffi::wgpu_recorded_render_pass_pop_debug_group(mPass
.get());
315 void RenderPassEncoder::InsertDebugMarker(const nsAString
& aString
) {
317 const NS_ConvertUTF16toUTF8
utf8(aString
);
318 ffi::wgpu_recorded_render_pass_insert_debug_marker(mPass
.get(), utf8
.get(),
323 void RenderPassEncoder::End() {
326 auto* pass
= mPass
.release();
328 mParent
->EndRenderPass(*pass
);
332 } // namespace mozilla::webgpu