blob: d871d9ce34ccdb29b1694ccc15980922134d9bd6 [file] [log] [blame]
#ifndef DISPLAY_VK_H
#define DISPLAY_VK_H
#include <deque>
#include <functional>
#include <future>
#include <memory>
#include <optional>
#include <tuple>
#include <unordered_map>
#include <unordered_set>
#include "CompositorVk.h"
#include "Hwc2.h"
#include "RenderContext.h"
#include "SwapChainStateVk.h"
#include "base/Lock.h"
#include "vulkan/cereal/common/goldfish_vk_dispatch.h"
// The DisplayVk class holds the Vulkan and other states required to draw a
// frame in a host window.
class DisplayVk {
public:
class DisplayBufferInfo {
public:
~DisplayBufferInfo();
private:
DisplayBufferInfo(const goldfish_vk::VulkanDispatch &, VkDevice, const VkImageCreateInfo &,
VkImage);
const goldfish_vk::VulkanDispatch &m_vk;
VkDevice m_vkDevice;
VkImageCreateInfo m_vkImageCreateInfo;
VkImage m_vkImage;
VkImageView m_vkImageView;
// m_compositorVkRenderTarget will be created when the first time the ColorBuffer is used as
// the render target of DisplayVk::compose. DisplayVk owns the m_compositorVkRenderTarget so
// that when the CompositorVk is recreated m_compositorVkRenderTarget can be restored to
// nullptr.
std::weak_ptr<CompositorVkRenderTarget> m_compositorVkRenderTarget;
friend class DisplayVk;
};
DisplayVk(const goldfish_vk::VulkanDispatch &, VkPhysicalDevice,
uint32_t swapChainQueueFamilyIndex, uint32_t compositorQueueFamilyIndex, VkDevice,
VkQueue compositorVkQueue, std::shared_ptr<android::base::Lock> compositorVkQueueLock,
VkQueue swapChainVkQueue, std::shared_ptr<android::base::Lock> swapChainVkQueueLock);
~DisplayVk();
void bindToSurface(VkSurfaceKHR, uint32_t width, uint32_t height);
// The caller is responsible to make sure the VkImage lives longer than the DisplayBufferInfo
// created here.
std::shared_ptr<DisplayBufferInfo> createDisplayBuffer(VkImage, const VkImageCreateInfo &);
// The first component of the returned tuple is false when the swapchain is no longer valid and
// bindToSurface() needs to be called again. When the first component is true, the second
// component of the returned tuple is a/ future that will complete when the GPU side of work
// completes. The caller is responsible to guarantee the synchronization and the layout of
// DisplayBufferInfo::m_vkImage is VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL.
std::tuple<bool, std::shared_future<void>> post(std::shared_ptr<DisplayBufferInfo>);
// dstWidth and dstHeight describe the size of the render target the guest
// "thinks" it composes to, essentially, the virtual display size. Note that
// this can be different from the actual window size. The first component of
// the returned tuple is false when the swapchain is no longer valid and
// bindToSurface() needs to be called again. When the first component is
// true, the second component of the returned tuple is a future that will
// complete when the GPU side of work completes.
std::tuple<bool, std::shared_future<void>> compose(
uint32_t numLayers, const ComposeLayer layers[],
std::vector<std::shared_ptr<DisplayBufferInfo>> composeBuffers,
std::shared_ptr<DisplayBufferInfo> renderTarget);
private:
VkFormatFeatureFlags getFormatFeatures(VkFormat, VkImageTiling);
bool canPost(const VkImageCreateInfo &);
// Check if the VkImage can be used as the compose layer to be sampled from.
bool canCompositeFrom(const VkImageCreateInfo &);
// Check if the VkImage can be used as the render target of the composition.
bool canCompositeTo(const VkImageCreateInfo &);
// Returns if the composition specified by the parameter is different from
// the previous composition. If the composition is different, update the
// previous composition stored in m_surfaceState. Must be called after
// bindToSurface() is called.
bool compareAndSaveComposition(
uint32_t renderTargetIndex, uint32_t numLayers, const ComposeLayer layers[],
const std::vector<std::shared_ptr<DisplayBufferInfo>> &composeBuffers);
const goldfish_vk::VulkanDispatch &m_vk;
VkPhysicalDevice m_vkPhysicalDevice;
uint32_t m_swapChainQueueFamilyIndex;
uint32_t m_compositorQueueFamilyIndex;
VkDevice m_vkDevice;
VkQueue m_compositorVkQueue;
std::shared_ptr<android::base::Lock> m_compositorVkQueueLock;
VkQueue m_swapChainVkQueue;
std::shared_ptr<android::base::Lock> m_swapChainVkQueueLock;
VkCommandPool m_vkCommandPool;
VkSampler m_compositionVkSampler;
class PostResource {
public:
const VkFence m_swapchainImageReleaseFence;
const VkSemaphore m_swapchainImageAcquireSemaphore;
const VkSemaphore m_swapchainImageReleaseSemaphore;
const VkCommandBuffer m_vkCommandBuffer;
static std::shared_ptr<PostResource> create(const goldfish_vk::VulkanDispatch &, VkDevice,
VkCommandPool);
~PostResource();
DISALLOW_COPY_ASSIGN_AND_MOVE(PostResource);
private:
PostResource(const goldfish_vk::VulkanDispatch &, VkDevice, VkCommandPool,
VkFence swapchainImageReleaseFence, VkSemaphore swapchainImageAcquireSemaphore,
VkSemaphore swapchainImageReleaseSemaphore, VkCommandBuffer);
const goldfish_vk::VulkanDispatch &m_vk;
const VkDevice m_vkDevice;
const VkCommandPool m_vkCommandPool;
};
std::deque<std::shared_ptr<PostResource>> m_freePostResources;
std::optional<std::shared_future<std::shared_ptr<PostResource>>> m_postResourceFuture;
class ComposeResource {
public:
const VkFence m_composeCompleteFence;
const VkCommandBuffer m_vkCommandBuffer;
static std::unique_ptr<ComposeResource> create(const goldfish_vk::VulkanDispatch &,
VkDevice, VkCommandPool);
~ComposeResource();
DISALLOW_COPY_ASSIGN_AND_MOVE(ComposeResource);
private:
ComposeResource(const goldfish_vk::VulkanDispatch &, VkDevice, VkCommandPool, VkFence,
VkCommandBuffer);
const goldfish_vk::VulkanDispatch &m_vk;
const VkDevice m_vkDevice;
const VkCommandPool m_vkCommandPool;
};
int m_inFlightFrameIndex;
std::optional<std::future<std::unique_ptr<ComposeResource>>> m_composeResourceFuture;
std::unique_ptr<SwapChainStateVk> m_swapChainStateVk;
std::unique_ptr<CompositorVk> m_compositorVk;
static constexpr uint32_t k_compositorVkRenderTargetCacheSize = 128;
std::deque<std::shared_ptr<CompositorVkRenderTarget>> m_compositorVkRenderTargets;
static constexpr VkFormat k_compositorVkRenderTargetFormat = VK_FORMAT_R8G8B8A8_UNORM;
struct SurfaceState {
struct Layer {
ComposeLayer m_hwc2Layer;
std::weak_ptr<DisplayBufferInfo> m_displayBuffer;
};
uint32_t m_width = 0;
uint32_t m_height = 0;
std::unordered_map<uint32_t, std::vector<std::unique_ptr<Layer>>> m_prevCompositions;
};
std::unique_ptr<SurfaceState> m_surfaceState;
std::unordered_map<VkFormat, VkFormatProperties> m_vkFormatProperties;
};
#endif