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