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