• 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 "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