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