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 "VulkanWindowContext.h"
10
11 #include "GrBackendSurface.h"
12 #include "GrContext.h"
13 #include "SkAutoMalloc.h"
14 #include "SkSurface.h"
15
16 #include "vk/GrVkExtensions.h"
17 #include "vk/GrVkImage.h"
18 #include "vk/GrVkTypes.h"
19 #include "vk/GrVkUtil.h"
20
21 #ifdef VK_USE_PLATFORM_WIN32_KHR
22 // windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
23 #undef CreateSemaphore
24 #endif
25
26 #define GET_PROC(F) f ## F = (PFN_vk ## F) fGetInstanceProcAddr(fInstance, "vk" #F)
27 #define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) fGetDeviceProcAddr(fDevice, "vk" #F)
28
29 namespace sk_app {
30
VulkanWindowContext(const DisplayParams & params,CreateVkSurfaceFn createVkSurface,CanPresentFn canPresent,PFN_vkGetInstanceProcAddr instProc,PFN_vkGetDeviceProcAddr devProc)31 VulkanWindowContext::VulkanWindowContext(const DisplayParams& params,
32 CreateVkSurfaceFn createVkSurface,
33 CanPresentFn canPresent,
34 PFN_vkGetInstanceProcAddr instProc,
35 PFN_vkGetDeviceProcAddr devProc)
36 : WindowContext(params)
37 , fCreateVkSurfaceFn(createVkSurface)
38 , fCanPresentFn(canPresent)
39 , fSurface(VK_NULL_HANDLE)
40 , fSwapchain(VK_NULL_HANDLE)
41 , fImages(nullptr)
42 , fImageLayouts(nullptr)
43 , fSurfaces(nullptr)
44 , fCommandPool(VK_NULL_HANDLE)
45 , fBackbuffers(nullptr) {
46 fGetInstanceProcAddr = instProc;
47 fGetDeviceProcAddr = devProc;
48 this->initializeContext();
49 }
50
initializeContext()51 void VulkanWindowContext::initializeContext() {
52 // any config code here (particularly for msaa)?
53
54 PFN_vkGetInstanceProcAddr getInstanceProc = fGetInstanceProcAddr;
55 PFN_vkGetDeviceProcAddr getDeviceProc = fGetDeviceProcAddr;
56 auto getProc = [getInstanceProc, getDeviceProc](const char* proc_name,
57 VkInstance instance, VkDevice device) {
58 if (device != VK_NULL_HANDLE) {
59 return getDeviceProc(device, proc_name);
60 }
61 return getInstanceProc(instance, proc_name);
62 };
63 GrVkBackendContext backendContext;
64 GrVkExtensions extensions;
65 VkPhysicalDeviceFeatures2 features;
66 if (!sk_gpu_test::CreateVkBackendContext(getProc, &backendContext, &extensions, &features,
67 &fDebugCallback, &fPresentQueueIndex, fCanPresentFn)) {
68 sk_gpu_test::FreeVulkanFeaturesStructs(&features);
69 return;
70 }
71
72 if (!extensions.hasExtension(VK_KHR_SURFACE_EXTENSION_NAME, 25) ||
73 !extensions.hasExtension(VK_KHR_SWAPCHAIN_EXTENSION_NAME, 68)) {
74 sk_gpu_test::FreeVulkanFeaturesStructs(&features);
75 return;
76 }
77
78 fInstance = backendContext.fInstance;
79 fPhysicalDevice = backendContext.fPhysicalDevice;
80 fDevice = backendContext.fDevice;
81 fGraphicsQueueIndex = backendContext.fGraphicsQueueIndex;
82 fGraphicsQueue = backendContext.fQueue;
83
84 PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties =
85 reinterpret_cast<PFN_vkGetPhysicalDeviceProperties>(
86 backendContext.fGetProc("vkGetPhysicalDeviceProperties",
87 backendContext.fInstance,
88 VK_NULL_HANDLE));
89 if (!localGetPhysicalDeviceProperties) {
90 sk_gpu_test::FreeVulkanFeaturesStructs(&features);
91 return;
92 }
93 VkPhysicalDeviceProperties physDeviceProperties;
94 localGetPhysicalDeviceProperties(backendContext.fPhysicalDevice, &physDeviceProperties);
95 uint32_t physDevVersion = physDeviceProperties.apiVersion;
96
97 fInterface.reset(new GrVkInterface(backendContext.fGetProc, fInstance, fDevice,
98 backendContext.fInstanceVersion, physDevVersion,
99 &extensions));
100
101 GET_PROC(DestroyInstance);
102 if (fDebugCallback != VK_NULL_HANDLE) {
103 GET_PROC(DestroyDebugReportCallbackEXT);
104 }
105 GET_PROC(DestroySurfaceKHR);
106 GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
107 GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
108 GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
109 GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
110 GET_DEV_PROC(DeviceWaitIdle);
111 GET_DEV_PROC(QueueWaitIdle);
112 GET_DEV_PROC(DestroyDevice);
113 GET_DEV_PROC(CreateSwapchainKHR);
114 GET_DEV_PROC(DestroySwapchainKHR);
115 GET_DEV_PROC(GetSwapchainImagesKHR);
116 GET_DEV_PROC(AcquireNextImageKHR);
117 GET_DEV_PROC(QueuePresentKHR);
118 GET_DEV_PROC(GetDeviceQueue);
119
120 fContext = GrContext::MakeVulkan(backendContext, fDisplayParams.fGrContextOptions);
121
122 fSurface = fCreateVkSurfaceFn(fInstance);
123 if (VK_NULL_HANDLE == fSurface) {
124 this->destroyContext();
125 sk_gpu_test::FreeVulkanFeaturesStructs(&features);
126 return;
127 }
128
129 VkBool32 supported;
130 VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fPhysicalDevice, fPresentQueueIndex,
131 fSurface, &supported);
132 if (VK_SUCCESS != res) {
133 this->destroyContext();
134 sk_gpu_test::FreeVulkanFeaturesStructs(&features);
135 return;
136 }
137
138 if (!this->createSwapchain(-1, -1, fDisplayParams)) {
139 this->destroyContext();
140 sk_gpu_test::FreeVulkanFeaturesStructs(&features);
141 return;
142 }
143
144 // create presentQueue
145 fGetDeviceQueue(fDevice, fPresentQueueIndex, 0, &fPresentQueue);
146 sk_gpu_test::FreeVulkanFeaturesStructs(&features);
147 }
148
createSwapchain(int width,int height,const DisplayParams & params)149 bool VulkanWindowContext::createSwapchain(int width, int height,
150 const DisplayParams& params) {
151 // check for capabilities
152 VkSurfaceCapabilitiesKHR caps;
153 VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fPhysicalDevice, fSurface, &caps);
154 if (VK_SUCCESS != res) {
155 return false;
156 }
157
158 uint32_t surfaceFormatCount;
159 res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
160 nullptr);
161 if (VK_SUCCESS != res) {
162 return false;
163 }
164
165 SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
166 VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
167 res = fGetPhysicalDeviceSurfaceFormatsKHR(fPhysicalDevice, fSurface, &surfaceFormatCount,
168 surfaceFormats);
169 if (VK_SUCCESS != res) {
170 return false;
171 }
172
173 uint32_t presentModeCount;
174 res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
175 nullptr);
176 if (VK_SUCCESS != res) {
177 return false;
178 }
179
180 SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
181 VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
182 res = fGetPhysicalDeviceSurfacePresentModesKHR(fPhysicalDevice, fSurface, &presentModeCount,
183 presentModes);
184 if (VK_SUCCESS != res) {
185 return false;
186 }
187
188 VkExtent2D extent = caps.currentExtent;
189 // use the hints
190 if (extent.width == (uint32_t)-1) {
191 extent.width = width;
192 extent.height = height;
193 }
194
195 // clamp width; to protect us from broken hints
196 if (extent.width < caps.minImageExtent.width) {
197 extent.width = caps.minImageExtent.width;
198 } else if (extent.width > caps.maxImageExtent.width) {
199 extent.width = caps.maxImageExtent.width;
200 }
201 // clamp height
202 if (extent.height < caps.minImageExtent.height) {
203 extent.height = caps.minImageExtent.height;
204 } else if (extent.height > caps.maxImageExtent.height) {
205 extent.height = caps.maxImageExtent.height;
206 }
207
208 fWidth = (int)extent.width;
209 fHeight = (int)extent.height;
210
211 uint32_t imageCount = caps.minImageCount + 2;
212 if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
213 // Application must settle for fewer images than desired:
214 imageCount = caps.maxImageCount;
215 }
216
217 VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
218 VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
219 VK_IMAGE_USAGE_TRANSFER_DST_BIT;
220 SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
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 = 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 case VK_FORMAT_B8G8R8A8_SRGB:
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 for (uint32_t i = 0; i < presentModeCount; ++i) {
266 // use mailbox
267 if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
268 mode = presentModes[i];
269 break;
270 }
271 }
272
273 VkSwapchainCreateInfoKHR swapchainCreateInfo;
274 memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
275 swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
276 swapchainCreateInfo.surface = fSurface;
277 swapchainCreateInfo.minImageCount = imageCount;
278 swapchainCreateInfo.imageFormat = surfaceFormat;
279 swapchainCreateInfo.imageColorSpace = colorSpace;
280 swapchainCreateInfo.imageExtent = extent;
281 swapchainCreateInfo.imageArrayLayers = 1;
282 swapchainCreateInfo.imageUsage = usageFlags;
283
284 uint32_t queueFamilies[] = { fGraphicsQueueIndex, fPresentQueueIndex };
285 if (fGraphicsQueueIndex != fPresentQueueIndex) {
286 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
287 swapchainCreateInfo.queueFamilyIndexCount = 2;
288 swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
289 } else {
290 swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
291 swapchainCreateInfo.queueFamilyIndexCount = 0;
292 swapchainCreateInfo.pQueueFamilyIndices = nullptr;
293 }
294
295 swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
296 swapchainCreateInfo.compositeAlpha = composite_alpha;
297 swapchainCreateInfo.presentMode = mode;
298 swapchainCreateInfo.clipped = true;
299 swapchainCreateInfo.oldSwapchain = fSwapchain;
300
301 res = fCreateSwapchainKHR(fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
302 if (VK_SUCCESS != res) {
303 return false;
304 }
305
306 // destroy the old swapchain
307 if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
308 fDeviceWaitIdle(fDevice);
309
310 this->destroyBuffers();
311
312 fDestroySwapchainKHR(fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
313 }
314
315 this->createBuffers(swapchainCreateInfo.imageFormat, colorType);
316
317 return true;
318 }
319
createBuffers(VkFormat format,SkColorType colorType)320 void VulkanWindowContext::createBuffers(VkFormat format, SkColorType colorType) {
321 fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, nullptr);
322 SkASSERT(fImageCount);
323 fImages = new VkImage[fImageCount];
324 fGetSwapchainImagesKHR(fDevice, fSwapchain, &fImageCount, fImages);
325
326 // set up initial image layouts and create surfaces
327 fImageLayouts = new VkImageLayout[fImageCount];
328 fSurfaces = new sk_sp<SkSurface>[fImageCount];
329 for (uint32_t i = 0; i < fImageCount; ++i) {
330 fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
331
332 GrVkImageInfo info;
333 info.fImage = fImages[i];
334 info.fAlloc = GrVkAlloc();
335 info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
336 info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
337 info.fFormat = format;
338 info.fLevelCount = 1;
339
340 GrBackendRenderTarget backendRT(fWidth, fHeight, fSampleCount, info);
341
342 fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(fContext.get(),
343 backendRT,
344 kTopLeft_GrSurfaceOrigin,
345 colorType,
346 fDisplayParams.fColorSpace,
347 &fDisplayParams.fSurfaceProps);
348 }
349
350 // create the command pool for the command buffers
351 if (VK_NULL_HANDLE == fCommandPool) {
352 VkCommandPoolCreateInfo commandPoolInfo;
353 memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
354 commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
355 // this needs to be on the render queue
356 commandPoolInfo.queueFamilyIndex = fGraphicsQueueIndex;
357 commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
358 GR_VK_CALL_ERRCHECK(fInterface,
359 CreateCommandPool(fDevice, &commandPoolInfo,
360 nullptr, &fCommandPool));
361 }
362
363 // set up the backbuffers
364 VkSemaphoreCreateInfo semaphoreInfo;
365 memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
366 semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
367 semaphoreInfo.pNext = nullptr;
368 semaphoreInfo.flags = 0;
369 VkCommandBufferAllocateInfo commandBuffersInfo;
370 memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
371 commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
372 commandBuffersInfo.pNext = nullptr;
373 commandBuffersInfo.commandPool = fCommandPool;
374 commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
375 commandBuffersInfo.commandBufferCount = 2;
376 VkFenceCreateInfo fenceInfo;
377 memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
378 fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
379 fenceInfo.pNext = nullptr;
380 fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
381
382 // we create one additional backbuffer structure here, because we want to
383 // give the command buffers they contain a chance to finish before we cycle back
384 fBackbuffers = new BackbufferInfo[fImageCount + 1];
385 for (uint32_t i = 0; i < fImageCount + 1; ++i) {
386 fBackbuffers[i].fImageIndex = -1;
387 GR_VK_CALL_ERRCHECK(fInterface,
388 CreateSemaphore(fDevice, &semaphoreInfo,
389 nullptr, &fBackbuffers[i].fAcquireSemaphore));
390 GR_VK_CALL_ERRCHECK(fInterface,
391 CreateSemaphore(fDevice, &semaphoreInfo,
392 nullptr, &fBackbuffers[i].fRenderSemaphore));
393 GR_VK_CALL_ERRCHECK(fInterface,
394 AllocateCommandBuffers(fDevice, &commandBuffersInfo,
395 fBackbuffers[i].fTransitionCmdBuffers));
396 GR_VK_CALL_ERRCHECK(fInterface,
397 CreateFence(fDevice, &fenceInfo, nullptr,
398 &fBackbuffers[i].fUsageFences[0]));
399 GR_VK_CALL_ERRCHECK(fInterface,
400 CreateFence(fDevice, &fenceInfo, nullptr,
401 &fBackbuffers[i].fUsageFences[1]));
402 }
403 fCurrentBackbufferIndex = fImageCount;
404 }
405
destroyBuffers()406 void VulkanWindowContext::destroyBuffers() {
407
408 if (fBackbuffers) {
409 for (uint32_t i = 0; i < fImageCount + 1; ++i) {
410 GR_VK_CALL_ERRCHECK(fInterface,
411 WaitForFences(fDevice, 2,
412 fBackbuffers[i].fUsageFences,
413 true, UINT64_MAX));
414 fBackbuffers[i].fImageIndex = -1;
415 GR_VK_CALL(fInterface,
416 DestroySemaphore(fDevice,
417 fBackbuffers[i].fAcquireSemaphore,
418 nullptr));
419 GR_VK_CALL(fInterface,
420 DestroySemaphore(fDevice,
421 fBackbuffers[i].fRenderSemaphore,
422 nullptr));
423 GR_VK_CALL(fInterface,
424 FreeCommandBuffers(fDevice, fCommandPool, 2,
425 fBackbuffers[i].fTransitionCmdBuffers));
426 GR_VK_CALL(fInterface,
427 DestroyFence(fDevice, fBackbuffers[i].fUsageFences[0], 0));
428 GR_VK_CALL(fInterface,
429 DestroyFence(fDevice, fBackbuffers[i].fUsageFences[1], 0));
430 }
431 }
432
433 delete[] fBackbuffers;
434 fBackbuffers = nullptr;
435
436 // Does this actually free the surfaces?
437 delete[] fSurfaces;
438 fSurfaces = nullptr;
439 delete[] fImageLayouts;
440 fImageLayouts = nullptr;
441 delete[] fImages;
442 fImages = nullptr;
443 }
444
~VulkanWindowContext()445 VulkanWindowContext::~VulkanWindowContext() {
446 this->destroyContext();
447 }
448
destroyContext()449 void VulkanWindowContext::destroyContext() {
450 if (this->isValid()) {
451 fQueueWaitIdle(fPresentQueue);
452 fDeviceWaitIdle(fDevice);
453
454 this->destroyBuffers();
455
456 if (VK_NULL_HANDLE != fCommandPool) {
457 GR_VK_CALL(fInterface, DestroyCommandPool(fDevice, fCommandPool, nullptr));
458 fCommandPool = VK_NULL_HANDLE;
459 }
460
461 if (VK_NULL_HANDLE != fSwapchain) {
462 fDestroySwapchainKHR(fDevice, fSwapchain, nullptr);
463 fSwapchain = VK_NULL_HANDLE;
464 }
465
466 if (VK_NULL_HANDLE != fSurface) {
467 fDestroySurfaceKHR(fInstance, fSurface, nullptr);
468 fSurface = VK_NULL_HANDLE;
469 }
470 }
471
472 fContext.reset();
473 fInterface.reset();
474
475 if (VK_NULL_HANDLE != fDevice) {
476 fDestroyDevice(fDevice, nullptr);
477 fDevice = VK_NULL_HANDLE;
478 }
479
480 #ifdef SK_ENABLE_VK_LAYERS
481 if (fDebugCallback != VK_NULL_HANDLE) {
482 fDestroyDebugReportCallbackEXT(fInstance, fDebugCallback, nullptr);
483 }
484 #endif
485
486 fPhysicalDevice = VK_NULL_HANDLE;
487
488 if (VK_NULL_HANDLE != fInstance) {
489 fDestroyInstance(fInstance, nullptr);
490 fInstance = VK_NULL_HANDLE;
491 }
492 }
493
getAvailableBackbuffer()494 VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() {
495 SkASSERT(fBackbuffers);
496
497 ++fCurrentBackbufferIndex;
498 if (fCurrentBackbufferIndex > fImageCount) {
499 fCurrentBackbufferIndex = 0;
500 }
501
502 BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
503 GR_VK_CALL_ERRCHECK(fInterface,
504 WaitForFences(fDevice, 2, backbuffer->fUsageFences,
505 true, UINT64_MAX));
506 return backbuffer;
507 }
508
getBackbufferSurface()509 sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() {
510 BackbufferInfo* backbuffer = this->getAvailableBackbuffer();
511 SkASSERT(backbuffer);
512
513 // reset the fence
514 GR_VK_CALL_ERRCHECK(fInterface,
515 ResetFences(fDevice, 2, backbuffer->fUsageFences));
516 // semaphores should be in unsignaled state
517
518 // acquire the image
519 VkResult res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
520 backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
521 &backbuffer->fImageIndex);
522 if (VK_ERROR_SURFACE_LOST_KHR == res) {
523 // need to figure out how to create a new vkSurface without the platformData*
524 // maybe use attach somehow? but need a Window
525 return nullptr;
526 }
527 if (VK_ERROR_OUT_OF_DATE_KHR == res) {
528 // tear swapchain down and try again
529 if (!this->createSwapchain(-1, -1, fDisplayParams)) {
530 return nullptr;
531 }
532 backbuffer = this->getAvailableBackbuffer();
533 GR_VK_CALL_ERRCHECK(fInterface,
534 ResetFences(fDevice, 2, backbuffer->fUsageFences));
535
536 // acquire the image
537 res = fAcquireNextImageKHR(fDevice, fSwapchain, UINT64_MAX,
538 backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
539 &backbuffer->fImageIndex);
540
541 if (VK_SUCCESS != res) {
542 return nullptr;
543 }
544 }
545
546 // set up layout transfer from initial to color attachment
547 VkImageLayout layout = fImageLayouts[backbuffer->fImageIndex];
548 SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
549 VkPipelineStageFlags srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
550 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
551 VkAccessFlags srcAccessMask = 0;
552 VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
553 VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
554
555 VkImageMemoryBarrier imageMemoryBarrier = {
556 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
557 NULL, // pNext
558 srcAccessMask, // outputMask
559 dstAccessMask, // inputMask
560 layout, // oldLayout
561 VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
562 fPresentQueueIndex, // srcQueueFamilyIndex
563 fGraphicsQueueIndex, // dstQueueFamilyIndex
564 fImages[backbuffer->fImageIndex], // image
565 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
566 };
567 GR_VK_CALL_ERRCHECK(fInterface,
568 ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[0], 0));
569 VkCommandBufferBeginInfo info;
570 memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
571 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
572 info.flags = 0;
573 GR_VK_CALL_ERRCHECK(fInterface,
574 BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[0], &info));
575
576 GR_VK_CALL(fInterface,
577 CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[0],
578 srcStageMask, dstStageMask, 0,
579 0, nullptr,
580 0, nullptr,
581 1, &imageMemoryBarrier));
582
583 GR_VK_CALL_ERRCHECK(fInterface,
584 EndCommandBuffer(backbuffer->fTransitionCmdBuffers[0]));
585
586 VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
587 // insert the layout transfer into the queue and wait on the acquire
588 VkSubmitInfo submitInfo;
589 memset(&submitInfo, 0, sizeof(VkSubmitInfo));
590 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
591 submitInfo.waitSemaphoreCount = 1;
592 submitInfo.pWaitSemaphores = &backbuffer->fAcquireSemaphore;
593 submitInfo.pWaitDstStageMask = &waitDstStageFlags;
594 submitInfo.commandBufferCount = 1;
595 submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[0];
596 submitInfo.signalSemaphoreCount = 0;
597
598 GR_VK_CALL_ERRCHECK(fInterface,
599 QueueSubmit(fGraphicsQueue, 1, &submitInfo,
600 backbuffer->fUsageFences[0]));
601
602 SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
603 GrBackendRenderTarget backendRT = surface->getBackendRenderTarget(
604 SkSurface::kFlushRead_BackendHandleAccess);
605 backendRT.setVkImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
606
607
608 return sk_ref_sp(surface);
609 }
610
swapBuffers()611 void VulkanWindowContext::swapBuffers() {
612
613 BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
614 SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
615
616 GrBackendRenderTarget backendRT = surface->getBackendRenderTarget(
617 SkSurface::kFlushRead_BackendHandleAccess);
618 GrVkImageInfo imageInfo;
619 SkAssertResult(backendRT.getVkImageInfo(&imageInfo));
620 // Check to make sure we never change the actually wrapped image
621 SkASSERT(imageInfo.fImage == fImages[backbuffer->fImageIndex]);
622
623 VkImageLayout layout = imageInfo.fImageLayout;
624 VkPipelineStageFlags srcStageMask = GrVkImage::LayoutToPipelineSrcStageFlags(layout);
625 VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
626 VkAccessFlags srcAccessMask = GrVkImage::LayoutToSrcAccessMask(layout);
627 VkAccessFlags dstAccessMask = 0;
628
629 VkImageMemoryBarrier imageMemoryBarrier = {
630 VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
631 NULL, // pNext
632 srcAccessMask, // outputMask
633 dstAccessMask, // inputMask
634 layout, // oldLayout
635 VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
636 fGraphicsQueueIndex, // srcQueueFamilyIndex
637 fPresentQueueIndex, // dstQueueFamilyIndex
638 fImages[backbuffer->fImageIndex], // image
639 { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
640 };
641 GR_VK_CALL_ERRCHECK(fInterface,
642 ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[1], 0));
643 VkCommandBufferBeginInfo info;
644 memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
645 info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
646 info.flags = 0;
647 GR_VK_CALL_ERRCHECK(fInterface,
648 BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[1], &info));
649 GR_VK_CALL(fInterface,
650 CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[1],
651 srcStageMask, dstStageMask, 0,
652 0, nullptr,
653 0, nullptr,
654 1, &imageMemoryBarrier));
655 GR_VK_CALL_ERRCHECK(fInterface,
656 EndCommandBuffer(backbuffer->fTransitionCmdBuffers[1]));
657
658 fImageLayouts[backbuffer->fImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
659
660 // insert the layout transfer into the queue and wait on the acquire
661 VkSubmitInfo submitInfo;
662 memset(&submitInfo, 0, sizeof(VkSubmitInfo));
663 submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
664 submitInfo.waitSemaphoreCount = 0;
665 submitInfo.pWaitDstStageMask = 0;
666 submitInfo.commandBufferCount = 1;
667 submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[1];
668 submitInfo.signalSemaphoreCount = 1;
669 submitInfo.pSignalSemaphores = &backbuffer->fRenderSemaphore;
670
671 GR_VK_CALL_ERRCHECK(fInterface,
672 QueueSubmit(fGraphicsQueue, 1, &submitInfo,
673 backbuffer->fUsageFences[1]));
674
675 // Submit present operation to present queue
676 const VkPresentInfoKHR presentInfo =
677 {
678 VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
679 NULL, // pNext
680 1, // waitSemaphoreCount
681 &backbuffer->fRenderSemaphore, // pWaitSemaphores
682 1, // swapchainCount
683 &fSwapchain, // pSwapchains
684 &backbuffer->fImageIndex, // pImageIndices
685 NULL // pResults
686 };
687
688 fQueuePresentKHR(fPresentQueue, &presentInfo);
689 }
690
691 } //namespace sk_app
692