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, ¤tExtents));
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 ¤tFramebuffer = 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 ¤tFramebuffer = chooseFramebuffer(swapchainResolveMode);
2215 if (currentFramebuffer.valid())
2216 {
2217 // Validation layers should detect if the render pass is really compatible.
2218 *framebufferOut = ¤tFramebuffer;
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 = ¤tFramebuffer;
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