• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "volk.h"
14 
15 #include "common/debug.h"
16 #include "libANGLE/Context.h"
17 #include "libANGLE/Display.h"
18 #include "libANGLE/formatutils.h"
19 #include "libANGLE/renderer/renderer_utils.h"
20 #include "libANGLE/renderer/vulkan/ContextVk.h"
21 #include "libANGLE/renderer/vulkan/DisplayVk.h"
22 #include "libANGLE/renderer/vulkan/RenderTargetVk.h"
23 #include "libANGLE/renderer/vulkan/RendererVk.h"
24 #include "libANGLE/renderer/vulkan/ResourceVk.h"
25 #include "libANGLE/renderer/vulkan/SurfaceVk.h"
26 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
27 #include "libANGLE/trace.h"
28 
29 namespace rx
30 {
31 
32 namespace
33 {
34 constexpr size_t kMinReadPixelsBufferSize = 128000;
35 
36 // Alignment value to accommodate the largest known, for now, uncompressed Vulkan format
37 // VK_FORMAT_R64G64B64A64_SFLOAT, while supporting 3-component types such as
38 // VK_FORMAT_R16G16B16_SFLOAT.
39 constexpr size_t kReadPixelsBufferAlignment = 32 * 3;
40 
41 // Clear values are only used when loadOp=Clear is set in clearWithRenderPassOp.  When starting a
42 // new render pass, the clear value is set to an unlikely value (bright pink) to stand out better
43 // in case of a bug.
44 constexpr VkClearValue kUninitializedClearValue = {{{0.95, 0.05, 0.95, 0.95}}};
45 
HasSrcBlitFeature(RendererVk * renderer,RenderTargetVk * srcRenderTarget)46 bool HasSrcBlitFeature(RendererVk *renderer, RenderTargetVk *srcRenderTarget)
47 {
48     const VkFormat srcFormat = srcRenderTarget->getImageFormat().vkImageFormat;
49     return renderer->hasImageFormatFeatureBits(srcFormat, VK_FORMAT_FEATURE_BLIT_SRC_BIT);
50 }
51 
HasDstBlitFeature(RendererVk * renderer,RenderTargetVk * dstRenderTarget)52 bool HasDstBlitFeature(RendererVk *renderer, RenderTargetVk *dstRenderTarget)
53 {
54     const VkFormat dstFormat = dstRenderTarget->getImageFormat().vkImageFormat;
55     return renderer->hasImageFormatFeatureBits(dstFormat, VK_FORMAT_FEATURE_BLIT_DST_BIT);
56 }
57 
58 // Returns false if destination has any channel the source doesn't.  This means that channel was
59 // emulated and using the Vulkan blit command would overwrite that emulated channel.
AreSrcAndDstColorChannelsBlitCompatible(RenderTargetVk * srcRenderTarget,RenderTargetVk * dstRenderTarget)60 bool AreSrcAndDstColorChannelsBlitCompatible(RenderTargetVk *srcRenderTarget,
61                                              RenderTargetVk *dstRenderTarget)
62 {
63     const angle::Format &srcFormat = srcRenderTarget->getImageFormat().intendedFormat();
64     const angle::Format &dstFormat = dstRenderTarget->getImageFormat().intendedFormat();
65 
66     // Luminance/alpha formats are not renderable, so they can't have ended up in a framebuffer to
67     // participate in a blit.
68     ASSERT(!dstFormat.isLUMA() && !srcFormat.isLUMA());
69 
70     // All color formats have the red channel.
71     ASSERT(dstFormat.redBits > 0 && srcFormat.redBits > 0);
72 
73     return (dstFormat.greenBits > 0 || srcFormat.greenBits == 0) &&
74            (dstFormat.blueBits > 0 || srcFormat.blueBits == 0) &&
75            (dstFormat.alphaBits > 0 || srcFormat.alphaBits == 0);
76 }
77 
AreSrcAndDstDepthStencilChannelsBlitCompatible(RenderTargetVk * srcRenderTarget,RenderTargetVk * dstRenderTarget)78 bool AreSrcAndDstDepthStencilChannelsBlitCompatible(RenderTargetVk *srcRenderTarget,
79                                                     RenderTargetVk *dstRenderTarget)
80 {
81     const angle::Format &srcFormat = srcRenderTarget->getImageFormat().intendedFormat();
82     const angle::Format &dstFormat = dstRenderTarget->getImageFormat().intendedFormat();
83 
84     return (dstFormat.depthBits > 0 || srcFormat.depthBits == 0) &&
85            (dstFormat.stencilBits > 0 || srcFormat.stencilBits == 0);
86 }
87 }  // anonymous namespace
88 
89 // static
CreateUserFBO(RendererVk * renderer,const gl::FramebufferState & state)90 FramebufferVk *FramebufferVk::CreateUserFBO(RendererVk *renderer, const gl::FramebufferState &state)
91 {
92     return new FramebufferVk(renderer, state, nullptr);
93 }
94 
95 // static
CreateDefaultFBO(RendererVk * renderer,const gl::FramebufferState & state,WindowSurfaceVk * backbuffer)96 FramebufferVk *FramebufferVk::CreateDefaultFBO(RendererVk *renderer,
97                                                const gl::FramebufferState &state,
98                                                WindowSurfaceVk *backbuffer)
99 {
100     return new FramebufferVk(renderer, state, backbuffer);
101 }
102 
FramebufferVk(RendererVk * renderer,const gl::FramebufferState & state,WindowSurfaceVk * backbuffer)103 FramebufferVk::FramebufferVk(RendererVk *renderer,
104                              const gl::FramebufferState &state,
105                              WindowSurfaceVk *backbuffer)
106     : FramebufferImpl(state),
107       mBackbuffer(backbuffer),
108       mFramebuffer(nullptr),
109       mActiveColorComponents(0),
110       mSupportDepthStencilFeedbackLoops(
111           renderer->getFeatures().supportDepthStencilRenderingFeedbackLoops.enabled)
112 {
113     mReadPixelBuffer.init(renderer, VK_BUFFER_USAGE_TRANSFER_DST_BIT, kReadPixelsBufferAlignment,
114                           kMinReadPixelsBufferSize, true);
115 }
116 
117 FramebufferVk::~FramebufferVk() = default;
118 
clearCache(ContextVk * contextVk)119 void FramebufferVk::clearCache(ContextVk *contextVk)
120 {
121     for (auto &entry : mFramebufferCache)
122     {
123         vk::FramebufferHelper &tmpFB = entry.second;
124         tmpFB.release(contextVk);
125     }
126     mFramebufferCache.clear();
127 }
128 
destroy(const gl::Context * context)129 void FramebufferVk::destroy(const gl::Context *context)
130 {
131     ContextVk *contextVk = vk::GetImpl(context);
132 
133     mReadPixelBuffer.release(contextVk->getRenderer());
134     clearCache(contextVk);
135 }
136 
discard(const gl::Context * context,size_t count,const GLenum * attachments)137 angle::Result FramebufferVk::discard(const gl::Context *context,
138                                      size_t count,
139                                      const GLenum *attachments)
140 {
141     return invalidate(context, count, attachments);
142 }
143 
invalidate(const gl::Context * context,size_t count,const GLenum * attachments)144 angle::Result FramebufferVk::invalidate(const gl::Context *context,
145                                         size_t count,
146                                         const GLenum *attachments)
147 {
148     // TODO(jmadill): Re-enable. See http://anglebug.com/4444
149     return angle::Result::Continue;
150 }
151 
invalidateSub(const gl::Context * context,size_t count,const GLenum * attachments,const gl::Rectangle & area)152 angle::Result FramebufferVk::invalidateSub(const gl::Context *context,
153                                            size_t count,
154                                            const GLenum *attachments,
155                                            const gl::Rectangle &area)
156 {
157     // TODO(jmadill): Re-enable. See http://anglebug.com/4444
158     return angle::Result::Continue;
159 }
160 
clear(const gl::Context * context,GLbitfield mask)161 angle::Result FramebufferVk::clear(const gl::Context *context, GLbitfield mask)
162 {
163     ContextVk *contextVk = vk::GetImpl(context);
164 
165     bool clearColor   = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_COLOR_BUFFER_BIT));
166     bool clearDepth   = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_DEPTH_BUFFER_BIT));
167     bool clearStencil = IsMaskFlagSet(mask, static_cast<GLbitfield>(GL_STENCIL_BUFFER_BIT));
168     gl::DrawBufferMask clearColorBuffers;
169     if (clearColor)
170     {
171         clearColorBuffers = mState.getEnabledDrawBuffers();
172     }
173 
174     const VkClearColorValue &clearColorValue = contextVk->getClearColorValue().color;
175     const VkClearDepthStencilValue &clearDepthStencilValue =
176         contextVk->getClearDepthStencilValue().depthStencil;
177 
178     return clearImpl(context, clearColorBuffers, clearDepth, clearStencil, clearColorValue,
179                      clearDepthStencilValue);
180 }
181 
clearImpl(const gl::Context * context,gl::DrawBufferMask clearColorBuffers,bool clearDepth,bool clearStencil,const VkClearColorValue & clearColorValue,const VkClearDepthStencilValue & clearDepthStencilValue)182 angle::Result FramebufferVk::clearImpl(const gl::Context *context,
183                                        gl::DrawBufferMask clearColorBuffers,
184                                        bool clearDepth,
185                                        bool clearStencil,
186                                        const VkClearColorValue &clearColorValue,
187                                        const VkClearDepthStencilValue &clearDepthStencilValue)
188 {
189     ContextVk *contextVk = vk::GetImpl(context);
190 
191     const gl::Rectangle scissoredRenderArea = getScissoredRenderArea(contextVk);
192 
193     // Discard clear altogether if scissor has 0 width or height.
194     if (scissoredRenderArea.width == 0 || scissoredRenderArea.height == 0)
195     {
196         return angle::Result::Continue;
197     }
198 
199     // This function assumes that only enabled attachments are asked to be cleared.
200     ASSERT((clearColorBuffers & mState.getEnabledDrawBuffers()) == clearColorBuffers);
201 
202     // Adjust clear behavior based on whether the respective attachments are present; if asked to
203     // clear a non-existent attachment, don't attempt to clear it.
204 
205     VkColorComponentFlags colorMaskFlags = contextVk->getClearColorMask();
206     bool clearColor                      = clearColorBuffers.any();
207 
208     const gl::FramebufferAttachment *depthAttachment = mState.getDepthAttachment();
209     clearDepth                                       = clearDepth && depthAttachment;
210     ASSERT(!clearDepth || depthAttachment->isAttached());
211 
212     const gl::FramebufferAttachment *stencilAttachment = mState.getStencilAttachment();
213     clearStencil                                       = clearStencil && stencilAttachment;
214     ASSERT(!clearStencil || stencilAttachment->isAttached());
215 
216     uint8_t stencilMask =
217         static_cast<uint8_t>(contextVk->getState().getDepthStencilState().stencilWritemask);
218 
219     // The front-end should ensure we don't attempt to clear color if all channels are masked.
220     ASSERT(!clearColor || colorMaskFlags != 0);
221     // The front-end should ensure we don't attempt to clear depth if depth write is disabled.
222     ASSERT(!clearDepth || contextVk->getState().getDepthStencilState().depthMask);
223     // The front-end should ensure we don't attempt to clear stencil if all bits are masked.
224     ASSERT(!clearStencil || stencilMask != 0);
225 
226     // Special case for rendering feedback loops: clears are always valid in GL since they don't
227     // sample from any textures.
228     if ((clearDepth || clearStencil) && mState.hasDepthStencilFeedbackLoop())
229     {
230         // We currently don't handle scissored clears with rendering feedback loops.
231         ANGLE_VK_CHECK(contextVk, scissoredRenderArea == getCompleteRenderArea(),
232                        VK_ERROR_INCOMPATIBLE_DRIVER);
233 
234         RenderTargetVk *depthStencilRT = mRenderTargetCache.getDepthStencil(true);
235         vk::ImageHelper &image         = depthStencilRT->getImage();
236 
237         vk::CommandBuffer *commandBuffer;
238         ANGLE_TRY(
239             contextVk->onImageWrite(image.getAspectFlags(), vk::ImageLayout::TransferDst, &image));
240         ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
241 
242         VkImageSubresourceRange range;
243         range.aspectMask     = image.getAspectFlags();
244         range.baseMipLevel   = depthStencilRT->getLevelIndex();
245         range.levelCount     = 1;
246         range.baseArrayLayer = depthStencilRT->getLayerIndex();
247         range.layerCount     = 1;
248 
249         commandBuffer->clearDepthStencilImage(image.getImage(),
250                                               VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
251                                               clearDepthStencilValue, 1, &range);
252         clearDepth   = false;
253         clearStencil = false;
254     }
255 
256     // If there is nothing to clear, return right away (for example, if asked to clear depth, but
257     // there is no depth attachment).
258     if (!clearColor && !clearDepth && !clearStencil)
259     {
260         return angle::Result::Continue;
261     }
262 
263     VkClearDepthStencilValue modifiedDepthStencilValue = clearDepthStencilValue;
264 
265     // We can use render pass load ops if clearing depth, unmasked color or unmasked stencil.  If
266     // there's a depth mask, depth clearing is already disabled.
267     bool maskedClearColor =
268         clearColor && (mActiveColorComponents & colorMaskFlags) != mActiveColorComponents;
269     bool maskedClearStencil = stencilMask != 0xFF;
270 
271     bool clearColorWithRenderPassLoadOp   = clearColor && !maskedClearColor;
272     bool clearStencilWithRenderPassLoadOp = clearStencil && !maskedClearStencil;
273 
274     // At least one of color, depth or stencil should be clearable with render pass loadOp for us
275     // to use this clear path.
276     bool clearAnyWithRenderPassLoadOp =
277         clearColorWithRenderPassLoadOp || clearDepth || clearStencilWithRenderPassLoadOp;
278 
279     if (clearAnyWithRenderPassLoadOp)
280     {
281         // Clearing color is indicated by the set bits in this mask.  If not clearing colors with
282         // render pass loadOp, the default value of all-zeros means the clear is not done in
283         // clearWithRenderPassOp below.  In that case, only clear depth/stencil with render pass
284         // loadOp.
285         gl::DrawBufferMask clearBuffersWithRenderPassLoadOp;
286         if (clearColorWithRenderPassLoadOp)
287         {
288             clearBuffersWithRenderPassLoadOp = clearColorBuffers;
289         }
290 
291         ANGLE_TRY(contextVk->clearWithRenderPassOp(
292             scissoredRenderArea, clearBuffersWithRenderPassLoadOp, clearDepth,
293             clearStencilWithRenderPassLoadOp, clearColorValue, modifiedDepthStencilValue));
294 
295         // Fallback to other methods for whatever isn't cleared here.
296         clearDepth = false;
297         if (clearColorWithRenderPassLoadOp)
298         {
299             clearColorBuffers.reset();
300             clearColor = false;
301         }
302         if (clearStencilWithRenderPassLoadOp)
303         {
304             clearStencil = false;
305         }
306 
307         // If nothing left to clear, early out.
308         if (!clearColor && !clearStencil)
309         {
310             return angle::Result::Continue;
311         }
312     }
313 
314     // Note: depth clear is always done through render pass loadOp.
315     ASSERT(clearDepth == false);
316 
317     // The most costly clear mode is when we need to mask out specific color channels or stencil
318     // bits. This can only be done with a draw call.
319     return clearWithDraw(contextVk, scissoredRenderArea, clearColorBuffers, clearStencil,
320                          colorMaskFlags, stencilMask, clearColorValue,
321                          static_cast<uint8_t>(modifiedDepthStencilValue.stencil));
322 }
323 
clearBufferfv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLfloat * values)324 angle::Result FramebufferVk::clearBufferfv(const gl::Context *context,
325                                            GLenum buffer,
326                                            GLint drawbuffer,
327                                            const GLfloat *values)
328 {
329     VkClearValue clearValue = {};
330 
331     bool clearDepth = false;
332     gl::DrawBufferMask clearColorBuffers;
333 
334     if (buffer == GL_DEPTH)
335     {
336         clearDepth                    = true;
337         clearValue.depthStencil.depth = values[0];
338     }
339     else
340     {
341         clearColorBuffers.set(drawbuffer);
342         clearValue.color.float32[0] = values[0];
343         clearValue.color.float32[1] = values[1];
344         clearValue.color.float32[2] = values[2];
345         clearValue.color.float32[3] = values[3];
346     }
347 
348     return clearImpl(context, clearColorBuffers, clearDepth, false, clearValue.color,
349                      clearValue.depthStencil);
350 }
351 
clearBufferuiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLuint * values)352 angle::Result FramebufferVk::clearBufferuiv(const gl::Context *context,
353                                             GLenum buffer,
354                                             GLint drawbuffer,
355                                             const GLuint *values)
356 {
357     VkClearValue clearValue = {};
358 
359     gl::DrawBufferMask clearColorBuffers;
360     clearColorBuffers.set(drawbuffer);
361 
362     clearValue.color.uint32[0] = values[0];
363     clearValue.color.uint32[1] = values[1];
364     clearValue.color.uint32[2] = values[2];
365     clearValue.color.uint32[3] = values[3];
366 
367     return clearImpl(context, clearColorBuffers, false, false, clearValue.color,
368                      clearValue.depthStencil);
369 }
370 
clearBufferiv(const gl::Context * context,GLenum buffer,GLint drawbuffer,const GLint * values)371 angle::Result FramebufferVk::clearBufferiv(const gl::Context *context,
372                                            GLenum buffer,
373                                            GLint drawbuffer,
374                                            const GLint *values)
375 {
376     VkClearValue clearValue = {};
377 
378     bool clearStencil = false;
379     gl::DrawBufferMask clearColorBuffers;
380 
381     if (buffer == GL_STENCIL)
382     {
383         clearStencil = true;
384         clearValue.depthStencil.stencil =
385             gl::clamp(values[0], 0, std::numeric_limits<uint8_t>::max());
386     }
387     else
388     {
389         clearColorBuffers.set(drawbuffer);
390         clearValue.color.int32[0] = values[0];
391         clearValue.color.int32[1] = values[1];
392         clearValue.color.int32[2] = values[2];
393         clearValue.color.int32[3] = values[3];
394     }
395 
396     return clearImpl(context, clearColorBuffers, false, clearStencil, clearValue.color,
397                      clearValue.depthStencil);
398 }
399 
clearBufferfi(const gl::Context * context,GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)400 angle::Result FramebufferVk::clearBufferfi(const gl::Context *context,
401                                            GLenum buffer,
402                                            GLint drawbuffer,
403                                            GLfloat depth,
404                                            GLint stencil)
405 {
406     VkClearValue clearValue = {};
407 
408     clearValue.depthStencil.depth   = depth;
409     clearValue.depthStencil.stencil = gl::clamp(stencil, 0, std::numeric_limits<uint8_t>::max());
410 
411     return clearImpl(context, gl::DrawBufferMask(), true, true, clearValue.color,
412                      clearValue.depthStencil);
413 }
414 
getImplementationColorReadFormat(const gl::Context * context) const415 const gl::InternalFormat &FramebufferVk::getImplementationColorReadFormat(
416     const gl::Context *context) const
417 {
418     ContextVk *contextVk       = vk::GetImpl(context);
419     GLenum sizedFormat         = mState.getReadAttachment()->getFormat().info->sizedInternalFormat;
420     const vk::Format &vkFormat = contextVk->getRenderer()->getFormat(sizedFormat);
421     GLenum implFormat          = vkFormat.actualImageFormat().fboImplementationInternalFormat;
422     return gl::GetSizedInternalFormatInfo(implFormat);
423 }
424 
readPixels(const gl::Context * context,const gl::Rectangle & area,GLenum format,GLenum type,void * pixels)425 angle::Result FramebufferVk::readPixels(const gl::Context *context,
426                                         const gl::Rectangle &area,
427                                         GLenum format,
428                                         GLenum type,
429                                         void *pixels)
430 {
431     // Clip read area to framebuffer.
432     const gl::Extents &fbSize = getState().getReadPixelsAttachment(format)->getSize();
433     const gl::Rectangle fbRect(0, 0, fbSize.width, fbSize.height);
434     ContextVk *contextVk = vk::GetImpl(context);
435 
436     gl::Rectangle clippedArea;
437     if (!ClipRectangle(area, fbRect, &clippedArea))
438     {
439         // nothing to read
440         return angle::Result::Continue;
441     }
442 
443     const gl::State &glState = contextVk->getState();
444     gl::Buffer *packBuffer   = glState.getTargetBuffer(gl::BufferBinding::PixelPack);
445 
446     GLuint outputSkipBytes = 0;
447     PackPixelsParams params;
448     ANGLE_TRY(vk::ImageHelper::GetReadPixelsParams(contextVk, glState.getPackState(), packBuffer,
449                                                    format, type, area, clippedArea, &params,
450                                                    &outputSkipBytes));
451 
452     if (contextVk->isViewportFlipEnabledForReadFBO())
453     {
454         params.area.y          = fbRect.height - clippedArea.y - clippedArea.height;
455         params.reverseRowOrder = !params.reverseRowOrder;
456     }
457 
458     ANGLE_TRY(readPixelsImpl(contextVk, params.area, params, getReadPixelsAspectFlags(format),
459                              getReadPixelsRenderTarget(format),
460                              static_cast<uint8_t *>(pixels) + outputSkipBytes));
461     mReadPixelBuffer.releaseInFlightBuffers(contextVk);
462     return angle::Result::Continue;
463 }
464 
getDepthStencilRenderTarget() const465 RenderTargetVk *FramebufferVk::getDepthStencilRenderTarget() const
466 {
467     // If we mask out depth/stencil feedback loops, do not allow the user to access the looped DS
468     // render target. Passing "false" to getDepthStencil forces a return of "nullptr" for loops.
469     return mRenderTargetCache.getDepthStencil(!mSupportDepthStencilFeedbackLoops);
470 }
471 
getColorDrawRenderTarget(size_t colorIndex) const472 RenderTargetVk *FramebufferVk::getColorDrawRenderTarget(size_t colorIndex) const
473 {
474     RenderTargetVk *renderTarget = mRenderTargetCache.getColorDraw(mState, colorIndex);
475     ASSERT(renderTarget && renderTarget->getImage().valid());
476     return renderTarget;
477 }
478 
getColorReadRenderTarget() const479 RenderTargetVk *FramebufferVk::getColorReadRenderTarget() const
480 {
481     RenderTargetVk *renderTarget = mRenderTargetCache.getColorRead(mState);
482     ASSERT(renderTarget && renderTarget->getImage().valid());
483     return renderTarget;
484 }
485 
getReadPixelsRenderTarget(GLenum format) const486 RenderTargetVk *FramebufferVk::getReadPixelsRenderTarget(GLenum format) const
487 {
488     switch (format)
489     {
490         case GL_DEPTH_COMPONENT:
491         case GL_STENCIL_INDEX_OES:
492             return getDepthStencilRenderTarget();
493         default:
494             return getColorReadRenderTarget();
495     }
496 }
497 
getReadPixelsAspectFlags(GLenum format) const498 VkImageAspectFlagBits FramebufferVk::getReadPixelsAspectFlags(GLenum format) const
499 {
500     switch (format)
501     {
502         case GL_DEPTH_COMPONENT:
503             return VK_IMAGE_ASPECT_DEPTH_BIT;
504         case GL_STENCIL_INDEX_OES:
505             return VK_IMAGE_ASPECT_STENCIL_BIT;
506         default:
507             return VK_IMAGE_ASPECT_COLOR_BIT;
508     }
509 }
510 
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)511 angle::Result FramebufferVk::blitWithCommand(ContextVk *contextVk,
512                                              const gl::Rectangle &sourceArea,
513                                              const gl::Rectangle &destArea,
514                                              RenderTargetVk *readRenderTarget,
515                                              RenderTargetVk *drawRenderTarget,
516                                              GLenum filter,
517                                              bool colorBlit,
518                                              bool depthBlit,
519                                              bool stencilBlit,
520                                              bool flipX,
521                                              bool flipY)
522 {
523     // Since blitRenderbufferRect is called for each render buffer that needs to be blitted,
524     // it should never be the case that both color and depth/stencil need to be blitted at
525     // at the same time.
526     ASSERT(colorBlit != (depthBlit || stencilBlit));
527 
528     vk::ImageHelper *srcImage = &readRenderTarget->getImage();
529     vk::ImageHelper *dstImage = drawRenderTarget->getImageForWrite(contextVk);
530 
531     VkImageAspectFlags imageAspectMask = srcImage->getAspectFlags();
532     VkImageAspectFlags blitAspectMask  = imageAspectMask;
533 
534     // Remove depth or stencil aspects if they are not requested to be blitted.
535     if (!depthBlit)
536     {
537         blitAspectMask &= ~VK_IMAGE_ASPECT_DEPTH_BIT;
538     }
539     if (!stencilBlit)
540     {
541         blitAspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT;
542     }
543 
544     vk::CommandBuffer *commandBuffer = nullptr;
545     ANGLE_TRY(contextVk->onImageRead(imageAspectMask, vk::ImageLayout::TransferSrc, srcImage));
546     ANGLE_TRY(contextVk->onImageWrite(imageAspectMask, vk::ImageLayout::TransferDst, dstImage));
547     ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
548 
549     VkImageBlit blit                   = {};
550     blit.srcSubresource.aspectMask     = blitAspectMask;
551     blit.srcSubresource.mipLevel       = readRenderTarget->getLevelIndex();
552     blit.srcSubresource.baseArrayLayer = readRenderTarget->getLayerIndex();
553     blit.srcSubresource.layerCount     = 1;
554     blit.srcOffsets[0]                 = {sourceArea.x0(), sourceArea.y0(), 0};
555     blit.srcOffsets[1]                 = {sourceArea.x1(), sourceArea.y1(), 1};
556     blit.dstSubresource.aspectMask     = blitAspectMask;
557     blit.dstSubresource.mipLevel       = drawRenderTarget->getLevelIndex();
558     blit.dstSubresource.baseArrayLayer = drawRenderTarget->getLayerIndex();
559     blit.dstSubresource.layerCount     = 1;
560     blit.dstOffsets[0]                 = {destArea.x0(), destArea.y0(), 0};
561     blit.dstOffsets[1]                 = {destArea.x1(), destArea.y1(), 1};
562 
563     commandBuffer->blitImage(srcImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
564                              dstImage->getImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit,
565                              gl_vk::GetFilter(filter));
566 
567     return angle::Result::Continue;
568 }
569 
blit(const gl::Context * context,const gl::Rectangle & sourceAreaIn,const gl::Rectangle & destAreaIn,GLbitfield mask,GLenum filter)570 angle::Result FramebufferVk::blit(const gl::Context *context,
571                                   const gl::Rectangle &sourceAreaIn,
572                                   const gl::Rectangle &destAreaIn,
573                                   GLbitfield mask,
574                                   GLenum filter)
575 {
576     ContextVk *contextVk = vk::GetImpl(context);
577     RendererVk *renderer = contextVk->getRenderer();
578     UtilsVk &utilsVk     = contextVk->getUtils();
579 
580     const gl::State &glState              = contextVk->getState();
581     const gl::Framebuffer *srcFramebuffer = glState.getReadFramebuffer();
582 
583     const bool blitColorBuffer   = (mask & GL_COLOR_BUFFER_BIT) != 0;
584     const bool blitDepthBuffer   = (mask & GL_DEPTH_BUFFER_BIT) != 0;
585     const bool blitStencilBuffer = (mask & GL_STENCIL_BUFFER_BIT) != 0;
586 
587     const bool isResolve =
588         srcFramebuffer->getCachedSamples(context, gl::AttachmentSampleType::Resource) > 1;
589 
590     FramebufferVk *srcFramebufferVk    = vk::GetImpl(srcFramebuffer);
591     const bool srcFramebufferFlippedY  = contextVk->isViewportFlipEnabledForReadFBO();
592     const bool destFramebufferFlippedY = contextVk->isViewportFlipEnabledForDrawFBO();
593 
594     gl::Rectangle sourceArea = sourceAreaIn;
595     gl::Rectangle destArea   = destAreaIn;
596 
597     // Note: GLES (all 3.x versions) require source and dest area to be identical when
598     // resolving.
599     ASSERT(!isResolve ||
600            (sourceArea.x == destArea.x && sourceArea.y == destArea.y &&
601             sourceArea.width == destArea.width && sourceArea.height == destArea.height));
602 
603     const gl::Rectangle srcFramebufferDimensions =
604         srcFramebufferVk->mState.getDimensions().toRect();
605 
606     // If the destination is flipped in either direction, we will flip the source instead so that
607     // the destination area is always unflipped.
608     sourceArea = sourceArea.flip(destArea.isReversedX(), destArea.isReversedY());
609     destArea   = destArea.removeReversal();
610 
611     // Calculate the stretch factor prior to any clipping, as it needs to remain constant.
612     const float stretch[2] = {
613         std::abs(sourceArea.width / static_cast<float>(destArea.width)),
614         std::abs(sourceArea.height / static_cast<float>(destArea.height)),
615     };
616 
617     // First, clip the source area to framebuffer.  That requires transforming the dest area to
618     // match the clipped source.
619     gl::Rectangle absSourceArea = sourceArea.removeReversal();
620     gl::Rectangle clippedSourceArea;
621     if (!gl::ClipRectangle(srcFramebufferDimensions, absSourceArea, &clippedSourceArea))
622     {
623         return angle::Result::Continue;
624     }
625 
626     // Resize the destination area based on the new size of source.  Note again that stretch is
627     // calculated as SrcDimension/DestDimension.
628     gl::Rectangle srcClippedDestArea;
629     if (isResolve)
630     {
631         // Source and dest areas are identical in resolve.
632         srcClippedDestArea = clippedSourceArea;
633     }
634     else if (clippedSourceArea == absSourceArea)
635     {
636         // If there was no clipping, keep dest area as is.
637         srcClippedDestArea = destArea;
638     }
639     else
640     {
641         // Shift dest area's x0,y0,x1,y1 by as much as the source area's got shifted (taking
642         // stretching into account)
643         float x0Shift = std::round((clippedSourceArea.x - absSourceArea.x) / stretch[0]);
644         float y0Shift = std::round((clippedSourceArea.y - absSourceArea.y) / stretch[1]);
645         float x1Shift = std::round((absSourceArea.x1() - clippedSourceArea.x1()) / stretch[0]);
646         float y1Shift = std::round((absSourceArea.y1() - clippedSourceArea.y1()) / stretch[1]);
647 
648         // If the source area was reversed in any direction, the shift should be applied in the
649         // opposite direction as well.
650         if (sourceArea.isReversedX())
651         {
652             std::swap(x0Shift, x1Shift);
653         }
654 
655         if (sourceArea.isReversedY())
656         {
657             std::swap(y0Shift, y1Shift);
658         }
659 
660         srcClippedDestArea.x = destArea.x0() + static_cast<int>(x0Shift);
661         srcClippedDestArea.y = destArea.y0() + static_cast<int>(y0Shift);
662         int x1               = destArea.x1() - static_cast<int>(x1Shift);
663         int y1               = destArea.y1() - static_cast<int>(y1Shift);
664 
665         srcClippedDestArea.width  = x1 - srcClippedDestArea.x;
666         srcClippedDestArea.height = y1 - srcClippedDestArea.y;
667     }
668 
669     // If framebuffers are flipped in Y, flip the source and dest area (which define the
670     // transformation regardless of clipping), as well as the blit area (which is the clipped
671     // dest area).
672     if (srcFramebufferFlippedY)
673     {
674         sourceArea.y      = srcFramebufferDimensions.height - sourceArea.y;
675         sourceArea.height = -sourceArea.height;
676     }
677     if (destFramebufferFlippedY)
678     {
679         destArea.y      = mState.getDimensions().height - destArea.y;
680         destArea.height = -destArea.height;
681 
682         srcClippedDestArea.y =
683             mState.getDimensions().height - srcClippedDestArea.y - srcClippedDestArea.height;
684     }
685 
686     const bool flipX = sourceArea.isReversedX() != destArea.isReversedX();
687     const bool flipY = sourceArea.isReversedY() != destArea.isReversedY();
688 
689     // GLES doesn't allow flipping the parameters of glBlitFramebuffer if performing a resolve.
690     ASSERT(!isResolve ||
691            (flipX == false && flipY == (srcFramebufferFlippedY != destFramebufferFlippedY)));
692 
693     // Again, transfer the destination flip to source, so dest is unflipped.  Note that destArea
694     // was not reversed until the final possible Y-flip.
695     ASSERT(!destArea.isReversedX());
696     sourceArea = sourceArea.flip(false, destArea.isReversedY());
697     destArea   = destArea.removeReversal();
698 
699     // Clip the destination area to the framebuffer size and scissor.  Note that we don't care
700     // about the source area anymore.  The offset translation is done based on the original source
701     // and destination rectangles.  The stretch factor is already calculated as well.
702     gl::Rectangle blitArea;
703     if (!gl::ClipRectangle(getScissoredRenderArea(contextVk), srcClippedDestArea, &blitArea))
704     {
705         return angle::Result::Continue;
706     }
707 
708     bool noClip = blitArea == destArea && stretch[0] == 1.0f && stretch[1] == 1.0f;
709     bool noFlip = !flipX && !flipY;
710     bool disableFlippingBlitWithCommand =
711         contextVk->getRenderer()->getFeatures().disableFlippingBlitWithCommand.enabled;
712 
713     UtilsVk::BlitResolveParameters params;
714     params.srcOffset[0]  = sourceArea.x;
715     params.srcOffset[1]  = sourceArea.y;
716     params.destOffset[0] = destArea.x;
717     params.destOffset[1] = destArea.y;
718     params.stretch[0]    = stretch[0];
719     params.stretch[1]    = stretch[1];
720     params.srcExtents[0] = srcFramebufferDimensions.width;
721     params.srcExtents[1] = srcFramebufferDimensions.height;
722     params.blitArea      = blitArea;
723     params.linear        = filter == GL_LINEAR;
724     params.flipX         = flipX;
725     params.flipY         = flipY;
726 
727     if (blitColorBuffer)
728     {
729         RenderTargetVk *readRenderTarget = srcFramebufferVk->getColorReadRenderTarget();
730         params.srcLayer                  = readRenderTarget->getLayerIndex();
731 
732         // Multisampled images are not allowed to have mips.
733         ASSERT(!isResolve || readRenderTarget->getLevelIndex() == 0);
734 
735         // If there was no clipping and the format capabilities allow us, use Vulkan's builtin blit.
736         // The reason clipping is prohibited in this path is that due to rounding errors, it would
737         // be hard to guarantee the image stretching remains perfect.  That also allows us not to
738         // have to transform back the dest clipping to source.
739         //
740         // For simplicity, we either blit all render targets with a Vulkan command, or none.
741         bool canBlitWithCommand = !isResolve && noClip &&
742                                   (noFlip || !disableFlippingBlitWithCommand) &&
743                                   HasSrcBlitFeature(renderer, readRenderTarget);
744         bool areChannelsBlitCompatible = true;
745         for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
746         {
747             RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
748             canBlitWithCommand =
749                 canBlitWithCommand && HasDstBlitFeature(renderer, drawRenderTarget);
750             areChannelsBlitCompatible =
751                 areChannelsBlitCompatible &&
752                 AreSrcAndDstColorChannelsBlitCompatible(readRenderTarget, drawRenderTarget);
753         }
754 
755         if (canBlitWithCommand && areChannelsBlitCompatible)
756         {
757             for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
758             {
759                 RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
760                 ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget,
761                                           drawRenderTarget, filter, true, false, false, flipX,
762                                           flipY));
763             }
764         }
765         // If we're not flipping, use Vulkan's builtin resolve.
766         else if (isResolve && !flipX && !flipY && areChannelsBlitCompatible)
767         {
768             ANGLE_TRY(resolveColorWithCommand(contextVk, params, &readRenderTarget->getImage()));
769         }
770         // Otherwise use a shader to do blit or resolve.
771         else
772         {
773             const vk::ImageView *readImageView = nullptr;
774             ANGLE_TRY(readRenderTarget->getImageView(contextVk, &readImageView));
775             readRenderTarget->retainImageViews(contextVk);
776             ANGLE_TRY(utilsVk.colorBlitResolve(contextVk, this, &readRenderTarget->getImage(),
777                                                readImageView, params));
778         }
779     }
780 
781     if (blitDepthBuffer || blitStencilBuffer)
782     {
783         RenderTargetVk *readRenderTarget = srcFramebufferVk->getDepthStencilRenderTarget();
784         RenderTargetVk *drawRenderTarget = mRenderTargetCache.getDepthStencil(true);
785         params.srcLayer                  = readRenderTarget->getLayerIndex();
786 
787         // Multisampled images are not allowed to have mips.
788         ASSERT(!isResolve || readRenderTarget->getLevelIndex() == 0);
789 
790         // Similarly, only blit if there's been no clipping.
791         bool canBlitWithCommand = !isResolve && noClip &&
792                                   (noFlip || !disableFlippingBlitWithCommand) &&
793                                   HasSrcBlitFeature(renderer, readRenderTarget) &&
794                                   HasDstBlitFeature(renderer, drawRenderTarget);
795         bool areChannelsBlitCompatible =
796             AreSrcAndDstDepthStencilChannelsBlitCompatible(readRenderTarget, drawRenderTarget);
797 
798         if (canBlitWithCommand && areChannelsBlitCompatible)
799         {
800             ANGLE_TRY(blitWithCommand(contextVk, sourceArea, destArea, readRenderTarget,
801                                       drawRenderTarget, filter, false, blitDepthBuffer,
802                                       blitStencilBuffer, flipX, flipY));
803         }
804         else
805         {
806             // Create depth- and stencil-only views for reading.
807             vk::DeviceScoped<vk::ImageView> depthView(contextVk->getDevice());
808             vk::DeviceScoped<vk::ImageView> stencilView(contextVk->getDevice());
809 
810             vk::ImageHelper *depthStencilImage = &readRenderTarget->getImage();
811             uint32_t levelIndex                = readRenderTarget->getLevelIndex();
812             uint32_t layerIndex                = readRenderTarget->getLayerIndex();
813             gl::TextureType textureType = vk::Get2DTextureType(depthStencilImage->getLayerCount(),
814                                                                depthStencilImage->getSamples());
815 
816             if (blitDepthBuffer)
817             {
818                 ANGLE_TRY(depthStencilImage->initLayerImageView(
819                     contextVk, textureType, VK_IMAGE_ASPECT_DEPTH_BIT, gl::SwizzleState(),
820                     &depthView.get(), levelIndex, 1, layerIndex, 1));
821             }
822 
823             if (blitStencilBuffer)
824             {
825                 ANGLE_TRY(depthStencilImage->initLayerImageView(
826                     contextVk, textureType, VK_IMAGE_ASPECT_STENCIL_BIT, gl::SwizzleState(),
827                     &stencilView.get(), levelIndex, 1, layerIndex, 1));
828             }
829 
830             // If shader stencil export is not possible, defer stencil blit/stencil to another pass.
831             bool hasShaderStencilExport =
832                 contextVk->getRenderer()->getFeatures().supportsShaderStencilExport.enabled;
833 
834             // Blit depth. If shader stencil export is present, blit stencil as well.
835             if (blitDepthBuffer || (blitStencilBuffer && hasShaderStencilExport))
836             {
837                 const vk::ImageView *depth = blitDepthBuffer ? &depthView.get() : nullptr;
838                 const vk::ImageView *stencil =
839                     blitStencilBuffer && hasShaderStencilExport ? &stencilView.get() : nullptr;
840 
841                 ANGLE_TRY(utilsVk.depthStencilBlitResolve(contextVk, this, depthStencilImage, depth,
842                                                           stencil, params));
843             }
844 
845             // If shader stencil export is not present, blit stencil through a different path.
846             if (blitStencilBuffer && !hasShaderStencilExport)
847             {
848                 ANGLE_TRY(utilsVk.stencilBlitResolveNoShaderExport(
849                     contextVk, this, depthStencilImage, &stencilView.get(), params));
850             }
851 
852             vk::ImageView depthViewObject   = depthView.release();
853             vk::ImageView stencilViewObject = stencilView.release();
854 
855             contextVk->addGarbage(&depthViewObject);
856             contextVk->addGarbage(&stencilViewObject);
857         }
858     }
859 
860     return angle::Result::Continue;
861 }  // namespace rx
862 
resolveColorWithCommand(ContextVk * contextVk,const UtilsVk::BlitResolveParameters & params,vk::ImageHelper * srcImage)863 angle::Result FramebufferVk::resolveColorWithCommand(ContextVk *contextVk,
864                                                      const UtilsVk::BlitResolveParameters &params,
865                                                      vk::ImageHelper *srcImage)
866 {
867     vk::CommandBuffer *commandBuffer = nullptr;
868     ANGLE_TRY(
869         contextVk->onImageRead(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferSrc, srcImage));
870 
871     VkImageResolve resolveRegion                = {};
872     resolveRegion.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
873     resolveRegion.srcSubresource.mipLevel       = 0;
874     resolveRegion.srcSubresource.baseArrayLayer = params.srcLayer;
875     resolveRegion.srcSubresource.layerCount     = 1;
876     resolveRegion.srcOffset.x                   = params.srcOffset[0];
877     resolveRegion.srcOffset.y                   = params.srcOffset[1];
878     resolveRegion.srcOffset.z                   = 0;
879     resolveRegion.dstSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
880     resolveRegion.dstSubresource.layerCount     = 1;
881     resolveRegion.dstOffset.x                   = params.destOffset[0];
882     resolveRegion.dstOffset.y                   = params.destOffset[1];
883     resolveRegion.dstOffset.z                   = 0;
884     resolveRegion.extent.width                  = params.srcExtents[0];
885     resolveRegion.extent.height                 = params.srcExtents[1];
886     resolveRegion.extent.depth                  = 1;
887 
888     for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
889     {
890         RenderTargetVk *drawRenderTarget = mRenderTargetCache.getColors()[colorIndexGL];
891         ANGLE_TRY(contextVk->onImageWrite(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst,
892                                           &drawRenderTarget->getImage()));
893         ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
894 
895         resolveRegion.dstSubresource.mipLevel       = drawRenderTarget->getLevelIndex();
896         resolveRegion.dstSubresource.baseArrayLayer = drawRenderTarget->getLayerIndex();
897 
898         srcImage->resolve(&drawRenderTarget->getImage(), resolveRegion, commandBuffer);
899     }
900 
901     return angle::Result::Continue;
902 }
903 
checkStatus(const gl::Context * context) const904 bool FramebufferVk::checkStatus(const gl::Context *context) const
905 {
906     // if we have both a depth and stencil buffer, they must refer to the same object
907     // since we only support packed_depth_stencil and not separate depth and stencil
908     if (mState.hasSeparateDepthAndStencilAttachments())
909     {
910         return false;
911     }
912 
913     return true;
914 }
915 
updateColorAttachment(const gl::Context * context,size_t colorIndexGL)916 angle::Result FramebufferVk::updateColorAttachment(const gl::Context *context, size_t colorIndexGL)
917 {
918     ContextVk *contextVk = vk::GetImpl(context);
919 
920     ANGLE_TRY(mRenderTargetCache.updateColorRenderTarget(context, mState, colorIndexGL));
921 
922     // Update cached masks for masked clears.
923     RenderTargetVk *renderTarget = mRenderTargetCache.getColors()[colorIndexGL];
924     if (renderTarget)
925     {
926         const angle::Format &actualFormat = renderTarget->getImageFormat().actualImageFormat();
927         updateActiveColorMasks(colorIndexGL, actualFormat.redBits > 0, actualFormat.greenBits > 0,
928                                actualFormat.blueBits > 0, actualFormat.alphaBits > 0);
929 
930         const angle::Format &sourceFormat = renderTarget->getImageFormat().intendedFormat();
931         mEmulatedAlphaAttachmentMask.set(colorIndexGL,
932                                          sourceFormat.alphaBits == 0 && actualFormat.alphaBits > 0);
933 
934         contextVk->updateColorMask(context->getState().getBlendState());
935     }
936     else
937     {
938         updateActiveColorMasks(colorIndexGL, false, false, false, false);
939     }
940 
941     return angle::Result::Continue;
942 }
943 
invalidateImpl(ContextVk * contextVk,size_t count,const GLenum * attachments)944 angle::Result FramebufferVk::invalidateImpl(ContextVk *contextVk,
945                                             size_t count,
946                                             const GLenum *attachments)
947 {
948     ASSERT(contextVk->hasStartedRenderPass());
949 
950     gl::DrawBufferMask invalidateColorBuffers;
951     bool invalidateDepthBuffer   = false;
952     bool invalidateStencilBuffer = false;
953 
954     for (size_t i = 0; i < count; ++i)
955     {
956         const GLenum attachment = attachments[i];
957 
958         switch (attachment)
959         {
960             case GL_DEPTH:
961             case GL_DEPTH_ATTACHMENT:
962                 invalidateDepthBuffer = true;
963                 break;
964             case GL_STENCIL:
965             case GL_STENCIL_ATTACHMENT:
966                 invalidateStencilBuffer = true;
967                 break;
968             case GL_DEPTH_STENCIL_ATTACHMENT:
969                 invalidateDepthBuffer   = true;
970                 invalidateStencilBuffer = true;
971                 break;
972             default:
973                 ASSERT(
974                     (attachment >= GL_COLOR_ATTACHMENT0 && attachment <= GL_COLOR_ATTACHMENT15) ||
975                     (attachment == GL_COLOR));
976 
977                 invalidateColorBuffers.set(
978                     attachment == GL_COLOR ? 0u : (attachment - GL_COLOR_ATTACHMENT0));
979         }
980     }
981 
982     // Set the appropriate storeOp for attachments.
983     size_t attachmentIndexVk = 0;
984     for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
985     {
986         if (invalidateColorBuffers.test(colorIndexGL))
987         {
988             contextVk->getStartedRenderPassCommands().invalidateRenderPassColorAttachment(
989                 attachmentIndexVk);
990         }
991         ++attachmentIndexVk;
992     }
993 
994     RenderTargetVk *depthStencilRenderTarget = mRenderTargetCache.getDepthStencil(true);
995     if (depthStencilRenderTarget)
996     {
997         if (invalidateDepthBuffer)
998         {
999             contextVk->getStartedRenderPassCommands().invalidateRenderPassDepthAttachment(
1000                 attachmentIndexVk);
1001         }
1002 
1003         if (invalidateStencilBuffer)
1004         {
1005             contextVk->getStartedRenderPassCommands().invalidateRenderPassStencilAttachment(
1006                 attachmentIndexVk);
1007         }
1008     }
1009 
1010     // NOTE: Possible future optimization is to delay setting the storeOp and only do so if the
1011     // render pass is closed by itself before another draw call.  Otherwise, in a situation like
1012     // this:
1013     //
1014     //     draw()
1015     //     invalidate()
1016     //     draw()
1017     //
1018     // We would be discarding the attachments only to load them for the next draw (which is less
1019     // efficient than keeping the render pass open and not do the discard at all).  While dEQP tests
1020     // this pattern, this optimization may not be necessary if no application does this.  It is
1021     // expected that an application would invalidate() when it's done with the framebuffer, so the
1022     // render pass would have closed either way.
1023     ANGLE_TRY(contextVk->endRenderPass());
1024 
1025     return angle::Result::Continue;
1026 }
1027 
updateDepthStencilAttachmentSerial(ContextVk * contextVk)1028 void FramebufferVk::updateDepthStencilAttachmentSerial(ContextVk *contextVk)
1029 {
1030     RenderTargetVk *depthStencilRT = getDepthStencilRenderTarget();
1031 
1032     if (depthStencilRT != nullptr)
1033     {
1034         mCurrentFramebufferDesc.update(vk::kFramebufferDescDepthStencilIndex,
1035                                        depthStencilRT->getAssignSerial(contextVk));
1036     }
1037     else
1038     {
1039         mCurrentFramebufferDesc.update(vk::kFramebufferDescDepthStencilIndex,
1040                                        vk::kZeroAttachmentSerial);
1041     }
1042 }
1043 
syncState(const gl::Context * context,GLenum binding,const gl::Framebuffer::DirtyBits & dirtyBits)1044 angle::Result FramebufferVk::syncState(const gl::Context *context,
1045                                        GLenum binding,
1046                                        const gl::Framebuffer::DirtyBits &dirtyBits)
1047 {
1048     ContextVk *contextVk = vk::GetImpl(context);
1049 
1050     vk::FramebufferDesc priorFramebufferDesc = mCurrentFramebufferDesc;
1051 
1052     // For any updated attachments we'll update their Serials below
1053     ASSERT(dirtyBits.any());
1054     for (size_t dirtyBit : dirtyBits)
1055     {
1056         switch (dirtyBit)
1057         {
1058             case gl::Framebuffer::DIRTY_BIT_DEPTH_ATTACHMENT:
1059                 ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState));
1060                 updateDepthStencilAttachmentSerial(contextVk);
1061                 break;
1062             case gl::Framebuffer::DIRTY_BIT_STENCIL_ATTACHMENT:
1063                 ANGLE_TRY(mRenderTargetCache.updateDepthStencilRenderTarget(context, mState));
1064                 updateDepthStencilAttachmentSerial(contextVk);
1065                 break;
1066             case gl::Framebuffer::DIRTY_BIT_DEPTH_BUFFER_CONTENTS:
1067             case gl::Framebuffer::DIRTY_BIT_STENCIL_BUFFER_CONTENTS:
1068                 updateDepthStencilAttachmentSerial(contextVk);
1069                 break;
1070             case gl::Framebuffer::DIRTY_BIT_READ_BUFFER:
1071                 ANGLE_TRY(mRenderTargetCache.update(context, mState, dirtyBits));
1072                 break;
1073             case gl::Framebuffer::DIRTY_BIT_DRAW_BUFFERS:
1074                 // Force update of serial for enabled draw buffers
1075                 mCurrentFramebufferDesc.reset();
1076                 for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1077                 {
1078                     mCurrentFramebufferDesc.update(
1079                         static_cast<uint32_t>(colorIndexGL),
1080                         mRenderTargetCache.getColors()[colorIndexGL]->getAssignSerial(contextVk));
1081                 }
1082                 updateDepthStencilAttachmentSerial(contextVk);
1083                 break;
1084             case gl::Framebuffer::DIRTY_BIT_DEFAULT_WIDTH:
1085             case gl::Framebuffer::DIRTY_BIT_DEFAULT_HEIGHT:
1086             case gl::Framebuffer::DIRTY_BIT_DEFAULT_SAMPLES:
1087             case gl::Framebuffer::DIRTY_BIT_DEFAULT_FIXED_SAMPLE_LOCATIONS:
1088                 // Invalidate the cache. If we have performance critical code hitting this path we
1089                 // can add related data (such as width/height) to the cache
1090                 clearCache(contextVk);
1091                 break;
1092             default:
1093             {
1094                 static_assert(gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0 == 0, "FB dirty bits");
1095                 uint32_t colorIndexGL;
1096                 if (dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_MAX)
1097                 {
1098                     colorIndexGL = static_cast<uint32_t>(
1099                         dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_ATTACHMENT_0);
1100                     ANGLE_TRY(updateColorAttachment(context, colorIndexGL));
1101                 }
1102                 else
1103                 {
1104                     ASSERT(dirtyBit >= gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 &&
1105                            dirtyBit < gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_MAX);
1106                     colorIndexGL = static_cast<uint32_t>(
1107                         dirtyBit - gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0);
1108                     ANGLE_TRY(mRenderTargetCache.getColors()[colorIndexGL]->flushStagedUpdates(
1109                         contextVk));
1110                 }
1111 
1112                 RenderTargetVk *renderTarget = mRenderTargetCache.getColors()[colorIndexGL];
1113 
1114                 if (renderTarget && mState.getEnabledDrawBuffers()[colorIndexGL])
1115                 {
1116                     mCurrentFramebufferDesc.update(colorIndexGL,
1117                                                    renderTarget->getAssignSerial(contextVk));
1118                 }
1119                 else
1120                 {
1121                     mCurrentFramebufferDesc.update(colorIndexGL, vk::kZeroAttachmentSerial);
1122                 }
1123                 break;
1124             }
1125         }
1126     }
1127 
1128     // No-op redundant changes to prevent closing the RenderPass.
1129     if (mCurrentFramebufferDesc == priorFramebufferDesc)
1130     {
1131         return angle::Result::Continue;
1132     }
1133 
1134     // The FBO's new attachment may have changed the renderable area
1135     const gl::State &glState = context->getState();
1136     ANGLE_TRY(contextVk->updateScissor(glState));
1137 
1138     mActiveColorComponents = gl_vk::GetColorComponentFlags(
1139         mActiveColorComponentMasksForClear[0].any(), mActiveColorComponentMasksForClear[1].any(),
1140         mActiveColorComponentMasksForClear[2].any(), mActiveColorComponentMasksForClear[3].any());
1141 
1142     ANGLE_TRY(contextVk->endRenderPass());
1143 
1144     // Notify the ContextVk to update the pipeline desc.
1145     updateRenderPassDesc();
1146 
1147     FramebufferVk *currentDrawFramebuffer = vk::GetImpl(context->getState().getDrawFramebuffer());
1148     if (currentDrawFramebuffer == this)
1149     {
1150         contextVk->onDrawFramebufferChange(this);
1151     }
1152     // Deactivate Framebuffer
1153     mFramebuffer = nullptr;
1154 
1155     return angle::Result::Continue;
1156 }
1157 
updateRenderPassDesc()1158 void FramebufferVk::updateRenderPassDesc()
1159 {
1160     mRenderPassDesc = {};
1161     mRenderPassDesc.setSamples(getSamples());
1162 
1163     const auto &colorRenderTargets              = mRenderTargetCache.getColors();
1164     const gl::DrawBufferMask enabledDrawBuffers = mState.getEnabledDrawBuffers();
1165     for (size_t colorIndexGL = 0; colorIndexGL < enabledDrawBuffers.size(); ++colorIndexGL)
1166     {
1167         if (enabledDrawBuffers[colorIndexGL])
1168         {
1169             RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
1170             ASSERT(colorRenderTarget);
1171             mRenderPassDesc.packColorAttachment(
1172                 colorIndexGL, colorRenderTarget->getImage().getFormat().intendedFormatID);
1173         }
1174         else
1175         {
1176             mRenderPassDesc.packColorAttachmentGap(colorIndexGL);
1177         }
1178     }
1179 
1180     RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
1181     if (depthStencilRenderTarget)
1182     {
1183         mRenderPassDesc.packDepthStencilAttachment(
1184             depthStencilRenderTarget->getImage().getFormat().intendedFormatID);
1185     }
1186 }
1187 
getFramebuffer(ContextVk * contextVk,vk::Framebuffer ** framebufferOut)1188 angle::Result FramebufferVk::getFramebuffer(ContextVk *contextVk, vk::Framebuffer **framebufferOut)
1189 {
1190     // First return a presently valid Framebuffer
1191     if (mFramebuffer != nullptr)
1192     {
1193         *framebufferOut = &mFramebuffer->getFramebuffer();
1194         return angle::Result::Continue;
1195     }
1196     // No current FB, so now check for previously cached Framebuffer
1197     auto iter = mFramebufferCache.find(mCurrentFramebufferDesc);
1198     if (iter != mFramebufferCache.end())
1199     {
1200         if (contextVk->getRenderer()->getFeatures().enableFramebufferVkCache.enabled)
1201         {
1202             *framebufferOut = &iter->second.getFramebuffer();
1203             return angle::Result::Continue;
1204         }
1205         else
1206         {
1207             // When cache is off just release previous entry, it will be recreated below
1208             iter->second.release(contextVk);
1209         }
1210     }
1211     vk::RenderPass *compatibleRenderPass = nullptr;
1212     ANGLE_TRY(contextVk->getCompatibleRenderPass(mRenderPassDesc, &compatibleRenderPass));
1213 
1214     // If we've a Framebuffer provided by a Surface (default FBO/backbuffer), query it.
1215     if (mBackbuffer)
1216     {
1217         return mBackbuffer->getCurrentFramebuffer(contextVk, *compatibleRenderPass, framebufferOut);
1218     }
1219 
1220     // Gather VkImageViews over all FBO attachments, also size of attached region.
1221     std::vector<VkImageView> attachments;
1222     gl::Extents attachmentsSize;
1223 
1224     const auto &colorRenderTargets = mRenderTargetCache.getColors();
1225     for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1226     {
1227         RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
1228         ASSERT(colorRenderTarget);
1229 
1230         const vk::ImageView *imageView = nullptr;
1231         ANGLE_TRY(colorRenderTarget->getImageView(contextVk, &imageView));
1232 
1233         attachments.push_back(imageView->getHandle());
1234 
1235         ASSERT(attachmentsSize.empty() || attachmentsSize == colorRenderTarget->getExtents());
1236         attachmentsSize = colorRenderTarget->getExtents();
1237     }
1238 
1239     RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
1240     if (depthStencilRenderTarget)
1241     {
1242         const vk::ImageView *imageView = nullptr;
1243         ANGLE_TRY(depthStencilRenderTarget->getImageView(contextVk, &imageView));
1244 
1245         attachments.push_back(imageView->getHandle());
1246 
1247         ASSERT(attachmentsSize.empty() ||
1248                attachmentsSize == depthStencilRenderTarget->getExtents());
1249         attachmentsSize = depthStencilRenderTarget->getExtents();
1250     }
1251 
1252     if (attachmentsSize.empty())
1253     {
1254         // No attachments, so use the default values.
1255         attachmentsSize.height = mState.getDefaultHeight();
1256         attachmentsSize.width  = mState.getDefaultWidth();
1257         attachmentsSize.depth  = 0;
1258     }
1259     VkFramebufferCreateInfo framebufferInfo = {};
1260 
1261     framebufferInfo.sType           = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1262     framebufferInfo.flags           = 0;
1263     framebufferInfo.renderPass      = compatibleRenderPass->getHandle();
1264     framebufferInfo.attachmentCount = static_cast<uint32_t>(attachments.size());
1265     framebufferInfo.pAttachments    = attachments.data();
1266     framebufferInfo.width           = static_cast<uint32_t>(attachmentsSize.width);
1267     framebufferInfo.height          = static_cast<uint32_t>(attachmentsSize.height);
1268     framebufferInfo.layers          = 1;
1269 
1270     vk::FramebufferHelper newFramebuffer;
1271     ANGLE_TRY(newFramebuffer.init(contextVk, framebufferInfo));
1272 
1273     // Sanity check that our description matches our attachments. Can catch implementation bugs.
1274     ASSERT(static_cast<uint32_t>(attachments.size()) == mCurrentFramebufferDesc.attachmentCount());
1275 
1276     mFramebufferCache[mCurrentFramebufferDesc] = std::move(newFramebuffer);
1277     mFramebuffer                               = &mFramebufferCache[mCurrentFramebufferDesc];
1278     *framebufferOut                            = &mFramebuffer->getFramebuffer();
1279     return angle::Result::Continue;
1280 }
1281 
clearWithDraw(ContextVk * contextVk,const gl::Rectangle & clearArea,gl::DrawBufferMask clearColorBuffers,bool clearStencil,VkColorComponentFlags colorMaskFlags,uint8_t stencilMask,const VkClearColorValue & clearColorValue,uint8_t clearStencilValue)1282 angle::Result FramebufferVk::clearWithDraw(ContextVk *contextVk,
1283                                            const gl::Rectangle &clearArea,
1284                                            gl::DrawBufferMask clearColorBuffers,
1285                                            bool clearStencil,
1286                                            VkColorComponentFlags colorMaskFlags,
1287                                            uint8_t stencilMask,
1288                                            const VkClearColorValue &clearColorValue,
1289                                            uint8_t clearStencilValue)
1290 {
1291     UtilsVk::ClearFramebufferParameters params = {};
1292     params.clearArea                           = clearArea;
1293     params.colorClearValue                     = clearColorValue;
1294     params.stencilClearValue                   = clearStencilValue;
1295     params.stencilMask                         = stencilMask;
1296 
1297     params.clearColor   = true;
1298     params.clearStencil = clearStencil;
1299 
1300     const auto &colorRenderTargets = mRenderTargetCache.getColors();
1301     for (size_t colorIndexGL : clearColorBuffers)
1302     {
1303         const RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
1304         ASSERT(colorRenderTarget);
1305 
1306         params.colorFormat = &colorRenderTarget->getImage().getFormat().actualImageFormat();
1307         params.colorAttachmentIndexGL = static_cast<uint32_t>(colorIndexGL);
1308         params.colorMaskFlags         = colorMaskFlags;
1309         if (mEmulatedAlphaAttachmentMask[colorIndexGL])
1310         {
1311             params.colorMaskFlags &= ~VK_COLOR_COMPONENT_A_BIT;
1312         }
1313 
1314         ANGLE_TRY(contextVk->getUtils().clearFramebuffer(contextVk, this, params));
1315 
1316         // Clear stencil only once!
1317         params.clearStencil = false;
1318     }
1319 
1320     // If there was no color clear, clear stencil alone.
1321     if (params.clearStencil)
1322     {
1323         params.clearColor = false;
1324         ANGLE_TRY(contextVk->getUtils().clearFramebuffer(contextVk, this, params));
1325     }
1326 
1327     return angle::Result::Continue;
1328 }
1329 
getSamplePosition(const gl::Context * context,size_t index,GLfloat * xy) const1330 angle::Result FramebufferVk::getSamplePosition(const gl::Context *context,
1331                                                size_t index,
1332                                                GLfloat *xy) const
1333 {
1334     int sampleCount = getSamples();
1335     rx::GetSamplePosition(sampleCount, index, xy);
1336     return angle::Result::Continue;
1337 }
1338 
startNewRenderPass(ContextVk * contextVk,const gl::Rectangle & renderArea,vk::CommandBuffer ** commandBufferOut)1339 angle::Result FramebufferVk::startNewRenderPass(ContextVk *contextVk,
1340                                                 const gl::Rectangle &renderArea,
1341                                                 vk::CommandBuffer **commandBufferOut)
1342 {
1343     vk::Framebuffer *framebuffer = nullptr;
1344     ANGLE_TRY(getFramebuffer(contextVk, &framebuffer));
1345 
1346     vk::AttachmentOpsArray renderPassAttachmentOps;
1347     std::vector<VkClearValue> attachmentClearValues;
1348 
1349     ANGLE_TRY(contextVk->endRenderPass());
1350 
1351     // Initialize RenderPass info.
1352     const auto &colorRenderTargets = mRenderTargetCache.getColors();
1353     for (size_t colorIndexGL : mState.getEnabledDrawBuffers())
1354     {
1355         RenderTargetVk *colorRenderTarget = colorRenderTargets[colorIndexGL];
1356         ASSERT(colorRenderTarget);
1357 
1358         ANGLE_TRY(colorRenderTarget->onColorDraw(contextVk));
1359 
1360         renderPassAttachmentOps.initWithStore(
1361             attachmentClearValues.size(), VK_ATTACHMENT_LOAD_OP_LOAD,
1362             vk::ImageLayout::ColorAttachment, vk::ImageLayout::ColorAttachment);
1363         attachmentClearValues.emplace_back(kUninitializedClearValue);
1364     }
1365 
1366     RenderTargetVk *depthStencilRenderTarget = getDepthStencilRenderTarget();
1367     if (depthStencilRenderTarget)
1368     {
1369         VkAttachmentLoadOp loadOp;
1370         if (depthStencilRenderTarget->hasDefinedContent())
1371         {
1372             loadOp = VK_ATTACHMENT_LOAD_OP_LOAD;
1373         }
1374         else
1375         {
1376             loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
1377         }
1378         renderPassAttachmentOps.initWithStore(attachmentClearValues.size(), loadOp,
1379                                               vk::ImageLayout::DepthStencilAttachment,
1380                                               vk::ImageLayout::DepthStencilAttachment);
1381 
1382         // This must be called after hasDefinedContent() since it will set content to valid. We are
1383         // tracking content valid very loosely here that as long as it is attached, it assumes will
1384         // have valid content. The only time it has undefined content is between swap and
1385         // startNewRenderPass
1386         ANGLE_TRY(depthStencilRenderTarget->onDepthStencilDraw(contextVk));
1387 
1388         attachmentClearValues.emplace_back(kUninitializedClearValue);
1389     }
1390 
1391     return contextVk->flushAndBeginRenderPass(*framebuffer, renderArea, mRenderPassDesc,
1392                                               renderPassAttachmentOps, attachmentClearValues,
1393                                               commandBufferOut);
1394 }
1395 
updateActiveColorMasks(size_t colorIndexGL,bool r,bool g,bool b,bool a)1396 void FramebufferVk::updateActiveColorMasks(size_t colorIndexGL, bool r, bool g, bool b, bool a)
1397 {
1398     mActiveColorComponentMasksForClear[0].set(colorIndexGL, r);
1399     mActiveColorComponentMasksForClear[1].set(colorIndexGL, g);
1400     mActiveColorComponentMasksForClear[2].set(colorIndexGL, b);
1401     mActiveColorComponentMasksForClear[3].set(colorIndexGL, a);
1402 }
1403 
getEmulatedAlphaAttachmentMask() const1404 const gl::DrawBufferMask &FramebufferVk::getEmulatedAlphaAttachmentMask() const
1405 {
1406     return mEmulatedAlphaAttachmentMask;
1407 }
1408 
readPixelsImpl(ContextVk * contextVk,const gl::Rectangle & area,const PackPixelsParams & packPixelsParams,VkImageAspectFlagBits copyAspectFlags,RenderTargetVk * renderTarget,void * pixels)1409 angle::Result FramebufferVk::readPixelsImpl(ContextVk *contextVk,
1410                                             const gl::Rectangle &area,
1411                                             const PackPixelsParams &packPixelsParams,
1412                                             VkImageAspectFlagBits copyAspectFlags,
1413                                             RenderTargetVk *renderTarget,
1414                                             void *pixels)
1415 {
1416     ANGLE_TRACE_EVENT0("gpu.angle", "FramebufferVk::readPixelsImpl");
1417     uint32_t level = renderTarget->getLevelIndex();
1418     uint32_t layer = renderTarget->getLayerIndex();
1419     return renderTarget->getImage().readPixels(contextVk, area, packPixelsParams, copyAspectFlags,
1420                                                level, layer, pixels, &mReadPixelBuffer);
1421 }
1422 
getReadImageExtents() const1423 gl::Extents FramebufferVk::getReadImageExtents() const
1424 {
1425     RenderTargetVk *readRenderTarget = mRenderTargetCache.getColorRead(mState);
1426 
1427     ASSERT(readRenderTarget->getExtents().width == mState.getDimensions().width);
1428     ASSERT(readRenderTarget->getExtents().height == mState.getDimensions().height);
1429 
1430     return readRenderTarget->getExtents();
1431 }
1432 
getCompleteRenderArea() const1433 gl::Rectangle FramebufferVk::getCompleteRenderArea() const
1434 {
1435     const gl::Box &dimensions = mState.getDimensions();
1436     return gl::Rectangle(0, 0, dimensions.width, dimensions.height);
1437 }
1438 
getScissoredRenderArea(ContextVk * contextVk) const1439 gl::Rectangle FramebufferVk::getScissoredRenderArea(ContextVk *contextVk) const
1440 {
1441     const gl::Box &dimensions = mState.getDimensions();
1442     const gl::Rectangle renderArea(0, 0, dimensions.width, dimensions.height);
1443     bool invertViewport = contextVk->isViewportFlipEnabledForDrawFBO();
1444 
1445     return ClipRectToScissor(contextVk->getState(), renderArea, invertViewport);
1446 }
1447 
getFirstRenderTarget() const1448 RenderTargetVk *FramebufferVk::getFirstRenderTarget() const
1449 {
1450     for (auto *renderTarget : mRenderTargetCache.getColors())
1451     {
1452         if (renderTarget)
1453         {
1454             return renderTarget;
1455         }
1456     }
1457 
1458     return getDepthStencilRenderTarget();
1459 }
1460 
getSamples() const1461 GLint FramebufferVk::getSamples() const
1462 {
1463     RenderTargetVk *firstRT = getFirstRenderTarget();
1464     return firstRT ? firstRT->getImage().getSamples() : 0;
1465 }
1466 
1467 }  // namespace rx
1468