• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2016 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // SurfaceVk.cpp:
7 //    Implements the class methods for SurfaceVk.
8 //
9 
10 #include "libANGLE/renderer/vulkan/SurfaceVk.h"
11 
12 #include "common/debug.h"
13 #include "libANGLE/Context.h"
14 #include "libANGLE/Display.h"
15 #include "libANGLE/Overlay.h"
16 #include "libANGLE/Surface.h"
17 #include "libANGLE/renderer/driver_utils.h"
18 #include "libANGLE/renderer/vulkan/ContextVk.h"
19 #include "libANGLE/renderer/vulkan/DisplayVk.h"
20 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
21 #include "libANGLE/renderer/vulkan/OverlayVk.h"
22 #include "libANGLE/renderer/vulkan/RendererVk.h"
23 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
24 #include "libANGLE/trace.h"
25 
26 namespace rx
27 {
28 
29 namespace
30 {
31 angle::SubjectIndex kAnySurfaceImageSubjectIndex = 0;
32 
33 // Special value for currentExtent if surface size is determined by the
34 // swapchain's extent. See VkSurfaceCapabilitiesKHR spec for more details.
35 constexpr uint32_t kSurfaceSizedBySwapchain = 0xFFFFFFFFu;
36 
GetSampleCount(const egl::Config * config)37 GLint GetSampleCount(const egl::Config *config)
38 {
39     GLint samples = 1;
40     if (config->sampleBuffers && config->samples > 1)
41     {
42         samples = config->samples;
43     }
44     return samples;
45 }
46 
GetDesiredPresentMode(const std::vector<VkPresentModeKHR> & presentModes,EGLint interval)47 VkPresentModeKHR GetDesiredPresentMode(const std::vector<VkPresentModeKHR> &presentModes,
48                                        EGLint interval)
49 {
50     ASSERT(!presentModes.empty());
51 
52     // If v-sync is enabled, use FIFO, which throttles you to the display rate and is guaranteed to
53     // always be supported.
54     if (interval > 0)
55     {
56         return VK_PRESENT_MODE_FIFO_KHR;
57     }
58 
59     // Otherwise, choose either of the following, if available, in order specified here:
60     //
61     // - Mailbox is similar to triple-buffering.
62     // - Immediate is similar to single-buffering.
63     //
64     // If neither is supported, we fallback to FIFO.
65 
66     bool mailboxAvailable   = false;
67     bool immediateAvailable = false;
68 
69     for (VkPresentModeKHR presentMode : presentModes)
70     {
71         switch (presentMode)
72         {
73             case VK_PRESENT_MODE_MAILBOX_KHR:
74                 mailboxAvailable = true;
75                 break;
76             case VK_PRESENT_MODE_IMMEDIATE_KHR:
77                 immediateAvailable = true;
78                 break;
79             default:
80                 break;
81         }
82     }
83 
84     if (immediateAvailable)
85     {
86         return VK_PRESENT_MODE_IMMEDIATE_KHR;
87     }
88 
89     if (mailboxAvailable)
90     {
91         return VK_PRESENT_MODE_MAILBOX_KHR;
92     }
93 
94     // Note again that VK_PRESENT_MODE_FIFO_KHR is guaranteed to be available.
95     return VK_PRESENT_MODE_FIFO_KHR;
96 }
97 
98 constexpr VkImageUsageFlags kSurfaceVkImageUsageFlags =
99     VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
100 constexpr VkImageUsageFlags kSurfaceVkColorImageUsageFlags =
101     kSurfaceVkImageUsageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
102 constexpr VkImageUsageFlags kSurfaceVkDepthStencilImageUsageFlags =
103     kSurfaceVkImageUsageFlags | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
104 
105 // If the device is rotated with any of the following transform flags, the swapchain width and
106 // height must be swapped (e.g. make a landscape window portrait).  This must also be done for all
107 // attachments used with the swapchain (i.e. depth, stencil, and multisample buffers).
108 constexpr VkSurfaceTransformFlagsKHR k90DegreeRotationVariants =
109     VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
110     VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
111     VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
112 
Is90DegreeRotation(VkSurfaceTransformFlagsKHR transform)113 bool Is90DegreeRotation(VkSurfaceTransformFlagsKHR transform)
114 {
115     return ((transform & k90DegreeRotationVariants) != 0);
116 }
117 
InitImageHelper(DisplayVk * displayVk,EGLint width,EGLint height,const vk::Format & vkFormat,GLint samples,bool isRobustResourceInitEnabled,bool hasProtectedContent,vk::ImageHelper * imageHelper)118 angle::Result InitImageHelper(DisplayVk *displayVk,
119                               EGLint width,
120                               EGLint height,
121                               const vk::Format &vkFormat,
122                               GLint samples,
123                               bool isRobustResourceInitEnabled,
124                               bool hasProtectedContent,
125                               vk::ImageHelper *imageHelper)
126 {
127     const angle::Format &textureFormat = vkFormat.getActualRenderableImageFormat();
128     bool isDepthOrStencilFormat   = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0;
129     const VkImageUsageFlags usage = isDepthOrStencilFormat ? kSurfaceVkDepthStencilImageUsageFlags
130                                                            : kSurfaceVkColorImageUsageFlags;
131 
132     VkExtent3D extents = {std::max(static_cast<uint32_t>(width), 1u),
133                           std::max(static_cast<uint32_t>(height), 1u), 1u};
134 
135     angle::FormatID renderableFormatId = vkFormat.getActualRenderableImageFormatID();
136     RendererVk *rendererVk             = displayVk->getRenderer();
137     // For devices that don't support creating swapchain images with RGB8, emulate with RGBA8.
138     if (rendererVk->getFeatures().overrideSurfaceFormatRGB8toRGBA8.enabled &&
139         renderableFormatId == angle::FormatID::R8G8B8_UNORM)
140     {
141         renderableFormatId = angle::FormatID::R8G8B8A8_UNORM;
142     }
143 
144     VkImageCreateFlags imageCreateFlags =
145         hasProtectedContent ? VK_IMAGE_CREATE_PROTECTED_BIT : vk::kVkImageCreateFlagsNone;
146     ANGLE_TRY(imageHelper->initExternal(
147         displayVk, gl::TextureType::_2D, extents, vkFormat.getIntendedFormatID(),
148         renderableFormatId, samples, usage, imageCreateFlags, vk::ImageLayout::Undefined, nullptr,
149         gl::LevelIndex(0), 1, 1, isRobustResourceInitEnabled, hasProtectedContent));
150 
151     return angle::Result::Continue;
152 }
153 
MapEglColorSpaceToVkColorSpace(EGLenum EGLColorspace)154 VkColorSpaceKHR MapEglColorSpaceToVkColorSpace(EGLenum EGLColorspace)
155 {
156     switch (EGLColorspace)
157     {
158         case EGL_NONE:
159         case EGL_GL_COLORSPACE_LINEAR:
160         case EGL_GL_COLORSPACE_SRGB_KHR:
161         case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT:
162             return VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
163         case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
164             return VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
165         case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
166             return VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT;
167         case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
168             return VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
169         case EGL_GL_COLORSPACE_SCRGB_EXT:
170             return VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
171         default:
172             UNREACHABLE();
173             return VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
174     }
175 }
176 
DoesSurfaceSupportFormatAndColorspace(DisplayVk * displayVk,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkFormat format,VkColorSpaceKHR colorSpace,bool * surfaceFormatSupported)177 angle::Result DoesSurfaceSupportFormatAndColorspace(DisplayVk *displayVk,
178                                                     VkPhysicalDevice physicalDevice,
179                                                     VkSurfaceKHR surface,
180                                                     VkFormat format,
181                                                     VkColorSpaceKHR colorSpace,
182                                                     bool *surfaceFormatSupported)
183 {
184     VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo2 = {};
185     surfaceInfo2.sType   = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
186     surfaceInfo2.surface = surface;
187 
188     uint32_t surfaceFormatCount = 0;
189     ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceFormats2KHR(physicalDevice, &surfaceInfo2,
190                                                                   &surfaceFormatCount, nullptr));
191 
192     std::vector<VkSurfaceFormat2KHR> surfaceFormats2(surfaceFormatCount);
193     for (VkSurfaceFormat2KHR &surfaceFormat2 : surfaceFormats2)
194     {
195         surfaceFormat2.sType = VK_STRUCTURE_TYPE_SURFACE_FORMAT_2_KHR;
196     }
197     ANGLE_VK_TRY(displayVk,
198                  vkGetPhysicalDeviceSurfaceFormats2KHR(
199                      physicalDevice, &surfaceInfo2, &surfaceFormatCount, surfaceFormats2.data()));
200 
201     for (VkSurfaceFormat2KHR &surfaceFormat2 : surfaceFormats2)
202     {
203         if (surfaceFormat2.surfaceFormat.format == format &&
204             surfaceFormat2.surfaceFormat.colorSpace == colorSpace)
205         {
206             *surfaceFormatSupported = true;
207             return angle::Result::Continue;
208         }
209     }
210 
211     return angle::Result::Continue;
212 }
213 
DoesSurfaceSupportFormat(DisplayVk * displayVk,VkPhysicalDevice physicalDevice,VkSurfaceKHR surface,VkFormat format,bool * surfaceFormatSupported)214 angle::Result DoesSurfaceSupportFormat(DisplayVk *displayVk,
215                                        VkPhysicalDevice physicalDevice,
216                                        VkSurfaceKHR surface,
217                                        VkFormat format,
218                                        bool *surfaceFormatSupported)
219 {
220     uint32_t surfaceFormatCount = 0;
221     ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface,
222                                                                  &surfaceFormatCount, nullptr));
223 
224     std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount);
225     ANGLE_VK_TRY(displayVk,
226                  vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &surfaceFormatCount,
227                                                       surfaceFormats.data()));
228 
229     if (surfaceFormatCount == 1u && surfaceFormats[0].format == VK_FORMAT_UNDEFINED)
230     {
231         // This is fine.
232         *surfaceFormatSupported = true;
233     }
234     else
235     {
236         for (const VkSurfaceFormatKHR &surfaceFormat : surfaceFormats)
237         {
238             if (surfaceFormat.format == format)
239             {
240                 *surfaceFormatSupported = true;
241                 return angle::Result::Continue;
242             }
243         }
244     }
245 
246     return angle::Result::Continue;
247 }
248 
249 }  // namespace
250 
251 #if defined(ANGLE_ENABLE_OVERLAY)
252 constexpr bool kEnableOverlay = ANGLE_ENABLE_OVERLAY;
253 #else
254 constexpr bool kEnableOverlay = false;
255 #endif
256 
SurfaceVk(const egl::SurfaceState & surfaceState)257 SurfaceVk::SurfaceVk(const egl::SurfaceState &surfaceState) : SurfaceImpl(surfaceState) {}
258 
259 SurfaceVk::~SurfaceVk() = default;
260 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)261 angle::Result SurfaceVk::getAttachmentRenderTarget(const gl::Context *context,
262                                                    GLenum binding,
263                                                    const gl::ImageIndex &imageIndex,
264                                                    GLsizei samples,
265                                                    FramebufferAttachmentRenderTarget **rtOut)
266 {
267     ASSERT(samples == 0);
268 
269     if (binding == GL_BACK)
270     {
271         *rtOut = &mColorRenderTarget;
272     }
273     else
274     {
275         ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
276         *rtOut = &mDepthStencilRenderTarget;
277     }
278 
279     return angle::Result::Continue;
280 }
281 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)282 void SurfaceVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
283 {
284     // Forward the notification to parent class that the staging buffer changed.
285     onStateChange(angle::SubjectMessage::SubjectChanged);
286 }
287 
AttachmentImage(SurfaceVk * surfaceVk)288 OffscreenSurfaceVk::AttachmentImage::AttachmentImage(SurfaceVk *surfaceVk)
289     : imageObserverBinding(surfaceVk, kAnySurfaceImageSubjectIndex)
290 {
291     imageObserverBinding.bind(&image);
292 }
293 
294 OffscreenSurfaceVk::AttachmentImage::~AttachmentImage() = default;
295 
initialize(DisplayVk * displayVk,EGLint width,EGLint height,const vk::Format & vkFormat,GLint samples,bool isRobustResourceInitEnabled,bool hasProtectedContent)296 angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *displayVk,
297                                                               EGLint width,
298                                                               EGLint height,
299                                                               const vk::Format &vkFormat,
300                                                               GLint samples,
301                                                               bool isRobustResourceInitEnabled,
302                                                               bool hasProtectedContent)
303 {
304     ANGLE_TRY(InitImageHelper(displayVk, width, height, vkFormat, samples,
305                               isRobustResourceInitEnabled, hasProtectedContent, &image));
306 
307     RendererVk *renderer        = displayVk->getRenderer();
308     VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
309     if (hasProtectedContent)
310     {
311         flags |= VK_MEMORY_PROPERTY_PROTECTED_BIT;
312     }
313     ANGLE_TRY(
314         image.initMemory(displayVk, hasProtectedContent, renderer->getMemoryProperties(), flags));
315 
316     imageViews.init(renderer);
317 
318     return angle::Result::Continue;
319 }
320 
destroy(const egl::Display * display)321 void OffscreenSurfaceVk::AttachmentImage::destroy(const egl::Display *display)
322 {
323     DisplayVk *displayVk = vk::GetImpl(display);
324     RendererVk *renderer = displayVk->getRenderer();
325     // Front end must ensure all usage has been submitted.
326     image.releaseImage(renderer);
327     image.releaseStagingBuffer(renderer);
328     imageViews.release(renderer);
329 }
330 
OffscreenSurfaceVk(const egl::SurfaceState & surfaceState,RendererVk * renderer)331 OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState, RendererVk *renderer)
332     : SurfaceVk(surfaceState),
333       mWidth(mState.attributes.getAsInt(EGL_WIDTH, 0)),
334       mHeight(mState.attributes.getAsInt(EGL_HEIGHT, 0)),
335       mColorAttachment(this),
336       mDepthStencilAttachment(this)
337 {
338     mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, nullptr, nullptr,
339                             gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
340     mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
341                                    &mDepthStencilAttachment.imageViews, nullptr, nullptr,
342                                    gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
343 }
344 
~OffscreenSurfaceVk()345 OffscreenSurfaceVk::~OffscreenSurfaceVk() {}
346 
initialize(const egl::Display * display)347 egl::Error OffscreenSurfaceVk::initialize(const egl::Display *display)
348 {
349     DisplayVk *displayVk = vk::GetImpl(display);
350     angle::Result result = initializeImpl(displayVk);
351     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
352 }
353 
initializeImpl(DisplayVk * displayVk)354 angle::Result OffscreenSurfaceVk::initializeImpl(DisplayVk *displayVk)
355 {
356     RendererVk *renderer      = displayVk->getRenderer();
357     const egl::Config *config = mState.config;
358 
359     renderer->reloadVolkIfNeeded();
360 
361     GLint samples = GetSampleCount(mState.config);
362     ANGLE_VK_CHECK(displayVk, samples > 0, VK_ERROR_INITIALIZATION_FAILED);
363 
364     bool robustInit = mState.isRobustResourceInitEnabled();
365 
366     if (config->renderTargetFormat != GL_NONE)
367     {
368         ANGLE_TRY(mColorAttachment.initialize(displayVk, mWidth, mHeight,
369                                               renderer->getFormat(config->renderTargetFormat),
370                                               samples, robustInit, mState.hasProtectedContent()));
371         mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, nullptr,
372                                 nullptr, gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
373     }
374 
375     if (config->depthStencilFormat != GL_NONE)
376     {
377         ANGLE_TRY(mDepthStencilAttachment.initialize(
378             displayVk, mWidth, mHeight, renderer->getFormat(config->depthStencilFormat), samples,
379             robustInit, mState.hasProtectedContent()));
380         mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
381                                        &mDepthStencilAttachment.imageViews, nullptr, nullptr,
382                                        gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
383     }
384 
385     return angle::Result::Continue;
386 }
387 
destroy(const egl::Display * display)388 void OffscreenSurfaceVk::destroy(const egl::Display *display)
389 {
390     mColorAttachment.destroy(display);
391     mDepthStencilAttachment.destroy(display);
392 }
393 
createDefaultFramebuffer(const gl::Context * context,const gl::FramebufferState & state)394 FramebufferImpl *OffscreenSurfaceVk::createDefaultFramebuffer(const gl::Context *context,
395                                                               const gl::FramebufferState &state)
396 {
397     RendererVk *renderer = vk::GetImpl(context)->getRenderer();
398 
399     // Use a user FBO for an offscreen RT.
400     return FramebufferVk::CreateUserFBO(renderer, state);
401 }
402 
swap(const gl::Context * context)403 egl::Error OffscreenSurfaceVk::swap(const gl::Context *context)
404 {
405     return egl::NoError();
406 }
407 
postSubBuffer(const gl::Context *,EGLint,EGLint,EGLint,EGLint)408 egl::Error OffscreenSurfaceVk::postSubBuffer(const gl::Context * /*context*/,
409                                              EGLint /*x*/,
410                                              EGLint /*y*/,
411                                              EGLint /*width*/,
412                                              EGLint /*height*/)
413 {
414     return egl::NoError();
415 }
416 
querySurfacePointerANGLE(EGLint,void **)417 egl::Error OffscreenSurfaceVk::querySurfacePointerANGLE(EGLint /*attribute*/, void ** /*value*/)
418 {
419     UNREACHABLE();
420     return egl::EglBadCurrentSurface();
421 }
422 
bindTexImage(const gl::Context *,gl::Texture *,EGLint)423 egl::Error OffscreenSurfaceVk::bindTexImage(const gl::Context * /*context*/,
424                                             gl::Texture * /*texture*/,
425                                             EGLint /*buffer*/)
426 {
427     return egl::NoError();
428 }
429 
releaseTexImage(const gl::Context *,EGLint)430 egl::Error OffscreenSurfaceVk::releaseTexImage(const gl::Context * /*context*/, EGLint /*buffer*/)
431 {
432     return egl::NoError();
433 }
434 
getSyncValues(EGLuint64KHR *,EGLuint64KHR *,EGLuint64KHR *)435 egl::Error OffscreenSurfaceVk::getSyncValues(EGLuint64KHR * /*ust*/,
436                                              EGLuint64KHR * /*msc*/,
437                                              EGLuint64KHR * /*sbc*/)
438 {
439     UNIMPLEMENTED();
440     return egl::EglBadAccess();
441 }
442 
getMscRate(EGLint *,EGLint *)443 egl::Error OffscreenSurfaceVk::getMscRate(EGLint * /*numerator*/, EGLint * /*denominator*/)
444 {
445     UNIMPLEMENTED();
446     return egl::EglBadAccess();
447 }
448 
setSwapInterval(EGLint)449 void OffscreenSurfaceVk::setSwapInterval(EGLint /*interval*/) {}
450 
getWidth() const451 EGLint OffscreenSurfaceVk::getWidth() const
452 {
453     return mWidth;
454 }
455 
getHeight() const456 EGLint OffscreenSurfaceVk::getHeight() const
457 {
458     return mHeight;
459 }
460 
isPostSubBufferSupported() const461 EGLint OffscreenSurfaceVk::isPostSubBufferSupported() const
462 {
463     return EGL_FALSE;
464 }
465 
getSwapBehavior() const466 EGLint OffscreenSurfaceVk::getSwapBehavior() const
467 {
468     return EGL_BUFFER_DESTROYED;
469 }
470 
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)471 angle::Result OffscreenSurfaceVk::initializeContents(const gl::Context *context,
472                                                      const gl::ImageIndex &imageIndex)
473 {
474     ContextVk *contextVk = vk::GetImpl(context);
475 
476     if (mColorAttachment.image.valid())
477     {
478         mColorAttachment.image.stageRobustResourceClear(imageIndex);
479         ANGLE_TRY(mColorAttachment.image.flushAllStagedUpdates(contextVk));
480     }
481 
482     if (mDepthStencilAttachment.image.valid())
483     {
484         mDepthStencilAttachment.image.stageRobustResourceClear(imageIndex);
485         ANGLE_TRY(mDepthStencilAttachment.image.flushAllStagedUpdates(contextVk));
486     }
487     return angle::Result::Continue;
488 }
489 
getColorAttachmentImage()490 vk::ImageHelper *OffscreenSurfaceVk::getColorAttachmentImage()
491 {
492     return &mColorAttachment.image;
493 }
494 
495 namespace impl
496 {
497 SwapchainCleanupData::SwapchainCleanupData() = default;
~SwapchainCleanupData()498 SwapchainCleanupData::~SwapchainCleanupData()
499 {
500     ASSERT(swapchain == VK_NULL_HANDLE);
501     ASSERT(semaphores.empty());
502 }
503 
SwapchainCleanupData(SwapchainCleanupData && other)504 SwapchainCleanupData::SwapchainCleanupData(SwapchainCleanupData &&other)
505     : swapchain(other.swapchain), semaphores(std::move(other.semaphores))
506 {
507     other.swapchain = VK_NULL_HANDLE;
508 }
509 
destroy(VkDevice device,vk::Recycler<vk::Semaphore> * semaphoreRecycler)510 void SwapchainCleanupData::destroy(VkDevice device, vk::Recycler<vk::Semaphore> *semaphoreRecycler)
511 {
512     if (swapchain)
513     {
514         vkDestroySwapchainKHR(device, swapchain, nullptr);
515         swapchain = VK_NULL_HANDLE;
516     }
517 
518     for (vk::Semaphore &semaphore : semaphores)
519     {
520         semaphoreRecycler->recycle(std::move(semaphore));
521     }
522     semaphores.clear();
523 }
524 
525 ImagePresentHistory::ImagePresentHistory() = default;
~ImagePresentHistory()526 ImagePresentHistory::~ImagePresentHistory()
527 {
528     ASSERT(!semaphore.valid());
529     ASSERT(oldSwapchains.empty());
530 }
531 
ImagePresentHistory(ImagePresentHistory && other)532 ImagePresentHistory::ImagePresentHistory(ImagePresentHistory &&other)
533     : semaphore(std::move(other.semaphore)), oldSwapchains(std::move(other.oldSwapchains))
534 {}
535 
operator =(ImagePresentHistory && other)536 ImagePresentHistory &ImagePresentHistory::operator=(ImagePresentHistory &&other)
537 {
538     std::swap(semaphore, other.semaphore);
539     std::swap(oldSwapchains, other.oldSwapchains);
540     return *this;
541 }
542 
543 SwapchainImage::SwapchainImage()  = default;
544 SwapchainImage::~SwapchainImage() = default;
545 
SwapchainImage(SwapchainImage && other)546 SwapchainImage::SwapchainImage(SwapchainImage &&other)
547     : image(std::move(other.image)),
548       imageViews(std::move(other.imageViews)),
549       framebuffer(std::move(other.framebuffer)),
550       presentHistory(std::move(other.presentHistory))
551 {}
552 }  // namespace impl
553 
554 using namespace impl;
555 
WindowSurfaceVk(const egl::SurfaceState & surfaceState,EGLNativeWindowType window)556 WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativeWindowType window)
557     : SurfaceVk(surfaceState),
558       mNativeWindowType(window),
559       mSurface(VK_NULL_HANDLE),
560       mSupportsProtectedSwapchain(false),
561       mSwapchain(VK_NULL_HANDLE),
562       mSwapchainPresentMode(VK_PRESENT_MODE_FIFO_KHR),
563       mDesiredSwapchainPresentMode(VK_PRESENT_MODE_FIFO_KHR),
564       mMinImageCount(0),
565       mPreTransform(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR),
566       mEmulatedPreTransform(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR),
567       mCompositeAlpha(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR),
568       mCurrentSwapchainImageIndex(0),
569       mAcquireImageSemaphore(nullptr),
570       mDepthStencilImageBinding(this, kAnySurfaceImageSubjectIndex),
571       mColorImageMSBinding(this, kAnySurfaceImageSubjectIndex),
572       mNeedToAcquireNextSwapchainImage(false),
573       mFrameCount(1)
574 {
575     // Initialize the color render target with the multisampled targets.  If not multisampled, the
576     // render target will be updated to refer to a swapchain image on every acquire.
577     mColorRenderTarget.init(&mColorImageMS, &mColorImageMSViews, nullptr, nullptr,
578                             gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
579     mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageViews, nullptr, nullptr,
580                                    gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
581     mDepthStencilImageBinding.bind(&mDepthStencilImage);
582     mColorImageMSBinding.bind(&mColorImageMS);
583 }
584 
~WindowSurfaceVk()585 WindowSurfaceVk::~WindowSurfaceVk()
586 {
587     ASSERT(mSurface == VK_NULL_HANDLE);
588     ASSERT(mSwapchain == VK_NULL_HANDLE);
589 }
590 
destroy(const egl::Display * display)591 void WindowSurfaceVk::destroy(const egl::Display *display)
592 {
593     DisplayVk *displayVk = vk::GetImpl(display);
594     RendererVk *renderer = displayVk->getRenderer();
595     VkDevice device      = renderer->getDevice();
596     VkInstance instance  = renderer->getInstance();
597 
598     // flush the pipe.
599     (void)renderer->finish(displayVk, mState.hasProtectedContent());
600 
601     destroySwapChainImages(displayVk);
602 
603     if (mSwapchain)
604     {
605         vkDestroySwapchainKHR(device, mSwapchain, nullptr);
606         mSwapchain = VK_NULL_HANDLE;
607     }
608 
609     for (vk::Semaphore &semaphore : mAcquireImageSemaphores)
610     {
611         semaphore.destroy(device);
612     }
613     for (SwapchainCleanupData &oldSwapchain : mOldSwapchains)
614     {
615         oldSwapchain.destroy(device, &mPresentSemaphoreRecycler);
616     }
617     mOldSwapchains.clear();
618 
619     if (mSurface)
620     {
621         vkDestroySurfaceKHR(instance, mSurface, nullptr);
622         mSurface = VK_NULL_HANDLE;
623     }
624 
625     mPresentSemaphoreRecycler.destroy(device);
626 }
627 
initialize(const egl::Display * display)628 egl::Error WindowSurfaceVk::initialize(const egl::Display *display)
629 {
630     DisplayVk *displayVk = vk::GetImpl(display);
631     angle::Result result = initializeImpl(displayVk);
632     if (result == angle::Result::Incomplete)
633     {
634         return angle::ToEGL(result, displayVk, EGL_BAD_MATCH);
635     }
636     else
637     {
638         return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
639     }
640 }
641 
initializeImpl(DisplayVk * displayVk)642 angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
643 {
644     RendererVk *renderer = displayVk->getRenderer();
645 
646     mColorImageMSViews.init(renderer);
647     mDepthStencilImageViews.init(renderer);
648 
649     renderer->reloadVolkIfNeeded();
650 
651     gl::Extents windowSize;
652     ANGLE_TRY(createSurfaceVk(displayVk, &windowSize));
653 
654     uint32_t presentQueue = 0;
655     ANGLE_TRY(renderer->selectPresentQueueForSurface(displayVk, mSurface, &presentQueue));
656     ANGLE_UNUSED_VARIABLE(presentQueue);
657 
658     const VkPhysicalDevice &physicalDevice = renderer->getPhysicalDevice();
659 
660     if (renderer->getFeatures().supportsSurfaceCapabilities2Extension.enabled)
661     {
662         VkPhysicalDeviceSurfaceInfo2KHR surfaceInfo2 = {};
663         surfaceInfo2.sType   = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SURFACE_INFO_2_KHR;
664         surfaceInfo2.surface = mSurface;
665 
666         VkSurfaceCapabilities2KHR surfaceCaps2 = {};
667         surfaceCaps2.sType                     = VK_STRUCTURE_TYPE_SURFACE_CAPABILITIES_2_KHR;
668 
669         VkSharedPresentSurfaceCapabilitiesKHR sharedPresentSurfaceCaps = {};
670         if (renderer->getFeatures().supportsSharedPresentableImageExtension.enabled)
671         {
672             sharedPresentSurfaceCaps.sType =
673                 VK_STRUCTURE_TYPE_SHARED_PRESENT_SURFACE_CAPABILITIES_KHR;
674             sharedPresentSurfaceCaps.sharedPresentSupportedUsageFlags =
675                 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
676 
677             vk::AddToPNextChain(&surfaceCaps2, &sharedPresentSurfaceCaps);
678         }
679 
680         VkSurfaceProtectedCapabilitiesKHR surfaceProtectedCaps = {};
681         if (renderer->getFeatures().supportsSurfaceProtectedCapabilitiesExtension.enabled)
682         {
683             surfaceProtectedCaps.sType = VK_STRUCTURE_TYPE_SURFACE_PROTECTED_CAPABILITIES_KHR;
684 
685             vk::AddToPNextChain(&surfaceCaps2, &surfaceProtectedCaps);
686         }
687 
688         ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceCapabilities2KHR(
689                                     physicalDevice, &surfaceInfo2, &surfaceCaps2));
690 
691         mSurfaceCaps                = surfaceCaps2.surfaceCapabilities;
692         mSupportsProtectedSwapchain = surfaceProtectedCaps.supportsProtected;
693     }
694     else
695     {
696         ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface,
697                                                                           &mSurfaceCaps));
698     }
699 
700     if (IsAndroid())
701     {
702         mSupportsProtectedSwapchain = true;
703     }
704 
705     ANGLE_VK_CHECK(displayVk, (mState.hasProtectedContent() ? mSupportsProtectedSwapchain : true),
706                    VK_ERROR_FEATURE_NOT_PRESENT);
707 
708     // Adjust width and height to the swapchain if necessary.
709     uint32_t width  = mSurfaceCaps.currentExtent.width;
710     uint32_t height = mSurfaceCaps.currentExtent.height;
711 
712     // TODO(jmadill): Support devices which don't support copy. We use this for ReadPixels.
713     ANGLE_VK_CHECK(displayVk,
714                    (mSurfaceCaps.supportedUsageFlags & kSurfaceVkColorImageUsageFlags) ==
715                        kSurfaceVkColorImageUsageFlags,
716                    VK_ERROR_INITIALIZATION_FAILED);
717 
718     EGLAttrib attribWidth  = mState.attributes.get(EGL_WIDTH, 0);
719     EGLAttrib attribHeight = mState.attributes.get(EGL_HEIGHT, 0);
720 
721     if (mSurfaceCaps.currentExtent.width == kSurfaceSizedBySwapchain)
722     {
723         ASSERT(mSurfaceCaps.currentExtent.height == kSurfaceSizedBySwapchain);
724 
725         width  = (attribWidth != 0) ? static_cast<uint32_t>(attribWidth) : windowSize.width;
726         height = (attribHeight != 0) ? static_cast<uint32_t>(attribHeight) : windowSize.height;
727     }
728 
729     gl::Extents extents(static_cast<int>(width), static_cast<int>(height), 1);
730 
731     // Introduction to Android rotation and pre-rotation:
732     //
733     // Android devices have one native orientation, but a window may be displayed in a different
734     // orientation.  This results in the window being "rotated" relative to the native orientation.
735     // For example, the native orientation of a Pixel 4 is portrait (i.e. height > width).
736     // However, many games want to be landscape (i.e. width > height).  Some applications will
737     // adapt to whatever orientation the user places the device in (e.g. auto-rotation).
738     //
739     // A convention is used within ANGLE of referring to the "rotated" and "non-rotated" aspects of
740     // a topic (e.g. a window's extents, a scissor, a viewport):
741     //
742     // - Non-rotated.  This refers to the way that the application views the window.  Rotation is
743     //   an Android concept, not a GL concept.  An application may view its window as landscape or
744     //   portrait, but not necessarily view its window as being rotated.  For example, an
745     //   application will set a scissor and viewport in a manner consistent with its view of the
746     //   window size (i.e. a non-rotated manner).
747     //
748     // - Rotated.  This refers to the way that Vulkan views the window.  If the window's
749     //   orientation is the same as the native orientation, the rotated view will happen to be
750     //   equivalent to the non-rotated view, but regardless of the window's orientation, ANGLE uses
751     //   the "rotated" term as whatever the Vulkan view of the window is.
752     //
753     // Most of ANGLE is designed to work with the non-rotated view of the window.  This is
754     // certainly true of the ANGLE front-end.  It is also true of most of the Vulkan back-end,
755     // which is still translating GL to Vulkan.  Only part of the Vulkan back-end needs to
756     // communicate directly to Vulkan in terms of the window's rotation.  For example, the viewport
757     // and scissor calculations are done with non-rotated values; and then the final values are
758     // rotated.
759     //
760     // ANGLE learns about the window's rotation from mSurfaceCaps.currentTransform.  If
761     // currentTransform is non-IDENTITY, ANGLE must "pre-rotate" various aspects of its work
762     // (e.g. rotate vertices in the vertex shaders, change scissor, viewport, and render-pass
763     // renderArea).  The swapchain's transform is given the value of mSurfaceCaps.currentTransform.
764     // That prevents SurfaceFlinger from doing a rotation blit for every frame (which is costly in
765     // terms of performance and power).
766     //
767     // When a window is rotated 90 or 270 degrees, the aspect ratio changes.  The width and height
768     // are swapped.  The x/y and width/height of various values in ANGLE must also be swapped
769     // before communicating the values to Vulkan.
770     if (renderer->getFeatures().enablePreRotateSurfaces.enabled)
771     {
772         // Use the surface's transform.  For many platforms, this will always be identity (ANGLE
773         // does not need to do any pre-rotation).  However, when mSurfaceCaps.currentTransform is
774         // not identity, the device has been rotated away from its natural orientation.  In such a
775         // case, ANGLE must rotate all rendering in order to avoid the compositor
776         // (e.g. SurfaceFlinger on Android) performing an additional rotation blit.  In addition,
777         // ANGLE must create the swapchain with VkSwapchainCreateInfoKHR::preTransform set to the
778         // value of mSurfaceCaps.currentTransform.
779         mPreTransform = mSurfaceCaps.currentTransform;
780     }
781     else
782     {
783         // Default to identity transform.
784         mPreTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
785 
786         if ((mSurfaceCaps.supportedTransforms & mPreTransform) == 0)
787         {
788             mPreTransform = mSurfaceCaps.currentTransform;
789         }
790     }
791 
792     // Set emulated pre-transform if any emulated prerotation features are set.
793     if (renderer->getFeatures().emulatedPrerotation90.enabled)
794     {
795         mEmulatedPreTransform = VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR;
796     }
797     else if (renderer->getFeatures().emulatedPrerotation180.enabled)
798     {
799         mEmulatedPreTransform = VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR;
800     }
801     else if (renderer->getFeatures().emulatedPrerotation270.enabled)
802     {
803         mEmulatedPreTransform = VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
804     }
805 
806     // If prerotation is emulated, the window is physically rotated.  With real prerotation, the
807     // surface reports the rotated sizes.  With emulated prerotation however, the surface reports
808     // the actual window sizes.  Adjust the window extents to match what real prerotation would have
809     // reported.
810     if (Is90DegreeRotation(mEmulatedPreTransform))
811     {
812         ASSERT(mPreTransform == VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR);
813         std::swap(extents.width, extents.height);
814     }
815 
816     uint32_t presentModeCount = 0;
817     ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface,
818                                                                       &presentModeCount, nullptr));
819     ASSERT(presentModeCount > 0);
820 
821     mPresentModes.resize(presentModeCount);
822     ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfacePresentModesKHR(
823                                 physicalDevice, mSurface, &presentModeCount, mPresentModes.data()));
824 
825     // Select appropriate present mode based on vsync parameter. Default to 1 (FIFO), though it
826     // will get clamped to the min/max values specified at display creation time.
827     EGLint preferredSwapInterval = mState.getPreferredSwapInterval();
828     if (renderer->getFeatures().disableFifoPresentMode.enabled)
829     {
830         preferredSwapInterval = 0;
831     }
832     setSwapInterval(preferredSwapInterval);
833 
834     const vk::Format &format = renderer->getFormat(mState.config->renderTargetFormat);
835     VkFormat nativeFormat    = format.getActualRenderableImageVkFormat();
836     RendererVk *rendererVk   = displayVk->getRenderer();
837     // For devices that don't support creating swapchain images with RGB8, emulate with RGBA8.
838     if (rendererVk->getFeatures().overrideSurfaceFormatRGB8toRGBA8.enabled &&
839         nativeFormat == VK_FORMAT_R8G8B8_UNORM)
840     {
841         nativeFormat = VK_FORMAT_R8G8B8A8_UNORM;
842     }
843 
844     bool surfaceFormatSupported = false;
845     VkColorSpaceKHR colorSpace  = MapEglColorSpaceToVkColorSpace(
846         static_cast<EGLenum>(mState.attributes.get(EGL_GL_COLORSPACE, EGL_NONE)));
847 
848     if (renderer->getFeatures().supportsSurfaceCapabilities2Extension.enabled)
849     {
850 
851         // If a non-linear colorspace was requested but the non-linear colorspace is
852         // not supported in combination with the vulkan surface format, treat it as a non-fatal
853         // error
854         ANGLE_TRY(DoesSurfaceSupportFormatAndColorspace(displayVk, physicalDevice, mSurface,
855                                                         nativeFormat, colorSpace,
856                                                         &surfaceFormatSupported));
857     }
858     else if (colorSpace != VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
859     {
860         // VK_KHR_get_surface_capabilities2 is required to query support for colorspaces
861         // from VK_EXT_swapchain_colorspace
862     }
863     else
864     {
865         // If a non-linear colorspace was requested but the non-linear format is
866         // not supported as a vulkan surface format, treat it as a non-fatal error
867         ANGLE_TRY(DoesSurfaceSupportFormat(displayVk, physicalDevice, mSurface, nativeFormat,
868                                            &surfaceFormatSupported));
869     }
870 
871     if (!surfaceFormatSupported)
872     {
873         return angle::Result::Incomplete;
874     }
875 
876     mCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
877     if ((mSurfaceCaps.supportedCompositeAlpha & mCompositeAlpha) == 0)
878     {
879         mCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
880     }
881     ANGLE_VK_CHECK(displayVk, (mSurfaceCaps.supportedCompositeAlpha & mCompositeAlpha) != 0,
882                    VK_ERROR_INITIALIZATION_FAILED);
883 
884     ANGLE_TRY(createSwapChain(displayVk, extents, VK_NULL_HANDLE));
885 
886     // Create the semaphores that will be used for vkAcquireNextImageKHR.
887     for (vk::Semaphore &semaphore : mAcquireImageSemaphores)
888     {
889         ANGLE_VK_TRY(displayVk, semaphore.init(displayVk->getDevice()));
890     }
891 
892     VkResult vkResult = acquireNextSwapchainImage(displayVk);
893     ASSERT(vkResult != VK_SUBOPTIMAL_KHR);
894     ANGLE_VK_TRY(displayVk, vkResult);
895 
896     return angle::Result::Continue;
897 }
898 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)899 angle::Result WindowSurfaceVk::getAttachmentRenderTarget(const gl::Context *context,
900                                                          GLenum binding,
901                                                          const gl::ImageIndex &imageIndex,
902                                                          GLsizei samples,
903                                                          FramebufferAttachmentRenderTarget **rtOut)
904 {
905     if (mNeedToAcquireNextSwapchainImage)
906     {
907         // Acquire the next image (previously deferred) before it is drawn to or read from.
908         ContextVk *contextVk = vk::GetImpl(context);
909         ANGLE_VK_TRACE_EVENT_AND_MARKER(contextVk, "First Swap Image Use");
910         ANGLE_TRY(doDeferredAcquireNextImage(context, false));
911     }
912     return SurfaceVk::getAttachmentRenderTarget(context, binding, imageIndex, samples, rtOut);
913 }
914 
recreateSwapchain(ContextVk * contextVk,const gl::Extents & extents)915 angle::Result WindowSurfaceVk::recreateSwapchain(ContextVk *contextVk, const gl::Extents &extents)
916 {
917     // If mOldSwapchains is not empty, it means that a new swapchain was created, but before
918     // any of its images were presented, it's asked to be recreated.  In this case, we can destroy
919     // the current swapchain immediately (although the old swapchains still need to be kept to be
920     // scheduled for destruction).  This can happen for example if vkQueuePresentKHR returns
921     // OUT_OF_DATE, the swapchain is recreated and the following vkAcquireNextImageKHR again
922     // returns OUT_OF_DATE.
923     //
924     // Otherwise, keep the current swapchain as the old swapchain to be scheduled for destruction
925     // and create a new one.
926 
927     VkSwapchainKHR swapchainToDestroy = VK_NULL_HANDLE;
928 
929     if (!mOldSwapchains.empty())
930     {
931         // Keep the old swapchain, destroy the current (never-used) swapchain.
932         swapchainToDestroy = mSwapchain;
933 
934         // Recycle present semaphores.
935         for (SwapchainImage &swapchainImage : mSwapchainImages)
936         {
937             for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
938             {
939                 ASSERT(presentHistory.semaphore.valid());
940                 ASSERT(presentHistory.oldSwapchains.empty());
941 
942                 mPresentSemaphoreRecycler.recycle(std::move(presentHistory.semaphore));
943             }
944         }
945     }
946     else
947     {
948         SwapchainCleanupData cleanupData;
949 
950         // Remember the current swapchain to be scheduled for destruction later.
951         cleanupData.swapchain = mSwapchain;
952 
953         // Accumulate the semaphores to be destroyed at the same time as the swapchain.
954         for (SwapchainImage &swapchainImage : mSwapchainImages)
955         {
956             for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
957             {
958                 ASSERT(presentHistory.semaphore.valid());
959                 cleanupData.semaphores.emplace_back(std::move(presentHistory.semaphore));
960 
961                 // Accumulate any previous swapchains that are pending destruction too.
962                 for (SwapchainCleanupData &oldSwapchain : presentHistory.oldSwapchains)
963                 {
964                     mOldSwapchains.emplace_back(std::move(oldSwapchain));
965                 }
966                 presentHistory.oldSwapchains.clear();
967             }
968         }
969 
970         // If too many old swapchains have accumulated, wait idle and destroy them.  This is to
971         // prevent failures due to too many swapchains allocated.
972         //
973         // Note: Nvidia has been observed to fail creation of swapchains after 20 are allocated on
974         // desktop, or less than 10 on Quadro P400.
975         static constexpr size_t kMaxOldSwapchains = 5;
976         if (mOldSwapchains.size() > kMaxOldSwapchains)
977         {
978             ANGLE_TRY(
979                 contextVk->getRenderer()->finish(contextVk, contextVk->hasProtectedContent()));
980             for (SwapchainCleanupData &oldSwapchain : mOldSwapchains)
981             {
982                 oldSwapchain.destroy(contextVk->getDevice(), &mPresentSemaphoreRecycler);
983             }
984             mOldSwapchains.clear();
985         }
986 
987         mOldSwapchains.emplace_back(std::move(cleanupData));
988     }
989 
990     // Recreate the swapchain based on the most recent one.
991     VkSwapchainKHR lastSwapchain = mSwapchain;
992     mSwapchain                   = VK_NULL_HANDLE;
993 
994     releaseSwapchainImages(contextVk);
995 
996     // If prerotation is emulated, adjust the window extents to match what real prerotation would
997     // have reported.
998     gl::Extents swapchainExtents = extents;
999     if (Is90DegreeRotation(mEmulatedPreTransform))
1000     {
1001         ASSERT(mPreTransform == VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR);
1002         std::swap(swapchainExtents.width, swapchainExtents.height);
1003     }
1004 
1005     angle::Result result = createSwapChain(contextVk, swapchainExtents, lastSwapchain);
1006 
1007     // Notify the parent classes of the surface's new state.
1008     onStateChange(angle::SubjectMessage::SurfaceChanged);
1009 
1010     // If the most recent swapchain was never used, destroy it right now.
1011     if (swapchainToDestroy)
1012     {
1013         vkDestroySwapchainKHR(contextVk->getDevice(), swapchainToDestroy, nullptr);
1014     }
1015 
1016     return result;
1017 }
1018 
newPresentSemaphore(vk::Context * context,vk::Semaphore * semaphoreOut)1019 angle::Result WindowSurfaceVk::newPresentSemaphore(vk::Context *context,
1020                                                    vk::Semaphore *semaphoreOut)
1021 {
1022     if (mPresentSemaphoreRecycler.empty())
1023     {
1024         ANGLE_VK_TRY(context, semaphoreOut->init(context->getDevice()));
1025     }
1026     else
1027     {
1028         mPresentSemaphoreRecycler.fetch(semaphoreOut);
1029     }
1030     return angle::Result::Continue;
1031 }
1032 
resizeSwapchainImages(vk::Context * context,uint32_t imageCount)1033 angle::Result WindowSurfaceVk::resizeSwapchainImages(vk::Context *context, uint32_t imageCount)
1034 {
1035     if (static_cast<size_t>(imageCount) != mSwapchainImages.size())
1036     {
1037         mSwapchainImageBindings.clear();
1038         mSwapchainImages.resize(imageCount);
1039 
1040         // Update the image bindings. Because the observer binding class uses raw pointers we
1041         // need to first ensure the entire image vector is fully allocated before binding the
1042         // subject and observer together.
1043         for (uint32_t index = 0; index < imageCount; ++index)
1044         {
1045             mSwapchainImageBindings.push_back(
1046                 angle::ObserverBinding(this, kAnySurfaceImageSubjectIndex));
1047         }
1048 
1049         for (uint32_t index = 0; index < imageCount; ++index)
1050         {
1051             mSwapchainImageBindings[index].bind(&mSwapchainImages[index].image);
1052         }
1053     }
1054 
1055     // At this point, if there was a previous swapchain, the previous present semaphores have all
1056     // been moved to mOldSwapchains to be scheduled for destruction, so all semaphore handles in
1057     // mSwapchainImages should be invalid.
1058     for (SwapchainImage &swapchainImage : mSwapchainImages)
1059     {
1060         for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
1061         {
1062             ASSERT(!presentHistory.semaphore.valid());
1063             ANGLE_TRY(newPresentSemaphore(context, &presentHistory.semaphore));
1064         }
1065     }
1066 
1067     return angle::Result::Continue;
1068 }
1069 
createSwapChain(vk::Context * context,const gl::Extents & extents,VkSwapchainKHR lastSwapchain)1070 angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context,
1071                                                const gl::Extents &extents,
1072                                                VkSwapchainKHR lastSwapchain)
1073 {
1074     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::createSwapchain");
1075 
1076     ASSERT(mSwapchain == VK_NULL_HANDLE);
1077 
1078     RendererVk *renderer = context->getRenderer();
1079     VkDevice device      = renderer->getDevice();
1080 
1081     const vk::Format &format         = renderer->getFormat(mState.config->renderTargetFormat);
1082     angle::FormatID actualFormatID   = format.getActualRenderableImageFormatID();
1083     angle::FormatID intendedFormatID = format.getIntendedFormatID();
1084 
1085     // For devices that don't support creating swapchain images with RGB8, emulate with RGBA8.
1086     if (renderer->getFeatures().overrideSurfaceFormatRGB8toRGBA8.enabled &&
1087         intendedFormatID == angle::FormatID::R8G8B8_UNORM)
1088     {
1089         actualFormatID = angle::FormatID::R8G8B8A8_UNORM;
1090     }
1091 
1092     gl::Extents rotatedExtents = extents;
1093     if (Is90DegreeRotation(getPreTransform()))
1094     {
1095         // The Surface is oriented such that its aspect ratio no longer matches that of the
1096         // device.  In this case, the width and height of the swapchain images must be swapped to
1097         // match the device's native orientation.  This must also be done for other attachments
1098         // used with the swapchain (e.g. depth buffer).  The width and height of the viewport,
1099         // scissor, and render-pass render area must also be swapped.  Then, when ANGLE rotates
1100         // gl_Position in the vertex shader, the rendering will look the same as if no
1101         // pre-rotation had been done.
1102         std::swap(rotatedExtents.width, rotatedExtents.height);
1103     }
1104 
1105     // We need transfer src for reading back from the backbuffer.
1106     VkImageUsageFlags imageUsageFlags = kSurfaceVkColorImageUsageFlags;
1107 
1108     // We need storage image for compute writes (debug overlay output).
1109     if (kEnableOverlay)
1110     {
1111         VkFormatFeatureFlags featureBits = renderer->getImageFormatFeatureBits(
1112             format.getActualRenderableImageFormatID(), VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT);
1113         if ((featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0)
1114         {
1115             imageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
1116         }
1117     }
1118 
1119     VkSwapchainCreateInfoKHR swapchainInfo = {};
1120     swapchainInfo.sType                    = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
1121     swapchainInfo.flags = mState.hasProtectedContent() ? VK_SWAPCHAIN_CREATE_PROTECTED_BIT_KHR : 0;
1122     swapchainInfo.surface         = mSurface;
1123     swapchainInfo.minImageCount   = mMinImageCount;
1124     swapchainInfo.imageFormat     = vk::GetVkFormatFromFormatID(actualFormatID);
1125     swapchainInfo.imageColorSpace = MapEglColorSpaceToVkColorSpace(
1126         static_cast<EGLenum>(mState.attributes.get(EGL_GL_COLORSPACE, EGL_NONE)));
1127     // Note: Vulkan doesn't allow 0-width/height swapchains.
1128     swapchainInfo.imageExtent.width     = std::max(rotatedExtents.width, 1);
1129     swapchainInfo.imageExtent.height    = std::max(rotatedExtents.height, 1);
1130     swapchainInfo.imageArrayLayers      = 1;
1131     swapchainInfo.imageUsage            = imageUsageFlags;
1132     swapchainInfo.imageSharingMode      = VK_SHARING_MODE_EXCLUSIVE;
1133     swapchainInfo.queueFamilyIndexCount = 0;
1134     swapchainInfo.pQueueFamilyIndices   = nullptr;
1135     swapchainInfo.preTransform          = mPreTransform;
1136     swapchainInfo.compositeAlpha        = mCompositeAlpha;
1137     swapchainInfo.presentMode           = mDesiredSwapchainPresentMode;
1138     swapchainInfo.clipped               = VK_TRUE;
1139     swapchainInfo.oldSwapchain          = lastSwapchain;
1140 
1141     if (mDesiredSwapchainPresentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR)
1142     {
1143         swapchainInfo.minImageCount = 1;
1144     }
1145 
1146     // On Android, vkCreateSwapchainKHR destroys lastSwapchain, which is incorrect.  Wait idle in
1147     // that case as a workaround.
1148     if (lastSwapchain && renderer->getFeatures().waitIdleBeforeSwapchainRecreation.enabled)
1149     {
1150         ANGLE_TRY(renderer->finish(context, mState.hasProtectedContent()));
1151     }
1152 
1153     // TODO(syoussefi): Once EGL_SWAP_BEHAVIOR_PRESERVED_BIT is supported, the contents of the old
1154     // swapchain need to carry over to the new one.  http://anglebug.com/2942
1155     VkSwapchainKHR newSwapChain = VK_NULL_HANDLE;
1156     ANGLE_VK_TRY(context, vkCreateSwapchainKHR(device, &swapchainInfo, nullptr, &newSwapChain));
1157     mSwapchain            = newSwapChain;
1158     mSwapchainPresentMode = mDesiredSwapchainPresentMode;
1159 
1160     // Initialize the swapchain image views.
1161     uint32_t imageCount = 0;
1162     ANGLE_VK_TRY(context, vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, nullptr));
1163 
1164     std::vector<VkImage> swapchainImages(imageCount);
1165     ANGLE_VK_TRY(context,
1166                  vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, swapchainImages.data()));
1167 
1168     // If multisampling is enabled, create a multisampled image which gets resolved just prior to
1169     // present.
1170     GLint samples = GetSampleCount(mState.config);
1171     ANGLE_VK_CHECK(context, samples > 0, VK_ERROR_INITIALIZATION_FAILED);
1172 
1173     VkExtent3D vkExtents;
1174     gl_vk::GetExtent(rotatedExtents, &vkExtents);
1175 
1176     bool robustInit = mState.isRobustResourceInitEnabled();
1177 
1178     if (samples > 1)
1179     {
1180         const VkImageUsageFlags usage = kSurfaceVkColorImageUsageFlags;
1181 
1182         // Create a multisampled image that will be rendered to, and then resolved to a swapchain
1183         // image.  The actual VkImage is created with rotated coordinates to make it easier to do
1184         // the resolve.  The ImageHelper::mExtents will have non-rotated extents in order to fit
1185         // with the rest of ANGLE, (e.g. which calculates the Vulkan scissor with non-rotated
1186         // values and then rotates the final rectangle).
1187         ANGLE_TRY(mColorImageMS.initMSAASwapchain(
1188             context, gl::TextureType::_2D, vkExtents, Is90DegreeRotation(getPreTransform()), format,
1189             samples, usage, gl::LevelIndex(0), 1, 1, robustInit, mState.hasProtectedContent()));
1190         ANGLE_TRY(mColorImageMS.initMemory(context, mState.hasProtectedContent(),
1191                                            renderer->getMemoryProperties(),
1192                                            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
1193 
1194         // Initialize the color render target with the multisampled targets.  If not multisampled,
1195         // the render target will be updated to refer to a swapchain image on every acquire.
1196         mColorRenderTarget.init(&mColorImageMS, &mColorImageMSViews, nullptr, nullptr,
1197                                 gl::LevelIndex(0), 0, 1, RenderTargetTransience::Default);
1198     }
1199 
1200     ANGLE_TRY(resizeSwapchainImages(context, imageCount));
1201 
1202     for (uint32_t imageIndex = 0; imageIndex < imageCount; ++imageIndex)
1203     {
1204         SwapchainImage &member = mSwapchainImages[imageIndex];
1205 
1206         member.image.init2DWeakReference(context, swapchainImages[imageIndex], extents,
1207                                          Is90DegreeRotation(getPreTransform()), intendedFormatID,
1208                                          actualFormatID, 1, robustInit);
1209         member.imageViews.init(renderer);
1210         member.mFrameNumber = 0;
1211     }
1212 
1213     // Initialize depth/stencil if requested.
1214     if (mState.config->depthStencilFormat != GL_NONE)
1215     {
1216         const vk::Format &dsFormat = renderer->getFormat(mState.config->depthStencilFormat);
1217 
1218         const VkImageUsageFlags dsUsage = kSurfaceVkDepthStencilImageUsageFlags;
1219 
1220         ANGLE_TRY(mDepthStencilImage.init(context, gl::TextureType::_2D, vkExtents, dsFormat,
1221                                           samples, dsUsage, gl::LevelIndex(0), 1, 1, robustInit,
1222                                           mState.hasProtectedContent()));
1223         ANGLE_TRY(mDepthStencilImage.initMemory(context, mState.hasProtectedContent(),
1224                                                 renderer->getMemoryProperties(),
1225                                                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
1226 
1227         mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageViews, nullptr,
1228                                        nullptr, gl::LevelIndex(0), 0, 1,
1229                                        RenderTargetTransience::Default);
1230 
1231         // We will need to pass depth/stencil image views to the RenderTargetVk in the future.
1232     }
1233 
1234     return angle::Result::Continue;
1235 }
1236 
isMultiSampled() const1237 bool WindowSurfaceVk::isMultiSampled() const
1238 {
1239     return mColorImageMS.valid();
1240 }
1241 
queryAndAdjustSurfaceCaps(ContextVk * contextVk,VkSurfaceCapabilitiesKHR * surfaceCaps)1242 angle::Result WindowSurfaceVk::queryAndAdjustSurfaceCaps(ContextVk *contextVk,
1243                                                          VkSurfaceCapabilitiesKHR *surfaceCaps)
1244 {
1245     const VkPhysicalDevice &physicalDevice = contextVk->getRenderer()->getPhysicalDevice();
1246     ANGLE_VK_TRY(contextVk,
1247                  vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, surfaceCaps));
1248     if (surfaceCaps->currentExtent.width == kSurfaceSizedBySwapchain)
1249     {
1250         ASSERT(surfaceCaps->currentExtent.height == kSurfaceSizedBySwapchain);
1251         ASSERT(!IsAndroid());
1252 
1253         // vkGetPhysicalDeviceSurfaceCapabilitiesKHR does not provide useful extents for some
1254         // platforms (e.g. Fuschia).  Therefore, we must query the window size via a
1255         // platform-specific mechanism.  Add those extents to the surfaceCaps
1256         gl::Extents currentExtents;
1257         ANGLE_TRY(getCurrentWindowSize(contextVk, &currentExtents));
1258         surfaceCaps->currentExtent.width  = currentExtents.width;
1259         surfaceCaps->currentExtent.height = currentExtents.height;
1260     }
1261 
1262     return angle::Result::Continue;
1263 }
1264 
checkForOutOfDateSwapchain(ContextVk * contextVk,bool presentOutOfDate)1265 angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(ContextVk *contextVk,
1266                                                           bool presentOutOfDate)
1267 {
1268     bool swapIntervalChanged = mSwapchainPresentMode != mDesiredSwapchainPresentMode;
1269     presentOutOfDate         = presentOutOfDate || swapIntervalChanged;
1270 
1271     // If there's no change, early out.
1272     if (!contextVk->getRenderer()->getFeatures().perFrameWindowSizeQuery.enabled &&
1273         !presentOutOfDate)
1274     {
1275         return angle::Result::Continue;
1276     }
1277 
1278     // Get the latest surface capabilities.
1279     ANGLE_TRY(queryAndAdjustSurfaceCaps(contextVk, &mSurfaceCaps));
1280 
1281     if (contextVk->getRenderer()->getFeatures().perFrameWindowSizeQuery.enabled &&
1282         !presentOutOfDate)
1283     {
1284         // This device generates neither VK_ERROR_OUT_OF_DATE_KHR nor VK_SUBOPTIMAL_KHR.  Check for
1285         // whether the size and/or rotation have changed since the swapchain was created.
1286         uint32_t swapchainWidth  = getWidth();
1287         uint32_t swapchainHeight = getHeight();
1288         presentOutOfDate         = mSurfaceCaps.currentTransform != mPreTransform ||
1289                            mSurfaceCaps.currentExtent.width != swapchainWidth ||
1290                            mSurfaceCaps.currentExtent.height != swapchainHeight;
1291     }
1292 
1293     // If anything has changed, recreate the swapchain.
1294     if (!presentOutOfDate)
1295     {
1296         return angle::Result::Continue;
1297     }
1298 
1299     gl::Extents newSwapchainExtents(mSurfaceCaps.currentExtent.width,
1300                                     mSurfaceCaps.currentExtent.height, 1);
1301 
1302     if (contextVk->getFeatures().enablePreRotateSurfaces.enabled)
1303     {
1304         // Update the surface's transform, which can change even if the window size does not.
1305         mPreTransform = mSurfaceCaps.currentTransform;
1306     }
1307 
1308     return recreateSwapchain(contextVk, newSwapchainExtents);
1309 }
1310 
releaseSwapchainImages(ContextVk * contextVk)1311 void WindowSurfaceVk::releaseSwapchainImages(ContextVk *contextVk)
1312 {
1313     RendererVk *renderer = contextVk->getRenderer();
1314 
1315     if (mDepthStencilImage.valid())
1316     {
1317         mDepthStencilImage.releaseImageFromShareContexts(renderer, contextVk);
1318         mDepthStencilImage.releaseStagingBuffer(renderer);
1319         mDepthStencilImageViews.release(renderer);
1320     }
1321 
1322     if (mColorImageMS.valid())
1323     {
1324         mColorImageMS.releaseImageFromShareContexts(renderer, contextVk);
1325         mColorImageMS.releaseStagingBuffer(renderer);
1326         mColorImageMSViews.release(renderer);
1327         contextVk->addGarbage(&mFramebufferMS);
1328     }
1329 
1330     mSwapchainImageBindings.clear();
1331 
1332     for (SwapchainImage &swapchainImage : mSwapchainImages)
1333     {
1334         // We don't own the swapchain image handles, so we just remove our reference to it.
1335         swapchainImage.image.resetImageWeakReference();
1336         swapchainImage.image.destroy(renderer);
1337 
1338         swapchainImage.imageViews.release(renderer);
1339         contextVk->addGarbage(&swapchainImage.framebuffer);
1340 
1341         // present history must have already been taken care of.
1342         for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
1343         {
1344             ASSERT(!presentHistory.semaphore.valid());
1345             ASSERT(presentHistory.oldSwapchains.empty());
1346         }
1347     }
1348 
1349     mSwapchainImages.clear();
1350 }
1351 
destroySwapChainImages(DisplayVk * displayVk)1352 void WindowSurfaceVk::destroySwapChainImages(DisplayVk *displayVk)
1353 {
1354     RendererVk *renderer = displayVk->getRenderer();
1355     VkDevice device      = displayVk->getDevice();
1356 
1357     mDepthStencilImage.destroy(renderer);
1358     mDepthStencilImageViews.destroy(device);
1359     mColorImageMS.destroy(renderer);
1360     mColorImageMSViews.destroy(device);
1361     mFramebufferMS.destroy(device);
1362 
1363     for (SwapchainImage &swapchainImage : mSwapchainImages)
1364     {
1365         // We don't own the swapchain image handles, so we just remove our reference to it.
1366         swapchainImage.image.resetImageWeakReference();
1367         swapchainImage.image.destroy(renderer);
1368         swapchainImage.imageViews.destroy(device);
1369         swapchainImage.framebuffer.destroy(device);
1370 
1371         for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
1372         {
1373             ASSERT(presentHistory.semaphore.valid());
1374 
1375             mPresentSemaphoreRecycler.recycle(std::move(presentHistory.semaphore));
1376             for (SwapchainCleanupData &oldSwapchain : presentHistory.oldSwapchains)
1377             {
1378                 oldSwapchain.destroy(device, &mPresentSemaphoreRecycler);
1379             }
1380             presentHistory.oldSwapchains.clear();
1381         }
1382     }
1383 
1384     mSwapchainImages.clear();
1385 }
1386 
createDefaultFramebuffer(const gl::Context * context,const gl::FramebufferState & state)1387 FramebufferImpl *WindowSurfaceVk::createDefaultFramebuffer(const gl::Context *context,
1388                                                            const gl::FramebufferState &state)
1389 {
1390     RendererVk *renderer = vk::GetImpl(context)->getRenderer();
1391     return FramebufferVk::CreateDefaultFBO(renderer, state, this);
1392 }
1393 
swapWithDamage(const gl::Context * context,const EGLint * rects,EGLint n_rects)1394 egl::Error WindowSurfaceVk::swapWithDamage(const gl::Context *context,
1395                                            const EGLint *rects,
1396                                            EGLint n_rects)
1397 {
1398     DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
1399     angle::Result result;
1400     result = swapImpl(context, rects, n_rects, nullptr);
1401     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
1402 }
1403 
swap(const gl::Context * context)1404 egl::Error WindowSurfaceVk::swap(const gl::Context *context)
1405 {
1406     DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
1407     angle::Result result = swapImpl(context, nullptr, 0, nullptr);
1408     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
1409 }
1410 
computePresentOutOfDate(vk::Context * context,VkResult result,bool * presentOutOfDate)1411 angle::Result WindowSurfaceVk::computePresentOutOfDate(vk::Context *context,
1412                                                        VkResult result,
1413                                                        bool *presentOutOfDate)
1414 {
1415     // If OUT_OF_DATE is returned, it's ok, we just need to recreate the swapchain before
1416     // continuing.
1417     // If VK_SUBOPTIMAL_KHR is returned it's because the device orientation changed and we should
1418     // recreate the swapchain with a new window orientation.
1419     if (context->getRenderer()->getFeatures().enablePreRotateSurfaces.enabled)
1420     {
1421         // Also check for VK_SUBOPTIMAL_KHR.
1422         *presentOutOfDate = ((result == VK_ERROR_OUT_OF_DATE_KHR) || (result == VK_SUBOPTIMAL_KHR));
1423         if (!*presentOutOfDate)
1424         {
1425             ANGLE_VK_TRY(context, result);
1426         }
1427     }
1428     else
1429     {
1430         // We aren't quite ready for that so just ignore for now.
1431         *presentOutOfDate = result == VK_ERROR_OUT_OF_DATE_KHR;
1432         if (!*presentOutOfDate && result != VK_SUBOPTIMAL_KHR)
1433         {
1434             ANGLE_VK_TRY(context, result);
1435         }
1436     }
1437     return angle::Result::Continue;
1438 }
1439 
present(ContextVk * contextVk,const EGLint * rects,EGLint n_rects,const void * pNextChain,bool * presentOutOfDate)1440 angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
1441                                        const EGLint *rects,
1442                                        EGLint n_rects,
1443                                        const void *pNextChain,
1444                                        bool *presentOutOfDate)
1445 {
1446     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::present");
1447     RendererVk *renderer = contextVk->getRenderer();
1448 
1449     // Throttle the submissions to avoid getting too far ahead of the GPU.
1450     Serial *swapSerial = &mSwapHistory.front();
1451     mSwapHistory.next();
1452 
1453     {
1454         ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::present: Throttle CPU");
1455         ANGLE_TRY(renderer->finishToSerial(contextVk, *swapSerial));
1456     }
1457 
1458     SwapchainImage &image               = mSwapchainImages[mCurrentSwapchainImageIndex];
1459     vk::Framebuffer &currentFramebuffer = mSwapchainImages[mCurrentSwapchainImageIndex].framebuffer;
1460     updateOverlay(contextVk);
1461     bool overlayHasWidget = overlayHasEnabledWidget(contextVk);
1462 
1463     // Make sure deferred clears are applied, if any.
1464     ANGLE_TRY(
1465         image.image.flushStagedUpdates(contextVk, gl::LevelIndex(0), gl::LevelIndex(1), 0, 1, {}));
1466 
1467     // We can only do present related optimization if this is the last renderpass that touches the
1468     // swapchain image. MSAA resolve and overlay will insert another renderpass which disqualifies
1469     // the optimization.
1470     if (!mColorImageMS.valid() && !overlayHasWidget && currentFramebuffer.valid())
1471     {
1472         contextVk->optimizeRenderPassForPresent(currentFramebuffer.getHandle());
1473     }
1474 
1475     // Because the color attachment defers layout changes until endRenderPass time, we must call
1476     // finalize the layout transition in the renderpass before we insert layout change to
1477     // ImageLayout::Present bellow.
1478     contextVk->finalizeImageLayout(&image.image);
1479 
1480     vk::CommandBuffer *commandBuffer;
1481     ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
1482 
1483     if (mColorImageMS.valid())
1484     {
1485         // Transition the multisampled image to TRANSFER_SRC for resolve.
1486         vk::CommandBufferAccess access;
1487         access.onImageTransferRead(VK_IMAGE_ASPECT_COLOR_BIT, &mColorImageMS);
1488         access.onImageTransferWrite(gl::LevelIndex(0), 1, 0, 1, VK_IMAGE_ASPECT_COLOR_BIT,
1489                                     &image.image);
1490 
1491         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer(access, &commandBuffer));
1492 
1493         VkImageResolve resolveRegion                = {};
1494         resolveRegion.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
1495         resolveRegion.srcSubresource.mipLevel       = 0;
1496         resolveRegion.srcSubresource.baseArrayLayer = 0;
1497         resolveRegion.srcSubresource.layerCount     = 1;
1498         resolveRegion.srcOffset                     = {};
1499         resolveRegion.dstSubresource                = resolveRegion.srcSubresource;
1500         resolveRegion.dstOffset                     = {};
1501         resolveRegion.extent                        = image.image.getRotatedExtents();
1502 
1503         mColorImageMS.resolve(&image.image, resolveRegion, commandBuffer);
1504     }
1505 
1506     if (overlayHasWidget)
1507     {
1508         ANGLE_TRY(drawOverlay(contextVk, &image));
1509         ANGLE_TRY(contextVk->getOutsideRenderPassCommandBuffer({}, &commandBuffer));
1510     }
1511 
1512     // This does nothing if it's already in the requested layout
1513     image.image.recordReadBarrier(contextVk, VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::Present,
1514                                   commandBuffer);
1515 
1516     // Knowing that the kSwapHistorySize'th submission ago has finished, we can know that the
1517     // (kSwapHistorySize+1)'th present ago of this image is definitely finished and so its wait
1518     // semaphore can be reused.  See doc/PresentSemaphores.md for details.
1519     //
1520     // This also means the swapchain(s) scheduled to be deleted at the same time can be deleted.
1521     ImagePresentHistory &presentHistory = image.presentHistory.front();
1522     image.presentHistory.next();
1523 
1524     vk::Semaphore *presentSemaphore = &presentHistory.semaphore;
1525     ASSERT(presentSemaphore->valid());
1526 
1527     for (SwapchainCleanupData &oldSwapchain : presentHistory.oldSwapchains)
1528     {
1529         oldSwapchain.destroy(contextVk->getDevice(), &mPresentSemaphoreRecycler);
1530     }
1531     presentHistory.oldSwapchains.clear();
1532 
1533     // Schedule pending old swapchains to be destroyed at the same time the semaphore for this
1534     // present can be destroyed.
1535     presentHistory.oldSwapchains = std::move(mOldSwapchains);
1536 
1537     ANGLE_TRY(contextVk->flushAndGetSerial(presentSemaphore, swapSerial,
1538                                            RenderPassClosureReason::EGLSwapBuffers));
1539 
1540     VkPresentInfoKHR presentInfo   = {};
1541     presentInfo.sType              = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
1542     presentInfo.pNext              = pNextChain;
1543     presentInfo.waitSemaphoreCount = 1;
1544     presentInfo.pWaitSemaphores    = presentSemaphore->ptr();
1545     presentInfo.swapchainCount     = 1;
1546     presentInfo.pSwapchains        = &mSwapchain;
1547     presentInfo.pImageIndices      = &mCurrentSwapchainImageIndex;
1548     presentInfo.pResults           = nullptr;
1549 
1550     VkPresentRegionKHR presentRegion   = {};
1551     VkPresentRegionsKHR presentRegions = {};
1552     std::vector<VkRectLayerKHR> vkRects;
1553     if (contextVk->getFeatures().supportsIncrementalPresent.enabled && (n_rects > 0))
1554     {
1555         EGLint width  = getWidth();
1556         EGLint height = getHeight();
1557 
1558         const EGLint *eglRects       = rects;
1559         presentRegion.rectangleCount = n_rects;
1560         vkRects.resize(n_rects);
1561         for (EGLint i = 0; i < n_rects; i++)
1562         {
1563             VkRectLayerKHR &rect = vkRects[i];
1564 
1565             // Make sure the damage rects are within swapchain bounds.
1566             rect.offset.x      = gl::clamp(*eglRects++, 0, width);
1567             rect.offset.y      = gl::clamp(*eglRects++, 0, height);
1568             rect.extent.width  = gl::clamp(*eglRects++, 0, width - rect.offset.x);
1569             rect.extent.height = gl::clamp(*eglRects++, 0, height - rect.offset.y);
1570             rect.layer         = 0;
1571             // No rotation is done to these damage rectangles per the Vulkan spec.
1572         }
1573         presentRegion.pRectangles = vkRects.data();
1574 
1575         presentRegions.sType          = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR;
1576         presentRegions.pNext          = presentInfo.pNext;
1577         presentRegions.swapchainCount = 1;
1578         presentRegions.pRegions       = &presentRegion;
1579 
1580         presentInfo.pNext = &presentRegions;
1581     }
1582 
1583     ASSERT(mAcquireImageSemaphore == nullptr);
1584 
1585     VkResult result = renderer->queuePresent(contextVk, contextVk->getPriority(), presentInfo);
1586 
1587     // Set FrameNumber for the presented image.
1588     mSwapchainImages[mCurrentSwapchainImageIndex].mFrameNumber = mFrameCount++;
1589 
1590     ANGLE_TRY(computePresentOutOfDate(contextVk, result, presentOutOfDate));
1591 
1592     return angle::Result::Continue;
1593 }
1594 
swapImpl(const gl::Context * context,const EGLint * rects,EGLint n_rects,const void * pNextChain)1595 angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context,
1596                                         const EGLint *rects,
1597                                         EGLint n_rects,
1598                                         const void *pNextChain)
1599 {
1600     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::swapImpl");
1601 
1602     ContextVk *contextVk = vk::GetImpl(context);
1603 
1604     if (mNeedToAcquireNextSwapchainImage)
1605     {
1606         // Acquire the next image (previously deferred).  The image may not have been already
1607         // acquired if there was no rendering done at all to the default framebuffer in this frame,
1608         // for example if all rendering was done to FBOs.
1609         ANGLE_VK_TRACE_EVENT_AND_MARKER(contextVk, "Acquire Swap Image Before Swap");
1610         ANGLE_TRY(doDeferredAcquireNextImage(context, false));
1611     }
1612 
1613     bool presentOutOfDate = false;
1614     ANGLE_TRY(present(contextVk, rects, n_rects, pNextChain, &presentOutOfDate));
1615 
1616     if (!presentOutOfDate)
1617     {
1618         // Defer acquiring the next swapchain image since the swapchain is not out-of-date.
1619         deferAcquireNextImage(context);
1620     }
1621     else
1622     {
1623         // Immediately try to acquire the next image, which will recognize the out-of-date
1624         // swapchain (potentially because of a rotation change), and recreate it.
1625         ANGLE_VK_TRACE_EVENT_AND_MARKER(contextVk, "Out-of-Date Swapbuffer");
1626         ANGLE_TRY(doDeferredAcquireNextImage(context, presentOutOfDate));
1627     }
1628 
1629     return angle::Result::Continue;
1630 }
1631 
deferAcquireNextImage(const gl::Context * context)1632 void WindowSurfaceVk::deferAcquireNextImage(const gl::Context *context)
1633 {
1634     mNeedToAcquireNextSwapchainImage = true;
1635 
1636     // Set gl::Framebuffer::DIRTY_BIT_COLOR_BUFFER_CONTENTS_0 via subject-observer message-passing
1637     // to the front-end Surface, Framebuffer, and Context classes.  The DIRTY_BIT_COLOR_ATTACHMENT_0
1638     // is processed before all other dirty bits.  However, since the attachments of the default
1639     // framebuffer cannot change, this bit will be processed before all others.  It will cause
1640     // WindowSurfaceVk::getAttachmentRenderTarget() to be called (which will acquire the next image)
1641     // before any RenderTargetVk accesses.  The processing of other dirty bits as well as other
1642     // setup for draws and reads will then access a properly-updated RenderTargetVk.
1643     onStateChange(angle::SubjectMessage::SubjectChanged);
1644 }
1645 
doDeferredAcquireNextImage(const gl::Context * context,bool presentOutOfDate)1646 angle::Result WindowSurfaceVk::doDeferredAcquireNextImage(const gl::Context *context,
1647                                                           bool presentOutOfDate)
1648 {
1649     ContextVk *contextVk = vk::GetImpl(context);
1650     DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
1651 
1652     // TODO(jmadill): Expose in CommandQueueInterface, or manage in CommandQueue. b/172704839
1653     if (contextVk->getFeatures().asyncCommandQueue.enabled)
1654     {
1655         VkResult result = contextVk->getRenderer()->getLastPresentResult(mSwapchain);
1656 
1657         // Now that we have the result from the last present need to determine if it's out of date
1658         // or not.
1659         ANGLE_TRY(computePresentOutOfDate(contextVk, result, &presentOutOfDate));
1660     }
1661 
1662     ANGLE_TRY(checkForOutOfDateSwapchain(contextVk, presentOutOfDate));
1663 
1664     {
1665         // Note: TRACE_EVENT0 is put here instead of inside the function to workaround this issue:
1666         // http://anglebug.com/2927
1667         ANGLE_TRACE_EVENT0("gpu.angle", "acquireNextSwapchainImage");
1668         // Get the next available swapchain image.
1669 
1670         VkResult result = acquireNextSwapchainImage(contextVk);
1671 
1672         ASSERT(result != VK_SUBOPTIMAL_KHR);
1673         // If OUT_OF_DATE is returned, it's ok, we just need to recreate the swapchain before
1674         // continuing.
1675         if (ANGLE_UNLIKELY(result == VK_ERROR_OUT_OF_DATE_KHR))
1676         {
1677             ANGLE_TRY(checkForOutOfDateSwapchain(contextVk, true));
1678             // Try one more time and bail if we fail
1679             result = acquireNextSwapchainImage(contextVk);
1680         }
1681         ANGLE_VK_TRY(contextVk, result);
1682     }
1683 
1684     RendererVk *renderer = contextVk->getRenderer();
1685     ANGLE_TRY(renderer->syncPipelineCacheVk(displayVk, context));
1686 
1687     return angle::Result::Continue;
1688 }
1689 
1690 // This method will either return VK_SUCCESS or VK_ERROR_*.  Thus, it is appropriate to ASSERT that
1691 // the return value won't be VK_SUBOPTIMAL_KHR.
acquireNextSwapchainImage(vk::Context * context)1692 VkResult WindowSurfaceVk::acquireNextSwapchainImage(vk::Context *context)
1693 {
1694     VkDevice device = context->getDevice();
1695 
1696     if (mSwapchainPresentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR)
1697     {
1698         ASSERT(mSwapchainImages.size());
1699         SwapchainImage &image = mSwapchainImages[0];
1700         if (image.image.valid() &&
1701             (image.image.getCurrentImageLayout() == vk::ImageLayout::SharedPresent))
1702         {  // This will check for OUT_OF_DATE when in single image mode. and prevent
1703            // re-AcquireNextImage.
1704             return vkGetSwapchainStatusKHR(device, mSwapchain);
1705         }
1706     }
1707 
1708     const vk::Semaphore *acquireImageSemaphore = &mAcquireImageSemaphores.front();
1709 
1710     VkResult result =
1711         vkAcquireNextImageKHR(device, mSwapchain, UINT64_MAX, acquireImageSemaphore->getHandle(),
1712                               VK_NULL_HANDLE, &mCurrentSwapchainImageIndex);
1713 
1714     acquireImageSemaphore->valid();
1715 
1716     // VK_SUBOPTIMAL_KHR is ok since we still have an Image that can be presented successfully
1717     if (ANGLE_UNLIKELY(result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR))
1718     {
1719         return result;
1720     }
1721 
1722     SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];
1723 
1724     // Single Image Mode
1725     if ((mSwapchainPresentMode == VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR) &&
1726         (image.image.getCurrentImageLayout() != vk::ImageLayout::SharedPresent))
1727     {
1728         rx::RendererVk *rendererVk = context->getRenderer();
1729         rx::vk::PrimaryCommandBuffer primaryCommandBuffer;
1730         if (rendererVk->getCommandBufferOneOff(context, mState.hasProtectedContent(),
1731                                                &primaryCommandBuffer) == angle::Result::Continue)
1732         {
1733             // Note return errors is early exit may leave new Image and Swapchain in unknown state.
1734             image.image.recordWriteBarrierOneOff(context, vk::ImageLayout::SharedPresent,
1735                                                  &primaryCommandBuffer);
1736             if (primaryCommandBuffer.end() != VK_SUCCESS)
1737             {
1738                 mDesiredSwapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
1739                 return VK_ERROR_OUT_OF_DATE_KHR;
1740             }
1741             Serial serial;
1742             if (rendererVk->queueSubmitOneOff(
1743                     context, std::move(primaryCommandBuffer), false, egl::ContextPriority::Medium,
1744                     acquireImageSemaphore, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, nullptr,
1745                     vk::SubmitPolicy::EnsureSubmitted, &serial) != angle::Result::Continue)
1746             {
1747                 mDesiredSwapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
1748                 return VK_ERROR_OUT_OF_DATE_KHR;
1749             }
1750             acquireImageSemaphore = nullptr;
1751         }
1752     }
1753 
1754     // The semaphore will be waited on in the next flush.
1755     mAcquireImageSemaphores.next();
1756     mAcquireImageSemaphore = acquireImageSemaphore;
1757 
1758     // Update RenderTarget pointers to this swapchain image if not multisampling.  Note: a possible
1759     // optimization is to defer the |vkAcquireNextImageKHR| call itself to |present()| if
1760     // multisampling, as the swapchain image is essentially unused until then.
1761     if (!mColorImageMS.valid())
1762     {
1763         mColorRenderTarget.updateSwapchainImage(&image.image, &image.imageViews, nullptr, nullptr);
1764     }
1765 
1766     // Notify the owning framebuffer there may be staged updates.
1767     if (image.image.hasStagedUpdatesInAllocatedLevels())
1768     {
1769         onStateChange(angle::SubjectMessage::SubjectChanged);
1770     }
1771 
1772     // Note that an acquire is no longer needed.
1773     mNeedToAcquireNextSwapchainImage = false;
1774 
1775     return VK_SUCCESS;
1776 }
1777 
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)1778 egl::Error WindowSurfaceVk::postSubBuffer(const gl::Context *context,
1779                                           EGLint x,
1780                                           EGLint y,
1781                                           EGLint width,
1782                                           EGLint height)
1783 {
1784     // TODO(jmadill)
1785     return egl::NoError();
1786 }
1787 
querySurfacePointerANGLE(EGLint attribute,void ** value)1788 egl::Error WindowSurfaceVk::querySurfacePointerANGLE(EGLint attribute, void **value)
1789 {
1790     UNREACHABLE();
1791     return egl::EglBadCurrentSurface();
1792 }
1793 
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)1794 egl::Error WindowSurfaceVk::bindTexImage(const gl::Context *context,
1795                                          gl::Texture *texture,
1796                                          EGLint buffer)
1797 {
1798     return egl::NoError();
1799 }
1800 
releaseTexImage(const gl::Context * context,EGLint buffer)1801 egl::Error WindowSurfaceVk::releaseTexImage(const gl::Context *context, EGLint buffer)
1802 {
1803     return egl::NoError();
1804 }
1805 
getSyncValues(EGLuint64KHR *,EGLuint64KHR *,EGLuint64KHR *)1806 egl::Error WindowSurfaceVk::getSyncValues(EGLuint64KHR * /*ust*/,
1807                                           EGLuint64KHR * /*msc*/,
1808                                           EGLuint64KHR * /*sbc*/)
1809 {
1810     UNIMPLEMENTED();
1811     return egl::EglBadAccess();
1812 }
1813 
getMscRate(EGLint *,EGLint *)1814 egl::Error WindowSurfaceVk::getMscRate(EGLint * /*numerator*/, EGLint * /*denominator*/)
1815 {
1816     UNIMPLEMENTED();
1817     return egl::EglBadAccess();
1818 }
1819 
setSwapInterval(EGLint interval)1820 void WindowSurfaceVk::setSwapInterval(EGLint interval)
1821 {
1822     const EGLint minSwapInterval = mState.config->minSwapInterval;
1823     const EGLint maxSwapInterval = mState.config->maxSwapInterval;
1824     ASSERT(minSwapInterval == 0 || minSwapInterval == 1);
1825     ASSERT(maxSwapInterval == 0 || maxSwapInterval == 1);
1826 
1827     interval = gl::clamp(interval, minSwapInterval, maxSwapInterval);
1828 
1829     mDesiredSwapchainPresentMode = GetDesiredPresentMode(mPresentModes, interval);
1830 
1831     // - On mailbox, we need at least three images; one is being displayed to the user until the
1832     //   next v-sync, and the application alternatingly renders to the other two, one being
1833     //   recorded, and the other queued for presentation if v-sync happens in the meantime.
1834     // - On immediate, we need at least two images; the application alternates between the two
1835     //   images.
1836     // - On fifo, we use at least three images.  Triple-buffering allows us to present an image,
1837     //   have one in the queue, and record in another.  Note: on certain configurations (windows +
1838     //   nvidia + windowed mode), we could get away with a smaller number.
1839     //
1840     // For simplicity, we always allocate at least three images.
1841     mMinImageCount = std::max(3u, mSurfaceCaps.minImageCount);
1842 
1843     // Make sure we don't exceed maxImageCount.
1844     if (mSurfaceCaps.maxImageCount > 0 && mMinImageCount > mSurfaceCaps.maxImageCount)
1845     {
1846         mMinImageCount = mSurfaceCaps.maxImageCount;
1847     }
1848 
1849     // On the next swap, if the desired present mode is different from the current one, the
1850     // swapchain will be recreated.
1851 }
1852 
getWidth() const1853 EGLint WindowSurfaceVk::getWidth() const
1854 {
1855     return static_cast<EGLint>(mColorRenderTarget.getExtents().width);
1856 }
1857 
getRotatedWidth() const1858 EGLint WindowSurfaceVk::getRotatedWidth() const
1859 {
1860     return static_cast<EGLint>(mColorRenderTarget.getRotatedExtents().width);
1861 }
1862 
getHeight() const1863 EGLint WindowSurfaceVk::getHeight() const
1864 {
1865     return static_cast<EGLint>(mColorRenderTarget.getExtents().height);
1866 }
1867 
getRotatedHeight() const1868 EGLint WindowSurfaceVk::getRotatedHeight() const
1869 {
1870     return static_cast<EGLint>(mColorRenderTarget.getRotatedExtents().height);
1871 }
1872 
getUserWidth(const egl::Display * display,EGLint * value) const1873 egl::Error WindowSurfaceVk::getUserWidth(const egl::Display *display, EGLint *value) const
1874 {
1875     DisplayVk *displayVk = vk::GetImpl(display);
1876 
1877     if (mSurfaceCaps.currentExtent.width == kSurfaceSizedBySwapchain)
1878     {
1879         // Surface has no intrinsic size; use current size.
1880         *value = getWidth();
1881         return egl::NoError();
1882     }
1883 
1884     VkSurfaceCapabilitiesKHR surfaceCaps;
1885     angle::Result result = getUserExtentsImpl(displayVk, &surfaceCaps);
1886     if (result == angle::Result::Continue)
1887     {
1888         // The EGL spec states that value is not written if there is an error
1889         ASSERT(surfaceCaps.currentExtent.width != kSurfaceSizedBySwapchain);
1890         *value = static_cast<EGLint>(surfaceCaps.currentExtent.width);
1891     }
1892     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
1893 }
1894 
getUserHeight(const egl::Display * display,EGLint * value) const1895 egl::Error WindowSurfaceVk::getUserHeight(const egl::Display *display, EGLint *value) const
1896 {
1897     DisplayVk *displayVk = vk::GetImpl(display);
1898 
1899     if (mSurfaceCaps.currentExtent.height == kSurfaceSizedBySwapchain)
1900     {
1901         // Surface has no intrinsic size; use current size.
1902         *value = getHeight();
1903         return egl::NoError();
1904     }
1905 
1906     VkSurfaceCapabilitiesKHR surfaceCaps;
1907     angle::Result result = getUserExtentsImpl(displayVk, &surfaceCaps);
1908     if (result == angle::Result::Continue)
1909     {
1910         // The EGL spec states that value is not written if there is an error
1911         ASSERT(surfaceCaps.currentExtent.height != kSurfaceSizedBySwapchain);
1912         *value = static_cast<EGLint>(surfaceCaps.currentExtent.height);
1913     }
1914     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
1915 }
1916 
getUserExtentsImpl(DisplayVk * displayVk,VkSurfaceCapabilitiesKHR * surfaceCaps) const1917 angle::Result WindowSurfaceVk::getUserExtentsImpl(DisplayVk *displayVk,
1918                                                   VkSurfaceCapabilitiesKHR *surfaceCaps) const
1919 {
1920     const VkPhysicalDevice &physicalDevice = displayVk->getRenderer()->getPhysicalDevice();
1921 
1922     ANGLE_VK_TRY(displayVk,
1923                  vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, surfaceCaps));
1924 
1925     // With real prerotation, the surface reports the rotated sizes.  With emulated prerotation,
1926     // adjust the window extents to match what real pre-rotation would have reported.
1927     if (Is90DegreeRotation(mEmulatedPreTransform))
1928     {
1929         std::swap(surfaceCaps->currentExtent.width, surfaceCaps->currentExtent.height);
1930     }
1931 
1932     return angle::Result::Continue;
1933 }
1934 
isPostSubBufferSupported() const1935 EGLint WindowSurfaceVk::isPostSubBufferSupported() const
1936 {
1937     // TODO(jmadill)
1938     return EGL_FALSE;
1939 }
1940 
getSwapBehavior() const1941 EGLint WindowSurfaceVk::getSwapBehavior() const
1942 {
1943     // TODO(jmadill)
1944     return EGL_BUFFER_DESTROYED;
1945 }
1946 
getCurrentFramebuffer(ContextVk * contextVk,const vk::RenderPass & compatibleRenderPass,vk::Framebuffer ** framebufferOut)1947 angle::Result WindowSurfaceVk::getCurrentFramebuffer(ContextVk *contextVk,
1948                                                      const vk::RenderPass &compatibleRenderPass,
1949                                                      vk::Framebuffer **framebufferOut)
1950 {
1951     // FramebufferVk dirty-bit processing should ensure that a new image was acquired.
1952     ASSERT(!mNeedToAcquireNextSwapchainImage);
1953 
1954     vk::Framebuffer &currentFramebuffer =
1955         isMultiSampled() ? mFramebufferMS
1956                          : mSwapchainImages[mCurrentSwapchainImageIndex].framebuffer;
1957 
1958     if (currentFramebuffer.valid())
1959     {
1960         // Validation layers should detect if the render pass is really compatible.
1961         *framebufferOut = &currentFramebuffer;
1962         return angle::Result::Continue;
1963     }
1964 
1965     VkFramebufferCreateInfo framebufferInfo = {};
1966 
1967     const gl::Extents rotatedExtents      = mColorRenderTarget.getRotatedExtents();
1968     std::array<VkImageView, 2> imageViews = {};
1969 
1970     if (mDepthStencilImage.valid())
1971     {
1972         const vk::ImageView *imageView = nullptr;
1973         ANGLE_TRY(mDepthStencilRenderTarget.getImageView(contextVk, &imageView));
1974         imageViews[1] = imageView->getHandle();
1975     }
1976 
1977     framebufferInfo.sType           = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1978     framebufferInfo.flags           = 0;
1979     framebufferInfo.renderPass      = compatibleRenderPass.getHandle();
1980     framebufferInfo.attachmentCount = (mDepthStencilImage.valid() ? 2u : 1u);
1981     framebufferInfo.pAttachments    = imageViews.data();
1982     framebufferInfo.width           = static_cast<uint32_t>(rotatedExtents.width);
1983     framebufferInfo.height          = static_cast<uint32_t>(rotatedExtents.height);
1984     framebufferInfo.layers          = 1;
1985 
1986     if (isMultiSampled())
1987     {
1988         // If multisampled, there is only a single color image and framebuffer.
1989         const vk::ImageView *imageView = nullptr;
1990         ANGLE_TRY(mColorRenderTarget.getImageView(contextVk, &imageView));
1991         imageViews[0] = imageView->getHandle();
1992         ANGLE_VK_TRY(contextVk, mFramebufferMS.init(contextVk->getDevice(), framebufferInfo));
1993     }
1994     else
1995     {
1996         for (SwapchainImage &swapchainImage : mSwapchainImages)
1997         {
1998             const vk::ImageView *imageView = nullptr;
1999             ANGLE_TRY(swapchainImage.imageViews.getLevelLayerDrawImageView(
2000                 contextVk, swapchainImage.image, vk::LevelIndex(0), 0,
2001                 gl::SrgbWriteControlMode::Default, &imageView));
2002 
2003             imageViews[0] = imageView->getHandle();
2004             ANGLE_VK_TRY(contextVk,
2005                          swapchainImage.framebuffer.init(contextVk->getDevice(), framebufferInfo));
2006         }
2007     }
2008 
2009     ASSERT(currentFramebuffer.valid());
2010     *framebufferOut = &currentFramebuffer;
2011     return angle::Result::Continue;
2012 }
2013 
getAndResetAcquireImageSemaphore()2014 const vk::Semaphore *WindowSurfaceVk::getAndResetAcquireImageSemaphore()
2015 {
2016     const vk::Semaphore *acquireSemaphore = mAcquireImageSemaphore;
2017     mAcquireImageSemaphore                = nullptr;
2018     return acquireSemaphore;
2019 }
2020 
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)2021 angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context,
2022                                                   const gl::ImageIndex &imageIndex)
2023 {
2024     ContextVk *contextVk = vk::GetImpl(context);
2025 
2026     if (mNeedToAcquireNextSwapchainImage)
2027     {
2028         // Acquire the next image (previously deferred).  Some tests (e.g.
2029         // GenerateMipmapWithRedefineBenchmark.Run/vulkan_webgl) cause this path to be taken,
2030         // because of dirty-object processing.
2031         ANGLE_VK_TRACE_EVENT_AND_MARKER(contextVk, "Initialize Swap Image");
2032         ANGLE_TRY(doDeferredAcquireNextImage(context, false));
2033     }
2034 
2035     ASSERT(mSwapchainImages.size() > 0);
2036     ASSERT(mCurrentSwapchainImageIndex < mSwapchainImages.size());
2037 
2038     vk::ImageHelper *image =
2039         isMultiSampled() ? &mColorImageMS : &mSwapchainImages[mCurrentSwapchainImageIndex].image;
2040     image->stageRobustResourceClear(imageIndex);
2041     ANGLE_TRY(image->flushAllStagedUpdates(contextVk));
2042 
2043     if (mDepthStencilImage.valid())
2044     {
2045         mDepthStencilImage.stageRobustResourceClear(gl::ImageIndex::Make2D(0));
2046         ANGLE_TRY(mDepthStencilImage.flushAllStagedUpdates(contextVk));
2047     }
2048 
2049     return angle::Result::Continue;
2050 }
2051 
updateOverlay(ContextVk * contextVk) const2052 void WindowSurfaceVk::updateOverlay(ContextVk *contextVk) const
2053 {
2054     const gl::OverlayType *overlay = contextVk->getOverlay();
2055 
2056     // If overlay is disabled, nothing to do.
2057     if (!overlay->isEnabled())
2058     {
2059         return;
2060     }
2061 
2062     RendererVk *renderer = contextVk->getRenderer();
2063 
2064     uint32_t validationMessageCount = 0;
2065     std::string lastValidationMessage =
2066         renderer->getAndClearLastValidationMessage(&validationMessageCount);
2067     if (validationMessageCount)
2068     {
2069         overlay->getTextWidget(gl::WidgetId::VulkanLastValidationMessage)
2070             ->set(std::move(lastValidationMessage));
2071         overlay->getCountWidget(gl::WidgetId::VulkanValidationMessageCount)
2072             ->add(validationMessageCount);
2073     }
2074 
2075     contextVk->updateOverlayOnPresent();
2076 }
2077 
overlayHasEnabledWidget(ContextVk * contextVk) const2078 ANGLE_INLINE bool WindowSurfaceVk::overlayHasEnabledWidget(ContextVk *contextVk) const
2079 {
2080     const gl::OverlayType *overlay = contextVk->getOverlay();
2081     OverlayVk *overlayVk           = vk::GetImpl(overlay);
2082     return overlayVk && overlayVk->getEnabledWidgetCount() > 0;
2083 }
2084 
drawOverlay(ContextVk * contextVk,SwapchainImage * image) const2085 angle::Result WindowSurfaceVk::drawOverlay(ContextVk *contextVk, SwapchainImage *image) const
2086 {
2087     const gl::OverlayType *overlay = contextVk->getOverlay();
2088     OverlayVk *overlayVk           = vk::GetImpl(overlay);
2089 
2090     // Draw overlay
2091     const vk::ImageView *imageView = nullptr;
2092     ANGLE_TRY(image->imageViews.getLevelLayerDrawImageView(
2093         contextVk, image->image, vk::LevelIndex(0), 0, gl::SrgbWriteControlMode::Default,
2094         &imageView));
2095     ANGLE_TRY(overlayVk->onPresent(contextVk, &image->image, imageView,
2096                                    Is90DegreeRotation(getPreTransform())));
2097 
2098     return angle::Result::Continue;
2099 }
2100 
getBufferAge(const gl::Context * context,EGLint * age)2101 egl::Error WindowSurfaceVk::getBufferAge(const gl::Context *context, EGLint *age)
2102 {
2103     if (mNeedToAcquireNextSwapchainImage)
2104     {
2105         // Acquire the current image if needed.
2106         DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
2107         egl::Error result =
2108             angle::ToEGL(doDeferredAcquireNextImage(context, false), displayVk, EGL_BAD_SURFACE);
2109         if (result.isError())
2110         {
2111             return result;
2112         }
2113     }
2114 
2115     if (age != nullptr)
2116     {
2117         uint64_t frameNumber = mSwapchainImages[mCurrentSwapchainImageIndex].mFrameNumber;
2118         if (frameNumber == 0)
2119         {
2120             *age = 0;  // Has not been used for rendering yet, no age.
2121         }
2122         else
2123         {
2124             *age = static_cast<EGLint>(mFrameCount - frameNumber);
2125         }
2126     }
2127     return egl::NoError();
2128 }
2129 
setRenderBuffer(EGLint renderBuffer)2130 egl::Error WindowSurfaceVk::setRenderBuffer(EGLint renderBuffer)
2131 {
2132     if (std::find(mPresentModes.begin(), mPresentModes.end(),
2133                   VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR) == mPresentModes.end())
2134     {
2135         return egl::EglBadMatch();
2136     }
2137 
2138     if (renderBuffer == EGL_SINGLE_BUFFER)
2139     {
2140         mDesiredSwapchainPresentMode = VK_PRESENT_MODE_SHARED_DEMAND_REFRESH_KHR;
2141     }
2142     else  // EGL_BACK_BUFFER
2143     {
2144         mDesiredSwapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR;
2145     }
2146     return egl::NoError();
2147 }
2148 
2149 }  // namespace rx
2150