blob: 78e50461c601dc6ae077356593de45cbbff8cc30 [file] [log] [blame]
#include "DisplayVk.h"
#include <glm/glm.hpp>
#include <glm/gtx/matrix_transform_2d.hpp>
#include "ErrorLog.h"
#include "NativeSubWindow.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 = {};
commandPoolCi.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
commandPoolCi.queueFamilyIndex = m_compositorQueueFamilyIndex;
VK_CHECK(m_vk.vkCreateCommandPool(m_vkDevice, &commandPoolCi, nullptr,
&m_vkCommandPool));
VkFenceCreateInfo fenceCi = {};
fenceCi.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fenceCi.flags = VK_FENCE_CREATE_SIGNALED_BIT;
VK_CHECK(m_vk.vkCreateFence(m_vkDevice, &fenceCi, nullptr,
&m_frameDrawCompleteFence));
VkSemaphoreCreateInfo semaphoreCi = {};
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 = {};
samplerCi.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
samplerCi.magFilter = VK_FILTER_NEAREST;
samplerCi.minFilter = VK_FILTER_NEAREST;
samplerCi.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
samplerCi.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
samplerCi.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER;
samplerCi.anisotropyEnable = VK_FALSE;
samplerCi.maxAnisotropy = 1.0f;
samplerCi.borderColor = VK_BORDER_COLOR_INT_TRANSPARENT_BLACK;
samplerCi.unnormalizedCoordinates = VK_FALSE;
samplerCi.compareEnable = VK_FALSE;
samplerCi.compareOp = VK_COMPARE_OP_ALWAYS;
samplerCi.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
samplerCi.mipLodBias = 0.0f;
samplerCi.minLod = 0.0f;
samplerCi.maxLod = 0.0f;
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 (m_swapChainStateVk == nullptr || m_compositorVk == nullptr) {
ERR("%s(%s:%d): Haven't bound to a surface, can't post color buffer.\n",
__FUNCTION__, __FILE__, static_cast<int>(__LINE__));
return;
}
auto &surfaceState = *m_surfaceState;
const auto &db = *displayBufferPtr;
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));
auto maybePrevDisplayBuffer = surfaceState.m_prevDisplayBuffer.lock();
if (!maybePrevDisplayBuffer || maybePrevDisplayBuffer != displayBufferPtr) {
if (!canComposite(db.m_vkFormat)) {
ERR("%s(%s:%d): Can't composite the DisplayBuffer(0x%" PRIxPTR
"). The image(VkFormat = %" PRIu64 ") can be sampled from.\n",
__FUNCTION__, __FILE__, static_cast<int>(__LINE__),
reinterpret_cast<uintptr_t>(displayBufferPtr.get()),
static_cast<uint64_t>(db.m_vkFormat));
return;
}
auto composition = std::make_unique<Composition>(
db.m_vkImageView, m_compositionVkSampler, db.m_width, db.m_height);
composition->m_transform =
glm::scale(glm::mat3(1.0),
glm::vec2(static_cast<float>(surfaceState.m_width) /
static_cast<float>(db.m_width),
static_cast<float>(surfaceState.m_height) /
static_cast<float>(db.m_height)));
m_compositorVk->setComposition(imageIndex, std::move(composition));
surfaceState.m_prevDisplayBuffer = displayBufferPtr;
}
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 = {};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.waitSemaphoreCount = 1;
submitInfo.pWaitSemaphores = &m_imageReadySem;
submitInfo.pWaitDstStageMask = waitStages;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &cmdBuff;
submitInfo.signalSemaphoreCount = 1;
submitInfo.pSignalSemaphores = &m_frameDrawCompleteSem;
VK_CHECK(m_vk.vkQueueSubmit(m_compositorVkQueue, 1, &submitInfo,
m_frameDrawCompleteFence));
auto swapChain = m_swapChainStateVk->getSwapChain();
VkPresentInfoKHR presentInfo = {};
presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
presentInfo.waitSemaphoreCount = 1;
presentInfo.pWaitSemaphores = &m_frameDrawCompleteSem;
presentInfo.swapchainCount = 1;
presentInfo.pSwapchains = &swapChain;
presentInfo.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;
}
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 = {};
imageViewCi.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
imageViewCi.image = image;
imageViewCi.viewType = VK_IMAGE_VIEW_TYPE_2D;
imageViewCi.format = format;
imageViewCi.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
imageViewCi.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
imageViewCi.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
imageViewCi.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
imageViewCi.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
imageViewCi.subresourceRange.baseMipLevel = 0;
imageViewCi.subresourceRange.levelCount = 1;
imageViewCi.subresourceRange.baseArrayLayer = 0;
imageViewCi.subresourceRange.layerCount = 1;
VK_CHECK(m_vk.vkCreateImageView(m_vkDevice, &imageViewCi, nullptr,
&m_vkImageView));
}
DisplayVk::DisplayBufferInfo::~DisplayBufferInfo() {
m_vk.vkDestroyImageView(m_vkDevice, m_vkImageView, nullptr);
}