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