1 // Copyright 2017 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_native/vulkan/MemoryAllocator.h" 16 17 #include "dawn_native/vulkan/DeviceVk.h" 18 #include "dawn_native/vulkan/FencedDeleter.h" 19 20 namespace dawn_native { namespace vulkan { 21 ~DeviceMemoryAllocation()22 DeviceMemoryAllocation::~DeviceMemoryAllocation() { 23 ASSERT(mMemory == VK_NULL_HANDLE); 24 } 25 GetMemory() const26 VkDeviceMemory DeviceMemoryAllocation::GetMemory() const { 27 return mMemory; 28 } 29 GetMemoryOffset() const30 size_t DeviceMemoryAllocation::GetMemoryOffset() const { 31 return mOffset; 32 } 33 GetMappedPointer() const34 uint8_t* DeviceMemoryAllocation::GetMappedPointer() const { 35 return mMappedPointer; 36 } 37 MemoryAllocator(Device * device)38 MemoryAllocator::MemoryAllocator(Device* device) : mDevice(device) { 39 } 40 ~MemoryAllocator()41 MemoryAllocator::~MemoryAllocator() { 42 } 43 Allocate(VkMemoryRequirements requirements,bool mappable,DeviceMemoryAllocation * allocation)44 bool MemoryAllocator::Allocate(VkMemoryRequirements requirements, 45 bool mappable, 46 DeviceMemoryAllocation* allocation) { 47 const VulkanDeviceInfo& info = mDevice->GetDeviceInfo(); 48 49 // Find a suitable memory type for this allocation 50 int bestType = -1; 51 for (size_t i = 0; i < info.memoryTypes.size(); ++i) { 52 // Resource must support this memory type 53 if ((requirements.memoryTypeBits & (1 << i)) == 0) { 54 continue; 55 } 56 57 // Mappable resource must be host visible 58 if (mappable && 59 (info.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) == 0) { 60 continue; 61 } 62 63 // Mappable must also be host coherent. 64 if (mappable && 65 (info.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_COHERENT_BIT) == 0) { 66 continue; 67 } 68 69 // Found the first candidate memory type 70 if (bestType == -1) { 71 bestType = static_cast<int>(i); 72 continue; 73 } 74 75 // For non-mappable resources, favor device local memory. 76 if (!mappable) { 77 if ((info.memoryTypes[bestType].propertyFlags & 78 VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) == 0 && 79 (info.memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) != 80 0) { 81 bestType = static_cast<int>(i); 82 continue; 83 } 84 } 85 86 // All things equal favor the memory in the biggest heap 87 VkDeviceSize bestTypeHeapSize = 88 info.memoryHeaps[info.memoryTypes[bestType].heapIndex].size; 89 VkDeviceSize candidateHeapSize = info.memoryHeaps[info.memoryTypes[i].heapIndex].size; 90 if (candidateHeapSize > bestTypeHeapSize) { 91 bestType = static_cast<int>(i); 92 continue; 93 } 94 } 95 96 // TODO(cwallez@chromium.org): I think the Vulkan spec guarantees this should never happen 97 if (bestType == -1) { 98 ASSERT(false); 99 return false; 100 } 101 102 VkMemoryAllocateInfo allocateInfo; 103 allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; 104 allocateInfo.pNext = nullptr; 105 allocateInfo.allocationSize = requirements.size; 106 allocateInfo.memoryTypeIndex = static_cast<uint32_t>(bestType); 107 108 VkDeviceMemory allocatedMemory = VK_NULL_HANDLE; 109 if (mDevice->fn.AllocateMemory(mDevice->GetVkDevice(), &allocateInfo, nullptr, 110 &allocatedMemory) != VK_SUCCESS) { 111 return false; 112 } 113 114 void* mappedPointer = nullptr; 115 if (mappable) { 116 if (mDevice->fn.MapMemory(mDevice->GetVkDevice(), allocatedMemory, 0, requirements.size, 117 0, &mappedPointer) != VK_SUCCESS) { 118 return false; 119 } 120 } 121 122 allocation->mMemory = allocatedMemory; 123 allocation->mOffset = 0; 124 allocation->mMappedPointer = static_cast<uint8_t*>(mappedPointer); 125 126 return true; 127 } 128 Free(DeviceMemoryAllocation * allocation)129 void MemoryAllocator::Free(DeviceMemoryAllocation* allocation) { 130 mDevice->GetFencedDeleter()->DeleteWhenUnused(allocation->mMemory); 131 allocation->mMemory = VK_NULL_HANDLE; 132 allocation->mOffset = 0; 133 allocation->mMappedPointer = nullptr; 134 } 135 Tick(Serial)136 void MemoryAllocator::Tick(Serial) { 137 } 138 }} // namespace dawn_native::vulkan 139