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