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