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