Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / webgpu / RenderPassEncoder.cpp
blobb485724342857a1e893887485fb210724be41e56
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 void ffiWGPURenderPassDeleter::operator()(ffi::WGPURecordedRenderPass* raw) {
22 if (raw) {
23 ffi::wgpu_render_pass_destroy(raw);
27 static ffi::WGPULoadOp ConvertLoadOp(const dom::GPULoadOp& aOp) {
28 switch (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) {
38 switch (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) {
48 ffi::WGPUColor color;
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);
53 return color;
56 static ffi::WGPUColor ConvertColor(const dom::GPUColorDict& aColor) {
57 ffi::WGPUColor color = {aColor.mR, aColor.mG, aColor.mB, aColor.mA};
58 return color;
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;
98 // -
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;
111 // -
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;
122 // -
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"));
130 return nullptr;
133 std::array<ffi::WGPURenderPassColorAttachment, WGPUMAX_COLOR_ATTACHMENTS>
134 colorDescs = {};
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)) {
171 mValid = !!mPass;
172 if (!mValid) {
173 return;
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() {
188 mValid = false;
189 mPass.release();
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) {
200 if (!mValid) {
201 return;
203 RawId bindGroup = 0;
204 if (aBindGroup) {
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) {
214 if (!mValid) {
215 return;
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) {
224 if (!mValid) {
225 return;
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) {
237 if (!mValid) {
238 return;
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) {
247 if (!mValid) {
248 return;
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) {
258 if (!mValid) {
259 return;
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) {
268 if (!mValid) {
269 return;
271 ffi::wgpu_recorded_render_pass_draw_indirect(mPass.get(), aIndirectBuffer.mId,
272 aIndirectOffset);
275 void RenderPassEncoder::DrawIndexedIndirect(const Buffer& aIndirectBuffer,
276 uint64_t aIndirectOffset) {
277 if (!mValid) {
278 return;
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) {
286 if (!mValid) {
287 return;
289 ffi::wgpu_recorded_render_pass_set_viewport(mPass.get(), x, y, width, height,
290 minDepth, maxDepth);
293 void RenderPassEncoder::SetScissorRect(uint32_t x, uint32_t y, uint32_t width,
294 uint32_t height) {
295 if (!mValid) {
296 return;
298 ffi::wgpu_recorded_render_pass_set_scissor_rect(mPass.get(), x, y, width,
299 height);
302 void RenderPassEncoder::SetBlendConstant(
303 const dom::DoubleSequenceOrGPUColorDict& color) {
304 if (!mValid) {
305 return;
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) {
312 if (!mValid) {
313 return;
315 ffi::wgpu_recorded_render_pass_set_stencil_reference(mPass.get(), reference);
318 void RenderPassEncoder::BeginOcclusionQuery(uint32_t aQueryIndex) {
319 if (!mValid) {
320 return;
322 ffi::wgpu_recorded_render_pass_begin_occlusion_query(mPass.get(),
323 aQueryIndex);
326 void RenderPassEncoder::EndOcclusionQuery() {
327 if (!mValid) {
328 return;
330 ffi::wgpu_recorded_render_pass_end_occlusion_query(mPass.get());
333 void RenderPassEncoder::ExecuteBundles(
334 const dom::Sequence<OwningNonNull<RenderBundle>>& aBundles) {
335 if (!mValid) {
336 return;
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) {
348 if (!mValid) {
349 return;
351 const NS_ConvertUTF16toUTF8 utf8(aString);
352 ffi::wgpu_recorded_render_pass_push_debug_group(mPass.get(), utf8.get(), 0);
354 void RenderPassEncoder::PopDebugGroup() {
355 if (!mValid) {
356 return;
358 ffi::wgpu_recorded_render_pass_pop_debug_group(mPass.get());
360 void RenderPassEncoder::InsertDebugMarker(const nsAString& aString) {
361 if (!mValid) {
362 return;
364 const NS_ConvertUTF16toUTF8 utf8(aString);
365 ffi::wgpu_recorded_render_pass_insert_debug_marker(mPass.get(), utf8.get(),
369 void RenderPassEncoder::End() {
370 if (!mValid) {
371 return;
373 MOZ_ASSERT(!!mPass);
374 mParent->EndRenderPass(*mPass);
375 Cleanup();
378 } // namespace mozilla::webgpu