OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrVkMemory.h" | 8 #include "GrVkMemory.h" |
9 | 9 |
10 #include "GrVkGpu.h" | 10 #include "GrVkGpu.h" |
11 #include "GrVkUtil.h" | 11 #include "GrVkUtil.h" |
12 | 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 | |
13 static bool get_valid_memory_type_index(const VkPhysicalDeviceMemoryProperties& physDevMemProps, | 19 static bool get_valid_memory_type_index(const VkPhysicalDeviceMemoryProperties& physDevMemProps, |
14 uint32_t typeBits, | 20 uint32_t typeBits, |
15 VkMemoryPropertyFlags requestedMemFlags, | 21 VkMemoryPropertyFlags requestedMemFlags, |
16 uint32_t* typeIndex) { | 22 uint32_t* typeIndex) { |
17 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) { | 23 for (uint32_t i = 0; i < physDevMemProps.memoryTypeCount; ++i) { |
18 if (typeBits & (1 << i)) { | 24 if (typeBits & (1 << i)) { |
19 uint32_t supportedFlags = physDevMemProps.memoryTypes[i].propertyFla gs & | 25 uint32_t supportedFlags = physDevMemProps.memoryTypes[i].propertyFla gs & |
20 requestedMemFlags; | 26 requestedMemFlags; |
21 if (supportedFlags == requestedMemFlags) { | 27 if (supportedFlags == requestedMemFlags) { |
22 *typeIndex = i; | 28 *typeIndex = i; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 alloc->fFlags = mpf & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ? 0x0 | 81 alloc->fFlags = mpf & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ? 0x0 |
76 : GrVkAlloc:: kNoncoherent_Flag; | 82 : GrVkAlloc:: kNoncoherent_Flag; |
77 } else { | 83 } else { |
78 // device-local memory should always be available for static buffers | 84 // device-local memory should always be available for static buffers |
79 SkASSERT_RELEASE(get_valid_memory_type_index(phDevMemProps, | 85 SkASSERT_RELEASE(get_valid_memory_type_index(phDevMemProps, |
80 memReqs.memoryTypeBits, | 86 memReqs.memoryTypeBits, |
81 VK_MEMORY_PROPERTY_DEVICE_L OCAL_BIT, | 87 VK_MEMORY_PROPERTY_DEVICE_L OCAL_BIT, |
82 &typeIndex)); | 88 &typeIndex)); |
83 alloc->fFlags = 0x0; | 89 alloc->fFlags = 0x0; |
84 } | 90 } |
91 uint32_t heapIndex = phDevMemProps.memoryTypes[typeIndex].heapIndex; | |
85 | 92 |
86 GrVkHeap* heap = gpu->getHeap(buffer_type_to_heap(type)); | 93 GrVkHeap* heap = gpu->getHeap(buffer_type_to_heap(type)); |
87 | 94 |
88 if (!heap->alloc(memReqs.size, memReqs.alignment, typeIndex, alloc)) { | 95 if (!heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, allo c)) { |
89 SkDebugf("Failed to alloc buffer\n"); | 96 // if static, try to allocate from non-host-visible non-device-local mem ory instead |
90 return false; | 97 if (dynamic || |
98 !get_valid_memory_type_index(phDevMemProps, memReqs.memoryTypeBits, 0, &typeIndex) || | |
99 !heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, alloc)) { | |
egdaniel
2016/09/22 13:25:46
do we need to update heap index between these?
jvanverth1
2016/09/22 14:14:51
Done.
| |
100 SkDebugf("Failed to alloc buffer\n"); | |
101 return false; | |
102 } | |
91 } | 103 } |
92 | 104 |
93 // Bind buffer | 105 // Bind buffer |
94 VkResult err = GR_VK_CALL(iface, BindBufferMemory(device, buffer, | 106 VkResult err = GR_VK_CALL(iface, BindBufferMemory(device, buffer, |
95 alloc->fMemory, alloc->fOf fset)); | 107 alloc->fMemory, alloc->fOf fset)); |
96 if (err) { | 108 if (err) { |
97 SkASSERT_RELEASE(heap->free(*alloc)); | 109 SkASSERT_RELEASE(heap->free(*alloc)); |
98 return false; | 110 return false; |
99 } | 111 } |
100 | 112 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
156 VK_MEMORY_PROPERTY_DEVICE_L OCAL_BIT, | 168 VK_MEMORY_PROPERTY_DEVICE_L OCAL_BIT, |
157 &typeIndex)); | 169 &typeIndex)); |
158 if (memReqs.size <= kMaxSmallImageSize) { | 170 if (memReqs.size <= kMaxSmallImageSize) { |
159 heap = gpu->getHeap(GrVkGpu::kSmallOptimalImage_Heap); | 171 heap = gpu->getHeap(GrVkGpu::kSmallOptimalImage_Heap); |
160 } else { | 172 } else { |
161 heap = gpu->getHeap(GrVkGpu::kOptimalImage_Heap); | 173 heap = gpu->getHeap(GrVkGpu::kOptimalImage_Heap); |
162 } | 174 } |
163 alloc->fFlags = 0x0; | 175 alloc->fFlags = 0x0; |
164 } | 176 } |
165 | 177 |
166 if (!heap->alloc(memReqs.size, memReqs.alignment, typeIndex, alloc)) { | 178 uint32_t heapIndex = phDevMemProps.memoryTypes[typeIndex].heapIndex; |
167 SkDebugf("Failed to alloc image\n"); | 179 if (!heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, allo c)) { |
168 return false; | 180 // if optimal, try to allocate from non-host-visible non-device-local me mory instead |
181 if (linearTiling || | |
182 !get_valid_memory_type_index(phDevMemProps, memReqs.memoryTypeBits, 0, &typeIndex) || | |
183 !heap->alloc(memReqs.size, memReqs.alignment, typeIndex, heapIndex, alloc)) { | |
184 SkDebugf("Failed to alloc image\n"); | |
185 return false; | |
186 } | |
169 } | 187 } |
170 | 188 |
171 // Bind image | 189 // Bind image |
172 VkResult err = GR_VK_CALL(iface, BindImageMemory(device, image, | 190 VkResult err = GR_VK_CALL(iface, BindImageMemory(device, image, |
173 alloc->fMemory, alloc->fOffset)); | 191 alloc->fMemory, alloc->fOffset)); |
174 if (err) { | 192 if (err) { |
175 SkASSERT_RELEASE(heap->free(*alloc)); | 193 SkASSERT_RELEASE(heap->free(*alloc)); |
176 return false; | 194 return false; |
177 } | 195 } |
178 | 196 |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
424 Block* block = iter.get(); | 442 Block* block = iter.get(); |
425 if (largestSize < block->fSize) { | 443 if (largestSize < block->fSize) { |
426 largestSize = block->fSize; | 444 largestSize = block->fSize; |
427 } | 445 } |
428 iter.next(); | 446 iter.next(); |
429 } | 447 } |
430 SkASSERT(fLargestBlockSize == largestSize); | 448 SkASSERT(fLargestBlockSize == largestSize); |
431 #endif | 449 #endif |
432 } | 450 } |
433 | 451 |
434 GrVkSubHeap::GrVkSubHeap(const GrVkGpu* gpu, uint32_t memoryTypeIndex, | 452 GrVkSubHeap::GrVkSubHeap(const GrVkGpu* gpu, uint32_t memoryTypeIndex, uint32_t heapIndex, |
435 VkDeviceSize size, VkDeviceSize alignment) | 453 VkDeviceSize size, VkDeviceSize alignment) |
436 : INHERITED(size, alignment) | 454 : INHERITED(size, alignment) |
437 , fGpu(gpu) | 455 , fGpu(gpu) |
438 , fMemoryTypeIndex(memoryTypeIndex) { | 456 , fMemoryTypeIndex(memoryTypeIndex) |
457 , fHeapIndex(heapIndex) { | |
439 | 458 |
440 VkMemoryAllocateInfo allocInfo = { | 459 VkMemoryAllocateInfo allocInfo = { |
441 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType | 460 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType |
442 NULL, // pNext | 461 NULL, // pNext |
443 size, // allocationSize | 462 size, // allocationSize |
444 memoryTypeIndex, // memoryTypeIndex | 463 memoryTypeIndex, // memoryTypeIndex |
445 }; | 464 }; |
446 | 465 |
447 VkResult err = GR_VK_CALL(gpu->vkInterface(), AllocateMemory(gpu->device(), | 466 VkResult err = GR_VK_CALL(gpu->vkInterface(), AllocateMemory(gpu->device(), |
448 &allocInfo, | 467 &allocInfo, |
449 nullptr, | 468 nullptr, |
450 &fAlloc)); | 469 &fAlloc)); |
451 if (VK_SUCCESS != err) { | 470 if (VK_SUCCESS != err) { |
452 this->reset(); | 471 this->reset(); |
472 } | |
473 #ifdef SK_DEBUG | |
474 else { | |
475 gHeapUsage[heapIndex] += size; | |
453 } | 476 } |
477 #endif | |
454 } | 478 } |
455 | 479 |
456 GrVkSubHeap::~GrVkSubHeap() { | 480 GrVkSubHeap::~GrVkSubHeap() { |
457 const GrVkInterface* iface = fGpu->vkInterface(); | 481 const GrVkInterface* iface = fGpu->vkInterface(); |
458 GR_VK_CALL(iface, FreeMemory(fGpu->device(), fAlloc, nullptr)); | 482 GR_VK_CALL(iface, FreeMemory(fGpu->device(), fAlloc, nullptr)); |
483 #ifdef SK_DEBUG | |
484 gHeapUsage[fHeapIndex] -= fSize; | |
485 #endif | |
459 } | 486 } |
460 | 487 |
461 bool GrVkSubHeap::alloc(VkDeviceSize size, GrVkAlloc* alloc) { | 488 bool GrVkSubHeap::alloc(VkDeviceSize size, GrVkAlloc* alloc) { |
462 alloc->fMemory = fAlloc; | 489 alloc->fMemory = fAlloc; |
463 return INHERITED::alloc(size, &alloc->fOffset, &alloc->fSize); | 490 return INHERITED::alloc(size, &alloc->fOffset, &alloc->fSize); |
464 } | 491 } |
465 | 492 |
466 void GrVkSubHeap::free(const GrVkAlloc& alloc) { | 493 void GrVkSubHeap::free(const GrVkAlloc& alloc) { |
467 SkASSERT(alloc.fMemory == fAlloc); | 494 SkASSERT(alloc.fMemory == fAlloc); |
468 | 495 |
469 INHERITED::free(alloc.fOffset, alloc.fSize); | 496 INHERITED::free(alloc.fOffset, alloc.fSize); |
470 } | 497 } |
471 | 498 |
472 bool GrVkHeap::subAlloc(VkDeviceSize size, VkDeviceSize alignment, | 499 bool GrVkHeap::subAlloc(VkDeviceSize size, VkDeviceSize alignment, |
473 uint32_t memoryTypeIndex, GrVkAlloc* alloc) { | 500 uint32_t memoryTypeIndex, uint32_t heapIndex, GrVkAlloc* alloc) { |
474 VkDeviceSize alignedSize = align_size(size, alignment); | 501 VkDeviceSize alignedSize = align_size(size, alignment); |
475 | 502 |
476 // if requested is larger than our subheap allocation, just alloc directly | 503 // if requested is larger than our subheap allocation, just alloc directly |
477 if (alignedSize > fSubHeapSize) { | 504 if (alignedSize > fSubHeapSize) { |
478 VkMemoryAllocateInfo allocInfo = { | 505 VkMemoryAllocateInfo allocInfo = { |
479 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType | 506 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, // sType |
480 NULL, // pNext | 507 NULL, // pNext |
481 size, // allocationSize | 508 size, // allocationSize |
482 memoryTypeIndex, // memoryTypeIndex | 509 memoryTypeIndex, // memoryTypeIndex |
483 }; | 510 }; |
484 | 511 |
485 VkResult err = GR_VK_CALL(fGpu->vkInterface(), AllocateMemory(fGpu->devi ce(), | 512 VkResult err = GR_VK_CALL(fGpu->vkInterface(), AllocateMemory(fGpu->devi ce(), |
486 &allocInfo , | 513 &allocInfo , |
487 nullptr, | 514 nullptr, |
488 &alloc->fM emory)); | 515 &alloc->fM emory)); |
489 if (VK_SUCCESS != err) { | 516 if (VK_SUCCESS != err) { |
490 return false; | 517 return false; |
491 } | 518 } |
492 alloc->fOffset = 0; | 519 alloc->fOffset = 0; |
493 alloc->fSize = 0; // hint that this is not a subheap allocation | 520 alloc->fSize = 0; // hint that this is not a subheap allocation |
521 #ifdef SK_DEBUG | |
522 gHeapUsage[VK_MAX_MEMORY_HEAPS] += alignedSize; | |
523 #endif | |
494 | 524 |
495 return true; | 525 return true; |
496 } | 526 } |
497 | 527 |
498 // first try to find a subheap that fits our allocation request | 528 // first try to find a subheap that fits our allocation request |
499 int bestFitIndex = -1; | 529 int bestFitIndex = -1; |
500 VkDeviceSize bestFitSize = 0x7FFFFFFF; | 530 VkDeviceSize bestFitSize = 0x7FFFFFFF; |
501 for (auto i = 0; i < fSubHeaps.count(); ++i) { | 531 for (auto i = 0; i < fSubHeaps.count(); ++i) { |
502 if (fSubHeaps[i]->memoryTypeIndex() == memoryTypeIndex && | 532 if (fSubHeaps[i]->memoryTypeIndex() == memoryTypeIndex && |
503 fSubHeaps[i]->alignment() == alignment) { | 533 fSubHeaps[i]->alignment() == alignment) { |
504 VkDeviceSize heapSize = fSubHeaps[i]->largestBlockSize(); | 534 VkDeviceSize heapSize = fSubHeaps[i]->largestBlockSize(); |
505 if (heapSize >= alignedSize && heapSize < bestFitSize) { | 535 if (heapSize >= alignedSize && heapSize < bestFitSize) { |
506 bestFitIndex = i; | 536 bestFitIndex = i; |
507 bestFitSize = heapSize; | 537 bestFitSize = heapSize; |
508 } | 538 } |
509 } | 539 } |
510 } | 540 } |
511 | 541 |
512 if (bestFitIndex >= 0) { | 542 if (bestFitIndex >= 0) { |
513 SkASSERT(fSubHeaps[bestFitIndex]->alignment() == alignment); | 543 SkASSERT(fSubHeaps[bestFitIndex]->alignment() == alignment); |
514 if (fSubHeaps[bestFitIndex]->alloc(size, alloc)) { | 544 if (fSubHeaps[bestFitIndex]->alloc(size, alloc)) { |
515 fUsedSize += alloc->fSize; | 545 fUsedSize += alloc->fSize; |
516 return true; | 546 return true; |
517 } | 547 } |
518 return false; | 548 return false; |
519 } | 549 } |
520 | 550 |
521 // need to allocate a new subheap | 551 // need to allocate a new subheap |
522 SkAutoTDelete<GrVkSubHeap>& subHeap = fSubHeaps.push_back(); | 552 SkAutoTDelete<GrVkSubHeap>& subHeap = fSubHeaps.push_back(); |
523 subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, fSubHeapSize, alignment )); | 553 subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, fSubHeapSize , alignment)); |
524 // try to recover from failed allocation by only allocating what we need | 554 // try to recover from failed allocation by only allocating what we need |
525 if (subHeap->size() == 0) { | 555 if (subHeap->size() == 0) { |
526 VkDeviceSize alignedSize = align_size(size, alignment); | 556 VkDeviceSize alignedSize = align_size(size, alignment); |
527 subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, alignedSize, alignm ent)); | 557 subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, alignedS ize, alignment)); |
528 if (subHeap->size() == 0) { | 558 if (subHeap->size() == 0) { |
529 return false; | 559 return false; |
530 } | 560 } |
531 } | 561 } |
532 fAllocSize += fSubHeapSize; | 562 fAllocSize += fSubHeapSize; |
533 if (subHeap->alloc(size, alloc)) { | 563 if (subHeap->alloc(size, alloc)) { |
534 fUsedSize += alloc->fSize; | 564 fUsedSize += alloc->fSize; |
535 return true; | 565 return true; |
536 } | 566 } |
537 | 567 |
538 return false; | 568 return false; |
539 } | 569 } |
540 | 570 |
541 bool GrVkHeap::singleAlloc(VkDeviceSize size, VkDeviceSize alignment, | 571 bool GrVkHeap::singleAlloc(VkDeviceSize size, VkDeviceSize alignment, |
542 uint32_t memoryTypeIndex, GrVkAlloc* alloc) { | 572 uint32_t memoryTypeIndex, uint32_t heapIndex, GrVkAll oc* alloc) { |
543 VkDeviceSize alignedSize = align_size(size, alignment); | 573 VkDeviceSize alignedSize = align_size(size, alignment); |
544 | 574 |
545 // first try to find an unallocated subheap that fits our allocation request | 575 // first try to find an unallocated subheap that fits our allocation request |
546 int bestFitIndex = -1; | 576 int bestFitIndex = -1; |
547 VkDeviceSize bestFitSize = 0x7FFFFFFF; | 577 VkDeviceSize bestFitSize = 0x7FFFFFFF; |
548 for (auto i = 0; i < fSubHeaps.count(); ++i) { | 578 for (auto i = 0; i < fSubHeaps.count(); ++i) { |
549 if (fSubHeaps[i]->memoryTypeIndex() == memoryTypeIndex && | 579 if (fSubHeaps[i]->memoryTypeIndex() == memoryTypeIndex && |
550 fSubHeaps[i]->alignment() == alignment && | 580 fSubHeaps[i]->alignment() == alignment && |
551 fSubHeaps[i]->unallocated()) { | 581 fSubHeaps[i]->unallocated()) { |
552 VkDeviceSize heapSize = fSubHeaps[i]->size(); | 582 VkDeviceSize heapSize = fSubHeaps[i]->size(); |
553 if (heapSize >= alignedSize && heapSize < bestFitSize) { | 583 if (heapSize >= alignedSize && heapSize < bestFitSize) { |
554 bestFitIndex = i; | 584 bestFitIndex = i; |
555 bestFitSize = heapSize; | 585 bestFitSize = heapSize; |
556 } | 586 } |
557 } | 587 } |
558 } | 588 } |
559 | 589 |
560 if (bestFitIndex >= 0) { | 590 if (bestFitIndex >= 0) { |
561 SkASSERT(fSubHeaps[bestFitIndex]->alignment() == alignment); | 591 SkASSERT(fSubHeaps[bestFitIndex]->alignment() == alignment); |
562 if (fSubHeaps[bestFitIndex]->alloc(size, alloc)) { | 592 if (fSubHeaps[bestFitIndex]->alloc(size, alloc)) { |
563 fUsedSize += alloc->fSize; | 593 fUsedSize += alloc->fSize; |
564 return true; | 594 return true; |
565 } | 595 } |
566 return false; | 596 return false; |
567 } | 597 } |
568 | 598 |
569 // need to allocate a new subheap | 599 // need to allocate a new subheap |
570 SkAutoTDelete<GrVkSubHeap>& subHeap = fSubHeaps.push_back(); | 600 SkAutoTDelete<GrVkSubHeap>& subHeap = fSubHeaps.push_back(); |
571 subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, alignedSize, alignment) ); | 601 subHeap.reset(new GrVkSubHeap(fGpu, memoryTypeIndex, heapIndex, alignedSize, alignment)); |
572 fAllocSize += alignedSize; | 602 fAllocSize += alignedSize; |
573 if (subHeap->alloc(size, alloc)) { | 603 if (subHeap->alloc(size, alloc)) { |
574 fUsedSize += alloc->fSize; | 604 fUsedSize += alloc->fSize; |
575 return true; | 605 return true; |
576 } | 606 } |
577 | 607 |
578 return false; | 608 return false; |
579 } | 609 } |
580 | 610 |
581 bool GrVkHeap::free(const GrVkAlloc& alloc) { | 611 bool GrVkHeap::free(const GrVkAlloc& alloc) { |
582 // a size of 0 means we're using the system heap | 612 // a size of 0 means we're using the system heap |
583 if (0 == alloc.fSize) { | 613 if (0 == alloc.fSize) { |
584 const GrVkInterface* iface = fGpu->vkInterface(); | 614 const GrVkInterface* iface = fGpu->vkInterface(); |
585 GR_VK_CALL(iface, FreeMemory(fGpu->device(), alloc.fMemory, nullptr)); | 615 GR_VK_CALL(iface, FreeMemory(fGpu->device(), alloc.fMemory, nullptr)); |
586 return true; | 616 return true; |
587 } | 617 } |
588 | 618 |
589 for (auto i = 0; i < fSubHeaps.count(); ++i) { | 619 for (auto i = 0; i < fSubHeaps.count(); ++i) { |
590 if (fSubHeaps[i]->memory() == alloc.fMemory) { | 620 if (fSubHeaps[i]->memory() == alloc.fMemory) { |
591 fSubHeaps[i]->free(alloc); | 621 fSubHeaps[i]->free(alloc); |
592 fUsedSize -= alloc.fSize; | 622 fUsedSize -= alloc.fSize; |
593 return true; | 623 return true; |
594 } | 624 } |
595 } | 625 } |
596 | 626 |
597 return false; | 627 return false; |
598 } | 628 } |
599 | 629 |
600 | 630 |
OLD | NEW |