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