blob: 01887a3faf646a08c8decb7d9739f6b1618375ea [file] [log] [blame]
// Copyright (C) 2018 The Android Open Source Project
// Copyright (C) 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "HostVisibleMemoryVirtualization.h"
#include <log/log.h>
#include <set>
namespace goldfish_vk {
bool canFitVirtualHostVisibleMemoryInfo(
const VkPhysicalDeviceMemoryProperties* memoryProperties) {
uint32_t typeCount =
memoryProperties->memoryTypeCount;
uint32_t heapCount =
memoryProperties->memoryHeapCount;
bool canFit = true;
if (typeCount == VK_MAX_MEMORY_TYPES) {
canFit = false;
ALOGE("Underlying device has no free memory types");
}
if (heapCount == VK_MAX_MEMORY_HEAPS) {
canFit = false;
ALOGE("Underlying device has no free memory heaps");
}
uint32_t numFreeMemoryTypes = VK_MAX_MEMORY_TYPES - typeCount;
uint32_t numFreeMemoryHeaps = VK_MAX_MEMORY_HEAPS - heapCount;
uint32_t hostVisibleMemoryTypeCount = 0;
uint32_t hostVisibleMemoryHeapCount = 0;
std::set<uint32_t> hostVisibleMemoryHeaps;
for (uint32_t i = 0; i < typeCount; ++i) {
const auto& type = memoryProperties->memoryTypes[i];
if (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
++hostVisibleMemoryTypeCount;
hostVisibleMemoryHeaps.insert(type.heapIndex);
}
}
hostVisibleMemoryHeapCount =
(uint32_t)hostVisibleMemoryHeaps.size();
if (hostVisibleMemoryTypeCount > numFreeMemoryTypes) {
ALOGE("Underlying device has too many host visible memory types (%u)"
"and not enough free types (%u)",
hostVisibleMemoryTypeCount, numFreeMemoryTypes);
canFit = false;
}
if (hostVisibleMemoryHeapCount > numFreeMemoryHeaps) {
ALOGE("Underlying device has too many host visible memory types (%u)"
"and not enough free types (%u)",
hostVisibleMemoryHeapCount, numFreeMemoryHeaps);
canFit = false;
}
return canFit;
}
void initHostVisibleMemoryVirtualizationInfo(
VkPhysicalDevice physicalDevice,
const VkPhysicalDeviceMemoryProperties* memoryProperties,
bool hasDirectMem,
HostVisibleMemoryVirtualizationInfo* info_out) {
info_out->memoryPropertiesSupported =
canFitVirtualHostVisibleMemoryInfo(memoryProperties);
info_out->directMemSupported = hasDirectMem;
if (!info_out->memoryPropertiesSupported ||
!info_out->directMemSupported) {
info_out->virtualizationSupported = false;
return;
}
info_out->virtualizationSupported = true;
uint32_t typeCount =
memoryProperties->memoryTypeCount;
uint32_t heapCount =
memoryProperties->memoryHeapCount;
info_out->physicalDevice = physicalDevice;
info_out->hostMemoryProperties = *memoryProperties;
info_out->guestMemoryProperties = *memoryProperties;
uint32_t firstFreeTypeIndex = typeCount;
uint32_t firstFreeHeapIndex = heapCount;
for (uint32_t i = 0; i < typeCount; ++i) {
// Set up identity mapping and not-both
// by default, to be edited later.
info_out->memoryTypeIndexMappingToHost[i] = i;
info_out->memoryHeapIndexMappingToHost[i] = i;
info_out->memoryTypeIndexMappingFromHost[i] = i;
info_out->memoryHeapIndexMappingFromHost[i] = i;
info_out->memoryTypeBitsShouldAdvertiseBoth[i] = false;
const auto& type = memoryProperties->memoryTypes[i];
if (type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
auto& guestMemoryType =
info_out->guestMemoryProperties.memoryTypes[i];
auto& newVirtualMemoryType =
info_out->guestMemoryProperties.memoryTypes[firstFreeTypeIndex];
auto& newVirtualMemoryHeap =
info_out->guestMemoryProperties.memoryHeaps[firstFreeHeapIndex];
newVirtualMemoryType = type;
// Set this memory type to have a separate heap.
newVirtualMemoryType.heapIndex = firstFreeHeapIndex;
// Remove all references to host visible in the guest memory type at
// index i, while transferring them to the new virtual memory type.
guestMemoryType.propertyFlags =
type.propertyFlags & \
~(VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
// Remove device local from the new virtual memory type.
newVirtualMemoryType.propertyFlags =
guestMemoryType.propertyFlags &
~(VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
// In the corresponding new memory heap, copy the information over,
// remove device local flags, and resize it based on what is
// supported by the PCI device.
newVirtualMemoryHeap.flags =
newVirtualMemoryHeap.flags &
~(VK_MEMORY_HEAP_DEVICE_LOCAL_BIT);
// TODO: Figure out how to support bigger sizes
newVirtualMemoryHeap.size = 512ULL * 1048576ULL; // 512 MB
info_out->memoryTypeIndexMappingToHost[firstFreeTypeIndex] = i;
info_out->memoryHeapIndexMappingToHost[firstFreeHeapIndex] = i;
info_out->memoryTypeIndexMappingFromHost[i] = firstFreeTypeIndex;
info_out->memoryHeapIndexMappingFromHost[i] = firstFreeHeapIndex;
// Was the original memory type also a device local type? If so,
// advertise both types in resulting type bits.
info_out->memoryTypeBitsShouldAdvertiseBoth[i] =
type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
++firstFreeTypeIndex;
++firstFreeHeapIndex;
}
}
}
} // namespace goldfish_vk