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