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