• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     params.reverseRowOrder = !params.reverseRowOrder;
288 
289     webgpu::ImageHelper *sourceImageHelper = getReadPixelsRenderTarget()->getImage();
290     ANGLE_TRY(sourceImageHelper->readPixels(contextWgpu, params.area, params,
291                                             static_cast<uint8_t *>(pixels) + outputSkipBytes));
292 
293     return angle::Result::Continue;
294 }
295 
blit(const gl::Context * context,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,GLbitfield mask,GLenum filter)296 angle::Result FramebufferWgpu::blit(const gl::Context *context,
297                                     const gl::Rectangle &sourceArea,
298                                     const gl::Rectangle &destArea,
299                                     GLbitfield mask,
300                                     GLenum filter)
301 {
302     return angle::Result::Continue;
303 }
304 
checkStatus(const gl::Context * context) const305 gl::FramebufferStatus FramebufferWgpu::checkStatus(const gl::Context *context) const
306 {
307     return gl::FramebufferStatus::Complete();
308 }
309 
syncState(const gl::Context * context,GLenum binding,const gl::Framebuffer::DirtyBits & dirtyBits,gl::Command command)310 angle::Result FramebufferWgpu::syncState(const gl::Context *context,
311                                          GLenum binding,
312                                          const gl::Framebuffer::DirtyBits &dirtyBits,
313                                          gl::Command command)
314 {
315     ContextWgpu *contextWgpu = webgpu::GetImpl(context);
316     bool dirtyDepthStencilAttachment = false;
317     ASSERT(dirtyBits.any());
318 
319     gl::DrawBufferMask dirtyColorAttachments;
320     for (size_t dirtyBit : dirtyBits)
321     {
322         switch (dirtyBit)
323         {
324             case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
325             case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS:
326             case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
327             case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS:
328             {
329                 ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState));
330                 dirtyDepthStencilAttachment = true;
331                 // Update the current depth stencil texture format let the context know if this
332                 // framebuffer is bound for draw
333                 RenderTargetWgpu *rt       = mRenderTargetCache.getDepthStencil();
334                 mCurrentDepthStencilFormat = (rt && rt->getImage())
335                                                  ? rt->getImage()->toWgpuTextureFormat()
336                                                  : wgpu::TextureFormat::Undefined;
337                 if (binding == GL_DRAW_FRAMEBUFFER)
338                 {
339                     contextWgpu->setDepthStencilFormat(mCurrentDepthStencilFormat);
340                 }
341 
342                 break;
343             }
344 
345             case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
346                 ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
347                 break;
348             case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
349             case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
350             case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
351             case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
352             case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
353             case gl::Framebuffer::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE:
354             case gl::Framebuffer::DIRTY_BIT_DEFAULT_LAYERS:
355             case gl::Framebuffer::DIRTY_BIT_FOVEATION:
356                 break;
357             default:
358             {
359                 static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
360                 uint32_t colorIndexGL;
361                 if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
362                 {
363                     colorIndexGL = static_cast<uint32_t>(
364                         dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
365                 }
366                 else
367                 {
368                     ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 &&
369                            dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX);
370                     colorIndexGL = static_cast<uint32_t>(
371                         dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
372                 }
373 
374                 ANGLE_TRY(
375                     mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL));
376 
377                 // Update the current color texture formats let the context know if this framebuffer
378                 // is bound for draw
379                 RenderTargetWgpu *rt = mRenderTargetCache.getColorDraw(mState, colorIndexGL);
380                 mCurrentColorAttachmentFormats[colorIndexGL] =
381                     (rt && rt->getImage()) ? rt->getImage()->toWgpuTextureFormat()
382                                            : wgpu::TextureFormat::Undefined;
383                 if (binding == GL_DRAW_FRAMEBUFFER)
384                 {
385                     contextWgpu->setColorAttachmentFormat(
386                         colorIndexGL, mCurrentColorAttachmentFormats[colorIndexGL]);
387                 }
388 
389                 dirtyColorAttachments.set(colorIndexGL);
390                 break;
391             }
392         }
393     }
394 
395     // Like in Vulkan, defer clears for draw framebuffer ops as well as clears to read framebuffer
396     // attachments that are not taking part in a blit operation.
397     const bool isBlitCommand = command >= gl::Command::Blit && command <= gl::Command::BlitAll;
398     bool deferColorClears    = binding == GL_DRAW_FRAMEBUFFER;
399     bool deferDepthStencilClears = binding == GL_DRAW_FRAMEBUFFER;
400     if (binding == GL_READ_FRAMEBUFFER && isBlitCommand)
401     {
402         uint32_t blitMask =
403             static_cast<uint32_t>(command) - static_cast<uint32_t>(gl::Command::Blit);
404         if ((blitMask & gl::CommandBlitBufferColor) == 0)
405         {
406             deferColorClears = true;
407         }
408         if ((blitMask & (gl::CommandBlitBufferDepth | gl::CommandBlitBufferStencil)) == 0)
409         {
410             deferDepthStencilClears = true;
411         }
412     }
413 
414     ANGLE_TRY(flushAttachmentUpdates(context, dirtyColorAttachments, dirtyDepthStencilAttachment,
415                                      deferColorClears, deferDepthStencilClears));
416 
417     // Notify the ContextWgpu to update the pipeline desc or restart the renderpass
418     ANGLE_TRY(contextWgpu->onFramebufferChange(this, command));
419 
420     return angle::Result::Continue;
421 }
422 
getSamplePosition(const gl::Context * context,size_t index,GLfloat * xy) const423 angle::Result FramebufferWgpu::getSamplePosition(const gl::Context *context,
424                                                  size_t index,
425                                                  GLfloat *xy) const
426 {
427     return angle::Result::Continue;
428 }
429 
getReadPixelsRenderTarget() const430 RenderTargetWgpu *FramebufferWgpu::getReadPixelsRenderTarget() const
431 {
432     return mRenderTargetCache.getColorRead(mState);
433 }
434 
addNewColorAttachments(std::vector<wgpu::RenderPassColorAttachment> newColorAttachments)435 void FramebufferWgpu::addNewColorAttachments(
436     std::vector<wgpu::RenderPassColorAttachment> newColorAttachments)
437 {
438     mNewColorAttachments.insert(mCurrentColorAttachments.end(), newColorAttachments.begin(),
439                                 newColorAttachments.end());
440 }
441 
updateDepthStencilAttachment(wgpu::RenderPassDepthStencilAttachment newRenderPassDepthStencilAttachment)442 void FramebufferWgpu::updateDepthStencilAttachment(
443     wgpu::RenderPassDepthStencilAttachment newRenderPassDepthStencilAttachment)
444 {
445     mNewDepthStencilAttachment      = std::move(newRenderPassDepthStencilAttachment);
446     mAddedNewDepthStencilAttachment = true;
447 }
448 
flushOneColorAttachmentUpdate(const gl::Context * context,bool deferClears,uint32_t colorIndexGL)449 angle::Result FramebufferWgpu::flushOneColorAttachmentUpdate(const gl::Context *context,
450                                                              bool deferClears,
451                                                              uint32_t colorIndexGL)
452 {
453     ContextWgpu *contextWgpu           = GetImplAs<ContextWgpu>(context);
454     RenderTargetWgpu *drawRenderTarget = nullptr;
455     RenderTargetWgpu *readRenderTarget = nullptr;
456 
457     drawRenderTarget = mRenderTargetCache.getColorDraw(mState, colorIndexGL);
458     if (drawRenderTarget)
459     {
460         if (deferClears)
461         {
462             ANGLE_TRY(drawRenderTarget->flushImageStagedUpdates(contextWgpu, &mDeferredClears,
463                                                                 colorIndexGL));
464         }
465         else
466         {
467             ANGLE_TRY(drawRenderTarget->flushImageStagedUpdates(contextWgpu, nullptr, 0));
468         }
469     }
470 
471     if (mState.getReadBufferState() != GL_NONE && mState.getReadIndex() == colorIndexGL)
472     {
473         readRenderTarget = mRenderTargetCache.getColorRead(mState);
474         if (readRenderTarget && readRenderTarget != drawRenderTarget)
475         {
476             ANGLE_TRY(readRenderTarget->flushImageStagedUpdates(contextWgpu, nullptr, 0));
477         }
478     }
479 
480     return angle::Result::Continue;
481 }
482 
flushAttachmentUpdates(const gl::Context * context,gl::DrawBufferMask dirtyColorAttachments,bool dirtyDepthStencilAttachment,bool deferColorClears,bool deferDepthStencilClears)483 angle::Result FramebufferWgpu::flushAttachmentUpdates(const gl::Context *context,
484                                                       gl::DrawBufferMask dirtyColorAttachments,
485                                                       bool dirtyDepthStencilAttachment,
486                                                       bool deferColorClears,
487                                                       bool deferDepthStencilClears)
488 {
489     for (size_t colorIndexGL : dirtyColorAttachments)
490     {
491         ANGLE_TRY(flushOneColorAttachmentUpdate(context, deferColorClears,
492                                                 static_cast<uint32_t>(colorIndexGL)));
493     }
494 
495     ContextWgpu *contextWgpu         = GetImplAs<ContextWgpu>(context);
496     RenderTargetWgpu *depthStencilRt = mRenderTargetCache.getDepthStencil();
497 
498     if (depthStencilRt && dirtyDepthStencilAttachment)
499     {
500         if (deferDepthStencilClears)
501         {
502             // The underlying ImageHelper will check if a clear has a stencil value and store the
503             // deferred clear in the correct index.
504             ANGLE_TRY(depthStencilRt->flushImageStagedUpdates(contextWgpu, &mDeferredClears,
505                                                               webgpu::kUnpackedDepthIndex));
506         }
507         else
508         {
509             ANGLE_TRY(depthStencilRt->flushImageStagedUpdates(contextWgpu, nullptr, 0));
510         }
511     }
512 
513     // If we added any new attachments, we start a render pass to fully flush the updates.
514     if ((!mNewColorAttachments.empty() &&
515          mNewColorAttachments.size() != mCurrentColorAttachments.size()) ||
516         mAddedNewDepthStencilAttachment)
517     {
518         ANGLE_TRY(startRenderPassNewAttachments(contextWgpu));
519     }
520     return angle::Result::Continue;
521 }
522 
flushDeferredClears(ContextWgpu * contextWgpu)523 angle::Result FramebufferWgpu::flushDeferredClears(ContextWgpu *contextWgpu)
524 {
525     if (mDeferredClears.empty())
526     {
527         return angle::Result::Continue;
528     }
529     ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
530     mCurrentColorAttachments.clear();
531     for (size_t colorIndexGL : mState.getColorAttachmentsMask())
532     {
533         if (!mDeferredClears.test(colorIndexGL))
534         {
535             continue;
536         }
537         mCurrentColorAttachments.push_back(webgpu::CreateNewClearColorAttachment(
538             mDeferredClears[colorIndexGL].clearColor, mDeferredClears[colorIndexGL].depthSlice,
539             mRenderTargetCache.getColorDraw(mState, colorIndexGL)->getTextureView()));
540     }
541     if (mRenderTargetCache.getDepthStencil() &&
542         (mDeferredClears.hasDepth() || mDeferredClears.hasStencil()))
543     {
544         mCurrentDepthStencilAttachment = webgpu::CreateNewDepthStencilAttachment(
545             mDeferredClears.getDepthValue(), mDeferredClears.getStencilValue(),
546             mRenderTargetCache.getDepthStencil()->getTextureView(), !mDeferredClears.hasDepth(),
547             !mDeferredClears.hasStencil());
548         mCurrentRenderPassDesc.depthStencilAttachment = &mCurrentDepthStencilAttachment;
549     }
550     else
551     {
552         mCurrentRenderPassDesc.depthStencilAttachment = nullptr;
553     }
554     mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size();
555     mCurrentRenderPassDesc.colorAttachments     = mCurrentColorAttachments.data();
556     ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
557     ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
558 
559     return angle::Result::Continue;
560 }
561 
startRenderPassNewAttachments(ContextWgpu * contextWgpu)562 angle::Result FramebufferWgpu::startRenderPassNewAttachments(ContextWgpu *contextWgpu)
563 {
564     // Flush out a render pass if there is an active one.
565     ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
566 
567     setUpForRenderPass(contextWgpu, mAddedNewDepthStencilAttachment, mNewColorAttachments,
568                        mNewDepthStencilAttachment);
569     mNewColorAttachments.clear();
570     mAddedNewDepthStencilAttachment = false;
571     ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
572     return angle::Result::Continue;
573 }
574 
startNewRenderPass(ContextWgpu * contextWgpu)575 angle::Result FramebufferWgpu::startNewRenderPass(ContextWgpu *contextWgpu)
576 {
577     ANGLE_TRY(contextWgpu->endRenderPass(webgpu::RenderPassClosureReason::NewRenderPass));
578 
579     mCurrentColorAttachments.clear();
580     for (size_t colorIndexGL : mState.getColorAttachmentsMask())
581     {
582         wgpu::RenderPassColorAttachment colorAttachment;
583         colorAttachment.view =
584             mRenderTargetCache.getColorDraw(mState, colorIndexGL)->getTextureView();
585         colorAttachment.depthSlice = wgpu::kDepthSliceUndefined;
586         colorAttachment.loadOp     = wgpu::LoadOp::Load;
587         colorAttachment.storeOp    = wgpu::StoreOp::Store;
588 
589         mCurrentColorAttachments.push_back(colorAttachment);
590     }
591     if (mRenderTargetCache.getDepthStencil())
592     {
593         mCurrentDepthStencilAttachment = webgpu::CreateNewDepthStencilAttachment(
594             contextWgpu->getState().getDepthClearValue(),
595             static_cast<uint32_t>(contextWgpu->getState().getStencilClearValue()),
596             mRenderTargetCache.getDepthStencil()->getTextureView(), mState.hasDepth(),
597             mState.hasStencil());
598         mCurrentRenderPassDesc.depthStencilAttachment = &mCurrentDepthStencilAttachment;
599     }
600     else
601     {
602         mCurrentRenderPassDesc.depthStencilAttachment = nullptr;
603     }
604 
605     mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size();
606     mCurrentRenderPassDesc.colorAttachments     = mCurrentColorAttachments.data();
607     ANGLE_TRY(contextWgpu->startRenderPass(mCurrentRenderPassDesc));
608 
609     return angle::Result::Continue;
610 }
611 
setUpForRenderPass(ContextWgpu * contextWgpu,bool depthOrStencil,std::vector<wgpu::RenderPassColorAttachment> colorAttachments,wgpu::RenderPassDepthStencilAttachment depthStencilAttachment)612 void FramebufferWgpu::setUpForRenderPass(
613     ContextWgpu *contextWgpu,
614     bool depthOrStencil,
615     std::vector<wgpu::RenderPassColorAttachment> colorAttachments,
616     wgpu::RenderPassDepthStencilAttachment depthStencilAttachment)
617 {
618     if (depthOrStencil)
619     {
620         mCurrentDepthStencilAttachment                = std::move(depthStencilAttachment);
621         mCurrentRenderPassDesc.depthStencilAttachment = &mCurrentDepthStencilAttachment;
622     }
623     else
624     {
625         mCurrentRenderPassDesc.depthStencilAttachment = nullptr;
626     }
627     mCurrentColorAttachments                    = std::move(colorAttachments);
628     mCurrentRenderPassDesc.colorAttachmentCount = mCurrentColorAttachments.size();
629     mCurrentRenderPassDesc.colorAttachments     = mCurrentColorAttachments.data();
630 }
631 
mergeClearWithDeferredClears(wgpu::Color clearValue,gl::DrawBufferMask clearColorBuffers,float depthValue,uint32_t stencilValue,bool clearColor,bool clearDepth,bool clearStencil)632 void FramebufferWgpu::mergeClearWithDeferredClears(wgpu::Color clearValue,
633                                                    gl::DrawBufferMask clearColorBuffers,
634                                                    float depthValue,
635                                                    uint32_t stencilValue,
636                                                    bool clearColor,
637                                                    bool clearDepth,
638                                                    bool clearStencil)
639 {
640     for (size_t enabledDrawBuffer : clearColorBuffers)
641     {
642         mDeferredClears.store(static_cast<uint32_t>(enabledDrawBuffer),
643                               {clearValue, wgpu::kDepthSliceUndefined, 0, 0});
644     }
645     if (clearDepth)
646     {
647         mDeferredClears.store(webgpu::kUnpackedDepthIndex,
648                               {clearValue, wgpu::kDepthSliceUndefined, depthValue, 0});
649     }
650     if (clearStencil)
651     {
652         mDeferredClears.store(webgpu::kUnpackedStencilIndex,
653                               {clearValue, wgpu::kDepthSliceUndefined, 0, stencilValue});
654     }
655 }
656 
657 }  // namespace rx
658