• 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 "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