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 #pragma once 15 16 #include <GLES2/gl2.h> 17 #include <vulkan/vulkan.h> 18 19 #include <atomic> 20 #include <functional> 21 #include <memory> 22 #include <unordered_map> 23 #include <unordered_set> 24 #include <vector> 25 26 #include "BorrowedImageVk.h" 27 #include "CompositorVk.h" 28 #include "DebugUtilsHelper.h" 29 #include "DisplayVk.h" 30 #include "FrameworkFormats.h" 31 #include "aemu/base/ManagedDescriptor.hpp" 32 #include "aemu/base/Optional.h" 33 #include "aemu/base/synchronization/Lock.h" 34 #include "goldfish_vk_private_defs.h" 35 #include "utils/GfxApiLogger.h" 36 #include "utils/RenderDoc.h" 37 38 namespace gfxstream { 39 namespace vk { 40 41 struct VulkanDispatch; 42 43 // Returns a consistent answer for which memory type index is best for staging 44 // memory. This is not the simplest thing in the world because even if a memory 45 // type index is host visible, that doesn't mean a VkBuffer is allowed to be 46 // associated with it. 47 bool getStagingMemoryTypeIndex(VulkanDispatch* vk, VkDevice device, 48 const VkPhysicalDeviceMemoryProperties* memProps, 49 uint32_t* typeIndex); 50 51 #ifdef _WIN32 52 typedef void* HANDLE; 53 #endif 54 55 #if defined(_WIN32) 56 // External memory objects are HANDLE on Windows 57 typedef HANDLE VK_EXT_MEMORY_HANDLE; 58 // corresponds to INVALID_HANDLE_VALUE 59 #define VK_EXT_MEMORY_HANDLE_INVALID (VK_EXT_MEMORY_HANDLE)(uintptr_t)(-1) 60 #define VK_EXT_MEMORY_HANDLE_TYPE_BIT VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT 61 #elif defined(__QNX__) 62 #include <screen/screen.h> 63 // External memory objects are screen_buffer_t handles on QNX 64 typedef screen_buffer_t VK_EXT_MEMORY_HANDLE; 65 #define VK_EXT_MEMORY_HANDLE_INVALID (VK_EXT_MEMORY_HANDLE) nullptr 66 #define VK_EXT_MEMORY_HANDLE_TYPE_BIT VK_EXTERNAL_MEMORY_HANDLE_TYPE_SCREEN_BUFFER_BIT_QNX 67 #else 68 // External memory objects are fd's on other POSIX systems 69 typedef int VK_EXT_MEMORY_HANDLE; 70 #define VK_EXT_MEMORY_HANDLE_INVALID (-1) 71 #define VK_EXT_MEMORY_HANDLE_TYPE_BIT VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT 72 #endif 73 74 VK_EXT_MEMORY_HANDLE dupExternalMemory(VK_EXT_MEMORY_HANDLE); 75 76 enum class AstcEmulationMode { 77 Disabled, // No ASTC emulation (ie: ASTC not supported unless the GPU supports it natively) 78 Cpu, // Decompress ASTC textures on the CPU 79 Gpu, // Decompress ASTC textures on the GPU 80 }; 81 82 // Global state that holds a global Vulkan instance along with globally 83 // exported memory allocations + images. This is in order to service things 84 // like AndroidHardwareBuffer/FuchsiaImagePipeHandle. Each such allocation is 85 // associated with a ColorBuffer handle, and depending on host-side support for 86 // GL_EXT_memory_object, also be able to zero-copy render into and readback 87 // with the traditional GL pipeline. 88 struct VkEmulation { 89 // Whether initialization succeeded. 90 bool live = false; 91 92 // Whether to use deferred command submission. 93 bool useDeferredCommands = false; 94 95 // Whether to fuse memory requirements getting with resource creation. 96 bool useCreateResourcesWithRequirements = false; 97 98 // RenderDoc integration for guest VkInstances. 99 std::unique_ptr<emugl::RenderDocWithMultipleVkInstances> guestRenderDoc = nullptr; 100 101 // Whether to use ASTC emulation. Our current ASTC decoder implementation may lead to device 102 // lost on certain device on Windows. 103 AstcEmulationMode astcLdrEmulationMode = AstcEmulationMode::Disabled; 104 105 // Whether to use ETC2 emulation. 106 bool enableEtc2Emulation = false; 107 108 // Whether to use Ycbcr emulation. If this feature is turned on, Ycbcr request will always use 109 // the emulation path regardless of whether the host Vulkan driver actually supports Ycbcr 110 // conversion or not. 111 bool enableYcbcrEmulation = false; 112 113 bool guestUsesAngle = false; 114 115 bool useDedicatedAllocations = false; 116 117 // Instance and device for creating the system-wide shareable objects. 118 VkInstance instance = VK_NULL_HANDLE; 119 VkPhysicalDevice physdev = VK_NULL_HANDLE; 120 VkDevice device = VK_NULL_HANDLE; 121 122 // Physical device index 123 uint32_t physicalDeviceIndex = 0; 124 125 // Global, instance and device dispatch tables. 126 VulkanDispatch* gvk = nullptr; 127 VulkanDispatch* ivk = nullptr; 128 VulkanDispatch* dvk = nullptr; 129 130 bool instanceSupportsExternalMemoryCapabilities = false; 131 bool instanceSupportsExternalSemaphoreCapabilities = false; 132 bool instanceSupportsSurface = false; 133 PFN_vkGetPhysicalDeviceImageFormatProperties2KHR getImageFormatProperties2Func = nullptr; 134 PFN_vkGetPhysicalDeviceProperties2KHR getPhysicalDeviceProperties2Func = nullptr; 135 PFN_vkGetPhysicalDeviceFeatures2 getPhysicalDeviceFeatures2Func = nullptr; 136 137 #if defined(__APPLE__) && defined(VK_MVK_moltenvk) 138 bool instanceSupportsMoltenVK = false; 139 PFN_vkSetMTLTextureMVK setMTLTextureFunc = nullptr; 140 PFN_vkGetMTLTextureMVK getMTLTextureFunc = nullptr; 141 #endif 142 143 bool debugUtilsAvailableAndRequested = false; 144 DebugUtilsHelper debugUtilsHelper = DebugUtilsHelper::withUtilsDisabled(); 145 146 // Queue, command pool, and command buffer 147 // for running commands to sync stuff system-wide. 148 // TODO(b/197362803): Encapsulate host side VkQueue and the lock. 149 VkQueue queue = VK_NULL_HANDLE; 150 std::shared_ptr<android::base::Lock> queueLock = nullptr; 151 uint32_t queueFamilyIndex = 0; 152 VkCommandPool commandPool = VK_NULL_HANDLE; 153 VkCommandBuffer commandBuffer = VK_NULL_HANDLE; 154 VkFence commandBufferFence = VK_NULL_HANDLE; 155 156 struct ImageSupportInfo { 157 // Input parameters 158 VkFormat format; 159 VkImageType type; 160 VkImageTiling tiling; 161 VkImageUsageFlags usageFlags; 162 VkImageCreateFlags createFlags; 163 164 // Output parameters 165 bool supported = false; 166 bool supportsExternalMemory = false; 167 bool requiresDedicatedAllocation = false; 168 169 // Keep the raw output around. 170 VkFormatProperties2 formatProps2; 171 VkImageFormatProperties2 imageFormatProps2; 172 VkExternalImageFormatProperties extFormatProps; 173 174 // Populated later when device is available. 175 uint32_t memoryTypeBits = 0; 176 bool memoryTypeBitsKnown = false; 177 }; 178 179 std::vector<ImageSupportInfo> imageSupportInfo; 180 181 struct DeviceSupportInfo { 182 bool hasGraphicsQueueFamily = false; 183 bool hasComputeQueueFamily = false; 184 bool supportsExternalMemoryImport = false; 185 bool supportsExternalMemoryExport = false; 186 bool supportsIdProperties = false; 187 bool supportsDriverProperties = false; 188 bool hasSamplerYcbcrConversionExtension = false; 189 bool supportsSamplerYcbcrConversion = false; 190 bool glInteropSupported = false; 191 192 std::vector<VkExtensionProperties> extensions; 193 194 std::vector<uint32_t> graphicsQueueFamilyIndices; 195 std::vector<uint32_t> computeQueueFamilyIndices; 196 197 VkPhysicalDeviceProperties physdevProps; 198 VkPhysicalDeviceMemoryProperties memProps; 199 VkPhysicalDeviceIDPropertiesKHR idProps; 200 201 std::string driverVendor; 202 std::string driverVersion; 203 204 PFN_vkGetImageMemoryRequirements2KHR getImageMemoryRequirements2Func = nullptr; 205 PFN_vkGetBufferMemoryRequirements2KHR getBufferMemoryRequirements2Func = nullptr; 206 207 #ifdef _WIN32 208 PFN_vkGetMemoryWin32HandleKHR getMemoryHandleFunc = nullptr; 209 #else 210 PFN_vkGetMemoryFdKHR getMemoryHandleFunc = nullptr; 211 #endif 212 }; 213 214 struct ExternalMemoryInfo { 215 // Input fields 216 VkDeviceSize size; 217 uint32_t typeIndex; 218 219 // Output fields 220 uint32_t id = 0; 221 VkDeviceMemory memory = VK_NULL_HANDLE; 222 223 // host-mapping fields 224 // host virtual address (hva). 225 void* mappedPtr = nullptr; 226 // host virtual address, aligned to 4KB page. 227 void* pageAlignedHva = nullptr; 228 // the offset of |mappedPtr| off its memory page. 229 uint32_t pageOffset = 0u; 230 // the offset set in |vkBindImageMemory| or |vkBindBufferMemory|. 231 uint32_t bindOffset = 0u; 232 // the size of all the pages the mmeory uses. 233 size_t sizeToPage = 0u; 234 // guest physical address. 235 uintptr_t gpa = 0u; 236 237 VK_EXT_MEMORY_HANDLE externalHandle = VK_EXT_MEMORY_HANDLE_INVALID; 238 239 bool dedicatedAllocation = false; 240 }; 241 242 // 128 mb staging buffer (really, just a few 4K frames or one 4k HDR frame) 243 // ought to be big enough for anybody! 244 static constexpr VkDeviceSize kDefaultStagingBufferSize = 128ULL * 1048576ULL; 245 246 struct StagingBufferInfo { 247 // TODO: Don't actually use this as external memory until host visible 248 // external is supported on all platforms 249 ExternalMemoryInfo memory; 250 VkBuffer buffer = VK_NULL_HANDLE; 251 VkDeviceSize size = kDefaultStagingBufferSize; 252 }; 253 254 enum class VulkanMode { 255 // Default: ColorBuffers can still be used with the existing GL-based 256 // API. Synchronization with (if it exists) Vulkan images happens on 257 // every one of the GL-based API calls: 258 // 259 // rcReadColorBuffer 260 // rcUpdateColorBuffer 261 // rcBindTexture 262 // rcBindRenderbuffer 263 // rcFlushWindowColorBuffer 264 // 265 // either through explicit CPU copies or implicit in the host driver 266 // if OpenGL interop is supported. 267 // 268 // When images are posted (rcFBPost), 269 // eglSwapBuffers is used, even if that requires a CPU readback. 270 271 Default = 0, 272 273 // VulkanOnly: It is assumed that the guest interacts entirely with 274 // the underlying Vulkan image in the guest and does not use the 275 // GL-based API. This means we can assume those APIs are not called: 276 // 277 // rcReadColorBuffer 278 // rcUpdateColorBuffer 279 // rcBindTexture 280 // rcBindRenderbuffer 281 // rcFlushWindowColorBuffer 282 // 283 // and thus we skip a lot of GL/Vk synchronization. 284 // 285 // When images are posted, eglSwapBuffers is only used if OpenGL 286 // interop is supported. If OpenGL interop is not supported, then we 287 // use a host platform-specific Vulkan swapchain to display the 288 // results. 289 290 VulkanOnly = 1, 291 }; 292 struct ColorBufferInfo { 293 ExternalMemoryInfo memory; 294 295 uint32_t handle; 296 297 /* Set in create(), before initialize() */ 298 uint32_t width; 299 uint32_t height; 300 GLenum internalFormat; 301 uint32_t memoryProperty; 302 int frameworkFormat; 303 int frameworkStride; 304 bool initialized = false; 305 306 VkImage image = VK_NULL_HANDLE; 307 VkImageView imageView = VK_NULL_HANDLE; 308 VkImageCreateInfo imageCreateInfoShallow = {}; 309 VkMemoryRequirements memReqs; 310 311 VkImageLayout currentLayout = VK_IMAGE_LAYOUT_UNDEFINED; 312 uint32_t currentQueueFamilyIndex = VK_QUEUE_FAMILY_EXTERNAL; 313 314 bool glExported = false; 315 316 VulkanMode vulkanMode = VulkanMode::Default; 317 318 MTLTextureRef mtlTexture = nullptr; 319 }; 320 321 struct BufferInfo { 322 ExternalMemoryInfo memory; 323 uint32_t handle; 324 325 VkDeviceSize size; 326 VkBufferCreateFlags createFlags; 327 VkBufferUsageFlags usageFlags; 328 VkSharingMode sharingMode; 329 330 VkBuffer buffer = VK_NULL_HANDLE; 331 VkMemoryRequirements memReqs; 332 333 bool glExported = false; 334 VulkanMode vulkanMode = VulkanMode::Default; 335 MTLBufferRef mtlBuffer = nullptr; 336 }; 337 338 // Track what is supported on whatever device was selected. 339 DeviceSupportInfo deviceInfo; 340 341 // Track additional vulkan diagnostics 342 uint32_t vulkanInstanceVersion; 343 std::vector<VkExtensionProperties> instanceExtensions; 344 345 // A single staging buffer to perform most transfers to/from OpenGL on the 346 // host. It is shareable across instances. The memory is shareable but the 347 // buffer is not; other users need to create buffers that 348 // bind to imported versions of the memory. 349 StagingBufferInfo staging; 350 351 // ColorBuffers are intended to back the guest's shareable images. 352 // For example: 353 // Android: gralloc 354 // Fuchsia: ImagePipeHandle 355 // Linux: dmabuf 356 std::unordered_map<uint32_t, ColorBufferInfo> colorBuffers; 357 358 // Buffers are intended to back the guest's shareable Vulkan buffers. 359 std::unordered_map<uint32_t, BufferInfo> buffers; 360 361 // In order to support VK_KHR_external_memory_(fd|win32) we need also to 362 // support the concept of plain external memories that are just memory and 363 // not necessarily images. These are then intended to pass through to the 364 // guest in some way, with 1:1 mapping between guest and host external 365 // memory handles. 366 std::unordered_map<uint32_t, ExternalMemoryInfo> externalMemories; 367 368 // The host keeps a set of occupied guest memory addresses to avoid a 369 // host memory address mapped to guest twice. 370 std::unordered_set<uint64_t> occupiedGpas; 371 372 // We can also consider using a single external memory object to back all 373 // host visible allocations in the guest. This would save memory, but we 374 // would also need to automatically add 375 // VkExternalMemory(Image|Buffer)CreateInfo, or if it is already there, OR 376 // it with the handle types on the host. 377 // A rough sketch: Some memories/images/buffers in the guest 378 // are backed by host visible memory: 379 // There is already a virtual memory type for those things in the current 380 // implementation. The guest doesn't know whether the pointer or the 381 // VkDeviceMemory object is backed by host external or non external. 382 // TODO: are all possible buffer / image usages compatible with 383 // external backing? 384 // TODO: try switching to this 385 ExternalMemoryInfo virtualHostVisibleHeap; 386 387 // Every command buffer in the pool is associated with a VkFence which is 388 // signaled only if the command buffer completes. 389 std::vector<std::tuple<VkCommandBuffer, VkFence>> transferQueueCommandBufferPool; 390 391 std::unique_ptr<CompositorVk> compositorVk; 392 393 // The implementation for Vulkan native swapchain. Only initialized in initVkEmulationFeatures 394 // if useVulkanNativeSwapchain is set. 395 std::unique_ptr<DisplayVk> displayVk; 396 397 // The host memory type index that will be used to create an emulated memory type specifically 398 // for AHardwareBuffers/ColorBuffers so that the host can control which memory flags are 399 // exposed to the guest (i.e. hide VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT from the guest). 400 std::optional<uint32_t> representativeColorBufferMemoryTypeIndex; 401 }; 402 403 VkEmulation* createGlobalVkEmulation(VulkanDispatch* vk, bool useVulkanNativeSwapchain); 404 405 struct VkEmulationFeatures { 406 bool glInteropSupported = false; 407 bool deferredCommands = false; 408 bool createResourceWithRequirements = false; 409 bool useVulkanComposition = false; 410 bool useVulkanNativeSwapchain = false; 411 std::unique_ptr<emugl::RenderDocWithMultipleVkInstances> guestRenderDoc = nullptr; 412 AstcEmulationMode astcLdrEmulationMode = AstcEmulationMode::Disabled; 413 bool enableEtc2Emulation = false; 414 bool enableYcbcrEmulation = false; 415 bool guestUsesAngle = false; 416 bool useDedicatedAllocations = false; 417 }; 418 void initVkEmulationFeatures(std::unique_ptr<VkEmulationFeatures>); 419 420 VkEmulation* getGlobalVkEmulation(); 421 void teardownGlobalVkEmulation(); 422 423 std::unique_ptr<gfxstream::DisplaySurface> createDisplaySurface(FBNativeWindowType window, 424 uint32_t width, uint32_t height); 425 426 bool allocExternalMemory( 427 VulkanDispatch* vk, VkEmulation::ExternalMemoryInfo* info, bool actuallyExternal = true, 428 android::base::Optional<uint64_t> deviceAlignment = android::base::kNullopt, 429 android::base::Optional<VkBuffer> bufferForDedicatedAllocation = android::base::kNullopt, 430 android::base::Optional<VkImage> imageForDedicatedAllocation = android::base::kNullopt); 431 void freeExternalMemoryLocked(VulkanDispatch* vk, VkEmulation::ExternalMemoryInfo* info); 432 433 bool importExternalMemory(VulkanDispatch* vk, VkDevice targetDevice, 434 const VkEmulation::ExternalMemoryInfo* info, VkDeviceMemory* out); 435 bool importExternalMemoryDedicatedImage(VulkanDispatch* vk, VkDevice targetDevice, 436 const VkEmulation::ExternalMemoryInfo* info, VkImage image, 437 VkDeviceMemory* out); 438 439 // ColorBuffer operations 440 441 bool isColorBufferExportedToGl(uint32_t colorBufferHandle, bool* exported); 442 443 bool getColorBufferAllocationInfo(uint32_t colorBufferHandle, VkDeviceSize* outSize, 444 uint32_t* outMemoryTypeIndex, bool* outMemoryIsDedicatedAlloc, 445 void** outMappedPtr); 446 447 std::unique_ptr<VkImageCreateInfo> generateColorBufferVkImageCreateInfo(VkFormat format, 448 uint32_t width, 449 uint32_t height, 450 VkImageTiling tiling); 451 452 bool createVkColorBuffer(uint32_t width, uint32_t height, GLenum format, 453 FrameworkFormat frameworkFormat, uint32_t colorBufferHandle, 454 bool vulkanOnly, uint32_t memoryProperty); 455 456 bool teardownVkColorBuffer(uint32_t colorBufferHandle); 457 458 bool importExtMemoryHandleToVkColorBuffer(uint32_t colorBufferHandle, uint32_t type, 459 VK_EXT_MEMORY_HANDLE extMemHandle); 460 461 VkEmulation::ColorBufferInfo getColorBufferInfo(uint32_t colorBufferHandle); 462 VK_EXT_MEMORY_HANDLE getColorBufferExtMemoryHandle(uint32_t colorBufferHandle); 463 464 struct VkColorBufferMemoryExport { 465 android::base::ManagedDescriptor descriptor; 466 uint64_t size = 0; 467 bool linearTiling = false; 468 bool dedicatedAllocation = false; 469 }; 470 std::optional<VkColorBufferMemoryExport> exportColorBufferMemory(uint32_t colorBufferHandle); 471 472 MTLTextureRef getColorBufferMTLTexture(uint32_t colorBufferHandle); 473 bool setColorBufferVulkanMode(uint32_t colorBufferHandle, uint32_t vulkanMode); 474 int32_t mapGpaToBufferHandle(uint32_t bufferHandle, uint64_t gpa, uint64_t size = 0); 475 476 bool colorBufferNeedsUpdateBetweenGlAndVk(uint32_t colorBufferHandle); 477 478 bool readColorBufferToBytes(uint32_t colorBufferHandle, std::vector<uint8_t>* bytes); 479 bool readColorBufferToBytes(uint32_t colorBufferHandle, uint32_t x, uint32_t y, uint32_t w, 480 uint32_t h, void* outPixels); 481 bool readColorBufferToBytesLocked(uint32_t colorBufferHandle, uint32_t x, uint32_t y, uint32_t w, 482 uint32_t h, void* outPixels); 483 484 bool updateColorBufferFromBytes(uint32_t colorBufferHandle, const std::vector<uint8_t>& bytes); 485 bool updateColorBufferFromBytes(uint32_t colorBufferHandle, uint32_t x, uint32_t y, uint32_t w, 486 uint32_t h, const void* pixels); 487 488 // Data buffer operations 489 bool getBufferAllocationInfo(uint32_t bufferHandle, VkDeviceSize* outSize, 490 uint32_t* outMemoryTypeIndex, bool* outMemoryIsDedicatedAlloc); 491 492 bool setupVkBuffer(uint64_t size, uint32_t bufferHandle, bool vulkanOnly = false, 493 uint32_t memoryProperty = 0); 494 bool teardownVkBuffer(uint32_t bufferHandle); 495 VK_EXT_MEMORY_HANDLE getBufferExtMemoryHandle(uint32_t bufferHandle); 496 497 bool readBufferToBytes(uint32_t bufferHandle, uint64_t offset, uint64_t size, void* outBytes); 498 bool updateBufferFromBytes(uint32_t bufferHandle, uint64_t offset, uint64_t size, 499 const void* bytes); 500 501 VkExternalMemoryHandleTypeFlags transformExternalMemoryHandleTypeFlags_tohost( 502 VkExternalMemoryHandleTypeFlags bits); 503 504 VkExternalMemoryHandleTypeFlags transformExternalMemoryHandleTypeFlags_fromhost( 505 VkExternalMemoryHandleTypeFlags hostBits, 506 VkExternalMemoryHandleTypeFlags wantedGuestHandleType); 507 508 VkExternalMemoryProperties transformExternalMemoryProperties_tohost( 509 VkExternalMemoryProperties props); 510 511 VkExternalMemoryProperties transformExternalMemoryProperties_fromhost( 512 VkExternalMemoryProperties props, VkExternalMemoryHandleTypeFlags wantedGuestHandleType); 513 514 void setColorBufferCurrentLayout(uint32_t colorBufferHandle, VkImageLayout); 515 516 void releaseColorBufferForGuestUse(uint32_t colorBufferHandle); 517 518 std::unique_ptr<BorrowedImageInfoVk> borrowColorBufferForComposition(uint32_t colorBufferHandle, 519 bool colorBufferIsTarget); 520 std::unique_ptr<BorrowedImageInfoVk> borrowColorBufferForDisplay(uint32_t colorBufferHandle); 521 522 } // namespace vk 523 } // namespace gfxstream 524