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 ffi::WGPURenderPass
* ScopedFfiRenderTraits::empty() { return nullptr; }
23 void ScopedFfiRenderTraits::release(ffi::WGPURenderPass
* raw
) {
25 ffi::wgpu_render_pass_destroy(raw
);
29 static ffi::WGPULoadOp
ConvertLoadOp(const dom::GPULoadOp
& 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_
:
38 MOZ_CRASH("bad GPULoadOp");
41 static ffi::WGPUStoreOp
ConvertStoreOp(const dom::GPUStoreOp
& 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_
:
50 MOZ_CRASH("bad GPUStoreOp");
53 static ffi::WGPUColor
ConvertColor(const dom::Sequence
<double>& aSeq
) {
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);
62 static ffi::WGPUColor
ConvertColor(const dom::GPUColorDict
& aColor
) {
63 ffi::WGPUColor color
= {aColor
.mR
, aColor
.mG
, aColor
.mB
, aColor
.mA
};
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
;
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
;
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
;
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"));
139 std::array
<ffi::WGPURenderPassColorAttachment
, WGPUMAX_COLOR_ATTACHMENTS
>
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
)) {
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() {
186 void RenderPassEncoder::SetBindGroup(
187 uint32_t aSlot
, const BindGroup
& aBindGroup
,
188 const dom::Sequence
<uint32_t>& aDynamicOffsets
) {
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
) {
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
) {
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
,
217 void RenderPassEncoder::SetVertexBuffer(uint32_t aSlot
, const Buffer
& aBuffer
,
218 uint64_t aOffset
, uint64_t aSize
) {
220 mUsedBuffers
.AppendElement(&aBuffer
);
221 ffi::wgpu_render_pass_set_vertex_buffer(mPass
, aSlot
, aBuffer
.mId
, aOffset
,
226 void RenderPassEncoder::Draw(uint32_t aVertexCount
, uint32_t aInstanceCount
,
227 uint32_t aFirstVertex
, uint32_t aFirstInstance
) {
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
) {
239 ffi::wgpu_render_pass_draw_indexed(mPass
, aIndexCount
, aInstanceCount
,
240 aFirstIndex
, aBaseVertex
,
245 void RenderPassEncoder::DrawIndirect(const Buffer
& aIndirectBuffer
,
246 uint64_t aIndirectOffset
) {
248 ffi::wgpu_render_pass_draw_indirect(mPass
, aIndirectBuffer
.mId
,
253 void RenderPassEncoder::DrawIndexedIndirect(const Buffer
& aIndirectBuffer
,
254 uint64_t aIndirectOffset
) {
256 ffi::wgpu_render_pass_draw_indexed_indirect(mPass
, aIndirectBuffer
.mId
,
261 void RenderPassEncoder::SetViewport(float x
, float y
, float width
, float height
,
262 float minDepth
, float maxDepth
) {
264 ffi::wgpu_render_pass_set_viewport(mPass
, x
, y
, width
, height
, minDepth
,
269 void RenderPassEncoder::SetScissorRect(uint32_t x
, uint32_t y
, uint32_t width
,
272 ffi::wgpu_render_pass_set_scissor_rect(mPass
, x
, y
, width
, height
);
276 void RenderPassEncoder::SetBlendConstant(
277 const dom::DoubleSequenceOrGPUColorDict
& color
) {
279 ffi::WGPUColor aColor
= ConvertColor(color
);
280 ffi::wgpu_render_pass_set_blend_constant(mPass
, &aColor
);
284 void RenderPassEncoder::SetStencilReference(uint32_t reference
) {
286 ffi::wgpu_render_pass_set_stencil_reference(mPass
, reference
);
290 void RenderPassEncoder::ExecuteBundles(
291 const dom::Sequence
<OwningNonNull
<RenderBundle
>>& aBundles
) {
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
) {
305 const NS_ConvertUTF16toUTF8
utf8(aString
);
306 ffi::wgpu_render_pass_push_debug_group(mPass
, utf8
.get(), 0);
309 void RenderPassEncoder::PopDebugGroup() {
311 ffi::wgpu_render_pass_pop_debug_group(mPass
);
314 void RenderPassEncoder::InsertDebugMarker(const nsAString
& aString
) {
316 const NS_ConvertUTF16toUTF8
utf8(aString
);
317 ffi::wgpu_render_pass_insert_debug_marker(mPass
, utf8
.get(), 0);
321 void RenderPassEncoder::End(ErrorResult
& aRv
) {
324 auto* pass
= mPass
.forget();
326 mParent
->EndRenderPass(*pass
, aRv
);
330 } // namespace mozilla::webgpu