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