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 "VkEmulatedPhysicalDeviceMemory.h"
30 #include "VkFormatUtils.h"
31 #include "VulkanDispatch.h"
32 #include "aemu/base/Optional.h"
33 #include "aemu/base/Tracing.h"
34 #include "aemu/base/containers/Lookup.h"
35 #include "aemu/base/containers/StaticMap.h"
36 #include "aemu/base/synchronization/Lock.h"
37 #include "aemu/base/system/System.h"
38 #include "common/goldfish_vk_dispatch.h"
39 #include "host-common/GfxstreamFatalError.h"
40 #include "host-common/emugl_vm_operations.h"
41 #include "host-common/vm_operations.h"
42
43 #ifdef _WIN32
44 #include <windows.h>
45 #else
46 #include <fcntl.h>
47 #include <unistd.h>
48 #endif
49
50 #ifdef __APPLE__
51 #include <CoreFoundation/CoreFoundation.h>
52 #include <vulkan/vulkan_beta.h> // for MoltenVK portability extensions
53 #endif
54
55 namespace gfxstream {
56 namespace vk {
57 namespace {
58
59 using android::base::AutoLock;
60 using android::base::kNullopt;
61 using android::base::Optional;
62 using android::base::StaticLock;
63 using android::base::StaticMap;
64 using emugl::ABORT_REASON_OTHER;
65 using emugl::FatalError;
66
67 #ifndef VERBOSE
68 #define VERBOSE(fmt, ...) \
69 if (android::base::isVerboseLogging()) { \
70 INFO(fmt, ##__VA_ARGS__); \
71 }
72 #endif
73
74 constexpr size_t kPageBits = 12;
75 constexpr size_t kPageSize = 1u << kPageBits;
76
77 static std::optional<std::string> sMemoryLogPath = std::nullopt;
78
string_AstcEmulationMode(AstcEmulationMode mode)79 const char* string_AstcEmulationMode(AstcEmulationMode mode) {
80 switch (mode) {
81 case AstcEmulationMode::Disabled:
82 return "Disabled";
83 case AstcEmulationMode::Cpu:
84 return "Cpu";
85 case AstcEmulationMode::Gpu:
86 return "Gpu";
87 }
88 return "Unknown";
89 }
90
91 } // namespace
92
93 static StaticMap<VkDevice, uint32_t> sKnownStagingTypeIndices;
94
exportMemoryHandle(VkDevice device,VkDeviceMemory memory)95 std::optional<GenericDescriptorInfo> VkEmulation::exportMemoryHandle(VkDevice device,
96 VkDeviceMemory memory) {
97 GenericDescriptorInfo ret;
98
99 #if defined(__unix__)
100 VkMemoryGetFdInfoKHR memoryGetFdInfo = {
101 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
102 .pNext = nullptr,
103 .memory = memory,
104 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
105 };
106 ret.streamHandleType = STREAM_HANDLE_TYPE_MEM_OPAQUE_FD;
107
108 #if defined(__linux__)
109 if (supportsDmaBuf()) {
110 memoryGetFdInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
111 ret.streamHandleType = STREAM_HANDLE_TYPE_MEM_DMABUF;
112 }
113 #endif
114
115 int fd = -1;
116 if (mDeviceInfo.getMemoryHandleFunc(mDevice, &memoryGetFdInfo, &fd) != VK_SUCCESS) {
117 return std::nullopt;
118 };
119
120 ret.descriptor = ManagedDescriptor(fd);
121
122 #elif defined(_WIN32)
123 VkMemoryGetWin32HandleInfoKHR memoryGetHandleInfo = {
124 .sType = VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
125 .pNext = nullptr,
126 .memory = memory,
127 .handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
128 };
129 ret.streamHandleType = STREAM_HANDLE_TYPE_MEM_OPAQUE_WIN32;
130
131 HANDLE handle;
132 if (mDeviceInfo.getMemoryHandleFunc(mDevice, &memoryGetHandleInfo, &handle) != VK_SUCCESS) {
133 return std::nullopt;
134 }
135
136 ret.descriptor = ManagedDescriptor(handle);
137 #else
138 ERR("Unsupported external memory handle type.");
139 return std::nullopt;
140 #endif
141
142 return std::move(ret);
143 }
144
dupExternalMemory(std::optional<ExternalHandleInfo> handleInfo)145 static std::optional<ExternalHandleInfo> dupExternalMemory(std::optional<ExternalHandleInfo> handleInfo) {
146 if (!handleInfo) {
147 ERR("dupExternalMemory: No external memory handle info provided to duplicate the external memory");
148 return std::nullopt;
149 }
150 #if defined(_WIN32)
151 auto myProcessHandle = GetCurrentProcess();
152 HANDLE res;
153 DuplicateHandle(myProcessHandle,
154 static_cast<HANDLE>(
155 reinterpret_cast<void*>(handleInfo->handle)), // source process and handle
156 myProcessHandle, &res, // target process and pointer to handle
157 0 /* desired access (ignored) */, true /* inherit */,
158 DUPLICATE_SAME_ACCESS /* same access option */);
159 return ExternalHandleInfo{
160 .handle = reinterpret_cast<ExternalHandleType>(res),
161 .streamHandleType = handleInfo->streamHandleType,
162 };
163 #elif defined(__QNX__)
164 if (STREAM_HANDLE_TYPE_PLATFORM_SCREEN_BUFFER_QNX == handleInfo->streamHandleType) {
165 // No dup required for the screen_buffer handle
166 return ExternalHandleInfo{
167 .handle = handleInfo->handle,
168 .streamHandleType = handleInfo->streamHandleType,
169 };
170 }
171 // TODO(aruby@blackberry.com): Support dup-ing for OPAQUE_FD or DMABUF types on QNX
172 return std::nullopt;
173 #else
174 // TODO(aruby@blackberry.com): Check handleType?
175 return ExternalHandleInfo{
176 .handle = static_cast<ExternalHandleType>(dup(handleInfo->handle)),
177 .streamHandleType = handleInfo->streamHandleType,
178 };
179 #endif
180 }
181
getStagingMemoryTypeIndex(VulkanDispatch * vk,VkDevice device,const VkPhysicalDeviceMemoryProperties * memProps,uint32_t * typeIndex)182 bool getStagingMemoryTypeIndex(VulkanDispatch* vk, VkDevice device,
183 const VkPhysicalDeviceMemoryProperties* memProps,
184 uint32_t* typeIndex) {
185 auto res = sKnownStagingTypeIndices.get(device);
186
187 if (res) {
188 *typeIndex = *res;
189 return true;
190 }
191
192 VkBufferCreateInfo testCreateInfo = {
193 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
194 0,
195 0,
196 4096,
197 // To be a staging buffer, it must support being
198 // both a transfer src and dst.
199 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
200 // TODO: See if buffers over shared queues need to be
201 // considered separately
202 VK_SHARING_MODE_EXCLUSIVE,
203 0,
204 nullptr,
205 };
206
207 VkBuffer testBuffer;
208 VkResult testBufferCreateRes =
209 vk->vkCreateBuffer(device, &testCreateInfo, nullptr, &testBuffer);
210
211 if (testBufferCreateRes != VK_SUCCESS) {
212 ERR("Could not create test buffer "
213 "for staging buffer query. VkResult: %s",
214 string_VkResult(testBufferCreateRes));
215 return false;
216 }
217
218 VkMemoryRequirements memReqs;
219 vk->vkGetBufferMemoryRequirements(device, testBuffer, &memReqs);
220
221 // To be a staging buffer, we need to allow CPU read/write access.
222 // Thus, we need the memory type index both to be host visible
223 // and to be supported in the memory requirements of the buffer.
224 bool foundSuitableStagingMemoryType = false;
225 uint32_t stagingMemoryTypeIndex = 0;
226
227 for (uint32_t i = 0; i < memProps->memoryTypeCount; ++i) {
228 const auto& typeInfo = memProps->memoryTypes[i];
229 bool hostVisible = typeInfo.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
230 bool hostCached = typeInfo.propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT;
231 bool allowedInBuffer = (1 << i) & memReqs.memoryTypeBits;
232 if (hostVisible && hostCached && allowedInBuffer) {
233 foundSuitableStagingMemoryType = true;
234 stagingMemoryTypeIndex = i;
235 break;
236 }
237 }
238
239 // If the previous loop failed, try to accept a type that is not HOST_CACHED.
240 if (!foundSuitableStagingMemoryType) {
241 for (uint32_t i = 0; i < memProps->memoryTypeCount; ++i) {
242 const auto& typeInfo = memProps->memoryTypes[i];
243 bool hostVisible = typeInfo.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
244 bool allowedInBuffer = (1 << i) & memReqs.memoryTypeBits;
245 if (hostVisible && allowedInBuffer) {
246 ERR("Warning: using non-cached HOST_VISIBLE type for staging memory");
247 foundSuitableStagingMemoryType = true;
248 stagingMemoryTypeIndex = i;
249 break;
250 }
251 }
252 }
253
254 vk->vkDestroyBuffer(device, testBuffer, nullptr);
255
256 if (!foundSuitableStagingMemoryType) {
257 std::stringstream ss;
258 ss << "Could not find suitable memory type index "
259 << "for staging buffer. Memory type bits: " << std::hex << memReqs.memoryTypeBits << "\n"
260 << "Available host visible memory type indices:"
261 << "\n";
262 for (uint32_t i = 0; i < VK_MAX_MEMORY_TYPES; ++i) {
263 if (memProps->memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
264 ss << "Host visible memory type index: %u" << i << "\n";
265 }
266 if (memProps->memoryTypes[i].propertyFlags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) {
267 ss << "Host cached memory type index: %u" << i << "\n";
268 }
269 }
270
271 ERR("Error: %s", ss.str().c_str());
272
273 return false;
274 }
275
276 sKnownStagingTypeIndices.set(device, stagingMemoryTypeIndex);
277 *typeIndex = stagingMemoryTypeIndex;
278
279 return true;
280 }
281
getDefaultExternalMemoryHandleType()282 VkExternalMemoryHandleTypeFlagBits VkEmulation::getDefaultExternalMemoryHandleType() {
283 #if defined(_WIN32)
284 return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
285 #else
286
287 #if defined(__APPLE__)
288 if (mInstanceSupportsMoltenVK) {
289 return VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
290 }
291 #endif
292
293 #if defined(__QNX__)
294 // TODO(aruby@blackberry.com): Use (DMABUF|OPAQUE_FD) on QNX, when screen_buffer not supported?
295 return VK_EXTERNAL_MEMORY_HANDLE_TYPE_SCREEN_BUFFER_BIT_QNX;
296 #endif
297
298 return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
299 #endif
300 }
301
extensionsSupported(const std::vector<VkExtensionProperties> & currentProps,const std::vector<const char * > & wantedExtNames)302 static bool extensionsSupported(const std::vector<VkExtensionProperties>& currentProps,
303 const std::vector<const char*>& wantedExtNames) {
304 std::vector<bool> foundExts(wantedExtNames.size(), false);
305
306 for (uint32_t i = 0; i < currentProps.size(); ++i) {
307 for (size_t j = 0; j < wantedExtNames.size(); ++j) {
308 if (!strcmp(wantedExtNames[j], currentProps[i].extensionName)) {
309 foundExts[j] = true;
310 }
311 }
312 }
313
314 for (size_t i = 0; i < wantedExtNames.size(); ++i) {
315 bool found = foundExts[i];
316 if (!found) {
317 VERBOSE("%s not found, bailing.", wantedExtNames[i]);
318 return false;
319 }
320 }
321
322 return true;
323 }
324
325 // Return true if format requires sampler YCBCR conversion for VK_IMAGE_ASPECT_COLOR_BIT image
326 // views. Table found in spec
formatRequiresYcbcrConversion(VkFormat format)327 static bool formatRequiresYcbcrConversion(VkFormat format) {
328 switch (format) {
329 case VK_FORMAT_G8B8G8R8_422_UNORM:
330 case VK_FORMAT_B8G8R8G8_422_UNORM:
331 case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM:
332 case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM:
333 case VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM:
334 case VK_FORMAT_G8_B8R8_2PLANE_422_UNORM:
335 case VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM:
336 case VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16:
337 case VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16:
338 case VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16:
339 case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16:
340 case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16:
341 case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16:
342 case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16:
343 case VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16:
344 case VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16:
345 case VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16:
346 case VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16:
347 case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16:
348 case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16:
349 case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16:
350 case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16:
351 case VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16:
352 case VK_FORMAT_G16B16G16R16_422_UNORM:
353 case VK_FORMAT_B16G16R16G16_422_UNORM:
354 case VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM:
355 case VK_FORMAT_G16_B16R16_2PLANE_420_UNORM:
356 case VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM:
357 case VK_FORMAT_G16_B16R16_2PLANE_422_UNORM:
358 case VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM:
359 case VK_FORMAT_G8_B8R8_2PLANE_444_UNORM:
360 case VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16:
361 case VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16:
362 case VK_FORMAT_G16_B16R16_2PLANE_444_UNORM:
363 return true;
364 default:
365 return false;
366 }
367 }
368
populateImageFormatExternalMemorySupportInfo(VulkanDispatch * vk,VkPhysicalDevice physdev,ImageSupportInfo * info)369 bool VkEmulation::populateImageFormatExternalMemorySupportInfo(VulkanDispatch* vk,
370 VkPhysicalDevice physdev,
371 ImageSupportInfo* info) {
372 // Currently there is nothing special we need to do about
373 // VkFormatProperties2, so just use the normal version
374 // and put it in the format2 struct.
375 VkFormatProperties outFormatProps;
376 vk->vkGetPhysicalDeviceFormatProperties(physdev, info->format, &outFormatProps);
377
378 info->formatProps2 = {
379 VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2,
380 0,
381 outFormatProps,
382 };
383
384 if (!mInstanceSupportsExternalMemoryCapabilities) {
385 info->supportsExternalMemory = false;
386 info->requiresDedicatedAllocation = false;
387
388 VkImageFormatProperties outImageFormatProps;
389 VkResult res = vk->vkGetPhysicalDeviceImageFormatProperties(
390 physdev, info->format, info->type, info->tiling, info->usageFlags, info->createFlags,
391 &outImageFormatProps);
392
393 if (res != VK_SUCCESS) {
394 if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
395 info->supported = false;
396 return true;
397 } else {
398 ERR("vkGetPhysicalDeviceImageFormatProperties query "
399 "failed with %s"
400 "for format 0x%x type 0x%x usage 0x%x flags 0x%x",
401 string_VkResult(res), info->format, info->type, info->usageFlags,
402 info->createFlags);
403 return false;
404 }
405 }
406
407 info->supported = true;
408
409 info->imageFormatProps2 = {
410 VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
411 0,
412 outImageFormatProps,
413 };
414
415 VERBOSE("Supported (not externally): %s %s %s %s", string_VkFormat(info->format),
416 string_VkImageType(info->type), string_VkImageTiling(info->tiling),
417 string_VkImageUsageFlagBits((VkImageUsageFlagBits)info->usageFlags));
418
419 return true;
420 }
421
422 VkPhysicalDeviceExternalImageFormatInfo extInfo = {
423 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_IMAGE_FORMAT_INFO,
424 0,
425 getDefaultExternalMemoryHandleType(),
426 };
427
428 VkPhysicalDeviceImageFormatInfo2 formatInfo2 = {
429 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGE_FORMAT_INFO_2,
430 &extInfo,
431 info->format,
432 info->type,
433 info->tiling,
434 info->usageFlags,
435 info->createFlags,
436 };
437
438 VkExternalImageFormatProperties outExternalProps = {
439 VK_STRUCTURE_TYPE_EXTERNAL_IMAGE_FORMAT_PROPERTIES,
440 0,
441 {
442 (VkExternalMemoryFeatureFlags)0,
443 (VkExternalMemoryHandleTypeFlags)0,
444 (VkExternalMemoryHandleTypeFlags)0,
445 },
446 };
447
448 VkImageFormatProperties2 outProps2 = {VK_STRUCTURE_TYPE_IMAGE_FORMAT_PROPERTIES_2,
449 &outExternalProps,
450 {
451 {0, 0, 0},
452 0,
453 0,
454 1,
455 0,
456 }};
457
458 VkResult res = mGetImageFormatProperties2Func(physdev, &formatInfo2, &outProps2);
459
460 if (res != VK_SUCCESS) {
461 if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
462 VERBOSE("Not Supported: %s %s %s %s", string_VkFormat(info->format),
463 string_VkImageType(info->type), string_VkImageTiling(info->tiling),
464 string_VkImageUsageFlagBits((VkImageUsageFlagBits)info->usageFlags));
465
466 info->supported = false;
467 return true;
468 } else {
469 ERR("vkGetPhysicalDeviceImageFormatProperties2KHR query "
470 "failed with %s "
471 "for format 0x%x type 0x%x usage 0x%x flags 0x%x",
472 string_VkResult(res), info->format, info->type, info->usageFlags,
473 info->createFlags);
474 return false;
475 }
476 }
477
478 info->supported = true;
479
480 VkExternalMemoryFeatureFlags featureFlags =
481 outExternalProps.externalMemoryProperties.externalMemoryFeatures;
482
483 VkExternalMemoryHandleTypeFlags exportImportedFlags =
484 outExternalProps.externalMemoryProperties.exportFromImportedHandleTypes;
485
486 // Don't really care about export form imported handle types yet
487 (void)exportImportedFlags;
488
489 VkExternalMemoryHandleTypeFlags compatibleHandleTypes =
490 outExternalProps.externalMemoryProperties.compatibleHandleTypes;
491
492 VkExternalMemoryHandleTypeFlags handleTypeNeeded = getDefaultExternalMemoryHandleType();
493
494 info->supportsExternalMemory = (handleTypeNeeded & compatibleHandleTypes) &&
495 (VK_EXTERNAL_MEMORY_FEATURE_EXPORTABLE_BIT & featureFlags) &&
496 (VK_EXTERNAL_MEMORY_FEATURE_IMPORTABLE_BIT & featureFlags);
497
498 info->requiresDedicatedAllocation =
499 (VK_EXTERNAL_MEMORY_FEATURE_DEDICATED_ONLY_BIT & featureFlags);
500
501 info->imageFormatProps2 = outProps2;
502 info->extFormatProps = outExternalProps;
503 info->imageFormatProps2.pNext = &info->extFormatProps;
504
505 VERBOSE("Supported: %s %s %s %s, supportsExternalMemory? %d, requiresDedicated? %d",
506 string_VkFormat(info->format), string_VkImageType(info->type),
507 string_VkImageTiling(info->tiling),
508 string_VkImageUsageFlagBits((VkImageUsageFlagBits)info->usageFlags),
509 info->supportsExternalMemory, info->requiresDedicatedAllocation);
510
511 return true;
512 }
513
514 // Vulkan driverVersions are bit-shift packs of their dotted versions
515 // For example, nvidia driverversion 1934229504 unpacks to 461.40
516 // note: while this is equivalent to VkPhysicalDeviceDriverProperties.driverInfo on NVIDIA,
517 // on intel that value is simply "Intel driver".
decodeDriverVersion(uint32_t vendorId,uint32_t driverVersion)518 static std::string decodeDriverVersion(uint32_t vendorId, uint32_t driverVersion) {
519 std::stringstream result;
520 switch (vendorId) {
521 case 0x10DE: {
522 // Nvidia. E.g. driverVersion = 1934229504(0x734a0000) maps to 461.40
523 uint32_t major = driverVersion >> 22;
524 uint32_t minor = (driverVersion >> 14) & 0xff;
525 uint32_t build = (driverVersion >> 6) & 0xff;
526 uint32_t revision = driverVersion & 0x3f;
527 result << major << '.' << minor << '.' << build << '.' << revision;
528 break;
529 }
530 case 0x8086: {
531 // Intel. E.g. driverVersion = 1647866(0x1924fa) maps to 100.9466 (27.20.100.9466)
532 uint32_t high = driverVersion >> 14;
533 uint32_t low = driverVersion & 0x3fff;
534 result << high << '.' << low;
535 break;
536 }
537 case 0x002: // amd
538 default: {
539 uint32_t major = VK_VERSION_MAJOR(driverVersion);
540 uint32_t minor = VK_VERSION_MINOR(driverVersion);
541 uint32_t patch = VK_VERSION_PATCH(driverVersion);
542 result << major << "." << minor << "." << patch;
543 break;
544 }
545 }
546 return result.str();
547 }
548
getBasicImageSupportList()549 /*static*/ std::vector<VkEmulation::ImageSupportInfo> VkEmulation::getBasicImageSupportList() {
550 struct ImageFeatureCombo {
551 VkFormat format;
552 VkImageCreateFlags createFlags = 0;
553 };
554 // Set the mutable flag for RGB UNORM formats so that the created image can also be sampled in
555 // the sRGB Colorspace. See
556 // https://chromium-review.googlesource.com/c/chromiumos/platform/minigbm/+/3827672/comments/77db9cb3_60663a6a
557 // for details.
558 std::vector<ImageFeatureCombo> combos = {
559 // Cover all the gralloc formats
560 {VK_FORMAT_R8G8B8A8_UNORM,
561 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
562 {VK_FORMAT_R8G8B8_UNORM,
563 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
564
565 {VK_FORMAT_R5G6B5_UNORM_PACK16},
566 {VK_FORMAT_A1R5G5B5_UNORM_PACK16},
567
568 {VK_FORMAT_R16G16B16A16_SFLOAT},
569 {VK_FORMAT_R16G16B16_SFLOAT},
570
571 {VK_FORMAT_B8G8R8A8_UNORM,
572 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
573
574 {VK_FORMAT_B4G4R4A4_UNORM_PACK16,
575 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
576 {VK_FORMAT_R4G4B4A4_UNORM_PACK16,
577 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
578
579 {VK_FORMAT_R8_UNORM,
580 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
581 {VK_FORMAT_R16_UNORM,
582 VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT},
583
584 {VK_FORMAT_A2R10G10B10_UINT_PACK32},
585 {VK_FORMAT_A2R10G10B10_UNORM_PACK32},
586 {VK_FORMAT_A2B10G10R10_UNORM_PACK32},
587
588 // Compressed texture formats
589 {VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK},
590 {VK_FORMAT_ASTC_4x4_UNORM_BLOCK},
591
592 // YUV formats used in Android
593 {VK_FORMAT_G8_B8R8_2PLANE_420_UNORM},
594 {VK_FORMAT_G8_B8R8_2PLANE_422_UNORM},
595 {VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM},
596 {VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM},
597 {VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16},
598 };
599
600 std::vector<VkImageType> types = {
601 VK_IMAGE_TYPE_2D,
602 };
603
604 std::vector<VkImageTiling> tilings = {
605 VK_IMAGE_TILING_LINEAR,
606 VK_IMAGE_TILING_OPTIMAL,
607 };
608
609 std::vector<VkImageUsageFlags> usageFlags = {
610 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
611 VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
612 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
613 };
614
615 std::vector<VkEmulation::ImageSupportInfo> res;
616
617 // Currently: 17 format + create flags combo, 2 tilings, 5 usage flags -> 170 cases to check.
618 for (auto combo : combos) {
619 for (auto t : types) {
620 for (auto ti : tilings) {
621 for (auto u : usageFlags) {
622 VkEmulation::ImageSupportInfo info;
623 info.format = combo.format;
624 info.type = t;
625 info.tiling = ti;
626 info.usageFlags = u;
627 info.createFlags = combo.createFlags;
628 res.push_back(info);
629 }
630 }
631 }
632 }
633
634 // Add depth attachment cases
635 std::vector<ImageFeatureCombo> depthCombos = {
636 // Depth formats
637 {VK_FORMAT_D16_UNORM},
638 {VK_FORMAT_X8_D24_UNORM_PACK32},
639 {VK_FORMAT_D24_UNORM_S8_UINT},
640 {VK_FORMAT_D32_SFLOAT},
641 {VK_FORMAT_D32_SFLOAT_S8_UINT},
642 };
643
644 std::vector<VkImageUsageFlags> depthUsageFlags = {
645 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT, VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT,
646 VK_IMAGE_USAGE_SAMPLED_BIT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
647 VK_IMAGE_USAGE_TRANSFER_DST_BIT,
648 };
649
650 for (auto combo : depthCombos) {
651 for (auto t : types) {
652 for (auto u : depthUsageFlags) {
653 ImageSupportInfo info;
654 info.format = combo.format;
655 info.type = t;
656 info.tiling = VK_IMAGE_TILING_OPTIMAL;
657 info.usageFlags = u;
658 info.createFlags = combo.createFlags;
659 res.push_back(info);
660 }
661 }
662 }
663
664 return res;
665 }
666
667 // Checks if the user enforced a specific GPU, it can be done via index or name.
668 // Otherwise try to find the best device with discrete GPU and high vulkan API level.
669 // Scoring of the devices is done by some implicit choices based on known driver
670 // quality, stability and performance issues of current GPUs.
671 // Only one Vulkan device is selected; this makes things simple for now, but we
672 // could consider utilizing multiple devices in use cases that make sense.
getSelectedGpuIndex(const std::vector<VkEmulation::DeviceSupportInfo> & deviceInfos)673 int VkEmulation::getSelectedGpuIndex(
674 const std::vector<VkEmulation::DeviceSupportInfo>& deviceInfos) {
675 const int physicalDeviceCount = deviceInfos.size();
676 if (physicalDeviceCount == 1) {
677 return 0;
678 }
679
680 if (!mInstanceSupportsGetPhysicalDeviceProperties2) {
681 // If we don't support physical device ID properties, pick the first physical device
682 WARN("Instance doesn't support '%s', picking the first physical device",
683 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME);
684 return 0;
685 }
686
687 const char* EnvVarSelectGpu = "ANDROID_EMU_VK_SELECT_GPU";
688 std::string enforcedGpuStr = android::base::getEnvironmentVariable(EnvVarSelectGpu);
689 int enforceGpuIndex = -1;
690 if (enforcedGpuStr.size()) {
691 INFO("%s is set to %s", EnvVarSelectGpu, enforcedGpuStr.c_str());
692
693 if (enforcedGpuStr[0] == '0') {
694 enforceGpuIndex = 0;
695 } else {
696 enforceGpuIndex = (atoi(enforcedGpuStr.c_str()));
697 if (enforceGpuIndex == 0) {
698 // Could not convert to an integer, try searching with device name
699 // Do the comparison case insensitive as vendor names don't have consistency
700 enforceGpuIndex = -1;
701 std::transform(enforcedGpuStr.begin(), enforcedGpuStr.end(), enforcedGpuStr.begin(),
702 [](unsigned char c) { return std::tolower(c); });
703
704 for (int i = 0; i < physicalDeviceCount; ++i) {
705 std::string deviceName = std::string(deviceInfos[i].physdevProps.deviceName);
706 std::transform(deviceName.begin(), deviceName.end(), deviceName.begin(),
707 [](unsigned char c) { return std::tolower(c); });
708 INFO("Physical device [%d] = %s", i, deviceName.c_str());
709
710 if (deviceName.find(enforcedGpuStr) != std::string::npos) {
711 enforceGpuIndex = i;
712 }
713 }
714 }
715 }
716
717 if (enforceGpuIndex != -1 && enforceGpuIndex >= 0 && enforceGpuIndex < (int)deviceInfos.size()) {
718 INFO("Selecting GPU (%s) at index %d.",
719 deviceInfos[enforceGpuIndex].physdevProps.deviceName, enforceGpuIndex);
720 } else {
721 WARN("Could not select the GPU with ANDROID_EMU_VK_GPU_SELECT.");
722 enforceGpuIndex = -1;
723 }
724 }
725
726 if (enforceGpuIndex != -1) {
727 return enforceGpuIndex;
728 }
729
730 // If there are multiple devices, and none of them are enforced to use,
731 // score each device and select the best
732 int selectedGpuIndex = 0;
733 auto getDeviceScore = [](const VkEmulation::DeviceSupportInfo& deviceInfo) {
734 uint32_t deviceScore = 0;
735 if (!deviceInfo.hasGraphicsQueueFamily) {
736 // Not supporting graphics, cannot be used.
737 return deviceScore;
738 }
739
740 // Matches the ordering in VkPhysicalDeviceType
741 const uint32_t deviceTypeScoreTable[] = {
742 100, // VK_PHYSICAL_DEVICE_TYPE_OTHER = 0,
743 1000, // VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1,
744 2000, // VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2,
745 500, // VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3,
746 600, // VK_PHYSICAL_DEVICE_TYPE_CPU = 4,
747 };
748
749 // Prefer discrete GPUs, then integrated and then others..
750 const int deviceType = deviceInfo.physdevProps.deviceType;
751 deviceScore += deviceTypeScoreTable[deviceType];
752
753 // Prefer higher level of Vulkan API support, restrict version numbers to
754 // common limits to ensure an always increasing scoring change
755 const uint32_t major = VK_API_VERSION_MAJOR(deviceInfo.physdevProps.apiVersion);
756 const uint32_t minor = VK_API_VERSION_MINOR(deviceInfo.physdevProps.apiVersion);
757 const uint32_t patch = VK_API_VERSION_PATCH(deviceInfo.physdevProps.apiVersion);
758 deviceScore += major * 5000 + std::min(minor, 10u) * 500 + std::min(patch, 400u);
759
760 return deviceScore;
761 };
762
763 uint32_t maxScore = 0;
764 for (int i = 0; i < physicalDeviceCount; ++i) {
765 const uint32_t score = getDeviceScore(deviceInfos[i]);
766 VERBOSE("Device selection score for '%s' = %d", deviceInfos[i].physdevProps.deviceName,
767 score);
768 if (score > maxScore) {
769 selectedGpuIndex = i;
770 maxScore = score;
771 }
772 }
773
774 return selectedGpuIndex;
775 }
776
777 /*static*/
create(VulkanDispatch * gvk,gfxstream::host::BackendCallbacks callbacks,gfxstream::host::FeatureSet features)778 std::unique_ptr<VkEmulation> VkEmulation::create(VulkanDispatch* gvk,
779 gfxstream::host::BackendCallbacks callbacks,
780 gfxstream::host::FeatureSet features) {
781 // Downstream branches can provide abort logic or otherwise use result without a new macro
782 #define VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(res, ...) \
783 do { \
784 (void)res; /* no-op of unused param*/ \
785 ERR(__VA_ARGS__); \
786 return nullptr; \
787 } while (0)
788
789 if (!vkDispatchValid(gvk)) {
790 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER, "Dispatch is invalid.");
791 }
792
793 std::unique_ptr<VkEmulation> emulation(new VkEmulation());
794
795 std::lock_guard<std::mutex> lock(emulation->mMutex);
796
797 emulation->mCallbacks = callbacks;
798 emulation->mFeatures = features;
799 emulation->mGvk = gvk;
800
801 std::vector<const char*> getPhysicalDeviceProperties2InstanceExtNames = {
802 VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
803 };
804 std::vector<const char*> externalMemoryInstanceExtNames = {
805 VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME,
806 };
807
808 std::vector<const char*> externalSemaphoreInstanceExtNames = {
809 VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME,
810 };
811
812 std::vector<const char*> externalFenceInstanceExtNames = {
813 VK_KHR_EXTERNAL_FENCE_CAPABILITIES_EXTENSION_NAME,
814 };
815
816 std::vector<const char*> surfaceInstanceExtNames = {
817 VK_KHR_SURFACE_EXTENSION_NAME,
818 };
819
820 std::vector<const char*> externalMemoryDeviceExtNames = {
821 VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME,
822 VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME,
823 VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
824 #ifdef _WIN32
825 VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
826 #elif defined(__QNX__)
827 VK_QNX_EXTERNAL_MEMORY_SCREEN_BUFFER_EXTENSION_NAME,
828 VK_EXT_QUEUE_FAMILY_FOREIGN_EXTENSION_NAME,
829 #elif defined(__APPLE__)
830 // VK_EXT_metal_objects will be added if host MoltenVK is enabled,
831 // otherwise VK_KHR_external_memory_fd will be used
832 #else
833 VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
834 #endif
835 };
836
837 #if defined(__APPLE__)
838 std::vector<const char*> moltenVkInstanceExtNames = {
839 VK_MVK_MACOS_SURFACE_EXTENSION_NAME,
840 VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME,
841 };
842 std::vector<const char*> moltenVkDeviceExtNames = {
843 VK_KHR_PORTABILITY_SUBSET_EXTENSION_NAME,
844 VK_EXT_METAL_OBJECTS_EXTENSION_NAME,
845 VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME,
846 };
847 #endif
848
849 std::vector<VkExtensionProperties>& instanceExts = emulation->mInstanceExtensions;
850 uint32_t instanceExtCount = 0;
851 gvk->vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, nullptr);
852 instanceExts.resize(instanceExtCount);
853 gvk->vkEnumerateInstanceExtensionProperties(nullptr, &instanceExtCount, instanceExts.data());
854
855 bool getPhysicalDeviceProperties2Supported =
856 extensionsSupported(instanceExts, getPhysicalDeviceProperties2InstanceExtNames);
857 bool externalMemoryCapabilitiesSupported = getPhysicalDeviceProperties2Supported &&
858 extensionsSupported(instanceExts, externalMemoryInstanceExtNames);
859 bool externalSemaphoreCapabilitiesSupported = getPhysicalDeviceProperties2Supported &&
860 extensionsSupported(instanceExts, externalSemaphoreInstanceExtNames);
861 bool externalFenceCapabilitiesSupported = getPhysicalDeviceProperties2Supported &&
862 extensionsSupported(instanceExts, externalFenceInstanceExtNames);
863 bool surfaceSupported = extensionsSupported(instanceExts, surfaceInstanceExtNames);
864 #if defined(__APPLE__)
865 const std::string vulkanIcd = android::base::getEnvironmentVariable("ANDROID_EMU_VK_ICD");
866 const bool moltenVKEnabled = (vulkanIcd == "moltenvk");
867 const bool moltenVKSupported = extensionsSupported(instanceExts, moltenVkInstanceExtNames);
868 if (moltenVKEnabled && !moltenVKSupported) {
869 // This might happen if the user manually changes moltenvk ICD library
870 ERR("MoltenVK requested, but the required extensions are not supported.");
871 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER)) << "MoltenVK requested, but the required extensions are not supported.";
872 }
873 const bool useMoltenVK = moltenVKEnabled && moltenVKSupported;
874 #endif
875
876 VkInstanceCreateInfo instCi = {
877 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, 0, 0, nullptr, 0, nullptr, 0, nullptr,
878 };
879
880 std::unordered_set<const char*> selectedInstanceExtensionNames;
881
882 const bool debugUtilsSupported =
883 extensionsSupported(instanceExts, {VK_EXT_DEBUG_UTILS_EXTENSION_NAME});
884 const bool debugUtilsRequested = emulation->mFeatures.VulkanDebugUtils.enabled;
885 const bool debugUtilsAvailableAndRequested = debugUtilsSupported && debugUtilsRequested;
886 if (debugUtilsAvailableAndRequested) {
887 selectedInstanceExtensionNames.emplace(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
888 } else if (debugUtilsRequested) {
889 WARN("VulkanDebugUtils requested, but '%' extension is not supported.",
890 VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
891 }
892
893 if (getPhysicalDeviceProperties2Supported) {
894 for (auto extension : getPhysicalDeviceProperties2InstanceExtNames) {
895 selectedInstanceExtensionNames.emplace(extension);
896 }
897 }
898
899 if (externalSemaphoreCapabilitiesSupported) {
900 for (auto extension : externalMemoryInstanceExtNames) {
901 selectedInstanceExtensionNames.emplace(extension);
902 }
903 }
904
905 if (externalFenceCapabilitiesSupported) {
906 for (auto extension : externalSemaphoreInstanceExtNames) {
907 selectedInstanceExtensionNames.emplace(extension);
908 }
909 }
910
911 if (externalMemoryCapabilitiesSupported) {
912 for (auto extension : externalFenceInstanceExtNames) {
913 selectedInstanceExtensionNames.emplace(extension);
914 }
915 }
916
917 if (surfaceSupported) {
918 for (auto extension : surfaceInstanceExtNames) {
919 selectedInstanceExtensionNames.emplace(extension);
920 }
921 }
922
923 if (emulation->mFeatures.VulkanNativeSwapchain.enabled) {
924 for (auto extension : SwapChainStateVk::getRequiredInstanceExtensions()) {
925 selectedInstanceExtensionNames.emplace(extension);
926 }
927 }
928
929 #if defined(__APPLE__)
930 if (useMoltenVK) {
931 INFO("MoltenVK is supported, enabling Vulkan portability.");
932 instCi.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
933 for (auto extension : moltenVkInstanceExtNames) {
934 selectedInstanceExtensionNames.emplace(extension);
935 }
936 }
937 #endif
938
939 std::vector<const char*> selectedInstanceExtensionNames_(selectedInstanceExtensionNames.begin(),
940 selectedInstanceExtensionNames.end());
941 instCi.enabledExtensionCount = static_cast<uint32_t>(selectedInstanceExtensionNames_.size());
942 instCi.ppEnabledExtensionNames = selectedInstanceExtensionNames_.data();
943
944 VkApplicationInfo appInfo = {
945 VK_STRUCTURE_TYPE_APPLICATION_INFO, 0, "AEMU", 1, "AEMU", 1, VK_MAKE_VERSION(1, 0, 0),
946 };
947
948 instCi.pApplicationInfo = &appInfo;
949
950 // Can we know instance version early?
951 if (gvk->vkEnumerateInstanceVersion) {
952 VERBOSE("global loader has vkEnumerateInstanceVersion.");
953 uint32_t instanceVersion;
954 VkResult res = gvk->vkEnumerateInstanceVersion(&instanceVersion);
955 if (VK_SUCCESS == res) {
956 if (instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
957 VERBOSE("global loader has vkEnumerateInstanceVersion returning >= 1.1.");
958 appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0);
959 }
960 }
961 }
962
963 VERBOSE("Creating instance, asking for version %d.%d.%d ...",
964 VK_VERSION_MAJOR(appInfo.apiVersion), VK_VERSION_MINOR(appInfo.apiVersion),
965 VK_VERSION_PATCH(appInfo.apiVersion));
966
967 VkResult res = gvk->vkCreateInstance(&instCi, nullptr, &emulation->mInstance);
968 if (res != VK_SUCCESS) {
969 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(res, "Failed to create Vulkan instance. Error %s.",
970 string_VkResult(res));
971 }
972
973 // Create instance level dispatch.
974 emulation->mIvk = new VulkanDispatch();
975 init_vulkan_dispatch_from_instance(gvk, emulation->mInstance, emulation->mIvk);
976
977 auto ivk = emulation->mIvk;
978 if (!vulkan_dispatch_check_instance_VK_VERSION_1_0(ivk)) {
979 ERR("Warning: Vulkan 1.0 APIs missing from instance");
980 }
981
982 if (ivk->vkEnumerateInstanceVersion) {
983 uint32_t instanceVersion;
984 VkResult enumInstanceRes = ivk->vkEnumerateInstanceVersion(&instanceVersion);
985 if ((VK_SUCCESS == enumInstanceRes) && instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
986 if (!vulkan_dispatch_check_instance_VK_VERSION_1_1(ivk)) {
987 ERR("Warning: Vulkan 1.1 APIs missing from instance (1st try)");
988 }
989 }
990
991 if (appInfo.apiVersion < VK_MAKE_VERSION(1, 1, 0) &&
992 instanceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
993 VERBOSE("Found out that we can create a higher version instance.");
994 appInfo.apiVersion = VK_MAKE_VERSION(1, 1, 0);
995
996 gvk->vkDestroyInstance(emulation->mInstance, nullptr);
997
998 res = gvk->vkCreateInstance(&instCi, nullptr, &emulation->mInstance);
999 if (res != VK_SUCCESS) {
1000 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(
1001 res, "Failed to create Vulkan 1.1 instance. Error %s.", string_VkResult(res));
1002 }
1003
1004 init_vulkan_dispatch_from_instance(gvk, emulation->mInstance, emulation->mIvk);
1005
1006 VERBOSE("Created Vulkan 1.1 instance on second try.");
1007
1008 if (!vulkan_dispatch_check_instance_VK_VERSION_1_1(ivk)) {
1009 ERR("Warning: Vulkan 1.1 APIs missing from instance (2nd try)");
1010 }
1011 }
1012 }
1013
1014 emulation->mVulkanInstanceVersion = appInfo.apiVersion;
1015
1016 // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceIDProperties.html
1017 // Provided by VK_VERSION_1_1, or VK_KHR_external_fence_capabilities, VK_KHR_external_memory_capabilities,
1018 // VK_KHR_external_semaphore_capabilities
1019 emulation->mInstanceSupportsPhysicalDeviceIDProperties = externalFenceCapabilitiesSupported ||
1020 externalMemoryCapabilitiesSupported ||
1021 externalSemaphoreCapabilitiesSupported;
1022
1023 emulation->mInstanceSupportsGetPhysicalDeviceProperties2 =
1024 getPhysicalDeviceProperties2Supported;
1025 emulation->mInstanceSupportsExternalMemoryCapabilities = externalMemoryCapabilitiesSupported;
1026 emulation->mInstanceSupportsExternalSemaphoreCapabilities =
1027 externalSemaphoreCapabilitiesSupported;
1028 emulation->mInstanceSupportsExternalFenceCapabilities = externalFenceCapabilitiesSupported;
1029 emulation->mInstanceSupportsSurface = surfaceSupported;
1030 #if defined(__APPLE__)
1031 emulation->mInstanceSupportsMoltenVK = useMoltenVK;
1032 #endif
1033
1034 if (emulation->mInstanceSupportsGetPhysicalDeviceProperties2) {
1035 emulation->mGetImageFormatProperties2Func = vk_util::getVkInstanceProcAddrWithFallback<
1036 vk_util::vk_fn_info::GetPhysicalDeviceImageFormatProperties2>(
1037 {ivk->vkGetInstanceProcAddr, gvk->vkGetInstanceProcAddr}, emulation->mInstance);
1038 emulation->mGetPhysicalDeviceProperties2Func = vk_util::getVkInstanceProcAddrWithFallback<
1039 vk_util::vk_fn_info::GetPhysicalDeviceProperties2>(
1040 {ivk->vkGetInstanceProcAddr, gvk->vkGetInstanceProcAddr}, emulation->mInstance);
1041 emulation->mGetPhysicalDeviceFeatures2Func = vk_util::getVkInstanceProcAddrWithFallback<
1042 vk_util::vk_fn_info::GetPhysicalDeviceFeatures2>(
1043 {ivk->vkGetInstanceProcAddr, gvk->vkGetInstanceProcAddr}, emulation->mInstance);
1044
1045 if (!emulation->mGetPhysicalDeviceProperties2Func) {
1046 ERR("Warning: device claims to support ID properties "
1047 "but vkGetPhysicalDeviceProperties2 could not be found");
1048 }
1049 }
1050
1051 #if defined(__APPLE__)
1052 if (emulation->mInstanceSupportsMoltenVK) {
1053 // Enable some specific extensions on MacOS when moltenVK is used.
1054 externalMemoryDeviceExtNames.push_back(VK_EXT_METAL_OBJECTS_EXTENSION_NAME);
1055 externalMemoryDeviceExtNames.push_back(VK_EXT_EXTERNAL_MEMORY_METAL_EXTENSION_NAME);
1056 } else {
1057 // When MoltenVK is not used(e.g. SwiftShader), use memory fd extension for external memory.
1058 externalMemoryDeviceExtNames.push_back(VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME);
1059 }
1060 #endif
1061
1062 uint32_t physicalDeviceCount = 0;
1063 ivk->vkEnumeratePhysicalDevices(emulation->mInstance, &physicalDeviceCount, nullptr);
1064 std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
1065 ivk->vkEnumeratePhysicalDevices(emulation->mInstance, &physicalDeviceCount,
1066 physicalDevices.data());
1067
1068 VERBOSE("Found %d Vulkan physical devices.", physicalDeviceCount);
1069
1070 if (physicalDeviceCount == 0) {
1071 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER, "No physical devices available.");
1072 }
1073
1074 std::vector<DeviceSupportInfo> deviceInfos(physicalDeviceCount);
1075
1076 for (uint32_t i = 0; i < physicalDeviceCount; ++i) {
1077 ivk->vkGetPhysicalDeviceProperties(physicalDevices[i], &deviceInfos[i].physdevProps);
1078
1079 VERBOSE("Considering Vulkan physical device %d : %s", i,
1080 deviceInfos[i].physdevProps.deviceName);
1081
1082 // It's easier to figure out the staging buffer along with
1083 // external memories if we have the memory properties on hand.
1084 ivk->vkGetPhysicalDeviceMemoryProperties(physicalDevices[i], &deviceInfos[i].memProps);
1085
1086 uint32_t deviceExtensionCount = 0;
1087 ivk->vkEnumerateDeviceExtensionProperties(physicalDevices[i], nullptr,
1088 &deviceExtensionCount, nullptr);
1089 std::vector<VkExtensionProperties>& deviceExts = deviceInfos[i].extensions;
1090 deviceExts.resize(deviceExtensionCount);
1091 ivk->vkEnumerateDeviceExtensionProperties(physicalDevices[i], nullptr,
1092 &deviceExtensionCount, deviceExts.data());
1093
1094 deviceInfos[i].supportsExternalMemoryImport = false;
1095 deviceInfos[i].supportsExternalMemoryExport = false;
1096 deviceInfos[i].glInteropSupported = 0; // set later
1097
1098 #if defined(__APPLE__)
1099 if (useMoltenVK && !extensionsSupported(deviceExts, moltenVkDeviceExtNames)) {
1100 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(
1101 ABORT_REASON_OTHER,
1102 "MoltenVK enabled but necessary device extensions are not supported.");
1103 }
1104 #endif
1105
1106 if (emulation->mInstanceSupportsExternalMemoryCapabilities) {
1107 deviceInfos[i].supportsExternalMemoryExport =
1108 deviceInfos[i].supportsExternalMemoryImport =
1109 extensionsSupported(deviceExts, externalMemoryDeviceExtNames);
1110 #if defined(__QNX__)
1111 // External memory export not supported on QNX
1112 deviceInfos[i].supportsExternalMemoryExport = false;
1113 #endif
1114 }
1115
1116 if (emulation->mInstanceSupportsGetPhysicalDeviceProperties2) {
1117 deviceInfos[i].supportsDriverProperties =
1118 extensionsSupported(deviceExts, {VK_KHR_DRIVER_PROPERTIES_EXTENSION_NAME}) ||
1119 (deviceInfos[i].physdevProps.apiVersion >= VK_API_VERSION_1_2);
1120 deviceInfos[i].supportsExternalMemoryHostProps =
1121 extensionsSupported(deviceExts, {VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME});
1122
1123 VkPhysicalDeviceProperties2 deviceProps = {
1124 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2_KHR,
1125 };
1126 auto devicePropsChain = vk_make_chain_iterator(&deviceProps);
1127
1128 VkPhysicalDeviceIDProperties idProps = {
1129 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES_KHR,
1130 };
1131 if (emulation->mInstanceSupportsPhysicalDeviceIDProperties) {
1132 vk_append_struct(&devicePropsChain, &idProps);
1133 }
1134
1135 VkPhysicalDeviceDriverPropertiesKHR driverProps = {
1136 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES_KHR,
1137 };
1138 if (deviceInfos[i].supportsDriverProperties) {
1139 vk_append_struct(&devicePropsChain, &driverProps);
1140 }
1141
1142 VkPhysicalDeviceExternalMemoryHostPropertiesEXT externalMemoryHostProps = {
1143 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_HOST_PROPERTIES_EXT,
1144 };
1145 if(deviceInfos[i].supportsExternalMemoryHostProps) {
1146 vk_append_struct(&devicePropsChain, &externalMemoryHostProps);
1147 }
1148 emulation->mGetPhysicalDeviceProperties2Func(physicalDevices[i], &deviceProps);
1149 deviceInfos[i].idProps = vk_make_orphan_copy(idProps);
1150 deviceInfos[i].externalMemoryHostProps = vk_make_orphan_copy(externalMemoryHostProps);
1151
1152 std::stringstream driverVendorBuilder;
1153 driverVendorBuilder << "Vendor " << std::hex << std::setfill('0') << std::showbase
1154 << deviceInfos[i].physdevProps.vendorID;
1155
1156 std::string decodedDriverVersion = decodeDriverVersion(
1157 deviceInfos[i].physdevProps.vendorID, deviceInfos[i].physdevProps.driverVersion);
1158
1159 std::stringstream driverVersionBuilder;
1160 driverVersionBuilder << "Driver Version " << std::hex << std::setfill('0')
1161 << std::showbase << deviceInfos[i].physdevProps.driverVersion
1162 << " Decoded As " << decodedDriverVersion;
1163
1164 std::string driverVendor = driverVendorBuilder.str();
1165 std::string driverVersion = driverVersionBuilder.str();
1166 if (deviceInfos[i].supportsDriverProperties && driverProps.driverID) {
1167 driverVendor = std::string{driverProps.driverName} + " (" + driverVendor + ")";
1168 driverVersion = std::string{driverProps.driverInfo} + " (" +
1169 string_VkDriverId(driverProps.driverID) + " " + driverVersion + ")";
1170 }
1171
1172 deviceInfos[i].driverVendor = driverVendor;
1173 deviceInfos[i].driverVersion = driverVersion;
1174 }
1175
1176 // TODO(aruby@qnx.com): Remove once dmabuf extension support has been flushed out on QNX
1177 #if !defined(__QNX__)
1178 bool dmaBufBlockList = (deviceInfos[i].driverVendor == "NVIDIA (Vendor 0x10de)");
1179 #ifdef CONFIG_AEMU
1180 // TODO(b/400999642): dma_buf support should be checked with image format support
1181 dmaBufBlockList |= (deviceInfos[i].driverVendor == "radv (Vendor 0x1002)");
1182 #endif
1183 deviceInfos[i].supportsDmaBuf =
1184 extensionsSupported(deviceExts, {VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME}) &&
1185 !dmaBufBlockList;
1186 #endif
1187
1188 deviceInfos[i].hasSamplerYcbcrConversionExtension =
1189 extensionsSupported(deviceExts, {VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME});
1190
1191 deviceInfos[i].hasNvidiaDeviceDiagnosticCheckpointsExtension =
1192 extensionsSupported(deviceExts, {VK_NV_DEVICE_DIAGNOSTIC_CHECKPOINTS_EXTENSION_NAME});
1193
1194 if (emulation->mGetPhysicalDeviceFeatures2Func) {
1195 VkPhysicalDeviceFeatures2 features2 = {
1196 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
1197 };
1198 auto features2Chain = vk_make_chain_iterator(&features2);
1199
1200 VkPhysicalDeviceSamplerYcbcrConversionFeatures samplerYcbcrConversionFeatures = {
1201 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
1202 };
1203 vk_append_struct(&features2Chain, &samplerYcbcrConversionFeatures);
1204
1205 #if defined(__QNX__)
1206 VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX extMemScreenBufferFeatures = {
1207 .sType =
1208 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX,
1209 };
1210 vk_append_struct(&features2Chain, &extMemScreenBufferFeatures);
1211 #endif
1212
1213 VkPhysicalDeviceDiagnosticsConfigFeaturesNV deviceDiagnosticsConfigFeatures = {
1214 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV,
1215 .diagnosticsConfig = VK_FALSE,
1216 };
1217 if (deviceInfos[i].hasNvidiaDeviceDiagnosticCheckpointsExtension) {
1218 vk_append_struct(&features2Chain, &deviceDiagnosticsConfigFeatures);
1219 }
1220
1221 VkPhysicalDevicePrivateDataFeatures privateDataFeatures = {
1222 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRIVATE_DATA_FEATURES,
1223 .privateData = VK_FALSE};
1224 if (extensionsSupported(deviceExts, {VK_EXT_PRIVATE_DATA_EXTENSION_NAME})) {
1225 vk_append_struct(&features2Chain, &privateDataFeatures);
1226 }
1227
1228 VkPhysicalDeviceRobustness2FeaturesEXT robustness2Features = {
1229 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ROBUSTNESS_2_FEATURES_EXT};
1230 const bool robustnessRequested = emulation->mFeatures.VulkanRobustness.enabled;
1231 const bool robustnessSupported =
1232 extensionsSupported(deviceExts, {VK_EXT_ROBUSTNESS_2_EXTENSION_NAME});
1233 if (robustnessRequested && robustnessSupported) {
1234 vk_append_struct(&features2Chain, &robustness2Features);
1235 }
1236
1237 emulation->mGetPhysicalDeviceFeatures2Func(physicalDevices[i], &features2);
1238
1239 deviceInfos[i].supportsSamplerYcbcrConversion =
1240 samplerYcbcrConversionFeatures.samplerYcbcrConversion == VK_TRUE;
1241
1242 deviceInfos[i].supportsNvidiaDeviceDiagnosticCheckpoints =
1243 deviceDiagnosticsConfigFeatures.diagnosticsConfig == VK_TRUE;
1244
1245 deviceInfos[i].supportsPrivateData = (privateDataFeatures.privateData == VK_TRUE);
1246
1247 // Enable robustness only when requested
1248 if (robustnessRequested && robustnessSupported) {
1249 deviceInfos[i].robustness2Features = vk_make_orphan_copy(robustness2Features);
1250 } else if (robustnessRequested) {
1251 WARN(
1252 "VulkanRobustness was requested but the "
1253 "VK_EXT_robustness2 extension is not supported.");
1254 }
1255
1256 #if defined(__QNX__)
1257 deviceInfos[i].supportsExternalMemoryImport =
1258 extMemScreenBufferFeatures.screenBufferImport == VK_TRUE;
1259 } else {
1260 deviceInfos[i].supportsExternalMemoryImport = false;
1261 #endif
1262 }
1263
1264 uint32_t queueFamilyCount = 0;
1265 ivk->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevices[i], &queueFamilyCount,
1266 nullptr);
1267 std::vector<VkQueueFamilyProperties> queueFamilyProps(queueFamilyCount);
1268 ivk->vkGetPhysicalDeviceQueueFamilyProperties(physicalDevices[i], &queueFamilyCount,
1269 queueFamilyProps.data());
1270
1271 for (uint32_t j = 0; j < queueFamilyCount; ++j) {
1272 auto count = queueFamilyProps[j].queueCount;
1273 auto flags = queueFamilyProps[j].queueFlags;
1274
1275 bool hasGraphicsQueueFamily = (count > 0 && (flags & VK_QUEUE_GRAPHICS_BIT));
1276 bool hasComputeQueueFamily = (count > 0 && (flags & VK_QUEUE_COMPUTE_BIT));
1277
1278 deviceInfos[i].hasGraphicsQueueFamily =
1279 deviceInfos[i].hasGraphicsQueueFamily || hasGraphicsQueueFamily;
1280
1281 deviceInfos[i].hasComputeQueueFamily =
1282 deviceInfos[i].hasComputeQueueFamily || hasComputeQueueFamily;
1283
1284 if (hasGraphicsQueueFamily) {
1285 deviceInfos[i].graphicsQueueFamilyIndices.push_back(j);
1286 VERBOSE("Graphics queue family index: %d", j);
1287 }
1288
1289 if (hasComputeQueueFamily) {
1290 deviceInfos[i].computeQueueFamilyIndices.push_back(j);
1291 VERBOSE("Compute queue family index: %d", j);
1292 }
1293 }
1294 }
1295
1296 // When there are multiple physical devices, find the best one or enable selecting
1297 // the one enforced by environment variable setting.
1298 int selectedGpuIndex = emulation->getSelectedGpuIndex(deviceInfos);
1299
1300 emulation->mPhysicalDevice = physicalDevices[selectedGpuIndex];
1301 emulation->mPhysicalDeviceIndex = selectedGpuIndex;
1302 emulation->mDeviceInfo = deviceInfos[selectedGpuIndex];
1303 // Postcondition: emulation has valid device support info
1304
1305 // Collect image support info of the selected device
1306 emulation->mImageSupportInfo = getBasicImageSupportList();
1307 for (size_t i = 0; i < emulation->mImageSupportInfo.size(); ++i) {
1308 emulation->populateImageFormatExternalMemorySupportInfo(ivk, emulation->mPhysicalDevice,
1309 &emulation->mImageSupportInfo[i]);
1310 }
1311
1312 if (!emulation->mDeviceInfo.hasGraphicsQueueFamily) {
1313 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1314 "No Vulkan devices with graphics queues found.");
1315 }
1316
1317 auto deviceVersion = emulation->mDeviceInfo.physdevProps.apiVersion;
1318 INFO("Selecting Vulkan device: %s, Version: %d.%d.%d",
1319 emulation->mDeviceInfo.physdevProps.deviceName, VK_VERSION_MAJOR(deviceVersion),
1320 VK_VERSION_MINOR(deviceVersion), VK_VERSION_PATCH(deviceVersion));
1321
1322 VERBOSE(
1323 "deviceInfo: \n"
1324 "hasGraphicsQueueFamily = %d\n"
1325 "hasComputeQueueFamily = %d\n"
1326 "supportsExternalMemoryImport = %d\n"
1327 "supportsExternalMemoryExport = %d\n"
1328 "supportsDriverProperties = %d\n"
1329 "hasSamplerYcbcrConversionExtension = %d\n"
1330 "supportsSamplerYcbcrConversion = %d\n"
1331 "glInteropSupported = %d",
1332 emulation->mDeviceInfo.hasGraphicsQueueFamily, emulation->mDeviceInfo.hasComputeQueueFamily,
1333 emulation->mDeviceInfo.supportsExternalMemoryImport,
1334 emulation->mDeviceInfo.supportsExternalMemoryExport,
1335 emulation->mDeviceInfo.supportsDriverProperties,
1336 emulation->mDeviceInfo.hasSamplerYcbcrConversionExtension,
1337 emulation->mDeviceInfo.supportsSamplerYcbcrConversion,
1338 emulation->mDeviceInfo.glInteropSupported);
1339
1340 float priority = 1.0f;
1341 VkDeviceQueueCreateInfo dqCi = {
1342 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, 0, 0,
1343 emulation->mDeviceInfo.graphicsQueueFamilyIndices[0], 1, &priority,
1344 };
1345
1346 std::unordered_set<const char*> selectedDeviceExtensionNames_;
1347
1348 if (emulation->mDeviceInfo.supportsExternalMemoryImport ||
1349 emulation->mDeviceInfo.supportsExternalMemoryExport) {
1350 for (auto extension : externalMemoryDeviceExtNames) {
1351 selectedDeviceExtensionNames_.emplace(extension);
1352 }
1353 }
1354
1355 #if defined(__linux__)
1356 if (emulation->mDeviceInfo.supportsDmaBuf) {
1357 selectedDeviceExtensionNames_.emplace(VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME);
1358 }
1359 #endif
1360
1361 // We need to always enable swapchain extensions to be able to use this device
1362 // to do VK_IMAGE_LAYOUT_PRESENT_SRC_KHR transition operations done
1363 // in releaseColorBufferForGuestUse for the apps using Vulkan swapchain
1364 selectedDeviceExtensionNames_.emplace(VK_KHR_SWAPCHAIN_EXTENSION_NAME);
1365
1366 if (emulation->mFeatures.VulkanNativeSwapchain.enabled) {
1367 for (auto extension : SwapChainStateVk::getRequiredDeviceExtensions()) {
1368 selectedDeviceExtensionNames_.emplace(extension);
1369 }
1370 }
1371
1372 if (emulation->mDeviceInfo.hasSamplerYcbcrConversionExtension) {
1373 selectedDeviceExtensionNames_.emplace(VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
1374 }
1375
1376 #if defined(__APPLE__)
1377 if (useMoltenVK) {
1378 for (auto extension : moltenVkDeviceExtNames) {
1379 selectedDeviceExtensionNames_.emplace(extension);
1380 }
1381 }
1382 #endif
1383
1384 if (emulation->mDeviceInfo.robustness2Features) {
1385 selectedDeviceExtensionNames_.emplace(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
1386 }
1387
1388 std::vector<const char*> selectedDeviceExtensionNames(selectedDeviceExtensionNames_.begin(),
1389 selectedDeviceExtensionNames_.end());
1390
1391 VkDeviceCreateInfo dCi = {};
1392 dCi.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
1393 dCi.queueCreateInfoCount = 1;
1394 dCi.pQueueCreateInfos = &dqCi;
1395 dCi.enabledExtensionCount = static_cast<uint32_t>(selectedDeviceExtensionNames.size());
1396 dCi.ppEnabledExtensionNames = selectedDeviceExtensionNames.data();
1397
1398 // Setting up VkDeviceCreateInfo::pNext
1399 auto deviceCiChain = vk_make_chain_iterator(&dCi);
1400
1401 VkPhysicalDeviceFeatures2 physicalDeviceFeatures = {
1402 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
1403 };
1404 vk_append_struct(&deviceCiChain, &physicalDeviceFeatures);
1405
1406 std::unique_ptr<VkPhysicalDeviceSamplerYcbcrConversionFeatures> samplerYcbcrConversionFeatures =
1407 nullptr;
1408 if (emulation->mDeviceInfo.supportsSamplerYcbcrConversion) {
1409 samplerYcbcrConversionFeatures =
1410 std::make_unique<VkPhysicalDeviceSamplerYcbcrConversionFeatures>(
1411 VkPhysicalDeviceSamplerYcbcrConversionFeatures{
1412 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES,
1413 .samplerYcbcrConversion = VK_TRUE,
1414 });
1415 vk_append_struct(&deviceCiChain, samplerYcbcrConversionFeatures.get());
1416 }
1417
1418 #if defined(__QNX__)
1419 std::unique_ptr<VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX>
1420 extMemScreenBufferFeaturesQNX = nullptr;
1421 if (emulation->mDeviceInfo.supportsExternalMemoryImport) {
1422 extMemScreenBufferFeaturesQNX = std::make_unique<
1423 VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX>(
1424 VkPhysicalDeviceExternalMemoryScreenBufferFeaturesQNX{
1425 .sType =
1426 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_MEMORY_SCREEN_BUFFER_FEATURES_QNX,
1427 .screenBufferImport = VK_TRUE,
1428 });
1429 vk_append_struct(&deviceCiChain, extMemScreenBufferFeaturesQNX.get());
1430 }
1431 #endif
1432
1433 const bool commandBufferCheckpointsSupported =
1434 emulation->mDeviceInfo.supportsNvidiaDeviceDiagnosticCheckpoints;
1435 const bool commandBufferCheckpointsRequested =
1436 emulation->mFeatures.VulkanCommandBufferCheckpoints.enabled;
1437 const bool commandBufferCheckpointsSupportedAndRequested =
1438 commandBufferCheckpointsSupported && commandBufferCheckpointsRequested;
1439 VkPhysicalDeviceDiagnosticsConfigFeaturesNV deviceDiagnosticsConfigFeatures = {
1440 .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DIAGNOSTICS_CONFIG_FEATURES_NV,
1441 .diagnosticsConfig = VK_TRUE,
1442 };
1443 if (commandBufferCheckpointsSupportedAndRequested) {
1444 INFO("Enabling command buffer checkpoints with VK_NV_device_diagnostic_checkpoints.");
1445 vk_append_struct(&deviceCiChain, &deviceDiagnosticsConfigFeatures);
1446 } else if (commandBufferCheckpointsRequested) {
1447 WARN(
1448 "VulkanCommandBufferCheckpoints was requested but the "
1449 "VK_NV_device_diagnostic_checkpoints extension is not supported.");
1450 }
1451
1452 VkPhysicalDeviceRobustness2FeaturesEXT r2features = {};
1453 if (emulation->mDeviceInfo.robustness2Features) {
1454 r2features = *emulation->mDeviceInfo.robustness2Features;
1455 INFO("Enabling VK_EXT_robustness2 (%d %d %d).", r2features.robustBufferAccess2,
1456 r2features.robustImageAccess2, r2features.nullDescriptor);
1457 vk_append_struct(&deviceCiChain, &r2features);
1458 }
1459
1460 ivk->vkCreateDevice(emulation->mPhysicalDevice, &dCi, nullptr, &emulation->mDevice);
1461
1462 if (res != VK_SUCCESS) {
1463 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(res, "Failed to create Vulkan device. Error %s.",
1464 string_VkResult(res));
1465 }
1466
1467 // device created; populate dispatch table
1468 emulation->mDvk = new VulkanDispatch();
1469 init_vulkan_dispatch_from_device(ivk, emulation->mDevice, emulation->mDvk);
1470
1471 auto dvk = emulation->mDvk;
1472
1473 // Check if the dispatch table has everything 1.1 related
1474 if (!vulkan_dispatch_check_device_VK_VERSION_1_0(dvk)) {
1475 ERR("Warning: Vulkan 1.0 APIs missing from device.");
1476 }
1477 if (deviceVersion >= VK_MAKE_VERSION(1, 1, 0)) {
1478 if (!vulkan_dispatch_check_device_VK_VERSION_1_1(dvk)) {
1479 ERR("Warning: Vulkan 1.1 APIs missing from device");
1480 }
1481 }
1482
1483 if (emulation->mDeviceInfo.supportsExternalMemoryImport) {
1484 emulation->mDeviceInfo.getImageMemoryRequirements2Func =
1485 reinterpret_cast<PFN_vkGetImageMemoryRequirements2KHR>(
1486 dvk->vkGetDeviceProcAddr(emulation->mDevice, "vkGetImageMemoryRequirements2KHR"));
1487 if (!emulation->mDeviceInfo.getImageMemoryRequirements2Func) {
1488 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1489 "Cannot find vkGetImageMemoryRequirements2KHR.");
1490 }
1491 emulation->mDeviceInfo.getBufferMemoryRequirements2Func =
1492 reinterpret_cast<PFN_vkGetBufferMemoryRequirements2KHR>(
1493 dvk->vkGetDeviceProcAddr(emulation->mDevice, "vkGetBufferMemoryRequirements2KHR"));
1494 if (!emulation->mDeviceInfo.getBufferMemoryRequirements2Func) {
1495 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1496 "Cannot find vkGetBufferMemoryRequirements2KHR");
1497 }
1498 }
1499 if (emulation->mDeviceInfo.supportsExternalMemoryExport) {
1500 #ifdef _WIN32
1501 // Use vkGetMemoryWin32HandleKHR
1502 emulation->mDeviceInfo.getMemoryHandleFunc =
1503 reinterpret_cast<PFN_vkGetMemoryWin32HandleKHR>(
1504 dvk->vkGetDeviceProcAddr(emulation->mDevice, "vkGetMemoryWin32HandleKHR"));
1505 if (!emulation->mDeviceInfo.getMemoryHandleFunc) {
1506 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1507 "Cannot find vkGetMemoryWin32HandleKHR");
1508 }
1509 #else
1510 if (emulation->mInstanceSupportsMoltenVK) {
1511 // We'll use vkGetMemoryMetalHandleEXT, no need to save into getMemoryHandleFunc
1512 emulation->mDeviceInfo.getMemoryHandleFunc = nullptr;
1513 if (!dvk->vkGetDeviceProcAddr(emulation->mDevice, "vkGetMemoryMetalHandleEXT")) {
1514 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1515 "Cannot find vkGetMemoryMetalHandleEXT");
1516 }
1517 } else {
1518 // Use vkGetMemoryFdKHR
1519 emulation->mDeviceInfo.getMemoryHandleFunc = reinterpret_cast<PFN_vkGetMemoryFdKHR>(
1520 dvk->vkGetDeviceProcAddr(emulation->mDevice, "vkGetMemoryFdKHR"));
1521 if (!emulation->mDeviceInfo.getMemoryHandleFunc) {
1522 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1523 "Cannot find vkGetMemoryFdKHR");
1524 }
1525 }
1526 #endif
1527 }
1528
1529 VERBOSE("Vulkan logical device created and extension functions obtained.");
1530
1531 emulation->mQueueLock = std::make_shared<android::base::Lock>();
1532 {
1533 android::base::AutoLock queueLock(*emulation->mQueueLock);
1534 dvk->vkGetDeviceQueue(emulation->mDevice,
1535 emulation->mDeviceInfo.graphicsQueueFamilyIndices[0], 0,
1536 &emulation->mQueue);
1537 }
1538
1539 emulation->mQueueFamilyIndex = emulation->mDeviceInfo.graphicsQueueFamilyIndices[0];
1540
1541 VERBOSE("Vulkan device queue obtained.");
1542
1543 VkCommandPoolCreateInfo poolCi = {
1544 VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
1545 0,
1546 VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
1547 emulation->mQueueFamilyIndex,
1548 };
1549
1550 VkResult poolCreateRes =
1551 dvk->vkCreateCommandPool(emulation->mDevice, &poolCi, nullptr, &emulation->mCommandPool);
1552
1553 if (poolCreateRes != VK_SUCCESS) {
1554 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(poolCreateRes,
1555 "Failed to create command pool. Error: %s.",
1556 string_VkResult(poolCreateRes));
1557 }
1558
1559 VkCommandBufferAllocateInfo cbAi = {
1560 VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
1561 0,
1562 emulation->mCommandPool,
1563 VK_COMMAND_BUFFER_LEVEL_PRIMARY,
1564 1,
1565 };
1566
1567 VkResult cbAllocRes =
1568 dvk->vkAllocateCommandBuffers(emulation->mDevice, &cbAi, &emulation->mCommandBuffer);
1569
1570 if (cbAllocRes != VK_SUCCESS) {
1571 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(cbAllocRes,
1572 "Failed to allocate command buffer. Error: %s.",
1573 string_VkResult(cbAllocRes));
1574 }
1575
1576 VkFenceCreateInfo fenceCi = {
1577 VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
1578 0,
1579 0,
1580 };
1581
1582 VkResult fenceCreateRes =
1583 dvk->vkCreateFence(emulation->mDevice, &fenceCi, nullptr, &emulation->mCommandBufferFence);
1584
1585 if (fenceCreateRes != VK_SUCCESS) {
1586 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(
1587 fenceCreateRes, "Failed to create fence for command buffer. Error: %s.",
1588 string_VkResult(fenceCreateRes));
1589 }
1590
1591 // At this point, the global emulation state's logical device can alloc
1592 // memory and send commands. However, it can't really do much yet to
1593 // communicate the results without the staging buffer. Set that up here.
1594 // Note that the staging buffer is meant to use external memory, with a
1595 // non-external-memory fallback.
1596
1597 VkBufferCreateInfo bufCi = {
1598 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
1599 0,
1600 0,
1601 emulation->mStaging.size,
1602 VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
1603 VK_SHARING_MODE_EXCLUSIVE,
1604 0,
1605 nullptr,
1606 };
1607
1608 VkResult bufCreateRes =
1609 dvk->vkCreateBuffer(emulation->mDevice, &bufCi, nullptr, &emulation->mStaging.buffer);
1610
1611 if (bufCreateRes != VK_SUCCESS) {
1612 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(bufCreateRes,
1613 "Failed to create staging buffer index. Error: %s.",
1614 string_VkResult(bufCreateRes));
1615 }
1616
1617 VkMemoryRequirements memReqs;
1618 dvk->vkGetBufferMemoryRequirements(emulation->mDevice, emulation->mStaging.buffer, &memReqs);
1619
1620 emulation->mStaging.memory.size = memReqs.size;
1621
1622 bool gotStagingTypeIndex =
1623 getStagingMemoryTypeIndex(dvk, emulation->mDevice, &emulation->mDeviceInfo.memProps,
1624 &emulation->mStaging.memory.typeIndex);
1625
1626 if (!gotStagingTypeIndex) {
1627 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1628 "Failed to determine staging memory type index.");
1629 }
1630
1631 if (!((1 << emulation->mStaging.memory.typeIndex) & memReqs.memoryTypeBits)) {
1632 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(
1633 ABORT_REASON_OTHER,
1634 "Failed: Inconsistent determination of memory type index for staging buffer");
1635 }
1636
1637 if (!emulation->allocExternalMemory(dvk, &emulation->mStaging.memory, false /* not external */,
1638 kNullopt /* deviceAlignment */)) {
1639 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(ABORT_REASON_OTHER,
1640 "Failed to allocate memory for staging buffer.");
1641 }
1642
1643 VkResult stagingBufferBindRes = dvk->vkBindBufferMemory(
1644 emulation->mDevice, emulation->mStaging.buffer, emulation->mStaging.memory.memory, 0);
1645
1646 if (stagingBufferBindRes != VK_SUCCESS) {
1647 VK_EMU_INIT_RETURN_OR_ABORT_ON_ERROR(stagingBufferBindRes,
1648 "Failed to bind memory for staging buffer. Error %s.",
1649 string_VkResult(stagingBufferBindRes));
1650 }
1651
1652 if (debugUtilsAvailableAndRequested) {
1653 emulation->mDebugUtilsAvailableAndRequested = true;
1654 emulation->mDebugUtilsHelper =
1655 DebugUtilsHelper::withUtilsEnabled(emulation->mDevice, emulation->mIvk);
1656
1657 emulation->mDebugUtilsHelper.addDebugLabel(emulation->mInstance, "AEMU_Instance");
1658 emulation->mDebugUtilsHelper.addDebugLabel(emulation->mDevice, "AEMU_Device");
1659 emulation->mDebugUtilsHelper.addDebugLabel(emulation->mStaging.buffer,
1660 "AEMU_StagingBuffer");
1661 emulation->mDebugUtilsHelper.addDebugLabel(emulation->mCommandBuffer, "AEMU_CommandBuffer");
1662 }
1663
1664 if (commandBufferCheckpointsSupportedAndRequested) {
1665 emulation->mCommandBufferCheckpointsSupportedAndRequested = true;
1666 emulation->mDeviceLostHelper.enableWithNvidiaDeviceDiagnosticCheckpoints();
1667 }
1668
1669 VERBOSE("Vulkan global emulation state successfully initialized.");
1670
1671 emulation->mTransferQueueCommandBufferPool.resize(0);
1672
1673 return emulation;
1674 }
1675
initFeatures(Features features)1676 void VkEmulation::initFeatures(Features features) {
1677 std::lock_guard<std::mutex> lock(mMutex);
1678 INFO("Initializing VkEmulation features:");
1679 INFO(" glInteropSupported: %s", features.glInteropSupported ? "true" : "false");
1680 INFO(" useDeferredCommands: %s", features.deferredCommands ? "true" : "false");
1681 INFO(" createResourceWithRequirements: %s",
1682 features.createResourceWithRequirements ? "true" : "false");
1683 INFO(" useVulkanComposition: %s", features.useVulkanComposition ? "true" : "false");
1684 INFO(" useVulkanNativeSwapchain: %s", features.useVulkanNativeSwapchain ? "true" : "false");
1685 INFO(" enable guestRenderDoc: %s", features.guestRenderDoc ? "true" : "false");
1686 INFO(" ASTC LDR emulation mode: %s", string_AstcEmulationMode(features.astcLdrEmulationMode));
1687 INFO(" enable ETC2 emulation: %s", features.enableEtc2Emulation ? "true" : "false");
1688 INFO(" enable Ycbcr emulation: %s", features.enableYcbcrEmulation ? "true" : "false");
1689 INFO(" guestVulkanOnly: %s", features.guestVulkanOnly ? "true" : "false");
1690 INFO(" useDedicatedAllocations: %s", features.useDedicatedAllocations ? "true" : "false");
1691 mDeviceInfo.glInteropSupported = features.glInteropSupported;
1692 mUseDeferredCommands = features.deferredCommands;
1693 mUseCreateResourcesWithRequirements = features.createResourceWithRequirements;
1694 mGuestRenderDoc = std::move(features.guestRenderDoc);
1695 mAstcLdrEmulationMode = features.astcLdrEmulationMode;
1696 mEnableEtc2Emulation = features.enableEtc2Emulation;
1697 mEnableYcbcrEmulation = features.enableYcbcrEmulation;
1698 mGuestVulkanOnly = features.guestVulkanOnly;
1699 mUseDedicatedAllocations = features.useDedicatedAllocations;
1700
1701 if (features.useVulkanComposition) {
1702 if (mCompositorVk) {
1703 ERR("Reset VkEmulation::compositorVk.");
1704 }
1705 mCompositorVk = CompositorVk::create(*mIvk, mDevice, mPhysicalDevice, mQueue, mQueueLock,
1706 mQueueFamilyIndex, 3, mDebugUtilsHelper);
1707 }
1708
1709 if (features.useVulkanNativeSwapchain) {
1710 if (mDisplayVk) {
1711 ERR("Reset VkEmulation::displayVk.");
1712 }
1713 mDisplayVk = std::make_unique<DisplayVk>(*mIvk, mPhysicalDevice, mQueueFamilyIndex,
1714 mQueueFamilyIndex, mDevice, mQueue, mQueueLock,
1715 mQueue, mQueueLock);
1716 }
1717
1718 auto representativeInfo = findRepresentativeColorBufferMemoryTypeIndexLocked();
1719 if (!representativeInfo) {
1720 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
1721 << "Failed to find memory type for ColorBuffers.";
1722 }
1723 mRepresentativeColorBufferMemoryTypeInfo = *representativeInfo;
1724 VERBOSE(
1725 "Representative ColorBuffer memory type using host memory type index %d "
1726 "and guest memory type index :%d",
1727 mRepresentativeColorBufferMemoryTypeInfo.hostMemoryTypeIndex,
1728 mRepresentativeColorBufferMemoryTypeInfo.guestMemoryTypeIndex);
1729 }
1730
~VkEmulation()1731 VkEmulation::~VkEmulation() {
1732 std::lock_guard<std::mutex> lock(mMutex);
1733
1734 mCompositorVk.reset();
1735 mDisplayVk.reset();
1736
1737 freeExternalMemoryLocked(mDvk, &mStaging.memory);
1738
1739 mDvk->vkDestroyBuffer(mDevice, mStaging.buffer, nullptr);
1740 mDvk->vkDestroyFence(mDevice, mCommandBufferFence, nullptr);
1741 mDvk->vkFreeCommandBuffers(mDevice, mCommandPool, 1, &mCommandBuffer);
1742 mDvk->vkDestroyCommandPool(mDevice, mCommandPool, nullptr);
1743
1744 mIvk->vkDestroyDevice(mDevice, nullptr);
1745
1746 mGvk->vkDestroyInstance(mInstance, nullptr);
1747 }
1748
isYcbcrEmulationEnabled() const1749 bool VkEmulation::isYcbcrEmulationEnabled() const { return mEnableYcbcrEmulation; }
1750
isEtc2EmulationEnabled() const1751 bool VkEmulation::isEtc2EmulationEnabled() const { return mEnableEtc2Emulation; }
1752
deferredCommandsEnabled() const1753 bool VkEmulation::deferredCommandsEnabled() const { return mUseDeferredCommands; }
1754
createResourcesWithRequirementsEnabled() const1755 bool VkEmulation::createResourcesWithRequirementsEnabled() const {
1756 return mUseCreateResourcesWithRequirements;
1757 }
1758
supportsGetPhysicalDeviceProperties2() const1759 bool VkEmulation::supportsGetPhysicalDeviceProperties2() const {
1760 return mInstanceSupportsGetPhysicalDeviceProperties2;
1761 }
1762
supportsExternalMemoryCapabilities() const1763 bool VkEmulation::supportsExternalMemoryCapabilities() const {
1764 return mInstanceSupportsExternalMemoryCapabilities;
1765 }
1766
supportsExternalSemaphoreCapabilities() const1767 bool VkEmulation::supportsExternalSemaphoreCapabilities() const {
1768 return mInstanceSupportsExternalSemaphoreCapabilities;
1769 }
1770
supportsExternalFenceCapabilities() const1771 bool VkEmulation::supportsExternalFenceCapabilities() const {
1772 return mInstanceSupportsExternalFenceCapabilities;
1773 }
1774
supportsSurfaces() const1775 bool VkEmulation::supportsSurfaces() const { return mInstanceSupportsSurface; }
1776
supportsMoltenVk() const1777 bool VkEmulation::supportsMoltenVk() const { return mInstanceSupportsMoltenVK; }
1778
supportsPhysicalDeviceIDProperties() const1779 bool VkEmulation::supportsPhysicalDeviceIDProperties() const {
1780 return mInstanceSupportsPhysicalDeviceIDProperties;
1781 }
1782
supportsPrivateData() const1783 bool VkEmulation::supportsPrivateData() const { return mDeviceInfo.supportsPrivateData; }
1784
supportsExternalMemoryImport() const1785 bool VkEmulation::supportsExternalMemoryImport() const {
1786 return mDeviceInfo.supportsExternalMemoryImport;
1787 }
1788
supportsDmaBuf() const1789 bool VkEmulation::supportsDmaBuf() const { return mDeviceInfo.supportsDmaBuf; }
1790
supportsExternalMemoryHostProperties() const1791 bool VkEmulation::supportsExternalMemoryHostProperties() const {
1792 return mDeviceInfo.supportsExternalMemoryHostProps;
1793 }
1794
getRobustness2Features() const1795 std::optional<VkPhysicalDeviceRobustness2FeaturesEXT> VkEmulation::getRobustness2Features() const {
1796 return mDeviceInfo.robustness2Features;
1797 }
1798
externalMemoryHostProperties() const1799 VkPhysicalDeviceExternalMemoryHostPropertiesEXT VkEmulation::externalMemoryHostProperties() const {
1800 return mDeviceInfo.externalMemoryHostProps;
1801 }
1802
isGuestVulkanOnly() const1803 bool VkEmulation::isGuestVulkanOnly() const { return mGuestVulkanOnly; }
1804
commandBufferCheckpointsEnabled() const1805 bool VkEmulation::commandBufferCheckpointsEnabled() const {
1806 return mCommandBufferCheckpointsSupportedAndRequested;
1807 }
1808
supportsSamplerYcbcrConversion() const1809 bool VkEmulation::supportsSamplerYcbcrConversion() const {
1810 return mDeviceInfo.supportsSamplerYcbcrConversion;
1811 }
1812
debugUtilsEnabled() const1813 bool VkEmulation::debugUtilsEnabled() const { return mDebugUtilsAvailableAndRequested; }
1814
getDebugUtilsHelper()1815 DebugUtilsHelper& VkEmulation::getDebugUtilsHelper() { return mDebugUtilsHelper; }
1816
getDeviceLostHelper()1817 DeviceLostHelper& VkEmulation::getDeviceLostHelper() { return mDeviceLostHelper; }
1818
getFeatures() const1819 const gfxstream::host::FeatureSet& VkEmulation::getFeatures() const { return mFeatures; }
1820
getCallbacks() const1821 const gfxstream::host::BackendCallbacks& VkEmulation::getCallbacks() const { return mCallbacks; }
1822
getAstcLdrEmulationMode() const1823 AstcEmulationMode VkEmulation::getAstcLdrEmulationMode() const { return mAstcLdrEmulationMode; }
1824
getRenderDoc()1825 emugl::RenderDocWithMultipleVkInstances* VkEmulation::getRenderDoc() {
1826 return mGuestRenderDoc.get();
1827 }
1828
getCompositor()1829 Compositor* VkEmulation::getCompositor() { return mCompositorVk.get(); }
1830
getDisplay()1831 DisplayVk* VkEmulation::getDisplay() { return mDisplayVk.get(); }
1832
getInstance()1833 VkInstance VkEmulation::getInstance() { return mInstance; }
1834
getDeviceUuid()1835 std::optional<std::array<uint8_t, VK_UUID_SIZE>> VkEmulation::getDeviceUuid() {
1836 if (!supportsPhysicalDeviceIDProperties()) {
1837 return std::nullopt;
1838 }
1839
1840 std::array<uint8_t, VK_UUID_SIZE> uuid;
1841 std::memcpy(uuid.data(), mDeviceInfo.idProps.deviceUUID, VK_UUID_SIZE);
1842 return uuid;
1843 }
1844
getDriverUuid()1845 std::optional<std::array<uint8_t, VK_UUID_SIZE>> VkEmulation::getDriverUuid() {
1846 if (!supportsPhysicalDeviceIDProperties()) {
1847 return std::nullopt;
1848 }
1849
1850 std::array<uint8_t, VK_UUID_SIZE> uuid;
1851 std::memcpy(uuid.data(), mDeviceInfo.idProps.driverUUID, VK_UUID_SIZE);
1852 return uuid;
1853 }
1854
getGpuVendor() const1855 std::string VkEmulation::getGpuVendor() const { return mDeviceInfo.driverVendor; }
1856
getGpuName() const1857 std::string VkEmulation::getGpuName() const { return mDeviceInfo.physdevProps.deviceName; }
1858
getGpuVersionString() const1859 std::string VkEmulation::getGpuVersionString() const {
1860 std::stringstream builder;
1861 builder << "Vulkan " //
1862 << VK_API_VERSION_MAJOR(mVulkanInstanceVersion) << "." //
1863 << VK_API_VERSION_MINOR(mVulkanInstanceVersion) << "." //
1864 << VK_API_VERSION_PATCH(mVulkanInstanceVersion) << " " //
1865 << getGpuVendor() << " " //
1866 << getGpuName();
1867 return builder.str();
1868 }
1869
getInstanceExtensionsString() const1870 std::string VkEmulation::getInstanceExtensionsString() const {
1871 std::stringstream builder;
1872 for (const auto& instanceExtension : mInstanceExtensions) {
1873 if (builder.tellp() != 0) {
1874 builder << " ";
1875 }
1876 builder << instanceExtension.extensionName;
1877 }
1878 return builder.str();
1879 }
1880
getDeviceExtensionsString() const1881 std::string VkEmulation::getDeviceExtensionsString() const {
1882 std::stringstream builder;
1883 for (const auto& deviceExtension : mDeviceInfo.extensions) {
1884 if (builder.tellp() != 0) {
1885 builder << " ";
1886 }
1887 builder << deviceExtension.extensionName;
1888 }
1889 return builder.str();
1890 }
1891
getPhysicalDeviceProperties() const1892 const VkPhysicalDeviceProperties VkEmulation::getPhysicalDeviceProperties() const {
1893 return mDeviceInfo.physdevProps;
1894 }
1895
1896 VkEmulation::RepresentativeColorBufferMemoryTypeInfo
getRepresentativeColorBufferMemoryTypeInfo() const1897 VkEmulation::getRepresentativeColorBufferMemoryTypeInfo() const {
1898 return mRepresentativeColorBufferMemoryTypeInfo;
1899 }
1900
onVkDeviceLost()1901 void VkEmulation::onVkDeviceLost() { VkDecoderGlobalState::get()->on_DeviceLost(); }
1902
createDisplaySurface(FBNativeWindowType window,uint32_t width,uint32_t height)1903 std::unique_ptr<gfxstream::DisplaySurface> VkEmulation::createDisplaySurface(
1904 FBNativeWindowType window, uint32_t width, uint32_t height) {
1905 auto surfaceVk = DisplaySurfaceVk::create(*mIvk, mInstance, window);
1906 if (!surfaceVk) {
1907 ERR("Failed to create DisplaySurfaceVk.");
1908 return nullptr;
1909 }
1910
1911 return std::make_unique<gfxstream::DisplaySurface>(width, height, std::move(surfaceVk));
1912 }
1913
1914 #ifdef __APPLE__
getMtlResourceFromVkDeviceMemory(VulkanDispatch * vk,VkDeviceMemory memory)1915 MTLResource_id VkEmulation::getMtlResourceFromVkDeviceMemory(VulkanDispatch* vk,
1916 VkDeviceMemory memory) {
1917 if (memory == VK_NULL_HANDLE) {
1918 WARN("Requested metal resource handle for null memory!");
1919 return nullptr;
1920 }
1921
1922 VkMemoryGetMetalHandleInfoEXT getMetalHandleInfo = {
1923 VK_STRUCTURE_TYPE_MEMORY_GET_METAL_HANDLE_INFO_EXT,
1924 nullptr,
1925 memory,
1926 VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT
1927 };
1928
1929 MTLResource_id outputHandle = nullptr;
1930 vk->vkGetMemoryMetalHandleEXT(mDevice, &getMetalHandleInfo, &outputHandle);
1931 if (outputHandle == nullptr) {
1932 ERR("vkGetMemoryMetalHandleEXT returned null");
1933 }
1934 return outputHandle;
1935 }
1936 #endif
1937
1938 // 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)1939 bool VkEmulation::allocExternalMemory(VulkanDispatch* vk, VkEmulation::ExternalMemoryInfo* info,
1940 bool actuallyExternal, Optional<uint64_t> deviceAlignment,
1941 Optional<VkBuffer> bufferForDedicatedAllocation,
1942 Optional<VkImage> imageForDedicatedAllocation) {
1943 VkExportMemoryAllocateInfo exportAi = {
1944 .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO,
1945 .pNext = nullptr,
1946 .handleTypes =
1947 static_cast<VkExternalMemoryHandleTypeFlags>(getDefaultExternalMemoryHandleType()),
1948 };
1949
1950 VkMemoryDedicatedAllocateInfo dedicatedAllocInfo = {
1951 .sType = VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
1952 .pNext = nullptr,
1953 .image = VK_NULL_HANDLE,
1954 .buffer = VK_NULL_HANDLE,
1955 };
1956
1957 VkMemoryAllocateInfo allocInfo = {
1958 .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
1959 .pNext = nullptr,
1960 .allocationSize = info->size,
1961 .memoryTypeIndex = info->typeIndex,
1962 };
1963
1964 auto allocInfoChain = vk_make_chain_iterator(&allocInfo);
1965
1966 if (mDeviceInfo.supportsExternalMemoryExport && actuallyExternal) {
1967 #ifdef __APPLE__
1968 if (mInstanceSupportsMoltenVK) {
1969 // Change handle type for metal resources
1970 exportAi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
1971 }
1972 #endif
1973 if (mDeviceInfo.supportsDmaBuf) {
1974 exportAi.handleTypes |= VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
1975 }
1976
1977 vk_append_struct(&allocInfoChain, &exportAi);
1978 }
1979
1980 if (bufferForDedicatedAllocation.hasValue() || imageForDedicatedAllocation.hasValue()) {
1981 info->dedicatedAllocation = true;
1982 if (bufferForDedicatedAllocation.hasValue()) {
1983 dedicatedAllocInfo.buffer = *bufferForDedicatedAllocation;
1984 }
1985 if (imageForDedicatedAllocation.hasValue()) {
1986 dedicatedAllocInfo.image = *imageForDedicatedAllocation;
1987 }
1988 vk_append_struct(&allocInfoChain, &dedicatedAllocInfo);
1989 }
1990
1991 bool memoryAllocated = false;
1992 std::vector<VkDeviceMemory> allocationAttempts;
1993 constexpr size_t kMaxAllocationAttempts = 20u;
1994
1995 while (!memoryAllocated) {
1996 VkResult allocRes = vk->vkAllocateMemory(mDevice, &allocInfo, nullptr, &info->memory);
1997
1998 if (allocRes != VK_SUCCESS) {
1999 VERBOSE("%s: failed in vkAllocateMemory: %s",
2000 __func__, string_VkResult(allocRes));
2001 break;
2002 }
2003
2004 if (mDeviceInfo.memProps.memoryTypes[info->typeIndex].propertyFlags &
2005 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
2006 VkResult mapRes =
2007 vk->vkMapMemory(mDevice, info->memory, 0, info->size, 0, &info->mappedPtr);
2008 if (mapRes != VK_SUCCESS) {
2009 VERBOSE("%s: failed in vkMapMemory: %s", __func__, string_VkResult(mapRes));
2010 break;
2011 }
2012 }
2013
2014 uint64_t mappedPtrPageOffset = reinterpret_cast<uint64_t>(info->mappedPtr) % kPageSize;
2015
2016 if ( // don't care about alignment (e.g. device-local memory)
2017 !deviceAlignment.hasValue() ||
2018 // If device has an alignment requirement larger than current
2019 // host pointer alignment (i.e. the lowest 1 bit of mappedPtr),
2020 // the only possible way to make mappedPtr valid is to ensure
2021 // that it is already aligned to page.
2022 mappedPtrPageOffset == 0u ||
2023 // If device has an alignment requirement smaller or equals to
2024 // current host pointer alignment, clients can set a offset
2025 // |kPageSize - mappedPtrPageOffset| in vkBindImageMemory to
2026 // make it aligned to page and compatible with device
2027 // requirements.
2028 (kPageSize - mappedPtrPageOffset) % deviceAlignment.value() == 0) {
2029 // allocation success.
2030 memoryAllocated = true;
2031 } else {
2032 allocationAttempts.push_back(info->memory);
2033
2034 VERBOSE("%s: attempt #%zu failed; deviceAlignment: %" PRIu64
2035 ", mappedPtrPageOffset: %" PRIu64,
2036 __func__, allocationAttempts.size(), deviceAlignment.valueOr(0), mappedPtrPageOffset);
2037
2038 if (allocationAttempts.size() >= kMaxAllocationAttempts) {
2039 VERBOSE(
2040 "%s: unable to allocate memory with CPU mapped ptr aligned to "
2041 "page", __func__);
2042 break;
2043 }
2044 }
2045 }
2046
2047 // clean up previous failed attempts
2048 for (const auto& mem : allocationAttempts) {
2049 vk->vkFreeMemory(mDevice, mem, nullptr /* allocator */);
2050 }
2051 if (!memoryAllocated) {
2052 return false;
2053 }
2054
2055 if (!mDeviceInfo.supportsExternalMemoryExport || !actuallyExternal) {
2056 return true;
2057 }
2058
2059 uint32_t streamHandleType = 0;
2060 VkResult exportRes = VK_SUCCESS;
2061 bool validHandle = false;
2062 #ifdef _WIN32
2063 VkMemoryGetWin32HandleInfoKHR getWin32HandleInfo = {
2064 VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR,
2065 0,
2066 info->memory,
2067 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
2068 };
2069
2070 HANDLE exportHandle = NULL;
2071 exportRes = mDeviceInfo.getMemoryHandleFunc(mDevice, &getWin32HandleInfo, &exportHandle);
2072 validHandle = (VK_SUCCESS == exportRes) && (NULL != exportHandle);
2073 info->handleInfo = ExternalHandleInfo{
2074 .handle = reinterpret_cast<ExternalHandleType>(exportHandle),
2075 .streamHandleType = STREAM_HANDLE_TYPE_MEM_OPAQUE_WIN32,
2076 };
2077 #else
2078
2079 bool opaqueFd = true;
2080 #if defined(__APPLE__)
2081 if (mInstanceSupportsMoltenVK) {
2082 opaqueFd = false;
2083 info->externalMetalHandle = getMtlResourceFromVkDeviceMemory(vk, info->memory);
2084 validHandle = (nullptr != info->externalMetalHandle);
2085 if (validHandle) {
2086 CFRetain(info->externalMetalHandle);
2087 exportRes = VK_SUCCESS;
2088 } else {
2089 exportRes = VK_ERROR_INVALID_EXTERNAL_HANDLE;
2090 }
2091 }
2092 #endif
2093
2094 if (opaqueFd) {
2095 streamHandleType = STREAM_HANDLE_TYPE_MEM_OPAQUE_FD;
2096 VkExternalMemoryHandleTypeFlagBits vkHandleType =
2097 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
2098 if (mDeviceInfo.supportsDmaBuf) {
2099 vkHandleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
2100 streamHandleType = STREAM_HANDLE_TYPE_MEM_DMABUF;
2101 }
2102
2103 VkMemoryGetFdInfoKHR getFdInfo = {
2104 VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR,
2105 0,
2106 info->memory,
2107 vkHandleType,
2108 };
2109 int exportFd = -1;
2110 exportRes = mDeviceInfo.getMemoryHandleFunc(mDevice, &getFdInfo, &exportFd);
2111 validHandle = (VK_SUCCESS == exportRes) && (-1 != exportFd);
2112 info->handleInfo = ExternalHandleInfo{
2113 .handle = exportFd,
2114 .streamHandleType = streamHandleType,
2115 };
2116 }
2117 #endif
2118
2119 if (exportRes != VK_SUCCESS || !validHandle) {
2120 WARN("%s: Failed to get external memory, result: %s",
2121 __func__, string_VkResult(exportRes));
2122 return false;
2123 }
2124
2125 return true;
2126 }
2127
freeExternalMemoryLocked(VulkanDispatch * vk,VkEmulation::ExternalMemoryInfo * info)2128 void VkEmulation::freeExternalMemoryLocked(VulkanDispatch* vk,
2129 VkEmulation::ExternalMemoryInfo* info) {
2130 if (!info->memory) return;
2131
2132 if (mDeviceInfo.memProps.memoryTypes[info->typeIndex].propertyFlags &
2133 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT) {
2134 if (mOccupiedGpas.find(info->gpa) != mOccupiedGpas.end()) {
2135 mOccupiedGpas.erase(info->gpa);
2136 get_emugl_vm_operations().unmapUserBackedRam(info->gpa, info->sizeToPage);
2137 info->gpa = 0u;
2138 }
2139
2140 if (info->mappedPtr != nullptr) {
2141 vk->vkUnmapMemory(mDevice, info->memory);
2142 info->mappedPtr = nullptr;
2143 info->pageAlignedHva = nullptr;
2144 }
2145 }
2146
2147 vk->vkFreeMemory(mDevice, info->memory, nullptr);
2148
2149 info->memory = VK_NULL_HANDLE;
2150
2151 if (info->handleInfo) {
2152 #ifdef _WIN32
2153 CloseHandle(static_cast<HANDLE>(reinterpret_cast<void*>(info->handleInfo->handle)));
2154 #else
2155 switch (info->handleInfo->streamHandleType) {
2156 case STREAM_HANDLE_TYPE_MEM_OPAQUE_FD:
2157 case STREAM_HANDLE_TYPE_MEM_DMABUF:
2158 close(info->handleInfo->handle);
2159 break;
2160 case STREAM_HANDLE_TYPE_PLATFORM_SCREEN_BUFFER_QNX:
2161 default:
2162 break;
2163 }
2164 #endif
2165 info->handleInfo = std::nullopt;
2166 }
2167
2168 #if defined(__APPLE__)
2169 if (info->externalMetalHandle) {
2170 CFRelease(info->externalMetalHandle);
2171 }
2172 #endif
2173 }
2174
importExternalMemory(VulkanDispatch * vk,VkDevice targetDevice,const VkEmulation::ExternalMemoryInfo * info,VkMemoryDedicatedAllocateInfo * dedicatedAllocInfoPtr,VkDeviceMemory * out)2175 bool VkEmulation::importExternalMemory(VulkanDispatch* vk, VkDevice targetDevice,
2176 const VkEmulation::ExternalMemoryInfo* info,
2177 VkMemoryDedicatedAllocateInfo* dedicatedAllocInfoPtr,
2178 VkDeviceMemory* out) {
2179 const void* importInfoPtr = nullptr;
2180 auto handleInfo = info->handleInfo;
2181 #ifdef _WIN32
2182 if (!handleInfo) {
2183 ERR("importExternalMemory: external handle info is not available, cannot retrieve win32 "
2184 "handle.");
2185 return false;
2186 }
2187 VkImportMemoryWin32HandleInfoKHR importInfo = {
2188 VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR,
2189 dedicatedAllocInfoPtr,
2190 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT,
2191 static_cast<HANDLE>(reinterpret_cast<void*>(handleInfo->handle)),
2192 0,
2193 };
2194 importInfoPtr = &importInfo;
2195 #elif defined(__QNX__)
2196 if (!handleInfo) {
2197 ERR("importExternalMemory: external handle info is not available, cannot retrieve "
2198 "screen_buffer_t handle.");
2199 return false;
2200 }
2201 VkImportScreenBufferInfoQNX importInfo = {
2202 VK_STRUCTURE_TYPE_IMPORT_SCREEN_BUFFER_INFO_QNX,
2203 dedicatedAllocInfoPtr,
2204 static_cast<screen_buffer_t>(reinterpret_cast<void*>(handleInfo->handle)),
2205 };
2206 importInfoPtr = &importInfo;
2207 #elif defined(__APPLE__)
2208 VkImportMemoryMetalHandleInfoEXT importInfoMetalInfo = {
2209 VK_STRUCTURE_TYPE_IMPORT_MEMORY_METAL_HANDLE_INFO_EXT, dedicatedAllocInfoPtr,
2210 VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT, nullptr};
2211 if (mInstanceSupportsMoltenVK) {
2212 importInfoMetalInfo.handle = info->externalMetalHandle;
2213 importInfoPtr = &importInfoMetalInfo;
2214 }
2215 #endif
2216
2217 VkImportMemoryFdInfoKHR importInfoFd = {
2218 VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR,
2219 dedicatedAllocInfoPtr,
2220 VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT,
2221 -1,
2222 };
2223 if (!importInfoPtr) {
2224 if (!handleInfo) {
2225 ERR("importExternalMemory: external handle info is not available, cannot retrieve "
2226 "information required to duplicate the external handle.");
2227 return false;
2228 }
2229 auto dupHandle = dupExternalMemory(handleInfo);
2230 if (!dupHandle) {
2231 ERR("importExternalMemory: Failed to duplicate handleInfo.handle: 0x%x, "
2232 "streamHandleType: %d",
2233 handleInfo->handle, handleInfo->streamHandleType);
2234 return false;
2235 }
2236 importInfoFd.fd = dupHandle->handle;
2237 importInfoPtr = &importInfoFd;
2238 }
2239
2240 VkMemoryAllocateInfo allocInfo = {
2241 VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
2242 importInfoPtr,
2243 info->size,
2244 info->typeIndex,
2245 };
2246
2247 VkResult res = vk->vkAllocateMemory(targetDevice, &allocInfo, nullptr, out);
2248
2249 if (res != VK_SUCCESS) {
2250 ERR("importExternalMemory: Failed with %s", string_VkResult(res));
2251 return false;
2252 }
2253
2254 return true;
2255 }
2256
2257 // From ANGLE "src/common/angleutils.h"
2258 #define GL_BGR10_A2_ANGLEX 0x6AF9
2259
glFormat2VkFormat(GLint internalFormat)2260 static VkFormat glFormat2VkFormat(GLint internalFormat) {
2261 switch (internalFormat) {
2262 case GL_R8:
2263 case GL_LUMINANCE:
2264 return VK_FORMAT_R8_UNORM;
2265 case GL_RGB:
2266 case GL_RGB8:
2267 // b/281550953
2268 // RGB8 is not supported on many vulkan drivers.
2269 // Try RGBA8 instead.
2270 // Note: updateColorBufferFromBytesLocked() performs channel conversion for this case.
2271 return VK_FORMAT_R8G8B8A8_UNORM;
2272 case GL_RGB565:
2273 return VK_FORMAT_R5G6B5_UNORM_PACK16;
2274 case GL_RGB16F:
2275 return VK_FORMAT_R16G16B16_SFLOAT;
2276 case GL_RGBA:
2277 case GL_RGBA8:
2278 return VK_FORMAT_R8G8B8A8_UNORM;
2279 case GL_RGB5_A1_OES:
2280 return VK_FORMAT_A1R5G5B5_UNORM_PACK16;
2281 case GL_RGBA4_OES: {
2282 // TODO: add R4G4B4A4 support to lavapipe, and check support programmatically
2283 const bool lavapipe =
2284 (android::base::getEnvironmentVariable("ANDROID_EMU_VK_ICD").compare("lavapipe") ==
2285 0);
2286 if (lavapipe) {
2287 // RGBA4 is not supported on lavapipe, use more widely available BGRA4 instead.
2288 // Note: updateColorBufferFromBytesLocked() performs channel conversion for this
2289 // case.
2290 return VK_FORMAT_B4G4R4A4_UNORM_PACK16;
2291 }
2292 return VK_FORMAT_R4G4B4A4_UNORM_PACK16;
2293 }
2294 case GL_RGB10_A2:
2295 case GL_UNSIGNED_INT_10_10_10_2_OES:
2296 return VK_FORMAT_A2R10G10B10_UNORM_PACK32;
2297 case GL_BGR10_A2_ANGLEX:
2298 return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
2299 case GL_RGBA16F:
2300 return VK_FORMAT_R16G16B16A16_SFLOAT;
2301 case GL_BGRA_EXT:
2302 case GL_BGRA8_EXT:
2303 return VK_FORMAT_B8G8R8A8_UNORM;
2304 case GL_R16_EXT:
2305 return VK_FORMAT_R16_UNORM;
2306 case GL_RG8_EXT:
2307 return VK_FORMAT_R8G8_UNORM;
2308 case GL_DEPTH_COMPONENT16:
2309 return VK_FORMAT_D16_UNORM;
2310 case GL_DEPTH_COMPONENT24:
2311 return VK_FORMAT_X8_D24_UNORM_PACK32;
2312 case GL_DEPTH24_STENCIL8:
2313 return VK_FORMAT_D24_UNORM_S8_UINT;
2314 case GL_DEPTH_COMPONENT32F:
2315 return VK_FORMAT_D32_SFLOAT;
2316 case GL_DEPTH32F_STENCIL8:
2317 return VK_FORMAT_D32_SFLOAT_S8_UINT;
2318 default:
2319 ERR("Unhandled format %d, falling back to VK_FORMAT_R8G8B8A8_UNORM", internalFormat);
2320 return VK_FORMAT_R8G8B8A8_UNORM;
2321 }
2322 };
2323
isFormatVulkanCompatible(GLenum internalFormat)2324 bool VkEmulation::isFormatVulkanCompatible(GLenum internalFormat) {
2325 VkFormat vkFormat = glFormat2VkFormat(internalFormat);
2326
2327 for (const auto& supportInfo : mImageSupportInfo) {
2328 if (supportInfo.format == vkFormat && supportInfo.supported) {
2329 return true;
2330 }
2331 }
2332
2333 return false;
2334 }
2335
getColorBufferShareInfo(uint32_t colorBufferHandle,bool * glExported,bool * externalMemoryCompatible)2336 bool VkEmulation::getColorBufferShareInfo(uint32_t colorBufferHandle, bool* glExported,
2337 bool* externalMemoryCompatible) {
2338 std::lock_guard<std::mutex> lock(mMutex);
2339
2340 auto info = android::base::find(mColorBuffers, colorBufferHandle);
2341 if (!info) {
2342 return false;
2343 }
2344
2345 *glExported = info->glExported;
2346 *externalMemoryCompatible = info->externalMemoryCompatible;
2347 return true;
2348 }
2349
getColorBufferAllocationInfoLocked(uint32_t colorBufferHandle,VkDeviceSize * outSize,uint32_t * outMemoryTypeIndex,bool * outMemoryIsDedicatedAlloc,void ** outMappedPtr)2350 bool VkEmulation::getColorBufferAllocationInfoLocked(uint32_t colorBufferHandle,
2351 VkDeviceSize* outSize,
2352 uint32_t* outMemoryTypeIndex,
2353 bool* outMemoryIsDedicatedAlloc,
2354 void** outMappedPtr) {
2355 auto info = android::base::find(mColorBuffers, colorBufferHandle);
2356 if (!info) {
2357 return false;
2358 }
2359
2360 if (outSize) {
2361 *outSize = info->memory.size;
2362 }
2363
2364 if (outMemoryTypeIndex) {
2365 *outMemoryTypeIndex = info->memory.typeIndex;
2366 }
2367
2368 if (outMemoryIsDedicatedAlloc) {
2369 *outMemoryIsDedicatedAlloc = info->memory.dedicatedAllocation;
2370 }
2371
2372 if (outMappedPtr) {
2373 *outMappedPtr = info->memory.mappedPtr;
2374 }
2375
2376 return true;
2377 }
2378
getColorBufferAllocationInfo(uint32_t colorBufferHandle,VkDeviceSize * outSize,uint32_t * outMemoryTypeIndex,bool * outMemoryIsDedicatedAlloc,void ** outMappedPtr)2379 bool VkEmulation::getColorBufferAllocationInfo(uint32_t colorBufferHandle, VkDeviceSize* outSize,
2380 uint32_t* outMemoryTypeIndex,
2381 bool* outMemoryIsDedicatedAlloc,
2382 void** outMappedPtr) {
2383 std::lock_guard<std::mutex> lock(mMutex);
2384 return getColorBufferAllocationInfoLocked(colorBufferHandle, outSize, outMemoryTypeIndex,
2385 outMemoryIsDedicatedAlloc, outMappedPtr);
2386 }
2387
2388 // This function will return the first memory type that exactly matches the
2389 // requested properties, if there is any. Otherwise it'll return the last
2390 // index that supports all the requested memory property flags.
2391 // Eg. this avoids returning a host coherent memory type when only device local
2392 // memory flag is requested, which may be slow or not support some other features,
2393 // such as association with optimal-tiling images on some implementations.
getValidMemoryTypeIndex(uint32_t requiredMemoryTypeBits,VkMemoryPropertyFlags memoryProperty)2394 uint32_t VkEmulation::getValidMemoryTypeIndex(uint32_t requiredMemoryTypeBits,
2395 VkMemoryPropertyFlags memoryProperty) {
2396 uint32_t secondBest = ~0;
2397 bool found = false;
2398 for (int32_t i = 0; i <= 31; i++) {
2399 if ((requiredMemoryTypeBits & (1u << i)) == 0) {
2400 // Not a suitable memory index
2401 continue;
2402 }
2403
2404 const VkMemoryPropertyFlags memPropertyFlags =
2405 mDeviceInfo.memProps.memoryTypes[i].propertyFlags;
2406
2407 // Exact match, return immediately
2408 if (memPropertyFlags == memoryProperty) {
2409 return i;
2410 }
2411
2412 // Valid memory index, but keep looking for an exact match
2413 // TODO: this should compare against memoryProperty, but some existing tests
2414 // are depending on this behavior.
2415 const bool propertyValid = !memoryProperty || ((memPropertyFlags & memoryProperty) != 0);
2416 if (propertyValid) {
2417 secondBest = i;
2418 found = true;
2419 }
2420 }
2421
2422 if (!found) {
2423 GFXSTREAM_ABORT(FatalError(ABORT_REASON_OTHER))
2424 << "Could not find a valid memory index with memoryProperty: "
2425 << string_VkMemoryPropertyFlags(memoryProperty)
2426 << ", and requiredMemoryTypeBits: " << requiredMemoryTypeBits;
2427 }
2428 return secondBest;
2429 }
2430
2431 // pNext, sharingMode, queueFamilyIndexCount, pQueueFamilyIndices, and initialLayout won't be
2432 // filled.
generateColorBufferVkImageCreateInfoLocked(VkFormat format,uint32_t width,uint32_t height,VkImageTiling tiling)2433 std::unique_ptr<VkImageCreateInfo> VkEmulation::generateColorBufferVkImageCreateInfoLocked(
2434 VkFormat format, uint32_t width, uint32_t height, VkImageTiling tiling) {
2435 const VkEmulation::ImageSupportInfo* maybeImageSupportInfo = nullptr;
2436 for (const auto& supportInfo : mImageSupportInfo) {
2437 if (supportInfo.format == format && supportInfo.supported) {
2438 maybeImageSupportInfo = &supportInfo;
2439 break;
2440 }
2441 }
2442 if (!maybeImageSupportInfo) {
2443 ERR("Format %s [%d] is not supported.", string_VkFormat(format), format);
2444 return nullptr;
2445 }
2446 const VkEmulation::ImageSupportInfo& imageSupportInfo = *maybeImageSupportInfo;
2447 const VkFormatProperties& formatProperties = imageSupportInfo.formatProps2.formatProperties;
2448
2449 constexpr std::pair<VkFormatFeatureFlags, VkImageUsageFlags> formatUsagePairs[] = {
2450 {VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT,
2451 VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT},
2452 {VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT,
2453 VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT},
2454 {VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT, VK_IMAGE_USAGE_SAMPLED_BIT},
2455 {VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT},
2456 {VK_FORMAT_FEATURE_TRANSFER_DST_BIT, VK_IMAGE_USAGE_TRANSFER_DST_BIT},
2457 {VK_FORMAT_FEATURE_BLIT_SRC_BIT, VK_IMAGE_USAGE_TRANSFER_SRC_BIT},
2458 };
2459 VkFormatFeatureFlags tilingFeatures = (tiling == VK_IMAGE_TILING_OPTIMAL)
2460 ? formatProperties.optimalTilingFeatures
2461 : formatProperties.linearTilingFeatures;
2462
2463 VkImageUsageFlags usage = 0;
2464 for (const auto& formatUsage : formatUsagePairs) {
2465 usage |= (tilingFeatures & formatUsage.first) ? formatUsage.second : 0u;
2466 }
2467
2468 return std::make_unique<VkImageCreateInfo>(VkImageCreateInfo{
2469 .sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
2470 // The caller is responsible to fill pNext.
2471 .pNext = nullptr,
2472 .flags = imageSupportInfo.createFlags,
2473 .imageType = VK_IMAGE_TYPE_2D,
2474 .format = format,
2475 .extent =
2476 {
2477 .width = width,
2478 .height = height,
2479 .depth = 1,
2480 },
2481 .mipLevels = 1,
2482 .arrayLayers = 1,
2483 .samples = VK_SAMPLE_COUNT_1_BIT,
2484 .tiling = tiling,
2485 .usage = usage,
2486 // The caller is responsible to fill sharingMode.
2487 .sharingMode = VK_SHARING_MODE_MAX_ENUM,
2488 // The caller is responsible to fill queueFamilyIndexCount.
2489 .queueFamilyIndexCount = 0,
2490 // The caller is responsible to fill pQueueFamilyIndices.
2491 .pQueueFamilyIndices = nullptr,
2492 // The caller is responsible to fill initialLayout.
2493 .initialLayout = VK_IMAGE_LAYOUT_MAX_ENUM,
2494 });
2495 }
2496
generateColorBufferVkImageCreateInfo(VkFormat format,uint32_t width,uint32_t height,VkImageTiling tiling)2497 std::unique_ptr<VkImageCreateInfo> VkEmulation::generateColorBufferVkImageCreateInfo(
2498 VkFormat format, uint32_t width, uint32_t height, VkImageTiling tiling) {
2499 std::lock_guard<std::mutex> lock(mMutex);
2500 return generateColorBufferVkImageCreateInfoLocked(format, width, height, tiling);
2501 }
2502
updateMemReqsForExtMem(std::optional<ExternalHandleInfo> extMemHandleInfo,VkMemoryRequirements * pMemReqs)2503 bool VkEmulation::updateMemReqsForExtMem(std::optional<ExternalHandleInfo> extMemHandleInfo,
2504 VkMemoryRequirements* pMemReqs) {
2505 #if defined(__QNX__)
2506 if (STREAM_HANDLE_TYPE_PLATFORM_SCREEN_BUFFER_QNX == extMemHandleInfo->streamHandleType) {
2507 VkScreenBufferPropertiesQNX screenBufferProps = {
2508 VK_STRUCTURE_TYPE_SCREEN_BUFFER_PROPERTIES_QNX,
2509 0,
2510 };
2511 VkResult queryRes = dvk->vkGetScreenBufferPropertiesQNX(
2512 device, (screen_buffer_t)extMemHandleInfo->handle, &screenBufferProps);
2513 if (VK_SUCCESS != queryRes) {
2514 ERR("Failed to get QNX Screen Buffer properties, VK error: %s",
2515 string_VkResult(queryRes));
2516 return false;
2517 }
2518 if (screenBufferProps.allocationSize < pMemReqs->size) {
2519 ERR("QNX Screen buffer allocationSize (0x%lx) is not large enough for ColorBuffer "
2520 "image "
2521 "size requirements (0x%lx)",
2522 screenBufferProps.allocationSize, pMemReqs->size);
2523 return false;
2524 }
2525 // Change memory requirements to the actual allocationSize; this may be larger
2526 // than the original memory requirements
2527 pMemReqs->size = screenBufferProps.allocationSize;
2528 // Mask the memoryTypeBits with the ones available for screen_buffer import
2529 pMemReqs->memoryTypeBits = screenBufferProps.memoryTypeBits;
2530 }
2531 #endif
2532
2533 return true;
2534 }
2535
2536 // TODO(liyl): Currently we can only specify required memoryProperty
2537 // and initial layout for a color buffer.
2538 //
2539 // Ideally we would like to specify a memory type index directly from
2540 // localAllocInfo.memoryTypeIndex when allocating color buffers in
2541 // vkAllocateMemory(). But this type index mechanism breaks "Modify the
2542 // allocation size and type index to suit the resulting image memory
2543 // size." which seems to be needed to keep the Android/Fuchsia guest
2544 // memory type index consistent across guest allocations, and without
2545 // which those guests might end up import allocating from a color buffer
2546 // with mismatched type indices.
2547 //
2548 // We should make it so the guest can only allocate external images/
2549 // buffers of one type index for image and one type index for buffer
2550 // to begin with, via filtering from the host.
2551
createVkColorBufferLocked(uint32_t width,uint32_t height,GLenum internalFormat,FrameworkFormat frameworkFormat,uint32_t colorBufferHandle,bool vulkanOnly,uint32_t memoryProperty)2552 bool VkEmulation::createVkColorBufferLocked(uint32_t width, uint32_t height, GLenum internalFormat,
2553 FrameworkFormat frameworkFormat,
2554 uint32_t colorBufferHandle, bool vulkanOnly,
2555 uint32_t memoryProperty) {
2556 if (!isFormatVulkanCompatible(internalFormat)) {
2557 ERR("Failed to create Vk ColorBuffer: format:%d not compatible.", internalFormat);
2558 return false;
2559 }
2560
2561 // Check the ExternalObjectManager for an external memory handle provided for import
2562 auto extMemHandleInfo =
2563 ExternalObjectManager::get()->removeResourceExternalHandleInfo(colorBufferHandle);
2564 if (extMemHandleInfo && !mDeviceInfo.supportsExternalMemoryImport) {
2565 ERR("Failed to initialize Vk ColorBuffer -- extMemHandleInfo provided, but device does "
2566 "not support externalMemoryImport");
2567 return false;
2568 }
2569
2570 VkEmulation::ColorBufferInfo res;
2571
2572 res.handle = colorBufferHandle;
2573 res.width = width;
2574 res.height = height;
2575 res.memoryProperty = memoryProperty;
2576 res.internalFormat = internalFormat;
2577 res.frameworkFormat = frameworkFormat;
2578 res.frameworkStride = 0;
2579
2580 if (vulkanOnly) {
2581 res.vulkanMode = VkEmulation::VulkanMode::VulkanOnly;
2582 }
2583
2584 mColorBuffers[colorBufferHandle] = res;
2585 auto infoPtr = &mColorBuffers[colorBufferHandle];
2586
2587 VkFormat vkFormat;
2588 switch (infoPtr->frameworkFormat) {
2589 case FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE:
2590 vkFormat = glFormat2VkFormat(infoPtr->internalFormat);
2591 break;
2592 case FrameworkFormat::FRAMEWORK_FORMAT_NV12:
2593 vkFormat = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
2594 break;
2595 case FrameworkFormat::FRAMEWORK_FORMAT_P010:
2596 vkFormat = VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16;
2597 break;
2598 case FrameworkFormat::FRAMEWORK_FORMAT_YV12:
2599 case FrameworkFormat::FRAMEWORK_FORMAT_YUV_420_888:
2600 vkFormat = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
2601 break;
2602 default:
2603 ERR("WARNING: unhandled framework format %d\n", infoPtr->frameworkFormat);
2604 vkFormat = glFormat2VkFormat(infoPtr->internalFormat);
2605 break;
2606 }
2607
2608 VkImageTiling tiling = (infoPtr->memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT)
2609 ? VK_IMAGE_TILING_LINEAR
2610 : VK_IMAGE_TILING_OPTIMAL;
2611 std::unique_ptr<VkImageCreateInfo> imageCi = generateColorBufferVkImageCreateInfoLocked(
2612 vkFormat, infoPtr->width, infoPtr->height, tiling);
2613 // pNext will be filled later.
2614 if (imageCi == nullptr) {
2615 // it can happen if the format is not supported
2616 return false;
2617 }
2618 imageCi->sharingMode = VK_SHARING_MODE_EXCLUSIVE;
2619 imageCi->queueFamilyIndexCount = 0;
2620 imageCi->pQueueFamilyIndices = nullptr;
2621 imageCi->initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
2622
2623 // Create the image. If external memory is supported, make it external.
2624 VkExternalMemoryImageCreateInfo extImageCi = {
2625 VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO,
2626 0,
2627 static_cast<VkExternalMemoryHandleTypeFlags>(getDefaultExternalMemoryHandleType()),
2628 };
2629 #if defined(__APPLE__)
2630 if (mInstanceSupportsMoltenVK) {
2631 // Using a different handle type when in MoltenVK mode
2632 extImageCi.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
2633 }
2634 #endif
2635
2636 VkExternalMemoryImageCreateInfo* extImageCiPtr = nullptr;
2637
2638 if (extMemHandleInfo || mDeviceInfo.supportsExternalMemoryExport) {
2639 extImageCiPtr = &extImageCi;
2640 }
2641
2642 imageCi->pNext = extImageCiPtr;
2643
2644 auto vk = mDvk;
2645
2646 VkResult createRes = vk->vkCreateImage(mDevice, imageCi.get(), nullptr, &infoPtr->image);
2647 if (createRes != VK_SUCCESS) {
2648 VERBOSE("Failed to create Vulkan image for ColorBuffer %d, error: %s", colorBufferHandle,
2649 string_VkResult(createRes));
2650 return false;
2651 }
2652
2653 bool useDedicated = mUseDedicatedAllocations;
2654
2655 infoPtr->imageCreateInfoShallow = vk_make_orphan_copy(*imageCi);
2656 infoPtr->currentQueueFamilyIndex = mQueueFamilyIndex;
2657
2658 VkMemoryRequirements memReqs;
2659 if (!useDedicated && vk->vkGetImageMemoryRequirements2KHR) {
2660 VkMemoryDedicatedRequirements dedicated_reqs{
2661 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, nullptr};
2662 VkMemoryRequirements2 reqs{VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &dedicated_reqs};
2663
2664 VkImageMemoryRequirementsInfo2 info{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
2665 nullptr, infoPtr->image};
2666 vk->vkGetImageMemoryRequirements2KHR(mDevice, &info, &reqs);
2667 useDedicated = dedicated_reqs.requiresDedicatedAllocation;
2668 memReqs = reqs.memoryRequirements;
2669 } else {
2670 vk->vkGetImageMemoryRequirements(mDevice, infoPtr->image, &memReqs);
2671 }
2672
2673 if (extMemHandleInfo) {
2674 infoPtr->memory.handleInfo = extMemHandleInfo;
2675 infoPtr->memory.dedicatedAllocation = true;
2676 // External memory might change the memReqs for allocation
2677 if (!updateMemReqsForExtMem(extMemHandleInfo, &memReqs)) {
2678 ERR("Failed to update memReqs for ColorBuffer memory allocation with external memory: "
2679 "%d\n",
2680 colorBufferHandle);
2681 return false;
2682 }
2683 #if defined(__APPLE_)
2684 // importExtMemoryHandleToVkColorBuffer is not supported with MoltenVK
2685 if (mInstanceSupportsMoltenVK) {
2686 WARN("extMemhandleInfo import in ColorBuffer creation is unexpected.");
2687 infoPtr->memory.externalMetalHandle = nullptr;
2688 }
2689 #endif
2690 }
2691
2692 // Currently we only care about two memory properties: DEVICE_LOCAL
2693 // and HOST_VISIBLE; other memory properties specified in
2694 // rcSetColorBufferVulkanMode2() call will be ignored for now.
2695 infoPtr->memoryProperty = infoPtr->memoryProperty & (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT |
2696 VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
2697
2698 infoPtr->memory.size = memReqs.size;
2699
2700 // Determine memory type.
2701 infoPtr->memory.typeIndex =
2702 getValidMemoryTypeIndex(memReqs.memoryTypeBits, infoPtr->memoryProperty);
2703
2704 const VkFormat imageVkFormat = infoPtr->imageCreateInfoShallow.format;
2705 VERBOSE(
2706 "ColorBuffer %u, %ux%u, %s, "
2707 "Memory [size: %llu, type: %d, props: %u / %u]",
2708 colorBufferHandle, infoPtr->width, infoPtr->height, string_VkFormat(imageVkFormat),
2709 infoPtr->memory.size, infoPtr->memory.typeIndex,
2710 mDeviceInfo.memProps.memoryTypes[infoPtr->memory.typeIndex].propertyFlags,
2711 infoPtr->memoryProperty);
2712
2713 const bool isHostVisible = (infoPtr->memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
2714 Optional<uint64_t> deviceAlignment =
2715 (!extMemHandleInfo && isHostVisible) ? Optional<uint64_t>(memReqs.alignment) : kNullopt;
2716 Optional<VkImage> dedicatedImage = useDedicated ? Optional<VkImage>(infoPtr->image) : kNullopt;
2717 if (extMemHandleInfo) {
2718 VkMemoryDedicatedAllocateInfo dedicatedInfo = {
2719 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO,
2720 nullptr,
2721 VK_NULL_HANDLE,
2722 VK_NULL_HANDLE,
2723 };
2724 VkMemoryDedicatedAllocateInfo* dedicatedInfoPtr = nullptr;
2725 if (useDedicated) {
2726 dedicatedInfo.image = *dedicatedImage;
2727 dedicatedInfoPtr = &dedicatedInfo;
2728 }
2729 if (!importExternalMemory(vk, mDevice, &infoPtr->memory, dedicatedInfoPtr,
2730 &infoPtr->memory.memory)) {
2731 ERR("Failed to import external memory%s for colorBuffer: %d\n",
2732 dedicatedInfoPtr ? " (dedicated)" : "", colorBufferHandle);
2733 return false;
2734 }
2735
2736 infoPtr->externalMemoryCompatible = true;
2737 } else {
2738 bool allocRes = allocExternalMemory(vk, &infoPtr->memory, true /*actuallyExternal*/,
2739 deviceAlignment, kNullopt, dedicatedImage);
2740 if (!allocRes) {
2741 ERR("Failed to allocate ColorBuffer with Vulkan backing.");
2742 return false;
2743 }
2744
2745 infoPtr->externalMemoryCompatible = mDeviceInfo.supportsExternalMemoryExport;
2746 }
2747
2748 infoPtr->memory.pageOffset = reinterpret_cast<uint64_t>(infoPtr->memory.mappedPtr) % kPageSize;
2749 if (deviceAlignment.hasValue()) {
2750 infoPtr->memory.bindOffset =
2751 infoPtr->memory.pageOffset ? kPageSize - infoPtr->memory.pageOffset : 0u;
2752 } else {
2753 // Allocated as aligned..
2754 infoPtr->memory.bindOffset = 0;
2755 }
2756
2757 VkResult bindImageMemoryRes = vk->vkBindImageMemory(
2758 mDevice, infoPtr->image, infoPtr->memory.memory, infoPtr->memory.bindOffset);
2759
2760 if (bindImageMemoryRes != VK_SUCCESS) {
2761 ERR("Failed to bind image memory. Error: %s", string_VkResult(bindImageMemoryRes));
2762 return false;
2763 }
2764
2765 VkSamplerYcbcrConversionInfo ycbcrInfo = {VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_INFO,
2766 nullptr, VK_NULL_HANDLE};
2767 const bool addConversion = formatRequiresYcbcrConversion(imageVkFormat);
2768 if (addConversion) {
2769 if (!mDeviceInfo.supportsSamplerYcbcrConversion) {
2770 ERR("VkFormat: %d requires conversion, but device does not have required extension "
2771 " for conversion (%s)",
2772 imageVkFormat, VK_KHR_SAMPLER_YCBCR_CONVERSION_EXTENSION_NAME);
2773 return false;
2774 }
2775 VkSamplerYcbcrConversionCreateInfo ycbcrCreateInfo = {
2776 VK_STRUCTURE_TYPE_SAMPLER_YCBCR_CONVERSION_CREATE_INFO,
2777 nullptr,
2778 imageVkFormat,
2779 VK_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY,
2780 VK_SAMPLER_YCBCR_RANGE_ITU_FULL,
2781 {VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
2782 VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY},
2783 VK_CHROMA_LOCATION_MIDPOINT,
2784 VK_CHROMA_LOCATION_MIDPOINT,
2785 VK_FILTER_NEAREST,
2786 VK_FALSE};
2787
2788 createRes = vk->vkCreateSamplerYcbcrConversion(mDevice, &ycbcrCreateInfo, nullptr,
2789 &infoPtr->ycbcrConversion);
2790 if (createRes != VK_SUCCESS) {
2791 VERBOSE(
2792 "Failed to create Vulkan ycbcrConversion for ColorBuffer %d with format %s [%d], "
2793 "Error: %s",
2794 colorBufferHandle, string_VkFormat(imageVkFormat), imageVkFormat,
2795 string_VkResult(createRes));
2796 return false;
2797 }
2798 ycbcrInfo.conversion = infoPtr->ycbcrConversion;
2799 }
2800
2801 const VkImageViewCreateInfo imageViewCi = {
2802 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
2803 .pNext = addConversion ? &ycbcrInfo : nullptr,
2804 .flags = 0,
2805 .image = infoPtr->image,
2806 .viewType = VK_IMAGE_VIEW_TYPE_2D,
2807 .format = imageVkFormat,
2808 .components =
2809 {
2810 .r = VK_COMPONENT_SWIZZLE_IDENTITY,
2811 .g = VK_COMPONENT_SWIZZLE_IDENTITY,
2812 .b = VK_COMPONENT_SWIZZLE_IDENTITY,
2813 .a = VK_COMPONENT_SWIZZLE_IDENTITY,
2814 },
2815 .subresourceRange =
2816 {
2817 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
2818 .baseMipLevel = 0,
2819 .levelCount = 1,
2820 .baseArrayLayer = 0,
2821 .layerCount = 1,
2822 },
2823 };
2824 createRes = vk->vkCreateImageView(mDevice, &imageViewCi, nullptr, &infoPtr->imageView);
2825 if (createRes != VK_SUCCESS) {
2826 VERBOSE("Failed to create Vulkan image view for ColorBuffer %d, Error: %s",
2827 colorBufferHandle, string_VkResult(createRes));
2828 return false;
2829 }
2830
2831 mDebugUtilsHelper.addDebugLabel(infoPtr->image, "ColorBuffer:%d", colorBufferHandle);
2832 mDebugUtilsHelper.addDebugLabel(infoPtr->imageView, "ColorBuffer:%d", colorBufferHandle);
2833 mDebugUtilsHelper.addDebugLabel(infoPtr->memory.memory, "ColorBuffer:%d", colorBufferHandle);
2834
2835 infoPtr->initialized = true;
2836
2837 return true;
2838 }
2839
isFormatSupported(GLenum format)2840 bool VkEmulation::isFormatSupported(GLenum format) {
2841 VkFormat vkFormat = glFormat2VkFormat(format);
2842 bool supported = !gfxstream::vk::formatIsDepthOrStencil(vkFormat);
2843 // TODO(b/356603558): add proper Vulkan querying, for now preserve existing assumption
2844 if (!supported) {
2845 for (size_t i = 0; i < mImageSupportInfo.size(); ++i) {
2846 // Only enable depth/stencil if it is usable as an attachment
2847 if (mImageSupportInfo[i].format == vkFormat &&
2848 gfxstream::vk::formatIsDepthOrStencil(mImageSupportInfo[i].format) &&
2849 mImageSupportInfo[i].supported &&
2850 mImageSupportInfo[i].formatProps2.formatProperties.optimalTilingFeatures &
2851 VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT) {
2852 supported = true;
2853 }
2854 }
2855 }
2856 return supported;
2857 }
2858
createVkColorBuffer(uint32_t width,uint32_t height,GLenum internalFormat,FrameworkFormat frameworkFormat,uint32_t colorBufferHandle,bool vulkanOnly,uint32_t memoryProperty)2859 bool VkEmulation::createVkColorBuffer(uint32_t width, uint32_t height, GLenum internalFormat,
2860 FrameworkFormat frameworkFormat, uint32_t colorBufferHandle,
2861 bool vulkanOnly, uint32_t memoryProperty) {
2862 std::lock_guard<std::mutex> lock(mMutex);
2863 auto infoPtr = android::base::find(mColorBuffers, colorBufferHandle);
2864 if (infoPtr) {
2865 VERBOSE("ColorBuffer already exists for handle: %d", colorBufferHandle);
2866 return false;
2867 }
2868
2869 return createVkColorBufferLocked(width, height, internalFormat, frameworkFormat,
2870 colorBufferHandle, vulkanOnly, memoryProperty);
2871 }
2872
exportColorBufferMemory(uint32_t colorBufferHandle)2873 std::optional<VkEmulation::VkColorBufferMemoryExport> VkEmulation::exportColorBufferMemory(
2874 uint32_t colorBufferHandle) {
2875 std::lock_guard<std::mutex> lock(mMutex);
2876
2877 if (!mDeviceInfo.supportsExternalMemoryExport && mDeviceInfo.supportsExternalMemoryImport) {
2878 return std::nullopt;
2879 }
2880
2881 auto info = android::base::find(mColorBuffers, colorBufferHandle);
2882 if (!info) {
2883 return std::nullopt;
2884 }
2885
2886 if ((info->vulkanMode != VkEmulation::VulkanMode::VulkanOnly) &&
2887 !mDeviceInfo.glInteropSupported) {
2888 return std::nullopt;
2889 }
2890
2891 if (info->frameworkFormat != FRAMEWORK_FORMAT_GL_COMPATIBLE) {
2892 return std::nullopt;
2893 }
2894
2895 auto handleInfo = info->memory.handleInfo;
2896 if (!handleInfo) {
2897 ERR("Could not export ColorBuffer memory, no external handle info available");
2898 return std::nullopt;
2899 }
2900
2901 auto dupHandle = dupExternalMemory(handleInfo);
2902 if (!dupHandle) {
2903 ERR("Could not dup external memory handle: 0x%x, with handleType: %d", handleInfo->handle,
2904 handleInfo->streamHandleType);
2905 return std::nullopt;
2906 }
2907
2908 info->glExported = true;
2909
2910 return VkColorBufferMemoryExport{
2911 .handleInfo = *dupHandle,
2912 .size = info->memory.size,
2913 .linearTiling = info->imageCreateInfoShallow.tiling == VK_IMAGE_TILING_LINEAR,
2914 .dedicatedAllocation = info->memory.dedicatedAllocation,
2915 };
2916 }
2917
teardownVkColorBufferLocked(uint32_t colorBufferHandle)2918 bool VkEmulation::teardownVkColorBufferLocked(uint32_t colorBufferHandle) {
2919 auto vk = mDvk;
2920
2921 auto infoPtr = android::base::find(mColorBuffers, colorBufferHandle);
2922
2923 if (!infoPtr) return false;
2924
2925 if (infoPtr->initialized) {
2926 auto& info = *infoPtr;
2927 {
2928 android::base::AutoLock queueLock(*mQueueLock);
2929 VK_CHECK(vk->vkQueueWaitIdle(mQueue));
2930 }
2931 vk->vkDestroyImageView(mDevice, info.imageView, nullptr);
2932 if (mDeviceInfo.hasSamplerYcbcrConversionExtension) {
2933 vk->vkDestroySamplerYcbcrConversion(mDevice, info.ycbcrConversion, nullptr);
2934 }
2935 vk->vkDestroyImage(mDevice, info.image, nullptr);
2936 freeExternalMemoryLocked(vk, &info.memory);
2937 }
2938
2939 mColorBuffers.erase(colorBufferHandle);
2940
2941 return true;
2942 }
2943
teardownVkColorBuffer(uint32_t colorBufferHandle)2944 bool VkEmulation::teardownVkColorBuffer(uint32_t colorBufferHandle) {
2945 std::lock_guard<std::mutex> lock(mMutex);
2946 return teardownVkColorBufferLocked(colorBufferHandle);
2947 }
2948
getColorBufferInfo(uint32_t colorBufferHandle)2949 std::optional<VkEmulation::ColorBufferInfo> VkEmulation::getColorBufferInfo(
2950 uint32_t colorBufferHandle) {
2951 std::lock_guard<std::mutex> lock(mMutex);
2952
2953 auto infoPtr = android::base::find(mColorBuffers, colorBufferHandle);
2954 if (!infoPtr) {
2955 return std::nullopt;
2956 }
2957
2958 return *infoPtr;
2959 }
2960
colorBufferNeedsUpdateBetweenGlAndVk(const VkEmulation::ColorBufferInfo & colorBufferInfo)2961 bool VkEmulation::colorBufferNeedsUpdateBetweenGlAndVk(
2962 const VkEmulation::ColorBufferInfo& colorBufferInfo) {
2963 // GL is not used.
2964 if (colorBufferInfo.vulkanMode == VkEmulation::VulkanMode::VulkanOnly) {
2965 return false;
2966 }
2967
2968 // YUV formats require extra conversions.
2969 if (colorBufferInfo.frameworkFormat != FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE) {
2970 return true;
2971 }
2972
2973 // GL and VK are sharing the same underlying memory.
2974 if (colorBufferInfo.glExported) {
2975 return false;
2976 }
2977
2978 return true;
2979 }
2980
colorBufferNeedsUpdateBetweenGlAndVk(uint32_t colorBufferHandle)2981 bool VkEmulation::colorBufferNeedsUpdateBetweenGlAndVk(uint32_t colorBufferHandle) {
2982 std::lock_guard<std::mutex> lock(mMutex);
2983
2984 auto colorBufferInfo = android::base::find(mColorBuffers, colorBufferHandle);
2985 if (!colorBufferInfo) {
2986 return false;
2987 }
2988
2989 return colorBufferNeedsUpdateBetweenGlAndVk(*colorBufferInfo);
2990 }
2991
readColorBufferToBytes(uint32_t colorBufferHandle,std::vector<uint8_t> * bytes)2992 bool VkEmulation::readColorBufferToBytes(uint32_t colorBufferHandle, std::vector<uint8_t>* bytes) {
2993 std::lock_guard<std::mutex> lock(mMutex);
2994
2995 auto colorBufferInfo = android::base::find(mColorBuffers, colorBufferHandle);
2996 if (!colorBufferInfo) {
2997 VERBOSE("Failed to read from ColorBuffer:%d, not found.", colorBufferHandle);
2998 bytes->clear();
2999 return false;
3000 }
3001
3002 VkDeviceSize bytesNeeded = 0;
3003 bool result = getFormatTransferInfo(colorBufferInfo->imageCreateInfoShallow.format,
3004 colorBufferInfo->imageCreateInfoShallow.extent.width,
3005 colorBufferInfo->imageCreateInfoShallow.extent.height,
3006 &bytesNeeded, nullptr);
3007 if (!result) {
3008 ERR("Failed to read from ColorBuffer:%d, failed to get read size.", colorBufferHandle);
3009 return false;
3010 }
3011
3012 bytes->resize(bytesNeeded);
3013
3014 result = readColorBufferToBytesLocked(
3015 colorBufferHandle, 0, 0, colorBufferInfo->imageCreateInfoShallow.extent.width,
3016 colorBufferInfo->imageCreateInfoShallow.extent.height, bytes->data(), bytes->size());
3017 if (!result) {
3018 ERR("Failed to read from ColorBuffer:%d, failed to get read size.", colorBufferHandle);
3019 return false;
3020 }
3021
3022 return true;
3023 }
3024
readColorBufferToBytes(uint32_t colorBufferHandle,uint32_t x,uint32_t y,uint32_t w,uint32_t h,void * outPixels,uint64_t outPixelsSize)3025 bool VkEmulation::readColorBufferToBytes(uint32_t colorBufferHandle, uint32_t x, uint32_t y,
3026 uint32_t w, uint32_t h, void* outPixels,
3027 uint64_t outPixelsSize) {
3028 std::lock_guard<std::mutex> lock(mMutex);
3029 return readColorBufferToBytesLocked(colorBufferHandle, x, y, w, h, outPixels, outPixelsSize);
3030 }
3031
readColorBufferToBytesLocked(uint32_t colorBufferHandle,uint32_t x,uint32_t y,uint32_t w,uint32_t h,void * outPixels,uint64_t outPixelsSize)3032 bool VkEmulation::readColorBufferToBytesLocked(uint32_t colorBufferHandle, uint32_t x, uint32_t y,
3033 uint32_t w, uint32_t h, void* outPixels,
3034 uint64_t outPixelsSize) {
3035 auto vk = mDvk;
3036
3037 auto colorBufferInfo = android::base::find(mColorBuffers, colorBufferHandle);
3038 if (!colorBufferInfo) {
3039 ERR("Failed to read from ColorBuffer:%d, not found.", colorBufferHandle);
3040 return false;
3041 }
3042
3043 if (!colorBufferInfo->image) {
3044 ERR("Failed to read from ColorBuffer:%d, no VkImage.", colorBufferHandle);
3045 return false;
3046 }
3047
3048 if (x != 0 || y != 0 || w != colorBufferInfo->imageCreateInfoShallow.extent.width ||
3049 h != colorBufferInfo->imageCreateInfoShallow.extent.height) {
3050 ERR("Failed to read from ColorBuffer:%d, unhandled subrect.", colorBufferHandle);
3051 return false;
3052 }
3053
3054 VkDeviceSize bufferCopySize = 0;
3055 std::vector<VkBufferImageCopy> bufferImageCopies;
3056 if (!getFormatTransferInfo(colorBufferInfo->imageCreateInfoShallow.format,
3057 colorBufferInfo->imageCreateInfoShallow.extent.width,
3058 colorBufferInfo->imageCreateInfoShallow.extent.height,
3059 &bufferCopySize, &bufferImageCopies)) {
3060 ERR("Failed to read ColorBuffer:%d, unable to get transfer info.", colorBufferHandle);
3061 return false;
3062 }
3063
3064 // Avoid transitioning from VK_IMAGE_LAYOUT_UNDEFINED. Unfortunetly, Android does not
3065 // yet have a mechanism for sharing the expected VkImageLayout. However, the Vulkan
3066 // spec's image layout transition sections says "If the old layout is
3067 // VK_IMAGE_LAYOUT_UNDEFINED, the contents of that range may be discarded." Some
3068 // Vulkan drivers have been observed to actually perform the discard which leads to
3069 // ColorBuffer-s being unintentionally cleared. See go/ahb-vkimagelayout for a more
3070 // thorough write up.
3071 if (colorBufferInfo->currentLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
3072 colorBufferInfo->currentLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
3073 }
3074
3075 // Record our synchronization commands.
3076 const VkCommandBufferBeginInfo beginInfo = {
3077 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
3078 .pNext = nullptr,
3079 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
3080 };
3081 VK_CHECK(vk->vkBeginCommandBuffer(mCommandBuffer, &beginInfo));
3082
3083 mDebugUtilsHelper.cmdBeginDebugLabel(mCommandBuffer, "readColorBufferToBytes(ColorBuffer:%d)",
3084 colorBufferHandle);
3085
3086 VkImageLayout currentLayout = colorBufferInfo->currentLayout;
3087 VkImageLayout transferSrcLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
3088
3089 const VkImageMemoryBarrier toTransferSrcImageBarrier = {
3090 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
3091 .pNext = nullptr,
3092 .srcAccessMask = 0,
3093 .dstAccessMask = VK_ACCESS_HOST_READ_BIT,
3094 .oldLayout = currentLayout,
3095 .newLayout = transferSrcLayout,
3096 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3097 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3098 .image = colorBufferInfo->image,
3099 .subresourceRange =
3100 {
3101 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
3102 .baseMipLevel = 0,
3103 .levelCount = 1,
3104 .baseArrayLayer = 0,
3105 .layerCount = 1,
3106 },
3107 };
3108
3109 vk->vkCmdPipelineBarrier(mCommandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
3110 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
3111 &toTransferSrcImageBarrier);
3112
3113 vk->vkCmdCopyImageToBuffer(mCommandBuffer, colorBufferInfo->image,
3114 VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, mStaging.buffer,
3115 bufferImageCopies.size(), bufferImageCopies.data());
3116
3117 // Change back to original layout
3118 if (currentLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
3119 // Transfer back to original layout.
3120 const VkImageMemoryBarrier toCurrentLayoutImageBarrier = {
3121 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
3122 .pNext = nullptr,
3123 .srcAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
3124 .dstAccessMask = VK_ACCESS_NONE_KHR,
3125 .oldLayout = transferSrcLayout,
3126 .newLayout = colorBufferInfo->currentLayout,
3127 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3128 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3129 .image = colorBufferInfo->image,
3130 .subresourceRange =
3131 {
3132 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
3133 .baseMipLevel = 0,
3134 .levelCount = 1,
3135 .baseArrayLayer = 0,
3136 .layerCount = 1,
3137 },
3138 };
3139 vk->vkCmdPipelineBarrier(mCommandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
3140 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
3141 &toCurrentLayoutImageBarrier);
3142 } else {
3143 colorBufferInfo->currentLayout = transferSrcLayout;
3144 }
3145
3146 mDebugUtilsHelper.cmdEndDebugLabel(mCommandBuffer);
3147
3148 VK_CHECK(vk->vkEndCommandBuffer(mCommandBuffer));
3149
3150 const VkSubmitInfo submitInfo = {
3151 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3152 .pNext = nullptr,
3153 .waitSemaphoreCount = 0,
3154 .pWaitSemaphores = nullptr,
3155 .pWaitDstStageMask = nullptr,
3156 .commandBufferCount = 1,
3157 .pCommandBuffers = &mCommandBuffer,
3158 .signalSemaphoreCount = 0,
3159 .pSignalSemaphores = nullptr,
3160 };
3161
3162 {
3163 android::base::AutoLock queueLock(*mQueueLock);
3164 VK_CHECK(vk->vkQueueSubmit(mQueue, 1, &submitInfo, mCommandBufferFence));
3165 }
3166
3167 static constexpr uint64_t ANB_MAX_WAIT_NS = 5ULL * 1000ULL * 1000ULL * 1000ULL;
3168 VkResult waitRes =
3169 vk->vkWaitForFences(mDevice, 1, &mCommandBufferFence, VK_TRUE, ANB_MAX_WAIT_NS);
3170 if (waitRes == VK_TIMEOUT) {
3171 // Give a warning and try once more on a timeout error
3172 ERR("readColorBufferToBytesLocked vkWaitForFences failed with timeout error "
3173 "(cb:%d, x:%d, y:%d, w:%d, h:%d, bufferCopySize:%llu), retrying...",
3174 colorBufferHandle, x, y, w, h, bufferCopySize);
3175 waitRes =
3176 vk->vkWaitForFences(mDevice, 1, &mCommandBufferFence, VK_TRUE, ANB_MAX_WAIT_NS * 2);
3177 }
3178
3179 VK_CHECK(waitRes);
3180
3181 VK_CHECK(vk->vkResetFences(mDevice, 1, &mCommandBufferFence));
3182
3183 const VkMappedMemoryRange toInvalidate = {
3184 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3185 .pNext = nullptr,
3186 .memory = mStaging.memory.memory,
3187 .offset = 0,
3188 .size = VK_WHOLE_SIZE,
3189 };
3190
3191 VK_CHECK(vk->vkInvalidateMappedMemoryRanges(mDevice, 1, &toInvalidate));
3192
3193 const auto* stagingBufferPtr = mStaging.memory.mappedPtr;
3194 if (bufferCopySize > outPixelsSize) {
3195 ERR("Invalid buffer size for readColorBufferToBytes operation."
3196 "Required: %llu, Actual: %llu",
3197 bufferCopySize, outPixelsSize);
3198 bufferCopySize = outPixelsSize;
3199 }
3200 std::memcpy(outPixels, stagingBufferPtr, bufferCopySize);
3201
3202 return true;
3203 }
3204
updateColorBufferFromBytes(uint32_t colorBufferHandle,const std::vector<uint8_t> & bytes)3205 bool VkEmulation::updateColorBufferFromBytes(uint32_t colorBufferHandle,
3206 const std::vector<uint8_t>& bytes) {
3207 std::lock_guard<std::mutex> lock(mMutex);
3208
3209 auto colorBufferInfo = android::base::find(mColorBuffers, colorBufferHandle);
3210 if (!colorBufferInfo) {
3211 VERBOSE("Failed to update ColorBuffer:%d, not found.", colorBufferHandle);
3212 return false;
3213 }
3214
3215 return updateColorBufferFromBytesLocked(
3216 colorBufferHandle, 0, 0, colorBufferInfo->imageCreateInfoShallow.extent.width,
3217 colorBufferInfo->imageCreateInfoShallow.extent.height, bytes.data(), bytes.size());
3218 }
3219
updateColorBufferFromBytes(uint32_t colorBufferHandle,uint32_t x,uint32_t y,uint32_t w,uint32_t h,const void * pixels)3220 bool VkEmulation::updateColorBufferFromBytes(uint32_t colorBufferHandle, uint32_t x, uint32_t y,
3221 uint32_t w, uint32_t h, const void* pixels) {
3222 std::lock_guard<std::mutex> lock(mMutex);
3223 return updateColorBufferFromBytesLocked(colorBufferHandle, x, y, w, h, pixels, 0);
3224 }
3225
convertRgbToRgbaPixels(void * dst,const void * src,uint32_t w,uint32_t h)3226 static void convertRgbToRgbaPixels(void* dst, const void* src, uint32_t w, uint32_t h) {
3227 const size_t pixelCount = w * h;
3228 const uint8_t* srcBytes = reinterpret_cast<const uint8_t*>(src);
3229 uint32_t* dstPixels = reinterpret_cast<uint32_t*>(dst);
3230 for (size_t i = 0; i < pixelCount; ++i) {
3231 const uint8_t r = *(srcBytes++);
3232 const uint8_t g = *(srcBytes++);
3233 const uint8_t b = *(srcBytes++);
3234 *(dstPixels++) = 0xff000000 | (b << 16) | (g << 8) | r;
3235 }
3236 }
3237
convertRgba4ToBGRA4Pixels(void * dst,const void * src,uint32_t w,uint32_t h)3238 static void convertRgba4ToBGRA4Pixels(void* dst, const void* src, uint32_t w, uint32_t h) {
3239 const size_t pixelCount = w * h;
3240 const uint16_t* srcPixels = reinterpret_cast<const uint16_t*>(src);
3241 uint16_t* dstPixels = reinterpret_cast<uint16_t*>(dst);
3242 for (size_t i = 0; i < pixelCount; ++i) {
3243 const uint16_t rgba4_pixel = srcPixels[i];
3244 const uint8_t red = (rgba4_pixel >> 12) & 0xF;
3245 const uint8_t green = (rgba4_pixel >> 8) & 0xF;
3246 const uint8_t blue = (rgba4_pixel >> 4) & 0xF;
3247 const uint8_t alpha = rgba4_pixel & 0xF;
3248 dstPixels[i] = (blue << 12) | (green << 8) | (red << 4) | alpha;
3249 }
3250 }
3251
updateColorBufferFromBytesLocked(uint32_t colorBufferHandle,uint32_t x,uint32_t y,uint32_t w,uint32_t h,const void * pixels,size_t inputPixelsSize)3252 bool VkEmulation::updateColorBufferFromBytesLocked(uint32_t colorBufferHandle, uint32_t x,
3253 uint32_t y, uint32_t w, uint32_t h,
3254 const void* pixels, size_t inputPixelsSize) {
3255 auto vk = mDvk;
3256
3257 auto colorBufferInfo = android::base::find(mColorBuffers, colorBufferHandle);
3258 if (!colorBufferInfo) {
3259 ERR("Failed to update ColorBuffer:%d, not found.", colorBufferHandle);
3260 return false;
3261 }
3262
3263 if (!colorBufferInfo->image) {
3264 ERR("Failed to update ColorBuffer:%d, no VkImage.", colorBufferHandle);
3265 return false;
3266 }
3267
3268 if (x != 0 || y != 0 || w != colorBufferInfo->imageCreateInfoShallow.extent.width ||
3269 h != colorBufferInfo->imageCreateInfoShallow.extent.height) {
3270 ERR("Failed to update ColorBuffer:%d, unhandled subrect.", colorBufferHandle);
3271 return false;
3272 }
3273
3274 const VkFormat creationFormat = colorBufferInfo->imageCreateInfoShallow.format;
3275 VkDeviceSize dstBufferSize = 0;
3276 std::vector<VkBufferImageCopy> bufferImageCopies;
3277 if (!getFormatTransferInfo(creationFormat,
3278 colorBufferInfo->imageCreateInfoShallow.extent.width,
3279 colorBufferInfo->imageCreateInfoShallow.extent.height,
3280 &dstBufferSize, &bufferImageCopies)) {
3281 ERR("Failed to update ColorBuffer:%d, unable to get transfer info.", colorBufferHandle);
3282 return false;
3283 }
3284
3285 const VkDeviceSize stagingBufferSize = mStaging.size;
3286 if (dstBufferSize > stagingBufferSize) {
3287 ERR("Failed to update ColorBuffer:%d, transfer size %" PRIu64
3288 " too large for staging buffer size:%" PRIu64 ".",
3289 colorBufferHandle, dstBufferSize, stagingBufferSize);
3290 return false;
3291 }
3292 const bool isRGBA4onBGRA4 = (colorBufferInfo->internalFormat == GL_RGBA4_OES) &&
3293 (creationFormat == VK_FORMAT_B4G4R4A4_UNORM_PACK16);
3294 const bool isThreeByteRgb =
3295 (colorBufferInfo->internalFormat == GL_RGB || colorBufferInfo->internalFormat == GL_RGB8);
3296 const size_t expectedInputSize = (isThreeByteRgb ? dstBufferSize / 4 * 3 : dstBufferSize);
3297
3298 if (inputPixelsSize != 0 && inputPixelsSize != expectedInputSize) {
3299 ERR("Unexpected contents size when trying to update ColorBuffer:%d, "
3300 "provided:%zu expected:%zu",
3301 colorBufferHandle, inputPixelsSize, expectedInputSize);
3302 return false;
3303 }
3304
3305 auto* stagingBufferPtr = mStaging.memory.mappedPtr;
3306
3307 if (isThreeByteRgb) {
3308 // Convert RGB to RGBA, since only for these types glFormat2VkFormat() makes
3309 // an incompatible choice of 4-byte backing VK_FORMAT_R8G8B8A8_UNORM.
3310 // b/281550953
3311 convertRgbToRgbaPixels(stagingBufferPtr, pixels, w, h);
3312 } else if(isRGBA4onBGRA4) {
3313 convertRgba4ToBGRA4Pixels(stagingBufferPtr, pixels, w, h);
3314 } else {
3315 std::memcpy(stagingBufferPtr, pixels, dstBufferSize);
3316 }
3317
3318 // NOTE: Host vulkan state might not know the correct layout of the
3319 // destination image, as guest grallocs are designed to be used by either
3320 // GL or Vulkan. Consequently, we typically avoid image transitions from
3321 // VK_IMAGE_LAYOUT_UNDEFINED as Vulkan spec allows the contents to be
3322 // discarded (and some drivers have been observed doing it). You can
3323 // check go/ahb-vkimagelayout for more information. But since this
3324 // function does not allow subrects (see above), it will write the
3325 // provided contents onto the entirety of the target buffer, meaning this
3326 // risk of discarding data should not impact anything.
3327
3328 // Record our synchronization commands.
3329 const VkCommandBufferBeginInfo beginInfo = {
3330 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
3331 .pNext = nullptr,
3332 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
3333 };
3334 VK_CHECK(vk->vkBeginCommandBuffer(mCommandBuffer, &beginInfo));
3335
3336 mDebugUtilsHelper.cmdBeginDebugLabel(
3337 mCommandBuffer, "updateColorBufferFromBytes(ColorBuffer:%d)", colorBufferHandle);
3338
3339 const bool isSnapshotLoad = VkDecoderGlobalState::get()->isSnapshotCurrentlyLoading();
3340 VkImageLayout currentLayout = colorBufferInfo->currentLayout;
3341 if (isSnapshotLoad) {
3342 currentLayout = VK_IMAGE_LAYOUT_UNDEFINED;
3343 }
3344 const VkImageMemoryBarrier toTransferDstImageBarrier = {
3345 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
3346 .pNext = nullptr,
3347 .srcAccessMask = 0,
3348 .dstAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
3349 .oldLayout = currentLayout,
3350 .newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3351 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3352 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3353 .image = colorBufferInfo->image,
3354 .subresourceRange =
3355 {
3356 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
3357 .baseMipLevel = 0,
3358 .levelCount = 1,
3359 .baseArrayLayer = 0,
3360 .layerCount = 1,
3361 },
3362 };
3363
3364 vk->vkCmdPipelineBarrier(mCommandBuffer, VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
3365 VK_PIPELINE_STAGE_HOST_BIT, 0, 0, nullptr, 0, nullptr, 1,
3366 &toTransferDstImageBarrier);
3367
3368 // Copy from staging buffer to color buffer image
3369 vk->vkCmdCopyBufferToImage(mCommandBuffer, mStaging.buffer, colorBufferInfo->image,
3370 VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, bufferImageCopies.size(),
3371 bufferImageCopies.data());
3372
3373 if (colorBufferInfo->currentLayout != VK_IMAGE_LAYOUT_UNDEFINED) {
3374 const VkImageMemoryBarrier toCurrentLayoutImageBarrier = {
3375 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
3376 .pNext = nullptr,
3377 .srcAccessMask = VK_ACCESS_HOST_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
3378 .dstAccessMask = VK_ACCESS_NONE_KHR,
3379 .oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
3380 .newLayout = colorBufferInfo->currentLayout,
3381 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3382 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
3383 .image = colorBufferInfo->image,
3384 .subresourceRange =
3385 {
3386 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
3387 .baseMipLevel = 0,
3388 .levelCount = 1,
3389 .baseArrayLayer = 0,
3390 .layerCount = 1,
3391 },
3392 };
3393 vk->vkCmdPipelineBarrier(mCommandBuffer, VK_PIPELINE_STAGE_HOST_BIT,
3394 VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, 0, 0, nullptr, 0, nullptr, 1,
3395 &toCurrentLayoutImageBarrier);
3396 } else {
3397 colorBufferInfo->currentLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
3398 }
3399
3400 mDebugUtilsHelper.cmdEndDebugLabel(mCommandBuffer);
3401
3402 VK_CHECK(vk->vkEndCommandBuffer(mCommandBuffer));
3403
3404 const VkSubmitInfo submitInfo = {
3405 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3406 .pNext = nullptr,
3407 .waitSemaphoreCount = 0,
3408 .pWaitSemaphores = nullptr,
3409 .pWaitDstStageMask = nullptr,
3410 .commandBufferCount = 1,
3411 .pCommandBuffers = &mCommandBuffer,
3412 .signalSemaphoreCount = 0,
3413 .pSignalSemaphores = nullptr,
3414 };
3415
3416 {
3417 android::base::AutoLock queueLock(*mQueueLock);
3418 VK_CHECK(vk->vkQueueSubmit(mQueue, 1, &submitInfo, mCommandBufferFence));
3419 }
3420
3421 static constexpr uint64_t ANB_MAX_WAIT_NS = 5ULL * 1000ULL * 1000ULL * 1000ULL;
3422 VK_CHECK(vk->vkWaitForFences(mDevice, 1, &mCommandBufferFence, VK_TRUE, ANB_MAX_WAIT_NS));
3423
3424 VK_CHECK(vk->vkResetFences(mDevice, 1, &mCommandBufferFence));
3425
3426 const VkMappedMemoryRange toInvalidate = {
3427 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3428 .pNext = nullptr,
3429 .memory = mStaging.memory.memory,
3430 .offset = 0,
3431 .size = VK_WHOLE_SIZE,
3432 };
3433 VK_CHECK(vk->vkInvalidateMappedMemoryRanges(mDevice, 1, &toInvalidate));
3434
3435 return true;
3436 }
3437
dupColorBufferExtMemoryHandle(uint32_t colorBufferHandle)3438 std::optional<ExternalHandleInfo> VkEmulation::dupColorBufferExtMemoryHandle(
3439 uint32_t colorBufferHandle) {
3440 std::lock_guard<std::mutex> lock(mMutex);
3441
3442 auto infoPtr = android::base::find(mColorBuffers, colorBufferHandle);
3443
3444 if (!infoPtr) {
3445 return std::nullopt;
3446 }
3447
3448 auto handleInfo = infoPtr->memory.handleInfo;
3449 if (!handleInfo) {
3450 ERR("Could not dup ColorBuffer external memory handle, no external handle info available");
3451 return std::nullopt;
3452 }
3453
3454 return dupExternalMemory(handleInfo);
3455 }
3456
3457 #ifdef __APPLE__
getColorBufferMetalMemoryHandle(uint32_t colorBuffer)3458 MTLResource_id VkEmulation::getColorBufferMetalMemoryHandle(uint32_t colorBuffer) {
3459 std::lock_guard<std::mutex> lock(mMutex);
3460
3461 auto infoPtr = android::base::find(mColorBuffers, colorBuffer);
3462
3463 if (!infoPtr) {
3464 // Color buffer not found; this is usually OK.
3465 return nullptr;
3466 }
3467
3468 return infoPtr->memory.externalMetalHandle;
3469 }
3470
3471 // TODO(b/351765838): Temporary function for MoltenVK
getColorBufferVkImage(uint32_t colorBufferHandle)3472 VkImage VkEmulation::getColorBufferVkImage(uint32_t colorBufferHandle) {
3473 std::lock_guard<std::mutex> lock(mMutex);
3474
3475 auto infoPtr = android::base::find(mColorBuffers, colorBufferHandle);
3476
3477 if (!infoPtr) {
3478 // Color buffer not found; this is usually OK.
3479 return nullptr;
3480 }
3481
3482 return infoPtr->image;
3483 }
3484 #endif // __APPLE__
3485
setColorBufferVulkanMode(uint32_t colorBuffer,uint32_t vulkanMode)3486 bool VkEmulation::setColorBufferVulkanMode(uint32_t colorBuffer, uint32_t vulkanMode) {
3487 std::lock_guard<std::mutex> lock(mMutex);
3488
3489 auto infoPtr = android::base::find(mColorBuffers, colorBuffer);
3490
3491 if (!infoPtr) {
3492 return false;
3493 }
3494
3495 infoPtr->vulkanMode = static_cast<VkEmulation::VulkanMode>(vulkanMode);
3496
3497 return true;
3498 }
3499
mapGpaToBufferHandle(uint32_t bufferHandle,uint64_t gpa,uint64_t size)3500 int32_t VkEmulation::mapGpaToBufferHandle(uint32_t bufferHandle, uint64_t gpa, uint64_t size) {
3501 std::lock_guard<std::mutex> lock(mMutex);
3502
3503 VkEmulation::ExternalMemoryInfo* memoryInfoPtr = nullptr;
3504
3505 auto colorBufferInfoPtr = android::base::find(mColorBuffers, bufferHandle);
3506 if (colorBufferInfoPtr) {
3507 memoryInfoPtr = &colorBufferInfoPtr->memory;
3508 }
3509 auto bufferInfoPtr = android::base::find(mBuffers, bufferHandle);
3510 if (bufferInfoPtr) {
3511 memoryInfoPtr = &bufferInfoPtr->memory;
3512 }
3513
3514 if (!memoryInfoPtr) {
3515 return VK_ERROR_INVALID_EXTERNAL_HANDLE;
3516 }
3517
3518 // memory should be already mapped to host.
3519 if (!memoryInfoPtr->mappedPtr) {
3520 return VK_ERROR_MEMORY_MAP_FAILED;
3521 }
3522
3523 memoryInfoPtr->gpa = gpa;
3524 memoryInfoPtr->pageAlignedHva =
3525 reinterpret_cast<uint8_t*>(memoryInfoPtr->mappedPtr) + memoryInfoPtr->bindOffset;
3526
3527 size_t rawSize = memoryInfoPtr->size + memoryInfoPtr->pageOffset;
3528 if (size && size < rawSize) {
3529 rawSize = size;
3530 }
3531
3532 memoryInfoPtr->sizeToPage = ((rawSize + kPageSize - 1) >> kPageBits) << kPageBits;
3533
3534 VERBOSE("mapGpaToColorBuffer: hva = %p, pageAlignedHva = %p -> [ 0x%" PRIxPTR ", 0x%" PRIxPTR
3535 " ]",
3536 memoryInfoPtr->mappedPtr, memoryInfoPtr->pageAlignedHva, memoryInfoPtr->gpa,
3537 memoryInfoPtr->gpa + memoryInfoPtr->sizeToPage);
3538
3539 if (mOccupiedGpas.find(gpa) != mOccupiedGpas.end()) {
3540 // emugl::emugl_crash_reporter("FATAL: already mapped gpa 0x%lx! ", gpa);
3541 return VK_ERROR_MEMORY_MAP_FAILED;
3542 }
3543
3544 get_emugl_vm_operations().mapUserBackedRam(gpa, memoryInfoPtr->pageAlignedHva,
3545 memoryInfoPtr->sizeToPage);
3546
3547 mOccupiedGpas.insert(gpa);
3548
3549 return memoryInfoPtr->pageOffset;
3550 }
3551
getBufferAllocationInfo(uint32_t bufferHandle,VkDeviceSize * outSize,uint32_t * outMemoryTypeIndex,bool * outMemoryIsDedicatedAlloc)3552 bool VkEmulation::getBufferAllocationInfo(uint32_t bufferHandle, VkDeviceSize* outSize,
3553 uint32_t* outMemoryTypeIndex,
3554 bool* outMemoryIsDedicatedAlloc) {
3555 std::lock_guard<std::mutex> lock(mMutex);
3556
3557 auto info = android::base::find(mBuffers, bufferHandle);
3558 if (!info) {
3559 return false;
3560 }
3561
3562 if (outSize) {
3563 *outSize = info->memory.size;
3564 }
3565
3566 if (outMemoryTypeIndex) {
3567 *outMemoryTypeIndex = info->memory.typeIndex;
3568 }
3569
3570 if (outMemoryIsDedicatedAlloc) {
3571 *outMemoryIsDedicatedAlloc = info->memory.dedicatedAllocation;
3572 }
3573
3574 return true;
3575 }
3576
setupVkBuffer(uint64_t size,uint32_t bufferHandle,bool vulkanOnly,uint32_t memoryProperty)3577 bool VkEmulation::setupVkBuffer(uint64_t size, uint32_t bufferHandle, bool vulkanOnly,
3578 uint32_t memoryProperty) {
3579 if (vulkanOnly == false) {
3580 ERR("Data buffers should be vulkanOnly. Setup failed.");
3581 return false;
3582 }
3583
3584 auto vk = mDvk;
3585
3586 std::lock_guard<std::mutex> lock(mMutex);
3587
3588 auto infoPtr = android::base::find(mBuffers, bufferHandle);
3589
3590 // Already setup
3591 if (infoPtr) {
3592 return true;
3593 }
3594
3595 VkEmulation::BufferInfo res;
3596
3597 res.handle = bufferHandle;
3598
3599 res.size = size;
3600 res.usageFlags = VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
3601 VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT |
3602 VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
3603 res.createFlags = 0;
3604
3605 res.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
3606
3607 // Create the buffer. If external memory is supported, make it external.
3608 VkExternalMemoryBufferCreateInfo extBufferCi = {
3609 VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_BUFFER_CREATE_INFO,
3610 0,
3611 static_cast<VkExternalMemoryHandleTypeFlags>(getDefaultExternalMemoryHandleType()),
3612 };
3613
3614 void* extBufferCiPtr = nullptr;
3615 if (mDeviceInfo.supportsExternalMemoryImport || mDeviceInfo.supportsExternalMemoryExport) {
3616 extBufferCiPtr = &extBufferCi;
3617 }
3618
3619 VkBufferCreateInfo bufferCi = {
3620 VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
3621 extBufferCiPtr,
3622 res.createFlags,
3623 res.size,
3624 res.usageFlags,
3625 res.sharingMode,
3626 /* queueFamilyIndexCount */ 0,
3627 /* pQueueFamilyIndices */ nullptr,
3628 };
3629
3630 VkResult createRes = vk->vkCreateBuffer(mDevice, &bufferCi, nullptr, &res.buffer);
3631
3632 if (createRes != VK_SUCCESS) {
3633 WARN("Failed to create Vulkan Buffer for Buffer %d, Error: %s", bufferHandle,
3634 string_VkResult(createRes));
3635 return false;
3636 }
3637 bool useDedicated = false;
3638 VkMemoryRequirements memReqs;
3639 if (vk->vkGetBufferMemoryRequirements2KHR) {
3640 VkMemoryDedicatedRequirements dedicated_reqs{
3641 VK_STRUCTURE_TYPE_MEMORY_DEDICATED_REQUIREMENTS, nullptr};
3642 VkMemoryRequirements2 reqs{VK_STRUCTURE_TYPE_MEMORY_REQUIREMENTS_2, &dedicated_reqs};
3643
3644 VkBufferMemoryRequirementsInfo2 info{VK_STRUCTURE_TYPE_IMAGE_MEMORY_REQUIREMENTS_INFO_2,
3645 nullptr, res.buffer};
3646 vk->vkGetBufferMemoryRequirements2KHR(mDevice, &info, &reqs);
3647 useDedicated = dedicated_reqs.requiresDedicatedAllocation;
3648 memReqs = reqs.memoryRequirements;
3649 } else {
3650 vk->vkGetBufferMemoryRequirements(mDevice, res.buffer, &memReqs);
3651 }
3652
3653 // Currently we only care about two memory properties: DEVICE_LOCAL
3654 // and HOST_VISIBLE; other memory properties specified in
3655 // rcSetColorBufferVulkanMode2() call will be ignored for now.
3656 memoryProperty = memoryProperty &
3657 (VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT | VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT);
3658
3659 res.memory.size = memReqs.size;
3660
3661 // Determine memory type.
3662 res.memory.typeIndex = getValidMemoryTypeIndex(memReqs.memoryTypeBits, memoryProperty);
3663
3664 VERBOSE(
3665 "Buffer %d "
3666 "allocation size and type index: %lu, %d, "
3667 "allocated memory property: %d, "
3668 "requested memory property: %d",
3669 bufferHandle, res.memory.size, res.memory.typeIndex,
3670 mDeviceInfo.memProps.memoryTypes[res.memory.typeIndex].propertyFlags, memoryProperty);
3671
3672 bool isHostVisible = memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
3673 Optional<uint64_t> deviceAlignment =
3674 isHostVisible ? Optional<uint64_t>(memReqs.alignment) : kNullopt;
3675 Optional<VkBuffer> dedicated_buffer = useDedicated ? Optional<VkBuffer>(res.buffer) : kNullopt;
3676 bool allocRes = allocExternalMemory(vk, &res.memory, true /* actuallyExternal */,
3677 deviceAlignment, dedicated_buffer);
3678
3679 if (!allocRes) {
3680 WARN("Failed to allocate ColorBuffer with Vulkan backing.");
3681 }
3682
3683 res.memory.pageOffset = reinterpret_cast<uint64_t>(res.memory.mappedPtr) % kPageSize;
3684 res.memory.bindOffset = res.memory.pageOffset ? kPageSize - res.memory.pageOffset : 0u;
3685
3686 VkResult bindBufferMemoryRes =
3687 vk->vkBindBufferMemory(mDevice, res.buffer, res.memory.memory, 0);
3688
3689 if (bindBufferMemoryRes != VK_SUCCESS) {
3690 ERR("Failed to bind buffer memory. Error: %s\n", string_VkResult(bindBufferMemoryRes));
3691 return bindBufferMemoryRes;
3692 }
3693
3694 bool isHostVisibleMemory = memoryProperty & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT;
3695
3696 if (isHostVisibleMemory) {
3697 VkResult mapMemoryRes = vk->vkMapMemory(mDevice, res.memory.memory, 0, res.memory.size, {},
3698 &res.memory.mappedPtr);
3699
3700 if (mapMemoryRes != VK_SUCCESS) {
3701 ERR("Failed to map image memory. Error: %s\n", string_VkResult(mapMemoryRes));
3702 return false;
3703 }
3704 }
3705
3706 res.glExported = false;
3707
3708 mBuffers[bufferHandle] = res;
3709
3710 mDebugUtilsHelper.addDebugLabel(res.buffer, "Buffer:%d", bufferHandle);
3711 mDebugUtilsHelper.addDebugLabel(res.memory.memory, "Buffer:%d", bufferHandle);
3712
3713 return allocRes;
3714 }
3715
teardownVkBuffer(uint32_t bufferHandle)3716 bool VkEmulation::teardownVkBuffer(uint32_t bufferHandle) {
3717 auto vk = mDvk;
3718 std::lock_guard<std::mutex> lock(mMutex);
3719
3720 auto infoPtr = android::base::find(mBuffers, bufferHandle);
3721 if (!infoPtr) return false;
3722 {
3723 android::base::AutoLock queueLock(*mQueueLock);
3724 VK_CHECK(vk->vkQueueWaitIdle(mQueue));
3725 }
3726 auto& info = *infoPtr;
3727
3728 vk->vkDestroyBuffer(mDevice, info.buffer, nullptr);
3729 freeExternalMemoryLocked(vk, &info.memory);
3730 mBuffers.erase(bufferHandle);
3731
3732 return true;
3733 }
3734
dupBufferExtMemoryHandle(uint32_t bufferHandle)3735 std::optional<ExternalHandleInfo> VkEmulation::dupBufferExtMemoryHandle(uint32_t bufferHandle) {
3736 std::lock_guard<std::mutex> lock(mMutex);
3737
3738 auto infoPtr = android::base::find(mBuffers, bufferHandle);
3739 if (!infoPtr) {
3740 return std::nullopt;
3741 }
3742
3743 auto handleInfo = infoPtr->memory.handleInfo;
3744 if (!handleInfo) {
3745 ERR("Could not dup Buffer external memory handle, no external handle info available");
3746 return std::nullopt;
3747 }
3748
3749 return dupExternalMemory(handleInfo);
3750 }
3751
3752 #ifdef __APPLE__
getBufferMetalMemoryHandle(uint32_t bufferHandle)3753 MTLResource_id VkEmulation::getBufferMetalMemoryHandle(uint32_t bufferHandle) {
3754 std::lock_guard<std::mutex> lock(mMutex);
3755
3756 auto infoPtr = android::base::find(mBuffers, bufferHandle);
3757 if (!infoPtr) {
3758 // Color buffer not found; this is usually OK.
3759 return nullptr;
3760 }
3761
3762 return infoPtr->memory.externalMetalHandle;
3763 }
3764 #endif
3765
readBufferToBytes(uint32_t bufferHandle,uint64_t offset,uint64_t size,void * outBytes)3766 bool VkEmulation::readBufferToBytes(uint32_t bufferHandle, uint64_t offset, uint64_t size,
3767 void* outBytes) {
3768 auto vk = mDvk;
3769
3770 std::lock_guard<std::mutex> lock(mMutex);
3771
3772 auto bufferInfo = android::base::find(mBuffers, bufferHandle);
3773 if (!bufferInfo) {
3774 ERR("Failed to read from Buffer:%d, not found.", bufferHandle);
3775 return false;
3776 }
3777
3778 const auto& stagingBufferInfo = mStaging;
3779 if (size > stagingBufferInfo.size) {
3780 ERR("Failed to read from Buffer:%d, staging buffer too small.", bufferHandle);
3781 return false;
3782 }
3783
3784 const VkCommandBufferBeginInfo beginInfo = {
3785 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
3786 .pNext = nullptr,
3787 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
3788 };
3789 VK_CHECK(vk->vkBeginCommandBuffer(mCommandBuffer, &beginInfo));
3790
3791 mDebugUtilsHelper.cmdBeginDebugLabel(mCommandBuffer, "readBufferToBytes(Buffer:%d)",
3792 bufferHandle);
3793
3794 const VkBufferCopy bufferCopy = {
3795 .srcOffset = offset,
3796 .dstOffset = 0,
3797 .size = size,
3798 };
3799 vk->vkCmdCopyBuffer(mCommandBuffer, bufferInfo->buffer, stagingBufferInfo.buffer, 1,
3800 &bufferCopy);
3801
3802 mDebugUtilsHelper.cmdEndDebugLabel(mCommandBuffer);
3803
3804 VK_CHECK(vk->vkEndCommandBuffer(mCommandBuffer));
3805
3806 const VkSubmitInfo submitInfo = {
3807 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3808 .pNext = nullptr,
3809 .waitSemaphoreCount = 0,
3810 .pWaitSemaphores = nullptr,
3811 .pWaitDstStageMask = nullptr,
3812 .commandBufferCount = 1,
3813 .pCommandBuffers = &mCommandBuffer,
3814 .signalSemaphoreCount = 0,
3815 .pSignalSemaphores = nullptr,
3816 };
3817
3818 {
3819 android::base::AutoLock queueLock(*mQueueLock);
3820 VK_CHECK(vk->vkQueueSubmit(mQueue, 1, &submitInfo, mCommandBufferFence));
3821 }
3822
3823 static constexpr uint64_t ANB_MAX_WAIT_NS = 5ULL * 1000ULL * 1000ULL * 1000ULL;
3824
3825 VK_CHECK(vk->vkWaitForFences(mDevice, 1, &mCommandBufferFence, VK_TRUE, ANB_MAX_WAIT_NS));
3826
3827 VK_CHECK(vk->vkResetFences(mDevice, 1, &mCommandBufferFence));
3828
3829 const VkMappedMemoryRange toInvalidate = {
3830 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3831 .pNext = nullptr,
3832 .memory = stagingBufferInfo.memory.memory,
3833 .offset = 0,
3834 .size = size,
3835 };
3836
3837 VK_CHECK(vk->vkInvalidateMappedMemoryRanges(mDevice, 1, &toInvalidate));
3838
3839 const void* srcPtr = reinterpret_cast<const void*>(
3840 reinterpret_cast<const char*>(stagingBufferInfo.memory.mappedPtr));
3841 void* dstPtr = outBytes;
3842 void* dstPtrOffset = reinterpret_cast<void*>(reinterpret_cast<char*>(dstPtr) + offset);
3843 std::memcpy(dstPtrOffset, srcPtr, size);
3844
3845 return true;
3846 }
3847
updateBufferFromBytes(uint32_t bufferHandle,uint64_t offset,uint64_t size,const void * bytes)3848 bool VkEmulation::updateBufferFromBytes(uint32_t bufferHandle, uint64_t offset, uint64_t size,
3849 const void* bytes) {
3850 auto vk = mDvk;
3851
3852 std::lock_guard<std::mutex> lock(mMutex);
3853
3854 auto bufferInfo = android::base::find(mBuffers, bufferHandle);
3855 if (!bufferInfo) {
3856 ERR("Failed to update Buffer:%d, not found.", bufferHandle);
3857 return false;
3858 }
3859
3860 const auto& stagingBufferInfo = mStaging;
3861 if (size > stagingBufferInfo.size) {
3862 ERR("Failed to update Buffer:%d, staging buffer too small.", bufferHandle);
3863 return false;
3864 }
3865
3866 const void* srcPtr = bytes;
3867 const void* srcPtrOffset =
3868 reinterpret_cast<const void*>(reinterpret_cast<const char*>(srcPtr) + offset);
3869 void* dstPtr = stagingBufferInfo.memory.mappedPtr;
3870 std::memcpy(dstPtr, srcPtrOffset, size);
3871
3872 const VkMappedMemoryRange toFlush = {
3873 .sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE,
3874 .pNext = nullptr,
3875 .memory = stagingBufferInfo.memory.memory,
3876 .offset = 0,
3877 .size = size,
3878 };
3879 VK_CHECK(vk->vkFlushMappedMemoryRanges(mDevice, 1, &toFlush));
3880
3881 const VkCommandBufferBeginInfo beginInfo = {
3882 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
3883 .pNext = nullptr,
3884 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
3885 };
3886 VK_CHECK(vk->vkBeginCommandBuffer(mCommandBuffer, &beginInfo));
3887
3888 mDebugUtilsHelper.cmdBeginDebugLabel(mCommandBuffer, "updateBufferFromBytes(Buffer:%d)",
3889 bufferHandle);
3890
3891 const VkBufferCopy bufferCopy = {
3892 .srcOffset = 0,
3893 .dstOffset = offset,
3894 .size = size,
3895 };
3896 vk->vkCmdCopyBuffer(mCommandBuffer, stagingBufferInfo.buffer, bufferInfo->buffer, 1,
3897 &bufferCopy);
3898
3899 mDebugUtilsHelper.cmdEndDebugLabel(mCommandBuffer);
3900
3901 VK_CHECK(vk->vkEndCommandBuffer(mCommandBuffer));
3902
3903 const VkSubmitInfo submitInfo = {
3904 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
3905 .pNext = nullptr,
3906 .waitSemaphoreCount = 0,
3907 .pWaitSemaphores = nullptr,
3908 .pWaitDstStageMask = nullptr,
3909 .commandBufferCount = 1,
3910 .pCommandBuffers = &mCommandBuffer,
3911 .signalSemaphoreCount = 0,
3912 .pSignalSemaphores = nullptr,
3913 };
3914
3915 {
3916 android::base::AutoLock queueLock(*mQueueLock);
3917 VK_CHECK(vk->vkQueueSubmit(mQueue, 1, &submitInfo, mCommandBufferFence));
3918 }
3919
3920 static constexpr uint64_t ANB_MAX_WAIT_NS = 5ULL * 1000ULL * 1000ULL * 1000ULL;
3921 VK_CHECK(vk->vkWaitForFences(mDevice, 1, &mCommandBufferFence, VK_TRUE, ANB_MAX_WAIT_NS));
3922
3923 VK_CHECK(vk->vkResetFences(mDevice, 1, &mCommandBufferFence));
3924
3925 return true;
3926 }
3927
transformExternalMemoryHandleTypeFlags_tohost(VkExternalMemoryHandleTypeFlags bits)3928 VkExternalMemoryHandleTypeFlags VkEmulation::transformExternalMemoryHandleTypeFlags_tohost(
3929 VkExternalMemoryHandleTypeFlags bits) {
3930 VkExternalMemoryHandleTypeFlags res = bits;
3931
3932 // Drop OPAQUE_FD_BIT if it was set. Host's default external memory bits
3933 // may set them again below
3934 if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT) {
3935 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
3936 res |= getDefaultExternalMemoryHandleType();
3937 }
3938
3939 #ifdef _WIN32
3940 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
3941 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
3942 #endif
3943
3944 // Replace guest AHardwareBuffer bits with host's default external memory bits
3945 if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID) {
3946 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID;
3947 res |= getDefaultExternalMemoryHandleType();
3948 }
3949
3950 // Replace guest Zircon VMO bits with host's default external memory bits
3951 if (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA) {
3952 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_ZIRCON_VMO_BIT_FUCHSIA;
3953 res |= getDefaultExternalMemoryHandleType();
3954 }
3955
3956 // If the host does not support dmabuf, replace guest Linux DMA_BUF bits with
3957 // the host's default external memory bits,
3958 if (!mDeviceInfo.supportsDmaBuf && (bits & VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT)) {
3959 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
3960 res |= getDefaultExternalMemoryHandleType();
3961 }
3962
3963 return res;
3964 }
3965
transformExternalMemoryHandleTypeFlags_fromhost(VkExternalMemoryHandleTypeFlags hostBits,VkExternalMemoryHandleTypeFlags wantedGuestHandleType)3966 VkExternalMemoryHandleTypeFlags VkEmulation::transformExternalMemoryHandleTypeFlags_fromhost(
3967 VkExternalMemoryHandleTypeFlags hostBits,
3968 VkExternalMemoryHandleTypeFlags wantedGuestHandleType) {
3969 VkExternalMemoryHandleTypeFlags res = hostBits;
3970
3971 VkExternalMemoryHandleTypeFlagBits handleTypeUsed = getDefaultExternalMemoryHandleType();
3972 #if defined(__APPLE__)
3973 if (mInstanceSupportsMoltenVK) {
3974 // Using a different handle type when in MoltenVK mode
3975 handleTypeUsed = VK_EXTERNAL_MEMORY_HANDLE_TYPE_MTLHEAP_BIT_EXT;
3976 }
3977 #endif
3978 if ((res & handleTypeUsed) == handleTypeUsed) {
3979 res &= ~handleTypeUsed;
3980 res |= wantedGuestHandleType;
3981 }
3982
3983 #ifdef _WIN32
3984 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT;
3985 res &= ~VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT_BIT;
3986 #endif
3987
3988 return res;
3989 }
3990
transformExternalMemoryProperties_tohost(VkExternalMemoryProperties props)3991 VkExternalMemoryProperties VkEmulation::transformExternalMemoryProperties_tohost(
3992 VkExternalMemoryProperties props) {
3993 VkExternalMemoryProperties res = props;
3994 res.exportFromImportedHandleTypes =
3995 transformExternalMemoryHandleTypeFlags_tohost(props.exportFromImportedHandleTypes);
3996 res.compatibleHandleTypes =
3997 transformExternalMemoryHandleTypeFlags_tohost(props.compatibleHandleTypes);
3998 return res;
3999 }
4000
transformExternalMemoryProperties_fromhost(VkExternalMemoryProperties props,VkExternalMemoryHandleTypeFlags wantedGuestHandleType)4001 VkExternalMemoryProperties VkEmulation::transformExternalMemoryProperties_fromhost(
4002 VkExternalMemoryProperties props, VkExternalMemoryHandleTypeFlags wantedGuestHandleType) {
4003 VkExternalMemoryProperties res = props;
4004 res.exportFromImportedHandleTypes = transformExternalMemoryHandleTypeFlags_fromhost(
4005 props.exportFromImportedHandleTypes, wantedGuestHandleType);
4006 res.compatibleHandleTypes = transformExternalMemoryHandleTypeFlags_fromhost(
4007 props.compatibleHandleTypes, wantedGuestHandleType);
4008 return res;
4009 }
4010
setColorBufferCurrentLayout(uint32_t colorBufferHandle,VkImageLayout layout)4011 void VkEmulation::setColorBufferCurrentLayout(uint32_t colorBufferHandle, VkImageLayout layout) {
4012 std::lock_guard<std::mutex> lock(mMutex);
4013
4014 auto infoPtr = android::base::find(mColorBuffers, colorBufferHandle);
4015 if (!infoPtr) {
4016 ERR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
4017 return;
4018 }
4019 infoPtr->currentLayout = layout;
4020 }
4021
getColorBufferCurrentLayout(uint32_t colorBufferHandle)4022 VkImageLayout VkEmulation::getColorBufferCurrentLayout(uint32_t colorBufferHandle) {
4023 std::lock_guard<std::mutex> lock(mMutex);
4024
4025 auto infoPtr = android::base::find(mColorBuffers, colorBufferHandle);
4026 if (!infoPtr) {
4027 ERR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
4028 return VK_IMAGE_LAYOUT_UNDEFINED;
4029 }
4030 return infoPtr->currentLayout;
4031 }
4032
4033 // Allocate a ready to use VkCommandBuffer for queue transfer. The caller needs
4034 // to signal the returned VkFence when the VkCommandBuffer completes.
allocateQueueTransferCommandBufferLocked()4035 std::tuple<VkCommandBuffer, VkFence> VkEmulation::allocateQueueTransferCommandBufferLocked() {
4036 auto vk = mDvk;
4037 // Check if a command buffer in the pool is ready to use. If the associated
4038 // VkFence is ready, vkGetFenceStatus will return VK_SUCCESS, and the
4039 // associated command buffer should be ready to use, so we return that
4040 // command buffer with the associated VkFence. If the associated VkFence is
4041 // not ready, vkGetFenceStatus will return VK_NOT_READY, we will continue to
4042 // search and test the next command buffer. If the VkFence is in an error
4043 // state, vkGetFenceStatus will return with other VkResult variants, we will
4044 // abort.
4045 for (auto& [commandBuffer, fence] : mTransferQueueCommandBufferPool) {
4046 auto res = vk->vkGetFenceStatus(mDevice, fence);
4047 if (res == VK_SUCCESS) {
4048 VK_CHECK(vk->vkResetFences(mDevice, 1, &fence));
4049 VK_CHECK(vk->vkResetCommandBuffer(commandBuffer,
4050 VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT));
4051 return std::make_tuple(commandBuffer, fence);
4052 }
4053 if (res == VK_NOT_READY) {
4054 continue;
4055 }
4056 // We either have a device lost, or an invalid fence state. For the device lost case,
4057 // VK_CHECK will ensure we capture the relevant streams.
4058 VK_CHECK(res);
4059 }
4060 VkCommandBuffer commandBuffer;
4061 VkCommandBufferAllocateInfo allocateInfo = {
4062 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
4063 .pNext = nullptr,
4064 .commandPool = mCommandPool,
4065 .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
4066 .commandBufferCount = 1,
4067 };
4068 VK_CHECK(vk->vkAllocateCommandBuffers(mDevice, &allocateInfo, &commandBuffer));
4069 VkFence fence;
4070 VkFenceCreateInfo fenceCi = {
4071 .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
4072 .pNext = nullptr,
4073 .flags = 0,
4074 };
4075 VK_CHECK(vk->vkCreateFence(mDevice, &fenceCi, nullptr, &fence));
4076
4077 const int cbIndex = static_cast<int>(mTransferQueueCommandBufferPool.size());
4078 mTransferQueueCommandBufferPool.emplace_back(commandBuffer, fence);
4079
4080 VERBOSE(
4081 "Create a new command buffer for queue transfer for a total of %d "
4082 "transfer command buffers",
4083 (cbIndex + 1));
4084
4085 mDebugUtilsHelper.addDebugLabel(commandBuffer, "QueueTransferCommandBuffer:%d", cbIndex);
4086
4087 return std::make_tuple(commandBuffer, fence);
4088 }
4089
4090 const VkImageLayout kGuestUseDefaultImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
4091
releaseColorBufferForGuestUse(uint32_t colorBufferHandle)4092 void VkEmulation::releaseColorBufferForGuestUse(uint32_t colorBufferHandle) {
4093 std::lock_guard<std::mutex> lock(mMutex);
4094
4095 auto infoPtr = android::base::find(mColorBuffers, colorBufferHandle);
4096 if (!infoPtr) {
4097 ERR("Failed to find ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
4098 return;
4099 }
4100
4101 std::optional<VkImageMemoryBarrier> layoutTransitionBarrier;
4102 if (infoPtr->currentLayout != kGuestUseDefaultImageLayout) {
4103 layoutTransitionBarrier = VkImageMemoryBarrier{
4104 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
4105 .pNext = nullptr,
4106 .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
4107 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
4108 .oldLayout = infoPtr->currentLayout,
4109 .newLayout = kGuestUseDefaultImageLayout,
4110 .srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4111 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED,
4112 .image = infoPtr->image,
4113 .subresourceRange =
4114 {
4115 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4116 .baseMipLevel = 0,
4117 .levelCount = 1,
4118 .baseArrayLayer = 0,
4119 .layerCount = 1,
4120 },
4121 };
4122 infoPtr->currentLayout = kGuestUseDefaultImageLayout;
4123 }
4124
4125 std::optional<VkImageMemoryBarrier> queueTransferBarrier;
4126 if (infoPtr->currentQueueFamilyIndex != VK_QUEUE_FAMILY_EXTERNAL) {
4127 queueTransferBarrier = VkImageMemoryBarrier{
4128 .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
4129 .pNext = nullptr,
4130 .srcAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
4131 .dstAccessMask = VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT,
4132 .oldLayout = infoPtr->currentLayout,
4133 .newLayout = infoPtr->currentLayout,
4134 .srcQueueFamilyIndex = infoPtr->currentQueueFamilyIndex,
4135 .dstQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL,
4136 .image = infoPtr->image,
4137 .subresourceRange =
4138 {
4139 .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
4140 .baseMipLevel = 0,
4141 .levelCount = 1,
4142 .baseArrayLayer = 0,
4143 .layerCount = 1,
4144 },
4145 };
4146 infoPtr->currentQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
4147 }
4148
4149 if (!layoutTransitionBarrier && !queueTransferBarrier) {
4150 return;
4151 }
4152
4153 auto vk = mDvk;
4154 auto [commandBuffer, fence] = allocateQueueTransferCommandBufferLocked();
4155
4156 VK_CHECK(vk->vkResetCommandBuffer(commandBuffer, 0));
4157
4158 const VkCommandBufferBeginInfo beginInfo = {
4159 .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
4160 .pNext = nullptr,
4161 .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT,
4162 .pInheritanceInfo = nullptr,
4163 };
4164 VK_CHECK(vk->vkBeginCommandBuffer(commandBuffer, &beginInfo));
4165
4166 mDebugUtilsHelper.cmdBeginDebugLabel(
4167 commandBuffer, "releaseColorBufferForGuestUse(ColorBuffer:%d)", colorBufferHandle);
4168
4169 if (layoutTransitionBarrier) {
4170 vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
4171 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
4172 &layoutTransitionBarrier.value());
4173 }
4174 if (queueTransferBarrier) {
4175 vk->vkCmdPipelineBarrier(commandBuffer, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT,
4176 VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, 0, nullptr, 0, nullptr, 1,
4177 &queueTransferBarrier.value());
4178 }
4179
4180 mDebugUtilsHelper.cmdEndDebugLabel(commandBuffer);
4181
4182 VK_CHECK(vk->vkEndCommandBuffer(commandBuffer));
4183
4184 const VkSubmitInfo submitInfo = {
4185 .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
4186 .pNext = nullptr,
4187 .waitSemaphoreCount = 0,
4188 .pWaitSemaphores = nullptr,
4189 .pWaitDstStageMask = nullptr,
4190 .commandBufferCount = 1,
4191 .pCommandBuffers = &commandBuffer,
4192 .signalSemaphoreCount = 0,
4193 .pSignalSemaphores = nullptr,
4194 };
4195 {
4196 android::base::AutoLock queueLock(*mQueueLock);
4197 VK_CHECK(vk->vkQueueSubmit(mQueue, 1, &submitInfo, fence));
4198 }
4199
4200 static constexpr uint64_t ANB_MAX_WAIT_NS = 5ULL * 1000ULL * 1000ULL * 1000ULL;
4201 VK_CHECK(vk->vkWaitForFences(mDevice, 1, &fence, VK_TRUE, ANB_MAX_WAIT_NS));
4202 }
4203
borrowColorBufferForComposition(uint32_t colorBufferHandle,bool colorBufferIsTarget)4204 std::unique_ptr<BorrowedImageInfoVk> VkEmulation::borrowColorBufferForComposition(
4205 uint32_t colorBufferHandle, bool colorBufferIsTarget) {
4206 std::lock_guard<std::mutex> lock(mMutex);
4207
4208 auto colorBufferInfo = android::base::find(mColorBuffers, colorBufferHandle);
4209 if (!colorBufferInfo) {
4210 ERR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
4211 return nullptr;
4212 }
4213
4214 auto compositorInfo = std::make_unique<BorrowedImageInfoVk>();
4215 compositorInfo->id = colorBufferInfo->handle;
4216 compositorInfo->width = colorBufferInfo->imageCreateInfoShallow.extent.width;
4217 compositorInfo->height = colorBufferInfo->imageCreateInfoShallow.extent.height;
4218 compositorInfo->image = colorBufferInfo->image;
4219 compositorInfo->imageView = colorBufferInfo->imageView;
4220 compositorInfo->imageCreateInfo = colorBufferInfo->imageCreateInfoShallow;
4221 compositorInfo->preBorrowLayout = colorBufferInfo->currentLayout;
4222 compositorInfo->preBorrowQueueFamilyIndex = colorBufferInfo->currentQueueFamilyIndex;
4223 if (colorBufferIsTarget && mDisplayVk) {
4224 // Instruct the compositor to perform the layout transition after use so
4225 // that it is ready to be blitted to the display.
4226 compositorInfo->postBorrowQueueFamilyIndex = mQueueFamilyIndex;
4227 compositorInfo->postBorrowLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
4228 } else {
4229 // Instruct the compositor to perform the queue transfer release after use
4230 // so that the color buffer can be acquired by the guest.
4231 compositorInfo->postBorrowQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
4232 compositorInfo->postBorrowLayout = colorBufferInfo->currentLayout;
4233
4234 if (compositorInfo->postBorrowLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
4235 compositorInfo->postBorrowLayout = kGuestUseDefaultImageLayout;
4236 }
4237 }
4238
4239 colorBufferInfo->currentLayout = compositorInfo->postBorrowLayout;
4240 colorBufferInfo->currentQueueFamilyIndex = compositorInfo->postBorrowQueueFamilyIndex;
4241
4242 return compositorInfo;
4243 }
4244
borrowColorBufferForDisplay(uint32_t colorBufferHandle)4245 std::unique_ptr<BorrowedImageInfoVk> VkEmulation::borrowColorBufferForDisplay(
4246 uint32_t colorBufferHandle) {
4247 std::lock_guard<std::mutex> lock(mMutex);
4248
4249 auto colorBufferInfo = android::base::find(mColorBuffers, colorBufferHandle);
4250 if (!colorBufferInfo) {
4251 ERR("Invalid ColorBuffer handle %d.", static_cast<int>(colorBufferHandle));
4252 return nullptr;
4253 }
4254
4255 auto compositorInfo = std::make_unique<BorrowedImageInfoVk>();
4256 compositorInfo->id = colorBufferInfo->handle;
4257 compositorInfo->width = colorBufferInfo->imageCreateInfoShallow.extent.width;
4258 compositorInfo->height = colorBufferInfo->imageCreateInfoShallow.extent.height;
4259 compositorInfo->image = colorBufferInfo->image;
4260 compositorInfo->imageView = colorBufferInfo->imageView;
4261 compositorInfo->imageCreateInfo = colorBufferInfo->imageCreateInfoShallow;
4262 compositorInfo->preBorrowLayout = colorBufferInfo->currentLayout;
4263 compositorInfo->preBorrowQueueFamilyIndex = mQueueFamilyIndex;
4264
4265 // Instruct the display to perform the queue transfer release after use so
4266 // that the color buffer can be acquired by the guest.
4267 compositorInfo->postBorrowQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL;
4268 compositorInfo->postBorrowLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
4269
4270 colorBufferInfo->currentLayout = compositorInfo->postBorrowLayout;
4271 colorBufferInfo->currentQueueFamilyIndex = compositorInfo->postBorrowQueueFamilyIndex;
4272
4273 return compositorInfo;
4274 }
4275
4276 std::optional<VkEmulation::RepresentativeColorBufferMemoryTypeInfo>
findRepresentativeColorBufferMemoryTypeIndexLocked()4277 VkEmulation::findRepresentativeColorBufferMemoryTypeIndexLocked() {
4278 constexpr const uint32_t kArbitraryWidth = 64;
4279 constexpr const uint32_t kArbitraryHeight = 64;
4280 constexpr const uint32_t kArbitraryHandle = std::numeric_limits<uint32_t>::max();
4281 if (!createVkColorBufferLocked(kArbitraryWidth, kArbitraryHeight, GL_RGBA8,
4282 FrameworkFormat::FRAMEWORK_FORMAT_GL_COMPATIBLE,
4283 kArbitraryHandle, true, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)) {
4284 ERR("Failed to setup memory type index test ColorBuffer.");
4285 return std::nullopt;
4286 }
4287
4288 uint32_t hostMemoryTypeIndex = 0;
4289 if (!getColorBufferAllocationInfoLocked(kArbitraryHandle, nullptr, &hostMemoryTypeIndex,
4290 nullptr, nullptr)) {
4291 ERR("Failed to lookup memory type index test ColorBuffer.");
4292 return std::nullopt;
4293 }
4294
4295 if (!teardownVkColorBufferLocked(kArbitraryHandle)) {
4296 ERR("Failed to clean up memory type index test ColorBuffer.");
4297 return std::nullopt;
4298 }
4299
4300 EmulatedPhysicalDeviceMemoryProperties helper(mDeviceInfo.memProps, hostMemoryTypeIndex,
4301 mFeatures);
4302 uint32_t guestMemoryTypeIndex = helper.getGuestColorBufferMemoryTypeIndex();
4303
4304 return VkEmulation::RepresentativeColorBufferMemoryTypeInfo{
4305 .hostMemoryTypeIndex = hostMemoryTypeIndex,
4306 .guestMemoryTypeIndex = guestMemoryTypeIndex,
4307 };
4308 }
4309
4310 } // namespace vk
4311 } // namespace gfxstream
4312