Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 1 | // Copyright (C) 2018 The Android Open Source Project |
| 2 | // Copyright (C) 2018 Google Inc. |
| 3 | // |
| 4 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | // you may not use this file except in compliance with the License. |
| 6 | // You may obtain a copy of the License at |
| 7 | // |
| 8 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | // |
| 10 | // Unless required by applicable law or agreed to in writing, software |
| 11 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | // See the License for the specific language governing permissions and |
| 14 | // limitations under the License. |
| 15 | #include "HostVisibleMemoryVirtualization.h" |
| 16 | |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 17 | #include "android/base/SubAllocator.h" |
| 18 | |
| 19 | #include "Resources.h" |
| 20 | #include "VkEncoder.h" |
| 21 | |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 22 | #include <log/log.h> |
| 23 | |
| 24 | #include <set> |
| 25 | |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 26 | using android::base::SubAllocator; |
| 27 | |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 28 | namespace goldfish_vk { |
| 29 | |
| 30 | bool canFitVirtualHostVisibleMemoryInfo( |
| 31 | const VkPhysicalDeviceMemoryProperties* memoryProperties) { |
| 32 | uint32_t typeCount = |
| 33 | memoryProperties->memoryTypeCount; |
| 34 | uint32_t heapCount = |
| 35 | memoryProperties->memoryHeapCount; |
| 36 | |
| 37 | bool canFit = true; |
| 38 | |
| 39 | if (typeCount == VK_MAX_MEMORY_TYPES) { |
| 40 | canFit = false; |
| 41 | ALOGE("Underlying device has no free memory types"); |
| 42 | } |
| 43 | |
| 44 | if (heapCount == VK_MAX_MEMORY_HEAPS) { |
| 45 | canFit = false; |
| 46 | ALOGE("Underlying device has no free memory heaps"); |
| 47 | } |
| 48 | |
| 49 | uint32_t numFreeMemoryTypes = VK_MAX_MEMORY_TYPES - typeCount; |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 50 | uint32_t hostVisibleMemoryTypeCount = 0; |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 51 | |
| 52 | if (hostVisibleMemoryTypeCount > numFreeMemoryTypes) { |
| 53 | ALOGE("Underlying device has too many host visible memory types (%u)" |
| 54 | "and not enough free types (%u)", |
| 55 | hostVisibleMemoryTypeCount, numFreeMemoryTypes); |
| 56 | canFit = false; |
| 57 | } |
| 58 | |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 59 | return canFit; |
| 60 | } |
| 61 | |
| 62 | void initHostVisibleMemoryVirtualizationInfo( |
| 63 | VkPhysicalDevice physicalDevice, |
| 64 | const VkPhysicalDeviceMemoryProperties* memoryProperties, |
Lingfeng Yang | afe29d3 | 2018-12-25 13:01:52 -0800 | [diff] [blame] | 65 | bool hasDirectMem, |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 66 | HostVisibleMemoryVirtualizationInfo* info_out) { |
Lingfeng Yang | afe29d3 | 2018-12-25 13:01:52 -0800 | [diff] [blame] | 67 | |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 68 | if (info_out->initialized) return; |
| 69 | |
Lingfeng Yang | 630abfb | 2018-12-26 12:31:47 -0800 | [diff] [blame] | 70 | info_out->hostMemoryProperties = *memoryProperties; |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 71 | info_out->initialized = true; |
| 72 | |
Lingfeng Yang | afe29d3 | 2018-12-25 13:01:52 -0800 | [diff] [blame] | 73 | info_out->memoryPropertiesSupported = |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 74 | canFitVirtualHostVisibleMemoryInfo(memoryProperties); |
| 75 | |
Lingfeng Yang | afe29d3 | 2018-12-25 13:01:52 -0800 | [diff] [blame] | 76 | info_out->directMemSupported = hasDirectMem; |
| 77 | |
| 78 | if (!info_out->memoryPropertiesSupported || |
| 79 | !info_out->directMemSupported) { |
| 80 | info_out->virtualizationSupported = false; |
| 81 | return; |
| 82 | } |
| 83 | |
| 84 | info_out->virtualizationSupported = true; |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 85 | |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 86 | info_out->physicalDevice = physicalDevice; |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 87 | info_out->guestMemoryProperties = *memoryProperties; |
| 88 | |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 89 | uint32_t typeCount = |
| 90 | memoryProperties->memoryTypeCount; |
| 91 | uint32_t heapCount = |
| 92 | memoryProperties->memoryHeapCount; |
| 93 | |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 94 | uint32_t firstFreeTypeIndex = typeCount; |
| 95 | uint32_t firstFreeHeapIndex = heapCount; |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 96 | |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 97 | for (uint32_t i = 0; i < typeCount; ++i) { |
| 98 | |
| 99 | // Set up identity mapping and not-both |
| 100 | // by default, to be edited later. |
| 101 | info_out->memoryTypeIndexMappingToHost[i] = i; |
| 102 | info_out->memoryHeapIndexMappingToHost[i] = i; |
| 103 | |
| 104 | info_out->memoryTypeIndexMappingFromHost[i] = i; |
| 105 | info_out->memoryHeapIndexMappingFromHost[i] = i; |
| 106 | |
| 107 | info_out->memoryTypeBitsShouldAdvertiseBoth[i] = false; |
| 108 | |
| 109 | const auto& type = memoryProperties->memoryTypes[i]; |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 110 | |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 111 | if (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) { |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 112 | uint32_t heapIndex = type.heapIndex; |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 113 | |
| 114 | auto& guestMemoryType = |
| 115 | info_out->guestMemoryProperties.memoryTypes[i]; |
| 116 | |
| 117 | auto& newVirtualMemoryType = |
| 118 | info_out->guestMemoryProperties.memoryTypes[firstFreeTypeIndex]; |
| 119 | |
| 120 | auto& newVirtualMemoryHeap = |
| 121 | info_out->guestMemoryProperties.memoryHeaps[firstFreeHeapIndex]; |
| 122 | |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 123 | // Remove all references to host visible in the guest memory type at |
| 124 | // index i, while transferring them to the new virtual memory type. |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 125 | newVirtualMemoryType = type; |
| 126 | |
| 127 | // Set this memory type to have a separate heap. |
| 128 | newVirtualMemoryType.heapIndex = firstFreeHeapIndex; |
| 129 | |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 130 | newVirtualMemoryType.propertyFlags = |
| 131 | type.propertyFlags & |
| 132 | ~(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); |
| 133 | |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 134 | guestMemoryType.propertyFlags = |
| 135 | type.propertyFlags & \ |
| 136 | ~(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | |
| 137 | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | |
| 138 | VK_MEMORY_PROPERTY_HOST_CACHED_BIT); |
| 139 | |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 140 | // In the corresponding new memory heap, copy the information over, |
| 141 | // remove device local flags, and resize it based on what is |
| 142 | // supported by the PCI device. |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 143 | newVirtualMemoryHeap = |
| 144 | memoryProperties->memoryHeaps[heapIndex]; |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 145 | newVirtualMemoryHeap.flags = |
| 146 | newVirtualMemoryHeap.flags & |
| 147 | ~(VK_MEMORY_HEAP_DEVICE_LOCAL_BIT); |
| 148 | |
| 149 | // TODO: Figure out how to support bigger sizes |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 150 | newVirtualMemoryHeap.size = VIRTUAL_HOST_VISIBLE_HEAP_SIZE; |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 151 | |
| 152 | info_out->memoryTypeIndexMappingToHost[firstFreeTypeIndex] = i; |
| 153 | info_out->memoryHeapIndexMappingToHost[firstFreeHeapIndex] = i; |
| 154 | |
| 155 | info_out->memoryTypeIndexMappingFromHost[i] = firstFreeTypeIndex; |
| 156 | info_out->memoryHeapIndexMappingFromHost[i] = firstFreeHeapIndex; |
| 157 | |
| 158 | // Was the original memory type also a device local type? If so, |
| 159 | // advertise both types in resulting type bits. |
| 160 | info_out->memoryTypeBitsShouldAdvertiseBoth[i] = |
| 161 | type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; |
| 162 | |
| 163 | ++firstFreeTypeIndex; |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 164 | |
| 165 | // Explicitly only create one new heap. |
| 166 | // ++firstFreeHeapIndex; |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 167 | } |
| 168 | } |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 169 | |
| 170 | info_out->guestMemoryProperties.memoryTypeCount = firstFreeTypeIndex; |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 171 | info_out->guestMemoryProperties.memoryHeapCount = firstFreeHeapIndex + 1; |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 172 | |
| 173 | for (uint32_t i = info_out->guestMemoryProperties.memoryTypeCount; i < VK_MAX_MEMORY_TYPES; ++i) { |
| 174 | memset(&info_out->guestMemoryProperties.memoryTypes[i], |
| 175 | 0x0, sizeof(VkMemoryType)); |
| 176 | } |
Lingfeng Yang | 58b89c8 | 2018-12-25 11:23:21 -0800 | [diff] [blame] | 177 | } |
| 178 | |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 179 | bool isHostVisibleMemoryTypeIndexForGuest( |
| 180 | const HostVisibleMemoryVirtualizationInfo* info, |
| 181 | uint32_t index) { |
Lingfeng Yang | 630abfb | 2018-12-26 12:31:47 -0800 | [diff] [blame] | 182 | |
| 183 | const auto& props = |
| 184 | info->virtualizationSupported ? |
| 185 | info->guestMemoryProperties : |
| 186 | info->hostMemoryProperties; |
| 187 | |
| 188 | return props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 189 | } |
| 190 | |
Lingfeng Yang | 5c70112 | 2019-03-05 08:34:46 -0800 | [diff] [blame^] | 191 | bool isDeviceLocalMemoryTypeIndexForGuest( |
| 192 | const HostVisibleMemoryVirtualizationInfo* info, |
| 193 | uint32_t index) { |
| 194 | |
| 195 | const auto& props = |
| 196 | info->virtualizationSupported ? |
| 197 | info->guestMemoryProperties : |
| 198 | info->hostMemoryProperties; |
| 199 | |
| 200 | return props.memoryTypes[index].propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; |
| 201 | } |
| 202 | |
| 203 | bool isNoFlagsMemoryTypeIndexForGuest( |
| 204 | const HostVisibleMemoryVirtualizationInfo* info, |
| 205 | uint32_t index) { |
| 206 | const auto& props = |
| 207 | info->virtualizationSupported ? |
| 208 | info->guestMemoryProperties : |
| 209 | info->hostMemoryProperties; |
| 210 | return props.memoryTypes[index].propertyFlags == 0; |
| 211 | } |
| 212 | |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 213 | VkResult finishHostMemAllocInit( |
Lingfeng Yang | 8e89eab | 2019-01-06 16:16:53 -0800 | [diff] [blame] | 214 | VkEncoder*, |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 215 | VkDevice device, |
| 216 | uint32_t memoryTypeIndex, |
| 217 | VkDeviceSize nonCoherentAtomSize, |
| 218 | VkDeviceSize allocSize, |
| 219 | VkDeviceSize mappedSize, |
| 220 | uint8_t* mappedPtr, |
| 221 | HostMemAlloc* out) { |
| 222 | |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 223 | out->device = device; |
| 224 | out->memoryTypeIndex = memoryTypeIndex; |
| 225 | out->nonCoherentAtomSize = nonCoherentAtomSize; |
| 226 | out->allocSize = allocSize; |
| 227 | out->mappedSize = mappedSize; |
| 228 | out->mappedPtr = mappedPtr; |
| 229 | |
Lingfeng Yang | 49c7de2 | 2019-01-23 16:19:50 -0800 | [diff] [blame] | 230 | // because it's not just nonCoherentAtomSize granularity, |
| 231 | // people will also use it for uniform buffers, images, etc. |
| 232 | // that need some bigger alignment |
| 233 | #define HIGHEST_BUFFER_OR_IMAGE_ALIGNMENT 1024 |
| 234 | |
| 235 | uint64_t neededPageSize = out->nonCoherentAtomSize; |
| 236 | if (HIGHEST_BUFFER_OR_IMAGE_ALIGNMENT > |
| 237 | neededPageSize) { |
| 238 | neededPageSize = HIGHEST_BUFFER_OR_IMAGE_ALIGNMENT; |
| 239 | } |
| 240 | |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 241 | out->subAlloc = new |
| 242 | SubAllocator( |
| 243 | out->mappedPtr, |
| 244 | out->mappedSize, |
Lingfeng Yang | 49c7de2 | 2019-01-23 16:19:50 -0800 | [diff] [blame] | 245 | neededPageSize); |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 246 | |
| 247 | out->initialized = true; |
| 248 | out->initResult = VK_SUCCESS; |
| 249 | return VK_SUCCESS; |
| 250 | } |
| 251 | |
| 252 | void destroyHostMemAlloc( |
Lingfeng Yang | 8e89eab | 2019-01-06 16:16:53 -0800 | [diff] [blame] | 253 | VkEncoder* enc, |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 254 | VkDevice device, |
| 255 | HostMemAlloc* toDestroy) { |
| 256 | |
| 257 | if (toDestroy->initResult != VK_SUCCESS) return; |
| 258 | if (!toDestroy->initialized) return; |
| 259 | |
Lingfeng Yang | 8e89eab | 2019-01-06 16:16:53 -0800 | [diff] [blame] | 260 | enc->vkFreeMemory(device, toDestroy->memory, nullptr); |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 261 | delete toDestroy->subAlloc; |
| 262 | } |
| 263 | |
| 264 | void subAllocHostMemory( |
| 265 | HostMemAlloc* alloc, |
| 266 | const VkMemoryAllocateInfo* pAllocateInfo, |
| 267 | SubAlloc* out) { |
| 268 | |
| 269 | VkDeviceSize mappedSize = |
| 270 | alloc->nonCoherentAtomSize * ( |
| 271 | (pAllocateInfo->allocationSize + |
| 272 | alloc->nonCoherentAtomSize - 1) / |
| 273 | alloc->nonCoherentAtomSize); |
| 274 | |
Lingfeng Yang | 49c7de2 | 2019-01-23 16:19:50 -0800 | [diff] [blame] | 275 | ALOGD("%s: alloc size %u mapped size %u ncaSize %u\n", __func__, |
| 276 | (unsigned int)pAllocateInfo->allocationSize, |
| 277 | (unsigned int)mappedSize, |
| 278 | (unsigned int)alloc->nonCoherentAtomSize); |
| 279 | |
Lingfeng Yang | 35e9c6a | 2018-12-25 17:13:36 -0800 | [diff] [blame] | 280 | void* subMapped = alloc->subAlloc->alloc(mappedSize); |
| 281 | out->mappedPtr = (uint8_t*)subMapped; |
| 282 | |
| 283 | out->subAllocSize = pAllocateInfo->allocationSize; |
| 284 | out->subMappedSize = mappedSize; |
| 285 | |
| 286 | out->baseMemory = alloc->memory; |
| 287 | out->baseOffset = alloc->subAlloc->getOffset(subMapped); |
| 288 | |
| 289 | out->subMemory = new_from_host_VkDeviceMemory(VK_NULL_HANDLE); |
| 290 | out->subAlloc = alloc->subAlloc; |
| 291 | } |
| 292 | |
| 293 | void subFreeHostMemory(SubAlloc* toFree) { |
| 294 | delete_goldfish_VkDeviceMemory(toFree->subMemory); |
| 295 | toFree->subAlloc->free(toFree->mappedPtr); |
| 296 | memset(toFree, 0x0, sizeof(SubAlloc)); |
| 297 | } |
| 298 | |
Lingfeng Yang | df17313 | 2018-12-25 13:30:57 -0800 | [diff] [blame] | 299 | } // namespace goldfish_vk |