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