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