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, ®ion);
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