1 // Copyright 2018 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 expresso or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 #include "VkCommonOperations.h"
15
16 #include <GLES2/gl2.h>
17 #include <GLES2/gl2ext.h>
18 #include <GLES3/gl3.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <vulkan/vk_enum_string_helper.h>
22
23 #include <iomanip>
24 #include <ostream>
25 #include <sstream>
26 #include <unordered_set>
27
28 #include "ExternalObjectManager.h"
29 #include "VkDecoderGlobalState.h"
30 #include "VkEmulatedPhysicalDeviceMemory.h"
31 #include "VkFormatUtils.h"
32 #include "VulkanDispatch.h"
33 #include "aemu/base/Optional.h"
34 #include "aemu/base/Tracing.h"
35 #include "aemu/base/containers/Lookup.h"
36 #include "aemu/base/containers/StaticMap.h"
37 #include "aemu/base/synchronization/Lock.h"
38 #include "aemu/base/system/System.h"
39 #include "common/goldfish_vk_dispatch.h"
40 #include "host-common/GfxstreamFatalError.h"
41 #include "host-common/emugl_vm_operations.h"
42 #include "host-common/vm_operations.h"
43
44 #ifdef _WIN32
45 #include <windows.h>
46 #else
47 #include <fcntl.h>
48 #include <unistd.h>
49 #endif
50
51 #ifdef __APPLE__
52 #include <CoreFoundation/CoreFoundation.h>
53 #include <vulkan/vulkan_beta.h> // for MoltenVK portability extensions
54 #endif
55
56 namespace gfxstream {
57 namespace vk {
58 namespace {
59
60 using android::base::AutoLock;
61 using android::base::kNullopt;
62 using android::base::ManagedDescriptor;
63 using android::base::Optional;
64 using android::base::StaticLock;
65 using android::base::StaticMap;
66 using emugl::ABORT_REASON_OTHER;
67 using emugl::FatalError;
68
69 #ifndef VERBOSE
70 #define VERBOSE(fmt, ...) \
71 if (android::base::isVerboseLogging()) { \
72 INFO(fmt, ##__VA_ARGS__); \
73 }
74 #endif
75
76 constexpr size_t kPageBits = 12;
77 constexpr size_t kPageSize = 1u << kPageBits;
78
79 static int kMaxDebugMarkerAnnotations = 10;
80
81 static std::optional<std::string> sMemoryLogPath = std::nullopt;
82
string_AstcEmulationMode(AstcEmulationMode mode)83 const char* string_AstcEmulationMode(AstcEmulationMode mode) {
84 switch (mode) {
85 case AstcEmulationMode::Disabled:
86 return "Disabled";
87 case AstcEmulationMode::Cpu:
88 return "Cpu";
89 case AstcEmulationMode::Gpu:
90 return "Gpu";
91 }
92 return "Unknown";
93 }
94
95 } // namespace
96
97 static StaticMap<VkDevice, uint32_t> sKnownStagingTypeIndices;
98
99 static android::base::StaticLock sVkEmulationLock;
100
101 static bool updateColorBufferFromBytesLocked(uint32_t colorBufferHandle, uint32_t x, uint32_t y,
102 uint32_t w, uint32_t h, const void* pixels,
103 size_t inputPixelsSize);
104
105 #if !defined(__QNX__)
dupExternalMemory(VK_EXT_MEMORY_HANDLE h)106 VK_EXT_MEMORY_HANDLE dupExternalMemory(VK_EXT_MEMORY_HANDLE h) {
107 #ifdef _WIN32
108 auto myProcessHandle = GetCurrentProcess();
109 VK_EXT_MEMORY_HANDLE res;
110 DuplicateHandle(myProcessHandle, h, // source process and handle
111 myProcessHandle, &res, // target process and pointer to handle
112 0 /* desired access (ignored) */, true /* inherit */,
113 DUPLICATE_SAME_ACCESS /* same access option */);
114 return res;
115 #else
116 return dup(h);
117 #endif
118 }
119 #endif
120
getStagingMemoryTypeIndex(VulkanDispatch * vk,VkDevice device,const VkPhysicalDeviceMemoryProperties * memProps,uint32_t * typeIndex)121 bool getStagingMemoryTypeIndex(VulkanDispatch* vk, VkDevice device,
122 const VkPhysicalDeviceMemoryProperties* memProps,
123 uint32_t* typeIndex) {
124 auto res = sKnownStagingTypeIndices.get(device);
125
126 if (res) {
127 *typeIndex = *res;
128 return true;
129 }
130
131 VkBufferCreateInfo testCreateInfo = {
132 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
133 0,
134 0,
135 4096,
136 // To be a staging buffer, it must support being
137 // both a transfer src and dst.
138 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
139 // TODO: See if buffers over shared queues need to be
140 // considered separately
141 VK_SHARING_MODE_EXCLUSIVE,
142 0,
143 nullptr,
144 };
145
146 VkBuffer testBuffer;
147 VkResult testBufferCreateRes =
148 vk->vkCreateBuffer(device, &testCreateInfo, nullptr, &testBuffer);
149
150 if (testBufferCreateRes != VK_SUCCESS) {
151 ERR("Could not create test buffer "
152 "for staging buffer query. VkResult: %s",
153 string_VkResult(testBufferCreateRes));
154 return false;
155 }
156
157 VkMemoryRequirements memReqs;
158 vk->vkGetBufferMemoryRequirements(device, testBuffer, &memReqs);
159
160 // To be a staging buffer, we need to allow CPU read/write access.
161 // Thus, we need the memory type index both to be host visible
162 // and to be supported in the memory requirements of the buffer.
163 bool foundSuitableStagingMemoryType = false;
164 uint32_t stagingMemoryTypeIndex = 0;
165
166 for (uint32_t i = 0; i < memProps->memoryTypeCount; ++i) {
167 const auto& typeInfo = memProps->memoryTypes[i];
168 bool hostVisible = typeInfo.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
169 bool hostCached = typeInfo.propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
170 bool allowedInBuffer = (1 << i) & memReqs.memoryTypeBits;
171 if (hostVisible && hostCached && allowedInBuffer) {
172 foundSuitableStagingMemoryType = true;
173 stagingMemoryTypeIndex = i;
174 break;
175 }
176 }
177
178 // If the previous loop failed, try to accept a type that is not HOST_CACHED.
179 if (!foundSuitableStagingMemoryType) {
180 for (uint32_t i = 0; i < memProps->memoryTypeCount; ++i) {
181 const auto& typeInfo = memProps->memoryTypes[i];
182 bool hostVisible = typeInfo.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
183 bool allowedInBuffer = (1 << i) & memReqs.memoryTypeBits;
184 if (hostVisible && allowedInBuffer) {
185 ERR("Warning: using non-cached HOST_VISIBLE type for staging memory");
186 foundSuitableStagingMemoryType = true;
187 stagingMemoryTypeIndex = i;
188 break;
189 }
190 }
191 }
192
193 vk->vkDestroyBuffer(device, testBuffer, nullptr);
194
195 if (!foundSuitableStagingMemoryType) {
196 std::stringstream ss;
197 ss << "Could not find suitable memory type index "
198 << "for staging buffer. Memory type bits: " << std::hex << memReqs.memoryTypeBits << "\n"
199 << "Available host visible memory type indices:"
200 << "\n";
201 for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
202 if (memProps->memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
203 ss << "Host visible memory type index: %u" << i << "\n";
204 }
205 if (memProps->memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
206 ss << "Host cached memory type index: %u" << i << "\n";
207 }
208 }
209
210 ERR("Error: %s", ss.str().c_str());
211
212 return false;
213 }
214
215 sKnownStagingTypeIndices.set(device, stagingMemoryTypeIndex);
216 *typeIndex = stagingMemoryTypeIndex;
217
218 return true;
219 }
220
221 static VkEmulation* sVkEmulation = nullptr;
222
extensionsSupported(const std::vector<VkExtensionProperties> & currentProps,const std::vector<const char * > & wantedExtNames)223 static bool extensionsSupported(const std::vector<VkExtensionProperties>& currentProps,
224 const std::vector<const char*>& wantedExtNames) {
225 std::vector<bool> foundExts(wantedExtNames.size(), false);
226
227 for (uint32_t i = 0; i < currentProps.size(); ++i) {
228 for (size_t j = 0; j < wantedExtNames.size(); ++j) {
229 if (!strcmp(wantedExtNames[j], currentProps[i].extensionName)) {
230 foundExts[j] = true;
231 }
232 }
233 }
234
235 for (size_t i = 0; i < wantedExtNames.size(); ++i) {
236 bool found = foundExts[i];
237 if (!found) {
238 VERBOSE("%s not found, bailing.", wantedExtNames[i]);
239 return false;
240 }
241 }
242
243 return true;
244 }
245
246 // Return true if format requires sampler YCBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image
247 // views. Table found in spec
formatRequiresYcbcrConversion(VkFormat format)248 static bool formatRequiresYcbcrConversion(VkFormat format) {
249 switch (format) {
250 case VK_FORMAT_G8B8G8R8_422_UNORM:
251 case VK_FORMAT_B8G8R8G8_422_UNORM:
252 case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
253 case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
254 case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
255 case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
256 case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
257 case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
258 case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
259 case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
260 case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
261 case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
262 case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
263 case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
264 case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
265 case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
266 case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
267 case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
268 case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
269 case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
270 case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
271 case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
272 case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
273 case VK_FORMAT_G16B16G16R16_422_UNORM:
274 case VK_FORMAT_B16G16R16G16_422_UNORM:
275 case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
276 case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
277 case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
278 case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
279 case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
280 case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
281 case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
282 case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
283 case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
284 return true;
285 default:
286 return false;
287 }
288 }
289
290 // For a given ImageSupportInfo, populates usageWithExternalHandles and
291 // requiresDedicatedAllocation. memoryTypeBits are populated later once the
292 // device is created, because that needs a test image to be created.
293 // If we don't support external memory, it's assumed dedicated allocations are
294 // not needed.
295 // Precondition: sVkEmulation instance has been created and ext memory caps known.
296 // Returns false if the query failed.
getImageFormatExternalMemorySupportInfo(VulkanDispatch * vk,VkPhysicalDevice physdev,VkEmulation::ImageSupportInfo * info)297 static bool getImageFormatExternalMemorySupportInfo(VulkanDispatch* vk, VkPhysicalDevice physdev,
298 VkEmulation::ImageSupportInfo* info) {
299 // Currently there is nothing special we need to do about
300 // VkFormatProperties2, so just use the normal version
301 // and put it in the format2 struct.
302 VkFormatProperties outFormatProps;
303 vk->vkGetPhysicalDeviceFormatProperties(physdev, info->format, &outFormatProps);
304
305 info->formatProps2 = {
306 VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
307 0,
308 outFormatProps,
309 };
310
311 if (!sVkEmulation->instanceSupportsExternalMemoryCapabilities) {
312 info->supportsExternalMemory = false;
313 info->requiresDedicatedAllocation = false;
314
315 VkImageFormatProperties outImageFormatProps;
316 VkResult res = vk->vkGetPhysicalDeviceImageFormatProperties(
317 physdev, info->format, info->type, info->tiling, info->usageFlags, info->createFlags,
318 &outImageFormatProps);
319
320 if (res != VK_SUCCESS) {
321 if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
322 info->supported = false;
323 return true;
324 } else {
325 ERR("vkGetPhysicalDeviceImageFormatProperties query "
326 "failed with %s"
327 "for format 0x%x type 0x%x usage 0x%x flags 0x%x",
328 string_VkResult(res), info->format, info->type, info->usageFlags,
329 info->createFlags);
330 return false;
331 }
332 }
333
334 info->supported = true;
335
336 info->imageFormatProps2 = {
337 VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
338 0,
339 outImageFormatProps,
340 };
341
342 VERBOSE("Supported (not externally): %s %s %s %s", string_VkFormat(info->format),
343 string_VkImageType(info->type), string_VkImageTiling(info->tiling),
344 string_VkImageUsageFlagBits((VkImageUsageFlagBits)info->usageFlags));
345
346 return true;
347 }
348
349 VkPhysicalDeviceExternalImageFormatInfo extInfo = {
350 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
351 0,
352 VK_EXT_MEMORY_HANDLE_TYPE_BIT,
353 };
354 #if defined(__APPLE__)
355 if (sVkEmulation->instanceSupportsMoltenVK) {
356 // Using a different handle type when in MoltenVK mode
357 extInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
358 }
359 #endif
360
361 VkPhysicalDeviceImageFormatInfo2 formatInfo2 = {
362 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
363 &extInfo,
364 info->format,
365 info->type,
366 info->tiling,
367 info->usageFlags,
368 info->createFlags,
369 };
370
371 VkExternalImageFormatProperties outExternalProps = {
372 VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
373 0,
374 {
375 (VkExternalMemoryFeatureFlags)0,
376 (VkExternalMemoryHandleTypeFlags)0,
377 (VkExternalMemoryHandleTypeFlags)0,
378 },
379 };
380
381 VkImageFormatProperties2 outProps2 = {VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
382 &outExternalProps,
383 {
384 {0, 0, 0},
385 0,
386 0,
387 1,
388 0,
389 }};
390
391 VkResult res = sVkEmulation->getImageFormatProperties2Func(physdev, &formatInfo2, &outProps2);
392
393 if (res != VK_SUCCESS) {
394 if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
395 VERBOSE("Not Supported: %s %s %s %s", string_VkFormat(info->format),
396 string_VkImageType(info->type), string_VkImageTiling(info->tiling),
397 string_VkImageUsageFlagBits((VkImageUsageFlagBits)info->usageFlags));
398
399 info->supported = false;
400 return true;
401 } else {
402 ERR("vkGetPhysicalDeviceImageFormatProperties2KHR query "
403 "failed with %s "
404 "for format 0x%x type 0x%x usage 0x%x flags 0x%x",
405 string_VkResult(res), info->format, info->type, info->usageFlags,
406 info->createFlags);
407 return false;
408 }
409 }
410
411 info->supported = true;
412
413 VkExternalMemoryFeatureFlags featureFlags =
414 outExternalProps.externalMemoryProperties.externalMemoryFeatures;
415
416 VkExternalMemoryHandleTypeFlags exportImportedFlags =
417 outExternalProps.externalMemoryProperties.exportFromImportedHandleTypes;
418
419 // Don't really care about export form imported handle types yet
420 (void)exportImportedFlags;
421
422 VkExternalMemoryHandleTypeFlags compatibleHandleTypes =
423 outExternalProps.externalMemoryProperties.compatibleHandleTypes;
424
425 VkExternalMemoryHandleTypeFlags handleTypeNeeded = VK_EXT_MEMORY_HANDLE_TYPE_BIT;
426 #if defined(__APPLE__)
427 if (sVkEmulation->instanceSupportsMoltenVK) {
428 // Using a different handle type when in MoltenVK mode
429 handleTypeNeeded = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
430 }
431 #endif
432
433 info->supportsExternalMemory = (handleTypeNeeded & compatibleHandleTypes) &&
434 (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT & featureFlags) &&
435 (VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT & featureFlags);
436
437 info->requiresDedicatedAllocation =
438 (VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT & featureFlags);
439
440 info->imageFormatProps2 = outProps2;
441 info->extFormatProps = outExternalProps;
442 info->imageFormatProps2.pNext = &info->extFormatProps;
443
444 VERBOSE("Supported: %s %s %s %s, supportsExternalMemory? %d, requiresDedicated? %d",
445 string_VkFormat(info->format), string_VkImageType(info->type),
446 string_VkImageTiling(info->tiling),
447 string_VkImageUsageFlagBits((VkImageUsageFlagBits)info->usageFlags),
448 info->supportsExternalMemory, info->requiresDedicatedAllocation);
449
450 return true;
451 }
452
453 // Vulkan driverVersions are bit-shift packs of their dotted versions
454 // For example, nvidia driverversion 1934229504 unpacks to 461.40
455 // note: while this is equivalent to VkPhysicalDeviceDriverProperties.driverInfo on NVIDIA,
456 // on intel that value is simply "Intel driver".
decodeDriverVersion(uint32_t vendorId,uint32_t driverVersion)457 static std::string decodeDriverVersion(uint32_t vendorId, uint32_t driverVersion) {
458 std::stringstream result;
459 switch (vendorId) {
460 case 0x10DE: {
461 // Nvidia. E.g. driverVersion = 1934229504(0x734a0000) maps to 461.40
462 uint32_t major = driverVersion >> 22;
463 uint32_t minor = (driverVersion >> 14) & 0xff;
464 uint32_t build = (driverVersion >> 6) & 0xff;
465 uint32_t revision = driverVersion & 0x3f;
466 result << major << '.' << minor << '.' << build << '.' << revision;
467 break;
468 }
469 case 0x8086: {
470 // Intel. E.g. driverVersion = 1647866(0x1924fa) maps to 100.9466 (27.20.100.9466)
471 uint32_t high = driverVersion >> 14;
472 uint32_t low = driverVersion & 0x3fff;
473 result << high << '.' << low;
474 break;
475 }
476 case 0x002: // amd
477 default: {
478 uint32_t major = VK_VERSION_MAJOR(driverVersion);
479 uint32_t minor = VK_VERSION_MINOR(driverVersion);
480 uint32_t patch = VK_VERSION_PATCH(driverVersion);
481 result << major << "." << minor << "." << patch;
482 break;
483 }
484 }
485 return result.str();
486 }
487
getBasicImageSupportList()488 static std::vector<VkEmulation::ImageSupportInfo> getBasicImageSupportList() {
489 struct ImageFeatureCombo {
490 VkFormat format;
491 VkImageCreateFlags createFlags = 0;
492 };
493 // Set the mutable flag for RGB UNORM formats so that the created image can also be sampled in
494 // the sRGB Colorspace. See
495 // https://chromium-review.googlesource.com/c/chromiumos/platform/minigbm/+/3827672/comments/77db9cb3_60663a6a
496 // for details.
497 std::vector<ImageFeatureCombo> combos = {
498 // Cover all the gralloc formats
499 {VK_FORMAT_R8G8B8A8_UNORM,
500 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
501 {VK_FORMAT_R8G8B8_UNORM,
502 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
503
504 {VK_FORMAT_R5G6B5_UNORM_PACK16},
505
506 {VK_FORMAT_R16G16B16A16_SFLOAT},
507 {VK_FORMAT_R16G16B16_SFLOAT},
508
509 {VK_FORMAT_B8G8R8A8_UNORM,
510 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
511
512 {VK_FORMAT_R8_UNORM,
513 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
514 {VK_FORMAT_R16_UNORM,
515 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
516
517 {VK_FORMAT_A2R10G10B10_UINT_PACK32},
518 {VK_FORMAT_A2R10G10B10_UNORM_PACK32},
519 {VK_FORMAT_A2B10G10R10_UNORM_PACK32},
520
521 // Compressed texture formats
522 {VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK},
523 {VK_FORMAT_ASTC_4x4_UNORM_BLOCK},
524
525 // TODO: YUV formats used in Android
526 // Fails on Mac
527 {VK_FORMAT_G8_B8R8_2PLANE_420_UNORM},
528 {VK_FORMAT_G8_B8R8_2PLANE_422_UNORM},
529 {VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM},
530 {VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM},
531 {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16},
532 };
533
534 std::vector<VkImageType> types = {
535 VK_IMAGE_TYPE_2D,
536 };
537
538 std::vector<VkImageTiling> tilings = {
539 VK_IMAGE_TILING_LINEAR,
540 VK_IMAGE_TILING_OPTIMAL,
541 };
542
543 std::vector<VkImageUsageFlags> usageFlags = {
544 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
545 VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
546 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
547 };
548
549 std::vector<VkEmulation::ImageSupportInfo> res;
550
551 // Currently: 17 format + create flags combo, 2 tilings, 5 usage flags -> 170 cases to check.
552 for (auto combo : combos) {
553 for (auto t : types) {
554 for (auto ti : tilings) {
555 for (auto u : usageFlags) {
556 VkEmulation::ImageSupportInfo info;
557 info.format = combo.format;
558 info.type = t;
559 info.tiling = ti;
560 info.usageFlags = u;
561 info.createFlags = combo.createFlags;
562 res.push_back(info);
563 }
564 }
565 }
566 }
567
568 // Add depth attachment cases
569 std::vector<ImageFeatureCombo> depthCombos = {
570 // Depth formats
571 {VK_FORMAT_D16_UNORM},
572 {VK_FORMAT_X8_D24_UNORM_PACK32},
573 {VK_FORMAT_D24_UNORM_S8_UINT},
574 {VK_FORMAT_D32_SFLOAT},
575 {VK_FORMAT_D32_SFLOAT_S8_UINT},
576 };
577
578 std::vector<VkImageUsageFlags> depthUsageFlags = {
579 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
580 VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
581 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
582 };
583
584 for (auto combo : depthCombos) {
585 for (auto t : types) {
586 for (auto u : depthUsageFlags) {
587 VkEmulation::ImageSupportInfo info;
588 info.format = combo.format;
589 info.type = t;
590 info.tiling = VK_IMAGE_TILING_OPTIMAL;
591 info.usageFlags = u;
592 info.createFlags = combo.createFlags;
593 res.push_back(info);
594 }
595 }
596 }
597
598 return res;
599 }
600
601 // Checks if the user enforced a specific GPU, it can be done via index or name.
602 // Otherwise try to find the best device with discrete GPU and high vulkan API level.
603 // Scoring of the devices is done by some implicit choices based on known driver
604 // quality, stability and performance issues of current GPUs.
605 // Only one Vulkan device is selected; this makes things simple for now, but we
606 // could consider utilizing multiple devices in use cases that make sense.
getSelectedGpuIndex(const std::vector<VkEmulation::DeviceSupportInfo> & deviceInfos)607 int getSelectedGpuIndex(const std::vector<VkEmulation::DeviceSupportInfo>& deviceInfos) {
608 const int physdevCount = deviceInfos.size();
609 if (physdevCount == 1) {
610 return 0;
611 }
612
613 if (!sVkEmulation->instanceSupportsGetPhysicalDeviceProperties2) {
614 // If we don't support physical device ID properties, pick the first physical device
615 WARN("Instance doesn't support '%s', picking the first physical device",
616 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
617 return 0;
618 }
619
620 const char* EnvVarSelectGpu = "ANDROID_EMU_VK_SELECT_GPU";
621 std::string enforcedGpuStr = android::base::getEnvironmentVariable(EnvVarSelectGpu);
622 int enforceGpuIndex = -1;
623 if (enforcedGpuStr.size()) {
624 INFO("%s is set to %s", EnvVarSelectGpu, enforcedGpuStr.c_str());
625
626 if (enforcedGpuStr[0] == '0') {
627 enforceGpuIndex = 0;
628 } else {
629 enforceGpuIndex = (atoi(enforcedGpuStr.c_str()));
630 if (enforceGpuIndex == 0) {
631 // Could not convert to an integer, try searching with device name
632 // Do the comparison case insensitive as vendor names don't have consistency
633 enforceGpuIndex = -1;
634 std::transform(enforcedGpuStr.begin(), enforcedGpuStr.end(), enforcedGpuStr.begin(),
635 [](unsigned char c) { return std::tolower(c); });
636
637 for (int i = 0; i < physdevCount; ++i) {
638 std::string deviceName = std::string(deviceInfos[i].physdevProps.deviceName);
639 std::transform(deviceName.begin(), deviceName.end(), deviceName.begin(),
640 [](unsigned char c) { return std::tolower(c); });
641 INFO("Physical device [%d] = %s", i, deviceName.c_str());
642
643 if (deviceName.find(enforcedGpuStr) != std::string::npos) {
644 enforceGpuIndex = i;
645 }
646 }
647 }
648 }
649
650 if (enforceGpuIndex != -1 && enforceGpuIndex >= 0 && enforceGpuIndex < deviceInfos.size()) {
651 INFO("Selecting GPU (%s) at index %d.",
652 deviceInfos[enforceGpuIndex].physdevProps.deviceName, enforceGpuIndex);
653 } else {
654 WARN("Could not select the GPU with ANDROID_EMU_VK_GPU_SELECT.");
655 enforceGpuIndex = -1;
656 }
657 }
658
659 if (enforceGpuIndex != -1) {
660 return enforceGpuIndex;
661 }
662
663 // If there are multiple devices, and none of them are enforced to use,
664 // score each device and select the best
665 int selectedGpuIndex = 0;
666 auto getDeviceScore = [](const VkEmulation::DeviceSupportInfo& deviceInfo) {
667 uint32_t deviceScore = 0;
668 if (!deviceInfo.hasGraphicsQueueFamily) {
669 // Not supporting graphics, cannot be used.
670 return deviceScore;
671 }
672
673 // Matches the ordering in VkPhysicalDeviceType
674 const uint32_t deviceTypeScoreTable[] = {
675 100, // VK_PHYSICAL_DEVICE_TYPE_OTHER = 0,
676 1000, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1,
677 2000, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2,
678 500, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3,
679 600, // VK_PHYSICAL_DEVICE_TYPE_CPU = 4,
680 };
681
682 // Prefer discrete GPUs, then integrated and then others..
683 const int deviceType = deviceInfo.physdevProps.deviceType;
684 deviceScore += deviceTypeScoreTable[deviceInfo.physdevProps.deviceType];
685
686 // Prefer higher level of Vulkan API support, restrict version numbers to
687 // common limits to ensure an always increasing scoring change
688 const uint32_t major = VK_API_VERSION_MAJOR(deviceInfo.physdevProps.apiVersion);
689 const uint32_t minor = VK_API_VERSION_MINOR(deviceInfo.physdevProps.apiVersion);
690 const uint32_t patch = VK_API_VERSION_PATCH(deviceInfo.physdevProps.apiVersion);
691 deviceScore += major * 5000 + std::min(minor, 10u) * 500 + std::min(patch, 400u);
692
693 return deviceScore;
694 };
695
696 uint32_t maxScore = 0;
697 for (int i = 0; i < physdevCount; ++i) {
698 const uint32_t score = getDeviceScore(deviceInfos[i]);
699 VERBOSE("Device selection score for '%s' = %d", deviceInfos[i].physdevProps.deviceName,
700 score);
701 if (score > maxScore) {
702 selectedGpuIndex = i;
703 maxScore = score;
704 }
705 }
706
707 return selectedGpuIndex;
708 }
709
createGlobalVkEmulation(VulkanDispatch * vk,gfxstream::host::BackendCallbacks callbacks,gfxstream::host::FeatureSet features)710 VkEmulation* createGlobalVkEmulation(VulkanDispatch* vk,
711 gfxstream::host::BackendCallbacks callbacks,
712 gfxstream::host::FeatureSet features) {
713 // Downstream branches can provide abort logic or otherwise use result without a new macro
714 #define VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(res, ...) \
715 do { \
716 (void)res; /* no-op of unused param*/ \
717 ERR(__VA_ARGS__); \
718 return nullptr; \
719 } while (0)
720
721 AutoLock lock(sVkEmulationLock);
722
723 if (sVkEmulation) return sVkEmulation;
724
725 if (!vkDispatchValid(vk)) {
726 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER, "Dispatch is invalid.");
727 }
728
729 sVkEmulation = new VkEmulation;
730 sVkEmulation->callbacks = callbacks;
731 sVkEmulation->features = features;
732
733 sVkEmulation->gvk = vk;
734 auto gvk = vk;
735
736 std::vector<const char*> getPhysicalDeviceProperties2InstanceExtNames = {
737 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
738 };
739 std::vector<const char*> externalMemoryInstanceExtNames = {
740 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
741 };
742
743 std::vector<const char*> externalSemaphoreInstanceExtNames = {
744 VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
745 };
746
747 std::vector<const char*> externalFenceInstanceExtNames = {
748 VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME,
749 };
750
751 std::vector<const char*> surfaceInstanceExtNames = {
752 VK_KHR_SURFACE_EXTENSION_NAME,
753 };
754
755 std::vector<const char*> externalMemoryDeviceExtNames = {
756 VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
757 VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
758 VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
759 #ifdef _WIN32
760 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
761 #elif defined(__QNX__)
762 VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_EXTENSION_NAME,
763 VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
764 #elif defined(__APPLE__)
765 // VK_EXT_metal_objects will be added if host MoltenVK is enabled,
766 // otherwise VK_KHR_external_memory_fd will be used
767 #else
768 VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
769 #endif
770 };
771
772 #if defined(__APPLE__)
773 std::vector<const char*> moltenVkInstanceExtNames = {
774 VK_MVK_MACOS_SURFACE_EXTENSION_NAME,
775 VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
776 };
777 std::vector<const char*> moltenVkDeviceExtNames = {
778 VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
779 VK_EXT_METAL_OBJECTS_EXTENSION_NAME,
780 VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME,
781 };
782 #endif
783
784 uint32_t instanceExtCount = 0;
785 gvk->vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr);
786 std::vector<VkExtensionProperties>& instanceExts = sVkEmulation->instanceExtensions;
787 instanceExts.resize(instanceExtCount);
788 gvk->vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, instanceExts.data());
789
790 bool getPhysicalDeviceProperties2Supported =
791 extensionsSupported(instanceExts, getPhysicalDeviceProperties2InstanceExtNames);
792 bool externalMemoryCapabilitiesSupported = getPhysicalDeviceProperties2Supported &&
793 extensionsSupported(instanceExts, externalMemoryInstanceExtNames);
794 bool externalSemaphoreCapabilitiesSupported = getPhysicalDeviceProperties2Supported &&
795 extensionsSupported(instanceExts, externalSemaphoreInstanceExtNames);
796 bool externalFenceCapabilitiesSupported = getPhysicalDeviceProperties2Supported &&
797 extensionsSupported(instanceExts, externalFenceInstanceExtNames);
798 bool surfaceSupported = extensionsSupported(instanceExts, surfaceInstanceExtNames);
799 #if defined(__APPLE__)
800 const std::string vulkanIcd = android::base::getEnvironmentVariable("ANDROID_EMU_VK_ICD");
801 const bool moltenVKEnabled = (vulkanIcd == "moltenvk");
802 const bool moltenVKSupported = extensionsSupported(instanceExts, moltenVkInstanceExtNames);
803 if (moltenVKEnabled && !moltenVKSupported) {
804 // This might happen if the user manually changes moltenvk ICD library
805 ERR("MoltenVK requested, but the required extensions are not supported.");
806 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "MoltenVK requested, but the required extensions are not supported.";
807 }
808 const bool useMoltenVK = moltenVKEnabled && moltenVKSupported;
809 #endif
810
811 VkInstanceCreateInfo instCi = {
812 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0, nullptr, 0, nullptr, 0, nullptr,
813 };
814
815 std::unordered_set<const char*> selectedInstanceExtensionNames;
816
817 const bool debugUtilsSupported =
818 extensionsSupported(instanceExts, {VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
819 const bool debugUtilsRequested = sVkEmulation->features.VulkanDebugUtils.enabled;
820 const bool debugUtilsAvailableAndRequested = debugUtilsSupported && debugUtilsRequested;
821 if (debugUtilsAvailableAndRequested) {
822 selectedInstanceExtensionNames.emplace(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
823 } else if (debugUtilsRequested) {
824 WARN("VulkanDebugUtils requested, but '%' extension is not supported.",
825 VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
826 }
827
828 if (getPhysicalDeviceProperties2Supported) {
829 for (auto extension : getPhysicalDeviceProperties2InstanceExtNames) {
830 selectedInstanceExtensionNames.emplace(extension);
831 }
832 }
833
834 if (externalSemaphoreCapabilitiesSupported) {
835 for (auto extension : externalMemoryInstanceExtNames) {
836 selectedInstanceExtensionNames.emplace(extension);
837 }
838 }
839
840 if (externalFenceCapabilitiesSupported) {
841 for (auto extension : externalSemaphoreInstanceExtNames) {
842 selectedInstanceExtensionNames.emplace(extension);
843 }
844 }
845
846 if (externalMemoryCapabilitiesSupported) {
847 for (auto extension : externalFenceInstanceExtNames) {
848 selectedInstanceExtensionNames.emplace(extension);
849 }
850 }
851
852 if (surfaceSupported) {
853 for (auto extension : surfaceInstanceExtNames) {
854 selectedInstanceExtensionNames.emplace(extension);
855 }
856 }
857
858 if (sVkEmulation->features.VulkanNativeSwapchain.enabled) {
859 for (auto extension : SwapChainStateVk::getRequiredInstanceExtensions()) {
860 selectedInstanceExtensionNames.emplace(extension);
861 }
862 }
863
864 #if defined(__APPLE__)
865 if (useMoltenVK) {
866 INFO("MoltenVK is supported, enabling Vulkan portability.");
867 instCi.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
868 for (auto extension : moltenVkInstanceExtNames) {
869 selectedInstanceExtensionNames.emplace(extension);
870 }
871 }
872 #endif
873
874 std::vector<const char*> selectedInstanceExtensionNames_(selectedInstanceExtensionNames.begin(),
875 selectedInstanceExtensionNames.end());
876 instCi.enabledExtensionCount = static_cast<uint32_t>(selectedInstanceExtensionNames_.size());
877 instCi.ppEnabledExtensionNames = selectedInstanceExtensionNames_.data();
878
879 VkApplicationInfo appInfo = {
880 VK_STRUCTURE_TYPE_APPLICATION_INFO, 0, "AEMU", 1, "AEMU", 1, VK_MAKE_VERSION(1, 0, 0),
881 };
882
883 instCi.pApplicationInfo = &appInfo;
884
885 // Can we know instance version early?
886 if (gvk->vkEnumerateInstanceVersion) {
887 VERBOSE("global loader has vkEnumerateInstanceVersion.");
888 uint32_t instanceVersion;
889 VkResult res = gvk->vkEnumerateInstanceVersion(&instanceVersion);
890 if (VK_SUCCESS == res) {
891 if (instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
892 VERBOSE("global loader has vkEnumerateInstanceVersion returning >= 1.1.");
893 appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0);
894 }
895 }
896 }
897
898 VERBOSE("Creating instance, asking for version %d.%d.%d ...",
899 VK_VERSION_MAJOR(appInfo.apiVersion), VK_VERSION_MINOR(appInfo.apiVersion),
900 VK_VERSION_PATCH(appInfo.apiVersion));
901
902 VkResult res = gvk->vkCreateInstance(&instCi, nullptr, &sVkEmulation->instance);
903
904 if (res != VK_SUCCESS) {
905 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(res, "Failed to create Vulkan instance. Error %s.",
906 string_VkResult(res));
907 }
908
909 // Create instance level dispatch.
910 sVkEmulation->ivk = new VulkanDispatch;
911 init_vulkan_dispatch_from_instance(vk, sVkEmulation->instance, sVkEmulation->ivk);
912
913 auto ivk = sVkEmulation->ivk;
914
915 if (!vulkan_dispatch_check_instance_VK_VERSION_1_0(ivk)) {
916 ERR("Warning: Vulkan 1.0 APIs missing from instance");
917 }
918
919 if (ivk->vkEnumerateInstanceVersion) {
920 uint32_t instanceVersion;
921 VkResult enumInstanceRes = ivk->vkEnumerateInstanceVersion(&instanceVersion);
922 if ((VK_SUCCESS == enumInstanceRes) && instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
923 if (!vulkan_dispatch_check_instance_VK_VERSION_1_1(ivk)) {
924 ERR("Warning: Vulkan 1.1 APIs missing from instance (1st try)");
925 }
926 }
927
928 if (appInfo.apiVersion < VK_MAKE_VERSION(1, 1, 0) &&
929 instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
930 VERBOSE("Found out that we can create a higher version instance.");
931 appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0);
932
933 gvk->vkDestroyInstance(sVkEmulation->instance, nullptr);
934
935 VkResult res = gvk->vkCreateInstance(&instCi, nullptr, &sVkEmulation->instance);
936
937 if (res != VK_SUCCESS) {
938 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(
939 res, "Failed to create Vulkan 1.1 instance. Error %s.", string_VkResult(res));
940 }
941
942 init_vulkan_dispatch_from_instance(vk, sVkEmulation->instance, sVkEmulation->ivk);
943
944 VERBOSE("Created Vulkan 1.1 instance on second try.");
945
946 if (!vulkan_dispatch_check_instance_VK_VERSION_1_1(ivk)) {
947 ERR("Warning: Vulkan 1.1 APIs missing from instance (2nd try)");
948 }
949 }
950 }
951
952 sVkEmulation->vulkanInstanceVersion = appInfo.apiVersion;
953
954 // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceIDProperties.html
955 // Provided by VK_VERSION_1_1, or VK_KHR_external_fence_capabilities, VK_KHR_external_memory_capabilities,
956 // VK_KHR_external_semaphore_capabilities
957 sVkEmulation->instanceSupportsPhysicalDeviceIDProperties =
958 externalFenceCapabilitiesSupported || externalMemoryCapabilitiesSupported ||
959 externalSemaphoreCapabilitiesSupported;
960
961 sVkEmulation->instanceSupportsGetPhysicalDeviceProperties2 = getPhysicalDeviceProperties2Supported;
962 sVkEmulation->instanceSupportsExternalMemoryCapabilities = externalMemoryCapabilitiesSupported;
963 sVkEmulation->instanceSupportsExternalSemaphoreCapabilities =
964 externalSemaphoreCapabilitiesSupported;
965 sVkEmulation->instanceSupportsExternalFenceCapabilities = externalFenceCapabilitiesSupported;
966 sVkEmulation->instanceSupportsSurface = surfaceSupported;
967 #if defined(__APPLE__)
968 sVkEmulation->instanceSupportsMoltenVK = useMoltenVK;
969 #endif
970
971 if (sVkEmulation->instanceSupportsGetPhysicalDeviceProperties2) {
972 sVkEmulation->getImageFormatProperties2Func = vk_util::getVkInstanceProcAddrWithFallback<
973 vk_util::vk_fn_info::GetPhysicalDeviceImageFormatProperties2>(
974 {ivk->vkGetInstanceProcAddr, vk->vkGetInstanceProcAddr}, sVkEmulation->instance);
975 sVkEmulation->getPhysicalDeviceProperties2Func = vk_util::getVkInstanceProcAddrWithFallback<
976 vk_util::vk_fn_info::GetPhysicalDeviceProperties2>(
977 {ivk->vkGetInstanceProcAddr, vk->vkGetInstanceProcAddr}, sVkEmulation->instance);
978 sVkEmulation->getPhysicalDeviceFeatures2Func = vk_util::getVkInstanceProcAddrWithFallback<
979 vk_util::vk_fn_info::GetPhysicalDeviceFeatures2>(
980 {ivk->vkGetInstanceProcAddr, vk->vkGetInstanceProcAddr}, sVkEmulation->instance);
981
982 if (!sVkEmulation->getPhysicalDeviceProperties2Func) {
983 ERR("Warning: device claims to support ID properties "
984 "but vkGetPhysicalDeviceProperties2 could not be found");
985 }
986 }
987
988 #if defined(__APPLE__)
989 if (sVkEmulation->instanceSupportsMoltenVK) {
990 // Enable some specific extensions on MacOS when moltenVK is used.
991 externalMemoryDeviceExtNames.push_back(VK_EXT_METAL_OBJECTS_EXTENSION_NAME);
992 externalMemoryDeviceExtNames.push_back(VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME);
993 } else {
994 // When MoltenVK is not used(e.g. SwiftShader), use memory fd extension for external memory.
995 externalMemoryDeviceExtNames.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
996 }
997 #endif
998
999 uint32_t physdevCount = 0;
1000 ivk->vkEnumeratePhysicalDevices(sVkEmulation->instance, &physdevCount, nullptr);
1001 std::vector<VkPhysicalDevice> physdevs(physdevCount);
1002 ivk->vkEnumeratePhysicalDevices(sVkEmulation->instance, &physdevCount, physdevs.data());
1003
1004 VERBOSE("Found %d Vulkan physical devices.", physdevCount);
1005
1006 if (physdevCount == 0) {
1007 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER, "No physical devices available.");
1008 }
1009
1010 std::vector<VkEmulation::DeviceSupportInfo> deviceInfos(physdevCount);
1011
1012 for (int i = 0; i < physdevCount; ++i) {
1013 ivk->vkGetPhysicalDeviceProperties(physdevs[i], &deviceInfos[i].physdevProps);
1014
1015 VERBOSE("Considering Vulkan physical device %d : %s", i,
1016 deviceInfos[i].physdevProps.deviceName);
1017
1018 // It's easier to figure out the staging buffer along with
1019 // external memories if we have the memory properties on hand.
1020 ivk->vkGetPhysicalDeviceMemoryProperties(physdevs[i], &deviceInfos[i].memProps);
1021
1022 uint32_t deviceExtensionCount = 0;
1023 ivk->vkEnumerateDeviceExtensionProperties(physdevs[i], nullptr, &deviceExtensionCount,
1024 nullptr);
1025 std::vector<VkExtensionProperties>& deviceExts = deviceInfos[i].extensions;
1026 deviceExts.resize(deviceExtensionCount);
1027 ivk->vkEnumerateDeviceExtensionProperties(physdevs[i], nullptr, &deviceExtensionCount,
1028 deviceExts.data());
1029
1030 deviceInfos[i].supportsExternalMemoryImport = false;
1031 deviceInfos[i].supportsExternalMemoryExport = false;
1032 deviceInfos[i].glInteropSupported = 0; // set later
1033
1034 #if defined(__APPLE__)
1035 if (useMoltenVK && !extensionsSupported(deviceExts, moltenVkDeviceExtNames)) {
1036 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(
1037 ABORT_REASON_OTHER,
1038 "MoltenVK enabled but necessary device extensions are not supported.");
1039 }
1040 #endif
1041
1042 if (sVkEmulation->instanceSupportsExternalMemoryCapabilities) {
1043 deviceInfos[i].supportsExternalMemoryExport =
1044 deviceInfos[i].supportsExternalMemoryImport =
1045 extensionsSupported(deviceExts, externalMemoryDeviceExtNames);
1046 #if defined(__QNX__)
1047 // External memory export not supported on QNX
1048 deviceInfos[i].supportsExternalMemoryExport = false;
1049 #endif
1050 }
1051
1052 if (sVkEmulation->instanceSupportsGetPhysicalDeviceProperties2) {
1053 deviceInfos[i].supportsDriverProperties =
1054 extensionsSupported(deviceExts, {VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME}) ||
1055 (deviceInfos[i].physdevProps.apiVersion >= VK_API_VERSION_1_2);
1056 deviceInfos[i].supportsExternalMemoryHostProps =
1057 extensionsSupported(deviceExts, {VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME});
1058
1059 VkPhysicalDeviceProperties2 deviceProps = {
1060 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
1061 };
1062 auto devicePropsChain = vk_make_chain_iterator(&deviceProps);
1063
1064 VkPhysicalDeviceIDProperties idProps = {
1065 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR,
1066 };
1067 if (sVkEmulation->instanceSupportsPhysicalDeviceIDProperties) {
1068 vk_append_struct(&devicePropsChain, &idProps);
1069 }
1070
1071 VkPhysicalDeviceDriverPropertiesKHR driverProps = {
1072 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR,
1073 };
1074 if (deviceInfos[i].supportsDriverProperties) {
1075 vk_append_struct(&devicePropsChain, &driverProps);
1076 }
1077
1078 VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemoryHostProps = {
1079 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT,
1080 };
1081 if(deviceInfos[i].supportsExternalMemoryHostProps) {
1082 vk_append_struct(&devicePropsChain, &externalMemoryHostProps);
1083 }
1084 sVkEmulation->getPhysicalDeviceProperties2Func(physdevs[i], &deviceProps);
1085 deviceInfos[i].idProps = vk_make_orphan_copy(idProps);
1086 deviceInfos[i].externalMemoryHostProps = vk_make_orphan_copy(externalMemoryHostProps);
1087
1088 std::stringstream driverVendorBuilder;
1089 driverVendorBuilder << "Vendor " << std::hex << std::setfill('0') << std::showbase
1090 << deviceInfos[i].physdevProps.vendorID;
1091
1092 std::string decodedDriverVersion = decodeDriverVersion(
1093 deviceInfos[i].physdevProps.vendorID, deviceInfos[i].physdevProps.driverVersion);
1094
1095 std::stringstream driverVersionBuilder;
1096 driverVersionBuilder << "Driver Version " << std::hex << std::setfill('0')
1097 << std::showbase << deviceInfos[i].physdevProps.driverVersion
1098 << " Decoded As " << decodedDriverVersion;
1099
1100 std::string driverVendor = driverVendorBuilder.str();
1101 std::string driverVersion = driverVersionBuilder.str();
1102 if (deviceInfos[i].supportsDriverProperties && driverProps.driverID) {
1103 driverVendor = std::string{driverProps.driverName} + " (" + driverVendor + ")";
1104 driverVersion = std::string{driverProps.driverInfo} + " (" +
1105 string_VkDriverId(driverProps.driverID) + " " + driverVersion + ")";
1106 }
1107
1108 deviceInfos[i].driverVendor = driverVendor;
1109 deviceInfos[i].driverVersion = driverVersion;
1110 }
1111
1112 bool dmaBufBlockList = deviceInfos[i].driverVendor == "NVIDIA (Vendor 0x10de)";
1113 deviceInfos[i].supportsDmaBuf =
1114 extensionsSupported(deviceExts, {VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME}) &&
1115 !dmaBufBlockList;
1116
1117 deviceInfos[i].hasSamplerYcbcrConversionExtension =
1118 extensionsSupported(deviceExts, {VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME});
1119
1120 deviceInfos[i].hasNvidiaDeviceDiagnosticCheckpointsExtension =
1121 extensionsSupported(deviceExts, {VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME});
1122
1123 if (sVkEmulation->getPhysicalDeviceFeatures2Func) {
1124 VkPhysicalDeviceFeatures2 features2 = {
1125 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
1126 };
1127 auto features2Chain = vk_make_chain_iterator(&features2);
1128
1129 VkPhysicalDeviceSamplerYcbcrConversionFeatures samplerYcbcrConversionFeatures = {
1130 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
1131 };
1132 vk_append_struct(&features2Chain, &samplerYcbcrConversionFeatures);
1133
1134 #if defined(__QNX__)
1135 VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX extMemScreenBufferFeatures = {
1136 .sType =
1137 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX,
1138 };
1139 vk_append_struct(&features2Chain, &extMemScreenBufferFeatures);
1140 #endif
1141
1142 VkPhysicalDeviceDiagnosticsConfigFeaturesNV deviceDiagnosticsConfigFeatures = {
1143 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV,
1144 .diagnosticsConfig = VK_FALSE,
1145 };
1146 if (deviceInfos[i].hasNvidiaDeviceDiagnosticCheckpointsExtension) {
1147 vk_append_struct(&features2Chain, &deviceDiagnosticsConfigFeatures);
1148 }
1149
1150 VkPhysicalDevicePrivateDataFeatures privateDataFeatures = {
1151 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES,
1152 .privateData = VK_FALSE};
1153 if (extensionsSupported(deviceExts, {VK_EXT_PRIVATE_DATA_EXTENSION_NAME})) {
1154 vk_append_struct(&features2Chain, &privateDataFeatures);
1155 }
1156
1157 sVkEmulation->getPhysicalDeviceFeatures2Func(physdevs[i], &features2);
1158
1159 deviceInfos[i].supportsSamplerYcbcrConversion =
1160 samplerYcbcrConversionFeatures.samplerYcbcrConversion == VK_TRUE;
1161
1162 deviceInfos[i].supportsNvidiaDeviceDiagnosticCheckpoints =
1163 deviceDiagnosticsConfigFeatures.diagnosticsConfig == VK_TRUE;
1164
1165 deviceInfos[i].supportsPrivateData = (privateDataFeatures.privateData == VK_TRUE);
1166
1167 #if defined(__QNX__)
1168 deviceInfos[i].supportsExternalMemoryImport =
1169 extMemScreenBufferFeatures.screenBufferImport == VK_TRUE;
1170 } else {
1171 deviceInfos[i].supportsExternalMemoryImport = false;
1172 #endif
1173 }
1174
1175 uint32_t queueFamilyCount = 0;
1176 ivk->vkGetPhysicalDeviceQueueFamilyProperties(physdevs[i], &queueFamilyCount, nullptr);
1177 std::vector<VkQueueFamilyProperties> queueFamilyProps(queueFamilyCount);
1178 ivk->vkGetPhysicalDeviceQueueFamilyProperties(physdevs[i], &queueFamilyCount,
1179 queueFamilyProps.data());
1180
1181 for (uint32_t j = 0; j < queueFamilyCount; ++j) {
1182 auto count = queueFamilyProps[j].queueCount;
1183 auto flags = queueFamilyProps[j].queueFlags;
1184
1185 bool hasGraphicsQueueFamily = (count > 0 && (flags & VK_QUEUE_GRAPHICS_BIT));
1186 bool hasComputeQueueFamily = (count > 0 && (flags & VK_QUEUE_COMPUTE_BIT));
1187
1188 deviceInfos[i].hasGraphicsQueueFamily =
1189 deviceInfos[i].hasGraphicsQueueFamily || hasGraphicsQueueFamily;
1190
1191 deviceInfos[i].hasComputeQueueFamily =
1192 deviceInfos[i].hasComputeQueueFamily || hasComputeQueueFamily;
1193
1194 if (hasGraphicsQueueFamily) {
1195 deviceInfos[i].graphicsQueueFamilyIndices.push_back(j);
1196 VERBOSE("Graphics queue family index: %d", j);
1197 }
1198
1199 if (hasComputeQueueFamily) {
1200 deviceInfos[i].computeQueueFamilyIndices.push_back(j);
1201 VERBOSE("Compute queue family index: %d", j);
1202 }
1203 }
1204 }
1205
1206 // When there are multiple physical devices, find the best one or enable selecting
1207 // the one enforced by environment variable setting.
1208 int selectedGpuIndex = getSelectedGpuIndex(deviceInfos);
1209
1210 sVkEmulation->physdev = physdevs[selectedGpuIndex];
1211 sVkEmulation->physicalDeviceIndex = selectedGpuIndex;
1212 sVkEmulation->deviceInfo = deviceInfos[selectedGpuIndex];
1213 // Postcondition: sVkEmulation has valid device support info
1214
1215 // Collect image support info of the selected device
1216 sVkEmulation->imageSupportInfo = getBasicImageSupportList();
1217 for (size_t i = 0; i < sVkEmulation->imageSupportInfo.size(); ++i) {
1218 getImageFormatExternalMemorySupportInfo(ivk, sVkEmulation->physdev,
1219 &sVkEmulation->imageSupportInfo[i]);
1220 }
1221
1222 if (!sVkEmulation->deviceInfo.hasGraphicsQueueFamily) {
1223 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1224 "No Vulkan devices with graphics queues found.");
1225 }
1226
1227 auto deviceVersion = sVkEmulation->deviceInfo.physdevProps.apiVersion;
1228 INFO("Selecting Vulkan device: %s, Version: %d.%d.%d",
1229 sVkEmulation->deviceInfo.physdevProps.deviceName, VK_VERSION_MAJOR(deviceVersion),
1230 VK_VERSION_MINOR(deviceVersion), VK_VERSION_PATCH(deviceVersion));
1231
1232 VERBOSE(
1233 "deviceInfo: \n"
1234 "hasGraphicsQueueFamily = %d\n"
1235 "hasComputeQueueFamily = %d\n"
1236 "supportsExternalMemoryImport = %d\n"
1237 "supportsExternalMemoryExport = %d\n"
1238 "supportsDriverProperties = %d\n"
1239 "hasSamplerYcbcrConversionExtension = %d\n"
1240 "supportsSamplerYcbcrConversion = %d\n"
1241 "glInteropSupported = %d",
1242 sVkEmulation->deviceInfo.hasGraphicsQueueFamily,
1243 sVkEmulation->deviceInfo.hasComputeQueueFamily,
1244 sVkEmulation->deviceInfo.supportsExternalMemoryImport,
1245 sVkEmulation->deviceInfo.supportsExternalMemoryExport,
1246 sVkEmulation->deviceInfo.supportsDriverProperties,
1247 sVkEmulation->deviceInfo.hasSamplerYcbcrConversionExtension,
1248 sVkEmulation->deviceInfo.supportsSamplerYcbcrConversion,
1249 sVkEmulation->deviceInfo.glInteropSupported);
1250
1251 float priority = 1.0f;
1252 VkDeviceQueueCreateInfo dqCi = {
1253 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO,
1254 0,
1255 0,
1256 sVkEmulation->deviceInfo.graphicsQueueFamilyIndices[0],
1257 1,
1258 &priority,
1259 };
1260
1261 std::unordered_set<const char*> selectedDeviceExtensionNames_;
1262
1263 if (sVkEmulation->deviceInfo.supportsExternalMemoryImport ||
1264 sVkEmulation->deviceInfo.supportsExternalMemoryExport) {
1265 for (auto extension : externalMemoryDeviceExtNames) {
1266 selectedDeviceExtensionNames_.emplace(extension);
1267 }
1268 }
1269
1270 #if defined(__linux__)
1271 if (sVkEmulation->deviceInfo.supportsDmaBuf) {
1272 selectedDeviceExtensionNames_.emplace(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME);
1273 }
1274 #endif
1275
1276 // We need to always enable swapchain extensions to be able to use this device
1277 // to do VK_IMAGE_LAYOUT_PRESENT_SRC_KHR transition operations done
1278 // in releaseColorBufferForGuestUse for the apps using Vulkan swapchain
1279 selectedDeviceExtensionNames_.emplace(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
1280
1281 if (sVkEmulation->features.VulkanNativeSwapchain.enabled) {
1282 for (auto extension : SwapChainStateVk::getRequiredDeviceExtensions()) {
1283 selectedDeviceExtensionNames_.emplace(extension);
1284 }
1285 }
1286
1287 if (sVkEmulation->deviceInfo.hasSamplerYcbcrConversionExtension) {
1288 selectedDeviceExtensionNames_.emplace(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
1289 }
1290
1291 #if defined(__APPLE__)
1292 if (useMoltenVK) {
1293 for (auto extension : moltenVkDeviceExtNames) {
1294 selectedDeviceExtensionNames_.emplace(extension);
1295 }
1296 }
1297 #endif
1298
1299 std::vector<const char*> selectedDeviceExtensionNames(selectedDeviceExtensionNames_.begin(),
1300 selectedDeviceExtensionNames_.end());
1301
1302 VkDeviceCreateInfo dCi = {};
1303 dCi.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
1304 dCi.queueCreateInfoCount = 1;
1305 dCi.pQueueCreateInfos = &dqCi;
1306 dCi.enabledExtensionCount = static_cast<uint32_t>(selectedDeviceExtensionNames.size());
1307 dCi.ppEnabledExtensionNames = selectedDeviceExtensionNames.data();
1308
1309 // Setting up VkDeviceCreateInfo::pNext
1310 auto deviceCiChain = vk_make_chain_iterator(&dCi);
1311
1312 VkPhysicalDeviceFeatures2 physicalDeviceFeatures = {
1313 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
1314 };
1315 vk_append_struct(&deviceCiChain, &physicalDeviceFeatures);
1316
1317 std::unique_ptr<VkPhysicalDeviceSamplerYcbcrConversionFeatures> samplerYcbcrConversionFeatures =
1318 nullptr;
1319 if (sVkEmulation->deviceInfo.supportsSamplerYcbcrConversion) {
1320 samplerYcbcrConversionFeatures =
1321 std::make_unique<VkPhysicalDeviceSamplerYcbcrConversionFeatures>(
1322 VkPhysicalDeviceSamplerYcbcrConversionFeatures{
1323 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
1324 .samplerYcbcrConversion = VK_TRUE,
1325 });
1326 vk_append_struct(&deviceCiChain, samplerYcbcrConversionFeatures.get());
1327 }
1328
1329 #if defined(__QNX__)
1330 std::unique_ptr<VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX>
1331 extMemScreenBufferFeaturesQNX = nullptr;
1332 if (sVkEmulation->deviceInfo.supportsExternalMemoryImport) {
1333 extMemScreenBufferFeaturesQNX = std::make_unique<
1334 VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX>(
1335 VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX{
1336 .sType =
1337 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX,
1338 .screenBufferImport = VK_TRUE,
1339 });
1340 vk_append_struct(&deviceCiChain, extMemScreenBufferFeaturesQNX.get());
1341 }
1342 #endif
1343
1344 const bool commandBufferCheckpointsSupported =
1345 sVkEmulation->deviceInfo.supportsNvidiaDeviceDiagnosticCheckpoints;
1346 const bool commandBufferCheckpointsRequested =
1347 sVkEmulation->features.VulkanCommandBufferCheckpoints.enabled;
1348 const bool commandBufferCheckpointsSupportedAndRequested =
1349 commandBufferCheckpointsSupported && commandBufferCheckpointsRequested;
1350 VkPhysicalDeviceDiagnosticsConfigFeaturesNV deviceDiagnosticsConfigFeatures = {
1351 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV,
1352 .diagnosticsConfig = VK_TRUE,
1353 };
1354 if (commandBufferCheckpointsSupportedAndRequested) {
1355 INFO("Enabling command buffer checkpoints with VK_NV_device_diagnostic_checkpoints.");
1356 vk_append_struct(&deviceCiChain, &deviceDiagnosticsConfigFeatures);
1357 } else if (commandBufferCheckpointsRequested) {
1358 WARN(
1359 "VulkanCommandBufferCheckpoints was requested but the "
1360 "VK_NV_device_diagnostic_checkpoints extension is not supported.");
1361 }
1362
1363 ivk->vkCreateDevice(sVkEmulation->physdev, &dCi, nullptr, &sVkEmulation->device);
1364
1365 if (res != VK_SUCCESS) {
1366 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(res, "Failed to create Vulkan device. Error %s.",
1367 string_VkResult(res));
1368 }
1369
1370 // device created; populate dispatch table
1371 sVkEmulation->dvk = new VulkanDispatch;
1372 init_vulkan_dispatch_from_device(ivk, sVkEmulation->device, sVkEmulation->dvk);
1373
1374 auto dvk = sVkEmulation->dvk;
1375
1376 // Check if the dispatch table has everything 1.1 related
1377 if (!vulkan_dispatch_check_device_VK_VERSION_1_0(dvk)) {
1378 ERR("Warning: Vulkan 1.0 APIs missing from device.");
1379 }
1380 if (deviceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
1381 if (!vulkan_dispatch_check_device_VK_VERSION_1_1(dvk)) {
1382 ERR("Warning: Vulkan 1.1 APIs missing from device");
1383 }
1384 }
1385
1386 if (sVkEmulation->deviceInfo.supportsExternalMemoryImport) {
1387 sVkEmulation->deviceInfo.getImageMemoryRequirements2Func =
1388 reinterpret_cast<PFN_vkGetImageMemoryRequirements2KHR>(
1389 dvk->vkGetDeviceProcAddr(sVkEmulation->device, "vkGetImageMemoryRequirements2KHR"));
1390 if (!sVkEmulation->deviceInfo.getImageMemoryRequirements2Func) {
1391 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1392 "Cannot find vkGetImageMemoryRequirements2KHR.");
1393 }
1394 sVkEmulation->deviceInfo.getBufferMemoryRequirements2Func =
1395 reinterpret_cast<PFN_vkGetBufferMemoryRequirements2KHR>(dvk->vkGetDeviceProcAddr(
1396 sVkEmulation->device, "vkGetBufferMemoryRequirements2KHR"));
1397 if (!sVkEmulation->deviceInfo.getBufferMemoryRequirements2Func) {
1398 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1399 "Cannot find vkGetBufferMemoryRequirements2KHR");
1400 }
1401 }
1402 if (sVkEmulation->deviceInfo.supportsExternalMemoryExport) {
1403 #ifdef _WIN32
1404 // Use vkGetMemoryWin32HandleKHR
1405 sVkEmulation->deviceInfo.getMemoryHandleFunc =
1406 reinterpret_cast<PFN_vkGetMemoryWin32HandleKHR>(
1407 dvk->vkGetDeviceProcAddr(sVkEmulation->device, "vkGetMemoryWin32HandleKHR"));
1408 if (!sVkEmulation->deviceInfo.getMemoryHandleFunc) {
1409 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1410 "Cannot find vkGetMemoryWin32HandleKHR");
1411 }
1412 #else
1413 if (sVkEmulation->instanceSupportsMoltenVK) {
1414 // We'll use vkGetMemoryMetalHandleEXT, no need to save into getMemoryHandleFunc
1415 sVkEmulation->deviceInfo.getMemoryHandleFunc = nullptr;
1416 if (!dvk->vkGetDeviceProcAddr(sVkEmulation->device, "vkGetMemoryMetalHandleEXT")) {
1417 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1418 "Cannot find vkGetMemoryMetalHandleEXT");
1419 }
1420 } else {
1421 // Use vkGetMemoryFdKHR
1422 sVkEmulation->deviceInfo.getMemoryHandleFunc = reinterpret_cast<PFN_vkGetMemoryFdKHR>(
1423 dvk->vkGetDeviceProcAddr(sVkEmulation->device, "vkGetMemoryFdKHR"));
1424 if (!sVkEmulation->deviceInfo.getMemoryHandleFunc) {
1425 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1426 "Cannot find vkGetMemoryFdKHR");
1427 }
1428 }
1429 #endif
1430 }
1431
1432 VERBOSE("Vulkan logical device created and extension functions obtained.");
1433
1434 sVkEmulation->queueLock = std::make_shared<android::base::Lock>();
1435 {
1436 android::base::AutoLock lock(*sVkEmulation->queueLock);
1437 dvk->vkGetDeviceQueue(sVkEmulation->device,
1438 sVkEmulation->deviceInfo.graphicsQueueFamilyIndices[0], 0,
1439 &sVkEmulation->queue);
1440 }
1441
1442 sVkEmulation->queueFamilyIndex = sVkEmulation->deviceInfo.graphicsQueueFamilyIndices[0];
1443
1444 VERBOSE("Vulkan device queue obtained.");
1445
1446 VkCommandPoolCreateInfo poolCi = {
1447 VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1448 0,
1449 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1450 sVkEmulation->queueFamilyIndex,
1451 };
1452
1453 VkResult poolCreateRes = dvk->vkCreateCommandPool(sVkEmulation->device, &poolCi, nullptr,
1454 &sVkEmulation->commandPool);
1455
1456 if (poolCreateRes != VK_SUCCESS) {
1457 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(poolCreateRes,
1458 "Failed to create command pool. Error: %s.",
1459 string_VkResult(poolCreateRes));
1460 }
1461
1462 VkCommandBufferAllocateInfo cbAi = {
1463 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1464 0,
1465 sVkEmulation->commandPool,
1466 VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1467 1,
1468 };
1469
1470 VkResult cbAllocRes =
1471 dvk->vkAllocateCommandBuffers(sVkEmulation->device, &cbAi, &sVkEmulation->commandBuffer);
1472
1473 if (cbAllocRes != VK_SUCCESS) {
1474 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(cbAllocRes,
1475 "Failed to allocate command buffer. Error: %s.",
1476 string_VkResult(cbAllocRes));
1477 }
1478
1479 VkFenceCreateInfo fenceCi = {
1480 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1481 0,
1482 0,
1483 };
1484
1485 VkResult fenceCreateRes = dvk->vkCreateFence(sVkEmulation->device, &fenceCi, nullptr,
1486 &sVkEmulation->commandBufferFence);
1487
1488 if (fenceCreateRes != VK_SUCCESS) {
1489 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(
1490 fenceCreateRes, "Failed to create fence for command buffer. Error: %s.",
1491 string_VkResult(fenceCreateRes));
1492 }
1493
1494 // At this point, the global emulation state's logical device can alloc
1495 // memory and send commands. However, it can't really do much yet to
1496 // communicate the results without the staging buffer. Set that up here.
1497 // Note that the staging buffer is meant to use external memory, with a
1498 // non-external-memory fallback.
1499
1500 VkBufferCreateInfo bufCi = {
1501 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1502 0,
1503 0,
1504 sVkEmulation->staging.size,
1505 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
1506 VK_SHARING_MODE_EXCLUSIVE,
1507 0,
1508 nullptr,
1509 };
1510
1511 VkResult bufCreateRes =
1512 dvk->vkCreateBuffer(sVkEmulation->device, &bufCi, nullptr, &sVkEmulation->staging.buffer);
1513
1514 if (bufCreateRes != VK_SUCCESS) {
1515 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(bufCreateRes,
1516 "Failed to create staging buffer index. Error: %s.",
1517 string_VkResult(bufCreateRes));
1518 }
1519
1520 VkMemoryRequirements memReqs;
1521 dvk->vkGetBufferMemoryRequirements(sVkEmulation->device, sVkEmulation->staging.buffer,
1522 &memReqs);
1523
1524 sVkEmulation->staging.memory.size = memReqs.size;
1525
1526 bool gotStagingTypeIndex =
1527 getStagingMemoryTypeIndex(dvk, sVkEmulation->device, &sVkEmulation->deviceInfo.memProps,
1528 &sVkEmulation->staging.memory.typeIndex);
1529
1530 if (!gotStagingTypeIndex) {
1531 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1532 "Failed to determine staging memory type index.");
1533 }
1534
1535 if (!((1 << sVkEmulation->staging.memory.typeIndex) & memReqs.memoryTypeBits)) {
1536 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(
1537 ABORT_REASON_OTHER,
1538 "Failed: Inconsistent determination of memory type index for staging buffer");
1539 }
1540
1541 if (!allocExternalMemory(dvk, &sVkEmulation->staging.memory, false /* not external */,
1542 kNullopt /* deviceAlignment */)) {
1543 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1544 "Failed to allocate memory for staging buffer.");
1545 }
1546
1547 VkResult stagingBufferBindRes = dvk->vkBindBufferMemory(
1548 sVkEmulation->device, sVkEmulation->staging.buffer, sVkEmulation->staging.memory.memory, 0);
1549
1550 if (stagingBufferBindRes != VK_SUCCESS) {
1551 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(stagingBufferBindRes,
1552 "Failed to bind memory for staging buffer. Error %s.",
1553 string_VkResult(stagingBufferBindRes));
1554 }
1555
1556 if (debugUtilsAvailableAndRequested) {
1557 sVkEmulation->debugUtilsAvailableAndRequested = true;
1558 sVkEmulation->debugUtilsHelper =
1559 DebugUtilsHelper::withUtilsEnabled(sVkEmulation->device, sVkEmulation->ivk);
1560
1561 sVkEmulation->debugUtilsHelper.addDebugLabel(sVkEmulation->instance, "AEMU_Instance");
1562 sVkEmulation->debugUtilsHelper.addDebugLabel(sVkEmulation->device, "AEMU_Device");
1563 sVkEmulation->debugUtilsHelper.addDebugLabel(sVkEmulation->staging.buffer,
1564 "AEMU_StagingBuffer");
1565 sVkEmulation->debugUtilsHelper.addDebugLabel(sVkEmulation->commandBuffer,
1566 "AEMU_CommandBuffer");
1567 }
1568
1569 if (commandBufferCheckpointsSupportedAndRequested) {
1570 sVkEmulation->commandBufferCheckpointsSupportedAndRequested = true;
1571 sVkEmulation->deviceLostHelper.enableWithNvidiaDeviceDiagnosticCheckpoints();
1572 }
1573
1574 VERBOSE("Vulkan global emulation state successfully initialized.");
1575 sVkEmulation->live = true;
1576
1577 sVkEmulation->transferQueueCommandBufferPool.resize(0);
1578
1579 return sVkEmulation;
1580 }
1581
1582 std::optional<VkEmulation::RepresentativeColorBufferMemoryTypeInfo>
1583 findRepresentativeColorBufferMemoryTypeIndexLocked();
1584
initVkEmulationFeatures(std::unique_ptr<VkEmulationFeatures> features)1585 void initVkEmulationFeatures(std::unique_ptr<VkEmulationFeatures> features) {
1586 if (!sVkEmulation || !sVkEmulation->live) {
1587 ERR("VkEmulation is either not initialized or destroyed.");
1588 return;
1589 }
1590
1591 AutoLock lock(sVkEmulationLock);
1592 INFO("Initializing VkEmulation features:");
1593 INFO(" glInteropSupported: %s", features->glInteropSupported ? "true" : "false");
1594 INFO(" useDeferredCommands: %s", features->deferredCommands ? "true" : "false");
1595 INFO(" createResourceWithRequirements: %s",
1596 features->createResourceWithRequirements ? "true" : "false");
1597 INFO(" useVulkanComposition: %s", features->useVulkanComposition ? "true" : "false");
1598 INFO(" useVulkanNativeSwapchain: %s", features->useVulkanNativeSwapchain ? "true" : "false");
1599 INFO(" enable guestRenderDoc: %s", features->guestRenderDoc ? "true" : "false");
1600 INFO(" ASTC LDR emulation mode: %d", features->astcLdrEmulationMode);
1601 INFO(" enable ETC2 emulation: %s", features->enableEtc2Emulation ? "true" : "false");
1602 INFO(" enable Ycbcr emulation: %s", features->enableYcbcrEmulation ? "true" : "false");
1603 INFO(" guestVulkanOnly: %s", features->guestVulkanOnly ? "true" : "false");
1604 INFO(" useDedicatedAllocations: %s", features->useDedicatedAllocations ? "true" : "false");
1605 sVkEmulation->deviceInfo.glInteropSupported = features->glInteropSupported;
1606 sVkEmulation->useDeferredCommands = features->deferredCommands;
1607 sVkEmulation->useCreateResourcesWithRequirements = features->createResourceWithRequirements;
1608 sVkEmulation->guestRenderDoc = std::move(features->guestRenderDoc);
1609 sVkEmulation->astcLdrEmulationMode = features->astcLdrEmulationMode;
1610 sVkEmulation->enableEtc2Emulation = features->enableEtc2Emulation;
1611 sVkEmulation->enableYcbcrEmulation = features->enableYcbcrEmulation;
1612 sVkEmulation->guestVulkanOnly = features->guestVulkanOnly;
1613 sVkEmulation->useDedicatedAllocations = features->useDedicatedAllocations;
1614
1615 if (features->useVulkanComposition) {
1616 if (sVkEmulation->compositorVk) {
1617 ERR("Reset VkEmulation::compositorVk.");
1618 }
1619 sVkEmulation->compositorVk =
1620 CompositorVk::create(*sVkEmulation->ivk, sVkEmulation->device, sVkEmulation->physdev,
1621 sVkEmulation->queue, sVkEmulation->queueLock,
1622 sVkEmulation->queueFamilyIndex, 3, sVkEmulation->debugUtilsHelper);
1623 }
1624
1625 if (features->useVulkanNativeSwapchain) {
1626 if (sVkEmulation->displayVk) {
1627 ERR("Reset VkEmulation::displayVk.");
1628 }
1629 sVkEmulation->displayVk = std::make_unique<DisplayVk>(
1630 *sVkEmulation->ivk, sVkEmulation->physdev, sVkEmulation->queueFamilyIndex,
1631 sVkEmulation->queueFamilyIndex, sVkEmulation->device, sVkEmulation->queue,
1632 sVkEmulation->queueLock, sVkEmulation->queue, sVkEmulation->queueLock);
1633 }
1634
1635 sVkEmulation->representativeColorBufferMemoryTypeInfo =
1636 findRepresentativeColorBufferMemoryTypeIndexLocked();
1637 if (sVkEmulation->representativeColorBufferMemoryTypeInfo) {
1638 VERBOSE(
1639 "Representative ColorBuffer memory type using host memory type index %d "
1640 "and guest memory type index :%d",
1641 sVkEmulation->representativeColorBufferMemoryTypeInfo->hostMemoryTypeIndex,
1642 sVkEmulation->representativeColorBufferMemoryTypeInfo->guestMemoryTypeIndex);
1643 } else {
1644 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
1645 << "Failed to find memory type for ColorBuffers.";
1646 }
1647 }
1648
getGlobalVkEmulation()1649 VkEmulation* getGlobalVkEmulation() {
1650 if (sVkEmulation && !sVkEmulation->live) return nullptr;
1651 return sVkEmulation;
1652 }
1653
teardownGlobalVkEmulation()1654 void teardownGlobalVkEmulation() {
1655 if (!sVkEmulation) return;
1656
1657 // Don't try to tear down something that did not set up completely; too risky
1658 if (!sVkEmulation->live) return;
1659
1660 sVkEmulation->compositorVk.reset();
1661 sVkEmulation->displayVk.reset();
1662
1663 freeExternalMemoryLocked(sVkEmulation->dvk, &sVkEmulation->staging.memory);
1664
1665 sVkEmulation->dvk->vkDestroyBuffer(sVkEmulation->device, sVkEmulation->staging.buffer, nullptr);
1666
1667 sVkEmulation->dvk->vkDestroyFence(sVkEmulation->device, sVkEmulation->commandBufferFence,
1668 nullptr);
1669
1670 sVkEmulation->dvk->vkFreeCommandBuffers(sVkEmulation->device, sVkEmulation->commandPool, 1,
1671 &sVkEmulation->commandBuffer);
1672
1673 sVkEmulation->dvk->vkDestroyCommandPool(sVkEmulation->device, sVkEmulation->commandPool,
1674 nullptr);
1675
1676 sVkEmulation->ivk->vkDestroyDevice(sVkEmulation->device, nullptr);
1677 sVkEmulation->gvk->vkDestroyInstance(sVkEmulation->instance, nullptr);
1678
1679 VkDecoderGlobalState::reset();
1680
1681 sVkEmulation->live = false;
1682 delete sVkEmulation;
1683 sVkEmulation = nullptr;
1684 }
1685
onVkDeviceLost()1686 void onVkDeviceLost() { VkDecoderGlobalState::get()->on_DeviceLost(); }
1687
createDisplaySurface(FBNativeWindowType window,uint32_t width,uint32_t height)1688 std::unique_ptr<gfxstream::DisplaySurface> createDisplaySurface(FBNativeWindowType window,
1689 uint32_t width, uint32_t height) {
1690 if (!sVkEmulation || !sVkEmulation->live) {
1691 return nullptr;
1692 }
1693
1694 auto surfaceVk = DisplaySurfaceVk::create(*sVkEmulation->ivk, sVkEmulation->instance, window);
1695 if (!surfaceVk) {
1696 ERR("Failed to create DisplaySurfaceVk.");
1697 return nullptr;
1698 }
1699
1700 return std::make_unique<gfxstream::DisplaySurface>(width, height, std::move(surfaceVk));
1701 }
1702
1703 #ifdef __APPLE__
getMtlResourceFromVkDeviceMemory(VulkanDispatch * vk,VkDeviceMemory memory)1704 static MTLResource_id getMtlResourceFromVkDeviceMemory(VulkanDispatch* vk, VkDeviceMemory memory) {
1705 if (memory == VK_NULL_HANDLE) {
1706 WARN("Requested metal resource handle for null memory!");
1707 return nullptr;
1708 }
1709
1710 VkMemoryGetMetalHandleInfoEXT getMetalHandleInfo = {
1711 VK_STRUCTURE_TYPE_MEMORY_GET_METAL_HANDLE_INFO_EXT,
1712 nullptr,
1713 memory,
1714 VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT
1715 };
1716
1717 MTLResource_id outputHandle = nullptr;
1718 vk->vkGetMemoryMetalHandleEXT(sVkEmulation->device, &getMetalHandleInfo, &outputHandle);
1719 if (outputHandle == nullptr) {
1720 ERR("vkGetMemoryMetalHandleEXT returned null");
1721 }
1722 return outputHandle;
1723 }
1724 #endif
1725
1726 // Precondition: sVkEmulation has valid device support info
allocExternalMemory(VulkanDispatch * vk,VkEmulation::ExternalMemoryInfo * info,bool actuallyExternal,Optional<uint64_t> deviceAlignment,Optional<VkBuffer> bufferForDedicatedAllocation,Optional<VkImage> imageForDedicatedAllocation)1727 bool allocExternalMemory(VulkanDispatch* vk, VkEmulation::ExternalMemoryInfo* info,
1728 bool actuallyExternal, Optional<uint64_t> deviceAlignment,
1729 Optional<VkBuffer> bufferForDedicatedAllocation,
1730 Optional<VkImage> imageForDedicatedAllocation) {
1731 VkExportMemoryAllocateInfo exportAi = {
1732 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
1733 .pNext = nullptr,
1734 .handleTypes = VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1735 };
1736
1737 VkMemoryDedicatedAllocateInfo dedicatedAllocInfo = {
1738 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
1739 .pNext = nullptr,
1740 .image = VK_NULL_HANDLE,
1741 .buffer = VK_NULL_HANDLE,
1742 };
1743
1744 VkMemoryAllocateInfo allocInfo = {
1745 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1746 .pNext = nullptr,
1747 .allocationSize = info->size,
1748 .memoryTypeIndex = info->typeIndex,
1749 };
1750
1751 auto allocInfoChain = vk_make_chain_iterator(&allocInfo);
1752
1753
1754 if (sVkEmulation->deviceInfo.supportsExternalMemoryExport && actuallyExternal) {
1755 #ifdef __APPLE__
1756 if (sVkEmulation->instanceSupportsMoltenVK) {
1757 // Change handle type for metal resources
1758 exportAi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
1759 }
1760 #endif
1761 if (sVkEmulation->deviceInfo.supportsDmaBuf) {
1762 exportAi.handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
1763 }
1764
1765 vk_append_struct(&allocInfoChain, &exportAi);
1766 }
1767
1768 if (bufferForDedicatedAllocation.hasValue() || imageForDedicatedAllocation.hasValue()) {
1769 info->dedicatedAllocation = true;
1770 if (bufferForDedicatedAllocation.hasValue()) {
1771 dedicatedAllocInfo.buffer = *bufferForDedicatedAllocation;
1772 }
1773 if (imageForDedicatedAllocation.hasValue()) {
1774 dedicatedAllocInfo.image = *imageForDedicatedAllocation;
1775 }
1776 vk_append_struct(&allocInfoChain, &dedicatedAllocInfo);
1777 }
1778
1779 bool memoryAllocated = false;
1780 std::vector<VkDeviceMemory> allocationAttempts;
1781 constexpr size_t kMaxAllocationAttempts = 20u;
1782
1783 while (!memoryAllocated) {
1784 VkResult allocRes =
1785 vk->vkAllocateMemory(sVkEmulation->device, &allocInfo, nullptr, &info->memory);
1786
1787 if (allocRes != VK_SUCCESS) {
1788 VERBOSE("allocExternalMemory: failed in vkAllocateMemory: %s",
1789 string_VkResult(allocRes));
1790 break;
1791 }
1792
1793 if (sVkEmulation->deviceInfo.memProps.memoryTypes[info->typeIndex].propertyFlags &
1794 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
1795 VkResult mapRes = vk->vkMapMemory(sVkEmulation->device, info->memory, 0, info->size, 0,
1796 &info->mappedPtr);
1797 if (mapRes != VK_SUCCESS) {
1798 VERBOSE("allocExternalMemory: failed in vkMapMemory: %s", string_VkResult(mapRes));
1799 break;
1800 }
1801 }
1802
1803 uint64_t mappedPtrPageOffset = reinterpret_cast<uint64_t>(info->mappedPtr) % kPageSize;
1804
1805 if ( // don't care about alignment (e.g. device-local memory)
1806 !deviceAlignment.hasValue() ||
1807 // If device has an alignment requirement larger than current
1808 // host pointer alignment (i.e. the lowest 1 bit of mappedPtr),
1809 // the only possible way to make mappedPtr valid is to ensure
1810 // that it is already aligned to page.
1811 mappedPtrPageOffset == 0u ||
1812 // If device has an alignment requirement smaller or equals to
1813 // current host pointer alignment, clients can set a offset
1814 // |kPageSize - mappedPtrPageOffset| in vkBindImageMemory to
1815 // make it aligned to page and compatible with device
1816 // requirements.
1817 (kPageSize - mappedPtrPageOffset) % deviceAlignment.value() == 0) {
1818 // allocation success.
1819 memoryAllocated = true;
1820 } else {
1821 allocationAttempts.push_back(info->memory);
1822
1823 VERBOSE("allocExternalMemory: attempt #%zu failed; deviceAlignment: %" PRIu64
1824 ", mappedPtrPageOffset: %" PRIu64,
1825 allocationAttempts.size(), deviceAlignment.valueOr(0), mappedPtrPageOffset);
1826
1827 if (allocationAttempts.size() >= kMaxAllocationAttempts) {
1828 VERBOSE(
1829 "allocExternalMemory: unable to allocate memory with CPU mapped ptr aligned to "
1830 "page");
1831 break;
1832 }
1833 }
1834 }
1835
1836 // clean up previous failed attempts
1837 for (const auto& mem : allocationAttempts) {
1838 vk->vkFreeMemory(sVkEmulation->device, mem, nullptr /* allocator */);
1839 }
1840 if (!memoryAllocated) {
1841 return false;
1842 }
1843
1844 if (!sVkEmulation->deviceInfo.supportsExternalMemoryExport || !actuallyExternal) {
1845 return true;
1846 }
1847
1848 VkExternalMemoryHandleTypeFlagBits vkHandleType = VK_EXT_MEMORY_HANDLE_TYPE_BIT;
1849 uint32_t streamHandleType = 0;
1850 VkResult exportRes = VK_SUCCESS;
1851 bool validHandle = false;
1852 #ifdef _WIN32
1853 VkMemoryGetWin32HandleInfoKHR getWin32HandleInfo = {
1854 VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
1855 0,
1856 info->memory,
1857 vkHandleType,
1858 };
1859
1860 exportRes = sVkEmulation->deviceInfo.getMemoryHandleFunc(
1861 sVkEmulation->device, &getWin32HandleInfo, &info->externalHandle);
1862 validHandle = (VK_EXT_MEMORY_HANDLE_INVALID != info->externalHandle);
1863 info->streamHandleType = STREAM_MEM_HANDLE_TYPE_OPAQUE_WIN32;
1864 #elif !defined(__QNX__)
1865
1866 bool opaqueFd = true;
1867 #if defined(__APPLE__)
1868 if (sVkEmulation->instanceSupportsMoltenVK) {
1869 opaqueFd = false;
1870 info->externalMetalHandle = getMtlResourceFromVkDeviceMemory(vk, info->memory);
1871 validHandle = (nullptr != info->externalMetalHandle);
1872 if (validHandle) {
1873 CFRetain(info->externalMetalHandle);
1874 exportRes = VK_SUCCESS;
1875 } else {
1876 exportRes = VK_ERROR_INVALID_EXTERNAL_HANDLE;
1877 }
1878 }
1879 #endif
1880
1881 if (opaqueFd) {
1882 if (sVkEmulation->deviceInfo.supportsDmaBuf) {
1883 vkHandleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
1884 info->streamHandleType = STREAM_MEM_HANDLE_TYPE_DMABUF;
1885 } else {
1886 info->streamHandleType = STREAM_MEM_HANDLE_TYPE_OPAQUE_FD;
1887 }
1888
1889 VkMemoryGetFdInfoKHR getFdInfo = {
1890 VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
1891 0,
1892 info->memory,
1893 vkHandleType,
1894 };
1895 exportRes = sVkEmulation->deviceInfo.getMemoryHandleFunc(sVkEmulation->device, &getFdInfo,
1896 &info->externalHandle);
1897 validHandle = (VK_EXT_MEMORY_HANDLE_INVALID != info->externalHandle);
1898 }
1899 #endif
1900
1901 if (exportRes != VK_SUCCESS || !validHandle) {
1902 WARN("allocExternalMemory: Failed to get external memory, result: %s",
1903 string_VkResult(exportRes));
1904 return false;
1905 }
1906
1907 return true;
1908 }
1909
freeExternalMemoryLocked(VulkanDispatch * vk,VkEmulation::ExternalMemoryInfo * info)1910 void freeExternalMemoryLocked(VulkanDispatch* vk, VkEmulation::ExternalMemoryInfo* info) {
1911 if (!info->memory) return;
1912
1913 if (sVkEmulation->deviceInfo.memProps.memoryTypes[info->typeIndex].propertyFlags &
1914 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
1915 if (sVkEmulation->occupiedGpas.find(info->gpa) != sVkEmulation->occupiedGpas.end()) {
1916 sVkEmulation->occupiedGpas.erase(info->gpa);
1917 get_emugl_vm_operations().unmapUserBackedRam(info->gpa, info->sizeToPage);
1918 info->gpa = 0u;
1919 }
1920
1921 if (info->mappedPtr != nullptr) {
1922 vk->vkUnmapMemory(sVkEmulation->device, info->memory);
1923 info->mappedPtr = nullptr;
1924 info->pageAlignedHva = nullptr;
1925 }
1926 }
1927
1928 vk->vkFreeMemory(sVkEmulation->device, info->memory, nullptr);
1929
1930 info->memory = VK_NULL_HANDLE;
1931
1932 if (info->externalHandle != VK_EXT_MEMORY_HANDLE_INVALID) {
1933 #ifdef _WIN32
1934 CloseHandle(info->externalHandle);
1935 #elif !defined(__QNX__)
1936 close(info->externalHandle);
1937 #endif
1938 info->externalHandle = VK_EXT_MEMORY_HANDLE_INVALID;
1939 }
1940
1941 #if defined(__APPLE__)
1942 if (info->externalMetalHandle) {
1943 CFRelease(info->externalMetalHandle);
1944 }
1945 #endif
1946 }
1947
importExternalMemory(VulkanDispatch * vk,VkDevice targetDevice,const VkEmulation::ExternalMemoryInfo * info,VkDeviceMemory * out)1948 bool importExternalMemory(VulkanDispatch* vk, VkDevice targetDevice,
1949 const VkEmulation::ExternalMemoryInfo* info, VkDeviceMemory* out) {
1950 const void* importInfoPtr = nullptr;
1951 #ifdef _WIN32
1952 VkImportMemoryWin32HandleInfoKHR importInfo = {
1953 VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
1954 0,
1955 VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1956 info->externalHandle,
1957 0,
1958 };
1959 importInfoPtr = &importInfo;
1960 #elif defined(__QNX__)
1961 VkImportScreenBufferInfoQNX importInfo = {
1962 VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX,
1963 NULL,
1964 info->externalHandle,
1965 };
1966 importInfoPtr = &importInfo;
1967 #else
1968
1969 bool opaqueFd = true;
1970 #ifdef __APPLE__
1971 VkImportMemoryMetalHandleInfoEXT importInfoMetalInfo = {
1972 VK_STRUCTURE_TYPE_IMPORT_MEMORY_METAL_HANDLE_INFO_EXT,
1973 0,
1974 VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT,
1975 nullptr
1976 };
1977 if (sVkEmulation->instanceSupportsMoltenVK) {
1978 opaqueFd = false;
1979 importInfoMetalInfo.handle = info->externalMetalHandle;
1980 importInfoPtr = &importInfoMetalInfo;
1981 }
1982 #endif
1983
1984 VkImportMemoryFdInfoKHR importInfoFd = {
1985 VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
1986 0,
1987 VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1988 VK_EXT_MEMORY_HANDLE_INVALID,
1989 };
1990 if (opaqueFd) {
1991 importInfoFd.fd = dupExternalMemory(info->externalHandle);
1992 importInfoPtr = &importInfoFd;
1993 }
1994 #endif
1995 VkMemoryAllocateInfo allocInfo = {
1996 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1997 importInfoPtr,
1998 info->size,
1999 info->typeIndex,
2000 };
2001
2002 VkResult res = vk->vkAllocateMemory(targetDevice, &allocInfo, nullptr, out);
2003
2004 if (res != VK_SUCCESS) {
2005 ERR("importExternalMemory: Failed with %s", string_VkResult(res));
2006 return false;
2007 }
2008
2009 return true;
2010 }
2011
importExternalMemoryDedicatedImage(VulkanDispatch * vk,VkDevice targetDevice,const VkEmulation::ExternalMemoryInfo * info,VkImage image,VkDeviceMemory * out)2012 bool importExternalMemoryDedicatedImage(VulkanDispatch* vk, VkDevice targetDevice,
2013 const VkEmulation::ExternalMemoryInfo* info, VkImage image,
2014 VkDeviceMemory* out) {
2015 VkMemoryDedicatedAllocateInfo dedicatedInfo = {
2016 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2017 0,
2018 image,
2019 VK_NULL_HANDLE,
2020 };
2021
2022 const void* importInfoPtr = nullptr;
2023 #ifdef _WIN32
2024 VkImportMemoryWin32HandleInfoKHR importInfo = {
2025 VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
2026 &dedicatedInfo,
2027 VK_EXT_MEMORY_HANDLE_TYPE_BIT,
2028 info->externalHandle,
2029 0,
2030 };
2031 importInfoPtr = &importInfo;
2032 #elif defined(__QNX__)
2033 VkImportScreenBufferInfoQNX importInfo = {
2034 VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX,
2035 &dedicatedInfo,
2036 info->externalHandle,
2037 };
2038 importInfoPtr = &importInfo;
2039 #else
2040
2041 bool opaqueFd = true;
2042 #ifdef __APPLE__
2043 VkImportMemoryMetalHandleInfoEXT importInfoMetalInfo = {
2044 VK_STRUCTURE_TYPE_IMPORT_MEMORY_METAL_HANDLE_INFO_EXT,
2045 &dedicatedInfo,
2046 VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT,
2047 nullptr
2048 };
2049 if (sVkEmulation->instanceSupportsMoltenVK) {
2050 importInfoMetalInfo.handle = info->externalMetalHandle;
2051 importInfoPtr = &importInfoMetalInfo;
2052 opaqueFd = false;
2053 }
2054 #endif
2055
2056 VkImportMemoryFdInfoKHR importInfoFd = {
2057 VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
2058 &dedicatedInfo,
2059 VK_EXT_MEMORY_HANDLE_TYPE_BIT,
2060 -1,
2061 };
2062 if (opaqueFd) {
2063 importInfoFd.fd = dupExternalMemory(info->externalHandle);
2064 importInfoPtr = &importInfoFd;
2065 }
2066 #endif
2067 VkMemoryAllocateInfo allocInfo = {
2068 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
2069 importInfoPtr,
2070 info->size,
2071 info->typeIndex,
2072 };
2073
2074 VkResult res = vk->vkAllocateMemory(targetDevice, &allocInfo, nullptr, out);
2075
2076 if (res != VK_SUCCESS) {
2077 ERR("importExternalMemoryDedicatedImage: Failed with %s", string_VkResult(res));
2078 return false;
2079 }
2080
2081 return true;
2082 }
2083
2084 // From ANGLE "src/common/angleutils.h"
2085 #define GL_BGR10_A2_ANGLEX 0x6AF9
2086
glFormat2VkFormat(GLint internalFormat)2087 static VkFormat glFormat2VkFormat(GLint internalFormat) {
2088 switch (internalFormat) {
2089 case GL_R8:
2090 case GL_LUMINANCE:
2091 return VK_FORMAT_R8_UNORM;
2092 case GL_RGB:
2093 case GL_RGB8:
2094 // b/281550953
2095 // RGB8 is not supported on many vulkan drivers.
2096 // Try RGBA8 instead.
2097 // Note: copyImageData() performs channel conversion for this case.
2098 return VK_FORMAT_R8G8B8A8_UNORM;
2099 case GL_RGB565:
2100 return VK_FORMAT_R5G6B5_UNORM_PACK16;
2101 case GL_RGB16F:
2102 return VK_FORMAT_R16G16B16_SFLOAT;
2103 case GL_RGBA:
2104 case GL_RGBA8:
2105 return VK_FORMAT_R8G8B8A8_UNORM;
2106 case GL_RGB5_A1_OES:
2107 return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
2108 case GL_RGBA4_OES:
2109 return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
2110 case GL_RGB10_A2:
2111 case GL_UNSIGNED_INT_10_10_10_2_OES:
2112 return VK_FORMAT_A2R10G10B10_UNORM_PACK32;
2113 case GL_BGR10_A2_ANGLEX:
2114 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
2115 case GL_RGBA16F:
2116 return VK_FORMAT_R16G16B16A16_SFLOAT;
2117 case GL_BGRA_EXT:
2118 case GL_BGRA8_EXT:
2119 return VK_FORMAT_B8G8R8A8_UNORM;
2120 case GL_R16_EXT:
2121 return VK_FORMAT_R16_UNORM;
2122 case GL_RG8_EXT:
2123 return VK_FORMAT_R8G8_UNORM;
2124 case GL_DEPTH_COMPONENT16:
2125 return VK_FORMAT_D16_UNORM;
2126 case GL_DEPTH_COMPONENT24:
2127 return VK_FORMAT_X8_D24_UNORM_PACK32;
2128 case GL_DEPTH24_STENCIL8:
2129 return VK_FORMAT_D24_UNORM_S8_UINT;
2130 case GL_DEPTH_COMPONENT32F:
2131 return VK_FORMAT_D32_SFLOAT;
2132 case GL_DEPTH32F_STENCIL8:
2133 return VK_FORMAT_D32_SFLOAT_S8_UINT;
2134 default:
2135 ERR("Unhandled format %d, falling back to VK_FORMAT_R8G8B8A8_UNORM", internalFormat);
2136 return VK_FORMAT_R8G8B8A8_UNORM;
2137 }
2138 };
2139
isFormatVulkanCompatible(GLenum internalFormat)2140 static bool isFormatVulkanCompatible(GLenum internalFormat) {
2141 VkFormat vkFormat = glFormat2VkFormat(internalFormat);
2142
2143 for (const auto& supportInfo : sVkEmulation->imageSupportInfo) {
2144 if (supportInfo.format == vkFormat && supportInfo.supported) {
2145 return true;
2146 }
2147 }
2148
2149 return false;
2150 }
2151
getColorBufferShareInfo(uint32_t colorBufferHandle,bool * glExported,bool * externalMemoryCompatible)2152 bool getColorBufferShareInfo(uint32_t colorBufferHandle, bool* glExported,
2153 bool* externalMemoryCompatible) {
2154 if (!sVkEmulation || !sVkEmulation->live) {
2155 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Vulkan emulation not available.";
2156 }
2157
2158 AutoLock lock(sVkEmulationLock);
2159
2160 auto info = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2161 if (!info) {
2162 return false;
2163 }
2164
2165 *glExported = info->glExported;
2166 *externalMemoryCompatible = info->externalMemoryCompatible;
2167 return true;
2168 }
2169
getColorBufferAllocationInfoLocked(uint32_t colorBufferHandle,VkDeviceSize * outSize,uint32_t * outMemoryTypeIndex,bool * outMemoryIsDedicatedAlloc,void ** outMappedPtr)2170 bool getColorBufferAllocationInfoLocked(uint32_t colorBufferHandle, VkDeviceSize* outSize,
2171 uint32_t* outMemoryTypeIndex,
2172 bool* outMemoryIsDedicatedAlloc, void** outMappedPtr) {
2173 auto info = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2174 if (!info) {
2175 return false;
2176 }
2177
2178 if (outSize) {
2179 *outSize = info->memory.size;
2180 }
2181
2182 if (outMemoryTypeIndex) {
2183 *outMemoryTypeIndex = info->memory.typeIndex;
2184 }
2185
2186 if (outMemoryIsDedicatedAlloc) {
2187 *outMemoryIsDedicatedAlloc = info->memory.dedicatedAllocation;
2188 }
2189
2190 if (outMappedPtr) {
2191 *outMappedPtr = info->memory.mappedPtr;
2192 }
2193
2194 return true;
2195 }
2196
getColorBufferAllocationInfo(uint32_t colorBufferHandle,VkDeviceSize * outSize,uint32_t * outMemoryTypeIndex,bool * outMemoryIsDedicatedAlloc,void ** outMappedPtr)2197 bool getColorBufferAllocationInfo(uint32_t colorBufferHandle, VkDeviceSize* outSize,
2198 uint32_t* outMemoryTypeIndex, bool* outMemoryIsDedicatedAlloc,
2199 void** outMappedPtr) {
2200 if (!sVkEmulation || !sVkEmulation->live) {
2201 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Vulkan emulation not available.";
2202 }
2203
2204 AutoLock lock(sVkEmulationLock);
2205 return getColorBufferAllocationInfoLocked(colorBufferHandle, outSize, outMemoryTypeIndex,
2206 outMemoryIsDedicatedAlloc, outMappedPtr);
2207 }
2208
2209 // This function will return the first memory type that exactly matches the
2210 // requested properties, if there is any. Otherwise it'll return the last
2211 // index that supports all the requested memory property flags.
2212 // Eg. this avoids returning a host coherent memory type when only device local
2213 // memory flag is requested, which may be slow or not support some other features,
2214 // such as association with optimal-tiling images on some implementations.
getValidMemoryTypeIndex(uint32_t requiredMemoryTypeBits,VkMemoryPropertyFlags memoryProperty=0)2215 static uint32_t getValidMemoryTypeIndex(uint32_t requiredMemoryTypeBits,
2216 VkMemoryPropertyFlags memoryProperty = 0) {
2217 uint32_t secondBest = ~0;
2218 bool found = false;
2219 for (int32_t i = 0; i <= 31; i++) {
2220 if ((requiredMemoryTypeBits & (1u << i)) == 0) {
2221 // Not a suitable memory index
2222 continue;
2223 }
2224
2225 const VkMemoryPropertyFlags memPropertyFlags =
2226 sVkEmulation->deviceInfo.memProps.memoryTypes[i].propertyFlags;
2227
2228 // Exact match, return immediately
2229 if (memPropertyFlags == memoryProperty) {
2230 return i;
2231 }
2232
2233 // Valid memory index, but keep looking for an exact match
2234 // TODO: this should compare against memoryProperty, but some existing tests
2235 // are depending on this behavior.
2236 const bool propertyValid = !memoryProperty || ((memPropertyFlags & memoryProperty) != 0);
2237 if (propertyValid) {
2238 secondBest = i;
2239 found = true;
2240 }
2241 }
2242
2243 if (!found) {
2244 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
2245 << "Could not find a valid memory index with memoryProperty: "
2246 << string_VkMemoryPropertyFlags(memoryProperty)
2247 << ", and requiredMemoryTypeBits: " << requiredMemoryTypeBits;
2248 }
2249 return secondBest;
2250 }
2251
2252 // pNext, sharingMode, queueFamilyIndexCount, pQueueFamilyIndices, and initialLayout won't be
2253 // filled.
generateColorBufferVkImageCreateInfo_locked(VkFormat format,uint32_t width,uint32_t height,VkImageTiling tiling)2254 static std::unique_ptr<VkImageCreateInfo> generateColorBufferVkImageCreateInfo_locked(
2255 VkFormat format, uint32_t width, uint32_t height, VkImageTiling tiling) {
2256 const VkEmulation::ImageSupportInfo* maybeImageSupportInfo = nullptr;
2257 for (const auto& supportInfo : sVkEmulation->imageSupportInfo) {
2258 if (supportInfo.format == format && supportInfo.supported) {
2259 maybeImageSupportInfo = &supportInfo;
2260 break;
2261 }
2262 }
2263 if (!maybeImageSupportInfo) {
2264 ERR("Format %s [%d] is not supported.", string_VkFormat(format), format);
2265 return nullptr;
2266 }
2267 const VkEmulation::ImageSupportInfo& imageSupportInfo = *maybeImageSupportInfo;
2268 const VkFormatProperties& formatProperties = imageSupportInfo.formatProps2.formatProperties;
2269
2270 constexpr std::pair<VkFormatFeatureFlags, VkImageUsageFlags> formatUsagePairs[] = {
2271 {VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,
2272 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT},
2273 {VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT,
2274 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT},
2275 {VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT, VK_IMAGE_USAGE_SAMPLED_BIT},
2276 {VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT},
2277 {VK_FORMAT_FEATURE_TRANSFER_DST_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT},
2278 {VK_FORMAT_FEATURE_BLIT_SRC_BIT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT},
2279 };
2280 VkFormatFeatureFlags tilingFeatures = (tiling == VK_IMAGE_TILING_OPTIMAL)
2281 ? formatProperties.optimalTilingFeatures
2282 : formatProperties.linearTilingFeatures;
2283
2284 VkImageUsageFlags usage = 0;
2285 for (const auto& formatUsage : formatUsagePairs) {
2286 usage |= (tilingFeatures & formatUsage.first) ? formatUsage.second : 0u;
2287 }
2288
2289 return std::make_unique<VkImageCreateInfo>(VkImageCreateInfo{
2290 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2291 // The caller is responsible to fill pNext.
2292 .pNext = nullptr,
2293 .flags = imageSupportInfo.createFlags,
2294 .imageType = VK_IMAGE_TYPE_2D,
2295 .format = format,
2296 .extent =
2297 {
2298 .width = width,
2299 .height = height,
2300 .depth = 1,
2301 },
2302 .mipLevels = 1,
2303 .arrayLayers = 1,
2304 .samples = VK_SAMPLE_COUNT_1_BIT,
2305 .tiling = tiling,
2306 .usage = usage,
2307 // The caller is responsible to fill sharingMode.
2308 .sharingMode = VK_SHARING_MODE_MAX_ENUM,
2309 // The caller is responsible to fill queueFamilyIndexCount.
2310 .queueFamilyIndexCount = 0,
2311 // The caller is responsible to fill pQueueFamilyIndices.
2312 .pQueueFamilyIndices = nullptr,
2313 // The caller is responsible to fill initialLayout.
2314 .initialLayout = VK_IMAGE_LAYOUT_MAX_ENUM,
2315 });
2316 }
2317
generateColorBufferVkImageCreateInfo(VkFormat format,uint32_t width,uint32_t height,VkImageTiling tiling)2318 std::unique_ptr<VkImageCreateInfo> generateColorBufferVkImageCreateInfo(VkFormat format,
2319 uint32_t width,
2320 uint32_t height,
2321 VkImageTiling tiling) {
2322 if (!sVkEmulation || !sVkEmulation->live) {
2323 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Host Vulkan device lost";
2324 }
2325 AutoLock lock(sVkEmulationLock);
2326 return generateColorBufferVkImageCreateInfo_locked(format, width, height, tiling);
2327 }
2328
updateExternalMemoryInfo(VK_EXT_MEMORY_HANDLE extMemHandle,const VkMemoryRequirements * pMemReqs,VkEmulation::ExternalMemoryInfo * pInfo)2329 static bool updateExternalMemoryInfo(VK_EXT_MEMORY_HANDLE extMemHandle,
2330 const VkMemoryRequirements* pMemReqs,
2331 VkEmulation::ExternalMemoryInfo* pInfo) {
2332 // Set externalHandle on the output info
2333 pInfo->externalHandle = extMemHandle;
2334 pInfo->dedicatedAllocation = true;
2335
2336 #if defined(__QNX__)
2337 VkScreenBufferPropertiesQNX screenBufferProps = {
2338 VK_STRUCTURE_TYPE_SCREEN_BUFFER_PROPERTIES_QNX,
2339 0,
2340 };
2341 auto vk = sVkEmulation->dvk;
2342 VkResult queryRes =
2343 vk->vkGetScreenBufferPropertiesQNX(sVkEmulation->device, extMemHandle, &screenBufferProps);
2344 if (VK_SUCCESS != queryRes) {
2345 ERR("Failed to get QNX Screen Buffer properties, VK error: %s", string_VkResult(queryRes));
2346 return false;
2347 }
2348 if (!((1 << pInfo->typeIndex) & screenBufferProps.memoryTypeBits)) {
2349 ERR("QNX Screen buffer can not be imported to memory (typeIndex=%d): %d", pInfo->typeIndex);
2350 return false;
2351 }
2352 if (screenBufferProps.allocationSize < pMemReqs->size) {
2353 ERR("QNX Screen buffer allocationSize (0x%lx) is not large enough for ColorBuffer image "
2354 "size requirements (0x%lx)",
2355 screenBufferProps.allocationSize, pMemReqs->size);
2356 return false;
2357 }
2358 // Use the actual allocationSize for VkDeviceMemory object creation
2359 pInfo->size = screenBufferProps.allocationSize;
2360 #endif
2361
2362 #ifdef __APPLE__
2363 // importExtMemoryHandleToVkColorBuffer is not supported with MoltenVK
2364 if (sVkEmulation->instanceSupportsMoltenVK) {
2365 WARN("Unexpected call to updateExternalMemoryInfo!");
2366 pInfo->externalMetalHandle = nullptr;
2367 }
2368 #endif
2369
2370 return true;
2371 }
2372
2373 // TODO(liyl): Currently we can only specify required memoryProperty
2374 // and initial layout for a color buffer.
2375 //
2376 // Ideally we would like to specify a memory type index directly from
2377 // localAllocInfo.memoryTypeIndex when allocating color buffers in
2378 // vkAllocateMemory(). But this type index mechanism breaks "Modify the
2379 // allocation size and type index to suit the resulting image memory
2380 // size." which seems to be needed to keep the Android/Fuchsia guest
2381 // memory type index consistent across guest allocations, and without
2382 // which those guests might end up import allocating from a color buffer
2383 // with mismatched type indices.
2384 //
2385 // We should make it so the guest can only allocate external images/
2386 // buffers of one type index for image and one type index for buffer
2387 // to begin with, via filtering from the host.
2388
initializeVkColorBufferLocked(uint32_t colorBufferHandle,VK_EXT_MEMORY_HANDLE extMemHandle=VK_EXT_MEMORY_HANDLE_INVALID)2389 bool initializeVkColorBufferLocked(
2390 uint32_t colorBufferHandle, VK_EXT_MEMORY_HANDLE extMemHandle = VK_EXT_MEMORY_HANDLE_INVALID) {
2391 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2392 // Not initialized
2393 if (!infoPtr) {
2394 return false;
2395 }
2396 // Already initialized Vulkan memory and other related Vulkan objects
2397 if (infoPtr->initialized) {
2398 return true;
2399 }
2400
2401 if (!isFormatVulkanCompatible(infoPtr->internalFormat)) {
2402 VERBOSE("Failed to create Vk ColorBuffer: format:%d not compatible.",
2403 infoPtr->internalFormat);
2404 return false;
2405 }
2406
2407 const bool extMemImport = (VK_EXT_MEMORY_HANDLE_INVALID != extMemHandle);
2408 if (extMemImport && !sVkEmulation->deviceInfo.supportsExternalMemoryImport) {
2409 ERR("Failed to initialize Vk ColorBuffer -- extMemHandle provided, but device does "
2410 "not support externalMemoryImport");
2411 return false;
2412 }
2413
2414 VkFormat vkFormat;
2415 bool glCompatible = (infoPtr->frameworkFormat == FRAMEWORK_FORMAT_GL_COMPATIBLE);
2416 switch (infoPtr->frameworkFormat) {
2417 case FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE:
2418 vkFormat = glFormat2VkFormat(infoPtr->internalFormat);
2419 break;
2420 case FrameworkFormat::FRAMEWORK_FORMAT_NV12:
2421 vkFormat = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
2422 break;
2423 case FrameworkFormat::FRAMEWORK_FORMAT_P010:
2424 vkFormat = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16;
2425 break;
2426 case FrameworkFormat::FRAMEWORK_FORMAT_YV12:
2427 case FrameworkFormat::FRAMEWORK_FORMAT_YUV_420_888:
2428 vkFormat = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
2429 break;
2430 default:
2431 ERR("WARNING: unhandled framework format %d\n", infoPtr->frameworkFormat);
2432 vkFormat = glFormat2VkFormat(infoPtr->internalFormat);
2433 break;
2434 }
2435
2436 VkImageTiling tiling = (infoPtr->memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
2437 ? VK_IMAGE_TILING_LINEAR
2438 : VK_IMAGE_TILING_OPTIMAL;
2439 std::unique_ptr<VkImageCreateInfo> imageCi = generateColorBufferVkImageCreateInfo_locked(
2440 vkFormat, infoPtr->width, infoPtr->height, tiling);
2441 // pNext will be filled later.
2442 if (imageCi == nullptr) {
2443 // it can happen if the format is not supported
2444 return false;
2445 }
2446 imageCi->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
2447 imageCi->queueFamilyIndexCount = 0;
2448 imageCi->pQueueFamilyIndices = nullptr;
2449 imageCi->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2450
2451 // Create the image. If external memory is supported, make it external.
2452 VkExternalMemoryImageCreateInfo extImageCi = {
2453 VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2454 0,
2455 VK_EXT_MEMORY_HANDLE_TYPE_BIT,
2456 };
2457 #if defined(__APPLE__)
2458 if (sVkEmulation->instanceSupportsMoltenVK) {
2459 // Using a different handle type when in MoltenVK mode
2460 extImageCi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
2461 }
2462 #endif
2463
2464 VkExternalMemoryImageCreateInfo* extImageCiPtr = nullptr;
2465
2466 if (extMemImport || sVkEmulation->deviceInfo.supportsExternalMemoryExport) {
2467 extImageCiPtr = &extImageCi;
2468 }
2469
2470 imageCi->pNext = extImageCiPtr;
2471
2472 auto vk = sVkEmulation->dvk;
2473
2474 VkResult createRes =
2475 vk->vkCreateImage(sVkEmulation->device, imageCi.get(), nullptr, &infoPtr->image);
2476 if (createRes != VK_SUCCESS) {
2477 VERBOSE("Failed to create Vulkan image for ColorBuffer %d, error: %s", colorBufferHandle,
2478 string_VkResult(createRes));
2479 return false;
2480 }
2481
2482 bool useDedicated = sVkEmulation->useDedicatedAllocations;
2483
2484 infoPtr->imageCreateInfoShallow = vk_make_orphan_copy(*imageCi);
2485 infoPtr->currentQueueFamilyIndex = sVkEmulation->queueFamilyIndex;
2486
2487 if (!useDedicated && vk->vkGetImageMemoryRequirements2KHR) {
2488 VkMemoryDedicatedRequirements dedicated_reqs{
2489 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, nullptr};
2490 VkMemoryRequirements2 reqs{VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &dedicated_reqs};
2491
2492 VkImageMemoryRequirementsInfo2 info{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
2493 nullptr, infoPtr->image};
2494 vk->vkGetImageMemoryRequirements2KHR(sVkEmulation->device, &info, &reqs);
2495 useDedicated = dedicated_reqs.requiresDedicatedAllocation;
2496 infoPtr->memReqs = reqs.memoryRequirements;
2497 } else {
2498 vk->vkGetImageMemoryRequirements(sVkEmulation->device, infoPtr->image, &infoPtr->memReqs);
2499 }
2500
2501 // Currently we only care about two memory properties: DEVICE_LOCAL
2502 // and HOST_VISIBLE; other memory properties specified in
2503 // rcSetColorBufferVulkanMode2() call will be ignored for now.
2504 infoPtr->memoryProperty = infoPtr->memoryProperty & (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
2505 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
2506
2507 infoPtr->memory.size = infoPtr->memReqs.size;
2508
2509 // Determine memory type.
2510 infoPtr->memory.typeIndex =
2511 getValidMemoryTypeIndex(infoPtr->memReqs.memoryTypeBits, infoPtr->memoryProperty);
2512
2513 const VkFormat imageVkFormat = infoPtr->imageCreateInfoShallow.format;
2514 VERBOSE(
2515 "ColorBuffer %d, dimensions: %dx%d, format: %s, "
2516 "allocation size and type index: %lu, %d, "
2517 "allocated memory property: %d, "
2518 "requested memory property: %d",
2519 colorBufferHandle, infoPtr->width, infoPtr->height,
2520 string_VkFormat(imageVkFormat),
2521 infoPtr->memory.size, infoPtr->memory.typeIndex,
2522 sVkEmulation->deviceInfo.memProps.memoryTypes[infoPtr->memory.typeIndex].propertyFlags,
2523 infoPtr->memoryProperty);
2524
2525 Optional<VkImage> dedicatedImage = useDedicated ? Optional<VkImage>(infoPtr->image) : kNullopt;
2526 if (VK_EXT_MEMORY_HANDLE_INVALID != extMemHandle) {
2527 if (!updateExternalMemoryInfo(extMemHandle, &infoPtr->memReqs, &infoPtr->memory)) {
2528 ERR("Failed to update external memory info for ColorBuffer: %d\n", colorBufferHandle);
2529 return false;
2530 }
2531 if (useDedicated) {
2532 if (!importExternalMemoryDedicatedImage(vk, sVkEmulation->device, &infoPtr->memory,
2533 *dedicatedImage, &infoPtr->memory.memory)) {
2534 ERR("Failed to import external memory with dedicated Image for colorBuffer: %d\n",
2535 colorBufferHandle);
2536 return false;
2537 }
2538 } else if (!importExternalMemory(vk, sVkEmulation->device, &infoPtr->memory,
2539 &infoPtr->memory.memory)) {
2540 ERR("Failed to import external memory for colorBuffer: %d\n", colorBufferHandle);
2541 return false;
2542 }
2543
2544 infoPtr->externalMemoryCompatible = true;
2545 } else {
2546 bool isHostVisible = infoPtr->memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
2547 Optional<uint64_t> deviceAlignment =
2548 isHostVisible ? Optional<uint64_t>(infoPtr->memReqs.alignment) : kNullopt;
2549 bool allocRes = allocExternalMemory(vk, &infoPtr->memory, true /*actuallyExternal*/,
2550 deviceAlignment, kNullopt, dedicatedImage);
2551 if (!allocRes) {
2552 ERR("Failed to allocate ColorBuffer with Vulkan backing.");
2553 return false;
2554 }
2555
2556 infoPtr->externalMemoryCompatible = sVkEmulation->deviceInfo.supportsExternalMemoryExport;
2557 }
2558
2559 infoPtr->memory.pageOffset = reinterpret_cast<uint64_t>(infoPtr->memory.mappedPtr) % kPageSize;
2560 infoPtr->memory.bindOffset =
2561 infoPtr->memory.pageOffset ? kPageSize - infoPtr->memory.pageOffset : 0u;
2562
2563 VkResult bindImageMemoryRes = vk->vkBindImageMemory(
2564 sVkEmulation->device, infoPtr->image, infoPtr->memory.memory, infoPtr->memory.bindOffset);
2565
2566 if (bindImageMemoryRes != VK_SUCCESS) {
2567 ERR("Failed to bind image memory. Error: %s", string_VkResult(bindImageMemoryRes));
2568 return false;
2569 }
2570
2571 VkSamplerYcbcrConversionInfo ycbcrInfo = {VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
2572 nullptr, VK_NULL_HANDLE};
2573 const bool addConversion = formatRequiresYcbcrConversion(imageVkFormat);
2574 if (addConversion) {
2575 VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo = {
2576 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
2577 nullptr,
2578 imageVkFormat,
2579 VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
2580 VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
2581 {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
2582 VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY},
2583 VK_CHROMA_LOCATION_MIDPOINT,
2584 VK_CHROMA_LOCATION_MIDPOINT,
2585 VK_FILTER_NEAREST,
2586 VK_FALSE};
2587
2588 createRes = vk->vkCreateSamplerYcbcrConversion(sVkEmulation->device, &ycbcrCreateInfo,
2589 nullptr, &infoPtr->ycbcrConversion);
2590 if (createRes != VK_SUCCESS) {
2591 VERBOSE(
2592 "Failed to create Vulkan ycbcrConversion for ColorBuffer %d with format %s [%d], "
2593 "Error: %s",
2594 colorBufferHandle, string_VkFormat(imageVkFormat), imageVkFormat,
2595 string_VkResult(createRes));
2596 return false;
2597 }
2598 ycbcrInfo.conversion = infoPtr->ycbcrConversion;
2599 }
2600
2601 const VkImageViewCreateInfo imageViewCi = {
2602 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
2603 .pNext = addConversion ? &ycbcrInfo : nullptr,
2604 .flags = 0,
2605 .image = infoPtr->image,
2606 .viewType = VK_IMAGE_VIEW_TYPE_2D,
2607 .format = imageVkFormat,
2608 .components =
2609 {
2610 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
2611 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
2612 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
2613 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
2614 },
2615 .subresourceRange =
2616 {
2617 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2618 .baseMipLevel = 0,
2619 .levelCount = 1,
2620 .baseArrayLayer = 0,
2621 .layerCount = 1,
2622 },
2623 };
2624 createRes =
2625 vk->vkCreateImageView(sVkEmulation->device, &imageViewCi, nullptr, &infoPtr->imageView);
2626 if (createRes != VK_SUCCESS) {
2627 VERBOSE("Failed to create Vulkan image view for ColorBuffer %d, Error: %s",
2628 colorBufferHandle, string_VkResult(createRes));
2629 return false;
2630 }
2631
2632 sVkEmulation->debugUtilsHelper.addDebugLabel(infoPtr->image, "ColorBuffer:%d",
2633 colorBufferHandle);
2634 sVkEmulation->debugUtilsHelper.addDebugLabel(infoPtr->imageView, "ColorBuffer:%d",
2635 colorBufferHandle);
2636 sVkEmulation->debugUtilsHelper.addDebugLabel(infoPtr->memory.memory, "ColorBuffer:%d",
2637 colorBufferHandle);
2638
2639 infoPtr->initialized = true;
2640
2641 return true;
2642 }
2643
createVkColorBufferLocked(uint32_t width,uint32_t height,GLenum internalFormat,FrameworkFormat frameworkFormat,uint32_t colorBufferHandle,bool vulkanOnly,uint32_t memoryProperty)2644 static bool createVkColorBufferLocked(uint32_t width, uint32_t height, GLenum internalFormat,
2645 FrameworkFormat frameworkFormat, uint32_t colorBufferHandle,
2646 bool vulkanOnly, uint32_t memoryProperty) {
2647 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2648 // Already initialized
2649 if (infoPtr) {
2650 return true;
2651 }
2652
2653 VkEmulation::ColorBufferInfo res;
2654
2655 res.handle = colorBufferHandle;
2656 res.width = width;
2657 res.height = height;
2658 res.memoryProperty = memoryProperty;
2659 res.internalFormat = internalFormat;
2660 res.frameworkFormat = frameworkFormat;
2661 res.frameworkStride = 0;
2662
2663 if (vulkanOnly) {
2664 res.vulkanMode = VkEmulation::VulkanMode::VulkanOnly;
2665 }
2666
2667 sVkEmulation->colorBuffers[colorBufferHandle] = res;
2668 return true;
2669 }
2670
isFormatSupported(GLenum format)2671 bool isFormatSupported(GLenum format) {
2672 VkFormat vkFormat = glFormat2VkFormat(format);
2673 bool supported = !gfxstream::vk::formatIsDepthOrStencil(vkFormat);
2674 // TODO(b/356603558): add proper Vulkan querying, for now preserve existing assumption
2675 if (!supported) {
2676 for (size_t i = 0; i < sVkEmulation->imageSupportInfo.size(); ++i) {
2677 // Only enable depth/stencil if it is usable as an attachment
2678 if (sVkEmulation->imageSupportInfo[i].format == vkFormat &&
2679 gfxstream::vk::formatIsDepthOrStencil(
2680 sVkEmulation->imageSupportInfo[i].format) &&
2681 sVkEmulation->imageSupportInfo[i].supported &&
2682 sVkEmulation->imageSupportInfo[i]
2683 .formatProps2.formatProperties.optimalTilingFeatures &
2684 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
2685 supported = true;
2686 }
2687 }
2688 }
2689 return supported;
2690 }
2691
createVkColorBuffer(uint32_t width,uint32_t height,GLenum internalFormat,FrameworkFormat frameworkFormat,uint32_t colorBufferHandle,bool vulkanOnly,uint32_t memoryProperty)2692 bool createVkColorBuffer(uint32_t width, uint32_t height, GLenum internalFormat,
2693 FrameworkFormat frameworkFormat, uint32_t colorBufferHandle,
2694 bool vulkanOnly, uint32_t memoryProperty) {
2695 if (!sVkEmulation || !sVkEmulation->live) {
2696 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "VkEmulation not available.";
2697 }
2698
2699 AutoLock lock(sVkEmulationLock);
2700 if (!createVkColorBufferLocked(width, height, internalFormat, frameworkFormat,
2701 colorBufferHandle, vulkanOnly, memoryProperty)) {
2702 return false;
2703 }
2704
2705 const auto& deviceInfo = sVkEmulation->deviceInfo;
2706 if (!deviceInfo.supportsExternalMemoryExport && deviceInfo.supportsExternalMemoryImport) {
2707 /* Returns, deferring initialization of the Vulkan components themselves.
2708 * Platforms that support import but not export of external memory must
2709 * use importExtMemoryHandleToVkColorBuffer(). Otherwise, the colorBuffer
2710 * memory can not be externalized.
2711 */
2712 return true;
2713 }
2714
2715 return initializeVkColorBufferLocked(colorBufferHandle);
2716 }
2717
exportColorBufferMemory(uint32_t colorBufferHandle)2718 std::optional<VkColorBufferMemoryExport> exportColorBufferMemory(uint32_t colorBufferHandle) {
2719 if (!sVkEmulation || !sVkEmulation->live) {
2720 return std::nullopt;
2721 }
2722
2723 AutoLock lock(sVkEmulationLock);
2724
2725 const auto& deviceInfo = sVkEmulation->deviceInfo;
2726 if (!deviceInfo.supportsExternalMemoryExport && deviceInfo.supportsExternalMemoryImport) {
2727 return std::nullopt;
2728 }
2729
2730 auto info = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2731 if (!info) {
2732 return std::nullopt;
2733 }
2734
2735 if ((info->vulkanMode != VkEmulation::VulkanMode::VulkanOnly) &&
2736 !deviceInfo.glInteropSupported) {
2737 return std::nullopt;
2738 }
2739
2740 if (info->frameworkFormat != FRAMEWORK_FORMAT_GL_COMPATIBLE) {
2741 return std::nullopt;
2742 }
2743
2744 #if !defined(__QNX__)
2745 ManagedDescriptor descriptor(dupExternalMemory(info->memory.externalHandle));
2746
2747 info->glExported = true;
2748
2749 return VkColorBufferMemoryExport{
2750 .descriptor = std::move(descriptor),
2751 .size = info->memory.size,
2752 .streamHandleType = info->memory.streamHandleType,
2753 .linearTiling = info->imageCreateInfoShallow.tiling == VK_IMAGE_TILING_LINEAR,
2754 .dedicatedAllocation = info->memory.dedicatedAllocation,
2755 };
2756 #else
2757 return std::nullopt;
2758 #endif
2759 }
2760
teardownVkColorBufferLocked(uint32_t colorBufferHandle)2761 bool teardownVkColorBufferLocked(uint32_t colorBufferHandle) {
2762 if (!sVkEmulation || !sVkEmulation->live) return false;
2763
2764 auto vk = sVkEmulation->dvk;
2765
2766 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2767
2768 if (!infoPtr) return false;
2769
2770 if (infoPtr->initialized) {
2771 auto& info = *infoPtr;
2772 {
2773 android::base::AutoLock lock(*sVkEmulation->queueLock);
2774 VK_CHECK(vk->vkQueueWaitIdle(sVkEmulation->queue));
2775 }
2776 vk->vkDestroyImageView(sVkEmulation->device, info.imageView, nullptr);
2777 vk->vkDestroySamplerYcbcrConversion(sVkEmulation->device, info.ycbcrConversion, nullptr);
2778 vk->vkDestroyImage(sVkEmulation->device, info.image, nullptr);
2779 freeExternalMemoryLocked(vk, &info.memory);
2780 }
2781
2782 sVkEmulation->colorBuffers.erase(colorBufferHandle);
2783
2784 return true;
2785 }
2786
teardownVkColorBuffer(uint32_t colorBufferHandle)2787 bool teardownVkColorBuffer(uint32_t colorBufferHandle) {
2788 if (!sVkEmulation || !sVkEmulation->live) return false;
2789
2790 AutoLock lock(sVkEmulationLock);
2791 return teardownVkColorBufferLocked(colorBufferHandle);
2792 }
2793
importExtMemoryHandleToVkColorBuffer(uint32_t colorBufferHandle,uint32_t type,VK_EXT_MEMORY_HANDLE extMemHandle)2794 bool importExtMemoryHandleToVkColorBuffer(uint32_t colorBufferHandle, uint32_t type,
2795 VK_EXT_MEMORY_HANDLE extMemHandle) {
2796 if (!sVkEmulation || !sVkEmulation->live) {
2797 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "VkEmulation not available.";
2798 }
2799 if (VK_EXT_MEMORY_HANDLE_INVALID == extMemHandle) {
2800 return false;
2801 }
2802
2803 AutoLock lock(sVkEmulationLock);
2804 // Initialize the colorBuffer with the external memory handle
2805 // Note that this will fail if the colorBuffer memory was previously initialized.
2806 return initializeVkColorBufferLocked(colorBufferHandle, extMemHandle);
2807 }
2808
getColorBufferInfo(uint32_t colorBufferHandle)2809 VkEmulation::ColorBufferInfo getColorBufferInfo(uint32_t colorBufferHandle) {
2810 VkEmulation::ColorBufferInfo res;
2811
2812 AutoLock lock(sVkEmulationLock);
2813
2814 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2815
2816 if (!infoPtr) return res;
2817
2818 res = *infoPtr;
2819 return res;
2820 }
2821
colorBufferNeedsUpdateBetweenGlAndVk(const VkEmulation::ColorBufferInfo & colorBufferInfo)2822 bool colorBufferNeedsUpdateBetweenGlAndVk(const VkEmulation::ColorBufferInfo& colorBufferInfo) {
2823 // GL is not used.
2824 if (colorBufferInfo.vulkanMode == VkEmulation::VulkanMode::VulkanOnly) {
2825 return false;
2826 }
2827
2828 // YUV formats require extra conversions.
2829 if (colorBufferInfo.frameworkFormat != FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE) {
2830 return true;
2831 }
2832
2833 // GL and VK are sharing the same underlying memory.
2834 if (colorBufferInfo.glExported) {
2835 return false;
2836 }
2837
2838 return true;
2839 }
2840
colorBufferNeedsUpdateBetweenGlAndVk(uint32_t colorBufferHandle)2841 bool colorBufferNeedsUpdateBetweenGlAndVk(uint32_t colorBufferHandle) {
2842 if (!sVkEmulation || !sVkEmulation->live) {
2843 return false;
2844 }
2845
2846 AutoLock lock(sVkEmulationLock);
2847
2848 auto colorBufferInfo = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2849 if (!colorBufferInfo) {
2850 return false;
2851 }
2852
2853 return colorBufferNeedsUpdateBetweenGlAndVk(*colorBufferInfo);
2854 }
2855
readColorBufferToBytes(uint32_t colorBufferHandle,std::vector<uint8_t> * bytes)2856 bool readColorBufferToBytes(uint32_t colorBufferHandle, std::vector<uint8_t>* bytes) {
2857 if (!sVkEmulation || !sVkEmulation->live) {
2858 VERBOSE("VkEmulation not available.");
2859 return false;
2860 }
2861
2862 AutoLock lock(sVkEmulationLock);
2863
2864 auto colorBufferInfo = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2865 if (!colorBufferInfo) {
2866 VERBOSE("Failed to read from ColorBuffer:%d, not found.", colorBufferHandle);
2867 bytes->clear();
2868 return false;
2869 }
2870
2871 VkDeviceSize bytesNeeded = 0;
2872 bool result = getFormatTransferInfo(colorBufferInfo->imageCreateInfoShallow.format,
2873 colorBufferInfo->imageCreateInfoShallow.extent.width,
2874 colorBufferInfo->imageCreateInfoShallow.extent.height,
2875 &bytesNeeded, nullptr);
2876 if (!result) {
2877 ERR("Failed to read from ColorBuffer:%d, failed to get read size.", colorBufferHandle);
2878 return false;
2879 }
2880
2881 bytes->resize(bytesNeeded);
2882
2883 result = readColorBufferToBytesLocked(
2884 colorBufferHandle, 0, 0, colorBufferInfo->imageCreateInfoShallow.extent.width,
2885 colorBufferInfo->imageCreateInfoShallow.extent.height, bytes->data(), bytes->size());
2886 if (!result) {
2887 ERR("Failed to read from ColorBuffer:%d, failed to get read size.", colorBufferHandle);
2888 return false;
2889 }
2890
2891 return true;
2892 }
2893
readColorBufferToBytes(uint32_t colorBufferHandle,uint32_t x,uint32_t y,uint32_t w,uint32_t h,void * outPixels,uint64_t outPixelsSize)2894 bool readColorBufferToBytes(uint32_t colorBufferHandle, uint32_t x, uint32_t y, uint32_t w,
2895 uint32_t h, void* outPixels, uint64_t outPixelsSize) {
2896 if (!sVkEmulation || !sVkEmulation->live) {
2897 ERR("VkEmulation not available.");
2898 return false;
2899 }
2900
2901 AutoLock lock(sVkEmulationLock);
2902 return readColorBufferToBytesLocked(colorBufferHandle, x, y, w, h, outPixels, outPixelsSize);
2903 }
2904
readColorBufferToBytesLocked(uint32_t colorBufferHandle,uint32_t x,uint32_t y,uint32_t w,uint32_t h,void * outPixels,uint64_t outPixelsSize)2905 bool readColorBufferToBytesLocked(uint32_t colorBufferHandle, uint32_t x, uint32_t y, uint32_t w,
2906 uint32_t h, void* outPixels, uint64_t outPixelsSize) {
2907 if (!sVkEmulation || !sVkEmulation->live) {
2908 ERR("VkEmulation not available.");
2909 return false;
2910 }
2911
2912 auto vk = sVkEmulation->dvk;
2913
2914 auto colorBufferInfo = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2915 if (!colorBufferInfo) {
2916 ERR("Failed to read from ColorBuffer:%d, not found.", colorBufferHandle);
2917 return false;
2918 }
2919
2920 if (!colorBufferInfo->image) {
2921 ERR("Failed to read from ColorBuffer:%d, no VkImage.", colorBufferHandle);
2922 return false;
2923 }
2924
2925 if (x != 0 || y != 0 || w != colorBufferInfo->imageCreateInfoShallow.extent.width ||
2926 h != colorBufferInfo->imageCreateInfoShallow.extent.height) {
2927 ERR("Failed to read from ColorBuffer:%d, unhandled subrect.", colorBufferHandle);
2928 return false;
2929 }
2930
2931 VkDeviceSize bufferCopySize = 0;
2932 std::vector<VkBufferImageCopy> bufferImageCopies;
2933 if (!getFormatTransferInfo(colorBufferInfo->imageCreateInfoShallow.format,
2934 colorBufferInfo->imageCreateInfoShallow.extent.width,
2935 colorBufferInfo->imageCreateInfoShallow.extent.height,
2936 &bufferCopySize, &bufferImageCopies)) {
2937 ERR("Failed to read ColorBuffer:%d, unable to get transfer info.", colorBufferHandle);
2938 return false;
2939 }
2940
2941 // Avoid transitioning from VK_IMAGE_LAYOUT_UNDEFINED. Unfortunetly, Android does not
2942 // yet have a mechanism for sharing the expected VkImageLayout. However, the Vulkan
2943 // spec's image layout transition sections says "If the old layout is
2944 // VK_IMAGE_LAYOUT_UNDEFINED, the contents of that range may be discarded." Some
2945 // Vulkan drivers have been observed to actually perform the discard which leads to
2946 // ColorBuffer-s being unintentionally cleared. See go/ahb-vkimagelayout for a more
2947 // thorough write up.
2948 if (colorBufferInfo->currentLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
2949 colorBufferInfo->currentLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2950 }
2951
2952 // Record our synchronization commands.
2953 const VkCommandBufferBeginInfo beginInfo = {
2954 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
2955 .pNext = nullptr,
2956 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
2957 };
2958
2959 VkCommandBuffer commandBuffer = sVkEmulation->commandBuffer;
2960
2961 VK_CHECK(vk->vkBeginCommandBuffer(commandBuffer, &beginInfo));
2962
2963 sVkEmulation->debugUtilsHelper.cmdBeginDebugLabel(
2964 commandBuffer, "readColorBufferToBytes(ColorBuffer:%d)", colorBufferHandle);
2965
2966 VkImageLayout currentLayout = colorBufferInfo->currentLayout;
2967 VkImageLayout transferSrcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
2968
2969 const VkImageMemoryBarrier toTransferSrcImageBarrier = {
2970 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
2971 .pNext = nullptr,
2972 .srcAccessMask = 0,
2973 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
2974 .oldLayout = currentLayout,
2975 .newLayout = transferSrcLayout,
2976 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2977 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2978 .image = colorBufferInfo->image,
2979 .subresourceRange =
2980 {
2981 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2982 .baseMipLevel = 0,
2983 .levelCount = 1,
2984 .baseArrayLayer = 0,
2985 .layerCount = 1,
2986 },
2987 };
2988
2989 vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
2990 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
2991 &toTransferSrcImageBarrier);
2992
2993 vk->vkCmdCopyImageToBuffer(commandBuffer, colorBufferInfo->image,
2994 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, sVkEmulation->staging.buffer,
2995 bufferImageCopies.size(), bufferImageCopies.data());
2996
2997 // Change back to original layout
2998 if (currentLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
2999 // Transfer back to original layout.
3000 const VkImageMemoryBarrier toCurrentLayoutImageBarrier = {
3001 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
3002 .pNext = nullptr,
3003 .srcAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
3004 .dstAccessMask = VK_ACCESS_NONE_KHR,
3005 .oldLayout = transferSrcLayout,
3006 .newLayout = colorBufferInfo->currentLayout,
3007 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3008 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3009 .image = colorBufferInfo->image,
3010 .subresourceRange =
3011 {
3012 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
3013 .baseMipLevel = 0,
3014 .levelCount = 1,
3015 .baseArrayLayer = 0,
3016 .layerCount = 1,
3017 },
3018 };
3019 vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
3020 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
3021 &toCurrentLayoutImageBarrier);
3022 } else {
3023 colorBufferInfo->currentLayout = transferSrcLayout;
3024 }
3025
3026 sVkEmulation->debugUtilsHelper.cmdEndDebugLabel(commandBuffer);
3027
3028 VK_CHECK(vk->vkEndCommandBuffer(commandBuffer));
3029
3030 const VkSubmitInfo submitInfo = {
3031 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3032 .pNext = nullptr,
3033 .waitSemaphoreCount = 0,
3034 .pWaitSemaphores = nullptr,
3035 .pWaitDstStageMask = nullptr,
3036 .commandBufferCount = 1,
3037 .pCommandBuffers = &commandBuffer,
3038 .signalSemaphoreCount = 0,
3039 .pSignalSemaphores = nullptr,
3040 };
3041
3042 {
3043 android::base::AutoLock lock(*sVkEmulation->queueLock);
3044 VK_CHECK(vk->vkQueueSubmit(sVkEmulation->queue, 1, &submitInfo,
3045 sVkEmulation->commandBufferFence));
3046 }
3047
3048 static constexpr uint64_t ANB_MAX_WAIT_NS = 5ULL * 1000ULL * 1000ULL * 1000ULL;
3049 VkResult waitRes = vk->vkWaitForFences(
3050 sVkEmulation->device, 1, &sVkEmulation->commandBufferFence, VK_TRUE, ANB_MAX_WAIT_NS);
3051 if (waitRes == VK_TIMEOUT) {
3052 // Give a warning and try once more on a timeout error
3053 ERR("readColorBufferToBytesLocked vkWaitForFences failed with timeout error "
3054 "(cb:%d, x:%d, y:%d, w:%d, h:%d, bufferCopySize:%llu), retrying...",
3055 colorBufferHandle, x, y, w, h, bufferCopySize);
3056 waitRes = vk->vkWaitForFences(sVkEmulation->device, 1, &sVkEmulation->commandBufferFence,
3057 VK_TRUE, ANB_MAX_WAIT_NS*2);
3058 }
3059
3060 VK_CHECK(waitRes);
3061
3062 VK_CHECK(vk->vkResetFences(sVkEmulation->device, 1, &sVkEmulation->commandBufferFence));
3063
3064 const VkMappedMemoryRange toInvalidate = {
3065 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3066 .pNext = nullptr,
3067 .memory = sVkEmulation->staging.memory.memory,
3068 .offset = 0,
3069 .size = VK_WHOLE_SIZE,
3070 };
3071
3072 VK_CHECK(vk->vkInvalidateMappedMemoryRanges(sVkEmulation->device, 1, &toInvalidate));
3073
3074 const auto* stagingBufferPtr = sVkEmulation->staging.memory.mappedPtr;
3075 if (bufferCopySize > outPixelsSize) {
3076 ERR("Invalid buffer size for readColorBufferToBytes operation."
3077 "Required: %llu, Actual: %llu",
3078 bufferCopySize, outPixelsSize);
3079 bufferCopySize = outPixelsSize;
3080 }
3081 std::memcpy(outPixels, stagingBufferPtr, bufferCopySize);
3082
3083 return true;
3084 }
3085
updateColorBufferFromBytes(uint32_t colorBufferHandle,const std::vector<uint8_t> & bytes)3086 bool updateColorBufferFromBytes(uint32_t colorBufferHandle, const std::vector<uint8_t>& bytes) {
3087 if (!sVkEmulation || !sVkEmulation->live) {
3088 VERBOSE("VkEmulation not available.");
3089 return false;
3090 }
3091
3092 AutoLock lock(sVkEmulationLock);
3093
3094 auto colorBufferInfo = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
3095 if (!colorBufferInfo) {
3096 VERBOSE("Failed to update ColorBuffer:%d, not found.", colorBufferHandle);
3097 return false;
3098 }
3099
3100 return updateColorBufferFromBytesLocked(
3101 colorBufferHandle, 0, 0, colorBufferInfo->imageCreateInfoShallow.extent.width,
3102 colorBufferInfo->imageCreateInfoShallow.extent.height, bytes.data(), bytes.size());
3103 }
3104
updateColorBufferFromBytes(uint32_t colorBufferHandle,uint32_t x,uint32_t y,uint32_t w,uint32_t h,const void * pixels)3105 bool updateColorBufferFromBytes(uint32_t colorBufferHandle, uint32_t x, uint32_t y, uint32_t w,
3106 uint32_t h, const void* pixels) {
3107 if (!sVkEmulation || !sVkEmulation->live) {
3108 ERR("VkEmulation not available.");
3109 return false;
3110 }
3111
3112 AutoLock lock(sVkEmulationLock);
3113 return updateColorBufferFromBytesLocked(colorBufferHandle, x, y, w, h, pixels, 0);
3114 }
3115
convertRgbToRgbaPixels(void * dst,const void * src,uint32_t w,uint32_t h)3116 static void convertRgbToRgbaPixels(void* dst, const void* src, uint32_t w, uint32_t h) {
3117 const size_t pixelCount = w * h;
3118 const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(src);
3119 uint32_t* dstPixels = reinterpret_cast<uint32_t*>(dst);
3120 for (size_t i = 0; i < pixelCount; ++i) {
3121 const uint8_t r = *(srcBytes++);
3122 const uint8_t g = *(srcBytes++);
3123 const uint8_t b = *(srcBytes++);
3124 *(dstPixels++) = 0xff000000 | (b << 16) | (g << 8) | r;
3125 }
3126 }
3127
updateColorBufferFromBytesLocked(uint32_t colorBufferHandle,uint32_t x,uint32_t y,uint32_t w,uint32_t h,const void * pixels,size_t inputPixelsSize)3128 static bool updateColorBufferFromBytesLocked(uint32_t colorBufferHandle, uint32_t x, uint32_t y,
3129 uint32_t w, uint32_t h, const void* pixels,
3130 size_t inputPixelsSize) {
3131 if (!sVkEmulation || !sVkEmulation->live) {
3132 ERR("VkEmulation not available.");
3133 return false;
3134 }
3135
3136 auto vk = sVkEmulation->dvk;
3137
3138 auto colorBufferInfo = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
3139 if (!colorBufferInfo) {
3140 ERR("Failed to update ColorBuffer:%d, not found.", colorBufferHandle);
3141 return false;
3142 }
3143
3144 if (!colorBufferInfo->image) {
3145 ERR("Failed to update ColorBuffer:%d, no VkImage.", colorBufferHandle);
3146 return false;
3147 }
3148
3149 if (x != 0 || y != 0 || w != colorBufferInfo->imageCreateInfoShallow.extent.width ||
3150 h != colorBufferInfo->imageCreateInfoShallow.extent.height) {
3151 ERR("Failed to update ColorBuffer:%d, unhandled subrect.", colorBufferHandle);
3152 return false;
3153 }
3154
3155 VkDeviceSize dstBufferSize = 0;
3156 std::vector<VkBufferImageCopy> bufferImageCopies;
3157 if (!getFormatTransferInfo(colorBufferInfo->imageCreateInfoShallow.format,
3158 colorBufferInfo->imageCreateInfoShallow.extent.width,
3159 colorBufferInfo->imageCreateInfoShallow.extent.height,
3160 &dstBufferSize, &bufferImageCopies)) {
3161 ERR("Failed to update ColorBuffer:%d, unable to get transfer info.", colorBufferHandle);
3162 return false;
3163 }
3164
3165 const VkDeviceSize stagingBufferSize = sVkEmulation->staging.size;
3166 if (dstBufferSize > stagingBufferSize) {
3167 ERR("Failed to update ColorBuffer:%d, transfer size %" PRIu64
3168 " too large for staging buffer size:%" PRIu64 ".",
3169 colorBufferHandle, dstBufferSize, stagingBufferSize);
3170 return false;
3171 }
3172
3173 bool isThreeByteRgb =
3174 (colorBufferInfo->internalFormat == GL_RGB || colorBufferInfo->internalFormat == GL_RGB8);
3175 size_t expectedInputSize = (isThreeByteRgb ? dstBufferSize / 4 * 3 : dstBufferSize);
3176
3177 if (inputPixelsSize != 0 && inputPixelsSize != expectedInputSize) {
3178 ERR("Unexpected contents size when trying to update ColorBuffer:%d, "
3179 "provided:%zu expected:%zu",
3180 colorBufferHandle, inputPixelsSize, expectedInputSize);
3181 return false;
3182 }
3183
3184 auto* stagingBufferPtr = sVkEmulation->staging.memory.mappedPtr;
3185
3186 if (isThreeByteRgb) {
3187 // Convert RGB to RGBA, since only for these types glFormat2VkFormat() makes
3188 // an incompatible choice of 4-byte backing VK_FORMAT_R8G8B8A8_UNORM.
3189 // b/281550953
3190 convertRgbToRgbaPixels(stagingBufferPtr, pixels, w, h);
3191 } else {
3192 std::memcpy(stagingBufferPtr, pixels, dstBufferSize);
3193 }
3194
3195 // NOTE: Host vulkan state might not know the correct layout of the
3196 // destination image, as guest grallocs are designed to be used by either
3197 // GL or Vulkan. Consequently, we typically avoid image transitions from
3198 // VK_IMAGE_LAYOUT_UNDEFINED as Vulkan spec allows the contents to be
3199 // discarded (and some drivers have been observed doing it). You can
3200 // check go/ahb-vkimagelayout for more information. But since this
3201 // function does not allow subrects (see above), it will write the
3202 // provided contents onto the entirety of the target buffer, meaning this
3203 // risk of discarding data should not impact anything.
3204
3205 // Record our synchronization commands.
3206 const VkCommandBufferBeginInfo beginInfo = {
3207 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
3208 .pNext = nullptr,
3209 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
3210 };
3211
3212 VkCommandBuffer commandBuffer = sVkEmulation->commandBuffer;
3213
3214 VK_CHECK(vk->vkBeginCommandBuffer(commandBuffer, &beginInfo));
3215
3216 sVkEmulation->debugUtilsHelper.cmdBeginDebugLabel(
3217 commandBuffer, "updateColorBufferFromBytes(ColorBuffer:%d)", colorBufferHandle);
3218
3219 bool isSnapshotLoad =
3220 VkDecoderGlobalState::get()->getSnapshotState() == VkDecoderGlobalState::Loading;
3221 VkImageLayout currentLayout = colorBufferInfo->currentLayout;
3222 if (isSnapshotLoad) {
3223 currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
3224 }
3225 const VkImageMemoryBarrier toTransferDstImageBarrier = {
3226 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
3227 .pNext = nullptr,
3228 .srcAccessMask = 0,
3229 .dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
3230 .oldLayout = currentLayout,
3231 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3232 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3233 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3234 .image = colorBufferInfo->image,
3235 .subresourceRange =
3236 {
3237 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
3238 .baseMipLevel = 0,
3239 .levelCount = 1,
3240 .baseArrayLayer = 0,
3241 .layerCount = 1,
3242 },
3243 };
3244
3245 vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3246 VK_PIPELINE_STAGE_HOST_BIT, 0, 0, nullptr, 0, nullptr, 1,
3247 &toTransferDstImageBarrier);
3248
3249 // Copy from staging buffer to color buffer image
3250 vk->vkCmdCopyBufferToImage(commandBuffer, sVkEmulation->staging.buffer, colorBufferInfo->image,
3251 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, bufferImageCopies.size(),
3252 bufferImageCopies.data());
3253
3254 if (colorBufferInfo->currentLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
3255 const VkImageMemoryBarrier toCurrentLayoutImageBarrier = {
3256 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
3257 .pNext = nullptr,
3258 .srcAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
3259 .dstAccessMask = VK_ACCESS_NONE_KHR,
3260 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3261 .newLayout = colorBufferInfo->currentLayout,
3262 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3263 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3264 .image = colorBufferInfo->image,
3265 .subresourceRange =
3266 {
3267 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
3268 .baseMipLevel = 0,
3269 .levelCount = 1,
3270 .baseArrayLayer = 0,
3271 .layerCount = 1,
3272 },
3273 };
3274 vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_HOST_BIT,
3275 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1,
3276 &toCurrentLayoutImageBarrier);
3277 } else {
3278 colorBufferInfo->currentLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
3279 }
3280
3281 sVkEmulation->debugUtilsHelper.cmdEndDebugLabel(commandBuffer);
3282
3283 VK_CHECK(vk->vkEndCommandBuffer(commandBuffer));
3284
3285 const VkSubmitInfo submitInfo = {
3286 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3287 .pNext = nullptr,
3288 .waitSemaphoreCount = 0,
3289 .pWaitSemaphores = nullptr,
3290 .pWaitDstStageMask = nullptr,
3291 .commandBufferCount = 1,
3292 .pCommandBuffers = &commandBuffer,
3293 .signalSemaphoreCount = 0,
3294 .pSignalSemaphores = nullptr,
3295 };
3296
3297 {
3298 android::base::AutoLock lock(*sVkEmulation->queueLock);
3299 VK_CHECK(vk->vkQueueSubmit(sVkEmulation->queue, 1, &submitInfo,
3300 sVkEmulation->commandBufferFence));
3301 }
3302
3303 static constexpr uint64_t ANB_MAX_WAIT_NS = 5ULL * 1000ULL * 1000ULL * 1000ULL;
3304
3305 VK_CHECK(vk->vkWaitForFences(sVkEmulation->device, 1, &sVkEmulation->commandBufferFence,
3306 VK_TRUE, ANB_MAX_WAIT_NS));
3307
3308 VK_CHECK(vk->vkResetFences(sVkEmulation->device, 1, &sVkEmulation->commandBufferFence));
3309
3310 const VkMappedMemoryRange toInvalidate = {
3311 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3312 .pNext = nullptr,
3313 .memory = sVkEmulation->staging.memory.memory,
3314 .offset = 0,
3315 .size = VK_WHOLE_SIZE,
3316 };
3317 VK_CHECK(vk->vkInvalidateMappedMemoryRanges(sVkEmulation->device, 1, &toInvalidate));
3318
3319 return true;
3320 }
3321
getColorBufferExtMemoryHandle(uint32_t colorBuffer)3322 VK_EXT_MEMORY_HANDLE getColorBufferExtMemoryHandle(uint32_t colorBuffer) {
3323 if (!sVkEmulation || !sVkEmulation->live) return VK_EXT_MEMORY_HANDLE_INVALID;
3324
3325 AutoLock lock(sVkEmulationLock);
3326
3327 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBuffer);
3328
3329 if (!infoPtr) {
3330 // Color buffer not found; this is usually OK.
3331 return VK_EXT_MEMORY_HANDLE_INVALID;
3332 }
3333
3334 return infoPtr->memory.externalHandle;
3335 }
3336
3337 #ifdef __APPLE__
getColorBufferMetalMemoryHandle(uint32_t colorBuffer)3338 MTLResource_id getColorBufferMetalMemoryHandle(uint32_t colorBuffer) {
3339 if (!sVkEmulation || !sVkEmulation->live) return nullptr;
3340
3341 AutoLock lock(sVkEmulationLock);
3342
3343 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBuffer);
3344
3345 if (!infoPtr) {
3346 // Color buffer not found; this is usually OK.
3347 return nullptr;
3348 }
3349
3350 return infoPtr->memory.externalMetalHandle;
3351 }
3352
3353 // TODO0(b/351765838): Temporary function for MoltenVK
getColorBufferVkImage(uint32_t colorBufferHandle)3354 VkImage getColorBufferVkImage(uint32_t colorBufferHandle) {
3355 if (!sVkEmulation || !sVkEmulation->live) return nullptr;
3356
3357 AutoLock lock(sVkEmulationLock);
3358
3359 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
3360
3361 if (!infoPtr) {
3362 // Color buffer not found; this is usually OK.
3363 return nullptr;
3364 }
3365
3366 return infoPtr->image;
3367 }
3368 #endif // __APPLE__
3369
setColorBufferVulkanMode(uint32_t colorBuffer,uint32_t vulkanMode)3370 bool setColorBufferVulkanMode(uint32_t colorBuffer, uint32_t vulkanMode) {
3371 if (!sVkEmulation || !sVkEmulation->live) return false;
3372
3373 AutoLock lock(sVkEmulationLock);
3374
3375 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBuffer);
3376
3377 if (!infoPtr) {
3378 return false;
3379 }
3380
3381 infoPtr->vulkanMode = static_cast<VkEmulation::VulkanMode>(vulkanMode);
3382
3383 return true;
3384 }
3385
mapGpaToBufferHandle(uint32_t bufferHandle,uint64_t gpa,uint64_t size)3386 int32_t mapGpaToBufferHandle(uint32_t bufferHandle, uint64_t gpa, uint64_t size) {
3387 if (!sVkEmulation || !sVkEmulation->live) return VK_ERROR_DEVICE_LOST;
3388
3389 AutoLock lock(sVkEmulationLock);
3390
3391 VkEmulation::ExternalMemoryInfo* memoryInfoPtr = nullptr;
3392
3393 auto colorBufferInfoPtr = android::base::find(sVkEmulation->colorBuffers, bufferHandle);
3394 if (colorBufferInfoPtr) {
3395 memoryInfoPtr = &colorBufferInfoPtr->memory;
3396 }
3397 auto bufferInfoPtr = android::base::find(sVkEmulation->buffers, bufferHandle);
3398 if (bufferInfoPtr) {
3399 memoryInfoPtr = &bufferInfoPtr->memory;
3400 }
3401
3402 if (!memoryInfoPtr) {
3403 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
3404 }
3405
3406 // memory should be already mapped to host.
3407 if (!memoryInfoPtr->mappedPtr) {
3408 return VK_ERROR_MEMORY_MAP_FAILED;
3409 }
3410
3411 memoryInfoPtr->gpa = gpa;
3412 memoryInfoPtr->pageAlignedHva =
3413 reinterpret_cast<uint8_t*>(memoryInfoPtr->mappedPtr) + memoryInfoPtr->bindOffset;
3414
3415 size_t rawSize = memoryInfoPtr->size + memoryInfoPtr->pageOffset;
3416 if (size && size < rawSize) {
3417 rawSize = size;
3418 }
3419
3420 memoryInfoPtr->sizeToPage = ((rawSize + kPageSize - 1) >> kPageBits) << kPageBits;
3421
3422 VERBOSE("mapGpaToColorBuffer: hva = %p, pageAlignedHva = %p -> [ 0x%" PRIxPTR ", 0x%" PRIxPTR
3423 " ]",
3424 memoryInfoPtr->mappedPtr, memoryInfoPtr->pageAlignedHva, memoryInfoPtr->gpa,
3425 memoryInfoPtr->gpa + memoryInfoPtr->sizeToPage);
3426
3427 if (sVkEmulation->occupiedGpas.find(gpa) != sVkEmulation->occupiedGpas.end()) {
3428 // emugl::emugl_crash_reporter("FATAL: already mapped gpa 0x%lx! ", gpa);
3429 return VK_ERROR_MEMORY_MAP_FAILED;
3430 }
3431
3432 get_emugl_vm_operations().mapUserBackedRam(gpa, memoryInfoPtr->pageAlignedHva,
3433 memoryInfoPtr->sizeToPage);
3434
3435 sVkEmulation->occupiedGpas.insert(gpa);
3436
3437 return memoryInfoPtr->pageOffset;
3438 }
3439
getBufferAllocationInfo(uint32_t bufferHandle,VkDeviceSize * outSize,uint32_t * outMemoryTypeIndex,bool * outMemoryIsDedicatedAlloc)3440 bool getBufferAllocationInfo(uint32_t bufferHandle, VkDeviceSize* outSize,
3441 uint32_t* outMemoryTypeIndex, bool* outMemoryIsDedicatedAlloc) {
3442 if (!sVkEmulation || !sVkEmulation->live) {
3443 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Vulkan emulation not available.";
3444 }
3445
3446 AutoLock lock(sVkEmulationLock);
3447
3448 auto info = android::base::find(sVkEmulation->buffers, bufferHandle);
3449 if (!info) {
3450 return false;
3451 }
3452
3453 if (outSize) {
3454 *outSize = info->memory.size;
3455 }
3456
3457 if (outMemoryTypeIndex) {
3458 *outMemoryTypeIndex = info->memory.typeIndex;
3459 }
3460
3461 if (outMemoryIsDedicatedAlloc) {
3462 *outMemoryIsDedicatedAlloc = info->memory.dedicatedAllocation;
3463 }
3464
3465 return true;
3466 }
3467
setupVkBuffer(uint64_t size,uint32_t bufferHandle,bool vulkanOnly,uint32_t memoryProperty)3468 bool setupVkBuffer(uint64_t size, uint32_t bufferHandle, bool vulkanOnly, uint32_t memoryProperty) {
3469 if (vulkanOnly == false) {
3470 ERR("Data buffers should be vulkanOnly. Setup failed.");
3471 return false;
3472 }
3473
3474 auto vk = sVkEmulation->dvk;
3475
3476 AutoLock lock(sVkEmulationLock);
3477
3478 auto infoPtr = android::base::find(sVkEmulation->buffers, bufferHandle);
3479
3480 // Already setup
3481 if (infoPtr) {
3482 return true;
3483 }
3484
3485 VkEmulation::BufferInfo res;
3486
3487 res.handle = bufferHandle;
3488
3489 res.size = size;
3490 res.usageFlags = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
3491 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
3492 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
3493 res.createFlags = 0;
3494
3495 res.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
3496
3497 // Create the buffer. If external memory is supported, make it external.
3498 VkExternalMemoryBufferCreateInfo extBufferCi = {
3499 VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
3500 0,
3501 VK_EXT_MEMORY_HANDLE_TYPE_BIT,
3502 };
3503 #if defined(__APPLE__)
3504 if (sVkEmulation->instanceSupportsMoltenVK) {
3505 // Using a different handle type when in MoltenVK mode
3506 extBufferCi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLBUFFER_BIT_EXT;
3507 }
3508 #endif
3509 void* extBufferCiPtr = nullptr;
3510 if (sVkEmulation->deviceInfo.supportsExternalMemoryImport ||
3511 sVkEmulation->deviceInfo.supportsExternalMemoryExport) {
3512 extBufferCiPtr = &extBufferCi;
3513 }
3514
3515 VkBufferCreateInfo bufferCi = {
3516 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
3517 extBufferCiPtr,
3518 res.createFlags,
3519 res.size,
3520 res.usageFlags,
3521 res.sharingMode,
3522 /* queueFamilyIndexCount */ 0,
3523 /* pQueueFamilyIndices */ nullptr,
3524 };
3525
3526 VkResult createRes = vk->vkCreateBuffer(sVkEmulation->device, &bufferCi, nullptr, &res.buffer);
3527
3528 if (createRes != VK_SUCCESS) {
3529 WARN("Failed to create Vulkan Buffer for Buffer %d, Error: %s", bufferHandle,
3530 string_VkResult(createRes));
3531 return false;
3532 }
3533 bool useDedicated = false;
3534 if (vk->vkGetBufferMemoryRequirements2KHR) {
3535 VkMemoryDedicatedRequirements dedicated_reqs{
3536 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, nullptr};
3537 VkMemoryRequirements2 reqs{VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &dedicated_reqs};
3538
3539 VkBufferMemoryRequirementsInfo2 info{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
3540 nullptr, res.buffer};
3541 vk->vkGetBufferMemoryRequirements2KHR(sVkEmulation->device, &info, &reqs);
3542 useDedicated = dedicated_reqs.requiresDedicatedAllocation;
3543 res.memReqs = reqs.memoryRequirements;
3544 } else {
3545 vk->vkGetBufferMemoryRequirements(sVkEmulation->device, res.buffer, &res.memReqs);
3546 }
3547
3548 // Currently we only care about two memory properties: DEVICE_LOCAL
3549 // and HOST_VISIBLE; other memory properties specified in
3550 // rcSetColorBufferVulkanMode2() call will be ignored for now.
3551 memoryProperty = memoryProperty &
3552 (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
3553
3554 res.memory.size = res.memReqs.size;
3555
3556 // Determine memory type.
3557 res.memory.typeIndex = getValidMemoryTypeIndex(res.memReqs.memoryTypeBits, memoryProperty);
3558
3559 VERBOSE(
3560 "Buffer %d "
3561 "allocation size and type index: %lu, %d, "
3562 "allocated memory property: %d, "
3563 "requested memory property: %d",
3564 bufferHandle, res.memory.size, res.memory.typeIndex,
3565 sVkEmulation->deviceInfo.memProps.memoryTypes[res.memory.typeIndex].propertyFlags,
3566 memoryProperty);
3567
3568 bool isHostVisible = memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
3569 Optional<uint64_t> deviceAlignment =
3570 isHostVisible ? Optional<uint64_t>(res.memReqs.alignment) : kNullopt;
3571 Optional<VkBuffer> dedicated_buffer = useDedicated ? Optional<VkBuffer>(res.buffer) : kNullopt;
3572 bool allocRes = allocExternalMemory(vk, &res.memory, true /* actuallyExternal */,
3573 deviceAlignment, dedicated_buffer);
3574
3575 if (!allocRes) {
3576 WARN("Failed to allocate ColorBuffer with Vulkan backing.");
3577 }
3578
3579 res.memory.pageOffset = reinterpret_cast<uint64_t>(res.memory.mappedPtr) % kPageSize;
3580 res.memory.bindOffset = res.memory.pageOffset ? kPageSize - res.memory.pageOffset : 0u;
3581
3582 VkResult bindBufferMemoryRes =
3583 vk->vkBindBufferMemory(sVkEmulation->device, res.buffer, res.memory.memory, 0);
3584
3585 if (bindBufferMemoryRes != VK_SUCCESS) {
3586 ERR("Failed to bind buffer memory. Error: %s\n", string_VkResult(bindBufferMemoryRes));
3587 return bindBufferMemoryRes;
3588 }
3589
3590 bool isHostVisibleMemory = memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
3591
3592 if (isHostVisibleMemory) {
3593 VkResult mapMemoryRes = vk->vkMapMemory(sVkEmulation->device, res.memory.memory, 0,
3594 res.memory.size, {}, &res.memory.mappedPtr);
3595
3596 if (mapMemoryRes != VK_SUCCESS) {
3597 ERR("Failed to map image memory. Error: %s\n", string_VkResult(mapMemoryRes));
3598 return false;
3599 }
3600 }
3601
3602 res.glExported = false;
3603
3604 sVkEmulation->buffers[bufferHandle] = res;
3605
3606 sVkEmulation->debugUtilsHelper.addDebugLabel(res.buffer, "Buffer:%d", bufferHandle);
3607 sVkEmulation->debugUtilsHelper.addDebugLabel(res.memory.memory, "Buffer:%d", bufferHandle);
3608
3609 return allocRes;
3610 }
3611
teardownVkBuffer(uint32_t bufferHandle)3612 bool teardownVkBuffer(uint32_t bufferHandle) {
3613 if (!sVkEmulation || !sVkEmulation->live) return false;
3614
3615 auto vk = sVkEmulation->dvk;
3616 AutoLock lock(sVkEmulationLock);
3617
3618 auto infoPtr = android::base::find(sVkEmulation->buffers, bufferHandle);
3619 if (!infoPtr) return false;
3620 {
3621 android::base::AutoLock lock(*sVkEmulation->queueLock);
3622 VK_CHECK(vk->vkQueueWaitIdle(sVkEmulation->queue));
3623 }
3624 auto& info = *infoPtr;
3625
3626 vk->vkDestroyBuffer(sVkEmulation->device, info.buffer, nullptr);
3627 freeExternalMemoryLocked(vk, &info.memory);
3628 sVkEmulation->buffers.erase(bufferHandle);
3629
3630 return true;
3631 }
3632
getBufferExtMemoryHandle(uint32_t bufferHandle,uint32_t * outStreamHandleType)3633 VK_EXT_MEMORY_HANDLE getBufferExtMemoryHandle(uint32_t bufferHandle,
3634 uint32_t* outStreamHandleType) {
3635 if (!sVkEmulation || !sVkEmulation->live) return VK_EXT_MEMORY_HANDLE_INVALID;
3636
3637 AutoLock lock(sVkEmulationLock);
3638
3639 auto infoPtr = android::base::find(sVkEmulation->buffers, bufferHandle);
3640 if (!infoPtr) {
3641 // Color buffer not found; this is usually OK.
3642 return VK_EXT_MEMORY_HANDLE_INVALID;
3643 }
3644
3645 *outStreamHandleType = infoPtr->memory.streamHandleType;
3646 return infoPtr->memory.externalHandle;
3647 }
3648
3649 #ifdef __APPLE__
getBufferMetalMemoryHandle(uint32_t bufferHandle)3650 MTLResource_id getBufferMetalMemoryHandle(uint32_t bufferHandle) {
3651 if (!sVkEmulation || !sVkEmulation->live) return nullptr;
3652
3653 AutoLock lock(sVkEmulationLock);
3654
3655 auto infoPtr = android::base::find(sVkEmulation->buffers, bufferHandle);
3656 if (!infoPtr) {
3657 // Color buffer not found; this is usually OK.
3658 return nullptr;
3659 }
3660
3661 return infoPtr->memory.externalMetalHandle;
3662 }
3663 #endif
3664
readBufferToBytes(uint32_t bufferHandle,uint64_t offset,uint64_t size,void * outBytes)3665 bool readBufferToBytes(uint32_t bufferHandle, uint64_t offset, uint64_t size, void* outBytes) {
3666 if (!sVkEmulation || !sVkEmulation->live) {
3667 ERR("VkEmulation not available.");
3668 return false;
3669 }
3670
3671 auto vk = sVkEmulation->dvk;
3672
3673 AutoLock lock(sVkEmulationLock);
3674
3675 auto bufferInfo = android::base::find(sVkEmulation->buffers, bufferHandle);
3676 if (!bufferInfo) {
3677 ERR("Failed to read from Buffer:%d, not found.", bufferHandle);
3678 return false;
3679 }
3680
3681 const auto& stagingBufferInfo = sVkEmulation->staging;
3682 if (size > stagingBufferInfo.size) {
3683 ERR("Failed to read from Buffer:%d, staging buffer too small.", bufferHandle);
3684 return false;
3685 }
3686
3687 const VkCommandBufferBeginInfo beginInfo = {
3688 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
3689 .pNext = nullptr,
3690 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
3691 };
3692
3693 VkCommandBuffer commandBuffer = sVkEmulation->commandBuffer;
3694
3695 VK_CHECK(vk->vkBeginCommandBuffer(commandBuffer, &beginInfo));
3696
3697 sVkEmulation->debugUtilsHelper.cmdBeginDebugLabel(commandBuffer, "readBufferToBytes(Buffer:%d)",
3698 bufferHandle);
3699
3700 const VkBufferCopy bufferCopy = {
3701 .srcOffset = offset,
3702 .dstOffset = 0,
3703 .size = size,
3704 };
3705 vk->vkCmdCopyBuffer(commandBuffer, bufferInfo->buffer, stagingBufferInfo.buffer, 1,
3706 &bufferCopy);
3707
3708 sVkEmulation->debugUtilsHelper.cmdEndDebugLabel(commandBuffer);
3709
3710 VK_CHECK(vk->vkEndCommandBuffer(commandBuffer));
3711
3712 const VkSubmitInfo submitInfo = {
3713 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3714 .pNext = nullptr,
3715 .waitSemaphoreCount = 0,
3716 .pWaitSemaphores = nullptr,
3717 .pWaitDstStageMask = nullptr,
3718 .commandBufferCount = 1,
3719 .pCommandBuffers = &commandBuffer,
3720 .signalSemaphoreCount = 0,
3721 .pSignalSemaphores = nullptr,
3722 };
3723
3724 {
3725 android::base::AutoLock lock(*sVkEmulation->queueLock);
3726 VK_CHECK(vk->vkQueueSubmit(sVkEmulation->queue, 1, &submitInfo,
3727 sVkEmulation->commandBufferFence));
3728 }
3729
3730 static constexpr uint64_t ANB_MAX_WAIT_NS = 5ULL * 1000ULL * 1000ULL * 1000ULL;
3731
3732 VK_CHECK(vk->vkWaitForFences(sVkEmulation->device, 1, &sVkEmulation->commandBufferFence,
3733 VK_TRUE, ANB_MAX_WAIT_NS));
3734
3735 VK_CHECK(vk->vkResetFences(sVkEmulation->device, 1, &sVkEmulation->commandBufferFence));
3736
3737 const VkMappedMemoryRange toInvalidate = {
3738 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3739 .pNext = nullptr,
3740 .memory = stagingBufferInfo.memory.memory,
3741 .offset = 0,
3742 .size = size,
3743 };
3744
3745 VK_CHECK(vk->vkInvalidateMappedMemoryRanges(sVkEmulation->device, 1, &toInvalidate));
3746
3747 const void* srcPtr = reinterpret_cast<const void*>(
3748 reinterpret_cast<const char*>(stagingBufferInfo.memory.mappedPtr));
3749 void* dstPtr = outBytes;
3750 void* dstPtrOffset = reinterpret_cast<void*>(reinterpret_cast<char*>(dstPtr) + offset);
3751 std::memcpy(dstPtrOffset, srcPtr, size);
3752
3753 return true;
3754 }
3755
updateBufferFromBytes(uint32_t bufferHandle,uint64_t offset,uint64_t size,const void * bytes)3756 bool updateBufferFromBytes(uint32_t bufferHandle, uint64_t offset, uint64_t size,
3757 const void* bytes) {
3758 if (!sVkEmulation || !sVkEmulation->live) {
3759 ERR("VkEmulation not available.");
3760 return false;
3761 }
3762
3763 auto vk = sVkEmulation->dvk;
3764
3765 AutoLock lock(sVkEmulationLock);
3766
3767 auto bufferInfo = android::base::find(sVkEmulation->buffers, bufferHandle);
3768 if (!bufferInfo) {
3769 ERR("Failed to update Buffer:%d, not found.", bufferHandle);
3770 return false;
3771 }
3772
3773 const auto& stagingBufferInfo = sVkEmulation->staging;
3774 if (size > stagingBufferInfo.size) {
3775 ERR("Failed to update Buffer:%d, staging buffer too small.", bufferHandle);
3776 return false;
3777 }
3778
3779 const void* srcPtr = bytes;
3780 const void* srcPtrOffset =
3781 reinterpret_cast<const void*>(reinterpret_cast<const char*>(srcPtr) + offset);
3782 void* dstPtr = stagingBufferInfo.memory.mappedPtr;
3783 std::memcpy(dstPtr, srcPtrOffset, size);
3784
3785 const VkMappedMemoryRange toFlush = {
3786 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3787 .pNext = nullptr,
3788 .memory = stagingBufferInfo.memory.memory,
3789 .offset = 0,
3790 .size = size,
3791 };
3792 VK_CHECK(vk->vkFlushMappedMemoryRanges(sVkEmulation->device, 1, &toFlush));
3793
3794 const VkCommandBufferBeginInfo beginInfo = {
3795 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
3796 .pNext = nullptr,
3797 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
3798 };
3799
3800 VkCommandBuffer commandBuffer = sVkEmulation->commandBuffer;
3801
3802 VK_CHECK(vk->vkBeginCommandBuffer(commandBuffer, &beginInfo));
3803
3804 sVkEmulation->debugUtilsHelper.cmdBeginDebugLabel(
3805 commandBuffer, "updateBufferFromBytes(Buffer:%d)", bufferHandle);
3806
3807 const VkBufferCopy bufferCopy = {
3808 .srcOffset = 0,
3809 .dstOffset = offset,
3810 .size = size,
3811 };
3812 vk->vkCmdCopyBuffer(commandBuffer, stagingBufferInfo.buffer, bufferInfo->buffer, 1,
3813 &bufferCopy);
3814
3815 sVkEmulation->debugUtilsHelper.cmdEndDebugLabel(commandBuffer);
3816
3817 VK_CHECK(vk->vkEndCommandBuffer(commandBuffer));
3818
3819 const VkSubmitInfo submitInfo = {
3820 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3821 .pNext = nullptr,
3822 .waitSemaphoreCount = 0,
3823 .pWaitSemaphores = nullptr,
3824 .pWaitDstStageMask = nullptr,
3825 .commandBufferCount = 1,
3826 .pCommandBuffers = &commandBuffer,
3827 .signalSemaphoreCount = 0,
3828 .pSignalSemaphores = nullptr,
3829 };
3830
3831 {
3832 android::base::AutoLock lock(*sVkEmulation->queueLock);
3833 VK_CHECK(vk->vkQueueSubmit(sVkEmulation->queue, 1, &submitInfo,
3834 sVkEmulation->commandBufferFence));
3835 }
3836
3837 static constexpr uint64_t ANB_MAX_WAIT_NS = 5ULL * 1000ULL * 1000ULL * 1000ULL;
3838
3839 VK_CHECK(vk->vkWaitForFences(sVkEmulation->device, 1, &sVkEmulation->commandBufferFence,
3840 VK_TRUE, ANB_MAX_WAIT_NS));
3841
3842 VK_CHECK(vk->vkResetFences(sVkEmulation->device, 1, &sVkEmulation->commandBufferFence));
3843
3844 return true;
3845 }
3846
transformExternalMemoryHandleTypeFlags_tohost(VkExternalMemoryHandleTypeFlags bits)3847 VkExternalMemoryHandleTypeFlags transformExternalMemoryHandleTypeFlags_tohost(
3848 VkExternalMemoryHandleTypeFlags bits) {
3849 VkExternalMemoryHandleTypeFlags res = bits;
3850
3851 // Transform Android/Fuchsia/Linux bits to host bits.
3852 if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) {
3853 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
3854 }
3855
3856 #ifdef _WIN32
3857 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
3858 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
3859 #endif
3860
3861 if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) {
3862 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
3863
3864 VkExternalMemoryHandleTypeFlagBits handleTypeNeeded = VK_EXT_MEMORY_HANDLE_TYPE_BIT;
3865 #if defined(__APPLE__)
3866 if (sVkEmulation->instanceSupportsMoltenVK) {
3867 // Using a different handle type when in MoltenVK mode
3868 handleTypeNeeded = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
3869 }
3870 #endif
3871 res |= handleTypeNeeded;
3872 }
3873
3874 if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA) {
3875 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
3876 res |= VK_EXT_MEMORY_HANDLE_TYPE_BIT;
3877 }
3878
3879 #if defined(__QNX__)
3880 // QNX only: Replace DMA_BUF_BIT_EXT with SCREEN_BUFFER_BIT_QNX for host calls
3881 if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT) {
3882 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
3883 res |= VK_EXT_MEMORY_HANDLE_TYPE_BIT;
3884 }
3885 #endif
3886
3887 return res;
3888 }
3889
transformExternalMemoryHandleTypeFlags_fromhost(VkExternalMemoryHandleTypeFlags hostBits,VkExternalMemoryHandleTypeFlags wantedGuestHandleType)3890 VkExternalMemoryHandleTypeFlags transformExternalMemoryHandleTypeFlags_fromhost(
3891 VkExternalMemoryHandleTypeFlags hostBits,
3892 VkExternalMemoryHandleTypeFlags wantedGuestHandleType) {
3893 VkExternalMemoryHandleTypeFlags res = hostBits;
3894
3895 VkExternalMemoryHandleTypeFlagBits handleTypeUsed = VK_EXT_MEMORY_HANDLE_TYPE_BIT;
3896 #if defined(__APPLE__)
3897 if (sVkEmulation->instanceSupportsMoltenVK) {
3898 // Using a different handle type when in MoltenVK mode
3899 handleTypeUsed = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
3900 }
3901 #endif
3902 if ((res & handleTypeUsed) == handleTypeUsed) {
3903 res &= ~handleTypeUsed;
3904 res |= wantedGuestHandleType;
3905 }
3906
3907 #ifdef _WIN32
3908 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
3909 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
3910 #endif
3911
3912 return res;
3913 }
3914
transformExternalMemoryProperties_tohost(VkExternalMemoryProperties props)3915 VkExternalMemoryProperties transformExternalMemoryProperties_tohost(
3916 VkExternalMemoryProperties props) {
3917 VkExternalMemoryProperties res = props;
3918 res.exportFromImportedHandleTypes =
3919 transformExternalMemoryHandleTypeFlags_tohost(props.exportFromImportedHandleTypes);
3920 res.compatibleHandleTypes =
3921 transformExternalMemoryHandleTypeFlags_tohost(props.compatibleHandleTypes);
3922 return res;
3923 }
3924
transformExternalMemoryProperties_fromhost(VkExternalMemoryProperties props,VkExternalMemoryHandleTypeFlags wantedGuestHandleType)3925 VkExternalMemoryProperties transformExternalMemoryProperties_fromhost(
3926 VkExternalMemoryProperties props, VkExternalMemoryHandleTypeFlags wantedGuestHandleType) {
3927 VkExternalMemoryProperties res = props;
3928 res.exportFromImportedHandleTypes = transformExternalMemoryHandleTypeFlags_fromhost(
3929 props.exportFromImportedHandleTypes, wantedGuestHandleType);
3930 res.compatibleHandleTypes = transformExternalMemoryHandleTypeFlags_fromhost(
3931 props.compatibleHandleTypes, wantedGuestHandleType);
3932 return res;
3933 }
3934
setColorBufferCurrentLayout(uint32_t colorBufferHandle,VkImageLayout layout)3935 void setColorBufferCurrentLayout(uint32_t colorBufferHandle, VkImageLayout layout) {
3936 AutoLock lock(sVkEmulationLock);
3937
3938 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
3939 if (!infoPtr) {
3940 ERR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
3941 return;
3942 }
3943 infoPtr->currentLayout = layout;
3944 }
3945
getColorBufferCurrentLayout(uint32_t colorBufferHandle)3946 VkImageLayout getColorBufferCurrentLayout(uint32_t colorBufferHandle) {
3947 AutoLock lock(sVkEmulationLock);
3948
3949 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
3950 if (!infoPtr) {
3951 ERR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
3952 return VK_IMAGE_LAYOUT_UNDEFINED;
3953 }
3954 return infoPtr->currentLayout;
3955 }
3956
setColorBufferLatestUse(uint32_t colorBufferHandle,DeviceOpWaitable waitable,DeviceOpTrackerPtr tracker)3957 void setColorBufferLatestUse(uint32_t colorBufferHandle, DeviceOpWaitable waitable,
3958 DeviceOpTrackerPtr tracker) {
3959 AutoLock lock(sVkEmulationLock);
3960 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
3961 if (!infoPtr) {
3962 ERR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
3963 return;
3964 }
3965
3966 infoPtr->latestUse = waitable;
3967 infoPtr->latestUseTracker = tracker;
3968 }
3969
waitSyncVkColorBuffer(uint32_t colorBufferHandle)3970 int waitSyncVkColorBuffer(uint32_t colorBufferHandle) {
3971 AutoLock lock(sVkEmulationLock);
3972 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
3973 if (!infoPtr) {
3974 ERR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
3975 return -1;
3976 }
3977
3978 if (infoPtr->latestUse && infoPtr->latestUseTracker) {
3979 while (!IsDone(*infoPtr->latestUse)) {
3980 infoPtr->latestUseTracker->Poll();
3981 }
3982 }
3983
3984 return 0;
3985 }
3986
3987 // Allocate a ready to use VkCommandBuffer for queue transfer. The caller needs
3988 // to signal the returned VkFence when the VkCommandBuffer completes.
allocateQueueTransferCommandBuffer_locked()3989 static std::tuple<VkCommandBuffer, VkFence> allocateQueueTransferCommandBuffer_locked() {
3990 auto vk = sVkEmulation->dvk;
3991 // Check if a command buffer in the pool is ready to use. If the associated
3992 // VkFence is ready, vkGetFenceStatus will return VK_SUCCESS, and the
3993 // associated command buffer should be ready to use, so we return that
3994 // command buffer with the associated VkFence. If the associated VkFence is
3995 // not ready, vkGetFenceStatus will return VK_NOT_READY, we will continue to
3996 // search and test the next command buffer. If the VkFence is in an error
3997 // state, vkGetFenceStatus will return with other VkResult variants, we will
3998 // abort.
3999 for (auto& [commandBuffer, fence] : sVkEmulation->transferQueueCommandBufferPool) {
4000 auto res = vk->vkGetFenceStatus(sVkEmulation->device, fence);
4001 if (res == VK_SUCCESS) {
4002 VK_CHECK(vk->vkResetFences(sVkEmulation->device, 1, &fence));
4003 VK_CHECK(vk->vkResetCommandBuffer(commandBuffer,
4004 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT));
4005 return std::make_tuple(commandBuffer, fence);
4006 }
4007 if (res == VK_NOT_READY) {
4008 continue;
4009 }
4010 // We either have a device lost, or an invalid fence state. For the device lost case,
4011 // VK_CHECK will ensure we capture the relevant streams.
4012 VK_CHECK(res);
4013 }
4014 VkCommandBuffer commandBuffer;
4015 VkCommandBufferAllocateInfo allocateInfo = {
4016 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
4017 .pNext = nullptr,
4018 .commandPool = sVkEmulation->commandPool,
4019 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
4020 .commandBufferCount = 1,
4021 };
4022 VK_CHECK(vk->vkAllocateCommandBuffers(sVkEmulation->device, &allocateInfo, &commandBuffer));
4023 VkFence fence;
4024 VkFenceCreateInfo fenceCi = {
4025 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
4026 .pNext = nullptr,
4027 .flags = 0,
4028 };
4029 VK_CHECK(vk->vkCreateFence(sVkEmulation->device, &fenceCi, nullptr, &fence));
4030
4031 const int cbIndex = static_cast<int>(sVkEmulation->transferQueueCommandBufferPool.size());
4032 sVkEmulation->transferQueueCommandBufferPool.emplace_back(commandBuffer, fence);
4033
4034 VERBOSE(
4035 "Create a new command buffer for queue transfer for a total of %d "
4036 "transfer command buffers",
4037 (cbIndex + 1));
4038
4039 sVkEmulation->debugUtilsHelper.addDebugLabel(commandBuffer, "QueueTransferCommandBuffer:%d",
4040 cbIndex);
4041
4042 return std::make_tuple(commandBuffer, fence);
4043 }
4044
4045 const VkImageLayout kGuestUseDefaultImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
4046
releaseColorBufferForGuestUse(uint32_t colorBufferHandle)4047 void releaseColorBufferForGuestUse(uint32_t colorBufferHandle) {
4048 if (!sVkEmulation || !sVkEmulation->live) {
4049 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Host Vulkan device lost";
4050 }
4051
4052 AutoLock lock(sVkEmulationLock);
4053
4054 auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
4055 if (!infoPtr) {
4056 ERR("Failed to find ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
4057 return;
4058 }
4059
4060 std::optional<VkImageMemoryBarrier> layoutTransitionBarrier;
4061 if (infoPtr->currentLayout != kGuestUseDefaultImageLayout) {
4062 layoutTransitionBarrier = VkImageMemoryBarrier{
4063 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
4064 .pNext = nullptr,
4065 .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
4066 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
4067 .oldLayout = infoPtr->currentLayout,
4068 .newLayout = kGuestUseDefaultImageLayout,
4069 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4070 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4071 .image = infoPtr->image,
4072 .subresourceRange =
4073 {
4074 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4075 .baseMipLevel = 0,
4076 .levelCount = 1,
4077 .baseArrayLayer = 0,
4078 .layerCount = 1,
4079 },
4080 };
4081 infoPtr->currentLayout = kGuestUseDefaultImageLayout;
4082 }
4083
4084 std::optional<VkImageMemoryBarrier> queueTransferBarrier;
4085 if (infoPtr->currentQueueFamilyIndex != VK_QUEUE_FAMILY_EXTERNAL) {
4086 queueTransferBarrier = VkImageMemoryBarrier{
4087 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
4088 .pNext = nullptr,
4089 .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
4090 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
4091 .oldLayout = infoPtr->currentLayout,
4092 .newLayout = infoPtr->currentLayout,
4093 .srcQueueFamilyIndex = infoPtr->currentQueueFamilyIndex,
4094 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
4095 .image = infoPtr->image,
4096 .subresourceRange =
4097 {
4098 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4099 .baseMipLevel = 0,
4100 .levelCount = 1,
4101 .baseArrayLayer = 0,
4102 .layerCount = 1,
4103 },
4104 };
4105 infoPtr->currentQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
4106 }
4107
4108 if (!layoutTransitionBarrier && !queueTransferBarrier) {
4109 return;
4110 }
4111
4112 auto vk = sVkEmulation->dvk;
4113 auto [commandBuffer, fence] = allocateQueueTransferCommandBuffer_locked();
4114
4115 VK_CHECK(vk->vkResetCommandBuffer(commandBuffer, 0));
4116
4117 const VkCommandBufferBeginInfo beginInfo = {
4118 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
4119 .pNext = nullptr,
4120 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
4121 .pInheritanceInfo = nullptr,
4122 };
4123 VK_CHECK(vk->vkBeginCommandBuffer(commandBuffer, &beginInfo));
4124
4125 sVkEmulation->debugUtilsHelper.cmdBeginDebugLabel(
4126 commandBuffer, "releaseColorBufferForGuestUse(ColorBuffer:%d)", colorBufferHandle);
4127
4128 if (layoutTransitionBarrier) {
4129 vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
4130 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
4131 &layoutTransitionBarrier.value());
4132 }
4133 if (queueTransferBarrier) {
4134 vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
4135 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
4136 &queueTransferBarrier.value());
4137 }
4138
4139 sVkEmulation->debugUtilsHelper.cmdEndDebugLabel(commandBuffer);
4140
4141 VK_CHECK(vk->vkEndCommandBuffer(commandBuffer));
4142
4143 const VkSubmitInfo submitInfo = {
4144 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
4145 .pNext = nullptr,
4146 .waitSemaphoreCount = 0,
4147 .pWaitSemaphores = nullptr,
4148 .pWaitDstStageMask = nullptr,
4149 .commandBufferCount = 1,
4150 .pCommandBuffers = &commandBuffer,
4151 .signalSemaphoreCount = 0,
4152 .pSignalSemaphores = nullptr,
4153 };
4154 {
4155 android::base::AutoLock lock(*sVkEmulation->queueLock);
4156 VK_CHECK(vk->vkQueueSubmit(sVkEmulation->queue, 1, &submitInfo, fence));
4157 }
4158
4159 static constexpr uint64_t ANB_MAX_WAIT_NS = 5ULL * 1000ULL * 1000ULL * 1000ULL;
4160 VK_CHECK(vk->vkWaitForFences(sVkEmulation->device, 1, &fence, VK_TRUE, ANB_MAX_WAIT_NS));
4161 }
4162
borrowColorBufferForComposition(uint32_t colorBufferHandle,bool colorBufferIsTarget)4163 std::unique_ptr<BorrowedImageInfoVk> borrowColorBufferForComposition(uint32_t colorBufferHandle,
4164 bool colorBufferIsTarget) {
4165 AutoLock lock(sVkEmulationLock);
4166
4167 auto colorBufferInfo = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
4168 if (!colorBufferInfo) {
4169 ERR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
4170 return nullptr;
4171 }
4172
4173 auto compositorInfo = std::make_unique<BorrowedImageInfoVk>();
4174 compositorInfo->id = colorBufferInfo->handle;
4175 compositorInfo->width = colorBufferInfo->imageCreateInfoShallow.extent.width;
4176 compositorInfo->height = colorBufferInfo->imageCreateInfoShallow.extent.height;
4177 compositorInfo->image = colorBufferInfo->image;
4178 compositorInfo->imageView = colorBufferInfo->imageView;
4179 compositorInfo->imageCreateInfo = colorBufferInfo->imageCreateInfoShallow;
4180 compositorInfo->preBorrowLayout = colorBufferInfo->currentLayout;
4181 compositorInfo->preBorrowQueueFamilyIndex = colorBufferInfo->currentQueueFamilyIndex;
4182 if (colorBufferIsTarget && sVkEmulation->displayVk) {
4183 // Instruct the compositor to perform the layout transition after use so
4184 // that it is ready to be blitted to the display.
4185 compositorInfo->postBorrowQueueFamilyIndex = sVkEmulation->queueFamilyIndex;
4186 compositorInfo->postBorrowLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4187 } else {
4188 // Instruct the compositor to perform the queue transfer release after use
4189 // so that the color buffer can be acquired by the guest.
4190 compositorInfo->postBorrowQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
4191 compositorInfo->postBorrowLayout = colorBufferInfo->currentLayout;
4192
4193 if (compositorInfo->postBorrowLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
4194 compositorInfo->postBorrowLayout = kGuestUseDefaultImageLayout;
4195 }
4196 }
4197
4198 colorBufferInfo->currentLayout = compositorInfo->postBorrowLayout;
4199 colorBufferInfo->currentQueueFamilyIndex = compositorInfo->postBorrowQueueFamilyIndex;
4200
4201 return compositorInfo;
4202 }
4203
borrowColorBufferForDisplay(uint32_t colorBufferHandle)4204 std::unique_ptr<BorrowedImageInfoVk> borrowColorBufferForDisplay(uint32_t colorBufferHandle) {
4205 AutoLock lock(sVkEmulationLock);
4206
4207 auto colorBufferInfo = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
4208 if (!colorBufferInfo) {
4209 ERR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
4210 return nullptr;
4211 }
4212
4213 auto compositorInfo = std::make_unique<BorrowedImageInfoVk>();
4214 compositorInfo->id = colorBufferInfo->handle;
4215 compositorInfo->width = colorBufferInfo->imageCreateInfoShallow.extent.width;
4216 compositorInfo->height = colorBufferInfo->imageCreateInfoShallow.extent.height;
4217 compositorInfo->image = colorBufferInfo->image;
4218 compositorInfo->imageView = colorBufferInfo->imageView;
4219 compositorInfo->imageCreateInfo = colorBufferInfo->imageCreateInfoShallow;
4220 compositorInfo->preBorrowLayout = colorBufferInfo->currentLayout;
4221 compositorInfo->preBorrowQueueFamilyIndex = sVkEmulation->queueFamilyIndex;
4222
4223 // Instruct the display to perform the queue transfer release after use so
4224 // that the color buffer can be acquired by the guest.
4225 compositorInfo->postBorrowQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
4226 compositorInfo->postBorrowLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
4227
4228 colorBufferInfo->currentLayout = compositorInfo->postBorrowLayout;
4229 colorBufferInfo->currentQueueFamilyIndex = compositorInfo->postBorrowQueueFamilyIndex;
4230
4231 return compositorInfo;
4232 }
4233
4234 std::optional<VkEmulation::RepresentativeColorBufferMemoryTypeInfo>
findRepresentativeColorBufferMemoryTypeIndexLocked()4235 findRepresentativeColorBufferMemoryTypeIndexLocked() {
4236 constexpr const uint32_t kArbitraryWidth = 64;
4237 constexpr const uint32_t kArbitraryHeight = 64;
4238 constexpr const uint32_t kArbitraryHandle = std::numeric_limits<uint32_t>::max();
4239 if (!createVkColorBufferLocked(kArbitraryWidth, kArbitraryHeight, GL_RGBA8,
4240 FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE,
4241 kArbitraryHandle, true, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
4242 ERR("Failed to setup memory type index test ColorBuffer.");
4243 return std::nullopt;
4244 }
4245 if (!initializeVkColorBufferLocked(kArbitraryHandle)) {
4246 ERR("Failed to initialize memory type index test ColorBuffer.");
4247 return std::nullopt;
4248 }
4249
4250 uint32_t hostMemoryTypeIndex = 0;
4251 if (!getColorBufferAllocationInfoLocked(kArbitraryHandle, nullptr, &hostMemoryTypeIndex,
4252 nullptr, nullptr)) {
4253 ERR("Failed to lookup memory type index test ColorBuffer.");
4254 return std::nullopt;
4255 }
4256
4257 if (!teardownVkColorBufferLocked(kArbitraryHandle)) {
4258 ERR("Failed to clean up memory type index test ColorBuffer.");
4259 return std::nullopt;
4260 }
4261
4262 EmulatedPhysicalDeviceMemoryProperties helper(sVkEmulation->deviceInfo.memProps,
4263 hostMemoryTypeIndex, sVkEmulation->features);
4264 uint32_t guestMemoryTypeIndex = helper.getGuestColorBufferMemoryTypeIndex();
4265
4266 return VkEmulation::RepresentativeColorBufferMemoryTypeInfo{
4267 .hostMemoryTypeIndex = hostMemoryTypeIndex,
4268 .guestMemoryTypeIndex = guestMemoryTypeIndex,
4269 };
4270 }
4271
4272 } // namespace vk
4273 } // namespace gfxstream
4274