xref: /aosp_15_r20/external/angle/src/libANGLE/renderer/vulkan/SurfaceVk.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker //
2*8975f5c5SAndroid Build Coastguard Worker // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3*8975f5c5SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
4*8975f5c5SAndroid Build Coastguard Worker // found in the LICENSE file.
5*8975f5c5SAndroid Build Coastguard Worker //
6*8975f5c5SAndroid Build Coastguard Worker // SurfaceVk.cpp:
7*8975f5c5SAndroid Build Coastguard Worker //    Implements the class methods for SurfaceVk.
8*8975f5c5SAndroid Build Coastguard Worker //
9*8975f5c5SAndroid Build Coastguard Worker 
10*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/SurfaceVk.h"
11*8975f5c5SAndroid Build Coastguard Worker 
12*8975f5c5SAndroid Build Coastguard Worker #include "common/debug.h"
13*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Context.h"
14*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Display.h"
15*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Overlay.h"
16*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/Surface.h"
17*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/driver_utils.h"
18*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/ContextVk.h"
19*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/DisplayVk.h"
20*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/FramebufferVk.h"
21*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/OverlayVk.h"
22*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/vk_format_utils.h"
23*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/renderer/vulkan/vk_renderer.h"
24*8975f5c5SAndroid Build Coastguard Worker #include "libANGLE/trace.h"
25*8975f5c5SAndroid Build Coastguard Worker 
26*8975f5c5SAndroid Build Coastguard Worker namespace rx
27*8975f5c5SAndroid Build Coastguard Worker {
28*8975f5c5SAndroid Build Coastguard Worker 
29*8975f5c5SAndroid Build Coastguard Worker namespace
30*8975f5c5SAndroid Build Coastguard Worker {
31*8975f5c5SAndroid Build Coastguard Worker angle::SubjectIndex kAnySurfaceImageSubjectIndex = 0;
32*8975f5c5SAndroid Build Coastguard Worker 
33*8975f5c5SAndroid Build Coastguard Worker // Special value for currentExtent if surface size is determined by the swapchain's extent.  See
34*8975f5c5SAndroid Build Coastguard Worker // the VkSurfaceCapabilitiesKHR spec for more details.
35*8975f5c5SAndroid Build Coastguard Worker constexpr uint32_t kSurfaceSizedBySwapchain = 0xFFFFFFFFu;
36*8975f5c5SAndroid Build Coastguard Worker 
37*8975f5c5SAndroid Build Coastguard Worker // Special value for ImagePresentOperation::imageIndex meaning that VK_EXT_swapchain_maintenance1 is
38*8975f5c5SAndroid Build Coastguard Worker // supported and fence is used instead of queueSerial.
39*8975f5c5SAndroid Build Coastguard Worker constexpr uint32_t kInvalidImageIndex = std::numeric_limits<uint32_t>::max();
40*8975f5c5SAndroid Build Coastguard Worker 
GetSampleCount(const egl::Config * config)41*8975f5c5SAndroid Build Coastguard Worker GLint GetSampleCount(const egl::Config *config)
42*8975f5c5SAndroid Build Coastguard Worker {
43*8975f5c5SAndroid Build Coastguard Worker     GLint samples = 1;
44*8975f5c5SAndroid Build Coastguard Worker     if (config->sampleBuffers && config->samples > 1)
45*8975f5c5SAndroid Build Coastguard Worker     {
46*8975f5c5SAndroid Build Coastguard Worker         samples = config->samples;
47*8975f5c5SAndroid Build Coastguard Worker     }
48*8975f5c5SAndroid Build Coastguard Worker     return samples;
49*8975f5c5SAndroid Build Coastguard Worker }
50*8975f5c5SAndroid Build Coastguard Worker 
GetDesiredPresentMode(const std::vector<vk::PresentMode> & presentModes,EGLint interval)51*8975f5c5SAndroid Build Coastguard Worker vk::PresentMode GetDesiredPresentMode(const std::vector<vk::PresentMode> &presentModes,
52*8975f5c5SAndroid Build Coastguard Worker                                       EGLint interval)
53*8975f5c5SAndroid Build Coastguard Worker {
54*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!presentModes.empty());
55*8975f5c5SAndroid Build Coastguard Worker 
56*8975f5c5SAndroid Build Coastguard Worker     // If v-sync is enabled, use FIFO, which throttles you to the display rate and is guaranteed to
57*8975f5c5SAndroid Build Coastguard Worker     // always be supported.
58*8975f5c5SAndroid Build Coastguard Worker     if (interval > 0)
59*8975f5c5SAndroid Build Coastguard Worker     {
60*8975f5c5SAndroid Build Coastguard Worker         return vk::PresentMode::FifoKHR;
61*8975f5c5SAndroid Build Coastguard Worker     }
62*8975f5c5SAndroid Build Coastguard Worker 
63*8975f5c5SAndroid Build Coastguard Worker     // Otherwise, choose either of the following, if available, in order specified here:
64*8975f5c5SAndroid Build Coastguard Worker     //
65*8975f5c5SAndroid Build Coastguard Worker     // - Mailbox is similar to triple-buffering.
66*8975f5c5SAndroid Build Coastguard Worker     // - Immediate is similar to single-buffering.
67*8975f5c5SAndroid Build Coastguard Worker     //
68*8975f5c5SAndroid Build Coastguard Worker     // If neither is supported, we fallback to FIFO.
69*8975f5c5SAndroid Build Coastguard Worker 
70*8975f5c5SAndroid Build Coastguard Worker     bool mailboxAvailable   = false;
71*8975f5c5SAndroid Build Coastguard Worker     bool immediateAvailable = false;
72*8975f5c5SAndroid Build Coastguard Worker     bool sharedPresent      = false;
73*8975f5c5SAndroid Build Coastguard Worker 
74*8975f5c5SAndroid Build Coastguard Worker     for (vk::PresentMode presentMode : presentModes)
75*8975f5c5SAndroid Build Coastguard Worker     {
76*8975f5c5SAndroid Build Coastguard Worker         switch (presentMode)
77*8975f5c5SAndroid Build Coastguard Worker         {
78*8975f5c5SAndroid Build Coastguard Worker             case vk::PresentMode::MailboxKHR:
79*8975f5c5SAndroid Build Coastguard Worker                 mailboxAvailable = true;
80*8975f5c5SAndroid Build Coastguard Worker                 break;
81*8975f5c5SAndroid Build Coastguard Worker             case vk::PresentMode::ImmediateKHR:
82*8975f5c5SAndroid Build Coastguard Worker                 immediateAvailable = true;
83*8975f5c5SAndroid Build Coastguard Worker                 break;
84*8975f5c5SAndroid Build Coastguard Worker             case vk::PresentMode::SharedDemandRefreshKHR:
85*8975f5c5SAndroid Build Coastguard Worker                 sharedPresent = true;
86*8975f5c5SAndroid Build Coastguard Worker                 break;
87*8975f5c5SAndroid Build Coastguard Worker             default:
88*8975f5c5SAndroid Build Coastguard Worker                 break;
89*8975f5c5SAndroid Build Coastguard Worker         }
90*8975f5c5SAndroid Build Coastguard Worker     }
91*8975f5c5SAndroid Build Coastguard Worker 
92*8975f5c5SAndroid Build Coastguard Worker     if (mailboxAvailable)
93*8975f5c5SAndroid Build Coastguard Worker     {
94*8975f5c5SAndroid Build Coastguard Worker         return vk::PresentMode::MailboxKHR;
95*8975f5c5SAndroid Build Coastguard Worker     }
96*8975f5c5SAndroid Build Coastguard Worker 
97*8975f5c5SAndroid Build Coastguard Worker     if (immediateAvailable)
98*8975f5c5SAndroid Build Coastguard Worker     {
99*8975f5c5SAndroid Build Coastguard Worker         return vk::PresentMode::ImmediateKHR;
100*8975f5c5SAndroid Build Coastguard Worker     }
101*8975f5c5SAndroid Build Coastguard Worker 
102*8975f5c5SAndroid Build Coastguard Worker     if (sharedPresent)
103*8975f5c5SAndroid Build Coastguard Worker     {
104*8975f5c5SAndroid Build Coastguard Worker         return vk::PresentMode::SharedDemandRefreshKHR;
105*8975f5c5SAndroid Build Coastguard Worker     }
106*8975f5c5SAndroid Build Coastguard Worker 
107*8975f5c5SAndroid Build Coastguard Worker     // Note again that VK_PRESENT_MODE_FIFO_KHR is guaranteed to be available.
108*8975f5c5SAndroid Build Coastguard Worker     return vk::PresentMode::FifoKHR;
109*8975f5c5SAndroid Build Coastguard Worker }
110*8975f5c5SAndroid Build Coastguard Worker 
GetMinImageCount(vk::Renderer * renderer,const VkSurfaceCapabilitiesKHR & surfaceCaps,vk::PresentMode presentMode)111*8975f5c5SAndroid Build Coastguard Worker uint32_t GetMinImageCount(vk::Renderer *renderer,
112*8975f5c5SAndroid Build Coastguard Worker                           const VkSurfaceCapabilitiesKHR &surfaceCaps,
113*8975f5c5SAndroid Build Coastguard Worker                           vk::PresentMode presentMode)
114*8975f5c5SAndroid Build Coastguard Worker {
115*8975f5c5SAndroid Build Coastguard Worker     // - On mailbox, we need at least three images; one is being displayed to the user until the
116*8975f5c5SAndroid Build Coastguard Worker     //   next v-sync, and the application alternatingly renders to the other two, one being
117*8975f5c5SAndroid Build Coastguard Worker     //   recorded, and the other queued for presentation if v-sync happens in the meantime.
118*8975f5c5SAndroid Build Coastguard Worker     // - On immediate, we need at least two images; the application alternates between the two
119*8975f5c5SAndroid Build Coastguard Worker     //   images.
120*8975f5c5SAndroid Build Coastguard Worker     // - On fifo, we use at least three images.  Triple-buffering allows us to present an image,
121*8975f5c5SAndroid Build Coastguard Worker     //   have one in the queue, and record in another.  Note: on certain configurations (windows +
122*8975f5c5SAndroid Build Coastguard Worker     //   nvidia + windowed mode), we could get away with a smaller number.
123*8975f5c5SAndroid Build Coastguard Worker 
124*8975f5c5SAndroid Build Coastguard Worker     // For simplicity, we always allocate at least three images, unless double buffer FIFO is
125*8975f5c5SAndroid Build Coastguard Worker     // specifically preferred.
126*8975f5c5SAndroid Build Coastguard Worker     const uint32_t imageCount =
127*8975f5c5SAndroid Build Coastguard Worker         renderer->getFeatures().preferDoubleBufferSwapchainOnFifoMode.enabled &&
128*8975f5c5SAndroid Build Coastguard Worker                 presentMode == vk::PresentMode::FifoKHR
129*8975f5c5SAndroid Build Coastguard Worker             ? 0x2u
130*8975f5c5SAndroid Build Coastguard Worker             : 0x3u;
131*8975f5c5SAndroid Build Coastguard Worker 
132*8975f5c5SAndroid Build Coastguard Worker     uint32_t minImageCount = std::max(imageCount, surfaceCaps.minImageCount);
133*8975f5c5SAndroid Build Coastguard Worker     // Make sure we don't exceed maxImageCount.
134*8975f5c5SAndroid Build Coastguard Worker     if (surfaceCaps.maxImageCount > 0 && minImageCount > surfaceCaps.maxImageCount)
135*8975f5c5SAndroid Build Coastguard Worker     {
136*8975f5c5SAndroid Build Coastguard Worker         minImageCount = surfaceCaps.maxImageCount;
137*8975f5c5SAndroid Build Coastguard Worker     }
138*8975f5c5SAndroid Build Coastguard Worker 
139*8975f5c5SAndroid Build Coastguard Worker     return minImageCount;
140*8975f5c5SAndroid Build Coastguard Worker }
141*8975f5c5SAndroid Build Coastguard Worker 
142*8975f5c5SAndroid Build Coastguard Worker constexpr VkImageUsageFlags kSurfaceVkImageUsageFlags =
143*8975f5c5SAndroid Build Coastguard Worker     VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
144*8975f5c5SAndroid Build Coastguard Worker constexpr VkImageUsageFlags kSurfaceVkColorImageUsageFlags =
145*8975f5c5SAndroid Build Coastguard Worker     kSurfaceVkImageUsageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
146*8975f5c5SAndroid Build Coastguard Worker constexpr VkImageUsageFlags kSurfaceVkDepthStencilImageUsageFlags =
147*8975f5c5SAndroid Build Coastguard Worker     kSurfaceVkImageUsageFlags | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
148*8975f5c5SAndroid Build Coastguard Worker 
149*8975f5c5SAndroid Build Coastguard Worker // If the device is rotated with any of the following transform flags, the swapchain width and
150*8975f5c5SAndroid Build Coastguard Worker // height must be swapped (e.g. make a landscape window portrait).  This must also be done for all
151*8975f5c5SAndroid Build Coastguard Worker // attachments used with the swapchain (i.e. depth, stencil, and multisample buffers).
152*8975f5c5SAndroid Build Coastguard Worker constexpr VkSurfaceTransformFlagsKHR k90DegreeRotationVariants =
153*8975f5c5SAndroid Build Coastguard Worker     VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
154*8975f5c5SAndroid Build Coastguard Worker     VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
155*8975f5c5SAndroid Build Coastguard Worker     VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
156*8975f5c5SAndroid Build Coastguard Worker 
Is90DegreeRotation(VkSurfaceTransformFlagsKHR transform)157*8975f5c5SAndroid Build Coastguard Worker bool Is90DegreeRotation(VkSurfaceTransformFlagsKHR transform)
158*8975f5c5SAndroid Build Coastguard Worker {
159*8975f5c5SAndroid Build Coastguard Worker     return ((transform & k90DegreeRotationVariants) != 0);
160*8975f5c5SAndroid Build Coastguard Worker }
161*8975f5c5SAndroid Build Coastguard Worker 
ColorNeedsInputAttachmentUsage(const angle::FeaturesVk & features)162*8975f5c5SAndroid Build Coastguard Worker bool ColorNeedsInputAttachmentUsage(const angle::FeaturesVk &features)
163*8975f5c5SAndroid Build Coastguard Worker {
164*8975f5c5SAndroid Build Coastguard Worker     return features.supportsShaderFramebufferFetch.enabled ||
165*8975f5c5SAndroid Build Coastguard Worker            features.supportsShaderFramebufferFetchNonCoherent.enabled ||
166*8975f5c5SAndroid Build Coastguard Worker            features.emulateAdvancedBlendEquations.enabled;
167*8975f5c5SAndroid Build Coastguard Worker }
168*8975f5c5SAndroid Build Coastguard Worker 
DepthStencilNeedsInputAttachmentUsage(const angle::FeaturesVk & features)169*8975f5c5SAndroid Build Coastguard Worker bool DepthStencilNeedsInputAttachmentUsage(const angle::FeaturesVk &features)
170*8975f5c5SAndroid Build Coastguard Worker {
171*8975f5c5SAndroid Build Coastguard Worker     return features.supportsShaderFramebufferFetchDepthStencil.enabled;
172*8975f5c5SAndroid Build Coastguard Worker }
173*8975f5c5SAndroid Build Coastguard Worker 
InitImageHelper(DisplayVk * displayVk,EGLint width,EGLint height,const vk::Format & vkFormat,GLint samples,bool isRobustResourceInitEnabled,bool hasProtectedContent,vk::ImageHelper * imageHelper)174*8975f5c5SAndroid Build Coastguard Worker angle::Result InitImageHelper(DisplayVk *displayVk,
175*8975f5c5SAndroid Build Coastguard Worker                               EGLint width,
176*8975f5c5SAndroid Build Coastguard Worker                               EGLint height,
177*8975f5c5SAndroid Build Coastguard Worker                               const vk::Format &vkFormat,
178*8975f5c5SAndroid Build Coastguard Worker                               GLint samples,
179*8975f5c5SAndroid Build Coastguard Worker                               bool isRobustResourceInitEnabled,
180*8975f5c5SAndroid Build Coastguard Worker                               bool hasProtectedContent,
181*8975f5c5SAndroid Build Coastguard Worker                               vk::ImageHelper *imageHelper)
182*8975f5c5SAndroid Build Coastguard Worker {
183*8975f5c5SAndroid Build Coastguard Worker     const angle::Format &textureFormat = vkFormat.getActualRenderableImageFormat();
184*8975f5c5SAndroid Build Coastguard Worker     bool isDepthOrStencilFormat        = textureFormat.hasDepthOrStencilBits();
185*8975f5c5SAndroid Build Coastguard Worker     VkImageUsageFlags usage = isDepthOrStencilFormat ? kSurfaceVkDepthStencilImageUsageFlags
186*8975f5c5SAndroid Build Coastguard Worker                                                      : kSurfaceVkColorImageUsageFlags;
187*8975f5c5SAndroid Build Coastguard Worker 
188*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = displayVk->getRenderer();
189*8975f5c5SAndroid Build Coastguard Worker     // If shaders may be fetching from this, we need this image to be an input
190*8975f5c5SAndroid Build Coastguard Worker     const bool isColorAndNeedsInputUsage =
191*8975f5c5SAndroid Build Coastguard Worker         !isDepthOrStencilFormat && ColorNeedsInputAttachmentUsage(renderer->getFeatures());
192*8975f5c5SAndroid Build Coastguard Worker     const bool isDepthStencilAndNeedsInputUsage =
193*8975f5c5SAndroid Build Coastguard Worker         isDepthOrStencilFormat && DepthStencilNeedsInputAttachmentUsage(renderer->getFeatures());
194*8975f5c5SAndroid Build Coastguard Worker     if (isColorAndNeedsInputUsage || isDepthStencilAndNeedsInputUsage)
195*8975f5c5SAndroid Build Coastguard Worker     {
196*8975f5c5SAndroid Build Coastguard Worker         usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
197*8975f5c5SAndroid Build Coastguard Worker     }
198*8975f5c5SAndroid Build Coastguard Worker 
199*8975f5c5SAndroid Build Coastguard Worker     VkExtent3D extents = {std::max(static_cast<uint32_t>(width), 1u),
200*8975f5c5SAndroid Build Coastguard Worker                           std::max(static_cast<uint32_t>(height), 1u), 1u};
201*8975f5c5SAndroid Build Coastguard Worker 
202*8975f5c5SAndroid Build Coastguard Worker     angle::FormatID renderableFormatId = vkFormat.getActualRenderableImageFormatID();
203*8975f5c5SAndroid Build Coastguard Worker     // For devices that don't support creating swapchain images with RGB8, emulate with RGBA8.
204*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().overrideSurfaceFormatRGB8ToRGBA8.enabled &&
205*8975f5c5SAndroid Build Coastguard Worker         renderableFormatId == angle::FormatID::R8G8B8_UNORM)
206*8975f5c5SAndroid Build Coastguard Worker     {
207*8975f5c5SAndroid Build Coastguard Worker         renderableFormatId = angle::FormatID::R8G8B8A8_UNORM;
208*8975f5c5SAndroid Build Coastguard Worker     }
209*8975f5c5SAndroid Build Coastguard Worker 
210*8975f5c5SAndroid Build Coastguard Worker     VkImageCreateFlags imageCreateFlags =
211*8975f5c5SAndroid Build Coastguard Worker         hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : vk::kVkImageCreateFlagsNone;
212*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(imageHelper->initExternal(
213*8975f5c5SAndroid Build Coastguard Worker         displayVk, gl::TextureType::_2D, extents, vkFormat.getIntendedFormatID(),
214*8975f5c5SAndroid Build Coastguard Worker         renderableFormatId, samples, usage, imageCreateFlags, vk::ImageLayout::Undefined, nullptr,
215*8975f5c5SAndroid Build Coastguard Worker         gl::LevelIndex(0), 1, 1, isRobustResourceInitEnabled, hasProtectedContent,
216*8975f5c5SAndroid Build Coastguard Worker         vk::YcbcrConversionDesc{}, nullptr));
217*8975f5c5SAndroid Build Coastguard Worker 
218*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
219*8975f5c5SAndroid Build Coastguard Worker }
220*8975f5c5SAndroid Build Coastguard Worker 
MapEglColorSpaceToVkColorSpace(vk::Renderer * renderer,EGLenum EGLColorspace)221*8975f5c5SAndroid Build Coastguard Worker VkColorSpaceKHR MapEglColorSpaceToVkColorSpace(vk::Renderer *renderer, EGLenum EGLColorspace)
222*8975f5c5SAndroid Build Coastguard Worker {
223*8975f5c5SAndroid Build Coastguard Worker     switch (EGLColorspace)
224*8975f5c5SAndroid Build Coastguard Worker     {
225*8975f5c5SAndroid Build Coastguard Worker         case EGL_NONE:
226*8975f5c5SAndroid Build Coastguard Worker             return VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
227*8975f5c5SAndroid Build Coastguard Worker         case EGL_GL_COLORSPACE_LINEAR:
228*8975f5c5SAndroid Build Coastguard Worker         case EGL_GL_COLORSPACE_SRGB_KHR:
229*8975f5c5SAndroid Build Coastguard Worker             return VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
230*8975f5c5SAndroid Build Coastguard Worker         case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
231*8975f5c5SAndroid Build Coastguard Worker             return VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
232*8975f5c5SAndroid Build Coastguard Worker         case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
233*8975f5c5SAndroid Build Coastguard Worker         case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT:
234*8975f5c5SAndroid Build Coastguard Worker             return VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT;
235*8975f5c5SAndroid Build Coastguard Worker         case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
236*8975f5c5SAndroid Build Coastguard Worker             return VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
237*8975f5c5SAndroid Build Coastguard Worker         case EGL_GL_COLORSPACE_SCRGB_EXT:
238*8975f5c5SAndroid Build Coastguard Worker             return VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
239*8975f5c5SAndroid Build Coastguard Worker         case EGL_GL_COLORSPACE_BT2020_LINEAR_EXT:
240*8975f5c5SAndroid Build Coastguard Worker             return VK_COLOR_SPACE_BT2020_LINEAR_EXT;
241*8975f5c5SAndroid Build Coastguard Worker         case EGL_GL_COLORSPACE_BT2020_PQ_EXT:
242*8975f5c5SAndroid Build Coastguard Worker             return VK_COLOR_SPACE_HDR10_ST2084_EXT;
243*8975f5c5SAndroid Build Coastguard Worker         case EGL_GL_COLORSPACE_BT2020_HLG_EXT:
244*8975f5c5SAndroid Build Coastguard Worker             return VK_COLOR_SPACE_HDR10_HLG_EXT;
245*8975f5c5SAndroid Build Coastguard Worker         default:
246*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
247*8975f5c5SAndroid Build Coastguard Worker             return VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
248*8975f5c5SAndroid Build Coastguard Worker     }
249*8975f5c5SAndroid Build Coastguard Worker }
250*8975f5c5SAndroid Build Coastguard Worker 
LockSurfaceImpl(DisplayVk * displayVk,vk::ImageHelper * image,vk::BufferHelper & lockBufferHelper,EGLint width,EGLint height,EGLint usageHint,bool preservePixels,uint8_t ** bufferPtrOut,EGLint * bufferPitchOut)251*8975f5c5SAndroid Build Coastguard Worker angle::Result LockSurfaceImpl(DisplayVk *displayVk,
252*8975f5c5SAndroid Build Coastguard Worker                               vk::ImageHelper *image,
253*8975f5c5SAndroid Build Coastguard Worker                               vk::BufferHelper &lockBufferHelper,
254*8975f5c5SAndroid Build Coastguard Worker                               EGLint width,
255*8975f5c5SAndroid Build Coastguard Worker                               EGLint height,
256*8975f5c5SAndroid Build Coastguard Worker                               EGLint usageHint,
257*8975f5c5SAndroid Build Coastguard Worker                               bool preservePixels,
258*8975f5c5SAndroid Build Coastguard Worker                               uint8_t **bufferPtrOut,
259*8975f5c5SAndroid Build Coastguard Worker                               EGLint *bufferPitchOut)
260*8975f5c5SAndroid Build Coastguard Worker {
261*8975f5c5SAndroid Build Coastguard Worker     const gl::InternalFormat &internalFormat =
262*8975f5c5SAndroid Build Coastguard Worker         gl::GetSizedInternalFormatInfo(image->getActualFormat().glInternalFormat);
263*8975f5c5SAndroid Build Coastguard Worker     GLuint rowStride = image->getActualFormat().pixelBytes * width;
264*8975f5c5SAndroid Build Coastguard Worker     VkDeviceSize bufferSize =
265*8975f5c5SAndroid Build Coastguard Worker         (static_cast<VkDeviceSize>(rowStride) * static_cast<VkDeviceSize>(height));
266*8975f5c5SAndroid Build Coastguard Worker 
267*8975f5c5SAndroid Build Coastguard Worker     if (!lockBufferHelper.valid() || (lockBufferHelper.getSize() != bufferSize))
268*8975f5c5SAndroid Build Coastguard Worker     {
269*8975f5c5SAndroid Build Coastguard Worker         lockBufferHelper.destroy(displayVk->getRenderer());
270*8975f5c5SAndroid Build Coastguard Worker 
271*8975f5c5SAndroid Build Coastguard Worker         VkBufferCreateInfo bufferCreateInfo = {};
272*8975f5c5SAndroid Build Coastguard Worker         bufferCreateInfo.sType              = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
273*8975f5c5SAndroid Build Coastguard Worker         bufferCreateInfo.pNext              = nullptr;
274*8975f5c5SAndroid Build Coastguard Worker         bufferCreateInfo.flags              = 0;
275*8975f5c5SAndroid Build Coastguard Worker         bufferCreateInfo.size               = bufferSize;
276*8975f5c5SAndroid Build Coastguard Worker         bufferCreateInfo.usage =
277*8975f5c5SAndroid Build Coastguard Worker             (VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT);
278*8975f5c5SAndroid Build Coastguard Worker         bufferCreateInfo.sharingMode           = VK_SHARING_MODE_EXCLUSIVE;
279*8975f5c5SAndroid Build Coastguard Worker         bufferCreateInfo.queueFamilyIndexCount = 0;
280*8975f5c5SAndroid Build Coastguard Worker         bufferCreateInfo.pQueueFamilyIndices   = 0;
281*8975f5c5SAndroid Build Coastguard Worker 
282*8975f5c5SAndroid Build Coastguard Worker         VkMemoryPropertyFlags memoryFlags =
283*8975f5c5SAndroid Build Coastguard Worker             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
284*8975f5c5SAndroid Build Coastguard Worker 
285*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(lockBufferHelper.init(displayVk, bufferCreateInfo, memoryFlags));
286*8975f5c5SAndroid Build Coastguard Worker 
287*8975f5c5SAndroid Build Coastguard Worker         uint8_t *bufferPtr = nullptr;
288*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(lockBufferHelper.map(displayVk, &bufferPtr));
289*8975f5c5SAndroid Build Coastguard Worker     }
290*8975f5c5SAndroid Build Coastguard Worker 
291*8975f5c5SAndroid Build Coastguard Worker     if (lockBufferHelper.valid())
292*8975f5c5SAndroid Build Coastguard Worker     {
293*8975f5c5SAndroid Build Coastguard Worker         if (preservePixels)
294*8975f5c5SAndroid Build Coastguard Worker         {
295*8975f5c5SAndroid Build Coastguard Worker             gl::LevelIndex sourceLevelGL(0);
296*8975f5c5SAndroid Build Coastguard Worker             const VkClearColorValue *clearColor;
297*8975f5c5SAndroid Build Coastguard Worker             if (image->removeStagedClearUpdatesAndReturnColor(sourceLevelGL, &clearColor))
298*8975f5c5SAndroid Build Coastguard Worker             {
299*8975f5c5SAndroid Build Coastguard Worker                 ASSERT(!image->hasStagedUpdatesForSubresource(sourceLevelGL, 0, 1));
300*8975f5c5SAndroid Build Coastguard Worker                 angle::Color<uint8_t> color((uint8_t)(clearColor->float32[0] * 255.0),
301*8975f5c5SAndroid Build Coastguard Worker                                             (uint8_t)(clearColor->float32[1] * 255.0),
302*8975f5c5SAndroid Build Coastguard Worker                                             (uint8_t)(clearColor->float32[2] * 255.0),
303*8975f5c5SAndroid Build Coastguard Worker                                             (uint8_t)(clearColor->float32[3] * 255.0));
304*8975f5c5SAndroid Build Coastguard Worker                 lockBufferHelper.fillWithColor(color, internalFormat);
305*8975f5c5SAndroid Build Coastguard Worker             }
306*8975f5c5SAndroid Build Coastguard Worker             else
307*8975f5c5SAndroid Build Coastguard Worker             {
308*8975f5c5SAndroid Build Coastguard Worker                 gl::Box sourceArea(0, 0, 0, width, height, 1);
309*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRY(image->copySurfaceImageToBuffer(displayVk, sourceLevelGL, 1, 0,
310*8975f5c5SAndroid Build Coastguard Worker                                                           sourceArea, &lockBufferHelper));
311*8975f5c5SAndroid Build Coastguard Worker             }
312*8975f5c5SAndroid Build Coastguard Worker         }
313*8975f5c5SAndroid Build Coastguard Worker 
314*8975f5c5SAndroid Build Coastguard Worker         *bufferPitchOut = rowStride;
315*8975f5c5SAndroid Build Coastguard Worker         *bufferPtrOut   = lockBufferHelper.getMappedMemory();
316*8975f5c5SAndroid Build Coastguard Worker     }
317*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
318*8975f5c5SAndroid Build Coastguard Worker }
319*8975f5c5SAndroid Build Coastguard Worker 
UnlockSurfaceImpl(DisplayVk * displayVk,vk::ImageHelper * image,vk::BufferHelper & lockBufferHelper,EGLint width,EGLint height,bool preservePixels)320*8975f5c5SAndroid Build Coastguard Worker angle::Result UnlockSurfaceImpl(DisplayVk *displayVk,
321*8975f5c5SAndroid Build Coastguard Worker                                 vk::ImageHelper *image,
322*8975f5c5SAndroid Build Coastguard Worker                                 vk::BufferHelper &lockBufferHelper,
323*8975f5c5SAndroid Build Coastguard Worker                                 EGLint width,
324*8975f5c5SAndroid Build Coastguard Worker                                 EGLint height,
325*8975f5c5SAndroid Build Coastguard Worker                                 bool preservePixels)
326*8975f5c5SAndroid Build Coastguard Worker {
327*8975f5c5SAndroid Build Coastguard Worker     if (preservePixels)
328*8975f5c5SAndroid Build Coastguard Worker     {
329*8975f5c5SAndroid Build Coastguard Worker         ASSERT(image->valid());
330*8975f5c5SAndroid Build Coastguard Worker 
331*8975f5c5SAndroid Build Coastguard Worker         gl::Box destArea(0, 0, 0, width, height, 1);
332*8975f5c5SAndroid Build Coastguard Worker         gl::LevelIndex destLevelGL(0);
333*8975f5c5SAndroid Build Coastguard Worker 
334*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(image->copyBufferToSurfaceImage(displayVk, destLevelGL, 1, 0, destArea,
335*8975f5c5SAndroid Build Coastguard Worker                                                   &lockBufferHelper));
336*8975f5c5SAndroid Build Coastguard Worker     }
337*8975f5c5SAndroid Build Coastguard Worker 
338*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
339*8975f5c5SAndroid Build Coastguard Worker }
340*8975f5c5SAndroid Build Coastguard Worker 
341*8975f5c5SAndroid Build Coastguard Worker // Converts an EGL rectangle, which is relative to the bottom-left of the surface,
342*8975f5c5SAndroid Build Coastguard Worker // to a VkRectLayerKHR, relative to Vulkan framebuffer-space, with top-left origin.
343*8975f5c5SAndroid Build Coastguard Worker // No rotation is done to these damage rectangles per the Vulkan spec.
344*8975f5c5SAndroid Build Coastguard Worker // The bottomLeftOrigin parameter is true on Android which assumes VkRectLayerKHR to
345*8975f5c5SAndroid Build Coastguard Worker // have a bottom-left origin.
ToVkRectLayer(const EGLint * eglRect,EGLint width,EGLint height,bool bottomLeftOrigin)346*8975f5c5SAndroid Build Coastguard Worker VkRectLayerKHR ToVkRectLayer(const EGLint *eglRect,
347*8975f5c5SAndroid Build Coastguard Worker                              EGLint width,
348*8975f5c5SAndroid Build Coastguard Worker                              EGLint height,
349*8975f5c5SAndroid Build Coastguard Worker                              bool bottomLeftOrigin)
350*8975f5c5SAndroid Build Coastguard Worker {
351*8975f5c5SAndroid Build Coastguard Worker     VkRectLayerKHR rect;
352*8975f5c5SAndroid Build Coastguard Worker     // Make sure the damage rects are within swapchain bounds.
353*8975f5c5SAndroid Build Coastguard Worker     rect.offset.x = gl::clamp(eglRect[0], 0, width);
354*8975f5c5SAndroid Build Coastguard Worker 
355*8975f5c5SAndroid Build Coastguard Worker     if (bottomLeftOrigin)
356*8975f5c5SAndroid Build Coastguard Worker     {
357*8975f5c5SAndroid Build Coastguard Worker         // EGL rectangles are already specified with a bottom-left origin, therefore the conversion
358*8975f5c5SAndroid Build Coastguard Worker         // is trivial as we just get its Y coordinate as it is
359*8975f5c5SAndroid Build Coastguard Worker         rect.offset.y = gl::clamp(eglRect[1], 0, height);
360*8975f5c5SAndroid Build Coastguard Worker     }
361*8975f5c5SAndroid Build Coastguard Worker     else
362*8975f5c5SAndroid Build Coastguard Worker     {
363*8975f5c5SAndroid Build Coastguard Worker         rect.offset.y =
364*8975f5c5SAndroid Build Coastguard Worker             gl::clamp(height - gl::clamp(eglRect[1], 0, height) - gl::clamp(eglRect[3], 0, height),
365*8975f5c5SAndroid Build Coastguard Worker                       0, height);
366*8975f5c5SAndroid Build Coastguard Worker     }
367*8975f5c5SAndroid Build Coastguard Worker     rect.extent.width  = gl::clamp(eglRect[2], 0, width - rect.offset.x);
368*8975f5c5SAndroid Build Coastguard Worker     rect.extent.height = gl::clamp(eglRect[3], 0, height - rect.offset.y);
369*8975f5c5SAndroid Build Coastguard Worker     rect.layer         = 0;
370*8975f5c5SAndroid Build Coastguard Worker     return rect;
371*8975f5c5SAndroid Build Coastguard Worker }
372*8975f5c5SAndroid Build Coastguard Worker 
GetPresentModes(DisplayVk * displayVk,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,std::vector<vk::PresentMode> * outPresentModes)373*8975f5c5SAndroid Build Coastguard Worker angle::Result GetPresentModes(DisplayVk *displayVk,
374*8975f5c5SAndroid Build Coastguard Worker                               VkPhysicalDevice physicalDevice,
375*8975f5c5SAndroid Build Coastguard Worker                               VkSurfaceKHR surface,
376*8975f5c5SAndroid Build Coastguard Worker                               std::vector<vk::PresentMode> *outPresentModes)
377*8975f5c5SAndroid Build Coastguard Worker {
378*8975f5c5SAndroid Build Coastguard Worker 
379*8975f5c5SAndroid Build Coastguard Worker     uint32_t presentModeCount = 0;
380*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface,
381*8975f5c5SAndroid Build Coastguard Worker                                                                       &presentModeCount, nullptr));
382*8975f5c5SAndroid Build Coastguard Worker     ASSERT(presentModeCount > 0);
383*8975f5c5SAndroid Build Coastguard Worker 
384*8975f5c5SAndroid Build Coastguard Worker     std::vector<VkPresentModeKHR> vkPresentModes(presentModeCount);
385*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfacePresentModesKHR(
386*8975f5c5SAndroid Build Coastguard Worker                                 physicalDevice, surface, &presentModeCount, vkPresentModes.data()));
387*8975f5c5SAndroid Build Coastguard Worker 
388*8975f5c5SAndroid Build Coastguard Worker     outPresentModes->resize(presentModeCount);
389*8975f5c5SAndroid Build Coastguard Worker     std::transform(begin(vkPresentModes), end(vkPresentModes), begin(*outPresentModes),
390*8975f5c5SAndroid Build Coastguard Worker                    vk::ConvertVkPresentModeToPresentMode);
391*8975f5c5SAndroid Build Coastguard Worker 
392*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
393*8975f5c5SAndroid Build Coastguard Worker }
394*8975f5c5SAndroid Build Coastguard Worker 
NewSemaphore(vk::Context * context,vk::Recycler<vk::Semaphore> * semaphoreRecycler,vk::Semaphore * semaphoreOut)395*8975f5c5SAndroid Build Coastguard Worker angle::Result NewSemaphore(vk::Context *context,
396*8975f5c5SAndroid Build Coastguard Worker                            vk::Recycler<vk::Semaphore> *semaphoreRecycler,
397*8975f5c5SAndroid Build Coastguard Worker                            vk::Semaphore *semaphoreOut)
398*8975f5c5SAndroid Build Coastguard Worker {
399*8975f5c5SAndroid Build Coastguard Worker     if (semaphoreRecycler->empty())
400*8975f5c5SAndroid Build Coastguard Worker     {
401*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(context, semaphoreOut->init(context->getDevice()));
402*8975f5c5SAndroid Build Coastguard Worker     }
403*8975f5c5SAndroid Build Coastguard Worker     else
404*8975f5c5SAndroid Build Coastguard Worker     {
405*8975f5c5SAndroid Build Coastguard Worker         semaphoreRecycler->fetch(semaphoreOut);
406*8975f5c5SAndroid Build Coastguard Worker     }
407*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
408*8975f5c5SAndroid Build Coastguard Worker }
409*8975f5c5SAndroid Build Coastguard Worker 
NewFence(VkDevice device,vk::Recycler<vk::Fence> * fenceRecycler,vk::Fence * fenceOut)410*8975f5c5SAndroid Build Coastguard Worker VkResult NewFence(VkDevice device, vk::Recycler<vk::Fence> *fenceRecycler, vk::Fence *fenceOut)
411*8975f5c5SAndroid Build Coastguard Worker {
412*8975f5c5SAndroid Build Coastguard Worker     VkResult result = VK_SUCCESS;
413*8975f5c5SAndroid Build Coastguard Worker     if (fenceRecycler->empty())
414*8975f5c5SAndroid Build Coastguard Worker     {
415*8975f5c5SAndroid Build Coastguard Worker         VkFenceCreateInfo fenceCreateInfo = {};
416*8975f5c5SAndroid Build Coastguard Worker         fenceCreateInfo.sType             = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
417*8975f5c5SAndroid Build Coastguard Worker         fenceCreateInfo.flags             = 0;
418*8975f5c5SAndroid Build Coastguard Worker         result                            = fenceOut->init(device, fenceCreateInfo);
419*8975f5c5SAndroid Build Coastguard Worker     }
420*8975f5c5SAndroid Build Coastguard Worker     else
421*8975f5c5SAndroid Build Coastguard Worker     {
422*8975f5c5SAndroid Build Coastguard Worker         fenceRecycler->fetch(fenceOut);
423*8975f5c5SAndroid Build Coastguard Worker         ASSERT(fenceOut->getStatus(device) == VK_NOT_READY);
424*8975f5c5SAndroid Build Coastguard Worker     }
425*8975f5c5SAndroid Build Coastguard Worker     return result;
426*8975f5c5SAndroid Build Coastguard Worker }
427*8975f5c5SAndroid Build Coastguard Worker 
RecycleUsedFence(VkDevice device,vk::Recycler<vk::Fence> * fenceRecycler,vk::Fence && fence)428*8975f5c5SAndroid Build Coastguard Worker void RecycleUsedFence(VkDevice device, vk::Recycler<vk::Fence> *fenceRecycler, vk::Fence &&fence)
429*8975f5c5SAndroid Build Coastguard Worker {
430*8975f5c5SAndroid Build Coastguard Worker     // Reset fence now to mitigate Intel driver bug, when accessing fence after Swapchain
431*8975f5c5SAndroid Build Coastguard Worker     // destruction causes crash.
432*8975f5c5SAndroid Build Coastguard Worker     VkResult result = fence.reset(device);
433*8975f5c5SAndroid Build Coastguard Worker     if (result != VK_SUCCESS)
434*8975f5c5SAndroid Build Coastguard Worker     {
435*8975f5c5SAndroid Build Coastguard Worker         ERR() << "Fence reset failed: " << result << "! Destroying fence...";
436*8975f5c5SAndroid Build Coastguard Worker         fence.destroy(device);
437*8975f5c5SAndroid Build Coastguard Worker         return;
438*8975f5c5SAndroid Build Coastguard Worker     }
439*8975f5c5SAndroid Build Coastguard Worker     fenceRecycler->recycle(std::move(fence));
440*8975f5c5SAndroid Build Coastguard Worker }
441*8975f5c5SAndroid Build Coastguard Worker 
AssociateQueueSerialWithPresentHistory(uint32_t imageIndex,QueueSerial queueSerial,std::deque<impl::ImagePresentOperation> * presentHistory)442*8975f5c5SAndroid Build Coastguard Worker void AssociateQueueSerialWithPresentHistory(uint32_t imageIndex,
443*8975f5c5SAndroid Build Coastguard Worker                                             QueueSerial queueSerial,
444*8975f5c5SAndroid Build Coastguard Worker                                             std::deque<impl::ImagePresentOperation> *presentHistory)
445*8975f5c5SAndroid Build Coastguard Worker {
446*8975f5c5SAndroid Build Coastguard Worker     // Walk the list backwards and find the entry for the given image index.  That's the last
447*8975f5c5SAndroid Build Coastguard Worker     // present with that image.  Associate the QueueSerial with that present operation.
448*8975f5c5SAndroid Build Coastguard Worker     for (size_t historyIndex = 0; historyIndex < presentHistory->size(); ++historyIndex)
449*8975f5c5SAndroid Build Coastguard Worker     {
450*8975f5c5SAndroid Build Coastguard Worker         impl::ImagePresentOperation &presentOperation =
451*8975f5c5SAndroid Build Coastguard Worker             (*presentHistory)[presentHistory->size() - historyIndex - 1];
452*8975f5c5SAndroid Build Coastguard Worker         // Must not use this function when VK_EXT_swapchain_maintenance1 is supported.
453*8975f5c5SAndroid Build Coastguard Worker         ASSERT(!presentOperation.fence.valid());
454*8975f5c5SAndroid Build Coastguard Worker         ASSERT(presentOperation.imageIndex != kInvalidImageIndex);
455*8975f5c5SAndroid Build Coastguard Worker 
456*8975f5c5SAndroid Build Coastguard Worker         if (presentOperation.imageIndex == imageIndex)
457*8975f5c5SAndroid Build Coastguard Worker         {
458*8975f5c5SAndroid Build Coastguard Worker             ASSERT(!presentOperation.queueSerial.valid());
459*8975f5c5SAndroid Build Coastguard Worker             presentOperation.queueSerial = queueSerial;
460*8975f5c5SAndroid Build Coastguard Worker             return;
461*8975f5c5SAndroid Build Coastguard Worker         }
462*8975f5c5SAndroid Build Coastguard Worker     }
463*8975f5c5SAndroid Build Coastguard Worker }
464*8975f5c5SAndroid Build Coastguard Worker 
HasAnyOldSwapchains(const std::deque<impl::ImagePresentOperation> & presentHistory)465*8975f5c5SAndroid Build Coastguard Worker bool HasAnyOldSwapchains(const std::deque<impl::ImagePresentOperation> &presentHistory)
466*8975f5c5SAndroid Build Coastguard Worker {
467*8975f5c5SAndroid Build Coastguard Worker     // Used to validate that swapchain clean up data can only be carried by the first present
468*8975f5c5SAndroid Build Coastguard Worker     // operation of a swapchain.  That operation is already removed from history when this call is
469*8975f5c5SAndroid Build Coastguard Worker     // made, so this verifies that no clean up data exists in the history.
470*8975f5c5SAndroid Build Coastguard Worker     for (const impl::ImagePresentOperation &presentOperation : presentHistory)
471*8975f5c5SAndroid Build Coastguard Worker     {
472*8975f5c5SAndroid Build Coastguard Worker         if (!presentOperation.oldSwapchains.empty())
473*8975f5c5SAndroid Build Coastguard Worker         {
474*8975f5c5SAndroid Build Coastguard Worker             return true;
475*8975f5c5SAndroid Build Coastguard Worker         }
476*8975f5c5SAndroid Build Coastguard Worker     }
477*8975f5c5SAndroid Build Coastguard Worker 
478*8975f5c5SAndroid Build Coastguard Worker     return false;
479*8975f5c5SAndroid Build Coastguard Worker }
480*8975f5c5SAndroid Build Coastguard Worker 
IsCompatiblePresentMode(vk::PresentMode mode,VkPresentModeKHR * compatibleModes,size_t compatibleModesCount)481*8975f5c5SAndroid Build Coastguard Worker bool IsCompatiblePresentMode(vk::PresentMode mode,
482*8975f5c5SAndroid Build Coastguard Worker                              VkPresentModeKHR *compatibleModes,
483*8975f5c5SAndroid Build Coastguard Worker                              size_t compatibleModesCount)
484*8975f5c5SAndroid Build Coastguard Worker {
485*8975f5c5SAndroid Build Coastguard Worker     VkPresentModeKHR vkMode              = vk::ConvertPresentModeToVkPresentMode(mode);
486*8975f5c5SAndroid Build Coastguard Worker     VkPresentModeKHR *compatibleModesEnd = compatibleModes + compatibleModesCount;
487*8975f5c5SAndroid Build Coastguard Worker     return std::find(compatibleModes, compatibleModesEnd, vkMode) != compatibleModesEnd;
488*8975f5c5SAndroid Build Coastguard Worker }
489*8975f5c5SAndroid Build Coastguard Worker 
490*8975f5c5SAndroid Build Coastguard Worker // This function MUST only be called from a thread where Surface is current.
AcquireNextImageUnlocked(VkDevice device,VkSwapchainKHR swapchain,impl::ImageAcquireOperation * acquire)491*8975f5c5SAndroid Build Coastguard Worker void AcquireNextImageUnlocked(VkDevice device,
492*8975f5c5SAndroid Build Coastguard Worker                               VkSwapchainKHR swapchain,
493*8975f5c5SAndroid Build Coastguard Worker                               impl::ImageAcquireOperation *acquire)
494*8975f5c5SAndroid Build Coastguard Worker {
495*8975f5c5SAndroid Build Coastguard Worker     ASSERT(acquire->state == impl::ImageAcquireState::NeedToAcquire);
496*8975f5c5SAndroid Build Coastguard Worker     ASSERT(swapchain != VK_NULL_HANDLE);
497*8975f5c5SAndroid Build Coastguard Worker 
498*8975f5c5SAndroid Build Coastguard Worker     impl::UnlockedAcquireData *data     = &acquire->unlockedAcquireData;
499*8975f5c5SAndroid Build Coastguard Worker     impl::UnlockedAcquireResult *result = &acquire->unlockedAcquireResult;
500*8975f5c5SAndroid Build Coastguard Worker 
501*8975f5c5SAndroid Build Coastguard Worker     result->imageIndex = std::numeric_limits<uint32_t>::max();
502*8975f5c5SAndroid Build Coastguard Worker 
503*8975f5c5SAndroid Build Coastguard Worker     // Get a semaphore to signal.
504*8975f5c5SAndroid Build Coastguard Worker     result->acquireSemaphore = data->acquireImageSemaphores.front().getHandle();
505*8975f5c5SAndroid Build Coastguard Worker 
506*8975f5c5SAndroid Build Coastguard Worker     // Try to acquire an image.
507*8975f5c5SAndroid Build Coastguard Worker     result->result = vkAcquireNextImageKHR(device, swapchain, UINT64_MAX, result->acquireSemaphore,
508*8975f5c5SAndroid Build Coastguard Worker                                            VK_NULL_HANDLE, &result->imageIndex);
509*8975f5c5SAndroid Build Coastguard Worker 
510*8975f5c5SAndroid Build Coastguard Worker     // Result processing will be done later in the same thread.
511*8975f5c5SAndroid Build Coastguard Worker     acquire->state = impl::ImageAcquireState::NeedToProcessResult;
512*8975f5c5SAndroid Build Coastguard Worker }
513*8975f5c5SAndroid Build Coastguard Worker 
AreAllFencesSignaled(VkDevice device,const std::vector<vk::Fence> & fences)514*8975f5c5SAndroid Build Coastguard Worker bool AreAllFencesSignaled(VkDevice device, const std::vector<vk::Fence> &fences)
515*8975f5c5SAndroid Build Coastguard Worker {
516*8975f5c5SAndroid Build Coastguard Worker     for (const vk::Fence &fence : fences)
517*8975f5c5SAndroid Build Coastguard Worker     {
518*8975f5c5SAndroid Build Coastguard Worker         if (fence.getStatus(device) != VK_SUCCESS)
519*8975f5c5SAndroid Build Coastguard Worker         {
520*8975f5c5SAndroid Build Coastguard Worker             return false;
521*8975f5c5SAndroid Build Coastguard Worker         }
522*8975f5c5SAndroid Build Coastguard Worker     }
523*8975f5c5SAndroid Build Coastguard Worker     return true;
524*8975f5c5SAndroid Build Coastguard Worker }
525*8975f5c5SAndroid Build Coastguard Worker }  // namespace
526*8975f5c5SAndroid Build Coastguard Worker 
SurfaceVk(const egl::SurfaceState & surfaceState)527*8975f5c5SAndroid Build Coastguard Worker SurfaceVk::SurfaceVk(const egl::SurfaceState &surfaceState)
528*8975f5c5SAndroid Build Coastguard Worker     : SurfaceImpl(surfaceState),
529*8975f5c5SAndroid Build Coastguard Worker       mWidth(mState.attributes.getAsInt(EGL_WIDTH, 0)),
530*8975f5c5SAndroid Build Coastguard Worker       mHeight(mState.attributes.getAsInt(EGL_HEIGHT, 0))
531*8975f5c5SAndroid Build Coastguard Worker {}
532*8975f5c5SAndroid Build Coastguard Worker 
~SurfaceVk()533*8975f5c5SAndroid Build Coastguard Worker SurfaceVk::~SurfaceVk() {}
534*8975f5c5SAndroid Build Coastguard Worker 
destroy(const egl::Display * display)535*8975f5c5SAndroid Build Coastguard Worker void SurfaceVk::destroy(const egl::Display *display)
536*8975f5c5SAndroid Build Coastguard Worker {
537*8975f5c5SAndroid Build Coastguard Worker     DisplayVk *displayVk   = vk::GetImpl(display);
538*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = displayVk->getRenderer();
539*8975f5c5SAndroid Build Coastguard Worker 
540*8975f5c5SAndroid Build Coastguard Worker     mColorRenderTarget.destroy(renderer);
541*8975f5c5SAndroid Build Coastguard Worker     mDepthStencilRenderTarget.destroy(renderer);
542*8975f5c5SAndroid Build Coastguard Worker }
543*8975f5c5SAndroid Build Coastguard Worker 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)544*8975f5c5SAndroid Build Coastguard Worker angle::Result SurfaceVk::getAttachmentRenderTarget(const gl::Context *context,
545*8975f5c5SAndroid Build Coastguard Worker                                                    GLenum binding,
546*8975f5c5SAndroid Build Coastguard Worker                                                    const gl::ImageIndex &imageIndex,
547*8975f5c5SAndroid Build Coastguard Worker                                                    GLsizei samples,
548*8975f5c5SAndroid Build Coastguard Worker                                                    FramebufferAttachmentRenderTarget **rtOut)
549*8975f5c5SAndroid Build Coastguard Worker {
550*8975f5c5SAndroid Build Coastguard Worker     ASSERT(samples == 0);
551*8975f5c5SAndroid Build Coastguard Worker 
552*8975f5c5SAndroid Build Coastguard Worker     if (binding == GL_BACK)
553*8975f5c5SAndroid Build Coastguard Worker     {
554*8975f5c5SAndroid Build Coastguard Worker         *rtOut = &mColorRenderTarget;
555*8975f5c5SAndroid Build Coastguard Worker     }
556*8975f5c5SAndroid Build Coastguard Worker     else
557*8975f5c5SAndroid Build Coastguard Worker     {
558*8975f5c5SAndroid Build Coastguard Worker         ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
559*8975f5c5SAndroid Build Coastguard Worker         *rtOut = &mDepthStencilRenderTarget;
560*8975f5c5SAndroid Build Coastguard Worker     }
561*8975f5c5SAndroid Build Coastguard Worker 
562*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
563*8975f5c5SAndroid Build Coastguard Worker }
564*8975f5c5SAndroid Build Coastguard Worker 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)565*8975f5c5SAndroid Build Coastguard Worker void SurfaceVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
566*8975f5c5SAndroid Build Coastguard Worker {
567*8975f5c5SAndroid Build Coastguard Worker     // Forward the notification to parent class that the staging buffer changed.
568*8975f5c5SAndroid Build Coastguard Worker     onStateChange(angle::SubjectMessage::SubjectChanged);
569*8975f5c5SAndroid Build Coastguard Worker }
570*8975f5c5SAndroid Build Coastguard Worker 
getWidth() const571*8975f5c5SAndroid Build Coastguard Worker EGLint SurfaceVk::getWidth() const
572*8975f5c5SAndroid Build Coastguard Worker {
573*8975f5c5SAndroid Build Coastguard Worker     return mWidth;
574*8975f5c5SAndroid Build Coastguard Worker }
575*8975f5c5SAndroid Build Coastguard Worker 
getHeight() const576*8975f5c5SAndroid Build Coastguard Worker EGLint SurfaceVk::getHeight() const
577*8975f5c5SAndroid Build Coastguard Worker {
578*8975f5c5SAndroid Build Coastguard Worker     return mHeight;
579*8975f5c5SAndroid Build Coastguard Worker }
580*8975f5c5SAndroid Build Coastguard Worker 
AttachmentImage(SurfaceVk * surfaceVk)581*8975f5c5SAndroid Build Coastguard Worker OffscreenSurfaceVk::AttachmentImage::AttachmentImage(SurfaceVk *surfaceVk)
582*8975f5c5SAndroid Build Coastguard Worker     : imageObserverBinding(surfaceVk, kAnySurfaceImageSubjectIndex)
583*8975f5c5SAndroid Build Coastguard Worker {
584*8975f5c5SAndroid Build Coastguard Worker     imageObserverBinding.bind(&image);
585*8975f5c5SAndroid Build Coastguard Worker }
586*8975f5c5SAndroid Build Coastguard Worker 
587*8975f5c5SAndroid Build Coastguard Worker OffscreenSurfaceVk::AttachmentImage::~AttachmentImage() = default;
588*8975f5c5SAndroid Build Coastguard Worker 
initialize(DisplayVk * displayVk,EGLint width,EGLint height,const vk::Format & vkFormat,GLint samples,bool isRobustResourceInitEnabled,bool hasProtectedContent)589*8975f5c5SAndroid Build Coastguard Worker angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *displayVk,
590*8975f5c5SAndroid Build Coastguard Worker                                                               EGLint width,
591*8975f5c5SAndroid Build Coastguard Worker                                                               EGLint height,
592*8975f5c5SAndroid Build Coastguard Worker                                                               const vk::Format &vkFormat,
593*8975f5c5SAndroid Build Coastguard Worker                                                               GLint samples,
594*8975f5c5SAndroid Build Coastguard Worker                                                               bool isRobustResourceInitEnabled,
595*8975f5c5SAndroid Build Coastguard Worker                                                               bool hasProtectedContent)
596*8975f5c5SAndroid Build Coastguard Worker {
597*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(InitImageHelper(displayVk, width, height, vkFormat, samples,
598*8975f5c5SAndroid Build Coastguard Worker                               isRobustResourceInitEnabled, hasProtectedContent, &image));
599*8975f5c5SAndroid Build Coastguard Worker 
600*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer      = displayVk->getRenderer();
601*8975f5c5SAndroid Build Coastguard Worker     VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
602*8975f5c5SAndroid Build Coastguard Worker     if (hasProtectedContent)
603*8975f5c5SAndroid Build Coastguard Worker     {
604*8975f5c5SAndroid Build Coastguard Worker         flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
605*8975f5c5SAndroid Build Coastguard Worker     }
606*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(image.initMemoryAndNonZeroFillIfNeeded(
607*8975f5c5SAndroid Build Coastguard Worker         displayVk, hasProtectedContent, renderer->getMemoryProperties(), flags,
608*8975f5c5SAndroid Build Coastguard Worker         vk::MemoryAllocationType::OffscreenSurfaceAttachmentImage));
609*8975f5c5SAndroid Build Coastguard Worker 
610*8975f5c5SAndroid Build Coastguard Worker     imageViews.init(renderer);
611*8975f5c5SAndroid Build Coastguard Worker 
612*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
613*8975f5c5SAndroid Build Coastguard Worker }
614*8975f5c5SAndroid Build Coastguard Worker 
destroy(const egl::Display * display)615*8975f5c5SAndroid Build Coastguard Worker void OffscreenSurfaceVk::AttachmentImage::destroy(const egl::Display *display)
616*8975f5c5SAndroid Build Coastguard Worker {
617*8975f5c5SAndroid Build Coastguard Worker     DisplayVk *displayVk   = vk::GetImpl(display);
618*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = displayVk->getRenderer();
619*8975f5c5SAndroid Build Coastguard Worker     // Front end must ensure all usage has been submitted.
620*8975f5c5SAndroid Build Coastguard Worker     imageViews.release(renderer, image.getResourceUse());
621*8975f5c5SAndroid Build Coastguard Worker     image.releaseImage(renderer);
622*8975f5c5SAndroid Build Coastguard Worker     image.releaseStagedUpdates(renderer);
623*8975f5c5SAndroid Build Coastguard Worker }
624*8975f5c5SAndroid Build Coastguard Worker 
OffscreenSurfaceVk(const egl::SurfaceState & surfaceState,vk::Renderer * renderer)625*8975f5c5SAndroid Build Coastguard Worker OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState,
626*8975f5c5SAndroid Build Coastguard Worker                                        vk::Renderer *renderer)
627*8975f5c5SAndroid Build Coastguard Worker     : SurfaceVk(surfaceState), mColorAttachment(this), mDepthStencilAttachment(this)
628*8975f5c5SAndroid Build Coastguard Worker {
629*8975f5c5SAndroid Build Coastguard Worker     mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, nullptr, nullptr,
630*8975f5c5SAndroid Build Coastguard Worker                             {}, gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
631*8975f5c5SAndroid Build Coastguard Worker     mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
632*8975f5c5SAndroid Build Coastguard Worker                                    &mDepthStencilAttachment.imageViews, nullptr, nullptr, {},
633*8975f5c5SAndroid Build Coastguard Worker                                    gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
634*8975f5c5SAndroid Build Coastguard Worker }
635*8975f5c5SAndroid Build Coastguard Worker 
~OffscreenSurfaceVk()636*8975f5c5SAndroid Build Coastguard Worker OffscreenSurfaceVk::~OffscreenSurfaceVk() {}
637*8975f5c5SAndroid Build Coastguard Worker 
initialize(const egl::Display * display)638*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::initialize(const egl::Display *display)
639*8975f5c5SAndroid Build Coastguard Worker {
640*8975f5c5SAndroid Build Coastguard Worker     DisplayVk *displayVk = vk::GetImpl(display);
641*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = initializeImpl(displayVk);
642*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(result, EGL_BAD_SURFACE);
643*8975f5c5SAndroid Build Coastguard Worker }
644*8975f5c5SAndroid Build Coastguard Worker 
initializeImpl(DisplayVk * displayVk)645*8975f5c5SAndroid Build Coastguard Worker angle::Result OffscreenSurfaceVk::initializeImpl(DisplayVk *displayVk)
646*8975f5c5SAndroid Build Coastguard Worker {
647*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer    = displayVk->getRenderer();
648*8975f5c5SAndroid Build Coastguard Worker     const egl::Config *config = mState.config;
649*8975f5c5SAndroid Build Coastguard Worker 
650*8975f5c5SAndroid Build Coastguard Worker     renderer->reloadVolkIfNeeded();
651*8975f5c5SAndroid Build Coastguard Worker 
652*8975f5c5SAndroid Build Coastguard Worker     GLint samples = GetSampleCount(mState.config);
653*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_CHECK(displayVk, samples > 0, VK_ERROR_INITIALIZATION_FAILED);
654*8975f5c5SAndroid Build Coastguard Worker 
655*8975f5c5SAndroid Build Coastguard Worker     bool robustInit = mState.isRobustResourceInitEnabled();
656*8975f5c5SAndroid Build Coastguard Worker 
657*8975f5c5SAndroid Build Coastguard Worker     if (config->renderTargetFormat != GL_NONE)
658*8975f5c5SAndroid Build Coastguard Worker     {
659*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mColorAttachment.initialize(displayVk, mWidth, mHeight,
660*8975f5c5SAndroid Build Coastguard Worker                                               renderer->getFormat(config->renderTargetFormat),
661*8975f5c5SAndroid Build Coastguard Worker                                               samples, robustInit, mState.hasProtectedContent()));
662*8975f5c5SAndroid Build Coastguard Worker         mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, nullptr,
663*8975f5c5SAndroid Build Coastguard Worker                                 nullptr, {}, gl::LevelIndex(0), 0, 1,
664*8975f5c5SAndroid Build Coastguard Worker                                 RenderTargetTransience::Default);
665*8975f5c5SAndroid Build Coastguard Worker     }
666*8975f5c5SAndroid Build Coastguard Worker 
667*8975f5c5SAndroid Build Coastguard Worker     if (config->depthStencilFormat != GL_NONE)
668*8975f5c5SAndroid Build Coastguard Worker     {
669*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mDepthStencilAttachment.initialize(
670*8975f5c5SAndroid Build Coastguard Worker             displayVk, mWidth, mHeight, renderer->getFormat(config->depthStencilFormat), samples,
671*8975f5c5SAndroid Build Coastguard Worker             robustInit, mState.hasProtectedContent()));
672*8975f5c5SAndroid Build Coastguard Worker         mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
673*8975f5c5SAndroid Build Coastguard Worker                                        &mDepthStencilAttachment.imageViews, nullptr, nullptr, {},
674*8975f5c5SAndroid Build Coastguard Worker                                        gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
675*8975f5c5SAndroid Build Coastguard Worker     }
676*8975f5c5SAndroid Build Coastguard Worker 
677*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
678*8975f5c5SAndroid Build Coastguard Worker }
679*8975f5c5SAndroid Build Coastguard Worker 
destroy(const egl::Display * display)680*8975f5c5SAndroid Build Coastguard Worker void OffscreenSurfaceVk::destroy(const egl::Display *display)
681*8975f5c5SAndroid Build Coastguard Worker {
682*8975f5c5SAndroid Build Coastguard Worker     mColorAttachment.destroy(display);
683*8975f5c5SAndroid Build Coastguard Worker     mDepthStencilAttachment.destroy(display);
684*8975f5c5SAndroid Build Coastguard Worker 
685*8975f5c5SAndroid Build Coastguard Worker     if (mLockBufferHelper.valid())
686*8975f5c5SAndroid Build Coastguard Worker     {
687*8975f5c5SAndroid Build Coastguard Worker         mLockBufferHelper.destroy(vk::GetImpl(display)->getRenderer());
688*8975f5c5SAndroid Build Coastguard Worker     }
689*8975f5c5SAndroid Build Coastguard Worker 
690*8975f5c5SAndroid Build Coastguard Worker     // Call parent class to destroy any resources parent owns.
691*8975f5c5SAndroid Build Coastguard Worker     SurfaceVk::destroy(display);
692*8975f5c5SAndroid Build Coastguard Worker }
693*8975f5c5SAndroid Build Coastguard Worker 
unMakeCurrent(const gl::Context * context)694*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::unMakeCurrent(const gl::Context *context)
695*8975f5c5SAndroid Build Coastguard Worker {
696*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
697*8975f5c5SAndroid Build Coastguard Worker 
698*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = contextVk->onSurfaceUnMakeCurrent(this);
699*8975f5c5SAndroid Build Coastguard Worker 
700*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(result, EGL_BAD_CURRENT_SURFACE);
701*8975f5c5SAndroid Build Coastguard Worker }
702*8975f5c5SAndroid Build Coastguard Worker 
swap(const gl::Context * context)703*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::swap(const gl::Context *context)
704*8975f5c5SAndroid Build Coastguard Worker {
705*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
706*8975f5c5SAndroid Build Coastguard Worker }
707*8975f5c5SAndroid Build Coastguard Worker 
postSubBuffer(const gl::Context *,EGLint,EGLint,EGLint,EGLint)708*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::postSubBuffer(const gl::Context * /*context*/,
709*8975f5c5SAndroid Build Coastguard Worker                                              EGLint /*x*/,
710*8975f5c5SAndroid Build Coastguard Worker                                              EGLint /*y*/,
711*8975f5c5SAndroid Build Coastguard Worker                                              EGLint /*width*/,
712*8975f5c5SAndroid Build Coastguard Worker                                              EGLint /*height*/)
713*8975f5c5SAndroid Build Coastguard Worker {
714*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
715*8975f5c5SAndroid Build Coastguard Worker }
716*8975f5c5SAndroid Build Coastguard Worker 
querySurfacePointerANGLE(EGLint,void **)717*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::querySurfacePointerANGLE(EGLint /*attribute*/, void ** /*value*/)
718*8975f5c5SAndroid Build Coastguard Worker {
719*8975f5c5SAndroid Build Coastguard Worker     UNREACHABLE();
720*8975f5c5SAndroid Build Coastguard Worker     return egl::EglBadCurrentSurface();
721*8975f5c5SAndroid Build Coastguard Worker }
722*8975f5c5SAndroid Build Coastguard Worker 
bindTexImage(const gl::Context *,gl::Texture *,EGLint)723*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::bindTexImage(const gl::Context * /*context*/,
724*8975f5c5SAndroid Build Coastguard Worker                                             gl::Texture * /*texture*/,
725*8975f5c5SAndroid Build Coastguard Worker                                             EGLint /*buffer*/)
726*8975f5c5SAndroid Build Coastguard Worker {
727*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
728*8975f5c5SAndroid Build Coastguard Worker }
729*8975f5c5SAndroid Build Coastguard Worker 
releaseTexImage(const gl::Context *,EGLint)730*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::releaseTexImage(const gl::Context * /*context*/, EGLint /*buffer*/)
731*8975f5c5SAndroid Build Coastguard Worker {
732*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
733*8975f5c5SAndroid Build Coastguard Worker }
734*8975f5c5SAndroid Build Coastguard Worker 
getSyncValues(EGLuint64KHR *,EGLuint64KHR *,EGLuint64KHR *)735*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::getSyncValues(EGLuint64KHR * /*ust*/,
736*8975f5c5SAndroid Build Coastguard Worker                                              EGLuint64KHR * /*msc*/,
737*8975f5c5SAndroid Build Coastguard Worker                                              EGLuint64KHR * /*sbc*/)
738*8975f5c5SAndroid Build Coastguard Worker {
739*8975f5c5SAndroid Build Coastguard Worker     UNIMPLEMENTED();
740*8975f5c5SAndroid Build Coastguard Worker     return egl::EglBadAccess();
741*8975f5c5SAndroid Build Coastguard Worker }
742*8975f5c5SAndroid Build Coastguard Worker 
getMscRate(EGLint *,EGLint *)743*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::getMscRate(EGLint * /*numerator*/, EGLint * /*denominator*/)
744*8975f5c5SAndroid Build Coastguard Worker {
745*8975f5c5SAndroid Build Coastguard Worker     UNIMPLEMENTED();
746*8975f5c5SAndroid Build Coastguard Worker     return egl::EglBadAccess();
747*8975f5c5SAndroid Build Coastguard Worker }
748*8975f5c5SAndroid Build Coastguard Worker 
setSwapInterval(const egl::Display * display,EGLint)749*8975f5c5SAndroid Build Coastguard Worker void OffscreenSurfaceVk::setSwapInterval(const egl::Display *display, EGLint /*interval*/) {}
750*8975f5c5SAndroid Build Coastguard Worker 
isPostSubBufferSupported() const751*8975f5c5SAndroid Build Coastguard Worker EGLint OffscreenSurfaceVk::isPostSubBufferSupported() const
752*8975f5c5SAndroid Build Coastguard Worker {
753*8975f5c5SAndroid Build Coastguard Worker     return EGL_FALSE;
754*8975f5c5SAndroid Build Coastguard Worker }
755*8975f5c5SAndroid Build Coastguard Worker 
getSwapBehavior() const756*8975f5c5SAndroid Build Coastguard Worker EGLint OffscreenSurfaceVk::getSwapBehavior() const
757*8975f5c5SAndroid Build Coastguard Worker {
758*8975f5c5SAndroid Build Coastguard Worker     return EGL_BUFFER_DESTROYED;
759*8975f5c5SAndroid Build Coastguard Worker }
760*8975f5c5SAndroid Build Coastguard Worker 
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)761*8975f5c5SAndroid Build Coastguard Worker angle::Result OffscreenSurfaceVk::initializeContents(const gl::Context *context,
762*8975f5c5SAndroid Build Coastguard Worker                                                      GLenum binding,
763*8975f5c5SAndroid Build Coastguard Worker                                                      const gl::ImageIndex &imageIndex)
764*8975f5c5SAndroid Build Coastguard Worker {
765*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
766*8975f5c5SAndroid Build Coastguard Worker 
767*8975f5c5SAndroid Build Coastguard Worker     switch (binding)
768*8975f5c5SAndroid Build Coastguard Worker     {
769*8975f5c5SAndroid Build Coastguard Worker         case GL_BACK:
770*8975f5c5SAndroid Build Coastguard Worker             ASSERT(mColorAttachment.image.valid());
771*8975f5c5SAndroid Build Coastguard Worker             mColorAttachment.image.stageRobustResourceClear(imageIndex);
772*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(mColorAttachment.image.flushAllStagedUpdates(contextVk));
773*8975f5c5SAndroid Build Coastguard Worker             break;
774*8975f5c5SAndroid Build Coastguard Worker 
775*8975f5c5SAndroid Build Coastguard Worker         case GL_DEPTH:
776*8975f5c5SAndroid Build Coastguard Worker         case GL_STENCIL:
777*8975f5c5SAndroid Build Coastguard Worker             ASSERT(mDepthStencilAttachment.image.valid());
778*8975f5c5SAndroid Build Coastguard Worker             mDepthStencilAttachment.image.stageRobustResourceClear(imageIndex);
779*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(mDepthStencilAttachment.image.flushAllStagedUpdates(contextVk));
780*8975f5c5SAndroid Build Coastguard Worker             break;
781*8975f5c5SAndroid Build Coastguard Worker 
782*8975f5c5SAndroid Build Coastguard Worker         default:
783*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
784*8975f5c5SAndroid Build Coastguard Worker             break;
785*8975f5c5SAndroid Build Coastguard Worker     }
786*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
787*8975f5c5SAndroid Build Coastguard Worker }
788*8975f5c5SAndroid Build Coastguard Worker 
getColorAttachmentImage()789*8975f5c5SAndroid Build Coastguard Worker vk::ImageHelper *OffscreenSurfaceVk::getColorAttachmentImage()
790*8975f5c5SAndroid Build Coastguard Worker {
791*8975f5c5SAndroid Build Coastguard Worker     return &mColorAttachment.image;
792*8975f5c5SAndroid Build Coastguard Worker }
793*8975f5c5SAndroid Build Coastguard Worker 
lockSurface(const egl::Display * display,EGLint usageHint,bool preservePixels,uint8_t ** bufferPtrOut,EGLint * bufferPitchOut)794*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::lockSurface(const egl::Display *display,
795*8975f5c5SAndroid Build Coastguard Worker                                            EGLint usageHint,
796*8975f5c5SAndroid Build Coastguard Worker                                            bool preservePixels,
797*8975f5c5SAndroid Build Coastguard Worker                                            uint8_t **bufferPtrOut,
798*8975f5c5SAndroid Build Coastguard Worker                                            EGLint *bufferPitchOut)
799*8975f5c5SAndroid Build Coastguard Worker {
800*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRACE_EVENT0("gpu.angle", "OffscreenSurfaceVk::lockSurface");
801*8975f5c5SAndroid Build Coastguard Worker 
802*8975f5c5SAndroid Build Coastguard Worker     vk::ImageHelper *image = &mColorAttachment.image;
803*8975f5c5SAndroid Build Coastguard Worker     ASSERT(image->valid());
804*8975f5c5SAndroid Build Coastguard Worker 
805*8975f5c5SAndroid Build Coastguard Worker     angle::Result result =
806*8975f5c5SAndroid Build Coastguard Worker         LockSurfaceImpl(vk::GetImpl(display), image, mLockBufferHelper, getWidth(), getHeight(),
807*8975f5c5SAndroid Build Coastguard Worker                         usageHint, preservePixels, bufferPtrOut, bufferPitchOut);
808*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(result, EGL_BAD_ACCESS);
809*8975f5c5SAndroid Build Coastguard Worker }
810*8975f5c5SAndroid Build Coastguard Worker 
unlockSurface(const egl::Display * display,bool preservePixels)811*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::unlockSurface(const egl::Display *display, bool preservePixels)
812*8975f5c5SAndroid Build Coastguard Worker {
813*8975f5c5SAndroid Build Coastguard Worker     vk::ImageHelper *image = &mColorAttachment.image;
814*8975f5c5SAndroid Build Coastguard Worker     ASSERT(image->valid());
815*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLockBufferHelper.valid());
816*8975f5c5SAndroid Build Coastguard Worker 
817*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(UnlockSurfaceImpl(vk::GetImpl(display), image, mLockBufferHelper,
818*8975f5c5SAndroid Build Coastguard Worker                                           getWidth(), getHeight(), preservePixels),
819*8975f5c5SAndroid Build Coastguard Worker                         EGL_BAD_ACCESS);
820*8975f5c5SAndroid Build Coastguard Worker }
821*8975f5c5SAndroid Build Coastguard Worker 
origin() const822*8975f5c5SAndroid Build Coastguard Worker EGLint OffscreenSurfaceVk::origin() const
823*8975f5c5SAndroid Build Coastguard Worker {
824*8975f5c5SAndroid Build Coastguard Worker     return EGL_UPPER_LEFT_KHR;
825*8975f5c5SAndroid Build Coastguard Worker }
826*8975f5c5SAndroid Build Coastguard Worker 
attachToFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)827*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::attachToFramebuffer(const gl::Context *context,
828*8975f5c5SAndroid Build Coastguard Worker                                                    gl::Framebuffer *framebuffer)
829*8975f5c5SAndroid Build Coastguard Worker {
830*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
831*8975f5c5SAndroid Build Coastguard Worker }
832*8975f5c5SAndroid Build Coastguard Worker 
detachFromFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)833*8975f5c5SAndroid Build Coastguard Worker egl::Error OffscreenSurfaceVk::detachFromFramebuffer(const gl::Context *context,
834*8975f5c5SAndroid Build Coastguard Worker                                                      gl::Framebuffer *framebuffer)
835*8975f5c5SAndroid Build Coastguard Worker {
836*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
837*8975f5c5SAndroid Build Coastguard Worker }
838*8975f5c5SAndroid Build Coastguard Worker 
839*8975f5c5SAndroid Build Coastguard Worker namespace impl
840*8975f5c5SAndroid Build Coastguard Worker {
841*8975f5c5SAndroid Build Coastguard Worker SwapchainCleanupData::SwapchainCleanupData() = default;
~SwapchainCleanupData()842*8975f5c5SAndroid Build Coastguard Worker SwapchainCleanupData::~SwapchainCleanupData()
843*8975f5c5SAndroid Build Coastguard Worker {
844*8975f5c5SAndroid Build Coastguard Worker     ASSERT(swapchain == VK_NULL_HANDLE);
845*8975f5c5SAndroid Build Coastguard Worker     ASSERT(fences.empty());
846*8975f5c5SAndroid Build Coastguard Worker     ASSERT(semaphores.empty());
847*8975f5c5SAndroid Build Coastguard Worker }
848*8975f5c5SAndroid Build Coastguard Worker 
SwapchainCleanupData(SwapchainCleanupData && other)849*8975f5c5SAndroid Build Coastguard Worker SwapchainCleanupData::SwapchainCleanupData(SwapchainCleanupData &&other)
850*8975f5c5SAndroid Build Coastguard Worker     : swapchain(other.swapchain),
851*8975f5c5SAndroid Build Coastguard Worker       fences(std::move(other.fences)),
852*8975f5c5SAndroid Build Coastguard Worker       semaphores(std::move(other.semaphores))
853*8975f5c5SAndroid Build Coastguard Worker {
854*8975f5c5SAndroid Build Coastguard Worker     other.swapchain = VK_NULL_HANDLE;
855*8975f5c5SAndroid Build Coastguard Worker }
856*8975f5c5SAndroid Build Coastguard Worker 
getFencesStatus(VkDevice device) const857*8975f5c5SAndroid Build Coastguard Worker VkResult SwapchainCleanupData::getFencesStatus(VkDevice device) const
858*8975f5c5SAndroid Build Coastguard Worker {
859*8975f5c5SAndroid Build Coastguard Worker     // From VkSwapchainPresentFenceInfoEXT documentation:
860*8975f5c5SAndroid Build Coastguard Worker     //   Fences associated with presentations to the same swapchain on the same VkQueue must be
861*8975f5c5SAndroid Build Coastguard Worker     //   signaled in the same order as the present operations.
862*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!fences.empty());
863*8975f5c5SAndroid Build Coastguard Worker     VkResult result = fences.back().getStatus(device);
864*8975f5c5SAndroid Build Coastguard Worker     ASSERT(result != VK_SUCCESS || AreAllFencesSignaled(device, fences));
865*8975f5c5SAndroid Build Coastguard Worker     return result;
866*8975f5c5SAndroid Build Coastguard Worker }
867*8975f5c5SAndroid Build Coastguard Worker 
waitFences(VkDevice device,uint64_t timeout) const868*8975f5c5SAndroid Build Coastguard Worker void SwapchainCleanupData::waitFences(VkDevice device, uint64_t timeout) const
869*8975f5c5SAndroid Build Coastguard Worker {
870*8975f5c5SAndroid Build Coastguard Worker     if (!fences.empty())
871*8975f5c5SAndroid Build Coastguard Worker     {
872*8975f5c5SAndroid Build Coastguard Worker         VkResult result = fences.back().wait(device, timeout);
873*8975f5c5SAndroid Build Coastguard Worker         ASSERT(result != VK_SUCCESS || AreAllFencesSignaled(device, fences));
874*8975f5c5SAndroid Build Coastguard Worker     }
875*8975f5c5SAndroid Build Coastguard Worker }
876*8975f5c5SAndroid Build Coastguard Worker 
destroy(VkDevice device,vk::Recycler<vk::Fence> * fenceRecycler,vk::Recycler<vk::Semaphore> * semaphoreRecycler)877*8975f5c5SAndroid Build Coastguard Worker void SwapchainCleanupData::destroy(VkDevice device,
878*8975f5c5SAndroid Build Coastguard Worker                                    vk::Recycler<vk::Fence> *fenceRecycler,
879*8975f5c5SAndroid Build Coastguard Worker                                    vk::Recycler<vk::Semaphore> *semaphoreRecycler)
880*8975f5c5SAndroid Build Coastguard Worker {
881*8975f5c5SAndroid Build Coastguard Worker     for (vk::Fence &fence : fences)
882*8975f5c5SAndroid Build Coastguard Worker     {
883*8975f5c5SAndroid Build Coastguard Worker         RecycleUsedFence(device, fenceRecycler, std::move(fence));
884*8975f5c5SAndroid Build Coastguard Worker     }
885*8975f5c5SAndroid Build Coastguard Worker     fences.clear();
886*8975f5c5SAndroid Build Coastguard Worker 
887*8975f5c5SAndroid Build Coastguard Worker     for (vk::Semaphore &semaphore : semaphores)
888*8975f5c5SAndroid Build Coastguard Worker     {
889*8975f5c5SAndroid Build Coastguard Worker         semaphoreRecycler->recycle(std::move(semaphore));
890*8975f5c5SAndroid Build Coastguard Worker     }
891*8975f5c5SAndroid Build Coastguard Worker     semaphores.clear();
892*8975f5c5SAndroid Build Coastguard Worker 
893*8975f5c5SAndroid Build Coastguard Worker     if (swapchain)
894*8975f5c5SAndroid Build Coastguard Worker     {
895*8975f5c5SAndroid Build Coastguard Worker         vkDestroySwapchainKHR(device, swapchain, nullptr);
896*8975f5c5SAndroid Build Coastguard Worker         swapchain = VK_NULL_HANDLE;
897*8975f5c5SAndroid Build Coastguard Worker     }
898*8975f5c5SAndroid Build Coastguard Worker }
899*8975f5c5SAndroid Build Coastguard Worker 
ImagePresentOperation()900*8975f5c5SAndroid Build Coastguard Worker ImagePresentOperation::ImagePresentOperation() : imageIndex(kInvalidImageIndex) {}
~ImagePresentOperation()901*8975f5c5SAndroid Build Coastguard Worker ImagePresentOperation::~ImagePresentOperation()
902*8975f5c5SAndroid Build Coastguard Worker {
903*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!fence.valid());
904*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!semaphore.valid());
905*8975f5c5SAndroid Build Coastguard Worker     ASSERT(oldSwapchains.empty());
906*8975f5c5SAndroid Build Coastguard Worker }
907*8975f5c5SAndroid Build Coastguard Worker 
ImagePresentOperation(ImagePresentOperation && other)908*8975f5c5SAndroid Build Coastguard Worker ImagePresentOperation::ImagePresentOperation(ImagePresentOperation &&other)
909*8975f5c5SAndroid Build Coastguard Worker     : fence(std::move(other.fence)),
910*8975f5c5SAndroid Build Coastguard Worker       semaphore(std::move(other.semaphore)),
911*8975f5c5SAndroid Build Coastguard Worker       imageIndex(other.imageIndex),
912*8975f5c5SAndroid Build Coastguard Worker       queueSerial(other.queueSerial),
913*8975f5c5SAndroid Build Coastguard Worker       oldSwapchains(std::move(other.oldSwapchains))
914*8975f5c5SAndroid Build Coastguard Worker {}
915*8975f5c5SAndroid Build Coastguard Worker 
operator =(ImagePresentOperation && other)916*8975f5c5SAndroid Build Coastguard Worker ImagePresentOperation &ImagePresentOperation::operator=(ImagePresentOperation &&other)
917*8975f5c5SAndroid Build Coastguard Worker {
918*8975f5c5SAndroid Build Coastguard Worker     std::swap(fence, other.fence);
919*8975f5c5SAndroid Build Coastguard Worker     std::swap(semaphore, other.semaphore);
920*8975f5c5SAndroid Build Coastguard Worker     std::swap(imageIndex, other.imageIndex);
921*8975f5c5SAndroid Build Coastguard Worker     std::swap(queueSerial, other.queueSerial);
922*8975f5c5SAndroid Build Coastguard Worker     std::swap(oldSwapchains, other.oldSwapchains);
923*8975f5c5SAndroid Build Coastguard Worker     return *this;
924*8975f5c5SAndroid Build Coastguard Worker }
925*8975f5c5SAndroid Build Coastguard Worker 
destroy(VkDevice device,vk::Recycler<vk::Fence> * fenceRecycler,vk::Recycler<vk::Semaphore> * semaphoreRecycler)926*8975f5c5SAndroid Build Coastguard Worker void ImagePresentOperation::destroy(VkDevice device,
927*8975f5c5SAndroid Build Coastguard Worker                                     vk::Recycler<vk::Fence> *fenceRecycler,
928*8975f5c5SAndroid Build Coastguard Worker                                     vk::Recycler<vk::Semaphore> *semaphoreRecycler)
929*8975f5c5SAndroid Build Coastguard Worker {
930*8975f5c5SAndroid Build Coastguard Worker     // fence is only used when VK_EXT_swapchain_maintenance1 is supported.
931*8975f5c5SAndroid Build Coastguard Worker     if (fence.valid())
932*8975f5c5SAndroid Build Coastguard Worker     {
933*8975f5c5SAndroid Build Coastguard Worker         RecycleUsedFence(device, fenceRecycler, std::move(fence));
934*8975f5c5SAndroid Build Coastguard Worker     }
935*8975f5c5SAndroid Build Coastguard Worker 
936*8975f5c5SAndroid Build Coastguard Worker     ASSERT(semaphore.valid());
937*8975f5c5SAndroid Build Coastguard Worker     semaphoreRecycler->recycle(std::move(semaphore));
938*8975f5c5SAndroid Build Coastguard Worker 
939*8975f5c5SAndroid Build Coastguard Worker     // Destroy old swapchains (relevant only when VK_EXT_swapchain_maintenance1 is not supported).
940*8975f5c5SAndroid Build Coastguard Worker     for (SwapchainCleanupData &oldSwapchain : oldSwapchains)
941*8975f5c5SAndroid Build Coastguard Worker     {
942*8975f5c5SAndroid Build Coastguard Worker         oldSwapchain.destroy(device, fenceRecycler, semaphoreRecycler);
943*8975f5c5SAndroid Build Coastguard Worker     }
944*8975f5c5SAndroid Build Coastguard Worker     oldSwapchains.clear();
945*8975f5c5SAndroid Build Coastguard Worker }
946*8975f5c5SAndroid Build Coastguard Worker 
947*8975f5c5SAndroid Build Coastguard Worker SwapchainImage::SwapchainImage()  = default;
948*8975f5c5SAndroid Build Coastguard Worker SwapchainImage::~SwapchainImage() = default;
949*8975f5c5SAndroid Build Coastguard Worker 
SwapchainImage(SwapchainImage && other)950*8975f5c5SAndroid Build Coastguard Worker SwapchainImage::SwapchainImage(SwapchainImage &&other)
951*8975f5c5SAndroid Build Coastguard Worker     : image(std::move(other.image)),
952*8975f5c5SAndroid Build Coastguard Worker       imageViews(std::move(other.imageViews)),
953*8975f5c5SAndroid Build Coastguard Worker       framebuffer(std::move(other.framebuffer)),
954*8975f5c5SAndroid Build Coastguard Worker       fetchFramebuffer(std::move(other.fetchFramebuffer)),
955*8975f5c5SAndroid Build Coastguard Worker       frameNumber(other.frameNumber)
956*8975f5c5SAndroid Build Coastguard Worker {}
957*8975f5c5SAndroid Build Coastguard Worker }  // namespace impl
958*8975f5c5SAndroid Build Coastguard Worker 
959*8975f5c5SAndroid Build Coastguard Worker using namespace impl;
960*8975f5c5SAndroid Build Coastguard Worker 
WindowSurfaceVk(const egl::SurfaceState & surfaceState,EGLNativeWindowType window)961*8975f5c5SAndroid Build Coastguard Worker WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativeWindowType window)
962*8975f5c5SAndroid Build Coastguard Worker     : SurfaceVk(surfaceState),
963*8975f5c5SAndroid Build Coastguard Worker       mNativeWindowType(window),
964*8975f5c5SAndroid Build Coastguard Worker       mSurface(VK_NULL_HANDLE),
965*8975f5c5SAndroid Build Coastguard Worker       mSupportsProtectedSwapchain(false),
966*8975f5c5SAndroid Build Coastguard Worker       mSwapchain(VK_NULL_HANDLE),
967*8975f5c5SAndroid Build Coastguard Worker       mLastSwapchain(VK_NULL_HANDLE),
968*8975f5c5SAndroid Build Coastguard Worker       mSwapchainPresentMode(vk::PresentMode::FifoKHR),
969*8975f5c5SAndroid Build Coastguard Worker       mDesiredSwapchainPresentMode(vk::PresentMode::FifoKHR),
970*8975f5c5SAndroid Build Coastguard Worker       mMinImageCount(0),
971*8975f5c5SAndroid Build Coastguard Worker       mPreTransform(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR),
972*8975f5c5SAndroid Build Coastguard Worker       mEmulatedPreTransform(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR),
973*8975f5c5SAndroid Build Coastguard Worker       mCompositeAlpha(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR),
974*8975f5c5SAndroid Build Coastguard Worker       mSurfaceColorSpace(VK_COLOR_SPACE_SRGB_NONLINEAR_KHR),
975*8975f5c5SAndroid Build Coastguard Worker       mCurrentSwapchainImageIndex(0),
976*8975f5c5SAndroid Build Coastguard Worker       mDepthStencilImageBinding(this, kAnySurfaceImageSubjectIndex),
977*8975f5c5SAndroid Build Coastguard Worker       mColorImageMSBinding(this, kAnySurfaceImageSubjectIndex),
978*8975f5c5SAndroid Build Coastguard Worker       mFrameCount(1),
979*8975f5c5SAndroid Build Coastguard Worker       mBufferAgeQueryFrameNumber(0)
980*8975f5c5SAndroid Build Coastguard Worker {
981*8975f5c5SAndroid Build Coastguard Worker     // Initialize the color render target with the multisampled targets.  If not multisampled, the
982*8975f5c5SAndroid Build Coastguard Worker     // render target will be updated to refer to a swapchain image on every acquire.
983*8975f5c5SAndroid Build Coastguard Worker     mColorRenderTarget.init(&mColorImageMS, &mColorImageMSViews, nullptr, nullptr, {},
984*8975f5c5SAndroid Build Coastguard Worker                             gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
985*8975f5c5SAndroid Build Coastguard Worker     mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageViews, nullptr, nullptr,
986*8975f5c5SAndroid Build Coastguard Worker                                    {}, gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
987*8975f5c5SAndroid Build Coastguard Worker     mDepthStencilImageBinding.bind(&mDepthStencilImage);
988*8975f5c5SAndroid Build Coastguard Worker     mColorImageMSBinding.bind(&mColorImageMS);
989*8975f5c5SAndroid Build Coastguard Worker     mSwapchainStatus.isPending = false;
990*8975f5c5SAndroid Build Coastguard Worker }
991*8975f5c5SAndroid Build Coastguard Worker 
~WindowSurfaceVk()992*8975f5c5SAndroid Build Coastguard Worker WindowSurfaceVk::~WindowSurfaceVk()
993*8975f5c5SAndroid Build Coastguard Worker {
994*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mSurface == VK_NULL_HANDLE);
995*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mSwapchain == VK_NULL_HANDLE);
996*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLastSwapchain == VK_NULL_HANDLE);
997*8975f5c5SAndroid Build Coastguard Worker }
998*8975f5c5SAndroid Build Coastguard Worker 
destroy(const egl::Display * display)999*8975f5c5SAndroid Build Coastguard Worker void WindowSurfaceVk::destroy(const egl::Display *display)
1000*8975f5c5SAndroid Build Coastguard Worker {
1001*8975f5c5SAndroid Build Coastguard Worker     DisplayVk *displayVk   = vk::GetImpl(display);
1002*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = displayVk->getRenderer();
1003*8975f5c5SAndroid Build Coastguard Worker     VkDevice device        = renderer->getDevice();
1004*8975f5c5SAndroid Build Coastguard Worker     VkInstance instance    = renderer->getInstance();
1005*8975f5c5SAndroid Build Coastguard Worker 
1006*8975f5c5SAndroid Build Coastguard Worker     // flush the pipe.
1007*8975f5c5SAndroid Build Coastguard Worker     (void)renderer->waitForPresentToBeSubmitted(&mSwapchainStatus);
1008*8975f5c5SAndroid Build Coastguard Worker     (void)finish(displayVk);
1009*8975f5c5SAndroid Build Coastguard Worker 
1010*8975f5c5SAndroid Build Coastguard Worker     if (mAcquireOperation.state == impl::ImageAcquireState::Ready)
1011*8975f5c5SAndroid Build Coastguard Worker     {
1012*8975f5c5SAndroid Build Coastguard Worker         // swapchain image doesn't own ANI semaphore. Release ANI semaphore from image so that it
1013*8975f5c5SAndroid Build Coastguard Worker         // can destroy cleanly without hitting assertion..
1014*8975f5c5SAndroid Build Coastguard Worker         // Only single swapchain image may have semaphore associated.
1015*8975f5c5SAndroid Build Coastguard Worker         ASSERT(!mSwapchainImages.empty());
1016*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mCurrentSwapchainImageIndex < mSwapchainImages.size());
1017*8975f5c5SAndroid Build Coastguard Worker         mSwapchainImages[mCurrentSwapchainImageIndex].image->resetAcquireNextImageSemaphore();
1018*8975f5c5SAndroid Build Coastguard Worker     }
1019*8975f5c5SAndroid Build Coastguard Worker 
1020*8975f5c5SAndroid Build Coastguard Worker     if (mLockBufferHelper.valid())
1021*8975f5c5SAndroid Build Coastguard Worker     {
1022*8975f5c5SAndroid Build Coastguard Worker         mLockBufferHelper.destroy(renderer);
1023*8975f5c5SAndroid Build Coastguard Worker     }
1024*8975f5c5SAndroid Build Coastguard Worker 
1025*8975f5c5SAndroid Build Coastguard Worker     for (impl::ImagePresentOperation &presentOperation : mPresentHistory)
1026*8975f5c5SAndroid Build Coastguard Worker     {
1027*8975f5c5SAndroid Build Coastguard Worker         if (presentOperation.fence.valid())
1028*8975f5c5SAndroid Build Coastguard Worker         {
1029*8975f5c5SAndroid Build Coastguard Worker             (void)presentOperation.fence.wait(device, renderer->getMaxFenceWaitTimeNs());
1030*8975f5c5SAndroid Build Coastguard Worker         }
1031*8975f5c5SAndroid Build Coastguard Worker         presentOperation.destroy(device, &mPresentFenceRecycler, &mPresentSemaphoreRecycler);
1032*8975f5c5SAndroid Build Coastguard Worker     }
1033*8975f5c5SAndroid Build Coastguard Worker     mPresentHistory.clear();
1034*8975f5c5SAndroid Build Coastguard Worker 
1035*8975f5c5SAndroid Build Coastguard Worker     destroySwapChainImages(displayVk);
1036*8975f5c5SAndroid Build Coastguard Worker 
1037*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mSwapchain == mLastSwapchain || mSwapchain == VK_NULL_HANDLE);
1038*8975f5c5SAndroid Build Coastguard Worker     if (mLastSwapchain != VK_NULL_HANDLE)
1039*8975f5c5SAndroid Build Coastguard Worker     {
1040*8975f5c5SAndroid Build Coastguard Worker         vkDestroySwapchainKHR(device, mLastSwapchain, nullptr);
1041*8975f5c5SAndroid Build Coastguard Worker         mSwapchain     = VK_NULL_HANDLE;
1042*8975f5c5SAndroid Build Coastguard Worker         mLastSwapchain = VK_NULL_HANDLE;
1043*8975f5c5SAndroid Build Coastguard Worker     }
1044*8975f5c5SAndroid Build Coastguard Worker 
1045*8975f5c5SAndroid Build Coastguard Worker     for (vk::Semaphore &semaphore : mAcquireOperation.unlockedAcquireData.acquireImageSemaphores)
1046*8975f5c5SAndroid Build Coastguard Worker     {
1047*8975f5c5SAndroid Build Coastguard Worker         semaphore.destroy(device);
1048*8975f5c5SAndroid Build Coastguard Worker     }
1049*8975f5c5SAndroid Build Coastguard Worker     for (SwapchainCleanupData &oldSwapchain : mOldSwapchains)
1050*8975f5c5SAndroid Build Coastguard Worker     {
1051*8975f5c5SAndroid Build Coastguard Worker         oldSwapchain.waitFences(device, renderer->getMaxFenceWaitTimeNs());
1052*8975f5c5SAndroid Build Coastguard Worker         oldSwapchain.destroy(device, &mPresentFenceRecycler, &mPresentSemaphoreRecycler);
1053*8975f5c5SAndroid Build Coastguard Worker     }
1054*8975f5c5SAndroid Build Coastguard Worker     mOldSwapchains.clear();
1055*8975f5c5SAndroid Build Coastguard Worker 
1056*8975f5c5SAndroid Build Coastguard Worker     mPresentSemaphoreRecycler.destroy(device);
1057*8975f5c5SAndroid Build Coastguard Worker     mPresentFenceRecycler.destroy(device);
1058*8975f5c5SAndroid Build Coastguard Worker 
1059*8975f5c5SAndroid Build Coastguard Worker     // Call parent class to destroy any resources parent owns.
1060*8975f5c5SAndroid Build Coastguard Worker     SurfaceVk::destroy(display);
1061*8975f5c5SAndroid Build Coastguard Worker 
1062*8975f5c5SAndroid Build Coastguard Worker     // Destroy the surface without holding the EGL lock.  This works around a specific deadlock
1063*8975f5c5SAndroid Build Coastguard Worker     // in Android.  On this platform:
1064*8975f5c5SAndroid Build Coastguard Worker     //
1065*8975f5c5SAndroid Build Coastguard Worker     // - For EGL applications, parts of surface creation and destruction are handled by the
1066*8975f5c5SAndroid Build Coastguard Worker     //   platform, and parts of it are done by the native EGL driver.  Namely, on surface
1067*8975f5c5SAndroid Build Coastguard Worker     //   destruction, native_window_api_disconnect is called outside the EGL driver.
1068*8975f5c5SAndroid Build Coastguard Worker     // - For Vulkan applications, vkDestroySurfaceKHR takes full responsibility for destroying
1069*8975f5c5SAndroid Build Coastguard Worker     //   the surface, including calling native_window_api_disconnect.
1070*8975f5c5SAndroid Build Coastguard Worker     //
1071*8975f5c5SAndroid Build Coastguard Worker     // Unfortunately, native_window_api_disconnect may use EGL sync objects and can lead to
1072*8975f5c5SAndroid Build Coastguard Worker     // calling into the EGL driver.  For ANGLE, this is particularly problematic because it is
1073*8975f5c5SAndroid Build Coastguard Worker     // simultaneously a Vulkan application and the EGL driver, causing `vkDestroySurfaceKHR` to
1074*8975f5c5SAndroid Build Coastguard Worker     // call back into ANGLE and attempt to reacquire the EGL lock.
1075*8975f5c5SAndroid Build Coastguard Worker     //
1076*8975f5c5SAndroid Build Coastguard Worker     // Since there are no users of the surface when calling vkDestroySurfaceKHR, it is safe for
1077*8975f5c5SAndroid Build Coastguard Worker     // ANGLE to destroy it without holding the EGL lock, effectively simulating the situation
1078*8975f5c5SAndroid Build Coastguard Worker     // for EGL applications, where native_window_api_disconnect is called after the EGL driver
1079*8975f5c5SAndroid Build Coastguard Worker     // has returned.
1080*8975f5c5SAndroid Build Coastguard Worker     if (mSurface)
1081*8975f5c5SAndroid Build Coastguard Worker     {
1082*8975f5c5SAndroid Build Coastguard Worker         egl::Display::GetCurrentThreadUnlockedTailCall()->add(
1083*8975f5c5SAndroid Build Coastguard Worker             [surface = mSurface, instance](void *resultOut) {
1084*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::destroy:vkDestroySurfaceKHR");
1085*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_UNUSED_VARIABLE(resultOut);
1086*8975f5c5SAndroid Build Coastguard Worker                 vkDestroySurfaceKHR(instance, surface, nullptr);
1087*8975f5c5SAndroid Build Coastguard Worker             });
1088*8975f5c5SAndroid Build Coastguard Worker         mSurface = VK_NULL_HANDLE;
1089*8975f5c5SAndroid Build Coastguard Worker     }
1090*8975f5c5SAndroid Build Coastguard Worker }
1091*8975f5c5SAndroid Build Coastguard Worker 
initialize(const egl::Display * display)1092*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::initialize(const egl::Display *display)
1093*8975f5c5SAndroid Build Coastguard Worker {
1094*8975f5c5SAndroid Build Coastguard Worker     DisplayVk *displayVk = vk::GetImpl(display);
1095*8975f5c5SAndroid Build Coastguard Worker     bool anyMatches      = false;
1096*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = initializeImpl(displayVk, &anyMatches);
1097*8975f5c5SAndroid Build Coastguard Worker     if (result == angle::Result::Continue && !anyMatches)
1098*8975f5c5SAndroid Build Coastguard Worker     {
1099*8975f5c5SAndroid Build Coastguard Worker         return angle::ToEGL(angle::Result::Stop, EGL_BAD_MATCH);
1100*8975f5c5SAndroid Build Coastguard Worker     }
1101*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(result, EGL_BAD_SURFACE);
1102*8975f5c5SAndroid Build Coastguard Worker }
1103*8975f5c5SAndroid Build Coastguard Worker 
unMakeCurrent(const gl::Context * context)1104*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::unMakeCurrent(const gl::Context *context)
1105*8975f5c5SAndroid Build Coastguard Worker {
1106*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
1107*8975f5c5SAndroid Build Coastguard Worker 
1108*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = contextVk->onSurfaceUnMakeCurrent(this);
1109*8975f5c5SAndroid Build Coastguard Worker     // Even though all swap chain images are tracked individually, the semaphores are not
1110*8975f5c5SAndroid Build Coastguard Worker     // tracked by ResourceUse. This propagates context's queue serial to surface when it
1111*8975f5c5SAndroid Build Coastguard Worker     // detaches from context so that surface will always wait until context is finished.
1112*8975f5c5SAndroid Build Coastguard Worker     mUse.merge(contextVk->getSubmittedResourceUse());
1113*8975f5c5SAndroid Build Coastguard Worker 
1114*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(result, EGL_BAD_CURRENT_SURFACE);
1115*8975f5c5SAndroid Build Coastguard Worker }
1116*8975f5c5SAndroid Build Coastguard Worker 
getIntendedFormatID(vk::Renderer * renderer)1117*8975f5c5SAndroid Build Coastguard Worker angle::FormatID WindowSurfaceVk::getIntendedFormatID(vk::Renderer *renderer)
1118*8975f5c5SAndroid Build Coastguard Worker {
1119*8975f5c5SAndroid Build Coastguard Worker     // Ensure that the format and colorspace pair is supported.
1120*8975f5c5SAndroid Build Coastguard Worker     const vk::Format &format = renderer->getFormat(mState.config->renderTargetFormat);
1121*8975f5c5SAndroid Build Coastguard Worker     return format.getIntendedFormatID();
1122*8975f5c5SAndroid Build Coastguard Worker }
1123*8975f5c5SAndroid Build Coastguard Worker 
getActualFormatID(vk::Renderer * renderer)1124*8975f5c5SAndroid Build Coastguard Worker angle::FormatID WindowSurfaceVk::getActualFormatID(vk::Renderer *renderer)
1125*8975f5c5SAndroid Build Coastguard Worker {
1126*8975f5c5SAndroid Build Coastguard Worker     // Ensure that the format and colorspace pair is supported.
1127*8975f5c5SAndroid Build Coastguard Worker     const vk::Format &format = renderer->getFormat(mState.config->renderTargetFormat);
1128*8975f5c5SAndroid Build Coastguard Worker 
1129*8975f5c5SAndroid Build Coastguard Worker     angle::FormatID actualFormatID   = format.getActualRenderableImageFormatID();
1130*8975f5c5SAndroid Build Coastguard Worker     angle::FormatID intendedFormatID = format.getIntendedFormatID();
1131*8975f5c5SAndroid Build Coastguard Worker 
1132*8975f5c5SAndroid Build Coastguard Worker     // For devices that don't support creating swapchain images with RGB8, emulate with RGBA8.
1133*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().overrideSurfaceFormatRGB8ToRGBA8.enabled &&
1134*8975f5c5SAndroid Build Coastguard Worker         intendedFormatID == angle::FormatID::R8G8B8_UNORM)
1135*8975f5c5SAndroid Build Coastguard Worker     {
1136*8975f5c5SAndroid Build Coastguard Worker         actualFormatID = angle::FormatID::R8G8B8A8_UNORM;
1137*8975f5c5SAndroid Build Coastguard Worker     }
1138*8975f5c5SAndroid Build Coastguard Worker     return actualFormatID;
1139*8975f5c5SAndroid Build Coastguard Worker }
1140*8975f5c5SAndroid Build Coastguard Worker 
updateColorSpace(DisplayVk * displayVk)1141*8975f5c5SAndroid Build Coastguard Worker bool WindowSurfaceVk::updateColorSpace(DisplayVk *displayVk)
1142*8975f5c5SAndroid Build Coastguard Worker {
1143*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = displayVk->getRenderer();
1144*8975f5c5SAndroid Build Coastguard Worker 
1145*8975f5c5SAndroid Build Coastguard Worker     VkFormat vkFormat = vk::GetVkFormatFromFormatID(renderer, getActualFormatID(renderer));
1146*8975f5c5SAndroid Build Coastguard Worker 
1147*8975f5c5SAndroid Build Coastguard Worker     EGLenum eglColorSpaceEnum =
1148*8975f5c5SAndroid Build Coastguard Worker         static_cast<EGLenum>(mState.attributes.get(EGL_GL_COLORSPACE, EGL_NONE));
1149*8975f5c5SAndroid Build Coastguard Worker 
1150*8975f5c5SAndroid Build Coastguard Worker     // If EGL did not specify color space, we will use VK_COLOR_SPACE_PASS_THROUGH_EXT if supported.
1151*8975f5c5SAndroid Build Coastguard Worker     if (eglColorSpaceEnum == EGL_NONE &&
1152*8975f5c5SAndroid Build Coastguard Worker         renderer->getFeatures().mapUnspecifiedColorSpaceToPassThrough.enabled &&
1153*8975f5c5SAndroid Build Coastguard Worker         displayVk->isSurfaceFormatColorspacePairSupported(mSurface, vkFormat,
1154*8975f5c5SAndroid Build Coastguard Worker                                                           VK_COLOR_SPACE_PASS_THROUGH_EXT))
1155*8975f5c5SAndroid Build Coastguard Worker     {
1156*8975f5c5SAndroid Build Coastguard Worker         mSurfaceColorSpace = VK_COLOR_SPACE_PASS_THROUGH_EXT;
1157*8975f5c5SAndroid Build Coastguard Worker         return true;
1158*8975f5c5SAndroid Build Coastguard Worker     }
1159*8975f5c5SAndroid Build Coastguard Worker 
1160*8975f5c5SAndroid Build Coastguard Worker     mSurfaceColorSpace = MapEglColorSpaceToVkColorSpace(renderer, eglColorSpaceEnum);
1161*8975f5c5SAndroid Build Coastguard Worker     return displayVk->isSurfaceFormatColorspacePairSupported(mSurface, vkFormat,
1162*8975f5c5SAndroid Build Coastguard Worker                                                              mSurfaceColorSpace);
1163*8975f5c5SAndroid Build Coastguard Worker }
1164*8975f5c5SAndroid Build Coastguard Worker 
initializeImpl(DisplayVk * displayVk,bool * anyMatchesOut)1165*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk, bool *anyMatchesOut)
1166*8975f5c5SAndroid Build Coastguard Worker {
1167*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = displayVk->getRenderer();
1168*8975f5c5SAndroid Build Coastguard Worker 
1169*8975f5c5SAndroid Build Coastguard Worker     mColorImageMSViews.init(renderer);
1170*8975f5c5SAndroid Build Coastguard Worker     mDepthStencilImageViews.init(renderer);
1171*8975f5c5SAndroid Build Coastguard Worker 
1172*8975f5c5SAndroid Build Coastguard Worker     renderer->reloadVolkIfNeeded();
1173*8975f5c5SAndroid Build Coastguard Worker 
1174*8975f5c5SAndroid Build Coastguard Worker     gl::Extents windowSize;
1175*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(createSurfaceVk(displayVk, &windowSize));
1176*8975f5c5SAndroid Build Coastguard Worker 
1177*8975f5c5SAndroid Build Coastguard Worker     // Check if the selected queue created supports present to this surface.
1178*8975f5c5SAndroid Build Coastguard Worker     bool presentSupported = false;
1179*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(renderer->checkQueueForSurfacePresent(displayVk, mSurface, &presentSupported));
1180*8975f5c5SAndroid Build Coastguard Worker     if (!presentSupported)
1181*8975f5c5SAndroid Build Coastguard Worker     {
1182*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
1183*8975f5c5SAndroid Build Coastguard Worker     }
1184*8975f5c5SAndroid Build Coastguard Worker 
1185*8975f5c5SAndroid Build Coastguard Worker     const VkPhysicalDevice &physicalDevice = renderer->getPhysicalDevice();
1186*8975f5c5SAndroid Build Coastguard Worker 
1187*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().supportsSurfaceCapabilities2Extension.enabled)
1188*8975f5c5SAndroid Build Coastguard Worker     {
1189*8975f5c5SAndroid Build Coastguard Worker         VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo2 = {};
1190*8975f5c5SAndroid Build Coastguard Worker         surfaceInfo2.sType   = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
1191*8975f5c5SAndroid Build Coastguard Worker         surfaceInfo2.surface = mSurface;
1192*8975f5c5SAndroid Build Coastguard Worker 
1193*8975f5c5SAndroid Build Coastguard Worker         VkSurfaceCapabilities2KHR surfaceCaps2 = {};
1194*8975f5c5SAndroid Build Coastguard Worker         surfaceCaps2.sType                     = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
1195*8975f5c5SAndroid Build Coastguard Worker 
1196*8975f5c5SAndroid Build Coastguard Worker         VkSharedPresentSurfaceCapabilitiesKHR sharedPresentSurfaceCaps = {};
1197*8975f5c5SAndroid Build Coastguard Worker         if (renderer->getFeatures().supportsSharedPresentableImageExtension.enabled)
1198*8975f5c5SAndroid Build Coastguard Worker         {
1199*8975f5c5SAndroid Build Coastguard Worker             sharedPresentSurfaceCaps.sType =
1200*8975f5c5SAndroid Build Coastguard Worker                 VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
1201*8975f5c5SAndroid Build Coastguard Worker             sharedPresentSurfaceCaps.sharedPresentSupportedUsageFlags =
1202*8975f5c5SAndroid Build Coastguard Worker                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
1203*8975f5c5SAndroid Build Coastguard Worker 
1204*8975f5c5SAndroid Build Coastguard Worker             vk::AddToPNextChain(&surfaceCaps2, &sharedPresentSurfaceCaps);
1205*8975f5c5SAndroid Build Coastguard Worker         }
1206*8975f5c5SAndroid Build Coastguard Worker 
1207*8975f5c5SAndroid Build Coastguard Worker         VkSurfaceProtectedCapabilitiesKHR surfaceProtectedCaps = {};
1208*8975f5c5SAndroid Build Coastguard Worker         if (renderer->getFeatures().supportsSurfaceProtectedCapabilitiesExtension.enabled)
1209*8975f5c5SAndroid Build Coastguard Worker         {
1210*8975f5c5SAndroid Build Coastguard Worker             surfaceProtectedCaps.sType = VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR;
1211*8975f5c5SAndroid Build Coastguard Worker 
1212*8975f5c5SAndroid Build Coastguard Worker             vk::AddToPNextChain(&surfaceCaps2, &surfaceProtectedCaps);
1213*8975f5c5SAndroid Build Coastguard Worker         }
1214*8975f5c5SAndroid Build Coastguard Worker 
1215*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceCapabilities2KHR(
1216*8975f5c5SAndroid Build Coastguard Worker                                     physicalDevice, &surfaceInfo2, &surfaceCaps2));
1217*8975f5c5SAndroid Build Coastguard Worker 
1218*8975f5c5SAndroid Build Coastguard Worker         mSurfaceCaps                = surfaceCaps2.surfaceCapabilities;
1219*8975f5c5SAndroid Build Coastguard Worker         mSupportsProtectedSwapchain = surfaceProtectedCaps.supportsProtected;
1220*8975f5c5SAndroid Build Coastguard Worker     }
1221*8975f5c5SAndroid Build Coastguard Worker     else
1222*8975f5c5SAndroid Build Coastguard Worker     {
1223*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface,
1224*8975f5c5SAndroid Build Coastguard Worker                                                                           &mSurfaceCaps));
1225*8975f5c5SAndroid Build Coastguard Worker     }
1226*8975f5c5SAndroid Build Coastguard Worker 
1227*8975f5c5SAndroid Build Coastguard Worker     if (IsAndroid())
1228*8975f5c5SAndroid Build Coastguard Worker     {
1229*8975f5c5SAndroid Build Coastguard Worker         mSupportsProtectedSwapchain = true;
1230*8975f5c5SAndroid Build Coastguard Worker     }
1231*8975f5c5SAndroid Build Coastguard Worker 
1232*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_CHECK(displayVk, (mState.hasProtectedContent() ? mSupportsProtectedSwapchain : true),
1233*8975f5c5SAndroid Build Coastguard Worker                    VK_ERROR_FEATURE_NOT_PRESENT);
1234*8975f5c5SAndroid Build Coastguard Worker 
1235*8975f5c5SAndroid Build Coastguard Worker     // Adjust width and height to the swapchain if necessary.
1236*8975f5c5SAndroid Build Coastguard Worker     uint32_t width  = mSurfaceCaps.currentExtent.width;
1237*8975f5c5SAndroid Build Coastguard Worker     uint32_t height = mSurfaceCaps.currentExtent.height;
1238*8975f5c5SAndroid Build Coastguard Worker 
1239*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_CHECK(displayVk,
1240*8975f5c5SAndroid Build Coastguard Worker                    (mSurfaceCaps.supportedUsageFlags & kSurfaceVkColorImageUsageFlags) ==
1241*8975f5c5SAndroid Build Coastguard Worker                        kSurfaceVkColorImageUsageFlags,
1242*8975f5c5SAndroid Build Coastguard Worker                    VK_ERROR_INITIALIZATION_FAILED);
1243*8975f5c5SAndroid Build Coastguard Worker 
1244*8975f5c5SAndroid Build Coastguard Worker     EGLAttrib attribWidth  = mState.attributes.get(EGL_WIDTH, 0);
1245*8975f5c5SAndroid Build Coastguard Worker     EGLAttrib attribHeight = mState.attributes.get(EGL_HEIGHT, 0);
1246*8975f5c5SAndroid Build Coastguard Worker 
1247*8975f5c5SAndroid Build Coastguard Worker     if (mSurfaceCaps.currentExtent.width == kSurfaceSizedBySwapchain)
1248*8975f5c5SAndroid Build Coastguard Worker     {
1249*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mSurfaceCaps.currentExtent.height == kSurfaceSizedBySwapchain);
1250*8975f5c5SAndroid Build Coastguard Worker 
1251*8975f5c5SAndroid Build Coastguard Worker         width  = (attribWidth != 0) ? static_cast<uint32_t>(attribWidth) : windowSize.width;
1252*8975f5c5SAndroid Build Coastguard Worker         height = (attribHeight != 0) ? static_cast<uint32_t>(attribHeight) : windowSize.height;
1253*8975f5c5SAndroid Build Coastguard Worker     }
1254*8975f5c5SAndroid Build Coastguard Worker 
1255*8975f5c5SAndroid Build Coastguard Worker     gl::Extents extents(static_cast<int>(width), static_cast<int>(height), 1);
1256*8975f5c5SAndroid Build Coastguard Worker 
1257*8975f5c5SAndroid Build Coastguard Worker     // Introduction to Android rotation and pre-rotation:
1258*8975f5c5SAndroid Build Coastguard Worker     //
1259*8975f5c5SAndroid Build Coastguard Worker     // Android devices have one native orientation, but a window may be displayed in a different
1260*8975f5c5SAndroid Build Coastguard Worker     // orientation.  This results in the window being "rotated" relative to the native orientation.
1261*8975f5c5SAndroid Build Coastguard Worker     // For example, the native orientation of a Pixel 4 is portrait (i.e. height > width).
1262*8975f5c5SAndroid Build Coastguard Worker     // However, many games want to be landscape (i.e. width > height).  Some applications will
1263*8975f5c5SAndroid Build Coastguard Worker     // adapt to whatever orientation the user places the device in (e.g. auto-rotation).
1264*8975f5c5SAndroid Build Coastguard Worker     //
1265*8975f5c5SAndroid Build Coastguard Worker     // A convention is used within ANGLE of referring to the "rotated" and "non-rotated" aspects of
1266*8975f5c5SAndroid Build Coastguard Worker     // a topic (e.g. a window's extents, a scissor, a viewport):
1267*8975f5c5SAndroid Build Coastguard Worker     //
1268*8975f5c5SAndroid Build Coastguard Worker     // - Non-rotated.  This refers to the way that the application views the window.  Rotation is
1269*8975f5c5SAndroid Build Coastguard Worker     //   an Android concept, not a GL concept.  An application may view its window as landscape or
1270*8975f5c5SAndroid Build Coastguard Worker     //   portrait, but not necessarily view its window as being rotated.  For example, an
1271*8975f5c5SAndroid Build Coastguard Worker     //   application will set a scissor and viewport in a manner consistent with its view of the
1272*8975f5c5SAndroid Build Coastguard Worker     //   window size (i.e. a non-rotated manner).
1273*8975f5c5SAndroid Build Coastguard Worker     //
1274*8975f5c5SAndroid Build Coastguard Worker     // - Rotated.  This refers to the way that Vulkan views the window.  If the window's
1275*8975f5c5SAndroid Build Coastguard Worker     //   orientation is the same as the native orientation, the rotated view will happen to be
1276*8975f5c5SAndroid Build Coastguard Worker     //   equivalent to the non-rotated view, but regardless of the window's orientation, ANGLE uses
1277*8975f5c5SAndroid Build Coastguard Worker     //   the "rotated" term as whatever the Vulkan view of the window is.
1278*8975f5c5SAndroid Build Coastguard Worker     //
1279*8975f5c5SAndroid Build Coastguard Worker     // Most of ANGLE is designed to work with the non-rotated view of the window.  This is
1280*8975f5c5SAndroid Build Coastguard Worker     // certainly true of the ANGLE front-end.  It is also true of most of the Vulkan back-end,
1281*8975f5c5SAndroid Build Coastguard Worker     // which is still translating GL to Vulkan.  Only part of the Vulkan back-end needs to
1282*8975f5c5SAndroid Build Coastguard Worker     // communicate directly to Vulkan in terms of the window's rotation.  For example, the viewport
1283*8975f5c5SAndroid Build Coastguard Worker     // and scissor calculations are done with non-rotated values; and then the final values are
1284*8975f5c5SAndroid Build Coastguard Worker     // rotated.
1285*8975f5c5SAndroid Build Coastguard Worker     //
1286*8975f5c5SAndroid Build Coastguard Worker     // ANGLE learns about the window's rotation from mSurfaceCaps.currentTransform.  If
1287*8975f5c5SAndroid Build Coastguard Worker     // currentTransform is non-IDENTITY, ANGLE must "pre-rotate" various aspects of its work
1288*8975f5c5SAndroid Build Coastguard Worker     // (e.g. rotate vertices in the vertex shaders, change scissor, viewport, and render-pass
1289*8975f5c5SAndroid Build Coastguard Worker     // renderArea).  The swapchain's transform is given the value of mSurfaceCaps.currentTransform.
1290*8975f5c5SAndroid Build Coastguard Worker     // That prevents SurfaceFlinger from doing a rotation blit for every frame (which is costly in
1291*8975f5c5SAndroid Build Coastguard Worker     // terms of performance and power).
1292*8975f5c5SAndroid Build Coastguard Worker     //
1293*8975f5c5SAndroid Build Coastguard Worker     // When a window is rotated 90 or 270 degrees, the aspect ratio changes.  The width and height
1294*8975f5c5SAndroid Build Coastguard Worker     // are swapped.  The x/y and width/height of various values in ANGLE must also be swapped
1295*8975f5c5SAndroid Build Coastguard Worker     // before communicating the values to Vulkan.
1296*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().enablePreRotateSurfaces.enabled)
1297*8975f5c5SAndroid Build Coastguard Worker     {
1298*8975f5c5SAndroid Build Coastguard Worker         // Use the surface's transform.  For many platforms, this will always be identity (ANGLE
1299*8975f5c5SAndroid Build Coastguard Worker         // does not need to do any pre-rotation).  However, when mSurfaceCaps.currentTransform is
1300*8975f5c5SAndroid Build Coastguard Worker         // not identity, the device has been rotated away from its natural orientation.  In such a
1301*8975f5c5SAndroid Build Coastguard Worker         // case, ANGLE must rotate all rendering in order to avoid the compositor
1302*8975f5c5SAndroid Build Coastguard Worker         // (e.g. SurfaceFlinger on Android) performing an additional rotation blit.  In addition,
1303*8975f5c5SAndroid Build Coastguard Worker         // ANGLE must create the swapchain with VkSwapchainCreateInfoKHR::preTransform set to the
1304*8975f5c5SAndroid Build Coastguard Worker         // value of mSurfaceCaps.currentTransform.
1305*8975f5c5SAndroid Build Coastguard Worker         mPreTransform = mSurfaceCaps.currentTransform;
1306*8975f5c5SAndroid Build Coastguard Worker     }
1307*8975f5c5SAndroid Build Coastguard Worker     else
1308*8975f5c5SAndroid Build Coastguard Worker     {
1309*8975f5c5SAndroid Build Coastguard Worker         // Default to identity transform.
1310*8975f5c5SAndroid Build Coastguard Worker         mPreTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
1311*8975f5c5SAndroid Build Coastguard Worker 
1312*8975f5c5SAndroid Build Coastguard Worker         if ((mSurfaceCaps.supportedTransforms & mPreTransform) == 0)
1313*8975f5c5SAndroid Build Coastguard Worker         {
1314*8975f5c5SAndroid Build Coastguard Worker             mPreTransform = mSurfaceCaps.currentTransform;
1315*8975f5c5SAndroid Build Coastguard Worker         }
1316*8975f5c5SAndroid Build Coastguard Worker     }
1317*8975f5c5SAndroid Build Coastguard Worker 
1318*8975f5c5SAndroid Build Coastguard Worker     // Set emulated pre-transform if any emulated prerotation features are set.
1319*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().emulatedPrerotation90.enabled)
1320*8975f5c5SAndroid Build Coastguard Worker     {
1321*8975f5c5SAndroid Build Coastguard Worker         mEmulatedPreTransform = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR;
1322*8975f5c5SAndroid Build Coastguard Worker     }
1323*8975f5c5SAndroid Build Coastguard Worker     else if (renderer->getFeatures().emulatedPrerotation180.enabled)
1324*8975f5c5SAndroid Build Coastguard Worker     {
1325*8975f5c5SAndroid Build Coastguard Worker         mEmulatedPreTransform = VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR;
1326*8975f5c5SAndroid Build Coastguard Worker     }
1327*8975f5c5SAndroid Build Coastguard Worker     else if (renderer->getFeatures().emulatedPrerotation270.enabled)
1328*8975f5c5SAndroid Build Coastguard Worker     {
1329*8975f5c5SAndroid Build Coastguard Worker         mEmulatedPreTransform = VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
1330*8975f5c5SAndroid Build Coastguard Worker     }
1331*8975f5c5SAndroid Build Coastguard Worker 
1332*8975f5c5SAndroid Build Coastguard Worker     // If prerotation is emulated, the window is physically rotated.  With real prerotation, the
1333*8975f5c5SAndroid Build Coastguard Worker     // surface reports the rotated sizes.  With emulated prerotation however, the surface reports
1334*8975f5c5SAndroid Build Coastguard Worker     // the actual window sizes.  Adjust the window extents to match what real prerotation would have
1335*8975f5c5SAndroid Build Coastguard Worker     // reported.
1336*8975f5c5SAndroid Build Coastguard Worker     if (Is90DegreeRotation(mEmulatedPreTransform))
1337*8975f5c5SAndroid Build Coastguard Worker     {
1338*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mPreTransform == VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR);
1339*8975f5c5SAndroid Build Coastguard Worker         std::swap(extents.width, extents.height);
1340*8975f5c5SAndroid Build Coastguard Worker     }
1341*8975f5c5SAndroid Build Coastguard Worker 
1342*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(GetPresentModes(displayVk, physicalDevice, mSurface, &mPresentModes));
1343*8975f5c5SAndroid Build Coastguard Worker 
1344*8975f5c5SAndroid Build Coastguard Worker     // Select appropriate present mode based on vsync parameter. Default to 1 (FIFO), though it
1345*8975f5c5SAndroid Build Coastguard Worker     // will get clamped to the min/max values specified at display creation time.
1346*8975f5c5SAndroid Build Coastguard Worker     setSwapInterval(displayVk, mState.getPreferredSwapInterval());
1347*8975f5c5SAndroid Build Coastguard Worker 
1348*8975f5c5SAndroid Build Coastguard Worker     if (!updateColorSpace(displayVk))
1349*8975f5c5SAndroid Build Coastguard Worker     {
1350*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
1351*8975f5c5SAndroid Build Coastguard Worker     }
1352*8975f5c5SAndroid Build Coastguard Worker 
1353*8975f5c5SAndroid Build Coastguard Worker     // Android used to only advertise INHERIT bit, but might update to advertise OPAQUE bit as a
1354*8975f5c5SAndroid Build Coastguard Worker     // hint for RGBX backed VK_FORMAT_R8G8B8A8_* surface format. So here we would default to the
1355*8975f5c5SAndroid Build Coastguard Worker     // INHERTI bit if detecting Android and the client has explicitly requested alpha channel.
1356*8975f5c5SAndroid Build Coastguard Worker     mCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
1357*8975f5c5SAndroid Build Coastguard Worker     if (IsAndroid() && mState.config->alphaSize != 0)
1358*8975f5c5SAndroid Build Coastguard Worker     {
1359*8975f5c5SAndroid Build Coastguard Worker         mCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
1360*8975f5c5SAndroid Build Coastguard Worker     }
1361*8975f5c5SAndroid Build Coastguard Worker 
1362*8975f5c5SAndroid Build Coastguard Worker     if ((mSurfaceCaps.supportedCompositeAlpha & mCompositeAlpha) == 0)
1363*8975f5c5SAndroid Build Coastguard Worker     {
1364*8975f5c5SAndroid Build Coastguard Worker         mCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
1365*8975f5c5SAndroid Build Coastguard Worker     }
1366*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_CHECK(displayVk, (mSurfaceCaps.supportedCompositeAlpha & mCompositeAlpha) != 0,
1367*8975f5c5SAndroid Build Coastguard Worker                    VK_ERROR_INITIALIZATION_FAILED);
1368*8975f5c5SAndroid Build Coastguard Worker 
1369*8975f5c5SAndroid Build Coastguard Worker     // Single buffer, if supported
1370*8975f5c5SAndroid Build Coastguard Worker     if ((mState.attributes.getAsInt(EGL_RENDER_BUFFER, EGL_BACK_BUFFER) == EGL_SINGLE_BUFFER) &&
1371*8975f5c5SAndroid Build Coastguard Worker         supportsPresentMode(vk::PresentMode::SharedDemandRefreshKHR))
1372*8975f5c5SAndroid Build Coastguard Worker     {
1373*8975f5c5SAndroid Build Coastguard Worker         std::vector<vk::PresentMode> presentModes = {vk::PresentMode::SharedDemandRefreshKHR};
1374*8975f5c5SAndroid Build Coastguard Worker         mDesiredSwapchainPresentMode              = GetDesiredPresentMode(presentModes, 0);
1375*8975f5c5SAndroid Build Coastguard Worker     }
1376*8975f5c5SAndroid Build Coastguard Worker 
1377*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(createSwapChain(displayVk, extents));
1378*8975f5c5SAndroid Build Coastguard Worker 
1379*8975f5c5SAndroid Build Coastguard Worker     // Create the semaphores that will be used for vkAcquireNextImageKHR.
1380*8975f5c5SAndroid Build Coastguard Worker     for (vk::Semaphore &semaphore : mAcquireOperation.unlockedAcquireData.acquireImageSemaphores)
1381*8975f5c5SAndroid Build Coastguard Worker     {
1382*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(displayVk, semaphore.init(displayVk->getDevice()));
1383*8975f5c5SAndroid Build Coastguard Worker     }
1384*8975f5c5SAndroid Build Coastguard Worker 
1385*8975f5c5SAndroid Build Coastguard Worker     VkResult vkResult = acquireNextSwapchainImage(displayVk);
1386*8975f5c5SAndroid Build Coastguard Worker     ASSERT(vkResult != VK_SUBOPTIMAL_KHR);
1387*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_TRY(displayVk, vkResult);
1388*8975f5c5SAndroid Build Coastguard Worker 
1389*8975f5c5SAndroid Build Coastguard Worker     *anyMatchesOut = true;
1390*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1391*8975f5c5SAndroid Build Coastguard Worker }
1392*8975f5c5SAndroid Build Coastguard Worker 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)1393*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::getAttachmentRenderTarget(const gl::Context *context,
1394*8975f5c5SAndroid Build Coastguard Worker                                                          GLenum binding,
1395*8975f5c5SAndroid Build Coastguard Worker                                                          const gl::ImageIndex &imageIndex,
1396*8975f5c5SAndroid Build Coastguard Worker                                                          GLsizei samples,
1397*8975f5c5SAndroid Build Coastguard Worker                                                          FramebufferAttachmentRenderTarget **rtOut)
1398*8975f5c5SAndroid Build Coastguard Worker {
1399*8975f5c5SAndroid Build Coastguard Worker     if (mAcquireOperation.state != impl::ImageAcquireState::Ready)
1400*8975f5c5SAndroid Build Coastguard Worker     {
1401*8975f5c5SAndroid Build Coastguard Worker         // Acquire the next image (previously deferred) before it is drawn to or read from.
1402*8975f5c5SAndroid Build Coastguard Worker         ContextVk *contextVk = vk::GetImpl(context);
1403*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRACE_EVENT_AND_MARKER(contextVk, "First Swap Image Use");
1404*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(doDeferredAcquireNextImage(context, false));
1405*8975f5c5SAndroid Build Coastguard Worker     }
1406*8975f5c5SAndroid Build Coastguard Worker     return SurfaceVk::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut);
1407*8975f5c5SAndroid Build Coastguard Worker }
1408*8975f5c5SAndroid Build Coastguard Worker 
collectOldSwapchain(ContextVk * contextVk,VkSwapchainKHR swapchain)1409*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::collectOldSwapchain(ContextVk *contextVk, VkSwapchainKHR swapchain)
1410*8975f5c5SAndroid Build Coastguard Worker {
1411*8975f5c5SAndroid Build Coastguard Worker     ASSERT(swapchain != VK_NULL_HANDLE);
1412*8975f5c5SAndroid Build Coastguard Worker     ASSERT(swapchain != mLastSwapchain);
1413*8975f5c5SAndroid Build Coastguard Worker 
1414*8975f5c5SAndroid Build Coastguard Worker     // If no present operation has been done on the new swapchain, it can be destroyed right away.
1415*8975f5c5SAndroid Build Coastguard Worker     // This means that a new swapchain was created, but before any of its images were presented,
1416*8975f5c5SAndroid Build Coastguard Worker     // it's asked to be recreated.  This can happen for example if vkQueuePresentKHR returns
1417*8975f5c5SAndroid Build Coastguard Worker     // OUT_OF_DATE, the swapchain is recreated and the following vkAcquireNextImageKHR again
1418*8975f5c5SAndroid Build Coastguard Worker     // returns OUT_OF_DATE.  Otherwise, keep the current swapchain as the old swapchain to be
1419*8975f5c5SAndroid Build Coastguard Worker     // scheduled for destruction.
1420*8975f5c5SAndroid Build Coastguard Worker     //
1421*8975f5c5SAndroid Build Coastguard Worker     // The old(er) swapchains still need to be kept to be scheduled for destruction.
1422*8975f5c5SAndroid Build Coastguard Worker 
1423*8975f5c5SAndroid Build Coastguard Worker     if (mPresentHistory.empty())
1424*8975f5c5SAndroid Build Coastguard Worker     {
1425*8975f5c5SAndroid Build Coastguard Worker         // Destroy the current (never-used) swapchain.
1426*8975f5c5SAndroid Build Coastguard Worker         vkDestroySwapchainKHR(contextVk->getDevice(), swapchain, nullptr);
1427*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
1428*8975f5c5SAndroid Build Coastguard Worker     }
1429*8975f5c5SAndroid Build Coastguard Worker 
1430*8975f5c5SAndroid Build Coastguard Worker     // Place all present operation into mOldSwapchains. That gets scheduled for destruction when the
1431*8975f5c5SAndroid Build Coastguard Worker     // semaphore of the first image of the next swapchain can be recycled or when fences are
1432*8975f5c5SAndroid Build Coastguard Worker     // signaled (when VK_EXT_swapchain_maintenance1 is supported).
1433*8975f5c5SAndroid Build Coastguard Worker     SwapchainCleanupData cleanupData;
1434*8975f5c5SAndroid Build Coastguard Worker 
1435*8975f5c5SAndroid Build Coastguard Worker     // Schedule the swapchain for destruction.
1436*8975f5c5SAndroid Build Coastguard Worker     cleanupData.swapchain = swapchain;
1437*8975f5c5SAndroid Build Coastguard Worker 
1438*8975f5c5SAndroid Build Coastguard Worker     for (impl::ImagePresentOperation &presentOperation : mPresentHistory)
1439*8975f5c5SAndroid Build Coastguard Worker     {
1440*8975f5c5SAndroid Build Coastguard Worker         // fence is only used when VK_EXT_swapchain_maintenance1 is supported.
1441*8975f5c5SAndroid Build Coastguard Worker         if (presentOperation.fence.valid())
1442*8975f5c5SAndroid Build Coastguard Worker         {
1443*8975f5c5SAndroid Build Coastguard Worker             cleanupData.fences.emplace_back(std::move(presentOperation.fence));
1444*8975f5c5SAndroid Build Coastguard Worker         }
1445*8975f5c5SAndroid Build Coastguard Worker 
1446*8975f5c5SAndroid Build Coastguard Worker         ASSERT(presentOperation.semaphore.valid());
1447*8975f5c5SAndroid Build Coastguard Worker         cleanupData.semaphores.emplace_back(std::move(presentOperation.semaphore));
1448*8975f5c5SAndroid Build Coastguard Worker 
1449*8975f5c5SAndroid Build Coastguard Worker         // Accumulate any previous swapchains that are pending destruction too.
1450*8975f5c5SAndroid Build Coastguard Worker         for (SwapchainCleanupData &oldSwapchain : presentOperation.oldSwapchains)
1451*8975f5c5SAndroid Build Coastguard Worker         {
1452*8975f5c5SAndroid Build Coastguard Worker             mOldSwapchains.emplace_back(std::move(oldSwapchain));
1453*8975f5c5SAndroid Build Coastguard Worker         }
1454*8975f5c5SAndroid Build Coastguard Worker         presentOperation.oldSwapchains.clear();
1455*8975f5c5SAndroid Build Coastguard Worker     }
1456*8975f5c5SAndroid Build Coastguard Worker     mPresentHistory.clear();
1457*8975f5c5SAndroid Build Coastguard Worker 
1458*8975f5c5SAndroid Build Coastguard Worker     // Add new item now, before below calls that may fail.
1459*8975f5c5SAndroid Build Coastguard Worker     mOldSwapchains.emplace_back(std::move(cleanupData));
1460*8975f5c5SAndroid Build Coastguard Worker 
1461*8975f5c5SAndroid Build Coastguard Worker     // Try to cleanup old swapchains first, before checking the kMaxOldSwapchains limit.
1462*8975f5c5SAndroid Build Coastguard Worker     if (contextVk->getFeatures().supportsSwapchainMaintenance1.enabled)
1463*8975f5c5SAndroid Build Coastguard Worker     {
1464*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(cleanUpOldSwapchains(contextVk));
1465*8975f5c5SAndroid Build Coastguard Worker     }
1466*8975f5c5SAndroid Build Coastguard Worker 
1467*8975f5c5SAndroid Build Coastguard Worker     // If too many old swapchains have accumulated, wait idle and destroy them.  This is to prevent
1468*8975f5c5SAndroid Build Coastguard Worker     // failures due to too many swapchains allocated.
1469*8975f5c5SAndroid Build Coastguard Worker     //
1470*8975f5c5SAndroid Build Coastguard Worker     // Note: Nvidia has been observed to fail creation of swapchains after 20 are allocated on
1471*8975f5c5SAndroid Build Coastguard Worker     // desktop, or less than 10 on Quadro P400.
1472*8975f5c5SAndroid Build Coastguard Worker     static constexpr size_t kMaxOldSwapchains = 5;
1473*8975f5c5SAndroid Build Coastguard Worker     if (mOldSwapchains.size() > kMaxOldSwapchains)
1474*8975f5c5SAndroid Build Coastguard Worker     {
1475*8975f5c5SAndroid Build Coastguard Worker         mUse.merge(contextVk->getSubmittedResourceUse());
1476*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(finish(contextVk));
1477*8975f5c5SAndroid Build Coastguard Worker         for (SwapchainCleanupData &oldSwapchain : mOldSwapchains)
1478*8975f5c5SAndroid Build Coastguard Worker         {
1479*8975f5c5SAndroid Build Coastguard Worker             oldSwapchain.waitFences(contextVk->getDevice(),
1480*8975f5c5SAndroid Build Coastguard Worker                                     contextVk->getRenderer()->getMaxFenceWaitTimeNs());
1481*8975f5c5SAndroid Build Coastguard Worker             oldSwapchain.destroy(contextVk->getDevice(), &mPresentFenceRecycler,
1482*8975f5c5SAndroid Build Coastguard Worker                                  &mPresentSemaphoreRecycler);
1483*8975f5c5SAndroid Build Coastguard Worker         }
1484*8975f5c5SAndroid Build Coastguard Worker         mOldSwapchains.clear();
1485*8975f5c5SAndroid Build Coastguard Worker     }
1486*8975f5c5SAndroid Build Coastguard Worker 
1487*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1488*8975f5c5SAndroid Build Coastguard Worker }
1489*8975f5c5SAndroid Build Coastguard Worker 
recreateSwapchain(ContextVk * contextVk,const gl::Extents & extents)1490*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::recreateSwapchain(ContextVk *contextVk, const gl::Extents &extents)
1491*8975f5c5SAndroid Build Coastguard Worker {
1492*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state != impl::ImageAcquireState::Ready);
1493*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mSwapchainStatus.isPending);
1494*8975f5c5SAndroid Build Coastguard Worker 
1495*8975f5c5SAndroid Build Coastguard Worker     // Invalidate the current swapchain while keep the last handle to create the new swapchain.
1496*8975f5c5SAndroid Build Coastguard Worker     // mSwapchain may be already NULL if this is a repeated call (after a previous failure).
1497*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mSwapchain == mLastSwapchain || mSwapchain == VK_NULL_HANDLE);
1498*8975f5c5SAndroid Build Coastguard Worker     mSwapchain = VK_NULL_HANDLE;
1499*8975f5c5SAndroid Build Coastguard Worker 
1500*8975f5c5SAndroid Build Coastguard Worker     releaseSwapchainImages(contextVk);
1501*8975f5c5SAndroid Build Coastguard Worker 
1502*8975f5c5SAndroid Build Coastguard Worker     // If prerotation is emulated, adjust the window extents to match what real prerotation would
1503*8975f5c5SAndroid Build Coastguard Worker     // have reported.
1504*8975f5c5SAndroid Build Coastguard Worker     gl::Extents swapchainExtents = extents;
1505*8975f5c5SAndroid Build Coastguard Worker     if (Is90DegreeRotation(mEmulatedPreTransform))
1506*8975f5c5SAndroid Build Coastguard Worker     {
1507*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mPreTransform == VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR);
1508*8975f5c5SAndroid Build Coastguard Worker         std::swap(swapchainExtents.width, swapchainExtents.height);
1509*8975f5c5SAndroid Build Coastguard Worker     }
1510*8975f5c5SAndroid Build Coastguard Worker 
1511*8975f5c5SAndroid Build Coastguard Worker     // On Android, vkCreateSwapchainKHR destroys mLastSwapchain, which is incorrect.  Wait idle in
1512*8975f5c5SAndroid Build Coastguard Worker     // that case as a workaround.
1513*8975f5c5SAndroid Build Coastguard Worker     if (mLastSwapchain != VK_NULL_HANDLE &&
1514*8975f5c5SAndroid Build Coastguard Worker         contextVk->getFeatures().waitIdleBeforeSwapchainRecreation.enabled)
1515*8975f5c5SAndroid Build Coastguard Worker     {
1516*8975f5c5SAndroid Build Coastguard Worker         mUse.merge(contextVk->getSubmittedResourceUse());
1517*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(finish(contextVk));
1518*8975f5c5SAndroid Build Coastguard Worker     }
1519*8975f5c5SAndroid Build Coastguard Worker 
1520*8975f5c5SAndroid Build Coastguard Worker     // Save the handle since it is going to be updated in the createSwapChain call below.
1521*8975f5c5SAndroid Build Coastguard Worker     VkSwapchainKHR oldSwapchain = mLastSwapchain;
1522*8975f5c5SAndroid Build Coastguard Worker 
1523*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = createSwapChain(contextVk, swapchainExtents);
1524*8975f5c5SAndroid Build Coastguard Worker 
1525*8975f5c5SAndroid Build Coastguard Worker     // Notify the parent classes of the surface's new state.
1526*8975f5c5SAndroid Build Coastguard Worker     onStateChange(angle::SubjectMessage::SurfaceChanged);
1527*8975f5c5SAndroid Build Coastguard Worker 
1528*8975f5c5SAndroid Build Coastguard Worker     // oldSwapchain was retired in the createSwapChain call above and can be collected.
1529*8975f5c5SAndroid Build Coastguard Worker     if (oldSwapchain != VK_NULL_HANDLE && oldSwapchain != mLastSwapchain)
1530*8975f5c5SAndroid Build Coastguard Worker     {
1531*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mLastSwapchain == mSwapchain);
1532*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(collectOldSwapchain(contextVk, oldSwapchain));
1533*8975f5c5SAndroid Build Coastguard Worker     }
1534*8975f5c5SAndroid Build Coastguard Worker 
1535*8975f5c5SAndroid Build Coastguard Worker     return result;
1536*8975f5c5SAndroid Build Coastguard Worker }
1537*8975f5c5SAndroid Build Coastguard Worker 
resizeSwapchainImages(vk::Context * context,uint32_t imageCount)1538*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::resizeSwapchainImages(vk::Context *context, uint32_t imageCount)
1539*8975f5c5SAndroid Build Coastguard Worker {
1540*8975f5c5SAndroid Build Coastguard Worker     if (static_cast<size_t>(imageCount) != mSwapchainImages.size())
1541*8975f5c5SAndroid Build Coastguard Worker     {
1542*8975f5c5SAndroid Build Coastguard Worker         mSwapchainImageBindings.clear();
1543*8975f5c5SAndroid Build Coastguard Worker         mSwapchainImages.resize(imageCount);
1544*8975f5c5SAndroid Build Coastguard Worker 
1545*8975f5c5SAndroid Build Coastguard Worker         // Update the image bindings. Because the observer binding class uses raw pointers we
1546*8975f5c5SAndroid Build Coastguard Worker         // need to first ensure the entire image vector is fully allocated before binding the
1547*8975f5c5SAndroid Build Coastguard Worker         // subject and observer together.
1548*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t index = 0; index < imageCount; ++index)
1549*8975f5c5SAndroid Build Coastguard Worker         {
1550*8975f5c5SAndroid Build Coastguard Worker             mSwapchainImageBindings.push_back(
1551*8975f5c5SAndroid Build Coastguard Worker                 angle::ObserverBinding(this, kAnySurfaceImageSubjectIndex));
1552*8975f5c5SAndroid Build Coastguard Worker         }
1553*8975f5c5SAndroid Build Coastguard Worker 
1554*8975f5c5SAndroid Build Coastguard Worker         for (uint32_t index = 0; index < imageCount; ++index)
1555*8975f5c5SAndroid Build Coastguard Worker         {
1556*8975f5c5SAndroid Build Coastguard Worker             mSwapchainImages[index].image = std::make_unique<vk::ImageHelper>();
1557*8975f5c5SAndroid Build Coastguard Worker             mSwapchainImageBindings[index].bind(mSwapchainImages[index].image.get());
1558*8975f5c5SAndroid Build Coastguard Worker         }
1559*8975f5c5SAndroid Build Coastguard Worker     }
1560*8975f5c5SAndroid Build Coastguard Worker 
1561*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1562*8975f5c5SAndroid Build Coastguard Worker }
1563*8975f5c5SAndroid Build Coastguard Worker 
createSwapChain(vk::Context * context,const gl::Extents & extents)1564*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context, const gl::Extents &extents)
1565*8975f5c5SAndroid Build Coastguard Worker {
1566*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::createSwapchain");
1567*8975f5c5SAndroid Build Coastguard Worker 
1568*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state != impl::ImageAcquireState::Ready);
1569*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mSwapchain == VK_NULL_HANDLE);
1570*8975f5c5SAndroid Build Coastguard Worker 
1571*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = context->getRenderer();
1572*8975f5c5SAndroid Build Coastguard Worker     VkDevice device        = renderer->getDevice();
1573*8975f5c5SAndroid Build Coastguard Worker 
1574*8975f5c5SAndroid Build Coastguard Worker     const vk::Format &format = renderer->getFormat(mState.config->renderTargetFormat);
1575*8975f5c5SAndroid Build Coastguard Worker 
1576*8975f5c5SAndroid Build Coastguard Worker     gl::Extents rotatedExtents = extents;
1577*8975f5c5SAndroid Build Coastguard Worker     if (Is90DegreeRotation(getPreTransform()))
1578*8975f5c5SAndroid Build Coastguard Worker     {
1579*8975f5c5SAndroid Build Coastguard Worker         // The Surface is oriented such that its aspect ratio no longer matches that of the
1580*8975f5c5SAndroid Build Coastguard Worker         // device.  In this case, the width and height of the swapchain images must be swapped to
1581*8975f5c5SAndroid Build Coastguard Worker         // match the device's native orientation.  This must also be done for other attachments
1582*8975f5c5SAndroid Build Coastguard Worker         // used with the swapchain (e.g. depth buffer).  The width and height of the viewport,
1583*8975f5c5SAndroid Build Coastguard Worker         // scissor, and render-pass render area must also be swapped.  Then, when ANGLE rotates
1584*8975f5c5SAndroid Build Coastguard Worker         // gl_Position in the vertex shader, the rendering will look the same as if no
1585*8975f5c5SAndroid Build Coastguard Worker         // pre-rotation had been done.
1586*8975f5c5SAndroid Build Coastguard Worker         std::swap(rotatedExtents.width, rotatedExtents.height);
1587*8975f5c5SAndroid Build Coastguard Worker     }
1588*8975f5c5SAndroid Build Coastguard Worker 
1589*8975f5c5SAndroid Build Coastguard Worker     // We need transfer src for reading back from the backbuffer.
1590*8975f5c5SAndroid Build Coastguard Worker     VkImageUsageFlags imageUsageFlags = kSurfaceVkColorImageUsageFlags;
1591*8975f5c5SAndroid Build Coastguard Worker 
1592*8975f5c5SAndroid Build Coastguard Worker     // If shaders may be fetching from this, we need this image to be an input
1593*8975f5c5SAndroid Build Coastguard Worker     if (ColorNeedsInputAttachmentUsage(renderer->getFeatures()))
1594*8975f5c5SAndroid Build Coastguard Worker     {
1595*8975f5c5SAndroid Build Coastguard Worker         imageUsageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
1596*8975f5c5SAndroid Build Coastguard Worker     }
1597*8975f5c5SAndroid Build Coastguard Worker 
1598*8975f5c5SAndroid Build Coastguard Worker     VkSwapchainCreateInfoKHR swapchainInfo = {};
1599*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.sType                    = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1600*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.flags = mState.hasProtectedContent() ? VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR : 0;
1601*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.surface = mSurface;
1602*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.minImageCount = mMinImageCount;
1603*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.imageFormat = vk::GetVkFormatFromFormatID(renderer, getActualFormatID(renderer));
1604*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.imageColorSpace = mSurfaceColorSpace;
1605*8975f5c5SAndroid Build Coastguard Worker     // Note: Vulkan doesn't allow 0-width/height swapchains.
1606*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.imageExtent.width     = std::max(rotatedExtents.width, 1);
1607*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.imageExtent.height    = std::max(rotatedExtents.height, 1);
1608*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.imageArrayLayers      = 1;
1609*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.imageUsage            = imageUsageFlags;
1610*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.imageSharingMode      = VK_SHARING_MODE_EXCLUSIVE;
1611*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.queueFamilyIndexCount = 0;
1612*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.pQueueFamilyIndices   = nullptr;
1613*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.preTransform          = mPreTransform;
1614*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.compositeAlpha        = mCompositeAlpha;
1615*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.presentMode = vk::ConvertPresentModeToVkPresentMode(mDesiredSwapchainPresentMode);
1616*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.clipped     = VK_TRUE;
1617*8975f5c5SAndroid Build Coastguard Worker     swapchainInfo.oldSwapchain = mLastSwapchain;
1618*8975f5c5SAndroid Build Coastguard Worker 
1619*8975f5c5SAndroid Build Coastguard Worker #if defined(ANGLE_PLATFORM_WINDOWS)
1620*8975f5c5SAndroid Build Coastguard Worker     // On some AMD drivers we need to explicitly enable the extension and set
1621*8975f5c5SAndroid Build Coastguard Worker     // it to "disallowed" mode in order to avoid seeing impossible-to-handle
1622*8975f5c5SAndroid Build Coastguard Worker     // extension-specific error codes from swapchain functions.
1623*8975f5c5SAndroid Build Coastguard Worker     VkSurfaceFullScreenExclusiveInfoEXT fullscreen = {};
1624*8975f5c5SAndroid Build Coastguard Worker     fullscreen.sType               = VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_INFO_EXT;
1625*8975f5c5SAndroid Build Coastguard Worker     fullscreen.fullScreenExclusive = VK_FULL_SCREEN_EXCLUSIVE_DISALLOWED_EXT;
1626*8975f5c5SAndroid Build Coastguard Worker 
1627*8975f5c5SAndroid Build Coastguard Worker     VkSurfaceFullScreenExclusiveWin32InfoEXT fullscreenWin32 = {};
1628*8975f5c5SAndroid Build Coastguard Worker     fullscreenWin32.sType    = VK_STRUCTURE_TYPE_SURFACE_FULL_SCREEN_EXCLUSIVE_WIN32_INFO_EXT;
1629*8975f5c5SAndroid Build Coastguard Worker     fullscreenWin32.hmonitor = MonitorFromWindow((HWND)mNativeWindowType, MONITOR_DEFAULTTONEAREST);
1630*8975f5c5SAndroid Build Coastguard Worker 
1631*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().supportsFullScreenExclusive.enabled &&
1632*8975f5c5SAndroid Build Coastguard Worker         renderer->getFeatures().forceDisableFullScreenExclusive.enabled)
1633*8975f5c5SAndroid Build Coastguard Worker     {
1634*8975f5c5SAndroid Build Coastguard Worker         vk::AddToPNextChain(&swapchainInfo, &fullscreen);
1635*8975f5c5SAndroid Build Coastguard Worker         vk::AddToPNextChain(&swapchainInfo, &fullscreenWin32);
1636*8975f5c5SAndroid Build Coastguard Worker     }
1637*8975f5c5SAndroid Build Coastguard Worker #endif
1638*8975f5c5SAndroid Build Coastguard Worker 
1639*8975f5c5SAndroid Build Coastguard Worker     if (context->getFeatures().supportsSwapchainMaintenance1.enabled)
1640*8975f5c5SAndroid Build Coastguard Worker     {
1641*8975f5c5SAndroid Build Coastguard Worker         swapchainInfo.flags |= VK_SWAPCHAIN_CREATE_DEFERRED_MEMORY_ALLOCATION_BIT_EXT;
1642*8975f5c5SAndroid Build Coastguard Worker     }
1643*8975f5c5SAndroid Build Coastguard Worker 
1644*8975f5c5SAndroid Build Coastguard Worker     if (isSharedPresentModeDesired())
1645*8975f5c5SAndroid Build Coastguard Worker     {
1646*8975f5c5SAndroid Build Coastguard Worker         swapchainInfo.minImageCount = 1;
1647*8975f5c5SAndroid Build Coastguard Worker 
1648*8975f5c5SAndroid Build Coastguard Worker         // This feature is by default disabled, and only affects Android platform wsi behavior
1649*8975f5c5SAndroid Build Coastguard Worker         // transparent to angle internal tracking for shared present.
1650*8975f5c5SAndroid Build Coastguard Worker         if (renderer->getFeatures().forceContinuousRefreshOnSharedPresent.enabled)
1651*8975f5c5SAndroid Build Coastguard Worker         {
1652*8975f5c5SAndroid Build Coastguard Worker             swapchainInfo.presentMode = VK_PRESENT_MODE_SHARED_CONTINUOUS_REFRESH_KHR;
1653*8975f5c5SAndroid Build Coastguard Worker         }
1654*8975f5c5SAndroid Build Coastguard Worker     }
1655*8975f5c5SAndroid Build Coastguard Worker 
1656*8975f5c5SAndroid Build Coastguard Worker     // Get the list of compatible present modes to avoid unnecessary swapchain recreation.  Also
1657*8975f5c5SAndroid Build Coastguard Worker     // update minImageCount with the per-present limit.
1658*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().supportsSurfaceMaintenance1.enabled)
1659*8975f5c5SAndroid Build Coastguard Worker     {
1660*8975f5c5SAndroid Build Coastguard Worker         VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo2 = {};
1661*8975f5c5SAndroid Build Coastguard Worker         surfaceInfo2.sType   = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
1662*8975f5c5SAndroid Build Coastguard Worker         surfaceInfo2.surface = mSurface;
1663*8975f5c5SAndroid Build Coastguard Worker 
1664*8975f5c5SAndroid Build Coastguard Worker         VkSurfacePresentModeEXT surfacePresentMode = {};
1665*8975f5c5SAndroid Build Coastguard Worker         surfacePresentMode.sType                   = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT;
1666*8975f5c5SAndroid Build Coastguard Worker         surfacePresentMode.presentMode             = swapchainInfo.presentMode;
1667*8975f5c5SAndroid Build Coastguard Worker         vk::AddToPNextChain(&surfaceInfo2, &surfacePresentMode);
1668*8975f5c5SAndroid Build Coastguard Worker 
1669*8975f5c5SAndroid Build Coastguard Worker         VkSurfaceCapabilities2KHR surfaceCaps2 = {};
1670*8975f5c5SAndroid Build Coastguard Worker         surfaceCaps2.sType                     = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
1671*8975f5c5SAndroid Build Coastguard Worker 
1672*8975f5c5SAndroid Build Coastguard Worker         mCompatiblePresentModes.resize(kCompatiblePresentModesSize);
1673*8975f5c5SAndroid Build Coastguard Worker 
1674*8975f5c5SAndroid Build Coastguard Worker         VkSurfacePresentModeCompatibilityEXT compatibleModes = {};
1675*8975f5c5SAndroid Build Coastguard Worker         compatibleModes.sType            = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_COMPATIBILITY_EXT;
1676*8975f5c5SAndroid Build Coastguard Worker         compatibleModes.presentModeCount = kCompatiblePresentModesSize;
1677*8975f5c5SAndroid Build Coastguard Worker         compatibleModes.pPresentModes    = mCompatiblePresentModes.data();
1678*8975f5c5SAndroid Build Coastguard Worker         vk::AddToPNextChain(&surfaceCaps2, &compatibleModes);
1679*8975f5c5SAndroid Build Coastguard Worker 
1680*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(context, vkGetPhysicalDeviceSurfaceCapabilities2KHR(
1681*8975f5c5SAndroid Build Coastguard Worker                                   renderer->getPhysicalDevice(), &surfaceInfo2, &surfaceCaps2));
1682*8975f5c5SAndroid Build Coastguard Worker 
1683*8975f5c5SAndroid Build Coastguard Worker         mCompatiblePresentModes.resize(compatibleModes.presentModeCount);
1684*8975f5c5SAndroid Build Coastguard Worker 
1685*8975f5c5SAndroid Build Coastguard Worker         // http://anglebug.com/368647924: in case of multiple drivers vulkan loader causes extension
1686*8975f5c5SAndroid Build Coastguard Worker         // to be listed when not actually supported. kCompatiblePresentModesSize is above max count
1687*8975f5c5SAndroid Build Coastguard Worker         // to catch this case and work around.
1688*8975f5c5SAndroid Build Coastguard Worker         if (compatibleModes.presentModeCount == kCompatiblePresentModesSize)
1689*8975f5c5SAndroid Build Coastguard Worker         {
1690*8975f5c5SAndroid Build Coastguard Worker             mCompatiblePresentModes.resize(1);
1691*8975f5c5SAndroid Build Coastguard Worker             mCompatiblePresentModes[0] = swapchainInfo.presentMode;
1692*8975f5c5SAndroid Build Coastguard Worker         }
1693*8975f5c5SAndroid Build Coastguard Worker 
1694*8975f5c5SAndroid Build Coastguard Worker         // The implementation must always return the given present mode as compatible with itself.
1695*8975f5c5SAndroid Build Coastguard Worker         ASSERT(IsCompatiblePresentMode(mDesiredSwapchainPresentMode, mCompatiblePresentModes.data(),
1696*8975f5c5SAndroid Build Coastguard Worker                                        mCompatiblePresentModes.size()));
1697*8975f5c5SAndroid Build Coastguard Worker 
1698*8975f5c5SAndroid Build Coastguard Worker         // Vulkan spec says "The per-present mode image counts may be less-than or greater-than the
1699*8975f5c5SAndroid Build Coastguard Worker         // image counts returned when VkSurfacePresentModeEXT is not provided.". Use the per present
1700*8975f5c5SAndroid Build Coastguard Worker         // mode imageCount here. Otherwise we may get into
1701*8975f5c5SAndroid Build Coastguard Worker         // VUID-VkSwapchainCreateInfoKHR-presentMode-02839.
1702*8975f5c5SAndroid Build Coastguard Worker         mSurfaceCaps   = surfaceCaps2.surfaceCapabilities;
1703*8975f5c5SAndroid Build Coastguard Worker         mMinImageCount = GetMinImageCount(renderer, mSurfaceCaps, mDesiredSwapchainPresentMode);
1704*8975f5c5SAndroid Build Coastguard Worker         swapchainInfo.minImageCount = mMinImageCount;
1705*8975f5c5SAndroid Build Coastguard Worker     }
1706*8975f5c5SAndroid Build Coastguard Worker 
1707*8975f5c5SAndroid Build Coastguard Worker     VkSwapchainPresentModesCreateInfoEXT compatibleModesInfo = {};
1708*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().supportsSwapchainMaintenance1.enabled &&
1709*8975f5c5SAndroid Build Coastguard Worker         mCompatiblePresentModes.size() > 1)
1710*8975f5c5SAndroid Build Coastguard Worker     {
1711*8975f5c5SAndroid Build Coastguard Worker         compatibleModesInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODES_CREATE_INFO_EXT;
1712*8975f5c5SAndroid Build Coastguard Worker         compatibleModesInfo.presentModeCount =
1713*8975f5c5SAndroid Build Coastguard Worker             static_cast<uint32_t>(mCompatiblePresentModes.size());
1714*8975f5c5SAndroid Build Coastguard Worker         compatibleModesInfo.pPresentModes = mCompatiblePresentModes.data();
1715*8975f5c5SAndroid Build Coastguard Worker 
1716*8975f5c5SAndroid Build Coastguard Worker         vk::AddToPNextChain(&swapchainInfo, &compatibleModesInfo);
1717*8975f5c5SAndroid Build Coastguard Worker     }
1718*8975f5c5SAndroid Build Coastguard Worker     else
1719*8975f5c5SAndroid Build Coastguard Worker     {
1720*8975f5c5SAndroid Build Coastguard Worker         // Without VK_EXT_swapchain_maintenance1, each present mode can be considered only
1721*8975f5c5SAndroid Build Coastguard Worker         // compatible with itself.
1722*8975f5c5SAndroid Build Coastguard Worker         mCompatiblePresentModes.resize(1);
1723*8975f5c5SAndroid Build Coastguard Worker         mCompatiblePresentModes[0] = swapchainInfo.presentMode;
1724*8975f5c5SAndroid Build Coastguard Worker     }
1725*8975f5c5SAndroid Build Coastguard Worker 
1726*8975f5c5SAndroid Build Coastguard Worker     // Old swapchain is retired regardless if the below call fails or not.
1727*8975f5c5SAndroid Build Coastguard Worker     mLastSwapchain = VK_NULL_HANDLE;
1728*8975f5c5SAndroid Build Coastguard Worker 
1729*8975f5c5SAndroid Build Coastguard Worker     // TODO: Once EGL_SWAP_BEHAVIOR_PRESERVED_BIT is supported, the contents of the old swapchain
1730*8975f5c5SAndroid Build Coastguard Worker     // need to carry over to the new one.  http://anglebug.com/42261637
1731*8975f5c5SAndroid Build Coastguard Worker     VkSwapchainKHR newSwapChain = VK_NULL_HANDLE;
1732*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_TRY(context, vkCreateSwapchainKHR(device, &swapchainInfo, nullptr, &newSwapChain));
1733*8975f5c5SAndroid Build Coastguard Worker     mSwapchain            = newSwapChain;
1734*8975f5c5SAndroid Build Coastguard Worker     mLastSwapchain        = newSwapChain;
1735*8975f5c5SAndroid Build Coastguard Worker     mSwapchainPresentMode = mDesiredSwapchainPresentMode;
1736*8975f5c5SAndroid Build Coastguard Worker     mWidth                = extents.width;
1737*8975f5c5SAndroid Build Coastguard Worker     mHeight               = extents.height;
1738*8975f5c5SAndroid Build Coastguard Worker 
1739*8975f5c5SAndroid Build Coastguard Worker     // If frame timestamp was enabled for the surface, [re]enable it when [re]creating the swapchain
1740*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().supportsTimestampSurfaceAttribute.enabled &&
1741*8975f5c5SAndroid Build Coastguard Worker         mState.timestampsEnabled)
1742*8975f5c5SAndroid Build Coastguard Worker     {
1743*8975f5c5SAndroid Build Coastguard Worker         // The implementation of "vkGetPastPresentationTimingGOOGLE" on Android calls into the
1744*8975f5c5SAndroid Build Coastguard Worker         // appropriate ANativeWindow API that enables frame timestamps.
1745*8975f5c5SAndroid Build Coastguard Worker         uint32_t count = 0;
1746*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(context,
1747*8975f5c5SAndroid Build Coastguard Worker                      vkGetPastPresentationTimingGOOGLE(device, mSwapchain, &count, nullptr));
1748*8975f5c5SAndroid Build Coastguard Worker     }
1749*8975f5c5SAndroid Build Coastguard Worker 
1750*8975f5c5SAndroid Build Coastguard Worker     // Initialize the swapchain image views.
1751*8975f5c5SAndroid Build Coastguard Worker     uint32_t imageCount = 0;
1752*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_TRY(context, vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, nullptr));
1753*8975f5c5SAndroid Build Coastguard Worker 
1754*8975f5c5SAndroid Build Coastguard Worker     std::vector<VkImage> swapchainImages(imageCount);
1755*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_TRY(context,
1756*8975f5c5SAndroid Build Coastguard Worker                  vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, swapchainImages.data()));
1757*8975f5c5SAndroid Build Coastguard Worker 
1758*8975f5c5SAndroid Build Coastguard Worker     // If multisampling is enabled, create a multisampled image which gets resolved just prior to
1759*8975f5c5SAndroid Build Coastguard Worker     // present.
1760*8975f5c5SAndroid Build Coastguard Worker     GLint samples = GetSampleCount(mState.config);
1761*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_CHECK(context, samples > 0, VK_ERROR_INITIALIZATION_FAILED);
1762*8975f5c5SAndroid Build Coastguard Worker 
1763*8975f5c5SAndroid Build Coastguard Worker     VkExtent3D vkExtents;
1764*8975f5c5SAndroid Build Coastguard Worker     gl_vk::GetExtent(rotatedExtents, &vkExtents);
1765*8975f5c5SAndroid Build Coastguard Worker 
1766*8975f5c5SAndroid Build Coastguard Worker     bool robustInit = mState.isRobustResourceInitEnabled();
1767*8975f5c5SAndroid Build Coastguard Worker 
1768*8975f5c5SAndroid Build Coastguard Worker     if (samples > 1)
1769*8975f5c5SAndroid Build Coastguard Worker     {
1770*8975f5c5SAndroid Build Coastguard Worker         VkImageUsageFlags usage = kSurfaceVkColorImageUsageFlags;
1771*8975f5c5SAndroid Build Coastguard Worker         if (ColorNeedsInputAttachmentUsage(renderer->getFeatures()))
1772*8975f5c5SAndroid Build Coastguard Worker         {
1773*8975f5c5SAndroid Build Coastguard Worker             usage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
1774*8975f5c5SAndroid Build Coastguard Worker         }
1775*8975f5c5SAndroid Build Coastguard Worker 
1776*8975f5c5SAndroid Build Coastguard Worker         // Create a multisampled image that will be rendered to, and then resolved to a swapchain
1777*8975f5c5SAndroid Build Coastguard Worker         // image.  The actual VkImage is created with rotated coordinates to make it easier to do
1778*8975f5c5SAndroid Build Coastguard Worker         // the resolve.  The ImageHelper::mExtents will have non-rotated extents in order to fit
1779*8975f5c5SAndroid Build Coastguard Worker         // with the rest of ANGLE, (e.g. which calculates the Vulkan scissor with non-rotated
1780*8975f5c5SAndroid Build Coastguard Worker         // values and then rotates the final rectangle).
1781*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mColorImageMS.initMSAASwapchain(
1782*8975f5c5SAndroid Build Coastguard Worker             context, gl::TextureType::_2D, vkExtents, Is90DegreeRotation(getPreTransform()), format,
1783*8975f5c5SAndroid Build Coastguard Worker             samples, usage, gl::LevelIndex(0), 1, 1, robustInit, mState.hasProtectedContent()));
1784*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mColorImageMS.initMemoryAndNonZeroFillIfNeeded(
1785*8975f5c5SAndroid Build Coastguard Worker             context, mState.hasProtectedContent(), renderer->getMemoryProperties(),
1786*8975f5c5SAndroid Build Coastguard Worker             VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, vk::MemoryAllocationType::SwapchainMSAAImage));
1787*8975f5c5SAndroid Build Coastguard Worker 
1788*8975f5c5SAndroid Build Coastguard Worker         // Initialize the color render target with the multisampled targets.  If not multisampled,
1789*8975f5c5SAndroid Build Coastguard Worker         // the render target will be updated to refer to a swapchain image on every acquire.
1790*8975f5c5SAndroid Build Coastguard Worker         mColorRenderTarget.init(&mColorImageMS, &mColorImageMSViews, nullptr, nullptr, {},
1791*8975f5c5SAndroid Build Coastguard Worker                                 gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
1792*8975f5c5SAndroid Build Coastguard Worker     }
1793*8975f5c5SAndroid Build Coastguard Worker 
1794*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(resizeSwapchainImages(context, imageCount));
1795*8975f5c5SAndroid Build Coastguard Worker 
1796*8975f5c5SAndroid Build Coastguard Worker     for (uint32_t imageIndex = 0; imageIndex < imageCount; ++imageIndex)
1797*8975f5c5SAndroid Build Coastguard Worker     {
1798*8975f5c5SAndroid Build Coastguard Worker         SwapchainImage &member = mSwapchainImages[imageIndex];
1799*8975f5c5SAndroid Build Coastguard Worker 
1800*8975f5c5SAndroid Build Coastguard Worker         // Convert swapchain create flags to image create flags
1801*8975f5c5SAndroid Build Coastguard Worker         const VkImageCreateFlags createFlags =
1802*8975f5c5SAndroid Build Coastguard Worker             (swapchainInfo.flags & VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR) != 0
1803*8975f5c5SAndroid Build Coastguard Worker                 ? VK_IMAGE_CREATE_PROTECTED_BIT
1804*8975f5c5SAndroid Build Coastguard Worker                 : 0;
1805*8975f5c5SAndroid Build Coastguard Worker 
1806*8975f5c5SAndroid Build Coastguard Worker         ASSERT(member.image);
1807*8975f5c5SAndroid Build Coastguard Worker         member.image->init2DWeakReference(
1808*8975f5c5SAndroid Build Coastguard Worker             context, swapchainImages[imageIndex], extents, Is90DegreeRotation(getPreTransform()),
1809*8975f5c5SAndroid Build Coastguard Worker             getIntendedFormatID(renderer), getActualFormatID(renderer), createFlags,
1810*8975f5c5SAndroid Build Coastguard Worker             imageUsageFlags, 1, robustInit);
1811*8975f5c5SAndroid Build Coastguard Worker         member.imageViews.init(renderer);
1812*8975f5c5SAndroid Build Coastguard Worker         member.frameNumber = 0;
1813*8975f5c5SAndroid Build Coastguard Worker     }
1814*8975f5c5SAndroid Build Coastguard Worker 
1815*8975f5c5SAndroid Build Coastguard Worker     // Initialize depth/stencil if requested.
1816*8975f5c5SAndroid Build Coastguard Worker     if (mState.config->depthStencilFormat != GL_NONE)
1817*8975f5c5SAndroid Build Coastguard Worker     {
1818*8975f5c5SAndroid Build Coastguard Worker         const vk::Format &dsFormat = renderer->getFormat(mState.config->depthStencilFormat);
1819*8975f5c5SAndroid Build Coastguard Worker 
1820*8975f5c5SAndroid Build Coastguard Worker         VkImageUsageFlags dsUsage = kSurfaceVkDepthStencilImageUsageFlags;
1821*8975f5c5SAndroid Build Coastguard Worker         if (DepthStencilNeedsInputAttachmentUsage(renderer->getFeatures()))
1822*8975f5c5SAndroid Build Coastguard Worker         {
1823*8975f5c5SAndroid Build Coastguard Worker             dsUsage |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
1824*8975f5c5SAndroid Build Coastguard Worker         }
1825*8975f5c5SAndroid Build Coastguard Worker 
1826*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mDepthStencilImage.init(context, gl::TextureType::_2D, vkExtents, dsFormat,
1827*8975f5c5SAndroid Build Coastguard Worker                                           samples, dsUsage, gl::LevelIndex(0), 1, 1, robustInit,
1828*8975f5c5SAndroid Build Coastguard Worker                                           mState.hasProtectedContent()));
1829*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mDepthStencilImage.initMemoryAndNonZeroFillIfNeeded(
1830*8975f5c5SAndroid Build Coastguard Worker             context, mState.hasProtectedContent(), renderer->getMemoryProperties(),
1831*8975f5c5SAndroid Build Coastguard Worker             VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
1832*8975f5c5SAndroid Build Coastguard Worker             vk::MemoryAllocationType::SwapchainDepthStencilImage));
1833*8975f5c5SAndroid Build Coastguard Worker 
1834*8975f5c5SAndroid Build Coastguard Worker         mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageViews, nullptr,
1835*8975f5c5SAndroid Build Coastguard Worker                                        nullptr, {}, gl::LevelIndex(0), 0, 1,
1836*8975f5c5SAndroid Build Coastguard Worker                                        RenderTargetTransience::Default);
1837*8975f5c5SAndroid Build Coastguard Worker 
1838*8975f5c5SAndroid Build Coastguard Worker         // We will need to pass depth/stencil image views to the RenderTargetVk in the future.
1839*8975f5c5SAndroid Build Coastguard Worker     }
1840*8975f5c5SAndroid Build Coastguard Worker 
1841*8975f5c5SAndroid Build Coastguard Worker     // Need to acquire a new image before the swapchain can be used.
1842*8975f5c5SAndroid Build Coastguard Worker     mAcquireOperation.state = impl::ImageAcquireState::NeedToAcquire;
1843*8975f5c5SAndroid Build Coastguard Worker 
1844*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1845*8975f5c5SAndroid Build Coastguard Worker }
1846*8975f5c5SAndroid Build Coastguard Worker 
isMultiSampled() const1847*8975f5c5SAndroid Build Coastguard Worker bool WindowSurfaceVk::isMultiSampled() const
1848*8975f5c5SAndroid Build Coastguard Worker {
1849*8975f5c5SAndroid Build Coastguard Worker     return mColorImageMS.valid();
1850*8975f5c5SAndroid Build Coastguard Worker }
1851*8975f5c5SAndroid Build Coastguard Worker 
queryAndAdjustSurfaceCaps(ContextVk * contextVk,VkSurfaceCapabilitiesKHR * surfaceCaps)1852*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::queryAndAdjustSurfaceCaps(ContextVk *contextVk,
1853*8975f5c5SAndroid Build Coastguard Worker                                                          VkSurfaceCapabilitiesKHR *surfaceCaps)
1854*8975f5c5SAndroid Build Coastguard Worker {
1855*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer                 = contextVk->getRenderer();
1856*8975f5c5SAndroid Build Coastguard Worker     const VkPhysicalDevice &physicalDevice = renderer->getPhysicalDevice();
1857*8975f5c5SAndroid Build Coastguard Worker 
1858*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().supportsSwapchainMaintenance1.enabled)
1859*8975f5c5SAndroid Build Coastguard Worker     {
1860*8975f5c5SAndroid Build Coastguard Worker         VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo2 = {};
1861*8975f5c5SAndroid Build Coastguard Worker         surfaceInfo2.sType   = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
1862*8975f5c5SAndroid Build Coastguard Worker         surfaceInfo2.surface = mSurface;
1863*8975f5c5SAndroid Build Coastguard Worker 
1864*8975f5c5SAndroid Build Coastguard Worker         VkSurfacePresentModeEXT surfacePresentMode = {};
1865*8975f5c5SAndroid Build Coastguard Worker         surfacePresentMode.sType                   = VK_STRUCTURE_TYPE_SURFACE_PRESENT_MODE_EXT;
1866*8975f5c5SAndroid Build Coastguard Worker         surfacePresentMode.presentMode =
1867*8975f5c5SAndroid Build Coastguard Worker             vk::ConvertPresentModeToVkPresentMode(mDesiredSwapchainPresentMode);
1868*8975f5c5SAndroid Build Coastguard Worker         vk::AddToPNextChain(&surfaceInfo2, &surfacePresentMode);
1869*8975f5c5SAndroid Build Coastguard Worker 
1870*8975f5c5SAndroid Build Coastguard Worker         VkSurfaceCapabilities2KHR surfaceCaps2 = {};
1871*8975f5c5SAndroid Build Coastguard Worker         surfaceCaps2.sType                     = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
1872*8975f5c5SAndroid Build Coastguard Worker 
1873*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(contextVk, vkGetPhysicalDeviceSurfaceCapabilities2KHR(
1874*8975f5c5SAndroid Build Coastguard Worker                                     renderer->getPhysicalDevice(), &surfaceInfo2, &surfaceCaps2));
1875*8975f5c5SAndroid Build Coastguard Worker         *surfaceCaps = surfaceCaps2.surfaceCapabilities;
1876*8975f5c5SAndroid Build Coastguard Worker     }
1877*8975f5c5SAndroid Build Coastguard Worker     else
1878*8975f5c5SAndroid Build Coastguard Worker     {
1879*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(contextVk, vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface,
1880*8975f5c5SAndroid Build Coastguard Worker                                                                           surfaceCaps));
1881*8975f5c5SAndroid Build Coastguard Worker     }
1882*8975f5c5SAndroid Build Coastguard Worker 
1883*8975f5c5SAndroid Build Coastguard Worker     if (surfaceCaps->currentExtent.width == kSurfaceSizedBySwapchain)
1884*8975f5c5SAndroid Build Coastguard Worker     {
1885*8975f5c5SAndroid Build Coastguard Worker         ASSERT(surfaceCaps->currentExtent.height == kSurfaceSizedBySwapchain);
1886*8975f5c5SAndroid Build Coastguard Worker         ASSERT(!IsAndroid());
1887*8975f5c5SAndroid Build Coastguard Worker 
1888*8975f5c5SAndroid Build Coastguard Worker         // vkGetPhysicalDeviceSurfaceCapabilitiesKHR does not provide useful extents for some
1889*8975f5c5SAndroid Build Coastguard Worker         // platforms (e.g. Fuschia).  Therefore, we must query the window size via a
1890*8975f5c5SAndroid Build Coastguard Worker         // platform-specific mechanism.  Add those extents to the surfaceCaps
1891*8975f5c5SAndroid Build Coastguard Worker         gl::Extents currentExtents;
1892*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(getCurrentWindowSize(contextVk, &currentExtents));
1893*8975f5c5SAndroid Build Coastguard Worker         surfaceCaps->currentExtent.width  = currentExtents.width;
1894*8975f5c5SAndroid Build Coastguard Worker         surfaceCaps->currentExtent.height = currentExtents.height;
1895*8975f5c5SAndroid Build Coastguard Worker     }
1896*8975f5c5SAndroid Build Coastguard Worker 
1897*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
1898*8975f5c5SAndroid Build Coastguard Worker }
1899*8975f5c5SAndroid Build Coastguard Worker 
checkForOutOfDateSwapchain(ContextVk * contextVk,bool forceRecreate)1900*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(ContextVk *contextVk, bool forceRecreate)
1901*8975f5c5SAndroid Build Coastguard Worker {
1902*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state != impl::ImageAcquireState::Ready);
1903*8975f5c5SAndroid Build Coastguard Worker 
1904*8975f5c5SAndroid Build Coastguard Worker     bool presentModeIncompatible =
1905*8975f5c5SAndroid Build Coastguard Worker         !IsCompatiblePresentMode(mDesiredSwapchainPresentMode, mCompatiblePresentModes.data(),
1906*8975f5c5SAndroid Build Coastguard Worker                                  mCompatiblePresentModes.size());
1907*8975f5c5SAndroid Build Coastguard Worker     bool swapchainMissing = (mSwapchain == VK_NULL_HANDLE);
1908*8975f5c5SAndroid Build Coastguard Worker     bool needRecreate     = forceRecreate || presentModeIncompatible || swapchainMissing;
1909*8975f5c5SAndroid Build Coastguard Worker 
1910*8975f5c5SAndroid Build Coastguard Worker     // If there's no change, early out.
1911*8975f5c5SAndroid Build Coastguard Worker     if (!contextVk->getFeatures().perFrameWindowSizeQuery.enabled && !needRecreate)
1912*8975f5c5SAndroid Build Coastguard Worker     {
1913*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
1914*8975f5c5SAndroid Build Coastguard Worker     }
1915*8975f5c5SAndroid Build Coastguard Worker 
1916*8975f5c5SAndroid Build Coastguard Worker     // Get the latest surface capabilities.
1917*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(queryAndAdjustSurfaceCaps(contextVk, &mSurfaceCaps));
1918*8975f5c5SAndroid Build Coastguard Worker 
1919*8975f5c5SAndroid Build Coastguard Worker     if (contextVk->getFeatures().perFrameWindowSizeQuery.enabled)
1920*8975f5c5SAndroid Build Coastguard Worker     {
1921*8975f5c5SAndroid Build Coastguard Worker         // On Android, rotation can cause the minImageCount to change
1922*8975f5c5SAndroid Build Coastguard Worker         uint32_t minImageCount =
1923*8975f5c5SAndroid Build Coastguard Worker             GetMinImageCount(contextVk->getRenderer(), mSurfaceCaps, mDesiredSwapchainPresentMode);
1924*8975f5c5SAndroid Build Coastguard Worker         if (mMinImageCount != minImageCount)
1925*8975f5c5SAndroid Build Coastguard Worker         {
1926*8975f5c5SAndroid Build Coastguard Worker             needRecreate     = true;
1927*8975f5c5SAndroid Build Coastguard Worker             mMinImageCount   = minImageCount;
1928*8975f5c5SAndroid Build Coastguard Worker         }
1929*8975f5c5SAndroid Build Coastguard Worker 
1930*8975f5c5SAndroid Build Coastguard Worker         if (!needRecreate)
1931*8975f5c5SAndroid Build Coastguard Worker         {
1932*8975f5c5SAndroid Build Coastguard Worker             // This device generates neither VK_ERROR_OUT_OF_DATE_KHR nor VK_SUBOPTIMAL_KHR.  Check
1933*8975f5c5SAndroid Build Coastguard Worker             // for whether the size and/or rotation have changed since the swapchain was created.
1934*8975f5c5SAndroid Build Coastguard Worker             uint32_t swapchainWidth  = getWidth();
1935*8975f5c5SAndroid Build Coastguard Worker             uint32_t swapchainHeight = getHeight();
1936*8975f5c5SAndroid Build Coastguard Worker             needRecreate             = mSurfaceCaps.currentTransform != mPreTransform ||
1937*8975f5c5SAndroid Build Coastguard Worker                            mSurfaceCaps.currentExtent.width != swapchainWidth ||
1938*8975f5c5SAndroid Build Coastguard Worker                            mSurfaceCaps.currentExtent.height != swapchainHeight;
1939*8975f5c5SAndroid Build Coastguard Worker         }
1940*8975f5c5SAndroid Build Coastguard Worker     }
1941*8975f5c5SAndroid Build Coastguard Worker 
1942*8975f5c5SAndroid Build Coastguard Worker     // If anything has changed, recreate the swapchain.
1943*8975f5c5SAndroid Build Coastguard Worker     if (!needRecreate)
1944*8975f5c5SAndroid Build Coastguard Worker     {
1945*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
1946*8975f5c5SAndroid Build Coastguard Worker     }
1947*8975f5c5SAndroid Build Coastguard Worker 
1948*8975f5c5SAndroid Build Coastguard Worker     gl::Extents newSwapchainExtents(mSurfaceCaps.currentExtent.width,
1949*8975f5c5SAndroid Build Coastguard Worker                                     mSurfaceCaps.currentExtent.height, 1);
1950*8975f5c5SAndroid Build Coastguard Worker 
1951*8975f5c5SAndroid Build Coastguard Worker     if (contextVk->getFeatures().enablePreRotateSurfaces.enabled)
1952*8975f5c5SAndroid Build Coastguard Worker     {
1953*8975f5c5SAndroid Build Coastguard Worker         // Update the surface's transform, which can change even if the window size does not.
1954*8975f5c5SAndroid Build Coastguard Worker         mPreTransform = mSurfaceCaps.currentTransform;
1955*8975f5c5SAndroid Build Coastguard Worker     }
1956*8975f5c5SAndroid Build Coastguard Worker 
1957*8975f5c5SAndroid Build Coastguard Worker     return recreateSwapchain(contextVk, newSwapchainExtents);
1958*8975f5c5SAndroid Build Coastguard Worker }
1959*8975f5c5SAndroid Build Coastguard Worker 
releaseSwapchainImages(ContextVk * contextVk)1960*8975f5c5SAndroid Build Coastguard Worker void WindowSurfaceVk::releaseSwapchainImages(ContextVk *contextVk)
1961*8975f5c5SAndroid Build Coastguard Worker {
1962*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
1963*8975f5c5SAndroid Build Coastguard Worker 
1964*8975f5c5SAndroid Build Coastguard Worker     mColorRenderTarget.releaseImageAndViews(contextVk);
1965*8975f5c5SAndroid Build Coastguard Worker     mDepthStencilRenderTarget.releaseImageAndViews(contextVk);
1966*8975f5c5SAndroid Build Coastguard Worker 
1967*8975f5c5SAndroid Build Coastguard Worker     if (mDepthStencilImage.valid())
1968*8975f5c5SAndroid Build Coastguard Worker     {
1969*8975f5c5SAndroid Build Coastguard Worker         mDepthStencilImageViews.release(renderer, mDepthStencilImage.getResourceUse());
1970*8975f5c5SAndroid Build Coastguard Worker         mDepthStencilImage.releaseImageFromShareContexts(renderer, contextVk, {});
1971*8975f5c5SAndroid Build Coastguard Worker         mDepthStencilImage.releaseStagedUpdates(renderer);
1972*8975f5c5SAndroid Build Coastguard Worker     }
1973*8975f5c5SAndroid Build Coastguard Worker 
1974*8975f5c5SAndroid Build Coastguard Worker     if (mColorImageMS.valid())
1975*8975f5c5SAndroid Build Coastguard Worker     {
1976*8975f5c5SAndroid Build Coastguard Worker         mColorImageMSViews.release(renderer, mColorImageMS.getResourceUse());
1977*8975f5c5SAndroid Build Coastguard Worker         mColorImageMS.releaseImageFromShareContexts(renderer, contextVk, {});
1978*8975f5c5SAndroid Build Coastguard Worker         mColorImageMS.releaseStagedUpdates(renderer);
1979*8975f5c5SAndroid Build Coastguard Worker         contextVk->addGarbage(&mFramebufferMS);
1980*8975f5c5SAndroid Build Coastguard Worker     }
1981*8975f5c5SAndroid Build Coastguard Worker 
1982*8975f5c5SAndroid Build Coastguard Worker     mSwapchainImageBindings.clear();
1983*8975f5c5SAndroid Build Coastguard Worker 
1984*8975f5c5SAndroid Build Coastguard Worker     for (SwapchainImage &swapchainImage : mSwapchainImages)
1985*8975f5c5SAndroid Build Coastguard Worker     {
1986*8975f5c5SAndroid Build Coastguard Worker         ASSERT(swapchainImage.image);
1987*8975f5c5SAndroid Build Coastguard Worker         swapchainImage.imageViews.release(renderer, swapchainImage.image->getResourceUse());
1988*8975f5c5SAndroid Build Coastguard Worker         // swapchain image must not have ANI semaphore assigned here, since acquired image must be
1989*8975f5c5SAndroid Build Coastguard Worker         // presented before swapchain recreation.
1990*8975f5c5SAndroid Build Coastguard Worker         swapchainImage.image->resetImageWeakReference();
1991*8975f5c5SAndroid Build Coastguard Worker         swapchainImage.image->destroy(renderer);
1992*8975f5c5SAndroid Build Coastguard Worker 
1993*8975f5c5SAndroid Build Coastguard Worker         contextVk->addGarbage(&swapchainImage.framebuffer);
1994*8975f5c5SAndroid Build Coastguard Worker         if (swapchainImage.fetchFramebuffer.valid())
1995*8975f5c5SAndroid Build Coastguard Worker         {
1996*8975f5c5SAndroid Build Coastguard Worker             contextVk->addGarbage(&swapchainImage.fetchFramebuffer);
1997*8975f5c5SAndroid Build Coastguard Worker         }
1998*8975f5c5SAndroid Build Coastguard Worker     }
1999*8975f5c5SAndroid Build Coastguard Worker 
2000*8975f5c5SAndroid Build Coastguard Worker     mSwapchainImages.clear();
2001*8975f5c5SAndroid Build Coastguard Worker }
2002*8975f5c5SAndroid Build Coastguard Worker 
finish(vk::Context * context)2003*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::finish(vk::Context *context)
2004*8975f5c5SAndroid Build Coastguard Worker {
2005*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = context->getRenderer();
2006*8975f5c5SAndroid Build Coastguard Worker 
2007*8975f5c5SAndroid Build Coastguard Worker     mUse.merge(mDepthStencilImage.getResourceUse());
2008*8975f5c5SAndroid Build Coastguard Worker     mUse.merge(mColorImageMS.getResourceUse());
2009*8975f5c5SAndroid Build Coastguard Worker     for (SwapchainImage &swapchainImage : mSwapchainImages)
2010*8975f5c5SAndroid Build Coastguard Worker     {
2011*8975f5c5SAndroid Build Coastguard Worker         mUse.merge(swapchainImage.image->getResourceUse());
2012*8975f5c5SAndroid Build Coastguard Worker     }
2013*8975f5c5SAndroid Build Coastguard Worker 
2014*8975f5c5SAndroid Build Coastguard Worker     return renderer->finishResourceUse(context, mUse);
2015*8975f5c5SAndroid Build Coastguard Worker }
2016*8975f5c5SAndroid Build Coastguard Worker 
destroySwapChainImages(DisplayVk * displayVk)2017*8975f5c5SAndroid Build Coastguard Worker void WindowSurfaceVk::destroySwapChainImages(DisplayVk *displayVk)
2018*8975f5c5SAndroid Build Coastguard Worker {
2019*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = displayVk->getRenderer();
2020*8975f5c5SAndroid Build Coastguard Worker     VkDevice device        = displayVk->getDevice();
2021*8975f5c5SAndroid Build Coastguard Worker 
2022*8975f5c5SAndroid Build Coastguard Worker     mDepthStencilImage.destroy(renderer);
2023*8975f5c5SAndroid Build Coastguard Worker     mDepthStencilImageViews.destroy(device);
2024*8975f5c5SAndroid Build Coastguard Worker     mColorImageMS.destroy(renderer);
2025*8975f5c5SAndroid Build Coastguard Worker     mColorImageMSViews.destroy(device);
2026*8975f5c5SAndroid Build Coastguard Worker     mFramebufferMS.destroy(device);
2027*8975f5c5SAndroid Build Coastguard Worker 
2028*8975f5c5SAndroid Build Coastguard Worker     for (SwapchainImage &swapchainImage : mSwapchainImages)
2029*8975f5c5SAndroid Build Coastguard Worker     {
2030*8975f5c5SAndroid Build Coastguard Worker         ASSERT(swapchainImage.image);
2031*8975f5c5SAndroid Build Coastguard Worker         // swapchain image must not have ANI semaphore assigned here, because it should be released
2032*8975f5c5SAndroid Build Coastguard Worker         // in the destroy() prior to calling this method.
2033*8975f5c5SAndroid Build Coastguard Worker         // We don't own the swapchain image handles, so we just remove our reference to it.
2034*8975f5c5SAndroid Build Coastguard Worker         swapchainImage.image->resetImageWeakReference();
2035*8975f5c5SAndroid Build Coastguard Worker         swapchainImage.image->destroy(renderer);
2036*8975f5c5SAndroid Build Coastguard Worker         swapchainImage.imageViews.destroy(device);
2037*8975f5c5SAndroid Build Coastguard Worker         swapchainImage.framebuffer.destroy(device);
2038*8975f5c5SAndroid Build Coastguard Worker         if (swapchainImage.fetchFramebuffer.valid())
2039*8975f5c5SAndroid Build Coastguard Worker         {
2040*8975f5c5SAndroid Build Coastguard Worker             swapchainImage.fetchFramebuffer.destroy(device);
2041*8975f5c5SAndroid Build Coastguard Worker         }
2042*8975f5c5SAndroid Build Coastguard Worker     }
2043*8975f5c5SAndroid Build Coastguard Worker 
2044*8975f5c5SAndroid Build Coastguard Worker     mSwapchainImages.clear();
2045*8975f5c5SAndroid Build Coastguard Worker }
2046*8975f5c5SAndroid Build Coastguard Worker 
prepareSwap(const gl::Context * context)2047*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::prepareSwap(const gl::Context *context)
2048*8975f5c5SAndroid Build Coastguard Worker {
2049*8975f5c5SAndroid Build Coastguard Worker     // Image is only required to be acquired here in case of a blocking present modes (FIFO).
2050*8975f5c5SAndroid Build Coastguard Worker     // However, we will acquire the image in any case, for simplicity and possibly for performance.
2051*8975f5c5SAndroid Build Coastguard Worker     if (mAcquireOperation.state != impl::ImageAcquireState::NeedToAcquire)
2052*8975f5c5SAndroid Build Coastguard Worker     {
2053*8975f5c5SAndroid Build Coastguard Worker         return egl::NoError();
2054*8975f5c5SAndroid Build Coastguard Worker     }
2055*8975f5c5SAndroid Build Coastguard Worker 
2056*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = vk::GetImpl(context)->getRenderer();
2057*8975f5c5SAndroid Build Coastguard Worker 
2058*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = prepareForAcquireNextSwapchainImage(context, false);
2059*8975f5c5SAndroid Build Coastguard Worker     if (result != angle::Result::Continue)
2060*8975f5c5SAndroid Build Coastguard Worker     {
2061*8975f5c5SAndroid Build Coastguard Worker         return angle::ToEGL(result, EGL_BAD_SURFACE);
2062*8975f5c5SAndroid Build Coastguard Worker     }
2063*8975f5c5SAndroid Build Coastguard Worker 
2064*8975f5c5SAndroid Build Coastguard Worker     // |mColorRenderTarget| may be invalid at this point (in case of swapchain recreate above),
2065*8975f5c5SAndroid Build Coastguard Worker     // however it will not be accessed until update in the |postProcessUnlockedAcquire| call.
2066*8975f5c5SAndroid Build Coastguard Worker 
2067*8975f5c5SAndroid Build Coastguard Worker     // Must check present mode after the above prepare (in case of swapchain recreate).
2068*8975f5c5SAndroid Build Coastguard Worker     if (isSharedPresentMode())
2069*8975f5c5SAndroid Build Coastguard Worker     {
2070*8975f5c5SAndroid Build Coastguard Worker         // Shared present mode requires special handling, because it requires use of
2071*8975f5c5SAndroid Build Coastguard Worker         // |skipAcquireNextSwapchainImageForSharedPresentMode| method.
2072*8975f5c5SAndroid Build Coastguard Worker         // Below call is not going to block.
2073*8975f5c5SAndroid Build Coastguard Worker         result = doDeferredAcquireNextImageWithUsableSwapchain(context);
2074*8975f5c5SAndroid Build Coastguard Worker         return angle::ToEGL(result, EGL_BAD_SURFACE);
2075*8975f5c5SAndroid Build Coastguard Worker     }
2076*8975f5c5SAndroid Build Coastguard Worker 
2077*8975f5c5SAndroid Build Coastguard Worker     // Call vkAcquireNextImageKHR without holding the share group and global locks.
2078*8975f5c5SAndroid Build Coastguard Worker     // The following are accessed by this function:
2079*8975f5c5SAndroid Build Coastguard Worker     //
2080*8975f5c5SAndroid Build Coastguard Worker     // - mAcquireOperation.state
2081*8975f5c5SAndroid Build Coastguard Worker     // - Contents of mAcquireOperation.unlockedAcquireData and
2082*8975f5c5SAndroid Build Coastguard Worker     //   mAcquireOperation.unlockedAcquireResult
2083*8975f5c5SAndroid Build Coastguard Worker     // - context->getDevice(), which doesn't need external synchronization
2084*8975f5c5SAndroid Build Coastguard Worker     // - mSwapchain
2085*8975f5c5SAndroid Build Coastguard Worker     //
2086*8975f5c5SAndroid Build Coastguard Worker     // All these members MUST only be accessed from a thread where Surface is current.
2087*8975f5c5SAndroid Build Coastguard Worker     // The |AcquireNextImageUnlocked| itself is also possible only from this thread, therefore there
2088*8975f5c5SAndroid Build Coastguard Worker     // is no need in synchronization between locked and unlocked calls.
2089*8975f5c5SAndroid Build Coastguard Worker     //
2090*8975f5c5SAndroid Build Coastguard Worker     // The result of this call is processed in doDeferredAcquireNextImage() by whoever ends up
2091*8975f5c5SAndroid Build Coastguard Worker     // calling it (likely the eglSwapBuffers call that follows)
2092*8975f5c5SAndroid Build Coastguard Worker 
2093*8975f5c5SAndroid Build Coastguard Worker     egl::Display::GetCurrentThreadUnlockedTailCall()->add(
2094*8975f5c5SAndroid Build Coastguard Worker         [device = renderer->getDevice(), swapchain = mSwapchain,
2095*8975f5c5SAndroid Build Coastguard Worker          acquire = &mAcquireOperation](void *resultOut) {
2096*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRACE_EVENT0("gpu.angle", "Acquire Swap Image Before Swap");
2097*8975f5c5SAndroid Build Coastguard Worker             ANGLE_UNUSED_VARIABLE(resultOut);
2098*8975f5c5SAndroid Build Coastguard Worker             AcquireNextImageUnlocked(device, swapchain, acquire);
2099*8975f5c5SAndroid Build Coastguard Worker         });
2100*8975f5c5SAndroid Build Coastguard Worker 
2101*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
2102*8975f5c5SAndroid Build Coastguard Worker }
2103*8975f5c5SAndroid Build Coastguard Worker 
swapWithDamage(const gl::Context * context,const EGLint * rects,EGLint n_rects)2104*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::swapWithDamage(const gl::Context *context,
2105*8975f5c5SAndroid Build Coastguard Worker                                            const EGLint *rects,
2106*8975f5c5SAndroid Build Coastguard Worker                                            EGLint n_rects)
2107*8975f5c5SAndroid Build Coastguard Worker {
2108*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = swapImpl(context, rects, n_rects, nullptr);
2109*8975f5c5SAndroid Build Coastguard Worker     if (result == angle::Result::Continue)
2110*8975f5c5SAndroid Build Coastguard Worker     {
2111*8975f5c5SAndroid Build Coastguard Worker         ContextVk *contextVk = vk::GetImpl(context);
2112*8975f5c5SAndroid Build Coastguard Worker         result               = contextVk->onFramebufferBoundary(context);
2113*8975f5c5SAndroid Build Coastguard Worker     }
2114*8975f5c5SAndroid Build Coastguard Worker 
2115*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(result, EGL_BAD_SURFACE);
2116*8975f5c5SAndroid Build Coastguard Worker }
2117*8975f5c5SAndroid Build Coastguard Worker 
swap(const gl::Context * context)2118*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::swap(const gl::Context *context)
2119*8975f5c5SAndroid Build Coastguard Worker {
2120*8975f5c5SAndroid Build Coastguard Worker     // When in shared present mode, eglSwapBuffers is unnecessary except for mode change.  When mode
2121*8975f5c5SAndroid Build Coastguard Worker     // change is not expected, the eglSwapBuffers call is forwarded to the context as a glFlush.
2122*8975f5c5SAndroid Build Coastguard Worker     // This allows the context to skip it if there's nothing to flush.  Otherwise control is bounced
2123*8975f5c5SAndroid Build Coastguard Worker     // back swapImpl().
2124*8975f5c5SAndroid Build Coastguard Worker     //
2125*8975f5c5SAndroid Build Coastguard Worker     // Some apps issue eglSwapBuffers after glFlush unnecessary, causing the CPU throttling logic to
2126*8975f5c5SAndroid Build Coastguard Worker     // effectively wait for the just submitted commands.
2127*8975f5c5SAndroid Build Coastguard Worker     if (isSharedPresentMode() && mSwapchainPresentMode == mDesiredSwapchainPresentMode)
2128*8975f5c5SAndroid Build Coastguard Worker     {
2129*8975f5c5SAndroid Build Coastguard Worker         const angle::Result result = vk::GetImpl(context)->flush(context);
2130*8975f5c5SAndroid Build Coastguard Worker         return angle::ToEGL(result, EGL_BAD_SURFACE);
2131*8975f5c5SAndroid Build Coastguard Worker     }
2132*8975f5c5SAndroid Build Coastguard Worker 
2133*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = swapImpl(context, nullptr, 0, nullptr);
2134*8975f5c5SAndroid Build Coastguard Worker     if (result == angle::Result::Continue)
2135*8975f5c5SAndroid Build Coastguard Worker     {
2136*8975f5c5SAndroid Build Coastguard Worker         ContextVk *contextVk = vk::GetImpl(context);
2137*8975f5c5SAndroid Build Coastguard Worker         result               = contextVk->onFramebufferBoundary(context);
2138*8975f5c5SAndroid Build Coastguard Worker     }
2139*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(result, EGL_BAD_SURFACE);
2140*8975f5c5SAndroid Build Coastguard Worker }
2141*8975f5c5SAndroid Build Coastguard Worker 
computePresentOutOfDate(vk::Context * context,VkResult result,bool * presentOutOfDate)2142*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::computePresentOutOfDate(vk::Context *context,
2143*8975f5c5SAndroid Build Coastguard Worker                                                        VkResult result,
2144*8975f5c5SAndroid Build Coastguard Worker                                                        bool *presentOutOfDate)
2145*8975f5c5SAndroid Build Coastguard Worker {
2146*8975f5c5SAndroid Build Coastguard Worker     // If OUT_OF_DATE is returned, it's ok, we just need to recreate the swapchain before
2147*8975f5c5SAndroid Build Coastguard Worker     // continuing.  We do the same when VK_SUBOPTIMAL_KHR is returned to avoid visual degradation
2148*8975f5c5SAndroid Build Coastguard Worker     // and handle device rotation / screen resize.
2149*8975f5c5SAndroid Build Coastguard Worker     *presentOutOfDate = result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR;
2150*8975f5c5SAndroid Build Coastguard Worker     if (!*presentOutOfDate)
2151*8975f5c5SAndroid Build Coastguard Worker     {
2152*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(context, result);
2153*8975f5c5SAndroid Build Coastguard Worker     }
2154*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
2155*8975f5c5SAndroid Build Coastguard Worker }
2156*8975f5c5SAndroid Build Coastguard Worker 
chooseFramebuffer()2157*8975f5c5SAndroid Build Coastguard Worker vk::Framebuffer &WindowSurfaceVk::chooseFramebuffer()
2158*8975f5c5SAndroid Build Coastguard Worker {
2159*8975f5c5SAndroid Build Coastguard Worker     if (isMultiSampled())
2160*8975f5c5SAndroid Build Coastguard Worker     {
2161*8975f5c5SAndroid Build Coastguard Worker         return mFramebufferMS;
2162*8975f5c5SAndroid Build Coastguard Worker     }
2163*8975f5c5SAndroid Build Coastguard Worker 
2164*8975f5c5SAndroid Build Coastguard Worker     // Choose which framebuffer to use based on fetch, so it will have a matching renderpass
2165*8975f5c5SAndroid Build Coastguard Worker     return mFramebufferFetchMode == vk::FramebufferFetchMode::Color
2166*8975f5c5SAndroid Build Coastguard Worker                ? mSwapchainImages[mCurrentSwapchainImageIndex].fetchFramebuffer
2167*8975f5c5SAndroid Build Coastguard Worker                : mSwapchainImages[mCurrentSwapchainImageIndex].framebuffer;
2168*8975f5c5SAndroid Build Coastguard Worker }
2169*8975f5c5SAndroid Build Coastguard Worker 
prePresentSubmit(ContextVk * contextVk,const vk::Semaphore & presentSemaphore)2170*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::prePresentSubmit(ContextVk *contextVk,
2171*8975f5c5SAndroid Build Coastguard Worker                                                 const vk::Semaphore &presentSemaphore)
2172*8975f5c5SAndroid Build Coastguard Worker {
2173*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
2174*8975f5c5SAndroid Build Coastguard Worker 
2175*8975f5c5SAndroid Build Coastguard Worker     SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];
2176*8975f5c5SAndroid Build Coastguard Worker 
2177*8975f5c5SAndroid Build Coastguard Worker     // Make sure deferred clears are applied, if any.
2178*8975f5c5SAndroid Build Coastguard Worker     if (mColorImageMS.valid())
2179*8975f5c5SAndroid Build Coastguard Worker     {
2180*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mColorImageMS.flushStagedUpdates(contextVk, gl::LevelIndex(0), gl::LevelIndex(1),
2181*8975f5c5SAndroid Build Coastguard Worker                                                    0, 1, {}));
2182*8975f5c5SAndroid Build Coastguard Worker     }
2183*8975f5c5SAndroid Build Coastguard Worker     else
2184*8975f5c5SAndroid Build Coastguard Worker     {
2185*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(image.image->flushStagedUpdates(contextVk, gl::LevelIndex(0), gl::LevelIndex(1),
2186*8975f5c5SAndroid Build Coastguard Worker                                                   0, 1, {}));
2187*8975f5c5SAndroid Build Coastguard Worker     }
2188*8975f5c5SAndroid Build Coastguard Worker 
2189*8975f5c5SAndroid Build Coastguard Worker     // If user calls eglSwapBuffer without use it, image may already in Present layout (if swap
2190*8975f5c5SAndroid Build Coastguard Worker     // without any draw) or Undefined (first time present). In this case, if
2191*8975f5c5SAndroid Build Coastguard Worker     // acquireNextImageSemaphore has not been waited, we must add to context will force the
2192*8975f5c5SAndroid Build Coastguard Worker     // semaphore wait so that it will be in unsignaled state and ready to use for ANI call.
2193*8975f5c5SAndroid Build Coastguard Worker     if (image.image->getAcquireNextImageSemaphore().valid())
2194*8975f5c5SAndroid Build Coastguard Worker     {
2195*8975f5c5SAndroid Build Coastguard Worker         ASSERT(!renderer->getFeatures().supportsPresentation.enabled ||
2196*8975f5c5SAndroid Build Coastguard Worker                image.image->getCurrentImageLayout() == vk::ImageLayout::Present ||
2197*8975f5c5SAndroid Build Coastguard Worker                image.image->getCurrentImageLayout() == vk::ImageLayout::Undefined);
2198*8975f5c5SAndroid Build Coastguard Worker         contextVk->addWaitSemaphore(image.image->getAcquireNextImageSemaphore().getHandle(),
2199*8975f5c5SAndroid Build Coastguard Worker                                     vk::kSwapchainAcquireImageWaitStageFlags);
2200*8975f5c5SAndroid Build Coastguard Worker         image.image->resetAcquireNextImageSemaphore();
2201*8975f5c5SAndroid Build Coastguard Worker     }
2202*8975f5c5SAndroid Build Coastguard Worker 
2203*8975f5c5SAndroid Build Coastguard Worker     // We can only do present related optimization if this is the last renderpass that touches the
2204*8975f5c5SAndroid Build Coastguard Worker     // swapchain image. MSAA resolve and overlay will insert another renderpass which disqualifies
2205*8975f5c5SAndroid Build Coastguard Worker     // the optimization.
2206*8975f5c5SAndroid Build Coastguard Worker     bool imageResolved = false;
2207*8975f5c5SAndroid Build Coastguard Worker     if (contextVk->hasStartedRenderPassWithDefaultFramebuffer())
2208*8975f5c5SAndroid Build Coastguard Worker     {
2209*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(contextVk->optimizeRenderPassForPresent(&image.imageViews, image.image.get(),
2210*8975f5c5SAndroid Build Coastguard Worker                                                           &mColorImageMS, mSwapchainPresentMode,
2211*8975f5c5SAndroid Build Coastguard Worker                                                           &imageResolved));
2212*8975f5c5SAndroid Build Coastguard Worker     }
2213*8975f5c5SAndroid Build Coastguard Worker 
2214*8975f5c5SAndroid Build Coastguard Worker     // Because the color attachment defers layout changes until endRenderPass time, we must call
2215*8975f5c5SAndroid Build Coastguard Worker     // finalize the layout transition in the renderpass before we insert layout change to
2216*8975f5c5SAndroid Build Coastguard Worker     // ImageLayout::Present bellow.
2217*8975f5c5SAndroid Build Coastguard Worker     contextVk->finalizeImageLayout(image.image.get(), {});
2218*8975f5c5SAndroid Build Coastguard Worker     contextVk->finalizeImageLayout(&mColorImageMS, {});
2219*8975f5c5SAndroid Build Coastguard Worker 
2220*8975f5c5SAndroid Build Coastguard Worker     vk::OutsideRenderPassCommandBufferHelper *commandBufferHelper;
2221*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBufferHelper));
2222*8975f5c5SAndroid Build Coastguard Worker 
2223*8975f5c5SAndroid Build Coastguard Worker     if (mColorImageMS.valid() && !imageResolved)
2224*8975f5c5SAndroid Build Coastguard Worker     {
2225*8975f5c5SAndroid Build Coastguard Worker         // Transition the multisampled image to TRANSFER_SRC for resolve.
2226*8975f5c5SAndroid Build Coastguard Worker         vk::CommandBufferAccess access;
2227*8975f5c5SAndroid Build Coastguard Worker         access.onImageTransferRead(VK_IMAGE_ASPECT_COLOR_BIT, &mColorImageMS);
2228*8975f5c5SAndroid Build Coastguard Worker         access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
2229*8975f5c5SAndroid Build Coastguard Worker                                     image.image.get());
2230*8975f5c5SAndroid Build Coastguard Worker 
2231*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper(access, &commandBufferHelper));
2232*8975f5c5SAndroid Build Coastguard Worker 
2233*8975f5c5SAndroid Build Coastguard Worker         VkImageResolve resolveRegion                = {};
2234*8975f5c5SAndroid Build Coastguard Worker         resolveRegion.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
2235*8975f5c5SAndroid Build Coastguard Worker         resolveRegion.srcSubresource.mipLevel       = 0;
2236*8975f5c5SAndroid Build Coastguard Worker         resolveRegion.srcSubresource.baseArrayLayer = 0;
2237*8975f5c5SAndroid Build Coastguard Worker         resolveRegion.srcSubresource.layerCount     = 1;
2238*8975f5c5SAndroid Build Coastguard Worker         resolveRegion.srcOffset                     = {};
2239*8975f5c5SAndroid Build Coastguard Worker         resolveRegion.dstSubresource                = resolveRegion.srcSubresource;
2240*8975f5c5SAndroid Build Coastguard Worker         resolveRegion.dstOffset                     = {};
2241*8975f5c5SAndroid Build Coastguard Worker         resolveRegion.extent                        = image.image->getRotatedExtents();
2242*8975f5c5SAndroid Build Coastguard Worker 
2243*8975f5c5SAndroid Build Coastguard Worker         mColorImageMS.resolve(image.image.get(), resolveRegion,
2244*8975f5c5SAndroid Build Coastguard Worker                               &commandBufferHelper->getCommandBuffer());
2245*8975f5c5SAndroid Build Coastguard Worker 
2246*8975f5c5SAndroid Build Coastguard Worker         contextVk->getPerfCounters().swapchainResolveOutsideSubpass++;
2247*8975f5c5SAndroid Build Coastguard Worker     }
2248*8975f5c5SAndroid Build Coastguard Worker 
2249*8975f5c5SAndroid Build Coastguard Worker     // The overlay is drawn after this.  This ensures that drawing the overlay does not interfere
2250*8975f5c5SAndroid Build Coastguard Worker     // with other functionality, especially counters used to validate said functionality.
2251*8975f5c5SAndroid Build Coastguard Worker     const bool shouldDrawOverlay = overlayHasEnabledWidget(contextVk);
2252*8975f5c5SAndroid Build Coastguard Worker 
2253*8975f5c5SAndroid Build Coastguard Worker     if (renderer->getFeatures().supportsPresentation.enabled && !shouldDrawOverlay)
2254*8975f5c5SAndroid Build Coastguard Worker     {
2255*8975f5c5SAndroid Build Coastguard Worker         // This does nothing if it's already in the requested layout
2256*8975f5c5SAndroid Build Coastguard Worker         image.image->recordReadBarrier(contextVk, VK_IMAGE_ASPECT_COLOR_BIT,
2257*8975f5c5SAndroid Build Coastguard Worker                                        vk::ImageLayout::Present, commandBufferHelper);
2258*8975f5c5SAndroid Build Coastguard Worker     }
2259*8975f5c5SAndroid Build Coastguard Worker 
2260*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(contextVk->flushAndSubmitCommands(shouldDrawOverlay ? nullptr : &presentSemaphore,
2261*8975f5c5SAndroid Build Coastguard Worker                                                 nullptr, RenderPassClosureReason::EGLSwapBuffers));
2262*8975f5c5SAndroid Build Coastguard Worker 
2263*8975f5c5SAndroid Build Coastguard Worker     if (shouldDrawOverlay)
2264*8975f5c5SAndroid Build Coastguard Worker     {
2265*8975f5c5SAndroid Build Coastguard Worker         updateOverlay(contextVk);
2266*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(drawOverlay(contextVk, &image));
2267*8975f5c5SAndroid Build Coastguard Worker 
2268*8975f5c5SAndroid Build Coastguard Worker         if (renderer->getFeatures().supportsPresentation.enabled)
2269*8975f5c5SAndroid Build Coastguard Worker         {
2270*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(contextVk->getOutsideRenderPassCommandBufferHelper({}, &commandBufferHelper));
2271*8975f5c5SAndroid Build Coastguard Worker             image.image->recordReadBarrier(contextVk, VK_IMAGE_ASPECT_COLOR_BIT,
2272*8975f5c5SAndroid Build Coastguard Worker                                            vk::ImageLayout::Present, commandBufferHelper);
2273*8975f5c5SAndroid Build Coastguard Worker         }
2274*8975f5c5SAndroid Build Coastguard Worker 
2275*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(contextVk->flushAndSubmitCommands(
2276*8975f5c5SAndroid Build Coastguard Worker             &presentSemaphore, nullptr, RenderPassClosureReason::AlreadySpecifiedElsewhere));
2277*8975f5c5SAndroid Build Coastguard Worker     }
2278*8975f5c5SAndroid Build Coastguard Worker 
2279*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
2280*8975f5c5SAndroid Build Coastguard Worker }
2281*8975f5c5SAndroid Build Coastguard Worker 
present(ContextVk * contextVk,const EGLint * rects,EGLint n_rects,const void * pNextChain,bool * presentOutOfDate)2282*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
2283*8975f5c5SAndroid Build Coastguard Worker                                        const EGLint *rects,
2284*8975f5c5SAndroid Build Coastguard Worker                                        EGLint n_rects,
2285*8975f5c5SAndroid Build Coastguard Worker                                        const void *pNextChain,
2286*8975f5c5SAndroid Build Coastguard Worker                                        bool *presentOutOfDate)
2287*8975f5c5SAndroid Build Coastguard Worker {
2288*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state == impl::ImageAcquireState::Ready);
2289*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mSwapchain != VK_NULL_HANDLE);
2290*8975f5c5SAndroid Build Coastguard Worker 
2291*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::present");
2292*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
2293*8975f5c5SAndroid Build Coastguard Worker 
2294*8975f5c5SAndroid Build Coastguard Worker     // Clean up whatever present is already finished. Do this before allocating new semaphore/fence
2295*8975f5c5SAndroid Build Coastguard Worker     // to reduce number of allocations.
2296*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(cleanUpPresentHistory(contextVk));
2297*8975f5c5SAndroid Build Coastguard Worker 
2298*8975f5c5SAndroid Build Coastguard Worker     // Get a new semaphore to use for present.
2299*8975f5c5SAndroid Build Coastguard Worker     vk::Semaphore presentSemaphore;
2300*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(NewSemaphore(contextVk, &mPresentSemaphoreRecycler, &presentSemaphore));
2301*8975f5c5SAndroid Build Coastguard Worker 
2302*8975f5c5SAndroid Build Coastguard Worker     // Make a submission before present to flush whatever's pending.  In the very least, a
2303*8975f5c5SAndroid Build Coastguard Worker     // submission is necessary to make sure the present semaphore is signaled.
2304*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(prePresentSubmit(contextVk, presentSemaphore));
2305*8975f5c5SAndroid Build Coastguard Worker 
2306*8975f5c5SAndroid Build Coastguard Worker     QueueSerial swapSerial = contextVk->getLastSubmittedQueueSerial();
2307*8975f5c5SAndroid Build Coastguard Worker 
2308*8975f5c5SAndroid Build Coastguard Worker     if (!contextVk->getFeatures().supportsSwapchainMaintenance1.enabled)
2309*8975f5c5SAndroid Build Coastguard Worker     {
2310*8975f5c5SAndroid Build Coastguard Worker         // Associate swapSerial of this present with the previous present of the same imageIndex.
2311*8975f5c5SAndroid Build Coastguard Worker         // Completion of swapSerial implies that current ANI semaphore was waited.  See
2312*8975f5c5SAndroid Build Coastguard Worker         // doc/PresentSemaphores.md for details.
2313*8975f5c5SAndroid Build Coastguard Worker         AssociateQueueSerialWithPresentHistory(mCurrentSwapchainImageIndex, swapSerial,
2314*8975f5c5SAndroid Build Coastguard Worker                                                &mPresentHistory);
2315*8975f5c5SAndroid Build Coastguard Worker     }
2316*8975f5c5SAndroid Build Coastguard Worker 
2317*8975f5c5SAndroid Build Coastguard Worker     VkPresentInfoKHR presentInfo   = {};
2318*8975f5c5SAndroid Build Coastguard Worker     presentInfo.sType              = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
2319*8975f5c5SAndroid Build Coastguard Worker     presentInfo.pNext              = pNextChain;
2320*8975f5c5SAndroid Build Coastguard Worker     presentInfo.waitSemaphoreCount = 1;
2321*8975f5c5SAndroid Build Coastguard Worker     presentInfo.pWaitSemaphores    = presentSemaphore.ptr();
2322*8975f5c5SAndroid Build Coastguard Worker     presentInfo.swapchainCount     = 1;
2323*8975f5c5SAndroid Build Coastguard Worker     presentInfo.pSwapchains        = &mSwapchain;
2324*8975f5c5SAndroid Build Coastguard Worker     presentInfo.pImageIndices      = &mCurrentSwapchainImageIndex;
2325*8975f5c5SAndroid Build Coastguard Worker     presentInfo.pResults           = nullptr;
2326*8975f5c5SAndroid Build Coastguard Worker 
2327*8975f5c5SAndroid Build Coastguard Worker     VkPresentRegionKHR presentRegion   = {};
2328*8975f5c5SAndroid Build Coastguard Worker     VkPresentRegionsKHR presentRegions = {};
2329*8975f5c5SAndroid Build Coastguard Worker     std::vector<VkRectLayerKHR> vkRects;
2330*8975f5c5SAndroid Build Coastguard Worker     if (contextVk->getFeatures().supportsIncrementalPresent.enabled && (n_rects > 0))
2331*8975f5c5SAndroid Build Coastguard Worker     {
2332*8975f5c5SAndroid Build Coastguard Worker         EGLint width  = getWidth();
2333*8975f5c5SAndroid Build Coastguard Worker         EGLint height = getHeight();
2334*8975f5c5SAndroid Build Coastguard Worker 
2335*8975f5c5SAndroid Build Coastguard Worker         const EGLint *eglRects       = rects;
2336*8975f5c5SAndroid Build Coastguard Worker         presentRegion.rectangleCount = n_rects;
2337*8975f5c5SAndroid Build Coastguard Worker         vkRects.resize(n_rects);
2338*8975f5c5SAndroid Build Coastguard Worker         for (EGLint i = 0; i < n_rects; i++)
2339*8975f5c5SAndroid Build Coastguard Worker         {
2340*8975f5c5SAndroid Build Coastguard Worker             vkRects[i] = ToVkRectLayer(
2341*8975f5c5SAndroid Build Coastguard Worker                 eglRects + i * 4, width, height,
2342*8975f5c5SAndroid Build Coastguard Worker                 contextVk->getFeatures().bottomLeftOriginPresentRegionRectangles.enabled);
2343*8975f5c5SAndroid Build Coastguard Worker         }
2344*8975f5c5SAndroid Build Coastguard Worker         presentRegion.pRectangles = vkRects.data();
2345*8975f5c5SAndroid Build Coastguard Worker 
2346*8975f5c5SAndroid Build Coastguard Worker         presentRegions.sType          = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR;
2347*8975f5c5SAndroid Build Coastguard Worker         presentRegions.swapchainCount = 1;
2348*8975f5c5SAndroid Build Coastguard Worker         presentRegions.pRegions       = &presentRegion;
2349*8975f5c5SAndroid Build Coastguard Worker 
2350*8975f5c5SAndroid Build Coastguard Worker         vk::AddToPNextChain(&presentInfo, &presentRegions);
2351*8975f5c5SAndroid Build Coastguard Worker     }
2352*8975f5c5SAndroid Build Coastguard Worker 
2353*8975f5c5SAndroid Build Coastguard Worker     VkSwapchainPresentFenceInfoEXT presentFenceInfo = {};
2354*8975f5c5SAndroid Build Coastguard Worker     VkSwapchainPresentModeInfoEXT presentModeInfo   = {};
2355*8975f5c5SAndroid Build Coastguard Worker     vk::Fence presentFence;
2356*8975f5c5SAndroid Build Coastguard Worker     VkPresentModeKHR presentMode;
2357*8975f5c5SAndroid Build Coastguard Worker     if (contextVk->getFeatures().supportsSwapchainMaintenance1.enabled)
2358*8975f5c5SAndroid Build Coastguard Worker     {
2359*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(contextVk,
2360*8975f5c5SAndroid Build Coastguard Worker                      NewFence(contextVk->getDevice(), &mPresentFenceRecycler, &presentFence));
2361*8975f5c5SAndroid Build Coastguard Worker 
2362*8975f5c5SAndroid Build Coastguard Worker         presentFenceInfo.sType          = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_FENCE_INFO_EXT;
2363*8975f5c5SAndroid Build Coastguard Worker         presentFenceInfo.swapchainCount = 1;
2364*8975f5c5SAndroid Build Coastguard Worker         presentFenceInfo.pFences        = presentFence.ptr();
2365*8975f5c5SAndroid Build Coastguard Worker 
2366*8975f5c5SAndroid Build Coastguard Worker         vk::AddToPNextChain(&presentInfo, &presentFenceInfo);
2367*8975f5c5SAndroid Build Coastguard Worker 
2368*8975f5c5SAndroid Build Coastguard Worker         // Update the present mode if necessary and possible
2369*8975f5c5SAndroid Build Coastguard Worker         if (mSwapchainPresentMode != mDesiredSwapchainPresentMode &&
2370*8975f5c5SAndroid Build Coastguard Worker             IsCompatiblePresentMode(mDesiredSwapchainPresentMode, mCompatiblePresentModes.data(),
2371*8975f5c5SAndroid Build Coastguard Worker                                     mCompatiblePresentModes.size()))
2372*8975f5c5SAndroid Build Coastguard Worker         {
2373*8975f5c5SAndroid Build Coastguard Worker             presentMode = vk::ConvertPresentModeToVkPresentMode(mDesiredSwapchainPresentMode);
2374*8975f5c5SAndroid Build Coastguard Worker 
2375*8975f5c5SAndroid Build Coastguard Worker             presentModeInfo.sType          = VK_STRUCTURE_TYPE_SWAPCHAIN_PRESENT_MODE_INFO_EXT;
2376*8975f5c5SAndroid Build Coastguard Worker             presentModeInfo.swapchainCount = 1;
2377*8975f5c5SAndroid Build Coastguard Worker             presentModeInfo.pPresentModes  = &presentMode;
2378*8975f5c5SAndroid Build Coastguard Worker 
2379*8975f5c5SAndroid Build Coastguard Worker             vk::AddToPNextChain(&presentInfo, &presentModeInfo);
2380*8975f5c5SAndroid Build Coastguard Worker 
2381*8975f5c5SAndroid Build Coastguard Worker             mSwapchainPresentMode = mDesiredSwapchainPresentMode;
2382*8975f5c5SAndroid Build Coastguard Worker         }
2383*8975f5c5SAndroid Build Coastguard Worker     }
2384*8975f5c5SAndroid Build Coastguard Worker 
2385*8975f5c5SAndroid Build Coastguard Worker     // The ANI semaphore must have been submitted and waited.
2386*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!mSwapchainImages[mCurrentSwapchainImageIndex]
2387*8975f5c5SAndroid Build Coastguard Worker                 .image->getAcquireNextImageSemaphore()
2388*8975f5c5SAndroid Build Coastguard Worker                 .valid());
2389*8975f5c5SAndroid Build Coastguard Worker 
2390*8975f5c5SAndroid Build Coastguard Worker     renderer->queuePresent(contextVk, contextVk->getPriority(), presentInfo, &mSwapchainStatus);
2391*8975f5c5SAndroid Build Coastguard Worker 
2392*8975f5c5SAndroid Build Coastguard Worker     // EGL_EXT_buffer_age
2393*8975f5c5SAndroid Build Coastguard Worker     // 4) What is the buffer age of a single buffered surface?
2394*8975f5c5SAndroid Build Coastguard Worker     //     RESOLVED: 0.  This falls out implicitly from the buffer age
2395*8975f5c5SAndroid Build Coastguard Worker     //     calculations, which dictate that a buffer's age starts at 0,
2396*8975f5c5SAndroid Build Coastguard Worker     //     and is only incremented by frame boundaries.  Since frame
2397*8975f5c5SAndroid Build Coastguard Worker     //     boundary functions do not affect single buffered surfaces,
2398*8975f5c5SAndroid Build Coastguard Worker     //     their age will always be 0.
2399*8975f5c5SAndroid Build Coastguard Worker     if (!isSharedPresentMode())
2400*8975f5c5SAndroid Build Coastguard Worker     {
2401*8975f5c5SAndroid Build Coastguard Worker         // Set FrameNumber for the presented image.
2402*8975f5c5SAndroid Build Coastguard Worker         mSwapchainImages[mCurrentSwapchainImageIndex].frameNumber = mFrameCount++;
2403*8975f5c5SAndroid Build Coastguard Worker     }
2404*8975f5c5SAndroid Build Coastguard Worker 
2405*8975f5c5SAndroid Build Coastguard Worker     // Place the semaphore in the present history.  Schedule pending old swapchains to be destroyed
2406*8975f5c5SAndroid Build Coastguard Worker     // at the same time the semaphore for this present can be destroyed.
2407*8975f5c5SAndroid Build Coastguard Worker     mPresentHistory.emplace_back();
2408*8975f5c5SAndroid Build Coastguard Worker     mPresentHistory.back().semaphore = std::move(presentSemaphore);
2409*8975f5c5SAndroid Build Coastguard Worker     if (contextVk->getFeatures().supportsSwapchainMaintenance1.enabled)
2410*8975f5c5SAndroid Build Coastguard Worker     {
2411*8975f5c5SAndroid Build Coastguard Worker         mPresentHistory.back().imageIndex = kInvalidImageIndex;
2412*8975f5c5SAndroid Build Coastguard Worker         mPresentHistory.back().fence      = std::move(presentFence);
2413*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(cleanUpOldSwapchains(contextVk));
2414*8975f5c5SAndroid Build Coastguard Worker     }
2415*8975f5c5SAndroid Build Coastguard Worker     else
2416*8975f5c5SAndroid Build Coastguard Worker     {
2417*8975f5c5SAndroid Build Coastguard Worker         // Image index is used to associate swapSerial in the next present.
2418*8975f5c5SAndroid Build Coastguard Worker         mPresentHistory.back().imageIndex    = mCurrentSwapchainImageIndex;
2419*8975f5c5SAndroid Build Coastguard Worker         mPresentHistory.back().oldSwapchains = std::move(mOldSwapchains);
2420*8975f5c5SAndroid Build Coastguard Worker     }
2421*8975f5c5SAndroid Build Coastguard Worker 
2422*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(
2423*8975f5c5SAndroid Build Coastguard Worker         computePresentOutOfDate(contextVk, mSwapchainStatus.lastPresentResult, presentOutOfDate));
2424*8975f5c5SAndroid Build Coastguard Worker 
2425*8975f5c5SAndroid Build Coastguard Worker     // Now apply CPU throttle if needed
2426*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(throttleCPU(contextVk, swapSerial));
2427*8975f5c5SAndroid Build Coastguard Worker 
2428*8975f5c5SAndroid Build Coastguard Worker     contextVk->resetPerFramePerfCounters();
2429*8975f5c5SAndroid Build Coastguard Worker 
2430*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
2431*8975f5c5SAndroid Build Coastguard Worker }
2432*8975f5c5SAndroid Build Coastguard Worker 
throttleCPU(vk::Context * context,const QueueSerial & currentSubmitSerial)2433*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::throttleCPU(vk::Context *context,
2434*8975f5c5SAndroid Build Coastguard Worker                                            const QueueSerial &currentSubmitSerial)
2435*8975f5c5SAndroid Build Coastguard Worker {
2436*8975f5c5SAndroid Build Coastguard Worker     // Wait on the oldest serial and replace it with the newest as the circular buffer moves
2437*8975f5c5SAndroid Build Coastguard Worker     // forward.
2438*8975f5c5SAndroid Build Coastguard Worker     QueueSerial swapSerial = mSwapHistory.front();
2439*8975f5c5SAndroid Build Coastguard Worker     mSwapHistory.front()   = currentSubmitSerial;
2440*8975f5c5SAndroid Build Coastguard Worker     mSwapHistory.next();
2441*8975f5c5SAndroid Build Coastguard Worker 
2442*8975f5c5SAndroid Build Coastguard Worker     if (swapSerial.valid() && !context->getRenderer()->hasQueueSerialFinished(swapSerial))
2443*8975f5c5SAndroid Build Coastguard Worker     {
2444*8975f5c5SAndroid Build Coastguard Worker         // Make this call after unlocking the EGL lock.  Renderer::finishQueueSerial is necessarily
2445*8975f5c5SAndroid Build Coastguard Worker         // thread-safe because it can get called from any number of GL commands, which don't
2446*8975f5c5SAndroid Build Coastguard Worker         // necessarily hold the EGL lock.
2447*8975f5c5SAndroid Build Coastguard Worker         //
2448*8975f5c5SAndroid Build Coastguard Worker         // As this is an unlocked tail call, it must not access anything else in Renderer.  The
2449*8975f5c5SAndroid Build Coastguard Worker         // display passed to |finishQueueSerial| is a |vk::Context|, and the only possible
2450*8975f5c5SAndroid Build Coastguard Worker         // modification to it is through |handleError()|.
2451*8975f5c5SAndroid Build Coastguard Worker         egl::Display::GetCurrentThreadUnlockedTailCall()->add(
2452*8975f5c5SAndroid Build Coastguard Worker             [context, swapSerial](void *resultOut) {
2453*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::throttleCPU");
2454*8975f5c5SAndroid Build Coastguard Worker                 ANGLE_UNUSED_VARIABLE(resultOut);
2455*8975f5c5SAndroid Build Coastguard Worker                 (void)context->getRenderer()->finishQueueSerial(context, swapSerial);
2456*8975f5c5SAndroid Build Coastguard Worker             });
2457*8975f5c5SAndroid Build Coastguard Worker     }
2458*8975f5c5SAndroid Build Coastguard Worker 
2459*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
2460*8975f5c5SAndroid Build Coastguard Worker }
2461*8975f5c5SAndroid Build Coastguard Worker 
cleanUpPresentHistory(vk::Context * context)2462*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::cleanUpPresentHistory(vk::Context *context)
2463*8975f5c5SAndroid Build Coastguard Worker {
2464*8975f5c5SAndroid Build Coastguard Worker     const VkDevice device = context->getDevice();
2465*8975f5c5SAndroid Build Coastguard Worker 
2466*8975f5c5SAndroid Build Coastguard Worker     while (!mPresentHistory.empty())
2467*8975f5c5SAndroid Build Coastguard Worker     {
2468*8975f5c5SAndroid Build Coastguard Worker         impl::ImagePresentOperation &presentOperation = mPresentHistory.front();
2469*8975f5c5SAndroid Build Coastguard Worker 
2470*8975f5c5SAndroid Build Coastguard Worker         // If there is no fence associated with the history, check queueSerial.
2471*8975f5c5SAndroid Build Coastguard Worker         if (!presentOperation.fence.valid())
2472*8975f5c5SAndroid Build Coastguard Worker         {
2473*8975f5c5SAndroid Build Coastguard Worker             // |kInvalidImageIndex| is only possible when |VkSwapchainPresentFenceInfoEXT| is used,
2474*8975f5c5SAndroid Build Coastguard Worker             // in which case |fence| is always valid.
2475*8975f5c5SAndroid Build Coastguard Worker             ASSERT(presentOperation.imageIndex != kInvalidImageIndex);
2476*8975f5c5SAndroid Build Coastguard Worker             // If queueSerial already assigned, check if it is finished.
2477*8975f5c5SAndroid Build Coastguard Worker             if (!presentOperation.queueSerial.valid() ||
2478*8975f5c5SAndroid Build Coastguard Worker                 !context->getRenderer()->hasQueueSerialFinished(presentOperation.queueSerial))
2479*8975f5c5SAndroid Build Coastguard Worker             {
2480*8975f5c5SAndroid Build Coastguard Worker                 // Not yet
2481*8975f5c5SAndroid Build Coastguard Worker                 break;
2482*8975f5c5SAndroid Build Coastguard Worker             }
2483*8975f5c5SAndroid Build Coastguard Worker         }
2484*8975f5c5SAndroid Build Coastguard Worker         // Otherwise check to see if the fence is signaled.
2485*8975f5c5SAndroid Build Coastguard Worker         else
2486*8975f5c5SAndroid Build Coastguard Worker         {
2487*8975f5c5SAndroid Build Coastguard Worker             VkResult result = presentOperation.fence.getStatus(device);
2488*8975f5c5SAndroid Build Coastguard Worker             if (result == VK_NOT_READY)
2489*8975f5c5SAndroid Build Coastguard Worker             {
2490*8975f5c5SAndroid Build Coastguard Worker                 // Not yet
2491*8975f5c5SAndroid Build Coastguard Worker                 break;
2492*8975f5c5SAndroid Build Coastguard Worker             }
2493*8975f5c5SAndroid Build Coastguard Worker 
2494*8975f5c5SAndroid Build Coastguard Worker             ANGLE_VK_TRY(context, result);
2495*8975f5c5SAndroid Build Coastguard Worker         }
2496*8975f5c5SAndroid Build Coastguard Worker 
2497*8975f5c5SAndroid Build Coastguard Worker         presentOperation.destroy(device, &mPresentFenceRecycler, &mPresentSemaphoreRecycler);
2498*8975f5c5SAndroid Build Coastguard Worker         mPresentHistory.pop_front();
2499*8975f5c5SAndroid Build Coastguard Worker     }
2500*8975f5c5SAndroid Build Coastguard Worker 
2501*8975f5c5SAndroid Build Coastguard Worker     // The present history can grow indefinitely if a present operation is done on an index that's
2502*8975f5c5SAndroid Build Coastguard Worker     // never presented in the future.  In that case, there's no queueSerial associated with that
2503*8975f5c5SAndroid Build Coastguard Worker     // present operation.  Move the offending entry to last, so the resources associated with the
2504*8975f5c5SAndroid Build Coastguard Worker     // rest of the present operations can be duly freed.
2505*8975f5c5SAndroid Build Coastguard Worker     if (mPresentHistory.size() > mSwapchainImages.size() * 2 &&
2506*8975f5c5SAndroid Build Coastguard Worker         !mPresentHistory.front().fence.valid() && !mPresentHistory.front().queueSerial.valid())
2507*8975f5c5SAndroid Build Coastguard Worker     {
2508*8975f5c5SAndroid Build Coastguard Worker         impl::ImagePresentOperation presentOperation = std::move(mPresentHistory.front());
2509*8975f5c5SAndroid Build Coastguard Worker         mPresentHistory.pop_front();
2510*8975f5c5SAndroid Build Coastguard Worker 
2511*8975f5c5SAndroid Build Coastguard Worker         // |kInvalidImageIndex| is only possible when |VkSwapchainPresentFenceInfoEXT| is used, in
2512*8975f5c5SAndroid Build Coastguard Worker         // which case |fence| is always valid.
2513*8975f5c5SAndroid Build Coastguard Worker         ASSERT(presentOperation.imageIndex != kInvalidImageIndex);
2514*8975f5c5SAndroid Build Coastguard Worker 
2515*8975f5c5SAndroid Build Coastguard Worker         // Move clean up data to the next (now first) present operation, if any.  Note that there
2516*8975f5c5SAndroid Build Coastguard Worker         // cannot be any clean up data on the rest of the present operations, because the first
2517*8975f5c5SAndroid Build Coastguard Worker         // present already gathers every old swapchain to clean up.
2518*8975f5c5SAndroid Build Coastguard Worker         ASSERT(!HasAnyOldSwapchains(mPresentHistory));
2519*8975f5c5SAndroid Build Coastguard Worker         mPresentHistory.front().oldSwapchains = std::move(presentOperation.oldSwapchains);
2520*8975f5c5SAndroid Build Coastguard Worker 
2521*8975f5c5SAndroid Build Coastguard Worker         // Put the present operation at the end of the queue so it's revisited after the rest of the
2522*8975f5c5SAndroid Build Coastguard Worker         // present operations are cleaned up.
2523*8975f5c5SAndroid Build Coastguard Worker         mPresentHistory.push_back(std::move(presentOperation));
2524*8975f5c5SAndroid Build Coastguard Worker     }
2525*8975f5c5SAndroid Build Coastguard Worker 
2526*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
2527*8975f5c5SAndroid Build Coastguard Worker }
2528*8975f5c5SAndroid Build Coastguard Worker 
cleanUpOldSwapchains(vk::Context * context)2529*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::cleanUpOldSwapchains(vk::Context *context)
2530*8975f5c5SAndroid Build Coastguard Worker {
2531*8975f5c5SAndroid Build Coastguard Worker     const VkDevice device = context->getDevice();
2532*8975f5c5SAndroid Build Coastguard Worker 
2533*8975f5c5SAndroid Build Coastguard Worker     ASSERT(context->getFeatures().supportsSwapchainMaintenance1.enabled);
2534*8975f5c5SAndroid Build Coastguard Worker 
2535*8975f5c5SAndroid Build Coastguard Worker     while (!mOldSwapchains.empty())
2536*8975f5c5SAndroid Build Coastguard Worker     {
2537*8975f5c5SAndroid Build Coastguard Worker         impl::SwapchainCleanupData &oldSwapchain = mOldSwapchains.front();
2538*8975f5c5SAndroid Build Coastguard Worker         VkResult result                          = oldSwapchain.getFencesStatus(device);
2539*8975f5c5SAndroid Build Coastguard Worker         if (result == VK_NOT_READY)
2540*8975f5c5SAndroid Build Coastguard Worker         {
2541*8975f5c5SAndroid Build Coastguard Worker             break;
2542*8975f5c5SAndroid Build Coastguard Worker         }
2543*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(context, result);
2544*8975f5c5SAndroid Build Coastguard Worker         oldSwapchain.destroy(device, &mPresentFenceRecycler, &mPresentSemaphoreRecycler);
2545*8975f5c5SAndroid Build Coastguard Worker         mOldSwapchains.pop_front();
2546*8975f5c5SAndroid Build Coastguard Worker     }
2547*8975f5c5SAndroid Build Coastguard Worker 
2548*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
2549*8975f5c5SAndroid Build Coastguard Worker }
2550*8975f5c5SAndroid Build Coastguard Worker 
swapImpl(const gl::Context * context,const EGLint * rects,EGLint n_rects,const void * pNextChain)2551*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context,
2552*8975f5c5SAndroid Build Coastguard Worker                                         const EGLint *rects,
2553*8975f5c5SAndroid Build Coastguard Worker                                         EGLint n_rects,
2554*8975f5c5SAndroid Build Coastguard Worker                                         const void *pNextChain)
2555*8975f5c5SAndroid Build Coastguard Worker {
2556*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::swapImpl");
2557*8975f5c5SAndroid Build Coastguard Worker 
2558*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
2559*8975f5c5SAndroid Build Coastguard Worker 
2560*8975f5c5SAndroid Build Coastguard Worker     // prepareSwap() has already called vkAcquireNextImageKHR if necessary, but its results need to
2561*8975f5c5SAndroid Build Coastguard Worker     // be processed now if not already.  doDeferredAcquireNextImage() will
2562*8975f5c5SAndroid Build Coastguard Worker     // automatically skip the prepareForAcquireNextSwapchainImage() and vkAcquireNextImageKHR calls
2563*8975f5c5SAndroid Build Coastguard Worker     // in that case.  The swapchain recreation path in
2564*8975f5c5SAndroid Build Coastguard Worker     // doDeferredAcquireNextImageWithUsableSwapchain() is acceptable because it only happens if
2565*8975f5c5SAndroid Build Coastguard Worker     // previous vkAcquireNextImageKHR failed.
2566*8975f5c5SAndroid Build Coastguard Worker     // Note: this method may be called from |onSharedPresentContextFlush|, therefore can't assume
2567*8975f5c5SAndroid Build Coastguard Worker     // that image is always acquired at this point.
2568*8975f5c5SAndroid Build Coastguard Worker     if (mAcquireOperation.state != impl::ImageAcquireState::Ready)
2569*8975f5c5SAndroid Build Coastguard Worker     {
2570*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(doDeferredAcquireNextImage(context, false));
2571*8975f5c5SAndroid Build Coastguard Worker     }
2572*8975f5c5SAndroid Build Coastguard Worker 
2573*8975f5c5SAndroid Build Coastguard Worker     bool presentOutOfDate = false;
2574*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(present(contextVk, rects, n_rects, pNextChain, &presentOutOfDate));
2575*8975f5c5SAndroid Build Coastguard Worker 
2576*8975f5c5SAndroid Build Coastguard Worker     // Defer acquiring the next swapchain image regardless if the swapchain is out-of-date or not.
2577*8975f5c5SAndroid Build Coastguard Worker     deferAcquireNextImage();
2578*8975f5c5SAndroid Build Coastguard Worker 
2579*8975f5c5SAndroid Build Coastguard Worker     if (presentOutOfDate)
2580*8975f5c5SAndroid Build Coastguard Worker     {
2581*8975f5c5SAndroid Build Coastguard Worker         // Immediately try to acquire the next image, which will recognize the out-of-date
2582*8975f5c5SAndroid Build Coastguard Worker         // swapchain (potentially because of a rotation change), and recreate it.
2583*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRACE_EVENT_AND_MARKER(contextVk, "Out-of-Date Swapbuffer");
2584*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(doDeferredAcquireNextImage(context, presentOutOfDate));
2585*8975f5c5SAndroid Build Coastguard Worker     }
2586*8975f5c5SAndroid Build Coastguard Worker 
2587*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
2588*8975f5c5SAndroid Build Coastguard Worker }
2589*8975f5c5SAndroid Build Coastguard Worker 
onSharedPresentContextFlush(const gl::Context * context)2590*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::onSharedPresentContextFlush(const gl::Context *context)
2591*8975f5c5SAndroid Build Coastguard Worker {
2592*8975f5c5SAndroid Build Coastguard Worker     return swapImpl(context, nullptr, 0, nullptr);
2593*8975f5c5SAndroid Build Coastguard Worker }
2594*8975f5c5SAndroid Build Coastguard Worker 
hasStagedUpdates() const2595*8975f5c5SAndroid Build Coastguard Worker bool WindowSurfaceVk::hasStagedUpdates() const
2596*8975f5c5SAndroid Build Coastguard Worker {
2597*8975f5c5SAndroid Build Coastguard Worker     return mAcquireOperation.state == impl::ImageAcquireState::Ready &&
2598*8975f5c5SAndroid Build Coastguard Worker            mSwapchainImages[mCurrentSwapchainImageIndex].image->hasStagedUpdatesInAllocatedLevels();
2599*8975f5c5SAndroid Build Coastguard Worker }
2600*8975f5c5SAndroid Build Coastguard Worker 
setTimestampsEnabled(bool enabled)2601*8975f5c5SAndroid Build Coastguard Worker void WindowSurfaceVk::setTimestampsEnabled(bool enabled)
2602*8975f5c5SAndroid Build Coastguard Worker {
2603*8975f5c5SAndroid Build Coastguard Worker     // The frontend has already cached the state, nothing to do.
2604*8975f5c5SAndroid Build Coastguard Worker     ASSERT(IsAndroid());
2605*8975f5c5SAndroid Build Coastguard Worker }
2606*8975f5c5SAndroid Build Coastguard Worker 
deferAcquireNextImage()2607*8975f5c5SAndroid Build Coastguard Worker void WindowSurfaceVk::deferAcquireNextImage()
2608*8975f5c5SAndroid Build Coastguard Worker {
2609*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state == impl::ImageAcquireState::Ready);
2610*8975f5c5SAndroid Build Coastguard Worker 
2611*8975f5c5SAndroid Build Coastguard Worker     mAcquireOperation.state = impl::ImageAcquireState::NeedToAcquire;
2612*8975f5c5SAndroid Build Coastguard Worker 
2613*8975f5c5SAndroid Build Coastguard Worker     // Set gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 via subject-observer message-passing
2614*8975f5c5SAndroid Build Coastguard Worker     // to the front-end Surface, Framebuffer, and Context classes.  The DIRTY_BIT_COLOR_ATTACHMENT_0
2615*8975f5c5SAndroid Build Coastguard Worker     // is processed before all other dirty bits.  However, since the attachments of the default
2616*8975f5c5SAndroid Build Coastguard Worker     // framebuffer cannot change, this bit will be processed before all others.  It will cause
2617*8975f5c5SAndroid Build Coastguard Worker     // WindowSurfaceVk::getAttachmentRenderTarget() to be called (which will acquire the next image)
2618*8975f5c5SAndroid Build Coastguard Worker     // before any RenderTargetVk accesses.  The processing of other dirty bits as well as other
2619*8975f5c5SAndroid Build Coastguard Worker     // setup for draws and reads will then access a properly-updated RenderTargetVk.
2620*8975f5c5SAndroid Build Coastguard Worker     onStateChange(angle::SubjectMessage::SwapchainImageChanged);
2621*8975f5c5SAndroid Build Coastguard Worker }
2622*8975f5c5SAndroid Build Coastguard Worker 
prepareForAcquireNextSwapchainImage(const gl::Context * context,bool forceSwapchainRecreate)2623*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::prepareForAcquireNextSwapchainImage(const gl::Context *context,
2624*8975f5c5SAndroid Build Coastguard Worker                                                                    bool forceSwapchainRecreate)
2625*8975f5c5SAndroid Build Coastguard Worker {
2626*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state == impl::ImageAcquireState::NeedToAcquire);
2627*8975f5c5SAndroid Build Coastguard Worker 
2628*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk   = vk::GetImpl(context);
2629*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
2630*8975f5c5SAndroid Build Coastguard Worker 
2631*8975f5c5SAndroid Build Coastguard Worker     // TODO(jmadill): Expose in CommandQueueInterface, or manage in CommandQueue. b/172704839
2632*8975f5c5SAndroid Build Coastguard Worker     if (renderer->isAsyncCommandQueueEnabled())
2633*8975f5c5SAndroid Build Coastguard Worker     {
2634*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(renderer->waitForPresentToBeSubmitted(&mSwapchainStatus));
2635*8975f5c5SAndroid Build Coastguard Worker         VkResult result = mSwapchainStatus.lastPresentResult;
2636*8975f5c5SAndroid Build Coastguard Worker 
2637*8975f5c5SAndroid Build Coastguard Worker         // Now that we have the result from the last present need to determine if it's out of date
2638*8975f5c5SAndroid Build Coastguard Worker         // or not.
2639*8975f5c5SAndroid Build Coastguard Worker         bool presentOutOfDate = false;
2640*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(computePresentOutOfDate(contextVk, result, &presentOutOfDate));
2641*8975f5c5SAndroid Build Coastguard Worker         forceSwapchainRecreate = forceSwapchainRecreate || presentOutOfDate;
2642*8975f5c5SAndroid Build Coastguard Worker     }
2643*8975f5c5SAndroid Build Coastguard Worker 
2644*8975f5c5SAndroid Build Coastguard Worker     return checkForOutOfDateSwapchain(contextVk, forceSwapchainRecreate);
2645*8975f5c5SAndroid Build Coastguard Worker }
2646*8975f5c5SAndroid Build Coastguard Worker 
doDeferredAcquireNextImage(const gl::Context * context,bool forceSwapchainRecreate)2647*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::doDeferredAcquireNextImage(const gl::Context *context,
2648*8975f5c5SAndroid Build Coastguard Worker                                                           bool forceSwapchainRecreate)
2649*8975f5c5SAndroid Build Coastguard Worker {
2650*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state == impl::ImageAcquireState::NeedToAcquire ||
2651*8975f5c5SAndroid Build Coastguard Worker            (mAcquireOperation.state == impl::ImageAcquireState::NeedToProcessResult &&
2652*8975f5c5SAndroid Build Coastguard Worker             !forceSwapchainRecreate));
2653*8975f5c5SAndroid Build Coastguard Worker     // prepareForAcquireNextSwapchainImage() may recreate Swapchain even if there is an image
2654*8975f5c5SAndroid Build Coastguard Worker     // acquired. Avoid this, by skipping the prepare call.
2655*8975f5c5SAndroid Build Coastguard Worker     if (mAcquireOperation.state == impl::ImageAcquireState::NeedToAcquire)
2656*8975f5c5SAndroid Build Coastguard Worker     {
2657*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(prepareForAcquireNextSwapchainImage(context, forceSwapchainRecreate));
2658*8975f5c5SAndroid Build Coastguard Worker     }
2659*8975f5c5SAndroid Build Coastguard Worker     return doDeferredAcquireNextImageWithUsableSwapchain(context);
2660*8975f5c5SAndroid Build Coastguard Worker }
2661*8975f5c5SAndroid Build Coastguard Worker 
doDeferredAcquireNextImageWithUsableSwapchain(const gl::Context * context)2662*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::doDeferredAcquireNextImageWithUsableSwapchain(
2663*8975f5c5SAndroid Build Coastguard Worker     const gl::Context *context)
2664*8975f5c5SAndroid Build Coastguard Worker {
2665*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state != impl::ImageAcquireState::Ready);
2666*8975f5c5SAndroid Build Coastguard Worker 
2667*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
2668*8975f5c5SAndroid Build Coastguard Worker 
2669*8975f5c5SAndroid Build Coastguard Worker     {
2670*8975f5c5SAndroid Build Coastguard Worker         // Note: TRACE_EVENT0 is put here instead of inside the function to workaround this issue:
2671*8975f5c5SAndroid Build Coastguard Worker         // http://anglebug.com/42261625
2672*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRACE_EVENT0("gpu.angle", "acquireNextSwapchainImage");
2673*8975f5c5SAndroid Build Coastguard Worker 
2674*8975f5c5SAndroid Build Coastguard Worker         // Get the next available swapchain image.
2675*8975f5c5SAndroid Build Coastguard Worker         VkResult result = acquireNextSwapchainImage(contextVk);
2676*8975f5c5SAndroid Build Coastguard Worker 
2677*8975f5c5SAndroid Build Coastguard Worker         ASSERT(result != VK_SUBOPTIMAL_KHR);
2678*8975f5c5SAndroid Build Coastguard Worker         // If OUT_OF_DATE is returned, it's ok, we just need to recreate the swapchain before
2679*8975f5c5SAndroid Build Coastguard Worker         // continuing.
2680*8975f5c5SAndroid Build Coastguard Worker         if (ANGLE_UNLIKELY(result == VK_ERROR_OUT_OF_DATE_KHR))
2681*8975f5c5SAndroid Build Coastguard Worker         {
2682*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(checkForOutOfDateSwapchain(contextVk, true));
2683*8975f5c5SAndroid Build Coastguard Worker             // Try one more time and bail if we fail
2684*8975f5c5SAndroid Build Coastguard Worker             result = acquireNextSwapchainImage(contextVk);
2685*8975f5c5SAndroid Build Coastguard Worker         }
2686*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRY(contextVk, result);
2687*8975f5c5SAndroid Build Coastguard Worker     }
2688*8975f5c5SAndroid Build Coastguard Worker 
2689*8975f5c5SAndroid Build Coastguard Worker     // Auto-invalidate the contents of the surface.  According to EGL, on swap:
2690*8975f5c5SAndroid Build Coastguard Worker     //
2691*8975f5c5SAndroid Build Coastguard Worker     // - When EGL_BUFFER_DESTROYED is specified, the contents of the color image can be
2692*8975f5c5SAndroid Build Coastguard Worker     //   invalidated.
2693*8975f5c5SAndroid Build Coastguard Worker     //    * This is disabled when buffer age has been queried to work around a dEQP test bug.
2694*8975f5c5SAndroid Build Coastguard Worker     // - Depth/Stencil can always be invalidated
2695*8975f5c5SAndroid Build Coastguard Worker     //
2696*8975f5c5SAndroid Build Coastguard Worker     // In all cases, when in shared present mode, swap is implicit and the swap behavior
2697*8975f5c5SAndroid Build Coastguard Worker     // doesn't apply so no invalidation is done.
2698*8975f5c5SAndroid Build Coastguard Worker     if (!isSharedPresentMode())
2699*8975f5c5SAndroid Build Coastguard Worker     {
2700*8975f5c5SAndroid Build Coastguard Worker         if (mState.swapBehavior == EGL_BUFFER_DESTROYED && mBufferAgeQueryFrameNumber == 0)
2701*8975f5c5SAndroid Build Coastguard Worker         {
2702*8975f5c5SAndroid Build Coastguard Worker             mSwapchainImages[mCurrentSwapchainImageIndex].image->invalidateSubresourceContent(
2703*8975f5c5SAndroid Build Coastguard Worker                 contextVk, gl::LevelIndex(0), 0, 1, nullptr);
2704*8975f5c5SAndroid Build Coastguard Worker             if (mColorImageMS.valid())
2705*8975f5c5SAndroid Build Coastguard Worker             {
2706*8975f5c5SAndroid Build Coastguard Worker                 mColorImageMS.invalidateSubresourceContent(contextVk, gl::LevelIndex(0), 0, 1,
2707*8975f5c5SAndroid Build Coastguard Worker                                                            nullptr);
2708*8975f5c5SAndroid Build Coastguard Worker             }
2709*8975f5c5SAndroid Build Coastguard Worker         }
2710*8975f5c5SAndroid Build Coastguard Worker         if (mDepthStencilImage.valid())
2711*8975f5c5SAndroid Build Coastguard Worker         {
2712*8975f5c5SAndroid Build Coastguard Worker             mDepthStencilImage.invalidateSubresourceContent(contextVk, gl::LevelIndex(0), 0, 1,
2713*8975f5c5SAndroid Build Coastguard Worker                                                             nullptr);
2714*8975f5c5SAndroid Build Coastguard Worker             mDepthStencilImage.invalidateSubresourceStencilContent(contextVk, gl::LevelIndex(0), 0,
2715*8975f5c5SAndroid Build Coastguard Worker                                                                    1, nullptr);
2716*8975f5c5SAndroid Build Coastguard Worker         }
2717*8975f5c5SAndroid Build Coastguard Worker     }
2718*8975f5c5SAndroid Build Coastguard Worker 
2719*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
2720*8975f5c5SAndroid Build Coastguard Worker }
2721*8975f5c5SAndroid Build Coastguard Worker 
skipAcquireNextSwapchainImageForSharedPresentMode() const2722*8975f5c5SAndroid Build Coastguard Worker bool WindowSurfaceVk::skipAcquireNextSwapchainImageForSharedPresentMode() const
2723*8975f5c5SAndroid Build Coastguard Worker {
2724*8975f5c5SAndroid Build Coastguard Worker     if (isSharedPresentMode())
2725*8975f5c5SAndroid Build Coastguard Worker     {
2726*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mSwapchainImages.size());
2727*8975f5c5SAndroid Build Coastguard Worker         const SwapchainImage &image = mSwapchainImages[0];
2728*8975f5c5SAndroid Build Coastguard Worker         ASSERT(image.image->valid());
2729*8975f5c5SAndroid Build Coastguard Worker         if (image.image->getCurrentImageLayout() == vk::ImageLayout::SharedPresent)
2730*8975f5c5SAndroid Build Coastguard Worker         {
2731*8975f5c5SAndroid Build Coastguard Worker             return true;
2732*8975f5c5SAndroid Build Coastguard Worker         }
2733*8975f5c5SAndroid Build Coastguard Worker     }
2734*8975f5c5SAndroid Build Coastguard Worker 
2735*8975f5c5SAndroid Build Coastguard Worker     return false;
2736*8975f5c5SAndroid Build Coastguard Worker }
2737*8975f5c5SAndroid Build Coastguard Worker 
2738*8975f5c5SAndroid Build Coastguard Worker // This method will either return VK_SUCCESS or VK_ERROR_*.  Thus, it is appropriate to ASSERT that
2739*8975f5c5SAndroid Build Coastguard Worker // the return value won't be VK_SUBOPTIMAL_KHR.
acquireNextSwapchainImage(vk::Context * context)2740*8975f5c5SAndroid Build Coastguard Worker VkResult WindowSurfaceVk::acquireNextSwapchainImage(vk::Context *context)
2741*8975f5c5SAndroid Build Coastguard Worker {
2742*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state != impl::ImageAcquireState::Ready);
2743*8975f5c5SAndroid Build Coastguard Worker 
2744*8975f5c5SAndroid Build Coastguard Worker     VkDevice device = context->getDevice();
2745*8975f5c5SAndroid Build Coastguard Worker 
2746*8975f5c5SAndroid Build Coastguard Worker     if (skipAcquireNextSwapchainImageForSharedPresentMode())
2747*8975f5c5SAndroid Build Coastguard Worker     {
2748*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mAcquireOperation.state == impl::ImageAcquireState::NeedToAcquire);
2749*8975f5c5SAndroid Build Coastguard Worker         ASSERT(mSwapchain != VK_NULL_HANDLE);
2750*8975f5c5SAndroid Build Coastguard Worker         // This will check for OUT_OF_DATE when in single image mode. and prevent
2751*8975f5c5SAndroid Build Coastguard Worker         // re-AcquireNextImage.
2752*8975f5c5SAndroid Build Coastguard Worker         VkResult result = vkGetSwapchainStatusKHR(device, mSwapchain);
2753*8975f5c5SAndroid Build Coastguard Worker         if (ANGLE_UNLIKELY(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR))
2754*8975f5c5SAndroid Build Coastguard Worker         {
2755*8975f5c5SAndroid Build Coastguard Worker             return result;
2756*8975f5c5SAndroid Build Coastguard Worker         }
2757*8975f5c5SAndroid Build Coastguard Worker         // Note that an acquire and result processing is no longer needed.
2758*8975f5c5SAndroid Build Coastguard Worker         mAcquireOperation.state = impl::ImageAcquireState::Ready;
2759*8975f5c5SAndroid Build Coastguard Worker         return VK_SUCCESS;
2760*8975f5c5SAndroid Build Coastguard Worker     }
2761*8975f5c5SAndroid Build Coastguard Worker 
2762*8975f5c5SAndroid Build Coastguard Worker     // If calling vkAcquireNextImageKHR is necessary, do so first.
2763*8975f5c5SAndroid Build Coastguard Worker     if (mAcquireOperation.state == impl::ImageAcquireState::NeedToAcquire)
2764*8975f5c5SAndroid Build Coastguard Worker     {
2765*8975f5c5SAndroid Build Coastguard Worker         AcquireNextImageUnlocked(context->getDevice(), mSwapchain, &mAcquireOperation);
2766*8975f5c5SAndroid Build Coastguard Worker     }
2767*8975f5c5SAndroid Build Coastguard Worker 
2768*8975f5c5SAndroid Build Coastguard Worker     // After the above call result is alway ready for processing.
2769*8975f5c5SAndroid Build Coastguard Worker     return postProcessUnlockedAcquire(context);
2770*8975f5c5SAndroid Build Coastguard Worker }
2771*8975f5c5SAndroid Build Coastguard Worker 
postProcessUnlockedAcquire(vk::Context * context)2772*8975f5c5SAndroid Build Coastguard Worker VkResult WindowSurfaceVk::postProcessUnlockedAcquire(vk::Context *context)
2773*8975f5c5SAndroid Build Coastguard Worker {
2774*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state == impl::ImageAcquireState::NeedToProcessResult);
2775*8975f5c5SAndroid Build Coastguard Worker 
2776*8975f5c5SAndroid Build Coastguard Worker     const VkResult result = mAcquireOperation.unlockedAcquireResult.result;
2777*8975f5c5SAndroid Build Coastguard Worker 
2778*8975f5c5SAndroid Build Coastguard Worker     // VK_SUBOPTIMAL_KHR is ok since we still have an Image that can be presented successfully
2779*8975f5c5SAndroid Build Coastguard Worker     if (ANGLE_UNLIKELY(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR))
2780*8975f5c5SAndroid Build Coastguard Worker     {
2781*8975f5c5SAndroid Build Coastguard Worker         // Skip processing the result on failure.  Acquire operation will be allowed again after
2782*8975f5c5SAndroid Build Coastguard Worker         // possible swapchain recreation caused by this failure.  In case if there will be no
2783*8975f5c5SAndroid Build Coastguard Worker         // recreation, error will be returned to an app and result will be processed again in the
2784*8975f5c5SAndroid Build Coastguard Worker         // possible next EGL/GLES call (where swapchain will be recreated).
2785*8975f5c5SAndroid Build Coastguard Worker         return result;
2786*8975f5c5SAndroid Build Coastguard Worker     }
2787*8975f5c5SAndroid Build Coastguard Worker 
2788*8975f5c5SAndroid Build Coastguard Worker     // Swapchain must be valid if acquire result is success (but may be NULL if error).
2789*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mSwapchain != VK_NULL_HANDLE);
2790*8975f5c5SAndroid Build Coastguard Worker 
2791*8975f5c5SAndroid Build Coastguard Worker     mCurrentSwapchainImageIndex = mAcquireOperation.unlockedAcquireResult.imageIndex;
2792*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!isSharedPresentMode() || mCurrentSwapchainImageIndex == 0);
2793*8975f5c5SAndroid Build Coastguard Worker 
2794*8975f5c5SAndroid Build Coastguard Worker     SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];
2795*8975f5c5SAndroid Build Coastguard Worker 
2796*8975f5c5SAndroid Build Coastguard Worker     const VkSemaphore acquireImageSemaphore =
2797*8975f5c5SAndroid Build Coastguard Worker         mAcquireOperation.unlockedAcquireResult.acquireSemaphore;
2798*8975f5c5SAndroid Build Coastguard Worker 
2799*8975f5c5SAndroid Build Coastguard Worker     // Let Image keep the ani semaphore so that it can add to the semaphore wait list if it is
2800*8975f5c5SAndroid Build Coastguard Worker     // being used. Image's barrier code will move the semaphore into CommandBufferHelper object
2801*8975f5c5SAndroid Build Coastguard Worker     // and then added to waitSemaphores when commands gets flushed and submitted. Since all
2802*8975f5c5SAndroid Build Coastguard Worker     // image use after ANI must go through barrier code, this approach is very robust. And since
2803*8975f5c5SAndroid Build Coastguard Worker     // this is tracked bny ImageHelper object, it also ensures it only added to command that
2804*8975f5c5SAndroid Build Coastguard Worker     // image is actually being referenced, thus avoid potential bugs.
2805*8975f5c5SAndroid Build Coastguard Worker     image.image->setAcquireNextImageSemaphore(acquireImageSemaphore);
2806*8975f5c5SAndroid Build Coastguard Worker 
2807*8975f5c5SAndroid Build Coastguard Worker     // Single Image Mode
2808*8975f5c5SAndroid Build Coastguard Worker     if (isSharedPresentMode())
2809*8975f5c5SAndroid Build Coastguard Worker     {
2810*8975f5c5SAndroid Build Coastguard Worker         ASSERT(image.image->valid() &&
2811*8975f5c5SAndroid Build Coastguard Worker                image.image->getCurrentImageLayout() != vk::ImageLayout::SharedPresent);
2812*8975f5c5SAndroid Build Coastguard Worker         rx::vk::Renderer *renderer = context->getRenderer();
2813*8975f5c5SAndroid Build Coastguard Worker         rx::vk::PrimaryCommandBuffer primaryCommandBuffer;
2814*8975f5c5SAndroid Build Coastguard Worker         auto protectionType = vk::ConvertProtectionBoolToType(mState.hasProtectedContent());
2815*8975f5c5SAndroid Build Coastguard Worker         if (renderer->getCommandBufferOneOff(context, protectionType, &primaryCommandBuffer) ==
2816*8975f5c5SAndroid Build Coastguard Worker             angle::Result::Continue)
2817*8975f5c5SAndroid Build Coastguard Worker         {
2818*8975f5c5SAndroid Build Coastguard Worker             VkSemaphore semaphore;
2819*8975f5c5SAndroid Build Coastguard Worker             // Note return errors is early exit may leave new Image and Swapchain in unknown state.
2820*8975f5c5SAndroid Build Coastguard Worker             image.image->recordWriteBarrierOneOff(context, vk::ImageLayout::SharedPresent,
2821*8975f5c5SAndroid Build Coastguard Worker                                                   &primaryCommandBuffer, &semaphore);
2822*8975f5c5SAndroid Build Coastguard Worker             ASSERT(semaphore == acquireImageSemaphore);
2823*8975f5c5SAndroid Build Coastguard Worker             if (primaryCommandBuffer.end() != VK_SUCCESS)
2824*8975f5c5SAndroid Build Coastguard Worker             {
2825*8975f5c5SAndroid Build Coastguard Worker                 mDesiredSwapchainPresentMode = vk::PresentMode::FifoKHR;
2826*8975f5c5SAndroid Build Coastguard Worker                 return VK_ERROR_OUT_OF_DATE_KHR;
2827*8975f5c5SAndroid Build Coastguard Worker             }
2828*8975f5c5SAndroid Build Coastguard Worker             QueueSerial queueSerial;
2829*8975f5c5SAndroid Build Coastguard Worker             if (renderer->queueSubmitOneOff(context, std::move(primaryCommandBuffer),
2830*8975f5c5SAndroid Build Coastguard Worker                                             protectionType, egl::ContextPriority::Medium, semaphore,
2831*8975f5c5SAndroid Build Coastguard Worker                                             VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
2832*8975f5c5SAndroid Build Coastguard Worker                                             vk::SubmitPolicy::EnsureSubmitted,
2833*8975f5c5SAndroid Build Coastguard Worker                                             &queueSerial) != angle::Result::Continue)
2834*8975f5c5SAndroid Build Coastguard Worker             {
2835*8975f5c5SAndroid Build Coastguard Worker                 mDesiredSwapchainPresentMode = vk::PresentMode::FifoKHR;
2836*8975f5c5SAndroid Build Coastguard Worker                 return VK_ERROR_OUT_OF_DATE_KHR;
2837*8975f5c5SAndroid Build Coastguard Worker             }
2838*8975f5c5SAndroid Build Coastguard Worker             mUse.setQueueSerial(queueSerial);
2839*8975f5c5SAndroid Build Coastguard Worker         }
2840*8975f5c5SAndroid Build Coastguard Worker     }
2841*8975f5c5SAndroid Build Coastguard Worker 
2842*8975f5c5SAndroid Build Coastguard Worker     // The semaphore will be waited on in the next flush.
2843*8975f5c5SAndroid Build Coastguard Worker     mAcquireOperation.unlockedAcquireData.acquireImageSemaphores.next();
2844*8975f5c5SAndroid Build Coastguard Worker 
2845*8975f5c5SAndroid Build Coastguard Worker     // Update RenderTarget pointers to this swapchain image if not multisampling.  Note: a possible
2846*8975f5c5SAndroid Build Coastguard Worker     // optimization is to defer the |vkAcquireNextImageKHR| call itself to |present()| if
2847*8975f5c5SAndroid Build Coastguard Worker     // multisampling, as the swapchain image is essentially unused until then.
2848*8975f5c5SAndroid Build Coastguard Worker     if (!mColorImageMS.valid())
2849*8975f5c5SAndroid Build Coastguard Worker     {
2850*8975f5c5SAndroid Build Coastguard Worker         mColorRenderTarget.updateSwapchainImage(image.image.get(), &image.imageViews, nullptr,
2851*8975f5c5SAndroid Build Coastguard Worker                                                 nullptr);
2852*8975f5c5SAndroid Build Coastguard Worker     }
2853*8975f5c5SAndroid Build Coastguard Worker 
2854*8975f5c5SAndroid Build Coastguard Worker     // Notify the owning framebuffer there may be staged updates.
2855*8975f5c5SAndroid Build Coastguard Worker     if (image.image->hasStagedUpdatesInAllocatedLevels())
2856*8975f5c5SAndroid Build Coastguard Worker     {
2857*8975f5c5SAndroid Build Coastguard Worker         onStateChange(angle::SubjectMessage::SwapchainImageChanged);
2858*8975f5c5SAndroid Build Coastguard Worker     }
2859*8975f5c5SAndroid Build Coastguard Worker 
2860*8975f5c5SAndroid Build Coastguard Worker     // Note that an acquire and result processing is no longer needed.
2861*8975f5c5SAndroid Build Coastguard Worker     mAcquireOperation.state = impl::ImageAcquireState::Ready;
2862*8975f5c5SAndroid Build Coastguard Worker 
2863*8975f5c5SAndroid Build Coastguard Worker     return VK_SUCCESS;
2864*8975f5c5SAndroid Build Coastguard Worker }
2865*8975f5c5SAndroid Build Coastguard Worker 
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)2866*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::postSubBuffer(const gl::Context *context,
2867*8975f5c5SAndroid Build Coastguard Worker                                           EGLint x,
2868*8975f5c5SAndroid Build Coastguard Worker                                           EGLint y,
2869*8975f5c5SAndroid Build Coastguard Worker                                           EGLint width,
2870*8975f5c5SAndroid Build Coastguard Worker                                           EGLint height)
2871*8975f5c5SAndroid Build Coastguard Worker {
2872*8975f5c5SAndroid Build Coastguard Worker     // TODO(jmadill)
2873*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
2874*8975f5c5SAndroid Build Coastguard Worker }
2875*8975f5c5SAndroid Build Coastguard Worker 
querySurfacePointerANGLE(EGLint attribute,void ** value)2876*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::querySurfacePointerANGLE(EGLint attribute, void **value)
2877*8975f5c5SAndroid Build Coastguard Worker {
2878*8975f5c5SAndroid Build Coastguard Worker     UNREACHABLE();
2879*8975f5c5SAndroid Build Coastguard Worker     return egl::EglBadCurrentSurface();
2880*8975f5c5SAndroid Build Coastguard Worker }
2881*8975f5c5SAndroid Build Coastguard Worker 
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)2882*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::bindTexImage(const gl::Context *context,
2883*8975f5c5SAndroid Build Coastguard Worker                                          gl::Texture *texture,
2884*8975f5c5SAndroid Build Coastguard Worker                                          EGLint buffer)
2885*8975f5c5SAndroid Build Coastguard Worker {
2886*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
2887*8975f5c5SAndroid Build Coastguard Worker }
2888*8975f5c5SAndroid Build Coastguard Worker 
releaseTexImage(const gl::Context * context,EGLint buffer)2889*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::releaseTexImage(const gl::Context *context, EGLint buffer)
2890*8975f5c5SAndroid Build Coastguard Worker {
2891*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
2892*8975f5c5SAndroid Build Coastguard Worker }
2893*8975f5c5SAndroid Build Coastguard Worker 
getSyncValues(EGLuint64KHR *,EGLuint64KHR *,EGLuint64KHR *)2894*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::getSyncValues(EGLuint64KHR * /*ust*/,
2895*8975f5c5SAndroid Build Coastguard Worker                                           EGLuint64KHR * /*msc*/,
2896*8975f5c5SAndroid Build Coastguard Worker                                           EGLuint64KHR * /*sbc*/)
2897*8975f5c5SAndroid Build Coastguard Worker {
2898*8975f5c5SAndroid Build Coastguard Worker     UNIMPLEMENTED();
2899*8975f5c5SAndroid Build Coastguard Worker     return egl::EglBadAccess();
2900*8975f5c5SAndroid Build Coastguard Worker }
2901*8975f5c5SAndroid Build Coastguard Worker 
getMscRate(EGLint *,EGLint *)2902*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::getMscRate(EGLint * /*numerator*/, EGLint * /*denominator*/)
2903*8975f5c5SAndroid Build Coastguard Worker {
2904*8975f5c5SAndroid Build Coastguard Worker     UNIMPLEMENTED();
2905*8975f5c5SAndroid Build Coastguard Worker     return egl::EglBadAccess();
2906*8975f5c5SAndroid Build Coastguard Worker }
2907*8975f5c5SAndroid Build Coastguard Worker 
setSwapInterval(DisplayVk * displayVk,EGLint interval)2908*8975f5c5SAndroid Build Coastguard Worker void WindowSurfaceVk::setSwapInterval(DisplayVk *displayVk, EGLint interval)
2909*8975f5c5SAndroid Build Coastguard Worker {
2910*8975f5c5SAndroid Build Coastguard Worker     // Don't let setSwapInterval change presentation mode if using SHARED present.
2911*8975f5c5SAndroid Build Coastguard Worker     if (isSharedPresentMode())
2912*8975f5c5SAndroid Build Coastguard Worker     {
2913*8975f5c5SAndroid Build Coastguard Worker         return;
2914*8975f5c5SAndroid Build Coastguard Worker     }
2915*8975f5c5SAndroid Build Coastguard Worker 
2916*8975f5c5SAndroid Build Coastguard Worker     const EGLint minSwapInterval = mState.config->minSwapInterval;
2917*8975f5c5SAndroid Build Coastguard Worker     const EGLint maxSwapInterval = mState.config->maxSwapInterval;
2918*8975f5c5SAndroid Build Coastguard Worker     ASSERT(minSwapInterval == 0 || minSwapInterval == 1);
2919*8975f5c5SAndroid Build Coastguard Worker     ASSERT(maxSwapInterval == 0 || maxSwapInterval == 1);
2920*8975f5c5SAndroid Build Coastguard Worker 
2921*8975f5c5SAndroid Build Coastguard Worker     interval = gl::clamp(interval, minSwapInterval, maxSwapInterval);
2922*8975f5c5SAndroid Build Coastguard Worker 
2923*8975f5c5SAndroid Build Coastguard Worker     mDesiredSwapchainPresentMode = GetDesiredPresentMode(mPresentModes, interval);
2924*8975f5c5SAndroid Build Coastguard Worker 
2925*8975f5c5SAndroid Build Coastguard Worker     // minImageCount may vary based on the Present Mode
2926*8975f5c5SAndroid Build Coastguard Worker     mMinImageCount =
2927*8975f5c5SAndroid Build Coastguard Worker         GetMinImageCount(displayVk->getRenderer(), mSurfaceCaps, mDesiredSwapchainPresentMode);
2928*8975f5c5SAndroid Build Coastguard Worker 
2929*8975f5c5SAndroid Build Coastguard Worker     // On the next swap, if the desired present mode is different from the current one, the
2930*8975f5c5SAndroid Build Coastguard Worker     // swapchain will be recreated.
2931*8975f5c5SAndroid Build Coastguard Worker }
2932*8975f5c5SAndroid Build Coastguard Worker 
setSwapInterval(const egl::Display * display,EGLint interval)2933*8975f5c5SAndroid Build Coastguard Worker void WindowSurfaceVk::setSwapInterval(const egl::Display *display, EGLint interval)
2934*8975f5c5SAndroid Build Coastguard Worker {
2935*8975f5c5SAndroid Build Coastguard Worker     DisplayVk *displayVk = vk::GetImpl(display);
2936*8975f5c5SAndroid Build Coastguard Worker     setSwapInterval(displayVk, interval);
2937*8975f5c5SAndroid Build Coastguard Worker }
2938*8975f5c5SAndroid Build Coastguard Worker 
getUserWidth(const egl::Display * display,EGLint * value) const2939*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::getUserWidth(const egl::Display *display, EGLint *value) const
2940*8975f5c5SAndroid Build Coastguard Worker {
2941*8975f5c5SAndroid Build Coastguard Worker     DisplayVk *displayVk = vk::GetImpl(display);
2942*8975f5c5SAndroid Build Coastguard Worker 
2943*8975f5c5SAndroid Build Coastguard Worker     if (mSurfaceCaps.currentExtent.width == kSurfaceSizedBySwapchain)
2944*8975f5c5SAndroid Build Coastguard Worker     {
2945*8975f5c5SAndroid Build Coastguard Worker         // Surface has no intrinsic size; use current size.
2946*8975f5c5SAndroid Build Coastguard Worker         *value = getWidth();
2947*8975f5c5SAndroid Build Coastguard Worker         return egl::NoError();
2948*8975f5c5SAndroid Build Coastguard Worker     }
2949*8975f5c5SAndroid Build Coastguard Worker 
2950*8975f5c5SAndroid Build Coastguard Worker     VkSurfaceCapabilitiesKHR surfaceCaps;
2951*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = getUserExtentsImpl(displayVk, &surfaceCaps);
2952*8975f5c5SAndroid Build Coastguard Worker     if (result == angle::Result::Continue)
2953*8975f5c5SAndroid Build Coastguard Worker     {
2954*8975f5c5SAndroid Build Coastguard Worker         // The EGL spec states that value is not written if there is an error
2955*8975f5c5SAndroid Build Coastguard Worker         ASSERT(surfaceCaps.currentExtent.width != kSurfaceSizedBySwapchain);
2956*8975f5c5SAndroid Build Coastguard Worker         *value = static_cast<EGLint>(surfaceCaps.currentExtent.width);
2957*8975f5c5SAndroid Build Coastguard Worker     }
2958*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(result, EGL_BAD_SURFACE);
2959*8975f5c5SAndroid Build Coastguard Worker }
2960*8975f5c5SAndroid Build Coastguard Worker 
getUserHeight(const egl::Display * display,EGLint * value) const2961*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::getUserHeight(const egl::Display *display, EGLint *value) const
2962*8975f5c5SAndroid Build Coastguard Worker {
2963*8975f5c5SAndroid Build Coastguard Worker     DisplayVk *displayVk = vk::GetImpl(display);
2964*8975f5c5SAndroid Build Coastguard Worker 
2965*8975f5c5SAndroid Build Coastguard Worker     if (mSurfaceCaps.currentExtent.height == kSurfaceSizedBySwapchain)
2966*8975f5c5SAndroid Build Coastguard Worker     {
2967*8975f5c5SAndroid Build Coastguard Worker         // Surface has no intrinsic size; use current size.
2968*8975f5c5SAndroid Build Coastguard Worker         *value = getHeight();
2969*8975f5c5SAndroid Build Coastguard Worker         return egl::NoError();
2970*8975f5c5SAndroid Build Coastguard Worker     }
2971*8975f5c5SAndroid Build Coastguard Worker 
2972*8975f5c5SAndroid Build Coastguard Worker     VkSurfaceCapabilitiesKHR surfaceCaps;
2973*8975f5c5SAndroid Build Coastguard Worker     angle::Result result = getUserExtentsImpl(displayVk, &surfaceCaps);
2974*8975f5c5SAndroid Build Coastguard Worker     if (result == angle::Result::Continue)
2975*8975f5c5SAndroid Build Coastguard Worker     {
2976*8975f5c5SAndroid Build Coastguard Worker         // The EGL spec states that value is not written if there is an error
2977*8975f5c5SAndroid Build Coastguard Worker         ASSERT(surfaceCaps.currentExtent.height != kSurfaceSizedBySwapchain);
2978*8975f5c5SAndroid Build Coastguard Worker         *value = static_cast<EGLint>(surfaceCaps.currentExtent.height);
2979*8975f5c5SAndroid Build Coastguard Worker     }
2980*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(result, EGL_BAD_SURFACE);
2981*8975f5c5SAndroid Build Coastguard Worker }
2982*8975f5c5SAndroid Build Coastguard Worker 
getUserExtentsImpl(DisplayVk * displayVk,VkSurfaceCapabilitiesKHR * surfaceCaps) const2983*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::getUserExtentsImpl(DisplayVk *displayVk,
2984*8975f5c5SAndroid Build Coastguard Worker                                                   VkSurfaceCapabilitiesKHR *surfaceCaps) const
2985*8975f5c5SAndroid Build Coastguard Worker {
2986*8975f5c5SAndroid Build Coastguard Worker     const VkPhysicalDevice &physicalDevice = displayVk->getRenderer()->getPhysicalDevice();
2987*8975f5c5SAndroid Build Coastguard Worker 
2988*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_TRY(displayVk,
2989*8975f5c5SAndroid Build Coastguard Worker                  vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, surfaceCaps));
2990*8975f5c5SAndroid Build Coastguard Worker 
2991*8975f5c5SAndroid Build Coastguard Worker     // With real prerotation, the surface reports the rotated sizes.  With emulated prerotation,
2992*8975f5c5SAndroid Build Coastguard Worker     // adjust the window extents to match what real pre-rotation would have reported.
2993*8975f5c5SAndroid Build Coastguard Worker     if (Is90DegreeRotation(mEmulatedPreTransform))
2994*8975f5c5SAndroid Build Coastguard Worker     {
2995*8975f5c5SAndroid Build Coastguard Worker         std::swap(surfaceCaps->currentExtent.width, surfaceCaps->currentExtent.height);
2996*8975f5c5SAndroid Build Coastguard Worker     }
2997*8975f5c5SAndroid Build Coastguard Worker 
2998*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
2999*8975f5c5SAndroid Build Coastguard Worker }
3000*8975f5c5SAndroid Build Coastguard Worker 
isPostSubBufferSupported() const3001*8975f5c5SAndroid Build Coastguard Worker EGLint WindowSurfaceVk::isPostSubBufferSupported() const
3002*8975f5c5SAndroid Build Coastguard Worker {
3003*8975f5c5SAndroid Build Coastguard Worker     // TODO(jmadill)
3004*8975f5c5SAndroid Build Coastguard Worker     return EGL_FALSE;
3005*8975f5c5SAndroid Build Coastguard Worker }
3006*8975f5c5SAndroid Build Coastguard Worker 
getSwapBehavior() const3007*8975f5c5SAndroid Build Coastguard Worker EGLint WindowSurfaceVk::getSwapBehavior() const
3008*8975f5c5SAndroid Build Coastguard Worker {
3009*8975f5c5SAndroid Build Coastguard Worker     // TODO(jmadill)
3010*8975f5c5SAndroid Build Coastguard Worker     return EGL_BUFFER_DESTROYED;
3011*8975f5c5SAndroid Build Coastguard Worker }
3012*8975f5c5SAndroid Build Coastguard Worker 
getCurrentFramebuffer(ContextVk * contextVk,vk::FramebufferFetchMode fetchMode,const vk::RenderPass & compatibleRenderPass,vk::Framebuffer * framebufferOut)3013*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::getCurrentFramebuffer(ContextVk *contextVk,
3014*8975f5c5SAndroid Build Coastguard Worker                                                      vk::FramebufferFetchMode fetchMode,
3015*8975f5c5SAndroid Build Coastguard Worker                                                      const vk::RenderPass &compatibleRenderPass,
3016*8975f5c5SAndroid Build Coastguard Worker                                                      vk::Framebuffer *framebufferOut)
3017*8975f5c5SAndroid Build Coastguard Worker {
3018*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!contextVk->getFeatures().preferDynamicRendering.enabled);
3019*8975f5c5SAndroid Build Coastguard Worker 
3020*8975f5c5SAndroid Build Coastguard Worker     // FramebufferVk dirty-bit processing should ensure that a new image was acquired.
3021*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state == impl::ImageAcquireState::Ready);
3022*8975f5c5SAndroid Build Coastguard Worker 
3023*8975f5c5SAndroid Build Coastguard Worker     // Track the new fetch mode
3024*8975f5c5SAndroid Build Coastguard Worker     mFramebufferFetchMode = fetchMode;
3025*8975f5c5SAndroid Build Coastguard Worker 
3026*8975f5c5SAndroid Build Coastguard Worker     SwapchainImage &swapchainImage = mSwapchainImages[mCurrentSwapchainImageIndex];
3027*8975f5c5SAndroid Build Coastguard Worker 
3028*8975f5c5SAndroid Build Coastguard Worker     vk::Framebuffer *currentFramebuffer = &chooseFramebuffer();
3029*8975f5c5SAndroid Build Coastguard Worker     if (currentFramebuffer->valid())
3030*8975f5c5SAndroid Build Coastguard Worker     {
3031*8975f5c5SAndroid Build Coastguard Worker         // Validation layers should detect if the render pass is really compatible.
3032*8975f5c5SAndroid Build Coastguard Worker         framebufferOut->setHandle(currentFramebuffer->getHandle());
3033*8975f5c5SAndroid Build Coastguard Worker         return angle::Result::Continue;
3034*8975f5c5SAndroid Build Coastguard Worker     }
3035*8975f5c5SAndroid Build Coastguard Worker 
3036*8975f5c5SAndroid Build Coastguard Worker     const gl::Extents rotatedExtents = mColorRenderTarget.getRotatedExtents();
3037*8975f5c5SAndroid Build Coastguard Worker     const uint32_t attachmentCount   = 1 + (mDepthStencilImage.valid() ? 1 : 0);
3038*8975f5c5SAndroid Build Coastguard Worker 
3039*8975f5c5SAndroid Build Coastguard Worker     std::array<VkImageView, 3> imageViews = {};
3040*8975f5c5SAndroid Build Coastguard Worker     if (mDepthStencilImage.valid())
3041*8975f5c5SAndroid Build Coastguard Worker     {
3042*8975f5c5SAndroid Build Coastguard Worker         const vk::ImageView *imageView = nullptr;
3043*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mDepthStencilRenderTarget.getImageView(contextVk, &imageView));
3044*8975f5c5SAndroid Build Coastguard Worker         imageViews[1] = imageView->getHandle();
3045*8975f5c5SAndroid Build Coastguard Worker     }
3046*8975f5c5SAndroid Build Coastguard Worker 
3047*8975f5c5SAndroid Build Coastguard Worker     if (isMultiSampled())
3048*8975f5c5SAndroid Build Coastguard Worker     {
3049*8975f5c5SAndroid Build Coastguard Worker         const vk::ImageView *imageView = nullptr;
3050*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(mColorRenderTarget.getImageView(contextVk, &imageView));
3051*8975f5c5SAndroid Build Coastguard Worker         imageViews[0] = imageView->getHandle();
3052*8975f5c5SAndroid Build Coastguard Worker     }
3053*8975f5c5SAndroid Build Coastguard Worker     else
3054*8975f5c5SAndroid Build Coastguard Worker     {
3055*8975f5c5SAndroid Build Coastguard Worker         const vk::ImageView *imageView = nullptr;
3056*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(swapchainImage.imageViews.getLevelLayerDrawImageView(
3057*8975f5c5SAndroid Build Coastguard Worker             contextVk, *swapchainImage.image, vk::LevelIndex(0), 0, &imageView));
3058*8975f5c5SAndroid Build Coastguard Worker         imageViews[0] = imageView->getHandle();
3059*8975f5c5SAndroid Build Coastguard Worker     }
3060*8975f5c5SAndroid Build Coastguard Worker 
3061*8975f5c5SAndroid Build Coastguard Worker     VkFramebufferCreateInfo framebufferInfo = {};
3062*8975f5c5SAndroid Build Coastguard Worker     framebufferInfo.sType                   = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
3063*8975f5c5SAndroid Build Coastguard Worker     framebufferInfo.flags                   = 0;
3064*8975f5c5SAndroid Build Coastguard Worker     framebufferInfo.renderPass              = compatibleRenderPass.getHandle();
3065*8975f5c5SAndroid Build Coastguard Worker     framebufferInfo.attachmentCount         = attachmentCount;
3066*8975f5c5SAndroid Build Coastguard Worker     framebufferInfo.pAttachments            = imageViews.data();
3067*8975f5c5SAndroid Build Coastguard Worker     framebufferInfo.width                   = static_cast<uint32_t>(rotatedExtents.width);
3068*8975f5c5SAndroid Build Coastguard Worker     framebufferInfo.height                  = static_cast<uint32_t>(rotatedExtents.height);
3069*8975f5c5SAndroid Build Coastguard Worker     framebufferInfo.layers                  = 1;
3070*8975f5c5SAndroid Build Coastguard Worker 
3071*8975f5c5SAndroid Build Coastguard Worker     ANGLE_VK_TRY(contextVk, currentFramebuffer->init(contextVk->getDevice(), framebufferInfo));
3072*8975f5c5SAndroid Build Coastguard Worker 
3073*8975f5c5SAndroid Build Coastguard Worker     framebufferOut->setHandle(currentFramebuffer->getHandle());
3074*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
3075*8975f5c5SAndroid Build Coastguard Worker }
3076*8975f5c5SAndroid Build Coastguard Worker 
initializeContents(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex)3077*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context,
3078*8975f5c5SAndroid Build Coastguard Worker                                                   GLenum binding,
3079*8975f5c5SAndroid Build Coastguard Worker                                                   const gl::ImageIndex &imageIndex)
3080*8975f5c5SAndroid Build Coastguard Worker {
3081*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
3082*8975f5c5SAndroid Build Coastguard Worker 
3083*8975f5c5SAndroid Build Coastguard Worker     if (mAcquireOperation.state != impl::ImageAcquireState::Ready)
3084*8975f5c5SAndroid Build Coastguard Worker     {
3085*8975f5c5SAndroid Build Coastguard Worker         // Acquire the next image (previously deferred).  Some tests (e.g.
3086*8975f5c5SAndroid Build Coastguard Worker         // GenerateMipmapWithRedefineBenchmark.Run/vulkan_webgl) cause this path to be taken,
3087*8975f5c5SAndroid Build Coastguard Worker         // because of dirty-object processing.
3088*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_TRACE_EVENT_AND_MARKER(contextVk, "Initialize Swap Image");
3089*8975f5c5SAndroid Build Coastguard Worker         ANGLE_TRY(doDeferredAcquireNextImage(context, false));
3090*8975f5c5SAndroid Build Coastguard Worker     }
3091*8975f5c5SAndroid Build Coastguard Worker 
3092*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mSwapchainImages.size() > 0);
3093*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mCurrentSwapchainImageIndex < mSwapchainImages.size());
3094*8975f5c5SAndroid Build Coastguard Worker 
3095*8975f5c5SAndroid Build Coastguard Worker     switch (binding)
3096*8975f5c5SAndroid Build Coastguard Worker     {
3097*8975f5c5SAndroid Build Coastguard Worker         case GL_BACK:
3098*8975f5c5SAndroid Build Coastguard Worker         {
3099*8975f5c5SAndroid Build Coastguard Worker             vk::ImageHelper *image =
3100*8975f5c5SAndroid Build Coastguard Worker                 isMultiSampled() ? &mColorImageMS
3101*8975f5c5SAndroid Build Coastguard Worker                                  : mSwapchainImages[mCurrentSwapchainImageIndex].image.get();
3102*8975f5c5SAndroid Build Coastguard Worker             image->stageRobustResourceClear(imageIndex);
3103*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(image->flushAllStagedUpdates(contextVk));
3104*8975f5c5SAndroid Build Coastguard Worker             break;
3105*8975f5c5SAndroid Build Coastguard Worker         }
3106*8975f5c5SAndroid Build Coastguard Worker         case GL_DEPTH:
3107*8975f5c5SAndroid Build Coastguard Worker         case GL_STENCIL:
3108*8975f5c5SAndroid Build Coastguard Worker             ASSERT(mDepthStencilImage.valid());
3109*8975f5c5SAndroid Build Coastguard Worker             mDepthStencilImage.stageRobustResourceClear(gl::ImageIndex::Make2D(0));
3110*8975f5c5SAndroid Build Coastguard Worker             ANGLE_TRY(mDepthStencilImage.flushAllStagedUpdates(contextVk));
3111*8975f5c5SAndroid Build Coastguard Worker             break;
3112*8975f5c5SAndroid Build Coastguard Worker         default:
3113*8975f5c5SAndroid Build Coastguard Worker             UNREACHABLE();
3114*8975f5c5SAndroid Build Coastguard Worker             break;
3115*8975f5c5SAndroid Build Coastguard Worker     }
3116*8975f5c5SAndroid Build Coastguard Worker 
3117*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
3118*8975f5c5SAndroid Build Coastguard Worker }
3119*8975f5c5SAndroid Build Coastguard Worker 
updateOverlay(ContextVk * contextVk) const3120*8975f5c5SAndroid Build Coastguard Worker void WindowSurfaceVk::updateOverlay(ContextVk *contextVk) const
3121*8975f5c5SAndroid Build Coastguard Worker {
3122*8975f5c5SAndroid Build Coastguard Worker     const gl::OverlayType *overlay = contextVk->getOverlay();
3123*8975f5c5SAndroid Build Coastguard Worker 
3124*8975f5c5SAndroid Build Coastguard Worker     // If overlay is disabled, nothing to do.
3125*8975f5c5SAndroid Build Coastguard Worker     if (!overlay->isEnabled())
3126*8975f5c5SAndroid Build Coastguard Worker     {
3127*8975f5c5SAndroid Build Coastguard Worker         return;
3128*8975f5c5SAndroid Build Coastguard Worker     }
3129*8975f5c5SAndroid Build Coastguard Worker 
3130*8975f5c5SAndroid Build Coastguard Worker     vk::Renderer *renderer = contextVk->getRenderer();
3131*8975f5c5SAndroid Build Coastguard Worker 
3132*8975f5c5SAndroid Build Coastguard Worker     uint32_t validationMessageCount = 0;
3133*8975f5c5SAndroid Build Coastguard Worker     std::string lastValidationMessage =
3134*8975f5c5SAndroid Build Coastguard Worker         renderer->getAndClearLastValidationMessage(&validationMessageCount);
3135*8975f5c5SAndroid Build Coastguard Worker     if (validationMessageCount)
3136*8975f5c5SAndroid Build Coastguard Worker     {
3137*8975f5c5SAndroid Build Coastguard Worker         overlay->getTextWidget(gl::WidgetId::VulkanLastValidationMessage)
3138*8975f5c5SAndroid Build Coastguard Worker             ->set(std::move(lastValidationMessage));
3139*8975f5c5SAndroid Build Coastguard Worker         overlay->getCountWidget(gl::WidgetId::VulkanValidationMessageCount)
3140*8975f5c5SAndroid Build Coastguard Worker             ->set(validationMessageCount);
3141*8975f5c5SAndroid Build Coastguard Worker     }
3142*8975f5c5SAndroid Build Coastguard Worker 
3143*8975f5c5SAndroid Build Coastguard Worker     contextVk->updateOverlayOnPresent();
3144*8975f5c5SAndroid Build Coastguard Worker }
3145*8975f5c5SAndroid Build Coastguard Worker 
overlayHasEnabledWidget(ContextVk * contextVk) const3146*8975f5c5SAndroid Build Coastguard Worker ANGLE_INLINE bool WindowSurfaceVk::overlayHasEnabledWidget(ContextVk *contextVk) const
3147*8975f5c5SAndroid Build Coastguard Worker {
3148*8975f5c5SAndroid Build Coastguard Worker     const gl::OverlayType *overlay = contextVk->getOverlay();
3149*8975f5c5SAndroid Build Coastguard Worker     OverlayVk *overlayVk           = vk::GetImpl(overlay);
3150*8975f5c5SAndroid Build Coastguard Worker     return overlayVk && overlayVk->getEnabledWidgetCount() > 0;
3151*8975f5c5SAndroid Build Coastguard Worker }
3152*8975f5c5SAndroid Build Coastguard Worker 
drawOverlay(ContextVk * contextVk,SwapchainImage * image) const3153*8975f5c5SAndroid Build Coastguard Worker angle::Result WindowSurfaceVk::drawOverlay(ContextVk *contextVk, SwapchainImage *image) const
3154*8975f5c5SAndroid Build Coastguard Worker {
3155*8975f5c5SAndroid Build Coastguard Worker     const gl::OverlayType *overlay = contextVk->getOverlay();
3156*8975f5c5SAndroid Build Coastguard Worker     OverlayVk *overlayVk           = vk::GetImpl(overlay);
3157*8975f5c5SAndroid Build Coastguard Worker 
3158*8975f5c5SAndroid Build Coastguard Worker     // Draw overlay
3159*8975f5c5SAndroid Build Coastguard Worker     const vk::ImageView *imageView = nullptr;
3160*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(image->imageViews.getLevelLayerDrawImageView(contextVk, *image->image,
3161*8975f5c5SAndroid Build Coastguard Worker                                                            vk::LevelIndex(0), 0, &imageView));
3162*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRY(overlayVk->onPresent(contextVk, image->image.get(), imageView,
3163*8975f5c5SAndroid Build Coastguard Worker                                    Is90DegreeRotation(getPreTransform())));
3164*8975f5c5SAndroid Build Coastguard Worker 
3165*8975f5c5SAndroid Build Coastguard Worker     return angle::Result::Continue;
3166*8975f5c5SAndroid Build Coastguard Worker }
3167*8975f5c5SAndroid Build Coastguard Worker 
setAutoRefreshEnabled(bool enabled)3168*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::setAutoRefreshEnabled(bool enabled)
3169*8975f5c5SAndroid Build Coastguard Worker {
3170*8975f5c5SAndroid Build Coastguard Worker     // Auto refresh is only applicable in shared present mode
3171*8975f5c5SAndroid Build Coastguard Worker     if (!isSharedPresentModeDesired())
3172*8975f5c5SAndroid Build Coastguard Worker     {
3173*8975f5c5SAndroid Build Coastguard Worker         return egl::NoError();
3174*8975f5c5SAndroid Build Coastguard Worker     }
3175*8975f5c5SAndroid Build Coastguard Worker 
3176*8975f5c5SAndroid Build Coastguard Worker     vk::PresentMode newDesiredSwapchainPresentMode =
3177*8975f5c5SAndroid Build Coastguard Worker         enabled ? vk::PresentMode::SharedContinuousRefreshKHR
3178*8975f5c5SAndroid Build Coastguard Worker                 : vk::PresentMode::SharedDemandRefreshKHR;
3179*8975f5c5SAndroid Build Coastguard Worker 
3180*8975f5c5SAndroid Build Coastguard Worker     // We only expose EGL_ANDROID_front_buffer_auto_refresh extension on Android with supported
3181*8975f5c5SAndroid Build Coastguard Worker     // VK_EXT_swapchain_maintenance1 extension, where present modes expected to be compatible.
3182*8975f5c5SAndroid Build Coastguard Worker     if (!IsCompatiblePresentMode(newDesiredSwapchainPresentMode, mCompatiblePresentModes.data(),
3183*8975f5c5SAndroid Build Coastguard Worker                                  mCompatiblePresentModes.size()))
3184*8975f5c5SAndroid Build Coastguard Worker     {
3185*8975f5c5SAndroid Build Coastguard Worker         // This should not happen, unless some specific Android platform requires swapchain
3186*8975f5c5SAndroid Build Coastguard Worker         // recreation for these present modes, in which case EGL_ANDROID_front_buffer_auto_refresh
3187*8975f5c5SAndroid Build Coastguard Worker         // should not be exposed or this code should be updated to support this scenario.
3188*8975f5c5SAndroid Build Coastguard Worker         return egl::EglBadMatch();
3189*8975f5c5SAndroid Build Coastguard Worker     }
3190*8975f5c5SAndroid Build Coastguard Worker 
3191*8975f5c5SAndroid Build Coastguard Worker     // Simply change mDesiredSwapchainPresentMode regardless if we are already in single buffer mode
3192*8975f5c5SAndroid Build Coastguard Worker     // or not, since compatible present modes does not require swapchain recreation.
3193*8975f5c5SAndroid Build Coastguard Worker     mDesiredSwapchainPresentMode = newDesiredSwapchainPresentMode;
3194*8975f5c5SAndroid Build Coastguard Worker 
3195*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
3196*8975f5c5SAndroid Build Coastguard Worker }
3197*8975f5c5SAndroid Build Coastguard Worker 
getBufferAge(const gl::Context * context,EGLint * age)3198*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::getBufferAge(const gl::Context *context, EGLint *age)
3199*8975f5c5SAndroid Build Coastguard Worker {
3200*8975f5c5SAndroid Build Coastguard Worker     ContextVk *contextVk = vk::GetImpl(context);
3201*8975f5c5SAndroid Build Coastguard Worker 
3202*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRACE_EVENT0("gpu.angle", "getBufferAge");
3203*8975f5c5SAndroid Build Coastguard Worker 
3204*8975f5c5SAndroid Build Coastguard Worker     // ANI may be skipped in case of multi sampled surface.
3205*8975f5c5SAndroid Build Coastguard Worker     if (isMultiSampled())
3206*8975f5c5SAndroid Build Coastguard Worker     {
3207*8975f5c5SAndroid Build Coastguard Worker         *age = 0;
3208*8975f5c5SAndroid Build Coastguard Worker         return egl::NoError();
3209*8975f5c5SAndroid Build Coastguard Worker     }
3210*8975f5c5SAndroid Build Coastguard Worker 
3211*8975f5c5SAndroid Build Coastguard Worker     // Image must be already acquired in the |prepareSwap| call.
3212*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mAcquireOperation.state != impl::ImageAcquireState::NeedToAcquire);
3213*8975f5c5SAndroid Build Coastguard Worker 
3214*8975f5c5SAndroid Build Coastguard Worker     // If the result of vkAcquireNextImageKHR is not yet processed, do so now.
3215*8975f5c5SAndroid Build Coastguard Worker     if (mAcquireOperation.state == impl::ImageAcquireState::NeedToProcessResult)
3216*8975f5c5SAndroid Build Coastguard Worker     {
3217*8975f5c5SAndroid Build Coastguard Worker         // In case of shared present mode |doDeferredAcquireNextImageWithUsableSwapchain| must be
3218*8975f5c5SAndroid Build Coastguard Worker         // already called in the |prepareSwap| call.
3219*8975f5c5SAndroid Build Coastguard Worker         ASSERT(!isSharedPresentMode());
3220*8975f5c5SAndroid Build Coastguard Worker         // Using this method and not |postProcessUnlockedAcquire|, in order to handle possible
3221*8975f5c5SAndroid Build Coastguard Worker         // VK_ERROR_OUT_OF_DATE_KHR error and recreate the swapchain, instead of failing.
3222*8975f5c5SAndroid Build Coastguard Worker         egl::Error result =
3223*8975f5c5SAndroid Build Coastguard Worker             angle::ToEGL(doDeferredAcquireNextImageWithUsableSwapchain(context), EGL_BAD_SURFACE);
3224*8975f5c5SAndroid Build Coastguard Worker         if (result.isError())
3225*8975f5c5SAndroid Build Coastguard Worker         {
3226*8975f5c5SAndroid Build Coastguard Worker             return result;
3227*8975f5c5SAndroid Build Coastguard Worker         }
3228*8975f5c5SAndroid Build Coastguard Worker     }
3229*8975f5c5SAndroid Build Coastguard Worker 
3230*8975f5c5SAndroid Build Coastguard Worker     if (mBufferAgeQueryFrameNumber == 0)
3231*8975f5c5SAndroid Build Coastguard Worker     {
3232*8975f5c5SAndroid Build Coastguard Worker         ANGLE_VK_PERF_WARNING(contextVk, GL_DEBUG_SEVERITY_LOW,
3233*8975f5c5SAndroid Build Coastguard Worker                               "Querying age of a surface will make it retain its content");
3234*8975f5c5SAndroid Build Coastguard Worker 
3235*8975f5c5SAndroid Build Coastguard Worker         mBufferAgeQueryFrameNumber = mFrameCount;
3236*8975f5c5SAndroid Build Coastguard Worker     }
3237*8975f5c5SAndroid Build Coastguard Worker 
3238*8975f5c5SAndroid Build Coastguard Worker     if (age != nullptr)
3239*8975f5c5SAndroid Build Coastguard Worker     {
3240*8975f5c5SAndroid Build Coastguard Worker         if (mState.swapBehavior == EGL_BUFFER_PRESERVED)
3241*8975f5c5SAndroid Build Coastguard Worker         {
3242*8975f5c5SAndroid Build Coastguard Worker             // EGL_EXT_buffer_age
3243*8975f5c5SAndroid Build Coastguard Worker             //
3244*8975f5c5SAndroid Build Coastguard Worker             // 1) What are the semantics if EGL_BUFFER_PRESERVED is in use
3245*8975f5c5SAndroid Build Coastguard Worker             //
3246*8975f5c5SAndroid Build Coastguard Worker             //     RESOLVED: The age will always be 1 in this case.
3247*8975f5c5SAndroid Build Coastguard Worker 
3248*8975f5c5SAndroid Build Coastguard Worker             // Note: if the query is made before the 1st swap then age needs to be 0
3249*8975f5c5SAndroid Build Coastguard Worker             *age = (mFrameCount == 1) ? 0 : 1;
3250*8975f5c5SAndroid Build Coastguard Worker 
3251*8975f5c5SAndroid Build Coastguard Worker             return egl::NoError();
3252*8975f5c5SAndroid Build Coastguard Worker         }
3253*8975f5c5SAndroid Build Coastguard Worker 
3254*8975f5c5SAndroid Build Coastguard Worker         uint64_t frameNumber = mSwapchainImages[mCurrentSwapchainImageIndex].frameNumber;
3255*8975f5c5SAndroid Build Coastguard Worker         if (frameNumber < mBufferAgeQueryFrameNumber)
3256*8975f5c5SAndroid Build Coastguard Worker         {
3257*8975f5c5SAndroid Build Coastguard Worker             *age = 0;  // Has not been used for rendering yet or since age was queried, no age.
3258*8975f5c5SAndroid Build Coastguard Worker         }
3259*8975f5c5SAndroid Build Coastguard Worker         else
3260*8975f5c5SAndroid Build Coastguard Worker         {
3261*8975f5c5SAndroid Build Coastguard Worker             *age = static_cast<EGLint>(mFrameCount - frameNumber);
3262*8975f5c5SAndroid Build Coastguard Worker         }
3263*8975f5c5SAndroid Build Coastguard Worker     }
3264*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
3265*8975f5c5SAndroid Build Coastguard Worker }
3266*8975f5c5SAndroid Build Coastguard Worker 
supportsPresentMode(vk::PresentMode presentMode) const3267*8975f5c5SAndroid Build Coastguard Worker bool WindowSurfaceVk::supportsPresentMode(vk::PresentMode presentMode) const
3268*8975f5c5SAndroid Build Coastguard Worker {
3269*8975f5c5SAndroid Build Coastguard Worker     return (std::find(mPresentModes.begin(), mPresentModes.end(), presentMode) !=
3270*8975f5c5SAndroid Build Coastguard Worker             mPresentModes.end());
3271*8975f5c5SAndroid Build Coastguard Worker }
3272*8975f5c5SAndroid Build Coastguard Worker 
setRenderBuffer(EGLint renderBuffer)3273*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::setRenderBuffer(EGLint renderBuffer)
3274*8975f5c5SAndroid Build Coastguard Worker {
3275*8975f5c5SAndroid Build Coastguard Worker     if (renderBuffer == EGL_SINGLE_BUFFER)
3276*8975f5c5SAndroid Build Coastguard Worker     {
3277*8975f5c5SAndroid Build Coastguard Worker         vk::PresentMode presentMode = mState.autoRefreshEnabled
3278*8975f5c5SAndroid Build Coastguard Worker                                           ? vk::PresentMode::SharedContinuousRefreshKHR
3279*8975f5c5SAndroid Build Coastguard Worker                                           : vk::PresentMode::SharedDemandRefreshKHR;
3280*8975f5c5SAndroid Build Coastguard Worker         if (!supportsPresentMode(presentMode))
3281*8975f5c5SAndroid Build Coastguard Worker         {
3282*8975f5c5SAndroid Build Coastguard Worker             return egl::EglBadMatch();
3283*8975f5c5SAndroid Build Coastguard Worker         }
3284*8975f5c5SAndroid Build Coastguard Worker         mDesiredSwapchainPresentMode = presentMode;
3285*8975f5c5SAndroid Build Coastguard Worker     }
3286*8975f5c5SAndroid Build Coastguard Worker     else  // EGL_BACK_BUFFER
3287*8975f5c5SAndroid Build Coastguard Worker     {
3288*8975f5c5SAndroid Build Coastguard Worker         mDesiredSwapchainPresentMode = vk::PresentMode::FifoKHR;
3289*8975f5c5SAndroid Build Coastguard Worker     }
3290*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
3291*8975f5c5SAndroid Build Coastguard Worker }
3292*8975f5c5SAndroid Build Coastguard Worker 
lockSurface(const egl::Display * display,EGLint usageHint,bool preservePixels,uint8_t ** bufferPtrOut,EGLint * bufferPitchOut)3293*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::lockSurface(const egl::Display *display,
3294*8975f5c5SAndroid Build Coastguard Worker                                         EGLint usageHint,
3295*8975f5c5SAndroid Build Coastguard Worker                                         bool preservePixels,
3296*8975f5c5SAndroid Build Coastguard Worker                                         uint8_t **bufferPtrOut,
3297*8975f5c5SAndroid Build Coastguard Worker                                         EGLint *bufferPitchOut)
3298*8975f5c5SAndroid Build Coastguard Worker {
3299*8975f5c5SAndroid Build Coastguard Worker     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::lockSurface");
3300*8975f5c5SAndroid Build Coastguard Worker 
3301*8975f5c5SAndroid Build Coastguard Worker     vk::ImageHelper *image = mSwapchainImages[mCurrentSwapchainImageIndex].image.get();
3302*8975f5c5SAndroid Build Coastguard Worker     ASSERT(image->valid());
3303*8975f5c5SAndroid Build Coastguard Worker 
3304*8975f5c5SAndroid Build Coastguard Worker     angle::Result result =
3305*8975f5c5SAndroid Build Coastguard Worker         LockSurfaceImpl(vk::GetImpl(display), image, mLockBufferHelper, getWidth(), getHeight(),
3306*8975f5c5SAndroid Build Coastguard Worker                         usageHint, preservePixels, bufferPtrOut, bufferPitchOut);
3307*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(result, EGL_BAD_ACCESS);
3308*8975f5c5SAndroid Build Coastguard Worker }
3309*8975f5c5SAndroid Build Coastguard Worker 
unlockSurface(const egl::Display * display,bool preservePixels)3310*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::unlockSurface(const egl::Display *display, bool preservePixels)
3311*8975f5c5SAndroid Build Coastguard Worker {
3312*8975f5c5SAndroid Build Coastguard Worker     vk::ImageHelper *image = mSwapchainImages[mCurrentSwapchainImageIndex].image.get();
3313*8975f5c5SAndroid Build Coastguard Worker     ASSERT(image->valid());
3314*8975f5c5SAndroid Build Coastguard Worker     ASSERT(mLockBufferHelper.valid());
3315*8975f5c5SAndroid Build Coastguard Worker 
3316*8975f5c5SAndroid Build Coastguard Worker     return angle::ToEGL(UnlockSurfaceImpl(vk::GetImpl(display), image, mLockBufferHelper,
3317*8975f5c5SAndroid Build Coastguard Worker                                           getWidth(), getHeight(), preservePixels),
3318*8975f5c5SAndroid Build Coastguard Worker                         EGL_BAD_ACCESS);
3319*8975f5c5SAndroid Build Coastguard Worker }
3320*8975f5c5SAndroid Build Coastguard Worker 
origin() const3321*8975f5c5SAndroid Build Coastguard Worker EGLint WindowSurfaceVk::origin() const
3322*8975f5c5SAndroid Build Coastguard Worker {
3323*8975f5c5SAndroid Build Coastguard Worker     return EGL_UPPER_LEFT_KHR;
3324*8975f5c5SAndroid Build Coastguard Worker }
3325*8975f5c5SAndroid Build Coastguard Worker 
attachToFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)3326*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::attachToFramebuffer(const gl::Context *context,
3327*8975f5c5SAndroid Build Coastguard Worker                                                 gl::Framebuffer *framebuffer)
3328*8975f5c5SAndroid Build Coastguard Worker {
3329*8975f5c5SAndroid Build Coastguard Worker     FramebufferVk *framebufferVk = GetImplAs<FramebufferVk>(framebuffer);
3330*8975f5c5SAndroid Build Coastguard Worker     ASSERT(!framebufferVk->getBackbuffer());
3331*8975f5c5SAndroid Build Coastguard Worker     framebufferVk->setBackbuffer(this);
3332*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
3333*8975f5c5SAndroid Build Coastguard Worker }
3334*8975f5c5SAndroid Build Coastguard Worker 
detachFromFramebuffer(const gl::Context * context,gl::Framebuffer * framebuffer)3335*8975f5c5SAndroid Build Coastguard Worker egl::Error WindowSurfaceVk::detachFromFramebuffer(const gl::Context *context,
3336*8975f5c5SAndroid Build Coastguard Worker                                                   gl::Framebuffer *framebuffer)
3337*8975f5c5SAndroid Build Coastguard Worker {
3338*8975f5c5SAndroid Build Coastguard Worker     FramebufferVk *framebufferVk = GetImplAs<FramebufferVk>(framebuffer);
3339*8975f5c5SAndroid Build Coastguard Worker     ASSERT(framebufferVk->getBackbuffer() == this);
3340*8975f5c5SAndroid Build Coastguard Worker     framebufferVk->setBackbuffer(nullptr);
3341*8975f5c5SAndroid Build Coastguard Worker     return egl::NoError();
3342*8975f5c5SAndroid Build Coastguard Worker }
3343*8975f5c5SAndroid Build Coastguard Worker 
3344*8975f5c5SAndroid Build Coastguard Worker }  // namespace rx
3345