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