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 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