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 "GrContext.h"
10 #include "GrRenderTarget.h"
11 #include "SkAutoMalloc.h"
12 #include "SkSurface.h"
13 #include "VulkanWindowContext.h"
14 
15 #include "vk/GrVkInterface.h"
16 #include "vk/GrVkMemory.h"
17 #include "vk/GrVkUtil.h"
18 #include "vk/GrVkTypes.h"
19 
20 #ifdef VK_USE_PLATFORM_WIN32_KHR
21 // windows wants to define this as CreateSemaphoreA or CreateSemaphoreW
22 #undef CreateSemaphore
23 #endif
24 
25 #define GET_PROC(F) f ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F)
26 #define GET_DEV_PROC(F) f ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F)
27 
28 namespace sk_app {
29 
VulkanWindowContext(const DisplayParams & params,CreateVkSurfaceFn createVkSurface,CanPresentFn canPresent)30 VulkanWindowContext::VulkanWindowContext(const DisplayParams& params,
31                                          CreateVkSurfaceFn createVkSurface,
32                                          CanPresentFn canPresent)
33     : WindowContext()
34     , fSurface(VK_NULL_HANDLE)
35     , fSwapchain(VK_NULL_HANDLE)
36     , fImages(nullptr)
37     , fImageLayouts(nullptr)
38     , fSurfaces(nullptr)
39     , fCommandPool(VK_NULL_HANDLE)
40     , fBackbuffers(nullptr) {
41 
42     // any config code here (particularly for msaa)?
43     fBackendContext.reset(GrVkBackendContext::Create(&fPresentQueueIndex, canPresent));
44 
45     if (!(fBackendContext->fExtensions & kKHR_surface_GrVkExtensionFlag) ||
46         !(fBackendContext->fExtensions & kKHR_swapchain_GrVkExtensionFlag)) {
47         fBackendContext.reset(nullptr);
48         return;
49     }
50 
51     VkInstance instance = fBackendContext->fInstance;
52     VkDevice device = fBackendContext->fDevice;
53     GET_PROC(DestroySurfaceKHR);
54     GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
55     GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
56     GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
57     GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
58     GET_DEV_PROC(CreateSwapchainKHR);
59     GET_DEV_PROC(DestroySwapchainKHR);
60     GET_DEV_PROC(GetSwapchainImagesKHR);
61     GET_DEV_PROC(AcquireNextImageKHR);
62     GET_DEV_PROC(QueuePresentKHR);
63 
64     fContext = GrContext::Create(kVulkan_GrBackend, (GrBackendContext) fBackendContext.get(),
65                                  params.fGrContextOptions);
66 
67     fSurface = createVkSurface(instance);
68     if (VK_NULL_HANDLE == fSurface) {
69         fBackendContext.reset(nullptr);
70         return;
71     }
72 
73     VkBool32 supported;
74     VkResult res = fGetPhysicalDeviceSurfaceSupportKHR(fBackendContext->fPhysicalDevice,
75                                                        fPresentQueueIndex, fSurface,
76                                                        &supported);
77     if (VK_SUCCESS != res) {
78         this->destroyContext();
79         return;
80     }
81 
82     if (!this->createSwapchain(-1, -1, params)) {
83         this->destroyContext();
84         return;
85     }
86 
87     // create presentQueue
88     vkGetDeviceQueue(fBackendContext->fDevice, fPresentQueueIndex, 0, &fPresentQueue);
89 }
90 
createSwapchain(int width,int height,const DisplayParams & params)91 bool VulkanWindowContext::createSwapchain(int width, int height,
92                                           const DisplayParams& params) {
93     // check for capabilities
94     VkSurfaceCapabilitiesKHR caps;
95     VkResult res = fGetPhysicalDeviceSurfaceCapabilitiesKHR(fBackendContext->fPhysicalDevice,
96                                                             fSurface, &caps);
97     if (VK_SUCCESS != res) {
98         return false;
99     }
100 
101     uint32_t surfaceFormatCount;
102     res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface,
103                                               &surfaceFormatCount, nullptr);
104     if (VK_SUCCESS != res) {
105         return false;
106     }
107 
108     SkAutoMalloc surfaceFormatAlloc(surfaceFormatCount * sizeof(VkSurfaceFormatKHR));
109     VkSurfaceFormatKHR* surfaceFormats = (VkSurfaceFormatKHR*)surfaceFormatAlloc.get();
110     res = fGetPhysicalDeviceSurfaceFormatsKHR(fBackendContext->fPhysicalDevice, fSurface,
111                                               &surfaceFormatCount, surfaceFormats);
112     if (VK_SUCCESS != res) {
113         return false;
114     }
115 
116     uint32_t presentModeCount;
117     res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface,
118                                                    &presentModeCount, nullptr);
119     if (VK_SUCCESS != res) {
120         return false;
121     }
122 
123     SkAutoMalloc presentModeAlloc(presentModeCount * sizeof(VkPresentModeKHR));
124     VkPresentModeKHR* presentModes = (VkPresentModeKHR*)presentModeAlloc.get();
125     res = fGetPhysicalDeviceSurfacePresentModesKHR(fBackendContext->fPhysicalDevice, fSurface,
126                                                    &presentModeCount, presentModes);
127     if (VK_SUCCESS != res) {
128         return false;
129     }
130 
131     VkExtent2D extent = caps.currentExtent;
132     // use the hints
133     if (extent.width == (uint32_t)-1) {
134         extent.width = width;
135         extent.height = height;
136     }
137 
138     // clamp width; to protect us from broken hints
139     if (extent.width < caps.minImageExtent.width) {
140         extent.width = caps.minImageExtent.width;
141     } else if (extent.width > caps.maxImageExtent.width) {
142         extent.width = caps.maxImageExtent.width;
143     }
144     // clamp height
145     if (extent.height < caps.minImageExtent.height) {
146         extent.height = caps.minImageExtent.height;
147     } else if (extent.height > caps.maxImageExtent.height) {
148         extent.height = caps.maxImageExtent.height;
149     }
150 
151     fWidth = (int)extent.width;
152     fHeight = (int)extent.height;
153 
154     uint32_t imageCount = caps.minImageCount + 2;
155     if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
156         // Application must settle for fewer images than desired:
157         imageCount = caps.maxImageCount;
158     }
159 
160     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
161                                    VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
162                                    VK_IMAGE_USAGE_TRANSFER_DST_BIT;
163     SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
164     SkASSERT(caps.supportedTransforms & caps.currentTransform);
165     SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
166                                              VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
167     VkCompositeAlphaFlagBitsKHR composite_alpha =
168         (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
169                                         VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
170                                         VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
171 
172     // Pick our surface format. For now, just make sure it matches our sRGB request:
173     VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
174     VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
175     auto srgbColorSpace = SkColorSpace::MakeSRGB();
176     bool wantSRGB = srgbColorSpace == params.fColorSpace;
177     for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
178         GrPixelConfig config;
179         if (GrVkFormatToPixelConfig(surfaceFormats[i].format, &config) &&
180             GrPixelConfigIsSRGB(config) == wantSRGB) {
181             surfaceFormat = surfaceFormats[i].format;
182             colorSpace = surfaceFormats[i].colorSpace;
183             break;
184         }
185     }
186     fDisplayParams = params;
187     fSampleCount = params.fMSAASampleCount;
188     fStencilBits = 8;
189 
190     if (VK_FORMAT_UNDEFINED == surfaceFormat) {
191         return false;
192     }
193 
194     // If mailbox mode is available, use it, as it is the lowest-latency non-
195     // tearing mode. If not, fall back to FIFO which is always available.
196     VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
197     for (uint32_t i = 0; i < presentModeCount; ++i) {
198         // use mailbox
199         if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
200             mode = presentModes[i];
201             break;
202         }
203     }
204 
205     VkSwapchainCreateInfoKHR swapchainCreateInfo;
206     memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
207     swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
208     swapchainCreateInfo.surface = fSurface;
209     swapchainCreateInfo.minImageCount = imageCount;
210     swapchainCreateInfo.imageFormat = surfaceFormat;
211     swapchainCreateInfo.imageColorSpace = colorSpace;
212     swapchainCreateInfo.imageExtent = extent;
213     swapchainCreateInfo.imageArrayLayers = 1;
214     swapchainCreateInfo.imageUsage = usageFlags;
215 
216     uint32_t queueFamilies[] = { fBackendContext->fGraphicsQueueIndex, fPresentQueueIndex };
217     if (fBackendContext->fGraphicsQueueIndex != fPresentQueueIndex) {
218         swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
219         swapchainCreateInfo.queueFamilyIndexCount = 2;
220         swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
221     } else {
222         swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
223         swapchainCreateInfo.queueFamilyIndexCount = 0;
224         swapchainCreateInfo.pQueueFamilyIndices = nullptr;
225     }
226 
227     swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
228     swapchainCreateInfo.compositeAlpha = composite_alpha;
229     swapchainCreateInfo.presentMode = mode;
230     swapchainCreateInfo.clipped = true;
231     swapchainCreateInfo.oldSwapchain = fSwapchain;
232 
233     res = fCreateSwapchainKHR(fBackendContext->fDevice, &swapchainCreateInfo, nullptr, &fSwapchain);
234     if (VK_SUCCESS != res) {
235         return false;
236     }
237 
238     // destroy the old swapchain
239     if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
240         GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));
241 
242         this->destroyBuffers();
243 
244         fDestroySwapchainKHR(fBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
245     }
246 
247     this->createBuffers(swapchainCreateInfo.imageFormat);
248 
249     return true;
250 }
251 
createBuffers(VkFormat format)252 void VulkanWindowContext::createBuffers(VkFormat format) {
253     GrVkFormatToPixelConfig(format, &fPixelConfig);
254 
255     fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, nullptr);
256     SkASSERT(fImageCount);
257     fImages = new VkImage[fImageCount];
258     fGetSwapchainImagesKHR(fBackendContext->fDevice, fSwapchain, &fImageCount, fImages);
259 
260     // set up initial image layouts and create surfaces
261     fImageLayouts = new VkImageLayout[fImageCount];
262     fSurfaces = new sk_sp<SkSurface>[fImageCount];
263     for (uint32_t i = 0; i < fImageCount; ++i) {
264         fImageLayouts[i] = VK_IMAGE_LAYOUT_UNDEFINED;
265 
266         GrBackendRenderTargetDesc desc;
267         GrVkImageInfo info;
268         info.fImage = fImages[i];
269         info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
270         info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
271         info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
272         info.fFormat = format;
273         info.fLevelCount = 1;
274         desc.fWidth = fWidth;
275         desc.fHeight = fHeight;
276         desc.fConfig = fPixelConfig;
277         desc.fOrigin = kTopLeft_GrSurfaceOrigin;
278         desc.fSampleCnt = fSampleCount;
279         desc.fStencilBits = fStencilBits;
280         desc.fRenderTargetHandle = (GrBackendObject) &info;
281 
282         fSurfaces[i] = SkSurface::MakeFromBackendRenderTarget(fContext, desc,
283                                                               fDisplayParams.fColorSpace,
284                                                               &fSurfaceProps);
285     }
286 
287     // create the command pool for the command buffers
288     if (VK_NULL_HANDLE == fCommandPool) {
289         VkCommandPoolCreateInfo commandPoolInfo;
290         memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
291         commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
292         // this needs to be on the render queue
293         commandPoolInfo.queueFamilyIndex = fBackendContext->fGraphicsQueueIndex;
294         commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
295         GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
296                             CreateCommandPool(fBackendContext->fDevice, &commandPoolInfo,
297                                               nullptr, &fCommandPool));
298     }
299 
300     // set up the backbuffers
301     VkSemaphoreCreateInfo semaphoreInfo;
302     memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
303     semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
304     semaphoreInfo.pNext = nullptr;
305     semaphoreInfo.flags = 0;
306     VkCommandBufferAllocateInfo commandBuffersInfo;
307     memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
308     commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
309     commandBuffersInfo.pNext = nullptr;
310     commandBuffersInfo.commandPool = fCommandPool;
311     commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
312     commandBuffersInfo.commandBufferCount = 2;
313     VkFenceCreateInfo fenceInfo;
314     memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
315     fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
316     fenceInfo.pNext = nullptr;
317     fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
318 
319     // we create one additional backbuffer structure here, because we want to
320     // give the command buffers they contain a chance to finish before we cycle back
321     fBackbuffers = new BackbufferInfo[fImageCount + 1];
322     for (uint32_t i = 0; i < fImageCount + 1; ++i) {
323         fBackbuffers[i].fImageIndex = -1;
324         GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
325                             CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
326                                             nullptr, &fBackbuffers[i].fAcquireSemaphore));
327         GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
328                             CreateSemaphore(fBackendContext->fDevice, &semaphoreInfo,
329                                             nullptr, &fBackbuffers[i].fRenderSemaphore));
330         GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
331                             AllocateCommandBuffers(fBackendContext->fDevice, &commandBuffersInfo,
332                                                    fBackbuffers[i].fTransitionCmdBuffers));
333         GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
334                             CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
335                                         &fBackbuffers[i].fUsageFences[0]));
336         GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
337                             CreateFence(fBackendContext->fDevice, &fenceInfo, nullptr,
338                                         &fBackbuffers[i].fUsageFences[1]));
339     }
340     fCurrentBackbufferIndex = fImageCount;
341 }
342 
destroyBuffers()343 void VulkanWindowContext::destroyBuffers() {
344 
345     if (fBackbuffers) {
346         for (uint32_t i = 0; i < fImageCount + 1; ++i) {
347             GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
348                                 WaitForFences(fBackendContext->fDevice, 2,
349                                               fBackbuffers[i].fUsageFences,
350                                               true, UINT64_MAX));
351             fBackbuffers[i].fImageIndex = -1;
352             GR_VK_CALL(fBackendContext->fInterface,
353                        DestroySemaphore(fBackendContext->fDevice,
354                                         fBackbuffers[i].fAcquireSemaphore,
355                                         nullptr));
356             GR_VK_CALL(fBackendContext->fInterface,
357                        DestroySemaphore(fBackendContext->fDevice,
358                                         fBackbuffers[i].fRenderSemaphore,
359                                         nullptr));
360             GR_VK_CALL(fBackendContext->fInterface,
361                        FreeCommandBuffers(fBackendContext->fDevice, fCommandPool, 2,
362                                           fBackbuffers[i].fTransitionCmdBuffers));
363             GR_VK_CALL(fBackendContext->fInterface,
364                        DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[0], 0));
365             GR_VK_CALL(fBackendContext->fInterface,
366                        DestroyFence(fBackendContext->fDevice, fBackbuffers[i].fUsageFences[1], 0));
367         }
368     }
369 
370     delete[] fBackbuffers;
371     fBackbuffers = nullptr;
372 
373     // Does this actually free the surfaces?
374     delete[] fSurfaces;
375     fSurfaces = nullptr;
376     delete[] fImageLayouts;
377     fImageLayouts = nullptr;
378     delete[] fImages;
379     fImages = nullptr;
380 }
381 
~VulkanWindowContext()382 VulkanWindowContext::~VulkanWindowContext() {
383     this->destroyContext();
384 }
385 
destroyContext()386 void VulkanWindowContext::destroyContext() {
387     if (!fBackendContext.get()) {
388         return;
389     }
390 
391     GR_VK_CALL(fBackendContext->fInterface, QueueWaitIdle(fPresentQueue));
392     GR_VK_CALL(fBackendContext->fInterface, DeviceWaitIdle(fBackendContext->fDevice));
393 
394     this->destroyBuffers();
395 
396     if (VK_NULL_HANDLE != fCommandPool) {
397         GR_VK_CALL(fBackendContext->fInterface, DestroyCommandPool(fBackendContext->fDevice,
398                                                                    fCommandPool, nullptr));
399         fCommandPool = VK_NULL_HANDLE;
400     }
401 
402     if (VK_NULL_HANDLE != fSwapchain) {
403         fDestroySwapchainKHR(fBackendContext->fDevice, fSwapchain, nullptr);
404         fSwapchain = VK_NULL_HANDLE;
405     }
406 
407     if (VK_NULL_HANDLE != fSurface) {
408         fDestroySurfaceKHR(fBackendContext->fInstance, fSurface, nullptr);
409         fSurface = VK_NULL_HANDLE;
410     }
411 
412     fContext->unref();
413 
414     fBackendContext.reset(nullptr);
415 }
416 
getAvailableBackbuffer()417 VulkanWindowContext::BackbufferInfo* VulkanWindowContext::getAvailableBackbuffer() {
418     SkASSERT(fBackbuffers);
419 
420     ++fCurrentBackbufferIndex;
421     if (fCurrentBackbufferIndex > fImageCount) {
422         fCurrentBackbufferIndex = 0;
423     }
424 
425     BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
426     GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
427                         WaitForFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences,
428                                       true, UINT64_MAX));
429     return backbuffer;
430 }
431 
getBackbufferSurface()432 sk_sp<SkSurface> VulkanWindowContext::getBackbufferSurface() {
433     BackbufferInfo* backbuffer = this->getAvailableBackbuffer();
434     SkASSERT(backbuffer);
435 
436     // reset the fence
437     GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
438                         ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences));
439     // semaphores should be in unsignaled state
440 
441     // acquire the image
442     VkResult res = fAcquireNextImageKHR(fBackendContext->fDevice, fSwapchain, UINT64_MAX,
443                                         backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
444                                         &backbuffer->fImageIndex);
445     if (VK_ERROR_SURFACE_LOST_KHR == res) {
446         // need to figure out how to create a new vkSurface without the platformData*
447         // maybe use attach somehow? but need a Window
448         return nullptr;
449     }
450     if (VK_ERROR_OUT_OF_DATE_KHR == res) {
451         // tear swapchain down and try again
452         if (!this->createSwapchain(-1, -1, fDisplayParams)) {
453             return nullptr;
454         }
455         backbuffer = this->getAvailableBackbuffer();
456         GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
457                             ResetFences(fBackendContext->fDevice, 2, backbuffer->fUsageFences));
458 
459         // acquire the image
460         res = fAcquireNextImageKHR(fBackendContext->fDevice, fSwapchain, UINT64_MAX,
461                                    backbuffer->fAcquireSemaphore, VK_NULL_HANDLE,
462                                    &backbuffer->fImageIndex);
463 
464         if (VK_SUCCESS != res) {
465             return nullptr;
466         }
467     }
468 
469     // set up layout transfer from initial to color attachment
470     VkImageLayout layout = fImageLayouts[backbuffer->fImageIndex];
471     SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
472     VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
473                                         VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
474                                         VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
475     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
476     VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
477                                   0 : VK_ACCESS_MEMORY_READ_BIT;
478     VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
479 
480     VkImageMemoryBarrier imageMemoryBarrier = {
481         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // sType
482         NULL,                                     // pNext
483         srcAccessMask,                            // outputMask
484         dstAccessMask,                            // inputMask
485         layout,                                   // oldLayout
486         VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
487         fPresentQueueIndex,                       // srcQueueFamilyIndex
488         fBackendContext->fGraphicsQueueIndex,     // dstQueueFamilyIndex
489         fImages[backbuffer->fImageIndex],         // image
490         { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
491     };
492     GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
493                         ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[0], 0));
494     VkCommandBufferBeginInfo info;
495     memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
496     info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
497     info.flags = 0;
498     GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
499                         BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[0], &info));
500 
501     GR_VK_CALL(fBackendContext->fInterface,
502                CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[0],
503                                   srcStageMask, dstStageMask, 0,
504                                   0, nullptr,
505                                   0, nullptr,
506                                   1, &imageMemoryBarrier));
507 
508     GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
509                         EndCommandBuffer(backbuffer->fTransitionCmdBuffers[0]));
510 
511     VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
512     // insert the layout transfer into the queue and wait on the acquire
513     VkSubmitInfo submitInfo;
514     memset(&submitInfo, 0, sizeof(VkSubmitInfo));
515     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
516     submitInfo.waitSemaphoreCount = 1;
517     submitInfo.pWaitSemaphores = &backbuffer->fAcquireSemaphore;
518     submitInfo.pWaitDstStageMask = &waitDstStageFlags;
519     submitInfo.commandBufferCount = 1;
520     submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[0];
521     submitInfo.signalSemaphoreCount = 0;
522 
523     GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
524                         QueueSubmit(fBackendContext->fQueue, 1, &submitInfo,
525                                     backbuffer->fUsageFences[0]));
526 
527     GrVkImageInfo* imageInfo;
528     SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
529     surface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
530                                    SkSurface::kFlushRead_BackendHandleAccess);
531     imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
532 
533     return sk_ref_sp(surface);
534 }
535 
swapBuffers()536 void VulkanWindowContext::swapBuffers() {
537 
538     BackbufferInfo* backbuffer = fBackbuffers + fCurrentBackbufferIndex;
539     GrVkImageInfo* imageInfo;
540     SkSurface* surface = fSurfaces[backbuffer->fImageIndex].get();
541     surface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
542                                    SkSurface::kFlushRead_BackendHandleAccess);
543     // Check to make sure we never change the actually wrapped image
544     SkASSERT(imageInfo->fImage == fImages[backbuffer->fImageIndex]);
545 
546     VkImageLayout layout = imageInfo->fImageLayout;
547     VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(layout);
548     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
549     VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(layout);
550     VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
551 
552     VkImageMemoryBarrier imageMemoryBarrier = {
553         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,   // sType
554         NULL,                                     // pNext
555         srcAccessMask,                            // outputMask
556         dstAccessMask,                            // inputMask
557         layout,                                   // oldLayout
558         VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,          // newLayout
559         fBackendContext->fGraphicsQueueIndex,     // srcQueueFamilyIndex
560         fPresentQueueIndex,                       // dstQueueFamilyIndex
561         fImages[backbuffer->fImageIndex],         // image
562         { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
563     };
564     GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
565                         ResetCommandBuffer(backbuffer->fTransitionCmdBuffers[1], 0));
566     VkCommandBufferBeginInfo info;
567     memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
568     info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
569     info.flags = 0;
570     GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
571                         BeginCommandBuffer(backbuffer->fTransitionCmdBuffers[1], &info));
572     GR_VK_CALL(fBackendContext->fInterface,
573                CmdPipelineBarrier(backbuffer->fTransitionCmdBuffers[1],
574                                   srcStageMask, dstStageMask, 0,
575                                   0, nullptr,
576                                   0, nullptr,
577                                   1, &imageMemoryBarrier));
578     GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
579                         EndCommandBuffer(backbuffer->fTransitionCmdBuffers[1]));
580 
581     fImageLayouts[backbuffer->fImageIndex] = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
582 
583     // insert the layout transfer into the queue and wait on the acquire
584     VkSubmitInfo submitInfo;
585     memset(&submitInfo, 0, sizeof(VkSubmitInfo));
586     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
587     submitInfo.waitSemaphoreCount = 0;
588     submitInfo.pWaitDstStageMask = 0;
589     submitInfo.commandBufferCount = 1;
590     submitInfo.pCommandBuffers = &backbuffer->fTransitionCmdBuffers[1];
591     submitInfo.signalSemaphoreCount = 1;
592     submitInfo.pSignalSemaphores = &backbuffer->fRenderSemaphore;
593 
594     GR_VK_CALL_ERRCHECK(fBackendContext->fInterface,
595                         QueueSubmit(fBackendContext->fQueue, 1, &submitInfo,
596                                     backbuffer->fUsageFences[1]));
597 
598     // Submit present operation to present queue
599     const VkPresentInfoKHR presentInfo =
600     {
601         VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
602         NULL, // pNext
603         1, // waitSemaphoreCount
604         &backbuffer->fRenderSemaphore, // pWaitSemaphores
605         1, // swapchainCount
606         &fSwapchain, // pSwapchains
607         &backbuffer->fImageIndex, // pImageIndices
608         NULL // pResults
609     };
610 
611     fQueuePresentKHR(fPresentQueue, &presentInfo);
612 }
613 
614 }   //namespace sk_app
615