1//
2// Copyright 2016 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// FramebufferVk.cpp:
7// Implements the class methods for FramebufferVk.
8//
9
10#include "libANGLE/renderer/vulkan/FramebufferVk.h"
11
12#include <array>
13
14#include "common/debug.h"
15#include "common/vulkan/vk_headers.h"
16#include "libANGLE/Context.h"
17#include "libANGLE/Display.h"
18#include "libANGLE/ErrorStrings.h"
19#include "libANGLE/formatutils.h"
20#include "libANGLE/renderer/renderer_utils.h"
21#include "libANGLE/renderer/vulkan/ContextVk.h"
22#include "libANGLE/renderer/vulkan/DisplayVk.h"
23#include "libANGLE/renderer/vulkan/RenderTargetVk.h"
24#include "libANGLE/renderer/vulkan/RendererVk.h"
25#include "libANGLE/renderer/vulkan/ResourceVk.h"
26#include "libANGLE/renderer/vulkan/SurfaceVk.h"
27#include "libANGLE/renderer/vulkan/vk_format_utils.h"
28
29namespace rx
30{
31
32namespace
33{
34// Clear values are only used when loadOp=Clear is set in clearWithRenderPassOp. When starting a
35// new render pass, the clear value is set to an unlikely value (bright pink) to stand out better
36// in case of a bug.
37constexpr VkClearValue kUninitializedClearValue = {.color: {.float32: {0.95, 0.05, 0.95, 0.95}}};
38
39// The value to assign an alpha channel that's emulated. The type is unsigned int, though it will
40// automatically convert to the actual data type.
41constexpr unsigned int kEmulatedAlphaValue = 1;
42
43bool HasSrcBlitFeature(RendererVk *renderer, RenderTargetVk *srcRenderTarget)
44{
45 angle::FormatID srcFormatID = srcRenderTarget->getImageActualFormatID();
46 return renderer->hasImageFormatFeatureBits(format: srcFormatID, featureBits: VK_FORMAT_FEATURE_BLIT_SRC_BIT);
47}
48
49bool HasDstBlitFeature(RendererVk *renderer, RenderTargetVk *dstRenderTarget)
50{
51 angle::FormatID dstFormatID = dstRenderTarget->getImageActualFormatID();
52 return renderer->hasImageFormatFeatureBits(format: dstFormatID, featureBits: VK_FORMAT_FEATURE_BLIT_DST_BIT);
53}
54
55// Returns false if destination has any channel the source doesn't. This means that channel was
56// emulated and using the Vulkan blit command would overwrite that emulated channel.
57bool AreSrcAndDstColorChannelsBlitCompatible(RenderTargetVk *srcRenderTarget,
58 RenderTargetVk *dstRenderTarget)
59{
60 const angle::Format &srcFormat = srcRenderTarget->getImageIntendedFormat();
61 const angle::Format &dstFormat = dstRenderTarget->getImageIntendedFormat();
62
63 // Luminance/alpha formats are not renderable, so they can't have ended up in a framebuffer to
64 // participate in a blit.
65 ASSERT(!dstFormat.isLUMA() && !srcFormat.isLUMA());
66
67 // All color formats have the red channel.
68 ASSERT(dstFormat.redBits > 0 && srcFormat.redBits > 0);
69
70 return (dstFormat.greenBits > 0 || srcFormat.greenBits == 0) &&
71 (dstFormat.blueBits > 0 || srcFormat.blueBits == 0) &&
72 (dstFormat.alphaBits > 0 || srcFormat.alphaBits == 0);
73}
74
75// Returns false if formats are not identical. vkCmdResolveImage and resolve attachments both
76// require identical formats between source and destination. vkCmdBlitImage additionally requires
77// the same for depth/stencil formats.
78bool AreSrcAndDstFormatsIdentical(RenderTargetVk *srcRenderTarget, RenderTargetVk *dstRenderTarget)
79{
80 angle::FormatID srcFormatID = srcRenderTarget->getImageActualFormatID();
81 angle::FormatID dstFormatID = dstRenderTarget->getImageActualFormatID();
82
83 return srcFormatID == dstFormatID;
84}
85
86bool AreSrcAndDstDepthStencilChannelsBlitCompatible(RenderTargetVk *srcRenderTarget,
87 RenderTargetVk *dstRenderTarget)
88{
89 const angle::Format &srcFormat = srcRenderTarget->getImageIntendedFormat();
90 const angle::Format &dstFormat = dstRenderTarget->getImageIntendedFormat();
91
92 return (dstFormat.depthBits > 0 || srcFormat.depthBits == 0) &&
93 (dstFormat.stencilBits > 0 || srcFormat.stencilBits == 0);
94}
95
96void EarlyAdjustFlipYForPreRotation(SurfaceRotation blitAngleIn,
97 SurfaceRotation *blitAngleOut,
98 bool *blitFlipYOut)
99{
100 switch (blitAngleIn)
101 {
102 case SurfaceRotation::Identity:
103 // No adjustments needed
104 break;
105 case SurfaceRotation::Rotated90Degrees:
106 *blitAngleOut = SurfaceRotation::Rotated90Degrees;
107 *blitFlipYOut = false;
108 break;
109 case SurfaceRotation::Rotated180Degrees:
110 *blitAngleOut = SurfaceRotation::Rotated180Degrees;
111 break;
112 case SurfaceRotation::Rotated270Degrees:
113 *blitAngleOut = SurfaceRotation::Rotated270Degrees;
114 *blitFlipYOut = false;
115 break;
116 default:
117 UNREACHABLE();
118 break;
119 }
120}
121
122void AdjustBlitAreaForPreRotation(SurfaceRotation framebufferAngle,
123 const gl::Rectangle &blitAreaIn,
124 const gl::Rectangle &framebufferDimensions,
125 gl::Rectangle *blitAreaOut)
126{
127 switch (framebufferAngle)
128 {
129 case SurfaceRotation::Identity:
130 // No adjustments needed
131 break;
132 case SurfaceRotation::Rotated90Degrees:
133 blitAreaOut->x = blitAreaIn.y;
134 blitAreaOut->y = blitAreaIn.x;
135 std::swap(x&: blitAreaOut->width, y&: blitAreaOut->height);
136 break;
137 case SurfaceRotation::Rotated180Degrees:
138 blitAreaOut->x = framebufferDimensions.width - blitAreaIn.x - blitAreaIn.width;
139 blitAreaOut->y = framebufferDimensions.height - blitAreaIn.y - blitAreaIn.height;
140 break;
141 case SurfaceRotation::Rotated270Degrees:
142 blitAreaOut->x = framebufferDimensions.height - blitAreaIn.y - blitAreaIn.height;
143 blitAreaOut->y = framebufferDimensions.width - blitAreaIn.x - blitAreaIn.width;
144 std::swap(x&: blitAreaOut->width, y&: blitAreaOut->height);
145 break;
146 default:
147 UNREACHABLE();
148 break;
149 }
150}
151
152void AdjustDimensionsAndFlipForPreRotation(SurfaceRotation framebufferAngle,
153 gl::Rectangle *framebufferDimensions,
154 bool *flipX,
155 bool *flipY)
156{
157 switch (framebufferAngle)
158 {
159 case SurfaceRotation::Identity:
160 // No adjustments needed
161 break;
162 case SurfaceRotation::Rotated90Degrees:
163 std::swap(x&: framebufferDimensions->width, y&: framebufferDimensions->height);
164 std::swap(x&: *flipX, y&: *flipY);
165 break;
166 case SurfaceRotation::Rotated180Degrees:
167 break;
168 case SurfaceRotation::Rotated270Degrees:
169 std::swap(x&: framebufferDimensions->width, y&: framebufferDimensions->height);
170 std::swap(x&: *flipX, y&: *flipY);
171 break;
172 default:
173 UNREACHABLE();
174 break;
175 }
176}
177
178// When blitting, the source and destination areas are viewed like UVs. For example, a 64x64
179// texture if flipped should have an offset of 64 in either X or Y which corresponds to U or V of 1.
180// On the other hand, when resolving, the source and destination areas are used as fragment
181// coordinates to fetch from. In that case, when flipped, the texture in the above example must
182// have an offset of 63.
183void AdjustBlitResolveParametersForResolve(const gl::Rectangle &sourceArea,
184 const gl::Rectangle &destArea,
185 UtilsVk::BlitResolveParameters *params)
186{
187 params->srcOffset[0] = sourceArea.x;
188 params->srcOffset[1] = sourceArea.y;
189 params->dstOffset[0] = destArea.x;
190 params->dstOffset[1] = destArea.y;
191
192 if (sourceArea.isReversedX())
193 {
194 ASSERT(sourceArea.x > 0);
195 --params->srcOffset[0];
196 }
197 if (sourceArea.isReversedY())
198 {
199 ASSERT(sourceArea.y > 0);
200 --params->srcOffset[1];
201 }
202 if (destArea.isReversedX())
203 {
204 ASSERT(destArea.x > 0);
205 --params->dstOffset[0];
206 }
207 if (destArea.isReversedY())
208 {
209 ASSERT(destArea.y > 0);
210 --params->dstOffset[1];
211 }
212}
213
214// Potentially make adjustments for pre-rotatation. Depending on the angle some of the params need
215// to be swapped and/or changes made to which axis are flipped.
216void AdjustBlitResolveParametersForPreRotation(SurfaceRotation framebufferAngle,
217 SurfaceRotation srcFramebufferAngle,
218 UtilsVk::BlitResolveParameters *params)
219{
220 switch (framebufferAngle)
221 {
222 case SurfaceRotation::Identity:
223 break;
224 case SurfaceRotation::Rotated90Degrees:
225 std::swap(x&: params->stretch[0], y&: params->stretch[1]);
226 std::swap(x&: params->srcOffset[0], y&: params->srcOffset[1]);
227 std::swap(x&: params->rotatedOffsetFactor[0], y&: params->rotatedOffsetFactor[1]);
228 std::swap(x&: params->flipX, y&: params->flipY);
229 if (srcFramebufferAngle == framebufferAngle)
230 {
231 std::swap(x&: params->dstOffset[0], y&: params->dstOffset[1]);
232 std::swap(x&: params->stretch[0], y&: params->stretch[1]);
233 }
234 break;
235 case SurfaceRotation::Rotated180Degrees:
236 // Combine flip info with api flip.
237 params->flipX = !params->flipX;
238 params->flipY = !params->flipY;
239 break;
240 case SurfaceRotation::Rotated270Degrees:
241 std::swap(x&: params->stretch[0], y&: params->stretch[1]);
242 std::swap(x&: params->srcOffset[0], y&: params->srcOffset[1]);
243 std::swap(x&: params->rotatedOffsetFactor[0], y&: params->rotatedOffsetFactor[1]);
244 if (srcFramebufferAngle == framebufferAngle)
245 {
246 std::swap(x&: params->stretch[0], y&: params->stretch[1]);
247 }
248 // Combine flip info with api flip.
249 params->flipX = !params->flipX;
250 params->flipY = !params->flipY;
251 std::swap(x&: params->flipX, y&: params->flipY);
252
253 break;
254 default:
255 UNREACHABLE();
256 break;
257 }
258}
259
260bool HasResolveAttachment(const gl::AttachmentArray<RenderTargetVk *> &colorRenderTargets,
261 const gl::DrawBufferMask &getEnabledDrawBuffers)
262{
263 for (size_t colorIndexGL : getEnabledDrawBuffers)
264 {
265 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
266 if (colorRenderTarget->hasResolveAttachment())
267 {
268 return true;
269 }
270 }
271 return false;
272}
273
274vk::FramebufferNonResolveAttachmentMask MakeUnresolveAttachmentMask(const vk::RenderPassDesc &desc)
275{
276 vk::FramebufferNonResolveAttachmentMask unresolveMask(
277 desc.getColorUnresolveAttachmentMask().bits());
278 if (desc.hasDepthUnresolveAttachment() || desc.hasStencilUnresolveAttachment())
279 {
280 // This mask only needs to know if the depth/stencil attachment needs to be unresolved, and
281 // is agnostic of the aspect.
282 unresolveMask.set(pos: vk::kUnpackedDepthIndex);
283 }
284 return unresolveMask;
285}
286
287bool IsAnyAttachment3DWithoutAllLayers(const RenderTargetCache<RenderTargetVk> &renderTargetCache,
288 gl::DrawBufferMask colorAttachmentsMask,
289 uint32_t framebufferLayerCount)
290{
291 const auto &colorRenderTargets = renderTargetCache.getColors();
292 for (size_t colorIndexGL : colorAttachmentsMask)
293 {
294 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
295 ASSERT(colorRenderTarget);
296
297 const vk::ImageHelper &image = colorRenderTarget->getImageForRenderPass();
298
299 if (image.getType() == VK_IMAGE_TYPE_3D && image.getExtents().depth > framebufferLayerCount)
300 {
301 return true;
302 }
303 }
304
305 // Depth/stencil attachments cannot be 3D.
306 ASSERT(renderTargetCache.getDepthStencil() == nullptr ||
307 renderTargetCache.getDepthStencil()->getImageForRenderPass().getType() !=
308 VK_IMAGE_TYPE_3D);
309
310 return false;
311}
312} // anonymous namespace
313
314FramebufferVk::FramebufferVk(RendererVk *renderer, const gl::FramebufferState &state)
315 : FramebufferImpl(state), mBackbuffer(nullptr), mActiveColorComponentMasksForClear(0)
316{
317 if (mState.isDefault())
318 {
319 // These are immutable for system default framebuffer.
320 mCurrentFramebufferDesc.updateLayerCount(layerCount: 1);
321 mCurrentFramebufferDesc.updateIsMultiview(isMultiview: false);
322 }
323
324 mIsCurrentFramebufferCached = !renderer->getFeatures().supportsImagelessFramebuffer.enabled;
325}
326
327FramebufferVk::~FramebufferVk() = default;
328
329void FramebufferVk::destroy(const gl::Context *context)
330{
331 ContextVk *contextVk = vk::GetImpl(glObject: context);
332 releaseCurrentFramebuffer(contextVk);
333}
334
335void FramebufferVk::insertCache(ContextVk *contextVk,
336 const vk::FramebufferDesc &desc,
337 vk::FramebufferHelper &&newFramebuffer)
338{
339 // Add it into per share group cache
340 contextVk->getShareGroup()->getFramebufferCache().insert(contextVk, desc,
341 framebufferHelper: std::move(newFramebuffer));
342
343 // Create a refcounted cache key object and have each attachment keep a refcount to it so that
344 // it can be destroyed promptly if those attachments change.
345 const vk::SharedFramebufferCacheKey sharedFramebufferCacheKey =
346 vk::CreateSharedFramebufferCacheKey(desc);
347
348 // Ask each attachment to hold a reference to the cache so that when any attachment is
349 // released, the cache can be destroyed.
350 const auto &colorRenderTargets = mRenderTargetCache.getColors();
351 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
352 {
353 colorRenderTargets[colorIndexGL]->onNewFramebuffer(sharedFramebufferCacheKey);
354 }
355
356 if (getDepthStencilRenderTarget())
357 {
358 getDepthStencilRenderTarget()->onNewFramebuffer(sharedFramebufferCacheKey);
359 }
360}
361
362angle::Result FramebufferVk::discard(const gl::Context *context,
363 size_t count,
364 const GLenum *attachments)
365{
366 return invalidate(context, count, attachments);
367}
368
369angle::Result FramebufferVk::invalidate(const gl::Context *context,
370 size_t count,
371 const GLenum *attachments)
372{
373 ContextVk *contextVk = vk::GetImpl(glObject: context);
374
375 ANGLE_TRY(invalidateImpl(contextVk, count, attachments, false,
376 getRotatedCompleteRenderArea(contextVk)));
377 return angle::Result::Continue;
378}
379
380angle::Result FramebufferVk::invalidateSub(const gl::Context *context,
381 size_t count,
382 const GLenum *attachments,
383 const gl::Rectangle &area)
384{
385 ContextVk *contextVk = vk::GetImpl(glObject: context);
386
387 const gl::Rectangle nonRotatedCompleteRenderArea = getNonRotatedCompleteRenderArea();
388 gl::Rectangle rotatedInvalidateArea;
389 RotateRectangle(rotation: contextVk->getRotationDrawFramebuffer(),
390 flipY: contextVk->isViewportFlipEnabledForDrawFBO(),
391 framebufferWidth: nonRotatedCompleteRenderArea.width, framebufferHeight: nonRotatedCompleteRenderArea.height, incoming: area,
392 outgoing: &rotatedInvalidateArea);
393
394 // If invalidateSub() covers the whole framebuffer area, make it behave as invalidate().
395 // The invalidate area is clipped to the render area for use inside invalidateImpl.
396 const gl::Rectangle completeRenderArea = getRotatedCompleteRenderArea(contextVk);
397 if (ClipRectangle(source: rotatedInvalidateArea, clip: completeRenderArea, intersection: &rotatedInvalidateArea) &&
398 rotatedInvalidateArea == completeRenderArea)
399 {
400 return invalidate(context, count, attachments);
401 }
402
403 // If there are deferred clears, redefer them. syncState may have accumulated deferred clears,
404 // but if the framebuffer's attachments are used after this call not through the framebuffer,
405 // those clears wouldn't get flushed otherwise (for example as the destination of
406 // glCopyTex[Sub]Image, shader storage image, etc).
407 redeferClears(contextVk);
408
409 if (contextVk->hasActiveRenderPass() &&
410 rotatedInvalidateArea.encloses(inside: contextVk->getStartedRenderPassCommands().getRenderArea()))
411 {
412 // Because the render pass's render area is within the invalidated area, it is fine for
413 // invalidateImpl() to use a storeOp of DONT_CARE (i.e. fine to not store the contents of
414 // the invalidated area).
415 ANGLE_TRY(invalidateImpl(contextVk, count, attachments, true, rotatedInvalidateArea));
416 }
417 else
418 {
419 ANGLE_VK_PERF_WARNING(
420 contextVk, GL_DEBUG_SEVERITY_LOW,
421 "InvalidateSubFramebuffer ignored due to area not covering the render area");
422 }
423
424 return angle::Result::Continue;
425}
426
427angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
428{
429 ANGLE_TRACE_EVENT0("gpu.angle", "FramebufferVk::clear");
430 ContextVk *contextVk = vk::GetImpl(glObject: context);
431
432 bool clearColor = IsMaskFlagSet(mask, flag: static_cast<GLbitfield>(GL_COLOR_BUFFER_BIT));
433 bool clearDepth = IsMaskFlagSet(mask, flag: static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT));
434 bool clearStencil = IsMaskFlagSet(mask, flag: static_cast<GLbitfield>(GL_STENCIL_BUFFER_BIT));
435 gl::DrawBufferMask clearColorBuffers;
436 if (clearColor)
437 {
438 clearColorBuffers = mState.getEnabledDrawBuffers();
439 }
440
441 const VkClearColorValue &clearColorValue = contextVk->getClearColorValue().color;
442 const VkClearDepthStencilValue &clearDepthStencilValue =
443 contextVk->getClearDepthStencilValue().depthStencil;
444
445 return clearImpl(context, clearColorBuffers, clearDepth, clearStencil, clearColorValue,
446 clearDepthStencilValue);
447}
448
449angle::Result FramebufferVk::clearImpl(const gl::Context *context,
450 gl::DrawBufferMask clearColorBuffers,
451 bool clearDepth,
452 bool clearStencil,
453 const VkClearColorValue &clearColorValue,
454 const VkClearDepthStencilValue &clearDepthStencilValue)
455{
456 ContextVk *contextVk = vk::GetImpl(glObject: context);
457
458 const gl::Rectangle scissoredRenderArea = getRotatedScissoredRenderArea(contextVk);
459 ASSERT(scissoredRenderArea.width != 0 && scissoredRenderArea.height != 0);
460
461 // This function assumes that only enabled attachments are asked to be cleared.
462 ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers);
463 ASSERT(!clearDepth || mState.getDepthAttachment() != nullptr);
464 ASSERT(!clearStencil || mState.getStencilAttachment() != nullptr);
465
466 gl::BlendStateExt::ColorMaskStorage::Type colorMasks = contextVk->getClearColorMasks();
467 bool clearColor = clearColorBuffers.any();
468
469 // When this function is called, there should always be something to clear.
470 ASSERT(clearColor || clearDepth || clearStencil);
471
472 const uint8_t stencilMask =
473 static_cast<uint8_t>(contextVk->getState().getDepthStencilState().stencilWritemask);
474
475 // The front-end should ensure we don't attempt to clear color if all channels are masked.
476 ASSERT(!clearColor || colorMasks != 0);
477 // The front-end should ensure we don't attempt to clear depth if depth write is disabled.
478 ASSERT(!clearDepth || contextVk->getState().getDepthStencilState().depthMask);
479 // The front-end should ensure we don't attempt to clear stencil if all bits are masked.
480 ASSERT(!clearStencil || stencilMask != 0);
481
482 // Make sure to close the render pass now if in read-only depth/stencil feedback loop mode and
483 // depth/stencil is being cleared.
484 if (clearDepth || clearStencil)
485 {
486 ANGLE_TRY(contextVk->updateRenderPassDepthFeedbackLoopMode(
487 clearDepth ? UpdateDepthFeedbackLoopReason::Clear : UpdateDepthFeedbackLoopReason::None,
488 clearStencil ? UpdateDepthFeedbackLoopReason::Clear
489 : UpdateDepthFeedbackLoopReason::None));
490 }
491
492 const bool scissoredClear = scissoredRenderArea != getRotatedCompleteRenderArea(contextVk);
493
494 // We use the draw path if scissored clear, or color or stencil are masked. Note that depth
495 // clearing is already disabled if there's a depth mask.
496 const bool maskedClearColor = clearColor && (mActiveColorComponentMasksForClear & colorMasks) !=
497 mActiveColorComponentMasksForClear;
498 const bool maskedClearStencil = clearStencil && stencilMask != 0xFF;
499
500 bool clearColorWithDraw = clearColor && (maskedClearColor || scissoredClear);
501 bool clearDepthWithDraw = clearDepth && scissoredClear;
502 bool clearStencilWithDraw = clearStencil && (maskedClearStencil || scissoredClear);
503
504 const bool isMidRenderPassClear =
505 contextVk->hasStartedRenderPassWithQueueSerial(queueSerial: mLastRenderPassQueueSerial) &&
506 !contextVk->getStartedRenderPassCommands().getCommandBuffer().empty();
507 if (isMidRenderPassClear)
508 {
509 // Emit debug-util markers for this mid-render-pass clear
510 ANGLE_TRY(
511 contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd));
512 }
513 else
514 {
515 ASSERT(!contextVk->hasActiveRenderPass() ||
516 contextVk->hasStartedRenderPassWithQueueSerial(mLastRenderPassQueueSerial));
517 // Emit debug-util markers for this outside-render-pass clear
518 ANGLE_TRY(
519 contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
520 }
521
522 const bool preferDrawOverClearAttachments =
523 contextVk->getRenderer()->getFeatures().preferDrawClearOverVkCmdClearAttachments.enabled;
524
525 // Merge current clears with the deferred clears, then proceed with only processing deferred
526 // clears. This simplifies the clear paths such that they don't need to consider both the
527 // current and deferred clears. Additionally, it avoids needing to undo an unresolve
528 // operation; say attachment A is deferred cleared and multisampled-render-to-texture
529 // attachment B is currently cleared. Assuming a render pass needs to start (because for
530 // example attachment C needs to clear with a draw path), starting one with only deferred
531 // clears and then applying the current clears won't work as attachment B is unresolved, and
532 // there are no facilities to undo that.
533 if (preferDrawOverClearAttachments && isMidRenderPassClear)
534 {
535 // On buggy hardware, prefer to clear with a draw call instead of vkCmdClearAttachments.
536 // Note that it's impossible to have deferred clears in the middle of the render pass.
537 ASSERT(!mDeferredClears.any());
538
539 clearColorWithDraw = clearColor;
540 clearDepthWithDraw = clearDepth;
541 clearStencilWithDraw = clearStencil;
542 }
543 else
544 {
545 gl::DrawBufferMask clearColorDrawBuffersMask;
546 if (clearColor && !clearColorWithDraw)
547 {
548 clearColorDrawBuffersMask = clearColorBuffers;
549 }
550
551 mergeClearsWithDeferredClears(clearColorBuffers: clearColorDrawBuffersMask, clearDepth: clearDepth && !clearDepthWithDraw,
552 clearStencil: clearStencil && !clearStencilWithDraw, clearColorValue,
553 clearDepthStencilValue);
554 }
555
556 // If any deferred clears, we can further defer them, clear them with vkCmdClearAttachments or
557 // flush them if necessary.
558 if (mDeferredClears.any())
559 {
560 const bool clearAnyWithDraw =
561 clearColorWithDraw || clearDepthWithDraw || clearStencilWithDraw;
562
563 bool isAnyAttachment3DWithoutAllLayers =
564 IsAnyAttachment3DWithoutAllLayers(renderTargetCache: mRenderTargetCache, colorAttachmentsMask: mState.getColorAttachmentsMask(),
565 framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount());
566
567 // If we are in an active renderpass that has recorded commands and the framebuffer hasn't
568 // changed, inline the clear.
569 if (isMidRenderPassClear)
570 {
571 ANGLE_VK_PERF_WARNING(
572 contextVk, GL_DEBUG_SEVERITY_LOW,
573 "Clear effectively discarding previous draw call results. Suggest earlier Clear "
574 "followed by masked color or depth/stencil draw calls instead, or "
575 "glInvalidateFramebuffer to discard data instead");
576
577 ASSERT(!preferDrawOverClearAttachments);
578
579 // clearWithCommand will operate on deferred clears.
580 clearWithCommand(contextVk, scissoredRenderArea, behavior: ClearWithCommand::OptimizeWithLoadOp,
581 clears: &mDeferredClears);
582
583 // clearWithCommand will clear only those attachments that have been used in the render
584 // pass, and removes them from mDeferredClears. Any deferred clears that are left can
585 // be performed with a renderpass loadOp.
586 if (mDeferredClears.any())
587 {
588 clearWithLoadOp(contextVk);
589 }
590 }
591 else
592 {
593 if (contextVk->hasActiveRenderPass())
594 {
595 // Typically, clears are deferred such that it's impossible to have a render pass
596 // opened without any additional commands recorded on it. This is not true for some
597 // corner cases, such as with 3D or external attachments. In those cases, a clear
598 // can open a render pass that's otherwise empty, and additional clears can continue
599 // to be accumulated in the render pass loadOps.
600 ASSERT(isAnyAttachment3DWithoutAllLayers || hasAnyExternalAttachments());
601 clearWithLoadOp(contextVk);
602 }
603
604 // This path will defer the current clears along with deferred clears. This won't work
605 // if any attachment needs to be subsequently cleared with a draw call. In that case,
606 // flush deferred clears, which will start a render pass with deferred clear values.
607 // The subsequent draw call will then operate on the cleared attachments.
608 //
609 // Additionally, if the framebuffer is layered, any attachment is 3D and it has a larger
610 // depth than the framebuffer layers, clears cannot be deferred. This is because the
611 // clear may later need to be flushed with vkCmdClearColorImage, which cannot partially
612 // clear the 3D texture. In that case, the clears are flushed immediately too.
613 //
614 // For external images such as from AHBs, the clears are not deferred so that they are
615 // definitely applied before the application uses them outside of the control of ANGLE.
616 if (clearAnyWithDraw || isAnyAttachment3DWithoutAllLayers ||
617 hasAnyExternalAttachments())
618 {
619 ANGLE_TRY(flushDeferredClears(contextVk));
620 }
621 else
622 {
623 redeferClears(contextVk);
624 }
625 }
626
627 // If nothing left to clear, early out.
628 if (!clearAnyWithDraw)
629 {
630 ASSERT(mDeferredClears.empty());
631 return angle::Result::Continue;
632 }
633 }
634
635 if (!clearColorWithDraw)
636 {
637 clearColorBuffers.reset();
638 }
639
640 // If we reach here simply because the clear is scissored (as opposed to masked), use
641 // vkCmdClearAttachments to clear the attachments. The attachments that are masked will
642 // continue to use a draw call. For depth, vkCmdClearAttachments can always be used, and no
643 // shader/pipeline support would then be required (though this is pending removal of the
644 // preferDrawOverClearAttachments workaround).
645 //
646 // A potential optimization is to use loadOp=Clear for scissored clears, but care needs to be
647 // taken to either break the render pass on growRenderArea(), or to turn the op back to Load and
648 // revert to vkCmdClearAttachments. This is not currently deemed necessary.
649 if (((clearColorBuffers.any() && !mEmulatedAlphaAttachmentMask.any() && !maskedClearColor) ||
650 clearDepthWithDraw || (clearStencilWithDraw && !maskedClearStencil)) &&
651 !preferDrawOverClearAttachments)
652 {
653 if (!contextVk->hasActiveRenderPass())
654 {
655 // Start a new render pass if necessary to record the commands.
656 vk::RenderPassCommandBuffer *commandBuffer;
657 gl::Rectangle renderArea = getRenderArea(contextVk);
658 ANGLE_TRY(contextVk->startRenderPass(renderArea, &commandBuffer, nullptr));
659 }
660
661 // Build clear values
662 vk::ClearValuesArray clears;
663 if (!maskedClearColor && !mEmulatedAlphaAttachmentMask.any())
664 {
665 VkClearValue colorClearValue = {};
666 colorClearValue.color = clearColorValue;
667 for (size_t colorIndexGL : clearColorBuffers)
668 {
669 clears.store(index: static_cast<uint32_t>(colorIndexGL), aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT,
670 clearValue: colorClearValue);
671 }
672 clearColorBuffers.reset();
673 }
674 VkImageAspectFlags dsAspectFlags = 0;
675 if (clearDepthWithDraw)
676 {
677 dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
678 clearDepthWithDraw = false;
679 }
680 if (clearStencilWithDraw && !maskedClearStencil)
681 {
682 dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
683 clearStencilWithDraw = false;
684 }
685 if (dsAspectFlags != 0)
686 {
687 VkClearValue dsClearValue = {};
688 dsClearValue.depthStencil = clearDepthStencilValue;
689 clears.store(index: vk::kUnpackedDepthIndex, aspectFlags: dsAspectFlags, clearValue: dsClearValue);
690 }
691
692 clearWithCommand(contextVk, scissoredRenderArea, behavior: ClearWithCommand::Always, clears: &clears);
693
694 if (!clearColorBuffers.any() && !clearStencilWithDraw)
695 {
696 ASSERT(!clearDepthWithDraw);
697 return angle::Result::Continue;
698 }
699 }
700
701 // The most costly clear mode is when we need to mask out specific color channels or stencil
702 // bits. This can only be done with a draw call.
703 return clearWithDraw(contextVk, clearArea: scissoredRenderArea, clearColorBuffers, clearDepth: clearDepthWithDraw,
704 clearStencil: clearStencilWithDraw, colorMasks, stencilMask, clearColorValue,
705 clearDepthStencilValue);
706}
707
708angle::Result FramebufferVk::clearBufferfv(const gl::Context *context,
709 GLenum buffer,
710 GLint drawbuffer,
711 const GLfloat *values)
712{
713 VkClearValue clearValue = {};
714
715 bool clearDepth = false;
716 gl::DrawBufferMask clearColorBuffers;
717
718 if (buffer == GL_DEPTH)
719 {
720 clearDepth = true;
721 clearValue.depthStencil.depth = values[0];
722 }
723 else
724 {
725 clearColorBuffers.set(pos: drawbuffer);
726 clearValue.color.float32[0] = values[0];
727 clearValue.color.float32[1] = values[1];
728 clearValue.color.float32[2] = values[2];
729 clearValue.color.float32[3] = values[3];
730 }
731
732 return clearImpl(context, clearColorBuffers, clearDepth, clearStencil: false, clearColorValue: clearValue.color,
733 clearDepthStencilValue: clearValue.depthStencil);
734}
735
736angle::Result FramebufferVk::clearBufferuiv(const gl::Context *context,
737 GLenum buffer,
738 GLint drawbuffer,
739 const GLuint *values)
740{
741 VkClearValue clearValue = {};
742
743 gl::DrawBufferMask clearColorBuffers;
744 clearColorBuffers.set(pos: drawbuffer);
745
746 clearValue.color.uint32[0] = values[0];
747 clearValue.color.uint32[1] = values[1];
748 clearValue.color.uint32[2] = values[2];
749 clearValue.color.uint32[3] = values[3];
750
751 return clearImpl(context, clearColorBuffers, clearDepth: false, clearStencil: false, clearColorValue: clearValue.color,
752 clearDepthStencilValue: clearValue.depthStencil);
753}
754
755angle::Result FramebufferVk::clearBufferiv(const gl::Context *context,
756 GLenum buffer,
757 GLint drawbuffer,
758 const GLint *values)
759{
760 VkClearValue clearValue = {};
761
762 bool clearStencil = false;
763 gl::DrawBufferMask clearColorBuffers;
764
765 if (buffer == GL_STENCIL)
766 {
767 clearStencil = true;
768 clearValue.depthStencil.stencil = static_cast<uint8_t>(values[0]);
769 }
770 else
771 {
772 clearColorBuffers.set(pos: drawbuffer);
773 clearValue.color.int32[0] = values[0];
774 clearValue.color.int32[1] = values[1];
775 clearValue.color.int32[2] = values[2];
776 clearValue.color.int32[3] = values[3];
777 }
778
779 return clearImpl(context, clearColorBuffers, clearDepth: false, clearStencil, clearColorValue: clearValue.color,
780 clearDepthStencilValue: clearValue.depthStencil);
781}
782
783angle::Result FramebufferVk::clearBufferfi(const gl::Context *context,
784 GLenum buffer,
785 GLint drawbuffer,
786 GLfloat depth,
787 GLint stencil)
788{
789 VkClearValue clearValue = {};
790
791 clearValue.depthStencil.depth = depth;
792 clearValue.depthStencil.stencil = static_cast<uint8_t>(stencil);
793
794 return clearImpl(context, clearColorBuffers: gl::DrawBufferMask(), clearDepth: true, clearStencil: true, clearColorValue: clearValue.color,
795 clearDepthStencilValue: clearValue.depthStencil);
796}
797
798const gl::InternalFormat &FramebufferVk::getImplementationColorReadFormat(
799 const gl::Context *context) const
800{
801 ContextVk *contextVk = vk::GetImpl(glObject: context);
802 GLenum sizedFormat = mState.getReadAttachment()->getFormat().info->sizedInternalFormat;
803 const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(internalFormat: sizedFormat);
804 GLenum implFormat = vkFormat.getActualRenderableImageFormat().fboImplementationInternalFormat;
805 return gl::GetSizedInternalFormatInfo(internalFormat: implFormat);
806}
807
808angle::Result FramebufferVk::readPixels(const gl::Context *context,
809 const gl::Rectangle &area,
810 GLenum format,
811 GLenum type,
812 const gl::PixelPackState &pack,
813 gl::Buffer *packBuffer,
814 void *pixels)
815{
816 // Clip read area to framebuffer.
817 const gl::Extents &fbSize = getState().getReadPixelsAttachment(readFormat: format)->getSize();
818 const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
819 ContextVk *contextVk = vk::GetImpl(glObject: context);
820
821 gl::Rectangle clippedArea;
822 if (!ClipRectangle(source: area, clip: fbRect, intersection: &clippedArea))
823 {
824 // nothing to read
825 return angle::Result::Continue;
826 }
827
828 // Flush any deferred clears.
829 ANGLE_TRY(flushDeferredClears(contextVk));
830
831 GLuint outputSkipBytes = 0;
832 PackPixelsParams params;
833 ANGLE_TRY(vk::ImageHelper::GetReadPixelsParams(contextVk, pack, packBuffer, format, type, area,
834 clippedArea, &params, &outputSkipBytes));
835
836 bool flipY = contextVk->isViewportFlipEnabledForReadFBO();
837 switch (params.rotation = contextVk->getRotationReadFramebuffer())
838 {
839 case SurfaceRotation::Identity:
840 // Do not rotate gl_Position (surface matches the device's orientation):
841 if (flipY)
842 {
843 params.area.y = fbRect.height - clippedArea.y - clippedArea.height;
844 }
845 break;
846 case SurfaceRotation::Rotated90Degrees:
847 // Rotate gl_Position 90 degrees:
848 params.area.x = clippedArea.y;
849 params.area.y =
850 flipY ? clippedArea.x : fbRect.width - clippedArea.x - clippedArea.width;
851 std::swap(x&: params.area.width, y&: params.area.height);
852 break;
853 case SurfaceRotation::Rotated180Degrees:
854 // Rotate gl_Position 180 degrees:
855 params.area.x = fbRect.width - clippedArea.x - clippedArea.width;
856 params.area.y =
857 flipY ? clippedArea.y : fbRect.height - clippedArea.y - clippedArea.height;
858 break;
859 case SurfaceRotation::Rotated270Degrees:
860 // Rotate gl_Position 270 degrees:
861 params.area.x = fbRect.height - clippedArea.y - clippedArea.height;
862 params.area.y =
863 flipY ? fbRect.width - clippedArea.x - clippedArea.width : clippedArea.x;
864 std::swap(x&: params.area.width, y&: params.area.height);
865 break;
866 default:
867 UNREACHABLE();
868 break;
869 }
870 if (flipY)
871 {
872 params.reverseRowOrder = !params.reverseRowOrder;
873 }
874
875 ANGLE_TRY(readPixelsImpl(contextVk, params.area, params, getReadPixelsAspectFlags(format),
876 getReadPixelsRenderTarget(format),
877 static_cast<uint8_t *>(pixels) + outputSkipBytes));
878 return angle::Result::Continue;
879}
880
881RenderTargetVk *FramebufferVk::getDepthStencilRenderTarget() const
882{
883 return mRenderTargetCache.getDepthStencil();
884}
885
886RenderTargetVk *FramebufferVk::getColorDrawRenderTarget(size_t colorIndexGL) const
887{
888 RenderTargetVk *renderTarget = mRenderTargetCache.getColorDraw(state: mState, colorIndex: colorIndexGL);
889 ASSERT(renderTarget && renderTarget->getImageForRenderPass().valid());
890 return renderTarget;
891}
892
893RenderTargetVk *FramebufferVk::getColorReadRenderTarget() const
894{
895 RenderTargetVk *renderTarget = mRenderTargetCache.getColorRead(state: mState);
896 ASSERT(renderTarget && renderTarget->getImageForRenderPass().valid());
897 return renderTarget;
898}
899
900RenderTargetVk *FramebufferVk::getReadPixelsRenderTarget(GLenum format) const
901{
902 switch (format)
903 {
904 case GL_DEPTH_COMPONENT:
905 case GL_STENCIL_INDEX_OES:
906 case GL_DEPTH_STENCIL_OES:
907 return getDepthStencilRenderTarget();
908 default:
909 return getColorReadRenderTarget();
910 }
911}
912
913VkImageAspectFlagBits FramebufferVk::getReadPixelsAspectFlags(GLenum format) const
914{
915 switch (format)
916 {
917 case GL_DEPTH_COMPONENT:
918 return VK_IMAGE_ASPECT_DEPTH_BIT;
919 case GL_STENCIL_INDEX_OES:
920 return VK_IMAGE_ASPECT_STENCIL_BIT;
921 case GL_DEPTH_STENCIL_OES:
922 return vk::IMAGE_ASPECT_DEPTH_STENCIL;
923 default:
924 return VK_IMAGE_ASPECT_COLOR_BIT;
925 }
926}
927
928angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
929 const gl::Rectangle &sourceArea,
930 const gl::Rectangle &destArea,
931 RenderTargetVk *readRenderTarget,
932 RenderTargetVk *drawRenderTarget,
933 GLenum filter,
934 bool colorBlit,
935 bool depthBlit,
936 bool stencilBlit,
937 bool flipX,
938 bool flipY)
939{
940 // Since blitRenderbufferRect is called for each render buffer that needs to be blitted,
941 // it should never be the case that both color and depth/stencil need to be blitted at
942 // at the same time.
943 ASSERT(colorBlit != (depthBlit || stencilBlit));
944
945 vk::ImageHelper *srcImage = &readRenderTarget->getImageForCopy();
946 vk::ImageHelper *dstImage = &drawRenderTarget->getImageForWrite();
947
948 VkImageAspectFlags imageAspectMask = srcImage->getAspectFlags();
949 VkImageAspectFlags blitAspectMask = imageAspectMask;
950
951 // Remove depth or stencil aspects if they are not requested to be blitted.
952 if (!depthBlit)
953 {
954 blitAspectMask &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
955 }
956 if (!stencilBlit)
957 {
958 blitAspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
959 }
960
961 vk::CommandBufferAccess access;
962 access.onImageTransferRead(aspectFlags: imageAspectMask, image: srcImage);
963 access.onImageTransferWrite(levelStart: drawRenderTarget->getLevelIndex(), levelCount: 1,
964 layerStart: drawRenderTarget->getLayerIndex(), layerCount: 1, aspectFlags: imageAspectMask, image: dstImage);
965 vk::OutsideRenderPassCommandBuffer *commandBuffer;
966 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
967
968 VkImageBlit blit = {};
969 blit.srcSubresource.aspectMask = blitAspectMask;
970 blit.srcSubresource.mipLevel = srcImage->toVkLevel(levelIndexGL: readRenderTarget->getLevelIndex()).get();
971 blit.srcSubresource.baseArrayLayer = readRenderTarget->getLayerIndex();
972 blit.srcSubresource.layerCount = 1;
973 blit.srcOffsets[0] = {.x: sourceArea.x0(), .y: sourceArea.y0(), .z: 0};
974 blit.srcOffsets[1] = {.x: sourceArea.x1(), .y: sourceArea.y1(), .z: 1};
975 blit.dstSubresource.aspectMask = blitAspectMask;
976 blit.dstSubresource.mipLevel = dstImage->toVkLevel(levelIndexGL: drawRenderTarget->getLevelIndex()).get();
977 blit.dstSubresource.baseArrayLayer = drawRenderTarget->getLayerIndex();
978 blit.dstSubresource.layerCount = 1;
979 blit.dstOffsets[0] = {.x: destArea.x0(), .y: destArea.y0(), .z: 0};
980 blit.dstOffsets[1] = {.x: destArea.x1(), .y: destArea.y1(), .z: 1};
981
982 commandBuffer->blitImage(srcImage: srcImage->getImage(), srcImageLayout: VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
983 dstImage: dstImage->getImage(), dstImageLayout: VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, regionCount: 1, regions: &blit,
984 filter: gl_vk::GetFilter(filter));
985
986 return angle::Result::Continue;
987}
988
989angle::Result FramebufferVk::blit(const gl::Context *context,
990 const gl::Rectangle &sourceAreaIn,
991 const gl::Rectangle &destAreaIn,
992 GLbitfield mask,
993 GLenum filter)
994{
995 ContextVk *contextVk = vk::GetImpl(glObject: context);
996 RendererVk *renderer = contextVk->getRenderer();
997 UtilsVk &utilsVk = contextVk->getUtils();
998
999 // If any clears were picked up when syncing the read framebuffer (as the blit source), redefer
1000 // them. They correspond to attachments that are not used in the blit. This will cause the
1001 // read framebuffer to become dirty, so the attachments will be synced again on the next command
1002 // that might be using them.
1003 const gl::State &glState = contextVk->getState();
1004 const gl::Framebuffer *srcFramebuffer = glState.getReadFramebuffer();
1005 FramebufferVk *srcFramebufferVk = vk::GetImpl(glObject: srcFramebuffer);
1006 if (srcFramebufferVk->mDeferredClears.any())
1007 {
1008 srcFramebufferVk->redeferClearsForReadFramebuffer(contextVk);
1009 }
1010
1011 // We can sometimes end up in a blit with some clear commands saved. Ensure all clear commands
1012 // are issued before we issue the blit command.
1013 ANGLE_TRY(flushDeferredClears(contextVk));
1014
1015 const bool blitColorBuffer = (mask & GL_COLOR_BUFFER_BIT) != 0;
1016 const bool blitDepthBuffer = (mask & GL_DEPTH_BUFFER_BIT) != 0;
1017 const bool blitStencilBuffer = (mask & GL_STENCIL_BUFFER_BIT) != 0;
1018
1019 // If a framebuffer contains a mixture of multisampled and multisampled-render-to-texture
1020 // attachments, this function could be simultaneously doing a blit on one attachment and resolve
1021 // on another. For the most part, this means resolve semantics apply. However, as the resolve
1022 // path cannot be taken for multisampled-render-to-texture attachments, the distinction of
1023 // whether resolve is done for each attachment or blit is made.
1024 const bool isColorResolve =
1025 blitColorBuffer &&
1026 srcFramebufferVk->getColorReadRenderTarget()->getImageForCopy().getSamples() > 1;
1027 const bool isDepthStencilResolve =
1028 (blitDepthBuffer || blitStencilBuffer) &&
1029 srcFramebufferVk->getDepthStencilRenderTarget()->getImageForCopy().getSamples() > 1;
1030 const bool isResolve = isColorResolve || isDepthStencilResolve;
1031
1032 bool srcFramebufferFlippedY = contextVk->isViewportFlipEnabledForReadFBO();
1033 bool dstFramebufferFlippedY = contextVk->isViewportFlipEnabledForDrawFBO();
1034
1035 gl::Rectangle sourceArea = sourceAreaIn;
1036 gl::Rectangle destArea = destAreaIn;
1037
1038 // Note: GLES (all 3.x versions) require source and destination area to be identical when
1039 // resolving.
1040 ASSERT(!isResolve ||
1041 (sourceArea.x == destArea.x && sourceArea.y == destArea.y &&
1042 sourceArea.width == destArea.width && sourceArea.height == destArea.height));
1043
1044 gl::Rectangle srcFramebufferDimensions = srcFramebufferVk->getNonRotatedCompleteRenderArea();
1045 gl::Rectangle dstFramebufferDimensions = getNonRotatedCompleteRenderArea();
1046
1047 // If the destination is flipped in either direction, we will flip the source instead so that
1048 // the destination area is always unflipped.
1049 sourceArea = sourceArea.flip(flipX: destArea.isReversedX(), flipY: destArea.isReversedY());
1050 destArea = destArea.removeReversal();
1051
1052 // Calculate the stretch factor prior to any clipping, as it needs to remain constant.
1053 const double stretch[2] = {
1054 std::abs(lcpp_x: sourceArea.width / static_cast<double>(destArea.width)),
1055 std::abs(lcpp_x: sourceArea.height / static_cast<double>(destArea.height)),
1056 };
1057
1058 // Potentially make adjustments for pre-rotatation. To handle various cases (e.g. clipping)
1059 // and to not interrupt the normal flow of the code, different adjustments are made in
1060 // different parts of the code. These first adjustments are for whether or not to flip the
1061 // y-axis, and to note the overall rotation (regardless of whether it is the source or
1062 // destination that is rotated).
1063 SurfaceRotation srcFramebufferRotation = contextVk->getRotationReadFramebuffer();
1064 SurfaceRotation dstFramebufferRotation = contextVk->getRotationDrawFramebuffer();
1065 SurfaceRotation rotation = SurfaceRotation::Identity;
1066 // Both the source and destination cannot be rotated (which would indicate both are the default
1067 // framebuffer (i.e. swapchain image).
1068 ASSERT((srcFramebufferRotation == SurfaceRotation::Identity) ||
1069 (dstFramebufferRotation == SurfaceRotation::Identity));
1070 EarlyAdjustFlipYForPreRotation(blitAngleIn: srcFramebufferRotation, blitAngleOut: &rotation, blitFlipYOut: &srcFramebufferFlippedY);
1071 EarlyAdjustFlipYForPreRotation(blitAngleIn: dstFramebufferRotation, blitAngleOut: &rotation, blitFlipYOut: &dstFramebufferFlippedY);
1072
1073 // First, clip the source area to framebuffer. That requires transforming the destination area
1074 // to match the clipped source.
1075 gl::Rectangle absSourceArea = sourceArea.removeReversal();
1076 gl::Rectangle clippedSourceArea;
1077 if (!gl::ClipRectangle(source: srcFramebufferDimensions, clip: absSourceArea, intersection: &clippedSourceArea))
1078 {
1079 return angle::Result::Continue;
1080 }
1081
1082 // Resize the destination area based on the new size of source. Note again that stretch is
1083 // calculated as SrcDimension/DestDimension.
1084 gl::Rectangle srcClippedDestArea;
1085 if (isResolve)
1086 {
1087 // Source and destination areas are identical in resolve (except rotate it, if appropriate).
1088 srcClippedDestArea = clippedSourceArea;
1089 AdjustBlitAreaForPreRotation(framebufferAngle: dstFramebufferRotation, blitAreaIn: clippedSourceArea,
1090 framebufferDimensions: dstFramebufferDimensions, blitAreaOut: &srcClippedDestArea);
1091 }
1092 else if (clippedSourceArea == absSourceArea)
1093 {
1094 // If there was no clipping, keep destination area as is (except rotate it, if appropriate).
1095 srcClippedDestArea = destArea;
1096 AdjustBlitAreaForPreRotation(framebufferAngle: dstFramebufferRotation, blitAreaIn: destArea, framebufferDimensions: dstFramebufferDimensions,
1097 blitAreaOut: &srcClippedDestArea);
1098 }
1099 else
1100 {
1101 // Shift destination area's x0,y0,x1,y1 by as much as the source area's got shifted (taking
1102 // stretching into account). Note that double is used as float doesn't have enough
1103 // precision near the end of int range.
1104 double x0Shift = std::round(x: (clippedSourceArea.x - absSourceArea.x) / stretch[0]);
1105 double y0Shift = std::round(x: (clippedSourceArea.y - absSourceArea.y) / stretch[1]);
1106 double x1Shift = std::round(x: (absSourceArea.x1() - clippedSourceArea.x1()) / stretch[0]);
1107 double y1Shift = std::round(x: (absSourceArea.y1() - clippedSourceArea.y1()) / stretch[1]);
1108
1109 // If the source area was reversed in any direction, the shift should be applied in the
1110 // opposite direction as well.
1111 if (sourceArea.isReversedX())
1112 {
1113 std::swap(x&: x0Shift, y&: x1Shift);
1114 }
1115
1116 if (sourceArea.isReversedY())
1117 {
1118 std::swap(x&: y0Shift, y&: y1Shift);
1119 }
1120
1121 srcClippedDestArea.x = destArea.x0() + static_cast<int>(x0Shift);
1122 srcClippedDestArea.y = destArea.y0() + static_cast<int>(y0Shift);
1123 int x1 = destArea.x1() - static_cast<int>(x1Shift);
1124 int y1 = destArea.y1() - static_cast<int>(y1Shift);
1125
1126 srcClippedDestArea.width = x1 - srcClippedDestArea.x;
1127 srcClippedDestArea.height = y1 - srcClippedDestArea.y;
1128
1129 // Rotate srcClippedDestArea if the destination is rotated
1130 if (dstFramebufferRotation != SurfaceRotation::Identity)
1131 {
1132 gl::Rectangle originalSrcClippedDestArea = srcClippedDestArea;
1133 AdjustBlitAreaForPreRotation(framebufferAngle: dstFramebufferRotation, blitAreaIn: originalSrcClippedDestArea,
1134 framebufferDimensions: dstFramebufferDimensions, blitAreaOut: &srcClippedDestArea);
1135 }
1136 }
1137
1138 // If framebuffers are flipped in Y, flip the source and destination area (which define the
1139 // transformation regardless of clipping), as well as the blit area (which is the clipped
1140 // destination area).
1141 if (srcFramebufferFlippedY)
1142 {
1143 sourceArea.y = srcFramebufferDimensions.height - sourceArea.y;
1144 sourceArea.height = -sourceArea.height;
1145 }
1146 if (dstFramebufferFlippedY)
1147 {
1148 destArea.y = dstFramebufferDimensions.height - destArea.y;
1149 destArea.height = -destArea.height;
1150
1151 srcClippedDestArea.y =
1152 dstFramebufferDimensions.height - srcClippedDestArea.y - srcClippedDestArea.height;
1153 }
1154
1155 bool flipX = sourceArea.isReversedX() != destArea.isReversedX();
1156 bool flipY = sourceArea.isReversedY() != destArea.isReversedY();
1157
1158 // GLES doesn't allow flipping the parameters of glBlitFramebuffer if performing a resolve.
1159 ASSERT(!isResolve ||
1160 (flipX == false && flipY == (srcFramebufferFlippedY != dstFramebufferFlippedY)));
1161
1162 // Again, transfer the destination flip to source, so destination is unflipped. Note that
1163 // destArea was not reversed until the final possible Y-flip.
1164 ASSERT(!destArea.isReversedX());
1165 sourceArea = sourceArea.flip(flipX: false, flipY: destArea.isReversedY());
1166 destArea = destArea.removeReversal();
1167
1168 // Now that clipping and flipping is done, rotate certain values that will be used for
1169 // UtilsVk::BlitResolveParameters
1170 gl::Rectangle sourceAreaOld = sourceArea;
1171 gl::Rectangle destAreaOld = destArea;
1172 if (srcFramebufferRotation == rotation)
1173 {
1174 AdjustBlitAreaForPreRotation(framebufferAngle: srcFramebufferRotation, blitAreaIn: sourceAreaOld,
1175 framebufferDimensions: srcFramebufferDimensions, blitAreaOut: &sourceArea);
1176 AdjustDimensionsAndFlipForPreRotation(framebufferAngle: srcFramebufferRotation, framebufferDimensions: &srcFramebufferDimensions,
1177 flipX: &flipX, flipY: &flipY);
1178 }
1179 SurfaceRotation rememberDestFramebufferRotation = dstFramebufferRotation;
1180 if (srcFramebufferRotation == SurfaceRotation::Rotated90Degrees)
1181 {
1182 dstFramebufferRotation = rotation;
1183 }
1184 AdjustBlitAreaForPreRotation(framebufferAngle: dstFramebufferRotation, blitAreaIn: destAreaOld, framebufferDimensions: dstFramebufferDimensions,
1185 blitAreaOut: &destArea);
1186 dstFramebufferRotation = rememberDestFramebufferRotation;
1187
1188 // Clip the destination area to the framebuffer size and scissor. Note that we don't care
1189 // about the source area anymore. The offset translation is done based on the original source
1190 // and destination rectangles. The stretch factor is already calculated as well.
1191 gl::Rectangle blitArea;
1192 if (!gl::ClipRectangle(source: getRotatedScissoredRenderArea(contextVk), clip: srcClippedDestArea, intersection: &blitArea))
1193 {
1194 return angle::Result::Continue;
1195 }
1196
1197 bool noClip = blitArea == destArea && stretch[0] == 1.0f && stretch[1] == 1.0f;
1198 bool noFlip = !flipX && !flipY;
1199 bool disableFlippingBlitWithCommand =
1200 contextVk->getRenderer()->getFeatures().disableFlippingBlitWithCommand.enabled;
1201
1202 UtilsVk::BlitResolveParameters commonParams;
1203 commonParams.srcOffset[0] = sourceArea.x;
1204 commonParams.srcOffset[1] = sourceArea.y;
1205 commonParams.dstOffset[0] = destArea.x;
1206 commonParams.dstOffset[1] = destArea.y;
1207 commonParams.rotatedOffsetFactor[0] = std::abs(x: sourceArea.width);
1208 commonParams.rotatedOffsetFactor[1] = std::abs(x: sourceArea.height);
1209 commonParams.stretch[0] = static_cast<float>(stretch[0]);
1210 commonParams.stretch[1] = static_cast<float>(stretch[1]);
1211 commonParams.srcExtents[0] = srcFramebufferDimensions.width;
1212 commonParams.srcExtents[1] = srcFramebufferDimensions.height;
1213 commonParams.blitArea = blitArea;
1214 commonParams.linear = filter == GL_LINEAR && !isResolve;
1215 commonParams.flipX = flipX;
1216 commonParams.flipY = flipY;
1217 commonParams.rotation = rotation;
1218
1219 if (blitColorBuffer)
1220 {
1221 RenderTargetVk *readRenderTarget = srcFramebufferVk->getColorReadRenderTarget();
1222 UtilsVk::BlitResolveParameters params = commonParams;
1223 params.srcLayer = readRenderTarget->getLayerIndex();
1224
1225 // Multisampled images are not allowed to have mips.
1226 ASSERT(!isColorResolve || readRenderTarget->getLevelIndex() == gl::LevelIndex(0));
1227
1228 // If there was no clipping and the format capabilities allow us, use Vulkan's builtin blit.
1229 // The reason clipping is prohibited in this path is that due to rounding errors, it would
1230 // be hard to guarantee the image stretching remains perfect. That also allows us not to
1231 // have to transform back the destination clipping to source.
1232 //
1233 // Non-identity pre-rotation cases do not use Vulkan's builtin blit.
1234 //
1235 // For simplicity, we either blit all render targets with a Vulkan command, or none.
1236 bool canBlitWithCommand =
1237 !isColorResolve && noClip && (noFlip || !disableFlippingBlitWithCommand) &&
1238 HasSrcBlitFeature(renderer, srcRenderTarget: readRenderTarget) && rotation == SurfaceRotation::Identity;
1239 // If we need to reinterpret the colorspace then the blit must be done through a shader
1240 bool reinterpretsColorspace =
1241 mCurrentFramebufferDesc.getWriteControlMode() != gl::SrgbWriteControlMode::Default;
1242 bool areChannelsBlitCompatible = true;
1243 bool areFormatsIdentical = true;
1244 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1245 {
1246 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
1247 canBlitWithCommand =
1248 canBlitWithCommand && HasDstBlitFeature(renderer, dstRenderTarget: drawRenderTarget);
1249 areChannelsBlitCompatible =
1250 areChannelsBlitCompatible &&
1251 AreSrcAndDstColorChannelsBlitCompatible(srcRenderTarget: readRenderTarget, dstRenderTarget: drawRenderTarget);
1252 areFormatsIdentical = areFormatsIdentical &&
1253 AreSrcAndDstFormatsIdentical(srcRenderTarget: readRenderTarget, dstRenderTarget: drawRenderTarget);
1254 }
1255
1256 // Now that all flipping is done, adjust the offsets for resolve and prerotation
1257 if (isColorResolve)
1258 {
1259 AdjustBlitResolveParametersForResolve(sourceArea, destArea, params: &params);
1260 }
1261 AdjustBlitResolveParametersForPreRotation(framebufferAngle: rotation, srcFramebufferAngle: srcFramebufferRotation, params: &params);
1262
1263 if (canBlitWithCommand && areChannelsBlitCompatible && !reinterpretsColorspace)
1264 {
1265 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1266 {
1267 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
1268 ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget,
1269 drawRenderTarget, filter, true, false, false, flipX,
1270 flipY));
1271 }
1272 }
1273 // If we're not flipping or rotating, use Vulkan's builtin resolve.
1274 else if (isColorResolve && !flipX && !flipY && areChannelsBlitCompatible &&
1275 areFormatsIdentical && rotation == SurfaceRotation::Identity &&
1276 !reinterpretsColorspace)
1277 {
1278 // Resolving with a subpass resolve attachment has a few restrictions:
1279 // 1.) glBlitFramebuffer() needs to copy the read color attachment to all enabled
1280 // attachments in the draw framebuffer, but Vulkan requires a 1:1 relationship for
1281 // multisample attachments to resolve attachments in the render pass subpass.
1282 // Due to this, we currently only support using resolve attachments when there is a
1283 // single draw attachment enabled.
1284 // 2.) Using a subpass resolve attachment relies on using the render pass that performs
1285 // the draw to still be open, so it can be updated to use the resolve attachment to draw
1286 // into. If there's no render pass with commands, then the multisampled render pass is
1287 // already done and whose data is already flushed from the tile (in a tile-based
1288 // renderer), so there's no chance for the resolve attachment to take advantage of the
1289 // data already being present in the tile.
1290
1291 // TODO(https://anglebug.com/4968): Support multiple open render passes so we can remove
1292 // this hack to 'restore' the finished render pass.
1293 // TODO(https://anglebug.com/7553): Look into optimization below in order to remove the
1294 // check of whether the current framebuffer is valid.
1295 bool isCurrentFramebufferValid = srcFramebufferVk->mCurrentFramebuffer.valid();
1296
1297 // glBlitFramebuffer() needs to copy the read color attachment to all enabled
1298 // attachments in the draw framebuffer, but Vulkan requires a 1:1 relationship for
1299 // multisample attachments to resolve attachments in the render pass subpass. Due to
1300 // this, we currently only support using resolve attachments when there is a single draw
1301 // attachment enabled.
1302 bool canResolveWithSubpass = isCurrentFramebufferValid &&
1303 mState.getEnabledDrawBuffers().count() == 1 &&
1304 mCurrentFramebufferDesc.getLayerCount() == 1 &&
1305 contextVk->hasStartedRenderPassWithQueueSerial(
1306 queueSerial: srcFramebufferVk->getLastRenderPassQueueSerial());
1307
1308 // Additionally, when resolving with a resolve attachment, the src and destination
1309 // offsets must match, the render area must match the resolve area, and there should be
1310 // no flipping or rotation. Fortunately, in GLES the blit source and destination areas
1311 // are already required to be identical.
1312 ASSERT(params.srcOffset[0] == params.dstOffset[0] &&
1313 params.srcOffset[1] == params.dstOffset[1]);
1314 canResolveWithSubpass =
1315 canResolveWithSubpass && noFlip && rotation == SurfaceRotation::Identity &&
1316 blitArea == contextVk->getStartedRenderPassCommands().getRenderArea();
1317
1318 if (canResolveWithSubpass)
1319 {
1320 ANGLE_TRY(resolveColorWithSubpass(contextVk, params));
1321 }
1322 else
1323 {
1324 ANGLE_TRY(resolveColorWithCommand(contextVk, params,
1325 &readRenderTarget->getImageForCopy()));
1326 }
1327 }
1328 // Otherwise use a shader to do blit or resolve.
1329 else
1330 {
1331 // Flush the render pass, which may incur a vkQueueSubmit, before taking any views.
1332 // Otherwise the view serials would not reflect the render pass they are really used in.
1333 // http://crbug.com/1272266#c22
1334 ANGLE_TRY(
1335 contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::PrepareForBlit));
1336
1337 const vk::ImageView *copyImageView = nullptr;
1338 ANGLE_TRY(readRenderTarget->getCopyImageView(contextVk, &copyImageView));
1339 ANGLE_TRY(utilsVk.colorBlitResolve(
1340 contextVk, this, &readRenderTarget->getImageForCopy(), copyImageView, params));
1341 }
1342 }
1343
1344 if (blitDepthBuffer || blitStencilBuffer)
1345 {
1346 RenderTargetVk *readRenderTarget = srcFramebufferVk->getDepthStencilRenderTarget();
1347 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getDepthStencil();
1348 UtilsVk::BlitResolveParameters params = commonParams;
1349 params.srcLayer = readRenderTarget->getLayerIndex();
1350
1351 // Multisampled images are not allowed to have mips.
1352 ASSERT(!isDepthStencilResolve || readRenderTarget->getLevelIndex() == gl::LevelIndex(0));
1353
1354 // Similarly, only blit if there's been no clipping or rotating.
1355 bool canBlitWithCommand =
1356 !isDepthStencilResolve && noClip && (noFlip || !disableFlippingBlitWithCommand) &&
1357 HasSrcBlitFeature(renderer, srcRenderTarget: readRenderTarget) &&
1358 HasDstBlitFeature(renderer, dstRenderTarget: drawRenderTarget) && rotation == SurfaceRotation::Identity;
1359 bool areChannelsBlitCompatible =
1360 AreSrcAndDstDepthStencilChannelsBlitCompatible(srcRenderTarget: readRenderTarget, dstRenderTarget: drawRenderTarget);
1361
1362 // glBlitFramebuffer requires that depth/stencil blits have matching formats.
1363 ASSERT(AreSrcAndDstFormatsIdentical(readRenderTarget, drawRenderTarget));
1364
1365 if (canBlitWithCommand && areChannelsBlitCompatible)
1366 {
1367 ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget,
1368 drawRenderTarget, filter, false, blitDepthBuffer,
1369 blitStencilBuffer, flipX, flipY));
1370 }
1371 else
1372 {
1373 // Now that all flipping is done, adjust the offsets for resolve and prerotation
1374 if (isDepthStencilResolve)
1375 {
1376 AdjustBlitResolveParametersForResolve(sourceArea, destArea, params: &params);
1377 }
1378 AdjustBlitResolveParametersForPreRotation(framebufferAngle: rotation, srcFramebufferAngle: srcFramebufferRotation, params: &params);
1379
1380 // Create depth- and stencil-only views for reading.
1381 vk::DeviceScoped<vk::ImageView> depthView(contextVk->getDevice());
1382 vk::DeviceScoped<vk::ImageView> stencilView(contextVk->getDevice());
1383
1384 vk::ImageHelper *depthStencilImage = &readRenderTarget->getImageForCopy();
1385 vk::LevelIndex levelIndex =
1386 depthStencilImage->toVkLevel(levelIndexGL: readRenderTarget->getLevelIndex());
1387 uint32_t layerIndex = readRenderTarget->getLayerIndex();
1388 gl::TextureType textureType = vk::Get2DTextureType(layerCount: depthStencilImage->getLayerCount(),
1389 samples: depthStencilImage->getSamples());
1390
1391 if (blitDepthBuffer)
1392 {
1393 ANGLE_TRY(depthStencilImage->initLayerImageView(
1394 contextVk, textureType, VK_IMAGE_ASPECT_DEPTH_BIT, gl::SwizzleState(),
1395 &depthView.get(), levelIndex, 1, layerIndex, 1,
1396 gl::SrgbWriteControlMode::Default, gl::YuvSamplingMode::Default,
1397 vk::ImageHelper::kDefaultImageViewUsageFlags));
1398 }
1399
1400 if (blitStencilBuffer)
1401 {
1402 ANGLE_TRY(depthStencilImage->initLayerImageView(
1403 contextVk, textureType, VK_IMAGE_ASPECT_STENCIL_BIT, gl::SwizzleState(),
1404 &stencilView.get(), levelIndex, 1, layerIndex, 1,
1405 gl::SrgbWriteControlMode::Default, gl::YuvSamplingMode::Default,
1406 vk::ImageHelper::kDefaultImageViewUsageFlags));
1407 }
1408
1409 // If shader stencil export is not possible, defer stencil blit/resolve to another pass.
1410 bool hasShaderStencilExport =
1411 contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled;
1412
1413 // Blit depth. If shader stencil export is present, blit stencil as well.
1414 if (blitDepthBuffer || (blitStencilBuffer && hasShaderStencilExport))
1415 {
1416 const vk::ImageView *depth = blitDepthBuffer ? &depthView.get() : nullptr;
1417 const vk::ImageView *stencil =
1418 blitStencilBuffer && hasShaderStencilExport ? &stencilView.get() : nullptr;
1419
1420 ANGLE_TRY(utilsVk.depthStencilBlitResolve(contextVk, this, depthStencilImage, depth,
1421 stencil, params));
1422 }
1423
1424 // If shader stencil export is not present, blit stencil through a different path.
1425 if (blitStencilBuffer && !hasShaderStencilExport)
1426 {
1427 ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
1428 "Inefficient BlitFramebuffer operation on the stencil aspect "
1429 "due to lack of shader stencil export support");
1430 ANGLE_TRY(utilsVk.stencilBlitResolveNoShaderExport(
1431 contextVk, this, depthStencilImage, &stencilView.get(), params));
1432 }
1433
1434 vk::ImageView depthViewObject = depthView.release();
1435 vk::ImageView stencilViewObject = stencilView.release();
1436
1437 contextVk->addGarbage(object: &depthViewObject);
1438 contextVk->addGarbage(object: &stencilViewObject);
1439 }
1440 }
1441
1442 return angle::Result::Continue;
1443}
1444
1445void FramebufferVk::updateColorResolveAttachment(
1446 uint32_t colorIndexGL,
1447 vk::ImageOrBufferViewSubresourceSerial resolveImageViewSerial)
1448{
1449 mCurrentFramebufferDesc.updateColorResolve(index: colorIndexGL, serial: resolveImageViewSerial);
1450 mRenderPassDesc.packColorResolveAttachment(colorIndexGL);
1451}
1452
1453void FramebufferVk::removeColorResolveAttachment(uint32_t colorIndexGL)
1454{
1455 mCurrentFramebufferDesc.updateColorResolve(index: colorIndexGL,
1456 serial: vk::kInvalidImageOrBufferViewSubresourceSerial);
1457 mRenderPassDesc.removeColorResolveAttachment(colorIndexGL);
1458}
1459
1460void FramebufferVk::releaseCurrentFramebuffer(ContextVk *contextVk)
1461{
1462 if (mIsCurrentFramebufferCached)
1463 {
1464 mCurrentFramebuffer.release();
1465 }
1466 else
1467 {
1468 contextVk->addGarbage(object: &mCurrentFramebuffer);
1469 }
1470}
1471
1472void FramebufferVk::updateLayerCount()
1473{
1474 uint32_t layerCount = std::numeric_limits<uint32_t>::max();
1475
1476 // Color attachments.
1477 const auto &colorRenderTargets = mRenderTargetCache.getColors();
1478 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
1479 {
1480 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
1481 ASSERT(colorRenderTarget);
1482 layerCount = std::min(a: layerCount, b: colorRenderTarget->getLayerCount());
1483 }
1484
1485 // Depth/stencil attachment.
1486 RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
1487 if (depthStencilRenderTarget)
1488 {
1489 layerCount = std::min(a: layerCount, b: depthStencilRenderTarget->getLayerCount());
1490 }
1491
1492 if (layerCount == std::numeric_limits<uint32_t>::max())
1493 {
1494 layerCount = mState.getDefaultLayers();
1495 }
1496
1497 // While layer count and view count are mutually exclusive, they result in different render
1498 // passes (and thus framebuffers). For multiview, layer count is set to view count and a flag
1499 // signifies that the framebuffer is multiview (as opposed to layered).
1500 const bool isMultiview = mState.isMultiview();
1501 if (isMultiview)
1502 {
1503 layerCount = mState.getNumViews();
1504 }
1505
1506 mCurrentFramebufferDesc.updateLayerCount(layerCount);
1507 mCurrentFramebufferDesc.updateIsMultiview(isMultiview);
1508}
1509
1510angle::Result FramebufferVk::resolveColorWithSubpass(ContextVk *contextVk,
1511 const UtilsVk::BlitResolveParameters &params)
1512{
1513 // Vulkan requires a 1:1 relationship for multisample attachments to resolve attachments in the
1514 // render pass subpass. Due to this, we currently only support using resolve attachments when
1515 // there is a single draw attachment enabled.
1516 ASSERT(mState.getEnabledDrawBuffers().count() == 1);
1517 uint32_t drawColorIndexGL = static_cast<uint32_t>(*mState.getEnabledDrawBuffers().begin());
1518
1519 const gl::State &glState = contextVk->getState();
1520 const gl::Framebuffer *srcFramebuffer = glState.getReadFramebuffer();
1521 FramebufferVk *srcFramebufferVk = vk::GetImpl(glObject: srcFramebuffer);
1522 uint32_t readColorIndexGL = srcFramebuffer->getState().getReadIndex();
1523
1524 // Use the draw FBO's color attachments as resolve attachments in the read FBO.
1525 // - Assign the draw FBO's color attachment Serial to the read FBO's resolve attachment
1526 // - Deactivate the source Framebuffer, since the description changed
1527 // - Update the renderpass description to indicate there's a resolve attachment
1528 vk::ImageOrBufferViewSubresourceSerial resolveImageViewSerial =
1529 mCurrentFramebufferDesc.getColorImageViewSerial(index: drawColorIndexGL);
1530 ASSERT(resolveImageViewSerial.viewSerial.valid());
1531 srcFramebufferVk->updateColorResolveAttachment(colorIndexGL: readColorIndexGL, resolveImageViewSerial);
1532 srcFramebufferVk->releaseCurrentFramebuffer(contextVk);
1533
1534 // Since the source FBO was updated with a resolve attachment it didn't have when the render
1535 // pass was started, we need to:
1536 // 1. Get the new framebuffer
1537 // - The draw framebuffer's ImageView will be used as the resolve attachment, so pass it along
1538 // in case vkCreateFramebuffer() needs to be called to create a new vkFramebuffer with the new
1539 // resolve attachment.
1540 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[drawColorIndexGL];
1541 const vk::ImageView *resolveImageView = nullptr;
1542 ANGLE_TRY(drawRenderTarget->getImageView(contextVk, &resolveImageView));
1543 vk::MaybeImagelessFramebuffer newSrcFramebuffer = {};
1544 ANGLE_TRY(srcFramebufferVk->getFramebuffer(contextVk, &newSrcFramebuffer, drawRenderTarget,
1545 resolveImageView, SwapchainResolveMode::Disabled));
1546 // 2. Update the RenderPassCommandBufferHelper with the new framebuffer and render pass
1547 vk::RenderPassCommandBufferHelper &commandBufferHelper =
1548 contextVk->getStartedRenderPassCommands();
1549 commandBufferHelper.updateRenderPassForResolve(contextVk, newFramebuffer&: newSrcFramebuffer,
1550 renderPassDesc: srcFramebufferVk->getRenderPassDesc());
1551
1552 // End the render pass now since we don't (yet) support subpass dependencies.
1553 drawRenderTarget->onColorResolve(contextVk, framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount());
1554 ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
1555 RenderPassClosureReason::AlreadySpecifiedElsewhere));
1556
1557 // Remove the resolve attachment from the source framebuffer.
1558 srcFramebufferVk->removeColorResolveAttachment(colorIndexGL: readColorIndexGL);
1559 srcFramebufferVk->releaseCurrentFramebuffer(contextVk);
1560
1561 return angle::Result::Continue;
1562}
1563
1564angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
1565 const UtilsVk::BlitResolveParameters &params,
1566 vk::ImageHelper *srcImage)
1567{
1568 vk::CommandBufferAccess access;
1569 access.onImageTransferRead(aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT, image: srcImage);
1570
1571 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1572 {
1573 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
1574 vk::ImageHelper &dstImage = drawRenderTarget->getImageForWrite();
1575
1576 access.onImageTransferWrite(levelStart: drawRenderTarget->getLevelIndex(), levelCount: 1,
1577 layerStart: drawRenderTarget->getLayerIndex(), layerCount: 1, aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT,
1578 image: &dstImage);
1579 }
1580
1581 vk::OutsideRenderPassCommandBuffer *commandBuffer;
1582 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1583
1584 VkImageResolve resolveRegion = {};
1585 resolveRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1586 resolveRegion.srcSubresource.mipLevel = 0;
1587 resolveRegion.srcSubresource.baseArrayLayer = params.srcLayer;
1588 resolveRegion.srcSubresource.layerCount = 1;
1589 resolveRegion.srcOffset.x = params.blitArea.x;
1590 resolveRegion.srcOffset.y = params.blitArea.y;
1591 resolveRegion.srcOffset.z = 0;
1592 resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1593 resolveRegion.dstSubresource.layerCount = 1;
1594 resolveRegion.dstOffset.x = params.blitArea.x;
1595 resolveRegion.dstOffset.y = params.blitArea.y;
1596 resolveRegion.dstOffset.z = 0;
1597 resolveRegion.extent.width = params.blitArea.width;
1598 resolveRegion.extent.height = params.blitArea.height;
1599 resolveRegion.extent.depth = 1;
1600
1601 angle::VulkanPerfCounters &perfCounters = contextVk->getPerfCounters();
1602 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1603 {
1604 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
1605 vk::ImageHelper &dstImage = drawRenderTarget->getImageForWrite();
1606
1607 vk::LevelIndex levelVk = dstImage.toVkLevel(levelIndexGL: drawRenderTarget->getLevelIndex());
1608 resolveRegion.dstSubresource.mipLevel = levelVk.get();
1609 resolveRegion.dstSubresource.baseArrayLayer = drawRenderTarget->getLayerIndex();
1610
1611 srcImage->resolve(dst: &dstImage, region: resolveRegion, commandBuffer);
1612
1613 perfCounters.resolveImageCommands++;
1614 }
1615
1616 return angle::Result::Continue;
1617}
1618
1619gl::FramebufferStatus FramebufferVk::checkStatus(const gl::Context *context) const
1620{
1621 // if we have both a depth and stencil buffer, they must refer to the same object
1622 // since we only support packed_depth_stencil and not separate depth and stencil
1623 if (mState.hasSeparateDepthAndStencilAttachments())
1624 {
1625 return gl::FramebufferStatus::Incomplete(
1626 GL_FRAMEBUFFER_UNSUPPORTED,
1627 reason: gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
1628 }
1629
1630 return gl::FramebufferStatus::Complete();
1631}
1632
1633angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
1634 size_t count,
1635 const GLenum *attachments,
1636 bool isSubInvalidate,
1637 const gl::Rectangle &invalidateArea)
1638{
1639 gl::DrawBufferMask invalidateColorBuffers;
1640 bool invalidateDepthBuffer = false;
1641 bool invalidateStencilBuffer = false;
1642
1643 for (size_t i = 0; i < count; ++i)
1644 {
1645 const GLenum attachment = attachments[i];
1646
1647 switch (attachment)
1648 {
1649 case GL_DEPTH:
1650 case GL_DEPTH_ATTACHMENT:
1651 invalidateDepthBuffer = true;
1652 break;
1653 case GL_STENCIL:
1654 case GL_STENCIL_ATTACHMENT:
1655 invalidateStencilBuffer = true;
1656 break;
1657 case GL_DEPTH_STENCIL_ATTACHMENT:
1658 invalidateDepthBuffer = true;
1659 invalidateStencilBuffer = true;
1660 break;
1661 default:
1662 ASSERT(
1663 (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) ||
1664 (attachment == GL_COLOR));
1665
1666 invalidateColorBuffers.set(
1667 pos: attachment == GL_COLOR ? 0u : (attachment - GL_COLOR_ATTACHMENT0));
1668 }
1669 }
1670
1671 // Shouldn't try to issue deferred clears if invalidating sub framebuffer.
1672 ASSERT(mDeferredClears.empty() || !isSubInvalidate);
1673
1674 // Remove deferred clears for the invalidated attachments.
1675 if (invalidateDepthBuffer)
1676 {
1677 mDeferredClears.reset(index: vk::kUnpackedDepthIndex);
1678 }
1679 if (invalidateStencilBuffer)
1680 {
1681 mDeferredClears.reset(index: vk::kUnpackedStencilIndex);
1682 }
1683 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1684 {
1685 if (invalidateColorBuffers.test(pos: colorIndexGL))
1686 {
1687 mDeferredClears.reset(index: colorIndexGL);
1688 }
1689 }
1690
1691 // If there are still deferred clears, redefer them. See relevant comment in invalidateSub.
1692 redeferClears(contextVk);
1693
1694 const auto &colorRenderTargets = mRenderTargetCache.getColors();
1695 RenderTargetVk *depthStencilRenderTarget = mRenderTargetCache.getDepthStencil();
1696
1697 // If not a partial invalidate, mark the contents of the invalidated attachments as undefined,
1698 // so their loadOp can be set to DONT_CARE in the following render pass.
1699 if (!isSubInvalidate)
1700 {
1701 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1702 {
1703 if (invalidateColorBuffers.test(pos: colorIndexGL))
1704 {
1705 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
1706 ASSERT(colorRenderTarget);
1707
1708 bool preferToKeepContentsDefined = false;
1709 colorRenderTarget->invalidateEntireContent(contextVk, preferToKeepContentsDefinedOut: &preferToKeepContentsDefined);
1710 if (preferToKeepContentsDefined)
1711 {
1712 invalidateColorBuffers.reset(pos: colorIndexGL);
1713 }
1714 }
1715 }
1716
1717 // If we have a depth / stencil render target, invalidate its aspects.
1718 if (depthStencilRenderTarget)
1719 {
1720 if (invalidateDepthBuffer)
1721 {
1722 bool preferToKeepContentsDefined = false;
1723 depthStencilRenderTarget->invalidateEntireContent(contextVk,
1724 preferToKeepContentsDefinedOut: &preferToKeepContentsDefined);
1725 if (preferToKeepContentsDefined)
1726 {
1727 invalidateDepthBuffer = false;
1728 }
1729 }
1730 if (invalidateStencilBuffer)
1731 {
1732 bool preferToKeepContentsDefined = false;
1733 depthStencilRenderTarget->invalidateEntireStencilContent(
1734 contextVk, preferToKeepContentsDefinedOut: &preferToKeepContentsDefined);
1735 if (preferToKeepContentsDefined)
1736 {
1737 invalidateStencilBuffer = false;
1738 }
1739 }
1740 }
1741 }
1742
1743 // To ensure we invalidate the right renderpass we require that the current framebuffer be the
1744 // same as the current renderpass' framebuffer. E.g. prevent sequence like:
1745 //- Bind FBO 1, draw
1746 //- Bind FBO 2, draw
1747 //- Bind FBO 1, invalidate D/S
1748 // to invalidate the D/S of FBO 2 since it would be the currently active renderpass.
1749 if (contextVk->hasStartedRenderPassWithQueueSerial(queueSerial: mLastRenderPassQueueSerial))
1750 {
1751 // Mark the invalidated attachments in the render pass for loadOp and storeOp determination
1752 // at its end.
1753 vk::PackedAttachmentIndex colorIndexVk(0);
1754 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
1755 {
1756 if (mState.getEnabledDrawBuffers()[colorIndexGL] &&
1757 invalidateColorBuffers.test(pos: colorIndexGL))
1758 {
1759 contextVk->getStartedRenderPassCommands().invalidateRenderPassColorAttachment(
1760 state: contextVk->getState(), colorIndexGL, attachmentIndex: colorIndexVk, invalidateArea);
1761 }
1762 ++colorIndexVk;
1763 }
1764
1765 if (depthStencilRenderTarget)
1766 {
1767 const gl::DepthStencilState &dsState = contextVk->getState().getDepthStencilState();
1768 if (invalidateDepthBuffer)
1769 {
1770 contextVk->getStartedRenderPassCommands().invalidateRenderPassDepthAttachment(
1771 dsState, invalidateArea);
1772 }
1773
1774 if (invalidateStencilBuffer)
1775 {
1776 contextVk->getStartedRenderPassCommands().invalidateRenderPassStencilAttachment(
1777 dsState, invalidateArea);
1778 }
1779 }
1780 if (invalidateColorBuffers.any())
1781 {
1782 // Only end the render pass if invalidating at least one color buffer. Do not end the
1783 // render pass if only the depth and/or stencil buffer is invalidated. At least one
1784 // application invalidates those every frame, disables depth, and then continues to
1785 // draw only to the color buffer.
1786 //
1787 // Since we are not aware of any application that invalidates a color buffer and
1788 // continues to draw to it, we leave that unoptimized.
1789 ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
1790 RenderPassClosureReason::ColorBufferInvalidate));
1791 }
1792 }
1793
1794 return angle::Result::Continue;
1795}
1796
1797angle::Result FramebufferVk::updateColorAttachment(const gl::Context *context,
1798 uint32_t colorIndexGL)
1799{
1800 ANGLE_TRY(mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL));
1801
1802 // Update cached masks for masked clears.
1803 RenderTargetVk *renderTarget = mRenderTargetCache.getColors()[colorIndexGL];
1804 if (renderTarget)
1805 {
1806 const angle::Format &actualFormat = renderTarget->getImageActualFormat();
1807 updateActiveColorMasks(colorIndex: colorIndexGL, r: actualFormat.redBits > 0, g: actualFormat.greenBits > 0,
1808 b: actualFormat.blueBits > 0, a: actualFormat.alphaBits > 0);
1809
1810 const angle::Format &intendedFormat = renderTarget->getImageIntendedFormat();
1811 mEmulatedAlphaAttachmentMask.set(
1812 pos: colorIndexGL, value: intendedFormat.alphaBits == 0 && actualFormat.alphaBits > 0);
1813 }
1814 else
1815 {
1816 updateActiveColorMasks(colorIndex: colorIndexGL, r: false, g: false, b: false, a: false);
1817 }
1818
1819 const bool enabledColor =
1820 renderTarget && mState.getColorAttachments()[colorIndexGL].isAttached();
1821 const bool enabledResolve = enabledColor && renderTarget->hasResolveAttachment();
1822
1823 if (enabledColor)
1824 {
1825 mCurrentFramebufferDesc.updateColor(index: colorIndexGL, serial: renderTarget->getDrawSubresourceSerial());
1826 const bool isExternalImage =
1827 mState.getColorAttachments()[colorIndexGL].isExternalImageWithoutIndividualSync();
1828 mIsExternalColorAttachments.set(pos: colorIndexGL, value: isExternalImage);
1829 mAttachmentHasFrontBufferUsage.set(
1830 pos: colorIndexGL, value: mState.getColorAttachments()[colorIndexGL].hasFrontBufferUsage());
1831 }
1832 else
1833 {
1834 mCurrentFramebufferDesc.updateColor(index: colorIndexGL,
1835 serial: vk::kInvalidImageOrBufferViewSubresourceSerial);
1836 }
1837
1838 if (enabledResolve)
1839 {
1840 mCurrentFramebufferDesc.updateColorResolve(index: colorIndexGL,
1841 serial: renderTarget->getResolveSubresourceSerial());
1842 }
1843 else
1844 {
1845 mCurrentFramebufferDesc.updateColorResolve(index: colorIndexGL,
1846 serial: vk::kInvalidImageOrBufferViewSubresourceSerial);
1847 }
1848
1849 return angle::Result::Continue;
1850}
1851
1852angle::Result FramebufferVk::updateDepthStencilAttachment(const gl::Context *context)
1853{
1854 ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState));
1855
1856 ContextVk *contextVk = vk::GetImpl(glObject: context);
1857 updateDepthStencilAttachmentSerial(contextVk);
1858
1859 return angle::Result::Continue;
1860}
1861
1862void FramebufferVk::updateDepthStencilAttachmentSerial(ContextVk *contextVk)
1863{
1864 RenderTargetVk *depthStencilRT = getDepthStencilRenderTarget();
1865
1866 if (depthStencilRT != nullptr)
1867 {
1868 mCurrentFramebufferDesc.updateDepthStencil(serial: depthStencilRT->getDrawSubresourceSerial());
1869 }
1870 else
1871 {
1872 mCurrentFramebufferDesc.updateDepthStencil(serial: vk::kInvalidImageOrBufferViewSubresourceSerial);
1873 }
1874
1875 if (depthStencilRT != nullptr && depthStencilRT->hasResolveAttachment())
1876 {
1877 mCurrentFramebufferDesc.updateDepthStencilResolve(
1878 serial: depthStencilRT->getResolveSubresourceSerial());
1879 }
1880 else
1881 {
1882 mCurrentFramebufferDesc.updateDepthStencilResolve(
1883 serial: vk::kInvalidImageOrBufferViewSubresourceSerial);
1884 }
1885}
1886
1887angle::Result FramebufferVk::flushColorAttachmentUpdates(const gl::Context *context,
1888 bool deferClears,
1889 uint32_t colorIndexGL)
1890{
1891 ContextVk *contextVk = vk::GetImpl(glObject: context);
1892 RenderTargetVk *readRenderTarget = nullptr;
1893 RenderTargetVk *drawRenderTarget = nullptr;
1894
1895 // It's possible for the read and draw color attachments to be different if different surfaces
1896 // are bound, so we need to flush any staged updates to both.
1897
1898 // Draw
1899 drawRenderTarget = mRenderTargetCache.getColorDraw(state: mState, colorIndex: colorIndexGL);
1900 if (drawRenderTarget)
1901 {
1902 if (deferClears)
1903 {
1904 ANGLE_TRY(
1905 drawRenderTarget->flushStagedUpdates(contextVk, &mDeferredClears, colorIndexGL,
1906 mCurrentFramebufferDesc.getLayerCount()));
1907 }
1908 else
1909 {
1910 ANGLE_TRY(drawRenderTarget->flushStagedUpdates(
1911 contextVk, nullptr, 0, mCurrentFramebufferDesc.getLayerCount()));
1912 }
1913 }
1914
1915 // Read
1916 if (mState.getReadBufferState() != GL_NONE && mState.getReadIndex() == colorIndexGL)
1917 {
1918 // Flush staged updates to the read render target as well, but only if it's not the same as
1919 // the draw render target. This can happen when the read render target is bound to another
1920 // surface.
1921 readRenderTarget = mRenderTargetCache.getColorRead(state: mState);
1922 if (readRenderTarget && readRenderTarget != drawRenderTarget)
1923 {
1924 ANGLE_TRY(readRenderTarget->flushStagedUpdates(
1925 contextVk, nullptr, 0, mCurrentFramebufferDesc.getLayerCount()));
1926 }
1927 }
1928
1929 return angle::Result::Continue;
1930}
1931
1932angle::Result FramebufferVk::flushDepthStencilAttachmentUpdates(const gl::Context *context,
1933 bool deferClears)
1934{
1935 ContextVk *contextVk = vk::GetImpl(glObject: context);
1936
1937 RenderTargetVk *depthStencilRT = getDepthStencilRenderTarget();
1938 if (depthStencilRT == nullptr)
1939 {
1940 return angle::Result::Continue;
1941 }
1942
1943 if (deferClears)
1944 {
1945 return depthStencilRT->flushStagedUpdates(contextVk, deferredClears: &mDeferredClears,
1946 deferredClearIndex: vk::kUnpackedDepthIndex,
1947 framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount());
1948 }
1949
1950 return depthStencilRT->flushStagedUpdates(contextVk, deferredClears: nullptr, deferredClearIndex: 0,
1951 framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount());
1952}
1953
1954angle::Result FramebufferVk::syncState(const gl::Context *context,
1955 GLenum binding,
1956 const gl::Framebuffer::DirtyBits &dirtyBits,
1957 gl::Command command)
1958{
1959 ContextVk *contextVk = vk::GetImpl(glObject: context);
1960
1961 vk::FramebufferDesc priorFramebufferDesc = mCurrentFramebufferDesc;
1962
1963 // Keep track of which attachments have dirty content and need their staged updates flushed.
1964 // The respective functions depend on |mCurrentFramebufferDesc::mLayerCount| which is updated
1965 // after all attachment render targets are updated.
1966 gl::DrawBufferMask dirtyColorAttachments;
1967 bool dirtyDepthStencilAttachment = false;
1968
1969 bool shouldUpdateColorMaskAndBlend = false;
1970 bool shouldUpdateLayerCount = false;
1971 bool shouldUpdateSrgbWriteControlMode = false;
1972
1973 // For any updated attachments we'll update their Serials below
1974 ASSERT(dirtyBits.any());
1975 for (size_t dirtyBit : dirtyBits)
1976 {
1977 switch (dirtyBit)
1978 {
1979 case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
1980 case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS:
1981 case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
1982 case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS:
1983 ANGLE_TRY(updateDepthStencilAttachment(context));
1984 shouldUpdateLayerCount = true;
1985 dirtyDepthStencilAttachment = true;
1986 break;
1987 case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
1988 ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
1989 break;
1990 case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
1991 shouldUpdateColorMaskAndBlend = true;
1992 shouldUpdateLayerCount = true;
1993 break;
1994 case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
1995 case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
1996 case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
1997 case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
1998 // Invalidate the cache. If we have performance critical code hitting this path we
1999 // can add related data (such as width/height) to the cache
2000 releaseCurrentFramebuffer(contextVk);
2001 break;
2002 case gl::Framebuffer::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE:
2003 shouldUpdateSrgbWriteControlMode = true;
2004 break;
2005 case gl::Framebuffer::DIRTY_BIT_DEFAULT_LAYERS:
2006 shouldUpdateLayerCount = true;
2007 break;
2008 default:
2009 {
2010 static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
2011 uint32_t colorIndexGL;
2012 if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
2013 {
2014 colorIndexGL = static_cast<uint32_t>(
2015 dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
2016 }
2017 else
2018 {
2019 ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 &&
2020 dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX);
2021 colorIndexGL = static_cast<uint32_t>(
2022 dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
2023 }
2024
2025 ANGLE_TRY(updateColorAttachment(context, colorIndexGL));
2026
2027 // Window system framebuffer only have one color attachment and its property should
2028 // never change unless via DIRTY_BIT_DRAW_BUFFERS bit.
2029 if (!mState.isDefault())
2030 {
2031 shouldUpdateColorMaskAndBlend = true;
2032 shouldUpdateLayerCount = true;
2033 }
2034 dirtyColorAttachments.set(pos: colorIndexGL);
2035
2036 break;
2037 }
2038 }
2039 }
2040
2041 if (shouldUpdateSrgbWriteControlMode)
2042 {
2043 // Framebuffer colorspace state has been modified, so refresh the current framebuffer
2044 // descriptor to reflect the new state.
2045 gl::SrgbWriteControlMode newSrgbWriteControlMode = mState.getWriteControlMode();
2046 mCurrentFramebufferDesc.setWriteControlMode(newSrgbWriteControlMode);
2047 mRenderPassDesc.setWriteControlMode(newSrgbWriteControlMode);
2048 }
2049
2050 if (shouldUpdateColorMaskAndBlend)
2051 {
2052 contextVk->updateColorMasks();
2053 contextVk->updateBlendFuncsAndEquations();
2054 }
2055
2056 if (shouldUpdateLayerCount)
2057 {
2058 updateLayerCount();
2059 }
2060
2061 // Defer clears for draw framebuffer ops. Note that this will result in a render area that
2062 // completely covers the framebuffer, even if the operation that follows is scissored.
2063 //
2064 // Additionally, defer clears for read framebuffer attachments that are not taking part in a
2065 // blit operation.
2066 const bool isBlitCommand = command >= gl::Command::Blit && command <= gl::Command::BlitAll;
2067
2068 bool deferColorClears = binding == GL_DRAW_FRAMEBUFFER;
2069 bool deferDepthStencilClears = binding == GL_DRAW_FRAMEBUFFER;
2070 if (binding == GL_READ_FRAMEBUFFER && isBlitCommand)
2071 {
2072 uint32_t blitMask =
2073 static_cast<uint32_t>(command) - static_cast<uint32_t>(gl::Command::Blit);
2074 if ((blitMask & gl::CommandBlitBufferColor) == 0)
2075 {
2076 deferColorClears = true;
2077 }
2078 if ((blitMask & (gl::CommandBlitBufferDepth | gl::CommandBlitBufferStencil)) == 0)
2079 {
2080 deferDepthStencilClears = true;
2081 }
2082 }
2083
2084 // If we are notified that any attachment is dirty, but we have deferred clears for them, a
2085 // flushDeferredClears() call is missing somewhere. ASSERT this to catch these bugs.
2086 vk::ClearValuesArray previousDeferredClears = mDeferredClears;
2087
2088 for (size_t colorIndexGL : dirtyColorAttachments)
2089 {
2090 ASSERT(!previousDeferredClears.test(colorIndexGL));
2091 ANGLE_TRY(flushColorAttachmentUpdates(context, deferColorClears,
2092 static_cast<uint32_t>(colorIndexGL)));
2093 }
2094 if (dirtyDepthStencilAttachment)
2095 {
2096 ASSERT(!previousDeferredClears.testDepth());
2097 ASSERT(!previousDeferredClears.testStencil());
2098 ANGLE_TRY(flushDepthStencilAttachmentUpdates(context, deferDepthStencilClears));
2099 }
2100
2101 // No-op redundant changes to prevent closing the RenderPass.
2102 if (mCurrentFramebufferDesc == priorFramebufferDesc &&
2103 mCurrentFramebufferDesc.attachmentCount() > 0)
2104 {
2105 return angle::Result::Continue;
2106 }
2107
2108 if (!isBlitCommand)
2109 {
2110 // Don't end the render pass when handling a blit to resolve, since we may be able to
2111 // optimize that path which requires modifying the current render pass.
2112 // We're deferring the resolve check to FramebufferVk::blit(), since if the read buffer is
2113 // multisampled-render-to-texture, then srcFramebuffer->getSamples(context) gives > 1, but
2114 // there's no resolve happening as the read buffer's single sampled image will be used as
2115 // blit src. FramebufferVk::blit() will handle those details for us.
2116
2117 // ContextVk::onFramebufferChange will end up calling onRenderPassFinished if necessary,
2118 // whih will trigger ending of current render pass if needed. But we still need to reset
2119 // mLastRenderPassQueueSerial so that it will not get reactivated, since the
2120 // mCurrentFramebufferDesc has changed.
2121 mLastRenderPassQueueSerial = QueueSerial();
2122 }
2123
2124 updateRenderPassDesc(contextVk);
2125
2126 // Deactivate Framebuffer
2127 releaseCurrentFramebuffer(contextVk);
2128
2129 // Notify the ContextVk to update the pipeline desc.
2130 return contextVk->onFramebufferChange(framebufferVk: this, command);
2131}
2132
2133void FramebufferVk::updateRenderPassDesc(ContextVk *contextVk)
2134{
2135 mRenderPassDesc = {};
2136 mRenderPassDesc.setSamples(getSamples());
2137 mRenderPassDesc.setViewCount(
2138 mState.isMultiview() && mState.getNumViews() > 1 ? mState.getNumViews() : 0);
2139
2140 // Color attachments.
2141 const auto &colorRenderTargets = mRenderTargetCache.getColors();
2142 const gl::DrawBufferMask colorAttachmentMask = mState.getColorAttachmentsMask();
2143 for (size_t colorIndexGL = 0; colorIndexGL < colorAttachmentMask.size(); ++colorIndexGL)
2144 {
2145 if (colorAttachmentMask[colorIndexGL])
2146 {
2147 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
2148 ASSERT(colorRenderTarget);
2149 mRenderPassDesc.packColorAttachment(
2150 colorIndexGL, formatID: colorRenderTarget->getImageForRenderPass().getActualFormatID());
2151
2152 // Add the resolve attachment, if any.
2153 if (colorRenderTarget->hasResolveAttachment())
2154 {
2155 mRenderPassDesc.packColorResolveAttachment(colorIndexGL);
2156 }
2157 }
2158 else
2159 {
2160 mRenderPassDesc.packColorAttachmentGap(colorIndexGL);
2161 }
2162 }
2163
2164 // Depth/stencil attachment.
2165 RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
2166 if (depthStencilRenderTarget)
2167 {
2168 mRenderPassDesc.packDepthStencilAttachment(
2169 angleFormatID: depthStencilRenderTarget->getImageForRenderPass().getActualFormatID());
2170
2171 // Add the resolve attachment, if any.
2172 if (depthStencilRenderTarget->hasResolveAttachment())
2173 {
2174 mRenderPassDesc.packDepthStencilResolveAttachment();
2175 }
2176 }
2177
2178 if (contextVk->isInFramebufferFetchMode())
2179 {
2180 mRenderPassDesc.setFramebufferFetchMode(true);
2181 }
2182
2183 if (contextVk->getFeatures().enableMultisampledRenderToTexture.enabled)
2184 {
2185 // Update descriptions regarding multisampled-render-to-texture use.
2186 bool isRenderToTexture = false;
2187 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
2188 {
2189 const gl::FramebufferAttachment *color = mState.getColorAttachment(colorAttachment: colorIndexGL);
2190 ASSERT(color);
2191
2192 if (color->isRenderToTexture())
2193 {
2194 isRenderToTexture = true;
2195 break;
2196 }
2197 }
2198 const gl::FramebufferAttachment *depthStencil = mState.getDepthStencilAttachment();
2199 if (depthStencil && depthStencil->isRenderToTexture())
2200 {
2201 isRenderToTexture = true;
2202 }
2203
2204 mCurrentFramebufferDesc.updateRenderToTexture(isRenderToTexture);
2205 mRenderPassDesc.updateRenderToTexture(isRenderToTexture);
2206 }
2207
2208 mCurrentFramebufferDesc.updateUnresolveMask(unresolveMask: {});
2209 mRenderPassDesc.setWriteControlMode(mCurrentFramebufferDesc.getWriteControlMode());
2210
2211 updateLegacyDither(contextVk);
2212}
2213
2214angle::Result FramebufferVk::getAttachmentsAndRenderTargets(
2215 ContextVk *contextVk,
2216 const vk::ImageView *resolveImageViewIn,
2217 RenderTargetVk *resolveRenderTargetIn,
2218 vk::FramebufferAttachmentsVector<VkImageView> *attachments,
2219 vk::FramebufferAttachmentsVector<RenderTargetInfo> *renderTargetsInfoOut)
2220{
2221 // Color attachments.
2222 const auto &colorRenderTargets = mRenderTargetCache.getColors();
2223 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
2224 {
2225 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
2226 ASSERT(colorRenderTarget);
2227
2228 const vk::ImageView *imageView = nullptr;
2229 ANGLE_TRY(colorRenderTarget->getImageViewWithColorspace(
2230 contextVk, mCurrentFramebufferDesc.getWriteControlMode(), &imageView));
2231
2232 attachments->push_back(value: imageView->getHandle());
2233 renderTargetsInfoOut->emplace_back(
2234 args: RenderTargetInfo(colorRenderTarget, RenderTargetImage::AttachmentImage));
2235 }
2236
2237 // Depth/stencil attachment.
2238 RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
2239 if (depthStencilRenderTarget)
2240 {
2241 const vk::ImageView *imageView = nullptr;
2242 ANGLE_TRY(depthStencilRenderTarget->getImageView(contextVk, &imageView));
2243
2244 attachments->push_back(value: imageView->getHandle());
2245 renderTargetsInfoOut->emplace_back(
2246 args: RenderTargetInfo(depthStencilRenderTarget, RenderTargetImage::AttachmentImage));
2247 }
2248
2249 // Color resolve attachments.
2250 if (resolveImageViewIn)
2251 {
2252 ASSERT(!HasResolveAttachment(colorRenderTargets, mState.getEnabledDrawBuffers()));
2253 ASSERT(resolveRenderTargetIn);
2254
2255 // Need to use the passed in ImageView for the resolve attachment, since it came from
2256 // another Framebuffer.
2257 attachments->push_back(value: resolveImageViewIn->getHandle());
2258 renderTargetsInfoOut->emplace_back(
2259 args: RenderTargetInfo(resolveRenderTargetIn, (resolveRenderTargetIn->hasResolveAttachment())
2260 ? RenderTargetImage::ResolveImage
2261 : RenderTargetImage::AttachmentImage));
2262 }
2263 else
2264 {
2265 // This Framebuffer owns all of the ImageViews, including its own resolve ImageViews.
2266 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
2267 {
2268 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
2269 ASSERT(colorRenderTarget);
2270
2271 if (colorRenderTarget->hasResolveAttachment())
2272 {
2273 const vk::ImageView *resolveImageView = nullptr;
2274 ANGLE_TRY(colorRenderTarget->getResolveImageView(contextVk, &resolveImageView));
2275
2276 attachments->push_back(value: resolveImageView->getHandle());
2277 renderTargetsInfoOut->emplace_back(
2278 args: RenderTargetInfo(colorRenderTarget, RenderTargetImage::ResolveImage));
2279 }
2280 }
2281 }
2282
2283 // Depth/stencil resolve attachment.
2284 if (depthStencilRenderTarget && depthStencilRenderTarget->hasResolveAttachment())
2285 {
2286 const vk::ImageView *imageView = nullptr;
2287 ANGLE_TRY(depthStencilRenderTarget->getResolveImageView(contextVk, &imageView));
2288
2289 attachments->push_back(value: imageView->getHandle());
2290 renderTargetsInfoOut->emplace_back(
2291 args: RenderTargetInfo(depthStencilRenderTarget, RenderTargetImage::ResolveImage));
2292 }
2293
2294 return angle::Result::Continue;
2295}
2296
2297angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
2298 vk::MaybeImagelessFramebuffer *framebufferOut,
2299 RenderTargetVk *resolveRenderTargetIn,
2300 const vk::ImageView *resolveImageViewIn,
2301 const SwapchainResolveMode swapchainResolveMode)
2302{
2303 ASSERT(mCurrentFramebufferDesc.hasFramebufferFetch() == mRenderPassDesc.hasFramebufferFetch());
2304
2305 // When using imageless framebuffers, the framebuffer cache is not utilized.
2306 bool useImagelessFramebuffer =
2307 contextVk->getFeatures().supportsImagelessFramebuffer.enabled && mBackbuffer == nullptr;
2308 vk::ImagelessStatus useImagelessFramebufferStatus = (useImagelessFramebuffer)
2309 ? vk::ImagelessStatus::Imageless
2310 : vk::ImagelessStatus::NotImageless;
2311
2312 // First return a presently valid Framebuffer
2313 if (mCurrentFramebuffer.valid())
2314 {
2315 // With imageless framebuffers, the image views used for the beginning of the render pass
2316 // should be updated.
2317 if (useImagelessFramebuffer)
2318 {
2319 vk::FramebufferAttachmentsVector<VkImageView> attachments;
2320 vk::FramebufferAttachmentsVector<RenderTargetInfo> renderTargetsInfo;
2321 ANGLE_TRY(getAttachmentsAndRenderTargets(contextVk, resolveImageViewIn,
2322 resolveRenderTargetIn, &attachments,
2323 &renderTargetsInfo));
2324 framebufferOut->updateFramebuffer(newFramebufferHandle: mCurrentFramebuffer.getHandle(), newImageViews: &attachments,
2325 imagelessStatus: useImagelessFramebufferStatus);
2326 }
2327
2328 framebufferOut->setHandle(mCurrentFramebuffer.getHandle());
2329 return angle::Result::Continue;
2330 }
2331
2332 // No current FB, so now check for previously cached Framebuffer.
2333 if (mBackbuffer == nullptr && !useImagelessFramebuffer &&
2334 contextVk->getShareGroup()->getFramebufferCache().get(contextVk, desc: mCurrentFramebufferDesc,
2335 framebuffer&: mCurrentFramebuffer))
2336 {
2337 ASSERT(mCurrentFramebuffer.valid());
2338 mIsCurrentFramebufferCached = true;
2339 framebufferOut->setHandle(mCurrentFramebuffer.getHandle());
2340 return angle::Result::Continue;
2341 }
2342
2343 const vk::RenderPass *compatibleRenderPass = nullptr;
2344 ANGLE_TRY(contextVk->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
2345
2346 // If we've a Framebuffer provided by a Surface (default FBO/backbuffer), query it.
2347 if (mBackbuffer)
2348 {
2349 return mBackbuffer->getCurrentFramebuffer(
2350 context: contextVk,
2351 fetchMode: mRenderPassDesc.hasFramebufferFetch() ? FramebufferFetchMode::Enabled
2352 : FramebufferFetchMode::Disabled,
2353 compatibleRenderPass: *compatibleRenderPass, swapchainResolveMode, framebufferOut);
2354 }
2355
2356 // Gather VkImageViews over all FBO attachments, also size of attached region.
2357 vk::FramebufferAttachmentsVector<VkImageView> attachments;
2358 vk::FramebufferAttachmentsVector<RenderTargetInfo> renderTargetsInfo;
2359 gl::Extents attachmentsSize = mState.getExtents();
2360 ASSERT(attachmentsSize.width != 0 && attachmentsSize.height != 0);
2361 ANGLE_TRY(getAttachmentsAndRenderTargets(contextVk, resolveImageViewIn, resolveRenderTargetIn,
2362 &attachments, &renderTargetsInfo));
2363
2364 // Create new framebuffer.
2365 vk::FramebufferHelper newFramebuffer;
2366
2367 VkFramebufferCreateInfo framebufferInfo = {};
2368 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
2369 framebufferInfo.flags = 0;
2370 framebufferInfo.renderPass = compatibleRenderPass->getHandle();
2371 framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
2372 framebufferInfo.pAttachments = attachments.data();
2373 framebufferInfo.width = static_cast<uint32_t>(attachmentsSize.width);
2374 framebufferInfo.height = static_cast<uint32_t>(attachmentsSize.height);
2375 framebufferInfo.layers = (!mCurrentFramebufferDesc.isMultiview())
2376 ? std::max(a: mCurrentFramebufferDesc.getLayerCount(), b: 1u)
2377 : 1;
2378
2379 // Check that our description matches our attachments. Can catch implementation bugs.
2380 ASSERT(static_cast<uint32_t>(attachments.size()) == mCurrentFramebufferDesc.attachmentCount());
2381
2382 if (!useImagelessFramebuffer)
2383 {
2384 // Since the cache key FramebufferDesc can't distinguish between
2385 // two FramebufferHelper, if they both have 0 attachment, but their sizes
2386 // are different, we could have wrong cache hit(new framebufferHelper has
2387 // a bigger height and width, but get cache hit with framebufferHelper of
2388 // lower height and width). As a workaround, do not cache the
2389 // FramebufferHelper if it doesn't have any attachment.
2390 ANGLE_TRY(newFramebuffer.init(contextVk, framebufferInfo));
2391 if (!attachments.empty())
2392 {
2393 insertCache(contextVk, desc: mCurrentFramebufferDesc, newFramebuffer: std::move(newFramebuffer));
2394
2395 bool result = contextVk->getShareGroup()->getFramebufferCache().get(
2396 contextVk, desc: mCurrentFramebufferDesc, framebuffer&: mCurrentFramebuffer);
2397 ASSERT(result);
2398 mIsCurrentFramebufferCached = true;
2399 }
2400 else
2401 {
2402 mCurrentFramebuffer = std::move(newFramebuffer.getFramebuffer());
2403 mIsCurrentFramebufferCached = false;
2404 }
2405 }
2406 else
2407 {
2408 // For imageless framebuffers, attachment image and create info objects should be defined
2409 // when creating the new framebuffer.
2410 std::vector<VkFramebufferAttachmentImageInfoKHR> fbAttachmentImageInfoArray;
2411
2412 for (auto const &info : renderTargetsInfo)
2413 {
2414 vk::ImageHelper *renderTargetImage =
2415 (info.renderTargetImage == RenderTargetImage::ResolveImage)
2416 ? &info.renderTarget->getResolveImageForRenderPass()
2417 : &info.renderTarget->getImageForRenderPass();
2418 uint32_t renderTargetLevel = info.renderTarget->getLevelIndex().get();
2419 uint32_t renderTargetLayerCount = info.renderTarget->getLayerCount();
2420
2421 VkFramebufferAttachmentImageInfoKHR fbAttachmentImageInfo = {};
2422 fbAttachmentImageInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO_KHR;
2423
2424 uint32_t baseLevel =
2425 static_cast<uint32_t>(renderTargetImage->getFirstAllocatedLevel().get());
2426 uint32_t level = (renderTargetLevel > baseLevel) ? (renderTargetLevel - baseLevel) : 0;
2427 uint32_t fbAttachmentWidth = renderTargetImage->getExtents().width >> level;
2428 uint32_t fbAttachmentHeight = renderTargetImage->getExtents().height >> level;
2429 fbAttachmentImageInfo.width = (fbAttachmentWidth > 0) ? fbAttachmentWidth : 1;
2430 fbAttachmentImageInfo.height = (fbAttachmentHeight > 0) ? fbAttachmentHeight : 1;
2431
2432 fbAttachmentImageInfo.layerCount =
2433 (mCurrentFramebufferDesc.isMultiview())
2434 ? std::max(a: static_cast<uint32_t>(mRenderPassDesc.viewCount()), b: 1u)
2435 : renderTargetLayerCount;
2436 fbAttachmentImageInfo.flags = renderTargetImage->getCreateFlags();
2437 fbAttachmentImageInfo.usage = renderTargetImage->getUsage();
2438 fbAttachmentImageInfo.viewFormatCount =
2439 static_cast<uint32_t>(renderTargetImage->getViewFormats().max_size());
2440 fbAttachmentImageInfo.pViewFormats = renderTargetImage->getViewFormats().data();
2441
2442 fbAttachmentImageInfoArray.push_back(x: fbAttachmentImageInfo);
2443 }
2444
2445 VkFramebufferAttachmentsCreateInfoKHR fbAttachmentsCreateInfo = {};
2446 fbAttachmentsCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO_KHR;
2447 fbAttachmentsCreateInfo.attachmentImageInfoCount =
2448 static_cast<uint32_t>(fbAttachmentImageInfoArray.size());
2449 fbAttachmentsCreateInfo.pAttachmentImageInfos = fbAttachmentImageInfoArray.data();
2450
2451 framebufferInfo.flags |= VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR;
2452 framebufferInfo.pAttachments = nullptr;
2453 vk::AddToPNextChain(chainStart: &framebufferInfo, ptr: &fbAttachmentsCreateInfo);
2454
2455 ANGLE_TRY(newFramebuffer.init(contextVk, framebufferInfo));
2456 mCurrentFramebuffer.setHandle(newFramebuffer.getFramebuffer().release());
2457
2458 // Update the image views to be used to begin the render pass.
2459 framebufferOut->updateFramebuffer(newFramebufferHandle: mCurrentFramebuffer.getHandle(), newImageViews: &attachments,
2460 imagelessStatus: useImagelessFramebufferStatus);
2461 }
2462
2463 ASSERT(mCurrentFramebuffer.valid());
2464
2465 framebufferOut->setHandle(mCurrentFramebuffer.getHandle());
2466 return angle::Result::Continue;
2467}
2468
2469void FramebufferVk::mergeClearsWithDeferredClears(
2470 gl::DrawBufferMask clearColorBuffers,
2471 bool clearDepth,
2472 bool clearStencil,
2473 const VkClearColorValue &clearColorValue,
2474 const VkClearDepthStencilValue &clearDepthStencilValue)
2475{
2476 // Apply clears to mDeferredClears. Note that clears override deferred clears.
2477
2478 // Color clears.
2479 for (size_t colorIndexGL : clearColorBuffers)
2480 {
2481 ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
2482 VkClearValue clearValue = getCorrectedColorClearValue(colorIndexGL, clearColor: clearColorValue);
2483 mDeferredClears.store(index: static_cast<uint32_t>(colorIndexGL), aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT,
2484 clearValue);
2485 }
2486
2487 // Depth and stencil clears.
2488 VkImageAspectFlags dsAspectFlags = 0;
2489 VkClearValue dsClearValue = {};
2490 dsClearValue.depthStencil = clearDepthStencilValue;
2491 if (clearDepth)
2492 {
2493 dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
2494 }
2495 if (clearStencil)
2496 {
2497 dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
2498 }
2499
2500 if (dsAspectFlags != 0)
2501 {
2502 mDeferredClears.store(index: vk::kUnpackedDepthIndex, aspectFlags: dsAspectFlags, clearValue: dsClearValue);
2503 }
2504}
2505
2506angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
2507 const gl::Rectangle &clearArea,
2508 gl::DrawBufferMask clearColorBuffers,
2509 bool clearDepth,
2510 bool clearStencil,
2511 gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
2512 uint8_t stencilMask,
2513 const VkClearColorValue &clearColorValue,
2514 const VkClearDepthStencilValue &clearDepthStencilValue)
2515{
2516 // All deferred clears should be handled already.
2517 ASSERT(mDeferredClears.empty());
2518
2519 UtilsVk::ClearFramebufferParameters params = {};
2520 params.clearArea = clearArea;
2521 params.colorClearValue = clearColorValue;
2522 params.depthStencilClearValue = clearDepthStencilValue;
2523 params.stencilMask = stencilMask;
2524
2525 params.clearColor = true;
2526 params.clearDepth = clearDepth;
2527 params.clearStencil = clearStencil;
2528
2529 const auto &colorRenderTargets = mRenderTargetCache.getColors();
2530 for (size_t colorIndexGL : clearColorBuffers)
2531 {
2532 const RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
2533 ASSERT(colorRenderTarget);
2534
2535 params.colorFormat = &colorRenderTarget->getImageForRenderPass().getActualFormat();
2536 params.colorAttachmentIndexGL = static_cast<uint32_t>(colorIndexGL);
2537 params.colorMaskFlags =
2538 gl::BlendStateExt::ColorMaskStorage::GetValueIndexed(index: colorIndexGL, values: colorMasks);
2539 if (mEmulatedAlphaAttachmentMask[colorIndexGL])
2540 {
2541 params.colorMaskFlags &= ~VK_COLOR_COMPONENT_A_BIT;
2542 }
2543
2544 // TODO: implement clear of layered framebuffers. UtilsVk::clearFramebuffer should add a
2545 // geometry shader that is instanced layerCount times (or loops layerCount times), each time
2546 // selecting a different layer.
2547 // http://anglebug.com/5453
2548 ASSERT(mCurrentFramebufferDesc.isMultiview() || colorRenderTarget->getLayerCount() == 1);
2549
2550 ANGLE_TRY(contextVk->getUtils().clearFramebuffer(contextVk, this, params));
2551
2552 // Clear depth/stencil only once!
2553 params.clearDepth = false;
2554 params.clearStencil = false;
2555 }
2556
2557 // If there was no color clear, clear depth/stencil alone.
2558 if (params.clearDepth || params.clearStencil)
2559 {
2560 params.clearColor = false;
2561 ANGLE_TRY(contextVk->getUtils().clearFramebuffer(contextVk, this, params));
2562 }
2563
2564 return angle::Result::Continue;
2565}
2566
2567VkClearValue FramebufferVk::getCorrectedColorClearValue(size_t colorIndexGL,
2568 const VkClearColorValue &clearColor) const
2569{
2570 VkClearValue clearValue = {};
2571 clearValue.color = clearColor;
2572
2573 if (!mEmulatedAlphaAttachmentMask[colorIndexGL])
2574 {
2575 return clearValue;
2576 }
2577
2578 // If the render target doesn't have alpha, but its emulated format has it, clear the alpha
2579 // to 1.
2580 RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL);
2581 const angle::Format &format = renderTarget->getImageActualFormat();
2582
2583 if (format.isUint())
2584 {
2585 clearValue.color.uint32[3] = kEmulatedAlphaValue;
2586 }
2587 else if (format.isSint())
2588 {
2589 clearValue.color.int32[3] = kEmulatedAlphaValue;
2590 }
2591 else
2592 {
2593 clearValue.color.float32[3] = kEmulatedAlphaValue;
2594 }
2595
2596 return clearValue;
2597}
2598
2599void FramebufferVk::redeferClears(ContextVk *contextVk)
2600{
2601 // Called when redeferring clears of the draw framebuffer. In that case, there can't be any
2602 // render passes open, otherwise the clear would have applied to the render pass. In the
2603 // exceptional occasion in blit where the read framebuffer accumulates deferred clears, it can
2604 // be deferred while this assumption doesn't hold (and redeferClearsForReadFramebuffer should be
2605 // used instead).
2606 ASSERT(!contextVk->hasActiveRenderPass() || !mDeferredClears.any());
2607 redeferClearsImpl(contextVk);
2608}
2609
2610void FramebufferVk::redeferClearsForReadFramebuffer(ContextVk *contextVk)
2611{
2612 redeferClearsImpl(contextVk);
2613}
2614
2615void FramebufferVk::redeferClearsImpl(ContextVk *contextVk)
2616{
2617 // Set the appropriate aspect and clear values for depth and stencil.
2618 VkImageAspectFlags dsAspectFlags = 0;
2619 VkClearValue dsClearValue = {};
2620 dsClearValue.depthStencil.depth = mDeferredClears.getDepthValue();
2621 dsClearValue.depthStencil.stencil = mDeferredClears.getStencilValue();
2622
2623 if (mDeferredClears.testDepth())
2624 {
2625 dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
2626 mDeferredClears.reset(index: vk::kUnpackedDepthIndex);
2627 }
2628
2629 if (mDeferredClears.testStencil())
2630 {
2631 dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
2632 mDeferredClears.reset(index: vk::kUnpackedStencilIndex);
2633 }
2634
2635 // Go through deferred clears and stage the clears for future.
2636 for (size_t colorIndexGL : mDeferredClears.getColorMask())
2637 {
2638 RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL);
2639 gl::ImageIndex imageIndex =
2640 renderTarget->getImageIndexForClear(layerCount: mCurrentFramebufferDesc.getLayerCount());
2641 renderTarget->getImageForWrite().stageClear(index: imageIndex, aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT,
2642 clearValue: mDeferredClears[colorIndexGL]);
2643 mDeferredClears.reset(index: colorIndexGL);
2644 }
2645
2646 if (dsAspectFlags)
2647 {
2648 RenderTargetVk *renderTarget = getDepthStencilRenderTarget();
2649 ASSERT(renderTarget);
2650
2651 gl::ImageIndex imageIndex =
2652 renderTarget->getImageIndexForClear(layerCount: mCurrentFramebufferDesc.getLayerCount());
2653 renderTarget->getImageForWrite().stageClear(index: imageIndex, aspectFlags: dsAspectFlags, clearValue: dsClearValue);
2654 }
2655}
2656
2657void FramebufferVk::clearWithCommand(ContextVk *contextVk,
2658 const gl::Rectangle &scissoredRenderArea,
2659 ClearWithCommand behavior,
2660 vk::ClearValuesArray *clears)
2661{
2662 // Clear is not affected by viewport, so ContextVk::updateScissor may have decided on a smaller
2663 // render area. Grow the render area to the full framebuffer size as this clear path is taken
2664 // when not scissored.
2665 vk::RenderPassCommandBufferHelper *renderPassCommands =
2666 &contextVk->getStartedRenderPassCommands();
2667 renderPassCommands->growRenderArea(contextVk, newRenderArea: scissoredRenderArea);
2668
2669 gl::AttachmentVector<VkClearAttachment> attachments;
2670
2671 const bool optimizeWithLoadOp = behavior == ClearWithCommand::OptimizeWithLoadOp;
2672
2673 // Go through deferred clears and add them to the list of attachments to clear. If any
2674 // attachment is unused, skip the clear. clearWithLoadOp will follow and move the remaining
2675 // clears up to loadOp.
2676 vk::PackedAttachmentIndex colorIndexVk(0);
2677 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
2678 {
2679 if (clears->getColorMask().test(pos: colorIndexGL))
2680 {
2681 if (!renderPassCommands->hasAnyColorAccess(packedAttachmentIndex: colorIndexVk) && optimizeWithLoadOp)
2682 {
2683 // Skip this attachment, so we can use a renderpass loadOp to clear it instead.
2684 // Note that if loadOp=Clear was already used for this color attachment, it will be
2685 // overriden by the new clear, which is valid because the attachment wasn't used in
2686 // between.
2687 ++colorIndexVk;
2688 continue;
2689 }
2690
2691 attachments.emplace_back(args: VkClearAttachment{.aspectMask: VK_IMAGE_ASPECT_COLOR_BIT,
2692 .colorAttachment: static_cast<uint32_t>(colorIndexGL),
2693 .clearValue: (*clears)[colorIndexGL]});
2694 clears->reset(index: colorIndexGL);
2695 ++contextVk->getPerfCounters().colorClearAttachments;
2696
2697 renderPassCommands->onColorAccess(packedAttachmentIndex: colorIndexVk, access: vk::ResourceAccess::ReadWrite);
2698 }
2699 ++colorIndexVk;
2700 }
2701
2702 // Add depth and stencil to list of attachments as needed.
2703 VkImageAspectFlags dsAspectFlags = 0;
2704 VkClearValue dsClearValue = {};
2705 dsClearValue.depthStencil.depth = clears->getDepthValue();
2706 dsClearValue.depthStencil.stencil = clears->getStencilValue();
2707 if (clears->testDepth() && (renderPassCommands->hasAnyDepthAccess() || !optimizeWithLoadOp))
2708 {
2709 dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
2710 // Explicitly mark a depth write because we are clearing the depth buffer.
2711 renderPassCommands->onDepthAccess(access: vk::ResourceAccess::ReadWrite);
2712 clears->reset(index: vk::kUnpackedDepthIndex);
2713 ++contextVk->getPerfCounters().depthClearAttachments;
2714 }
2715
2716 if (clears->testStencil() && (renderPassCommands->hasAnyStencilAccess() || !optimizeWithLoadOp))
2717 {
2718 dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
2719 // Explicitly mark a stencil write because we are clearing the stencil buffer.
2720 renderPassCommands->onStencilAccess(access: vk::ResourceAccess::ReadWrite);
2721 clears->reset(index: vk::kUnpackedStencilIndex);
2722 ++contextVk->getPerfCounters().stencilClearAttachments;
2723 }
2724
2725 if (dsAspectFlags != 0)
2726 {
2727 attachments.emplace_back(args: VkClearAttachment{.aspectMask: dsAspectFlags, .colorAttachment: 0, .clearValue: dsClearValue});
2728
2729 // Because we may have changed the depth/stencil access mode, update read only depth/stencil
2730 // mode.
2731 renderPassCommands->updateDepthStencilReadOnlyMode(
2732 dsUsageFlags: contextVk->getDepthStencilAttachmentFlags(), dsAspectFlags);
2733 }
2734
2735 if (attachments.empty())
2736 {
2737 // If called with the intent to definitely clear something with vkCmdClearAttachments, there
2738 // must have been something to clear!
2739 ASSERT(optimizeWithLoadOp);
2740 return;
2741 }
2742
2743 const uint32_t layerCount = mState.isMultiview() ? 1 : mCurrentFramebufferDesc.getLayerCount();
2744
2745 VkClearRect rect = {};
2746 rect.rect.offset.x = scissoredRenderArea.x;
2747 rect.rect.offset.y = scissoredRenderArea.y;
2748 rect.rect.extent.width = scissoredRenderArea.width;
2749 rect.rect.extent.height = scissoredRenderArea.height;
2750 rect.layerCount = layerCount;
2751 vk::RenderPassCommandBuffer *renderPassCommandBuffer = &renderPassCommands->getCommandBuffer();
2752
2753 renderPassCommandBuffer->clearAttachments(attachmentCount: static_cast<uint32_t>(attachments.size()),
2754 attachments: attachments.data(), rectCount: 1, rects: &rect);
2755 return;
2756}
2757
2758void FramebufferVk::clearWithLoadOp(ContextVk *contextVk)
2759{
2760 vk::RenderPassCommandBufferHelper *renderPassCommands =
2761 &contextVk->getStartedRenderPassCommands();
2762
2763 // Update the render pass loadOps to clear the attachments.
2764 vk::PackedAttachmentIndex colorIndexVk(0);
2765 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
2766 {
2767 if (!mDeferredClears.test(index: colorIndexGL))
2768 {
2769 ++colorIndexVk;
2770 continue;
2771 }
2772
2773 ASSERT(!renderPassCommands->hasAnyColorAccess(colorIndexVk));
2774
2775 renderPassCommands->updateRenderPassColorClear(colorIndexVk, colorClearValue: mDeferredClears[colorIndexGL]);
2776
2777 mDeferredClears.reset(index: colorIndexGL);
2778
2779 ++colorIndexVk;
2780 }
2781
2782 VkClearValue dsClearValue = {};
2783 dsClearValue.depthStencil.depth = mDeferredClears.getDepthValue();
2784 dsClearValue.depthStencil.stencil = mDeferredClears.getStencilValue();
2785 VkImageAspectFlags dsAspects = 0;
2786
2787 if (mDeferredClears.testDepth())
2788 {
2789 ASSERT(!renderPassCommands->hasAnyDepthAccess());
2790 dsAspects |= VK_IMAGE_ASPECT_DEPTH_BIT;
2791 mDeferredClears.reset(index: vk::kUnpackedDepthIndex);
2792 }
2793
2794 if (mDeferredClears.testStencil())
2795 {
2796 ASSERT(!renderPassCommands->hasAnyStencilAccess());
2797 dsAspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
2798 mDeferredClears.reset(index: vk::kUnpackedStencilIndex);
2799 }
2800
2801 if (dsAspects != 0)
2802 {
2803 renderPassCommands->updateRenderPassDepthStencilClear(aspectFlags: dsAspects, clearValue: dsClearValue);
2804
2805 // The render pass can no longer be in read-only depth/stencil mode.
2806 renderPassCommands->updateDepthStencilReadOnlyMode(
2807 dsUsageFlags: contextVk->getDepthStencilAttachmentFlags(), dsAspectFlags: dsAspects);
2808 }
2809}
2810
2811angle::Result FramebufferVk::getSamplePosition(const gl::Context *context,
2812 size_t index,
2813 GLfloat *xy) const
2814{
2815 int sampleCount = getSamples();
2816 rx::GetSamplePosition(sampleCount, index, xy);
2817 return angle::Result::Continue;
2818}
2819
2820angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
2821 const gl::Rectangle &renderArea,
2822 vk::RenderPassCommandBuffer **commandBufferOut,
2823 bool *renderPassDescChangedOut)
2824{
2825 ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::NewRenderPass));
2826
2827 // Initialize RenderPass info.
2828 vk::AttachmentOpsArray renderPassAttachmentOps;
2829 vk::PackedClearValuesArray packedClearValues;
2830 gl::DrawBufferMask previousUnresolveColorMask =
2831 mRenderPassDesc.getColorUnresolveAttachmentMask();
2832 const bool hasDeferredClears = mDeferredClears.any();
2833 const bool previousUnresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment();
2834 const bool previousUnresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment();
2835
2836 // Make sure render pass and framebuffer are in agreement w.r.t unresolve attachments.
2837 ASSERT(mCurrentFramebufferDesc.getUnresolveAttachmentMask() ==
2838 MakeUnresolveAttachmentMask(mRenderPassDesc));
2839
2840 // Color attachments.
2841 const auto &colorRenderTargets = mRenderTargetCache.getColors();
2842 vk::PackedAttachmentIndex colorIndexVk(0);
2843 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
2844 {
2845 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
2846 ASSERT(colorRenderTarget);
2847
2848 // Color render targets are never entirely transient. Only depth/stencil
2849 // multisampled-render-to-texture textures can be so.
2850 ASSERT(!colorRenderTarget->isEntirelyTransient());
2851 const vk::RenderPassStoreOp storeOp = colorRenderTarget->isImageTransient()
2852 ? vk::RenderPassStoreOp::DontCare
2853 : vk::RenderPassStoreOp::Store;
2854
2855 if (mDeferredClears.test(index: colorIndexGL))
2856 {
2857 renderPassAttachmentOps.setOps(index: colorIndexVk, loadOp: vk::RenderPassLoadOp::Clear, storeOp);
2858 packedClearValues.store(index: colorIndexVk, aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT,
2859 clearValue: mDeferredClears[colorIndexGL]);
2860 mDeferredClears.reset(index: colorIndexGL);
2861 }
2862 else
2863 {
2864 const vk::RenderPassLoadOp loadOp = colorRenderTarget->hasDefinedContent()
2865 ? vk::RenderPassLoadOp::Load
2866 : vk::RenderPassLoadOp::DontCare;
2867
2868 renderPassAttachmentOps.setOps(index: colorIndexVk, loadOp, storeOp);
2869 packedClearValues.store(index: colorIndexVk, aspectFlags: VK_IMAGE_ASPECT_COLOR_BIT,
2870 clearValue: kUninitializedClearValue);
2871 }
2872 renderPassAttachmentOps.setStencilOps(index: colorIndexVk, loadOp: vk::RenderPassLoadOp::DontCare,
2873 storeOp: vk::RenderPassStoreOp::DontCare);
2874
2875 // If there's a resolve attachment, and loadOp needs to be LOAD, the multisampled attachment
2876 // needs to take its value from the resolve attachment. In this case, an initial subpass is
2877 // added for this very purpose which uses the resolve attachment as input attachment. As a
2878 // result, loadOp of the multisampled attachment can remain DONT_CARE.
2879 //
2880 // Note that this only needs to be done if the multisampled image and the resolve attachment
2881 // come from the same source. isImageTransient() indicates whether this should happen.
2882 if (colorRenderTarget->hasResolveAttachment() && colorRenderTarget->isImageTransient())
2883 {
2884 if (renderPassAttachmentOps[colorIndexVk].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
2885 {
2886 renderPassAttachmentOps[colorIndexVk].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
2887
2888 // Update the render pass desc to specify that this attachment should be unresolved.
2889 mRenderPassDesc.packColorUnresolveAttachment(colorIndexGL);
2890 }
2891 else
2892 {
2893 mRenderPassDesc.removeColorUnresolveAttachment(colorIndexGL);
2894 }
2895 }
2896 else
2897 {
2898 ASSERT(!mRenderPassDesc.getColorUnresolveAttachmentMask().test(colorIndexGL));
2899 }
2900
2901 ++colorIndexVk;
2902 }
2903
2904 // Depth/stencil attachment.
2905 vk::PackedAttachmentIndex depthStencilAttachmentIndex = vk::kAttachmentIndexInvalid;
2906 RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
2907 if (depthStencilRenderTarget)
2908 {
2909 // depth stencil attachment always immediately follows color attachment
2910 depthStencilAttachmentIndex = colorIndexVk;
2911
2912 vk::RenderPassLoadOp depthLoadOp = vk::RenderPassLoadOp::Load;
2913 vk::RenderPassLoadOp stencilLoadOp = vk::RenderPassLoadOp::Load;
2914 vk::RenderPassStoreOp depthStoreOp = vk::RenderPassStoreOp::Store;
2915 vk::RenderPassStoreOp stencilStoreOp = vk::RenderPassStoreOp::Store;
2916
2917 // If the image data was previously discarded (with no update in between), don't attempt to
2918 // load the image. Additionally, if the multisampled image data is transient and there is
2919 // no resolve attachment, there's no data to load. The latter is the case with
2920 // depth/stencil texture attachments per GL_EXT_multisampled_render_to_texture2.
2921 if (!depthStencilRenderTarget->hasDefinedContent() ||
2922 depthStencilRenderTarget->isEntirelyTransient())
2923 {
2924 depthLoadOp = vk::RenderPassLoadOp::DontCare;
2925 }
2926 if (!depthStencilRenderTarget->hasDefinedStencilContent() ||
2927 depthStencilRenderTarget->isEntirelyTransient())
2928 {
2929 stencilLoadOp = vk::RenderPassLoadOp::DontCare;
2930 }
2931
2932 // If depth/stencil image is transient, no need to store its data at the end of the render
2933 // pass.
2934 if (depthStencilRenderTarget->isImageTransient())
2935 {
2936 depthStoreOp = vk::RenderPassStoreOp::DontCare;
2937 stencilStoreOp = vk::RenderPassStoreOp::DontCare;
2938 }
2939
2940 if (mDeferredClears.testDepth() || mDeferredClears.testStencil())
2941 {
2942 VkClearValue clearValue = {};
2943
2944 if (mDeferredClears.testDepth())
2945 {
2946 depthLoadOp = vk::RenderPassLoadOp::Clear;
2947 clearValue.depthStencil.depth = mDeferredClears.getDepthValue();
2948 mDeferredClears.reset(index: vk::kUnpackedDepthIndex);
2949 }
2950
2951 if (mDeferredClears.testStencil())
2952 {
2953 stencilLoadOp = vk::RenderPassLoadOp::Clear;
2954 clearValue.depthStencil.stencil = mDeferredClears.getStencilValue();
2955 mDeferredClears.reset(index: vk::kUnpackedStencilIndex);
2956 }
2957
2958 // Note the aspect is only depth here. That's intentional.
2959 packedClearValues.store(index: depthStencilAttachmentIndex, aspectFlags: VK_IMAGE_ASPECT_DEPTH_BIT,
2960 clearValue);
2961 }
2962 else
2963 {
2964 // Note the aspect is only depth here. That's intentional.
2965 packedClearValues.store(index: depthStencilAttachmentIndex, aspectFlags: VK_IMAGE_ASPECT_DEPTH_BIT,
2966 clearValue: kUninitializedClearValue);
2967 }
2968
2969 const angle::Format &format = depthStencilRenderTarget->getImageIntendedFormat();
2970 // If the format we picked has stencil but user did not ask for it due to hardware
2971 // limitations, use DONT_CARE for load/store. The same logic for depth follows.
2972 if (format.stencilBits == 0)
2973 {
2974 stencilLoadOp = vk::RenderPassLoadOp::DontCare;
2975 stencilStoreOp = vk::RenderPassStoreOp::DontCare;
2976 }
2977 if (format.depthBits == 0)
2978 {
2979 depthLoadOp = vk::RenderPassLoadOp::DontCare;
2980 depthStoreOp = vk::RenderPassStoreOp::DontCare;
2981 }
2982
2983 // Similar to color attachments, if there's a resolve attachment and the multisampled image
2984 // is transient, depth/stencil data need to be unresolved in an initial subpass.
2985 if (depthStencilRenderTarget->hasResolveAttachment() &&
2986 depthStencilRenderTarget->isImageTransient())
2987 {
2988 const bool unresolveDepth = depthLoadOp == vk::RenderPassLoadOp::Load;
2989 const bool unresolveStencil = stencilLoadOp == vk::RenderPassLoadOp::Load;
2990
2991 if (unresolveDepth)
2992 {
2993 depthLoadOp = vk::RenderPassLoadOp::DontCare;
2994 }
2995
2996 if (unresolveStencil)
2997 {
2998 stencilLoadOp = vk::RenderPassLoadOp::DontCare;
2999
3000 // If VK_EXT_shader_stencil_export is not supported, stencil unresolve is done
3001 // through a method that requires stencil to have been cleared.
3002 if (!contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled)
3003 {
3004 stencilLoadOp = vk::RenderPassLoadOp::Clear;
3005
3006 // Note the aspect is only depth here. That's intentional.
3007 VkClearValue clearValue = packedClearValues[depthStencilAttachmentIndex];
3008 clearValue.depthStencil.stencil = 0;
3009 packedClearValues.store(index: depthStencilAttachmentIndex, aspectFlags: VK_IMAGE_ASPECT_DEPTH_BIT,
3010 clearValue);
3011 }
3012 }
3013
3014 if (unresolveDepth || unresolveStencil)
3015 {
3016 mRenderPassDesc.packDepthStencilUnresolveAttachment(unresolveDepth,
3017 unresolveStencil);
3018 }
3019 else
3020 {
3021 mRenderPassDesc.removeDepthStencilUnresolveAttachment();
3022 }
3023 }
3024
3025 renderPassAttachmentOps.setOps(index: depthStencilAttachmentIndex, loadOp: depthLoadOp, storeOp: depthStoreOp);
3026 renderPassAttachmentOps.setStencilOps(index: depthStencilAttachmentIndex, loadOp: stencilLoadOp,
3027 storeOp: stencilStoreOp);
3028 }
3029
3030 // If render pass description is changed, the previous render pass desc is no longer compatible.
3031 // Tell the context so that the graphics pipelines can be recreated.
3032 //
3033 // Note that render passes are compatible only if the differences are in loadOp/storeOp values,
3034 // or the existence of resolve attachments in single subpass render passes. The modification
3035 // here can add/remove a subpass, or modify its input attachments.
3036 gl::DrawBufferMask unresolveColorMask = mRenderPassDesc.getColorUnresolveAttachmentMask();
3037 const bool unresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment();
3038 const bool unresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment();
3039 const bool unresolveChanged = previousUnresolveColorMask != unresolveColorMask ||
3040 previousUnresolveDepth != unresolveDepth ||
3041 previousUnresolveStencil != unresolveStencil;
3042 if (unresolveChanged)
3043 {
3044 // Make sure framebuffer is recreated.
3045 releaseCurrentFramebuffer(contextVk);
3046
3047 mCurrentFramebufferDesc.updateUnresolveMask(unresolveMask: MakeUnresolveAttachmentMask(desc: mRenderPassDesc));
3048 }
3049
3050 vk::MaybeImagelessFramebuffer framebuffer = {};
3051 ANGLE_TRY(
3052 getFramebuffer(contextVk, &framebuffer, nullptr, nullptr, SwapchainResolveMode::Disabled));
3053
3054 // If deferred clears were used in the render pass, the render area must cover the whole
3055 // framebuffer.
3056 ASSERT(!hasDeferredClears || renderArea == getRotatedCompleteRenderArea(contextVk));
3057
3058 ANGLE_TRY(contextVk->beginNewRenderPass(
3059 framebuffer, renderArea, mRenderPassDesc, renderPassAttachmentOps, colorIndexVk,
3060 depthStencilAttachmentIndex, packedClearValues, commandBufferOut));
3061 mLastRenderPassQueueSerial = contextVk->getStartedRenderPassCommands().getQueueSerial();
3062
3063 // Add the images to the renderpass tracking list (through onColorDraw).
3064 vk::PackedAttachmentIndex colorAttachmentIndex(0);
3065 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
3066 {
3067 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
3068 colorRenderTarget->onColorDraw(contextVk, framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount(),
3069 index: colorAttachmentIndex);
3070 ++colorAttachmentIndex;
3071 }
3072
3073 if (depthStencilRenderTarget)
3074 {
3075 // This must be called after hasDefined*Content() since it will set content to valid. If
3076 // the attachment ends up not used in the render pass, contents will be marked undefined at
3077 // endRenderPass. The actual layout determination is also deferred until the same time.
3078 depthStencilRenderTarget->onDepthStencilDraw(contextVk,
3079 framebufferLayerCount: mCurrentFramebufferDesc.getLayerCount());
3080 }
3081
3082 const bool anyUnresolve = unresolveColorMask.any() || unresolveDepth || unresolveStencil;
3083 if (anyUnresolve)
3084 {
3085 // Unresolve attachments if any.
3086 UtilsVk::UnresolveParameters params;
3087 params.unresolveColorMask = unresolveColorMask;
3088 params.unresolveDepth = unresolveDepth;
3089 params.unresolveStencil = unresolveStencil;
3090
3091 ANGLE_TRY(contextVk->getUtils().unresolve(contextVk, this, params));
3092
3093 // The unresolve subpass has only one draw call.
3094 ANGLE_TRY(contextVk->startNextSubpass());
3095 }
3096
3097 if (unresolveChanged || anyUnresolve)
3098 {
3099 contextVk->onDrawFramebufferRenderPassDescChange(framebufferVk: this, renderPassDescChangedOut);
3100 }
3101
3102 return angle::Result::Continue;
3103}
3104
3105gl::Rectangle FramebufferVk::getRenderArea(ContextVk *contextVk) const
3106{
3107 if (hasDeferredClears())
3108 {
3109 return getRotatedCompleteRenderArea(contextVk);
3110 }
3111 else
3112 {
3113 return getRotatedScissoredRenderArea(contextVk);
3114 }
3115}
3116
3117void FramebufferVk::updateActiveColorMasks(size_t colorIndexGL, bool r, bool g, bool b, bool a)
3118{
3119 gl::BlendStateExt::ColorMaskStorage::SetValueIndexed(
3120 index: colorIndexGL, value: gl::BlendStateExt::PackColorMask(red: r, green: g, blue: b, alpha: a),
3121 target: &mActiveColorComponentMasksForClear);
3122}
3123
3124const gl::DrawBufferMask &FramebufferVk::getEmulatedAlphaAttachmentMask() const
3125{
3126 return mEmulatedAlphaAttachmentMask;
3127}
3128
3129angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
3130 const gl::Rectangle &area,
3131 const PackPixelsParams &packPixelsParams,
3132 VkImageAspectFlagBits copyAspectFlags,
3133 RenderTargetVk *renderTarget,
3134 void *pixels)
3135{
3136 ANGLE_TRACE_EVENT0("gpu.angle", "FramebufferVk::readPixelsImpl");
3137 gl::LevelIndex levelGL = renderTarget->getLevelIndex();
3138 uint32_t layer = renderTarget->getLayerIndex();
3139 return renderTarget->getImageForCopy().readPixels(contextVk, area, packPixelsParams,
3140 copyAspectFlags, levelGL, layer, pixels);
3141}
3142
3143gl::Extents FramebufferVk::getReadImageExtents() const
3144{
3145 RenderTargetVk *readRenderTarget = mRenderTargetCache.getColorRead(state: mState);
3146 return readRenderTarget->getExtents();
3147}
3148
3149// Return the framebuffer's non-rotated render area. This is a gl::Rectangle that is based on the
3150// dimensions of the framebuffer, IS NOT rotated, and IS NOT y-flipped
3151gl::Rectangle FramebufferVk::getNonRotatedCompleteRenderArea() const
3152{
3153 const gl::Box &dimensions = mState.getDimensions();
3154 return gl::Rectangle(0, 0, dimensions.width, dimensions.height);
3155}
3156
3157// Return the framebuffer's rotated render area. This is a gl::Rectangle that is based on the
3158// dimensions of the framebuffer, IS ROTATED for the draw FBO, and IS NOT y-flipped
3159//
3160// Note: Since the rectangle is not scissored (i.e. x and y are guaranteed to be zero), only the
3161// width and height must be swapped if the rotation is 90 or 270 degrees.
3162gl::Rectangle FramebufferVk::getRotatedCompleteRenderArea(ContextVk *contextVk) const
3163{
3164 gl::Rectangle renderArea = getNonRotatedCompleteRenderArea();
3165 if (contextVk->isRotatedAspectRatioForDrawFBO())
3166 {
3167 // The surface is rotated 90/270 degrees. This changes the aspect ratio of the surface.
3168 std::swap(x&: renderArea.width, y&: renderArea.height);
3169 }
3170 return renderArea;
3171}
3172
3173// Return the framebuffer's scissored and rotated render area. This is a gl::Rectangle that is
3174// based on the dimensions of the framebuffer, is clipped to the scissor, IS ROTATED and IS
3175// Y-FLIPPED for the draw FBO.
3176//
3177// Note: Since the rectangle is scissored, it must be fully rotated, and not just have the width
3178// and height swapped.
3179gl::Rectangle FramebufferVk::getRotatedScissoredRenderArea(ContextVk *contextVk) const
3180{
3181 const gl::Rectangle renderArea = getNonRotatedCompleteRenderArea();
3182 bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO();
3183 gl::Rectangle scissoredArea = ClipRectToScissor(glState: contextVk->getState(), rect: renderArea, invertY: false);
3184 gl::Rectangle rotatedScissoredArea;
3185 RotateRectangle(rotation: contextVk->getRotationDrawFramebuffer(), flipY: invertViewport, framebufferWidth: renderArea.width,
3186 framebufferHeight: renderArea.height, incoming: scissoredArea, outgoing: &rotatedScissoredArea);
3187 return rotatedScissoredArea;
3188}
3189
3190GLint FramebufferVk::getSamples() const
3191{
3192 const gl::FramebufferAttachment *lastAttachment = nullptr;
3193
3194 for (size_t colorIndexGL : mState.getEnabledDrawBuffers() & mState.getColorAttachmentsMask())
3195 {
3196 const gl::FramebufferAttachment *color = mState.getColorAttachment(colorAttachment: colorIndexGL);
3197 ASSERT(color);
3198
3199 if (color->isRenderToTexture())
3200 {
3201 return color->getSamples();
3202 }
3203
3204 lastAttachment = color;
3205 }
3206 const gl::FramebufferAttachment *depthStencil = mState.getDepthOrStencilAttachment();
3207 if (depthStencil)
3208 {
3209 if (depthStencil->isRenderToTexture())
3210 {
3211 return depthStencil->getSamples();
3212 }
3213 lastAttachment = depthStencil;
3214 }
3215
3216 // If none of the attachments are multisampled-render-to-texture, take the sample count from the
3217 // last attachment (any would have worked, as they would all have the same sample count).
3218 return std::max(a: lastAttachment ? lastAttachment->getSamples() : 1, b: 1);
3219}
3220
3221angle::Result FramebufferVk::flushDeferredClears(ContextVk *contextVk)
3222{
3223 if (mDeferredClears.empty())
3224 {
3225 return angle::Result::Continue;
3226 }
3227
3228 return contextVk->startRenderPass(renderArea: getRotatedCompleteRenderArea(contextVk), commandBufferOut: nullptr, renderPassDescChangedOut: nullptr);
3229}
3230
3231void FramebufferVk::switchToFramebufferFetchMode(ContextVk *contextVk, bool hasFramebufferFetch)
3232{
3233 // The switch happens once, and is permanent.
3234 if (mCurrentFramebufferDesc.hasFramebufferFetch() == hasFramebufferFetch)
3235 {
3236 return;
3237 }
3238
3239 // Make sure framebuffer is recreated.
3240 releaseCurrentFramebuffer(contextVk);
3241 mCurrentFramebufferDesc.setFramebufferFetchMode(hasFramebufferFetch);
3242
3243 mRenderPassDesc.setFramebufferFetchMode(hasFramebufferFetch);
3244 contextVk->onDrawFramebufferRenderPassDescChange(framebufferVk: this, renderPassDescChangedOut: nullptr);
3245
3246 // Clear the framebuffer cache, as none of the old framebuffers are usable.
3247 if (contextVk->getFeatures().permanentlySwitchToFramebufferFetchMode.enabled)
3248 {
3249 ASSERT(hasFramebufferFetch);
3250 releaseCurrentFramebuffer(contextVk);
3251 }
3252}
3253
3254bool FramebufferVk::updateLegacyDither(ContextVk *contextVk)
3255{
3256 if (contextVk->getFeatures().supportsLegacyDithering.enabled &&
3257 mRenderPassDesc.isLegacyDitherEnabled() != contextVk->isDitherEnabled())
3258 {
3259 mRenderPassDesc.setLegacyDither(contextVk->isDitherEnabled());
3260 return true;
3261 }
3262
3263 return false;
3264}
3265} // namespace rx
3266

Provided by KDAB

Privacy Policy
Learn more about Flutter for embedded and desktop on industrialflutter.com

source code of flutter_engine/third_party/angle/src/libANGLE/renderer/vulkan/FramebufferVk.cpp