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