• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "vulkan/cereal/common/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 
58     // The underlying storage for all of the uniform buffer objects.
59     struct UniformBufferStorage {
60         VkBuffer m_vkBuffer = VK_NULL_HANDLE;
61         VkDeviceMemory m_vkDeviceMemory = VK_NULL_HANDLE;
62         VkDeviceSize m_stride = 0;
63     } m_uniformStorage;
64 
65     // Keep in sync with vulkan/Compositor.frag.
66     struct SamplerBinding {
67         VkImageView sampledImageView = VK_NULL_HANDLE;
68     };
69 
70     // Keep in sync with vulkan/Compositor.vert.
71     struct UniformBufferBinding {
72         alignas(16) glm::mat4 positionTransform;
73         alignas(16) glm::mat4 texCoordTransform;
74     };
75 
76     // The cached contents of a given descriptor set.
77     struct DescriptorSetContents {
78         SamplerBinding binding0;
79         UniformBufferBinding binding1;
80     };
81 
82     // The cached contents of all descriptors sets of a given frame.
83     struct FrameDescriptorSetsContents {
84         std::vector<DescriptorSetContents> descriptorSets;
85     };
86 
87     friend bool operator==(const DescriptorSetContents& lhs, const DescriptorSetContents& rhs);
88 
89     friend bool operator==(const FrameDescriptorSetsContents& lhs,
90                            const FrameDescriptorSetsContents& rhs);
91 
92     struct PerFrameResources {
93         VkFence m_vkFence = VK_NULL_HANDLE;
94         VkCommandBuffer m_vkCommandBuffer = VK_NULL_HANDLE;
95         std::vector<VkDescriptorSet> m_layerDescriptorSets;
96         // Pointers into the underlying uniform buffer storage for the uniform
97         // buffer of part of each descriptor set for each layer.
98         std::vector<UniformBufferBinding*> m_layerUboStorages;
99         std::optional<FrameDescriptorSetsContents> m_vkDescriptorSetsContents;
100     };
101     std::vector<PerFrameResources> m_frameResources;
102     std::deque<std::shared_future<PerFrameResources*>> m_availableFrameResources;
103 
CompositorVkBaseCompositorVkBase104     explicit CompositorVkBase(const VulkanDispatch& vk, VkDevice device,
105                               VkPhysicalDevice physicalDevice, VkQueue queue,
106                               std::shared_ptr<android::base::Lock> queueLock,
107                               uint32_t queueFamilyIndex, uint32_t maxFramesInFlight)
108         : m_vk(vk),
109           m_vkDevice(device),
110           m_vkPhysicalDevice(physicalDevice),
111           m_vkQueue(queue),
112           m_queueFamilyIndex(queueFamilyIndex),
113           m_vkQueueLock(queueLock),
114           m_vkDescriptorSetLayout(VK_NULL_HANDLE),
115           m_vkPipelineLayout(VK_NULL_HANDLE),
116           m_vkRenderPass(VK_NULL_HANDLE),
117           m_graphicsVkPipeline(VK_NULL_HANDLE),
118           m_vertexVkBuffer(VK_NULL_HANDLE),
119           m_vertexVkDeviceMemory(VK_NULL_HANDLE),
120           m_indexVkBuffer(VK_NULL_HANDLE),
121           m_indexVkDeviceMemory(VK_NULL_HANDLE),
122           m_vkDescriptorPool(VK_NULL_HANDLE),
123           m_vkCommandPool(VK_NULL_HANDLE),
124           m_vkSampler(VK_NULL_HANDLE),
125           m_frameResources(maxFramesInFlight) {}
126 };
127 
128 class CompositorVk : protected CompositorVkBase, public Compositor {
129    public:
130     static std::unique_ptr<CompositorVk> create(const VulkanDispatch& vk, VkDevice vkDevice,
131                                                 VkPhysicalDevice vkPhysicalDevice, VkQueue vkQueue,
132                                                 std::shared_ptr<android::base::Lock> queueLock,
133                                                 uint32_t queueFamilyIndex,
134                                                 uint32_t maxFramesInFlight);
135 
136     ~CompositorVk();
137 
138     CompositionFinishedWaitable compose(const CompositionRequest& compositionRequest) override;
139 
140     void onImageDestroyed(uint32_t imageId) override;
141 
queueSupportsComposition(const VkQueueFamilyProperties & properties)142     static bool queueSupportsComposition(const VkQueueFamilyProperties& properties) {
143         return properties.queueFlags & VK_QUEUE_GRAPHICS_BIT;
144     }
145 
146    private:
147     explicit CompositorVk(const VulkanDispatch&, VkDevice, VkPhysicalDevice, VkQueue,
148                           std::shared_ptr<android::base::Lock> queueLock, uint32_t queueFamilyIndex,
149                           uint32_t maxFramesInFlight);
150 
151     void setUpGraphicsPipeline();
152     void setUpVertexBuffers();
153     void setUpSampler();
154     void setUpDescriptorSets();
155     void setUpUniformBuffers();
156     void setUpCommandPool();
157     void setUpFences();
158     void setUpFrameResourceFutures();
159 
160     std::optional<std::tuple<VkBuffer, VkDeviceMemory>> createBuffer(VkDeviceSize,
161                                                                      VkBufferUsageFlags,
162                                                                      VkMemoryPropertyFlags) const;
163     std::tuple<VkBuffer, VkDeviceMemory> createStagingBufferWithData(const void* data,
164                                                                      VkDeviceSize size) const;
165     void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize) const;
166 
167     VkFormatFeatureFlags getFormatFeatures(VkFormat format, VkImageTiling tiling);
168 
169     // Check if the ColorBuffer can be used as a compose layer to be sampled from.
170     bool canCompositeFrom(const VkImageCreateInfo& info);
171 
172     // Check if the ColorBuffer can be used as a render target of a composition.
173     bool canCompositeTo(const VkImageCreateInfo& info);
174 
175     // A consolidated view of a `Compositor::CompositionRequestLayer` with only
176     // the Vulkan components needed for command recording and submission.
177     struct CompositionLayerVk {
178         VkImage image = VK_NULL_HANDLE;
179         VkImageView imageView = VK_NULL_HANDLE;
180         VkImageLayout preCompositionLayout = VK_IMAGE_LAYOUT_UNDEFINED;
181         uint32_t preCompositionQueueFamilyIndex = 0;
182         VkImageLayout postCompositionLayout = VK_IMAGE_LAYOUT_UNDEFINED;
183         uint32_t postCompositionQueueFamilyIndex = 0;
184     };
185 
186     // A consolidated view of a `Compositor::CompositionRequest` with only
187     // the Vulkan components needed for command recording and submission.
188     struct CompositionVk {
189         const BorrowedImageInfoVk* targetImage = nullptr;
190         VkFramebuffer targetFramebuffer = VK_NULL_HANDLE;
191         std::vector<const BorrowedImageInfoVk*> layersSourceImages;
192         FrameDescriptorSetsContents layersDescriptorSets;
193     };
194     void buildCompositionVk(const CompositionRequest& compositionRequest,
195                             CompositionVk* compositionVk);
196 
197     void updateDescriptorSetsIfChanged(const FrameDescriptorSetsContents& contents,
198                                        PerFrameResources* frameResources);
199 
200     class RenderTarget {
201        public:
202         ~RenderTarget();
203 
204         DISALLOW_COPY_ASSIGN_AND_MOVE(RenderTarget);
205 
206        private:
207         friend class CompositorVk;
208         RenderTarget(const VulkanDispatch& vk, VkDevice vkDevice, VkImage vkImage,
209                      VkImageView vkImageView, uint32_t width, uint32_t height,
210                      VkRenderPass vkRenderPass);
211 
212         const VulkanDispatch& m_vk;
213         VkDevice m_vkDevice;
214         VkImage m_vkImage;
215         VkFramebuffer m_vkFramebuffer;
216         uint32_t m_width;
217         uint32_t m_height;
218     };
219 
220     // Gets the RenderTarget used for composing into the given image if it already exists,
221     // otherwise creates it.
222     RenderTarget* getOrCreateRenderTargetInfo(const BorrowedImageInfoVk& info);
223 
224     // Cached format properties used for checking if composition is supported with a given
225     // format.
226     std::unordered_map<VkFormat, VkFormatProperties> m_vkFormatProperties;
227 
228     uint32_t m_maxFramesInFlight = 0;
229 
230     static constexpr const VkFormat k_renderTargetFormat = VK_FORMAT_R8G8B8A8_UNORM;
231     static constexpr const uint32_t k_renderTargetCacheSize = 128;
232     // Maps from borrowed image ids to render target info.
233     android::base::LruCache<uint32_t, std::unique_ptr<RenderTarget>> m_renderTargetCache;
234 };
235 
236 }  // namespace vk
237 }  // namespace gfxstream
238 
239 #endif /* COMPOSITOR_VK_H */
240