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 "GrVkMemory.h"
      9 
     10 #include "GrVkGpu.h"
     11 #include "GrVkUtil.h"
     12 
     13 #ifdef SK_DEBUG
     14 // for simple tracking of how much we're using in each heap
     15 // last counter is for non-subheap allocations
     16 VkDeviceSize gHeapUsage[VK_MAX_MEMORY_HEAPS+1] = { 0 };
     17 #endif
     18 
     19 static bool get_valid_memory_type_index(const VkPhysicalDeviceMemoryProperties& physDevMemProps,
     20                                         uint32_t typeBits,
     21                                         VkMemoryPropertyFlags requestedMemFlags,
     22                                         uint32_t* typeIndex,
     23                                         uint32_t* heapIndex) {
     24     for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) {
     25         if (typeBits & (1 << i)) {
     26             uint32_t supportedFlags = physDevMemProps.memoryTypes[i].propertyFlags &
     27                                       requestedMemFlags;
     28             if (supportedFlags == requestedMemFlags) {
     29                 *typeIndex = i;
     30                 *heapIndex = physDevMemProps.memoryTypes[i].heapIndex;
     31                 return true;
     32             }
     33         }
     34     }
     35     return false;
     36 }
     37 
     38 static GrVkGpu::Heap buffer_type_to_heap(GrVkBuffer::Type type) {
     39     const GrVkGpu::Heap kBufferToHeap[]{
     40         GrVkGpu::kVertexBuffer_Heap,
     41         GrVkGpu::kIndexBuffer_Heap,
     42         GrVkGpu::kUniformBuffer_Heap,
     43         GrVkGpu::kTexelBuffer_Heap,
     44         GrVkGpu::kCopyReadBuffer_Heap,
     45         GrVkGpu::kCopyWriteBuffer_Heap,
     46     };
     47     GR_STATIC_ASSERT(0 == GrVkBuffer::kVertex_Type);
     48     GR_STATIC_ASSERT(1 == GrVkBuffer::kIndex_Type);
     49     GR_STATIC_ASSERT(2 == GrVkBuffer::kUniform_Type);
     50     GR_STATIC_ASSERT(3 == GrVkBuffer::kTexel_Type);
     51     GR_STATIC_ASSERT(4 == GrVkBuffer::kCopyRead_Type);
     52     GR_STATIC_ASSERT(5 == GrVkBuffer::kCopyWrite_Type);
     53 
     54     return kBufferToHeap[type];
     55 }
     56 
     57 bool GrVkMemory::AllocAndBindBufferMemory(const GrVkGpu* gpu,
     58                                           VkBuffer buffer,
     59                                           GrVkBuffer::Type type,
     60                                           bool dynamic,
     61                                           GrVkAlloc* alloc) {
     62     const GrVkInterface* iface = gpu->vkInterface();
     63     VkDevice device = gpu->device();
     64 
     65     VkMemoryRequirements memReqs;
     66     GR_VK_CALL(iface, GetBufferMemoryRequirements(device, buffer, &memReqs));
     67 
     68     uint32_t typeIndex = 0;
     69     uint32_t heapIndex = 0;
     70     const VkPhysicalDeviceMemoryProperties& phDevMemProps = gpu->physicalDeviceMemoryProperties();
     71     if (dynamic) {
     72         // try to get cached and ideally non-coherent memory first
     73         if (!get_valid_memory_type_index(phDevMemProps,
     74                                          memReqs.memoryTypeBits,
     75                                          VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
     76                                          VK_MEMORY_PROPERTY_HOST_CACHED_BIT,
     77                                          &typeIndex,
     78                                          &heapIndex)) {
     79             // some sort of host-visible memory type should always be available for dynamic buffers
     80             SkASSERT_RELEASE(get_valid_memory_type_index(phDevMemProps,
     81                                                          memReqs.memoryTypeBits,
     82                                                          VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
     83                                                          &typeIndex,
     84                                                          &heapIndex));
     85         }
     86 
     87         VkMemoryPropertyFlags mpf = phDevMemProps.memoryTypes[typeIndex].propertyFlags;
     88         alloc->fFlags = mpf & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ? 0x0
     89                                                                    : GrVkAlloc::kNoncoherent_Flag;
     90     } else {
     91         // device-local memory should always be available for static buffers
     92         SkASSERT_RELEASE(get_valid_memory_type_index(phDevMemProps,
     93                                                      memReqs.memoryTypeBits,
     94                                                      VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
     95                                                      &typeIndex,
     96                                                      &heapIndex));
     97         alloc->fFlags = 0x0;
     98     }
     99 
    100     GrVkHeap* heap = gpu->getHeap(buffer_type_to_heap(type));
    101 
    102     if (!heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, alloc)) {
    103         // if static, try to allocate from non-host-visible non-device-local memory instead
    104         if (dynamic ||
    105             !get_valid_memory_type_index(phDevMemProps, memReqs.memoryTypeBits,
    106                                          0, &typeIndex, &heapIndex) ||
    107             !heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, alloc)) {
    108             SkDebugf("Failed to alloc buffer\n");
    109             return false;
    110         }
    111     }
    112 
    113     // Bind buffer
    114     VkResult err = GR_VK_CALL(iface, BindBufferMemory(device, buffer,
    115                                                       alloc->fMemory, alloc->fOffset));
    116     if (err) {
    117         SkASSERT_RELEASE(heap->free(*alloc));
    118         return false;
    119     }
    120 
    121     return true;
    122 }
    123 
    124 void GrVkMemory::FreeBufferMemory(const GrVkGpu* gpu, GrVkBuffer::Type type,
    125                                   const GrVkAlloc& alloc) {
    126 
    127     GrVkHeap* heap = gpu->getHeap(buffer_type_to_heap(type));
    128     SkASSERT_RELEASE(heap->free(alloc));
    129 }
    130 
    131 // for debugging
    132 static uint64_t gTotalImageMemory = 0;
    133 static uint64_t gTotalImageMemoryFullPage = 0;
    134 
    135 const VkDeviceSize kMaxSmallImageSize = 16 * 1024;
    136 const VkDeviceSize kMinVulkanPageSize = 16 * 1024;
    137 
    138 static VkDeviceSize align_size(VkDeviceSize size, VkDeviceSize alignment) {
    139     return (size + alignment - 1) & ~(alignment - 1);
    140 }
    141 
    142 bool GrVkMemory::AllocAndBindImageMemory(const GrVkGpu* gpu,
    143                                          VkImage image,
    144                                          bool linearTiling,
    145                                          GrVkAlloc* alloc) {
    146     const GrVkInterface* iface = gpu->vkInterface();
    147     VkDevice device = gpu->device();
    148 
    149     VkMemoryRequirements memReqs;
    150     GR_VK_CALL(iface, GetImageMemoryRequirements(device, image, &memReqs));
    151 
    152     uint32_t typeIndex = 0;
    153     uint32_t heapIndex = 0;
    154     GrVkHeap* heap;
    155     const VkPhysicalDeviceMemoryProperties& phDevMemProps = gpu->physicalDeviceMemoryProperties();
    156     if (linearTiling) {
    157         VkMemoryPropertyFlags desiredMemProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
    158                                                 VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
    159         if (!get_valid_memory_type_index(phDevMemProps,
    160                                          memReqs.memoryTypeBits,
    161                                          desiredMemProps,
    162                                          &typeIndex,
    163                                          &heapIndex)) {
    164             // some sort of host-visible memory type should always be available
    165             SkASSERT_RELEASE(get_valid_memory_type_index(phDevMemProps,
    166                                                          memReqs.memoryTypeBits,
    167                                                          VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT,
    168                                                          &typeIndex,
    169                                                          &heapIndex));
    170         }
    171         heap = gpu->getHeap(GrVkGpu::kLinearImage_Heap);
    172         VkMemoryPropertyFlags mpf = phDevMemProps.memoryTypes[typeIndex].propertyFlags;
    173         alloc->fFlags = mpf & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ? 0x0
    174                                                                    : GrVkAlloc::kNoncoherent_Flag;
    175     } else {
    176         // this memory type should always be available
    177         SkASSERT_RELEASE(get_valid_memory_type_index(phDevMemProps,
    178                                                      memReqs.memoryTypeBits,
    179                                                      VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
    180                                                      &typeIndex,
    181                                                      &heapIndex));
    182         if (memReqs.size <= kMaxSmallImageSize) {
    183             heap = gpu->getHeap(GrVkGpu::kSmallOptimalImage_Heap);
    184         } else {
    185             heap = gpu->getHeap(GrVkGpu::kOptimalImage_Heap);
    186         }
    187         alloc->fFlags = 0x0;
    188     }
    189 
    190     if (!heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, alloc)) {
    191         // if optimal, try to allocate from non-host-visible non-device-local memory instead
    192         if (linearTiling ||
    193             !get_valid_memory_type_index(phDevMemProps, memReqs.memoryTypeBits,
    194                                          0, &typeIndex, &heapIndex) ||
    195             !heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, alloc)) {
    196             SkDebugf("Failed to alloc image\n");
    197             return false;
    198         }
    199     }
    200 
    201     // Bind image
    202     VkResult err = GR_VK_CALL(iface, BindImageMemory(device, image,
    203                               alloc->fMemory, alloc->fOffset));
    204     if (err) {
    205         SkASSERT_RELEASE(heap->free(*alloc));
    206         return false;
    207     }
    208 
    209     gTotalImageMemory += alloc->fSize;
    210 
    211     VkDeviceSize pageAlignedSize = align_size(alloc->fSize, kMinVulkanPageSize);
    212     gTotalImageMemoryFullPage += pageAlignedSize;
    213 
    214     return true;
    215 }
    216 
    217 void GrVkMemory::FreeImageMemory(const GrVkGpu* gpu, bool linearTiling,
    218                                  const GrVkAlloc& alloc) {
    219     GrVkHeap* heap;
    220     if (linearTiling) {
    221         heap = gpu->getHeap(GrVkGpu::kLinearImage_Heap);
    222     } else if (alloc.fSize <= kMaxSmallImageSize) {
    223         heap = gpu->getHeap(GrVkGpu::kSmallOptimalImage_Heap);
    224     } else {
    225         heap = gpu->getHeap(GrVkGpu::kOptimalImage_Heap);
    226     }
    227     if (!heap->free(alloc)) {
    228         // must be an adopted allocation
    229         GR_VK_CALL(gpu->vkInterface(), FreeMemory(gpu->device(), alloc.fMemory, nullptr));
    230     } else {
    231         gTotalImageMemory -= alloc.fSize;
    232         VkDeviceSize pageAlignedSize = align_size(alloc.fSize, kMinVulkanPageSize);
    233         gTotalImageMemoryFullPage -= pageAlignedSize;
    234     }
    235 }
    236 
    237 VkPipelineStageFlags GrVkMemory::LayoutToPipelineStageFlags(const VkImageLayout layout) {
    238     if (VK_IMAGE_LAYOUT_GENERAL == layout) {
    239         return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
    240     } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout ||
    241                VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
    242         return VK_PIPELINE_STAGE_TRANSFER_BIT;
    243     } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout ||
    244                VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout ||
    245                VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL == layout ||
    246                VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
    247         return VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT;
    248     } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
    249         return VK_PIPELINE_STAGE_HOST_BIT;
    250     }
    251 
    252     SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout);
    253     return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
    254 }
    255 
    256 VkAccessFlags GrVkMemory::LayoutToSrcAccessMask(const VkImageLayout layout) {
    257     // Currently we assume we will never being doing any explict shader writes (this doesn't include
    258     // color attachment or depth/stencil writes). So we will ignore the
    259     // VK_MEMORY_OUTPUT_SHADER_WRITE_BIT.
    260 
    261     // We can only directly access the host memory if we are in preinitialized or general layout,
    262     // and the image is linear.
    263     // TODO: Add check for linear here so we are not always adding host to general, and we should
    264     //       only be in preinitialized if we are linear
    265     VkAccessFlags flags = 0;;
    266     if (VK_IMAGE_LAYOUT_GENERAL == layout) {
    267         flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
    268                 VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
    269                 VK_ACCESS_TRANSFER_WRITE_BIT |
    270                 VK_ACCESS_TRANSFER_READ_BIT |
    271                 VK_ACCESS_SHADER_READ_BIT |
    272                 VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT;
    273     } else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
    274         flags = VK_ACCESS_HOST_WRITE_BIT;
    275     } else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
    276         flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
    277     } else if (VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL == layout) {
    278         flags = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
    279     } else if (VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL == layout) {
    280         flags = VK_ACCESS_TRANSFER_WRITE_BIT;
    281     } else if (VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL == layout) {
    282         flags = VK_ACCESS_TRANSFER_READ_BIT;
    283     } else if (VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL == layout) {
    284         flags = VK_ACCESS_SHADER_READ_BIT;
    285     }
    286     return flags;
    287 }
    288 
    289 void GrVkMemory::FlushMappedAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc) {
    290     if (alloc.fFlags & GrVkAlloc::kNoncoherent_Flag) {
    291         VkMappedMemoryRange mappedMemoryRange;
    292         memset(&mappedMemoryRange, 0, sizeof(VkMappedMemoryRange));
    293         mappedMemoryRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
    294         mappedMemoryRange.memory = alloc.fMemory;
    295         mappedMemoryRange.offset = alloc.fOffset;
    296         mappedMemoryRange.size = alloc.fSize;
    297         GR_VK_CALL(gpu->vkInterface(), FlushMappedMemoryRanges(gpu->device(),
    298                                                                1, &mappedMemoryRange));
    299     }
    300 }
    301 
    302 void GrVkMemory::InvalidateMappedAlloc(const GrVkGpu* gpu, const GrVkAlloc& alloc) {
    303     if (alloc.fFlags & GrVkAlloc::kNoncoherent_Flag) {
    304         VkMappedMemoryRange mappedMemoryRange;
    305         memset(&mappedMemoryRange, 0, sizeof(VkMappedMemoryRange));
    306         mappedMemoryRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE;
    307         mappedMemoryRange.memory = alloc.fMemory;
    308         mappedMemoryRange.offset = alloc.fOffset;
    309         mappedMemoryRange.size = alloc.fSize;
    310         GR_VK_CALL(gpu->vkInterface(), InvalidateMappedMemoryRanges(gpu->device(),
    311                                                                1, &mappedMemoryRange));
    312     }
    313 }
    314 
    315 bool GrVkFreeListAlloc::alloc(VkDeviceSize requestedSize,
    316                               VkDeviceSize* allocOffset, VkDeviceSize* allocSize) {
    317     VkDeviceSize alignedSize = align_size(requestedSize, fAlignment);
    318 
    319     // find the smallest block big enough for our allocation
    320     FreeList::Iter iter = fFreeList.headIter();
    321     FreeList::Iter bestFitIter;
    322     VkDeviceSize   bestFitSize = fSize + 1;
    323     VkDeviceSize   secondLargestSize = 0;
    324     VkDeviceSize   secondLargestOffset = 0;
    325     while (iter.get()) {
    326         Block* block = iter.get();
    327         // need to adjust size to match desired alignment
    328         SkASSERT(align_size(block->fOffset, fAlignment) - block->fOffset == 0);
    329         if (block->fSize >= alignedSize && block->fSize < bestFitSize) {
    330             bestFitIter = iter;
    331             bestFitSize = block->fSize;
    332         }
    333         if (secondLargestSize < block->fSize && block->fOffset != fLargestBlockOffset) {
    334             secondLargestSize = block->fSize;
    335             secondLargestOffset = block->fOffset;
    336         }
    337         iter.next();
    338     }
    339     SkASSERT(secondLargestSize <= fLargestBlockSize);
    340 
    341     Block* bestFit = bestFitIter.get();
    342     if (bestFit) {
    343         SkASSERT(align_size(bestFit->fOffset, fAlignment) == bestFit->fOffset);
    344         *allocOffset = bestFit->fOffset;
    345         *allocSize = alignedSize;
    346         // adjust or remove current block
    347         VkDeviceSize originalBestFitOffset = bestFit->fOffset;
    348         if (bestFit->fSize > alignedSize) {
    349             bestFit->fOffset += alignedSize;
    350             bestFit->fSize -= alignedSize;
    351             if (fLargestBlockOffset == originalBestFitOffset) {
    352                 if (bestFit->fSize >= secondLargestSize) {
    353                     fLargestBlockSize = bestFit->fSize;
    354                     fLargestBlockOffset = bestFit->fOffset;
    355                 } else {
    356                     fLargestBlockSize = secondLargestSize;
    357                     fLargestBlockOffset = secondLargestOffset;
    358                 }
    359             }
    360 #ifdef SK_DEBUG
    361             VkDeviceSize largestSize = 0;
    362             iter = fFreeList.headIter();
    363             while (iter.get()) {
    364                 Block* block = iter.get();
    365                 if (largestSize < block->fSize) {
    366                     largestSize = block->fSize;
    367                 }
    368                 iter.next();
    369             }
    370             SkASSERT(largestSize == fLargestBlockSize);
    371 #endif
    372         } else {
    373             SkASSERT(bestFit->fSize == alignedSize);
    374             if (fLargestBlockOffset == originalBestFitOffset) {
    375                 fLargestBlockSize = secondLargestSize;
    376                 fLargestBlockOffset = secondLargestOffset;
    377             }
    378             fFreeList.remove(bestFit);
    379 #ifdef SK_DEBUG
    380             VkDeviceSize largestSize = 0;
    381             iter = fFreeList.headIter();
    382             while (iter.get()) {
    383                 Block* block = iter.get();
    384                 if (largestSize < block->fSize) {
    385                     largestSize = block->fSize;
    386                 }
    387                 iter.next();
    388             }
    389             SkASSERT(largestSize == fLargestBlockSize);
    390 #endif
    391         }
    392         fFreeSize -= alignedSize;
    393         SkASSERT(*allocSize > 0);
    394 
    395         return true;
    396     }
    397 
    398     SkDebugf("Can't allocate %d bytes, %d bytes available, largest free block %d\n", alignedSize, fFreeSize, fLargestBlockSize);
    399 
    400     return false;
    401 }
    402 
    403 void GrVkFreeListAlloc::free(VkDeviceSize allocOffset, VkDeviceSize allocSize) {
    404     // find the block right after this allocation
    405     FreeList::Iter iter = fFreeList.headIter();
    406     FreeList::Iter prev;
    407     while (iter.get() && iter.get()->fOffset < allocOffset) {
    408         prev = iter;
    409         iter.next();
    410     }
    411     // we have four cases:
    412     // we exactly follow the previous one
    413     Block* block;
    414     if (prev.get() && prev.get()->fOffset + prev.get()->fSize == allocOffset) {
    415         block = prev.get();
    416         block->fSize += allocSize;
    417         if (block->fOffset == fLargestBlockOffset) {
    418             fLargestBlockSize = block->fSize;
    419         }
    420         // and additionally we may exactly precede the next one
    421         if (iter.get() && iter.get()->fOffset == allocOffset + allocSize) {
    422             block->fSize += iter.get()->fSize;
    423             if (iter.get()->fOffset == fLargestBlockOffset) {
    424                 fLargestBlockOffset = block->fOffset;
    425                 fLargestBlockSize = block->fSize;
    426             }
    427             fFreeList.remove(iter.get());
    428         }
    429     // or we only exactly proceed the next one
    430     } else if (iter.get() && iter.get()->fOffset == allocOffset + allocSize) {
    431         block = iter.get();
    432         block->fSize += allocSize;
    433         if (block->fOffset == fLargestBlockOffset) {
    434             fLargestBlockOffset = allocOffset;
    435             fLargestBlockSize = block->fSize;
    436         }
    437         block->fOffset = allocOffset;
    438     // or we fall somewhere in between, with gaps
    439     } else {
    440         block = fFreeList.addBefore(iter);
    441         block->fOffset = allocOffset;
    442         block->fSize = allocSize;
    443     }
    444     fFreeSize += allocSize;
    445     if (block->fSize > fLargestBlockSize) {
    446         fLargestBlockSize = block->fSize;
    447         fLargestBlockOffset = block->fOffset;
    448     }
    449 
    450 #ifdef SK_DEBUG
    451     VkDeviceSize   largestSize = 0;
    452     iter = fFreeList.headIter();
    453     while (iter.get()) {
    454         Block* block = iter.get();
    455         if (largestSize < block->fSize) {
    456             largestSize = block->fSize;
    457         }
    458         iter.next();
    459     }
    460     SkASSERT(fLargestBlockSize == largestSize);
    461 #endif
    462 }
    463 
    464 GrVkSubHeap::GrVkSubHeap(const GrVkGpu* gpu, uint32_t memoryTypeIndex, uint32_t heapIndex,
    465                          VkDeviceSize size, VkDeviceSize alignment)
    466     : INHERITED(size, alignment)
    467     , fGpu(gpu)
    468 #ifdef SK_DEBUG
    469     , fHeapIndex(heapIndex)
    470 #endif
    471     , fMemoryTypeIndex(memoryTypeIndex) {
    472 
    473     VkMemoryAllocateInfo allocInfo = {
    474         VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,      // sType
    475         NULL,                                        // pNext
    476         size,                                        // allocationSize
    477         memoryTypeIndex,                             // memoryTypeIndex
    478     };
    479 
    480     VkResult err = GR_VK_CALL(gpu->vkInterface(), AllocateMemory(gpu->device(),
    481                                                                  &allocInfo,
    482                                                                  nullptr,
    483                                                                  &fAlloc));
    484     if (VK_SUCCESS != err) {
    485         this->reset();
    486     }
    487 #ifdef SK_DEBUG
    488     else {
    489         gHeapUsage[heapIndex] += size;
    490     }
    491 #endif
    492 }
    493 
    494 GrVkSubHeap::~GrVkSubHeap() {
    495     const GrVkInterface* iface = fGpu->vkInterface();
    496     GR_VK_CALL(iface, FreeMemory(fGpu->device(), fAlloc, nullptr));
    497 #ifdef SK_DEBUG
    498     gHeapUsage[fHeapIndex] -= fSize;
    499 #endif
    500 }
    501 
    502 bool GrVkSubHeap::alloc(VkDeviceSize size, GrVkAlloc* alloc) {
    503     alloc->fMemory = fAlloc;
    504     return INHERITED::alloc(size, &alloc->fOffset, &alloc->fSize);
    505 }
    506 
    507 void GrVkSubHeap::free(const GrVkAlloc& alloc) {
    508     SkASSERT(alloc.fMemory == fAlloc);
    509 
    510     INHERITED::free(alloc.fOffset, alloc.fSize);
    511 }
    512 
    513 bool GrVkHeap::subAlloc(VkDeviceSize size, VkDeviceSize alignment,
    514                         uint32_t memoryTypeIndex, uint32_t heapIndex, GrVkAlloc* alloc) {
    515     VkDeviceSize alignedSize = align_size(size, alignment);
    516 
    517     // if requested is larger than our subheap allocation, just alloc directly
    518     if (alignedSize > fSubHeapSize) {
    519         VkMemoryAllocateInfo allocInfo = {
    520             VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,      // sType
    521             NULL,                                        // pNext
    522             size,                                        // allocationSize
    523             memoryTypeIndex,                             // memoryTypeIndex
    524         };
    525 
    526         VkResult err = GR_VK_CALL(fGpu->vkInterface(), AllocateMemory(fGpu->device(),
    527                                                                       &allocInfo,
    528                                                                       nullptr,
    529                                                                       &alloc->fMemory));
    530         if (VK_SUCCESS != err) {
    531             return false;
    532         }
    533         alloc->fOffset = 0;
    534         alloc->fSize = 0;    // hint that this is not a subheap allocation
    535 #ifdef SK_DEBUG
    536         gHeapUsage[VK_MAX_MEMORY_HEAPS] += alignedSize;
    537 #endif
    538 
    539         return true;
    540     }
    541 
    542     // first try to find a subheap that fits our allocation request
    543     int bestFitIndex = -1;
    544     VkDeviceSize bestFitSize = 0x7FFFFFFF;
    545     for (auto i = 0; i < fSubHeaps.count(); ++i) {
    546         if (fSubHeaps[i]->memoryTypeIndex() == memoryTypeIndex &&
    547             fSubHeaps[i]->alignment() == alignment) {
    548             VkDeviceSize heapSize = fSubHeaps[i]->largestBlockSize();
    549             if (heapSize >= alignedSize && heapSize < bestFitSize) {
    550                 bestFitIndex = i;
    551                 bestFitSize = heapSize;
    552             }
    553         }
    554     }
    555 
    556     if (bestFitIndex >= 0) {
    557         SkASSERT(fSubHeaps[bestFitIndex]->alignment() == alignment);
    558         if (fSubHeaps[bestFitIndex]->alloc(size, alloc)) {
    559             fUsedSize += alloc->fSize;
    560             return true;
    561         }
    562         return false;
    563     }
    564 
    565     // need to allocate a new subheap
    566     std::unique_ptr<GrVkSubHeap>& subHeap = fSubHeaps.push_back();
    567     subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, fSubHeapSize, alignment));
    568     // try to recover from failed allocation by only allocating what we need
    569     if (subHeap->size() == 0) {
    570         VkDeviceSize alignedSize = align_size(size, alignment);
    571         subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, alignedSize, alignment));
    572         if (subHeap->size() == 0) {
    573             return false;
    574         }
    575     }
    576     fAllocSize += fSubHeapSize;
    577     if (subHeap->alloc(size, alloc)) {
    578         fUsedSize += alloc->fSize;
    579         return true;
    580     }
    581 
    582     return false;
    583 }
    584 
    585 bool GrVkHeap::singleAlloc(VkDeviceSize size, VkDeviceSize alignment,
    586                            uint32_t memoryTypeIndex, uint32_t heapIndex, GrVkAlloc* alloc) {
    587     VkDeviceSize alignedSize = align_size(size, alignment);
    588 
    589     // first try to find an unallocated subheap that fits our allocation request
    590     int bestFitIndex = -1;
    591     VkDeviceSize bestFitSize = 0x7FFFFFFF;
    592     for (auto i = 0; i < fSubHeaps.count(); ++i) {
    593         if (fSubHeaps[i]->memoryTypeIndex() == memoryTypeIndex &&
    594             fSubHeaps[i]->alignment() == alignment &&
    595             fSubHeaps[i]->unallocated()) {
    596             VkDeviceSize heapSize = fSubHeaps[i]->size();
    597             if (heapSize >= alignedSize && heapSize < bestFitSize) {
    598                 bestFitIndex = i;
    599                 bestFitSize = heapSize;
    600             }
    601         }
    602     }
    603 
    604     if (bestFitIndex >= 0) {
    605         SkASSERT(fSubHeaps[bestFitIndex]->alignment() == alignment);
    606         if (fSubHeaps[bestFitIndex]->alloc(size, alloc)) {
    607             fUsedSize += alloc->fSize;
    608             return true;
    609         }
    610         return false;
    611     }
    612 
    613     // need to allocate a new subheap
    614     std::unique_ptr<GrVkSubHeap>& subHeap = fSubHeaps.push_back();
    615     subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, alignedSize, alignment));
    616     fAllocSize += alignedSize;
    617     if (subHeap->alloc(size, alloc)) {
    618         fUsedSize += alloc->fSize;
    619         return true;
    620     }
    621 
    622     return false;
    623 }
    624 
    625 bool GrVkHeap::free(const GrVkAlloc& alloc) {
    626     // a size of 0 means we're using the system heap
    627     if (0 == alloc.fSize) {
    628         const GrVkInterface* iface = fGpu->vkInterface();
    629         GR_VK_CALL(iface, FreeMemory(fGpu->device(), alloc.fMemory, nullptr));
    630         return true;
    631     }
    632 
    633     for (auto i = 0; i < fSubHeaps.count(); ++i) {
    634         if (fSubHeaps[i]->memory() == alloc.fMemory) {
    635             fSubHeaps[i]->free(alloc);
    636             fUsedSize -= alloc.fSize;
    637             return true;
    638         }
    639     }
    640 
    641     return false;
    642 }
    643 
    644 
    645