xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/wgpu/FramebufferWgpu.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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, &params,
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