1 // Copyright 2024 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 15 #pragma once 16 17 #include <vulkan/vulkan.h> 18 19 #ifdef _WIN32 20 #include <malloc.h> 21 #endif 22 23 #include <stdlib.h> 24 25 #include <condition_variable> 26 #include <mutex> 27 #include <optional> 28 #include <set> 29 #include <string> 30 #include <unordered_map> 31 32 #include "DebugUtilsHelper.h" 33 #include "DeviceOpTracker.h" 34 #include "Handle.h" 35 #include "VkEmulatedPhysicalDeviceMemory.h" 36 #include "VkEmulatedPhysicalDeviceQueue.h" 37 #include "aemu/base/files/Stream.h" 38 #include "aemu/base/memory/SharedMemory.h" 39 #include "aemu/base/synchronization/ConditionVariable.h" 40 #include "aemu/base/synchronization/Lock.h" 41 #include "common/goldfish_vk_deepcopy.h" 42 #include "vulkan/VkAndroidNativeBuffer.h" 43 #include "vulkan/VkFormatUtils.h" 44 #include "vulkan/emulated_textures/CompressedImageInfo.h" 45 46 namespace gfxstream { 47 namespace vk { 48 49 template <class TDispatch> 50 class ExternalFencePool { 51 public: ExternalFencePool(TDispatch * dispatch,VkDevice device)52 ExternalFencePool(TDispatch* dispatch, VkDevice device) 53 : m_vk(dispatch), mDevice(device), mMaxSize(5) {} 54 ~ExternalFencePool()55 ~ExternalFencePool() { 56 if (!mPool.empty()) { 57 GFXSTREAM_ABORT(emugl::FatalError(emugl::ABORT_REASON_OTHER)) 58 << "External fence pool for device " << static_cast<void*>(mDevice) 59 << " destroyed but " << mPool.size() << " fences still not destroyed."; 60 } 61 } 62 add(VkFence fence)63 void add(VkFence fence) { 64 android::base::AutoLock lock(mLock); 65 mPool.push_back(fence); 66 if (mPool.size() > mMaxSize) { 67 INFO("External fence pool for %p has increased to size %d", mDevice, mPool.size()); 68 mMaxSize = mPool.size(); 69 } 70 } 71 pop(const VkFenceCreateInfo * pCreateInfo)72 VkFence pop(const VkFenceCreateInfo* pCreateInfo) { 73 VkFence fence = VK_NULL_HANDLE; 74 { 75 android::base::AutoLock lock(mLock); 76 auto it = std::find_if(mPool.begin(), mPool.end(), [this](const VkFence& fence) { 77 VkResult status = m_vk->vkGetFenceStatus(mDevice, fence); 78 if (status != VK_SUCCESS) { 79 if (status != VK_NOT_READY) { 80 VK_CHECK(status); 81 } 82 83 // Status is valid, but fence is not yet signaled 84 return false; 85 } 86 return true; 87 }); 88 if (it == mPool.end()) { 89 return VK_NULL_HANDLE; 90 } 91 92 fence = *it; 93 mPool.erase(it); 94 } 95 96 if (!(pCreateInfo->flags & VK_FENCE_CREATE_SIGNALED_BIT)) { 97 VK_CHECK(m_vk->vkResetFences(mDevice, 1, &fence)); 98 } 99 100 return fence; 101 } 102 popAll()103 std::vector<VkFence> popAll() { 104 android::base::AutoLock lock(mLock); 105 std::vector<VkFence> popped = mPool; 106 mPool.clear(); 107 return popped; 108 } 109 110 private: 111 TDispatch* m_vk; 112 VkDevice mDevice; 113 android::base::Lock mLock; 114 std::vector<VkFence> mPool; 115 size_t mMaxSize; 116 }; 117 118 class PrivateMemory { 119 public: PrivateMemory(size_t alignment,size_t size)120 PrivateMemory(size_t alignment, size_t size) { 121 #ifdef _WIN32 122 mAddr = _aligned_malloc(size, alignment); 123 #else 124 mAddr = aligned_alloc(alignment, size); 125 #endif 126 } ~PrivateMemory()127 ~PrivateMemory() { 128 if (mAddr) { 129 #ifdef _WIN32 130 _aligned_free(mAddr); 131 #else 132 free(mAddr); 133 #endif 134 mAddr = nullptr; 135 } 136 } getAddr()137 void* getAddr() { 138 return mAddr; 139 } 140 private: 141 void* mAddr{nullptr}; 142 }; 143 144 // We always map the whole size on host. 145 // This makes it much easier to implement 146 // the memory map API. 147 struct MemoryInfo { 148 // This indicates whether the VkDecoderGlobalState needs to clean up 149 // and unmap the mapped memory; only the owner of the mapped memory 150 // should call unmap. 151 bool needUnmap = false; 152 // When ptr is null, it means the VkDeviceMemory object 153 // was not allocated with the HOST_VISIBLE property. 154 void* ptr = nullptr; 155 VkDeviceSize size; 156 // GLDirectMem info 157 bool directMapped = false; 158 bool virtioGpuMapped = false; 159 uint32_t caching = 0; 160 uint64_t guestPhysAddr = 0; 161 void* pageAlignedHva = nullptr; 162 uint64_t sizeToPage = 0; 163 uint64_t hostmemId = 0; 164 VkDevice device = VK_NULL_HANDLE; 165 uint32_t memoryIndex = 0; 166 // Set if the memory is backed by shared memory. 167 std::optional<android::base::SharedMemory> sharedMemory; 168 169 std::shared_ptr<PrivateMemory> privateMemory; 170 // virtio-gpu blobs 171 uint64_t blobId = 0; 172 173 // Buffer, provided via vkAllocateMemory(). 174 std::optional<HandleType> boundBuffer; 175 // ColorBuffer, provided via vkAllocateMemory(). 176 std::optional<HandleType> boundColorBuffer; 177 }; 178 179 struct InstanceInfo { 180 std::vector<std::string> enabledExtensionNames; 181 uint32_t apiVersion = VK_MAKE_VERSION(1, 0, 0); 182 VkInstance boxed = nullptr; 183 bool isAngle = false; 184 std::string applicationName; 185 std::string engineName; 186 }; 187 188 struct PhysicalDeviceInfo { 189 VkInstance instance = VK_NULL_HANDLE; 190 VkPhysicalDeviceProperties props; 191 std::unique_ptr<EmulatedPhysicalDeviceMemoryProperties> memoryPropertiesHelper; 192 std::unique_ptr<EmulatedPhysicalDeviceQueueProperties> queuePropertiesHelper; 193 VkPhysicalDevice boxed = nullptr; 194 }; 195 196 struct ExternalFenceInfo { 197 VkExternalSemaphoreHandleTypeFlagBits supportedBinarySemaphoreHandleTypes; 198 VkExternalFenceHandleTypeFlagBits supportedFenceHandleTypes; 199 }; 200 201 struct DeviceInfo { 202 std::unordered_map<uint32_t, std::vector<VkQueue>> queues; 203 std::vector<std::string> enabledExtensionNames; 204 bool emulateTextureEtc2 = false; 205 bool emulateTextureAstc = false; 206 bool useAstcCpuDecompression = false; 207 208 ExternalFenceInfo externalFenceInfo; 209 VkPhysicalDevice physicalDevice; 210 VkDevice boxed = nullptr; 211 DebugUtilsHelper debugUtilsHelper = DebugUtilsHelper::withUtilsDisabled(); 212 std::unique_ptr<ExternalFencePool<VulkanDispatch>> externalFencePool = nullptr; 213 std::set<VkFormat> imageFormats = {}; // image formats used on this device 214 std::unique_ptr<GpuDecompressionPipelineManager> decompPipelines = nullptr; 215 DeviceOpTrackerPtr deviceOpTracker = nullptr; 216 std::optional<uint32_t> virtioGpuContextId; 217 218 // True if this is a compressed image that needs to be decompressed on the GPU (with our 219 // compute shader) needGpuDecompressionDeviceInfo220 bool needGpuDecompression(const CompressedImageInfo& cmpInfo) { 221 return ((cmpInfo.isEtc2() && emulateTextureEtc2) || 222 (cmpInfo.isAstc() && emulateTextureAstc && !useAstcCpuDecompression)); 223 } needEmulatedDecompressionDeviceInfo224 bool needEmulatedDecompression(const CompressedImageInfo& cmpInfo) { 225 return ((cmpInfo.isEtc2() && emulateTextureEtc2) || 226 (cmpInfo.isAstc() && emulateTextureAstc)); 227 } needEmulatedDecompressionDeviceInfo228 bool needEmulatedDecompression(VkFormat format) { 229 return (gfxstream::vk::isEtc2(format) && emulateTextureEtc2) || 230 (gfxstream::vk::isAstc(format) && emulateTextureAstc); 231 } 232 }; 233 234 struct QueueInfo { 235 std::shared_ptr<std::mutex> queueMutex; 236 VkDevice device; 237 uint32_t queueFamilyIndex; 238 VkQueue boxed = nullptr; 239 240 // In order to create a virtual queue handle, we use an offset to the physical 241 // queue handle value. This assumes the new generated virtual handle value will 242 // be unique and won't be generated by the actual GPU. This is expected to be 243 // true since most implementations will use a pointer for the handle value and 244 // they will be at least 4-byte aligned. Using a small value allows us to check 245 // if a given 'unboxed' queue handle value is virtual and convert into the actual 246 // physical one easily, without locking for mQueueInfo. 247 static const uint64_t kVirtualQueueBit = 0x1; 248 }; 249 250 struct BufferInfo { 251 VkDevice device; 252 VkBufferUsageFlags usage; 253 VkDeviceMemory memory = 0; 254 VkDeviceSize memoryOffset = 0; 255 VkDeviceSize size; 256 std::shared_ptr<bool> alive{new bool(true)}; 257 }; 258 259 struct ImageInfo { 260 VkDevice device; 261 VkImageCreateInfo imageCreateInfoShallow; 262 std::unique_ptr<AndroidNativeBufferInfo> anbInfo; 263 CompressedImageInfo cmpInfo; 264 // ColorBuffer, provided via vkAllocateMemory(). 265 std::optional<HandleType> boundColorBuffer; 266 // TODO: might need to use an array of layouts to represent each sub resource 267 VkImageLayout layout = VK_IMAGE_LAYOUT_UNDEFINED; 268 VkDeviceMemory memory = VK_NULL_HANDLE; 269 }; 270 271 struct ImageViewInfo { 272 VkDevice device; 273 bool needEmulatedAlpha = false; 274 275 // Color buffer, provided via vkAllocateMemory(). 276 std::optional<HandleType> boundColorBuffer; 277 std::shared_ptr<bool> alive{new bool(true)}; 278 }; 279 280 struct SamplerInfo { 281 VkDevice device; 282 bool needEmulatedAlpha = false; 283 VkSamplerCreateInfo createInfo = {}; 284 VkSampler emulatedborderSampler = VK_NULL_HANDLE; 285 android::base::BumpPool pool = android::base::BumpPool(256); 286 SamplerInfo() = default; 287 SamplerInfo& operator=(const SamplerInfo& other) { 288 deepcopy_VkSamplerCreateInfo(&pool, VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, 289 &other.createInfo, &createInfo); 290 device = other.device; 291 needEmulatedAlpha = other.needEmulatedAlpha; 292 emulatedborderSampler = other.emulatedborderSampler; 293 return *this; 294 } SamplerInfoSamplerInfo295 SamplerInfo(const SamplerInfo& other) { *this = other; } 296 SamplerInfo(SamplerInfo&& other) = delete; 297 SamplerInfo& operator=(SamplerInfo&& other) = delete; 298 std::shared_ptr<bool> alive{new bool(true)}; 299 }; 300 301 struct FenceInfo { 302 VkDevice device = VK_NULL_HANDLE; 303 VkFence boxed = VK_NULL_HANDLE; 304 VulkanDispatch* vk = nullptr; 305 306 std::mutex mutex; 307 std::condition_variable cv; 308 309 enum class State { 310 kNotWaitable, // Newly created or reset 311 kWaitable, // A submission is made, or created as signaled 312 kWaiting, // Fence waitable status is acknowledged 313 }; 314 State state = State::kNotWaitable; 315 316 bool external = false; 317 318 // If this fence was used in an additional host operation that must be waited 319 // upon before destruction (e.g. as part of a vkAcquireImageANDROID() call), 320 // the waitable that tracking that host operation. 321 std::optional<DeviceOpWaitable> latestUse; 322 }; 323 324 struct SemaphoreInfo { 325 VkDevice device; 326 int externalHandleId = 0; 327 VK_EXT_SYNC_HANDLE externalHandle = VK_EXT_SYNC_HANDLE_INVALID; 328 // If this fence was used in an additional host operation that must be waited 329 // upon before destruction (e.g. as part of a vkAcquireImageANDROID() call), 330 // the waitable that tracking that host operation. 331 std::optional<DeviceOpWaitable> latestUse; 332 }; 333 struct DescriptorSetLayoutInfo { 334 VkDevice device = 0; 335 VkDescriptorSetLayout boxed = 0; 336 VkDescriptorSetLayoutCreateInfo createInfo; 337 std::vector<VkDescriptorSetLayoutBinding> bindings; 338 }; 339 340 struct DescriptorPoolInfo { 341 VkDevice device = 0; 342 VkDescriptorPool boxed = 0; 343 struct PoolState { 344 VkDescriptorType type; 345 uint32_t descriptorCount; 346 uint32_t used; 347 }; 348 349 VkDescriptorPoolCreateInfo createInfo; 350 uint32_t maxSets; 351 uint32_t usedSets; 352 std::vector<PoolState> pools; 353 354 std::unordered_map<VkDescriptorSet, VkDescriptorSet> allocedSetsToBoxed; 355 std::vector<uint64_t> poolIds; 356 }; 357 358 struct DescriptorSetInfo { 359 enum DescriptorWriteType { 360 Empty = 0, 361 ImageInfo = 1, 362 BufferInfo = 2, 363 BufferView = 3, 364 InlineUniformBlock = 4, 365 AccelerationStructure = 5, 366 }; 367 368 struct DescriptorWrite { 369 VkDescriptorType descriptorType; 370 DescriptorWriteType writeType = DescriptorWriteType::Empty; 371 uint32_t dstArrayElement; // Only used for inlineUniformBlock and accelerationStructure. 372 373 union { 374 VkDescriptorImageInfo imageInfo; 375 VkDescriptorBufferInfo bufferInfo; 376 VkBufferView bufferView; 377 VkWriteDescriptorSetInlineUniformBlockEXT inlineUniformBlock; 378 VkWriteDescriptorSetAccelerationStructureKHR accelerationStructure; 379 }; 380 381 std::vector<uint8_t> inlineUniformBlockBuffer; 382 // Weak pointer(s) to detect if all objects on dependency chain are alive. 383 std::vector<std::weak_ptr<bool>> alives; 384 std::optional<HandleType> boundColorBuffer; 385 }; 386 387 VkDevice device; 388 VkDescriptorPool pool; 389 VkDescriptorSetLayout unboxedLayout = 0; 390 std::vector<std::vector<DescriptorWrite>> allWrites; 391 std::vector<VkDescriptorSetLayoutBinding> bindings; 392 }; 393 394 struct ShaderModuleInfo { 395 VkDevice device; 396 }; 397 398 struct PipelineCacheInfo { 399 VkDevice device; 400 }; 401 402 struct PipelineLayoutInfo { 403 VkDevice device; 404 }; 405 406 struct PipelineInfo { 407 VkDevice device; 408 }; 409 410 struct RenderPassInfo { 411 VkDevice device; 412 }; 413 414 struct FramebufferInfo { 415 VkDevice device; 416 std::vector<HandleType> attachedColorBuffers; 417 }; 418 419 typedef std::function<void()> PreprocessFunc; 420 struct CommandBufferInfo { 421 std::vector<PreprocessFunc> preprocessFuncs = {}; 422 std::vector<VkCommandBuffer> subCmds = {}; 423 VkDevice device = VK_NULL_HANDLE; 424 VkCommandPool cmdPool = VK_NULL_HANDLE; 425 VkCommandBuffer boxed = VK_NULL_HANDLE; 426 DebugUtilsHelper debugUtilsHelper = DebugUtilsHelper::withUtilsDisabled(); 427 428 // Most recently bound compute pipeline and descriptor sets. We save it here so that we can 429 // restore it after doing emulated texture decompression. 430 VkPipeline computePipeline = VK_NULL_HANDLE; 431 uint32_t firstSet = 0; 432 VkPipelineLayout descriptorLayout = VK_NULL_HANDLE; 433 std::vector<VkDescriptorSet> currentDescriptorSets; 434 std::unordered_set<VkDescriptorSet> allDescriptorSets; 435 std::vector<uint32_t> dynamicOffsets; 436 std::unordered_set<HandleType> acquiredColorBuffers; 437 std::unordered_set<HandleType> releasedColorBuffers; 438 std::unordered_map<HandleType, VkImageLayout> cbLayouts; 439 std::unordered_map<VkImage, VkImageLayout> imageLayouts; 440 resetCommandBufferInfo441 void reset() { 442 subCmds.clear(); 443 computePipeline = VK_NULL_HANDLE; 444 firstSet = 0; 445 descriptorLayout = VK_NULL_HANDLE; 446 currentDescriptorSets.clear(); 447 allDescriptorSets.clear(); 448 dynamicOffsets.clear(); 449 acquiredColorBuffers.clear(); 450 releasedColorBuffers.clear(); 451 cbLayouts.clear(); 452 imageLayouts.clear(); 453 } 454 }; 455 456 struct CommandPoolInfo { 457 VkDevice device = VK_NULL_HANDLE; 458 VkCommandPool boxed = VK_NULL_HANDLE; 459 std::unordered_set<VkCommandBuffer> cmdBuffers = {}; 460 }; 461 462 struct InstanceObjects { 463 std::unordered_map<VkInstance, InstanceInfo>::node_type instance; 464 std::unordered_map<VkPhysicalDevice, PhysicalDeviceInfo> physicalDevices; 465 struct DeviceObjects { 466 std::unordered_map<VkDevice, DeviceInfo>::node_type device; 467 468 std::unordered_map<VkBuffer, BufferInfo> buffers; 469 std::unordered_map<VkCommandBuffer, CommandBufferInfo> commandBuffers; 470 std::unordered_map<VkCommandPool, CommandPoolInfo> commandPools; 471 std::unordered_map<VkDescriptorPool, DescriptorPoolInfo> descriptorPools; 472 std::unordered_map<VkDescriptorSet, DescriptorSetInfo> descriptorSets; 473 std::unordered_map<VkDescriptorSetLayout, DescriptorSetLayoutInfo> descriptorSetLayouts; 474 std::unordered_map<VkDeviceMemory, MemoryInfo> memories; 475 std::unordered_map<VkFence, FenceInfo> fences; 476 std::unordered_map<VkFramebuffer, FramebufferInfo> framebuffers; 477 std::unordered_map<VkImage, ImageInfo> images; 478 std::unordered_map<VkImageView, ImageViewInfo> imageViews; 479 std::unordered_map<VkPipeline, PipelineInfo> pipelines; 480 std::unordered_map<VkPipelineCache, PipelineCacheInfo> pipelineCaches; 481 std::unordered_map<VkPipelineLayout, PipelineLayoutInfo> pipelineLayouts; 482 std::unordered_map<VkQueue, QueueInfo> queues; 483 std::unordered_map<VkRenderPass, RenderPassInfo> renderPasses; 484 std::unordered_map<VkSampler, SamplerInfo> samplers; 485 std::unordered_map<VkSemaphore, SemaphoreInfo> semaphores; 486 std::unordered_map<VkShaderModule, ShaderModuleInfo> shaderModules; 487 }; 488 std::vector<DeviceObjects> devices; 489 }; 490 491 } // namespace vk 492 } // namespace gfxstream 493