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