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