Home | History | Annotate | Download | only in vulkan_enc
      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 
     17 #include "android/base/SubAllocator.h"
     18 
     19 #include "Resources.h"
     20 #include "VkEncoder.h"
     21 
     22 #include <log/log.h>
     23 
     24 #include <set>
     25 
     26 using android::base::SubAllocator;
     27 
     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;
     50     uint32_t hostVisibleMemoryTypeCount = 0;
     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 
     59     return canFit;
     60 }
     61 
     62 void initHostVisibleMemoryVirtualizationInfo(
     63     VkPhysicalDevice physicalDevice,
     64     const VkPhysicalDeviceMemoryProperties* memoryProperties,
     65     bool hasDirectMem,
     66     HostVisibleMemoryVirtualizationInfo* info_out) {
     67 
     68     if (info_out->initialized) return;
     69 
     70     info_out->hostMemoryProperties = *memoryProperties;
     71     info_out->initialized = true;
     72 
     73     info_out->memoryPropertiesSupported =
     74         canFitVirtualHostVisibleMemoryInfo(memoryProperties);
     75 
     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;
     85 
     86     info_out->physicalDevice = physicalDevice;
     87     info_out->guestMemoryProperties = *memoryProperties;
     88 
     89     uint32_t typeCount =
     90         memoryProperties->memoryTypeCount;
     91     uint32_t heapCount =
     92         memoryProperties->memoryHeapCount;
     93 
     94     uint32_t firstFreeTypeIndex = typeCount;
     95     uint32_t firstFreeHeapIndex = heapCount;
     96 
     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];
    110 
    111         if (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
    112             uint32_t heapIndex = type.heapIndex;
    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 
    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.
    125             newVirtualMemoryType = type;
    126 
    127             // Set this memory type to have a separate heap.
    128             newVirtualMemoryType.heapIndex = firstFreeHeapIndex;
    129 
    130             newVirtualMemoryType.propertyFlags =
    131                 type.propertyFlags &
    132                 ~(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
    133 
    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 
    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.
    143             newVirtualMemoryHeap =
    144                 memoryProperties->memoryHeaps[heapIndex];
    145             newVirtualMemoryHeap.flags =
    146                 newVirtualMemoryHeap.flags &
    147                 ~(VK_MEMORY_HEAP_DEVICE_LOCAL_BIT);
    148 
    149             // TODO: Figure out how to support bigger sizes
    150             newVirtualMemoryHeap.size = VIRTUAL_HOST_VISIBLE_HEAP_SIZE;
    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;
    164 
    165             // Explicitly only create one new heap.
    166             // ++firstFreeHeapIndex;
    167         }
    168     }
    169 
    170     info_out->guestMemoryProperties.memoryTypeCount = firstFreeTypeIndex;
    171     info_out->guestMemoryProperties.memoryHeapCount = firstFreeHeapIndex + 1;
    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     }
    177 }
    178 
    179 bool isHostVisibleMemoryTypeIndexForGuest(
    180     const HostVisibleMemoryVirtualizationInfo* info,
    181     uint32_t index) {
    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;
    189 }
    190 
    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 
    213 VkResult finishHostMemAllocInit(
    214     VkEncoder*,
    215     VkDevice device,
    216     uint32_t memoryTypeIndex,
    217     VkDeviceSize nonCoherentAtomSize,
    218     VkDeviceSize allocSize,
    219     VkDeviceSize mappedSize,
    220     uint8_t* mappedPtr,
    221     HostMemAlloc* out) {
    222 
    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 
    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 
    241     out->subAlloc = new
    242         SubAllocator(
    243             out->mappedPtr,
    244             out->mappedSize,
    245             neededPageSize);
    246 
    247     out->initialized = true;
    248     out->initResult = VK_SUCCESS;
    249     return VK_SUCCESS;
    250 }
    251 
    252 void destroyHostMemAlloc(
    253     VkEncoder* enc,
    254     VkDevice device,
    255     HostMemAlloc* toDestroy) {
    256 
    257     if (toDestroy->initResult != VK_SUCCESS) return;
    258     if (!toDestroy->initialized) return;
    259 
    260     enc->vkFreeMemory(device, toDestroy->memory, nullptr);
    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 
    275     ALOGV("%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 
    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 
    299 bool canSubAlloc(android::base::SubAllocator* subAlloc, VkDeviceSize size) {
    300     auto ptr = subAlloc->alloc(size);
    301     if (!ptr) return false;
    302     subAlloc->free(ptr);
    303     return true;
    304 }
    305 
    306 } // namespace goldfish_vk
    307