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