1 #ifndef COMPOSITOR_VK_H 2 #define COMPOSITOR_VK_H 3 4 #include <array> 5 #include <deque> 6 #include <future> 7 #include <glm/glm.hpp> 8 #include <list> 9 #include <memory> 10 #include <optional> 11 #include <tuple> 12 #include <unordered_map> 13 #include <vector> 14 15 #include "BorrowedImage.h" 16 #include "BorrowedImageVk.h" 17 #include "Compositor.h" 18 #include "DebugUtilsHelper.h" 19 #include "Hwc2.h" 20 #include "aemu/base/LruCache.h" 21 #include "aemu/base/synchronization/Lock.h" 22 #include "goldfish_vk_dispatch.h" 23 #include "vulkan/vk_util.h" 24 25 namespace gfxstream { 26 namespace vk { 27 28 // We do see a composition requests with 12 layers. (b/222700096) 29 // Inside hwc2, we will ask for surfaceflinger to 30 // do the composition, if the layers more than 16. 31 // If we see rendering error or significant time spent on updating 32 // descriptors in setComposition, we should tune this number. 33 static constexpr const uint32_t kMaxLayersPerFrame = 16; 34 static const uint64_t kVkWaitForFencesTimeoutNsecs = 5ULL * 1000ULL * 1000ULL * 1000ULL; 35 36 // Base used to grant visibility to members to the vk_util::* helper classes. 37 struct CompositorVkBase : public vk_util::MultiCrtp<CompositorVkBase, // 38 vk_util::FindMemoryType, // 39 vk_util::RunSingleTimeCommand> { 40 const VulkanDispatch& m_vk; 41 const VkDevice m_vkDevice; 42 const VkPhysicalDevice m_vkPhysicalDevice; 43 const VkQueue m_vkQueue; 44 const uint32_t m_queueFamilyIndex; 45 const DebugUtilsHelper m_debugUtilsHelper; 46 std::shared_ptr<android::base::Lock> m_vkQueueLock; 47 VkDescriptorSetLayout m_vkDescriptorSetLayout; 48 VkPipelineLayout m_vkPipelineLayout; 49 struct PerFormatResources { 50 VkRenderPass m_vkRenderPass = VK_NULL_HANDLE; 51 VkPipeline m_graphicsVkPipeline = VK_NULL_HANDLE; 52 }; 53 std::unordered_map<VkFormat, PerFormatResources> m_formatResources; 54 VkBuffer m_vertexVkBuffer; 55 VkDeviceMemory m_vertexVkDeviceMemory; 56 VkBuffer m_indexVkBuffer; 57 VkDeviceMemory m_indexVkDeviceMemory; 58 VkDescriptorPool m_vkDescriptorPool; 59 VkCommandPool m_vkCommandPool; 60 // TODO: create additional VkSampler-s for YCbCr layers. 61 VkSampler m_vkSampler; 62 // Unused image that is solely used to occupy the sampled image binding 63 // when compositing a solid color layer. 64 struct DefaultImage { 65 VkImage m_vkImage = VK_NULL_HANDLE; 66 VkImageView m_vkImageView = VK_NULL_HANDLE; 67 VkDeviceMemory m_vkImageMemory = VK_NULL_HANDLE; 68 } m_defaultImage; 69 70 // The underlying storage for all of the uniform buffer objects. 71 struct UniformBufferStorage { 72 VkBuffer m_vkBuffer = VK_NULL_HANDLE; 73 VkDeviceMemory m_vkDeviceMemory = VK_NULL_HANDLE; 74 VkDeviceSize m_stride = 0; 75 } m_uniformStorage; 76 77 // Keep in sync with vulkan/Compositor.frag. 78 struct SamplerBinding { 79 // Include the image id to trigger a descriptor update to handle the case 80 // that the VkImageView is recycled across different images (b/322998473). 81 uint32_t sampledImageId = 0; 82 VkImageView sampledImageView = VK_NULL_HANDLE; 83 }; 84 85 // Keep in sync with vulkan/Compositor.vert. 86 struct UniformBufferBinding { 87 alignas(16) glm::mat4 positionTransform; 88 alignas(16) glm::mat4 texCoordTransform; 89 alignas(16) glm::uvec4 mode; 90 alignas(16) glm::vec4 alpha; 91 alignas(16) glm::vec4 color; 92 }; 93 94 // The cached contents of a given descriptor set. 95 struct DescriptorSetContents { 96 SamplerBinding binding0; 97 UniformBufferBinding binding1; 98 }; 99 100 // The cached contents of all descriptors sets of a given frame. 101 struct FrameDescriptorSetsContents { 102 std::vector<DescriptorSetContents> descriptorSets; 103 }; 104 105 friend bool operator==(const DescriptorSetContents& lhs, const DescriptorSetContents& rhs); 106 107 friend bool operator==(const FrameDescriptorSetsContents& lhs, 108 const FrameDescriptorSetsContents& rhs); 109 110 struct PerFrameResources { 111 VkFence m_vkFence = VK_NULL_HANDLE; 112 VkCommandBuffer m_vkCommandBuffer = VK_NULL_HANDLE; 113 std::vector<VkDescriptorSet> m_layerDescriptorSets; 114 // Pointers into the underlying uniform buffer storage for the uniform 115 // buffer of part of each descriptor set for each layer. 116 std::vector<UniformBufferBinding*> m_layerUboStorages; 117 std::optional<FrameDescriptorSetsContents> m_vkDescriptorSetsContents; 118 }; 119 std::vector<PerFrameResources> m_frameResources; 120 std::deque<std::shared_future<PerFrameResources*>> m_availableFrameResources; 121 CompositorVkBaseCompositorVkBase122 explicit CompositorVkBase(const VulkanDispatch& vk, VkDevice device, 123 VkPhysicalDevice physicalDevice, VkQueue queue, 124 std::shared_ptr<android::base::Lock> queueLock, 125 uint32_t queueFamilyIndex, uint32_t maxFramesInFlight, 126 DebugUtilsHelper debugUtils) 127 : m_vk(vk), 128 m_vkDevice(device), 129 m_vkPhysicalDevice(physicalDevice), 130 m_vkQueue(queue), 131 m_queueFamilyIndex(queueFamilyIndex), 132 m_debugUtilsHelper(debugUtils), 133 m_vkQueueLock(queueLock), 134 m_vkDescriptorSetLayout(VK_NULL_HANDLE), 135 m_vkPipelineLayout(VK_NULL_HANDLE), 136 m_vertexVkBuffer(VK_NULL_HANDLE), 137 m_vertexVkDeviceMemory(VK_NULL_HANDLE), 138 m_indexVkBuffer(VK_NULL_HANDLE), 139 m_indexVkDeviceMemory(VK_NULL_HANDLE), 140 m_vkDescriptorPool(VK_NULL_HANDLE), 141 m_vkCommandPool(VK_NULL_HANDLE), 142 m_vkSampler(VK_NULL_HANDLE), 143 m_frameResources(maxFramesInFlight) {} 144 }; 145 146 class CompositorVk : protected CompositorVkBase, public Compositor { 147 public: 148 static std::unique_ptr<CompositorVk> create( 149 const VulkanDispatch& vk, VkDevice vkDevice, VkPhysicalDevice vkPhysicalDevice, 150 VkQueue vkQueue, std::shared_ptr<android::base::Lock> queueLock, uint32_t queueFamilyIndex, 151 uint32_t maxFramesInFlight, 152 DebugUtilsHelper debugUtils = DebugUtilsHelper::withUtilsDisabled()); 153 154 ~CompositorVk(); 155 156 CompositionFinishedWaitable compose(const CompositionRequest& compositionRequest) override; 157 158 void onImageDestroyed(uint32_t imageId) override; 159 queueSupportsComposition(const VkQueueFamilyProperties & properties)160 static bool queueSupportsComposition(const VkQueueFamilyProperties& properties) { 161 return properties.queueFlags & VK_QUEUE_GRAPHICS_BIT; 162 } 163 164 private: 165 explicit CompositorVk(const VulkanDispatch&, VkDevice, VkPhysicalDevice, VkQueue, 166 std::shared_ptr<android::base::Lock> queueLock, uint32_t queueFamilyIndex, 167 uint32_t maxFramesInFlight, DebugUtilsHelper debugUtils); 168 169 void setUpGraphicsPipeline(); 170 void setUpVertexBuffers(); 171 void setUpSampler(); 172 void setUpDescriptorSets(); 173 void setUpUniformBuffers(); 174 void setUpCommandPool(); 175 void setUpFences(); 176 void setUpDefaultImage(); 177 void setUpFrameResourceFutures(); 178 179 std::optional<std::tuple<VkBuffer, VkDeviceMemory>> createBuffer(VkDeviceSize, 180 VkBufferUsageFlags, 181 VkMemoryPropertyFlags) const; 182 std::tuple<VkBuffer, VkDeviceMemory> createStagingBufferWithData(const void* data, 183 VkDeviceSize size) const; 184 void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize) const; 185 186 VkFormatFeatureFlags getFormatFeatures(VkFormat format, VkImageTiling tiling); 187 188 // Check if the ColorBuffer can be used as a compose layer to be sampled from. 189 bool canCompositeFrom(const VkImageCreateInfo& info); 190 191 // Check if the ColorBuffer can be used as a render target of a composition. 192 bool canCompositeTo(const VkImageCreateInfo& info); 193 194 // A consolidated view of a `Compositor::CompositionRequestLayer` with only 195 // the Vulkan components needed for command recording and submission. 196 struct CompositionLayerVk { 197 VkImage image = VK_NULL_HANDLE; 198 VkImageView imageView = VK_NULL_HANDLE; 199 VkImageLayout preCompositionLayout = VK_IMAGE_LAYOUT_UNDEFINED; 200 uint32_t preCompositionQueueFamilyIndex = 0; 201 VkImageLayout postCompositionLayout = VK_IMAGE_LAYOUT_UNDEFINED; 202 uint32_t postCompositionQueueFamilyIndex = 0; 203 }; 204 205 // A consolidated view of a `Compositor::CompositionRequest` with only 206 // the Vulkan components needed for command recording and submission. 207 struct CompositionVk { 208 const BorrowedImageInfoVk* targetImage = nullptr; 209 VkRenderPass targetRenderPass = VK_NULL_HANDLE; 210 VkFramebuffer targetFramebuffer = VK_NULL_HANDLE; 211 VkPipeline pipeline = VK_NULL_HANDLE; 212 std::vector<const BorrowedImageInfoVk*> layersSourceImages; 213 FrameDescriptorSetsContents layersDescriptorSets; 214 }; 215 void buildCompositionVk(const CompositionRequest& compositionRequest, 216 CompositionVk* compositionVk); 217 218 void updateDescriptorSetsIfChanged(const FrameDescriptorSetsContents& contents, 219 PerFrameResources* frameResources); 220 221 class RenderTarget { 222 public: 223 ~RenderTarget(); 224 225 DISALLOW_COPY_ASSIGN_AND_MOVE(RenderTarget); 226 227 private: 228 friend class CompositorVk; 229 RenderTarget(const VulkanDispatch& vk, VkDevice vkDevice, VkImage vkImage, 230 VkImageView vkImageView, uint32_t width, uint32_t height, 231 VkRenderPass vkRenderPass); 232 233 const VulkanDispatch& m_vk; 234 VkDevice m_vkDevice; 235 VkImage m_vkImage; 236 VkFramebuffer m_vkFramebuffer; 237 uint32_t m_width; 238 uint32_t m_height; 239 }; 240 241 // Gets the RenderTarget used for composing into the given image if it already exists, 242 // otherwise creates it. 243 RenderTarget* getOrCreateRenderTargetInfo(const BorrowedImageInfoVk& info); 244 245 // Cached format properties used for checking if composition is supported with a given 246 // format. 247 std::unordered_map<VkFormat, VkFormatProperties> m_vkFormatProperties; 248 249 uint32_t m_maxFramesInFlight = 0; 250 251 static constexpr const VkFormat k_renderTargetFormat = VK_FORMAT_R8G8B8A8_UNORM; 252 static constexpr const uint32_t k_renderTargetCacheSize = 128; 253 // Maps from borrowed image ids to render target info. 254 android::base::LruCache<uint32_t, std::unique_ptr<RenderTarget>> m_renderTargetCache; 255 }; 256 257 } // namespace vk 258 } // namespace gfxstream 259 260 #endif /* COMPOSITOR_VK_H */ 261