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