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