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
28namespace sk_app {
29
30VulkanWindowContext::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
91bool 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
252void 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
343void 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
382VulkanWindowContext::~VulkanWindowContext() {
383    this->destroyContext();
384}
385
386void 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
417VulkanWindowContext::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
432sk_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
536void 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