• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 Google LLC
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "tools/window/SkVulkanWindowContext.h"
9 
10 #include "include/core/SkSurface.h"
11 #include "include/gpu/GrBackendSemaphore.h"
12 #include "include/gpu/GrBackendSurface.h"
13 #include "include/gpu/GrDirectContext.h"
14 #include "src/base/SkAutoMalloc.h"
15 
16 #include "include/gpu/vk/GrVkTypes.h"
17 #include "include/gpu/vk/VulkanExtensions.h"
18 #include "src/gpu/ganesh/vk/GrVkImage.h"
19 #include "src/gpu/ganesh/vk/GrVkUtil.h"
20 #include "src/gpu/vk/VulkanInterface.h"
21 
22 #ifdef VK_USE_PLATFORM_WIN32_KHR
23 // windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
24 #undef CreateSemaphore
25 #endif
26 
27 #define GET_PROC(F) f ## F = \
28     (PFN_vk ## F) backendContext.fGetProc("vk" #F, fInstance, VK_NULL_HANDLE)
29 #define GET_DEV_PROC(F) f ## F = \
30     (PFN_vk ## F) backendContext.fGetProc("vk" #F, VK_NULL_HANDLE, fDevice)
31 
SkVulkanWindowContext(const SkDisplayParams & params,CreateVkSurfaceFn createVkSurface,CanPresentFn canPresent,PFN_vkGetInstanceProcAddr instProc)32 SkVulkanWindowContext::SkVulkanWindowContext(const SkDisplayParams& params,
33                                              CreateVkSurfaceFn createVkSurface,
34                                              CanPresentFn canPresent,
35                                              PFN_vkGetInstanceProcAddr instProc)
36     : SkWindowContext(params)
37     , fCreateVkSurfaceFn(createVkSurface)
38     , fCanPresentFn(canPresent)
39     , fSurface(VK_NULL_HANDLE)
40     , fSwapchain(VK_NULL_HANDLE)
41     , fImages(nullptr)
42     , fImageLayouts(nullptr)
43     , fSurfaces(nullptr)
44     , fBackbuffers(nullptr) {
45     fGetInstanceProcAddr = instProc;
46     this->initializeContext();
47 }
48 
initializeContext()49 void SkVulkanWindowContext::initializeContext() {
50     SkASSERT(!fContext);
51     // any config code here (particularly for msaa)?
52 
53     PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr;
54     GrVkBackendContext backendContext;
55     skgpu::VulkanExtensions extensions;
56     VkPhysicalDeviceFeatures2 features;
57     if (!sk_gpu_test::CreateVkBackendContext(getInstanceProc, &backendContext, &extensions,
58                                              &features, &fDebugCallback, &fPresentQueueIndex,
59                                              fCanPresentFn)) {
60         sk_gpu_test::FreeVulkanFeaturesStructs(&features);
61         return;
62     }
63 
64     if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME, 25) ||
65         !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 68)) {
66         sk_gpu_test::FreeVulkanFeaturesStructs(&features);
67         return;
68     }
69 
70     fInstance = backendContext.fInstance;
71     fPhysicalDevice = backendContext.fPhysicalDevice;
72     fDevice = backendContext.fDevice;
73     fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex;
74     fGraphicsQueue = backendContext.fQueue;
75 
76     PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties =
77             reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
78                     backendContext.fGetProc("vkGetPhysicalDeviceProperties",
79                                             backendContext.fInstance,
80                                             VK_NULL_HANDLE));
81     if (!localGetPhysicalDeviceProperties) {
82         sk_gpu_test::FreeVulkanFeaturesStructs(&features);
83         return;
84     }
85     VkPhysicalDeviceProperties physDeviceProperties;
86     localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties);
87     uint32_t physDevVersion = physDeviceProperties.apiVersion;
88 
89     fInterface.reset(new skgpu::VulkanInterface(backendContext.fGetProc, fInstance, fDevice,
90                                                 backendContext.fInstanceVersion, physDevVersion,
91                                                 &extensions));
92 
93     GET_PROC(DestroyInstance);
94     if (fDebugCallback != VK_NULL_HANDLE) {
95         GET_PROC(DestroyDebugReportCallbackEXT);
96     }
97     GET_PROC(DestroySurfaceKHR);
98     GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
99     GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
100     GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
101     GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
102     GET_DEV_PROC(DeviceWaitIdle);
103     GET_DEV_PROC(QueueWaitIdle);
104     GET_DEV_PROC(DestroyDevice);
105     GET_DEV_PROC(CreateSwapchainKHR);
106     GET_DEV_PROC(DestroySwapchainKHR);
107     GET_DEV_PROC(GetSwapchainImagesKHR);
108     GET_DEV_PROC(AcquireNextImageKHR);
109     GET_DEV_PROC(QueuePresentKHR);
110     GET_DEV_PROC(GetDeviceQueue);
111 
112     fContext = GrDirectContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions);
113 
114     fSurface = fCreateVkSurfaceFn(fInstance);
115     if (VK_NULL_HANDLE == fSurface) {
116         this->destroyContext();
117         sk_gpu_test::FreeVulkanFeaturesStructs(&features);
118         return;
119     }
120 
121     VkBool32 supported;
122     VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex,
123                                                        fSurface, &supported);
124     if (VK_SUCCESS != res) {
125         this->destroyContext();
126         sk_gpu_test::FreeVulkanFeaturesStructs(&features);
127         return;
128     }
129 
130     if (!this->createSwapchain(-1, -1, fDisplayParams)) {
131         this->destroyContext();
132         sk_gpu_test::FreeVulkanFeaturesStructs(&features);
133         return;
134     }
135 
136     // create presentQueue
137     fGetDeviceQueue(fDevice, fPresentQueueIndex, 0, &fPresentQueue);
138     sk_gpu_test::FreeVulkanFeaturesStructs(&features);
139 }
140 
createSwapchain(int width,int height,const SkDisplayParams & params)141 bool SkVulkanWindowContext::createSwapchain(int width, int height,
142                                           const SkDisplayParams& params) {
143     // check for capabilities
144     VkSurfaceCapabilitiesKHR caps;
145     VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fPhysicalDevice, fSurface, &caps);
146     if (VK_SUCCESS != res) {
147         return false;
148     }
149 
150     uint32_t surfaceFormatCount;
151     res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
152                                               nullptr);
153     if (VK_SUCCESS != res) {
154         return false;
155     }
156 
157     SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
158     VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
159     res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
160                                               surfaceFormats);
161     if (VK_SUCCESS != res) {
162         return false;
163     }
164 
165     uint32_t presentModeCount;
166     res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
167                                                    nullptr);
168     if (VK_SUCCESS != res) {
169         return false;
170     }
171 
172     SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
173     VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
174     res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
175                                                    presentModes);
176     if (VK_SUCCESS != res) {
177         return false;
178     }
179 
180     VkExtent2D extent = caps.currentExtent;
181     // use the hints
182     if (extent.width == (uint32_t)-1) {
183         extent.width = width;
184         extent.height = height;
185     }
186 
187     // clamp width; to protect us from broken hints
188     if (extent.width < caps.minImageExtent.width) {
189         extent.width = caps.minImageExtent.width;
190     } else if (extent.width > caps.maxImageExtent.width) {
191         extent.width = caps.maxImageExtent.width;
192     }
193     // clamp height
194     if (extent.height < caps.minImageExtent.height) {
195         extent.height = caps.minImageExtent.height;
196     } else if (extent.height > caps.maxImageExtent.height) {
197         extent.height = caps.maxImageExtent.height;
198     }
199 
200     fWidth = (int)extent.width;
201     fHeight = (int)extent.height;
202 
203     uint32_t imageCount = caps.minImageCount + 2;
204     if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
205         // Application must settle for fewer images than desired:
206         imageCount = caps.maxImageCount;
207     }
208 
209     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
210                                    VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
211                                    VK_IMAGE_USAGE_TRANSFER_DST_BIT;
212     SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
213     if (caps.supportedUsageFlags & VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT) {
214         usageFlags |= VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
215     }
216     if (caps.supportedUsageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
217         usageFlags |= VK_IMAGE_USAGE_SAMPLED_BIT;
218     }
219     SkASSERT(caps.supportedTransforms & caps.currentTransform);
220     SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
221                                              VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
222     VkCompositeAlphaFlagBitsKHR composite_alpha =
223         (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
224                                         VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
225                                         VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
226 
227     // Pick our surface format.
228     VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
229     VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
230     for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
231         VkFormat localFormat = surfaceFormats[i].format;
232         if (GrVkFormatIsSupported(localFormat)) {
233             surfaceFormat = localFormat;
234             colorSpace = surfaceFormats[i].colorSpace;
235             break;
236         }
237     }
238     fDisplayParams = params;
239     fSampleCount = std::max(1, params.fMSAASampleCount);
240     fStencilBits = 8;
241 
242     if (VK_FORMAT_UNDEFINED == surfaceFormat) {
243         return false;
244     }
245 
246     SkColorType colorType;
247     switch (surfaceFormat) {
248         case VK_FORMAT_R8G8B8A8_UNORM: // fall through
249         case VK_FORMAT_R8G8B8A8_SRGB:
250             colorType = kRGBA_8888_SkColorType;
251             break;
252         case VK_FORMAT_B8G8R8A8_UNORM: // fall through
253             colorType = kBGRA_8888_SkColorType;
254             break;
255         default:
256             return false;
257     }
258 
259     // If mailbox mode is available, use it, as it is the lowest-latency non-
260     // tearing mode. If not, fall back to FIFO which is always available.
261     VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
262     bool hasImmediate = false;
263     for (uint32_t i = 0; i < presentModeCount; ++i) {
264         // use mailbox
265         if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
266             mode = VK_PRESENT_MODE_MAILBOX_KHR;
267         }
268         if (VK_PRESENT_MODE_IMMEDIATE_KHR == presentModes[i]) {
269             hasImmediate = true;
270         }
271     }
272     if (params.fDisableVsync && hasImmediate) {
273         mode = VK_PRESENT_MODE_IMMEDIATE_KHR;
274     }
275 
276     VkSwapchainCreateInfoKHR swapchainCreateInfo;
277     memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
278     swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
279     swapchainCreateInfo.surface = fSurface;
280     swapchainCreateInfo.minImageCount = imageCount;
281     swapchainCreateInfo.imageFormat = surfaceFormat;
282     swapchainCreateInfo.imageColorSpace = colorSpace;
283     swapchainCreateInfo.imageExtent = extent;
284     swapchainCreateInfo.imageArrayLayers = 1;
285     swapchainCreateInfo.imageUsage = usageFlags;
286 
287     uint32_t queueFamilies[] = { fGraphicsQueueIndex, fPresentQueueIndex };
288     if (fGraphicsQueueIndex != fPresentQueueIndex) {
289         swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
290         swapchainCreateInfo.queueFamilyIndexCount = 2;
291         swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
292     } else {
293         swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
294         swapchainCreateInfo.queueFamilyIndexCount = 0;
295         swapchainCreateInfo.pQueueFamilyIndices = nullptr;
296     }
297 
298     swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
299     swapchainCreateInfo.compositeAlpha = composite_alpha;
300     swapchainCreateInfo.presentMode = mode;
301     swapchainCreateInfo.clipped = true;
302     swapchainCreateInfo.oldSwapchain = fSwapchain;
303 
304     res = fCreateSwapchainKHR(fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
305     if (VK_SUCCESS != res) {
306         return false;
307     }
308 
309     // destroy the old swapchain
310     if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
311         fDeviceWaitIdle(fDevice);
312 
313         this->destroyBuffers();
314 
315         fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
316     }
317 
318     if (!this->createBuffers(swapchainCreateInfo.imageFormat, usageFlags, colorType,
319                              swapchainCreateInfo.imageSharingMode)) {
320         fDeviceWaitIdle(fDevice);
321 
322         this->destroyBuffers();
323 
324         fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
325     }
326 
327     return true;
328 }
329 
createBuffers(VkFormat format,VkImageUsageFlags usageFlags,SkColorType colorType,VkSharingMode sharingMode)330 bool SkVulkanWindowContext::createBuffers(VkFormat format, VkImageUsageFlags usageFlags,
331                                         SkColorType colorType,
332                                         VkSharingMode sharingMode) {
333     fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr);
334     SkASSERT(fImageCount);
335     fImages = new VkImage[fImageCount];
336     fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, fImages);
337 
338     // set up initial image layouts and create surfaces
339     fImageLayouts = new VkImageLayout[fImageCount];
340     fSurfaces = new sk_sp<SkSurface>[fImageCount];
341     for (uint32_t i = 0; i < fImageCount; ++i) {
342         fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
343 
344         GrVkImageInfo info;
345         info.fImage = fImages[i];
346         info.fAlloc = skgpu::VulkanAlloc();
347         info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
348         info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
349         info.fFormat = format;
350         info.fImageUsageFlags = usageFlags;
351         info.fLevelCount = 1;
352         info.fCurrentQueueFamily = fPresentQueueIndex;
353         info.fSharingMode = sharingMode;
354 
355         if (usageFlags & VK_IMAGE_USAGE_SAMPLED_BIT) {
356             GrBackendTexture backendTexture(fWidth, fHeight, info);
357             fSurfaces[i] = SkSurface::MakeFromBackendTexture(
358                     fContext.get(), backendTexture, kTopLeft_GrSurfaceOrigin,
359                     fDisplayParams.fMSAASampleCount,
360                     colorType, fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps);
361         } else {
362             if (fDisplayParams.fMSAASampleCount > 1) {
363                 return false;
364             }
365             GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info);
366             fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(
367                     fContext.get(), backendRT, kTopLeft_GrSurfaceOrigin, colorType,
368                     fDisplayParams.fColorSpace, &fDisplayParams.fSurfaceProps);
369 
370         }
371         if (!fSurfaces[i]) {
372             return false;
373         }
374     }
375 
376     // set up the backbuffers
377     VkSemaphoreCreateInfo semaphoreInfo;
378     memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
379     semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
380     semaphoreInfo.pNext = nullptr;
381     semaphoreInfo.flags = 0;
382 
383     // we create one additional backbuffer structure here, because we want to
384     // give the command buffers they contain a chance to finish before we cycle back
385     fBackbuffers = new BackbufferInfo[fImageCount + 1];
386     for (uint32_t i = 0; i < fImageCount + 1; ++i) {
387         fBackbuffers[i].fImageIndex = -1;
388         SkDEBUGCODE(VkResult result = )GR_VK_CALL(fInterface,
389                 CreateSemaphore(fDevice, &semaphoreInfo, nullptr,
390                                 &fBackbuffers[i].fRenderSemaphore));
391         SkASSERT(result == VK_SUCCESS);
392     }
393     fCurrentBackbufferIndex = fImageCount;
394     return true;
395 }
396 
destroyBuffers()397 void SkVulkanWindowContext::destroyBuffers() {
398 
399     if (fBackbuffers) {
400         for (uint32_t i = 0; i < fImageCount + 1; ++i) {
401             fBackbuffers[i].fImageIndex = -1;
402             GR_VK_CALL(fInterface,
403                        DestroySemaphore(fDevice,
404                                         fBackbuffers[i].fRenderSemaphore,
405                                         nullptr));
406         }
407     }
408 
409     delete[] fBackbuffers;
410     fBackbuffers = nullptr;
411 
412     // Does this actually free the surfaces?
413     delete[] fSurfaces;
414     fSurfaces = nullptr;
415     delete[] fImageLayouts;
416     fImageLayouts = nullptr;
417     delete[] fImages;
418     fImages = nullptr;
419 }
420 
~SkVulkanWindowContext()421 SkVulkanWindowContext::~SkVulkanWindowContext() {
422     this->destroyContext();
423 }
424 
destroyContext()425 void SkVulkanWindowContext::destroyContext() {
426     if (this->isValid()) {
427         fQueueWaitIdle(fPresentQueue);
428         fDeviceWaitIdle(fDevice);
429 
430         this->destroyBuffers();
431 
432         if (VK_NULL_HANDLE != fSwapchain) {
433             fDestroySwapchainKHR(fDevice, fSwapchain, nullptr);
434             fSwapchain = VK_NULL_HANDLE;
435         }
436 
437         if (VK_NULL_HANDLE != fSurface) {
438             fDestroySurfaceKHR(fInstance, fSurface, nullptr);
439             fSurface = VK_NULL_HANDLE;
440         }
441     }
442 
443     SkASSERT(fContext->unique());
444     fContext.reset();
445     fInterface.reset();
446 
447     if (VK_NULL_HANDLE != fDevice) {
448         fDestroyDevice(fDevice, nullptr);
449         fDevice = VK_NULL_HANDLE;
450     }
451 
452 #ifdef SK_ENABLE_VK_LAYERS
453     if (fDebugCallback != VK_NULL_HANDLE) {
454         fDestroyDebugReportCallbackEXT(fInstance, fDebugCallback, nullptr);
455     }
456 #endif
457 
458     fPhysicalDevice = VK_NULL_HANDLE;
459 
460     if (VK_NULL_HANDLE != fInstance) {
461         fDestroyInstance(fInstance, nullptr);
462         fInstance = VK_NULL_HANDLE;
463     }
464 }
465 
getAvailableBackbuffer()466 SkVulkanWindowContext::BackbufferInfo* SkVulkanWindowContext::getAvailableBackbuffer() {
467     SkASSERT(fBackbuffers);
468 
469     ++fCurrentBackbufferIndex;
470     if (fCurrentBackbufferIndex > fImageCount) {
471         fCurrentBackbufferIndex = 0;
472     }
473 
474     BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
475     return backbuffer;
476 }
477 
getBackbufferSurface()478 sk_sp<SkSurface> SkVulkanWindowContext::getBackbufferSurface() {
479     BackbufferInfo* backbuffer = this->getAvailableBackbuffer();
480     SkASSERT(backbuffer);
481 
482     // semaphores should be in unsignaled state
483     VkSemaphoreCreateInfo semaphoreInfo;
484     memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
485     semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
486     semaphoreInfo.pNext = nullptr;
487     semaphoreInfo.flags = 0;
488     VkSemaphore semaphore;
489     SkDEBUGCODE(VkResult result = )GR_VK_CALL(fInterface, CreateSemaphore(fDevice, &semaphoreInfo,
490                                                                           nullptr, &semaphore));
491     SkASSERT(result == VK_SUCCESS);
492 
493     // acquire the image
494     VkResult res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
495                                         semaphore, VK_NULL_HANDLE,
496                                         &backbuffer->fImageIndex);
497     if (VK_ERROR_SURFACE_LOST_KHR == res) {
498         // need to figure out how to create a new vkSurface without the platformData*
499         // maybe use attach somehow? but need a Window
500         GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
501         return nullptr;
502     }
503     if (VK_ERROR_OUT_OF_DATE_KHR == res) {
504         // tear swapchain down and try again
505         if (!this->createSwapchain(-1, -1, fDisplayParams)) {
506             GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
507             return nullptr;
508         }
509         backbuffer = this->getAvailableBackbuffer();
510 
511         // acquire the image
512         res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
513                                    semaphore, VK_NULL_HANDLE,
514                                    &backbuffer->fImageIndex);
515 
516         if (VK_SUCCESS != res) {
517             GR_VK_CALL(fInterface, DestroySemaphore(fDevice, semaphore, nullptr));
518             return nullptr;
519         }
520     }
521 
522     SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
523 
524     GrBackendSemaphore beSemaphore;
525     beSemaphore.initVulkan(semaphore);
526 
527     surface->wait(1, &beSemaphore);
528 
529     return sk_ref_sp(surface);
530 }
531 
swapBuffers()532 void SkVulkanWindowContext::swapBuffers() {
533 
534     BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
535     SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
536 
537     GrBackendSemaphore beSemaphore;
538     beSemaphore.initVulkan(backbuffer->fRenderSemaphore);
539 
540     GrFlushInfo info;
541     info.fNumSemaphores = 1;
542     info.fSignalSemaphores = &beSemaphore;
543     skgpu::MutableTextureState presentState(VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, fPresentQueueIndex);
544     surface->flush(info, &presentState);
545     surface->recordingContext()->asDirectContext()->submit();
546 
547     // Submit present operation to present queue
548     const VkPresentInfoKHR presentInfo =
549     {
550         VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
551         nullptr, // pNext
552         1, // waitSemaphoreCount
553         &backbuffer->fRenderSemaphore, // pWaitSemaphores
554         1, // swapchainCount
555         &fSwapchain, // pSwapchains
556         &backbuffer->fImageIndex, // pImageIndices
557         nullptr // pResults
558     };
559 
560     fQueuePresentKHR(fPresentQueue, &presentInfo);
561 }
562