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