1 // Copyright (C) 2024 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //      http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #include "VkEmulatedPhysicalDeviceMemory.h"
16 
17 #include <algorithm>
18 #include <limits>
19 
20 #include "host-common/GfxstreamFatalError.h"
21 
22 namespace gfxstream {
23 namespace vk {
24 namespace {
25 
26 static constexpr const uint32_t kInvalidMemoryTypeIndex = std::numeric_limits<uint32_t>::max();
27 
28 }  // namespace
29 
EmulatedPhysicalDeviceMemoryProperties(const VkPhysicalDeviceMemoryProperties & hostMemoryProperties,const uint32_t hostColorBufferMemoryTypeIndex,const gfxstream::host::FeatureSet & features)30 EmulatedPhysicalDeviceMemoryProperties::EmulatedPhysicalDeviceMemoryProperties(
31     const VkPhysicalDeviceMemoryProperties& hostMemoryProperties,
32     const uint32_t hostColorBufferMemoryTypeIndex, const gfxstream::host::FeatureSet& features) {
33     // Start with the original host memory properties:
34     mHostMemoryProperties = hostMemoryProperties;
35     mGuestMemoryProperties = hostMemoryProperties;
36     std::fill_n(mGuestToHostMemoryTypeIndexMap, VK_MAX_MEMORY_TYPES, kInvalidMemoryTypeIndex);
37     std::fill_n(mHostToGuestMemoryTypeIndexMap, VK_MAX_MEMORY_TYPES, kInvalidMemoryTypeIndex);
38     for (uint32_t i = 0; i < mHostMemoryProperties.memoryTypeCount; i++) {
39         mGuestToHostMemoryTypeIndexMap[i] = i;
40         mHostToGuestMemoryTypeIndexMap[i] = i;
41     }
42     mGuestColorBufferMemoryTypeIndex = hostColorBufferMemoryTypeIndex;
43 
44     // Hide any bogus heap sizes from bad drivers with a reasonable default that will not
45     // break the bank on 32-bit userspaces.
46     static constexpr VkDeviceSize kMaxSafeHeapSize = 2ULL * 1024ULL * 1024ULL * 1024ULL;
47     for (uint32_t i = 0; i < mHostMemoryProperties.memoryHeapCount; i++) {
48         if (mGuestMemoryProperties.memoryHeaps[i].size > kMaxSafeHeapSize) {
49             mGuestMemoryProperties.memoryHeaps[i].size = kMaxSafeHeapSize;
50         }
51     }
52 
53     // If enabled, hide non device memory types from the guest.
54     // (useful to work around a bug where KVM can't map TTM memory).
55     if (features.VulkanAllocateDeviceMemoryOnly.enabled) {
56         for (uint32_t i = 0; i < mGuestMemoryProperties.memoryTypeCount; i++) {
57             auto guestMemoryProperties = mGuestMemoryProperties.memoryTypes[i].propertyFlags;
58             if (!(guestMemoryProperties & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
59                 mGuestMemoryProperties.memoryTypes[i].propertyFlags = 0;
60             }
61         }
62     }
63 
64     // Coherent memory in the guest requires one of these features:
65     if (!features.GlDirectMem.enabled && !features.VirtioGpuNext.enabled) {
66         for (uint32_t i = 0; i < mGuestMemoryProperties.memoryTypeCount; i++) {
67             mGuestMemoryProperties.memoryTypes[i].propertyFlags =
68                 mGuestMemoryProperties.memoryTypes[i].propertyFlags &
69                 ~(VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
70         }
71     }
72 
73     // If enabled, reserve an additional memory type for AHB backed buffers and images
74     // so that the host can control its memory properties. This ensures that the guest
75     // only sees `VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT` and will not try to map the
76     // memory.
77     if (features.VulkanUseDedicatedAhbMemoryType.enabled) {
78         if (mGuestMemoryProperties.memoryTypeCount == VK_MAX_MEMORY_TYPES) {
79             GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER))
80                 << "Unable to create emulated AHB memory type because VK_MAX_MEMORY_TYPES "
81                    "already in use.";
82         }
83 
84         uint32_t ahbMemoryTypeIndex = mGuestMemoryProperties.memoryTypeCount;
85         ++mGuestMemoryProperties.memoryTypeCount;
86 
87         VkMemoryType& ahbMemoryType = mGuestMemoryProperties.memoryTypes[ahbMemoryTypeIndex];
88         ahbMemoryType.propertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
89         ahbMemoryType.heapIndex =
90             mHostMemoryProperties.memoryTypes[hostColorBufferMemoryTypeIndex].heapIndex;
91 
92         mGuestToHostMemoryTypeIndexMap[ahbMemoryTypeIndex] = hostColorBufferMemoryTypeIndex;
93 
94         mGuestColorBufferMemoryTypeIndex = ahbMemoryTypeIndex;
95     }
96 }
97 
98 std::optional<EmulatedPhysicalDeviceMemoryProperties::HostMemoryInfo>
getHostMemoryInfoFromHostMemoryTypeIndex(uint32_t hostMemoryTypeIndex) const99 EmulatedPhysicalDeviceMemoryProperties::getHostMemoryInfoFromHostMemoryTypeIndex(
100     uint32_t hostMemoryTypeIndex) const {
101     if (hostMemoryTypeIndex >= mHostMemoryProperties.memoryTypeCount) {
102         return std::nullopt;
103     }
104 
105     return HostMemoryInfo{
106         .index = hostMemoryTypeIndex,
107         .memoryType = mHostMemoryProperties.memoryTypes[hostMemoryTypeIndex],
108     };
109 }
110 
111 std::optional<EmulatedPhysicalDeviceMemoryProperties::HostMemoryInfo>
getHostMemoryInfoFromGuestMemoryTypeIndex(uint32_t guestMemoryTypeIndex) const112 EmulatedPhysicalDeviceMemoryProperties::getHostMemoryInfoFromGuestMemoryTypeIndex(
113     uint32_t guestMemoryTypeIndex) const {
114     if (guestMemoryTypeIndex >= mGuestMemoryProperties.memoryTypeCount) {
115         return std::nullopt;
116     }
117 
118     uint32_t hostMemoryTypeIndex = mGuestToHostMemoryTypeIndexMap[guestMemoryTypeIndex];
119     if (hostMemoryTypeIndex == kInvalidMemoryTypeIndex) {
120         return std::nullopt;
121     }
122 
123     return getHostMemoryInfoFromHostMemoryTypeIndex(hostMemoryTypeIndex);
124 }
125 
transformToGuestMemoryRequirements(VkMemoryRequirements * memoryRequirements) const126 void EmulatedPhysicalDeviceMemoryProperties::transformToGuestMemoryRequirements(
127     VkMemoryRequirements* memoryRequirements) const {
128     uint32_t guestMemoryTypeBits = 0;
129 
130     const uint32_t hostMemoryTypeBits = memoryRequirements->memoryTypeBits;
131     for (uint32_t hostMemoryTypeIndex = 0;
132          hostMemoryTypeIndex < mHostMemoryProperties.memoryTypeCount; hostMemoryTypeIndex++) {
133         if (!(hostMemoryTypeBits & (1u << hostMemoryTypeIndex))) {
134             continue;
135         }
136 
137         uint32_t guestMemoryTypeIndex = mHostToGuestMemoryTypeIndexMap[hostMemoryTypeIndex];
138         if (guestMemoryTypeIndex == kInvalidMemoryTypeIndex) {
139             continue;
140         }
141 
142         guestMemoryTypeBits |= (1u << guestMemoryTypeIndex);
143     }
144 
145     memoryRequirements->memoryTypeBits = guestMemoryTypeBits;
146 }
147 
148 }  // namespace vk
149 }  // namespace gfxstream