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
;
34 MOZ_CRASH("bad GPULoadOp");
37 static ffi::WGPUStoreOp
ConvertStoreOp(const dom::GPUStoreOp
& aOp
) {
39 case dom::GPUStoreOp::Store
:
40 return ffi::WGPUStoreOp_Store
;
41 case dom::GPUStoreOp::Discard
:
42 return ffi::WGPUStoreOp_Discard
;
44 MOZ_CRASH("bad GPUStoreOp");
47 static ffi::WGPUColor
ConvertColor(const dom::Sequence
<double>& aSeq
) {
49 color
.r
= aSeq
.SafeElementAt(0, 0.0);
50 color
.g
= aSeq
.SafeElementAt(1, 0.0);
51 color
.b
= aSeq
.SafeElementAt(2, 0.0);
52 color
.a
= aSeq
.SafeElementAt(3, 1.0);
56 static ffi::WGPUColor
ConvertColor(const dom::GPUColorDict
& aColor
) {
57 ffi::WGPUColor color
= {aColor
.mR
, aColor
.mG
, aColor
.mB
, aColor
.mA
};
61 static ffi::WGPUColor
ConvertColor(
62 const dom::DoubleSequenceOrGPUColorDict
& aColor
) {
63 if (aColor
.IsDoubleSequence()) {
64 return ConvertColor(aColor
.GetAsDoubleSequence());
66 if (aColor
.IsGPUColorDict()) {
67 return ConvertColor(aColor
.GetAsGPUColorDict());
69 MOZ_ASSERT_UNREACHABLE(
70 "Unexpected dom::DoubleSequenceOrGPUColorDict variant");
71 return ffi::WGPUColor();
73 static ffi::WGPUColor
ConvertColor(
74 const dom::OwningDoubleSequenceOrGPUColorDict
& aColor
) {
75 if (aColor
.IsDoubleSequence()) {
76 return ConvertColor(aColor
.GetAsDoubleSequence());
78 if (aColor
.IsGPUColorDict()) {
79 return ConvertColor(aColor
.GetAsGPUColorDict());
81 MOZ_ASSERT_UNREACHABLE(
82 "Unexpected dom::OwningDoubleSequenceOrGPUColorDict variant");
83 return ffi::WGPUColor();
86 ffi::WGPURecordedRenderPass
* BeginRenderPass(
87 CommandEncoder
* const aParent
, const dom::GPURenderPassDescriptor
& aDesc
) {
88 ffi::WGPURenderPassDescriptor desc
= {};
90 webgpu::StringHelper
label(aDesc
.mLabel
);
91 desc
.label
= label
.Get();
93 ffi::WGPURenderPassDepthStencilAttachment dsDesc
= {};
94 if (aDesc
.mDepthStencilAttachment
.WasPassed()) {
95 const auto& dsa
= aDesc
.mDepthStencilAttachment
.Value();
96 dsDesc
.view
= dsa
.mView
->mId
;
100 if (dsa
.mDepthClearValue
.WasPassed()) {
101 dsDesc
.depth
.clear_value
= dsa
.mDepthClearValue
.Value();
103 if (dsa
.mDepthLoadOp
.WasPassed()) {
104 dsDesc
.depth
.load_op
= ConvertLoadOp(dsa
.mDepthLoadOp
.Value());
106 if (dsa
.mDepthStoreOp
.WasPassed()) {
107 dsDesc
.depth
.store_op
= ConvertStoreOp(dsa
.mDepthStoreOp
.Value());
109 dsDesc
.depth
.read_only
= dsa
.mDepthReadOnly
;
113 dsDesc
.stencil
.clear_value
= dsa
.mStencilClearValue
;
114 if (dsa
.mStencilLoadOp
.WasPassed()) {
115 dsDesc
.stencil
.load_op
= ConvertLoadOp(dsa
.mStencilLoadOp
.Value());
117 if (dsa
.mStencilStoreOp
.WasPassed()) {
118 dsDesc
.stencil
.store_op
= ConvertStoreOp(dsa
.mStencilStoreOp
.Value());
120 dsDesc
.stencil
.read_only
= dsa
.mStencilReadOnly
;
124 desc
.depth_stencil_attachment
= &dsDesc
;
127 if (aDesc
.mColorAttachments
.Length() > WGPUMAX_COLOR_ATTACHMENTS
) {
128 aParent
->GetDevice()->GenerateValidationError(nsLiteralCString(
129 "Too many color attachments in GPURenderPassDescriptor"));
133 std::array
<ffi::WGPURenderPassColorAttachment
, WGPUMAX_COLOR_ATTACHMENTS
>
135 desc
.color_attachments
= colorDescs
.data();
136 desc
.color_attachments_length
= aDesc
.mColorAttachments
.Length();
138 for (size_t i
= 0; i
< aDesc
.mColorAttachments
.Length(); ++i
) {
139 const auto& ca
= aDesc
.mColorAttachments
[i
];
140 ffi::WGPURenderPassColorAttachment
& cd
= colorDescs
[i
];
141 cd
.view
= ca
.mView
->mId
;
142 cd
.channel
.store_op
= ConvertStoreOp(ca
.mStoreOp
);
144 if (ca
.mResolveTarget
.WasPassed()) {
145 cd
.resolve_target
= ca
.mResolveTarget
.Value().mId
;
148 cd
.channel
.load_op
= ConvertLoadOp(ca
.mLoadOp
);
149 if (ca
.mClearValue
.WasPassed()) {
150 cd
.channel
.clear_value
= ConvertColor(ca
.mClearValue
.Value());
154 if (aDesc
.mOcclusionQuerySet
.WasPassed()) {
155 desc
.occlusion_query_set
= aDesc
.mOcclusionQuerySet
.Value().mId
;
158 ffi::WGPUPassTimestampWrites passTimestampWrites
= {};
159 if (aDesc
.mTimestampWrites
.WasPassed()) {
160 AssignPassTimestampWrites(aDesc
.mTimestampWrites
.Value(),
161 passTimestampWrites
);
162 desc
.timestamp_writes
= &passTimestampWrites
;
165 return ffi::wgpu_command_encoder_begin_render_pass(&desc
);
168 RenderPassEncoder::RenderPassEncoder(CommandEncoder
* const aParent
,
169 const dom::GPURenderPassDescriptor
& aDesc
)
170 : ChildOf(aParent
), mPass(BeginRenderPass(aParent
, aDesc
)) {
176 for (const auto& at
: aDesc
.mColorAttachments
) {
177 mUsedTextureViews
.AppendElement(at
.mView
);
179 if (aDesc
.mDepthStencilAttachment
.WasPassed()) {
180 mUsedTextureViews
.AppendElement(
181 aDesc
.mDepthStencilAttachment
.Value().mView
);
185 RenderPassEncoder::~RenderPassEncoder() { Cleanup(); }
187 void RenderPassEncoder::Cleanup() {
190 mUsedBindGroups
.Clear();
191 mUsedBuffers
.Clear();
192 mUsedPipelines
.Clear();
193 mUsedTextureViews
.Clear();
194 mUsedRenderBundles
.Clear();
197 void RenderPassEncoder::SetBindGroup(
198 uint32_t aSlot
, BindGroup
* const aBindGroup
,
199 const dom::Sequence
<uint32_t>& aDynamicOffsets
) {
205 mUsedBindGroups
.AppendElement(aBindGroup
);
206 bindGroup
= aBindGroup
->mId
;
208 ffi::wgpu_recorded_render_pass_set_bind_group(mPass
.get(), aSlot
, bindGroup
,
209 aDynamicOffsets
.Elements(),
210 aDynamicOffsets
.Length());
213 void RenderPassEncoder::SetPipeline(const RenderPipeline
& aPipeline
) {
217 mUsedPipelines
.AppendElement(&aPipeline
);
218 ffi::wgpu_recorded_render_pass_set_pipeline(mPass
.get(), aPipeline
.mId
);
221 void RenderPassEncoder::SetIndexBuffer(const Buffer
& aBuffer
,
222 const dom::GPUIndexFormat
& aIndexFormat
,
223 uint64_t aOffset
, uint64_t aSize
) {
227 mUsedBuffers
.AppendElement(&aBuffer
);
228 const auto iformat
= aIndexFormat
== dom::GPUIndexFormat::Uint32
229 ? ffi::WGPUIndexFormat_Uint32
230 : ffi::WGPUIndexFormat_Uint16
;
231 ffi::wgpu_recorded_render_pass_set_index_buffer(mPass
.get(), aBuffer
.mId
,
232 iformat
, aOffset
, aSize
);
235 void RenderPassEncoder::SetVertexBuffer(uint32_t aSlot
, const Buffer
& aBuffer
,
236 uint64_t aOffset
, uint64_t aSize
) {
240 mUsedBuffers
.AppendElement(&aBuffer
);
241 ffi::wgpu_recorded_render_pass_set_vertex_buffer(mPass
.get(), aSlot
,
242 aBuffer
.mId
, aOffset
, aSize
);
245 void RenderPassEncoder::Draw(uint32_t aVertexCount
, uint32_t aInstanceCount
,
246 uint32_t aFirstVertex
, uint32_t aFirstInstance
) {
250 ffi::wgpu_recorded_render_pass_draw(mPass
.get(), aVertexCount
, aInstanceCount
,
251 aFirstVertex
, aFirstInstance
);
254 void RenderPassEncoder::DrawIndexed(uint32_t aIndexCount
,
255 uint32_t aInstanceCount
,
256 uint32_t aFirstIndex
, int32_t aBaseVertex
,
257 uint32_t aFirstInstance
) {
261 ffi::wgpu_recorded_render_pass_draw_indexed(mPass
.get(), aIndexCount
,
262 aInstanceCount
, aFirstIndex
,
263 aBaseVertex
, aFirstInstance
);
266 void RenderPassEncoder::DrawIndirect(const Buffer
& aIndirectBuffer
,
267 uint64_t aIndirectOffset
) {
271 ffi::wgpu_recorded_render_pass_draw_indirect(mPass
.get(), aIndirectBuffer
.mId
,
275 void RenderPassEncoder::DrawIndexedIndirect(const Buffer
& aIndirectBuffer
,
276 uint64_t aIndirectOffset
) {
280 ffi::wgpu_recorded_render_pass_draw_indexed_indirect(
281 mPass
.get(), aIndirectBuffer
.mId
, aIndirectOffset
);
284 void RenderPassEncoder::SetViewport(float x
, float y
, float width
, float height
,
285 float minDepth
, float maxDepth
) {
289 ffi::wgpu_recorded_render_pass_set_viewport(mPass
.get(), x
, y
, width
, height
,
293 void RenderPassEncoder::SetScissorRect(uint32_t x
, uint32_t y
, uint32_t width
,
298 ffi::wgpu_recorded_render_pass_set_scissor_rect(mPass
.get(), x
, y
, width
,
302 void RenderPassEncoder::SetBlendConstant(
303 const dom::DoubleSequenceOrGPUColorDict
& color
) {
307 ffi::WGPUColor aColor
= ConvertColor(color
);
308 ffi::wgpu_recorded_render_pass_set_blend_constant(mPass
.get(), &aColor
);
311 void RenderPassEncoder::SetStencilReference(uint32_t reference
) {
315 ffi::wgpu_recorded_render_pass_set_stencil_reference(mPass
.get(), reference
);
318 void RenderPassEncoder::BeginOcclusionQuery(uint32_t aQueryIndex
) {
322 ffi::wgpu_recorded_render_pass_begin_occlusion_query(mPass
.get(),
326 void RenderPassEncoder::EndOcclusionQuery() {
330 ffi::wgpu_recorded_render_pass_end_occlusion_query(mPass
.get());
333 void RenderPassEncoder::ExecuteBundles(
334 const dom::Sequence
<OwningNonNull
<RenderBundle
>>& aBundles
) {
338 nsTArray
<ffi::WGPURenderBundleId
> renderBundles(aBundles
.Length());
339 for (const auto& bundle
: aBundles
) {
340 mUsedRenderBundles
.AppendElement(bundle
);
341 renderBundles
.AppendElement(bundle
->mId
);
343 ffi::wgpu_recorded_render_pass_execute_bundles(
344 mPass
.get(), renderBundles
.Elements(), renderBundles
.Length());
347 void RenderPassEncoder::PushDebugGroup(const nsAString
& aString
) {
351 const NS_ConvertUTF16toUTF8
utf8(aString
);
352 ffi::wgpu_recorded_render_pass_push_debug_group(mPass
.get(), utf8
.get(), 0);
354 void RenderPassEncoder::PopDebugGroup() {
358 ffi::wgpu_recorded_render_pass_pop_debug_group(mPass
.get());
360 void RenderPassEncoder::InsertDebugMarker(const nsAString
& aString
) {
364 const NS_ConvertUTF16toUTF8
utf8(aString
);
365 ffi::wgpu_recorded_render_pass_insert_debug_marker(mPass
.get(), utf8
.get(),
369 void RenderPassEncoder::End() {
374 mParent
->EndRenderPass(*mPass
);
378 } // namespace mozilla::webgpu