You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

360 lines
16 KiB

#include "DisplayVk.h"
#include <glm/glm.hpp>
#include <glm/gtx/matrix_transform_2d.hpp>
#include "ErrorLog.h"
DisplayVk::DisplayVk(const goldfish_vk::VulkanDispatch &vk,
VkPhysicalDevice vkPhysicalDevice,
uint32_t swapChainQueueFamilyIndex,
uint32_t compositorQueueFamilyIndex, VkDevice vkDevice,
VkQueue compositorVkQueue, VkQueue swapChainVkqueue)
: m_vk(vk),
m_vkPhysicalDevice(vkPhysicalDevice),
m_swapChainQueueFamilyIndex(swapChainQueueFamilyIndex),
m_compositorQueueFamilyIndex(compositorQueueFamilyIndex),
m_vkDevice(vkDevice),
m_compositorVkQueue(compositorVkQueue),
m_swapChainVkQueue(swapChainVkqueue),
m_vkCommandPool(VK_NULL_HANDLE),
m_swapChainStateVk(nullptr),
m_compositorVk(nullptr),
m_surfaceState(nullptr),
m_canComposite() {
// TODO(kaiyili): validate the capabilites of the passed in Vulkan
// components.
VkCommandPoolCreateInfo commandPoolCi = {
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.queueFamilyIndex = m_compositorQueueFamilyIndex,
};
VK_CHECK(m_vk.vkCreateCommandPool(m_vkDevice, &commandPoolCi, nullptr,
&m_vkCommandPool));
VkFenceCreateInfo fenceCi = {.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
.flags = VK_FENCE_CREATE_SIGNALED_BIT};
VK_CHECK(m_vk.vkCreateFence(m_vkDevice, &fenceCi, nullptr,
&m_frameDrawCompleteFence));
VkSemaphoreCreateInfo semaphoreCi = {
.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
VK_CHECK(m_vk.vkCreateSemaphore(m_vkDevice, &semaphoreCi, nullptr,
&m_imageReadySem));
VK_CHECK(m_vk.vkCreateSemaphore(m_vkDevice, &semaphoreCi, nullptr,
&m_frameDrawCompleteSem));
VkSamplerCreateInfo samplerCi = {
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
.magFilter = VK_FILTER_NEAREST,
.minFilter = VK_FILTER_NEAREST,
.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR,
.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER,
.mipLodBias = 0.0f,
.anisotropyEnable = VK_FALSE,
.maxAnisotropy = 1.0f,
.compareEnable = VK_FALSE,
.compareOp = VK_COMPARE_OP_ALWAYS,
.minLod = 0.0f,
.maxLod = 0.0f,
.borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK,
.unnormalizedCoordinates = VK_FALSE};
VK_CHECK(m_vk.vkCreateSampler(m_vkDevice, &samplerCi, nullptr,
&m_compositionVkSampler));
}
DisplayVk::~DisplayVk() {
m_vk.vkDestroySampler(m_vkDevice, m_compositionVkSampler, nullptr);
m_vk.vkDestroySemaphore(m_vkDevice, m_imageReadySem, nullptr);
m_vk.vkDestroySemaphore(m_vkDevice, m_frameDrawCompleteSem, nullptr);
m_vk.vkDestroyFence(m_vkDevice, m_frameDrawCompleteFence, nullptr);
m_compositorVk.reset();
m_swapChainStateVk.reset();
m_vk.vkDestroyCommandPool(m_vkDevice, m_vkCommandPool, nullptr);
}
void DisplayVk::bindToSurface(VkSurfaceKHR surface, uint32_t width,
uint32_t height) {
if (!SwapChainStateVk::validateQueueFamilyProperties(
m_vk, m_vkPhysicalDevice, surface, m_swapChainQueueFamilyIndex)) {
ERR("%s(%s:%d): DisplayVk can't create VkSwapchainKHR with given "
"VkDevice and VkSurfaceKHR.\n",
__FUNCTION__, __FILE__, static_cast<int>(__LINE__));
::abort();
}
auto swapChainCi = SwapChainStateVk::createSwapChainCi(
m_vk, surface, m_vkPhysicalDevice, width, height,
{m_swapChainQueueFamilyIndex, m_compositorQueueFamilyIndex});
VkFormatProperties formatProps;
m_vk.vkGetPhysicalDeviceFormatProperties(
m_vkPhysicalDevice, swapChainCi->imageFormat, &formatProps);
if (!(formatProps.optimalTilingFeatures &
VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
ERR("%s(%s:%d): DisplayVk: The image format chosen for present VkImage "
"can't be used as the color attachment, and therefore can't be "
"used as the render target of CompositorVk.\n",
__FUNCTION__, __FILE__, static_cast<int>(__LINE__));
::abort();
}
m_swapChainStateVk =
std::make_unique<SwapChainStateVk>(m_vk, m_vkDevice, *swapChainCi);
m_compositorVk = CompositorVk::create(
m_vk, m_vkDevice, m_vkPhysicalDevice, m_compositorVkQueue,
m_swapChainStateVk->getFormat(), VK_IMAGE_LAYOUT_UNDEFINED,
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, width, height,
m_swapChainStateVk->getVkImageViews(), m_vkCommandPool);
auto surfaceState = std::make_unique<SurfaceState>();
surfaceState->m_height = height;
surfaceState->m_width = width;
m_surfaceState = std::move(surfaceState);
}
std::shared_ptr<DisplayVk::DisplayBufferInfo> DisplayVk::createDisplayBuffer(
VkImage image, VkFormat format, uint32_t width, uint32_t height) {
return std::shared_ptr<DisplayBufferInfo>(
new DisplayBufferInfo(m_vk, m_vkDevice, width, height, format, image));
}
void DisplayVk::post(
const std::shared_ptr<DisplayBufferInfo> &displayBufferPtr) {
if (!displayBufferPtr) {
fprintf(stderr, "%s: warning: null ptr passed to post buffer\n",
__func__);
return;
}
ComposeLayer composeLayer = {
0,
HWC2_COMPOSITION_DEVICE,
{0, 0, static_cast<int>(displayBufferPtr->m_width),
static_cast<int>(displayBufferPtr->m_height)},
{0.0f, 0.0f, static_cast<float>(displayBufferPtr->m_width),
static_cast<float>(displayBufferPtr->m_height)},
HWC2_BLEND_MODE_PREMULTIPLIED,
1.0f,
{0, 0, 0, 0},
static_cast<hwc_transform_t>(0) /* transform */
};
compose(1, &composeLayer, {std::move(displayBufferPtr)});
}
void DisplayVk::compose(
uint32_t numLayers, const ComposeLayer layers[],
const std::vector<std::shared_ptr<DisplayBufferInfo>> &composeBuffers) {
if (!m_swapChainStateVk || !m_compositorVk || !m_surfaceState) {
ERR("%s(%s:%d): Haven't bound to a surface, can't compose color "
"buffer.\n",
__FUNCTION__, __FILE__, static_cast<int>(__LINE__));
return;
}
auto &surfaceState = *m_surfaceState;
std::vector<std::unique_ptr<ComposeLayerVk>> composeLayers;
for (int i = 0; i < numLayers; ++i) {
if (!composeBuffers[i]) {
fprintf(
stderr,
"%s: warning: null ptr passed to compose buffer for layer %d\n",
__func__, i);
continue;
}
const auto &db = *composeBuffers[i];
if (!canComposite(db.m_vkFormat)) {
ERR("%s(%s:%d): Can't composite the DisplayBuffer(0x%" PRIxPTR
"). The image(VkFormat = %" PRIu64 ") can't be sampled from.\n",
__FUNCTION__, __FILE__, static_cast<int>(__LINE__),
reinterpret_cast<uintptr_t>(&db),
static_cast<uint64_t>(db.m_vkFormat));
continue;
}
auto layer = ComposeLayerVk::createFromHwc2ComposeLayer(
m_compositionVkSampler, composeBuffers[i]->m_vkImageView, layers[i],
composeBuffers[i]->m_width, composeBuffers[i]->m_height,
surfaceState.m_width, surfaceState.m_height);
composeLayers.emplace_back(std::move(layer));
}
if (composeLayers.empty()) {
return;
}
VK_CHECK(m_vk.vkWaitForFences(m_vkDevice, 1, &m_frameDrawCompleteFence,
VK_TRUE, UINT64_MAX));
uint32_t imageIndex;
VK_CHECK(m_vk.vkAcquireNextImageKHR(
m_vkDevice, m_swapChainStateVk->getSwapChain(), UINT64_MAX,
m_imageReadySem, VK_NULL_HANDLE, &imageIndex));
if (compareAndSaveComposition(imageIndex, numLayers, layers,
composeBuffers)) {
auto composition =
std::make_unique<Composition>(std::move(composeLayers));
m_compositorVk->setComposition(imageIndex, std::move(composition));
}
auto cmdBuff = m_compositorVk->getCommandBuffer(imageIndex);
VK_CHECK(m_vk.vkResetFences(m_vkDevice, 1, &m_frameDrawCompleteFence));
VkPipelineStageFlags waitStages[] = {
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT};
VkSubmitInfo submitInfo = {.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &m_imageReadySem,
.pWaitDstStageMask = waitStages,
.commandBufferCount = 1,
.pCommandBuffers = &cmdBuff,
.signalSemaphoreCount = 1,
.pSignalSemaphores = &m_frameDrawCompleteSem};
VK_CHECK(m_vk.vkQueueSubmit(m_compositorVkQueue, 1, &submitInfo,
m_frameDrawCompleteFence));
auto swapChain = m_swapChainStateVk->getSwapChain();
VkPresentInfoKHR presentInfo = {.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.waitSemaphoreCount = 1,
.pWaitSemaphores = &m_frameDrawCompleteSem,
.swapchainCount = 1,
.pSwapchains = &swapChain,
.pImageIndices = &imageIndex};
VK_CHECK(m_vk.vkQueuePresentKHR(m_swapChainVkQueue, &presentInfo));
VK_CHECK(m_vk.vkWaitForFences(m_vkDevice, 1, &m_frameDrawCompleteFence,
VK_TRUE, UINT64_MAX));
}
bool DisplayVk::canComposite(VkFormat format) {
auto it = m_canComposite.find(format);
if (it != m_canComposite.end()) {
return it->second;
}
VkFormatProperties formatProps = {};
m_vk.vkGetPhysicalDeviceFormatProperties(m_vkPhysicalDevice, format,
&formatProps);
bool res =
formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT;
m_canComposite.emplace(format, res);
return res;
}
bool DisplayVk::compareAndSaveComposition(
uint32_t renderTargetIndex, uint32_t numLayers, const ComposeLayer layers[],
const std::vector<std::shared_ptr<DisplayBufferInfo>> &composeBuffers) {
if (!m_surfaceState) {
ERR("%s(%s:%d): Haven't bound to a surface, can't compare and save "
"composition\n",
__FUNCTION__, __FILE__, static_cast<int>(__LINE__));
::abort();
}
auto [iPrevComposition, compositionNotFound] =
m_surfaceState->m_prevCompositions.emplace(renderTargetIndex, 0);
auto &prevComposition = iPrevComposition->second;
bool compositionChanged = false;
if (numLayers == prevComposition.size()) {
for (int i = 0; i < numLayers; i++) {
if (composeBuffers[i] == nullptr) {
// If the display buffer of the current layer doesn't exist, we
// check if the layer at the same index in the previous
// composition doesn't exist either.
if (prevComposition[i] == nullptr) {
continue;
} else {
compositionChanged = true;
break;
}
}
if (prevComposition[i] == nullptr) {
// If the display buffer of the current layer exists but the
// layer at the same index in the previous composition doesn't
// exist, the composition is changed.
compositionChanged = true;
break;
}
const auto &prevLayer = *prevComposition[i];
const auto prevDisplayBufferPtr = prevLayer.m_displayBuffer.lock();
// prevLayer.m_displayBuffer is a weak pointer, so if
// prevDisplayBufferPtr is null, the color buffer
// prevDisplayBufferPtr pointed to should have been released or
// re-allocated, and we should consider the composition is changed.
// If prevDisplayBufferPtr exists and it points to the same display
// buffer as the input composeBuffers[i] we consider the composition
// not changed.
if (!prevDisplayBufferPtr ||
prevDisplayBufferPtr != composeBuffers[i]) {
compositionChanged = true;
break;
}
const auto &prevHwc2Layer = prevLayer.m_hwc2Layer;
const auto hwc2Layer = layers[i];
compositionChanged =
(prevHwc2Layer.cbHandle != hwc2Layer.cbHandle) ||
(prevHwc2Layer.composeMode != hwc2Layer.composeMode) ||
(prevHwc2Layer.displayFrame.left !=
hwc2Layer.displayFrame.left) ||
(prevHwc2Layer.displayFrame.top !=
hwc2Layer.displayFrame.top) ||
(prevHwc2Layer.displayFrame.right !=
hwc2Layer.displayFrame.right) ||
(prevHwc2Layer.displayFrame.bottom !=
hwc2Layer.displayFrame.bottom) ||
(prevHwc2Layer.crop.left != hwc2Layer.crop.left) ||
(prevHwc2Layer.crop.top != hwc2Layer.crop.top) ||
(prevHwc2Layer.crop.right != hwc2Layer.crop.right) ||
(prevHwc2Layer.crop.bottom != hwc2Layer.crop.bottom) ||
(prevHwc2Layer.blendMode != hwc2Layer.blendMode) ||
(prevHwc2Layer.alpha != hwc2Layer.alpha) ||
(prevHwc2Layer.color.r != hwc2Layer.color.r) ||
(prevHwc2Layer.color.g != hwc2Layer.color.g) ||
(prevHwc2Layer.color.b != hwc2Layer.color.b) ||
(prevHwc2Layer.color.a != hwc2Layer.color.a) ||
(prevHwc2Layer.transform != hwc2Layer.transform);
if (compositionChanged) {
break;
}
}
} else {
compositionChanged = true;
}
bool needsSave = compositionNotFound || compositionChanged;
if (needsSave) {
prevComposition.clear();
for (int i = 0; i < numLayers; i++) {
if (composeBuffers[i] == nullptr) {
prevComposition.emplace_back(nullptr);
continue;
}
auto layer = std::make_unique<SurfaceState::Layer>();
layer->m_hwc2Layer = layers[i];
layer->m_displayBuffer = composeBuffers[i];
prevComposition.emplace_back(std::move(layer));
}
}
return needsSave;
}
DisplayVk::DisplayBufferInfo::DisplayBufferInfo(
const goldfish_vk::VulkanDispatch &vk, VkDevice vkDevice, uint32_t width,
uint32_t height, VkFormat format, VkImage image)
: m_vk(vk),
m_vkDevice(vkDevice),
m_width(width),
m_height(height),
m_vkFormat(format),
m_vkImageView(VK_NULL_HANDLE) {
VkImageViewCreateInfo imageViewCi = {
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
.image = image,
.viewType = VK_IMAGE_VIEW_TYPE_2D,
.format = format,
.components = {.r = VK_COMPONENT_SWIZZLE_IDENTITY,
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
.a = VK_COMPONENT_SWIZZLE_IDENTITY},
.subresourceRange = {.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0,
.levelCount = 1,
.baseArrayLayer = 0,
.layerCount = 1}};
VK_CHECK(m_vk.vkCreateImageView(m_vkDevice, &imageViewCi, nullptr,
&m_vkImageView));
}
DisplayVk::DisplayBufferInfo::~DisplayBufferInfo() {
m_vk.vkDestroyImageView(m_vkDevice, m_vkImageView, nullptr);
}