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/SurfaceVk.h"
25 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
26 #include "libANGLE/renderer/vulkan/vk_renderer.h"
27 #include "libANGLE/renderer/vulkan/vk_resource.h"
28
29 namespace rx
30 {
31
32 namespace
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.
37 constexpr VkClearValue kUninitializedClearValue = {{{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.
41 constexpr unsigned int kEmulatedAlphaValue = 1;
42
HasSrcBlitFeature(vk::Renderer * renderer,RenderTargetVk * srcRenderTarget)43 bool HasSrcBlitFeature(vk::Renderer *renderer, RenderTargetVk *srcRenderTarget)
44 {
45 angle::FormatID srcFormatID = srcRenderTarget->getImageActualFormatID();
46 return renderer->hasImageFormatFeatureBits(srcFormatID, VK_FORMAT_FEATURE_BLIT_SRC_BIT);
47 }
48
HasDstBlitFeature(vk::Renderer * renderer,RenderTargetVk * dstRenderTarget)49 bool HasDstBlitFeature(vk::Renderer *renderer, RenderTargetVk *dstRenderTarget)
50 {
51 angle::FormatID dstFormatID = dstRenderTarget->getImageActualFormatID();
52 return renderer->hasImageFormatFeatureBits(dstFormatID, 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.
AreSrcAndDstColorChannelsBlitCompatible(RenderTargetVk * srcRenderTarget,RenderTargetVk * dstRenderTarget)57 bool 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.
AreSrcAndDstFormatsIdentical(RenderTargetVk * srcRenderTarget,RenderTargetVk * dstRenderTarget)78 bool 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
AreSrcAndDstDepthStencilChannelsBlitCompatible(RenderTargetVk * srcRenderTarget,RenderTargetVk * dstRenderTarget)86 bool 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
EarlyAdjustFlipYForPreRotation(SurfaceRotation blitAngleIn,SurfaceRotation * blitAngleOut,bool * blitFlipYOut)96 void 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
AdjustBlitAreaForPreRotation(SurfaceRotation framebufferAngle,const gl::Rectangle & blitAreaIn,const gl::Rectangle & framebufferDimensions,gl::Rectangle * blitAreaOut)122 void 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(blitAreaOut->width, 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(blitAreaOut->width, blitAreaOut->height);
145 break;
146 default:
147 UNREACHABLE();
148 break;
149 }
150 }
151
AdjustDimensionsAndFlipForPreRotation(SurfaceRotation framebufferAngle,gl::Rectangle * framebufferDimensions,bool * flipX,bool * flipY)152 void 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(framebufferDimensions->width, framebufferDimensions->height);
164 std::swap(*flipX, *flipY);
165 break;
166 case SurfaceRotation::Rotated180Degrees:
167 break;
168 case SurfaceRotation::Rotated270Degrees:
169 std::swap(framebufferDimensions->width, framebufferDimensions->height);
170 std::swap(*flipX, *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.
AdjustBlitResolveParametersForResolve(const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,UtilsVk::BlitResolveParameters * params)183 void 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.
AdjustBlitResolveParametersForPreRotation(SurfaceRotation framebufferAngle,SurfaceRotation srcFramebufferAngle,UtilsVk::BlitResolveParameters * params)216 void 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(params->stretch[0], params->stretch[1]);
226 std::swap(params->srcOffset[0], params->srcOffset[1]);
227 std::swap(params->rotatedOffsetFactor[0], params->rotatedOffsetFactor[1]);
228 std::swap(params->flipX, params->flipY);
229 if (srcFramebufferAngle == framebufferAngle)
230 {
231 std::swap(params->dstOffset[0], params->dstOffset[1]);
232 std::swap(params->stretch[0], 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(params->stretch[0], params->stretch[1]);
242 std::swap(params->srcOffset[0], params->srcOffset[1]);
243 std::swap(params->rotatedOffsetFactor[0], params->rotatedOffsetFactor[1]);
244 if (srcFramebufferAngle == framebufferAngle)
245 {
246 std::swap(params->stretch[0], params->stretch[1]);
247 }
248 // Combine flip info with api flip.
249 params->flipX = !params->flipX;
250 params->flipY = !params->flipY;
251 std::swap(params->flipX, params->flipY);
252
253 break;
254 default:
255 UNREACHABLE();
256 break;
257 }
258 }
259
MakeUnresolveAttachmentMask(const vk::RenderPassDesc & desc)260 vk::FramebufferNonResolveAttachmentMask MakeUnresolveAttachmentMask(const vk::RenderPassDesc &desc)
261 {
262 vk::FramebufferNonResolveAttachmentMask unresolveMask(
263 desc.getColorUnresolveAttachmentMask().bits());
264 if (desc.hasDepthUnresolveAttachment() || desc.hasStencilUnresolveAttachment())
265 {
266 // This mask only needs to know if the depth/stencil attachment needs to be unresolved, and
267 // is agnostic of the aspect.
268 unresolveMask.set(vk::kUnpackedDepthIndex);
269 }
270 return unresolveMask;
271 }
272
IsAnyAttachment3DWithoutAllLayers(const RenderTargetCache<RenderTargetVk> & renderTargetCache,gl::DrawBufferMask colorAttachmentsMask,uint32_t framebufferLayerCount)273 bool IsAnyAttachment3DWithoutAllLayers(const RenderTargetCache<RenderTargetVk> &renderTargetCache,
274 gl::DrawBufferMask colorAttachmentsMask,
275 uint32_t framebufferLayerCount)
276 {
277 const auto &colorRenderTargets = renderTargetCache.getColors();
278 for (size_t colorIndexGL : colorAttachmentsMask)
279 {
280 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
281 ASSERT(colorRenderTarget);
282
283 const vk::ImageHelper &image = colorRenderTarget->getImageForRenderPass();
284
285 if (image.getType() == VK_IMAGE_TYPE_3D && image.getExtents().depth > framebufferLayerCount)
286 {
287 return true;
288 }
289 }
290
291 // Depth/stencil attachments cannot be 3D.
292 ASSERT(renderTargetCache.getDepthStencil() == nullptr ||
293 renderTargetCache.getDepthStencil()->getImageForRenderPass().getType() !=
294 VK_IMAGE_TYPE_3D);
295
296 return false;
297 }
298
299 // Should be called when the image type is VK_IMAGE_TYPE_3D. Typically, the subresource, offsets
300 // and extents are filled in as if images are 2D layers (because depth slices of 3D images are also
301 // specified through "layers" everywhere, particularly by gl::ImageIndex). This function adjusts
302 // the layer base/count and offsets.z/extents.z appropriately after these structs are set up.
AdjustLayersAndDepthFor3DImages(VkImageSubresourceLayers * subresource,VkOffset3D * offsetsStart,VkOffset3D * offsetsEnd)303 void AdjustLayersAndDepthFor3DImages(VkImageSubresourceLayers *subresource,
304 VkOffset3D *offsetsStart,
305 VkOffset3D *offsetsEnd)
306 {
307 // The struct must be set up as if the image was 2D array.
308 ASSERT(offsetsStart->z == 0);
309 ASSERT(offsetsEnd->z == 1);
310
311 offsetsStart->z = subresource->baseArrayLayer;
312 offsetsEnd->z = subresource->baseArrayLayer + subresource->layerCount;
313
314 subresource->baseArrayLayer = 0;
315 subresource->layerCount = 1;
316 }
317
AllowAddingResolveAttachmentsToSubpass(const vk::RenderPassDesc & desc)318 bool AllowAddingResolveAttachmentsToSubpass(const vk::RenderPassDesc &desc)
319 {
320 // When in render-to-texture emulation mode, there are already resolve attachments present, and
321 // render pass compatibility rules would require packing those first before packing resolve
322 // attachments that may be added later (through glBlitFramebuffer). While supporting that is
323 // not onerous, the code is simplified by not supporting this combination. In practice no
324 // application should be mixing MSRTT textures and and truly multisampled textures in the same
325 // framebuffer (they could be using MSRTT for both).
326 //
327 // For the same reason, adding resolve attachments after the fact is disabled with YUV resolve.
328 return !desc.isRenderToTexture() && !desc.hasYUVResolveAttachment();
329 }
330 } // anonymous namespace
331
FramebufferVk(vk::Renderer * renderer,const gl::FramebufferState & state)332 FramebufferVk::FramebufferVk(vk::Renderer *renderer, const gl::FramebufferState &state)
333 : FramebufferImpl(state), mBackbuffer(nullptr), mActiveColorComponentMasksForClear(0)
334 {
335 if (mState.isDefault())
336 {
337 // These are immutable for system default framebuffer.
338 mCurrentFramebufferDesc.updateLayerCount(1);
339 mCurrentFramebufferDesc.updateIsMultiview(false);
340 }
341
342 mIsCurrentFramebufferCached = !renderer->getFeatures().supportsImagelessFramebuffer.enabled;
343 mIsYUVResolve = false;
344 }
345
346 FramebufferVk::~FramebufferVk() = default;
347
destroy(const gl::Context * context)348 void FramebufferVk::destroy(const gl::Context *context)
349 {
350 ContextVk *contextVk = vk::GetImpl(context);
351
352 if (mFragmentShadingRateImage.valid())
353 {
354 vk::Renderer *renderer = contextVk->getRenderer();
355 mFragmentShadingRateImageView.release(renderer, mFragmentShadingRateImage.getResourceUse());
356 mFragmentShadingRateImage.releaseImage(renderer);
357 }
358
359 releaseCurrentFramebuffer(contextVk);
360 }
361
insertCache(ContextVk * contextVk,const vk::FramebufferDesc & desc,vk::FramebufferHelper && newFramebuffer)362 void FramebufferVk::insertCache(ContextVk *contextVk,
363 const vk::FramebufferDesc &desc,
364 vk::FramebufferHelper &&newFramebuffer)
365 {
366 // Add it into per share group cache
367 contextVk->getShareGroup()->getFramebufferCache().insert(contextVk, desc,
368 std::move(newFramebuffer));
369
370 // Create a refcounted cache key object and have each attachment keep a refcount to it so that
371 // it can be destroyed promptly if those attachments change.
372 const vk::SharedFramebufferCacheKey sharedFramebufferCacheKey =
373 vk::CreateSharedFramebufferCacheKey(desc);
374
375 // Ask each attachment to hold a reference to the cache so that when any attachment is
376 // released, the cache can be destroyed.
377 const auto &colorRenderTargets = mRenderTargetCache.getColors();
378 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
379 {
380 colorRenderTargets[colorIndexGL]->onNewFramebuffer(sharedFramebufferCacheKey);
381 }
382
383 if (getDepthStencilRenderTarget())
384 {
385 getDepthStencilRenderTarget()->onNewFramebuffer(sharedFramebufferCacheKey);
386 }
387 }
388
discard(const gl::Context * context,size_t count,const GLenum * attachments)389 angle::Result FramebufferVk::discard(const gl::Context *context,
390 size_t count,
391 const GLenum *attachments)
392 {
393 return invalidate(context, count, attachments);
394 }
395
invalidate(const gl::Context * context,size_t count,const GLenum * attachments)396 angle::Result FramebufferVk::invalidate(const gl::Context *context,
397 size_t count,
398 const GLenum *attachments)
399 {
400 ContextVk *contextVk = vk::GetImpl(context);
401
402 ANGLE_TRY(invalidateImpl(contextVk, count, attachments, false,
403 getRotatedCompleteRenderArea(contextVk)));
404 return angle::Result::Continue;
405 }
406
invalidateSub(const gl::Context * context,size_t count,const GLenum * attachments,const gl::Rectangle & area)407 angle::Result FramebufferVk::invalidateSub(const gl::Context *context,
408 size_t count,
409 const GLenum *attachments,
410 const gl::Rectangle &area)
411 {
412 ContextVk *contextVk = vk::GetImpl(context);
413
414 const gl::Rectangle nonRotatedCompleteRenderArea = getNonRotatedCompleteRenderArea();
415 gl::Rectangle rotatedInvalidateArea;
416 RotateRectangle(contextVk->getRotationDrawFramebuffer(),
417 contextVk->isViewportFlipEnabledForDrawFBO(),
418 nonRotatedCompleteRenderArea.width, nonRotatedCompleteRenderArea.height, area,
419 &rotatedInvalidateArea);
420
421 // If invalidateSub() covers the whole framebuffer area, make it behave as invalidate().
422 // The invalidate area is clipped to the render area for use inside invalidateImpl.
423 const gl::Rectangle completeRenderArea = getRotatedCompleteRenderArea(contextVk);
424 if (ClipRectangle(rotatedInvalidateArea, completeRenderArea, &rotatedInvalidateArea) &&
425 rotatedInvalidateArea == completeRenderArea)
426 {
427 return invalidate(context, count, attachments);
428 }
429
430 // If there are deferred clears, restage them. syncState may have accumulated deferred clears,
431 // but if the framebuffer's attachments are used after this call not through the framebuffer,
432 // those clears wouldn't get flushed otherwise (for example as the destination of
433 // glCopyTex[Sub]Image, shader storage image, etc).
434 restageDeferredClears(contextVk);
435
436 if (contextVk->hasActiveRenderPass() &&
437 rotatedInvalidateArea.encloses(contextVk->getStartedRenderPassCommands().getRenderArea()))
438 {
439 // Because the render pass's render area is within the invalidated area, it is fine for
440 // invalidateImpl() to use a storeOp of DONT_CARE (i.e. fine to not store the contents of
441 // the invalidated area).
442 ANGLE_TRY(invalidateImpl(contextVk, count, attachments, true, rotatedInvalidateArea));
443 }
444 else
445 {
446 ANGLE_VK_PERF_WARNING(
447 contextVk, GL_DEBUG_SEVERITY_LOW,
448 "InvalidateSubFramebuffer ignored due to area not covering the render area");
449 }
450
451 return angle::Result::Continue;
452 }
453
clear(const gl::Context * context,GLbitfield mask)454 angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
455 {
456 ANGLE_TRACE_EVENT0("gpu.angle", "FramebufferVk::clear");
457 ContextVk *contextVk = vk::GetImpl(context);
458
459 bool clearColor = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_COLOR_BUFFER_BIT));
460 bool clearDepth = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT));
461 bool clearStencil = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_STENCIL_BUFFER_BIT));
462 gl::DrawBufferMask clearColorBuffers;
463 if (clearColor)
464 {
465 clearColorBuffers = mState.getEnabledDrawBuffers();
466 }
467
468 const VkClearColorValue &clearColorValue = contextVk->getClearColorValue().color;
469 const VkClearDepthStencilValue &clearDepthStencilValue =
470 contextVk->getClearDepthStencilValue().depthStencil;
471
472 return clearImpl(context, clearColorBuffers, clearDepth, clearStencil, clearColorValue,
473 clearDepthStencilValue);
474 }
475
adjustFloatClearColorPrecision(const VkClearColorValue & color,const angle::Format & colorFormat)476 VkClearColorValue adjustFloatClearColorPrecision(const VkClearColorValue &color,
477 const angle::Format &colorFormat)
478 {
479 // Truncate x to b bits: round(x * (2^b-1)) / (2^b-1)
480 // Implemented as floor(x * ((1 << b) - 1) + 0.5) / ((1 << b) - 1)
481
482 float floatClearColorRed = color.float32[0];
483 GLuint targetRedBits = colorFormat.redBits;
484 floatClearColorRed = floor(floatClearColorRed * ((1 << targetRedBits) - 1) + 0.5f);
485 floatClearColorRed = floatClearColorRed / ((1 << targetRedBits) - 1);
486
487 float floatClearColorGreen = color.float32[1];
488 GLuint targetGreenBits = colorFormat.greenBits;
489 floatClearColorGreen = floor(floatClearColorGreen * ((1 << targetGreenBits) - 1) + 0.5f);
490 floatClearColorGreen = floatClearColorGreen / ((1 << targetGreenBits) - 1);
491
492 float floatClearColorBlue = color.float32[2];
493 GLuint targetBlueBits = colorFormat.blueBits;
494 floatClearColorBlue = floor(floatClearColorBlue * ((1 << targetBlueBits) - 1) + 0.5f);
495 floatClearColorBlue = floatClearColorBlue / ((1 << targetBlueBits) - 1);
496
497 float floatClearColorAlpha = color.float32[3];
498 GLuint targetAlphaBits = colorFormat.alphaBits;
499 floatClearColorAlpha = floor(floatClearColorAlpha * ((1 << targetAlphaBits) - 1) + 0.5f);
500 floatClearColorAlpha = floatClearColorAlpha / ((1 << targetAlphaBits) - 1);
501
502 VkClearColorValue adjustedClearColor = color;
503 adjustedClearColor.float32[0] = floatClearColorRed;
504 adjustedClearColor.float32[1] = floatClearColorGreen;
505 adjustedClearColor.float32[2] = floatClearColorBlue;
506 adjustedClearColor.float32[3] = floatClearColorAlpha;
507
508 return adjustedClearColor;
509 }
510
clearImpl(const gl::Context * context,gl::DrawBufferMask clearColorBuffers,bool clearDepth,bool clearStencil,const VkClearColorValue & clearColorValue,const VkClearDepthStencilValue & clearDepthStencilValue)511 angle::Result FramebufferVk::clearImpl(const gl::Context *context,
512 gl::DrawBufferMask clearColorBuffers,
513 bool clearDepth,
514 bool clearStencil,
515 const VkClearColorValue &clearColorValue,
516 const VkClearDepthStencilValue &clearDepthStencilValue)
517 {
518 ContextVk *contextVk = vk::GetImpl(context);
519
520 const gl::Rectangle scissoredRenderArea = getRotatedScissoredRenderArea(contextVk);
521 if (scissoredRenderArea.width == 0 || scissoredRenderArea.height == 0)
522 {
523 restageDeferredClears(contextVk);
524 return angle::Result::Continue;
525 }
526
527 // This function assumes that only enabled attachments are asked to be cleared.
528 ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers);
529 ASSERT(!clearDepth || mState.getDepthAttachment() != nullptr);
530 ASSERT(!clearStencil || mState.getStencilAttachment() != nullptr);
531
532 gl::BlendStateExt::ColorMaskStorage::Type colorMasks = contextVk->getClearColorMasks();
533 bool clearColor = clearColorBuffers.any();
534
535 // When this function is called, there should always be something to clear.
536 ASSERT(clearColor || clearDepth || clearStencil);
537
538 gl::DrawBuffersArray<VkClearColorValue> adjustedClearColorValues;
539 const gl::DrawBufferMask colorAttachmentMask = mState.getColorAttachmentsMask();
540 const auto &colorRenderTargets = mRenderTargetCache.getColors();
541 for (size_t colorIndexGL = 0; colorIndexGL < colorAttachmentMask.size(); ++colorIndexGL)
542 {
543 if (colorAttachmentMask[colorIndexGL])
544 {
545 adjustedClearColorValues[colorIndexGL] = clearColorValue;
546
547 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
548 ASSERT(colorRenderTarget);
549 if (colorRenderTarget->isYuvResolve())
550 {
551 // OpenGLES spec says "clear color should be defined in yuv color space and so
552 // floating point r, g, and b value will be mapped to corresponding y, u and v
553 // value" https://registry.khronos.org/OpenGL/extensions/EXT/EXT_YUV_target.txt.
554 // But vulkan spec says "Values in the G, B, and R channels of the color
555 // attachment will be written to the Y, CB, and CR channels of the external
556 // format image, respectively." So we have to adjust the component mapping from
557 // GL order to vulkan order.
558 adjustedClearColorValues[colorIndexGL].float32[0] = clearColorValue.float32[2];
559 adjustedClearColorValues[colorIndexGL].float32[1] = clearColorValue.float32[0];
560 adjustedClearColorValues[colorIndexGL].float32[2] = clearColorValue.float32[1];
561 }
562 else if (contextVk->getRenderer()->getFeatures().adjustClearColorPrecision.enabled)
563 {
564 const angle::FormatID colorRenderTargetFormat =
565 colorRenderTarget->getImageForRenderPass().getActualFormatID();
566 if (colorRenderTargetFormat == angle::FormatID::R5G5B5A1_UNORM)
567 {
568 // Temporary workaround for https://issuetracker.google.com/292282210 to avoid
569 // dithering being automatically applied
570 adjustedClearColorValues[colorIndexGL] = adjustFloatClearColorPrecision(
571 clearColorValue, angle::Format::Get(colorRenderTargetFormat));
572 }
573 }
574 }
575 }
576
577 const uint8_t stencilMask =
578 static_cast<uint8_t>(contextVk->getState().getDepthStencilState().stencilWritemask);
579
580 // The front-end should ensure we don't attempt to clear color if all channels are masked.
581 ASSERT(!clearColor || colorMasks != 0);
582 // The front-end should ensure we don't attempt to clear depth if depth write is disabled.
583 ASSERT(!clearDepth || contextVk->getState().getDepthStencilState().depthMask);
584 // The front-end should ensure we don't attempt to clear stencil if all bits are masked.
585 ASSERT(!clearStencil || stencilMask != 0);
586
587 // Make sure to close the render pass now if in read-only depth/stencil feedback loop mode and
588 // depth/stencil is being cleared.
589 if (clearDepth || clearStencil)
590 {
591 ANGLE_TRY(contextVk->updateRenderPassDepthFeedbackLoopMode(
592 clearDepth ? UpdateDepthFeedbackLoopReason::Clear : UpdateDepthFeedbackLoopReason::None,
593 clearStencil ? UpdateDepthFeedbackLoopReason::Clear
594 : UpdateDepthFeedbackLoopReason::None));
595 }
596
597 const bool scissoredClear = scissoredRenderArea != getRotatedCompleteRenderArea(contextVk);
598
599 // We use the draw path if scissored clear, or color or stencil are masked. Note that depth
600 // clearing is already disabled if there's a depth mask.
601 const bool maskedClearColor = clearColor && (mActiveColorComponentMasksForClear & colorMasks) !=
602 mActiveColorComponentMasksForClear;
603 const bool maskedClearStencil = clearStencil && stencilMask != 0xFF;
604
605 bool clearColorWithDraw = clearColor && (maskedClearColor || scissoredClear);
606 bool clearDepthWithDraw = clearDepth && scissoredClear;
607 bool clearStencilWithDraw = clearStencil && (maskedClearStencil || scissoredClear);
608
609 const bool isMidRenderPassClear =
610 contextVk->hasStartedRenderPassWithQueueSerial(mLastRenderPassQueueSerial) &&
611 !contextVk->getStartedRenderPassCommands().getCommandBuffer().empty();
612 if (isMidRenderPassClear)
613 {
614 // Emit debug-util markers for this mid-render-pass clear
615 ANGLE_TRY(
616 contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InRenderPassCmdBufQueryCmd));
617 }
618 else
619 {
620 ASSERT(!contextVk->hasActiveRenderPass() ||
621 contextVk->hasStartedRenderPassWithQueueSerial(mLastRenderPassQueueSerial));
622 // Emit debug-util markers for this outside-render-pass clear
623 ANGLE_TRY(
624 contextVk->handleGraphicsEventLog(rx::GraphicsEventCmdBuf::InOutsideCmdBufQueryCmd));
625 }
626
627 const bool preferDrawOverClearAttachments =
628 contextVk->getRenderer()->getFeatures().preferDrawClearOverVkCmdClearAttachments.enabled;
629
630 // Merge current clears with the deferred clears, then proceed with only processing deferred
631 // clears. This simplifies the clear paths such that they don't need to consider both the
632 // current and deferred clears. Additionally, it avoids needing to undo an unresolve
633 // operation; say attachment A is deferred cleared and multisampled-render-to-texture
634 // attachment B is currently cleared. Assuming a render pass needs to start (because for
635 // example attachment C needs to clear with a draw path), starting one with only deferred
636 // clears and then applying the current clears won't work as attachment B is unresolved, and
637 // there are no facilities to undo that.
638 if (preferDrawOverClearAttachments && isMidRenderPassClear)
639 {
640 // On buggy hardware, prefer to clear with a draw call instead of vkCmdClearAttachments.
641 // Note that it's impossible to have deferred clears in the middle of the render pass.
642 ASSERT(!mDeferredClears.any());
643
644 clearColorWithDraw = clearColor;
645 clearDepthWithDraw = clearDepth;
646 clearStencilWithDraw = clearStencil;
647 }
648 else
649 {
650 gl::DrawBufferMask clearColorDrawBuffersMask;
651 if (clearColor && !clearColorWithDraw)
652 {
653 clearColorDrawBuffersMask = clearColorBuffers;
654 }
655
656 mergeClearsWithDeferredClears(clearColorDrawBuffersMask, clearDepth && !clearDepthWithDraw,
657 clearStencil && !clearStencilWithDraw,
658 adjustedClearColorValues, clearDepthStencilValue);
659 }
660
661 // If any deferred clears, we can further defer them, clear them with vkCmdClearAttachments or
662 // flush them if necessary.
663 if (mDeferredClears.any())
664 {
665 const bool clearAnyWithDraw =
666 clearColorWithDraw || clearDepthWithDraw || clearStencilWithDraw;
667
668 bool isAnyAttachment3DWithoutAllLayers =
669 IsAnyAttachment3DWithoutAllLayers(mRenderTargetCache, mState.getColorAttachmentsMask(),
670 mCurrentFramebufferDesc.getLayerCount());
671
672 // If we are in an active renderpass that has recorded commands and the framebuffer hasn't
673 // changed, inline the clear.
674 if (isMidRenderPassClear)
675 {
676 ANGLE_VK_PERF_WARNING(
677 contextVk, GL_DEBUG_SEVERITY_LOW,
678 "Clear effectively discarding previous draw call results. Suggest earlier Clear "
679 "followed by masked color or depth/stencil draw calls instead, or "
680 "glInvalidateFramebuffer to discard data instead");
681
682 ASSERT(!preferDrawOverClearAttachments);
683
684 // clearWithCommand will operate on deferred clears.
685 clearWithCommand(contextVk, scissoredRenderArea, ClearWithCommand::OptimizeWithLoadOp,
686 &mDeferredClears);
687
688 // clearWithCommand will clear only those attachments that have been used in the render
689 // pass, and removes them from mDeferredClears. Any deferred clears that are left can
690 // be performed with a renderpass loadOp.
691 if (mDeferredClears.any())
692 {
693 clearWithLoadOp(contextVk);
694 }
695 }
696 else
697 {
698 if (contextVk->hasActiveRenderPass())
699 {
700 // Typically, clears are deferred such that it's impossible to have a render pass
701 // opened without any additional commands recorded on it. This is not true for some
702 // corner cases, such as with 3D or external attachments. In those cases, a clear
703 // can open a render pass that's otherwise empty, and additional clears can continue
704 // to be accumulated in the render pass loadOps.
705 ASSERT(isAnyAttachment3DWithoutAllLayers || hasAnyExternalAttachments());
706 clearWithLoadOp(contextVk);
707 }
708
709 // This path will defer the current clears along with deferred clears. This won't work
710 // if any attachment needs to be subsequently cleared with a draw call. In that case,
711 // flush deferred clears, which will start a render pass with deferred clear values.
712 // The subsequent draw call will then operate on the cleared attachments.
713 //
714 // Additionally, if the framebuffer is layered, any attachment is 3D and it has a larger
715 // depth than the framebuffer layers, clears cannot be deferred. This is because the
716 // clear may later need to be flushed with vkCmdClearColorImage, which cannot partially
717 // clear the 3D texture. In that case, the clears are flushed immediately too.
718 //
719 // For external images such as from AHBs, the clears are not deferred so that they are
720 // definitely applied before the application uses them outside of the control of ANGLE.
721 if (clearAnyWithDraw || isAnyAttachment3DWithoutAllLayers ||
722 hasAnyExternalAttachments())
723 {
724 ANGLE_TRY(flushDeferredClears(contextVk));
725 }
726 else
727 {
728 restageDeferredClears(contextVk);
729 }
730 }
731
732 // If nothing left to clear, early out.
733 if (!clearAnyWithDraw)
734 {
735 ASSERT(mDeferredClears.empty());
736 return angle::Result::Continue;
737 }
738 }
739
740 if (!clearColorWithDraw)
741 {
742 clearColorBuffers.reset();
743 }
744
745 // If we reach here simply because the clear is scissored (as opposed to masked), use
746 // vkCmdClearAttachments to clear the attachments. The attachments that are masked will
747 // continue to use a draw call. For depth, vkCmdClearAttachments can always be used, and no
748 // shader/pipeline support would then be required (though this is pending removal of the
749 // preferDrawOverClearAttachments workaround).
750 //
751 // A potential optimization is to use loadOp=Clear for scissored clears, but care needs to be
752 // taken to either break the render pass on growRenderArea(), or to turn the op back to Load and
753 // revert to vkCmdClearAttachments. This is not currently deemed necessary.
754 if (((clearColorBuffers.any() && !mEmulatedAlphaAttachmentMask.any() && !maskedClearColor) ||
755 clearDepthWithDraw || (clearStencilWithDraw && !maskedClearStencil)) &&
756 !preferDrawOverClearAttachments)
757 {
758 if (!contextVk->hasActiveRenderPass())
759 {
760 // Start a new render pass if necessary to record the commands.
761 vk::RenderPassCommandBuffer *commandBuffer;
762 gl::Rectangle renderArea = getRenderArea(contextVk);
763 ANGLE_TRY(contextVk->startRenderPass(renderArea, &commandBuffer, nullptr));
764 }
765
766 // Build clear values
767 vk::ClearValuesArray clears;
768 if (!maskedClearColor && !mEmulatedAlphaAttachmentMask.any())
769 {
770 VkClearValue colorClearValue = {};
771 for (size_t colorIndexGL : clearColorBuffers)
772 {
773 colorClearValue.color = adjustedClearColorValues[colorIndexGL];
774 clears.store(static_cast<uint32_t>(colorIndexGL), VK_IMAGE_ASPECT_COLOR_BIT,
775 colorClearValue);
776 }
777 clearColorBuffers.reset();
778 }
779 VkImageAspectFlags dsAspectFlags = 0;
780 if (clearDepthWithDraw)
781 {
782 dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
783 clearDepthWithDraw = false;
784 }
785 if (clearStencilWithDraw && !maskedClearStencil)
786 {
787 dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
788 clearStencilWithDraw = false;
789 }
790 if (dsAspectFlags != 0)
791 {
792 VkClearValue dsClearValue = {};
793 dsClearValue.depthStencil = clearDepthStencilValue;
794 clears.store(vk::kUnpackedDepthIndex, dsAspectFlags, dsClearValue);
795 }
796
797 clearWithCommand(contextVk, scissoredRenderArea, ClearWithCommand::Always, &clears);
798
799 if (!clearColorBuffers.any() && !clearStencilWithDraw)
800 {
801 ASSERT(!clearDepthWithDraw);
802 return angle::Result::Continue;
803 }
804 }
805
806 // The most costly clear mode is when we need to mask out specific color channels or stencil
807 // bits. This can only be done with a draw call.
808 return clearWithDraw(contextVk, scissoredRenderArea, clearColorBuffers, clearDepthWithDraw,
809 clearStencilWithDraw, colorMasks, stencilMask, adjustedClearColorValues,
810 clearDepthStencilValue);
811 }
812
clearBufferfv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLfloat * values)813 angle::Result FramebufferVk::clearBufferfv(const gl::Context *context,
814 GLenum buffer,
815 GLint drawbuffer,
816 const GLfloat *values)
817 {
818 VkClearValue clearValue = {};
819
820 bool clearDepth = false;
821 gl::DrawBufferMask clearColorBuffers;
822
823 if (buffer == GL_DEPTH)
824 {
825 clearDepth = true;
826 clearValue.depthStencil.depth = values[0];
827 }
828 else
829 {
830 clearColorBuffers.set(drawbuffer);
831 clearValue.color.float32[0] = values[0];
832 clearValue.color.float32[1] = values[1];
833 clearValue.color.float32[2] = values[2];
834 clearValue.color.float32[3] = values[3];
835 }
836
837 return clearImpl(context, clearColorBuffers, clearDepth, false, clearValue.color,
838 clearValue.depthStencil);
839 }
840
clearBufferuiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLuint * values)841 angle::Result FramebufferVk::clearBufferuiv(const gl::Context *context,
842 GLenum buffer,
843 GLint drawbuffer,
844 const GLuint *values)
845 {
846 VkClearValue clearValue = {};
847
848 gl::DrawBufferMask clearColorBuffers;
849 clearColorBuffers.set(drawbuffer);
850
851 clearValue.color.uint32[0] = values[0];
852 clearValue.color.uint32[1] = values[1];
853 clearValue.color.uint32[2] = values[2];
854 clearValue.color.uint32[3] = values[3];
855
856 return clearImpl(context, clearColorBuffers, false, false, clearValue.color,
857 clearValue.depthStencil);
858 }
859
clearBufferiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLint * values)860 angle::Result FramebufferVk::clearBufferiv(const gl::Context *context,
861 GLenum buffer,
862 GLint drawbuffer,
863 const GLint *values)
864 {
865 VkClearValue clearValue = {};
866
867 bool clearStencil = false;
868 gl::DrawBufferMask clearColorBuffers;
869
870 if (buffer == GL_STENCIL)
871 {
872 clearStencil = true;
873 clearValue.depthStencil.stencil = static_cast<uint8_t>(values[0]);
874 }
875 else
876 {
877 clearColorBuffers.set(drawbuffer);
878 clearValue.color.int32[0] = values[0];
879 clearValue.color.int32[1] = values[1];
880 clearValue.color.int32[2] = values[2];
881 clearValue.color.int32[3] = values[3];
882 }
883
884 return clearImpl(context, clearColorBuffers, false, clearStencil, clearValue.color,
885 clearValue.depthStencil);
886 }
887
clearBufferfi(const gl::Context * context,GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)888 angle::Result FramebufferVk::clearBufferfi(const gl::Context *context,
889 GLenum buffer,
890 GLint drawbuffer,
891 GLfloat depth,
892 GLint stencil)
893 {
894 VkClearValue clearValue = {};
895
896 clearValue.depthStencil.depth = depth;
897 clearValue.depthStencil.stencil = static_cast<uint8_t>(stencil);
898
899 return clearImpl(context, gl::DrawBufferMask(), true, true, clearValue.color,
900 clearValue.depthStencil);
901 }
902
getImplementationColorReadFormat(const gl::Context * context) const903 const gl::InternalFormat &FramebufferVk::getImplementationColorReadFormat(
904 const gl::Context *context) const
905 {
906 ContextVk *contextVk = vk::GetImpl(context);
907 GLenum sizedFormat = mState.getReadAttachment()->getFormat().info->sizedInternalFormat;
908 const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(sizedFormat);
909 GLenum implFormat = vkFormat.getActualRenderableImageFormat().fboImplementationInternalFormat;
910 return gl::GetSizedInternalFormatInfo(implFormat);
911 }
912
readPixels(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,const gl::PixelPackState & pack,gl::Buffer * packBuffer,void * pixels)913 angle::Result FramebufferVk::readPixels(const gl::Context *context,
914 const gl::Rectangle &area,
915 GLenum format,
916 GLenum type,
917 const gl::PixelPackState &pack,
918 gl::Buffer *packBuffer,
919 void *pixels)
920 {
921 // Clip read area to framebuffer.
922 const gl::Extents &fbSize = getState().getReadPixelsAttachment(format)->getSize();
923 const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
924 ContextVk *contextVk = vk::GetImpl(context);
925
926 gl::Rectangle clippedArea;
927 if (!ClipRectangle(area, fbRect, &clippedArea))
928 {
929 // nothing to read
930 return angle::Result::Continue;
931 }
932
933 // Flush any deferred clears.
934 ANGLE_TRY(flushDeferredClears(contextVk));
935
936 GLuint outputSkipBytes = 0;
937 PackPixelsParams params;
938 ANGLE_TRY(vk::ImageHelper::GetReadPixelsParams(contextVk, pack, packBuffer, format, type, area,
939 clippedArea, ¶ms, &outputSkipBytes));
940
941 bool flipY = contextVk->isViewportFlipEnabledForReadFBO();
942 switch (params.rotation = contextVk->getRotationReadFramebuffer())
943 {
944 case SurfaceRotation::Identity:
945 // Do not rotate gl_Position (surface matches the device's orientation):
946 if (flipY)
947 {
948 params.area.y = fbRect.height - clippedArea.y - clippedArea.height;
949 }
950 break;
951 case SurfaceRotation::Rotated90Degrees:
952 // Rotate gl_Position 90 degrees:
953 params.area.x = clippedArea.y;
954 params.area.y =
955 flipY ? clippedArea.x : fbRect.width - clippedArea.x - clippedArea.width;
956 std::swap(params.area.width, params.area.height);
957 break;
958 case SurfaceRotation::Rotated180Degrees:
959 // Rotate gl_Position 180 degrees:
960 params.area.x = fbRect.width - clippedArea.x - clippedArea.width;
961 params.area.y =
962 flipY ? clippedArea.y : fbRect.height - clippedArea.y - clippedArea.height;
963 break;
964 case SurfaceRotation::Rotated270Degrees:
965 // Rotate gl_Position 270 degrees:
966 params.area.x = fbRect.height - clippedArea.y - clippedArea.height;
967 params.area.y =
968 flipY ? fbRect.width - clippedArea.x - clippedArea.width : clippedArea.x;
969 std::swap(params.area.width, params.area.height);
970 break;
971 default:
972 UNREACHABLE();
973 break;
974 }
975 if (flipY)
976 {
977 params.reverseRowOrder = !params.reverseRowOrder;
978 }
979
980 ANGLE_TRY(readPixelsImpl(contextVk, params.area, params, getReadPixelsAspectFlags(format),
981 getReadPixelsRenderTarget(format),
982 static_cast<uint8_t *>(pixels) + outputSkipBytes));
983 return angle::Result::Continue;
984 }
985
getDepthStencilRenderTarget() const986 RenderTargetVk *FramebufferVk::getDepthStencilRenderTarget() const
987 {
988 return mRenderTargetCache.getDepthStencil();
989 }
990
getColorDrawRenderTarget(size_t colorIndexGL) const991 RenderTargetVk *FramebufferVk::getColorDrawRenderTarget(size_t colorIndexGL) const
992 {
993 RenderTargetVk *renderTarget = mRenderTargetCache.getColorDraw(mState, colorIndexGL);
994 ASSERT(renderTarget && renderTarget->getImageForRenderPass().valid());
995 return renderTarget;
996 }
997
getColorReadRenderTarget() const998 RenderTargetVk *FramebufferVk::getColorReadRenderTarget() const
999 {
1000 RenderTargetVk *renderTarget = mRenderTargetCache.getColorRead(mState);
1001 ASSERT(renderTarget && renderTarget->getImageForRenderPass().valid());
1002 return renderTarget;
1003 }
1004
getReadPixelsRenderTarget(GLenum format) const1005 RenderTargetVk *FramebufferVk::getReadPixelsRenderTarget(GLenum format) const
1006 {
1007 switch (format)
1008 {
1009 case GL_DEPTH_COMPONENT:
1010 case GL_STENCIL_INDEX_OES:
1011 case GL_DEPTH_STENCIL_OES:
1012 return getDepthStencilRenderTarget();
1013 default:
1014 return getColorReadRenderTarget();
1015 }
1016 }
1017
getReadPixelsAspectFlags(GLenum format) const1018 VkImageAspectFlagBits FramebufferVk::getReadPixelsAspectFlags(GLenum format) const
1019 {
1020 switch (format)
1021 {
1022 case GL_DEPTH_COMPONENT:
1023 return VK_IMAGE_ASPECT_DEPTH_BIT;
1024 case GL_STENCIL_INDEX_OES:
1025 return VK_IMAGE_ASPECT_STENCIL_BIT;
1026 case GL_DEPTH_STENCIL_OES:
1027 return vk::IMAGE_ASPECT_DEPTH_STENCIL;
1028 default:
1029 return VK_IMAGE_ASPECT_COLOR_BIT;
1030 }
1031 }
1032
blitWithCommand(ContextVk * contextVk,const gl::Rectangle & sourceArea,const gl::Rectangle & destArea,RenderTargetVk * readRenderTarget,RenderTargetVk * drawRenderTarget,GLenum filter,bool colorBlit,bool depthBlit,bool stencilBlit,bool flipX,bool flipY)1033 angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
1034 const gl::Rectangle &sourceArea,
1035 const gl::Rectangle &destArea,
1036 RenderTargetVk *readRenderTarget,
1037 RenderTargetVk *drawRenderTarget,
1038 GLenum filter,
1039 bool colorBlit,
1040 bool depthBlit,
1041 bool stencilBlit,
1042 bool flipX,
1043 bool flipY)
1044 {
1045 // Since blitRenderbufferRect is called for each render buffer that needs to be blitted,
1046 // it should never be the case that both color and depth/stencil need to be blitted at
1047 // at the same time.
1048 ASSERT(colorBlit != (depthBlit || stencilBlit));
1049
1050 vk::ImageHelper *srcImage = &readRenderTarget->getImageForCopy();
1051 vk::ImageHelper *dstImage = &drawRenderTarget->getImageForWrite();
1052
1053 VkImageAspectFlags imageAspectMask = srcImage->getAspectFlags();
1054 VkImageAspectFlags blitAspectMask = imageAspectMask;
1055
1056 // Remove depth or stencil aspects if they are not requested to be blitted.
1057 if (!depthBlit)
1058 {
1059 blitAspectMask &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
1060 }
1061 if (!stencilBlit)
1062 {
1063 blitAspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
1064 }
1065
1066 vk::CommandBufferAccess access;
1067 access.onImageTransferRead(imageAspectMask, srcImage);
1068 access.onImageTransferWrite(drawRenderTarget->getLevelIndex(), 1,
1069 drawRenderTarget->getLayerIndex(), 1, imageAspectMask, dstImage);
1070 vk::OutsideRenderPassCommandBuffer *commandBuffer;
1071 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1072
1073 VkImageBlit blit = {};
1074 blit.srcSubresource.aspectMask = blitAspectMask;
1075 blit.srcSubresource.mipLevel = srcImage->toVkLevel(readRenderTarget->getLevelIndex()).get();
1076 blit.srcSubresource.baseArrayLayer = readRenderTarget->getLayerIndex();
1077 blit.srcSubresource.layerCount = 1;
1078 blit.srcOffsets[0] = {sourceArea.x0(), sourceArea.y0(), 0};
1079 blit.srcOffsets[1] = {sourceArea.x1(), sourceArea.y1(), 1};
1080 blit.dstSubresource.aspectMask = blitAspectMask;
1081 blit.dstSubresource.mipLevel = dstImage->toVkLevel(drawRenderTarget->getLevelIndex()).get();
1082 blit.dstSubresource.baseArrayLayer = drawRenderTarget->getLayerIndex();
1083 blit.dstSubresource.layerCount = 1;
1084 blit.dstOffsets[0] = {destArea.x0(), destArea.y0(), 0};
1085 blit.dstOffsets[1] = {destArea.x1(), destArea.y1(), 1};
1086
1087 // Note: vkCmdBlitImage doesn't actually work between 3D and 2D array images due to Vulkan valid
1088 // usage restrictions (https://gitlab.khronos.org/vulkan/vulkan/-/issues/3490), but drivers seem
1089 // to work as expected anyway. ANGLE continues to use vkCmdBlitImage in that case.
1090
1091 const bool isSrc3D = srcImage->getType() == VK_IMAGE_TYPE_3D;
1092 const bool isDst3D = dstImage->getType() == VK_IMAGE_TYPE_3D;
1093 if (isSrc3D)
1094 {
1095 AdjustLayersAndDepthFor3DImages(&blit.srcSubresource, &blit.srcOffsets[0],
1096 &blit.srcOffsets[1]);
1097 }
1098 if (isDst3D)
1099 {
1100 AdjustLayersAndDepthFor3DImages(&blit.dstSubresource, &blit.dstOffsets[0],
1101 &blit.dstOffsets[1]);
1102 }
1103
1104 commandBuffer->blitImage(srcImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1105 dstImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
1106 gl_vk::GetFilter(filter));
1107
1108 return angle::Result::Continue;
1109 }
1110
blit(const gl::Context * context,const gl::Rectangle & sourceAreaIn,const gl::Rectangle & destAreaIn,GLbitfield mask,GLenum filter)1111 angle::Result FramebufferVk::blit(const gl::Context *context,
1112 const gl::Rectangle &sourceAreaIn,
1113 const gl::Rectangle &destAreaIn,
1114 GLbitfield mask,
1115 GLenum filter)
1116 {
1117 ContextVk *contextVk = vk::GetImpl(context);
1118 vk::Renderer *renderer = contextVk->getRenderer();
1119 UtilsVk &utilsVk = contextVk->getUtils();
1120
1121 // If any clears were picked up when syncing the read framebuffer (as the blit source), restage
1122 // them. They correspond to attachments that are not used in the blit. This will cause the
1123 // read framebuffer to become dirty, so the attachments will be synced again on the next command
1124 // that might be using them.
1125 const gl::State &glState = contextVk->getState();
1126 const gl::Framebuffer *srcFramebuffer = glState.getReadFramebuffer();
1127 FramebufferVk *srcFramebufferVk = vk::GetImpl(srcFramebuffer);
1128 if (srcFramebufferVk->mDeferredClears.any())
1129 {
1130 srcFramebufferVk->restageDeferredClearsForReadFramebuffer(contextVk);
1131 }
1132
1133 // We can sometimes end up in a blit with some clear commands saved. Ensure all clear commands
1134 // are issued before we issue the blit command.
1135 ANGLE_TRY(flushDeferredClears(contextVk));
1136
1137 const bool blitColorBuffer = (mask & GL_COLOR_BUFFER_BIT) != 0;
1138 const bool blitDepthBuffer = (mask & GL_DEPTH_BUFFER_BIT) != 0;
1139 const bool blitStencilBuffer = (mask & GL_STENCIL_BUFFER_BIT) != 0;
1140
1141 // If a framebuffer contains a mixture of multisampled and multisampled-render-to-texture
1142 // attachments, this function could be simultaneously doing a blit on one attachment and resolve
1143 // on another. For the most part, this means resolve semantics apply. However, as the resolve
1144 // path cannot be taken for multisampled-render-to-texture attachments, the distinction of
1145 // whether resolve is done for each attachment or blit is made.
1146 const bool isColorResolve =
1147 blitColorBuffer &&
1148 srcFramebufferVk->getColorReadRenderTarget()->getImageForCopy().getSamples() > 1;
1149 const bool isDepthStencilResolve =
1150 (blitDepthBuffer || blitStencilBuffer) &&
1151 srcFramebufferVk->getDepthStencilRenderTarget()->getImageForCopy().getSamples() > 1;
1152 const bool isResolve = isColorResolve || isDepthStencilResolve;
1153
1154 bool srcFramebufferFlippedY = contextVk->isViewportFlipEnabledForReadFBO();
1155 bool dstFramebufferFlippedY = contextVk->isViewportFlipEnabledForDrawFBO();
1156
1157 gl::Rectangle sourceArea = sourceAreaIn;
1158 gl::Rectangle destArea = destAreaIn;
1159
1160 // Note: GLES (all 3.x versions) require source and destination area to be identical when
1161 // resolving.
1162 ASSERT(!isResolve ||
1163 (sourceArea.x == destArea.x && sourceArea.y == destArea.y &&
1164 sourceArea.width == destArea.width && sourceArea.height == destArea.height));
1165
1166 gl::Rectangle srcFramebufferDimensions = srcFramebufferVk->getNonRotatedCompleteRenderArea();
1167 gl::Rectangle dstFramebufferDimensions = getNonRotatedCompleteRenderArea();
1168
1169 // If the destination is flipped in either direction, we will flip the source instead so that
1170 // the destination area is always unflipped.
1171 sourceArea = sourceArea.flip(destArea.isReversedX(), destArea.isReversedY());
1172 destArea = destArea.removeReversal();
1173
1174 // Calculate the stretch factor prior to any clipping, as it needs to remain constant.
1175 const double stretch[2] = {
1176 std::abs(sourceArea.width / static_cast<double>(destArea.width)),
1177 std::abs(sourceArea.height / static_cast<double>(destArea.height)),
1178 };
1179
1180 // Potentially make adjustments for pre-rotatation. To handle various cases (e.g. clipping)
1181 // and to not interrupt the normal flow of the code, different adjustments are made in
1182 // different parts of the code. These first adjustments are for whether or not to flip the
1183 // y-axis, and to note the overall rotation (regardless of whether it is the source or
1184 // destination that is rotated).
1185 SurfaceRotation srcFramebufferRotation = contextVk->getRotationReadFramebuffer();
1186 SurfaceRotation dstFramebufferRotation = contextVk->getRotationDrawFramebuffer();
1187 SurfaceRotation rotation = SurfaceRotation::Identity;
1188 // Both the source and destination cannot be rotated (which would indicate both are the default
1189 // framebuffer (i.e. swapchain image).
1190 ASSERT((srcFramebufferRotation == SurfaceRotation::Identity) ||
1191 (dstFramebufferRotation == SurfaceRotation::Identity));
1192 EarlyAdjustFlipYForPreRotation(srcFramebufferRotation, &rotation, &srcFramebufferFlippedY);
1193 EarlyAdjustFlipYForPreRotation(dstFramebufferRotation, &rotation, &dstFramebufferFlippedY);
1194
1195 // First, clip the source area to framebuffer. That requires transforming the destination area
1196 // to match the clipped source.
1197 gl::Rectangle absSourceArea = sourceArea.removeReversal();
1198 gl::Rectangle clippedSourceArea;
1199 if (!gl::ClipRectangle(srcFramebufferDimensions, absSourceArea, &clippedSourceArea))
1200 {
1201 return angle::Result::Continue;
1202 }
1203
1204 // Resize the destination area based on the new size of source. Note again that stretch is
1205 // calculated as SrcDimension/DestDimension.
1206 gl::Rectangle srcClippedDestArea;
1207 if (isResolve)
1208 {
1209 // Source and destination areas are identical in resolve (except rotate it, if appropriate).
1210 srcClippedDestArea = clippedSourceArea;
1211 AdjustBlitAreaForPreRotation(dstFramebufferRotation, clippedSourceArea,
1212 dstFramebufferDimensions, &srcClippedDestArea);
1213 }
1214 else if (clippedSourceArea == absSourceArea)
1215 {
1216 // If there was no clipping, keep destination area as is (except rotate it, if appropriate).
1217 srcClippedDestArea = destArea;
1218 AdjustBlitAreaForPreRotation(dstFramebufferRotation, destArea, dstFramebufferDimensions,
1219 &srcClippedDestArea);
1220 }
1221 else
1222 {
1223 // Shift destination area's x0,y0,x1,y1 by as much as the source area's got shifted (taking
1224 // stretching into account). Note that double is used as float doesn't have enough
1225 // precision near the end of int range.
1226 double x0Shift = std::round((clippedSourceArea.x - absSourceArea.x) / stretch[0]);
1227 double y0Shift = std::round((clippedSourceArea.y - absSourceArea.y) / stretch[1]);
1228 double x1Shift = std::round((absSourceArea.x1() - clippedSourceArea.x1()) / stretch[0]);
1229 double y1Shift = std::round((absSourceArea.y1() - clippedSourceArea.y1()) / stretch[1]);
1230
1231 // If the source area was reversed in any direction, the shift should be applied in the
1232 // opposite direction as well.
1233 if (sourceArea.isReversedX())
1234 {
1235 std::swap(x0Shift, x1Shift);
1236 }
1237
1238 if (sourceArea.isReversedY())
1239 {
1240 std::swap(y0Shift, y1Shift);
1241 }
1242
1243 srcClippedDestArea.x = destArea.x0() + static_cast<int>(x0Shift);
1244 srcClippedDestArea.y = destArea.y0() + static_cast<int>(y0Shift);
1245 int x1 = destArea.x1() - static_cast<int>(x1Shift);
1246 int y1 = destArea.y1() - static_cast<int>(y1Shift);
1247
1248 srcClippedDestArea.width = x1 - srcClippedDestArea.x;
1249 srcClippedDestArea.height = y1 - srcClippedDestArea.y;
1250
1251 // Rotate srcClippedDestArea if the destination is rotated
1252 if (dstFramebufferRotation != SurfaceRotation::Identity)
1253 {
1254 gl::Rectangle originalSrcClippedDestArea = srcClippedDestArea;
1255 AdjustBlitAreaForPreRotation(dstFramebufferRotation, originalSrcClippedDestArea,
1256 dstFramebufferDimensions, &srcClippedDestArea);
1257 }
1258 }
1259
1260 // If framebuffers are flipped in Y, flip the source and destination area (which define the
1261 // transformation regardless of clipping), as well as the blit area (which is the clipped
1262 // destination area).
1263 if (srcFramebufferFlippedY)
1264 {
1265 sourceArea.y = srcFramebufferDimensions.height - sourceArea.y;
1266 sourceArea.height = -sourceArea.height;
1267 }
1268 if (dstFramebufferFlippedY)
1269 {
1270 destArea.y = dstFramebufferDimensions.height - destArea.y;
1271 destArea.height = -destArea.height;
1272
1273 srcClippedDestArea.y =
1274 dstFramebufferDimensions.height - srcClippedDestArea.y - srcClippedDestArea.height;
1275 }
1276
1277 bool flipX = sourceArea.isReversedX() != destArea.isReversedX();
1278 bool flipY = sourceArea.isReversedY() != destArea.isReversedY();
1279
1280 // GLES doesn't allow flipping the parameters of glBlitFramebuffer if performing a resolve.
1281 ASSERT(!isResolve ||
1282 (flipX == false && flipY == (srcFramebufferFlippedY != dstFramebufferFlippedY)));
1283
1284 // Again, transfer the destination flip to source, so destination is unflipped. Note that
1285 // destArea was not reversed until the final possible Y-flip.
1286 ASSERT(!destArea.isReversedX());
1287 sourceArea = sourceArea.flip(false, destArea.isReversedY());
1288 destArea = destArea.removeReversal();
1289
1290 // Now that clipping and flipping is done, rotate certain values that will be used for
1291 // UtilsVk::BlitResolveParameters
1292 gl::Rectangle sourceAreaOld = sourceArea;
1293 gl::Rectangle destAreaOld = destArea;
1294 if (srcFramebufferRotation == rotation)
1295 {
1296 AdjustBlitAreaForPreRotation(srcFramebufferRotation, sourceAreaOld,
1297 srcFramebufferDimensions, &sourceArea);
1298 AdjustDimensionsAndFlipForPreRotation(srcFramebufferRotation, &srcFramebufferDimensions,
1299 &flipX, &flipY);
1300 }
1301 SurfaceRotation rememberDestFramebufferRotation = dstFramebufferRotation;
1302 if (srcFramebufferRotation == SurfaceRotation::Rotated90Degrees)
1303 {
1304 dstFramebufferRotation = rotation;
1305 }
1306 AdjustBlitAreaForPreRotation(dstFramebufferRotation, destAreaOld, dstFramebufferDimensions,
1307 &destArea);
1308 dstFramebufferRotation = rememberDestFramebufferRotation;
1309
1310 // Clip the destination area to the framebuffer size and scissor. Note that we don't care
1311 // about the source area anymore. The offset translation is done based on the original source
1312 // and destination rectangles. The stretch factor is already calculated as well.
1313 gl::Rectangle blitArea;
1314 if (!gl::ClipRectangle(getRotatedScissoredRenderArea(contextVk), srcClippedDestArea, &blitArea))
1315 {
1316 return angle::Result::Continue;
1317 }
1318
1319 bool noClip = blitArea == destArea && stretch[0] == 1.0f && stretch[1] == 1.0f;
1320 bool noFlip = !flipX && !flipY;
1321 bool disableFlippingBlitWithCommand =
1322 renderer->getFeatures().disableFlippingBlitWithCommand.enabled;
1323
1324 UtilsVk::BlitResolveParameters commonParams;
1325 commonParams.srcOffset[0] = sourceArea.x;
1326 commonParams.srcOffset[1] = sourceArea.y;
1327 commonParams.dstOffset[0] = destArea.x;
1328 commonParams.dstOffset[1] = destArea.y;
1329 commonParams.rotatedOffsetFactor[0] = std::abs(sourceArea.width);
1330 commonParams.rotatedOffsetFactor[1] = std::abs(sourceArea.height);
1331 commonParams.stretch[0] = static_cast<float>(stretch[0]);
1332 commonParams.stretch[1] = static_cast<float>(stretch[1]);
1333 commonParams.srcExtents[0] = srcFramebufferDimensions.width;
1334 commonParams.srcExtents[1] = srcFramebufferDimensions.height;
1335 commonParams.blitArea = blitArea;
1336 commonParams.linear = filter == GL_LINEAR && !isResolve;
1337 commonParams.flipX = flipX;
1338 commonParams.flipY = flipY;
1339 commonParams.rotation = rotation;
1340
1341 if (blitColorBuffer)
1342 {
1343 RenderTargetVk *readRenderTarget = srcFramebufferVk->getColorReadRenderTarget();
1344 UtilsVk::BlitResolveParameters params = commonParams;
1345 params.srcLayer = readRenderTarget->getLayerIndex();
1346
1347 // Multisampled images are not allowed to have mips.
1348 ASSERT(!isColorResolve || readRenderTarget->getLevelIndex() == gl::LevelIndex(0));
1349
1350 // If there was no clipping and the format capabilities allow us, use Vulkan's builtin blit.
1351 // The reason clipping is prohibited in this path is that due to rounding errors, it would
1352 // be hard to guarantee the image stretching remains perfect. That also allows us not to
1353 // have to transform back the destination clipping to source.
1354 //
1355 // Non-identity pre-rotation cases do not use Vulkan's builtin blit. Additionally, blits
1356 // between 3D and non-3D-non-layer-0 images are forbidden (possibly due to an oversight:
1357 // https://gitlab.khronos.org/vulkan/vulkan/-/issues/3490)
1358 //
1359 // For simplicity, we either blit all render targets with a Vulkan command, or none.
1360 bool canBlitWithCommand =
1361 !isColorResolve && noClip && (noFlip || !disableFlippingBlitWithCommand) &&
1362 HasSrcBlitFeature(renderer, readRenderTarget) && rotation == SurfaceRotation::Identity;
1363 // If we need to reinterpret the colorspace then the blit must be done through a shader
1364 bool reinterpretsColorspace =
1365 mCurrentFramebufferDesc.getWriteControlMode() != gl::SrgbWriteControlMode::Default;
1366 bool areChannelsBlitCompatible = true;
1367 bool areFormatsIdentical = true;
1368 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1369 {
1370 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
1371 canBlitWithCommand =
1372 canBlitWithCommand && HasDstBlitFeature(renderer, drawRenderTarget);
1373 areChannelsBlitCompatible =
1374 areChannelsBlitCompatible &&
1375 AreSrcAndDstColorChannelsBlitCompatible(readRenderTarget, drawRenderTarget);
1376 areFormatsIdentical = areFormatsIdentical &&
1377 AreSrcAndDstFormatsIdentical(readRenderTarget, drawRenderTarget);
1378 }
1379
1380 // Now that all flipping is done, adjust the offsets for resolve and prerotation
1381 if (isColorResolve)
1382 {
1383 AdjustBlitResolveParametersForResolve(sourceArea, destArea, ¶ms);
1384 }
1385 AdjustBlitResolveParametersForPreRotation(rotation, srcFramebufferRotation, ¶ms);
1386
1387 if (canBlitWithCommand && areChannelsBlitCompatible && !reinterpretsColorspace)
1388 {
1389 // Stash all images that involved with blit so that we can track them all at once.
1390 angle::FixedVector<vk::ImageHelper *, 1 + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS>
1391 accessedImages;
1392 accessedImages.push_back(&readRenderTarget->getImageForCopy());
1393 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1394 {
1395 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
1396 ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget,
1397 drawRenderTarget, filter, true, false, false, flipX,
1398 flipY));
1399 accessedImages.push_back(&drawRenderTarget->getImageForWrite());
1400 }
1401 contextVk->trackImagesWithOutsideRenderPassEvent(accessedImages.data(),
1402 accessedImages.size());
1403 }
1404 // If we're not flipping or rotating, use Vulkan's builtin resolve.
1405 else if (isColorResolve && !flipX && !flipY && areChannelsBlitCompatible &&
1406 areFormatsIdentical && rotation == SurfaceRotation::Identity &&
1407 !reinterpretsColorspace)
1408 {
1409 // Resolving with a subpass resolve attachment has a few restrictions:
1410 // 1.) glBlitFramebuffer() needs to copy the read color attachment to all enabled
1411 // attachments in the draw framebuffer, but Vulkan requires a 1:1 relationship for
1412 // multisample attachments to resolve attachments in the render pass subpass.
1413 // Due to this, we currently only support using resolve attachments when there is a
1414 // single draw attachment enabled.
1415 // 2.) Using a subpass resolve attachment relies on using the render pass that performs
1416 // the draw to still be open, so it can be updated to use the resolve attachment to draw
1417 // into. If there's no render pass with commands, then the multisampled render pass is
1418 // already done and whose data is already flushed from the tile (in a tile-based
1419 // renderer), so there's no chance for the resolve attachment to take advantage of the
1420 // data already being present in the tile.
1421
1422 // glBlitFramebuffer() needs to copy the read color attachment to all enabled
1423 // attachments in the draw framebuffer, but Vulkan requires a 1:1 relationship for
1424 // multisample attachments to resolve attachments in the render pass subpass. Due to
1425 // this, we currently only support using resolve attachments when there is a single draw
1426 // attachment enabled.
1427 //
1428 // Additionally, when resolving with a resolve attachment, the src and destination
1429 // offsets must match, the render area must match the resolve area, and there should be
1430 // no flipping or rotation. Fortunately, in GLES the blit source and destination areas
1431 // are already required to be identical.
1432 ASSERT(params.srcOffset[0] == params.dstOffset[0] &&
1433 params.srcOffset[1] == params.dstOffset[1]);
1434 bool canResolveWithSubpass = mState.getEnabledDrawBuffers().count() == 1 &&
1435 mCurrentFramebufferDesc.getLayerCount() == 1 &&
1436 contextVk->hasStartedRenderPassWithQueueSerial(
1437 srcFramebufferVk->getLastRenderPassQueueSerial());
1438
1439 if (canResolveWithSubpass)
1440 {
1441 const vk::RenderPassCommandBufferHelper &renderPassCommands =
1442 contextVk->getStartedRenderPassCommands();
1443 const vk::RenderPassDesc &renderPassDesc = renderPassCommands.getRenderPassDesc();
1444
1445 // Make sure that:
1446 // - The blit and render areas are identical
1447 // - There is no resolve attachment for the corresponding index already
1448 // Additionally, disable the optimization for a few corner cases that are
1449 // unrealistic and inconvenient.
1450 const uint32_t readColorIndexGL = srcFramebuffer->getState().getReadIndex();
1451 canResolveWithSubpass =
1452 blitArea == renderPassCommands.getRenderArea() &&
1453 !renderPassDesc.hasColorResolveAttachment(readColorIndexGL) &&
1454 AllowAddingResolveAttachmentsToSubpass(renderPassDesc);
1455 }
1456
1457 if (canResolveWithSubpass)
1458 {
1459 ANGLE_TRY(resolveColorWithSubpass(contextVk, params));
1460 }
1461 else
1462 {
1463 ANGLE_TRY(resolveColorWithCommand(contextVk, params,
1464 &readRenderTarget->getImageForCopy()));
1465 }
1466 }
1467 else
1468 {
1469 // Otherwise use a shader to do blit or resolve.
1470
1471 // Flush the render pass, which may incur a vkQueueSubmit, before taking any views.
1472 // Otherwise the view serials would not reflect the render pass they are really used in.
1473 // http://crbug.com/1272266#c22
1474 ANGLE_TRY(
1475 contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::PrepareForBlit));
1476
1477 const vk::ImageView *copyImageView = nullptr;
1478 ANGLE_TRY(readRenderTarget->getCopyImageView(contextVk, ©ImageView));
1479 ANGLE_TRY(utilsVk.colorBlitResolve(
1480 contextVk, this, &readRenderTarget->getImageForCopy(), copyImageView, params));
1481 }
1482 }
1483
1484 if (blitDepthBuffer || blitStencilBuffer)
1485 {
1486 RenderTargetVk *readRenderTarget = srcFramebufferVk->getDepthStencilRenderTarget();
1487 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getDepthStencil();
1488 UtilsVk::BlitResolveParameters params = commonParams;
1489 params.srcLayer = readRenderTarget->getLayerIndex();
1490
1491 // Multisampled images are not allowed to have mips.
1492 ASSERT(!isDepthStencilResolve || readRenderTarget->getLevelIndex() == gl::LevelIndex(0));
1493
1494 // Similarly, only blit if there's been no clipping or rotating.
1495 bool canBlitWithCommand =
1496 !isDepthStencilResolve && noClip && (noFlip || !disableFlippingBlitWithCommand) &&
1497 HasSrcBlitFeature(renderer, readRenderTarget) &&
1498 HasDstBlitFeature(renderer, drawRenderTarget) && rotation == SurfaceRotation::Identity;
1499 bool areChannelsBlitCompatible =
1500 AreSrcAndDstDepthStencilChannelsBlitCompatible(readRenderTarget, drawRenderTarget);
1501
1502 // glBlitFramebuffer requires that depth/stencil blits have matching formats.
1503 ASSERT(AreSrcAndDstFormatsIdentical(readRenderTarget, drawRenderTarget));
1504
1505 if (canBlitWithCommand && areChannelsBlitCompatible)
1506 {
1507 ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget,
1508 drawRenderTarget, filter, false, blitDepthBuffer,
1509 blitStencilBuffer, flipX, flipY));
1510 contextVk->trackImagesWithOutsideRenderPassEvent(&readRenderTarget->getImageForCopy(),
1511 &drawRenderTarget->getImageForWrite());
1512 }
1513 else
1514 {
1515 vk::ImageHelper *depthStencilImage = &readRenderTarget->getImageForCopy();
1516
1517 VkImageAspectFlags resolveAspects = 0;
1518 if (blitDepthBuffer)
1519 {
1520 resolveAspects |= VK_IMAGE_ASPECT_DEPTH_BIT;
1521 }
1522 if (blitStencilBuffer)
1523 {
1524 resolveAspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
1525 }
1526
1527 // See comment on canResolveWithSubpass for the color path.
1528 bool canResolveWithSubpass =
1529 isDepthStencilResolve &&
1530 !renderer->getFeatures().disableDepthStencilResolveThroughAttachment.enabled &&
1531 areChannelsBlitCompatible && mCurrentFramebufferDesc.getLayerCount() == 1 &&
1532 contextVk->hasStartedRenderPassWithQueueSerial(
1533 srcFramebufferVk->getLastRenderPassQueueSerial()) &&
1534 noFlip && rotation == SurfaceRotation::Identity;
1535
1536 if (canResolveWithSubpass)
1537 {
1538 const vk::RenderPassCommandBufferHelper &renderPassCommands =
1539 contextVk->getStartedRenderPassCommands();
1540 const vk::RenderPassDesc &renderPassDesc = renderPassCommands.getRenderPassDesc();
1541
1542 const VkImageAspectFlags depthStencilImageAspects =
1543 depthStencilImage->getAspectFlags();
1544 const bool resolvesAllAspects =
1545 (resolveAspects & depthStencilImageAspects) == depthStencilImageAspects;
1546
1547 // Make sure that:
1548 // - The blit and render areas are identical
1549 // - There is no resolve attachment already
1550 // Additionally, disable the optimization for a few corner cases that are
1551 // unrealistic and inconvenient.
1552 //
1553 // Note: currently, if two separate `glBlitFramebuffer` calls are made for each
1554 // aspect, only the first one is optimized as a resolve attachment. Applications
1555 // should use one `glBlitFramebuffer` call with both aspects if they want to resolve
1556 // both.
1557 canResolveWithSubpass =
1558 blitArea == renderPassCommands.getRenderArea() &&
1559 (resolvesAllAspects ||
1560 renderer->getFeatures().supportsDepthStencilIndependentResolveNone.enabled) &&
1561 !renderPassDesc.hasDepthStencilResolveAttachment() &&
1562 AllowAddingResolveAttachmentsToSubpass(renderPassDesc);
1563 }
1564
1565 if (canResolveWithSubpass)
1566 {
1567 ANGLE_TRY(resolveDepthStencilWithSubpass(contextVk, params, resolveAspects));
1568 }
1569 else
1570 {
1571 // See comment for the draw-based color blit. The render pass must be flushed
1572 // before creating the views.
1573 ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(
1574 RenderPassClosureReason::PrepareForBlit));
1575
1576 // Now that all flipping is done, adjust the offsets for resolve and prerotation
1577 if (isDepthStencilResolve)
1578 {
1579 AdjustBlitResolveParametersForResolve(sourceArea, destArea, ¶ms);
1580 }
1581 AdjustBlitResolveParametersForPreRotation(rotation, srcFramebufferRotation,
1582 ¶ms);
1583
1584 // Create depth- and stencil-only views for reading.
1585 vk::DeviceScoped<vk::ImageView> depthView(contextVk->getDevice());
1586 vk::DeviceScoped<vk::ImageView> stencilView(contextVk->getDevice());
1587
1588 vk::LevelIndex levelIndex =
1589 depthStencilImage->toVkLevel(readRenderTarget->getLevelIndex());
1590 uint32_t layerIndex = readRenderTarget->getLayerIndex();
1591 gl::TextureType textureType = vk::Get2DTextureType(
1592 depthStencilImage->getLayerCount(), depthStencilImage->getSamples());
1593
1594 if (blitDepthBuffer)
1595 {
1596 ANGLE_TRY(depthStencilImage->initLayerImageView(
1597 contextVk, textureType, VK_IMAGE_ASPECT_DEPTH_BIT, gl::SwizzleState(),
1598 &depthView.get(), levelIndex, 1, layerIndex, 1,
1599 gl::SrgbWriteControlMode::Default, gl::YuvSamplingMode::Default,
1600 vk::ImageHelper::kDefaultImageViewUsageFlags));
1601 }
1602
1603 if (blitStencilBuffer)
1604 {
1605 ANGLE_TRY(depthStencilImage->initLayerImageView(
1606 contextVk, textureType, VK_IMAGE_ASPECT_STENCIL_BIT, gl::SwizzleState(),
1607 &stencilView.get(), levelIndex, 1, layerIndex, 1,
1608 gl::SrgbWriteControlMode::Default, gl::YuvSamplingMode::Default,
1609 vk::ImageHelper::kDefaultImageViewUsageFlags));
1610 }
1611
1612 // If shader stencil export is not possible, defer stencil blit/resolve to another
1613 // pass.
1614 const bool hasShaderStencilExport =
1615 renderer->getFeatures().supportsShaderStencilExport.enabled;
1616
1617 // Blit depth. If shader stencil export is present, blit stencil as well.
1618 if (blitDepthBuffer || (blitStencilBuffer && hasShaderStencilExport))
1619 {
1620 const vk::ImageView *depth = blitDepthBuffer ? &depthView.get() : nullptr;
1621 const vk::ImageView *stencil =
1622 blitStencilBuffer && hasShaderStencilExport ? &stencilView.get() : nullptr;
1623
1624 ANGLE_TRY(utilsVk.depthStencilBlitResolve(contextVk, this, depthStencilImage,
1625 depth, stencil, params));
1626 }
1627
1628 // If shader stencil export is not present, blit stencil through a different path.
1629 if (blitStencilBuffer && !hasShaderStencilExport)
1630 {
1631 ANGLE_VK_PERF_WARNING(
1632 contextVk, GL_DEBUG_SEVERITY_LOW,
1633 "Inefficient BlitFramebuffer operation on the stencil aspect "
1634 "due to lack of shader stencil export support");
1635 ANGLE_TRY(utilsVk.stencilBlitResolveNoShaderExport(
1636 contextVk, this, depthStencilImage, &stencilView.get(), params));
1637 }
1638
1639 vk::ImageView depthViewObject = depthView.release();
1640 vk::ImageView stencilViewObject = stencilView.release();
1641
1642 contextVk->addGarbage(&depthViewObject);
1643 contextVk->addGarbage(&stencilViewObject);
1644 }
1645 }
1646 }
1647
1648 return angle::Result::Continue;
1649 }
1650
releaseCurrentFramebuffer(ContextVk * contextVk)1651 void FramebufferVk::releaseCurrentFramebuffer(ContextVk *contextVk)
1652 {
1653 if (mIsCurrentFramebufferCached)
1654 {
1655 mCurrentFramebuffer.release();
1656 }
1657 else
1658 {
1659 contextVk->addGarbage(&mCurrentFramebuffer);
1660 }
1661 }
1662
updateLayerCount()1663 void FramebufferVk::updateLayerCount()
1664 {
1665 uint32_t layerCount = std::numeric_limits<uint32_t>::max();
1666
1667 // Color attachments.
1668 const auto &colorRenderTargets = mRenderTargetCache.getColors();
1669 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
1670 {
1671 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
1672 ASSERT(colorRenderTarget);
1673 layerCount = std::min(layerCount, colorRenderTarget->getLayerCount());
1674 }
1675
1676 // Depth/stencil attachment.
1677 RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
1678 if (depthStencilRenderTarget)
1679 {
1680 layerCount = std::min(layerCount, depthStencilRenderTarget->getLayerCount());
1681 }
1682
1683 if (layerCount == std::numeric_limits<uint32_t>::max())
1684 {
1685 layerCount = mState.getDefaultLayers();
1686 }
1687
1688 // While layer count and view count are mutually exclusive, they result in different render
1689 // passes (and thus framebuffers). For multiview, layer count is set to view count and a flag
1690 // signifies that the framebuffer is multiview (as opposed to layered).
1691 const bool isMultiview = mState.isMultiview();
1692 if (isMultiview)
1693 {
1694 layerCount = mState.getNumViews();
1695 }
1696
1697 mCurrentFramebufferDesc.updateLayerCount(layerCount);
1698 mCurrentFramebufferDesc.updateIsMultiview(isMultiview);
1699 }
1700
ensureFragmentShadingRateImageAndViewInitialized(ContextVk * contextVk,const uint32_t fragmentShadingRateAttachmentWidth,const uint32_t fragmentShadingRateAttachmentHeight)1701 angle::Result FramebufferVk::ensureFragmentShadingRateImageAndViewInitialized(
1702 ContextVk *contextVk,
1703 const uint32_t fragmentShadingRateAttachmentWidth,
1704 const uint32_t fragmentShadingRateAttachmentHeight)
1705 {
1706 vk::Renderer *renderer = contextVk->getRenderer();
1707
1708 // Release current valid image iff attachment extents need to change.
1709 if (mFragmentShadingRateImage.valid() &&
1710 (mFragmentShadingRateImage.getExtents().width != fragmentShadingRateAttachmentWidth ||
1711 mFragmentShadingRateImage.getExtents().height != fragmentShadingRateAttachmentHeight))
1712 {
1713 mFragmentShadingRateImageView.release(renderer, mFragmentShadingRateImage.getResourceUse());
1714 mFragmentShadingRateImage.releaseImage(renderer);
1715 }
1716
1717 if (!mFragmentShadingRateImage.valid())
1718 {
1719 ANGLE_TRY(mFragmentShadingRateImage.init(
1720 contextVk, gl::TextureType::_2D,
1721 VkExtent3D{fragmentShadingRateAttachmentWidth, fragmentShadingRateAttachmentHeight, 1},
1722 renderer->getFormat(angle::FormatID::R8_UINT), 1,
1723 VK_IMAGE_USAGE_FRAGMENT_SHADING_RATE_ATTACHMENT_BIT_KHR |
1724 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
1725 gl::LevelIndex(0), 1, 1, false,
1726 contextVk->getProtectionType() == vk::ProtectionType::Protected));
1727 ANGLE_TRY(contextVk->initImageAllocation(
1728 &mFragmentShadingRateImage, false, renderer->getMemoryProperties(),
1729 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vk::MemoryAllocationType::TextureImage));
1730
1731 mFragmentShadingRateImageView.init(renderer);
1732 ANGLE_TRY(mFragmentShadingRateImageView.initFragmentShadingRateView(
1733 contextVk, &mFragmentShadingRateImage));
1734 }
1735
1736 return angle::Result::Continue;
1737 }
1738
generateFragmentShadingRateWithCPU(ContextVk * contextVk,const bool isGainZero,const uint32_t fragmentShadingRateWidth,const uint32_t fragmentShadingRateHeight,const uint32_t fragmentShadingRateBlockWidth,const uint32_t fragmentShadingRateBlockHeight,const uint32_t foveatedAttachmentWidth,const uint32_t foveatedAttachmentHeight,const std::vector<gl::FocalPoint> & activeFocalPoints)1739 angle::Result FramebufferVk::generateFragmentShadingRateWithCPU(
1740 ContextVk *contextVk,
1741 const bool isGainZero,
1742 const uint32_t fragmentShadingRateWidth,
1743 const uint32_t fragmentShadingRateHeight,
1744 const uint32_t fragmentShadingRateBlockWidth,
1745 const uint32_t fragmentShadingRateBlockHeight,
1746 const uint32_t foveatedAttachmentWidth,
1747 const uint32_t foveatedAttachmentHeight,
1748 const std::vector<gl::FocalPoint> &activeFocalPoints)
1749 {
1750 // Fill in image with fragment shading rate data
1751 size_t bufferSize = fragmentShadingRateWidth * fragmentShadingRateHeight;
1752 VkBufferCreateInfo bufferCreateInfo = {};
1753 bufferCreateInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
1754 bufferCreateInfo.size = bufferSize;
1755 bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
1756 bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1757 vk::RendererScoped<vk::BufferHelper> stagingBuffer(contextVk->getRenderer());
1758 vk::BufferHelper *buffer = &stagingBuffer.get();
1759 ANGLE_TRY(buffer->init(contextVk, bufferCreateInfo, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT));
1760 uint8_t *mappedBuffer;
1761 ANGLE_TRY(buffer->map(contextVk, &mappedBuffer));
1762 uint8_t val = 0;
1763 memset(mappedBuffer, 0, bufferSize);
1764 if (!isGainZero)
1765 {
1766 // The spec requires min_pixel_density to be computed thusly -
1767 //
1768 // min_pixel_density=0.;
1769 // for(int i=0;i<focalPointsPerLayer;++i)
1770 // {
1771 // focal_point_density = 1./max((focalX[i]-px)^2*gainX[i]^2+
1772 // (focalY[i]-py)^2*gainY[i]^2-foveaArea[i],1.);
1773 //
1774 // min_pixel_density=max(min_pixel_density,focal_point_density);
1775 // }
1776 float minPixelDensity = 0.0f;
1777 float focalPointDensity = 0.0f;
1778 for (uint32_t y = 0; y < fragmentShadingRateHeight; y++)
1779 {
1780 for (uint32_t x = 0; x < fragmentShadingRateWidth; x++)
1781 {
1782 minPixelDensity = 0.0f;
1783 float px = (static_cast<float>(x) * fragmentShadingRateBlockWidth /
1784 foveatedAttachmentWidth -
1785 0.5f) *
1786 2.0f;
1787 float py = (static_cast<float>(y) * fragmentShadingRateBlockHeight /
1788 foveatedAttachmentHeight -
1789 0.5f) *
1790 2.0f;
1791 focalPointDensity = 0.0f;
1792 for (uint32_t point = 0; point < activeFocalPoints.size(); point++)
1793 {
1794 float density =
1795 1.0f / std::max(std::pow(activeFocalPoints[point].focalX - px, 2.0f) *
1796 std::pow(activeFocalPoints[point].gainX, 2.0f) +
1797 std::pow(activeFocalPoints[point].focalY - py, 2.0f) *
1798 std::pow(activeFocalPoints[point].gainY, 2.0f) -
1799 activeFocalPoints[point].foveaArea,
1800 1.0f);
1801
1802 // When focal points are overlapping choose the highest quality of all
1803 if (density > focalPointDensity)
1804 {
1805 focalPointDensity = density;
1806 }
1807 }
1808 minPixelDensity = std::max(minPixelDensity, focalPointDensity);
1809
1810 // https://docs.vulkan.org/spec/latest/chapters/primsrast.html#primsrast-fragment-shading-rate-attachment
1811 //
1812 // w = 2^((texel/4) & 3)
1813 // h = 2^(texel & 3)
1814 // `texel` would then be => log2(w) << 2 | log2(h).
1815 //
1816 // 1) The supported shading rates are - 1x1, 1x2, 2x1, 2x2
1817 // 2) log2(1) == 0, log2(2) == 1
1818 if (minPixelDensity > 0.75f)
1819 {
1820 // Use shading rate 1x1
1821 val = 0;
1822 }
1823 else if (minPixelDensity > 0.5f)
1824 {
1825 // Use shading rate 2x1
1826 val = (1 << 2);
1827 }
1828 else
1829 {
1830 // Use shading rate 2x2
1831 val = (1 << 2) | 1;
1832 }
1833 mappedBuffer[y * fragmentShadingRateWidth + x] = val;
1834 }
1835 }
1836 }
1837 ANGLE_TRY(buffer->flush(contextVk->getRenderer(), 0, buffer->getSize()));
1838 buffer->unmap(contextVk->getRenderer());
1839 // copy data from staging buffer to image
1840 vk::CommandBufferAccess access;
1841 access.onBufferTransferRead(buffer);
1842 access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
1843 &mFragmentShadingRateImage);
1844 vk::OutsideRenderPassCommandBuffer *dataUpload;
1845 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &dataUpload));
1846 VkBufferImageCopy copy = {};
1847 copy.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1848 copy.imageSubresource.layerCount = 1;
1849 copy.imageExtent.depth = 1;
1850 copy.imageExtent.width = fragmentShadingRateWidth;
1851 copy.imageExtent.height = fragmentShadingRateHeight;
1852 dataUpload->copyBufferToImage(buffer->getBuffer().getHandle(),
1853 mFragmentShadingRateImage.getImage(),
1854 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ©);
1855
1856 contextVk->trackImageWithOutsideRenderPassEvent(&mFragmentShadingRateImage);
1857
1858 return angle::Result::Continue;
1859 }
1860
updateFragmentShadingRateAttachment(ContextVk * contextVk,const gl::FoveationState & foveationState,const gl::Extents & foveatedAttachmentSize)1861 angle::Result FramebufferVk::updateFragmentShadingRateAttachment(
1862 ContextVk *contextVk,
1863 const gl::FoveationState &foveationState,
1864 const gl::Extents &foveatedAttachmentSize)
1865 {
1866 const VkExtent2D fragmentShadingRateExtent =
1867 contextVk->getRenderer()->getMaxFragmentShadingRateAttachmentTexelSize();
1868 const uint32_t fragmentShadingRateBlockWidth = fragmentShadingRateExtent.width;
1869 const uint32_t fragmentShadingRateBlockHeight = fragmentShadingRateExtent.height;
1870 const uint32_t foveatedAttachmentWidth = foveatedAttachmentSize.width;
1871 const uint32_t foveatedAttachmentHeight = foveatedAttachmentSize.height;
1872 const uint32_t fragmentShadingRateWidth =
1873 UnsignedCeilDivide(foveatedAttachmentWidth, fragmentShadingRateBlockWidth);
1874 const uint32_t fragmentShadingRateHeight =
1875 UnsignedCeilDivide(foveatedAttachmentHeight, fragmentShadingRateBlockHeight);
1876
1877 ANGLE_TRY(ensureFragmentShadingRateImageAndViewInitialized(contextVk, fragmentShadingRateWidth,
1878 fragmentShadingRateHeight));
1879 ASSERT(mFragmentShadingRateImage.valid());
1880
1881 bool isGainZero = true;
1882 std::vector<gl::FocalPoint> activeFocalPoints;
1883 for (uint32_t point = 0; point < gl::IMPLEMENTATION_MAX_FOCAL_POINTS; point++)
1884 {
1885 const gl::FocalPoint &focalPoint = foveationState.getFocalPoint(0, point);
1886 if (focalPoint != gl::kInvalidFocalPoint)
1887 {
1888 isGainZero = isGainZero && focalPoint.gainX == 0 && focalPoint.gainY == 0;
1889 activeFocalPoints.push_back(focalPoint);
1890 }
1891 }
1892
1893 return generateFragmentShadingRateWithCPU(
1894 contextVk, isGainZero, fragmentShadingRateWidth, fragmentShadingRateHeight,
1895 fragmentShadingRateBlockWidth, fragmentShadingRateBlockHeight, foveatedAttachmentWidth,
1896 foveatedAttachmentHeight, activeFocalPoints);
1897 }
1898
updateFoveationState(ContextVk * contextVk,const gl::FoveationState & newFoveationState,const gl::Extents & foveatedAttachmentSize)1899 angle::Result FramebufferVk::updateFoveationState(ContextVk *contextVk,
1900 const gl::FoveationState &newFoveationState,
1901 const gl::Extents &foveatedAttachmentSize)
1902 {
1903 const bool isFoveationEnabled = newFoveationState.isFoveated();
1904 vk::ImageOrBufferViewSubresourceSerial serial = vk::kInvalidImageOrBufferViewSubresourceSerial;
1905 if (isFoveationEnabled)
1906 {
1907 ANGLE_TRY(updateFragmentShadingRateAttachment(contextVk, newFoveationState,
1908 foveatedAttachmentSize));
1909 ASSERT(mFragmentShadingRateImage.valid());
1910
1911 serial = mFragmentShadingRateImageView.getSubresourceSerial(
1912 gl::LevelIndex(0), 1, 0, vk::LayerMode::All, vk::SrgbDecodeMode::SkipDecode,
1913 gl::SrgbOverride::Default);
1914 }
1915
1916 // Update state after the possible failure point.
1917 mFoveationState = newFoveationState;
1918 mCurrentFramebufferDesc.updateFragmentShadingRate(serial);
1919 // mRenderPassDesc will be updated later in updateRenderPassDesc() in case if
1920 // mCurrentFramebufferDesc was changed.
1921 return angle::Result::Continue;
1922 }
1923
resolveColorWithSubpass(ContextVk * contextVk,const UtilsVk::BlitResolveParameters & params)1924 angle::Result FramebufferVk::resolveColorWithSubpass(ContextVk *contextVk,
1925 const UtilsVk::BlitResolveParameters ¶ms)
1926 {
1927 // Vulkan requires a 1:1 relationship for multisample attachments to resolve attachments in the
1928 // render pass subpass. Due to this, we currently only support using resolve attachments when
1929 // there is a single draw attachment enabled.
1930 ASSERT(mState.getEnabledDrawBuffers().count() == 1);
1931 uint32_t drawColorIndexGL = static_cast<uint32_t>(*mState.getEnabledDrawBuffers().begin());
1932 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[drawColorIndexGL];
1933 const vk::ImageView *resolveImageView = nullptr;
1934 ANGLE_TRY(drawRenderTarget->getImageView(contextVk, &resolveImageView));
1935
1936 const gl::Framebuffer *srcFramebuffer = contextVk->getState().getReadFramebuffer();
1937 uint32_t readColorIndexGL = srcFramebuffer->getState().getReadIndex();
1938
1939 vk::RenderPassCommandBufferHelper &renderPassCommands =
1940 contextVk->getStartedRenderPassCommands();
1941 ASSERT(!renderPassCommands.getRenderPassDesc().hasColorResolveAttachment(readColorIndexGL));
1942
1943 renderPassCommands.addColorResolveAttachment(readColorIndexGL, resolveImageView->getHandle());
1944 drawRenderTarget->onColorResolve(contextVk, mCurrentFramebufferDesc.getLayerCount());
1945
1946 // The render pass is already closed because of the change in the draw buffer. Just don't let
1947 // it reactivate now that it has a resolve attachment.
1948 contextVk->disableRenderPassReactivation();
1949
1950 return angle::Result::Continue;
1951 }
1952
resolveDepthStencilWithSubpass(ContextVk * contextVk,const UtilsVk::BlitResolveParameters & params,VkImageAspectFlags aspects)1953 angle::Result FramebufferVk::resolveDepthStencilWithSubpass(
1954 ContextVk *contextVk,
1955 const UtilsVk::BlitResolveParameters ¶ms,
1956 VkImageAspectFlags aspects)
1957 {
1958 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getDepthStencil();
1959 const vk::ImageView *resolveImageView = nullptr;
1960 ANGLE_TRY(drawRenderTarget->getImageView(contextVk, &resolveImageView));
1961
1962 vk::RenderPassCommandBufferHelper &renderPassCommands =
1963 contextVk->getStartedRenderPassCommands();
1964 ASSERT(!renderPassCommands.getRenderPassDesc().hasDepthStencilResolveAttachment());
1965
1966 renderPassCommands.addDepthStencilResolveAttachment(resolveImageView->getHandle(), aspects);
1967 drawRenderTarget->onDepthStencilResolve(contextVk, mCurrentFramebufferDesc.getLayerCount());
1968
1969 // The render pass is already closed because of the change in the draw buffer. Just don't let
1970 // it reactivate now that it has a resolve attachment.
1971 contextVk->disableRenderPassReactivation();
1972
1973 return angle::Result::Continue;
1974 }
1975
resolveColorWithCommand(ContextVk * contextVk,const UtilsVk::BlitResolveParameters & params,vk::ImageHelper * srcImage)1976 angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
1977 const UtilsVk::BlitResolveParameters ¶ms,
1978 vk::ImageHelper *srcImage)
1979 {
1980 vk::CommandBufferAccess access;
1981 access.onImageTransferRead(VK_IMAGE_ASPECT_COLOR_BIT, srcImage);
1982
1983 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1984 {
1985 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
1986 vk::ImageHelper &dstImage = drawRenderTarget->getImageForWrite();
1987
1988 access.onImageTransferWrite(drawRenderTarget->getLevelIndex(), 1,
1989 drawRenderTarget->getLayerIndex(), 1, VK_IMAGE_ASPECT_COLOR_BIT,
1990 &dstImage);
1991 }
1992
1993 vk::OutsideRenderPassCommandBuffer *commandBuffer;
1994 ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1995
1996 VkImageResolve resolveRegion = {};
1997 resolveRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
1998 resolveRegion.srcSubresource.mipLevel = 0;
1999 resolveRegion.srcSubresource.baseArrayLayer = params.srcLayer;
2000 resolveRegion.srcSubresource.layerCount = 1;
2001 resolveRegion.srcOffset.x = params.blitArea.x;
2002 resolveRegion.srcOffset.y = params.blitArea.y;
2003 resolveRegion.srcOffset.z = 0;
2004 resolveRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
2005 resolveRegion.dstSubresource.layerCount = 1;
2006 resolveRegion.dstOffset.x = params.blitArea.x;
2007 resolveRegion.dstOffset.y = params.blitArea.y;
2008 resolveRegion.dstOffset.z = 0;
2009 resolveRegion.extent.width = params.blitArea.width;
2010 resolveRegion.extent.height = params.blitArea.height;
2011 resolveRegion.extent.depth = 1;
2012
2013 angle::VulkanPerfCounters &perfCounters = contextVk->getPerfCounters();
2014 angle::FixedVector<vk::ImageHelperPtr, 1 + gl::IMPLEMENTATION_MAX_DRAW_BUFFERS> accessedImages;
2015 accessedImages.push_back(srcImage);
2016 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
2017 {
2018 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
2019 vk::ImageHelper &dstImage = drawRenderTarget->getImageForWrite();
2020
2021 vk::LevelIndex levelVk = dstImage.toVkLevel(drawRenderTarget->getLevelIndex());
2022 resolveRegion.dstSubresource.mipLevel = levelVk.get();
2023 resolveRegion.dstSubresource.baseArrayLayer = drawRenderTarget->getLayerIndex();
2024
2025 srcImage->resolve(&dstImage, resolveRegion, commandBuffer);
2026
2027 perfCounters.resolveImageCommands++;
2028 accessedImages.push_back(&dstImage);
2029 }
2030 contextVk->trackImagesWithOutsideRenderPassEvent(accessedImages.data(), accessedImages.size());
2031
2032 return angle::Result::Continue;
2033 }
2034
checkStatus(const gl::Context * context) const2035 gl::FramebufferStatus FramebufferVk::checkStatus(const gl::Context *context) const
2036 {
2037 // if we have both a depth and stencil buffer, they must refer to the same object
2038 // since we only support packed_depth_stencil and not separate depth and stencil
2039 if (mState.hasSeparateDepthAndStencilAttachments())
2040 {
2041 return gl::FramebufferStatus::Incomplete(
2042 GL_FRAMEBUFFER_UNSUPPORTED,
2043 gl::err::kFramebufferIncompleteUnsupportedSeparateDepthStencilBuffers);
2044 }
2045
2046 return gl::FramebufferStatus::Complete();
2047 }
2048
invalidateImpl(ContextVk * contextVk,size_t count,const GLenum * attachments,bool isSubInvalidate,const gl::Rectangle & invalidateArea)2049 angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
2050 size_t count,
2051 const GLenum *attachments,
2052 bool isSubInvalidate,
2053 const gl::Rectangle &invalidateArea)
2054 {
2055 gl::DrawBufferMask invalidateColorBuffers;
2056 bool invalidateDepthBuffer = false;
2057 bool invalidateStencilBuffer = false;
2058
2059 for (size_t i = 0; i < count; ++i)
2060 {
2061 const GLenum attachment = attachments[i];
2062
2063 switch (attachment)
2064 {
2065 case GL_DEPTH:
2066 case GL_DEPTH_ATTACHMENT:
2067 invalidateDepthBuffer = true;
2068 break;
2069 case GL_STENCIL:
2070 case GL_STENCIL_ATTACHMENT:
2071 invalidateStencilBuffer = true;
2072 break;
2073 case GL_DEPTH_STENCIL_ATTACHMENT:
2074 invalidateDepthBuffer = true;
2075 invalidateStencilBuffer = true;
2076 break;
2077 default:
2078 ASSERT(
2079 (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) ||
2080 (attachment == GL_COLOR));
2081
2082 invalidateColorBuffers.set(
2083 attachment == GL_COLOR ? 0u : (attachment - GL_COLOR_ATTACHMENT0));
2084 }
2085 }
2086
2087 // Shouldn't try to issue deferred clears if invalidating sub framebuffer.
2088 ASSERT(mDeferredClears.empty() || !isSubInvalidate);
2089
2090 // Remove deferred clears for the invalidated attachments.
2091 if (invalidateDepthBuffer)
2092 {
2093 mDeferredClears.reset(vk::kUnpackedDepthIndex);
2094 }
2095 if (invalidateStencilBuffer)
2096 {
2097 mDeferredClears.reset(vk::kUnpackedStencilIndex);
2098 }
2099 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
2100 {
2101 if (invalidateColorBuffers.test(colorIndexGL))
2102 {
2103 mDeferredClears.reset(colorIndexGL);
2104 }
2105 }
2106
2107 // If there are still deferred clears, restage them. See relevant comment in invalidateSub.
2108 restageDeferredClears(contextVk);
2109
2110 const auto &colorRenderTargets = mRenderTargetCache.getColors();
2111 RenderTargetVk *depthStencilRenderTarget = mRenderTargetCache.getDepthStencil();
2112
2113 // If not a partial invalidate, mark the contents of the invalidated attachments as undefined,
2114 // so their loadOp can be set to DONT_CARE in the following render pass.
2115 if (!isSubInvalidate)
2116 {
2117 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
2118 {
2119 if (invalidateColorBuffers.test(colorIndexGL))
2120 {
2121 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
2122 ASSERT(colorRenderTarget);
2123
2124 bool preferToKeepContentsDefined = false;
2125 colorRenderTarget->invalidateEntireContent(contextVk, &preferToKeepContentsDefined);
2126 if (preferToKeepContentsDefined)
2127 {
2128 invalidateColorBuffers.reset(colorIndexGL);
2129 }
2130 }
2131 }
2132
2133 // If we have a depth / stencil render target, invalidate its aspects.
2134 if (depthStencilRenderTarget)
2135 {
2136 if (invalidateDepthBuffer)
2137 {
2138 bool preferToKeepContentsDefined = false;
2139 depthStencilRenderTarget->invalidateEntireContent(contextVk,
2140 &preferToKeepContentsDefined);
2141 if (preferToKeepContentsDefined)
2142 {
2143 invalidateDepthBuffer = false;
2144 }
2145 }
2146 if (invalidateStencilBuffer)
2147 {
2148 bool preferToKeepContentsDefined = false;
2149 depthStencilRenderTarget->invalidateEntireStencilContent(
2150 contextVk, &preferToKeepContentsDefined);
2151 if (preferToKeepContentsDefined)
2152 {
2153 invalidateStencilBuffer = false;
2154 }
2155 }
2156 }
2157 }
2158
2159 // To ensure we invalidate the right renderpass we require that the current framebuffer be the
2160 // same as the current renderpass' framebuffer. E.g. prevent sequence like:
2161 //- Bind FBO 1, draw
2162 //- Bind FBO 2, draw
2163 //- Bind FBO 1, invalidate D/S
2164 // to invalidate the D/S of FBO 2 since it would be the currently active renderpass.
2165 if (contextVk->hasStartedRenderPassWithQueueSerial(mLastRenderPassQueueSerial))
2166 {
2167 // Mark the invalidated attachments in the render pass for loadOp and storeOp determination
2168 // at its end.
2169 vk::PackedAttachmentIndex colorIndexVk(0);
2170 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
2171 {
2172 if (mState.getEnabledDrawBuffers()[colorIndexGL] &&
2173 invalidateColorBuffers.test(colorIndexGL))
2174 {
2175 contextVk->getStartedRenderPassCommands().invalidateRenderPassColorAttachment(
2176 contextVk->getState(), colorIndexGL, colorIndexVk, invalidateArea);
2177 }
2178 ++colorIndexVk;
2179 }
2180
2181 if (depthStencilRenderTarget)
2182 {
2183 const gl::DepthStencilState &dsState = contextVk->getState().getDepthStencilState();
2184 if (invalidateDepthBuffer)
2185 {
2186 contextVk->getStartedRenderPassCommands().invalidateRenderPassDepthAttachment(
2187 dsState, invalidateArea);
2188 }
2189
2190 if (invalidateStencilBuffer)
2191 {
2192 contextVk->getStartedRenderPassCommands().invalidateRenderPassStencilAttachment(
2193 dsState, invalidateArea);
2194 }
2195 }
2196 }
2197
2198 return angle::Result::Continue;
2199 }
2200
updateColorAttachment(const gl::Context * context,uint32_t colorIndexGL)2201 angle::Result FramebufferVk::updateColorAttachment(const gl::Context *context,
2202 uint32_t colorIndexGL)
2203 {
2204 ANGLE_TRY(mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL));
2205
2206 // Update cached masks for masked clears.
2207 RenderTargetVk *renderTarget = mRenderTargetCache.getColors()[colorIndexGL];
2208 if (renderTarget)
2209 {
2210 const angle::Format &actualFormat = renderTarget->getImageActualFormat();
2211 updateActiveColorMasks(colorIndexGL, actualFormat.redBits > 0, actualFormat.greenBits > 0,
2212 actualFormat.blueBits > 0, actualFormat.alphaBits > 0);
2213
2214 const angle::Format &intendedFormat = renderTarget->getImageIntendedFormat();
2215 mEmulatedAlphaAttachmentMask.set(
2216 colorIndexGL, intendedFormat.alphaBits == 0 && actualFormat.alphaBits > 0);
2217 }
2218 else
2219 {
2220 updateActiveColorMasks(colorIndexGL, false, false, false, false);
2221 }
2222
2223 const bool enabledColor =
2224 renderTarget && mState.getColorAttachments()[colorIndexGL].isAttached();
2225 const bool enabledResolve = enabledColor && renderTarget->hasResolveAttachment();
2226
2227 if (enabledColor)
2228 {
2229 mCurrentFramebufferDesc.updateColor(colorIndexGL, renderTarget->getDrawSubresourceSerial());
2230 const bool isExternalImage =
2231 mState.getColorAttachments()[colorIndexGL].isExternalImageWithoutIndividualSync();
2232 mIsExternalColorAttachments.set(colorIndexGL, isExternalImage);
2233 mAttachmentHasFrontBufferUsage.set(
2234 colorIndexGL, mState.getColorAttachments()[colorIndexGL].hasFrontBufferUsage());
2235 }
2236 else
2237 {
2238 mCurrentFramebufferDesc.updateColor(colorIndexGL,
2239 vk::kInvalidImageOrBufferViewSubresourceSerial);
2240 }
2241
2242 if (enabledResolve)
2243 {
2244 mCurrentFramebufferDesc.updateColorResolve(colorIndexGL,
2245 renderTarget->getResolveSubresourceSerial());
2246 }
2247 else
2248 {
2249 mCurrentFramebufferDesc.updateColorResolve(colorIndexGL,
2250 vk::kInvalidImageOrBufferViewSubresourceSerial);
2251 }
2252
2253 return angle::Result::Continue;
2254 }
2255
updateDepthStencilAttachment(const gl::Context * context)2256 angle::Result FramebufferVk::updateDepthStencilAttachment(const gl::Context *context)
2257 {
2258 ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState));
2259
2260 ContextVk *contextVk = vk::GetImpl(context);
2261 updateDepthStencilAttachmentSerial(contextVk);
2262
2263 return angle::Result::Continue;
2264 }
2265
updateDepthStencilAttachmentSerial(ContextVk * contextVk)2266 void FramebufferVk::updateDepthStencilAttachmentSerial(ContextVk *contextVk)
2267 {
2268 RenderTargetVk *depthStencilRT = getDepthStencilRenderTarget();
2269
2270 if (depthStencilRT != nullptr)
2271 {
2272 mCurrentFramebufferDesc.updateDepthStencil(depthStencilRT->getDrawSubresourceSerial());
2273 }
2274 else
2275 {
2276 mCurrentFramebufferDesc.updateDepthStencil(vk::kInvalidImageOrBufferViewSubresourceSerial);
2277 }
2278
2279 if (depthStencilRT != nullptr && depthStencilRT->hasResolveAttachment())
2280 {
2281 mCurrentFramebufferDesc.updateDepthStencilResolve(
2282 depthStencilRT->getResolveSubresourceSerial());
2283 }
2284 else
2285 {
2286 mCurrentFramebufferDesc.updateDepthStencilResolve(
2287 vk::kInvalidImageOrBufferViewSubresourceSerial);
2288 }
2289 }
2290
flushColorAttachmentUpdates(const gl::Context * context,bool deferClears,uint32_t colorIndexGL)2291 angle::Result FramebufferVk::flushColorAttachmentUpdates(const gl::Context *context,
2292 bool deferClears,
2293 uint32_t colorIndexGL)
2294 {
2295 ContextVk *contextVk = vk::GetImpl(context);
2296 RenderTargetVk *readRenderTarget = nullptr;
2297 RenderTargetVk *drawRenderTarget = nullptr;
2298
2299 // It's possible for the read and draw color attachments to be different if different surfaces
2300 // are bound, so we need to flush any staged updates to both.
2301
2302 // Draw
2303 drawRenderTarget = mRenderTargetCache.getColorDraw(mState, colorIndexGL);
2304 if (drawRenderTarget)
2305 {
2306 if (deferClears)
2307 {
2308 ANGLE_TRY(
2309 drawRenderTarget->flushStagedUpdates(contextVk, &mDeferredClears, colorIndexGL,
2310 mCurrentFramebufferDesc.getLayerCount()));
2311 }
2312 else
2313 {
2314 ANGLE_TRY(drawRenderTarget->flushStagedUpdates(
2315 contextVk, nullptr, 0, mCurrentFramebufferDesc.getLayerCount()));
2316 }
2317 }
2318
2319 // Read
2320 if (mState.getReadBufferState() != GL_NONE && mState.getReadIndex() == colorIndexGL)
2321 {
2322 // Flush staged updates to the read render target as well, but only if it's not the same as
2323 // the draw render target. This can happen when the read render target is bound to another
2324 // surface.
2325 readRenderTarget = mRenderTargetCache.getColorRead(mState);
2326 if (readRenderTarget && readRenderTarget != drawRenderTarget)
2327 {
2328 ANGLE_TRY(readRenderTarget->flushStagedUpdates(
2329 contextVk, nullptr, 0, mCurrentFramebufferDesc.getLayerCount()));
2330 }
2331 }
2332
2333 return angle::Result::Continue;
2334 }
2335
flushDepthStencilAttachmentUpdates(const gl::Context * context,bool deferClears)2336 angle::Result FramebufferVk::flushDepthStencilAttachmentUpdates(const gl::Context *context,
2337 bool deferClears)
2338 {
2339 ContextVk *contextVk = vk::GetImpl(context);
2340
2341 RenderTargetVk *depthStencilRT = getDepthStencilRenderTarget();
2342 if (depthStencilRT == nullptr)
2343 {
2344 return angle::Result::Continue;
2345 }
2346
2347 if (deferClears)
2348 {
2349 return depthStencilRT->flushStagedUpdates(contextVk, &mDeferredClears,
2350 vk::kUnpackedDepthIndex,
2351 mCurrentFramebufferDesc.getLayerCount());
2352 }
2353
2354 return depthStencilRT->flushStagedUpdates(contextVk, nullptr, 0,
2355 mCurrentFramebufferDesc.getLayerCount());
2356 }
2357
syncState(const gl::Context * context,GLenum binding,const gl::Framebuffer::DirtyBits & dirtyBits,gl::Command command)2358 angle::Result FramebufferVk::syncState(const gl::Context *context,
2359 GLenum binding,
2360 const gl::Framebuffer::DirtyBits &dirtyBits,
2361 gl::Command command)
2362 {
2363 ContextVk *contextVk = vk::GetImpl(context);
2364
2365 vk::FramebufferDesc priorFramebufferDesc = mCurrentFramebufferDesc;
2366
2367 // Keep track of which attachments have dirty content and need their staged updates flushed.
2368 // The respective functions depend on |mCurrentFramebufferDesc::mLayerCount| which is updated
2369 // after all attachment render targets are updated.
2370 gl::DrawBufferMask dirtyColorAttachments;
2371 bool dirtyDepthStencilAttachment = false;
2372
2373 bool shouldUpdateColorMaskAndBlend = false;
2374 bool shouldUpdateLayerCount = false;
2375 bool shouldUpdateSrgbWriteControlMode = false;
2376
2377 // Cache new foveation state, if any
2378 const gl::FoveationState *newFoveationState = nullptr;
2379 gl::Extents foveatedAttachmentSize;
2380
2381 // For any updated attachments we'll update their Serials below
2382 ASSERT(dirtyBits.any());
2383 for (size_t dirtyBit : dirtyBits)
2384 {
2385 switch (dirtyBit)
2386 {
2387 case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
2388 case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS:
2389 case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
2390 case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS:
2391 ANGLE_TRY(updateDepthStencilAttachment(context));
2392 shouldUpdateLayerCount = true;
2393 dirtyDepthStencilAttachment = true;
2394 break;
2395 case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
2396 ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
2397 break;
2398 case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
2399 shouldUpdateColorMaskAndBlend = true;
2400 shouldUpdateLayerCount = true;
2401 break;
2402 case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
2403 case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
2404 case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
2405 case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
2406 // Invalidate the cache. If we have performance critical code hitting this path we
2407 // can add related data (such as width/height) to the cache
2408 releaseCurrentFramebuffer(contextVk);
2409 break;
2410 case gl::Framebuffer::DIRTY_BIT_FRAMEBUFFER_SRGB_WRITE_CONTROL_MODE:
2411 shouldUpdateSrgbWriteControlMode = true;
2412 break;
2413 case gl::Framebuffer::DIRTY_BIT_DEFAULT_LAYERS:
2414 shouldUpdateLayerCount = true;
2415 break;
2416 case gl::Framebuffer::DIRTY_BIT_FOVEATION:
2417 // This dirty bit is set iff the framebuffer itself is foveated
2418 ASSERT(mState.isFoveationEnabled());
2419
2420 newFoveationState = &mState.getFoveationState();
2421 foveatedAttachmentSize = mState.getExtents();
2422 break;
2423 default:
2424 {
2425 static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
2426 uint32_t colorIndexGL;
2427 if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
2428 {
2429 colorIndexGL = static_cast<uint32_t>(
2430 dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
2431 }
2432 else
2433 {
2434 ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 &&
2435 dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX);
2436 colorIndexGL = static_cast<uint32_t>(
2437 dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
2438 }
2439
2440 ANGLE_TRY(updateColorAttachment(context, colorIndexGL));
2441
2442 // Check if attachment has foveated rendering, if so grab foveation state
2443 const gl::FramebufferAttachment *attachment =
2444 mState.getColorAttachment(colorIndexGL);
2445 if (attachment && attachment->hasFoveatedRendering())
2446 {
2447 // If attachment is foveated the framebuffer must not be.
2448 ASSERT(!mState.isFoveationEnabled());
2449
2450 newFoveationState = attachment->getFoveationState();
2451 ASSERT(newFoveationState != nullptr);
2452
2453 foveatedAttachmentSize = attachment->getSize();
2454 }
2455
2456 // Window system framebuffer only have one color attachment and its property should
2457 // never change unless via DIRTY_BIT_DRAW_BUFFERS bit.
2458 if (!mState.isDefault())
2459 {
2460 shouldUpdateColorMaskAndBlend = true;
2461 shouldUpdateLayerCount = true;
2462 }
2463 dirtyColorAttachments.set(colorIndexGL);
2464
2465 break;
2466 }
2467 }
2468 }
2469
2470 if (shouldUpdateSrgbWriteControlMode)
2471 {
2472 // Framebuffer colorspace state has been modified, so refresh the current framebuffer
2473 // descriptor to reflect the new state.
2474 gl::SrgbWriteControlMode newSrgbWriteControlMode = mState.getWriteControlMode();
2475 mCurrentFramebufferDesc.setWriteControlMode(newSrgbWriteControlMode);
2476 // mRenderPassDesc will be updated later in updateRenderPassDesc() in case if
2477 // mCurrentFramebufferDesc was changed.
2478 }
2479
2480 if (shouldUpdateColorMaskAndBlend)
2481 {
2482 contextVk->updateColorMasks();
2483 contextVk->updateBlendFuncsAndEquations();
2484 }
2485
2486 if (shouldUpdateLayerCount)
2487 {
2488 updateLayerCount();
2489 }
2490
2491 if (newFoveationState && mFoveationState != *newFoveationState)
2492 {
2493 ANGLE_TRY(updateFoveationState(contextVk, *newFoveationState, foveatedAttachmentSize));
2494 }
2495
2496 // Defer clears for draw framebuffer ops. Note that this will result in a render area that
2497 // completely covers the framebuffer, even if the operation that follows is scissored.
2498 //
2499 // Additionally, defer clears for read framebuffer attachments that are not taking part in a
2500 // blit operation.
2501 const bool isBlitCommand = command >= gl::Command::Blit && command <= gl::Command::BlitAll;
2502
2503 bool deferColorClears = binding == GL_DRAW_FRAMEBUFFER;
2504 bool deferDepthStencilClears = binding == GL_DRAW_FRAMEBUFFER;
2505 if (binding == GL_READ_FRAMEBUFFER && isBlitCommand)
2506 {
2507 uint32_t blitMask =
2508 static_cast<uint32_t>(command) - static_cast<uint32_t>(gl::Command::Blit);
2509 if ((blitMask & gl::CommandBlitBufferColor) == 0)
2510 {
2511 deferColorClears = true;
2512 }
2513 if ((blitMask & (gl::CommandBlitBufferDepth | gl::CommandBlitBufferStencil)) == 0)
2514 {
2515 deferDepthStencilClears = true;
2516 }
2517 }
2518
2519 // If we are notified that any attachment is dirty, but we have deferred clears for them, a
2520 // flushDeferredClears() call is missing somewhere. ASSERT this to catch these bugs.
2521 vk::ClearValuesArray previousDeferredClears = mDeferredClears;
2522
2523 for (size_t colorIndexGL : dirtyColorAttachments)
2524 {
2525 ASSERT(!previousDeferredClears.test(colorIndexGL));
2526 ANGLE_TRY(flushColorAttachmentUpdates(context, deferColorClears,
2527 static_cast<uint32_t>(colorIndexGL)));
2528 }
2529 if (dirtyDepthStencilAttachment)
2530 {
2531 ASSERT(!previousDeferredClears.testDepth());
2532 ASSERT(!previousDeferredClears.testStencil());
2533 ANGLE_TRY(flushDepthStencilAttachmentUpdates(context, deferDepthStencilClears));
2534 }
2535
2536 // No-op redundant changes to prevent closing the RenderPass.
2537 if (mCurrentFramebufferDesc == priorFramebufferDesc &&
2538 mCurrentFramebufferDesc.attachmentCount() > 0)
2539 {
2540 return angle::Result::Continue;
2541 }
2542
2543 // ContextVk::onFramebufferChange will end up calling onRenderPassFinished if necessary,
2544 // which will trigger ending of current render pass. |mLastRenderPassQueueSerial| is reset
2545 // so that the render pass will not get reactivated, since |mCurrentFramebufferDesc| has
2546 // changed.
2547 mLastRenderPassQueueSerial = QueueSerial();
2548
2549 updateRenderPassDesc(contextVk);
2550
2551 // Deactivate Framebuffer
2552 releaseCurrentFramebuffer(contextVk);
2553
2554 // Notify the ContextVk to update the pipeline desc.
2555 return contextVk->onFramebufferChange(this, command);
2556 }
2557
updateRenderPassDesc(ContextVk * contextVk)2558 void FramebufferVk::updateRenderPassDesc(ContextVk *contextVk)
2559 {
2560 mRenderPassDesc = {};
2561 mRenderPassDesc.setSamples(getSamples());
2562 mRenderPassDesc.setViewCount(
2563 mState.isMultiview() && mState.getNumViews() > 1 ? mState.getNumViews() : 0);
2564
2565 // Color attachments.
2566 const auto &colorRenderTargets = mRenderTargetCache.getColors();
2567 const gl::DrawBufferMask colorAttachmentMask = mState.getColorAttachmentsMask();
2568 for (size_t colorIndexGL = 0; colorIndexGL < colorAttachmentMask.size(); ++colorIndexGL)
2569 {
2570 if (colorAttachmentMask[colorIndexGL])
2571 {
2572 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
2573 ASSERT(colorRenderTarget);
2574
2575 if (colorRenderTarget->isYuvResolve())
2576 {
2577 // If this is YUV resolve target, we use resolveImage's format since image maybe
2578 // nullptr
2579 auto const &resolveImage = colorRenderTarget->getResolveImageForRenderPass();
2580 mRenderPassDesc.packColorAttachment(colorIndexGL, resolveImage.getActualFormatID());
2581 mRenderPassDesc.packYUVResolveAttachment(colorIndexGL);
2582 }
2583 else
2584 {
2585 mRenderPassDesc.packColorAttachment(
2586 colorIndexGL, colorRenderTarget->getImageForRenderPass().getActualFormatID());
2587 // Add the resolve attachment, if any.
2588 if (colorRenderTarget->hasResolveAttachment())
2589 {
2590 mRenderPassDesc.packColorResolveAttachment(colorIndexGL);
2591 }
2592 }
2593 }
2594 else
2595 {
2596 mRenderPassDesc.packColorAttachmentGap(colorIndexGL);
2597 }
2598 }
2599
2600 // Depth/stencil attachment.
2601 RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
2602 if (depthStencilRenderTarget)
2603 {
2604 mRenderPassDesc.packDepthStencilAttachment(
2605 depthStencilRenderTarget->getImageForRenderPass().getActualFormatID());
2606
2607 // Add the resolve attachment, if any.
2608 if (depthStencilRenderTarget->hasResolveAttachment())
2609 {
2610 mRenderPassDesc.packDepthResolveAttachment();
2611 mRenderPassDesc.packStencilResolveAttachment();
2612 }
2613 }
2614
2615 if (contextVk->isInFramebufferFetchMode())
2616 {
2617 mRenderPassDesc.setFramebufferFetchMode(true);
2618 }
2619
2620 if (contextVk->getFeatures().enableMultisampledRenderToTexture.enabled)
2621 {
2622 // Update descriptions regarding multisampled-render-to-texture use.
2623 bool isRenderToTexture = false;
2624 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
2625 {
2626 const gl::FramebufferAttachment *color = mState.getColorAttachment(colorIndexGL);
2627 ASSERT(color);
2628
2629 if (color->isRenderToTexture())
2630 {
2631 isRenderToTexture = true;
2632 break;
2633 }
2634 }
2635 const gl::FramebufferAttachment *depthStencil = mState.getDepthStencilAttachment();
2636 if (depthStencil && depthStencil->isRenderToTexture())
2637 {
2638 isRenderToTexture = true;
2639 }
2640
2641 mCurrentFramebufferDesc.updateRenderToTexture(isRenderToTexture);
2642 mRenderPassDesc.updateRenderToTexture(isRenderToTexture);
2643 }
2644
2645 mCurrentFramebufferDesc.updateUnresolveMask({});
2646 mRenderPassDesc.setWriteControlMode(mCurrentFramebufferDesc.getWriteControlMode());
2647 mRenderPassDesc.setFragmentShadingAttachment(
2648 mCurrentFramebufferDesc.hasFragmentShadingRateAttachment());
2649
2650 updateLegacyDither(contextVk);
2651 }
2652
getAttachmentsAndRenderTargets(vk::Context * context,vk::FramebufferAttachmentsVector<VkImageView> * unpackedAttachments,vk::FramebufferAttachmentsVector<RenderTargetInfo> * packedRenderTargetsInfoOut)2653 angle::Result FramebufferVk::getAttachmentsAndRenderTargets(
2654 vk::Context *context,
2655 vk::FramebufferAttachmentsVector<VkImageView> *unpackedAttachments,
2656 vk::FramebufferAttachmentsVector<RenderTargetInfo> *packedRenderTargetsInfoOut)
2657 {
2658 // Color attachments.
2659 mIsYUVResolve = false;
2660 const auto &colorRenderTargets = mRenderTargetCache.getColors();
2661 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
2662 {
2663 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
2664 ASSERT(colorRenderTarget);
2665
2666 if (colorRenderTarget->isYuvResolve())
2667 {
2668 mIsYUVResolve = true;
2669 if (context->getRenderer()->nullColorAttachmentWithExternalFormatResolve())
2670 {
2671 continue;
2672 }
2673 }
2674 const vk::ImageView *imageView = nullptr;
2675 ANGLE_TRY(colorRenderTarget->getImageViewWithColorspace(
2676 context, mCurrentFramebufferDesc.getWriteControlMode(), &imageView));
2677 unpackedAttachments->push_back(imageView->getHandle());
2678
2679 packedRenderTargetsInfoOut->emplace_back(
2680 RenderTargetInfo(colorRenderTarget, RenderTargetImage::Attachment));
2681 }
2682
2683 // Depth/stencil attachment.
2684 RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
2685 if (depthStencilRenderTarget)
2686 {
2687 const vk::ImageView *imageView = nullptr;
2688 ANGLE_TRY(depthStencilRenderTarget->getImageView(context, &imageView));
2689
2690 unpackedAttachments->push_back(imageView->getHandle());
2691 packedRenderTargetsInfoOut->emplace_back(
2692 RenderTargetInfo(depthStencilRenderTarget, RenderTargetImage::Attachment));
2693 }
2694
2695 // Fragment shading rate attachment.
2696 if (mCurrentFramebufferDesc.hasFragmentShadingRateAttachment())
2697 {
2698 const vk::ImageViewHelper *imageViewHelper = &mFragmentShadingRateImageView;
2699 unpackedAttachments->push_back(
2700 imageViewHelper->getFragmentShadingRateImageView().getHandle());
2701 packedRenderTargetsInfoOut->emplace_back(nullptr, RenderTargetImage::FragmentShadingRate);
2702 }
2703
2704 // Color resolve attachments. From here on, the views are placed at sparse indices because of
2705 // |RenderPassFramebuffer|. That allows more resolve attachments to be added later.
2706 unpackedAttachments->resize(vk::kMaxFramebufferAttachments, VK_NULL_HANDLE);
2707 static_assert(vk::RenderPassFramebuffer::kColorResolveAttachmentBegin <
2708 vk::kMaxFramebufferAttachments);
2709 static_assert(vk::RenderPassFramebuffer::kDepthStencilResolveAttachment <
2710 vk::kMaxFramebufferAttachments);
2711
2712 bool anyResolveAttachments = false;
2713
2714 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
2715 {
2716 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
2717 ASSERT(colorRenderTarget);
2718
2719 if (colorRenderTarget->hasResolveAttachment())
2720 {
2721 const vk::ImageView *resolveImageView = nullptr;
2722 ANGLE_TRY(colorRenderTarget->getResolveImageView(context, &resolveImageView));
2723
2724 constexpr size_t kBaseIndex = vk::RenderPassFramebuffer::kColorResolveAttachmentBegin;
2725 (*unpackedAttachments)[kBaseIndex + colorIndexGL] = resolveImageView->getHandle();
2726 packedRenderTargetsInfoOut->emplace_back(
2727 RenderTargetInfo(colorRenderTarget, RenderTargetImage::Resolve));
2728
2729 anyResolveAttachments = true;
2730 }
2731 }
2732
2733 // Depth/stencil resolve attachment.
2734 if (depthStencilRenderTarget && depthStencilRenderTarget->hasResolveAttachment())
2735 {
2736 const vk::ImageView *imageView = nullptr;
2737 ANGLE_TRY(depthStencilRenderTarget->getResolveImageView(context, &imageView));
2738
2739 (*unpackedAttachments)[vk::RenderPassFramebuffer::kDepthStencilResolveAttachment] =
2740 imageView->getHandle();
2741 packedRenderTargetsInfoOut->emplace_back(
2742 RenderTargetInfo(depthStencilRenderTarget, RenderTargetImage::Resolve));
2743
2744 anyResolveAttachments = true;
2745 }
2746
2747 // Make sure |AllowAddingResolveAttachmentsToSubpass()| is guarding against all cases where a
2748 // resolve attachment is pre-present in the render pass.
2749 if (anyResolveAttachments)
2750 {
2751 ASSERT(!AllowAddingResolveAttachmentsToSubpass(mRenderPassDesc));
2752 }
2753
2754 return angle::Result::Continue;
2755 }
2756
createNewFramebuffer(ContextVk * contextVk,uint32_t framebufferWidth,const uint32_t framebufferHeight,const uint32_t framebufferLayers,const vk::FramebufferAttachmentsVector<VkImageView> & unpackedAttachments,const vk::FramebufferAttachmentsVector<RenderTargetInfo> & renderTargetsInfo)2757 angle::Result FramebufferVk::createNewFramebuffer(
2758 ContextVk *contextVk,
2759 uint32_t framebufferWidth,
2760 const uint32_t framebufferHeight,
2761 const uint32_t framebufferLayers,
2762 const vk::FramebufferAttachmentsVector<VkImageView> &unpackedAttachments,
2763 const vk::FramebufferAttachmentsVector<RenderTargetInfo> &renderTargetsInfo)
2764 {
2765 // The backbuffer framebuffer is cached in WindowSurfaceVk instead.
2766 ASSERT(mBackbuffer == nullptr);
2767 // Called only when a new framebuffer is needed.
2768 ASSERT(!mCurrentFramebuffer.valid());
2769
2770 // When using imageless framebuffers, the framebuffer cache is not utilized.
2771 const bool useImagelessFramebuffer =
2772 contextVk->getFeatures().supportsImagelessFramebuffer.enabled;
2773
2774 // Try to retrieve a framebuffer from the cache.
2775 if (!useImagelessFramebuffer && contextVk->getShareGroup()->getFramebufferCache().get(
2776 contextVk, mCurrentFramebufferDesc, mCurrentFramebuffer))
2777 {
2778 ASSERT(mCurrentFramebuffer.valid());
2779 mIsCurrentFramebufferCached = true;
2780 return angle::Result::Continue;
2781 }
2782
2783 const vk::RenderPass *compatibleRenderPass = nullptr;
2784 ANGLE_TRY(contextVk->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
2785
2786 // Create a new framebuffer.
2787 vk::FramebufferHelper newFramebuffer;
2788
2789 VkFramebufferCreateInfo framebufferInfo = {};
2790 framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
2791 framebufferInfo.flags = 0;
2792 framebufferInfo.renderPass = compatibleRenderPass->getHandle();
2793 framebufferInfo.attachmentCount = static_cast<uint32_t>(renderTargetsInfo.size());
2794 framebufferInfo.width = framebufferWidth;
2795 framebufferInfo.height = framebufferHeight;
2796 framebufferInfo.layers = framebufferLayers;
2797
2798 // Check that our description matches our attachments. Can catch implementation bugs.
2799 ASSERT((mIsYUVResolve &&
2800 contextVk->getRenderer()->nullColorAttachmentWithExternalFormatResolve()) ||
2801 static_cast<uint32_t>(renderTargetsInfo.size()) ==
2802 mCurrentFramebufferDesc.attachmentCount());
2803
2804 if (!useImagelessFramebuffer)
2805 {
2806 vk::FramebufferAttachmentsVector<VkImageView> packedAttachments = unpackedAttachments;
2807 vk::RenderPassFramebuffer::PackViews(&packedAttachments);
2808
2809 ASSERT(renderTargetsInfo.size() == packedAttachments.size());
2810 framebufferInfo.pAttachments = packedAttachments.data();
2811
2812 // The cache key (|FramebufferDesc|) can't distinguish between two framebuffers with 0
2813 // attachments but with different sizes. For simplicity, 0-attachment framebuffers are not
2814 // cached.
2815 ANGLE_TRY(newFramebuffer.init(contextVk, framebufferInfo));
2816 if (packedAttachments.empty())
2817 {
2818 mCurrentFramebuffer = std::move(newFramebuffer.getFramebuffer());
2819 mIsCurrentFramebufferCached = false;
2820 }
2821 else
2822 {
2823 insertCache(contextVk, mCurrentFramebufferDesc, std::move(newFramebuffer));
2824
2825 const bool result = contextVk->getShareGroup()->getFramebufferCache().get(
2826 contextVk, mCurrentFramebufferDesc, mCurrentFramebuffer);
2827 ASSERT(result);
2828 mIsCurrentFramebufferCached = true;
2829 }
2830
2831 return angle::Result::Continue;
2832 }
2833
2834 // For imageless framebuffers, attachment image and create info objects should be defined
2835 // when creating the new framebuffer.
2836 vk::FramebufferAttachmentsVector<VkFramebufferAttachmentImageInfo> attachmentImageInfos(
2837 renderTargetsInfo.size(), {});
2838
2839 for (size_t index = 0; index < renderTargetsInfo.size(); ++index)
2840 {
2841 const RenderTargetInfo &info = renderTargetsInfo[index];
2842 VkFramebufferAttachmentImageInfo &attachmentInfo = attachmentImageInfos[index];
2843
2844 attachmentInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENT_IMAGE_INFO;
2845
2846 // The fragment shading rate attachment does not have a corresponding render target, and is
2847 // handled specially.
2848 if (info.renderTargetImage == RenderTargetImage::FragmentShadingRate)
2849 {
2850 attachmentInfo.width = mFragmentShadingRateImage.getExtents().width;
2851 attachmentInfo.height = mFragmentShadingRateImage.getExtents().height;
2852
2853 attachmentInfo.layerCount = 1;
2854 attachmentInfo.flags = mFragmentShadingRateImage.getCreateFlags();
2855 attachmentInfo.usage = mFragmentShadingRateImage.getUsage();
2856 attachmentInfo.viewFormatCount =
2857 static_cast<uint32_t>(mFragmentShadingRateImage.getViewFormats().size());
2858 attachmentInfo.pViewFormats = mFragmentShadingRateImage.getViewFormats().data();
2859 continue;
2860 }
2861
2862 vk::ImageHelper *image = (info.renderTargetImage == RenderTargetImage::Resolve ||
2863 info.renderTarget->isYuvResolve())
2864 ? &info.renderTarget->getResolveImageForRenderPass()
2865 : &info.renderTarget->getImageForRenderPass();
2866
2867 const gl::LevelIndex level = info.renderTarget->getLevelIndexForImage(*image);
2868 const uint32_t layerCount = info.renderTarget->getLayerCount();
2869 const gl::Extents extents = image->getLevelExtents2D(image->toVkLevel(level));
2870
2871 attachmentInfo.width = std::max(extents.width, 1);
2872 attachmentInfo.height = std::max(extents.height, 1);
2873 attachmentInfo.layerCount = mCurrentFramebufferDesc.isMultiview()
2874 ? std::max<uint32_t>(mRenderPassDesc.viewCount(), 1u)
2875 : layerCount;
2876 attachmentInfo.flags = image->getCreateFlags();
2877 attachmentInfo.usage = image->getUsage();
2878 attachmentInfo.viewFormatCount = static_cast<uint32_t>(image->getViewFormats().size());
2879 attachmentInfo.pViewFormats = image->getViewFormats().data();
2880 }
2881
2882 VkFramebufferAttachmentsCreateInfo attachmentsCreateInfo = {};
2883 attachmentsCreateInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_ATTACHMENTS_CREATE_INFO;
2884 attachmentsCreateInfo.attachmentImageInfoCount =
2885 static_cast<uint32_t>(attachmentImageInfos.size());
2886 attachmentsCreateInfo.pAttachmentImageInfos = attachmentImageInfos.data();
2887
2888 framebufferInfo.flags |= VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT;
2889 vk::AddToPNextChain(&framebufferInfo, &attachmentsCreateInfo);
2890
2891 ANGLE_TRY(newFramebuffer.init(contextVk, framebufferInfo));
2892 mCurrentFramebuffer = std::move(newFramebuffer.getFramebuffer());
2893
2894 return angle::Result::Continue;
2895 }
2896
getFramebuffer(ContextVk * contextVk,vk::RenderPassFramebuffer * framebufferOut)2897 angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk,
2898 vk::RenderPassFramebuffer *framebufferOut)
2899 {
2900 ASSERT(mCurrentFramebufferDesc.hasFramebufferFetch() == mRenderPassDesc.hasFramebufferFetch());
2901
2902 const gl::Extents attachmentsSize = mState.getExtents();
2903 ASSERT(attachmentsSize.width != 0 && attachmentsSize.height != 0);
2904
2905 uint32_t framebufferWidth = static_cast<uint32_t>(attachmentsSize.width);
2906 uint32_t framebufferHeight = static_cast<uint32_t>(attachmentsSize.height);
2907 const uint32_t framebufferLayers = !mCurrentFramebufferDesc.isMultiview()
2908 ? std::max(mCurrentFramebufferDesc.getLayerCount(), 1u)
2909 : 1;
2910
2911 vk::FramebufferAttachmentsVector<VkImageView> unpackedAttachments;
2912 vk::FramebufferAttachmentsVector<RenderTargetInfo> renderTargetsInfo;
2913 ANGLE_TRY(getAttachmentsAndRenderTargets(contextVk, &unpackedAttachments, &renderTargetsInfo));
2914
2915 vk::Framebuffer framebufferHandle;
2916 if (mCurrentFramebuffer.valid())
2917 {
2918 // If a valid framebuffer is already created, use it. This is not done when the swapchain
2919 // is being resolved, because the appropriate framebuffer needs to be queried from the back
2920 // buffer.
2921 framebufferHandle.setHandle(mCurrentFramebuffer.getHandle());
2922 }
2923 else
2924 {
2925 // For the default framebuffer attached to a window surface, WindowSurfaceVk caches a
2926 // handful of framebuffer objects which are queried here. For the rest, a framebuffer needs
2927 // to be created based on the current attachments to the FBO.
2928 if (mBackbuffer == nullptr)
2929 {
2930 // Create a new framebuffer
2931 ANGLE_TRY(createNewFramebuffer(contextVk, framebufferWidth, framebufferHeight,
2932 framebufferLayers, unpackedAttachments,
2933 renderTargetsInfo));
2934 ASSERT(mCurrentFramebuffer.valid());
2935 framebufferHandle.setHandle(mCurrentFramebuffer.getHandle());
2936 }
2937 else
2938 {
2939 const vk::RenderPass *compatibleRenderPass = nullptr;
2940 ANGLE_TRY(contextVk->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
2941
2942 // If there is a backbuffer, query the framebuffer from WindowSurfaceVk instead.
2943 ANGLE_TRY(mBackbuffer->getCurrentFramebuffer(
2944 contextVk,
2945 mRenderPassDesc.hasFramebufferFetch() ? FramebufferFetchMode::Enabled
2946 : FramebufferFetchMode::Disabled,
2947 *compatibleRenderPass, &framebufferHandle));
2948
2949 // Account for swapchain pre-rotation
2950 framebufferWidth = renderTargetsInfo[0].renderTarget->getRotatedExtents().width;
2951 framebufferHeight = renderTargetsInfo[0].renderTarget->getRotatedExtents().height;
2952 }
2953 }
2954
2955 const vk::ImagelessFramebuffer imagelessFramebuffer =
2956 contextVk->getFeatures().supportsImagelessFramebuffer.enabled && mBackbuffer == nullptr
2957 ? vk::ImagelessFramebuffer::Yes
2958 : vk::ImagelessFramebuffer::No;
2959
2960 framebufferOut->setFramebuffer(std::move(framebufferHandle), std::move(unpackedAttachments),
2961 framebufferWidth, framebufferHeight, framebufferLayers,
2962 imagelessFramebuffer);
2963
2964 return angle::Result::Continue;
2965 }
2966
mergeClearsWithDeferredClears(gl::DrawBufferMask clearColorBuffers,bool clearDepth,bool clearStencil,const gl::DrawBuffersArray<VkClearColorValue> & clearColorValues,const VkClearDepthStencilValue & clearDepthStencilValue)2967 void FramebufferVk::mergeClearsWithDeferredClears(
2968 gl::DrawBufferMask clearColorBuffers,
2969 bool clearDepth,
2970 bool clearStencil,
2971 const gl::DrawBuffersArray<VkClearColorValue> &clearColorValues,
2972 const VkClearDepthStencilValue &clearDepthStencilValue)
2973 {
2974 // Apply clears to mDeferredClears. Note that clears override deferred clears.
2975
2976 // Color clears.
2977 for (size_t colorIndexGL : clearColorBuffers)
2978 {
2979 ASSERT(mState.getEnabledDrawBuffers().test(colorIndexGL));
2980 VkClearValue clearValue =
2981 getCorrectedColorClearValue(colorIndexGL, clearColorValues[colorIndexGL]);
2982 mDeferredClears.store(static_cast<uint32_t>(colorIndexGL), VK_IMAGE_ASPECT_COLOR_BIT,
2983 clearValue);
2984 }
2985
2986 // Depth and stencil clears.
2987 VkImageAspectFlags dsAspectFlags = 0;
2988 VkClearValue dsClearValue = {};
2989 dsClearValue.depthStencil = clearDepthStencilValue;
2990 if (clearDepth)
2991 {
2992 dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
2993 }
2994 if (clearStencil)
2995 {
2996 dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
2997 }
2998
2999 if (dsAspectFlags != 0)
3000 {
3001 mDeferredClears.store(vk::kUnpackedDepthIndex, dsAspectFlags, dsClearValue);
3002 }
3003 }
3004
clearWithDraw(ContextVk * contextVk,const gl::Rectangle & clearArea,gl::DrawBufferMask clearColorBuffers,bool clearDepth,bool clearStencil,gl::BlendStateExt::ColorMaskStorage::Type colorMasks,uint8_t stencilMask,const gl::DrawBuffersArray<VkClearColorValue> & clearColorValues,const VkClearDepthStencilValue & clearDepthStencilValue)3005 angle::Result FramebufferVk::clearWithDraw(
3006 ContextVk *contextVk,
3007 const gl::Rectangle &clearArea,
3008 gl::DrawBufferMask clearColorBuffers,
3009 bool clearDepth,
3010 bool clearStencil,
3011 gl::BlendStateExt::ColorMaskStorage::Type colorMasks,
3012 uint8_t stencilMask,
3013 const gl::DrawBuffersArray<VkClearColorValue> &clearColorValues,
3014 const VkClearDepthStencilValue &clearDepthStencilValue)
3015 {
3016 // All deferred clears should be handled already.
3017 ASSERT(mDeferredClears.empty());
3018
3019 UtilsVk::ClearFramebufferParameters params = {};
3020 params.clearArea = clearArea;
3021 params.depthStencilClearValue = clearDepthStencilValue;
3022 params.stencilMask = stencilMask;
3023
3024 params.clearColor = true;
3025 params.clearDepth = clearDepth;
3026 params.clearStencil = clearStencil;
3027
3028 const auto &colorRenderTargets = mRenderTargetCache.getColors();
3029 for (size_t colorIndexGL : clearColorBuffers)
3030 {
3031 const RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
3032 ASSERT(colorRenderTarget);
3033
3034 params.colorClearValue = clearColorValues[colorIndexGL];
3035 params.colorFormat = &colorRenderTarget->getImageForRenderPass().getActualFormat();
3036 params.colorAttachmentIndexGL = static_cast<uint32_t>(colorIndexGL);
3037 params.colorMaskFlags =
3038 gl::BlendStateExt::ColorMaskStorage::GetValueIndexed(colorIndexGL, colorMasks);
3039 if (mEmulatedAlphaAttachmentMask[colorIndexGL])
3040 {
3041 params.colorMaskFlags &= ~VK_COLOR_COMPONENT_A_BIT;
3042 }
3043
3044 // TODO: implement clear of layered framebuffers. UtilsVk::clearFramebuffer should add a
3045 // geometry shader that is instanced layerCount times (or loops layerCount times), each time
3046 // selecting a different layer.
3047 // http://anglebug.com/5453
3048 ASSERT(mCurrentFramebufferDesc.isMultiview() || colorRenderTarget->getLayerCount() == 1);
3049
3050 ANGLE_TRY(contextVk->getUtils().clearFramebuffer(contextVk, this, params));
3051
3052 // Clear depth/stencil only once!
3053 params.clearDepth = false;
3054 params.clearStencil = false;
3055 }
3056
3057 // If there was no color clear, clear depth/stencil alone.
3058 if (params.clearDepth || params.clearStencil)
3059 {
3060 params.clearColor = false;
3061 ANGLE_TRY(contextVk->getUtils().clearFramebuffer(contextVk, this, params));
3062 }
3063
3064 return angle::Result::Continue;
3065 }
3066
getCorrectedColorClearValue(size_t colorIndexGL,const VkClearColorValue & clearColor) const3067 VkClearValue FramebufferVk::getCorrectedColorClearValue(size_t colorIndexGL,
3068 const VkClearColorValue &clearColor) const
3069 {
3070 VkClearValue clearValue = {};
3071 clearValue.color = clearColor;
3072
3073 if (!mEmulatedAlphaAttachmentMask[colorIndexGL])
3074 {
3075 return clearValue;
3076 }
3077
3078 // If the render target doesn't have alpha, but its emulated format has it, clear the alpha
3079 // to 1.
3080 RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL);
3081 const angle::Format &format = renderTarget->getImageActualFormat();
3082
3083 if (format.isUint())
3084 {
3085 clearValue.color.uint32[3] = kEmulatedAlphaValue;
3086 }
3087 else if (format.isSint())
3088 {
3089 clearValue.color.int32[3] = kEmulatedAlphaValue;
3090 }
3091 else
3092 {
3093 clearValue.color.float32[3] = kEmulatedAlphaValue;
3094 }
3095
3096 return clearValue;
3097 }
3098
restageDeferredClears(ContextVk * contextVk)3099 void FramebufferVk::restageDeferredClears(ContextVk *contextVk)
3100 {
3101 // Called when restaging clears of the draw framebuffer. In that case, there can't be any
3102 // render passes open, otherwise the clear would have applied to the render pass. In the
3103 // exceptional occasion in blit where the read framebuffer accumulates deferred clears, it can
3104 // be deferred while this assumption doesn't hold (and restageDeferredClearsForReadFramebuffer
3105 // should be used instead).
3106 ASSERT(!contextVk->hasActiveRenderPass() || !mDeferredClears.any());
3107 restageDeferredClearsImpl(contextVk);
3108 }
3109
restageDeferredClearsForReadFramebuffer(ContextVk * contextVk)3110 void FramebufferVk::restageDeferredClearsForReadFramebuffer(ContextVk *contextVk)
3111 {
3112 restageDeferredClearsImpl(contextVk);
3113 }
3114
restageDeferredClearsImpl(ContextVk * contextVk)3115 void FramebufferVk::restageDeferredClearsImpl(ContextVk *contextVk)
3116 {
3117 // Set the appropriate aspect and clear values for depth and stencil.
3118 VkImageAspectFlags dsAspectFlags = 0;
3119 VkClearValue dsClearValue = {};
3120 dsClearValue.depthStencil.depth = mDeferredClears.getDepthValue();
3121 dsClearValue.depthStencil.stencil = mDeferredClears.getStencilValue();
3122
3123 if (mDeferredClears.testDepth())
3124 {
3125 dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
3126 mDeferredClears.reset(vk::kUnpackedDepthIndex);
3127 }
3128
3129 if (mDeferredClears.testStencil())
3130 {
3131 dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
3132 mDeferredClears.reset(vk::kUnpackedStencilIndex);
3133 }
3134
3135 // Go through deferred clears and stage the clears for future.
3136 for (size_t colorIndexGL : mDeferredClears.getColorMask())
3137 {
3138 RenderTargetVk *renderTarget = getColorDrawRenderTarget(colorIndexGL);
3139 gl::ImageIndex imageIndex =
3140 renderTarget->getImageIndexForClear(mCurrentFramebufferDesc.getLayerCount());
3141 renderTarget->getImageForWrite().stageClear(imageIndex, VK_IMAGE_ASPECT_COLOR_BIT,
3142 mDeferredClears[colorIndexGL]);
3143 mDeferredClears.reset(colorIndexGL);
3144 }
3145
3146 if (dsAspectFlags)
3147 {
3148 RenderTargetVk *renderTarget = getDepthStencilRenderTarget();
3149 ASSERT(renderTarget);
3150
3151 gl::ImageIndex imageIndex =
3152 renderTarget->getImageIndexForClear(mCurrentFramebufferDesc.getLayerCount());
3153 renderTarget->getImageForWrite().stageClear(imageIndex, dsAspectFlags, dsClearValue);
3154 }
3155 }
3156
clearWithCommand(ContextVk * contextVk,const gl::Rectangle & scissoredRenderArea,ClearWithCommand behavior,vk::ClearValuesArray * clears)3157 void FramebufferVk::clearWithCommand(ContextVk *contextVk,
3158 const gl::Rectangle &scissoredRenderArea,
3159 ClearWithCommand behavior,
3160 vk::ClearValuesArray *clears)
3161 {
3162 // Clear is not affected by viewport, so ContextVk::updateScissor may have decided on a smaller
3163 // render area. Grow the render area to the full framebuffer size as this clear path is taken
3164 // when not scissored.
3165 vk::RenderPassCommandBufferHelper *renderPassCommands =
3166 &contextVk->getStartedRenderPassCommands();
3167 renderPassCommands->growRenderArea(contextVk, scissoredRenderArea);
3168
3169 gl::AttachmentVector<VkClearAttachment> attachments;
3170
3171 const bool optimizeWithLoadOp = behavior == ClearWithCommand::OptimizeWithLoadOp;
3172
3173 // Go through deferred clears and add them to the list of attachments to clear. If any
3174 // attachment is unused, skip the clear. clearWithLoadOp will follow and move the remaining
3175 // clears up to loadOp.
3176 vk::PackedAttachmentIndex colorIndexVk(0);
3177 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
3178 {
3179 if (clears->getColorMask().test(colorIndexGL))
3180 {
3181 if (renderPassCommands->hasAnyColorAccess(colorIndexVk) ||
3182 renderPassCommands->getRenderPassDesc().hasColorUnresolveAttachment(colorIndexGL) ||
3183 !optimizeWithLoadOp)
3184 {
3185 attachments.emplace_back(VkClearAttachment{VK_IMAGE_ASPECT_COLOR_BIT,
3186 static_cast<uint32_t>(colorIndexGL),
3187 (*clears)[colorIndexGL]});
3188 clears->reset(colorIndexGL);
3189 ++contextVk->getPerfCounters().colorClearAttachments;
3190
3191 renderPassCommands->onColorAccess(colorIndexVk, vk::ResourceAccess::ReadWrite);
3192 }
3193 else
3194 {
3195 // Skip this attachment, so we can use a renderpass loadOp to clear it instead.
3196 // Note that if loadOp=Clear was already used for this color attachment, it will be
3197 // overriden by the new clear, which is valid because the attachment wasn't used in
3198 // between.
3199 }
3200 }
3201 ++colorIndexVk;
3202 }
3203
3204 // Add depth and stencil to list of attachments as needed.
3205 VkImageAspectFlags dsAspectFlags = 0;
3206 VkClearValue dsClearValue = {};
3207 dsClearValue.depthStencil.depth = clears->getDepthValue();
3208 dsClearValue.depthStencil.stencil = clears->getStencilValue();
3209 if (clears->testDepth() &&
3210 (renderPassCommands->hasAnyDepthAccess() ||
3211 renderPassCommands->getRenderPassDesc().hasDepthUnresolveAttachment() ||
3212 !optimizeWithLoadOp))
3213 {
3214 dsAspectFlags |= VK_IMAGE_ASPECT_DEPTH_BIT;
3215 // Explicitly mark a depth write because we are clearing the depth buffer.
3216 renderPassCommands->onDepthAccess(vk::ResourceAccess::ReadWrite);
3217 clears->reset(vk::kUnpackedDepthIndex);
3218 ++contextVk->getPerfCounters().depthClearAttachments;
3219 }
3220
3221 if (clears->testStencil() &&
3222 (renderPassCommands->hasAnyStencilAccess() ||
3223 renderPassCommands->getRenderPassDesc().hasStencilUnresolveAttachment() ||
3224 !optimizeWithLoadOp))
3225 {
3226 dsAspectFlags |= VK_IMAGE_ASPECT_STENCIL_BIT;
3227 // Explicitly mark a stencil write because we are clearing the stencil buffer.
3228 renderPassCommands->onStencilAccess(vk::ResourceAccess::ReadWrite);
3229 clears->reset(vk::kUnpackedStencilIndex);
3230 ++contextVk->getPerfCounters().stencilClearAttachments;
3231 }
3232
3233 if (dsAspectFlags != 0)
3234 {
3235 attachments.emplace_back(VkClearAttachment{dsAspectFlags, 0, dsClearValue});
3236
3237 // Because we may have changed the depth/stencil access mode, update read only depth/stencil
3238 // mode.
3239 renderPassCommands->updateDepthStencilReadOnlyMode(
3240 contextVk->getDepthStencilAttachmentFlags(), dsAspectFlags);
3241 }
3242
3243 if (attachments.empty())
3244 {
3245 // If called with the intent to definitely clear something with vkCmdClearAttachments, there
3246 // must have been something to clear!
3247 ASSERT(optimizeWithLoadOp);
3248 return;
3249 }
3250
3251 const uint32_t layerCount = mState.isMultiview() ? 1 : mCurrentFramebufferDesc.getLayerCount();
3252
3253 VkClearRect rect = {};
3254 rect.rect.offset.x = scissoredRenderArea.x;
3255 rect.rect.offset.y = scissoredRenderArea.y;
3256 rect.rect.extent.width = scissoredRenderArea.width;
3257 rect.rect.extent.height = scissoredRenderArea.height;
3258 rect.layerCount = layerCount;
3259 vk::RenderPassCommandBuffer *renderPassCommandBuffer = &renderPassCommands->getCommandBuffer();
3260
3261 renderPassCommandBuffer->clearAttachments(static_cast<uint32_t>(attachments.size()),
3262 attachments.data(), 1, &rect);
3263 return;
3264 }
3265
clearWithLoadOp(ContextVk * contextVk)3266 void FramebufferVk::clearWithLoadOp(ContextVk *contextVk)
3267 {
3268 vk::RenderPassCommandBufferHelper *renderPassCommands =
3269 &contextVk->getStartedRenderPassCommands();
3270
3271 // Update the render pass loadOps to clear the attachments.
3272 vk::PackedAttachmentIndex colorIndexVk(0);
3273 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
3274 {
3275 if (!mDeferredClears.test(colorIndexGL))
3276 {
3277 ++colorIndexVk;
3278 continue;
3279 }
3280
3281 ASSERT(!renderPassCommands->hasAnyColorAccess(colorIndexVk));
3282
3283 renderPassCommands->updateRenderPassColorClear(colorIndexVk, mDeferredClears[colorIndexGL]);
3284
3285 mDeferredClears.reset(colorIndexGL);
3286
3287 ++colorIndexVk;
3288 }
3289
3290 VkClearValue dsClearValue = {};
3291 dsClearValue.depthStencil.depth = mDeferredClears.getDepthValue();
3292 dsClearValue.depthStencil.stencil = mDeferredClears.getStencilValue();
3293 VkImageAspectFlags dsAspects = 0;
3294
3295 if (mDeferredClears.testDepth())
3296 {
3297 ASSERT(!renderPassCommands->hasAnyDepthAccess());
3298 dsAspects |= VK_IMAGE_ASPECT_DEPTH_BIT;
3299 mDeferredClears.reset(vk::kUnpackedDepthIndex);
3300 }
3301
3302 if (mDeferredClears.testStencil())
3303 {
3304 ASSERT(!renderPassCommands->hasAnyStencilAccess());
3305 dsAspects |= VK_IMAGE_ASPECT_STENCIL_BIT;
3306 mDeferredClears.reset(vk::kUnpackedStencilIndex);
3307 }
3308
3309 if (dsAspects != 0)
3310 {
3311 renderPassCommands->updateRenderPassDepthStencilClear(dsAspects, dsClearValue);
3312
3313 // The render pass can no longer be in read-only depth/stencil mode.
3314 renderPassCommands->updateDepthStencilReadOnlyMode(
3315 contextVk->getDepthStencilAttachmentFlags(), dsAspects);
3316 }
3317 }
3318
getSamplePosition(const gl::Context * context,size_t index,GLfloat * xy) const3319 angle::Result FramebufferVk::getSamplePosition(const gl::Context *context,
3320 size_t index,
3321 GLfloat *xy) const
3322 {
3323 int sampleCount = getSamples();
3324 rx::GetSamplePosition(sampleCount, index, xy);
3325 return angle::Result::Continue;
3326 }
3327
startNewRenderPass(ContextVk * contextVk,const gl::Rectangle & renderArea,vk::RenderPassCommandBuffer ** commandBufferOut,bool * renderPassDescChangedOut)3328 angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
3329 const gl::Rectangle &renderArea,
3330 vk::RenderPassCommandBuffer **commandBufferOut,
3331 bool *renderPassDescChangedOut)
3332 {
3333 ANGLE_TRY(contextVk->flushCommandsAndEndRenderPass(RenderPassClosureReason::NewRenderPass));
3334
3335 // Initialize RenderPass info.
3336 vk::AttachmentOpsArray renderPassAttachmentOps;
3337 vk::PackedClearValuesArray packedClearValues;
3338 gl::DrawBufferMask previousUnresolveColorMask =
3339 mRenderPassDesc.getColorUnresolveAttachmentMask();
3340 const bool hasDeferredClears = mDeferredClears.any();
3341 const bool previousUnresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment();
3342 const bool previousUnresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment();
3343
3344 // Make sure render pass and framebuffer are in agreement w.r.t unresolve attachments.
3345 ASSERT(mCurrentFramebufferDesc.getUnresolveAttachmentMask() ==
3346 MakeUnresolveAttachmentMask(mRenderPassDesc));
3347 // ... w.r.t sRGB write control.
3348 ASSERT(mCurrentFramebufferDesc.getWriteControlMode() ==
3349 mRenderPassDesc.getSRGBWriteControlMode());
3350 // ... w.r.t foveation.
3351 ASSERT(mCurrentFramebufferDesc.hasFragmentShadingRateAttachment() ==
3352 mRenderPassDesc.hasFragmentShadingAttachment());
3353
3354 // Color attachments.
3355 const auto &colorRenderTargets = mRenderTargetCache.getColors();
3356 vk::PackedAttachmentIndex colorIndexVk(0);
3357 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
3358 {
3359 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
3360 ASSERT(colorRenderTarget);
3361
3362 // Color render targets are never entirely transient. Only depth/stencil
3363 // multisampled-render-to-texture textures can be so.
3364 ASSERT(!colorRenderTarget->isEntirelyTransient());
3365 const vk::RenderPassStoreOp storeOp = colorRenderTarget->isImageTransient()
3366 ? vk::RenderPassStoreOp::DontCare
3367 : vk::RenderPassStoreOp::Store;
3368
3369 if (mDeferredClears.test(colorIndexGL))
3370 {
3371 renderPassAttachmentOps.setOps(colorIndexVk, vk::RenderPassLoadOp::Clear, storeOp);
3372 packedClearValues.store(colorIndexVk, VK_IMAGE_ASPECT_COLOR_BIT,
3373 mDeferredClears[colorIndexGL]);
3374 mDeferredClears.reset(colorIndexGL);
3375 }
3376 else
3377 {
3378 const vk::RenderPassLoadOp loadOp = colorRenderTarget->hasDefinedContent()
3379 ? vk::RenderPassLoadOp::Load
3380 : vk::RenderPassLoadOp::DontCare;
3381
3382 renderPassAttachmentOps.setOps(colorIndexVk, loadOp, storeOp);
3383 packedClearValues.store(colorIndexVk, VK_IMAGE_ASPECT_COLOR_BIT,
3384 kUninitializedClearValue);
3385 }
3386 renderPassAttachmentOps.setStencilOps(colorIndexVk, vk::RenderPassLoadOp::DontCare,
3387 vk::RenderPassStoreOp::DontCare);
3388
3389 // If there's a resolve attachment, and loadOp needs to be LOAD, the multisampled attachment
3390 // needs to take its value from the resolve attachment. In this case, an initial subpass is
3391 // added for this very purpose which uses the resolve attachment as input attachment. As a
3392 // result, loadOp of the multisampled attachment can remain DONT_CARE.
3393 //
3394 // Note that this only needs to be done if the multisampled image and the resolve attachment
3395 // come from the same source. isImageTransient() indicates whether this should happen.
3396 if (colorRenderTarget->hasResolveAttachment() && colorRenderTarget->isImageTransient())
3397 {
3398 if (renderPassAttachmentOps[colorIndexVk].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD)
3399 {
3400 renderPassAttachmentOps[colorIndexVk].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
3401
3402 // Update the render pass desc to specify that this attachment should be unresolved.
3403 mRenderPassDesc.packColorUnresolveAttachment(colorIndexGL);
3404 }
3405 else
3406 {
3407 mRenderPassDesc.removeColorUnresolveAttachment(colorIndexGL);
3408 }
3409 }
3410 else
3411 {
3412 ASSERT(!mRenderPassDesc.getColorUnresolveAttachmentMask().test(colorIndexGL));
3413 }
3414
3415 ++colorIndexVk;
3416 }
3417
3418 // Depth/stencil attachment.
3419 vk::PackedAttachmentIndex depthStencilAttachmentIndex = vk::kAttachmentIndexInvalid;
3420 RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
3421 if (depthStencilRenderTarget)
3422 {
3423 // depth stencil attachment always immediately follows color attachment
3424 depthStencilAttachmentIndex = colorIndexVk;
3425
3426 vk::RenderPassLoadOp depthLoadOp = vk::RenderPassLoadOp::Load;
3427 vk::RenderPassLoadOp stencilLoadOp = vk::RenderPassLoadOp::Load;
3428 vk::RenderPassStoreOp depthStoreOp = vk::RenderPassStoreOp::Store;
3429 vk::RenderPassStoreOp stencilStoreOp = vk::RenderPassStoreOp::Store;
3430
3431 // If the image data was previously discarded (with no update in between), don't attempt to
3432 // load the image. Additionally, if the multisampled image data is transient and there is
3433 // no resolve attachment, there's no data to load. The latter is the case with
3434 // depth/stencil texture attachments per GL_EXT_multisampled_render_to_texture2.
3435 if (!depthStencilRenderTarget->hasDefinedContent() ||
3436 depthStencilRenderTarget->isEntirelyTransient())
3437 {
3438 depthLoadOp = vk::RenderPassLoadOp::DontCare;
3439 }
3440 if (!depthStencilRenderTarget->hasDefinedStencilContent() ||
3441 depthStencilRenderTarget->isEntirelyTransient())
3442 {
3443 stencilLoadOp = vk::RenderPassLoadOp::DontCare;
3444 }
3445
3446 // If depth/stencil image is transient, no need to store its data at the end of the render
3447 // pass.
3448 if (depthStencilRenderTarget->isImageTransient())
3449 {
3450 depthStoreOp = vk::RenderPassStoreOp::DontCare;
3451 stencilStoreOp = vk::RenderPassStoreOp::DontCare;
3452 }
3453
3454 if (mDeferredClears.testDepth() || mDeferredClears.testStencil())
3455 {
3456 VkClearValue clearValue = {};
3457
3458 if (mDeferredClears.testDepth())
3459 {
3460 depthLoadOp = vk::RenderPassLoadOp::Clear;
3461 clearValue.depthStencil.depth = mDeferredClears.getDepthValue();
3462 mDeferredClears.reset(vk::kUnpackedDepthIndex);
3463 }
3464
3465 if (mDeferredClears.testStencil())
3466 {
3467 stencilLoadOp = vk::RenderPassLoadOp::Clear;
3468 clearValue.depthStencil.stencil = mDeferredClears.getStencilValue();
3469 mDeferredClears.reset(vk::kUnpackedStencilIndex);
3470 }
3471
3472 // Note the aspect is only depth here. That's intentional.
3473 packedClearValues.store(depthStencilAttachmentIndex, VK_IMAGE_ASPECT_DEPTH_BIT,
3474 clearValue);
3475 }
3476 else
3477 {
3478 // Note the aspect is only depth here. That's intentional.
3479 packedClearValues.store(depthStencilAttachmentIndex, VK_IMAGE_ASPECT_DEPTH_BIT,
3480 kUninitializedClearValue);
3481 }
3482
3483 const angle::Format &format = depthStencilRenderTarget->getImageIntendedFormat();
3484 // If the format we picked has stencil but user did not ask for it due to hardware
3485 // limitations, use DONT_CARE for load/store. The same logic for depth follows.
3486 if (format.stencilBits == 0)
3487 {
3488 stencilLoadOp = vk::RenderPassLoadOp::DontCare;
3489 stencilStoreOp = vk::RenderPassStoreOp::DontCare;
3490 }
3491 if (format.depthBits == 0)
3492 {
3493 depthLoadOp = vk::RenderPassLoadOp::DontCare;
3494 depthStoreOp = vk::RenderPassStoreOp::DontCare;
3495 }
3496
3497 // Similar to color attachments, if there's a resolve attachment and the multisampled image
3498 // is transient, depth/stencil data need to be unresolved in an initial subpass.
3499 if (depthStencilRenderTarget->hasResolveAttachment() &&
3500 depthStencilRenderTarget->isImageTransient())
3501 {
3502 const bool unresolveDepth = depthLoadOp == vk::RenderPassLoadOp::Load;
3503 const bool unresolveStencil = stencilLoadOp == vk::RenderPassLoadOp::Load;
3504
3505 if (unresolveDepth)
3506 {
3507 depthLoadOp = vk::RenderPassLoadOp::DontCare;
3508 }
3509
3510 if (unresolveStencil)
3511 {
3512 stencilLoadOp = vk::RenderPassLoadOp::DontCare;
3513
3514 // If VK_EXT_shader_stencil_export is not supported, stencil unresolve is done
3515 // through a method that requires stencil to have been cleared.
3516 if (!contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled)
3517 {
3518 stencilLoadOp = vk::RenderPassLoadOp::Clear;
3519
3520 // Note the aspect is only depth here. That's intentional.
3521 VkClearValue clearValue = packedClearValues[depthStencilAttachmentIndex];
3522 clearValue.depthStencil.stencil = 0;
3523 packedClearValues.store(depthStencilAttachmentIndex, VK_IMAGE_ASPECT_DEPTH_BIT,
3524 clearValue);
3525 }
3526 }
3527
3528 if (unresolveDepth || unresolveStencil)
3529 {
3530 if (unresolveDepth)
3531 {
3532 mRenderPassDesc.packDepthUnresolveAttachment();
3533 }
3534 if (unresolveStencil)
3535 {
3536 mRenderPassDesc.packStencilUnresolveAttachment();
3537 }
3538 }
3539 else
3540 {
3541 mRenderPassDesc.removeDepthStencilUnresolveAttachment();
3542 }
3543 }
3544
3545 renderPassAttachmentOps.setOps(depthStencilAttachmentIndex, depthLoadOp, depthStoreOp);
3546 renderPassAttachmentOps.setStencilOps(depthStencilAttachmentIndex, stencilLoadOp,
3547 stencilStoreOp);
3548 }
3549
3550 // If render pass description is changed, the previous render pass desc is no longer compatible.
3551 // Tell the context so that the graphics pipelines can be recreated.
3552 //
3553 // Note that render passes are compatible only if the differences are in loadOp/storeOp values,
3554 // or the existence of resolve attachments in single subpass render passes. The modification
3555 // here can add/remove a subpass, or modify its input attachments.
3556 gl::DrawBufferMask unresolveColorMask = mRenderPassDesc.getColorUnresolveAttachmentMask();
3557 const bool unresolveDepth = mRenderPassDesc.hasDepthUnresolveAttachment();
3558 const bool unresolveStencil = mRenderPassDesc.hasStencilUnresolveAttachment();
3559 const bool unresolveChanged = previousUnresolveColorMask != unresolveColorMask ||
3560 previousUnresolveDepth != unresolveDepth ||
3561 previousUnresolveStencil != unresolveStencil;
3562 if (unresolveChanged)
3563 {
3564 // Make sure framebuffer is recreated.
3565 releaseCurrentFramebuffer(contextVk);
3566
3567 mCurrentFramebufferDesc.updateUnresolveMask(MakeUnresolveAttachmentMask(mRenderPassDesc));
3568 }
3569
3570 vk::RenderPassFramebuffer framebuffer = {};
3571 ANGLE_TRY(getFramebuffer(contextVk, &framebuffer));
3572
3573 // If deferred clears were used in the render pass, the render area must cover the whole
3574 // framebuffer.
3575 ASSERT(!hasDeferredClears || renderArea == getRotatedCompleteRenderArea(contextVk));
3576
3577 ANGLE_TRY(contextVk->beginNewRenderPass(
3578 std::move(framebuffer), renderArea, mRenderPassDesc, renderPassAttachmentOps, colorIndexVk,
3579 depthStencilAttachmentIndex, packedClearValues, commandBufferOut));
3580 mLastRenderPassQueueSerial = contextVk->getStartedRenderPassCommands().getQueueSerial();
3581
3582 // Add the images to the renderpass tracking list (through onColorDraw).
3583 vk::PackedAttachmentIndex colorAttachmentIndex(0);
3584 for (size_t colorIndexGL : mState.getColorAttachmentsMask())
3585 {
3586 RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
3587 colorRenderTarget->onColorDraw(contextVk, mCurrentFramebufferDesc.getLayerCount(),
3588 colorAttachmentIndex);
3589 ++colorAttachmentIndex;
3590 }
3591
3592 if (depthStencilRenderTarget)
3593 {
3594 // This must be called after hasDefined*Content() since it will set content to valid. If
3595 // the attachment ends up not used in the render pass, contents will be marked undefined at
3596 // endRenderPass. The actual layout determination is also deferred until the same time.
3597 depthStencilRenderTarget->onDepthStencilDraw(contextVk,
3598 mCurrentFramebufferDesc.getLayerCount());
3599 }
3600
3601 const bool anyUnresolve = unresolveColorMask.any() || unresolveDepth || unresolveStencil;
3602 if (anyUnresolve)
3603 {
3604 // Unresolve attachments if any.
3605 UtilsVk::UnresolveParameters params;
3606 params.unresolveColorMask = unresolveColorMask;
3607 params.unresolveDepth = unresolveDepth;
3608 params.unresolveStencil = unresolveStencil;
3609
3610 ANGLE_TRY(contextVk->getUtils().unresolve(contextVk, this, params));
3611
3612 // The unresolve subpass has only one draw call.
3613 ANGLE_TRY(contextVk->startNextSubpass());
3614 }
3615
3616 if (unresolveChanged || anyUnresolve)
3617 {
3618 contextVk->onDrawFramebufferRenderPassDescChange(this, renderPassDescChangedOut);
3619 }
3620
3621 // Add fragment shading rate to the tracking list.
3622 if (mCurrentFramebufferDesc.hasFragmentShadingRateAttachment())
3623 {
3624 contextVk->onFragmentShadingRateRead(&mFragmentShadingRateImage);
3625 }
3626
3627 return angle::Result::Continue;
3628 }
3629
getRenderArea(ContextVk * contextVk) const3630 gl::Rectangle FramebufferVk::getRenderArea(ContextVk *contextVk) const
3631 {
3632 if (hasDeferredClears())
3633 {
3634 return getRotatedCompleteRenderArea(contextVk);
3635 }
3636 else
3637 {
3638 return getRotatedScissoredRenderArea(contextVk);
3639 }
3640 }
3641
updateActiveColorMasks(size_t colorIndexGL,bool r,bool g,bool b,bool a)3642 void FramebufferVk::updateActiveColorMasks(size_t colorIndexGL, bool r, bool g, bool b, bool a)
3643 {
3644 gl::BlendStateExt::ColorMaskStorage::SetValueIndexed(
3645 colorIndexGL, gl::BlendStateExt::PackColorMask(r, g, b, a),
3646 &mActiveColorComponentMasksForClear);
3647 }
3648
getEmulatedAlphaAttachmentMask() const3649 const gl::DrawBufferMask &FramebufferVk::getEmulatedAlphaAttachmentMask() const
3650 {
3651 return mEmulatedAlphaAttachmentMask;
3652 }
3653
readPixelsImpl(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,RenderTargetVk * renderTarget,void * pixels)3654 angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
3655 const gl::Rectangle &area,
3656 const PackPixelsParams &packPixelsParams,
3657 VkImageAspectFlagBits copyAspectFlags,
3658 RenderTargetVk *renderTarget,
3659 void *pixels)
3660 {
3661 ANGLE_TRACE_EVENT0("gpu.angle", "FramebufferVk::readPixelsImpl");
3662 gl::LevelIndex levelGL = renderTarget->getLevelIndex();
3663 uint32_t layer = renderTarget->getLayerIndex();
3664 return renderTarget->getImageForCopy().readPixels(contextVk, area, packPixelsParams,
3665 copyAspectFlags, levelGL, layer, pixels);
3666 }
3667
getReadImageExtents() const3668 gl::Extents FramebufferVk::getReadImageExtents() const
3669 {
3670 RenderTargetVk *readRenderTarget = mRenderTargetCache.getColorRead(mState);
3671 return readRenderTarget->getExtents();
3672 }
3673
3674 // Return the framebuffer's non-rotated render area. This is a gl::Rectangle that is based on the
3675 // dimensions of the framebuffer, IS NOT rotated, and IS NOT y-flipped
getNonRotatedCompleteRenderArea() const3676 gl::Rectangle FramebufferVk::getNonRotatedCompleteRenderArea() const
3677 {
3678 const gl::Box &dimensions = mState.getDimensions();
3679 return gl::Rectangle(0, 0, dimensions.width, dimensions.height);
3680 }
3681
3682 // Return the framebuffer's rotated render area. This is a gl::Rectangle that is based on the
3683 // dimensions of the framebuffer, IS ROTATED for the draw FBO, and IS NOT y-flipped
3684 //
3685 // Note: Since the rectangle is not scissored (i.e. x and y are guaranteed to be zero), only the
3686 // width and height must be swapped if the rotation is 90 or 270 degrees.
getRotatedCompleteRenderArea(ContextVk * contextVk) const3687 gl::Rectangle FramebufferVk::getRotatedCompleteRenderArea(ContextVk *contextVk) const
3688 {
3689 gl::Rectangle renderArea = getNonRotatedCompleteRenderArea();
3690 if (contextVk->isRotatedAspectRatioForDrawFBO())
3691 {
3692 // The surface is rotated 90/270 degrees. This changes the aspect ratio of the surface.
3693 std::swap(renderArea.width, renderArea.height);
3694 }
3695 return renderArea;
3696 }
3697
3698 // Return the framebuffer's scissored and rotated render area. This is a gl::Rectangle that is
3699 // based on the dimensions of the framebuffer, is clipped to the scissor, IS ROTATED and IS
3700 // Y-FLIPPED for the draw FBO.
3701 //
3702 // Note: Since the rectangle is scissored, it must be fully rotated, and not just have the width
3703 // and height swapped.
getRotatedScissoredRenderArea(ContextVk * contextVk) const3704 gl::Rectangle FramebufferVk::getRotatedScissoredRenderArea(ContextVk *contextVk) const
3705 {
3706 const gl::Rectangle renderArea = getNonRotatedCompleteRenderArea();
3707 bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO();
3708 gl::Rectangle scissoredArea = ClipRectToScissor(contextVk->getState(), renderArea, false);
3709 gl::Rectangle rotatedScissoredArea;
3710 RotateRectangle(contextVk->getRotationDrawFramebuffer(), invertViewport, renderArea.width,
3711 renderArea.height, scissoredArea, &rotatedScissoredArea);
3712 return rotatedScissoredArea;
3713 }
3714
getSamples() const3715 GLint FramebufferVk::getSamples() const
3716 {
3717 const gl::FramebufferAttachment *lastAttachment = nullptr;
3718
3719 for (size_t colorIndexGL : mState.getEnabledDrawBuffers() & mState.getColorAttachmentsMask())
3720 {
3721 const gl::FramebufferAttachment *color = mState.getColorAttachment(colorIndexGL);
3722 ASSERT(color);
3723
3724 if (color->isRenderToTexture())
3725 {
3726 return color->getSamples();
3727 }
3728
3729 lastAttachment = color;
3730 }
3731 const gl::FramebufferAttachment *depthStencil = mState.getDepthOrStencilAttachment();
3732 if (depthStencil)
3733 {
3734 if (depthStencil->isRenderToTexture())
3735 {
3736 return depthStencil->getSamples();
3737 }
3738 lastAttachment = depthStencil;
3739 }
3740
3741 // If none of the attachments are multisampled-render-to-texture, take the sample count from the
3742 // last attachment (any would have worked, as they would all have the same sample count).
3743 return std::max(lastAttachment ? lastAttachment->getSamples() : 1, 1);
3744 }
3745
flushDeferredClears(ContextVk * contextVk)3746 angle::Result FramebufferVk::flushDeferredClears(ContextVk *contextVk)
3747 {
3748 if (mDeferredClears.empty())
3749 {
3750 return angle::Result::Continue;
3751 }
3752
3753 return contextVk->startRenderPass(getRotatedCompleteRenderArea(contextVk), nullptr, nullptr);
3754 }
3755
switchToFramebufferFetchMode(ContextVk * contextVk,bool hasFramebufferFetch)3756 void FramebufferVk::switchToFramebufferFetchMode(ContextVk *contextVk, bool hasFramebufferFetch)
3757 {
3758 // The switch happens once, and is permanent.
3759 if (mCurrentFramebufferDesc.hasFramebufferFetch() == hasFramebufferFetch)
3760 {
3761 return;
3762 }
3763
3764 // Make sure framebuffer is recreated.
3765 releaseCurrentFramebuffer(contextVk);
3766 mCurrentFramebufferDesc.setFramebufferFetchMode(hasFramebufferFetch);
3767
3768 mRenderPassDesc.setFramebufferFetchMode(hasFramebufferFetch);
3769 contextVk->onDrawFramebufferRenderPassDescChange(this, nullptr);
3770
3771 // Clear the framebuffer cache, as none of the old framebuffers are usable.
3772 if (contextVk->getFeatures().permanentlySwitchToFramebufferFetchMode.enabled)
3773 {
3774 ASSERT(hasFramebufferFetch);
3775 releaseCurrentFramebuffer(contextVk);
3776 }
3777 }
3778
updateLegacyDither(ContextVk * contextVk)3779 bool FramebufferVk::updateLegacyDither(ContextVk *contextVk)
3780 {
3781 if (contextVk->getFeatures().supportsLegacyDithering.enabled &&
3782 mRenderPassDesc.isLegacyDitherEnabled() != contextVk->isDitherEnabled())
3783 {
3784 mRenderPassDesc.setLegacyDither(contextVk->isDitherEnabled());
3785 return true;
3786 }
3787
3788 return false;
3789 }
3790 } // namespace rx
3791