• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "FrameBuffer.h"
29 #include "VulkanDispatch.h"
30 #include "base/Lock.h"
31 #include "base/Lookup.h"
32 #include "base/Optional.h"
33 #include "base/StaticMap.h"
34 #include "base/System.h"
35 #include "base/Tracing.h"
36 #include "common/goldfish_vk_dispatch.h"
37 #include "host-common/GfxstreamFatalError.h"
38 #include "host-common/vm_operations.h"
39 
40 #ifdef _WIN32
41 #include <windows.h>
42 #else
43 #include <fcntl.h>
44 #include <unistd.h>
45 #endif
46 
47 #ifdef __APPLE__
48 #include <CoreFoundation/CoreFoundation.h>
49 #endif
50 
51 #define VK_COMMON_ERROR(fmt,...) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
52 #define VK_COMMON_LOG(fmt,...) fprintf(stdout, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
53 #define VK_COMMON_VERBOSE(fmt,...) if (android::base::isVerboseLogging()) fprintf(stderr, "%s:%d " fmt "\n", __func__, __LINE__, ##__VA_ARGS__);
54 
55 using android::base::AutoLock;
56 using android::base::Optional;
57 using android::base::StaticLock;
58 using android::base::StaticMap;
59 
60 using android::base::kNullopt;
61 using emugl::ABORT_REASON_OTHER;
62 using emugl::FatalError;
63 
64 namespace goldfish_vk {
65 
66 namespace {
67 
68 constexpr size_t kPageBits = 12;
69 constexpr size_t kPageSize = 1u << kPageBits;
70 
71 }  // namespace
72 
73 static StaticMap<VkDevice, uint32_t>
74 sKnownStagingTypeIndices;
75 
76 static android::base::StaticLock sVkEmulationLock;
77 
dupExternalMemory(VK_EXT_MEMORY_HANDLE h)78 VK_EXT_MEMORY_HANDLE dupExternalMemory(VK_EXT_MEMORY_HANDLE h) {
79 #ifdef _WIN32
80     auto myProcessHandle = GetCurrentProcess();
81     VK_EXT_MEMORY_HANDLE res;
82     DuplicateHandle(
83         myProcessHandle, h, // source process and handle
84         myProcessHandle, &res, // target process and pointer to handle
85         0 /* desired access (ignored) */,
86         true /* inherit */,
87         DUPLICATE_SAME_ACCESS /* same access option */);
88     return res;
89 #else
90     return dup(h);
91 #endif
92 }
93 
getStagingMemoryTypeIndex(VulkanDispatch * vk,VkDevice device,const VkPhysicalDeviceMemoryProperties * memProps,uint32_t * typeIndex)94 bool getStagingMemoryTypeIndex(
95     VulkanDispatch* vk,
96     VkDevice device,
97     const VkPhysicalDeviceMemoryProperties* memProps,
98     uint32_t* typeIndex) {
99 
100     auto res = sKnownStagingTypeIndices.get(device);
101 
102     if (res) {
103         *typeIndex = *res;
104         return true;
105     }
106 
107     VkBufferCreateInfo testCreateInfo = {
108         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, 0,
109         4096,
110         // To be a staging buffer, it must support being
111         // both a transfer src and dst.
112         VK_BUFFER_USAGE_TRANSFER_DST_BIT |
113         VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
114         // TODO: See if buffers over shared queues need to be
115         // considered separately
116         VK_SHARING_MODE_EXCLUSIVE,
117         0, nullptr,
118     };
119 
120     VkBuffer testBuffer;
121     VkResult testBufferCreateRes =
122         vk->vkCreateBuffer(device, &testCreateInfo, nullptr, &testBuffer);
123 
124     if (testBufferCreateRes != VK_SUCCESS) {
125         VK_COMMON_ERROR(
126             "Could not create test buffer "
127             "for staging buffer query. VkResult: 0x%llx",
128             (unsigned long long)testBufferCreateRes);
129         return false;
130     }
131 
132     VkMemoryRequirements memReqs;
133     vk->vkGetBufferMemoryRequirements(device, testBuffer, &memReqs);
134 
135     // To be a staging buffer, we need to allow CPU read/write access.
136     // Thus, we need the memory type index both to be host visible
137     // and to be supported in the memory requirements of the buffer.
138     bool foundSuitableStagingMemoryType = false;
139     uint32_t stagingMemoryTypeIndex = 0;
140 
141     for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
142         const auto& typeInfo = memProps->memoryTypes[i];
143         bool hostVisible =
144             typeInfo.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
145         bool hostCached =
146             typeInfo.propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
147         bool allowedInBuffer = (1 << i) & memReqs.memoryTypeBits;
148         if (hostVisible && hostCached && allowedInBuffer) {
149             foundSuitableStagingMemoryType = true;
150             stagingMemoryTypeIndex = i;
151             break;
152         }
153     }
154 
155     vk->vkDestroyBuffer(device, testBuffer, nullptr);
156 
157     if (!foundSuitableStagingMemoryType) {
158         std::stringstream ss;
159         ss <<
160             "Could not find suitable memory type index " <<
161             "for staging buffer. Memory type bits: " <<
162             std::hex << memReqs.memoryTypeBits << "\n" <<
163             "Available host visible memory type indices:" << "\n";
164         for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
165             if (memProps->memoryTypes[i].propertyFlags &
166                 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
167                 ss << "Host visible memory type index: %u" << i << "\n";
168             }
169             if (memProps->memoryTypes[i].propertyFlags &
170                 VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
171                 ss << "Host cached memory type index: %u" << i << "\n";
172             }
173         }
174 
175         VK_COMMON_ERROR("Error: %s", ss.str().c_str());
176 
177         return false;
178     }
179 
180     sKnownStagingTypeIndices.set(device, stagingMemoryTypeIndex);
181     *typeIndex = stagingMemoryTypeIndex;
182 
183     return true;
184 }
185 
186 static VkEmulation* sVkEmulation = nullptr;
187 
extensionsSupported(const std::vector<VkExtensionProperties> & currentProps,const std::vector<const char * > & wantedExtNames)188 static bool extensionsSupported(
189     const std::vector<VkExtensionProperties>& currentProps,
190     const std::vector<const char*>& wantedExtNames) {
191 
192     std::vector<bool> foundExts(wantedExtNames.size(), false);
193 
194     for (uint32_t i = 0; i < currentProps.size(); ++i) {
195         VK_COMMON_VERBOSE("has extension: %s", currentProps[i].extensionName);
196         for (size_t j = 0; j < wantedExtNames.size(); ++j) {
197             if (!strcmp(wantedExtNames[j], currentProps[i].extensionName)) {
198                 foundExts[j] = true;
199             }
200         }
201     }
202 
203     for (size_t i = 0; i < wantedExtNames.size(); ++i) {
204         bool found = foundExts[i];
205         // LOG(VERBOSE) << "needed extension: " << wantedExtNames[i]
206         //              << " found: " << found;
207         if (!found) {
208             // LOG(VERBOSE) << wantedExtNames[i] << " not found, bailing.";
209             return false;
210         }
211     }
212 
213     return true;
214 }
215 
216 // For a given ImageSupportInfo, populates usageWithExternalHandles and
217 // requiresDedicatedAllocation. memoryTypeBits are populated later once the
218 // device is created, beacuse that needs a test image to be created.
219 // If we don't support external memory, it's assumed dedicated allocations are
220 // not needed.
221 // Precondition: sVkEmulation instance has been created and ext memory caps known.
222 // Returns false if the query failed.
getImageFormatExternalMemorySupportInfo(VulkanDispatch * vk,VkPhysicalDevice physdev,VkEmulation::ImageSupportInfo * info)223 static bool getImageFormatExternalMemorySupportInfo(
224     VulkanDispatch* vk,
225     VkPhysicalDevice physdev,
226     VkEmulation::ImageSupportInfo* info) {
227 
228     // Currently there is nothing special we need to do about
229     // VkFormatProperties2, so just use the normal version
230     // and put it in the format2 struct.
231     VkFormatProperties outFormatProps;
232     vk->vkGetPhysicalDeviceFormatProperties(
233             physdev, info->format, &outFormatProps);
234 
235     info->formatProps2 = {
236         VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2, 0,
237         outFormatProps,
238     };
239 
240     if (!sVkEmulation->instanceSupportsExternalMemoryCapabilities) {
241         info->supportsExternalMemory = false;
242         info->requiresDedicatedAllocation = false;
243 
244         VkImageFormatProperties outImageFormatProps;
245         VkResult res = vk->vkGetPhysicalDeviceImageFormatProperties(
246                 physdev, info->format, info->type, info->tiling,
247                 info->usageFlags, info->createFlags, &outImageFormatProps);
248 
249         if (res != VK_SUCCESS) {
250             if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
251                 info->supported = false;
252                 return true;
253             } else {
254                 fprintf(stderr,
255                         "%s: vkGetPhysicalDeviceImageFormatProperties query "
256                         "failed with %d "
257                         "for format 0x%x type 0x%x usage 0x%x flags 0x%x\n",
258                         __func__, res, info->format, info->type,
259                         info->usageFlags, info->createFlags);
260                 return false;
261             }
262         }
263 
264         info->supported = true;
265 
266         info->imageFormatProps2 = {
267             VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, 0,
268             outImageFormatProps,
269         };
270 
271         // LOG(VERBOSE) << "Supported (not externally): "
272         //     << string_VkFormat(info->format) << " "
273         //     << string_VkImageType(info->type) << " "
274         //     << string_VkImageTiling(info->tiling) << " "
275         //     << string_VkImageUsageFlagBits(
276         //            (VkImageUsageFlagBits)info->usageFlags);
277 
278         return true;
279     }
280 
281     VkPhysicalDeviceExternalImageFormatInfo extInfo = {
282         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO, 0,
283         VK_EXT_MEMORY_HANDLE_TYPE_BIT,
284     };
285 
286     VkPhysicalDeviceImageFormatInfo2 formatInfo2 = {
287         VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2, &extInfo,
288         info->format, info->type, info->tiling,
289         info->usageFlags, info->createFlags,
290     };
291 
292     VkExternalImageFormatProperties outExternalProps = {
293         VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
294         0,
295         {
296             (VkExternalMemoryFeatureFlags)0,
297             (VkExternalMemoryHandleTypeFlags)0,
298             (VkExternalMemoryHandleTypeFlags)0,
299         },
300     };
301 
302     VkImageFormatProperties2 outProps2 = {
303         VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2, &outExternalProps,
304         {
305             { 0, 0, 0},
306             0, 0,
307             1, 0,
308         }
309     };
310 
311     VkResult res = sVkEmulation->getImageFormatProperties2Func(
312         physdev,
313         &formatInfo2,
314         &outProps2);
315 
316     if (res != VK_SUCCESS) {
317         if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
318             info->supported = false;
319             return true;
320         } else {
321             fprintf(stderr,
322                     "%s: vkGetPhysicalDeviceImageFormatProperties2KHR query "
323                     "failed "
324                     "for format 0x%x type 0x%x usage 0x%x flags 0x%x\n",
325                     __func__, info->format, info->type, info->usageFlags,
326                     info->createFlags);
327             return false;
328         }
329     }
330 
331     info->supported = true;
332 
333     VkExternalMemoryFeatureFlags featureFlags =
334         outExternalProps.externalMemoryProperties.externalMemoryFeatures;
335 
336     VkExternalMemoryHandleTypeFlags exportImportedFlags =
337         outExternalProps.externalMemoryProperties.exportFromImportedHandleTypes;
338 
339     // Don't really care about export form imported handle types yet
340     (void)exportImportedFlags;
341 
342     VkExternalMemoryHandleTypeFlags compatibleHandleTypes =
343         outExternalProps.externalMemoryProperties.compatibleHandleTypes;
344 
345     info->supportsExternalMemory =
346         (VK_EXT_MEMORY_HANDLE_TYPE_BIT & compatibleHandleTypes) &&
347         (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT & featureFlags) &&
348         (VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT & featureFlags);
349 
350     info->requiresDedicatedAllocation =
351         (VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT & featureFlags);
352 
353     info->imageFormatProps2 = outProps2;
354     info->extFormatProps = outExternalProps;
355     info->imageFormatProps2.pNext = &info->extFormatProps;
356 
357     // LOG(VERBOSE) << "Supported: "
358     //              << string_VkFormat(info->format) << " "
359     //              << string_VkImageType(info->type) << " "
360     //              << string_VkImageTiling(info->tiling) << " "
361     //              << string_VkImageUsageFlagBits(
362     //                         (VkImageUsageFlagBits)info->usageFlags)
363     //              << " "
364     //              << "supportsExternalMemory? " << info->supportsExternalMemory
365     //              << " "
366     //              << "requiresDedicated? " << info->requiresDedicatedAllocation;
367 
368     return true;
369 }
370 
371 // Vulkan driverVersions are bit-shift packs of their dotted versions
372 // For example, nvidia driverversion 1934229504 unpacks to 461.40
373 // note: while this is equivalent to VkPhysicalDeviceDriverProperties.driverInfo on NVIDIA,
374 // on intel that value is simply "Intel driver".
decodeDriverVersion(uint32_t vendorId,uint32_t driverVersion)375 static std::string decodeDriverVersion(uint32_t vendorId, uint32_t driverVersion) {
376     std::stringstream result;
377     switch (vendorId) {
378         case 0x10DE: {
379             // Nvidia. E.g. driverVersion = 1934229504(0x734a0000) maps to 461.40
380             uint32_t major = driverVersion >> 22;
381             uint32_t minor = (driverVersion >> 14) & 0xff;
382             uint32_t build = (driverVersion >> 6) & 0xff;
383             uint32_t revision = driverVersion & 0x3f;
384             result << major << '.' << minor << '.' << build << '.' << revision;
385             break;
386         }
387         case 0x8086: {
388             // Intel. E.g. driverVersion = 1647866(0x1924fa) maps to 100.9466 (27.20.100.9466)
389             uint32_t high = driverVersion >> 14;
390             uint32_t low = driverVersion & 0x3fff;
391             result << high << '.' << low;
392             break;
393         }
394         case 0x002:  // amd
395         default: {
396             uint32_t major = VK_VERSION_MAJOR(driverVersion);
397             uint32_t minor = VK_VERSION_MINOR(driverVersion);
398             uint32_t patch = VK_VERSION_PATCH(driverVersion);
399             result << major << "." << minor << "." << patch;
400             break;
401         }
402     }
403     return result.str();
404 }
405 
getBasicImageSupportList()406 static std::vector<VkEmulation::ImageSupportInfo> getBasicImageSupportList() {
407     std::vector<VkFormat> formats = {
408         // Cover all the gralloc formats
409         VK_FORMAT_R8G8B8A8_UNORM,
410         VK_FORMAT_R8G8B8_UNORM,
411 
412         VK_FORMAT_R5G6B5_UNORM_PACK16,
413 
414         VK_FORMAT_R16G16B16A16_SFLOAT,
415         VK_FORMAT_R16G16B16_SFLOAT,
416 
417         VK_FORMAT_B8G8R8A8_UNORM,
418 
419         VK_FORMAT_R8_UNORM,
420 
421         VK_FORMAT_A2R10G10B10_UINT_PACK32,
422         VK_FORMAT_A2R10G10B10_UNORM_PACK32,
423 
424         // Compressed texture formats
425         VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK,
426         VK_FORMAT_ASTC_4x4_UNORM_BLOCK,
427 
428         // TODO: YUV formats used in Android
429         // Fails on Mac
430         VK_FORMAT_G8_B8R8_2PLANE_420_UNORM,
431         VK_FORMAT_G8_B8R8_2PLANE_422_UNORM,
432         VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM,
433         VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM,
434 
435     };
436 
437     std::vector<VkImageType> types = {
438         VK_IMAGE_TYPE_2D,
439     };
440 
441     std::vector<VkImageTiling> tilings = {
442         VK_IMAGE_TILING_LINEAR,
443         VK_IMAGE_TILING_OPTIMAL,
444     };
445 
446     std::vector<VkImageUsageFlags> usageFlags = {
447         VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
448         VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
449         VK_IMAGE_USAGE_SAMPLED_BIT,
450         VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
451         VK_IMAGE_USAGE_TRANSFER_DST_BIT,
452     };
453 
454     std::vector<VkImageCreateFlags> createFlags = {
455         0,
456     };
457 
458     std::vector<VkEmulation::ImageSupportInfo> res;
459 
460     // Currently: 12 formats, 2 tilings, 5 usage flags -> 120 cases
461     // to check
462     for (auto f : formats) {
463         for (auto t : types) {
464             for (auto ti : tilings) {
465                 for (auto u : usageFlags) {
466                     for (auto c : createFlags) {
467                         VkEmulation::ImageSupportInfo info;
468                         info.format = f;
469                         info.type = t;
470                         info.tiling = ti;
471                         info.usageFlags = u;
472                         info.createFlags = c;
473                         res.push_back(info);
474                     }
475                 }
476             }
477         }
478     }
479 
480     return res;
481 }
482 
createGlobalVkEmulation(VulkanDispatch * vk)483 VkEmulation* createGlobalVkEmulation(VulkanDispatch* vk) {
484 #define VK_EMU_INIT_RETURN_ON_ERROR(...) \
485     do {                                 \
486         ERR(__VA_ARGS__);                \
487         return nullptr;                  \
488     } while (0)
489 
490     AutoLock lock(sVkEmulationLock);
491 
492     if (sVkEmulation) return sVkEmulation;
493 
494     if (!emugl::vkDispatchValid(vk)) {
495         VK_EMU_INIT_RETURN_ON_ERROR("Dispatch is invalid.");
496     }
497 
498     sVkEmulation = new VkEmulation;
499 
500     sVkEmulation->gvk = vk;
501     auto gvk = vk;
502 
503     std::vector<const char*> externalMemoryInstanceExtNames = {
504         "VK_KHR_external_memory_capabilities",
505         "VK_KHR_get_physical_device_properties2",
506     };
507 
508     std::vector<const char*> externalMemoryDeviceExtNames = {
509         "VK_KHR_dedicated_allocation",
510         "VK_KHR_get_memory_requirements2",
511         "VK_KHR_external_memory",
512 #ifdef _WIN32
513         "VK_KHR_external_memory_win32",
514 #else
515         "VK_KHR_external_memory_fd",
516 #endif
517     };
518 
519     uint32_t extCount = 0;
520     gvk->vkEnumerateInstanceExtensionProperties(nullptr, &extCount, nullptr);
521     std::vector<VkExtensionProperties>& exts = sVkEmulation->instanceExtensions;
522     exts.resize(extCount);
523     gvk->vkEnumerateInstanceExtensionProperties(nullptr, &extCount, exts.data());
524 
525     bool externalMemoryCapabilitiesSupported =
526         extensionsSupported(exts, externalMemoryInstanceExtNames);
527     bool moltenVKSupported = (vk->vkGetMTLTextureMVK != nullptr) &&
528         (vk->vkSetMTLTextureMVK != nullptr);
529 
530     VkInstanceCreateInfo instCi = {
531         VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
532         0, 0, nullptr, 0, nullptr,
533         0, nullptr,
534     };
535 
536     std::unordered_set<const char*> enabledExtensions;
537 
538     if (externalMemoryCapabilitiesSupported) {
539         for (auto extension : externalMemoryInstanceExtNames) {
540             enabledExtensions.emplace(extension);
541         }
542     }
543 
544     if (moltenVKSupported) {
545         // We don't need both moltenVK and external memory. Disable
546         // external memory if moltenVK is supported.
547         externalMemoryCapabilitiesSupported = false;
548         enabledExtensions.clear();
549     }
550 
551     for (auto extension : SwapChainStateVk::getRequiredInstanceExtensions()) {
552         enabledExtensions.emplace(extension);
553     }
554     std::vector<const char*> enabledExtensions_(enabledExtensions.begin(),
555                                                 enabledExtensions.end());
556     instCi.enabledExtensionCount =
557         static_cast<uint32_t>(enabledExtensions_.size());
558     instCi.ppEnabledExtensionNames = enabledExtensions_.data();
559 
560     VkApplicationInfo appInfo = {
561         VK_STRUCTURE_TYPE_APPLICATION_INFO, 0,
562         "AEMU", 1,
563         "AEMU", 1,
564         VK_MAKE_VERSION(1, 0, 0),
565     };
566 
567     instCi.pApplicationInfo = &appInfo;
568 
569     // Can we know instance version early?
570     if (gvk->vkEnumerateInstanceVersion) {
571         // LOG(VERBOSE) << "global loader has vkEnumerateInstanceVersion.";
572         uint32_t instanceVersion;
573         VkResult res = gvk->vkEnumerateInstanceVersion(&instanceVersion);
574         if (VK_SUCCESS == res) {
575             if (instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
576                 // LOG(VERBOSE) << "global loader has vkEnumerateInstanceVersion returning >= 1.1.";
577                 appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0);
578             }
579         }
580     }
581 
582     // LOG(VERBOSE) << "Creating instance, asking for version "
583     //              << VK_VERSION_MAJOR(appInfo.apiVersion) << "."
584     //              << VK_VERSION_MINOR(appInfo.apiVersion) << "."
585     //              << VK_VERSION_PATCH(appInfo.apiVersion) << " ...";
586 
587     VkResult res = gvk->vkCreateInstance(&instCi, nullptr, &sVkEmulation->instance);
588 
589     if (res != VK_SUCCESS) {
590         VK_EMU_INIT_RETURN_ON_ERROR("Failed to create Vulkan instance. Error %s.",
591                                     string_VkResult(res));
592     }
593 
594     // Create instance level dispatch.
595     sVkEmulation->ivk = new VulkanDispatch;
596     init_vulkan_dispatch_from_instance(
597         vk, sVkEmulation->instance, sVkEmulation->ivk);
598 
599     auto ivk = sVkEmulation->ivk;
600 
601     if (!vulkan_dispatch_check_instance_VK_VERSION_1_0(ivk)) {
602         fprintf(stderr, "%s: Warning: Vulkan 1.0 APIs missing from instance\n", __func__);
603     }
604 
605     if (ivk->vkEnumerateInstanceVersion) {
606         uint32_t instanceVersion;
607         VkResult enumInstanceRes = ivk->vkEnumerateInstanceVersion(&instanceVersion);
608         if ((VK_SUCCESS == enumInstanceRes) &&
609             instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
610             if (!vulkan_dispatch_check_instance_VK_VERSION_1_1(ivk)) {
611                 fprintf(stderr, "%s: Warning: Vulkan 1.1 APIs missing from instance (1st try)\n", __func__);
612             }
613         }
614 
615         if (appInfo.apiVersion < VK_MAKE_VERSION(1, 1, 0) &&
616             instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
617             // LOG(VERBOSE) << "Found out that we can create a higher version instance.";
618             appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0);
619 
620             gvk->vkDestroyInstance(sVkEmulation->instance, nullptr);
621 
622             VkResult res = gvk->vkCreateInstance(&instCi, nullptr, &sVkEmulation->instance);
623 
624             if (res != VK_SUCCESS) {
625                 VK_EMU_INIT_RETURN_ON_ERROR("Failed to create Vulkan 1.1 instance. Error %s.",
626                                             string_VkResult(res));
627             }
628 
629             init_vulkan_dispatch_from_instance(
630                 vk, sVkEmulation->instance, sVkEmulation->ivk);
631 
632             // LOG(VERBOSE) << "Created Vulkan 1.1 instance on second try.";
633 
634             if (!vulkan_dispatch_check_instance_VK_VERSION_1_1(ivk)) {
635                 fprintf(stderr, "%s: Warning: Vulkan 1.1 APIs missing from instance (2nd try)\n", __func__);
636             }
637         }
638     }
639 
640     sVkEmulation->vulkanInstanceVersion = appInfo.apiVersion;
641 
642     sVkEmulation->instanceSupportsExternalMemoryCapabilities =
643         externalMemoryCapabilitiesSupported;
644     sVkEmulation->instanceSupportsMoltenVK = moltenVKSupported;
645 
646     if (sVkEmulation->instanceSupportsExternalMemoryCapabilities) {
647         sVkEmulation->getImageFormatProperties2Func = vk_util::getVkInstanceProcAddrWithFallback<
648             vk_util::vk_fn_info::GetPhysicalDeviceImageFormatProperties2>(
649             {ivk->vkGetInstanceProcAddr, vk->vkGetInstanceProcAddr}, sVkEmulation->instance);
650         sVkEmulation->getPhysicalDeviceProperties2Func = vk_util::getVkInstanceProcAddrWithFallback<
651             vk_util::vk_fn_info::GetPhysicalDeviceProperties2>(
652             {ivk->vkGetInstanceProcAddr, vk->vkGetInstanceProcAddr}, sVkEmulation->instance);
653     }
654     sVkEmulation->getPhysicalDeviceFeatures2Func =
655         vk_util::getVkInstanceProcAddrWithFallback<vk_util::vk_fn_info::GetPhysicalDeviceFeatures2>(
656             {ivk->vkGetInstanceProcAddr, vk->vkGetInstanceProcAddr}, sVkEmulation->instance);
657 
658     if (sVkEmulation->instanceSupportsMoltenVK) {
659         sVkEmulation->setMTLTextureFunc = reinterpret_cast<PFN_vkSetMTLTextureMVK>(
660                 vk->vkGetInstanceProcAddr(
661                         sVkEmulation->instance, "vkSetMTLTextureMVK"));
662 
663         if (!sVkEmulation->setMTLTextureFunc) {
664             VK_EMU_INIT_RETURN_ON_ERROR("Cannot find vkSetMTLTextureMVK.");
665         }
666        sVkEmulation->getMTLTextureFunc = reinterpret_cast<PFN_vkGetMTLTextureMVK>(
667                 vk->vkGetInstanceProcAddr(
668                         sVkEmulation->instance, "vkGetMTLTextureMVK"));
669         if (!sVkEmulation->getMTLTextureFunc) {
670             VK_EMU_INIT_RETURN_ON_ERROR("Cannot find vkGetMTLTextureMVK.");
671         }
672         // LOG(VERBOSE) << "Instance supports VK_MVK_moltenvk.";
673     }
674 
675     uint32_t physdevCount = 0;
676     ivk->vkEnumeratePhysicalDevices(sVkEmulation->instance, &physdevCount,
677                                    nullptr);
678     std::vector<VkPhysicalDevice> physdevs(physdevCount);
679     ivk->vkEnumeratePhysicalDevices(sVkEmulation->instance, &physdevCount,
680                                    physdevs.data());
681 
682     // LOG(VERBOSE) << "Found " << physdevCount << " Vulkan physical devices.";
683 
684     if (physdevCount == 0) {
685         VK_EMU_INIT_RETURN_ON_ERROR("No physical devices available.");
686     }
687 
688     std::vector<VkEmulation::DeviceSupportInfo> deviceInfos(physdevCount);
689 
690     for (int i = 0; i < physdevCount; ++i) {
691         ivk->vkGetPhysicalDeviceProperties(physdevs[i],
692                                            &deviceInfos[i].physdevProps);
693 
694         // LOG(VERBOSE) << "Considering Vulkan physical device " << i << ": "
695         //              << deviceInfos[i].physdevProps.deviceName;
696 
697         // It's easier to figure out the staging buffer along with
698         // external memories if we have the memory properties on hand.
699         ivk->vkGetPhysicalDeviceMemoryProperties(physdevs[i],
700                                                 &deviceInfos[i].memProps);
701 
702         uint32_t deviceExtensionCount = 0;
703         ivk->vkEnumerateDeviceExtensionProperties(
704             physdevs[i], nullptr, &deviceExtensionCount, nullptr);
705         std::vector<VkExtensionProperties>& deviceExts = deviceInfos[i].extensions;
706         deviceExts.resize(deviceExtensionCount);
707         ivk->vkEnumerateDeviceExtensionProperties(
708             physdevs[i], nullptr, &deviceExtensionCount, deviceExts.data());
709 
710         deviceInfos[i].supportsExternalMemory = false;
711         deviceInfos[i].glInteropSupported = 0; // set later
712 
713         if (sVkEmulation->instanceSupportsExternalMemoryCapabilities) {
714             deviceInfos[i].supportsExternalMemory =
715                 extensionsSupported(deviceExts, externalMemoryDeviceExtNames);
716             deviceInfos[i].supportsIdProperties =
717                 sVkEmulation->getPhysicalDeviceProperties2Func != nullptr;
718             deviceInfos[i].supportsDriverProperties =
719                 extensionsSupported(deviceExts, {VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME}) ||
720                 (deviceInfos[i].physdevProps.apiVersion >= VK_API_VERSION_1_2);
721 
722             if (!sVkEmulation->getPhysicalDeviceProperties2Func) {
723                 fprintf(stderr, "%s: warning: device claims to support ID properties "
724                         "but vkGetPhysicalDeviceProperties2 could not be found\n", __func__);
725             }
726         }
727 
728         if (sVkEmulation->getPhysicalDeviceProperties2Func) {
729             VkPhysicalDeviceProperties2 deviceProps = {
730                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
731             };
732             VkPhysicalDeviceIDProperties idProps = {
733                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR,
734             };
735             VkPhysicalDeviceDriverPropertiesKHR driverProps = {
736                 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR,
737             };
738 
739             auto devicePropsChain = vk_make_chain_iterator(&deviceProps);
740 
741             if (deviceInfos[i].supportsIdProperties) {
742                 vk_append_struct(&devicePropsChain, &idProps);
743             }
744 
745             if (deviceInfos[i].supportsDriverProperties) {
746                 vk_append_struct(&devicePropsChain, &driverProps);
747             }
748 
749             sVkEmulation->getPhysicalDeviceProperties2Func(
750                 physdevs[i],
751                 &deviceProps);
752 
753             deviceInfos[i].idProps = vk_make_orphan_copy(idProps);
754 
755             std::stringstream driverVendorBuilder;
756             driverVendorBuilder << "Vendor " << std::hex << std::setfill('0') << std::showbase
757                                 << deviceInfos[i].physdevProps.vendorID;
758 
759             std::string decodedDriverVersion = decodeDriverVersion(
760                 deviceInfos[i].physdevProps.vendorID,
761                 deviceInfos[i].physdevProps.driverVersion);
762 
763             std::stringstream driverVersionBuilder;
764             driverVersionBuilder << "Driver Version " << std::hex << std::setfill('0')
765                                  << std::showbase << deviceInfos[i].physdevProps.driverVersion
766                                  << " Decoded As " << decodedDriverVersion;
767 
768             std::string driverVendor = driverVendorBuilder.str();
769             std::string driverVersion = driverVersionBuilder.str();
770             if (deviceInfos[i].supportsDriverProperties && driverProps.driverID) {
771                 driverVendor = std::string{driverProps.driverName} + " (" + driverVendor + ")";
772                 driverVersion = std::string{driverProps.driverInfo} + " (" +
773                                 string_VkDriverId(driverProps.driverID) + " " + driverVersion + ")";
774             }
775 
776             deviceInfos[i].driverVendor = driverVendor;
777             deviceInfos[i].driverVersion = driverVersion;
778         }
779 
780         deviceInfos[i].hasSamplerYcbcrConversionExtension =
781             extensionsSupported(deviceExts, {VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME});
782         if (sVkEmulation->getPhysicalDeviceFeatures2Func) {
783             VkPhysicalDeviceFeatures2 features2 = {
784                 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
785             };
786             auto features2Chain = vk_make_chain_iterator(&features2);
787             VkPhysicalDeviceSamplerYcbcrConversionFeatures samplerYcbcrConversionFeatures = {
788                 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
789             };
790             vk_append_struct(&features2Chain, &samplerYcbcrConversionFeatures);
791             sVkEmulation->getPhysicalDeviceFeatures2Func(physdevs[i], &features2);
792 
793             deviceInfos[i].supportsSamplerYcbcrConversion =
794                 samplerYcbcrConversionFeatures.samplerYcbcrConversion == VK_TRUE;
795         }
796 
797         uint32_t queueFamilyCount = 0;
798         ivk->vkGetPhysicalDeviceQueueFamilyProperties(
799                 physdevs[i], &queueFamilyCount, nullptr);
800         std::vector<VkQueueFamilyProperties> queueFamilyProps(queueFamilyCount);
801         ivk->vkGetPhysicalDeviceQueueFamilyProperties(
802                 physdevs[i], &queueFamilyCount, queueFamilyProps.data());
803 
804         for (uint32_t j = 0; j < queueFamilyCount; ++j) {
805             auto count = queueFamilyProps[j].queueCount;
806             auto flags = queueFamilyProps[j].queueFlags;
807 
808             bool hasGraphicsQueueFamily =
809                 (count > 0 && (flags & VK_QUEUE_GRAPHICS_BIT));
810             bool hasComputeQueueFamily =
811                 (count > 0 && (flags & VK_QUEUE_COMPUTE_BIT));
812 
813             deviceInfos[i].hasGraphicsQueueFamily =
814                 deviceInfos[i].hasGraphicsQueueFamily ||
815                 hasGraphicsQueueFamily;
816 
817             deviceInfos[i].hasComputeQueueFamily =
818                 deviceInfos[i].hasComputeQueueFamily ||
819                 hasComputeQueueFamily;
820 
821             if (hasGraphicsQueueFamily) {
822                 deviceInfos[i].graphicsQueueFamilyIndices.push_back(j);
823                 // LOG(VERBOSE) << "Graphics queue family index: " << j;
824             }
825 
826             if (hasComputeQueueFamily) {
827                 deviceInfos[i].computeQueueFamilyIndices.push_back(j);
828                 // LOG(VERBOSE) << "Compute queue family index: " << j;
829             }
830         }
831     }
832 
833     // Of all the devices enumerated, find the best one. Try to find a device
834     // with graphics queue as the highest priority, then ext memory, then
835     // compute.
836 
837     // Graphics queue is highest priority since without that, we really
838     // shouldn't be using the driver. Although, one could make a case for doing
839     // some sorts of things if only a compute queue is available (such as for
840     // AI), that's not really the priority yet.
841 
842     // As for external memory, we really should not be running on any driver
843     // without external memory support, but we might be able to pull it off, and
844     // single Vulkan apps might work via CPU transfer of the rendered frames.
845 
846     // Compute support is treated as icing on the cake and not relied upon yet
847     // for anything critical to emulation. However, we might potentially use it
848     // to perform image format conversion on GPUs where that's not natively
849     // supported.
850 
851     // Another implicit choice is to select only one Vulkan device. This makes
852     // things simple for now, but we could consider utilizing multiple devices
853     // in use cases that make sense, if/when they come up.
854 
855     std::vector<uint32_t> deviceScores(physdevCount, 0);
856 
857     for (uint32_t i = 0; i < physdevCount; ++i) {
858         uint32_t deviceScore = 0;
859         if (deviceInfos[i].hasGraphicsQueueFamily) deviceScore += 10000;
860         if (deviceInfos[i].supportsExternalMemory) deviceScore += 1000;
861         if (deviceInfos[i].physdevProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU ||
862             deviceInfos[i].physdevProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU) {
863             deviceScore += 100;
864         }
865         if (deviceInfos[i].physdevProps.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) {
866             deviceScore += 50;
867         }
868         deviceScores[i] = deviceScore;
869     }
870 
871     uint32_t maxScoringIndex = 0;
872     uint32_t maxScore = 0;
873 
874     // If we don't support physical device ID properties,
875     // just pick the first physical device.
876     if (!sVkEmulation->instanceSupportsExternalMemoryCapabilities) {
877         fprintf(stderr, "%s: warning: instance doesn't support "
878             "external memory capabilities, picking first physical device\n", __func__);
879         maxScoringIndex = 0;
880     } else {
881         for (uint32_t i = 0; i < physdevCount; ++i) {
882             if (deviceScores[i] > maxScore) {
883                 maxScoringIndex = i;
884                 maxScore = deviceScores[i];
885             }
886         }
887     }
888 
889     sVkEmulation->physdev = physdevs[maxScoringIndex];
890     sVkEmulation->deviceInfo = deviceInfos[maxScoringIndex];
891     // Postcondition: sVkEmulation has valid device support info
892 
893     // Ask about image format support here.
894     // TODO: May have to first ask when selecting physical devices
895     // (e.g., choose between Intel or NVIDIA GPU for certain image format
896     // support)
897     sVkEmulation->imageSupportInfo = getBasicImageSupportList();
898     for (size_t i = 0; i < sVkEmulation->imageSupportInfo.size(); ++i) {
899         getImageFormatExternalMemorySupportInfo(
900                 ivk, sVkEmulation->physdev, &sVkEmulation->imageSupportInfo[i]);
901     }
902 
903     if (!sVkEmulation->deviceInfo.hasGraphicsQueueFamily) {
904         VK_EMU_INIT_RETURN_ON_ERROR("No Vulkan devices with graphics queues found.");
905     }
906 
907     auto deviceVersion = sVkEmulation->deviceInfo.physdevProps.apiVersion;
908     VK_COMMON_LOG("Selecting Vulkan device: %s", sVkEmulation->deviceInfo.physdevProps.deviceName);
909 
910     // LOG(VERBOSE) << "Version: "
911     //              << VK_VERSION_MAJOR(deviceVersion) << "." << VK_VERSION_MINOR(deviceVersion) << "." << VK_VERSION_PATCH(deviceVersion);
912     // LOG(VERBOSE) << "Has graphics queue? "
913     //              << sVkEmulation->deviceInfo.hasGraphicsQueueFamily;
914     // LOG(VERBOSE) << "Has external memory support? "
915     //              << sVkEmulation->deviceInfo.supportsExternalMemory;
916     // LOG(VERBOSE) << "Has compute queue? "
917     //              << sVkEmulation->deviceInfo.hasComputeQueueFamily;
918 
919     float priority = 1.0f;
920     VkDeviceQueueCreateInfo dqCi = {
921         VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0,
922         sVkEmulation->deviceInfo.graphicsQueueFamilyIndices[0],
923         1, &priority,
924     };
925 
926     std::unordered_set<const char*> selectedDeviceExtensionNames_;
927 
928     if (sVkEmulation->deviceInfo.supportsExternalMemory) {
929         for (auto extension : externalMemoryDeviceExtNames) {
930             selectedDeviceExtensionNames_.emplace(extension);
931         }
932     }
933     for (auto extension : SwapChainStateVk::getRequiredDeviceExtensions()) {
934         selectedDeviceExtensionNames_.emplace(extension);
935     }
936     if (sVkEmulation->deviceInfo.hasSamplerYcbcrConversionExtension) {
937         selectedDeviceExtensionNames_.emplace(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
938     }
939     std::vector<const char*> selectedDeviceExtensionNames(
940         selectedDeviceExtensionNames_.begin(),
941         selectedDeviceExtensionNames_.end());
942 
943     VkDeviceCreateInfo dCi = {};
944     dCi.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
945     dCi.queueCreateInfoCount = 1;
946     dCi.pQueueCreateInfos = &dqCi;
947     dCi.enabledExtensionCount =
948         static_cast<uint32_t>(selectedDeviceExtensionNames.size());
949     dCi.ppEnabledExtensionNames = selectedDeviceExtensionNames.data();
950 
951     // Setting up VkDeviceCreateInfo::pNext
952     auto deviceCiChain = vk_make_chain_iterator(&dCi);
953 
954     VkPhysicalDeviceFeatures2 features = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2};
955     vk_append_struct(&deviceCiChain, &features);
956 
957     std::unique_ptr<VkPhysicalDeviceSamplerYcbcrConversionFeatures> samplerYcbcrConversionFeatures =
958         nullptr;
959     if (sVkEmulation->deviceInfo.supportsSamplerYcbcrConversion) {
960         samplerYcbcrConversionFeatures =
961             std::make_unique<VkPhysicalDeviceSamplerYcbcrConversionFeatures>(
962                 VkPhysicalDeviceSamplerYcbcrConversionFeatures{
963                     .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
964                     .samplerYcbcrConversion = VK_TRUE,
965                 });
966         vk_append_struct(&deviceCiChain, samplerYcbcrConversionFeatures.get());
967     }
968 
969     ivk->vkCreateDevice(sVkEmulation->physdev, &dCi, nullptr,
970                         &sVkEmulation->device);
971 
972     if (res != VK_SUCCESS) {
973         VK_EMU_INIT_RETURN_ON_ERROR("Failed to create Vulkan device. Error %s.",
974                                     string_VkResult(res));
975     }
976 
977     // device created; populate dispatch table
978     sVkEmulation->dvk = new VulkanDispatch;
979     init_vulkan_dispatch_from_device(
980         ivk, sVkEmulation->device, sVkEmulation->dvk);
981 
982     auto dvk = sVkEmulation->dvk;
983 
984     // Check if the dispatch table has everything 1.1 related
985     if (!vulkan_dispatch_check_device_VK_VERSION_1_0(dvk)) {
986         fprintf(stderr, "%s: Warning: Vulkan 1.0 APIs missing from device.\n", __func__);
987     }
988     if (deviceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
989         if (!vulkan_dispatch_check_device_VK_VERSION_1_1(dvk)) {
990             fprintf(stderr, "%s: Warning: Vulkan 1.1 APIs missing from device\n", __func__);
991         }
992     }
993 
994     if (sVkEmulation->deviceInfo.supportsExternalMemory) {
995         sVkEmulation->deviceInfo.getImageMemoryRequirements2Func =
996             reinterpret_cast<PFN_vkGetImageMemoryRequirements2KHR>(
997                 dvk->vkGetDeviceProcAddr(
998                     sVkEmulation->device, "vkGetImageMemoryRequirements2KHR"));
999         if (!sVkEmulation->deviceInfo.getImageMemoryRequirements2Func) {
1000             VK_EMU_INIT_RETURN_ON_ERROR("Cannot find vkGetImageMemoryRequirements2KHR.");
1001         }
1002         sVkEmulation->deviceInfo.getBufferMemoryRequirements2Func =
1003             reinterpret_cast<PFN_vkGetBufferMemoryRequirements2KHR>(
1004                 dvk->vkGetDeviceProcAddr(
1005                     sVkEmulation->device, "vkGetBufferMemoryRequirements2KHR"));
1006         if (!sVkEmulation->deviceInfo.getBufferMemoryRequirements2Func) {
1007             VK_EMU_INIT_RETURN_ON_ERROR("Cannot find vkGetBufferMemoryRequirements2KHR");
1008         }
1009 #ifdef _WIN32
1010         sVkEmulation->deviceInfo.getMemoryHandleFunc =
1011                 reinterpret_cast<PFN_vkGetMemoryWin32HandleKHR>(
1012                         dvk->vkGetDeviceProcAddr(sVkEmulation->device,
1013                                                 "vkGetMemoryWin32HandleKHR"));
1014 #else
1015         sVkEmulation->deviceInfo.getMemoryHandleFunc =
1016                 reinterpret_cast<PFN_vkGetMemoryFdKHR>(
1017                         dvk->vkGetDeviceProcAddr(sVkEmulation->device,
1018                                                 "vkGetMemoryFdKHR"));
1019 #endif
1020         if (!sVkEmulation->deviceInfo.getMemoryHandleFunc) {
1021             VK_EMU_INIT_RETURN_ON_ERROR("Cannot find vkGetMemory(Fd|Win32Handle)KHR");
1022         }
1023     }
1024 
1025     // LOG(VERBOSE) << "Vulkan logical device created and extension functions obtained.\n";
1026 
1027     sVkEmulation->queueLock = std::make_shared<android::base::Lock>();
1028     {
1029         android::base::AutoLock lock(*sVkEmulation->queueLock);
1030         dvk->vkGetDeviceQueue(
1031             sVkEmulation->device,
1032             sVkEmulation->deviceInfo.graphicsQueueFamilyIndices[0], 0,
1033             &sVkEmulation->queue);
1034     }
1035 
1036     sVkEmulation->queueFamilyIndex =
1037             sVkEmulation->deviceInfo.graphicsQueueFamilyIndices[0];
1038 
1039     // LOG(VERBOSE) << "Vulkan device queue obtained.";
1040 
1041     VkCommandPoolCreateInfo poolCi = {
1042         VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, 0,
1043         VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1044         sVkEmulation->queueFamilyIndex,
1045     };
1046 
1047     VkResult poolCreateRes = dvk->vkCreateCommandPool(
1048             sVkEmulation->device, &poolCi, nullptr, &sVkEmulation->commandPool);
1049 
1050     if (poolCreateRes != VK_SUCCESS) {
1051         VK_EMU_INIT_RETURN_ON_ERROR("Failed to create command pool. Error: %s.",
1052                                     string_VkResult(poolCreateRes));
1053     }
1054 
1055     VkCommandBufferAllocateInfo cbAi = {
1056         VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, 0,
1057         sVkEmulation->commandPool, VK_COMMAND_BUFFER_LEVEL_PRIMARY, 1,
1058     };
1059 
1060     VkResult cbAllocRes = dvk->vkAllocateCommandBuffers(
1061             sVkEmulation->device, &cbAi, &sVkEmulation->commandBuffer);
1062 
1063     if (cbAllocRes != VK_SUCCESS) {
1064         VK_EMU_INIT_RETURN_ON_ERROR("Failed to allocate command buffer. Error: %s.",
1065                                     string_VkResult(cbAllocRes));
1066     }
1067 
1068     VkFenceCreateInfo fenceCi = {
1069         VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, 0, 0,
1070     };
1071 
1072     VkResult fenceCreateRes = dvk->vkCreateFence(
1073         sVkEmulation->device, &fenceCi, nullptr,
1074         &sVkEmulation->commandBufferFence);
1075 
1076     if (fenceCreateRes != VK_SUCCESS) {
1077         VK_EMU_INIT_RETURN_ON_ERROR("Failed to create fence for command buffer. Error: %s.",
1078                                     string_VkResult(fenceCreateRes));
1079     }
1080 
1081     // At this point, the global emulation state's logical device can alloc
1082     // memory and send commands. However, it can't really do much yet to
1083     // communicate the results without the staging buffer. Set that up here.
1084     // Note that the staging buffer is meant to use external memory, with a
1085     // non-external-memory fallback.
1086 
1087     VkBufferCreateInfo bufCi = {
1088         VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, 0, 0,
1089         sVkEmulation->staging.size,
1090         VK_BUFFER_USAGE_TRANSFER_DST_BIT |
1091         VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
1092         VK_SHARING_MODE_EXCLUSIVE,
1093         0, nullptr,
1094     };
1095 
1096     VkResult bufCreateRes =
1097             dvk->vkCreateBuffer(sVkEmulation->device, &bufCi, nullptr,
1098                                &sVkEmulation->staging.buffer);
1099 
1100     if (bufCreateRes != VK_SUCCESS) {
1101         VK_EMU_INIT_RETURN_ON_ERROR("Failed to create staging buffer index. Error: %s.",
1102                                     string_VkResult(bufCreateRes));
1103     }
1104 
1105     VkMemoryRequirements memReqs;
1106     dvk->vkGetBufferMemoryRequirements(sVkEmulation->device,
1107                                       sVkEmulation->staging.buffer, &memReqs);
1108 
1109     sVkEmulation->staging.memory.size = memReqs.size;
1110 
1111     bool gotStagingTypeIndex = getStagingMemoryTypeIndex(
1112             dvk, sVkEmulation->device, &sVkEmulation->deviceInfo.memProps,
1113             &sVkEmulation->staging.memory.typeIndex);
1114 
1115     if (!gotStagingTypeIndex) {
1116         VK_EMU_INIT_RETURN_ON_ERROR("Failed to determine staging memory type index.");
1117     }
1118 
1119     if (!((1 << sVkEmulation->staging.memory.typeIndex) &
1120           memReqs.memoryTypeBits)) {
1121         VK_EMU_INIT_RETURN_ON_ERROR(
1122             "Failed: Inconsistent determination of memory type index for staging buffer");
1123     }
1124 
1125     if (!allocExternalMemory(dvk, &sVkEmulation->staging.memory,
1126                              false /* not external */,
1127                              kNullopt /* deviceAlignment */)) {
1128         VK_EMU_INIT_RETURN_ON_ERROR("Failed to allocate memory for staging buffer.");
1129     }
1130 
1131     VkResult stagingBufferBindRes = dvk->vkBindBufferMemory(
1132         sVkEmulation->device,
1133         sVkEmulation->staging.buffer,
1134         sVkEmulation->staging.memory.memory, 0);
1135 
1136     if (stagingBufferBindRes != VK_SUCCESS) {
1137         VK_EMU_INIT_RETURN_ON_ERROR("Failed to bind memory for staging buffer.");
1138     }
1139 
1140     // LOG(VERBOSE) << "Vulkan global emulation state successfully initialized.";
1141     sVkEmulation->live = true;
1142 
1143     sVkEmulation->transferQueueCommandBufferPool.resize(0);
1144 
1145     return sVkEmulation;
1146 }
1147 
initVkEmulationFeatures(std::unique_ptr<VkEmulationFeatures> features)1148 void initVkEmulationFeatures(std::unique_ptr<VkEmulationFeatures> features) {
1149     if (!sVkEmulation || !sVkEmulation->live) {
1150         ERR("VkEmulation is either not initialized or destroyed.");
1151         return;
1152     }
1153 
1154     AutoLock lock(sVkEmulationLock);
1155     INFO("Initializing VkEmulation features:");
1156     INFO("    glInteropSupported: %s", features->glInteropSupported ? "true" : "false");
1157     INFO("    useDeferredCommands: %s", features->deferredCommands ? "true" : "false");
1158     INFO("    createResourceWithRequirements: %s",
1159          features->createResourceWithRequirements ? "true" : "false");
1160     INFO("    useVulkanNativeSwapchain: %s", features->useVulkanNativeSwapchain ? "true" : "false");
1161     INFO("    enable guestRenderDoc: %s", features->guestRenderDoc ? "true" : "false");
1162     sVkEmulation->deviceInfo.glInteropSupported = features->glInteropSupported;
1163     sVkEmulation->useDeferredCommands = features->deferredCommands;
1164     sVkEmulation->useCreateResourcesWithRequirements = features->createResourceWithRequirements;
1165     sVkEmulation->guestRenderDoc = std::move(features->guestRenderDoc);
1166 
1167     if (features->useVulkanNativeSwapchain) {
1168         if (sVkEmulation->displayVk) {
1169             ERR("Reset VkEmulation::displayVk.");
1170         }
1171         sVkEmulation->displayVk = std::make_unique<DisplayVk>(
1172             *sVkEmulation->ivk, sVkEmulation->physdev, sVkEmulation->queueFamilyIndex,
1173             sVkEmulation->queueFamilyIndex, sVkEmulation->device, sVkEmulation->queue,
1174             sVkEmulation->queueLock, sVkEmulation->queue, sVkEmulation->queueLock);
1175     }
1176 }
1177 
getGlobalVkEmulation()1178 VkEmulation* getGlobalVkEmulation() {
1179     if (sVkEmulation && !sVkEmulation->live) return nullptr;
1180     return sVkEmulation;
1181 }
1182 
teardownGlobalVkEmulation()1183 void teardownGlobalVkEmulation() {
1184     if (!sVkEmulation) return;
1185 
1186     // Don't try to tear down something that did not set up completely; too risky
1187     if (!sVkEmulation->live) return;
1188 
1189     sVkEmulation->displayVk.reset();
1190 
1191     freeExternalMemoryLocked(sVkEmulation->dvk, &sVkEmulation->staging.memory);
1192 
1193     sVkEmulation->ivk->vkDestroyDevice(sVkEmulation->device, nullptr);
1194     sVkEmulation->gvk->vkDestroyInstance(sVkEmulation->instance, nullptr);
1195 
1196     sVkEmulation->live = false;
1197     delete sVkEmulation;
1198     sVkEmulation = nullptr;
1199 }
1200 
1201 // Precondition: sVkEmulation has valid device support info
allocExternalMemory(VulkanDispatch * vk,VkEmulation::ExternalMemoryInfo * info,bool actuallyExternal,Optional<uint64_t> deviceAlignment)1202 bool allocExternalMemory(VulkanDispatch* vk,
1203                          VkEmulation::ExternalMemoryInfo* info,
1204                          bool actuallyExternal,
1205                          Optional<uint64_t> deviceAlignment) {
1206     VkExportMemoryAllocateInfo exportAi = {
1207         VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, 0,
1208         VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1209     };
1210 
1211     VkExportMemoryAllocateInfo* exportAiPtr = nullptr;
1212 
1213     if (sVkEmulation->deviceInfo.supportsExternalMemory &&
1214         actuallyExternal) {
1215         exportAiPtr = &exportAi;
1216     }
1217 
1218     info->actualSize = (info->size + 2 * kPageSize - 1) / kPageSize * kPageSize;
1219     VkMemoryAllocateInfo allocInfo = {
1220             VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1221             exportAiPtr,
1222             info->actualSize,
1223             info->typeIndex,
1224     };
1225 
1226     bool memoryAllocated = false;
1227     std::vector<VkDeviceMemory> allocationAttempts;
1228     constexpr size_t kMaxAllocationAttempts = 20u;
1229 
1230     while (!memoryAllocated) {
1231         VkResult allocRes = vk->vkAllocateMemory(
1232                 sVkEmulation->device, &allocInfo, nullptr, &info->memory);
1233 
1234         if (allocRes != VK_SUCCESS) {
1235             // LOG(VERBOSE) << "allocExternalMemory: failed in vkAllocateMemory: "
1236             //              << allocRes;
1237             break;
1238         }
1239 
1240         if (sVkEmulation->deviceInfo.memProps.memoryTypes[info->typeIndex]
1241                     .propertyFlags &
1242             VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
1243             VkResult mapRes =
1244                     vk->vkMapMemory(sVkEmulation->device, info->memory, 0,
1245                                     info->actualSize, 0, &info->mappedPtr);
1246             if (mapRes != VK_SUCCESS) {
1247                 // LOG(VERBOSE) << "allocExternalMemory: failed in vkMapMemory: "
1248                 //              << mapRes;
1249                 break;
1250             }
1251         }
1252 
1253         uint64_t mappedPtrPageOffset =
1254                 reinterpret_cast<uint64_t>(info->mappedPtr) % kPageSize;
1255 
1256         if (  // don't care about alignment (e.g. device-local memory)
1257                 !deviceAlignment.hasValue() ||
1258                 // If device has an alignment requirement larger than current
1259                 // host pointer alignment (i.e. the lowest 1 bit of mappedPtr),
1260                 // the only possible way to make mappedPtr valid is to ensure
1261                 // that it is already aligned to page.
1262                 mappedPtrPageOffset == 0u ||
1263                 // If device has an alignment requirement smaller or equals to
1264                 // current host pointer alignment, clients can set a offset
1265                 // |kPageSize - mappedPtrPageOffset| in vkBindImageMemory to
1266                 // make it aligned to page and compatible with device
1267                 // requirements.
1268                 (kPageSize - mappedPtrPageOffset) % deviceAlignment.value() == 0) {
1269             // allocation success.
1270             memoryAllocated = true;
1271         } else {
1272             allocationAttempts.push_back(info->memory);
1273 
1274             // LOG(VERBOSE) << "allocExternalMemory: attempt #"
1275             //              << allocationAttempts.size()
1276             //              << " failed; deviceAlignment: "
1277             //              << deviceAlignment.valueOr(0)
1278             //              << " mappedPtrPageOffset: " << mappedPtrPageOffset;
1279 
1280             if (allocationAttempts.size() >= kMaxAllocationAttempts) {
1281                 // LOG(VERBOSE) << "allocExternalMemory: unable to allocate"
1282                 //              << " memory with CPU mapped ptr aligned to page";
1283                 break;
1284             }
1285         }
1286     }
1287 
1288     // clean up previous failed attempts
1289     for (const auto& mem : allocationAttempts) {
1290         vk->vkFreeMemory(sVkEmulation->device, mem, nullptr /* allocator */);
1291     }
1292     if (!memoryAllocated) {
1293         return false;
1294     }
1295 
1296     if (!sVkEmulation->deviceInfo.supportsExternalMemory ||
1297         !actuallyExternal) {
1298         return true;
1299     }
1300 
1301 #ifdef _WIN32
1302     VkMemoryGetWin32HandleInfoKHR getWin32HandleInfo = {
1303         VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR, 0,
1304         info->memory, VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1305     };
1306     VkResult exportRes =
1307         sVkEmulation->deviceInfo.getMemoryHandleFunc(
1308             sVkEmulation->device, &getWin32HandleInfo,
1309             &info->exportedHandle);
1310 #else
1311     VkMemoryGetFdInfoKHR getFdInfo = {
1312         VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR, 0,
1313         info->memory, VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1314     };
1315     VkResult exportRes =
1316         sVkEmulation->deviceInfo.getMemoryHandleFunc(
1317             sVkEmulation->device, &getFdInfo,
1318             &info->exportedHandle);
1319 #endif
1320 
1321     if (exportRes != VK_SUCCESS) {
1322         // LOG(VERBOSE) << "allocExternalMemory: Failed to get external memory "
1323         //                 "native handle: "
1324         //              << exportRes;
1325         return false;
1326     }
1327 
1328     info->actuallyExternal = true;
1329 
1330     return true;
1331 }
1332 
freeExternalMemoryLocked(VulkanDispatch * vk,VkEmulation::ExternalMemoryInfo * info)1333 void freeExternalMemoryLocked(VulkanDispatch* vk,
1334                               VkEmulation::ExternalMemoryInfo* info) {
1335     if (!info->memory)
1336         return;
1337 
1338     if (sVkEmulation->deviceInfo.memProps.memoryTypes[info->typeIndex]
1339                 .propertyFlags &
1340         VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
1341         if (sVkEmulation->occupiedGpas.find(info->gpa) !=
1342             sVkEmulation->occupiedGpas.end()) {
1343             sVkEmulation->occupiedGpas.erase(info->gpa);
1344             get_emugl_vm_operations().unmapUserBackedRam(info->gpa,
1345                                                          info->sizeToPage);
1346             info->gpa = 0u;
1347         }
1348 
1349         vk->vkUnmapMemory(sVkEmulation->device, info->memory);
1350         info->mappedPtr = nullptr;
1351         info->pageAlignedHva = nullptr;
1352     }
1353 
1354     vk->vkFreeMemory(sVkEmulation->device, info->memory, nullptr);
1355 
1356     info->memory = VK_NULL_HANDLE;
1357 
1358     if (info->exportedHandle != VK_EXT_MEMORY_HANDLE_INVALID) {
1359 #ifdef _WIN32
1360         CloseHandle(info->exportedHandle);
1361 #else
1362         close(info->exportedHandle);
1363 #endif
1364         info->exportedHandle = VK_EXT_MEMORY_HANDLE_INVALID;
1365     }
1366 }
1367 
importExternalMemory(VulkanDispatch * vk,VkDevice targetDevice,const VkEmulation::ExternalMemoryInfo * info,VkDeviceMemory * out)1368 bool importExternalMemory(VulkanDispatch* vk,
1369                           VkDevice targetDevice,
1370                           const VkEmulation::ExternalMemoryInfo* info,
1371                           VkDeviceMemory* out) {
1372 #ifdef _WIN32
1373     VkImportMemoryWin32HandleInfoKHR importInfo = {
1374         VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR, 0,
1375         VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1376         info->exportedHandle,
1377         0,
1378     };
1379 #else
1380     VkImportMemoryFdInfoKHR importInfo = {
1381         VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR, 0,
1382         VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1383         dupExternalMemory(info->exportedHandle),
1384     };
1385 #endif
1386     VkMemoryAllocateInfo allocInfo = {
1387         VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1388         &importInfo,
1389         info->size,
1390         info->typeIndex,
1391     };
1392 
1393     VkResult res = vk->vkAllocateMemory(targetDevice, &allocInfo, nullptr, out);
1394 
1395     if (res != VK_SUCCESS) {
1396         // LOG(ERROR) << "importExternalMemory: Failed with " << res;
1397         return false;
1398     }
1399 
1400     return true;
1401 }
1402 
importExternalMemoryDedicatedImage(VulkanDispatch * vk,VkDevice targetDevice,const VkEmulation::ExternalMemoryInfo * info,VkImage image,VkDeviceMemory * out)1403 bool importExternalMemoryDedicatedImage(
1404     VulkanDispatch* vk,
1405     VkDevice targetDevice,
1406     const VkEmulation::ExternalMemoryInfo* info,
1407     VkImage image,
1408     VkDeviceMemory* out) {
1409 
1410     VkMemoryDedicatedAllocateInfo dedicatedInfo = {
1411         VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO, 0,
1412         image,
1413         VK_NULL_HANDLE,
1414     };
1415 
1416 #ifdef _WIN32
1417     VkImportMemoryWin32HandleInfoKHR importInfo = {
1418         VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
1419         &dedicatedInfo,
1420         VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1421         info->exportedHandle,
1422         0,
1423     };
1424 #else
1425     VkImportMemoryFdInfoKHR importInfo = {
1426         VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
1427         &dedicatedInfo,
1428         VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1429         info->exportedHandle,
1430     };
1431 #endif
1432     VkMemoryAllocateInfo allocInfo = {
1433         VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1434         &importInfo,
1435         info->size,
1436         info->typeIndex,
1437     };
1438 
1439     VkResult res = vk->vkAllocateMemory(targetDevice, &allocInfo, nullptr, out);
1440 
1441     if (res != VK_SUCCESS) {
1442         // LOG(ERROR) << "importExternalMemoryDedicatedImage: Failed with " << res;
1443         return false;
1444     }
1445 
1446     return true;
1447 }
1448 
glFormat2VkFormat(GLint internalformat)1449 static VkFormat glFormat2VkFormat(GLint internalformat) {
1450     switch (internalformat) {
1451         case GL_LUMINANCE:
1452             return VK_FORMAT_R8_UNORM;
1453         case GL_RGB:
1454         case GL_RGB8:
1455             return VK_FORMAT_R8G8B8_UNORM;
1456         case GL_RGB565:
1457             return VK_FORMAT_R5G6B5_UNORM_PACK16;
1458         case GL_RGB16F:
1459             return VK_FORMAT_R16G16B16_SFLOAT;
1460         case GL_RGBA:
1461         case GL_RGBA8:
1462             return VK_FORMAT_R8G8B8A8_UNORM;
1463         case GL_RGB5_A1_OES:
1464             return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
1465         case GL_RGBA4_OES:
1466             return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
1467         case GL_RGB10_A2:
1468         case GL_UNSIGNED_INT_10_10_10_2_OES:
1469             return VK_FORMAT_A2R10G10B10_UNORM_PACK32;
1470         case GL_BGR10_A2_ANGLEX:
1471             return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
1472         case GL_RGBA16F:
1473             return VK_FORMAT_R16G16B16A16_SFLOAT;
1474         case GL_BGRA_EXT:
1475         case GL_BGRA8_EXT:
1476             return VK_FORMAT_B8G8R8A8_UNORM;;
1477         default:
1478             return VK_FORMAT_R8G8B8A8_UNORM;
1479     }
1480 };
1481 
isColorBufferVulkanCompatible(uint32_t colorBufferHandle)1482 bool isColorBufferVulkanCompatible(uint32_t colorBufferHandle) {
1483     auto fb = FrameBuffer::getFB();
1484 
1485     int width;
1486     int height;
1487     GLint internalformat;
1488 
1489     if (!fb->getColorBufferInfo(colorBufferHandle, &width, &height,
1490                                 &internalformat)) {
1491         return false;
1492     }
1493 
1494     VkFormat vkFormat = glFormat2VkFormat(internalformat);
1495 
1496     for (const auto& supportInfo : sVkEmulation->imageSupportInfo) {
1497         if (supportInfo.format == vkFormat && supportInfo.supported) {
1498             return true;
1499         }
1500     }
1501 
1502     return false;
1503 }
1504 
lastGoodTypeIndex(uint32_t indices)1505 static uint32_t lastGoodTypeIndex(uint32_t indices) {
1506     for (int32_t i = 31; i >= 0; --i) {
1507         if (indices & (1 << i)) {
1508             return i;
1509         }
1510     }
1511     return 0;
1512 }
1513 
lastGoodTypeIndexWithMemoryProperties(uint32_t indices,VkMemoryPropertyFlags memoryProperty)1514 static uint32_t lastGoodTypeIndexWithMemoryProperties(
1515         uint32_t indices,
1516         VkMemoryPropertyFlags memoryProperty) {
1517     for (int32_t i = 31; i >= 0; --i) {
1518         if ((indices & (1u << i)) &&
1519             (!memoryProperty ||
1520              (sVkEmulation->deviceInfo.memProps.memoryTypes[i].propertyFlags &
1521               memoryProperty))) {
1522             return i;
1523         }
1524     }
1525     return 0;
1526 }
1527 
1528 // pNext, sharingMode, queueFamilyIndexCount, pQueueFamilyIndices, and initialLayout won't be
1529 // filled.
generateColorBufferVkImageCreateInfo_locked(VkFormat format,uint32_t width,uint32_t height,VkImageTiling tiling)1530 static std::unique_ptr<VkImageCreateInfo> generateColorBufferVkImageCreateInfo_locked(
1531     VkFormat format, uint32_t width, uint32_t height, VkImageTiling tiling) {
1532     const VkFormatProperties* maybeFormatProperties = nullptr;
1533     for (const auto& supportInfo : sVkEmulation->imageSupportInfo) {
1534         if (supportInfo.format == format && supportInfo.supported) {
1535             maybeFormatProperties = &supportInfo.formatProps2.formatProperties;
1536             break;
1537         }
1538     }
1539     if (!maybeFormatProperties) {
1540         ERR("Format %s is not supported.", string_VkFormat(format));
1541         return nullptr;
1542     }
1543     const VkFormatProperties& formatProperties = *maybeFormatProperties;
1544 
1545     constexpr std::pair<VkFormatFeatureFlags, VkImageUsageFlags> formatUsagePairs[] = {
1546         {VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,
1547             VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT|VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT},
1548         {VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT,
1549             VK_IMAGE_USAGE_SAMPLED_BIT},
1550         {VK_FORMAT_FEATURE_TRANSFER_SRC_BIT,
1551             VK_IMAGE_USAGE_TRANSFER_SRC_BIT},
1552         {VK_FORMAT_FEATURE_TRANSFER_DST_BIT,
1553             VK_IMAGE_USAGE_TRANSFER_DST_BIT},
1554         {VK_FORMAT_FEATURE_BLIT_SRC_BIT,
1555             VK_IMAGE_USAGE_TRANSFER_SRC_BIT},
1556     };
1557     VkFormatFeatureFlags tilingFeatures = (tiling == VK_IMAGE_TILING_OPTIMAL)
1558                                               ? formatProperties.optimalTilingFeatures
1559                                               : formatProperties.linearTilingFeatures;
1560 
1561     VkImageUsageFlags usage = 0;
1562     for (const auto& formatUsage : formatUsagePairs) {
1563         usage |= (tilingFeatures & formatUsage.first) ? formatUsage.second : 0u;
1564     }
1565 
1566     return std::make_unique<VkImageCreateInfo>(VkImageCreateInfo{
1567         .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
1568         // The caller is responsible to fill pNext.
1569         .pNext = nullptr,
1570         .flags = 0,
1571         .imageType = VK_IMAGE_TYPE_2D,
1572         .format = format,
1573         .extent =
1574             {
1575                 .width = width,
1576                 .height = height,
1577                 .depth = 1,
1578             },
1579         .mipLevels = 1,
1580         .arrayLayers = 1,
1581         .samples = VK_SAMPLE_COUNT_1_BIT,
1582         .tiling = tiling,
1583         .usage = usage,
1584         // The caller is responsible to fill sharingMode.
1585         .sharingMode = VK_SHARING_MODE_MAX_ENUM,
1586         // The caller is responsible to fill queueFamilyIndexCount.
1587         .queueFamilyIndexCount = 0,
1588         // The caller is responsible to fill pQueueFamilyIndices.
1589         .pQueueFamilyIndices = nullptr,
1590         // The caller is responsible to fill initialLayout.
1591         .initialLayout = VK_IMAGE_LAYOUT_MAX_ENUM,
1592     });
1593 }
1594 
generateColorBufferVkImageCreateInfo(VkFormat format,uint32_t width,uint32_t height,VkImageTiling tiling)1595 std::unique_ptr<VkImageCreateInfo> generateColorBufferVkImageCreateInfo(VkFormat format,
1596                                                                         uint32_t width,
1597                                                                         uint32_t height,
1598                                                                         VkImageTiling tiling) {
1599     if (!sVkEmulation || !sVkEmulation->live) {
1600         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Host Vulkan device lost";
1601     }
1602     AutoLock lock(sVkEmulationLock);
1603     return generateColorBufferVkImageCreateInfo_locked(format, width, height, tiling);
1604 }
1605 
1606 // TODO(liyl): Currently we can only specify required memoryProperty
1607 // for a color buffer.
1608 //
1609 // Ideally we would like to specify a memory type index directly from
1610 // localAllocInfo.memoryTypeIndex when allocating color buffers in
1611 // vkAllocateMemory(). But this type index mechanism breaks "Modify the
1612 // allocation size and type index to suit the resulting image memory
1613 // size." which seems to be needed to keep the Android/Fuchsia guest
1614 // memory type index consistent across guest allocations, and without
1615 // which those guests might end up import allocating from a color buffer
1616 // with mismatched type indices.
1617 //
1618 // We should make it so the guest can only allocate external images/
1619 // buffers of one type index for image and one type index for buffer
1620 // to begin with, via filtering from the host.
setupVkColorBuffer(uint32_t colorBufferHandle,bool vulkanOnly,uint32_t memoryProperty,bool * exported,VkDeviceSize * allocSize,uint32_t * typeIndex,void ** mappedPtr)1621 bool setupVkColorBuffer(uint32_t colorBufferHandle,
1622                         bool vulkanOnly,
1623                         uint32_t memoryProperty,
1624                         bool* exported,
1625                         VkDeviceSize* allocSize,
1626                         uint32_t* typeIndex,
1627                         void** mappedPtr) {
1628     if (!isColorBufferVulkanCompatible(colorBufferHandle)) return false;
1629 
1630     auto vk = sVkEmulation->dvk;
1631 
1632     auto fb = FrameBuffer::getFB();
1633 
1634     int width;
1635     int height;
1636     GLint internalformat;
1637     FrameworkFormat frameworkFormat;
1638 
1639     if (!fb->getColorBufferInfo(colorBufferHandle, &width, &height,
1640                                 &internalformat, &frameworkFormat)) {
1641         return false;
1642     }
1643 
1644     AutoLock lock(sVkEmulationLock);
1645 
1646     auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
1647 
1648     // Already setup
1649     if (infoPtr) {
1650         // Setting exported is required for on_vkCreateImage backed by
1651         // an AHardwareBuffer.
1652         if (exported) *exported = infoPtr->glExported;
1653         // Update the allocation size to what the host driver wanted, or we
1654         // might get VK_ERROR_OUT_OF_DEVICE_MEMORY and a host crash
1655         if (allocSize) *allocSize = infoPtr->memory.size;
1656         // Update the type index to what the host driver wanted, or we might
1657         // get VK_ERROR_DEVICE_LOST
1658         if (typeIndex) *typeIndex = infoPtr->memory.typeIndex;
1659         // Update the mappedPtr to what the host driver wanted, otherwise we
1660         // may map the same memory twice.
1661         if (mappedPtr)
1662             *mappedPtr = infoPtr->memory.mappedPtr;
1663         return true;
1664     }
1665 
1666     VkFormat vkFormat;
1667     bool glCompatible = (frameworkFormat == FRAMEWORK_FORMAT_GL_COMPATIBLE);
1668     switch (frameworkFormat) {
1669         case FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE:
1670             vkFormat = glFormat2VkFormat(internalformat);
1671             break;
1672         case FrameworkFormat::FRAMEWORK_FORMAT_NV12:
1673             vkFormat = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
1674             break;
1675         case FrameworkFormat::FRAMEWORK_FORMAT_YV12:
1676         case FrameworkFormat::FRAMEWORK_FORMAT_YUV_420_888:
1677             vkFormat = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
1678             break;
1679         default:
1680             vkFormat = glFormat2VkFormat(internalformat);
1681             fprintf(stderr, "WARNING: unsupported framework format %d\n", frameworkFormat);
1682             break;
1683     }
1684 
1685     VkEmulation::ColorBufferInfo res;
1686 
1687     res.handle = colorBufferHandle;
1688 
1689     // TODO
1690     res.frameworkFormat = frameworkFormat;
1691     res.frameworkStride = 0;
1692 
1693     VkImageTiling tiling = (memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
1694                                ? VK_IMAGE_TILING_LINEAR
1695                                : VK_IMAGE_TILING_OPTIMAL;
1696     std::unique_ptr<VkImageCreateInfo> imageCi =
1697         generateColorBufferVkImageCreateInfo_locked(vkFormat, width, height, tiling);
1698     // pNext will be filled later.
1699     imageCi->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
1700     imageCi->queueFamilyIndexCount = 0;
1701     imageCi->pQueueFamilyIndices = nullptr;
1702     imageCi->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
1703 
1704     res.extent = imageCi->extent;
1705     res.format = imageCi->format;
1706     res.type = imageCi->imageType;
1707     res.tiling = imageCi->tiling;
1708     res.usageFlags = imageCi->usage;
1709     res.createFlags = imageCi->flags;
1710     res.sharingMode = imageCi->sharingMode;
1711 
1712     // Create the image. If external memory is supported, make it external.
1713     VkExternalMemoryImageCreateInfo extImageCi = {
1714         VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO, 0,
1715         VK_EXT_MEMORY_HANDLE_TYPE_BIT,
1716     };
1717 
1718     VkExternalMemoryImageCreateInfo* extImageCiPtr = nullptr;
1719 
1720     if (sVkEmulation->deviceInfo.supportsExternalMemory) {
1721         extImageCiPtr = &extImageCi;
1722     }
1723 
1724     imageCi->pNext = extImageCiPtr;
1725 
1726     VkResult createRes =
1727         vk->vkCreateImage(sVkEmulation->device, imageCi.get(), nullptr, &res.image);
1728     if (createRes != VK_SUCCESS) {
1729         // LOG(VERBOSE) << "Failed to create Vulkan image for ColorBuffer "
1730         //              << colorBufferHandle;
1731         return false;
1732     }
1733 
1734     vk->vkGetImageMemoryRequirements(sVkEmulation->device, res.image,
1735                                      &res.memReqs);
1736 
1737     // Currently we only care about two memory properties: DEVICE_LOCAL
1738     // and HOST_VISIBLE; other memory properties specified in
1739     // rcSetColorBufferVulkanMode2() call will be ignored for now.
1740     memoryProperty = memoryProperty & (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
1741                                        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
1742 
1743     res.memory.size = res.memReqs.size;
1744 
1745     // Determine memory type.
1746     if (memoryProperty) {
1747         res.memory.typeIndex = lastGoodTypeIndexWithMemoryProperties(
1748                 res.memReqs.memoryTypeBits, memoryProperty);
1749     } else {
1750         res.memory.typeIndex = lastGoodTypeIndex(res.memReqs.memoryTypeBits);
1751     }
1752 
1753     // LOG(VERBOSE) << "ColorBuffer " << colorBufferHandle
1754     //              << ", allocation size and type index: " << res.memory.size
1755     //              << ", " << res.memory.typeIndex
1756     //              << ", allocated memory property: "
1757     //              << sVkEmulation->deviceInfo.memProps
1758     //                         .memoryTypes[res.memory.typeIndex]
1759     //                         .propertyFlags
1760     //              << ", requested memory property: " << memoryProperty;
1761 
1762     bool isHostVisible = memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
1763     Optional<uint64_t> deviceAlignment =
1764             isHostVisible ? Optional<uint64_t>(res.memReqs.alignment) : kNullopt;
1765     bool allocRes = allocExternalMemory(
1766             vk, &res.memory, true /*actuallyExternal*/, deviceAlignment);
1767 
1768     if (!allocRes) {
1769         // LOG(VERBOSE) << "Failed to allocate ColorBuffer with Vulkan backing.";
1770         return false;
1771     }
1772 
1773     res.memory.pageOffset =
1774             reinterpret_cast<uint64_t>(res.memory.mappedPtr) % kPageSize;
1775     res.memory.bindOffset =
1776             res.memory.pageOffset ? kPageSize - res.memory.pageOffset : 0u;
1777 
1778     VkResult bindImageMemoryRes =
1779             vk->vkBindImageMemory(sVkEmulation->device, res.image,
1780                                   res.memory.memory, res.memory.bindOffset);
1781 
1782     if (bindImageMemoryRes != VK_SUCCESS) {
1783         fprintf(stderr, "%s: Failed to bind image memory. %d\n", __func__,
1784         bindImageMemoryRes);
1785         return false;
1786     }
1787 
1788     if (sVkEmulation->instanceSupportsMoltenVK) {
1789         sVkEmulation->getMTLTextureFunc(res.image, &res.mtlTexture);
1790         if (!res.mtlTexture) {
1791             fprintf(stderr, "%s: Failed to get MTLTexture.\n", __func__);
1792         }
1793 
1794 #ifdef __APPLE__
1795         CFRetain(res.mtlTexture);
1796 #endif
1797     }
1798 
1799     if (sVkEmulation->deviceInfo.supportsExternalMemory &&
1800         glCompatible &&
1801         FrameBuffer::getFB()->importMemoryToColorBuffer(
1802             dupExternalMemory(res.memory.exportedHandle), res.memory.size, false /* dedicated */,
1803             vulkanOnly, colorBufferHandle, res.image, *imageCi)) {
1804         res.glExported = true;
1805     }
1806 
1807     if (exported) *exported = res.glExported;
1808     if (allocSize) *allocSize = res.memory.size;
1809     if (typeIndex) *typeIndex = res.memory.typeIndex;
1810     if (mappedPtr)
1811         *mappedPtr = res.memory.mappedPtr;
1812 
1813     res.ownedByHost = std::make_shared<std::atomic_bool>(true);
1814 
1815     sVkEmulation->colorBuffers[colorBufferHandle] = res;
1816     return true;
1817 }
1818 
teardownVkColorBuffer(uint32_t colorBufferHandle)1819 bool teardownVkColorBuffer(uint32_t colorBufferHandle) {
1820     if (!sVkEmulation || !sVkEmulation->live) return false;
1821 
1822     auto vk = sVkEmulation->dvk;
1823 
1824     AutoLock lock(sVkEmulationLock);
1825 
1826     auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
1827 
1828     if (!infoPtr) return false;
1829 
1830     auto& info = *infoPtr;
1831     {
1832         android::base::AutoLock lock(*sVkEmulation->queueLock);
1833         VK_CHECK(vk->vkQueueWaitIdle(sVkEmulation->queue));
1834     }
1835     vk->vkDestroyImage(sVkEmulation->device, info.image, nullptr);
1836     freeExternalMemoryLocked(vk, &info.memory);
1837 
1838 #ifdef __APPLE__
1839     if (info.mtlTexture) {
1840         CFRelease(info.mtlTexture);
1841     }
1842 #endif
1843 
1844     sVkEmulation->colorBuffers.erase(colorBufferHandle);
1845 
1846     return true;
1847 }
1848 
getColorBufferInfo(uint32_t colorBufferHandle)1849 VkEmulation::ColorBufferInfo getColorBufferInfo(uint32_t colorBufferHandle) {
1850     VkEmulation::ColorBufferInfo res;
1851 
1852     AutoLock lock(sVkEmulationLock);
1853 
1854     auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
1855 
1856     if (!infoPtr) return res;
1857 
1858     res = *infoPtr;
1859     return res;
1860 }
1861 
updateColorBufferFromVkImage(uint32_t colorBufferHandle)1862 bool updateColorBufferFromVkImage(uint32_t colorBufferHandle) {
1863     if (!sVkEmulation || !sVkEmulation->live) return false;
1864 
1865     auto vk = sVkEmulation->dvk;
1866 
1867     AutoLock lock(sVkEmulationLock);
1868 
1869     auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
1870 
1871     if (!infoPtr) {
1872         // Color buffer not found; this is usually OK.
1873         return false;
1874     }
1875 
1876     if (!infoPtr->image) {
1877         fprintf(stderr, "%s: error: ColorBuffer 0x%x has no VkImage\n", __func__, colorBufferHandle);
1878         return false;
1879     }
1880 
1881     if (infoPtr->glExported ||
1882         (infoPtr->vulkanMode == VkEmulation::VulkanMode::VulkanOnly) ||
1883         infoPtr->frameworkFormat != FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE) {
1884         // No sync needed if exported to GL or in Vulkan-only mode
1885         return true;
1886     }
1887 
1888     // Record our synchronization commands.
1889     VkCommandBufferBeginInfo beginInfo = {
1890         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0,
1891         VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
1892         nullptr /* no inheritance info */,
1893     };
1894 
1895     vk->vkBeginCommandBuffer(
1896         sVkEmulation->commandBuffer,
1897         &beginInfo);
1898 
1899     // From the spec: If an application does not need the contents of a resource
1900     // to remain valid when transferring from one queue family to another, then
1901     // the ownership transfer should be skipped.
1902 
1903     // We definitely need to transition the image to
1904     // VK_TRANSFER_SRC_OPTIMAL and back.
1905 
1906     VkImageMemoryBarrier presentToTransferSrc = {
1907         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
1908         0,
1909         VK_ACCESS_HOST_READ_BIT,
1910         infoPtr->currentLayout,
1911         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1912         VK_QUEUE_FAMILY_IGNORED,
1913         VK_QUEUE_FAMILY_IGNORED,
1914         infoPtr->image,
1915         {
1916             VK_IMAGE_ASPECT_COLOR_BIT,
1917             0, 1, 0, 1,
1918         },
1919     };
1920 
1921     vk->vkCmdPipelineBarrier(
1922         sVkEmulation->commandBuffer,
1923         VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
1924         VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
1925         0,
1926         0, nullptr,
1927         0, nullptr,
1928         1, &presentToTransferSrc);
1929 
1930     infoPtr->currentLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
1931 
1932     // Copy to staging buffer
1933     uint32_t bpp = 4; /* format always rgba8...not */
1934     switch (infoPtr->format) {
1935         case VK_FORMAT_R5G6B5_UNORM_PACK16:
1936             bpp = 2;
1937             break;
1938         case VK_FORMAT_R8G8B8_UNORM:
1939             bpp = 3;
1940             break;
1941         default:
1942         case VK_FORMAT_R8G8B8A8_UNORM:
1943             bpp = 4;
1944             break;
1945     }
1946     VkBufferImageCopy region = {
1947         0 /* buffer offset */,
1948         infoPtr->extent.width,
1949         infoPtr->extent.height,
1950         {
1951             VK_IMAGE_ASPECT_COLOR_BIT,
1952             0, 0, 1,
1953         },
1954         { 0, 0, 0 },
1955         infoPtr->extent,
1956     };
1957 
1958     vk->vkCmdCopyImageToBuffer(
1959         sVkEmulation->commandBuffer,
1960         infoPtr->image,
1961         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
1962         sVkEmulation->staging.buffer,
1963         1, &region);
1964 
1965     vk->vkEndCommandBuffer(sVkEmulation->commandBuffer);
1966 
1967     VkSubmitInfo submitInfo = {
1968         VK_STRUCTURE_TYPE_SUBMIT_INFO, 0,
1969         0, nullptr,
1970         nullptr,
1971         1, &sVkEmulation->commandBuffer,
1972         0, nullptr,
1973     };
1974 
1975     {
1976         android::base::AutoLock lock(*sVkEmulation->queueLock);
1977         vk->vkQueueSubmit(sVkEmulation->queue, 1, &submitInfo,
1978                           sVkEmulation->commandBufferFence);
1979     }
1980 
1981     static constexpr uint64_t ANB_MAX_WAIT_NS =
1982         5ULL * 1000ULL * 1000ULL * 1000ULL;
1983 
1984     vk->vkWaitForFences(
1985         sVkEmulation->device, 1, &sVkEmulation->commandBufferFence,
1986         VK_TRUE, ANB_MAX_WAIT_NS);
1987     vk->vkResetFences(
1988         sVkEmulation->device, 1, &sVkEmulation->commandBufferFence);
1989 
1990     VkMappedMemoryRange toInvalidate = {
1991         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0,
1992         sVkEmulation->staging.memory.memory,
1993         0, VK_WHOLE_SIZE,
1994     };
1995 
1996     vk->vkInvalidateMappedMemoryRanges(
1997         sVkEmulation->device, 1, &toInvalidate);
1998 
1999     FrameBuffer::getFB()->
2000         replaceColorBufferContents(
2001             colorBufferHandle,
2002             sVkEmulation->staging.memory.mappedPtr,
2003             bpp * infoPtr->extent.width * infoPtr->extent.height);
2004 
2005     return true;
2006 }
2007 
updateVkImageFromColorBuffer(uint32_t colorBufferHandle)2008 bool updateVkImageFromColorBuffer(uint32_t colorBufferHandle) {
2009     if (!sVkEmulation || !sVkEmulation->live) return false;
2010 
2011     auto vk = sVkEmulation->dvk;
2012 
2013     AutoLock lock(sVkEmulationLock);
2014 
2015     auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2016 
2017     if (!infoPtr) {
2018         // Color buffer not found; this is usually OK.
2019         return false;
2020     }
2021 
2022     if (infoPtr->frameworkFormat == FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE && (
2023         infoPtr->glExported ||
2024         infoPtr->vulkanMode == VkEmulation::VulkanMode::VulkanOnly)) {
2025         // No sync needed if exported to GL or in Vulkan-only mode
2026         return true;
2027     }
2028 
2029     size_t cbNumBytes = 0;
2030     bool readRes = FrameBuffer::getFB()->
2031         readColorBufferContents(
2032             colorBufferHandle, &cbNumBytes, nullptr);
2033     if (!readRes) {
2034         fprintf(stderr, "%s: Failed to read color buffer 0x%x\n",
2035                 __func__, colorBufferHandle);
2036         return false;
2037     }
2038 
2039     if (cbNumBytes > sVkEmulation->staging.memory.size) {
2040         fprintf(stderr,
2041             "%s: Not enough space to read to staging buffer. "
2042             "Wanted: 0x%llx Have: 0x%llx\n", __func__,
2043             (unsigned long long)cbNumBytes,
2044             (unsigned long long)(sVkEmulation->staging.memory.size));
2045         return false;
2046     }
2047 
2048     readRes = FrameBuffer::getFB()->
2049         readColorBufferContents(
2050             colorBufferHandle, &cbNumBytes,
2051             sVkEmulation->staging.memory.mappedPtr);
2052 
2053     if (!readRes) {
2054         fprintf(stderr, "%s: Failed to read color buffer 0x%x (at glReadPixels)\n",
2055                 __func__, colorBufferHandle);
2056         return false;
2057     }
2058 
2059     // Record our synchronization commands.
2060     VkCommandBufferBeginInfo beginInfo = {
2061         VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, 0,
2062         VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
2063         nullptr /* no inheritance info */,
2064     };
2065 
2066     vk->vkBeginCommandBuffer(
2067         sVkEmulation->commandBuffer,
2068         &beginInfo);
2069 
2070     // From the spec: If an application does not need the contents of a resource
2071     // to remain valid when transferring from one queue family to another, then
2072     // the ownership transfer should be skipped.
2073 
2074     // We definitely need to transition the image to
2075     // VK_TRANSFER_SRC_OPTIMAL and back.
2076 
2077     VkImageMemoryBarrier presentToTransferSrc = {
2078         VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, 0,
2079         0,
2080         VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
2081         infoPtr->currentLayout,
2082         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2083         VK_QUEUE_FAMILY_IGNORED,
2084         VK_QUEUE_FAMILY_IGNORED,
2085         infoPtr->image,
2086         {
2087             VK_IMAGE_ASPECT_COLOR_BIT,
2088             0, 1, 0, 1,
2089         },
2090     };
2091 
2092     infoPtr->currentLayout =
2093         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
2094 
2095     vk->vkCmdPipelineBarrier(
2096         sVkEmulation->commandBuffer,
2097         VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
2098         VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
2099         0,
2100         0, nullptr,
2101         0, nullptr,
2102         1, &presentToTransferSrc);
2103 
2104     // Copy to staging buffer
2105     std::vector<VkBufferImageCopy> regions;
2106     if (infoPtr->frameworkFormat == FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE) {
2107         regions.push_back({
2108             0 /* buffer offset */,
2109             infoPtr->extent.width,
2110             infoPtr->extent.height,
2111             {
2112                 VK_IMAGE_ASPECT_COLOR_BIT,
2113                 0, 0, 1,
2114             },
2115             { 0, 0, 0 },
2116             infoPtr->extent,
2117         });
2118     } else {
2119         // YUV formats
2120         bool swapUV = infoPtr->frameworkFormat == FRAMEWORK_FORMAT_YV12;
2121         VkExtent3D subplaneExtent = {
2122             infoPtr->extent.width / 2,
2123             infoPtr->extent.height / 2,
2124             1
2125         };
2126         regions.push_back({
2127             0 /* buffer offset */,
2128             infoPtr->extent.width,
2129             infoPtr->extent.height,
2130             {
2131                 VK_IMAGE_ASPECT_PLANE_0_BIT,
2132                 0, 0, 1,
2133             },
2134             { 0, 0, 0 },
2135             infoPtr->extent,
2136         });
2137         regions.push_back({
2138             infoPtr->extent.width * infoPtr->extent.height /* buffer offset */,
2139             subplaneExtent.width,
2140             subplaneExtent.height,
2141             {
2142                 (VkImageAspectFlags)(swapUV ? VK_IMAGE_ASPECT_PLANE_2_BIT : VK_IMAGE_ASPECT_PLANE_1_BIT),
2143                 0, 0, 1,
2144             },
2145             { 0, 0, 0 },
2146             subplaneExtent,
2147         });
2148         if (infoPtr->frameworkFormat == FRAMEWORK_FORMAT_YUV_420_888
2149             || infoPtr->frameworkFormat == FRAMEWORK_FORMAT_YV12) {
2150             regions.push_back({
2151                 infoPtr->extent.width * infoPtr->extent.height
2152                     + subplaneExtent.width * subplaneExtent.height,
2153                 subplaneExtent.width,
2154                 subplaneExtent.height,
2155                 {
2156                    (VkImageAspectFlags)(swapUV ? VK_IMAGE_ASPECT_PLANE_1_BIT : VK_IMAGE_ASPECT_PLANE_2_BIT),
2157                     0, 0, 1,
2158                 },
2159                 { 0, 0, 0 },
2160                 subplaneExtent,
2161             });
2162         }
2163     }
2164 
2165     vk->vkCmdCopyBufferToImage(
2166         sVkEmulation->commandBuffer,
2167         sVkEmulation->staging.buffer,
2168         infoPtr->image,
2169         VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
2170         regions.size(), regions.data());
2171 
2172     vk->vkEndCommandBuffer(sVkEmulation->commandBuffer);
2173 
2174     VkSubmitInfo submitInfo = {
2175         VK_STRUCTURE_TYPE_SUBMIT_INFO, 0,
2176         0, nullptr,
2177         nullptr,
2178         1, &sVkEmulation->commandBuffer,
2179         0, nullptr,
2180     };
2181 
2182     {
2183         android::base::AutoLock lock(*sVkEmulation->queueLock);
2184         vk->vkQueueSubmit(sVkEmulation->queue, 1, &submitInfo,
2185                           sVkEmulation->commandBufferFence);
2186     }
2187 
2188     static constexpr uint64_t ANB_MAX_WAIT_NS =
2189         5ULL * 1000ULL * 1000ULL * 1000ULL;
2190 
2191     vk->vkWaitForFences(
2192         sVkEmulation->device, 1, &sVkEmulation->commandBufferFence,
2193         VK_TRUE, ANB_MAX_WAIT_NS);
2194     vk->vkResetFences(
2195         sVkEmulation->device, 1, &sVkEmulation->commandBufferFence);
2196 
2197     VkMappedMemoryRange toInvalidate = {
2198         VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE, 0,
2199         sVkEmulation->staging.memory.memory,
2200         0, VK_WHOLE_SIZE,
2201     };
2202 
2203     vk->vkInvalidateMappedMemoryRanges(
2204         sVkEmulation->device, 1, &toInvalidate);
2205     return true;
2206 }
2207 
getColorBufferExtMemoryHandle(uint32_t colorBuffer)2208 VK_EXT_MEMORY_HANDLE getColorBufferExtMemoryHandle(uint32_t colorBuffer) {
2209     if (!sVkEmulation || !sVkEmulation->live) return VK_EXT_MEMORY_HANDLE_INVALID;
2210 
2211     AutoLock lock(sVkEmulationLock);
2212 
2213     auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBuffer);
2214 
2215     if (!infoPtr) {
2216         // Color buffer not found; this is usually OK.
2217         return VK_EXT_MEMORY_HANDLE_INVALID;
2218     }
2219 
2220     return infoPtr->memory.exportedHandle;
2221 }
2222 
setColorBufferVulkanMode(uint32_t colorBuffer,uint32_t vulkanMode)2223 bool setColorBufferVulkanMode(uint32_t colorBuffer, uint32_t vulkanMode) {
2224     if (!sVkEmulation || !sVkEmulation->live) return VK_EXT_MEMORY_HANDLE_INVALID;
2225 
2226     AutoLock lock(sVkEmulationLock);
2227 
2228     auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBuffer);
2229 
2230     if (!infoPtr) {
2231         return false;
2232     }
2233 
2234     infoPtr->vulkanMode = static_cast<VkEmulation::VulkanMode>(vulkanMode);
2235 
2236     return true;
2237 }
2238 
getColorBufferMTLTexture(uint32_t colorBuffer)2239 MTLTextureRef getColorBufferMTLTexture(uint32_t colorBuffer) {
2240     if (!sVkEmulation || !sVkEmulation->live) return nullptr;
2241 
2242     AutoLock lock(sVkEmulationLock);
2243 
2244     auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBuffer);
2245 
2246     if (!infoPtr) {
2247         // Color buffer not found; this is usually OK.
2248         return nullptr;
2249     }
2250 
2251 #ifdef __APPLE__
2252     CFRetain(infoPtr->mtlTexture);
2253 #endif
2254     return infoPtr->mtlTexture;
2255 }
2256 
mapGpaToBufferHandle(uint32_t bufferHandle,uint64_t gpa,uint64_t size)2257 int32_t mapGpaToBufferHandle(uint32_t bufferHandle,
2258                              uint64_t gpa,
2259                              uint64_t size) {
2260     if (!sVkEmulation || !sVkEmulation->live)
2261         return VK_ERROR_DEVICE_LOST;
2262 
2263     AutoLock lock(sVkEmulationLock);
2264 
2265     VkEmulation::ExternalMemoryInfo* memoryInfoPtr = nullptr;
2266 
2267     auto colorBufferInfoPtr =
2268             android::base::find(sVkEmulation->colorBuffers, bufferHandle);
2269     if (colorBufferInfoPtr) {
2270         memoryInfoPtr = &colorBufferInfoPtr->memory;
2271     }
2272     auto bufferInfoPtr =
2273             android::base::find(sVkEmulation->buffers, bufferHandle);
2274     if (bufferInfoPtr) {
2275         memoryInfoPtr = &bufferInfoPtr->memory;
2276     }
2277 
2278     if (!memoryInfoPtr) {
2279         return VK_ERROR_INVALID_EXTERNAL_HANDLE;
2280     }
2281 
2282     // memory should be already mapped to host.
2283     if (!memoryInfoPtr->mappedPtr) {
2284         return VK_ERROR_MEMORY_MAP_FAILED;
2285     }
2286 
2287     memoryInfoPtr->gpa = gpa;
2288     memoryInfoPtr->pageAlignedHva =
2289             reinterpret_cast<uint8_t*>(memoryInfoPtr->mappedPtr) +
2290             memoryInfoPtr->bindOffset;
2291 
2292     size_t rawSize = memoryInfoPtr->size + memoryInfoPtr->pageOffset;
2293     if (size && size < rawSize) {
2294         rawSize = size;
2295     }
2296 
2297     memoryInfoPtr->sizeToPage = ((rawSize + kPageSize - 1) >> kPageBits)
2298                                 << kPageBits;
2299 
2300     // LOG(VERBOSE) << "mapGpaToColorBuffer: hva = " << memoryInfoPtr->mappedPtr
2301     //              << ", pageAlignedHva = " << memoryInfoPtr->pageAlignedHva
2302     //              << " -> [ " << memoryInfoPtr->gpa << ", "
2303     //              << memoryInfoPtr->gpa + memoryInfoPtr->sizeToPage << " ]";
2304 
2305     if (sVkEmulation->occupiedGpas.find(gpa) !=
2306         sVkEmulation->occupiedGpas.end()) {
2307         // emugl::emugl_crash_reporter("FATAL: already mapped gpa 0x%lx! ", gpa);
2308         return VK_ERROR_MEMORY_MAP_FAILED;
2309     }
2310 
2311     get_emugl_vm_operations().mapUserBackedRam(
2312             gpa, memoryInfoPtr->pageAlignedHva, memoryInfoPtr->sizeToPage);
2313 
2314     sVkEmulation->occupiedGpas.insert(gpa);
2315 
2316     return memoryInfoPtr->pageOffset;
2317 }
2318 
setupVkBuffer(uint32_t bufferHandle,bool vulkanOnly,uint32_t memoryProperty,bool * exported,VkDeviceSize * allocSize,uint32_t * typeIndex)2319 bool setupVkBuffer(uint32_t bufferHandle,
2320                    bool vulkanOnly,
2321                    uint32_t memoryProperty,
2322                    bool* exported,
2323                    VkDeviceSize* allocSize,
2324                    uint32_t* typeIndex) {
2325     if (vulkanOnly == false) {
2326         fprintf(stderr, "Data buffers should be vulkanOnly. Setup failed.\n");
2327         return false;
2328     }
2329 
2330     auto vk = sVkEmulation->dvk;
2331     auto fb = FrameBuffer::getFB();
2332 
2333     int size;
2334     if (!fb->getBufferInfo(bufferHandle, &size)) {
2335         return false;
2336     }
2337 
2338     AutoLock lock(sVkEmulationLock);
2339 
2340     auto infoPtr = android::base::find(sVkEmulation->buffers, bufferHandle);
2341 
2342     // Already setup
2343     if (infoPtr) {
2344         // Update the allocation size to what the host driver wanted, or we
2345         // might get VK_ERROR_OUT_OF_DEVICE_MEMORY and a host crash
2346         if (allocSize)
2347             *allocSize = infoPtr->memory.size;
2348         // Update the type index to what the host driver wanted, or we might
2349         // get VK_ERROR_DEVICE_LOST
2350         if (typeIndex)
2351             *typeIndex = infoPtr->memory.typeIndex;
2352         return true;
2353     }
2354 
2355     VkEmulation::BufferInfo res;
2356 
2357     res.handle = bufferHandle;
2358 
2359     res.size = size;
2360     res.usageFlags = VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
2361                      VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
2362                      VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
2363                      VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
2364                      VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
2365                      VK_BUFFER_USAGE_TRANSFER_DST_BIT;
2366     res.createFlags = 0;
2367 
2368     res.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
2369 
2370     // Create the image. If external memory is supported, make it external.
2371     VkExternalMemoryBufferCreateInfo extBufferCi = {
2372             VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
2373             0,
2374             VK_EXT_MEMORY_HANDLE_TYPE_BIT,
2375     };
2376 
2377     VkExternalMemoryBufferCreateInfo* extBufferCiPtr = nullptr;
2378     if (sVkEmulation->deviceInfo.supportsExternalMemory) {
2379         extBufferCiPtr = &extBufferCi;
2380     }
2381 
2382     VkBufferCreateInfo bufferCi = {
2383             VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2384             extBufferCiPtr,
2385             res.createFlags,
2386             res.size,
2387             res.usageFlags,
2388             res.sharingMode,
2389             /* queueFamilyIndexCount */ 0,
2390             /* pQueueFamilyIndices */ nullptr,
2391     };
2392 
2393     VkResult createRes = vk->vkCreateBuffer(sVkEmulation->device, &bufferCi,
2394                                             nullptr, &res.buffer);
2395 
2396     if (createRes != VK_SUCCESS) {
2397         // LOG(VERBOSE) << "Failed to create Vulkan Buffer for Buffer "
2398                      // << bufferHandle;
2399         return false;
2400     }
2401 
2402     vk->vkGetBufferMemoryRequirements(sVkEmulation->device, res.buffer,
2403                                       &res.memReqs);
2404 
2405     // Currently we only care about two memory properties: DEVICE_LOCAL
2406     // and HOST_VISIBLE; other memory properties specified in
2407     // rcSetColorBufferVulkanMode2() call will be ignored for now.
2408     memoryProperty = memoryProperty & (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
2409                                        VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
2410 
2411     res.memory.size = res.memReqs.size;
2412 
2413     // Determine memory type.
2414     if (memoryProperty) {
2415         res.memory.typeIndex = lastGoodTypeIndexWithMemoryProperties(
2416                 res.memReqs.memoryTypeBits, memoryProperty);
2417     } else {
2418         res.memory.typeIndex = lastGoodTypeIndex(res.memReqs.memoryTypeBits);
2419     }
2420 
2421     // LOG(VERBOSE) << "Buffer " << bufferHandle
2422     //              << "allocation size and type index: " << res.memory.size
2423     //              << ", " << res.memory.typeIndex
2424     //              << ", allocated memory property: "
2425     //              << sVkEmulation->deviceInfo.memProps
2426     //                         .memoryTypes[res.memory.typeIndex]
2427     //                         .propertyFlags
2428     //              << ", requested memory property: " << memoryProperty;
2429 
2430     bool isHostVisible = memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
2431     Optional<uint64_t> deviceAlignment =
2432             isHostVisible ? Optional<uint64_t>(res.memReqs.alignment) : kNullopt;
2433     bool allocRes = allocExternalMemory(
2434             vk, &res.memory, true /* actuallyExternal */, deviceAlignment);
2435 
2436     if (!allocRes) {
2437         // LOG(VERBOSE) << "Failed to allocate ColorBuffer with Vulkan backing.";
2438     }
2439 
2440     res.memory.pageOffset =
2441             reinterpret_cast<uint64_t>(res.memory.mappedPtr) % kPageSize;
2442     res.memory.bindOffset =
2443             res.memory.pageOffset ? kPageSize - res.memory.pageOffset : 0u;
2444 
2445     VkResult bindBufferMemoryRes = vk->vkBindBufferMemory(
2446             sVkEmulation->device, res.buffer, res.memory.memory, 0);
2447 
2448     if (bindBufferMemoryRes != VK_SUCCESS) {
2449         fprintf(stderr, "%s: Failed to bind buffer memory. %d\n", __func__,
2450                 bindBufferMemoryRes);
2451         return bindBufferMemoryRes;
2452     }
2453 
2454     bool isHostVisibleMemory =
2455             memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
2456 
2457     if (isHostVisibleMemory) {
2458         VkResult mapMemoryRes =
2459                 vk->vkMapMemory(sVkEmulation->device, res.memory.memory, 0,
2460                                 res.memory.size, {}, &res.memory.mappedPtr);
2461 
2462         if (mapMemoryRes != VK_SUCCESS) {
2463             fprintf(stderr, "%s: Failed to map image memory. %d\n", __func__,
2464                     mapMemoryRes);
2465             return false;
2466         }
2467     }
2468 
2469     res.glExported = false;
2470     if (exported)
2471         *exported = res.glExported;
2472     if (allocSize)
2473         *allocSize = res.memory.size;
2474     if (typeIndex)
2475         *typeIndex = res.memory.typeIndex;
2476 
2477     sVkEmulation->buffers[bufferHandle] = res;
2478     return allocRes;
2479 }
2480 
teardownVkBuffer(uint32_t bufferHandle)2481 bool teardownVkBuffer(uint32_t bufferHandle) {
2482     if (!sVkEmulation || !sVkEmulation->live)
2483         return false;
2484 
2485     auto vk = sVkEmulation->dvk;
2486     AutoLock lock(sVkEmulationLock);
2487 
2488     auto infoPtr = android::base::find(sVkEmulation->buffers, bufferHandle);
2489     if (!infoPtr)
2490         return false;
2491     {
2492         android::base::AutoLock lock(*sVkEmulation->queueLock);
2493         VK_CHECK(vk->vkQueueWaitIdle(sVkEmulation->queue));
2494     }
2495     auto& info = *infoPtr;
2496 
2497     vk->vkDestroyBuffer(sVkEmulation->device, info.buffer, nullptr);
2498     freeExternalMemoryLocked(vk, &info.memory);
2499     sVkEmulation->buffers.erase(bufferHandle);
2500 
2501     return true;
2502 }
2503 
getBufferExtMemoryHandle(uint32_t bufferHandle)2504 VK_EXT_MEMORY_HANDLE getBufferExtMemoryHandle(uint32_t bufferHandle) {
2505     if (!sVkEmulation || !sVkEmulation->live)
2506         return VK_EXT_MEMORY_HANDLE_INVALID;
2507 
2508     AutoLock lock(sVkEmulationLock);
2509 
2510     auto infoPtr = android::base::find(sVkEmulation->buffers, bufferHandle);
2511     if (!infoPtr) {
2512         // Color buffer not found; this is usually OK.
2513         return VK_EXT_MEMORY_HANDLE_INVALID;
2514     }
2515 
2516     return infoPtr->memory.exportedHandle;
2517 }
2518 
2519 VkExternalMemoryHandleTypeFlags
transformExternalMemoryHandleTypeFlags_tohost(VkExternalMemoryHandleTypeFlags bits)2520 transformExternalMemoryHandleTypeFlags_tohost(
2521     VkExternalMemoryHandleTypeFlags bits) {
2522 
2523     VkExternalMemoryHandleTypeFlags res = bits;
2524 
2525     // Transform Android/Fuchsia/Linux bits to host bits.
2526     if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) {
2527         res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
2528     }
2529 
2530 #ifdef _WIN32
2531     res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
2532     res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
2533 #endif
2534 
2535     if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) {
2536         res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
2537         res |= VK_EXT_MEMORY_HANDLE_TYPE_BIT;
2538     }
2539 
2540     if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA) {
2541         res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
2542         res |= VK_EXT_MEMORY_HANDLE_TYPE_BIT;
2543     }
2544 
2545     if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA) {
2546         res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
2547         res |= VK_EXT_MEMORY_HANDLE_TYPE_BIT;
2548     }
2549     return res;
2550 }
2551 
2552 VkExternalMemoryHandleTypeFlags
transformExternalMemoryHandleTypeFlags_fromhost(VkExternalMemoryHandleTypeFlags hostBits,VkExternalMemoryHandleTypeFlags wantedGuestHandleType)2553 transformExternalMemoryHandleTypeFlags_fromhost(
2554     VkExternalMemoryHandleTypeFlags hostBits,
2555     VkExternalMemoryHandleTypeFlags wantedGuestHandleType) {
2556 
2557     VkExternalMemoryHandleTypeFlags res = hostBits;
2558 
2559     if (res & VK_EXT_MEMORY_HANDLE_TYPE_BIT) {
2560         res &= ~VK_EXT_MEMORY_HANDLE_TYPE_BIT;
2561         res |= wantedGuestHandleType;
2562     }
2563 
2564 #ifdef _WIN32
2565     res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
2566     res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
2567 #endif
2568 
2569     return res;
2570 }
2571 
2572 VkExternalMemoryProperties
transformExternalMemoryProperties_tohost(VkExternalMemoryProperties props)2573 transformExternalMemoryProperties_tohost(
2574     VkExternalMemoryProperties props) {
2575     VkExternalMemoryProperties res = props;
2576     res.exportFromImportedHandleTypes =
2577         transformExternalMemoryHandleTypeFlags_tohost(
2578             props.exportFromImportedHandleTypes);
2579     res.compatibleHandleTypes =
2580         transformExternalMemoryHandleTypeFlags_tohost(
2581             props.compatibleHandleTypes);
2582     return res;
2583 }
2584 
2585 VkExternalMemoryProperties
transformExternalMemoryProperties_fromhost(VkExternalMemoryProperties props,VkExternalMemoryHandleTypeFlags wantedGuestHandleType)2586 transformExternalMemoryProperties_fromhost(
2587     VkExternalMemoryProperties props,
2588     VkExternalMemoryHandleTypeFlags wantedGuestHandleType) {
2589     VkExternalMemoryProperties res = props;
2590     res.exportFromImportedHandleTypes =
2591         transformExternalMemoryHandleTypeFlags_fromhost(
2592             props.exportFromImportedHandleTypes,
2593             wantedGuestHandleType);
2594     res.compatibleHandleTypes =
2595         transformExternalMemoryHandleTypeFlags_fromhost(
2596             props.compatibleHandleTypes,
2597             wantedGuestHandleType);
2598     return res;
2599 }
2600 
2601 // Allocate a ready to use VkCommandBuffer for queue transfer. The caller needs
2602 // to signal the returned VkFence when the VkCommandBuffer completes.
allocateQueueTransferCommandBuffer_locked()2603 static std::tuple<VkCommandBuffer, VkFence> allocateQueueTransferCommandBuffer_locked() {
2604     auto vk = sVkEmulation->dvk;
2605     // Check if a command buffer in the pool is ready to use. If the associated
2606     // VkFence is ready, vkGetFenceStatus will return VK_SUCCESS, and the
2607     // associated command buffer should be ready to use, so we return that
2608     // command buffer with the associated VkFence. If the associated VkFence is
2609     // not ready, vkGetFenceStatus will return VK_NOT_READY, we will continue to
2610     // search and test the next command buffer. If the VkFence is in an error
2611     // state, vkGetFenceStatus will return with other VkResult variants, we will
2612     // abort.
2613     for (auto& [commandBuffer, fence] : sVkEmulation->transferQueueCommandBufferPool) {
2614         auto res = vk->vkGetFenceStatus(sVkEmulation->device, fence);
2615         if (res == VK_SUCCESS) {
2616             VK_CHECK(vk->vkResetFences(sVkEmulation->device, 1, &fence));
2617             VK_CHECK(vk->vkResetCommandBuffer(
2618                 commandBuffer,
2619                 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT));
2620             return std::make_tuple(commandBuffer, fence);
2621         }
2622         if (res == VK_NOT_READY) {
2623             continue;
2624         }
2625         // We either have a device lost, or an invalid fence state. For the device lost case,
2626         // VK_CHECK will ensure we capture the relevant streams.
2627         VK_CHECK(res);
2628     }
2629     VkCommandBuffer commandBuffer;
2630     VkCommandBufferAllocateInfo allocateInfo = {
2631         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
2632         .pNext = nullptr,
2633         .commandPool = sVkEmulation->commandPool,
2634         .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
2635         .commandBufferCount = 1,
2636     };
2637     VK_CHECK(vk->vkAllocateCommandBuffers(sVkEmulation->device, &allocateInfo,
2638                                           &commandBuffer));
2639     VkFence fence;
2640     VkFenceCreateInfo fenceCi = {
2641         .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
2642         .pNext = nullptr,
2643         .flags = 0,
2644     };
2645     VK_CHECK(
2646         vk->vkCreateFence(sVkEmulation->device, &fenceCi, nullptr, &fence));
2647 
2648     sVkEmulation->transferQueueCommandBufferPool.emplace_back(commandBuffer, fence);
2649 
2650     VK_COMMON_VERBOSE(
2651         "Create a new command buffer for queue transfer for a total of %d "
2652         "transfer command buffers",
2653         static_cast<int>(sVkEmulation->transferQueueCommandBufferPool.size()));
2654 
2655     return std::make_tuple(commandBuffer, fence);
2656 }
2657 
acquireColorBuffersForHostComposing(const std::vector<uint32_t> & layerColorBuffers,uint32_t renderTargetColorBuffer)2658 void acquireColorBuffersForHostComposing(const std::vector<uint32_t>& layerColorBuffers,
2659                                          uint32_t renderTargetColorBuffer) {
2660     if (!sVkEmulation || !sVkEmulation->live) {
2661         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Host Vulkan device lost";
2662     }
2663 
2664     std::vector<std::tuple<uint32_t, VkImageLayout>> colorBuffersAndLayouts;
2665     for (uint32_t layerColorBuffer : layerColorBuffers) {
2666         colorBuffersAndLayouts.emplace_back(
2667             layerColorBuffer, FrameBuffer::getFB()->getVkImageLayoutForComposeLayer());
2668     }
2669     colorBuffersAndLayouts.emplace_back(renderTargetColorBuffer,
2670                                         VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
2671     AutoLock lock(sVkEmulationLock);
2672     auto vk = sVkEmulation->dvk;
2673 
2674     std::vector<std::tuple<VkEmulation::ColorBufferInfo*, VkImageLayout>>
2675         colorBufferInfosAndLayouts;
2676     for (auto [colorBufferHandle, newLayout] : colorBuffersAndLayouts) {
2677         VkEmulation::ColorBufferInfo *infoPtr =
2678             android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2679         if (!infoPtr) {
2680             VK_COMMON_ERROR("Invalid ColorBuffer handle %d.",
2681                             static_cast<int>(colorBufferHandle));
2682             continue;
2683         }
2684         colorBufferInfosAndLayouts.emplace_back(infoPtr, newLayout);
2685     }
2686 
2687     std::vector<VkImageMemoryBarrier> queueTransferBarriers;
2688     std::stringstream transferredColorBuffers;
2689     for (auto [infoPtr, _] : colorBufferInfosAndLayouts) {
2690         if (infoPtr->ownedByHost->load()) {
2691             VK_COMMON_VERBOSE("Skipping queue transfer from guest to host for ColorBuffer(id = %d)",
2692                               static_cast<int>(infoPtr->handle));
2693             continue;
2694         }
2695         VkImageMemoryBarrier queueTransferBarrier = {
2696             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
2697             .pNext = nullptr,
2698             .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT,
2699             // VK_ACCESS_SHADER_READ_BIT for the compose layers, and VK_ACCESS_TRANSFER_READ_BIT for
2700             // the render target/post source.
2701             .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT,
2702             .oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
2703             .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
2704             .srcQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
2705             .dstQueueFamilyIndex = sVkEmulation->queueFamilyIndex,
2706             .image = infoPtr->image,
2707             .subresourceRange =
2708                 {
2709                     .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2710                     .baseMipLevel = 0,
2711                     .levelCount = 1,
2712                     .baseArrayLayer = 0,
2713                     .layerCount = 1,
2714                 },
2715         };
2716         queueTransferBarriers.emplace_back(queueTransferBarrier);
2717         transferredColorBuffers << infoPtr->handle << " ";
2718         infoPtr->ownedByHost->store(true);
2719         infoPtr->currentLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
2720     }
2721 
2722     std::vector<VkImageMemoryBarrier> layoutTransitionBarriers;
2723     for (auto [infoPtr, newLayout] : colorBufferInfosAndLayouts) {
2724         if (newLayout == VK_IMAGE_LAYOUT_UNDEFINED || infoPtr->currentLayout == newLayout) {
2725             continue;
2726         }
2727         VkImageMemoryBarrier layoutTransitionBarrier = {
2728             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
2729             .pNext = nullptr,
2730             .srcAccessMask = VK_ACCESS_MEMORY_WRITE_BIT | VK_ACCESS_MEMORY_READ_BIT,
2731             // VK_ACCESS_SHADER_READ_BIT for the compose layers, and VK_ACCESS_TRANSFER_READ_BIT for
2732             // the render target/post source.
2733             .dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT,
2734             .oldLayout = infoPtr->currentLayout,
2735             .newLayout = newLayout,
2736             .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2737             .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2738             .image = infoPtr->image,
2739             .subresourceRange =
2740                 {
2741                     .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2742                     .baseMipLevel = 0,
2743                     .levelCount = 1,
2744                     .baseArrayLayer = 0,
2745                     .layerCount = 1,
2746                 },
2747         };
2748         layoutTransitionBarriers.emplace_back(layoutTransitionBarrier);
2749         infoPtr->currentLayout = newLayout;
2750     }
2751 
2752     auto [commandBuffer, fence] = allocateQueueTransferCommandBuffer_locked();
2753 
2754     VkCommandBufferBeginInfo beginInfo = {
2755         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
2756         .pNext = nullptr,
2757         .flags = 0,
2758         .pInheritanceInfo = nullptr,
2759     };
2760     VK_CHECK(vk->vkBeginCommandBuffer(commandBuffer, &beginInfo));
2761     if (!queueTransferBarriers.empty()) {
2762         vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
2763                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr,
2764                                  static_cast<uint32_t>(queueTransferBarriers.size()),
2765                                  queueTransferBarriers.data());
2766     }
2767     if (!layoutTransitionBarriers.empty()) {
2768         vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
2769                                  VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr,
2770                                  static_cast<uint32_t>(layoutTransitionBarriers.size()),
2771                                  layoutTransitionBarriers.data());
2772     }
2773     VK_CHECK(vk->vkEndCommandBuffer(commandBuffer));
2774 
2775     // We assume the host Vulkan compositor lives on the same queue, so we don't
2776     // need to use semaphore to synchronize with the host compositor.
2777     VkSubmitInfo submitInfo = {
2778         .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
2779         .pNext = nullptr,
2780         .waitSemaphoreCount = 0,
2781         .pWaitSemaphores = nullptr,
2782         .pWaitDstStageMask = nullptr,
2783         .commandBufferCount = 1,
2784         .pCommandBuffers = &commandBuffer,
2785         .signalSemaphoreCount = 0,
2786         .pSignalSemaphores = nullptr,
2787     };
2788     {
2789         std::stringstream ss;
2790         ss << __func__
2791            << ": submitting commands to issue acquire queue transfer from "
2792               "guest to host for ColorBuffer("
2793            << transferredColorBuffers.str() << ")";
2794         AEMU_SCOPED_TRACE(ss.str().c_str());
2795         android::base::AutoLock lock(*sVkEmulation->queueLock);
2796         VK_CHECK(vk->vkQueueSubmit(sVkEmulation->queue, 1, &submitInfo, fence));
2797     }
2798 }
2799 
doReleaseColorBufferForGuestRendering(const std::vector<uint32_t> & colorBufferHandles)2800 static VkFence doReleaseColorBufferForGuestRendering(
2801     const std::vector<uint32_t>& colorBufferHandles) {
2802     if (!sVkEmulation || !sVkEmulation->live) {
2803         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Host Vulkan device lost";
2804     }
2805 
2806     AutoLock lock(sVkEmulationLock);
2807     auto vk = sVkEmulation->dvk;
2808 
2809     std::stringstream transferredColorBuffers;
2810     std::vector<VkImageMemoryBarrier> layoutTransitionBarriers;
2811     std::vector<VkImageMemoryBarrier> queueTransferBarriers;
2812     for (uint32_t colorBufferHandle : colorBufferHandles) {
2813         auto infoPtr =
2814             android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2815         if (!infoPtr) {
2816             VK_COMMON_ERROR("Invalid ColorBuffer handle %d.",
2817                             static_cast<int>(colorBufferHandle));
2818             continue;
2819         }
2820         if (!infoPtr->ownedByHost->load()) {
2821             VK_COMMON_VERBOSE(
2822                 "Skipping queue transfer from host to guest for "
2823                 "ColorBuffer(id = %d)",
2824                 static_cast<int>(colorBufferHandle));
2825             continue;
2826         }
2827         VkImageMemoryBarrier layoutTransitionBarrier = {
2828             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
2829             .pNext = nullptr,
2830             .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
2831             .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
2832             .oldLayout = infoPtr->currentLayout,
2833             .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
2834             .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2835             .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
2836             .image = infoPtr->image,
2837             .subresourceRange =
2838                 {
2839                     .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2840                     .baseMipLevel = 0,
2841                     .levelCount = 1,
2842                     .baseArrayLayer = 0,
2843                     .layerCount = 1,
2844                 },
2845         };
2846         layoutTransitionBarriers.emplace_back(layoutTransitionBarrier);
2847         infoPtr->currentLayout = layoutTransitionBarrier.newLayout;
2848 
2849         VkImageMemoryBarrier queueTransferBarrier = {
2850             .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
2851             .pNext = nullptr,
2852             .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
2853             .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
2854             .oldLayout = infoPtr->currentLayout,
2855             .newLayout = infoPtr->currentLayout,
2856             .srcQueueFamilyIndex = sVkEmulation->queueFamilyIndex,
2857             .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
2858             .image = infoPtr->image,
2859             .subresourceRange =
2860                 {
2861                     .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2862                     .baseMipLevel = 0,
2863                     .levelCount = 1,
2864                     .baseArrayLayer = 0,
2865                     .layerCount = 1,
2866                 },
2867         };
2868         queueTransferBarriers.emplace_back(queueTransferBarrier);
2869         transferredColorBuffers << colorBufferHandle << " ";
2870         infoPtr->ownedByHost->store(false);
2871     }
2872 
2873     auto [commandBuffer, fence] = allocateQueueTransferCommandBuffer_locked();
2874 
2875     VK_CHECK(vk->vkResetCommandBuffer(commandBuffer, 0));
2876     VkCommandBufferBeginInfo beginInfo = {
2877         .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
2878         .pNext = nullptr,
2879         .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
2880         .pInheritanceInfo = nullptr,
2881     };
2882     VK_CHECK(vk->vkBeginCommandBuffer(commandBuffer, &beginInfo));
2883     vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
2884                              VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr,
2885                              static_cast<uint32_t>(layoutTransitionBarriers.size()),
2886                              layoutTransitionBarriers.data());
2887     vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
2888                              VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr,
2889                              static_cast<uint32_t>(queueTransferBarriers.size()),
2890                              queueTransferBarriers.data());
2891     VK_CHECK(vk->vkEndCommandBuffer(commandBuffer));
2892     // We assume the host Vulkan compositor lives on the same queue, so we don't
2893     // need to use semaphore to synchronize with the host compositor.
2894     VkSubmitInfo submitInfo = {
2895         .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
2896         .pNext = nullptr,
2897         .waitSemaphoreCount = 0,
2898         .pWaitSemaphores = nullptr,
2899         .pWaitDstStageMask = nullptr,
2900         .commandBufferCount = 1,
2901         .pCommandBuffers = &commandBuffer,
2902         .signalSemaphoreCount = 0,
2903         .pSignalSemaphores = nullptr,
2904     };
2905 
2906     {
2907         std::stringstream ss;
2908         ss << __func__
2909            << ": submitting commands to issue release queue transfer from host "
2910               "to guest for ColorBuffer("
2911            << transferredColorBuffers.str() << ")";
2912         AEMU_SCOPED_TRACE(ss.str().c_str());
2913         android::base::AutoLock lock(*sVkEmulation->queueLock);
2914         VK_CHECK(vk->vkQueueSubmit(sVkEmulation->queue, 1, &submitInfo, fence));
2915     }
2916     return fence;
2917 }
2918 
releaseColorBufferFromHostComposing(const std::vector<uint32_t> & colorBufferHandles)2919 void releaseColorBufferFromHostComposing(const std::vector<uint32_t>& colorBufferHandles) {
2920     doReleaseColorBufferForGuestRendering(colorBufferHandles);
2921 }
2922 
releaseColorBufferFromHostComposingSync(const std::vector<uint32_t> & colorBufferHandles)2923 void releaseColorBufferFromHostComposingSync(const std::vector<uint32_t>& colorBufferHandles) {
2924     VkFence fence = doReleaseColorBufferForGuestRendering(colorBufferHandles);
2925     if (!sVkEmulation || !sVkEmulation->live) {
2926         GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "Host Vulkan device lost";
2927     }
2928 
2929     AutoLock lock(sVkEmulationLock);
2930     auto vk = sVkEmulation->dvk;
2931     static constexpr uint64_t ANB_MAX_WAIT_NS =
2932         5ULL * 1000ULL * 1000ULL * 1000ULL;
2933     VK_CHECK(vk->vkWaitForFences(sVkEmulation->device, 1, &fence, VK_TRUE,
2934                                  ANB_MAX_WAIT_NS));
2935 }
2936 
setColorBufferCurrentLayout(uint32_t colorBufferHandle,VkImageLayout layout)2937 void setColorBufferCurrentLayout(uint32_t colorBufferHandle, VkImageLayout layout) {
2938     AutoLock lock(sVkEmulationLock);
2939 
2940     auto infoPtr = android::base::find(sVkEmulation->colorBuffers, colorBufferHandle);
2941     if (!infoPtr) {
2942         VK_COMMON_ERROR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
2943         return;
2944     }
2945     infoPtr->currentLayout = layout;
2946 }
2947 
2948 } // namespace goldfish_vk
2949