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