• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
canFitVirtualHostVisibleMemoryInfo(const VkPhysicalDeviceMemoryProperties * memoryProperties)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 
initHostVisibleMemoryVirtualizationInfo(VkPhysicalDevice physicalDevice,const VkPhysicalDeviceMemoryProperties * memoryProperties,bool hasDirectMem,HostVisibleMemoryVirtualizationInfo * info_out)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 
isHostVisibleMemoryTypeIndexForGuest(const HostVisibleMemoryVirtualizationInfo * info,uint32_t index)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 
isDeviceLocalMemoryTypeIndexForGuest(const HostVisibleMemoryVirtualizationInfo * info,uint32_t index)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 
isNoFlagsMemoryTypeIndexForGuest(const HostVisibleMemoryVirtualizationInfo * info,uint32_t index)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 
finishHostMemAllocInit(VkEncoder *,VkDevice device,uint32_t memoryTypeIndex,VkDeviceSize nonCoherentAtomSize,VkDeviceSize allocSize,VkDeviceSize mappedSize,uint8_t * mappedPtr,HostMemAlloc * out)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 
destroyHostMemAlloc(VkEncoder * enc,VkDevice device,HostMemAlloc * toDestroy)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 
subAllocHostMemory(HostMemAlloc * alloc,const VkMemoryAllocateInfo * pAllocateInfo,SubAlloc * out)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 
subFreeHostMemory(SubAlloc * toFree)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 
canSubAlloc(android::base::SubAllocator * subAlloc,VkDeviceSize size)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