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