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