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