• 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/vulkan/ContextVk.h"
18 #include "libANGLE/renderer/vulkan/DisplayVk.h"
19 #include "libANGLE/renderer/vulkan/FramebufferVk.h"
20 #include "libANGLE/renderer/vulkan/OverlayVk.h"
21 #include "libANGLE/renderer/vulkan/RendererVk.h"
22 #include "libANGLE/renderer/vulkan/vk_format_utils.h"
23 #include "libANGLE/trace.h"
24 
25 namespace rx
26 {
27 
28 namespace
29 {
30 angle::SubjectIndex kAnySurfaceImageSubjectIndex = 0;
31 
32 // Special value for currentExtent if surface size is determined by the
33 // swapchain's extent. See VkSurfaceCapabilitiesKHR spec for more details.
34 constexpr uint32_t kSurfaceSizedBySwapchain = 0xFFFFFFFFu;
35 
GetSampleCount(const egl::Config * config)36 GLint GetSampleCount(const egl::Config *config)
37 {
38     GLint samples = 1;
39     if (config->sampleBuffers && config->samples > 1)
40     {
41         samples = config->samples;
42     }
43     return samples;
44 }
45 
GetDesiredPresentMode(const std::vector<VkPresentModeKHR> & presentModes,EGLint interval)46 VkPresentModeKHR GetDesiredPresentMode(const std::vector<VkPresentModeKHR> &presentModes,
47                                        EGLint interval)
48 {
49     ASSERT(!presentModes.empty());
50 
51     // If v-sync is enabled, use FIFO, which throttles you to the display rate and is guaranteed to
52     // always be supported.
53     if (interval > 0)
54     {
55         return VK_PRESENT_MODE_FIFO_KHR;
56     }
57 
58     // Otherwise, choose either of the following, if available, in order specified here:
59     //
60     // - Mailbox is similar to triple-buffering.
61     // - Immediate is similar to single-buffering.
62     //
63     // If neither is supported, we fallback to FIFO.
64 
65     bool mailboxAvailable   = false;
66     bool immediateAvailable = false;
67 
68     for (VkPresentModeKHR presentMode : presentModes)
69     {
70         switch (presentMode)
71         {
72             case VK_PRESENT_MODE_MAILBOX_KHR:
73                 mailboxAvailable = true;
74                 break;
75             case VK_PRESENT_MODE_IMMEDIATE_KHR:
76                 immediateAvailable = true;
77                 break;
78             default:
79                 break;
80         }
81     }
82 
83     if (immediateAvailable)
84     {
85         return VK_PRESENT_MODE_IMMEDIATE_KHR;
86     }
87 
88     if (mailboxAvailable)
89     {
90         return VK_PRESENT_MODE_MAILBOX_KHR;
91     }
92 
93     // Note again that VK_PRESENT_MODE_FIFO_KHR is guaranteed to be available.
94     return VK_PRESENT_MODE_FIFO_KHR;
95 }
96 
97 constexpr VkImageUsageFlags kSurfaceVKImageUsageFlags =
98     VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
99 constexpr VkImageUsageFlags kSurfaceVKColorImageUsageFlags =
100     kSurfaceVKImageUsageFlags | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
101 constexpr VkImageUsageFlags kSurfaceVKDepthStencilImageUsageFlags =
102     kSurfaceVKImageUsageFlags | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT;
103 
104 // If the device is rotated with any of the following transform flags, the swapchain width and
105 // height must be swapped (e.g. make a landscape window portrait).  This must also be done for all
106 // attachments used with the swapchain (i.e. depth, stencil, and multisample buffers).
107 constexpr VkSurfaceTransformFlagsKHR k90DegreeRotationVariants =
108     VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR | VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR |
109     VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR |
110     VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR;
111 
Is90DegreeRotation(VkSurfaceTransformFlagsKHR transform)112 bool Is90DegreeRotation(VkSurfaceTransformFlagsKHR transform)
113 {
114     return ((transform & k90DegreeRotationVariants) != 0);
115 }
116 
117 }  // namespace
118 
SurfaceVk(const egl::SurfaceState & surfaceState)119 SurfaceVk::SurfaceVk(const egl::SurfaceState &surfaceState) : SurfaceImpl(surfaceState) {}
120 
121 SurfaceVk::~SurfaceVk() = default;
122 
getAttachmentRenderTarget(const gl::Context * context,GLenum binding,const gl::ImageIndex & imageIndex,GLsizei samples,FramebufferAttachmentRenderTarget ** rtOut)123 angle::Result SurfaceVk::getAttachmentRenderTarget(const gl::Context *context,
124                                                    GLenum binding,
125                                                    const gl::ImageIndex &imageIndex,
126                                                    GLsizei samples,
127                                                    FramebufferAttachmentRenderTarget **rtOut)
128 {
129     if (binding == GL_BACK)
130     {
131         *rtOut = &mColorRenderTarget;
132     }
133     else
134     {
135         ASSERT(binding == GL_DEPTH || binding == GL_STENCIL || binding == GL_DEPTH_STENCIL);
136         *rtOut = &mDepthStencilRenderTarget;
137     }
138 
139     return angle::Result::Continue;
140 }
141 
onSubjectStateChange(angle::SubjectIndex index,angle::SubjectMessage message)142 void SurfaceVk::onSubjectStateChange(angle::SubjectIndex index, angle::SubjectMessage message)
143 {
144     // Forward the notification to parent class that the staging buffer changed.
145     onStateChange(angle::SubjectMessage::SubjectChanged);
146 }
147 
AttachmentImage(SurfaceVk * surfaceVk)148 OffscreenSurfaceVk::AttachmentImage::AttachmentImage(SurfaceVk *surfaceVk)
149     : imageObserverBinding(surfaceVk, kAnySurfaceImageSubjectIndex)
150 {
151     imageObserverBinding.bind(&image);
152 }
153 
154 OffscreenSurfaceVk::AttachmentImage::~AttachmentImage() = default;
155 
initialize(DisplayVk * displayVk,EGLint width,EGLint height,const vk::Format & vkFormat,GLint samples)156 angle::Result OffscreenSurfaceVk::AttachmentImage::initialize(DisplayVk *displayVk,
157                                                               EGLint width,
158                                                               EGLint height,
159                                                               const vk::Format &vkFormat,
160                                                               GLint samples)
161 {
162     RendererVk *renderer = displayVk->getRenderer();
163 
164     const angle::Format &textureFormat = vkFormat.actualImageFormat();
165     bool isDepthOrStencilFormat   = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0;
166     const VkImageUsageFlags usage = isDepthOrStencilFormat ? kSurfaceVKDepthStencilImageUsageFlags
167                                                            : kSurfaceVKColorImageUsageFlags;
168 
169     VkExtent3D extents = {std::max(static_cast<uint32_t>(width), 1u),
170                           std::max(static_cast<uint32_t>(height), 1u), 1u};
171     ANGLE_TRY(
172         image.init(displayVk, gl::TextureType::_2D, extents, vkFormat, samples, usage, 0, 0, 1, 1));
173 
174     VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
175     ANGLE_TRY(image.initMemory(displayVk, renderer->getMemoryProperties(), flags));
176 
177     return angle::Result::Continue;
178 }
179 
initializeWithExternalMemory(DisplayVk * displayVk,EGLint width,EGLint height,const vk::Format & vkFormat,GLint samples,void * buffer)180 angle::Result OffscreenSurfaceVk::AttachmentImage::initializeWithExternalMemory(
181     DisplayVk *displayVk,
182     EGLint width,
183     EGLint height,
184     const vk::Format &vkFormat,
185     GLint samples,
186     void *buffer)
187 {
188     RendererVk *renderer = displayVk->getRenderer();
189 
190     ASSERT(renderer->getFeatures().supportsExternalMemoryHost.enabled);
191 
192     const angle::Format &textureFormat = vkFormat.actualImageFormat();
193     bool isDepthOrStencilFormat   = textureFormat.depthBits > 0 || textureFormat.stencilBits > 0;
194     const VkImageUsageFlags usage = isDepthOrStencilFormat ? kSurfaceVKDepthStencilImageUsageFlags
195                                                            : kSurfaceVKColorImageUsageFlags;
196 
197     VkExtent3D extents = {std::max(static_cast<uint32_t>(width), 1u),
198                           std::max(static_cast<uint32_t>(height), 1u), 1u};
199     ANGLE_TRY(
200         image.init(displayVk, gl::TextureType::_2D, extents, vkFormat, samples, usage, 0, 0, 1, 1));
201 
202     VkImportMemoryHostPointerInfoEXT importMemoryHostPointerInfo = {};
203     importMemoryHostPointerInfo.sType = VK_STRUCTURE_TYPE_IMPORT_MEMORY_HOST_POINTER_INFO_EXT;
204     importMemoryHostPointerInfo.pNext = nullptr;
205     importMemoryHostPointerInfo.handleType =
206         VK_EXTERNAL_MEMORY_HANDLE_TYPE_HOST_MAPPED_FOREIGN_MEMORY_BIT_EXT;
207     importMemoryHostPointerInfo.pHostPointer = buffer;
208 
209     VkMemoryRequirements externalMemoryRequirements;
210     image.getImage().getMemoryRequirements(renderer->getDevice(), &externalMemoryRequirements);
211 
212     VkMemoryPropertyFlags flags = 0;
213     ANGLE_TRY(image.initExternalMemory(displayVk, renderer->getMemoryProperties(),
214                                        externalMemoryRequirements, &importMemoryHostPointerInfo,
215                                        VK_QUEUE_FAMILY_EXTERNAL, flags));
216 
217     return angle::Result::Continue;
218 }
219 
destroy(const egl::Display * display)220 void OffscreenSurfaceVk::AttachmentImage::destroy(const egl::Display *display)
221 {
222     DisplayVk *displayVk = vk::GetImpl(display);
223     RendererVk *renderer = displayVk->getRenderer();
224     image.releaseImage(renderer);
225     image.releaseStagingBuffer(renderer);
226     imageViews.release(renderer);
227 }
228 
OffscreenSurfaceVk(const egl::SurfaceState & surfaceState)229 OffscreenSurfaceVk::OffscreenSurfaceVk(const egl::SurfaceState &surfaceState)
230     : SurfaceVk(surfaceState),
231       mWidth(mState.attributes.getAsInt(EGL_WIDTH, 0)),
232       mHeight(mState.attributes.getAsInt(EGL_HEIGHT, 0)),
233       mColorAttachment(this),
234       mDepthStencilAttachment(this)
235 {
236     mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, 0, 0);
237     mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
238                                    &mDepthStencilAttachment.imageViews, 0, 0);
239 }
240 
~OffscreenSurfaceVk()241 OffscreenSurfaceVk::~OffscreenSurfaceVk() {}
242 
initialize(const egl::Display * display)243 egl::Error OffscreenSurfaceVk::initialize(const egl::Display *display)
244 {
245     DisplayVk *displayVk = vk::GetImpl(display);
246     angle::Result result = initializeImpl(displayVk);
247     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
248 }
249 
initializeImpl(DisplayVk * displayVk)250 angle::Result OffscreenSurfaceVk::initializeImpl(DisplayVk *displayVk)
251 {
252     RendererVk *renderer      = displayVk->getRenderer();
253     const egl::Config *config = mState.config;
254 
255     renderer->reloadVolkIfNeeded();
256 
257     GLint samples = GetSampleCount(mState.config);
258     ANGLE_VK_CHECK(displayVk, samples > 0, VK_ERROR_INITIALIZATION_FAILED);
259 
260     if (config->renderTargetFormat != GL_NONE)
261     {
262         ANGLE_TRY(mColorAttachment.initialize(
263             displayVk, mWidth, mHeight, renderer->getFormat(config->renderTargetFormat), samples));
264         mColorRenderTarget.init(&mColorAttachment.image, &mColorAttachment.imageViews, 0, 0);
265     }
266 
267     if (config->depthStencilFormat != GL_NONE)
268     {
269         ANGLE_TRY(mDepthStencilAttachment.initialize(
270             displayVk, mWidth, mHeight, renderer->getFormat(config->depthStencilFormat), samples));
271         mDepthStencilRenderTarget.init(&mDepthStencilAttachment.image,
272                                        &mDepthStencilAttachment.imageViews, 0, 0);
273     }
274 
275     return angle::Result::Continue;
276 }
277 
destroy(const egl::Display * display)278 void OffscreenSurfaceVk::destroy(const egl::Display *display)
279 {
280     mColorAttachment.destroy(display);
281     mDepthStencilAttachment.destroy(display);
282 }
283 
createDefaultFramebuffer(const gl::Context * context,const gl::FramebufferState & state)284 FramebufferImpl *OffscreenSurfaceVk::createDefaultFramebuffer(const gl::Context *context,
285                                                               const gl::FramebufferState &state)
286 {
287     RendererVk *renderer = vk::GetImpl(context)->getRenderer();
288 
289     // Use a user FBO for an offscreen RT.
290     return FramebufferVk::CreateUserFBO(renderer, state);
291 }
292 
swap(const gl::Context * context)293 egl::Error OffscreenSurfaceVk::swap(const gl::Context *context)
294 {
295     return egl::NoError();
296 }
297 
postSubBuffer(const gl::Context *,EGLint,EGLint,EGLint,EGLint)298 egl::Error OffscreenSurfaceVk::postSubBuffer(const gl::Context * /*context*/,
299                                              EGLint /*x*/,
300                                              EGLint /*y*/,
301                                              EGLint /*width*/,
302                                              EGLint /*height*/)
303 {
304     return egl::NoError();
305 }
306 
querySurfacePointerANGLE(EGLint,void **)307 egl::Error OffscreenSurfaceVk::querySurfacePointerANGLE(EGLint /*attribute*/, void ** /*value*/)
308 {
309     UNREACHABLE();
310     return egl::EglBadCurrentSurface();
311 }
312 
bindTexImage(const gl::Context *,gl::Texture *,EGLint)313 egl::Error OffscreenSurfaceVk::bindTexImage(const gl::Context * /*context*/,
314                                             gl::Texture * /*texture*/,
315                                             EGLint /*buffer*/)
316 {
317     return egl::NoError();
318 }
319 
releaseTexImage(const gl::Context *,EGLint)320 egl::Error OffscreenSurfaceVk::releaseTexImage(const gl::Context * /*context*/, EGLint /*buffer*/)
321 {
322     return egl::NoError();
323 }
324 
getSyncValues(EGLuint64KHR *,EGLuint64KHR *,EGLuint64KHR *)325 egl::Error OffscreenSurfaceVk::getSyncValues(EGLuint64KHR * /*ust*/,
326                                              EGLuint64KHR * /*msc*/,
327                                              EGLuint64KHR * /*sbc*/)
328 {
329     UNIMPLEMENTED();
330     return egl::EglBadAccess();
331 }
332 
getMscRate(EGLint *,EGLint *)333 egl::Error OffscreenSurfaceVk::getMscRate(EGLint * /*numerator*/, EGLint * /*denominator*/)
334 {
335     UNIMPLEMENTED();
336     return egl::EglBadAccess();
337 }
338 
setSwapInterval(EGLint)339 void OffscreenSurfaceVk::setSwapInterval(EGLint /*interval*/) {}
340 
getWidth() const341 EGLint OffscreenSurfaceVk::getWidth() const
342 {
343     return mWidth;
344 }
345 
getHeight() const346 EGLint OffscreenSurfaceVk::getHeight() const
347 {
348     return mHeight;
349 }
350 
isPostSubBufferSupported() const351 EGLint OffscreenSurfaceVk::isPostSubBufferSupported() const
352 {
353     return EGL_FALSE;
354 }
355 
getSwapBehavior() const356 EGLint OffscreenSurfaceVk::getSwapBehavior() const
357 {
358     return EGL_BUFFER_DESTROYED;
359 }
360 
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)361 angle::Result OffscreenSurfaceVk::initializeContents(const gl::Context *context,
362                                                      const gl::ImageIndex &imageIndex)
363 {
364     ContextVk *contextVk = vk::GetImpl(context);
365 
366     if (mColorAttachment.image.valid())
367     {
368         mColorAttachment.image.stageRobustResourceClear(imageIndex);
369         ANGLE_TRY(mColorAttachment.image.flushAllStagedUpdates(contextVk));
370     }
371 
372     if (mDepthStencilAttachment.image.valid())
373     {
374         mDepthStencilAttachment.image.stageRobustResourceClear(imageIndex);
375         ANGLE_TRY(mDepthStencilAttachment.image.flushAllStagedUpdates(contextVk));
376     }
377     return angle::Result::Continue;
378 }
379 
getColorAttachmentImage()380 vk::ImageHelper *OffscreenSurfaceVk::getColorAttachmentImage()
381 {
382     return &mColorAttachment.image;
383 }
384 
385 namespace impl
386 {
387 SwapchainCleanupData::SwapchainCleanupData() = default;
~SwapchainCleanupData()388 SwapchainCleanupData::~SwapchainCleanupData()
389 {
390     ASSERT(swapchain == VK_NULL_HANDLE);
391     ASSERT(semaphores.empty());
392 }
393 
SwapchainCleanupData(SwapchainCleanupData && other)394 SwapchainCleanupData::SwapchainCleanupData(SwapchainCleanupData &&other)
395     : swapchain(other.swapchain), semaphores(std::move(other.semaphores))
396 {
397     other.swapchain = VK_NULL_HANDLE;
398 }
399 
destroy(VkDevice device,vk::Recycler<vk::Semaphore> * semaphoreRecycler)400 void SwapchainCleanupData::destroy(VkDevice device, vk::Recycler<vk::Semaphore> *semaphoreRecycler)
401 {
402     if (swapchain)
403     {
404         vkDestroySwapchainKHR(device, swapchain, nullptr);
405         swapchain = VK_NULL_HANDLE;
406     }
407 
408     for (vk::Semaphore &semaphore : semaphores)
409     {
410         semaphoreRecycler->recycle(std::move(semaphore));
411     }
412     semaphores.clear();
413 }
414 
415 ImagePresentHistory::ImagePresentHistory() = default;
~ImagePresentHistory()416 ImagePresentHistory::~ImagePresentHistory()
417 {
418     ASSERT(!semaphore.valid());
419     ASSERT(oldSwapchains.empty());
420 }
421 
ImagePresentHistory(ImagePresentHistory && other)422 ImagePresentHistory::ImagePresentHistory(ImagePresentHistory &&other)
423     : semaphore(std::move(other.semaphore)), oldSwapchains(std::move(other.oldSwapchains))
424 {}
425 
426 SwapchainImage::SwapchainImage()  = default;
427 SwapchainImage::~SwapchainImage() = default;
428 
SwapchainImage(SwapchainImage && other)429 SwapchainImage::SwapchainImage(SwapchainImage &&other)
430     : image(std::move(other.image)),
431       imageViews(std::move(other.imageViews)),
432       framebuffer(std::move(other.framebuffer)),
433       presentHistory(std::move(other.presentHistory)),
434       currentPresentHistoryIndex(other.currentPresentHistoryIndex)
435 {}
436 
437 SwapHistory::SwapHistory() = default;
438 
439 SwapHistory::~SwapHistory() = default;
440 
destroy(RendererVk * renderer)441 void SwapHistory::destroy(RendererVk *renderer)
442 {
443     renderer->resetSharedFence(&sharedFence);
444 }
445 
waitFence(ContextVk * contextVk)446 angle::Result SwapHistory::waitFence(ContextVk *contextVk)
447 {
448     ASSERT(sharedFence.isReferenced());
449     ANGLE_VK_TRY(contextVk, sharedFence.get().wait(contextVk->getDevice(),
450                                                    std::numeric_limits<uint64_t>::max()));
451     return angle::Result::Continue;
452 }
453 }  // namespace impl
454 
455 using namespace impl;
456 
WindowSurfaceVk(const egl::SurfaceState & surfaceState,EGLNativeWindowType window)457 WindowSurfaceVk::WindowSurfaceVk(const egl::SurfaceState &surfaceState, EGLNativeWindowType window)
458     : SurfaceVk(surfaceState),
459       mNativeWindowType(window),
460       mSurface(VK_NULL_HANDLE),
461       mSwapchain(VK_NULL_HANDLE),
462       mSwapchainPresentMode(VK_PRESENT_MODE_FIFO_KHR),
463       mDesiredSwapchainPresentMode(VK_PRESENT_MODE_FIFO_KHR),
464       mMinImageCount(0),
465       mPreTransform(VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR),
466       mCompositeAlpha(VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR),
467       mCurrentSwapHistoryIndex(0),
468       mCurrentSwapchainImageIndex(0),
469       mDepthStencilImageBinding(this, kAnySurfaceImageSubjectIndex),
470       mColorImageMSBinding(this, kAnySurfaceImageSubjectIndex)
471 {
472     // Initialize the color render target with the multisampled targets.  If not multisampled, the
473     // render target will be updated to refer to a swapchain image on every acquire.
474     mColorRenderTarget.init(&mColorImageMS, &mColorImageMSViews, 0, 0);
475     mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageViews, 0, 0);
476     mDepthStencilImageBinding.bind(&mDepthStencilImage);
477     mColorImageMSBinding.bind(&mColorImageMS);
478 }
479 
~WindowSurfaceVk()480 WindowSurfaceVk::~WindowSurfaceVk()
481 {
482     ASSERT(mSurface == VK_NULL_HANDLE);
483     ASSERT(mSwapchain == VK_NULL_HANDLE);
484 }
485 
destroy(const egl::Display * display)486 void WindowSurfaceVk::destroy(const egl::Display *display)
487 {
488     DisplayVk *displayVk = vk::GetImpl(display);
489     RendererVk *renderer = displayVk->getRenderer();
490     VkDevice device      = renderer->getDevice();
491     VkInstance instance  = renderer->getInstance();
492 
493     // flush the pipe.
494     (void)renderer->deviceWaitIdle(displayVk);
495 
496     destroySwapChainImages(displayVk);
497 
498     for (SwapHistory &swap : mSwapHistory)
499     {
500         swap.destroy(renderer);
501     }
502 
503     if (mSwapchain)
504     {
505         vkDestroySwapchainKHR(device, mSwapchain, nullptr);
506         mSwapchain = VK_NULL_HANDLE;
507     }
508 
509     for (SwapchainCleanupData &oldSwapchain : mOldSwapchains)
510     {
511         oldSwapchain.destroy(device, &mPresentSemaphoreRecycler);
512     }
513     mOldSwapchains.clear();
514 
515     if (mSurface)
516     {
517         vkDestroySurfaceKHR(instance, mSurface, nullptr);
518         mSurface = VK_NULL_HANDLE;
519     }
520 
521     mAcquireImageSemaphore.destroy(device);
522     mPresentSemaphoreRecycler.destroy(device);
523 }
524 
initialize(const egl::Display * display)525 egl::Error WindowSurfaceVk::initialize(const egl::Display *display)
526 {
527     DisplayVk *displayVk = vk::GetImpl(display);
528     angle::Result result = initializeImpl(displayVk);
529     if (result == angle::Result::Incomplete)
530     {
531         return angle::ToEGL(result, displayVk, EGL_BAD_MATCH);
532     }
533     else
534     {
535         return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
536     }
537 }
538 
initializeImpl(DisplayVk * displayVk)539 angle::Result WindowSurfaceVk::initializeImpl(DisplayVk *displayVk)
540 {
541     RendererVk *renderer = displayVk->getRenderer();
542 
543     renderer->reloadVolkIfNeeded();
544 
545     gl::Extents windowSize;
546     ANGLE_TRY(createSurfaceVk(displayVk, &windowSize));
547 
548     uint32_t presentQueue = 0;
549     ANGLE_TRY(renderer->selectPresentQueueForSurface(displayVk, mSurface, &presentQueue));
550     ANGLE_UNUSED_VARIABLE(presentQueue);
551 
552     const VkPhysicalDevice &physicalDevice = renderer->getPhysicalDevice();
553 
554     ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface,
555                                                                       &mSurfaceCaps));
556 
557     // Adjust width and height to the swapchain if necessary.
558     uint32_t width  = mSurfaceCaps.currentExtent.width;
559     uint32_t height = mSurfaceCaps.currentExtent.height;
560 
561     // TODO(jmadill): Support devices which don't support copy. We use this for ReadPixels.
562     ANGLE_VK_CHECK(displayVk,
563                    (mSurfaceCaps.supportedUsageFlags & kSurfaceVKColorImageUsageFlags) ==
564                        kSurfaceVKColorImageUsageFlags,
565                    VK_ERROR_INITIALIZATION_FAILED);
566 
567     EGLAttrib attribWidth  = mState.attributes.get(EGL_WIDTH, 0);
568     EGLAttrib attribHeight = mState.attributes.get(EGL_HEIGHT, 0);
569 
570     if (mSurfaceCaps.currentExtent.width == kSurfaceSizedBySwapchain)
571     {
572         ASSERT(mSurfaceCaps.currentExtent.height == kSurfaceSizedBySwapchain);
573 
574         width  = (attribWidth != 0) ? static_cast<uint32_t>(attribWidth) : windowSize.width;
575         height = (attribHeight != 0) ? static_cast<uint32_t>(attribHeight) : windowSize.height;
576     }
577 
578     gl::Extents extents(static_cast<int>(width), static_cast<int>(height), 1);
579 
580     if (renderer->getFeatures().enablePreRotateSurfaces.enabled)
581     {
582         // Use the surface's transform.  For many platforms, this will always be identity (ANGLE
583         // does not need to do any pre-rotation).  However, when mSurfaceCaps.currentTransform is
584         // not identity, the device has been rotated away from its natural orientation.  In such a
585         // case, ANGLE must rotate all rendering in order to avoid the compositor
586         // (e.g. SurfaceFlinger on Android) performing an additional rotation blit.  In addition,
587         // ANGLE must create the swapchain with VkSwapchainCreateInfoKHR::preTransform set to the
588         // value of mSurfaceCaps.currentTransform.
589         mPreTransform = mSurfaceCaps.currentTransform;
590     }
591     else
592     {
593         // Default to identity transform.
594         mPreTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
595         if ((mSurfaceCaps.supportedTransforms & mPreTransform) == 0)
596         {
597             mPreTransform = mSurfaceCaps.currentTransform;
598         }
599     }
600 
601     uint32_t presentModeCount = 0;
602     ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, mSurface,
603                                                                       &presentModeCount, nullptr));
604     ASSERT(presentModeCount > 0);
605 
606     mPresentModes.resize(presentModeCount);
607     ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfacePresentModesKHR(
608                                 physicalDevice, mSurface, &presentModeCount, mPresentModes.data()));
609 
610     // Select appropriate present mode based on vsync parameter.  Default to 1 (FIFO), though it
611     // will get clamped to the min/max values specified at display creation time.
612     setSwapInterval(renderer->getFeatures().disableFifoPresentMode.enabled ? 0 : 1);
613 
614     uint32_t surfaceFormatCount = 0;
615     ANGLE_VK_TRY(displayVk, vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface,
616                                                                  &surfaceFormatCount, nullptr));
617 
618     std::vector<VkSurfaceFormatKHR> surfaceFormats(surfaceFormatCount);
619     ANGLE_VK_TRY(displayVk,
620                  vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, mSurface, &surfaceFormatCount,
621                                                       surfaceFormats.data()));
622 
623     const vk::Format &format = renderer->getFormat(mState.config->renderTargetFormat);
624     VkFormat nativeFormat    = format.vkImageFormat;
625 
626     if (surfaceFormatCount == 1u && surfaceFormats[0].format == VK_FORMAT_UNDEFINED)
627     {
628         // This is fine.
629     }
630     else
631     {
632         bool foundFormat = false;
633         for (const VkSurfaceFormatKHR &surfaceFormat : surfaceFormats)
634         {
635             if (surfaceFormat.format == nativeFormat)
636             {
637                 foundFormat = true;
638                 break;
639             }
640         }
641 
642         // If a non-linear colorspace was requested but the non-linear format is
643         // not supported as a vulkan surface format, treat it as a non-fatal error
644         if (!foundFormat)
645         {
646             return angle::Result::Incomplete;
647         }
648     }
649 
650     mCompositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
651     if ((mSurfaceCaps.supportedCompositeAlpha & mCompositeAlpha) == 0)
652     {
653         mCompositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR;
654     }
655     ANGLE_VK_CHECK(displayVk, (mSurfaceCaps.supportedCompositeAlpha & mCompositeAlpha) != 0,
656                    VK_ERROR_INITIALIZATION_FAILED);
657 
658     ANGLE_TRY(createSwapChain(displayVk, extents, VK_NULL_HANDLE));
659 
660     VkResult vkResult = nextSwapchainImage(displayVk);
661     // VK_SUBOPTIMAL_KHR is ok since we still have an Image that can be presented successfully
662     if (ANGLE_UNLIKELY((vkResult != VK_SUCCESS) && (vkResult != VK_SUBOPTIMAL_KHR)))
663     {
664         ANGLE_VK_TRY(displayVk, vkResult);
665     }
666 
667     return angle::Result::Continue;
668 }
669 
recreateSwapchain(ContextVk * contextVk,const gl::Extents & extents,uint32_t swapHistoryIndex)670 angle::Result WindowSurfaceVk::recreateSwapchain(ContextVk *contextVk,
671                                                  const gl::Extents &extents,
672                                                  uint32_t swapHistoryIndex)
673 {
674     // If mOldSwapchains is not empty, it means that a new swapchain was created, but before
675     // any of its images were presented, it's asked to be recreated.  In this case, we can destroy
676     // the current swapchain immediately (although the old swapchains still need to be kept to be
677     // scheduled for destruction).  This can happen for example if vkQueuePresentKHR returns
678     // OUT_OF_DATE, the swapchain is recreated and the following vkAcquireNextImageKHR again
679     // returns OUT_OF_DATE.
680     //
681     // Otherwise, keep the current swapchain as the old swapchain to be scheduled for destruction
682     // and create a new one.
683 
684     VkSwapchainKHR swapchainToDestroy = VK_NULL_HANDLE;
685 
686     if (!mOldSwapchains.empty())
687     {
688         // Keep the old swapchain, destroy the current (never-used) swapchain.
689         swapchainToDestroy = mSwapchain;
690 
691         // Recycle present semaphores.
692         for (SwapchainImage &swapchainImage : mSwapchainImages)
693         {
694             for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
695             {
696                 ASSERT(presentHistory.semaphore.valid());
697                 ASSERT(presentHistory.oldSwapchains.empty());
698 
699                 mPresentSemaphoreRecycler.recycle(std::move(presentHistory.semaphore));
700             }
701         }
702     }
703     else
704     {
705         SwapchainCleanupData cleanupData;
706 
707         // Remember the current swapchain to be scheduled for destruction later.
708         cleanupData.swapchain = mSwapchain;
709 
710         // Accumulate the semaphores to be destroyed at the same time as the swapchain.
711         for (SwapchainImage &swapchainImage : mSwapchainImages)
712         {
713             for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
714             {
715                 ASSERT(presentHistory.semaphore.valid());
716                 cleanupData.semaphores.emplace_back(std::move(presentHistory.semaphore));
717 
718                 // Accumulate any previous swapchains that are pending destruction too.
719                 for (SwapchainCleanupData &oldSwapchain : presentHistory.oldSwapchains)
720                 {
721                     mOldSwapchains.emplace_back(std::move(oldSwapchain));
722                 }
723                 presentHistory.oldSwapchains.clear();
724             }
725         }
726 
727         // If too many old swapchains have accumulated, wait idle and destroy them.  This is to
728         // prevent failures due to too many swapchains allocated.
729         //
730         // Note: Nvidia has been observed to fail creation of swapchains after 20 are allocated on
731         // desktop, or less than 10 on Quadro P400.
732         static constexpr size_t kMaxOldSwapchains = 5;
733         if (mOldSwapchains.size() > kMaxOldSwapchains)
734         {
735             ANGLE_TRY(contextVk->getRenderer()->queueWaitIdle(contextVk, contextVk->getPriority()));
736             for (SwapchainCleanupData &oldSwapchain : mOldSwapchains)
737             {
738                 oldSwapchain.destroy(contextVk->getDevice(), &mPresentSemaphoreRecycler);
739             }
740             mOldSwapchains.clear();
741         }
742 
743         mOldSwapchains.emplace_back(std::move(cleanupData));
744     }
745 
746     // Recreate the swapchain based on the most recent one.
747     VkSwapchainKHR lastSwapchain = mSwapchain;
748     mSwapchain                   = VK_NULL_HANDLE;
749 
750     releaseSwapchainImages(contextVk);
751 
752     angle::Result result = createSwapChain(contextVk, extents, lastSwapchain);
753 
754     // If the most recent swapchain was never used, destroy it right now.
755     if (swapchainToDestroy)
756     {
757         vkDestroySwapchainKHR(contextVk->getDevice(), swapchainToDestroy, nullptr);
758     }
759 
760     return result;
761 }
762 
newPresentSemaphore(vk::Context * context,vk::Semaphore * semaphoreOut)763 angle::Result WindowSurfaceVk::newPresentSemaphore(vk::Context *context,
764                                                    vk::Semaphore *semaphoreOut)
765 {
766     if (mPresentSemaphoreRecycler.empty())
767     {
768         ANGLE_VK_TRY(context, semaphoreOut->init(context->getDevice()));
769     }
770     else
771     {
772         mPresentSemaphoreRecycler.fetch(semaphoreOut);
773     }
774     return angle::Result::Continue;
775 }
776 
MapEglColorSpaceToVkColorSpace(EGLenum EGLColorspace)777 static VkColorSpaceKHR MapEglColorSpaceToVkColorSpace(EGLenum EGLColorspace)
778 {
779     switch (EGLColorspace)
780     {
781         case EGL_NONE:
782         case EGL_GL_COLORSPACE_LINEAR:
783         case EGL_GL_COLORSPACE_SRGB_KHR:
784         case EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT:
785             return VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
786         case EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT:
787             return VK_COLOR_SPACE_DISPLAY_P3_LINEAR_EXT;
788         case EGL_GL_COLORSPACE_DISPLAY_P3_EXT:
789             return VK_COLOR_SPACE_DISPLAY_P3_NONLINEAR_EXT;
790         case EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT:
791             return VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT;
792         case EGL_GL_COLORSPACE_SCRGB_EXT:
793             return VK_COLOR_SPACE_EXTENDED_SRGB_NONLINEAR_EXT;
794         default:
795             UNREACHABLE();
796             return VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
797     }
798 }
799 
resizeSwapchainImages(vk::Context * context,uint32_t imageCount)800 angle::Result WindowSurfaceVk::resizeSwapchainImages(vk::Context *context, uint32_t imageCount)
801 {
802     if (static_cast<size_t>(imageCount) != mSwapchainImages.size())
803     {
804         mSwapchainImageBindings.clear();
805         mSwapchainImages.resize(imageCount);
806 
807         // Update the image bindings. Because the observer binding class uses raw pointers we
808         // need to first ensure the entire image vector is fully allocated before binding the
809         // subject and observer together.
810         for (uint32_t index = 0; index < imageCount; ++index)
811         {
812             mSwapchainImageBindings.push_back(
813                 angle::ObserverBinding(this, kAnySurfaceImageSubjectIndex));
814         }
815 
816         for (uint32_t index = 0; index < imageCount; ++index)
817         {
818             mSwapchainImageBindings[index].bind(&mSwapchainImages[index].image);
819         }
820     }
821 
822     // At this point, if there was a previous swapchain, the previous present semaphores have all
823     // been moved to mOldSwapchains to be scheduled for destruction, so all semaphore handles in
824     // mSwapchainImages should be invalid.
825     for (SwapchainImage &swapchainImage : mSwapchainImages)
826     {
827         for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
828         {
829             ASSERT(!presentHistory.semaphore.valid());
830             ANGLE_TRY(newPresentSemaphore(context, &presentHistory.semaphore));
831         }
832     }
833 
834     return angle::Result::Continue;
835 }
836 
createSwapChain(vk::Context * context,const gl::Extents & extents,VkSwapchainKHR lastSwapchain)837 angle::Result WindowSurfaceVk::createSwapChain(vk::Context *context,
838                                                const gl::Extents &extents,
839                                                VkSwapchainKHR lastSwapchain)
840 {
841     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::createSwapchain");
842 
843     ASSERT(mSwapchain == VK_NULL_HANDLE);
844 
845     RendererVk *renderer = context->getRenderer();
846     VkDevice device      = renderer->getDevice();
847 
848     const vk::Format &format = renderer->getFormat(mState.config->renderTargetFormat);
849     VkFormat nativeFormat    = format.vkImageFormat;
850 
851     gl::Extents rotatedExtents = extents;
852     if (Is90DegreeRotation(mPreTransform))
853     {
854         // The Surface is oriented such that its aspect ratio no longer matches that of the
855         // device.  In this case, the width and height of the swapchain images must be swapped to
856         // match the device's native orientation.  This must also be done for other attachments
857         // used with the swapchain (e.g. depth buffer).  The width and height of the viewport,
858         // scissor, and render-pass render area must also be swapped.  Then, when ANGLE rotates
859         // gl_Position in the vertex shader, the rendering will look the same as if no
860         // pre-rotation had been done.
861         std::swap(rotatedExtents.width, rotatedExtents.height);
862     }
863 
864     // We need transfer src for reading back from the backbuffer.
865     VkImageUsageFlags imageUsageFlags = kSurfaceVKColorImageUsageFlags;
866 
867 #if ANGLE_ENABLE_OVERLAY
868     // We need storage image for compute writes (debug overlay output).
869     VkFormatFeatureFlags featureBits =
870         renderer->getImageFormatFeatureBits(nativeFormat, VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT);
871     if ((featureBits & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT) != 0)
872     {
873         imageUsageFlags |= VK_IMAGE_USAGE_STORAGE_BIT;
874     }
875 #endif
876 
877     VkSwapchainCreateInfoKHR swapchainInfo = {};
878     swapchainInfo.sType                    = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
879     swapchainInfo.flags                    = 0;
880     swapchainInfo.surface                  = mSurface;
881     swapchainInfo.minImageCount            = mMinImageCount;
882     swapchainInfo.imageFormat              = nativeFormat;
883     swapchainInfo.imageColorSpace          = MapEglColorSpaceToVkColorSpace(
884         static_cast<EGLenum>(mState.attributes.get(EGL_GL_COLORSPACE, EGL_NONE)));
885     // Note: Vulkan doesn't allow 0-width/height swapchains.
886     swapchainInfo.imageExtent.width     = std::max(rotatedExtents.width, 1);
887     swapchainInfo.imageExtent.height    = std::max(rotatedExtents.height, 1);
888     swapchainInfo.imageArrayLayers      = 1;
889     swapchainInfo.imageUsage            = imageUsageFlags;
890     swapchainInfo.imageSharingMode      = VK_SHARING_MODE_EXCLUSIVE;
891     swapchainInfo.queueFamilyIndexCount = 0;
892     swapchainInfo.pQueueFamilyIndices   = nullptr;
893     swapchainInfo.preTransform          = mPreTransform;
894     swapchainInfo.compositeAlpha        = mCompositeAlpha;
895     swapchainInfo.presentMode           = mDesiredSwapchainPresentMode;
896     swapchainInfo.clipped               = VK_TRUE;
897     swapchainInfo.oldSwapchain          = lastSwapchain;
898 
899     // TODO(syoussefi): Once EGL_SWAP_BEHAVIOR_PRESERVED_BIT is supported, the contents of the old
900     // swapchain need to carry over to the new one.  http://anglebug.com/2942
901     VkSwapchainKHR newSwapChain = VK_NULL_HANDLE;
902     ANGLE_VK_TRY(context, vkCreateSwapchainKHR(device, &swapchainInfo, nullptr, &newSwapChain));
903     mSwapchain            = newSwapChain;
904     mSwapchainPresentMode = mDesiredSwapchainPresentMode;
905 
906     // Intialize the swapchain image views.
907     uint32_t imageCount = 0;
908     ANGLE_VK_TRY(context, vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, nullptr));
909 
910     std::vector<VkImage> swapchainImages(imageCount);
911     ANGLE_VK_TRY(context,
912                  vkGetSwapchainImagesKHR(device, mSwapchain, &imageCount, swapchainImages.data()));
913 
914     // If multisampling is enabled, create a multisampled image which gets resolved just prior to
915     // present.
916     GLint samples = GetSampleCount(mState.config);
917     ANGLE_VK_CHECK(context, samples > 0, VK_ERROR_INITIALIZATION_FAILED);
918 
919     VkExtent3D vkExtents;
920     gl_vk::GetExtent(rotatedExtents, &vkExtents);
921 
922     if (samples > 1)
923     {
924         const VkImageUsageFlags usage = kSurfaceVKColorImageUsageFlags;
925 
926         ANGLE_TRY(mColorImageMS.init(context, gl::TextureType::_2D, vkExtents, format, samples,
927                                      usage, 0, 0, 1, 1));
928         ANGLE_TRY(mColorImageMS.initMemory(context, renderer->getMemoryProperties(),
929                                            VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
930 
931         // Initialize the color render target with the multisampled targets.  If not multisampled,
932         // the render target will be updated to refer to a swapchain image on every acquire.
933         mColorRenderTarget.init(&mColorImageMS, &mColorImageMSViews, 0, 0);
934     }
935 
936     ANGLE_TRY(resizeSwapchainImages(context, imageCount));
937 
938     for (uint32_t imageIndex = 0; imageIndex < imageCount; ++imageIndex)
939     {
940         SwapchainImage &member = mSwapchainImages[imageIndex];
941         member.image.init2DWeakReference(context, swapchainImages[imageIndex], extents, format, 1);
942     }
943 
944     // Initialize depth/stencil if requested.
945     if (mState.config->depthStencilFormat != GL_NONE)
946     {
947         const vk::Format &dsFormat = renderer->getFormat(mState.config->depthStencilFormat);
948 
949         const VkImageUsageFlags dsUsage = kSurfaceVKDepthStencilImageUsageFlags;
950 
951         ANGLE_TRY(mDepthStencilImage.init(context, gl::TextureType::_2D, vkExtents, dsFormat,
952                                           samples, dsUsage, 0, 0, 1, 1));
953         ANGLE_TRY(mDepthStencilImage.initMemory(context, renderer->getMemoryProperties(),
954                                                 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT));
955 
956         mDepthStencilRenderTarget.init(&mDepthStencilImage, &mDepthStencilImageViews, 0, 0);
957 
958         // We will need to pass depth/stencil image views to the RenderTargetVk in the future.
959     }
960 
961     return angle::Result::Continue;
962 }
963 
isMultiSampled() const964 bool WindowSurfaceVk::isMultiSampled() const
965 {
966     return mColorImageMS.valid();
967 }
968 
checkForOutOfDateSwapchain(ContextVk * contextVk,uint32_t swapHistoryIndex,bool presentOutOfDate)969 angle::Result WindowSurfaceVk::checkForOutOfDateSwapchain(ContextVk *contextVk,
970                                                           uint32_t swapHistoryIndex,
971                                                           bool presentOutOfDate)
972 {
973     bool swapIntervalChanged = mSwapchainPresentMode != mDesiredSwapchainPresentMode;
974 
975     // If anything has changed, recreate the swapchain.
976     if (swapIntervalChanged || presentOutOfDate ||
977         contextVk->getRenderer()->getFeatures().perFrameWindowSizeQuery.enabled)
978     {
979         gl::Extents swapchainExtents(getWidth(), getHeight(), 1);
980 
981         gl::Extents currentExtents;
982         ANGLE_TRY(getCurrentWindowSize(contextVk, &currentExtents));
983 
984         // If window size has changed, check with surface capabilities.  It has been observed on
985         // Android that `getCurrentWindowSize()` returns 1920x1080 for example, while surface
986         // capabilities returns the size the surface was created with.
987         const VkPhysicalDevice &physicalDevice = contextVk->getRenderer()->getPhysicalDevice();
988         ANGLE_VK_TRY(contextVk, vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface,
989                                                                           &mSurfaceCaps));
990         if (contextVk->getFeatures().enablePreRotateSurfaces.enabled)
991         {
992             // Update the surface's transform, which can change even if the window size does not.
993             mPreTransform = mSurfaceCaps.currentTransform;
994         }
995 
996         if (currentExtents != swapchainExtents)
997         {
998             uint32_t width  = mSurfaceCaps.currentExtent.width;
999             uint32_t height = mSurfaceCaps.currentExtent.height;
1000 
1001             if (width != kSurfaceSizedBySwapchain)
1002             {
1003                 ASSERT(height != kSurfaceSizedBySwapchain);
1004                 currentExtents.width  = width;
1005                 currentExtents.height = height;
1006             }
1007         }
1008 
1009         // Check for window resize and recreate swapchain if necessary.
1010         // Work-around for some device which does not return OUT_OF_DATE after window resizing
1011         if (swapIntervalChanged || presentOutOfDate || currentExtents != swapchainExtents)
1012         {
1013             ANGLE_TRY(recreateSwapchain(contextVk, currentExtents, swapHistoryIndex));
1014         }
1015     }
1016 
1017     return angle::Result::Continue;
1018 }
1019 
releaseSwapchainImages(ContextVk * contextVk)1020 void WindowSurfaceVk::releaseSwapchainImages(ContextVk *contextVk)
1021 {
1022     RendererVk *renderer = contextVk->getRenderer();
1023 
1024     if (mDepthStencilImage.valid())
1025     {
1026         mDepthStencilImage.releaseImage(renderer);
1027         mDepthStencilImage.releaseStagingBuffer(renderer);
1028         mDepthStencilImageViews.release(renderer);
1029     }
1030 
1031     if (mColorImageMS.valid())
1032     {
1033         mColorImageMS.releaseImage(renderer);
1034         mColorImageMS.releaseStagingBuffer(renderer);
1035         mColorImageMSViews.release(renderer);
1036         contextVk->addGarbage(&mFramebufferMS);
1037     }
1038 
1039     mSwapchainImageBindings.clear();
1040 
1041     for (SwapchainImage &swapchainImage : mSwapchainImages)
1042     {
1043         // We don't own the swapchain image handles, so we just remove our reference to it.
1044         swapchainImage.image.resetImageWeakReference();
1045         swapchainImage.image.destroy(renderer);
1046 
1047         swapchainImage.imageViews.release(renderer);
1048         contextVk->addGarbage(&swapchainImage.framebuffer);
1049 
1050         // present history must have already been taken care of.
1051         for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
1052         {
1053             ASSERT(!presentHistory.semaphore.valid());
1054             ASSERT(presentHistory.oldSwapchains.empty());
1055         }
1056     }
1057 
1058     mSwapchainImages.clear();
1059 }
1060 
destroySwapChainImages(DisplayVk * displayVk)1061 void WindowSurfaceVk::destroySwapChainImages(DisplayVk *displayVk)
1062 {
1063     RendererVk *renderer = displayVk->getRenderer();
1064     VkDevice device      = displayVk->getDevice();
1065 
1066     mDepthStencilImage.destroy(renderer);
1067     mDepthStencilImageViews.destroy(device);
1068     mColorImageMS.destroy(renderer);
1069     mColorImageMSViews.destroy(device);
1070     mFramebufferMS.destroy(device);
1071 
1072     for (SwapchainImage &swapchainImage : mSwapchainImages)
1073     {
1074         // We don't own the swapchain image handles, so we just remove our reference to it.
1075         swapchainImage.image.resetImageWeakReference();
1076         swapchainImage.image.destroy(renderer);
1077         swapchainImage.imageViews.destroy(device);
1078         swapchainImage.framebuffer.destroy(device);
1079 
1080         for (ImagePresentHistory &presentHistory : swapchainImage.presentHistory)
1081         {
1082             ASSERT(presentHistory.semaphore.valid());
1083 
1084             mPresentSemaphoreRecycler.recycle(std::move(presentHistory.semaphore));
1085             for (SwapchainCleanupData &oldSwapchain : presentHistory.oldSwapchains)
1086             {
1087                 oldSwapchain.destroy(device, &mPresentSemaphoreRecycler);
1088             }
1089             presentHistory.oldSwapchains.clear();
1090         }
1091     }
1092 
1093     mSwapchainImages.clear();
1094 }
1095 
createDefaultFramebuffer(const gl::Context * context,const gl::FramebufferState & state)1096 FramebufferImpl *WindowSurfaceVk::createDefaultFramebuffer(const gl::Context *context,
1097                                                            const gl::FramebufferState &state)
1098 {
1099     RendererVk *renderer = vk::GetImpl(context)->getRenderer();
1100     return FramebufferVk::CreateDefaultFBO(renderer, state, this);
1101 }
1102 
swapWithDamage(const gl::Context * context,EGLint * rects,EGLint n_rects)1103 egl::Error WindowSurfaceVk::swapWithDamage(const gl::Context *context,
1104                                            EGLint *rects,
1105                                            EGLint n_rects)
1106 {
1107     DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
1108     angle::Result result = swapImpl(context, rects, n_rects, nullptr);
1109     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
1110 }
1111 
swap(const gl::Context * context)1112 egl::Error WindowSurfaceVk::swap(const gl::Context *context)
1113 {
1114     DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
1115     angle::Result result = swapImpl(context, nullptr, 0, nullptr);
1116     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
1117 }
1118 
present(ContextVk * contextVk,EGLint * rects,EGLint n_rects,const void * pNextChain,bool * presentOutOfDate)1119 angle::Result WindowSurfaceVk::present(ContextVk *contextVk,
1120                                        EGLint *rects,
1121                                        EGLint n_rects,
1122                                        const void *pNextChain,
1123                                        bool *presentOutOfDate)
1124 {
1125     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::present");
1126 
1127     // Throttle the submissions to avoid getting too far ahead of the GPU.
1128     SwapHistory &swap = mSwapHistory[mCurrentSwapHistoryIndex];
1129     {
1130         ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::present: Throttle CPU");
1131         if (swap.sharedFence.isReferenced())
1132         {
1133             ANGLE_TRY(swap.waitFence(contextVk));
1134             swap.destroy(contextVk->getRenderer());
1135         }
1136     }
1137 
1138     SwapchainImage &image               = mSwapchainImages[mCurrentSwapchainImageIndex];
1139     vk::Framebuffer &currentFramebuffer = mSwapchainImages[mCurrentSwapchainImageIndex].framebuffer;
1140     updateOverlay(contextVk);
1141     bool overlayHasWidget = overlayHasEnabledWidget(contextVk);
1142 
1143     // We can only do present related optimization if this is the last renderpass that touches the
1144     // swapchain image. MSAA resolve and overlay will insert another renderpass which disqualifies
1145     // the optimization.
1146     if (!mColorImageMS.valid() && !overlayHasWidget && currentFramebuffer.valid())
1147     {
1148         contextVk->optimizeRenderPassForPresent(currentFramebuffer.getHandle());
1149     }
1150 
1151     vk::CommandBuffer *commandBuffer = nullptr;
1152     ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
1153 
1154     if (mColorImageMS.valid())
1155     {
1156         // Transition the multisampled image to TRANSFER_SRC for resolve.
1157         ANGLE_TRY(contextVk->onImageRead(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferSrc,
1158                                          &mColorImageMS));
1159         ANGLE_TRY(contextVk->onImageWrite(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::TransferDst,
1160                                           &image.image));
1161         ANGLE_TRY(contextVk->endRenderPassAndGetCommandBuffer(&commandBuffer));
1162 
1163         VkImageResolve resolveRegion                = {};
1164         resolveRegion.srcSubresource.aspectMask     = VK_IMAGE_ASPECT_COLOR_BIT;
1165         resolveRegion.srcSubresource.mipLevel       = 0;
1166         resolveRegion.srcSubresource.baseArrayLayer = 0;
1167         resolveRegion.srcSubresource.layerCount     = 1;
1168         resolveRegion.srcOffset                     = {};
1169         resolveRegion.dstSubresource                = resolveRegion.srcSubresource;
1170         resolveRegion.dstOffset                     = {};
1171         resolveRegion.extent                        = image.image.getExtents();
1172 
1173         mColorImageMS.resolve(&image.image, resolveRegion, commandBuffer);
1174     }
1175 
1176     if (overlayHasWidget)
1177     {
1178         ANGLE_TRY(drawOverlay(contextVk, &image));
1179     }
1180 
1181     // This does nothing if it already in the requested layout
1182     image.image.changeLayout(VK_IMAGE_ASPECT_COLOR_BIT, vk::ImageLayout::Present, commandBuffer);
1183 
1184     // Knowing that the kSwapHistorySize'th submission ago has finished, we can know that the
1185     // (kSwapHistorySize+1)'th present ago of this image is definitely finished and so its wait
1186     // semaphore can be reused.  See doc/PresentSemaphores.md for details.
1187     //
1188     // This also means the swapchain(s) scheduled to be deleted at the same time can be deleted.
1189     ImagePresentHistory &presentHistory = image.presentHistory[image.currentPresentHistoryIndex];
1190     vk::Semaphore *presentSemaphore     = &presentHistory.semaphore;
1191     ASSERT(presentSemaphore->valid());
1192 
1193     for (SwapchainCleanupData &oldSwapchain : presentHistory.oldSwapchains)
1194     {
1195         oldSwapchain.destroy(contextVk->getDevice(), &mPresentSemaphoreRecycler);
1196     }
1197     presentHistory.oldSwapchains.clear();
1198 
1199     // Schedule pending old swapchains to be destroyed at the same time the semaphore for this
1200     // present can be destroyed.
1201     presentHistory.oldSwapchains = std::move(mOldSwapchains);
1202 
1203     image.currentPresentHistoryIndex =
1204         (image.currentPresentHistoryIndex + 1) % image.presentHistory.size();
1205 
1206     ANGLE_TRY(contextVk->flushImpl(presentSemaphore));
1207 
1208     VkPresentInfoKHR presentInfo   = {};
1209     presentInfo.sType              = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
1210     presentInfo.pNext              = pNextChain;
1211     presentInfo.waitSemaphoreCount = 1;
1212     presentInfo.pWaitSemaphores    = presentSemaphore->ptr();
1213     presentInfo.swapchainCount     = 1;
1214     presentInfo.pSwapchains        = &mSwapchain;
1215     presentInfo.pImageIndices      = &mCurrentSwapchainImageIndex;
1216     presentInfo.pResults           = nullptr;
1217 
1218     VkPresentRegionKHR presentRegion   = {};
1219     VkPresentRegionsKHR presentRegions = {};
1220     std::vector<VkRectLayerKHR> vkRects;
1221     if (contextVk->getFeatures().supportsIncrementalPresent.enabled && (n_rects > 0))
1222     {
1223         EGLint width  = getWidth();
1224         EGLint height = getHeight();
1225 
1226         EGLint *eglRects             = rects;
1227         presentRegion.rectangleCount = n_rects;
1228         vkRects.resize(n_rects);
1229         for (EGLint i = 0; i < n_rects; i++)
1230         {
1231             VkRectLayerKHR &rect = vkRects[i];
1232 
1233             // Make sure the damage rects are within swapchain bounds.
1234             rect.offset.x      = gl::clamp(*eglRects++, 0, width);
1235             rect.offset.y      = gl::clamp(*eglRects++, 0, height);
1236             rect.extent.width  = gl::clamp(*eglRects++, 0, width - rect.offset.x);
1237             rect.extent.height = gl::clamp(*eglRects++, 0, height - rect.offset.y);
1238             rect.layer         = 0;
1239         }
1240         presentRegion.pRectangles = vkRects.data();
1241 
1242         presentRegions.sType          = VK_STRUCTURE_TYPE_PRESENT_REGIONS_KHR;
1243         presentRegions.pNext          = nullptr;
1244         presentRegions.swapchainCount = 1;
1245         presentRegions.pRegions       = &presentRegion;
1246 
1247         presentInfo.pNext = &presentRegions;
1248     }
1249 
1250     // Update the swap history for this presentation
1251     swap.sharedFence = contextVk->getLastSubmittedFence();
1252     ASSERT(!mAcquireImageSemaphore.valid());
1253 
1254     ++mCurrentSwapHistoryIndex;
1255     mCurrentSwapHistoryIndex =
1256         mCurrentSwapHistoryIndex == mSwapHistory.size() ? 0 : mCurrentSwapHistoryIndex;
1257 
1258     VkResult result = contextVk->getRenderer()->queuePresent(contextVk->getPriority(), presentInfo);
1259 
1260     // If OUT_OF_DATE is returned, it's ok, we just need to recreate the swapchain before
1261     // continuing.
1262     // If VK_SUBOPTIMAL_KHR is returned it's because the device orientation changed and we should
1263     // recreate the swapchain with a new window orientation.
1264     if (contextVk->getFeatures().enablePreRotateSurfaces.enabled)
1265     {
1266         // Also check for VK_SUBOPTIMAL_KHR.
1267         *presentOutOfDate = ((result == VK_ERROR_OUT_OF_DATE_KHR) || (result == VK_SUBOPTIMAL_KHR));
1268         if (!*presentOutOfDate)
1269         {
1270             ANGLE_VK_TRY(contextVk, result);
1271         }
1272     }
1273     else
1274     {
1275         // We aren't quite ready for that so just ignore for now.
1276         *presentOutOfDate = result == VK_ERROR_OUT_OF_DATE_KHR;
1277         if (!*presentOutOfDate && result != VK_SUBOPTIMAL_KHR)
1278         {
1279             ANGLE_VK_TRY(contextVk, result);
1280         }
1281     }
1282 
1283     return angle::Result::Continue;
1284 }
1285 
swapImpl(const gl::Context * context,EGLint * rects,EGLint n_rects,const void * pNextChain)1286 angle::Result WindowSurfaceVk::swapImpl(const gl::Context *context,
1287                                         EGLint *rects,
1288                                         EGLint n_rects,
1289                                         const void *pNextChain)
1290 {
1291     ANGLE_TRACE_EVENT0("gpu.angle", "WindowSurfaceVk::swapImpl");
1292 
1293     ContextVk *contextVk = vk::GetImpl(context);
1294     DisplayVk *displayVk = vk::GetImpl(context->getDisplay());
1295 
1296     bool presentOutOfDate = false;
1297     // Save this now, since present() will increment the value.
1298     uint32_t currentSwapHistoryIndex = static_cast<uint32_t>(mCurrentSwapHistoryIndex);
1299 
1300     ANGLE_TRY(present(contextVk, rects, n_rects, pNextChain, &presentOutOfDate));
1301 
1302     ANGLE_TRY(checkForOutOfDateSwapchain(contextVk, currentSwapHistoryIndex, presentOutOfDate));
1303 
1304     {
1305         // Note: TRACE_EVENT0 is put here instead of inside the function to workaround this issue:
1306         // http://anglebug.com/2927
1307         ANGLE_TRACE_EVENT0("gpu.angle", "nextSwapchainImage");
1308         // Get the next available swapchain image.
1309 
1310         VkResult result = nextSwapchainImage(contextVk);
1311         // If SUBOPTIMAL/OUT_OF_DATE is returned, it's ok, we just need to recreate the swapchain
1312         // before continuing.
1313         if (ANGLE_UNLIKELY((result == VK_ERROR_OUT_OF_DATE_KHR) || (result == VK_SUBOPTIMAL_KHR)))
1314         {
1315             ANGLE_TRY(checkForOutOfDateSwapchain(contextVk, currentSwapHistoryIndex, true));
1316             // Try one more time and bail if we fail
1317             result = nextSwapchainImage(contextVk);
1318         }
1319         ANGLE_VK_TRY(contextVk, result);
1320     }
1321 
1322     RendererVk *renderer = contextVk->getRenderer();
1323     ANGLE_TRY(renderer->syncPipelineCacheVk(displayVk));
1324 
1325     return angle::Result::Continue;
1326 }
1327 
nextSwapchainImage(vk::Context * context)1328 VkResult WindowSurfaceVk::nextSwapchainImage(vk::Context *context)
1329 {
1330     VkDevice device = context->getDevice();
1331 
1332     vk::DeviceScoped<vk::Semaphore> acquireImageSemaphore(device);
1333     VkResult result = acquireImageSemaphore.get().init(device);
1334     if (ANGLE_UNLIKELY(result != VK_SUCCESS))
1335     {
1336         return result;
1337     }
1338 
1339     result = vkAcquireNextImageKHR(device, mSwapchain, UINT64_MAX,
1340                                    acquireImageSemaphore.get().getHandle(), VK_NULL_HANDLE,
1341                                    &mCurrentSwapchainImageIndex);
1342     if (ANGLE_UNLIKELY(result != VK_SUCCESS))
1343     {
1344         return result;
1345     }
1346 
1347     // The semaphore will be waited on in the next flush.
1348     mAcquireImageSemaphore = acquireImageSemaphore.release();
1349 
1350     SwapchainImage &image = mSwapchainImages[mCurrentSwapchainImageIndex];
1351 
1352     // Update RenderTarget pointers to this swapchain image if not multisampling.  Note: a possible
1353     // optimization is to defer the |vkAcquireNextImageKHR| call itself to |present()| if
1354     // multisampling, as the swapchain image is essentially unused until then.
1355     if (!mColorImageMS.valid())
1356     {
1357         mColorRenderTarget.updateSwapchainImage(&image.image, &image.imageViews);
1358     }
1359 
1360     // Notify the owning framebuffer there may be staged updates.
1361     if (image.image.hasStagedUpdates())
1362     {
1363         onStateChange(angle::SubjectMessage::SubjectChanged);
1364     }
1365 
1366     return VK_SUCCESS;
1367 }
1368 
postSubBuffer(const gl::Context * context,EGLint x,EGLint y,EGLint width,EGLint height)1369 egl::Error WindowSurfaceVk::postSubBuffer(const gl::Context *context,
1370                                           EGLint x,
1371                                           EGLint y,
1372                                           EGLint width,
1373                                           EGLint height)
1374 {
1375     // TODO(jmadill)
1376     return egl::NoError();
1377 }
1378 
querySurfacePointerANGLE(EGLint attribute,void ** value)1379 egl::Error WindowSurfaceVk::querySurfacePointerANGLE(EGLint attribute, void **value)
1380 {
1381     UNREACHABLE();
1382     return egl::EglBadCurrentSurface();
1383 }
1384 
bindTexImage(const gl::Context * context,gl::Texture * texture,EGLint buffer)1385 egl::Error WindowSurfaceVk::bindTexImage(const gl::Context *context,
1386                                          gl::Texture *texture,
1387                                          EGLint buffer)
1388 {
1389     return egl::NoError();
1390 }
1391 
releaseTexImage(const gl::Context * context,EGLint buffer)1392 egl::Error WindowSurfaceVk::releaseTexImage(const gl::Context *context, EGLint buffer)
1393 {
1394     return egl::NoError();
1395 }
1396 
getSyncValues(EGLuint64KHR *,EGLuint64KHR *,EGLuint64KHR *)1397 egl::Error WindowSurfaceVk::getSyncValues(EGLuint64KHR * /*ust*/,
1398                                           EGLuint64KHR * /*msc*/,
1399                                           EGLuint64KHR * /*sbc*/)
1400 {
1401     UNIMPLEMENTED();
1402     return egl::EglBadAccess();
1403 }
1404 
getMscRate(EGLint *,EGLint *)1405 egl::Error WindowSurfaceVk::getMscRate(EGLint * /*numerator*/, EGLint * /*denominator*/)
1406 {
1407     UNIMPLEMENTED();
1408     return egl::EglBadAccess();
1409 }
1410 
setSwapInterval(EGLint interval)1411 void WindowSurfaceVk::setSwapInterval(EGLint interval)
1412 {
1413     const EGLint minSwapInterval = mState.config->minSwapInterval;
1414     const EGLint maxSwapInterval = mState.config->maxSwapInterval;
1415     ASSERT(minSwapInterval == 0 || minSwapInterval == 1);
1416     ASSERT(maxSwapInterval == 0 || maxSwapInterval == 1);
1417 
1418     interval = gl::clamp(interval, minSwapInterval, maxSwapInterval);
1419 
1420     mDesiredSwapchainPresentMode = GetDesiredPresentMode(mPresentModes, interval);
1421 
1422     // - On mailbox, we need at least three images; one is being displayed to the user until the
1423     //   next v-sync, and the application alternatingly renders to the other two, one being
1424     //   recorded, and the other queued for presentation if v-sync happens in the meantime.
1425     // - On immediate, we need at least two images; the application alternates between the two
1426     //   images.
1427     // - On fifo, we use at least three images.  Triple-buffering allows us to present an image,
1428     //   have one in the queue, and record in another.  Note: on certain configurations (windows +
1429     //   nvidia + windowed mode), we could get away with a smaller number.
1430     //
1431     // For simplicity, we always allocate at least three images.
1432     mMinImageCount = std::max(3u, mSurfaceCaps.minImageCount);
1433 
1434     // Make sure we don't exceed maxImageCount.
1435     if (mSurfaceCaps.maxImageCount > 0 && mMinImageCount > mSurfaceCaps.maxImageCount)
1436     {
1437         mMinImageCount = mSurfaceCaps.maxImageCount;
1438     }
1439 
1440     // On the next swap, if the desired present mode is different from the current one, the
1441     // swapchain will be recreated.
1442 }
1443 
getWidth() const1444 EGLint WindowSurfaceVk::getWidth() const
1445 {
1446     return static_cast<EGLint>(mColorRenderTarget.getExtents().width);
1447 }
1448 
getHeight() const1449 EGLint WindowSurfaceVk::getHeight() const
1450 {
1451     return static_cast<EGLint>(mColorRenderTarget.getExtents().height);
1452 }
1453 
getUserWidth(const egl::Display * display,EGLint * value) const1454 egl::Error WindowSurfaceVk::getUserWidth(const egl::Display *display, EGLint *value) const
1455 {
1456     DisplayVk *displayVk = vk::GetImpl(display);
1457 
1458     if (mSurfaceCaps.currentExtent.width == kSurfaceSizedBySwapchain)
1459     {
1460         // Surface has no intrinsic size; use current size.
1461         *value = getWidth();
1462         return egl::NoError();
1463     }
1464 
1465     VkSurfaceCapabilitiesKHR surfaceCaps;
1466     angle::Result result = getUserExtentsImpl(displayVk, &surfaceCaps);
1467     if (result == angle::Result::Continue)
1468     {
1469         // The EGL spec states that value is not written if there is an error
1470         ASSERT(surfaceCaps.currentExtent.width != kSurfaceSizedBySwapchain);
1471         *value = static_cast<EGLint>(surfaceCaps.currentExtent.width);
1472     }
1473     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
1474 }
1475 
getUserHeight(const egl::Display * display,EGLint * value) const1476 egl::Error WindowSurfaceVk::getUserHeight(const egl::Display *display, EGLint *value) const
1477 {
1478     DisplayVk *displayVk = vk::GetImpl(display);
1479 
1480     if (mSurfaceCaps.currentExtent.height == kSurfaceSizedBySwapchain)
1481     {
1482         // Surface has no intrinsic size; use current size.
1483         *value = getHeight();
1484         return egl::NoError();
1485     }
1486 
1487     VkSurfaceCapabilitiesKHR surfaceCaps;
1488     angle::Result result = getUserExtentsImpl(displayVk, &surfaceCaps);
1489     if (result == angle::Result::Continue)
1490     {
1491         // The EGL spec states that value is not written if there is an error
1492         ASSERT(surfaceCaps.currentExtent.height != kSurfaceSizedBySwapchain);
1493         *value = static_cast<EGLint>(surfaceCaps.currentExtent.height);
1494     }
1495     return angle::ToEGL(result, displayVk, EGL_BAD_SURFACE);
1496 }
1497 
getUserExtentsImpl(DisplayVk * displayVk,VkSurfaceCapabilitiesKHR * surfaceCaps) const1498 angle::Result WindowSurfaceVk::getUserExtentsImpl(DisplayVk *displayVk,
1499                                                   VkSurfaceCapabilitiesKHR *surfaceCaps) const
1500 {
1501     const VkPhysicalDevice &physicalDevice = displayVk->getRenderer()->getPhysicalDevice();
1502 
1503     ANGLE_VK_TRY(displayVk,
1504                  vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, mSurface, surfaceCaps));
1505 
1506     return angle::Result::Continue;
1507 }
1508 
isPostSubBufferSupported() const1509 EGLint WindowSurfaceVk::isPostSubBufferSupported() const
1510 {
1511     // TODO(jmadill)
1512     return EGL_FALSE;
1513 }
1514 
getSwapBehavior() const1515 EGLint WindowSurfaceVk::getSwapBehavior() const
1516 {
1517     // TODO(jmadill)
1518     return EGL_BUFFER_DESTROYED;
1519 }
1520 
getCurrentFramebuffer(ContextVk * contextVk,const vk::RenderPass & compatibleRenderPass,vk::Framebuffer ** framebufferOut)1521 angle::Result WindowSurfaceVk::getCurrentFramebuffer(ContextVk *contextVk,
1522                                                      const vk::RenderPass &compatibleRenderPass,
1523                                                      vk::Framebuffer **framebufferOut)
1524 {
1525     vk::Framebuffer &currentFramebuffer =
1526         isMultiSampled() ? mFramebufferMS
1527                          : mSwapchainImages[mCurrentSwapchainImageIndex].framebuffer;
1528 
1529     if (currentFramebuffer.valid())
1530     {
1531         // Validation layers should detect if the render pass is really compatible.
1532         *framebufferOut = &currentFramebuffer;
1533         return angle::Result::Continue;
1534     }
1535 
1536     VkFramebufferCreateInfo framebufferInfo = {};
1537 
1538     const gl::Extents extents             = mColorRenderTarget.getExtents();
1539     std::array<VkImageView, 2> imageViews = {};
1540 
1541     if (mDepthStencilImage.valid())
1542     {
1543         const vk::ImageView *imageView = nullptr;
1544         ANGLE_TRY(mDepthStencilRenderTarget.getImageView(contextVk, &imageView));
1545         imageViews[1] = imageView->getHandle();
1546     }
1547 
1548     framebufferInfo.sType           = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
1549     framebufferInfo.flags           = 0;
1550     framebufferInfo.renderPass      = compatibleRenderPass.getHandle();
1551     framebufferInfo.attachmentCount = (mDepthStencilImage.valid() ? 2u : 1u);
1552     framebufferInfo.pAttachments    = imageViews.data();
1553     framebufferInfo.width           = static_cast<uint32_t>(extents.width);
1554     framebufferInfo.height          = static_cast<uint32_t>(extents.height);
1555     if (Is90DegreeRotation(mPreTransform))
1556     {
1557         std::swap(framebufferInfo.width, framebufferInfo.height);
1558     }
1559     framebufferInfo.layers = 1;
1560 
1561     if (isMultiSampled())
1562     {
1563         // If multisampled, there is only a single color image and framebuffer.
1564         const vk::ImageView *imageView = nullptr;
1565         ANGLE_TRY(mColorRenderTarget.getImageView(contextVk, &imageView));
1566         imageViews[0] = imageView->getHandle();
1567         ANGLE_VK_TRY(contextVk, mFramebufferMS.init(contextVk->getDevice(), framebufferInfo));
1568     }
1569     else
1570     {
1571         for (SwapchainImage &swapchainImage : mSwapchainImages)
1572         {
1573             const vk::ImageView *imageView = nullptr;
1574             ANGLE_TRY(swapchainImage.imageViews.getLevelLayerDrawImageView(
1575                 contextVk, swapchainImage.image, 0, 0, &imageView));
1576 
1577             imageViews[0] = imageView->getHandle();
1578             ANGLE_VK_TRY(contextVk,
1579                          swapchainImage.framebuffer.init(contextVk->getDevice(), framebufferInfo));
1580         }
1581     }
1582 
1583     ASSERT(currentFramebuffer.valid());
1584     *framebufferOut = &currentFramebuffer;
1585     return angle::Result::Continue;
1586 }
1587 
getAcquireImageSemaphore()1588 vk::Semaphore WindowSurfaceVk::getAcquireImageSemaphore()
1589 {
1590     return std::move(mAcquireImageSemaphore);
1591 }
1592 
initializeContents(const gl::Context * context,const gl::ImageIndex & imageIndex)1593 angle::Result WindowSurfaceVk::initializeContents(const gl::Context *context,
1594                                                   const gl::ImageIndex &imageIndex)
1595 {
1596     ContextVk *contextVk = vk::GetImpl(context);
1597 
1598     ASSERT(mSwapchainImages.size() > 0);
1599     ASSERT(mCurrentSwapchainImageIndex < mSwapchainImages.size());
1600 
1601     vk::ImageHelper *image =
1602         isMultiSampled() ? &mColorImageMS : &mSwapchainImages[mCurrentSwapchainImageIndex].image;
1603     image->stageRobustResourceClear(imageIndex);
1604     ANGLE_TRY(image->flushAllStagedUpdates(contextVk));
1605 
1606     if (mDepthStencilImage.valid())
1607     {
1608         mDepthStencilImage.stageRobustResourceClear(gl::ImageIndex::Make2D(0));
1609         ANGLE_TRY(mDepthStencilImage.flushAllStagedUpdates(contextVk));
1610     }
1611 
1612     return angle::Result::Continue;
1613 }
1614 
updateOverlay(ContextVk * contextVk) const1615 void WindowSurfaceVk::updateOverlay(ContextVk *contextVk) const
1616 {
1617     const gl::OverlayType *overlay = contextVk->getOverlay();
1618     OverlayVk *overlayVk           = vk::GetImpl(overlay);
1619 
1620     // If overlay is disabled, nothing to do.
1621     if (overlayVk == nullptr)
1622     {
1623         return;
1624     }
1625 
1626     RendererVk *rendererVk = contextVk->getRenderer();
1627 
1628     uint32_t validationMessageCount = 0;
1629     std::string lastValidationMessage =
1630         rendererVk->getAndClearLastValidationMessage(&validationMessageCount);
1631     if (validationMessageCount)
1632     {
1633         overlay->getTextWidget(gl::WidgetId::VulkanLastValidationMessage)
1634             ->set(std::move(lastValidationMessage));
1635         overlay->getCountWidget(gl::WidgetId::VulkanValidationMessageCount)
1636             ->add(validationMessageCount);
1637     }
1638 
1639     contextVk->updateOverlayOnPresent();
1640 }
1641 
overlayHasEnabledWidget(ContextVk * contextVk) const1642 ANGLE_INLINE bool WindowSurfaceVk::overlayHasEnabledWidget(ContextVk *contextVk) const
1643 {
1644     const gl::OverlayType *overlay = contextVk->getOverlay();
1645     OverlayVk *overlayVk           = vk::GetImpl(overlay);
1646     return overlayVk && overlayVk->getEnabledWidgetCount() > 0;
1647 }
1648 
drawOverlay(ContextVk * contextVk,SwapchainImage * image) const1649 angle::Result WindowSurfaceVk::drawOverlay(ContextVk *contextVk, SwapchainImage *image) const
1650 {
1651     const gl::OverlayType *overlay = contextVk->getOverlay();
1652     OverlayVk *overlayVk           = vk::GetImpl(overlay);
1653 
1654     // Draw overlay
1655     const vk::ImageView *imageView = nullptr;
1656     ANGLE_TRY(
1657         image->imageViews.getLevelLayerDrawImageView(contextVk, image->image, 0, 0, &imageView));
1658     ANGLE_TRY(overlayVk->onPresent(contextVk, &image->image, imageView));
1659 
1660     return angle::Result::Continue;
1661 }
1662 
1663 }  // namespace rx
1664