Home | History | Annotate | Download | only in vk
      1 /*
      2  * Copyright 2015 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "GrVkGpu.h"
      9 #include "GrVkImage.h"
     10 #include "GrVkMemory.h"
     11 #include "GrVkUtil.h"
     12 
     13 #define VK_CALL(GPU, X) GR_VK_CALL(GPU->vkInterface(), X)
     14 
     15 VkImageAspectFlags vk_format_to_aspect_flags(VkFormat format) {
     16     switch (format) {
     17         case VK_FORMAT_S8_UINT:
     18             return VK_IMAGE_ASPECT_STENCIL_BIT;
     19         case VK_FORMAT_D24_UNORM_S8_UINT: // fallthrough
     20         case VK_FORMAT_D32_SFLOAT_S8_UINT:
     21             return VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
     22         default:
     23             SkASSERT(GrVkFormatIsSupported(format));
     24             return VK_IMAGE_ASPECT_COLOR_BIT;
     25     }
     26 }
     27 
     28 void GrVkImage::setImageLayout(const GrVkGpu* gpu, VkImageLayout newLayout,
     29                                VkAccessFlags dstAccessMask,
     30                                VkPipelineStageFlags dstStageMask,
     31                                bool byRegion,
     32                                bool releaseFamilyQueue) {
     33     SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED != newLayout &&
     34              VK_IMAGE_LAYOUT_PREINITIALIZED != newLayout);
     35     VkImageLayout currentLayout = this->currentLayout();
     36 
     37     if (releaseFamilyQueue && fInfo.fCurrentQueueFamily == fInfo.fInitialQueueFamily) {
     38         // We never transfered the image to this queue and we are releasing it so don't do anything.
     39         return;
     40     }
     41 
     42     // If the old and new layout are the same and the layout is a read only layout, there is no need
     43     // to put in a barrier.
     44     if (newLayout == currentLayout &&
     45         !releaseFamilyQueue &&
     46         (VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == currentLayout ||
     47          VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == currentLayout ||
     48          VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == currentLayout)) {
     49         return;
     50     }
     51 
     52     VkAccessFlags srcAccessMask = GrVkMemory::LayoutToSrcAccessMask(currentLayout);
     53     VkPipelineStageFlags srcStageMask = GrVkMemory::LayoutToPipelineStageFlags(currentLayout);
     54 
     55     VkImageAspectFlags aspectFlags = vk_format_to_aspect_flags(fInfo.fFormat);
     56 
     57     uint32_t srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
     58     uint32_t dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
     59     if (VK_QUEUE_FAMILY_IGNORED != fInfo.fCurrentQueueFamily) {
     60         srcQueueFamilyIndex = fInfo.fInitialQueueFamily;
     61         dstQueueFamilyIndex = gpu->queueIndex();
     62         fInfo.fCurrentQueueFamily = VK_QUEUE_FAMILY_IGNORED;
     63     } else if (releaseFamilyQueue) {
     64         srcQueueFamilyIndex = gpu->queueIndex();
     65         dstQueueFamilyIndex = fInfo.fInitialQueueFamily;
     66         fInfo.fCurrentQueueFamily = fInfo.fInitialQueueFamily;
     67     }
     68 
     69     VkImageMemoryBarrier imageMemoryBarrier = {
     70         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,          // sType
     71         nullptr,                                         // pNext
     72         srcAccessMask,                                   // outputMask
     73         dstAccessMask,                                   // inputMask
     74         currentLayout,                                   // oldLayout
     75         newLayout,                                       // newLayout
     76         srcQueueFamilyIndex,                             // srcQueueFamilyIndex
     77         dstQueueFamilyIndex,                             // dstQueueFamilyIndex
     78         fInfo.fImage,                                    // image
     79         { aspectFlags, 0, fInfo.fLevelCount, 0, 1 }      // subresourceRange
     80     };
     81 
     82     gpu->addImageMemoryBarrier(srcStageMask, dstStageMask, byRegion, &imageMemoryBarrier);
     83 
     84     fInfo.fImageLayout = newLayout;
     85 }
     86 
     87 bool GrVkImage::InitImageInfo(const GrVkGpu* gpu, const ImageDesc& imageDesc, GrVkImageInfo* info) {
     88     if (0 == imageDesc.fWidth || 0 == imageDesc.fHeight) {
     89         return false;
     90     }
     91     VkImage image = 0;
     92     GrVkAlloc alloc;
     93 
     94     bool isLinear = VK_IMAGE_TILING_LINEAR == imageDesc.fImageTiling;
     95     VkImageLayout initialLayout = isLinear ? VK_IMAGE_LAYOUT_PREINITIALIZED
     96                                            : VK_IMAGE_LAYOUT_UNDEFINED;
     97 
     98     // Create Image
     99     VkSampleCountFlagBits vkSamples;
    100     if (!GrSampleCountToVkSampleCount(imageDesc.fSamples, &vkSamples)) {
    101         return false;
    102     }
    103 
    104     SkASSERT(VK_IMAGE_TILING_OPTIMAL == imageDesc.fImageTiling ||
    105              VK_SAMPLE_COUNT_1_BIT == vkSamples);
    106 
    107     // sRGB format images may need to be aliased to linear for various reasons (legacy mode):
    108     VkImageCreateFlags createFlags = GrVkFormatIsSRGB(imageDesc.fFormat, nullptr)
    109         ? VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT : 0;
    110 
    111     const VkImageCreateInfo imageCreateInfo = {
    112         VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,         // sType
    113         nullptr,                                     // pNext
    114         createFlags,                                 // VkImageCreateFlags
    115         imageDesc.fImageType,                        // VkImageType
    116         imageDesc.fFormat,                           // VkFormat
    117         { imageDesc.fWidth, imageDesc.fHeight, 1 },  // VkExtent3D
    118         imageDesc.fLevels,                           // mipLevels
    119         1,                                           // arrayLayers
    120         vkSamples,                                   // samples
    121         imageDesc.fImageTiling,                      // VkImageTiling
    122         imageDesc.fUsageFlags,                       // VkImageUsageFlags
    123         VK_SHARING_MODE_EXCLUSIVE,                   // VkSharingMode
    124         0,                                           // queueFamilyCount
    125         0,                                           // pQueueFamilyIndices
    126         initialLayout                                // initialLayout
    127     };
    128 
    129     GR_VK_CALL_ERRCHECK(gpu->vkInterface(), CreateImage(gpu->device(), &imageCreateInfo, nullptr,
    130                                                         &image));
    131 
    132     if (!GrVkMemory::AllocAndBindImageMemory(gpu, image, isLinear, &alloc)) {
    133         VK_CALL(gpu, DestroyImage(gpu->device(), image, nullptr));
    134         return false;
    135     }
    136 
    137     info->fImage = image;
    138     info->fAlloc = alloc;
    139     info->fImageTiling = imageDesc.fImageTiling;
    140     info->fImageLayout = initialLayout;
    141     info->fFormat = imageDesc.fFormat;
    142     info->fLevelCount = imageDesc.fLevels;
    143     return true;
    144 }
    145 
    146 void GrVkImage::DestroyImageInfo(const GrVkGpu* gpu, GrVkImageInfo* info) {
    147     VK_CALL(gpu, DestroyImage(gpu->device(), info->fImage, nullptr));
    148     bool isLinear = VK_IMAGE_TILING_LINEAR == info->fImageTiling;
    149     GrVkMemory::FreeImageMemory(gpu, isLinear, info->fAlloc);
    150 }
    151 
    152 void GrVkImage::setNewResource(VkImage image, const GrVkAlloc& alloc, VkImageTiling tiling) {
    153     fResource = new Resource(image, alloc, tiling);
    154 }
    155 
    156 GrVkImage::~GrVkImage() {
    157     // should have been released or abandoned first
    158     SkASSERT(!fResource);
    159 }
    160 
    161 void GrVkImage::releaseImage(const GrVkGpu* gpu) {
    162     if (VK_QUEUE_FAMILY_IGNORED != fInfo.fInitialQueueFamily) {
    163         this->setImageLayout(gpu, fInfo.fImageLayout, 0, 0, false, true);
    164     }
    165     if (fResource) {
    166         fResource->unref(gpu);
    167         fResource = nullptr;
    168     }
    169 }
    170 
    171 void GrVkImage::abandonImage() {
    172     if (fResource) {
    173         fResource->unrefAndAbandon();
    174         fResource = nullptr;
    175     }
    176 }
    177 
    178 void GrVkImage::setResourceRelease(sk_sp<GrReleaseProcHelper> releaseHelper) {
    179     // Forward the release proc on to GrVkImage::Resource
    180     fResource->setRelease(std::move(releaseHelper));
    181 }
    182 
    183 void GrVkImage::Resource::freeGPUData(const GrVkGpu* gpu) const {
    184     SkASSERT(!fReleaseHelper);
    185     VK_CALL(gpu, DestroyImage(gpu->device(), fImage, nullptr));
    186     bool isLinear = (VK_IMAGE_TILING_LINEAR == fImageTiling);
    187     GrVkMemory::FreeImageMemory(gpu, isLinear, fAlloc);
    188 }
    189 
    190 void GrVkImage::BorrowedResource::freeGPUData(const GrVkGpu* gpu) const {
    191     this->invokeReleaseProc();
    192 }
    193 
    194 void GrVkImage::BorrowedResource::abandonGPUData() const {
    195     this->invokeReleaseProc();
    196 }
    197 
    198