1 //
2 // Copyright 2024 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // FramebufferWgpu.cpp:
7 // Implements the class methods for FramebufferWgpu.
8 //
9
10 #include "libANGLE/renderer/wgpu/FramebufferWgpu.h"
11 #include <__config>
12
13 #include "common/debug.h"
14 #include "libANGLE/Context.h"
15 #include "libANGLE/formatutils.h"
16 #include "libANGLE/renderer/wgpu/BufferWgpu.h"
17 #include "libANGLE/renderer/wgpu/ContextWgpu.h"
18 #include "libANGLE/renderer/wgpu/RenderTargetWgpu.h"
19 #include "libANGLE/renderer/wgpu/wgpu_utils.h"
20
21 namespace rx
22 {
23
24 namespace
25 {
CompareColorRenderPassAttachments(const wgpu::RenderPassColorAttachment & attachment1,const wgpu::RenderPassColorAttachment & attachment2)26 bool CompareColorRenderPassAttachments(const wgpu::RenderPassColorAttachment &attachment1,
27 const wgpu::RenderPassColorAttachment &attachment2)
28 {
29
30 if (attachment1.nextInChain != nullptr || attachment2.nextInChain != nullptr)
31 {
32 return false;
33 }
34
35 return attachment1.view.Get() == attachment2.view.Get() &&
36 attachment1.depthSlice == attachment2.depthSlice &&
37 attachment1.resolveTarget.Get() == attachment2.resolveTarget.Get() &&
38 attachment1.loadOp == attachment2.loadOp && attachment1.storeOp == attachment2.storeOp &&
39 attachment1.clearValue.r == attachment2.clearValue.r &&
40 attachment1.clearValue.g == attachment2.clearValue.g &&
41 attachment1.clearValue.b == attachment2.clearValue.b &&
42 attachment1.clearValue.a == attachment2.clearValue.a;
43 }
44
CompareColorRenderPassAttachmentVectors(const std::vector<wgpu::RenderPassColorAttachment> & attachments1,const std::vector<wgpu::RenderPassColorAttachment> & attachments2)45 bool CompareColorRenderPassAttachmentVectors(
46 const std::vector<wgpu::RenderPassColorAttachment> &attachments1,
47 const std::vector<wgpu::RenderPassColorAttachment> &attachments2)
48 {
49 if (attachments1.size() != attachments2.size())
50 {
51 return false;
52 }
53
54 for (uint32_t i = 0; i < attachments1.size(); ++i)
55 {
56 if (!CompareColorRenderPassAttachments(attachments1[i], attachments2[i]))
57 {
58 return false;
59 }
60 }
61
62 return true;
63 }
64
CompareDepthStencilRenderPassAttachments(const wgpu::RenderPassDepthStencilAttachment & attachment1,const wgpu::RenderPassDepthStencilAttachment & attachment2)65 bool CompareDepthStencilRenderPassAttachments(
66 const wgpu::RenderPassDepthStencilAttachment &attachment1,
67 const wgpu::RenderPassDepthStencilAttachment &attachment2)
68 {
69 return attachment1.view.Get() == attachment2.view.Get() &&
70 attachment1.depthLoadOp == attachment2.depthLoadOp &&
71 attachment1.depthStoreOp == attachment2.depthStoreOp &&
72 attachment1.depthClearValue == attachment2.depthClearValue &&
73 attachment1.stencilLoadOp == attachment2.stencilLoadOp &&
74 attachment1.stencilStoreOp == attachment2.stencilStoreOp &&
75 attachment1.stencilClearValue == attachment2.stencilClearValue &&
76 attachment1.stencilReadOnly == attachment2.stencilReadOnly;
77 }
78 } // namespace
79
FramebufferWgpu(const gl::FramebufferState & state)80 FramebufferWgpu::FramebufferWgpu(const gl::FramebufferState &state) : FramebufferImpl(state)
81 {
82 mCurrentColorAttachmentFormats.fill(wgpu::TextureFormat::Undefined);
83 }
84
~FramebufferWgpu()85 FramebufferWgpu::~FramebufferWgpu() {}
86
discard(const gl::Context * context,size_t count,const GLenum * attachments)87 angle::Result FramebufferWgpu::discard(const gl::Context *context,
88 size_t count,
89 const GLenum *attachments)
90 {
91 return angle::Result::Continue;
92 }
93
invalidate(const gl::Context * context,size_t count,const GLenum * attachments)94 angle::Result FramebufferWgpu::invalidate(const gl::Context *context,
95 size_t count,
96 const GLenum *attachments)
97 {
98 return angle::Result::Continue;
99 }
100
invalidateSub(const gl::Context * context,size_t count,const GLenum * attachments,const gl::Rectangle & area)101 angle::Result FramebufferWgpu::invalidateSub(const gl::Context *context,
102 size_t count,
103 const GLenum *attachments,
104 const gl::Rectangle &area)
105 {
106 return angle::Result::Continue;
107 }
108
clear(const gl::Context * context,GLbitfield mask)109 angle::Result FramebufferWgpu::clear(const gl::Context *context, GLbitfield mask)
110 {
111 bool clearColor = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_COLOR_BUFFER_BIT));
112 bool clearDepth = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT));
113 bool clearStencil = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_STENCIL_BUFFER_BIT));
114
115 ASSERT(clearDepth || clearStencil || clearColor);
116
117 ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
118
119 gl::ColorF colorClearValue = context->getState().getColorClearValue();
120 gl::DrawBufferMask clearColorBuffers = mState.getEnabledDrawBuffers();
121 wgpu::Color clearValue;
122 clearValue.r = colorClearValue.red;
123 clearValue.g = colorClearValue.green;
124 clearValue.b = colorClearValue.blue;
125 clearValue.a = colorClearValue.alpha;
126 std::vector<wgpu::RenderPassColorAttachment> colorAttachments;
127 wgpu::RenderPassDepthStencilAttachment depthStencilAttachment;
128 float depthValue = 1;
129 uint32_t stencilValue = 0;
130 for (size_t enabledDrawBuffer : clearColorBuffers)
131 {
132 colorAttachments.push_back(webgpu::CreateNewClearColorAttachment(
133 clearValue, wgpu::kDepthSliceUndefined,
134 mRenderTargetCache.getColorDraw(mState, enabledDrawBuffer)->getTextureView()));
135 }
136
137 // Attempt to end a render pass if one has already been started.
138 bool isActiveRenderPass =
139 !CompareColorRenderPassAttachmentVectors(mCurrentColorAttachments, colorAttachments) ||
140 contextWgpu->hasActiveRenderPass();
141
142 if (clearDepth || clearStencil)
143 {
144
145 depthValue = context->getState().getDepthClearValue();
146 stencilValue = static_cast<uint32_t>(context->getState().getStencilClearValue());
147 depthStencilAttachment = webgpu::CreateNewDepthStencilAttachment(
148 depthValue, stencilValue, mRenderTargetCache.getDepthStencil()->getTextureView(),
149 clearDepth, clearStencil);
150
151 isActiveRenderPass =
152 isActiveRenderPass || !CompareDepthStencilRenderPassAttachments(
153 depthStencilAttachment, mCurrentDepthStencilAttachment);
154 }
155
156 if (mDeferredClears.any())
157 {
158 // Merge the current clear command with any deferred clears. This is to keep the clear paths
159 // simpler so they only need to consider the current or the deferred clears.
160 mergeClearWithDeferredClears(clearValue, clearColorBuffers, depthValue, stencilValue,
161 clearColor, clearDepth, clearStencil);
162 if (isActiveRenderPass)
163 {
164 ANGLE_TRY(flushDeferredClears(contextWgpu));
165 }
166 else
167 {
168 for (size_t colorIndexGL : mDeferredClears.getColorMask())
169 {
170 RenderTargetWgpu *renderTarget =
171 mRenderTargetCache.getColorDraw(mState, colorIndexGL);
172 webgpu::ClearValues deferredClearValue;
173 deferredClearValue = mDeferredClears[colorIndexGL];
174 if (mDeferredClears.hasDepth())
175 {
176 deferredClearValue.depthValue = mDeferredClears.getDepthValue();
177 }
178 if (mDeferredClears.hasStencil())
179 {
180 deferredClearValue.stencilValue = mDeferredClears.getStencilValue();
181 }
182 renderTarget->getImage()->stageClear(
183 renderTarget->getImage()->toGlLevel(renderTarget->getLevelIndex()),
184 deferredClearValue, false, false);
185 }
186 if (mDeferredClears.hasDepth() || mDeferredClears.hasStencil())
187 {
188 webgpu::ClearValues dsClearValue = {};
189 dsClearValue.depthValue = mDeferredClears.getDepthValue();
190 dsClearValue.stencilValue = mDeferredClears.getStencilValue();
191 RenderTargetWgpu *renderTarget = mRenderTargetCache.getDepthStencil();
192 renderTarget->getImage()->stageClear(
193 renderTarget->getImage()->toGlLevel(renderTarget->getLevelIndex()),
194 dsClearValue, mDeferredClears.hasDepth(), mDeferredClears.hasStencil());
195 }
196 mDeferredClears.reset();
197 }
198 return angle::Result::Continue;
199 }
200
201 if (isActiveRenderPass)
202 {
203 ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
204 }
205
206 setUpForRenderPass(contextWgpu, (clearDepth || clearStencil), std::move(colorAttachments),
207 depthStencilAttachment);
208 ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
209 ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
210 return angle::Result::Continue;
211 }
212
clearBufferfv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLfloat * values)213 angle::Result FramebufferWgpu::clearBufferfv(const gl::Context *context,
214 GLenum buffer,
215 GLint drawbuffer,
216 const GLfloat *values)
217 {
218 return angle::Result::Continue;
219 }
220
clearBufferuiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLuint * values)221 angle::Result FramebufferWgpu::clearBufferuiv(const gl::Context *context,
222 GLenum buffer,
223 GLint drawbuffer,
224 const GLuint *values)
225 {
226 return angle::Result::Continue;
227 }
228
clearBufferiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLint * values)229 angle::Result FramebufferWgpu::clearBufferiv(const gl::Context *context,
230 GLenum buffer,
231 GLint drawbuffer,
232 const GLint *values)
233 {
234 return angle::Result::Continue;
235 }
236
clearBufferfi(const gl::Context * context,GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)237 angle::Result FramebufferWgpu::clearBufferfi(const gl::Context *context,
238 GLenum buffer,
239 GLint drawbuffer,
240 GLfloat depth,
241 GLint stencil)
242 {
243 return angle::Result::Continue;
244 }
245
readPixels(const gl::Context * context,const gl::Rectangle & origArea,GLenum format,GLenum type,const gl::PixelPackState & pack,gl::Buffer * packBuffer,void * ptrOrOffset)246 angle::Result FramebufferWgpu::readPixels(const gl::Context *context,
247 const gl::Rectangle &origArea,
248 GLenum format,
249 GLenum type,
250 const gl::PixelPackState &pack,
251 gl::Buffer *packBuffer,
252 void *ptrOrOffset)
253 {
254 // Get the pointer to write to from the argument or the pack buffer
255 GLubyte *pixels = nullptr;
256 if (packBuffer != nullptr)
257 {
258 UNREACHABLE();
259 }
260 else
261 {
262 pixels = reinterpret_cast<GLubyte *>(ptrOrOffset);
263 }
264
265 // Clip read area to framebuffer.
266 const gl::Extents fbSize = getState().getReadPixelsAttachment(format)->getSize();
267 const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
268 gl::Rectangle clippedArea;
269 if (!ClipRectangle(origArea, fbRect, &clippedArea))
270 {
271 // nothing to read
272 return angle::Result::Continue;
273 }
274
275 ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
276
277 ANGLE_TRY(flushDeferredClears(contextWgpu));
278
279 ANGLE_TRY(contextWgpu->flush(webgpu::RenderPassClosureReason::GLReadPixels));
280
281 GLuint outputSkipBytes = 0;
282 PackPixelsParams params;
283 ANGLE_TRY(webgpu::ImageHelper::getReadPixelsParams(contextWgpu, pack, packBuffer, format, type,
284 origArea, clippedArea, ¶ms,
285 &outputSkipBytes));
286
287 webgpu::ImageHelper *sourceImageHelper = getReadPixelsRenderTarget()->getImage();
288 ANGLE_TRY(sourceImageHelper->readPixels(contextWgpu, params.area, params,
289 static_cast<uint8_t *>(pixels) + outputSkipBytes));
290
291 return angle::Result::Continue;
292 }
293
blit(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,GLbitfield mask,GLenum filter)294 angle::Result FramebufferWgpu::blit(const gl::Context *context,
295 const gl::Rectangle &sourceArea,
296 const gl::Rectangle &destArea,
297 GLbitfield mask,
298 GLenum filter)
299 {
300 return angle::Result::Continue;
301 }
302
checkStatus(const gl::Context * context) const303 gl::FramebufferStatus FramebufferWgpu::checkStatus(const gl::Context *context) const
304 {
305 return gl::FramebufferStatus::Complete();
306 }
307
syncState(const gl::Context * context,GLenum binding,const gl::Framebuffer::DirtyBits & dirtyBits,gl::Command command)308 angle::Result FramebufferWgpu::syncState(const gl::Context *context,
309 GLenum binding,
310 const gl::Framebuffer::DirtyBits &dirtyBits,
311 gl::Command command)
312 {
313 ContextWgpu *contextWgpu = webgpu::GetImpl(context);
314 bool dirtyDepthStencilAttachment = false;
315 ASSERT(dirtyBits.any());
316
317 gl::DrawBufferMask dirtyColorAttachments;
318 for (size_t dirtyBit : dirtyBits)
319 {
320 switch (dirtyBit)
321 {
322 case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
323 case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS:
324 case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
325 case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS:
326 {
327 ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState));
328 dirtyDepthStencilAttachment = true;
329 // Update the current depth stencil texture format let the context know if this
330 // framebuffer is bound for draw
331 RenderTargetWgpu *rt = mRenderTargetCache.getDepthStencil();
332 mCurrentDepthStencilFormat = (rt && rt->getImage())
333 ? rt->getImage()->toWgpuTextureFormat()
334 : wgpu::TextureFormat::Undefined;
335 if (binding == GL_DRAW_FRAMEBUFFER)
336 {
337 contextWgpu->setDepthStencilFormat(mCurrentDepthStencilFormat);
338 }
339
340 break;
341 }
342
343 case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
344 ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
345 break;
346 case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
347 case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
348 case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
349 case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
350 case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
351 case gl::Framebuffer::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE:
352 case gl::Framebuffer::DIRTY_BIT_DEFAULT_LAYERS:
353 case gl::Framebuffer::DIRTY_BIT_FOVEATION:
354 break;
355 default:
356 {
357 static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
358 uint32_t colorIndexGL;
359 if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
360 {
361 colorIndexGL = static_cast<uint32_t>(
362 dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
363 }
364 else
365 {
366 ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 &&
367 dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX);
368 colorIndexGL = static_cast<uint32_t>(
369 dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
370 }
371
372 ANGLE_TRY(
373 mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL));
374
375 // Update the current color texture formats let the context know if this framebuffer
376 // is bound for draw
377 RenderTargetWgpu *rt = mRenderTargetCache.getColorDraw(mState, colorIndexGL);
378 mCurrentColorAttachmentFormats[colorIndexGL] =
379 (rt && rt->getImage()) ? rt->getImage()->toWgpuTextureFormat()
380 : wgpu::TextureFormat::Undefined;
381 if (binding == GL_DRAW_FRAMEBUFFER)
382 {
383 contextWgpu->setColorAttachmentFormat(
384 colorIndexGL, mCurrentColorAttachmentFormats[colorIndexGL]);
385 }
386
387 dirtyColorAttachments.set(colorIndexGL);
388 break;
389 }
390 }
391 }
392
393 // Like in Vulkan, defer clears for draw framebuffer ops as well as clears to read framebuffer
394 // attachments that are not taking part in a blit operation.
395 const bool isBlitCommand = command >= gl::Command::Blit && command <= gl::Command::BlitAll;
396 bool deferColorClears = binding == GL_DRAW_FRAMEBUFFER;
397 bool deferDepthStencilClears = binding == GL_DRAW_FRAMEBUFFER;
398 if (binding == GL_READ_FRAMEBUFFER && isBlitCommand)
399 {
400 uint32_t blitMask =
401 static_cast<uint32_t>(command) - static_cast<uint32_t>(gl::Command::Blit);
402 if ((blitMask & gl::CommandBlitBufferColor) == 0)
403 {
404 deferColorClears = true;
405 }
406 if ((blitMask & (gl::CommandBlitBufferDepth | gl::CommandBlitBufferStencil)) == 0)
407 {
408 deferDepthStencilClears = true;
409 }
410 }
411
412 ANGLE_TRY(flushAttachmentUpdates(context, dirtyColorAttachments, dirtyDepthStencilAttachment,
413 deferColorClears, deferDepthStencilClears));
414
415 // Notify the ContextWgpu to update the pipeline desc or restart the renderpass
416 ANGLE_TRY(contextWgpu->onFramebufferChange(this, command));
417
418 return angle::Result::Continue;
419 }
420
getSamplePosition(const gl::Context * context,size_t index,GLfloat * xy) const421 angle::Result FramebufferWgpu::getSamplePosition(const gl::Context *context,
422 size_t index,
423 GLfloat *xy) const
424 {
425 return angle::Result::Continue;
426 }
427
getReadPixelsRenderTarget() const428 RenderTargetWgpu *FramebufferWgpu::getReadPixelsRenderTarget() const
429 {
430 return mRenderTargetCache.getColorRead(mState);
431 }
432
addNewColorAttachments(std::vector<wgpu::RenderPassColorAttachment> newColorAttachments)433 void FramebufferWgpu::addNewColorAttachments(
434 std::vector<wgpu::RenderPassColorAttachment> newColorAttachments)
435 {
436 mNewColorAttachments.insert(mCurrentColorAttachments.end(), newColorAttachments.begin(),
437 newColorAttachments.end());
438 }
439
updateDepthStencilAttachment(wgpu::RenderPassDepthStencilAttachment newRenderPassDepthStencilAttachment)440 void FramebufferWgpu::updateDepthStencilAttachment(
441 wgpu::RenderPassDepthStencilAttachment newRenderPassDepthStencilAttachment)
442 {
443 mNewDepthStencilAttachment = std::move(newRenderPassDepthStencilAttachment);
444 mAddedNewDepthStencilAttachment = true;
445 }
446
flushOneColorAttachmentUpdate(const gl::Context * context,bool deferClears,uint32_t colorIndexGL)447 angle::Result FramebufferWgpu::flushOneColorAttachmentUpdate(const gl::Context *context,
448 bool deferClears,
449 uint32_t colorIndexGL)
450 {
451 ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
452 RenderTargetWgpu *drawRenderTarget = nullptr;
453 RenderTargetWgpu *readRenderTarget = nullptr;
454
455 drawRenderTarget = mRenderTargetCache.getColorDraw(mState, colorIndexGL);
456 if (drawRenderTarget)
457 {
458 if (deferClears)
459 {
460 ANGLE_TRY(drawRenderTarget->flushImageStagedUpdates(contextWgpu, &mDeferredClears,
461 colorIndexGL));
462 }
463 else
464 {
465 ANGLE_TRY(drawRenderTarget->flushImageStagedUpdates(contextWgpu, nullptr, 0));
466 }
467 }
468
469 if (mState.getReadBufferState() != GL_NONE && mState.getReadIndex() == colorIndexGL)
470 {
471 readRenderTarget = mRenderTargetCache.getColorRead(mState);
472 if (readRenderTarget && readRenderTarget != drawRenderTarget)
473 {
474 ANGLE_TRY(readRenderTarget->flushImageStagedUpdates(contextWgpu, nullptr, 0));
475 }
476 }
477
478 return angle::Result::Continue;
479 }
480
flushAttachmentUpdates(const gl::Context * context,gl::DrawBufferMask dirtyColorAttachments,bool dirtyDepthStencilAttachment,bool deferColorClears,bool deferDepthStencilClears)481 angle::Result FramebufferWgpu::flushAttachmentUpdates(const gl::Context *context,
482 gl::DrawBufferMask dirtyColorAttachments,
483 bool dirtyDepthStencilAttachment,
484 bool deferColorClears,
485 bool deferDepthStencilClears)
486 {
487 for (size_t colorIndexGL : dirtyColorAttachments)
488 {
489 ANGLE_TRY(flushOneColorAttachmentUpdate(context, deferColorClears,
490 static_cast<uint32_t>(colorIndexGL)));
491 }
492
493 ContextWgpu *contextWgpu = GetImplAs<ContextWgpu>(context);
494 RenderTargetWgpu *depthStencilRt = mRenderTargetCache.getDepthStencil();
495
496 if (depthStencilRt && dirtyDepthStencilAttachment)
497 {
498 if (deferDepthStencilClears)
499 {
500 // The underlying ImageHelper will check if a clear has a stencil value and store the
501 // deferred clear in the correct index.
502 ANGLE_TRY(depthStencilRt->flushImageStagedUpdates(contextWgpu, &mDeferredClears,
503 webgpu::kUnpackedDepthIndex));
504 }
505 else
506 {
507 ANGLE_TRY(depthStencilRt->flushImageStagedUpdates(contextWgpu, nullptr, 0));
508 }
509 }
510
511 // If we added any new attachments, we start a render pass to fully flush the updates.
512 if ((!mNewColorAttachments.empty() &&
513 mNewColorAttachments.size() != mCurrentColorAttachments.size()) ||
514 mAddedNewDepthStencilAttachment)
515 {
516 ANGLE_TRY(startRenderPassNewAttachments(contextWgpu));
517 }
518 return angle::Result::Continue;
519 }
520
flushDeferredClears(ContextWgpu * contextWgpu)521 angle::Result FramebufferWgpu::flushDeferredClears(ContextWgpu *contextWgpu)
522 {
523 if (mDeferredClears.empty())
524 {
525 return angle::Result::Continue;
526 }
527 ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
528 mCurrentColorAttachments.clear();
529 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
530 {
531 if (!mDeferredClears.test(colorIndexGL))
532 {
533 continue;
534 }
535 mCurrentColorAttachments.push_back(webgpu::CreateNewClearColorAttachment(
536 mDeferredClears[colorIndexGL].clearColor, mDeferredClears[colorIndexGL].depthSlice,
537 mRenderTargetCache.getColorDraw(mState, colorIndexGL)->getTextureView()));
538 }
539 if (mRenderTargetCache.getDepthStencil() &&
540 (mDeferredClears.hasDepth() || mDeferredClears.hasStencil()))
541 {
542 mCurrentDepthStencilAttachment = webgpu::CreateNewDepthStencilAttachment(
543 mDeferredClears.getDepthValue(), mDeferredClears.getStencilValue(),
544 mRenderTargetCache.getDepthStencil()->getTextureView(), !mDeferredClears.hasDepth(),
545 !mDeferredClears.hasStencil());
546 mCurrentRenderPassDesc.depthStencilAttachment = &mCurrentDepthStencilAttachment;
547 }
548 else
549 {
550 mCurrentRenderPassDesc.depthStencilAttachment = nullptr;
551 }
552 mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size();
553 mCurrentRenderPassDesc.colorAttachments = mCurrentColorAttachments.data();
554 ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
555 ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
556
557 return angle::Result::Continue;
558 }
559
startRenderPassNewAttachments(ContextWgpu * contextWgpu)560 angle::Result FramebufferWgpu::startRenderPassNewAttachments(ContextWgpu *contextWgpu)
561 {
562 // Flush out a render pass if there is an active one.
563 ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
564
565 setUpForRenderPass(contextWgpu, mAddedNewDepthStencilAttachment, mNewColorAttachments,
566 mNewDepthStencilAttachment);
567 mNewColorAttachments.clear();
568 mAddedNewDepthStencilAttachment = false;
569 ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
570 return angle::Result::Continue;
571 }
572
startNewRenderPass(ContextWgpu * contextWgpu)573 angle::Result FramebufferWgpu::startNewRenderPass(ContextWgpu *contextWgpu)
574 {
575 ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
576
577 mCurrentColorAttachments.clear();
578 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
579 {
580 wgpu::RenderPassColorAttachment colorAttachment;
581 colorAttachment.view =
582 mRenderTargetCache.getColorDraw(mState, colorIndexGL)->getTextureView();
583 colorAttachment.depthSlice = wgpu::kDepthSliceUndefined;
584 colorAttachment.loadOp = wgpu::LoadOp::Load;
585 colorAttachment.storeOp = wgpu::StoreOp::Store;
586
587 mCurrentColorAttachments.push_back(colorAttachment);
588 }
589 if (mRenderTargetCache.getDepthStencil())
590 {
591 mCurrentDepthStencilAttachment = webgpu::CreateNewDepthStencilAttachment(
592 contextWgpu->getState().getDepthClearValue(),
593 static_cast<uint32_t>(contextWgpu->getState().getStencilClearValue()),
594 mRenderTargetCache.getDepthStencil()->getTextureView(), mState.hasDepth(),
595 mState.hasStencil());
596 mCurrentRenderPassDesc.depthStencilAttachment = &mCurrentDepthStencilAttachment;
597 }
598 else
599 {
600 mCurrentRenderPassDesc.depthStencilAttachment = nullptr;
601 }
602
603 mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size();
604 mCurrentRenderPassDesc.colorAttachments = mCurrentColorAttachments.data();
605 ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
606
607 return angle::Result::Continue;
608 }
609
setUpForRenderPass(ContextWgpu * contextWgpu,bool depthOrStencil,std::vector<wgpu::RenderPassColorAttachment> colorAttachments,wgpu::RenderPassDepthStencilAttachment depthStencilAttachment)610 void FramebufferWgpu::setUpForRenderPass(
611 ContextWgpu *contextWgpu,
612 bool depthOrStencil,
613 std::vector<wgpu::RenderPassColorAttachment> colorAttachments,
614 wgpu::RenderPassDepthStencilAttachment depthStencilAttachment)
615 {
616 if (depthOrStencil)
617 {
618 mCurrentDepthStencilAttachment = std::move(depthStencilAttachment);
619 mCurrentRenderPassDesc.depthStencilAttachment = &mCurrentDepthStencilAttachment;
620 }
621 else
622 {
623 mCurrentRenderPassDesc.depthStencilAttachment = nullptr;
624 }
625 mCurrentColorAttachments = std::move(colorAttachments);
626 mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size();
627 mCurrentRenderPassDesc.colorAttachments = mCurrentColorAttachments.data();
628 }
629
mergeClearWithDeferredClears(wgpu::Color clearValue,gl::DrawBufferMask clearColorBuffers,float depthValue,uint32_t stencilValue,bool clearColor,bool clearDepth,bool clearStencil)630 void FramebufferWgpu::mergeClearWithDeferredClears(wgpu::Color clearValue,
631 gl::DrawBufferMask clearColorBuffers,
632 float depthValue,
633 uint32_t stencilValue,
634 bool clearColor,
635 bool clearDepth,
636 bool clearStencil)
637 {
638 for (size_t enabledDrawBuffer : clearColorBuffers)
639 {
640 mDeferredClears.store(static_cast<uint32_t>(enabledDrawBuffer),
641 {clearValue, wgpu::kDepthSliceUndefined, 0, 0});
642 }
643 if (clearDepth)
644 {
645 mDeferredClears.store(webgpu::kUnpackedDepthIndex,
646 {clearValue, wgpu::kDepthSliceUndefined, depthValue, 0});
647 }
648 if (clearStencil)
649 {
650 mDeferredClears.store(webgpu::kUnpackedStencilIndex,
651 {clearValue, wgpu::kDepthSliceUndefined, 0, stencilValue});
652 }
653 }
654
655 } // namespace rx
656