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.
860 lines
38 KiB
860 lines
38 KiB
#include "CompositorVk.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <cinttypes>
|
|
#include <glm/gtc/matrix_transform.hpp>
|
|
#include <optional>
|
|
|
|
#include "ErrorLog.h"
|
|
#include "vulkan/vk_util.h"
|
|
|
|
namespace CompositorVkShader {
|
|
#include "vulkan/CompositorFragmentShader.h"
|
|
#include "vulkan/CompositorVertexShader.h"
|
|
} // namespace CompositorVkShader
|
|
|
|
static VkShaderModule createShaderModule(const goldfish_vk::VulkanDispatch &vk,
|
|
VkDevice device,
|
|
const std::vector<uint32_t> &code) {
|
|
VkShaderModuleCreateInfo shaderModuleCi = {
|
|
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
.codeSize = static_cast<uint32_t>(code.size() * sizeof(uint32_t)),
|
|
.pCode = code.data()};
|
|
VkShaderModule res;
|
|
VK_CHECK(vk.vkCreateShaderModule(device, &shaderModuleCi, nullptr, &res));
|
|
return res;
|
|
}
|
|
|
|
ComposeLayerVk::ComposeLayerVk(VkSampler vkSampler, VkImageView vkImageView,
|
|
const LayerTransform &layerTransform)
|
|
: m_vkSampler(vkSampler),
|
|
m_vkImageView(vkImageView),
|
|
m_layerTransform(
|
|
{.pos = layerTransform.pos, .texcoord = layerTransform.texcoord}) {}
|
|
|
|
std::unique_ptr<ComposeLayerVk> ComposeLayerVk::createFromHwc2ComposeLayer(
|
|
VkSampler vkSampler, VkImageView vkImageView,
|
|
const ComposeLayer &composeLayer, uint32_t cbWidth, uint32_t cbHeight,
|
|
uint32_t dstWidth, uint32_t dstHeight) {
|
|
// Calculate the posTransform and the texcoordTransform needed in the
|
|
// uniform of the Compositor.vert shader. The posTransform should transform
|
|
// the square(top = -1, bottom = 1, left = -1, right = 1) to the position
|
|
// where the layer should be drawn in NDC space given the composeLayer.
|
|
// texcoordTransform should transform the unit square(top = 0, bottom = 1,
|
|
// left = 0, right = 1) to where we should sample the layer in the
|
|
// normalized uv space given the composeLayer.
|
|
const hwc_rect_t &posRect = composeLayer.displayFrame;
|
|
const hwc_frect_t &texcoordRect = composeLayer.crop;
|
|
|
|
int posWidth = posRect.right - posRect.left;
|
|
int posHeight = posRect.bottom - posRect.top;
|
|
|
|
float posScaleX = float(posWidth) / dstWidth;
|
|
float posScaleY = float(posHeight) / dstHeight;
|
|
|
|
float posTranslateX =
|
|
-1.0f + posScaleX + 2.0f * float(posRect.left) / dstWidth;
|
|
float posTranslateY =
|
|
-1.0f + posScaleY + 2.0f * float(posRect.top) / dstHeight;
|
|
|
|
float texcoordScalX =
|
|
(texcoordRect.right - texcoordRect.left) / float(cbWidth);
|
|
float texCoordScaleY =
|
|
(texcoordRect.bottom - texcoordRect.top) / float(cbHeight);
|
|
|
|
float texCoordTranslateX = texcoordRect.left / float(cbWidth);
|
|
float texCoordTranslateY = texcoordRect.top / float(cbHeight);
|
|
|
|
float texcoordRotation = 0.0f;
|
|
|
|
const float pi = glm::pi<float>();
|
|
|
|
switch (composeLayer.transform) {
|
|
case HWC_TRANSFORM_ROT_90:
|
|
texcoordRotation = pi * 0.5f;
|
|
break;
|
|
case HWC_TRANSFORM_ROT_180:
|
|
texcoordRotation = pi;
|
|
break;
|
|
case HWC_TRANSFORM_ROT_270:
|
|
texcoordRotation = pi * 1.5f;
|
|
break;
|
|
case HWC_TRANSFORM_FLIP_H:
|
|
texcoordScalX *= -1.0f;
|
|
break;
|
|
case HWC_TRANSFORM_FLIP_V:
|
|
texCoordScaleY *= -1.0f;
|
|
break;
|
|
case HWC_TRANSFORM_FLIP_H_ROT_90:
|
|
texcoordRotation = pi * 0.5f;
|
|
texcoordScalX *= -1.0f;
|
|
break;
|
|
case HWC_TRANSFORM_FLIP_V_ROT_90:
|
|
texcoordRotation = pi * 0.5f;
|
|
texCoordScaleY *= -1.0f;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
ComposeLayerVk::LayerTransform layerTransform = {
|
|
.pos =
|
|
glm::translate(glm::mat4(1.0f),
|
|
glm::vec3(posTranslateX, posTranslateY, 0.0f)) *
|
|
glm::scale(glm::mat4(1.0f), glm::vec3(posScaleX, posScaleY, 1.0f)),
|
|
.texcoord = glm::translate(glm::mat4(1.0f),
|
|
glm::vec3(texCoordTranslateX,
|
|
texCoordTranslateY, 0.0f)) *
|
|
glm::scale(glm::mat4(1.0f),
|
|
glm::vec3(texcoordScalX, texCoordScaleY, 1.0f)) *
|
|
glm::rotate(glm::mat4(1.0f), texcoordRotation,
|
|
glm::vec3(0.0f, 0.0f, 1.0f)),
|
|
};
|
|
|
|
return std::unique_ptr<ComposeLayerVk>(
|
|
new ComposeLayerVk(vkSampler, vkImageView, layerTransform));
|
|
}
|
|
|
|
Composition::Composition(
|
|
std::vector<std::unique_ptr<ComposeLayerVk>> composeLayers)
|
|
: m_composeLayers(std::move(composeLayers)) {}
|
|
|
|
const std::vector<CompositorVk::Vertex> CompositorVk::k_vertices = {
|
|
{{-1.0f, -1.0f}, {0.0f, 0.0f}},
|
|
{{1.0f, -1.0f}, {1.0f, 0.0f}},
|
|
{{1.0f, 1.0f}, {1.0f, 1.0f}},
|
|
{{-1.0f, 1.0f}, {0.0f, 1.0f}},
|
|
};
|
|
|
|
const std::vector<uint16_t> CompositorVk::k_indices = {0, 1, 2, 2, 3, 0};
|
|
|
|
const VkExtent2D CompositorVk::k_emptyCompositionExtent = {1, 1};
|
|
|
|
std::unique_ptr<CompositorVk> CompositorVk::create(
|
|
const goldfish_vk::VulkanDispatch &vk, VkDevice vkDevice,
|
|
VkPhysicalDevice vkPhysicalDevice, VkQueue vkQueue, VkFormat format,
|
|
VkImageLayout initialLayout, VkImageLayout finalLayout, uint32_t width,
|
|
uint32_t height, const std::vector<VkImageView> &renderTargets,
|
|
VkCommandPool commandPool) {
|
|
auto res = std::unique_ptr<CompositorVk>(new CompositorVk(
|
|
vk, vkDevice, vkPhysicalDevice, vkQueue, commandPool, width, height));
|
|
res->setUpGraphicsPipeline(width, height, format, initialLayout,
|
|
finalLayout);
|
|
res->setUpVertexBuffers();
|
|
res->setUpFramebuffers(renderTargets, width, height);
|
|
res->setUpUniformBuffers();
|
|
res->setUpDescriptorSets();
|
|
res->setUpCommandBuffers(width, height);
|
|
res->setUpEmptyComposition(format);
|
|
res->m_currentCompositions.resize(renderTargets.size());
|
|
for (auto i = 0; i < renderTargets.size(); i++) {
|
|
std::vector<std::unique_ptr<ComposeLayerVk>> emptyCompositionLayers;
|
|
res->setComposition(i, std::make_unique<Composition>(
|
|
std::move(emptyCompositionLayers)));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
CompositorVk::CompositorVk(const goldfish_vk::VulkanDispatch &vk,
|
|
VkDevice vkDevice, VkPhysicalDevice vkPhysicalDevice,
|
|
VkQueue vkQueue, VkCommandPool vkCommandPool,
|
|
uint32_t renderTargetWidth,
|
|
uint32_t renderTargetHeight)
|
|
: CompositorVkBase(vk, vkDevice, vkPhysicalDevice, vkQueue, vkCommandPool),
|
|
m_renderTargetWidth(renderTargetWidth),
|
|
m_renderTargetHeight(renderTargetHeight),
|
|
m_emptyCompositionVkImage(VK_NULL_HANDLE),
|
|
m_emptyCompositionVkDeviceMemory(VK_NULL_HANDLE),
|
|
m_emptyCompositionVkImageView(VK_NULL_HANDLE),
|
|
m_emptyCompositionVkSampler(VK_NULL_HANDLE),
|
|
m_currentCompositions(0),
|
|
m_uniformStorage({VK_NULL_HANDLE, VK_NULL_HANDLE, nullptr, 0}) {
|
|
(void)m_renderTargetWidth;
|
|
(void)m_renderTargetHeight;
|
|
|
|
VkPhysicalDeviceProperties physicalDeviceProperties;
|
|
m_vk.vkGetPhysicalDeviceProperties(m_vkPhysicalDevice,
|
|
&physicalDeviceProperties);
|
|
auto alignment =
|
|
physicalDeviceProperties.limits.minUniformBufferOffsetAlignment;
|
|
m_uniformStorage.m_stride =
|
|
((sizeof(UniformBufferObject) - 1) / alignment + 1) * alignment;
|
|
}
|
|
|
|
CompositorVk::~CompositorVk() {
|
|
m_vk.vkDestroySampler(m_vkDevice, m_emptyCompositionVkSampler, nullptr);
|
|
m_vk.vkDestroyImageView(m_vkDevice, m_emptyCompositionVkImageView, nullptr);
|
|
m_vk.vkFreeMemory(m_vkDevice, m_emptyCompositionVkDeviceMemory, nullptr);
|
|
m_vk.vkDestroyImage(m_vkDevice, m_emptyCompositionVkImage, nullptr);
|
|
m_vk.vkDestroyDescriptorPool(m_vkDevice, m_vkDescriptorPool, nullptr);
|
|
m_vk.vkFreeCommandBuffers(m_vkDevice, m_vkCommandPool,
|
|
static_cast<uint32_t>(m_vkCommandBuffers.size()),
|
|
m_vkCommandBuffers.data());
|
|
if (m_uniformStorage.m_vkDeviceMemory != VK_NULL_HANDLE) {
|
|
m_vk.vkUnmapMemory(m_vkDevice, m_uniformStorage.m_vkDeviceMemory);
|
|
}
|
|
m_vk.vkDestroyBuffer(m_vkDevice, m_uniformStorage.m_vkBuffer, nullptr);
|
|
m_vk.vkFreeMemory(m_vkDevice, m_uniformStorage.m_vkDeviceMemory, nullptr);
|
|
while (!m_renderTargetVkFrameBuffers.empty()) {
|
|
m_vk.vkDestroyFramebuffer(m_vkDevice,
|
|
m_renderTargetVkFrameBuffers.back(), nullptr);
|
|
m_renderTargetVkFrameBuffers.pop_back();
|
|
}
|
|
m_vk.vkFreeMemory(m_vkDevice, m_vertexVkDeviceMemory, nullptr);
|
|
m_vk.vkDestroyBuffer(m_vkDevice, m_vertexVkBuffer, nullptr);
|
|
m_vk.vkFreeMemory(m_vkDevice, m_indexVkDeviceMemory, nullptr);
|
|
m_vk.vkDestroyBuffer(m_vkDevice, m_indexVkBuffer, nullptr);
|
|
m_vk.vkDestroyPipeline(m_vkDevice, m_graphicsVkPipeline, nullptr);
|
|
m_vk.vkDestroyRenderPass(m_vkDevice, m_vkRenderPass, nullptr);
|
|
m_vk.vkDestroyPipelineLayout(m_vkDevice, m_vkPipelineLayout, nullptr);
|
|
m_vk.vkDestroyDescriptorSetLayout(m_vkDevice, m_vkDescriptorSetLayout,
|
|
nullptr);
|
|
}
|
|
|
|
void CompositorVk::setUpGraphicsPipeline(uint32_t width, uint32_t height,
|
|
VkFormat renderTargetFormat,
|
|
VkImageLayout initialLayout,
|
|
VkImageLayout finalLayout) {
|
|
const std::vector<uint32_t> vertSpvBuff(
|
|
CompositorVkShader::compositorVertexShader,
|
|
std::end(CompositorVkShader::compositorVertexShader));
|
|
const std::vector<uint32_t> fragSpvBuff(
|
|
CompositorVkShader::compositorFragmentShader,
|
|
std::end(CompositorVkShader::compositorFragmentShader));
|
|
const auto vertShaderMod =
|
|
createShaderModule(m_vk, m_vkDevice, vertSpvBuff);
|
|
const auto fragShaderMod =
|
|
createShaderModule(m_vk, m_vkDevice, fragSpvBuff);
|
|
|
|
VkPipelineShaderStageCreateInfo shaderStageCis[2] = {
|
|
{.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
.module = vertShaderMod,
|
|
.pName = "main"},
|
|
{.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
.module = fragShaderMod,
|
|
.pName = "main"}};
|
|
|
|
auto bindingDescription = Vertex::getBindingDescription();
|
|
auto attributeDescription = Vertex::getAttributeDescription();
|
|
VkPipelineVertexInputStateCreateInfo vertexInputStateCi = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
.vertexBindingDescriptionCount = 1,
|
|
.pVertexBindingDescriptions = &bindingDescription,
|
|
.vertexAttributeDescriptionCount =
|
|
static_cast<uint32_t>(attributeDescription.size()),
|
|
.pVertexAttributeDescriptions = attributeDescription.data()};
|
|
VkPipelineInputAssemblyStateCreateInfo inputAssemblyStateCi = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
.primitiveRestartEnable = VK_FALSE,
|
|
};
|
|
|
|
VkViewport viewport = {.x = 0.0f,
|
|
.y = 0.0f,
|
|
.width = static_cast<float>(width),
|
|
.height = static_cast<float>(height),
|
|
.minDepth = 0.0f,
|
|
.maxDepth = 1.0f};
|
|
|
|
VkRect2D scissor = {.offset = {0, 0}, .extent = {width, height}};
|
|
|
|
VkPipelineViewportStateCreateInfo viewportStateCi = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
.viewportCount = 1,
|
|
.pViewports = &viewport,
|
|
.scissorCount = 1,
|
|
.pScissors = &scissor};
|
|
|
|
VkPipelineRasterizationStateCreateInfo rasterizerStateCi = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
.depthClampEnable = VK_FALSE,
|
|
.rasterizerDiscardEnable = VK_FALSE,
|
|
.polygonMode = VK_POLYGON_MODE_FILL,
|
|
.cullMode = VK_CULL_MODE_BACK_BIT,
|
|
.frontFace = VK_FRONT_FACE_CLOCKWISE,
|
|
.depthBiasEnable = VK_FALSE,
|
|
.depthBiasConstantFactor = 0.0f,
|
|
.depthBiasClamp = 0.0f,
|
|
.depthBiasSlopeFactor = 0.0f,
|
|
.lineWidth = 1.0f};
|
|
|
|
VkPipelineMultisampleStateCreateInfo multisampleStateCi = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
|
.sampleShadingEnable = VK_FALSE,
|
|
.minSampleShading = 1.0f,
|
|
.pSampleMask = nullptr,
|
|
.alphaToCoverageEnable = VK_FALSE,
|
|
.alphaToOneEnable = VK_FALSE};
|
|
|
|
VkPipelineColorBlendAttachmentState colorBlendAttachment = {
|
|
.blendEnable = VK_TRUE,
|
|
.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
|
.colorBlendOp = VK_BLEND_OP_ADD,
|
|
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
|
.alphaBlendOp = VK_BLEND_OP_ADD,
|
|
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
|
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT};
|
|
|
|
VkPipelineColorBlendStateCreateInfo colorBlendStateCi = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
.logicOpEnable = VK_FALSE,
|
|
.attachmentCount = 1,
|
|
.pAttachments = &colorBlendAttachment};
|
|
|
|
VkDescriptorSetLayoutBinding layoutBindings[2] = {
|
|
{.binding = 0,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.descriptorCount = 1,
|
|
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
.pImmutableSamplers = nullptr},
|
|
{.binding = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.descriptorCount = 1,
|
|
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
.pImmutableSamplers = nullptr}};
|
|
|
|
VkDescriptorBindingFlagsEXT bindingFlags[] = {
|
|
VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT, 0};
|
|
VkDescriptorSetLayoutBindingFlagsCreateInfoEXT bindingFlagsCi = {
|
|
.sType =
|
|
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT,
|
|
.bindingCount = static_cast<uint32_t>(std::size(bindingFlags)),
|
|
.pBindingFlags = bindingFlags,
|
|
};
|
|
VkDescriptorSetLayoutCreateInfo descriptorSetLayoutCi = {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
.pNext = &bindingFlagsCi,
|
|
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT,
|
|
.bindingCount = static_cast<uint32_t>(std::size(layoutBindings)),
|
|
.pBindings = layoutBindings};
|
|
VK_CHECK(m_vk.vkCreateDescriptorSetLayout(
|
|
m_vkDevice, &descriptorSetLayoutCi, nullptr, &m_vkDescriptorSetLayout));
|
|
|
|
VkPipelineLayoutCreateInfo pipelineLayoutCi = {
|
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
|
.setLayoutCount = 1,
|
|
.pSetLayouts = &m_vkDescriptorSetLayout,
|
|
.pushConstantRangeCount = 0};
|
|
|
|
VK_CHECK(m_vk.vkCreatePipelineLayout(m_vkDevice, &pipelineLayoutCi, nullptr,
|
|
&m_vkPipelineLayout));
|
|
|
|
VkAttachmentDescription colorAttachment = {
|
|
.format = renderTargetFormat,
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
.initialLayout = initialLayout,
|
|
.finalLayout = finalLayout};
|
|
|
|
VkAttachmentReference colorAttachmentRef = {
|
|
.attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL};
|
|
|
|
VkSubpassDescription subpass = {
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
.colorAttachmentCount = 1,
|
|
.pColorAttachments = &colorAttachmentRef};
|
|
|
|
// TODO: to support multiple layer composition, we could run the same render
|
|
// pass for multiple time. In that case, we should use explicit
|
|
// VkImageMemoryBarriers to transform the image layout instead of relying on
|
|
// renderpass to do it.
|
|
VkSubpassDependency subpassDependency = {
|
|
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
.dstSubpass = 0,
|
|
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
.srcAccessMask = 0,
|
|
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT};
|
|
|
|
VkRenderPassCreateInfo renderPassCi = {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
.attachmentCount = 1,
|
|
.pAttachments = &colorAttachment,
|
|
.subpassCount = 1,
|
|
.pSubpasses = &subpass,
|
|
.dependencyCount = 1,
|
|
.pDependencies = &subpassDependency};
|
|
|
|
VK_CHECK(m_vk.vkCreateRenderPass(m_vkDevice, &renderPassCi, nullptr,
|
|
&m_vkRenderPass));
|
|
|
|
VkGraphicsPipelineCreateInfo graphicsPipelineCi = {
|
|
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
.stageCount = static_cast<uint32_t>(std::size(shaderStageCis)),
|
|
.pStages = shaderStageCis,
|
|
.pVertexInputState = &vertexInputStateCi,
|
|
.pInputAssemblyState = &inputAssemblyStateCi,
|
|
.pViewportState = &viewportStateCi,
|
|
.pRasterizationState = &rasterizerStateCi,
|
|
.pMultisampleState = &multisampleStateCi,
|
|
.pDepthStencilState = nullptr,
|
|
.pColorBlendState = &colorBlendStateCi,
|
|
.pDynamicState = nullptr,
|
|
.layout = m_vkPipelineLayout,
|
|
.renderPass = m_vkRenderPass,
|
|
.subpass = 0,
|
|
.basePipelineHandle = VK_NULL_HANDLE,
|
|
.basePipelineIndex = -1};
|
|
|
|
VK_CHECK(m_vk.vkCreateGraphicsPipelines(m_vkDevice, VK_NULL_HANDLE, 1,
|
|
&graphicsPipelineCi, nullptr,
|
|
&m_graphicsVkPipeline));
|
|
|
|
m_vk.vkDestroyShaderModule(m_vkDevice, vertShaderMod, nullptr);
|
|
m_vk.vkDestroyShaderModule(m_vkDevice, fragShaderMod, nullptr);
|
|
}
|
|
|
|
// Create a VkBuffer and a bound VkDeviceMemory. When the specified memory type
|
|
// can't be found, return std::nullopt. When Vulkan call fails, terminate the
|
|
// program.
|
|
std::optional<std::tuple<VkBuffer, VkDeviceMemory>> CompositorVk::createBuffer(
|
|
VkDeviceSize size, VkBufferUsageFlags usage,
|
|
VkMemoryPropertyFlags memProperty) const {
|
|
VkBufferCreateInfo bufferCi = {
|
|
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
.size = size,
|
|
.usage = usage,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE};
|
|
VkBuffer resBuffer;
|
|
VK_CHECK(m_vk.vkCreateBuffer(m_vkDevice, &bufferCi, nullptr, &resBuffer));
|
|
VkMemoryRequirements memRequirements;
|
|
m_vk.vkGetBufferMemoryRequirements(m_vkDevice, resBuffer, &memRequirements);
|
|
VkPhysicalDeviceMemoryProperties physicalMemProperties;
|
|
m_vk.vkGetPhysicalDeviceMemoryProperties(m_vkPhysicalDevice,
|
|
&physicalMemProperties);
|
|
auto maybeMemoryTypeIndex =
|
|
findMemoryType(memRequirements.memoryTypeBits, memProperty);
|
|
if (!maybeMemoryTypeIndex.has_value()) {
|
|
m_vk.vkDestroyBuffer(m_vkDevice, resBuffer, nullptr);
|
|
return std::nullopt;
|
|
}
|
|
VkMemoryAllocateInfo memAllocInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
.allocationSize = memRequirements.size,
|
|
.memoryTypeIndex = maybeMemoryTypeIndex.value()};
|
|
VkDeviceMemory resMemory;
|
|
VK_CHECK(
|
|
m_vk.vkAllocateMemory(m_vkDevice, &memAllocInfo, nullptr, &resMemory));
|
|
VK_CHECK(m_vk.vkBindBufferMemory(m_vkDevice, resBuffer, resMemory, 0));
|
|
return std::make_tuple(resBuffer, resMemory);
|
|
}
|
|
|
|
std::tuple<VkBuffer, VkDeviceMemory> CompositorVk::createStagingBufferWithData(
|
|
const void *srcData, VkDeviceSize size) const {
|
|
auto [stagingBuffer, stagingBufferMemory] =
|
|
createBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
|
|
.value();
|
|
void *data;
|
|
VK_CHECK(
|
|
m_vk.vkMapMemory(m_vkDevice, stagingBufferMemory, 0, size, 0, &data));
|
|
memcpy(data, srcData, size);
|
|
m_vk.vkUnmapMemory(m_vkDevice, stagingBufferMemory);
|
|
return std::make_tuple(stagingBuffer, stagingBufferMemory);
|
|
}
|
|
|
|
void CompositorVk::copyBuffer(VkBuffer src, VkBuffer dst,
|
|
VkDeviceSize size) const {
|
|
runSingleTimeCommands(m_vkQueue, [&, this](const auto &cmdBuff) {
|
|
VkBufferCopy copyRegion = {};
|
|
copyRegion.srcOffset = 0;
|
|
copyRegion.dstOffset = 0;
|
|
copyRegion.size = size;
|
|
m_vk.vkCmdCopyBuffer(cmdBuff, src, dst, 1, ©Region);
|
|
});
|
|
}
|
|
|
|
void CompositorVk::setUpVertexBuffers() {
|
|
const VkDeviceSize vertexBufferSize =
|
|
sizeof(k_vertices[0]) * k_vertices.size();
|
|
std::tie(m_vertexVkBuffer, m_vertexVkDeviceMemory) =
|
|
createBuffer(vertexBufferSize,
|
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
|
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
|
|
.value();
|
|
auto [vertexStagingBuffer, vertexStagingBufferMemory] =
|
|
createStagingBufferWithData(k_vertices.data(), vertexBufferSize);
|
|
copyBuffer(vertexStagingBuffer, m_vertexVkBuffer, vertexBufferSize);
|
|
m_vk.vkDestroyBuffer(m_vkDevice, vertexStagingBuffer, nullptr);
|
|
m_vk.vkFreeMemory(m_vkDevice, vertexStagingBufferMemory, nullptr);
|
|
|
|
VkDeviceSize indexBufferSize = sizeof(k_indices[0]) * k_indices.size();
|
|
auto [indexStagingBuffer, indexStagingBufferMemory] =
|
|
createStagingBufferWithData(k_indices.data(), indexBufferSize);
|
|
std::tie(m_indexVkBuffer, m_indexVkDeviceMemory) =
|
|
createBuffer(
|
|
indexBufferSize,
|
|
VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
|
|
.value();
|
|
copyBuffer(indexStagingBuffer, m_indexVkBuffer, indexBufferSize);
|
|
m_vk.vkDestroyBuffer(m_vkDevice, indexStagingBuffer, nullptr);
|
|
m_vk.vkFreeMemory(m_vkDevice, indexStagingBufferMemory, nullptr);
|
|
}
|
|
|
|
void CompositorVk::setUpFramebuffers(
|
|
const std::vector<VkImageView> &renderTargets, uint32_t width,
|
|
uint32_t height) {
|
|
for (size_t i = 0; i < renderTargets.size(); i++) {
|
|
VkFramebufferCreateInfo fbCi = {
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
.renderPass = m_vkRenderPass,
|
|
.attachmentCount = 1,
|
|
.pAttachments = &renderTargets[i],
|
|
.width = width,
|
|
.height = height,
|
|
.layers = 1};
|
|
VkFramebuffer framebuffer;
|
|
VK_CHECK(
|
|
m_vk.vkCreateFramebuffer(m_vkDevice, &fbCi, nullptr, &framebuffer));
|
|
m_renderTargetVkFrameBuffers.push_back(framebuffer);
|
|
}
|
|
}
|
|
|
|
// We don't see composition requests with more than 10 layers from the guest for
|
|
// now. If we see rendering error or significant time spent on updating
|
|
// descriptors in setComposition, we should tune this number.
|
|
static const uint32_t kMaxLayersPerFrame = 10;
|
|
|
|
void CompositorVk::setUpDescriptorSets() {
|
|
uint32_t numOfFrames =
|
|
static_cast<uint32_t>(m_renderTargetVkFrameBuffers.size());
|
|
|
|
uint32_t setsPerDescriptorType = numOfFrames * kMaxLayersPerFrame;
|
|
|
|
VkDescriptorPoolSize descriptorPoolSizes[2] = {
|
|
{.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.descriptorCount = setsPerDescriptorType},
|
|
{.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.descriptorCount = setsPerDescriptorType}};
|
|
|
|
VkDescriptorPoolCreateInfo descriptorPoolCi = {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
.flags = VK_DESCRIPTOR_POOL_CREATE_UPDATE_AFTER_BIND_BIT_EXT,
|
|
.maxSets = static_cast<uint32_t>(setsPerDescriptorType),
|
|
.poolSizeCount = static_cast<uint32_t>(std::size(descriptorPoolSizes)),
|
|
.pPoolSizes = descriptorPoolSizes};
|
|
VK_CHECK(m_vk.vkCreateDescriptorPool(m_vkDevice, &descriptorPoolCi, nullptr,
|
|
&m_vkDescriptorPool));
|
|
std::vector<VkDescriptorSetLayout> layouts(setsPerDescriptorType,
|
|
m_vkDescriptorSetLayout);
|
|
VkDescriptorSetAllocateInfo descriptorSetAllocInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
.descriptorPool = m_vkDescriptorPool,
|
|
.descriptorSetCount = setsPerDescriptorType,
|
|
.pSetLayouts = layouts.data()};
|
|
m_vkDescriptorSets.resize(setsPerDescriptorType);
|
|
VK_CHECK(m_vk.vkAllocateDescriptorSets(m_vkDevice, &descriptorSetAllocInfo,
|
|
m_vkDescriptorSets.data()));
|
|
for (size_t i = 0; i < setsPerDescriptorType; i++) {
|
|
VkDescriptorBufferInfo bufferInfo = {
|
|
.buffer = m_uniformStorage.m_vkBuffer,
|
|
.offset = i * m_uniformStorage.m_stride,
|
|
.range = sizeof(UniformBufferObject)};
|
|
VkWriteDescriptorSet descriptorSetWrite = {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.dstSet = m_vkDescriptorSets[i],
|
|
.dstBinding = 1,
|
|
.dstArrayElement = 0,
|
|
.descriptorCount = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
|
.pBufferInfo = &bufferInfo};
|
|
m_vk.vkUpdateDescriptorSets(m_vkDevice, 1, &descriptorSetWrite, 0,
|
|
nullptr);
|
|
}
|
|
}
|
|
|
|
void CompositorVk::setUpCommandBuffers(uint32_t width, uint32_t height) {
|
|
VkCommandBufferAllocateInfo cmdBuffAllocInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
|
|
.commandPool = m_vkCommandPool,
|
|
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
|
|
.commandBufferCount =
|
|
static_cast<uint32_t>(m_renderTargetVkFrameBuffers.size())};
|
|
m_vkCommandBuffers.resize(m_renderTargetVkFrameBuffers.size());
|
|
VK_CHECK(m_vk.vkAllocateCommandBuffers(m_vkDevice, &cmdBuffAllocInfo,
|
|
m_vkCommandBuffers.data()));
|
|
|
|
for (size_t i = 0; i < m_vkCommandBuffers.size(); i++) {
|
|
VkCommandBufferBeginInfo beginInfo = {
|
|
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO};
|
|
const auto &cmdBuffer = m_vkCommandBuffers[i];
|
|
VK_CHECK(m_vk.vkBeginCommandBuffer(cmdBuffer, &beginInfo));
|
|
|
|
VkClearValue clearColor = {
|
|
.color = {.float32 = {0.0f, 0.0f, 0.0f, 1.0f}}};
|
|
VkRenderPassBeginInfo renderPassBeginInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
.renderPass = m_vkRenderPass,
|
|
.framebuffer = m_renderTargetVkFrameBuffers[i],
|
|
.renderArea = {.offset = {0, 0}, .extent = {width, height}},
|
|
.clearValueCount = 1,
|
|
.pClearValues = &clearColor};
|
|
m_vk.vkCmdBeginRenderPass(cmdBuffer, &renderPassBeginInfo,
|
|
VK_SUBPASS_CONTENTS_INLINE);
|
|
m_vk.vkCmdBindPipeline(cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
m_graphicsVkPipeline);
|
|
VkDeviceSize offsets[] = {0};
|
|
m_vk.vkCmdBindVertexBuffers(cmdBuffer, 0, 1, &m_vertexVkBuffer,
|
|
offsets);
|
|
m_vk.vkCmdBindIndexBuffer(cmdBuffer, m_indexVkBuffer, 0,
|
|
VK_INDEX_TYPE_UINT16);
|
|
for (uint32_t j = 0; j < kMaxLayersPerFrame; ++j) {
|
|
m_vk.vkCmdBindDescriptorSets(
|
|
cmdBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_vkPipelineLayout,
|
|
0, 1, &m_vkDescriptorSets[i * kMaxLayersPerFrame + j], 0,
|
|
nullptr);
|
|
m_vk.vkCmdDrawIndexed(
|
|
cmdBuffer, static_cast<uint32_t>(k_indices.size()), 1, 0, 0, 0);
|
|
}
|
|
m_vk.vkCmdEndRenderPass(cmdBuffer);
|
|
|
|
VK_CHECK(m_vk.vkEndCommandBuffer(cmdBuffer));
|
|
}
|
|
}
|
|
|
|
void CompositorVk::setUpEmptyComposition(VkFormat format) {
|
|
VkImageCreateInfo imageCi = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
.flags = 0,
|
|
.imageType = VK_IMAGE_TYPE_2D,
|
|
.format = format,
|
|
.extent = {.width = k_emptyCompositionExtent.width,
|
|
.height = k_emptyCompositionExtent.height,
|
|
.depth = 1},
|
|
.mipLevels = 1,
|
|
.arrayLayers = 1,
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
|
.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED};
|
|
VK_CHECK(m_vk.vkCreateImage(m_vkDevice, &imageCi, nullptr,
|
|
&m_emptyCompositionVkImage));
|
|
|
|
VkMemoryRequirements memRequirements;
|
|
m_vk.vkGetImageMemoryRequirements(m_vkDevice, m_emptyCompositionVkImage,
|
|
&memRequirements);
|
|
VkMemoryAllocateInfo allocInfo = {
|
|
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
.allocationSize = memRequirements.size,
|
|
.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits,
|
|
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT)
|
|
.value()};
|
|
VK_CHECK(m_vk.vkAllocateMemory(m_vkDevice, &allocInfo, nullptr,
|
|
&m_emptyCompositionVkDeviceMemory));
|
|
VK_CHECK(m_vk.vkBindImageMemory(m_vkDevice, m_emptyCompositionVkImage,
|
|
m_emptyCompositionVkDeviceMemory, 0));
|
|
runSingleTimeCommands(m_vkQueue, [&, this](const auto &cmdBuff) {
|
|
recordImageLayoutTransformCommands(
|
|
cmdBuff, m_emptyCompositionVkImage, VK_IMAGE_LAYOUT_UNDEFINED,
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
|
VkClearColorValue clearColor = {.float32 = {0.0, 0.0, 0.0, 1.0}};
|
|
VkImageSubresourceRange range = {
|
|
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
.baseMipLevel = 0,
|
|
.levelCount = 1,
|
|
.baseArrayLayer = 0,
|
|
.layerCount = 1};
|
|
m_vk.vkCmdClearColorImage(cmdBuff, m_emptyCompositionVkImage,
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
&clearColor, 1, &range);
|
|
recordImageLayoutTransformCommands(
|
|
cmdBuff, m_emptyCompositionVkImage,
|
|
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
|
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
});
|
|
|
|
VkImageViewCreateInfo imageViewCi = {
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
.image = m_emptyCompositionVkImage,
|
|
.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_emptyCompositionVkImageView));
|
|
|
|
VkSamplerCreateInfo samplerCi = {
|
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO,
|
|
.magFilter = VK_FILTER_LINEAR,
|
|
.minFilter = VK_FILTER_LINEAR,
|
|
.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_emptyCompositionVkSampler));
|
|
}
|
|
|
|
void CompositorVk::setUpUniformBuffers() {
|
|
auto numOfFrames = m_renderTargetVkFrameBuffers.size();
|
|
VkDeviceSize size =
|
|
m_uniformStorage.m_stride * numOfFrames * kMaxLayersPerFrame;
|
|
auto maybeBuffer = createBuffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT |
|
|
VK_MEMORY_PROPERTY_HOST_CACHED_BIT);
|
|
auto buffer = std::make_tuple<VkBuffer, VkDeviceMemory>(VK_NULL_HANDLE,
|
|
VK_NULL_HANDLE);
|
|
if (maybeBuffer.has_value()) {
|
|
buffer = maybeBuffer.value();
|
|
} else {
|
|
buffer = createBuffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
|
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT)
|
|
.value();
|
|
}
|
|
std::tie(m_uniformStorage.m_vkBuffer, m_uniformStorage.m_vkDeviceMemory) =
|
|
buffer;
|
|
VK_CHECK(m_vk.vkMapMemory(
|
|
m_vkDevice, m_uniformStorage.m_vkDeviceMemory, 0, size, 0,
|
|
reinterpret_cast<void **>(&m_uniformStorage.m_data)));
|
|
}
|
|
|
|
bool CompositorVk::validatePhysicalDeviceFeatures(
|
|
const VkPhysicalDeviceFeatures2 &features) {
|
|
auto descIndexingFeatures =
|
|
vk_find_struct<VkPhysicalDeviceDescriptorIndexingFeaturesEXT>(
|
|
&features);
|
|
if (descIndexingFeatures == nullptr) {
|
|
return false;
|
|
}
|
|
return descIndexingFeatures->descriptorBindingSampledImageUpdateAfterBind ==
|
|
VK_TRUE;
|
|
}
|
|
|
|
bool CompositorVk::validateQueueFamilyProperties(
|
|
const VkQueueFamilyProperties &properties) {
|
|
return properties.queueFlags & VK_QUEUE_GRAPHICS_BIT;
|
|
}
|
|
|
|
bool CompositorVk::enablePhysicalDeviceFeatures(
|
|
VkPhysicalDeviceFeatures2 &features) {
|
|
auto descIndexingFeatures =
|
|
vk_find_struct<VkPhysicalDeviceDescriptorIndexingFeaturesEXT>(
|
|
&features);
|
|
if (descIndexingFeatures == nullptr) {
|
|
return false;
|
|
}
|
|
descIndexingFeatures->descriptorBindingSampledImageUpdateAfterBind =
|
|
VK_TRUE;
|
|
return true;
|
|
}
|
|
|
|
std::vector<const char *> CompositorVk::getRequiredDeviceExtensions() {
|
|
return {VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME};
|
|
}
|
|
|
|
VkCommandBuffer CompositorVk::getCommandBuffer(uint32_t i) const {
|
|
return m_vkCommandBuffers[i];
|
|
}
|
|
|
|
void CompositorVk::setComposition(uint32_t rtIndex,
|
|
std::unique_ptr<Composition> &&composition) {
|
|
m_currentCompositions[rtIndex] = std::move(composition);
|
|
const auto ¤tComposition = *m_currentCompositions[rtIndex];
|
|
if (currentComposition.m_composeLayers.size() > kMaxLayersPerFrame) {
|
|
ERR("%s(%s:%d): CompositorVk can't compose more than %" PRIu32
|
|
" layers, %" PRIu32 " layers asked.\n",
|
|
__FUNCTION__, __FILE__, static_cast<int>(__LINE__),
|
|
kMaxLayersPerFrame,
|
|
static_cast<uint32_t>(currentComposition.m_composeLayers.size()));
|
|
}
|
|
|
|
memset(reinterpret_cast<uint8_t *>(m_uniformStorage.m_data) +
|
|
(rtIndex * kMaxLayersPerFrame + 0) * m_uniformStorage.m_stride,
|
|
0, sizeof(ComposeLayerVk::LayerTransform) * kMaxLayersPerFrame);
|
|
|
|
std::vector<VkDescriptorImageInfo> imageInfos(
|
|
currentComposition.m_composeLayers.size());
|
|
std::vector<VkWriteDescriptorSet> descriptorWrites;
|
|
for (size_t i = 0; i < currentComposition.m_composeLayers.size(); ++i) {
|
|
const auto &layer = currentComposition.m_composeLayers[i];
|
|
imageInfos[i] = VkDescriptorImageInfo(
|
|
{.sampler = layer->m_vkSampler,
|
|
.imageView = layer->m_vkImageView,
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL});
|
|
const VkDescriptorImageInfo &imageInfo = imageInfos[i];
|
|
descriptorWrites.emplace_back(VkWriteDescriptorSet(
|
|
{.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.dstSet = m_vkDescriptorSets[rtIndex * kMaxLayersPerFrame + i],
|
|
.dstBinding = 0,
|
|
.dstArrayElement = 0,
|
|
.descriptorCount = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.pImageInfo = &imageInfo}));
|
|
memcpy(
|
|
reinterpret_cast<uint8_t *>(m_uniformStorage.m_data) +
|
|
(rtIndex * kMaxLayersPerFrame + i) * m_uniformStorage.m_stride,
|
|
&layer->m_layerTransform, sizeof(ComposeLayerVk::LayerTransform));
|
|
}
|
|
m_vk.vkUpdateDescriptorSets(m_vkDevice, descriptorWrites.size(),
|
|
descriptorWrites.data(), 0, nullptr);
|
|
|
|
for (size_t i = currentComposition.m_composeLayers.size();
|
|
i < kMaxLayersPerFrame; ++i) {
|
|
VkDescriptorImageInfo imageInfo = {
|
|
.sampler = m_emptyCompositionVkSampler,
|
|
.imageView = m_emptyCompositionVkImageView,
|
|
.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL};
|
|
VkWriteDescriptorSet descriptorSetWrite = {
|
|
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
|
|
.dstSet = m_vkDescriptorSets[rtIndex * kMaxLayersPerFrame + i],
|
|
.dstBinding = 0,
|
|
.dstArrayElement = 0,
|
|
.descriptorCount = 1,
|
|
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
|
|
.pImageInfo = &imageInfo};
|
|
m_vk.vkUpdateDescriptorSets(m_vkDevice, 1, &descriptorSetWrite, 0,
|
|
nullptr);
|
|
}
|
|
}
|
|
|
|
VkVertexInputBindingDescription CompositorVk::Vertex::getBindingDescription() {
|
|
return {.binding = 0,
|
|
.stride = sizeof(struct Vertex),
|
|
.inputRate = VK_VERTEX_INPUT_RATE_VERTEX};
|
|
}
|
|
|
|
std::array<VkVertexInputAttributeDescription, 2>
|
|
CompositorVk::Vertex::getAttributeDescription() {
|
|
return {VkVertexInputAttributeDescription{
|
|
.location = 0,
|
|
.binding = 0,
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
.offset = offsetof(struct Vertex, pos)},
|
|
VkVertexInputAttributeDescription{
|
|
.location = 1,
|
|
.binding = 0,
|
|
.format = VK_FORMAT_R32G32_SFLOAT,
|
|
.offset = offsetof(struct Vertex, texPos)}};
|
|
}
|