[vulkan] Collect (but do not use) host-visible memory virtualization info

bug: 111137294
bug: 121420031

Change-Id: I769d6e0f4179bf86a05fe1da2b4166edb1de3c04
diff --git a/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp b/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
new file mode 100644
index 0000000..e8a2fb7
--- /dev/null
+++ b/system/vulkan_enc/HostVisibleMemoryVirtualization.cpp
@@ -0,0 +1,166 @@
+// 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,
+    HostVisibleMemoryVirtualizationInfo* info_out) {
+    
+    info_out->supported =
+        canFitVirtualHostVisibleMemoryInfo(memoryProperties);
+
+    if (!info_out->supported) return;
+
+    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
\ No newline at end of file