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