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