Home | History | Annotate | Download | only in renderthread
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "VulkanManager.h"
     18 
     19 #include "DeviceInfo.h"
     20 #include "Properties.h"
     21 #include "RenderThread.h"
     22 #include "renderstate/RenderState.h"
     23 #include "utils/FatVector.h"
     24 
     25 #include <GrBackendSurface.h>
     26 #include <GrContext.h>
     27 #include <GrTypes.h>
     28 #include <vk/GrVkTypes.h>
     29 
     30 namespace android {
     31 namespace uirenderer {
     32 namespace renderthread {
     33 
     34 #define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F)
     35 #define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F)
     36 
     37 VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
     38 
     39 void VulkanManager::destroy() {
     40     if (!hasVkContext()) return;
     41 
     42     mRenderThread.renderState().onVkContextDestroyed();
     43     mRenderThread.setGrContext(nullptr);
     44 
     45     if (VK_NULL_HANDLE != mCommandPool) {
     46         mDestroyCommandPool(mBackendContext->fDevice, mCommandPool, nullptr);
     47         mCommandPool = VK_NULL_HANDLE;
     48     }
     49     mBackendContext.reset();
     50 }
     51 
     52 void VulkanManager::initialize() {
     53     if (hasVkContext()) {
     54         return;
     55     }
     56 
     57     auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; };
     58 
     59     mBackendContext.reset(GrVkBackendContext::Create(vkGetInstanceProcAddr, vkGetDeviceProcAddr,
     60                                                      &mPresentQueueIndex, canPresent));
     61     LOG_ALWAYS_FATAL_IF(!mBackendContext.get());
     62 
     63     // Get all the addresses of needed vulkan functions
     64     VkInstance instance = mBackendContext->fInstance;
     65     VkDevice device = mBackendContext->fDevice;
     66     GET_PROC(CreateAndroidSurfaceKHR);
     67     GET_PROC(DestroySurfaceKHR);
     68     GET_PROC(GetPhysicalDeviceSurfaceSupportKHR);
     69     GET_PROC(GetPhysicalDeviceSurfaceCapabilitiesKHR);
     70     GET_PROC(GetPhysicalDeviceSurfaceFormatsKHR);
     71     GET_PROC(GetPhysicalDeviceSurfacePresentModesKHR);
     72     GET_DEV_PROC(CreateSwapchainKHR);
     73     GET_DEV_PROC(DestroySwapchainKHR);
     74     GET_DEV_PROC(GetSwapchainImagesKHR);
     75     GET_DEV_PROC(AcquireNextImageKHR);
     76     GET_DEV_PROC(QueuePresentKHR);
     77     GET_DEV_PROC(CreateCommandPool);
     78     GET_DEV_PROC(DestroyCommandPool);
     79     GET_DEV_PROC(AllocateCommandBuffers);
     80     GET_DEV_PROC(FreeCommandBuffers);
     81     GET_DEV_PROC(ResetCommandBuffer);
     82     GET_DEV_PROC(BeginCommandBuffer);
     83     GET_DEV_PROC(EndCommandBuffer);
     84     GET_DEV_PROC(CmdPipelineBarrier);
     85     GET_DEV_PROC(GetDeviceQueue);
     86     GET_DEV_PROC(QueueSubmit);
     87     GET_DEV_PROC(QueueWaitIdle);
     88     GET_DEV_PROC(DeviceWaitIdle);
     89     GET_DEV_PROC(CreateSemaphore);
     90     GET_DEV_PROC(DestroySemaphore);
     91     GET_DEV_PROC(CreateFence);
     92     GET_DEV_PROC(DestroyFence);
     93     GET_DEV_PROC(WaitForFences);
     94     GET_DEV_PROC(ResetFences);
     95 
     96     // create the command pool for the command buffers
     97     if (VK_NULL_HANDLE == mCommandPool) {
     98         VkCommandPoolCreateInfo commandPoolInfo;
     99         memset(&commandPoolInfo, 0, sizeof(VkCommandPoolCreateInfo));
    100         commandPoolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
    101         // this needs to be on the render queue
    102         commandPoolInfo.queueFamilyIndex = mBackendContext->fGraphicsQueueIndex;
    103         commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
    104         SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice, &commandPoolInfo,
    105                                                        nullptr, &mCommandPool);
    106         SkASSERT(VK_SUCCESS == res);
    107     }
    108 
    109     mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue);
    110 
    111     GrContextOptions options;
    112     options.fDisableDistanceFieldPaths = true;
    113     mRenderThread.cacheManager().configureContext(&options);
    114     sk_sp<GrContext> grContext(GrContext::MakeVulkan(mBackendContext, options));
    115     LOG_ALWAYS_FATAL_IF(!grContext.get());
    116     mRenderThread.setGrContext(grContext);
    117     DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize());
    118 
    119     if (Properties::enablePartialUpdates && Properties::useBufferAge) {
    120         mSwapBehavior = SwapBehavior::BufferAge;
    121     }
    122 
    123     mRenderThread.renderState().onVkContextCreated();
    124 }
    125 
    126 // Returns the next BackbufferInfo to use for the next draw. The function will make sure all
    127 // previous uses have finished before returning.
    128 VulkanSurface::BackbufferInfo* VulkanManager::getAvailableBackbuffer(VulkanSurface* surface) {
    129     SkASSERT(surface->mBackbuffers);
    130 
    131     ++surface->mCurrentBackbufferIndex;
    132     if (surface->mCurrentBackbufferIndex > surface->mImageCount) {
    133         surface->mCurrentBackbufferIndex = 0;
    134     }
    135 
    136     VulkanSurface::BackbufferInfo* backbuffer =
    137             surface->mBackbuffers + surface->mCurrentBackbufferIndex;
    138 
    139     // Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
    140     // reuse its commands buffers.
    141     VkResult res =
    142             mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences, true, UINT64_MAX);
    143     if (res != VK_SUCCESS) {
    144         return nullptr;
    145     }
    146 
    147     return backbuffer;
    148 }
    149 
    150 SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
    151     VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface);
    152     SkASSERT(backbuffer);
    153 
    154     VkResult res;
    155 
    156     res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences);
    157     SkASSERT(VK_SUCCESS == res);
    158 
    159     // The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
    160     // finished presenting and that it is safe to begin sending new commands to the returned image.
    161     res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
    162                                backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
    163                                &backbuffer->mImageIndex);
    164 
    165     if (VK_ERROR_SURFACE_LOST_KHR == res) {
    166         // need to figure out how to create a new vkSurface without the platformData*
    167         // maybe use attach somehow? but need a Window
    168         return nullptr;
    169     }
    170     if (VK_ERROR_OUT_OF_DATE_KHR == res) {
    171         // tear swapchain down and try again
    172         if (!createSwapchain(surface)) {
    173             return nullptr;
    174         }
    175         backbuffer = getAvailableBackbuffer(surface);
    176         res = mResetFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences);
    177         SkASSERT(VK_SUCCESS == res);
    178 
    179         // acquire the image
    180         res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
    181                                    backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
    182                                    &backbuffer->mImageIndex);
    183 
    184         if (VK_SUCCESS != res) {
    185             return nullptr;
    186         }
    187     }
    188 
    189     // set up layout transfer from initial to color attachment
    190     VkImageLayout layout = surface->mImageInfos[backbuffer->mImageIndex].mImageLayout;
    191     SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
    192     VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout)
    193                                                 ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
    194                                                 : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    195     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    196     VkAccessFlags srcAccessMask =
    197             (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? 0 : VK_ACCESS_MEMORY_READ_BIT;
    198     VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    199 
    200     VkImageMemoryBarrier imageMemoryBarrier = {
    201             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,     // sType
    202             NULL,                                       // pNext
    203             srcAccessMask,                              // outputMask
    204             dstAccessMask,                              // inputMask
    205             layout,                                     // oldLayout
    206             VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,   // newLayout
    207             mPresentQueueIndex,                         // srcQueueFamilyIndex
    208             mBackendContext->fGraphicsQueueIndex,       // dstQueueFamilyIndex
    209             surface->mImages[backbuffer->mImageIndex],  // image
    210             {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}     // subresourceRange
    211     };
    212     mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0);
    213 
    214     VkCommandBufferBeginInfo info;
    215     memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
    216     info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    217     info.flags = 0;
    218     mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info);
    219 
    220     mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, 0,
    221                         nullptr, 0, nullptr, 1, &imageMemoryBarrier);
    222 
    223     mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]);
    224 
    225     VkPipelineStageFlags waitDstStageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
    226     // insert the layout transfer into the queue and wait on the acquire
    227     VkSubmitInfo submitInfo;
    228     memset(&submitInfo, 0, sizeof(VkSubmitInfo));
    229     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    230     submitInfo.waitSemaphoreCount = 1;
    231     // Wait to make sure aquire semaphore set above has signaled.
    232     submitInfo.pWaitSemaphores = &backbuffer->mAcquireSemaphore;
    233     submitInfo.pWaitDstStageMask = &waitDstStageFlags;
    234     submitInfo.commandBufferCount = 1;
    235     submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[0];
    236     submitInfo.signalSemaphoreCount = 0;
    237 
    238     // Attach first fence to submission here so we can track when the command buffer finishes.
    239     mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[0]);
    240 
    241     // We need to notify Skia that we changed the layout of the wrapped VkImage
    242     GrVkImageInfo* imageInfo;
    243     sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface;
    244     skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
    245                                      SkSurface::kFlushRead_BackendHandleAccess);
    246     imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
    247 
    248     surface->mBackbuffer = std::move(skSurface);
    249     return surface->mBackbuffer.get();
    250 }
    251 
    252 void VulkanManager::destroyBuffers(VulkanSurface* surface) {
    253     if (surface->mBackbuffers) {
    254         for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
    255             mWaitForFences(mBackendContext->fDevice, 2, surface->mBackbuffers[i].mUsageFences, true,
    256                            UINT64_MAX);
    257             surface->mBackbuffers[i].mImageIndex = -1;
    258             mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mAcquireSemaphore,
    259                               nullptr);
    260             mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mRenderSemaphore,
    261                               nullptr);
    262             mFreeCommandBuffers(mBackendContext->fDevice, mCommandPool, 2,
    263                                 surface->mBackbuffers[i].mTransitionCmdBuffers);
    264             mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
    265             mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
    266         }
    267     }
    268 
    269     delete[] surface->mBackbuffers;
    270     surface->mBackbuffers = nullptr;
    271     delete[] surface->mImageInfos;
    272     surface->mImageInfos = nullptr;
    273     delete[] surface->mImages;
    274     surface->mImages = nullptr;
    275 }
    276 
    277 void VulkanManager::destroySurface(VulkanSurface* surface) {
    278     // Make sure all submit commands have finished before starting to destroy objects.
    279     if (VK_NULL_HANDLE != mPresentQueue) {
    280         mQueueWaitIdle(mPresentQueue);
    281     }
    282     mDeviceWaitIdle(mBackendContext->fDevice);
    283 
    284     destroyBuffers(surface);
    285 
    286     if (VK_NULL_HANDLE != surface->mSwapchain) {
    287         mDestroySwapchainKHR(mBackendContext->fDevice, surface->mSwapchain, nullptr);
    288         surface->mSwapchain = VK_NULL_HANDLE;
    289     }
    290 
    291     if (VK_NULL_HANDLE != surface->mVkSurface) {
    292         mDestroySurfaceKHR(mBackendContext->fInstance, surface->mVkSurface, nullptr);
    293         surface->mVkSurface = VK_NULL_HANDLE;
    294     }
    295     delete surface;
    296 }
    297 
    298 void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
    299     mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
    300                            nullptr);
    301     SkASSERT(surface->mImageCount);
    302     surface->mImages = new VkImage[surface->mImageCount];
    303     mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
    304                            surface->mImages);
    305 
    306     SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
    307 
    308     // set up initial image layouts and create surfaces
    309     surface->mImageInfos = new VulkanSurface::ImageInfo[surface->mImageCount];
    310     for (uint32_t i = 0; i < surface->mImageCount; ++i) {
    311         GrVkImageInfo info;
    312         info.fImage = surface->mImages[i];
    313         info.fAlloc = GrVkAlloc();
    314         info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
    315         info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
    316         info.fFormat = format;
    317         info.fLevelCount = 1;
    318 
    319         GrBackendRenderTarget backendRT(extent.width, extent.height, 0, 0, info);
    320 
    321         VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
    322         imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(
    323                 mRenderThread.getGrContext(), backendRT, kTopLeft_GrSurfaceOrigin, nullptr, &props);
    324     }
    325 
    326     SkASSERT(mCommandPool != VK_NULL_HANDLE);
    327 
    328     // set up the backbuffers
    329     VkSemaphoreCreateInfo semaphoreInfo;
    330     memset(&semaphoreInfo, 0, sizeof(VkSemaphoreCreateInfo));
    331     semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
    332     semaphoreInfo.pNext = nullptr;
    333     semaphoreInfo.flags = 0;
    334     VkCommandBufferAllocateInfo commandBuffersInfo;
    335     memset(&commandBuffersInfo, 0, sizeof(VkCommandBufferAllocateInfo));
    336     commandBuffersInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
    337     commandBuffersInfo.pNext = nullptr;
    338     commandBuffersInfo.commandPool = mCommandPool;
    339     commandBuffersInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
    340     commandBuffersInfo.commandBufferCount = 2;
    341     VkFenceCreateInfo fenceInfo;
    342     memset(&fenceInfo, 0, sizeof(VkFenceCreateInfo));
    343     fenceInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
    344     fenceInfo.pNext = nullptr;
    345     fenceInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
    346 
    347     // we create one additional backbuffer structure here, because we want to
    348     // give the command buffers they contain a chance to finish before we cycle back
    349     surface->mBackbuffers = new VulkanSurface::BackbufferInfo[surface->mImageCount + 1];
    350     for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
    351         SkDEBUGCODE(VkResult res);
    352         surface->mBackbuffers[i].mImageIndex = -1;
    353         SkDEBUGCODE(res =) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
    354                                             &surface->mBackbuffers[i].mAcquireSemaphore);
    355         SkDEBUGCODE(res =) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
    356                                             &surface->mBackbuffers[i].mRenderSemaphore);
    357         SkDEBUGCODE(res =) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo,
    358                                                    surface->mBackbuffers[i].mTransitionCmdBuffers);
    359         SkDEBUGCODE(res =) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
    360                                         &surface->mBackbuffers[i].mUsageFences[0]);
    361         SkDEBUGCODE(res =) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
    362                                         &surface->mBackbuffers[i].mUsageFences[1]);
    363         SkASSERT(VK_SUCCESS == res);
    364     }
    365     surface->mCurrentBackbufferIndex = surface->mImageCount;
    366 }
    367 
    368 bool VulkanManager::createSwapchain(VulkanSurface* surface) {
    369     // check for capabilities
    370     VkSurfaceCapabilitiesKHR caps;
    371     VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mBackendContext->fPhysicalDevice,
    372                                                             surface->mVkSurface, &caps);
    373     if (VK_SUCCESS != res) {
    374         return false;
    375     }
    376 
    377     uint32_t surfaceFormatCount;
    378     res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
    379                                               &surfaceFormatCount, nullptr);
    380     if (VK_SUCCESS != res) {
    381         return false;
    382     }
    383 
    384     FatVector<VkSurfaceFormatKHR, 4> surfaceFormats(surfaceFormatCount);
    385     res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
    386                                               &surfaceFormatCount, surfaceFormats.data());
    387     if (VK_SUCCESS != res) {
    388         return false;
    389     }
    390 
    391     uint32_t presentModeCount;
    392     res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
    393                                                    surface->mVkSurface, &presentModeCount, nullptr);
    394     if (VK_SUCCESS != res) {
    395         return false;
    396     }
    397 
    398     FatVector<VkPresentModeKHR, VK_PRESENT_MODE_RANGE_SIZE_KHR> presentModes(presentModeCount);
    399     res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
    400                                                    surface->mVkSurface, &presentModeCount,
    401                                                    presentModes.data());
    402     if (VK_SUCCESS != res) {
    403         return false;
    404     }
    405 
    406     VkExtent2D extent = caps.currentExtent;
    407     // clamp width; to handle currentExtent of -1 and  protect us from broken hints
    408     if (extent.width < caps.minImageExtent.width) {
    409         extent.width = caps.minImageExtent.width;
    410     }
    411     SkASSERT(extent.width <= caps.maxImageExtent.width);
    412     // clamp height
    413     if (extent.height < caps.minImageExtent.height) {
    414         extent.height = caps.minImageExtent.height;
    415     }
    416     SkASSERT(extent.height <= caps.maxImageExtent.height);
    417 
    418     uint32_t imageCount = caps.minImageCount + 2;
    419     if (caps.maxImageCount > 0 && imageCount > caps.maxImageCount) {
    420         // Application must settle for fewer images than desired:
    421         imageCount = caps.maxImageCount;
    422     }
    423 
    424     // Currently Skia requires the images to be color attchments and support all transfer
    425     // operations.
    426     VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
    427                                    VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
    428                                    VK_IMAGE_USAGE_TRANSFER_DST_BIT;
    429     SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
    430     SkASSERT(caps.supportedTransforms & caps.currentTransform);
    431     SkASSERT(caps.supportedCompositeAlpha &
    432              (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
    433     VkCompositeAlphaFlagBitsKHR composite_alpha =
    434             (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
    435                     ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
    436                     : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
    437 
    438     // Pick our surface format. For now, just make sure it matches our sRGB request:
    439     VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
    440     VkColorSpaceKHR colorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
    441 
    442     bool wantSRGB = false;
    443 #ifdef ANDROID_ENABLE_LINEAR_BLENDING
    444     wantSRGB = true;
    445 #endif
    446     for (uint32_t i = 0; i < surfaceFormatCount; ++i) {
    447         // We are assuming we can get either R8G8B8A8_UNORM or R8G8B8A8_SRGB
    448         VkFormat desiredFormat = wantSRGB ? VK_FORMAT_R8G8B8A8_SRGB : VK_FORMAT_R8G8B8A8_UNORM;
    449         if (desiredFormat == surfaceFormats[i].format) {
    450             surfaceFormat = surfaceFormats[i].format;
    451             colorSpace = surfaceFormats[i].colorSpace;
    452         }
    453     }
    454 
    455     if (VK_FORMAT_UNDEFINED == surfaceFormat) {
    456         return false;
    457     }
    458 
    459     // If mailbox mode is available, use it, as it is the lowest-latency non-
    460     // tearing mode. If not, fall back to FIFO which is always available.
    461     VkPresentModeKHR mode = VK_PRESENT_MODE_FIFO_KHR;
    462     for (uint32_t i = 0; i < presentModeCount; ++i) {
    463         // use mailbox
    464         if (VK_PRESENT_MODE_MAILBOX_KHR == presentModes[i]) {
    465             mode = presentModes[i];
    466             break;
    467         }
    468     }
    469 
    470     VkSwapchainCreateInfoKHR swapchainCreateInfo;
    471     memset(&swapchainCreateInfo, 0, sizeof(VkSwapchainCreateInfoKHR));
    472     swapchainCreateInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
    473     swapchainCreateInfo.surface = surface->mVkSurface;
    474     swapchainCreateInfo.minImageCount = imageCount;
    475     swapchainCreateInfo.imageFormat = surfaceFormat;
    476     swapchainCreateInfo.imageColorSpace = colorSpace;
    477     swapchainCreateInfo.imageExtent = extent;
    478     swapchainCreateInfo.imageArrayLayers = 1;
    479     swapchainCreateInfo.imageUsage = usageFlags;
    480 
    481     uint32_t queueFamilies[] = {mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex};
    482     if (mBackendContext->fGraphicsQueueIndex != mPresentQueueIndex) {
    483         swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
    484         swapchainCreateInfo.queueFamilyIndexCount = 2;
    485         swapchainCreateInfo.pQueueFamilyIndices = queueFamilies;
    486     } else {
    487         swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
    488         swapchainCreateInfo.queueFamilyIndexCount = 0;
    489         swapchainCreateInfo.pQueueFamilyIndices = nullptr;
    490     }
    491 
    492     swapchainCreateInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
    493     swapchainCreateInfo.compositeAlpha = composite_alpha;
    494     swapchainCreateInfo.presentMode = mode;
    495     swapchainCreateInfo.clipped = true;
    496     swapchainCreateInfo.oldSwapchain = surface->mSwapchain;
    497 
    498     res = mCreateSwapchainKHR(mBackendContext->fDevice, &swapchainCreateInfo, nullptr,
    499                               &surface->mSwapchain);
    500     if (VK_SUCCESS != res) {
    501         return false;
    502     }
    503 
    504     // destroy the old swapchain
    505     if (swapchainCreateInfo.oldSwapchain != VK_NULL_HANDLE) {
    506         mDeviceWaitIdle(mBackendContext->fDevice);
    507 
    508         destroyBuffers(surface);
    509 
    510         mDestroySwapchainKHR(mBackendContext->fDevice, swapchainCreateInfo.oldSwapchain, nullptr);
    511     }
    512 
    513     createBuffers(surface, surfaceFormat, extent);
    514 
    515     return true;
    516 }
    517 
    518 VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) {
    519     initialize();
    520 
    521     if (!window) {
    522         return nullptr;
    523     }
    524 
    525     VulkanSurface* surface = new VulkanSurface();
    526 
    527     VkAndroidSurfaceCreateInfoKHR surfaceCreateInfo;
    528     memset(&surfaceCreateInfo, 0, sizeof(VkAndroidSurfaceCreateInfoKHR));
    529     surfaceCreateInfo.sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR;
    530     surfaceCreateInfo.pNext = nullptr;
    531     surfaceCreateInfo.flags = 0;
    532     surfaceCreateInfo.window = window;
    533 
    534     VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo, nullptr,
    535                                             &surface->mVkSurface);
    536     if (VK_SUCCESS != res) {
    537         delete surface;
    538         return nullptr;
    539     }
    540 
    541     SkDEBUGCODE(VkBool32 supported; res = mGetPhysicalDeviceSurfaceSupportKHR(
    542                                             mBackendContext->fPhysicalDevice, mPresentQueueIndex,
    543                                             surface->mVkSurface, &supported);
    544                 // All physical devices and queue families on Android must be capable of
    545                 // presentation with any
    546                 // native window.
    547                 SkASSERT(VK_SUCCESS == res && supported););
    548 
    549     if (!createSwapchain(surface)) {
    550         destroySurface(surface);
    551         return nullptr;
    552     }
    553 
    554     return surface;
    555 }
    556 
    557 // Helper to know which src stage flags we need to set when transitioning to the present layout
    558 static VkPipelineStageFlags layoutToPipelineStageFlags(const VkImageLayout layout) {
    559     if (VK_IMAGE_LAYOUT_GENERAL == layout) {
    560         return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
    561     } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
    562                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
    563         return VK_PIPELINE_STAGE_TRANSFER_BIT;
    564     } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout ||
    565                VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
    566                VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout ||
    567                VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
    568         return VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
    569     } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
    570         return VK_PIPELINE_STAGE_HOST_BIT;
    571     }
    572 
    573     SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
    574     return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
    575 }
    576 
    577 // Helper to know which src access mask we need to set when transitioning to the present layout
    578 static VkAccessFlags layoutToSrcAccessMask(const VkImageLayout layout) {
    579     VkAccessFlags flags = 0;
    580     if (VK_IMAGE_LAYOUT_GENERAL == layout) {
    581         flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
    582                 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
    583                 VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_HOST_WRITE_BIT |
    584                 VK_ACCESS_HOST_READ_BIT;
    585     } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
    586         flags = VK_ACCESS_HOST_WRITE_BIT;
    587     } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
    588         flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    589     } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
    590         flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
    591     } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
    592         flags = VK_ACCESS_TRANSFER_WRITE_BIT;
    593     } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
    594         flags = VK_ACCESS_TRANSFER_READ_BIT;
    595     } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
    596         flags = VK_ACCESS_SHADER_READ_BIT;
    597     }
    598     return flags;
    599 }
    600 
    601 void VulkanManager::swapBuffers(VulkanSurface* surface) {
    602     if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
    603         ATRACE_NAME("Finishing GPU work");
    604         mDeviceWaitIdle(mBackendContext->fDevice);
    605     }
    606 
    607     SkASSERT(surface->mBackbuffers);
    608     VulkanSurface::BackbufferInfo* backbuffer =
    609             surface->mBackbuffers + surface->mCurrentBackbufferIndex;
    610     GrVkImageInfo* imageInfo;
    611     SkSurface* skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface.get();
    612     skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
    613                                      SkSurface::kFlushRead_BackendHandleAccess);
    614     // Check to make sure we never change the actually wrapped image
    615     SkASSERT(imageInfo->fImage == surface->mImages[backbuffer->mImageIndex]);
    616 
    617     // We need to transition the image to VK_IMAGE_LAYOUT_PRESENT_SRC_KHR and make sure that all
    618     // previous work is complete for before presenting. So we first add the necessary barrier here.
    619     VkImageLayout layout = imageInfo->fImageLayout;
    620     VkPipelineStageFlags srcStageMask = layoutToPipelineStageFlags(layout);
    621     VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
    622     VkAccessFlags srcAccessMask = layoutToSrcAccessMask(layout);
    623     VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
    624 
    625     VkImageMemoryBarrier imageMemoryBarrier = {
    626             VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,     // sType
    627             NULL,                                       // pNext
    628             srcAccessMask,                              // outputMask
    629             dstAccessMask,                              // inputMask
    630             layout,                                     // oldLayout
    631             VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,            // newLayout
    632             mBackendContext->fGraphicsQueueIndex,       // srcQueueFamilyIndex
    633             mPresentQueueIndex,                         // dstQueueFamilyIndex
    634             surface->mImages[backbuffer->mImageIndex],  // image
    635             {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1}     // subresourceRange
    636     };
    637 
    638     mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0);
    639     VkCommandBufferBeginInfo info;
    640     memset(&info, 0, sizeof(VkCommandBufferBeginInfo));
    641     info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    642     info.flags = 0;
    643     mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info);
    644     mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, 0,
    645                         nullptr, 0, nullptr, 1, &imageMemoryBarrier);
    646     mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
    647 
    648     surface->mImageInfos[backbuffer->mImageIndex].mImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
    649 
    650     // insert the layout transfer into the queue and wait on the acquire
    651     VkSubmitInfo submitInfo;
    652     memset(&submitInfo, 0, sizeof(VkSubmitInfo));
    653     submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    654     submitInfo.waitSemaphoreCount = 0;
    655     submitInfo.pWaitDstStageMask = 0;
    656     submitInfo.commandBufferCount = 1;
    657     submitInfo.pCommandBuffers = &backbuffer->mTransitionCmdBuffers[1];
    658     submitInfo.signalSemaphoreCount = 1;
    659     // When this command buffer finishes we will signal this semaphore so that we know it is now
    660     // safe to present the image to the screen.
    661     submitInfo.pSignalSemaphores = &backbuffer->mRenderSemaphore;
    662 
    663     // Attach second fence to submission here so we can track when the command buffer finishes.
    664     mQueueSubmit(mBackendContext->fQueue, 1, &submitInfo, backbuffer->mUsageFences[1]);
    665 
    666     // Submit present operation to present queue. We use a semaphore here to make sure all rendering
    667     // to the image is complete and that the layout has been change to present on the graphics
    668     // queue.
    669     const VkPresentInfoKHR presentInfo = {
    670             VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,  // sType
    671             NULL,                                // pNext
    672             1,                                   // waitSemaphoreCount
    673             &backbuffer->mRenderSemaphore,       // pWaitSemaphores
    674             1,                                   // swapchainCount
    675             &surface->mSwapchain,                // pSwapchains
    676             &backbuffer->mImageIndex,            // pImageIndices
    677             NULL                                 // pResults
    678     };
    679 
    680     mQueuePresentKHR(mPresentQueue, &presentInfo);
    681 
    682     surface->mBackbuffer.reset();
    683     surface->mImageInfos[backbuffer->mImageIndex].mLastUsed = surface->mCurrentTime;
    684     surface->mImageInfos[backbuffer->mImageIndex].mInvalid = false;
    685     surface->mCurrentTime++;
    686 }
    687 
    688 int VulkanManager::getAge(VulkanSurface* surface) {
    689     SkASSERT(surface->mBackbuffers);
    690     VulkanSurface::BackbufferInfo* backbuffer =
    691             surface->mBackbuffers + surface->mCurrentBackbufferIndex;
    692     if (mSwapBehavior == SwapBehavior::Discard ||
    693         surface->mImageInfos[backbuffer->mImageIndex].mInvalid) {
    694         return 0;
    695     }
    696     uint16_t lastUsed = surface->mImageInfos[backbuffer->mImageIndex].mLastUsed;
    697     return surface->mCurrentTime - lastUsed;
    698 }
    699 
    700 } /* namespace renderthread */
    701 } /* namespace uirenderer */
    702 } /* namespace android */
    703