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