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