• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef DISPLAY_VK_H
2 #define DISPLAY_VK_H
3 
4 #include <deque>
5 #include <functional>
6 #include <future>
7 #include <memory>
8 #include <optional>
9 #include <tuple>
10 #include <unordered_map>
11 #include <unordered_set>
12 
13 #include "CompositorVk.h"
14 #include "Hwc2.h"
15 #include "RenderContext.h"
16 #include "SwapChainStateVk.h"
17 #include "base/Lock.h"
18 #include "vulkan/cereal/common/goldfish_vk_dispatch.h"
19 
20 // The DisplayVk class holds the Vulkan and other states required to draw a
21 // frame in a host window.
22 
23 class DisplayVk {
24    public:
25     class DisplayBufferInfo {
26        public:
27         ~DisplayBufferInfo();
28 
29        private:
30         DisplayBufferInfo(const goldfish_vk::VulkanDispatch &, VkDevice, const VkImageCreateInfo &,
31                           VkImage);
32 
33         const goldfish_vk::VulkanDispatch &m_vk;
34         VkDevice m_vkDevice;
35         VkImageCreateInfo m_vkImageCreateInfo;
36 
37         VkImage m_vkImage;
38         VkImageView m_vkImageView;
39         // m_compositorVkRenderTarget will be created when the first time the ColorBuffer is used as
40         // the render target of DisplayVk::compose. DisplayVk owns the m_compositorVkRenderTarget so
41         // that when the CompositorVk is recreated m_compositorVkRenderTarget can be restored to
42         // nullptr.
43         std::weak_ptr<CompositorVkRenderTarget> m_compositorVkRenderTarget;
44 
45         friend class DisplayVk;
46     };
47     DisplayVk(const goldfish_vk::VulkanDispatch &, VkPhysicalDevice,
48               uint32_t swapChainQueueFamilyIndex, uint32_t compositorQueueFamilyIndex, VkDevice,
49               VkQueue compositorVkQueue, std::shared_ptr<android::base::Lock> compositorVkQueueLock,
50               VkQueue swapChainVkQueue, std::shared_ptr<android::base::Lock> swapChainVkQueueLock);
51     ~DisplayVk();
52     void bindToSurface(VkSurfaceKHR, uint32_t width, uint32_t height);
53     // The caller is responsible to make sure the VkImage lives longer than the DisplayBufferInfo
54     // created here.
55     std::shared_ptr<DisplayBufferInfo> createDisplayBuffer(VkImage, const VkImageCreateInfo &);
56     // The first component of the returned tuple is false when the swapchain is no longer valid and
57     // bindToSurface() needs to be called again. When the first component is true, the second
58     // component of the returned tuple is a/ future that will complete when the GPU side of work
59     // completes. The caller is responsible to guarantee the synchronization and the layout of
60     // DisplayBufferInfo::m_vkImage is VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL.
61     std::tuple<bool, std::shared_future<void>> post(std::shared_ptr<DisplayBufferInfo>);
62 
63     // dstWidth and dstHeight describe the size of the render target the guest
64     // "thinks" it composes to, essentially, the virtual display size. Note that
65     // this can be different from the actual window size. The first component of
66     // the returned tuple is false when the swapchain is no longer valid and
67     // bindToSurface() needs to be called again. When the first component is
68     // true, the second component of the returned tuple is a future that will
69     // complete when the GPU side of work completes.
70     std::tuple<bool, std::shared_future<void>> compose(
71         uint32_t numLayers, const ComposeLayer layers[],
72         std::vector<std::shared_ptr<DisplayBufferInfo>> composeBuffers,
73         std::shared_ptr<DisplayBufferInfo> renderTarget);
74 
75    private:
76     VkFormatFeatureFlags getFormatFeatures(VkFormat, VkImageTiling);
77     bool canPost(const VkImageCreateInfo &);
78     // Check if the VkImage can be used as the compose layer to be sampled from.
79     bool canCompositeFrom(const VkImageCreateInfo &);
80     // Check if the VkImage can be used as the render target of the composition.
81     bool canCompositeTo(const VkImageCreateInfo &);
82     // Returns if the composition specified by the parameter is different from
83     // the previous composition. If the composition is different, update the
84     // previous composition stored in m_surfaceState. Must be called after
85     // bindToSurface() is called.
86     bool compareAndSaveComposition(
87         uint32_t renderTargetIndex, uint32_t numLayers, const ComposeLayer layers[],
88         const std::vector<std::shared_ptr<DisplayBufferInfo>> &composeBuffers);
89 
90     const goldfish_vk::VulkanDispatch &m_vk;
91     VkPhysicalDevice m_vkPhysicalDevice;
92     uint32_t m_swapChainQueueFamilyIndex;
93     uint32_t m_compositorQueueFamilyIndex;
94     VkDevice m_vkDevice;
95     VkQueue m_compositorVkQueue;
96     std::shared_ptr<android::base::Lock> m_compositorVkQueueLock;
97     VkQueue m_swapChainVkQueue;
98     std::shared_ptr<android::base::Lock> m_swapChainVkQueueLock;
99     VkCommandPool m_vkCommandPool;
100     VkSampler m_compositionVkSampler;
101 
102     class PostResource {
103        public:
104         const VkFence m_swapchainImageReleaseFence;
105         const VkSemaphore m_swapchainImageAcquireSemaphore;
106         const VkSemaphore m_swapchainImageReleaseSemaphore;
107         const VkCommandBuffer m_vkCommandBuffer;
108         static std::shared_ptr<PostResource> create(const goldfish_vk::VulkanDispatch &, VkDevice,
109                                                     VkCommandPool);
110         ~PostResource();
111         DISALLOW_COPY_ASSIGN_AND_MOVE(PostResource);
112 
113        private:
114         PostResource(const goldfish_vk::VulkanDispatch &, VkDevice, VkCommandPool,
115                      VkFence swapchainImageReleaseFence, VkSemaphore swapchainImageAcquireSemaphore,
116                      VkSemaphore swapchainImageReleaseSemaphore, VkCommandBuffer);
117         const goldfish_vk::VulkanDispatch &m_vk;
118         const VkDevice m_vkDevice;
119         const VkCommandPool m_vkCommandPool;
120     };
121 
122     std::deque<std::shared_ptr<PostResource>> m_freePostResources;
123     std::optional<std::shared_future<std::shared_ptr<PostResource>>> m_postResourceFuture;
124 
125     class ComposeResource {
126        public:
127         const VkFence m_composeCompleteFence;
128         const VkCommandBuffer m_vkCommandBuffer;
129         static std::unique_ptr<ComposeResource> create(const goldfish_vk::VulkanDispatch &,
130                                                        VkDevice, VkCommandPool);
131         ~ComposeResource();
132         DISALLOW_COPY_ASSIGN_AND_MOVE(ComposeResource);
133 
134        private:
135         ComposeResource(const goldfish_vk::VulkanDispatch &, VkDevice, VkCommandPool, VkFence,
136                         VkCommandBuffer);
137         const goldfish_vk::VulkanDispatch &m_vk;
138         const VkDevice m_vkDevice;
139         const VkCommandPool m_vkCommandPool;
140     };
141 
142     int m_inFlightFrameIndex;
143     std::optional<std::future<std::unique_ptr<ComposeResource>>> m_composeResourceFuture;
144 
145     std::unique_ptr<SwapChainStateVk> m_swapChainStateVk;
146     std::unique_ptr<CompositorVk> m_compositorVk;
147     static constexpr uint32_t k_compositorVkRenderTargetCacheSize = 128;
148     std::deque<std::shared_ptr<CompositorVkRenderTarget>> m_compositorVkRenderTargets;
149     static constexpr VkFormat k_compositorVkRenderTargetFormat = VK_FORMAT_R8G8B8A8_UNORM;
150     struct SurfaceState {
151         struct Layer {
152             ComposeLayer m_hwc2Layer;
153             std::weak_ptr<DisplayBufferInfo> m_displayBuffer;
154         };
155 
156         uint32_t m_width = 0;
157         uint32_t m_height = 0;
158         std::unordered_map<uint32_t, std::vector<std::unique_ptr<Layer>>> m_prevCompositions;
159     };
160     std::unique_ptr<SurfaceState> m_surfaceState;
161 
162     std::unordered_map<VkFormat, VkFormatProperties> m_vkFormatProperties;
163 };
164 
165 #endif
166