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