2024-08-17 18:01:21 +08:00
|
|
|
|
#include "vkn/vulkan_api.h"
|
|
|
|
|
|
#include "vkn/vulkan_window.h"
|
2024-09-22 20:26:49 +08:00
|
|
|
|
#include "vkn/vulkan_api_help.h"
|
2024-09-07 17:48:12 +08:00
|
|
|
|
#include "vkn/wrapper/device.h"
|
2024-08-27 20:21:32 +08:00
|
|
|
|
#include "vkn/thread/buffer_worker.h"
|
|
|
|
|
|
#include "vkn/thread/command_worker.h"
|
2024-10-25 22:57:25 +08:00
|
|
|
|
#include "vkn/loader/vulkan_glsl_loader.h"
|
2024-08-25 22:41:25 +08:00
|
|
|
|
#include "render/asset/mesh.h"
|
2024-12-13 11:32:34 +08:00
|
|
|
|
#include "event/event_system.h"
|
2024-09-21 17:19:22 +08:00
|
|
|
|
#include "tinyimageformat/tinyimageformat_apis.h"
|
2024-10-21 16:31:02 +08:00
|
|
|
|
#include "zlog.h"
|
2024-08-17 18:01:21 +08:00
|
|
|
|
namespace vkn {
|
2024-12-13 11:32:34 +08:00
|
|
|
|
using api::EventSystem;
|
2024-09-07 17:48:12 +08:00
|
|
|
|
VulkanAPI::VulkanAPI() : RenderAPI(new VulkanContext())
|
|
|
|
|
|
, window(*VulkanWindow::Ptr())
|
|
|
|
|
|
, backend(VulkanEngineName)
|
2024-08-17 18:01:21 +08:00
|
|
|
|
{
|
2024-08-23 22:13:05 +08:00
|
|
|
|
|
2024-08-17 18:01:21 +08:00
|
|
|
|
}
|
|
|
|
|
|
void VulkanAPI::Init()
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
void VulkanAPI::Shutdown()
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2024-08-25 22:41:25 +08:00
|
|
|
|
void VulkanAPI::SetStaticMesh(Mesh& mesh)
|
|
|
|
|
|
{
|
2024-08-27 20:21:32 +08:00
|
|
|
|
auto& Indices = mesh.GetIndices();
|
|
|
|
|
|
auto& Vertices = mesh.GetVertices();
|
|
|
|
|
|
MeshVAO& VAO = MeshTable[mesh.GetGuid()];
|
|
|
|
|
|
VAO.indexCount = Indices.size();
|
|
|
|
|
|
VAO.vertexCount = Vertices.size();
|
2024-08-25 22:41:25 +08:00
|
|
|
|
|
2024-11-08 17:18:23 +08:00
|
|
|
|
BufferUpload indexBuffer{};
|
|
|
|
|
|
indexBuffer.pBuffer = &VAO.indexBuffer;
|
|
|
|
|
|
indexBuffer.pAllocation = &VAO.indexAllocation;
|
2024-08-27 20:21:32 +08:00
|
|
|
|
indexBuffer.pCpuData = Indices.data();
|
|
|
|
|
|
indexBuffer.size = sizeof(decltype(Indices[0])) * Indices.size();
|
|
|
|
|
|
indexBuffer.usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT;
|
|
|
|
|
|
Backend::TransferWorker->Invoke(indexBuffer);
|
|
|
|
|
|
|
2024-11-08 17:18:23 +08:00
|
|
|
|
BufferUpload vertexBuffer{};
|
|
|
|
|
|
vertexBuffer.pBuffer = &VAO.vertexBuffer;
|
|
|
|
|
|
vertexBuffer.pAllocation = &VAO.vertexAllocation;
|
2024-08-27 20:21:32 +08:00
|
|
|
|
vertexBuffer.pCpuData = Vertices.data();
|
|
|
|
|
|
vertexBuffer.size = Vertices.data_size();
|
|
|
|
|
|
vertexBuffer.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT;
|
|
|
|
|
|
Backend::TransferWorker->Invoke(vertexBuffer);
|
2024-08-25 22:41:25 +08:00
|
|
|
|
}
|
|
|
|
|
|
void VulkanAPI::DrawStaticMesh(Mesh& mesh)
|
|
|
|
|
|
{
|
2024-10-30 15:15:25 +08:00
|
|
|
|
MeshVAO& vulkanVAO = MeshTable[mesh.GetGuid()];
|
|
|
|
|
|
if (!vulkanVAO.indexBuffer || !vulkanVAO.vertexBuffer) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
VulkanPipeline& pipeline = PipelineTable[mesh.GetShaderGuid()];
|
|
|
|
|
|
VulkanContext& ctx = *(VulkanContext*)&context;
|
|
|
|
|
|
VkCommandBuffer ptr = ctx.command;
|
|
|
|
|
|
VkBuffer vertexBuffers[] = { vulkanVAO.vertexBuffer };
|
|
|
|
|
|
VkDeviceSize offsets[] = { 0 };
|
|
|
|
|
|
vkCmdBindVertexBuffers(ptr, 0, 1, vertexBuffers, offsets);
|
|
|
|
|
|
vkCmdBindIndexBuffer(ptr, vulkanVAO.indexBuffer, 0, VK_INDEX_TYPE_UINT32);
|
|
|
|
|
|
vkCmdBindPipeline(ptr, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipeline);
|
2024-11-26 20:29:29 +08:00
|
|
|
|
if (pipeline.descCount > 0) {
|
|
|
|
|
|
auto& materialInst = mesh.GetMaterialInstance();
|
|
|
|
|
|
auto& materialInfo = materialInst.GetInfo();
|
|
|
|
|
|
auto& gpuBlock = materialInfo.gpuBlock;
|
|
|
|
|
|
uint32_t staticCount = materialInfo.staticBlock.count;
|
|
|
|
|
|
materialInfo.staticBlock.Upload(gpuBlock.pMappingAddr);
|
|
|
|
|
|
materialInfo.classBlock.Upload(gpuBlock.pMappingAddr + staticCount);
|
2024-11-02 17:55:55 +08:00
|
|
|
|
vkCmdBindDescriptorSets(ptr, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline.pipelineLayout, 0, pipeline.descCount, pipeline.descList, 0, VK_NULL_HANDLE);
|
2024-11-26 20:29:29 +08:00
|
|
|
|
}
|
2024-10-30 15:15:25 +08:00
|
|
|
|
vkCmdDrawIndexed(ptr, vulkanVAO.indexCount, 1, 0, 0, 0);
|
2024-08-25 22:41:25 +08:00
|
|
|
|
}
|
2024-11-08 17:18:23 +08:00
|
|
|
|
void VulkanAPI::SetUpMaterialInstance(MaterialInstance& material)
|
|
|
|
|
|
{
|
|
|
|
|
|
Shader& shader = *material->GetShader();
|
2024-11-26 20:29:29 +08:00
|
|
|
|
VulkanPipeline& pipeline = PipelineTable[shader.GetGuid()];
|
2024-11-08 17:18:23 +08:00
|
|
|
|
pmr::vector<api::ShaderProgram*> programList{ FramePool() };
|
|
|
|
|
|
programList.push_back(shader.GetVertHandle().Ptr());
|
|
|
|
|
|
programList.push_back(shader.GetFragHandle().Ptr());
|
2024-11-26 20:29:29 +08:00
|
|
|
|
VulkanGlslLoader::LoadShaderBuffer(pipeline.descList, programList, material.GetInfo());
|
2024-11-08 17:18:23 +08:00
|
|
|
|
}
|
2024-10-30 21:02:51 +08:00
|
|
|
|
void VulkanAPI::LoadShader(Shader& shader, size_t passKey)
|
2024-08-25 22:41:25 +08:00
|
|
|
|
{
|
2024-10-30 21:02:51 +08:00
|
|
|
|
auto itPass = RenderPassCache.find(passKey);
|
|
|
|
|
|
if (itPass == RenderPassCache.end()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2024-12-21 15:32:22 +08:00
|
|
|
|
VkRenderPass renderpass = itPass->second.pass;
|
2024-10-25 22:57:25 +08:00
|
|
|
|
pmr::vector<VkPipelineShaderStageCreateInfo> shaderStages;
|
|
|
|
|
|
std::map<VkShaderStageFlagBits, VkShaderModule> shaderModules;
|
|
|
|
|
|
auto& device = backend.GetDevice();
|
2024-11-08 17:18:23 +08:00
|
|
|
|
pmr::vector<api::ShaderProgram*> programList{FramePool()};
|
2024-11-02 17:55:55 +08:00
|
|
|
|
programList.push_back(shader.GetVertHandle().Ptr());
|
|
|
|
|
|
programList.push_back(shader.GetFragHandle().Ptr());
|
|
|
|
|
|
for (auto program : programList) {
|
|
|
|
|
|
vkShaderProgram* vkProgram = (vkShaderProgram*)program;
|
|
|
|
|
|
auto shaderModule = vkProgram->Ptr();
|
|
|
|
|
|
shaderModules.insert(std::make_pair(vkProgram->GetVkStage(), shaderModule));
|
|
|
|
|
|
}
|
2024-10-25 22:57:25 +08:00
|
|
|
|
for (auto& shaderModule : shaderModules)
|
|
|
|
|
|
{
|
|
|
|
|
|
VkPipelineShaderStageCreateInfo shaderStageInfo = {};
|
|
|
|
|
|
shaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
|
|
|
|
|
shaderStageInfo.stage = shaderModule.first;
|
|
|
|
|
|
shaderStageInfo.module = shaderModule.second;
|
|
|
|
|
|
shaderStageInfo.pName = "main";
|
|
|
|
|
|
shaderStages.push_back(shaderStageInfo);
|
|
|
|
|
|
}
|
2024-10-30 21:02:51 +08:00
|
|
|
|
auto meta = refl::find_meta(shader.Name(),string_hash("vkMeta"));
|
2024-10-25 22:57:25 +08:00
|
|
|
|
// 设置顶点输入格式
|
|
|
|
|
|
VkPipelineVertexInputStateCreateInfo vertexInputInfo = {};
|
|
|
|
|
|
VkVertexInputBindingDescription bindingDescription = {};
|
|
|
|
|
|
bindingDescription.binding = 0;
|
|
|
|
|
|
bindingDescription.stride = meta->size;
|
|
|
|
|
|
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
|
|
|
|
|
//这里顶点属性不能大余16
|
|
|
|
|
|
std::array<VkVertexInputAttributeDescription, 16> attributeDescriptions = { };
|
|
|
|
|
|
{
|
|
|
|
|
|
uint32_t count = 0;
|
|
|
|
|
|
for (auto& field : meta->GetFields(refl::FIND_ALL_MEMBER, Name(""))) {
|
|
|
|
|
|
auto& attr = attributeDescriptions[count];
|
|
|
|
|
|
attr.binding = 0;
|
|
|
|
|
|
attr.location = count++;
|
|
|
|
|
|
attr.format = field.GetMeta() ? (VkFormat)field.GetMeta().CastTo<uint32_t>() : VK_FORMAT_R32G32B32_SFLOAT;
|
|
|
|
|
|
attr.offset = field.GetOffset();
|
|
|
|
|
|
}
|
|
|
|
|
|
vertexInputInfo.vertexAttributeDescriptionCount = count;
|
|
|
|
|
|
}
|
|
|
|
|
|
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
|
|
|
|
|
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
|
|
|
|
|
|
vertexInputInfo.pVertexAttributeDescriptions = attributeDescriptions.data();
|
|
|
|
|
|
vertexInputInfo.vertexBindingDescriptionCount = 1;
|
|
|
|
|
|
|
|
|
|
|
|
// 设置图元
|
|
|
|
|
|
VkPipelineInputAssemblyStateCreateInfo inputAssemblyInfo = {};
|
|
|
|
|
|
inputAssemblyInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
|
|
|
|
|
inputAssemblyInfo.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
|
|
|
|
|
inputAssemblyInfo.primitiveRestartEnable = VK_FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
// ViewPort信息,这里不直接设置,下面弄成动态的
|
|
|
|
|
|
VkPipelineViewportStateCreateInfo viewportStateInfo = {};
|
|
|
|
|
|
viewportStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
|
|
|
|
|
viewportStateInfo.viewportCount = 1;
|
|
|
|
|
|
viewportStateInfo.scissorCount = 1;
|
|
|
|
|
|
|
|
|
|
|
|
// View Port和Scissor设置为动态,每帧绘制时决定
|
|
|
|
|
|
pmr::vector<VkDynamicState> dynamicStates = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
|
|
|
|
|
|
VkPipelineDynamicStateCreateInfo dynamicStateInfo = {};
|
|
|
|
|
|
dynamicStateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
|
|
|
|
|
dynamicStateInfo.pDynamicStates = dynamicStates.data();
|
|
|
|
|
|
dynamicStateInfo.dynamicStateCount = static_cast<uint32_t>(dynamicStates.size());
|
|
|
|
|
|
|
|
|
|
|
|
// 设置光栅化阶段
|
|
|
|
|
|
VkPipelineRasterizationStateCreateInfo rasterizationInfo = {};
|
|
|
|
|
|
rasterizationInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
|
|
|
|
|
// 如果depthClampEnable设置为VK_TRUE,超过远近裁剪面的片元会进行收敛,而不是丢弃它们
|
|
|
|
|
|
rasterizationInfo.depthClampEnable = VK_FALSE;
|
|
|
|
|
|
// 如果rasterizerDiscardEnable设置为VK_TRUE,那么几何图元永远不会传递到光栅化阶段
|
|
|
|
|
|
// 这是禁止任何数据输出到framebuffer的方法
|
|
|
|
|
|
rasterizationInfo.rasterizerDiscardEnable = VK_FALSE;
|
|
|
|
|
|
// 设置片元如何从几何模型中产生,如果不是FILL,需要开启GPU feature
|
|
|
|
|
|
// VK_POLYGON_MODE_FILL: 多边形区域填充
|
|
|
|
|
|
// VK_POLYGON_MODE_LINE: 多边形边缘线框绘制
|
|
|
|
|
|
// VK_POLYGON_MODE_POINT : 多边形顶点作为描点绘制
|
|
|
|
|
|
rasterizationInfo.polygonMode = VK_POLYGON_MODE_FILL;
|
|
|
|
|
|
rasterizationInfo.lineWidth = 1.0f;
|
|
|
|
|
|
rasterizationInfo.cullMode = VK_CULL_MODE_FRONT_BIT;
|
|
|
|
|
|
rasterizationInfo.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
|
|
|
|
|
// 渲染阴影的偏移配置
|
|
|
|
|
|
rasterizationInfo.depthBiasEnable = VK_FALSE;
|
|
|
|
|
|
rasterizationInfo.depthBiasConstantFactor = 0.0f;
|
|
|
|
|
|
rasterizationInfo.depthBiasClamp = 0.0f;
|
|
|
|
|
|
rasterizationInfo.depthBiasSlopeFactor = 0.0f;
|
|
|
|
|
|
|
|
|
|
|
|
// 设置Shader采样纹理的MSAA(不是输出到屏幕上的MSAA),需要创建逻辑设备的时候开启VkPhysicalDeviceFeatures里的sampleRateShading才能生效,暂时关闭
|
|
|
|
|
|
VkPipelineMultisampleStateCreateInfo multisampleInfo = {};
|
|
|
|
|
|
multisampleInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
|
|
|
|
|
multisampleInfo.sampleShadingEnable = (VK_SAMPLE_COUNT_1_BIT & VK_SAMPLE_COUNT_1_BIT ? VK_FALSE : VK_TRUE);
|
|
|
|
|
|
multisampleInfo.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
|
|
|
|
|
// 这个是调整sampleShading效果的,越接近1效果越平滑,越接近0性能越好
|
|
|
|
|
|
multisampleInfo.minSampleShading = 1.0f;
|
|
|
|
|
|
multisampleInfo.pSampleMask = VK_NULL_HANDLE;
|
|
|
|
|
|
multisampleInfo.alphaToCoverageEnable = VK_FALSE;
|
|
|
|
|
|
multisampleInfo.alphaToOneEnable = VK_FALSE;
|
|
|
|
|
|
// Color Blend
|
|
|
|
|
|
VkPipelineColorBlendAttachmentState colorBlendAttachment{};
|
|
|
|
|
|
colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
|
|
|
|
|
colorBlendAttachment.blendEnable = VK_TRUE;
|
|
|
|
|
|
colorBlendAttachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
|
|
|
|
|
colorBlendAttachment.dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
|
|
|
|
colorBlendAttachment.colorBlendOp = VK_BLEND_OP_ADD;
|
|
|
|
|
|
colorBlendAttachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
|
|
|
|
|
colorBlendAttachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
|
|
|
|
|
colorBlendAttachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
|
|
|
|
|
VkPipelineColorBlendStateCreateInfo colorBlending{};
|
|
|
|
|
|
colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
|
|
|
|
|
colorBlending.logicOpEnable = VK_FALSE;
|
|
|
|
|
|
colorBlending.logicOp = VK_LOGIC_OP_COPY;
|
|
|
|
|
|
colorBlending.pAttachments = &colorBlendAttachment;
|
|
|
|
|
|
colorBlending.attachmentCount = 1;
|
|
|
|
|
|
// 深度和模板配置
|
|
|
|
|
|
VkPipelineDepthStencilStateCreateInfo depthStencilInfo = {};
|
|
|
|
|
|
depthStencilInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
|
|
|
|
|
// Depth
|
|
|
|
|
|
depthStencilInfo.depthWriteEnable = VK_FALSE;
|
|
|
|
|
|
depthStencilInfo.depthTestEnable = VK_TRUE;
|
|
|
|
|
|
depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS;
|
|
|
|
|
|
depthStencilInfo.depthBoundsTestEnable = VK_FALSE;
|
|
|
|
|
|
depthStencilInfo.minDepthBounds = 0.0f;
|
|
|
|
|
|
depthStencilInfo.maxDepthBounds = 1.0f;
|
|
|
|
|
|
// Stencil
|
|
|
|
|
|
depthStencilInfo.stencilTestEnable = VK_FALSE;
|
|
|
|
|
|
depthStencilInfo.front = {};
|
|
|
|
|
|
depthStencilInfo.back = {};
|
2024-11-02 17:55:55 +08:00
|
|
|
|
|
|
|
|
|
|
VulkanPipeline& vulkan_pipeline = PipelineTable[shader.GetGuid()];
|
|
|
|
|
|
vulkan_pipeline.descCount = VulkanGlslLoader::GetShaderLayout(vulkan_pipeline.descLayoutList, programList);
|
|
|
|
|
|
VkDescriptorSet descriptorSet;
|
|
|
|
|
|
VkDescriptorSetAllocateInfo allocInfo{};
|
|
|
|
|
|
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
|
|
|
|
|
allocInfo.descriptorPool = backend.GetPool().Ptr();
|
|
|
|
|
|
allocInfo.descriptorSetCount = vulkan_pipeline.descCount;
|
|
|
|
|
|
allocInfo.pSetLayouts = vulkan_pipeline.descLayoutList;
|
|
|
|
|
|
vkAllocateDescriptorSets(device.Ptr(), &allocInfo, vulkan_pipeline.descList);
|
|
|
|
|
|
|
2024-10-30 15:15:25 +08:00
|
|
|
|
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
|
|
|
|
|
|
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
2024-11-02 17:55:55 +08:00
|
|
|
|
pipelineLayoutInfo.setLayoutCount = vulkan_pipeline.descCount;
|
|
|
|
|
|
pipelineLayoutInfo.pSetLayouts = vulkan_pipeline.descLayoutList;
|
2024-10-30 15:15:25 +08:00
|
|
|
|
VkPipelineLayout pipelineLayout;
|
|
|
|
|
|
if (vkCreatePipelineLayout(device.Ptr(), &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS)
|
|
|
|
|
|
throw std::runtime_error("failed to create pipeline layout!");
|
2024-10-25 22:57:25 +08:00
|
|
|
|
|
|
|
|
|
|
VkGraphicsPipelineCreateInfo pipelineInfo{};
|
|
|
|
|
|
pipelineInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
|
|
|
|
|
pipelineInfo.pStages = shaderStages.data();
|
|
|
|
|
|
pipelineInfo.stageCount = (uint32_t)shaderStages.size();
|
|
|
|
|
|
pipelineInfo.pVertexInputState = &vertexInputInfo;
|
|
|
|
|
|
pipelineInfo.pInputAssemblyState = &inputAssemblyInfo;
|
|
|
|
|
|
pipelineInfo.pViewportState = &viewportStateInfo;
|
|
|
|
|
|
pipelineInfo.pDynamicState = &dynamicStateInfo;
|
|
|
|
|
|
pipelineInfo.pRasterizationState = &rasterizationInfo;
|
|
|
|
|
|
pipelineInfo.pMultisampleState = &multisampleInfo;
|
|
|
|
|
|
pipelineInfo.pColorBlendState = &colorBlending;
|
|
|
|
|
|
pipelineInfo.pDepthStencilState = nullptr; //&depthStencilInfo;
|
|
|
|
|
|
pipelineInfo.layout = pipelineLayout;
|
2024-10-26 17:54:54 +08:00
|
|
|
|
pipelineInfo.renderPass = renderpass;
|
2024-10-25 22:57:25 +08:00
|
|
|
|
pipelineInfo.subpass = 0;
|
|
|
|
|
|
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
|
|
|
|
|
|
pipelineInfo.basePipelineIndex = -1;
|
|
|
|
|
|
|
|
|
|
|
|
VkPipeline pipeLine;
|
|
|
|
|
|
if (vkCreateGraphicsPipelines(device.Ptr(), VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &pipeLine) != VK_SUCCESS)
|
|
|
|
|
|
throw std::runtime_error("failed to create graphics pipeline!");
|
|
|
|
|
|
|
|
|
|
|
|
for (auto& shaderModule : shaderModules)
|
|
|
|
|
|
vkDestroyShaderModule(device.Ptr(), shaderModule.second, nullptr);
|
|
|
|
|
|
|
|
|
|
|
|
vulkan_pipeline.name = shader.Name();
|
|
|
|
|
|
vulkan_pipeline.pipeline = pipeLine;
|
|
|
|
|
|
vulkan_pipeline.inUse = true;
|
|
|
|
|
|
vulkan_pipeline.pipelineLayout = pipelineLayout;
|
2024-11-08 17:18:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
void VulkanAPI::CreateBuffer(BufferDesc& desc)
|
|
|
|
|
|
{
|
|
|
|
|
|
|
2024-08-25 22:41:25 +08:00
|
|
|
|
}
|
2024-12-19 17:23:52 +08:00
|
|
|
|
void VulkanAPI::CreateTexture(TextureDesc& desc)
|
2024-10-21 16:31:02 +08:00
|
|
|
|
{
|
|
|
|
|
|
VkImageCreateInfo imageCreateInfo = {
|
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
|
|
|
|
|
.pNext = NULL,
|
|
|
|
|
|
.flags = vkApiGetImageCreateFlag(desc.dimension, desc.arraySize),
|
|
|
|
|
|
.imageType = vkApiGetImageType(desc.dimension),
|
|
|
|
|
|
.format = (VkFormat)TinyImageFormat_ToVkFormat(desc.format),
|
|
|
|
|
|
.extent = {
|
|
|
|
|
|
.width = (uint32_t)desc.width,
|
|
|
|
|
|
.height = (uint32_t)desc.height,
|
|
|
|
|
|
.depth = (uint32_t)desc.depth,
|
|
|
|
|
|
},
|
|
|
|
|
|
.mipLevels = desc.mipLevel,
|
|
|
|
|
|
.arrayLayers = desc.arraySize,
|
|
|
|
|
|
.samples = vkApiGetSmpleCountFlag(desc.sampleCount),
|
|
|
|
|
|
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
2024-12-19 17:23:52 +08:00
|
|
|
|
.usage = vkApiGetImageUsageFlags(desc.usage),
|
2024-10-21 16:31:02 +08:00
|
|
|
|
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
|
|
|
|
.queueFamilyIndexCount = 0,
|
|
|
|
|
|
.pQueueFamilyIndices = NULL,
|
2024-12-19 17:23:52 +08:00
|
|
|
|
.initialLayout = vkApiGetImageLayout(desc.state)
|
2024-10-21 16:31:02 +08:00
|
|
|
|
};
|
2024-12-19 17:23:52 +08:00
|
|
|
|
ImageCreator imageCreator{ .imageInfo = imageCreateInfo ,.image = (VkImage*)&desc.image };
|
|
|
|
|
|
Backend::TransferWorker->CreateImage(imageCreator);
|
2024-10-21 16:31:02 +08:00
|
|
|
|
}
|
2024-12-19 17:23:52 +08:00
|
|
|
|
ImageViewPtr VulkanAPI::CreateTextureView(TextureViewKey desc)
|
2024-10-21 16:31:02 +08:00
|
|
|
|
{
|
|
|
|
|
|
VkImageViewCreateInfo createInfo = {};
|
|
|
|
|
|
createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
|
|
|
|
|
createInfo.image = (VkImage)desc.image;
|
|
|
|
|
|
createInfo.viewType = vkApiGetImageViewType(desc.dimension, desc.layerCount);
|
|
|
|
|
|
createInfo.format = (VkFormat)TinyImageFormat_ToVkFormat(desc.format);
|
|
|
|
|
|
|
|
|
|
|
|
// components字段允许调整颜色通道的最终的映射逻辑
|
|
|
|
|
|
// 比如,我们可以将所有颜色通道映射为红色通道,以实现单色纹理,我们也可以将通道映射具体的常量数值0和1
|
|
|
|
|
|
// 这里用默认的
|
|
|
|
|
|
createInfo.components.r = VK_COMPONENT_SWIZZLE_R;
|
|
|
|
|
|
createInfo.components.g = VK_COMPONENT_SWIZZLE_G;
|
|
|
|
|
|
createInfo.components.b = VK_COMPONENT_SWIZZLE_B;
|
|
|
|
|
|
createInfo.components.a = VK_COMPONENT_SWIZZLE_A;
|
|
|
|
|
|
|
|
|
|
|
|
// subresourceRangle字段用于描述图像的使用目标是什么,以及可以被访问的有效区域
|
|
|
|
|
|
// 这个图像用作填充color还是depth stencil等
|
|
|
|
|
|
createInfo.subresourceRange.aspectMask = vkApiGetImageAspectMask(createInfo.format, false);
|
|
|
|
|
|
// 默认处理所有Mipmap
|
|
|
|
|
|
createInfo.subresourceRange.baseMipLevel = desc.baseMipLevel;
|
|
|
|
|
|
createInfo.subresourceRange.levelCount = desc.levelCount;
|
|
|
|
|
|
// 默认处理所有Layers
|
|
|
|
|
|
createInfo.subresourceRange.baseArrayLayer = desc.baseArrayLayer;
|
|
|
|
|
|
createInfo.subresourceRange.layerCount = desc.layerCount;
|
|
|
|
|
|
|
|
|
|
|
|
VkImageView imageView;
|
|
|
|
|
|
vkCreateImageView(backend.GetDevice().Ptr(), &createInfo, nullptr, &imageView);
|
|
|
|
|
|
return (ImageViewPtr)imageView;
|
|
|
|
|
|
}
|
2024-12-20 10:29:52 +08:00
|
|
|
|
SamplerPtr VulkanAPI::CreateTextureSampler(TextureSampler key)
|
|
|
|
|
|
{
|
|
|
|
|
|
VkSamplerCreateInfo samplerInfo = vkApiGetSamplerCreateInfo(key);
|
|
|
|
|
|
VkSampler sampler;
|
|
|
|
|
|
vkCreateSampler(backend.GetDevice().Ptr(), &samplerInfo, nullptr, &sampler);
|
|
|
|
|
|
return sampler;
|
|
|
|
|
|
}
|
2024-08-30 22:09:05 +08:00
|
|
|
|
void VulkanAPI::BeginFrame()
|
|
|
|
|
|
{
|
2024-10-12 17:40:59 +08:00
|
|
|
|
VulkanContext& ctx = *(VulkanContext*)&context;
|
|
|
|
|
|
window.Aquire(ctx);
|
2024-12-19 17:23:52 +08:00
|
|
|
|
graph.Input(ctx.surface);
|
|
|
|
|
|
EventSystem::Ptr()->BeginRenderFrame.Invoke(graph, ctx.frame);
|
2024-08-30 22:09:05 +08:00
|
|
|
|
}
|
|
|
|
|
|
void VulkanAPI::EndFrame()
|
|
|
|
|
|
{
|
2024-10-12 17:40:59 +08:00
|
|
|
|
VulkanContext& ctx = *(VulkanContext*)&context;
|
|
|
|
|
|
window.Present(ctx);
|
2024-09-07 17:48:12 +08:00
|
|
|
|
}
|
2024-09-21 17:19:22 +08:00
|
|
|
|
void VulkanAPI::ExecuteResourceBarriers(const ResourceBarrierDesc& desc) {
|
2024-09-22 20:26:49 +08:00
|
|
|
|
VulkanContext& ctx = *(VulkanContext*)&context;
|
2024-09-21 17:19:22 +08:00
|
|
|
|
pmr::vector<VkBufferMemoryBarrier> bufferBarriers{ FramePool() };
|
|
|
|
|
|
bufferBarriers.reserve(desc.bufferBarriersCount);
|
|
|
|
|
|
pmr::vector<VkImageMemoryBarrier> imageBarriers{ FramePool() };
|
|
|
|
|
|
imageBarriers.reserve(desc.textureBarriersCount);
|
2024-09-30 17:56:12 +08:00
|
|
|
|
VkPipelineStageFlags srcStageMask = 0, dstStageMask = 0;
|
2024-09-21 17:19:22 +08:00
|
|
|
|
for (uint32_t i = 0; i < desc.textureBarriersCount; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
auto& barrier = desc.pTextureBarriers[i];
|
2024-10-21 16:31:02 +08:00
|
|
|
|
auto desc = vkApiGetTextureTransition(srcStageMask, dstStageMask, barrier);
|
2024-09-22 20:26:49 +08:00
|
|
|
|
imageBarriers.push_back(desc);
|
2024-09-21 17:19:22 +08:00
|
|
|
|
}
|
2024-10-12 17:40:59 +08:00
|
|
|
|
if (dstStageMask == 0) {
|
|
|
|
|
|
dstStageMask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
|
|
|
|
|
|
}
|
2024-12-12 22:20:56 +08:00
|
|
|
|
VkCommandBuffer command = desc.type == RenderPassType::Present ? ctx.surfaceCommand : ctx.command;
|
|
|
|
|
|
vkCmdPipelineBarrier(command, srcStageMask, dstStageMask, 0, 0, NULL, 0, NULL, imageBarriers.size(), imageBarriers.data());
|
2024-09-21 17:19:22 +08:00
|
|
|
|
}
|
2024-12-12 22:20:56 +08:00
|
|
|
|
void VulkanAPI::BeginRenderPass(RenderPassNode* node, FnEnterRenderPass callback)
|
2024-09-21 17:19:22 +08:00
|
|
|
|
{
|
2024-12-21 15:32:22 +08:00
|
|
|
|
RenderPassKey config{};
|
|
|
|
|
|
FramebufferKey frameKey{.layers = 1};
|
|
|
|
|
|
VkClearValue clearValues[MAX_SUPPORTED_RENDER_TARGET_COUNT] = { 0 };
|
|
|
|
|
|
RenderPassParams& params = node->params;
|
|
|
|
|
|
int clearSurfaceIndex = -1;
|
|
|
|
|
|
int i = 0, attachmentCount = 0;
|
2024-09-21 17:19:22 +08:00
|
|
|
|
for (auto& it : node->outEdges) {
|
2024-12-21 15:32:22 +08:00
|
|
|
|
uint32_t flag = 1 << i;
|
|
|
|
|
|
TextureDesc& texture = it->CastTo<TextureDesc>();
|
|
|
|
|
|
frameKey.imageViews[attachmentCount++] = (VkImageView)graph.ResolveTextureView(texture);
|
|
|
|
|
|
frameKey.height = texture.height;
|
|
|
|
|
|
frameKey.width = texture.width;
|
|
|
|
|
|
config.colorFormat[i] = texture.format;
|
|
|
|
|
|
if (params.sampleMask & flag) {
|
|
|
|
|
|
TextureDesc resolve = texture.Resolve();
|
|
|
|
|
|
graph.AcquireTexture(resolve);
|
|
|
|
|
|
frameKey.imageViews[attachmentCount++] = (VkImageView)graph.ResolveTextureView(resolve);
|
2024-09-21 17:19:22 +08:00
|
|
|
|
}
|
2024-12-21 15:32:22 +08:00
|
|
|
|
if (texture.sampleCount > config.samples)
|
|
|
|
|
|
config.samples = texture.sampleCount;
|
|
|
|
|
|
VkClearValue& clearValue = clearValues[i];
|
|
|
|
|
|
const bool bclear = params.clear & flag;
|
|
|
|
|
|
if (texture.state == ResourceState::COLOR_ATTACHMENT) {
|
|
|
|
|
|
if (!bclear && context.surface.id == texture.id && node->IsFirstInput()) {
|
|
|
|
|
|
clearSurfaceIndex = i;//需要手动清除
|
|
|
|
|
|
}
|
|
|
|
|
|
if (bclear || clearSurfaceIndex == i) {
|
|
|
|
|
|
clearValue.color.float32[0] = params.clearColor.r;
|
|
|
|
|
|
clearValue.color.float32[1] = params.clearColor.g;
|
|
|
|
|
|
clearValue.color.float32[2] = params.clearColor.b;
|
|
|
|
|
|
clearValue.color.float32[3] = params.clearColor.a;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
config.depthMask |= flag;
|
|
|
|
|
|
if (bclear) {
|
|
|
|
|
|
clearValue.depthStencil = { (float)params.clearDepth, params.clearStencil };
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
i++;
|
2024-09-21 17:19:22 +08:00
|
|
|
|
}
|
2024-12-21 15:32:22 +08:00
|
|
|
|
frameKey.attachmentCount = attachmentCount;
|
|
|
|
|
|
config.clear = params.clear;
|
|
|
|
|
|
config.discardEnd = params.discardEnd;
|
|
|
|
|
|
config.discardStart = params.discardStart;
|
2024-12-19 17:23:52 +08:00
|
|
|
|
RenderPassInfo* passInfo = GetRenderPassInfo(node->name, node->hash);
|
2024-12-14 17:57:33 +08:00
|
|
|
|
if (!passInfo) {
|
|
|
|
|
|
passInfo = GetRenderPassInfo(node->hash, config);
|
|
|
|
|
|
}
|
2024-12-21 15:32:22 +08:00
|
|
|
|
frameKey.pass = passInfo->pass;
|
2024-10-21 16:31:02 +08:00
|
|
|
|
auto it = FramebufferCache.find(frameKey);
|
|
|
|
|
|
VkFramebuffer framebuffer = it->second;
|
|
|
|
|
|
if (it == FramebufferCache.end()) {
|
|
|
|
|
|
VkFramebufferCreateInfo framebufferInfo = {
|
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
2024-12-12 22:20:56 +08:00
|
|
|
|
.renderPass = frameKey.pass,
|
2024-10-21 16:31:02 +08:00
|
|
|
|
.attachmentCount = frameKey.attachmentCount,
|
|
|
|
|
|
.pAttachments = frameKey.imageViews,
|
|
|
|
|
|
.width = frameKey.width,
|
|
|
|
|
|
.height = frameKey.height,
|
|
|
|
|
|
.layers = frameKey.layers
|
|
|
|
|
|
};
|
|
|
|
|
|
vkCreateFramebuffer(backend.GetDevice().Ptr(), &framebufferInfo, nullptr, &framebuffer);
|
|
|
|
|
|
FramebufferCache.emplace(frameKey, framebuffer);
|
|
|
|
|
|
}
|
|
|
|
|
|
VkRect2D renderAarea = {
|
|
|
|
|
|
.offset = {0,0},
|
|
|
|
|
|
.extent = {frameKey.width,frameKey.height}
|
|
|
|
|
|
};
|
|
|
|
|
|
VkRenderPassBeginInfo beginInfo = {
|
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
|
|
|
|
|
|
.pNext = VK_NULL_HANDLE,
|
2024-12-12 22:20:56 +08:00
|
|
|
|
.renderPass = frameKey.pass,
|
2024-10-21 16:31:02 +08:00
|
|
|
|
.framebuffer = framebuffer,
|
|
|
|
|
|
.renderArea = renderAarea,
|
|
|
|
|
|
.clearValueCount = frameKey.attachmentCount,
|
|
|
|
|
|
.pClearValues = clearValues
|
|
|
|
|
|
};
|
|
|
|
|
|
VulkanContext& ctx = *(VulkanContext*)&context;
|
2024-12-14 17:57:33 +08:00
|
|
|
|
CommandBuffer cmd = passInfo->commands[context.frame];
|
2024-12-12 22:20:56 +08:00
|
|
|
|
ctx.command = cmd.Ptr();
|
|
|
|
|
|
cmd.BeginRecord(VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT);
|
|
|
|
|
|
if(callback) callback(node);
|
|
|
|
|
|
vkCmdBeginRenderPass(cmd.Ptr(), &beginInfo, VK_SUBPASS_CONTENTS_INLINE);
|
2024-12-21 15:32:22 +08:00
|
|
|
|
if (clearSurfaceIndex != -1)ctx.ClearSurface(clearValues[clearSurfaceIndex].color);
|
2024-09-21 17:19:22 +08:00
|
|
|
|
}
|
|
|
|
|
|
void VulkanAPI::EndRenderPass(RenderPassNode* node)
|
|
|
|
|
|
{
|
2024-10-21 16:31:02 +08:00
|
|
|
|
VulkanContext& ctx = *(VulkanContext*)&context;
|
2024-12-14 17:57:33 +08:00
|
|
|
|
RenderPassInfo* passInfo = GetRenderPassInfo(node->name, node->hash);
|
|
|
|
|
|
CommandBuffer cmd = passInfo->commands[context.frame];
|
2024-12-12 22:20:56 +08:00
|
|
|
|
vkCmdEndRenderPass(cmd.Ptr());
|
|
|
|
|
|
cmd.EndRecord();
|
|
|
|
|
|
VkSemaphore waitSemaphores[8];
|
|
|
|
|
|
VkPipelineStageFlags waitDstStageMasks[8];
|
|
|
|
|
|
uint32_t semaphoreCount = 0;
|
2024-12-15 17:24:35 +08:00
|
|
|
|
if (node->IsFirstInput()) {
|
2024-12-12 22:20:56 +08:00
|
|
|
|
waitDstStageMasks[semaphoreCount] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
|
|
|
|
waitSemaphores[semaphoreCount++] = ctx.surfaceSemaphore;
|
2024-12-20 10:29:52 +08:00
|
|
|
|
gLogSemaphore("-----wait {:#x}", (uintptr_t)ctx.surfaceSemaphore);
|
2024-12-12 22:20:56 +08:00
|
|
|
|
}
|
2024-12-15 17:24:35 +08:00
|
|
|
|
for (auto& it : node->dependencies) {
|
|
|
|
|
|
RenderPassInfo* inputInfo = GetRenderPassInfo(it->name ,it->hash);
|
2024-12-12 22:20:56 +08:00
|
|
|
|
waitDstStageMasks[semaphoreCount] = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
2024-12-14 17:57:33 +08:00
|
|
|
|
waitSemaphores[semaphoreCount++] = inputInfo->semaphores[context.frame];
|
2024-12-20 10:29:52 +08:00
|
|
|
|
gLogSemaphore("-----wait {:#x}", (uintptr_t)inputInfo->semaphores[context.frame]);
|
2024-12-12 22:20:56 +08:00
|
|
|
|
}
|
|
|
|
|
|
VkSubmitInfo submitInfo{};
|
|
|
|
|
|
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
|
|
|
|
submitInfo.commandBufferCount = 1;
|
|
|
|
|
|
submitInfo.pCommandBuffers = &cmd.Ptr();
|
2024-12-14 17:57:33 +08:00
|
|
|
|
submitInfo.pSignalSemaphores = &passInfo->semaphores[context.frame];
|
2024-12-12 22:20:56 +08:00
|
|
|
|
submitInfo.signalSemaphoreCount = 1;
|
|
|
|
|
|
submitInfo.pWaitSemaphores = waitSemaphores;
|
|
|
|
|
|
submitInfo.pWaitDstStageMask = waitDstStageMasks;
|
|
|
|
|
|
submitInfo.waitSemaphoreCount = semaphoreCount;
|
2024-12-16 21:49:57 +08:00
|
|
|
|
VkFence fence = nullptr;
|
2024-12-15 17:24:35 +08:00
|
|
|
|
if (node->IsLastOutput()) {
|
2024-12-14 17:57:33 +08:00
|
|
|
|
ctx.graphSemaphore = passInfo->semaphores[context.frame];
|
2024-12-20 10:29:52 +08:00
|
|
|
|
TextureDesc& surface = graph.GetRenderSurface();
|
|
|
|
|
|
if (surface.state == ResourceState::PRESENT) {
|
2024-12-16 21:49:57 +08:00
|
|
|
|
fence = ctx.surfaceFence;
|
|
|
|
|
|
}
|
2024-12-12 22:20:56 +08:00
|
|
|
|
}
|
2024-12-20 10:29:52 +08:00
|
|
|
|
gLogSemaphore("+++++sign {:#x}", (uintptr_t)passInfo->semaphores[context.frame]);
|
2024-12-16 21:49:57 +08:00
|
|
|
|
vkQueueSubmit(Backend::RenderWorker->GetQueue().Ptr(), 1, &submitInfo, fence);
|
2024-09-21 17:19:22 +08:00
|
|
|
|
}
|
2024-12-14 17:57:33 +08:00
|
|
|
|
RenderPassInfo* VulkanAPI::GetRenderPassInfo(Name name, size_t hash) {
|
|
|
|
|
|
if (hash) {
|
|
|
|
|
|
auto it = RenderPassCache.find(hash);
|
|
|
|
|
|
if (it != RenderPassCache.end()) {
|
|
|
|
|
|
return &it->second;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (name) {
|
|
|
|
|
|
auto it = RenderPassNameCache.find(name);
|
|
|
|
|
|
if (it != RenderPassNameCache.end()) {
|
|
|
|
|
|
return &it->second;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
|
}
|
2024-12-21 15:32:22 +08:00
|
|
|
|
//单一renderpass,config.passMask 可以取 0
|
2024-12-14 17:57:33 +08:00
|
|
|
|
RenderPassInfo* VulkanAPI::GetRenderPassInfo(size_t& hash, const RenderPassKey& config) {
|
|
|
|
|
|
hash = config;
|
2024-12-21 15:32:22 +08:00
|
|
|
|
if (auto it = RenderPassCache.find(hash); it != RenderPassCache.end()) {
|
2024-12-14 17:57:33 +08:00
|
|
|
|
return &it->second;
|
2024-09-15 11:31:27 +08:00
|
|
|
|
}
|
|
|
|
|
|
// Set up some const aliases for terseness.
|
|
|
|
|
|
const VkAttachmentLoadOp kClear = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
|
|
|
|
|
const VkAttachmentLoadOp kDontCare = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
|
|
|
|
|
const VkAttachmentLoadOp kKeep = VK_ATTACHMENT_LOAD_OP_LOAD;
|
|
|
|
|
|
const VkAttachmentStoreOp kDisableStore = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
|
|
|
|
|
const VkAttachmentStoreOp kEnableStore = VK_ATTACHMENT_STORE_OP_STORE;
|
|
|
|
|
|
|
|
|
|
|
|
VkAttachmentReference inputAttachmentRef[MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
|
|
|
|
|
VkAttachmentReference colorAttachmentRefs[2][MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
2024-12-21 15:32:22 +08:00
|
|
|
|
VkAttachmentReference resolveAttachmentRef[2][MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
|
|
|
|
|
VkAttachmentReference depthAttachmentRef[2] = {};
|
|
|
|
|
|
|
|
|
|
|
|
const bool hasSubpasses = config.subpassMask;
|
|
|
|
|
|
const bool hasDepth1 = (!hasSubpasses && config.depthMask) || config.depthMask & config.passMask;
|
|
|
|
|
|
const bool hasDepth2 = config.depthMask & config.subpassMask;
|
|
|
|
|
|
const bool hasSample1 = (!hasSubpasses && config.sampleMask) || config.sampleMask & config.passMask;
|
|
|
|
|
|
const bool hasSample2 = config.sampleMask & config.subpassMask;
|
2024-09-15 11:31:27 +08:00
|
|
|
|
VkSubpassDescription subpasses[2] = { {
|
|
|
|
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
|
|
|
|
.pInputAttachments = nullptr,
|
|
|
|
|
|
.pColorAttachments = colorAttachmentRefs[0],
|
2024-12-21 15:32:22 +08:00
|
|
|
|
.pResolveAttachments = hasSample1 ? resolveAttachmentRef[0] : nullptr,
|
|
|
|
|
|
.pDepthStencilAttachment = hasDepth1 ? &depthAttachmentRef[0] : nullptr
|
2024-09-15 11:31:27 +08:00
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
|
|
|
|
.pInputAttachments = inputAttachmentRef,
|
|
|
|
|
|
.pColorAttachments = colorAttachmentRefs[1],
|
2024-12-21 15:32:22 +08:00
|
|
|
|
.pResolveAttachments = hasSample2 ? resolveAttachmentRef[1] : nullptr,
|
|
|
|
|
|
.pDepthStencilAttachment = hasDepth2 ? &depthAttachmentRef[1] : nullptr
|
2024-09-15 11:31:27 +08:00
|
|
|
|
} };
|
2024-12-21 15:32:22 +08:00
|
|
|
|
|
|
|
|
|
|
VkAttachmentDescription attachments[MAX_SUPPORTED_RENDER_TARGET_COUNT] = {};
|
2024-09-15 11:31:27 +08:00
|
|
|
|
// We support 2 subpasses, which means we need to supply 1 dependency struct.
|
|
|
|
|
|
VkSubpassDependency dependencies[1] = { {
|
|
|
|
|
|
.srcSubpass = 0,
|
|
|
|
|
|
.dstSubpass = 1,
|
|
|
|
|
|
.dependencyFlags = VK_DEPENDENCY_BY_REGION_BIT,
|
|
|
|
|
|
} };
|
2024-09-07 17:48:12 +08:00
|
|
|
|
// Finally, create the VkRenderPass.
|
|
|
|
|
|
VkRenderPassCreateInfo renderPassInfo{
|
|
|
|
|
|
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
|
|
|
|
|
|
.attachmentCount = 0u,
|
|
|
|
|
|
.pAttachments = attachments,
|
|
|
|
|
|
.subpassCount = hasSubpasses ? 2u : 1u,
|
|
|
|
|
|
.pSubpasses = subpasses,
|
|
|
|
|
|
.dependencyCount = hasSubpasses ? 1u : 0u,
|
|
|
|
|
|
};
|
2024-12-21 15:32:22 +08:00
|
|
|
|
const VkSampleCountFlagBits samplecount = vkApiGetSmpleCountFlag(config.samples);
|
|
|
|
|
|
uint32_t attachmentIndex = 0, samplePassIndex1 = 0, samplePassIndex2 = 0;
|
2024-09-15 11:31:27 +08:00
|
|
|
|
// Populate the Color Attachments.
|
2024-12-21 15:32:22 +08:00
|
|
|
|
for (uint32_t i = 0; i < MAX_SUPPORTED_RENDER_TARGET_COUNT; i++) {
|
|
|
|
|
|
if (config.colorFormat[i] == TinyImageFormat_UNDEFINED) {
|
|
|
|
|
|
break;
|
2024-09-15 11:31:27 +08:00
|
|
|
|
}
|
2024-12-21 15:32:22 +08:00
|
|
|
|
const uint8_t flag = 1 << i;
|
|
|
|
|
|
const bool clear = config.clear & flag;
|
|
|
|
|
|
const bool discard = config.discardStart & flag;
|
|
|
|
|
|
const bool discardEnd = config.discardEnd & flag;
|
|
|
|
|
|
const bool sample = config.sampleMask & flag;
|
|
|
|
|
|
const VkFormat format = (VkFormat)TinyImageFormat_ToVkFormat(config.colorFormat[i]);
|
|
|
|
|
|
VkImageLayout layout = vkApiGetAttachmentLayout(format, true);
|
|
|
|
|
|
attachments[attachmentIndex] = {
|
|
|
|
|
|
.format = format,
|
|
|
|
|
|
.samples = sample ? samplecount : VK_SAMPLE_COUNT_1_BIT,
|
2024-09-15 11:31:27 +08:00
|
|
|
|
.loadOp = clear ? kClear : (discard ? kDontCare : kKeep),
|
2024-12-21 15:32:22 +08:00
|
|
|
|
.storeOp = discardEnd ? kDisableStore : kEnableStore,
|
2024-09-15 11:31:27 +08:00
|
|
|
|
.stencilLoadOp = kDontCare,
|
|
|
|
|
|
.stencilStoreOp = kDisableStore,
|
2024-10-21 16:31:02 +08:00
|
|
|
|
.initialLayout = layout,
|
|
|
|
|
|
.finalLayout = layout,
|
2024-09-15 11:31:27 +08:00
|
|
|
|
};
|
2024-12-21 15:32:22 +08:00
|
|
|
|
if (sample) {
|
|
|
|
|
|
attachments[attachmentIndex + 1] = {
|
|
|
|
|
|
.format = format,
|
|
|
|
|
|
.samples = VK_SAMPLE_COUNT_1_BIT,
|
|
|
|
|
|
.loadOp = clear ? kClear : (discard ? kDontCare : kKeep),
|
|
|
|
|
|
.storeOp = discardEnd ? kDisableStore : kEnableStore,
|
|
|
|
|
|
.stencilLoadOp = kDontCare,
|
|
|
|
|
|
.stencilStoreOp = kDisableStore,
|
|
|
|
|
|
.initialLayout = layout,
|
|
|
|
|
|
.finalLayout = layout,
|
|
|
|
|
|
};
|
2024-09-15 11:31:27 +08:00
|
|
|
|
}
|
2024-12-21 15:32:22 +08:00
|
|
|
|
const bool isDepth = config.depthMask & flag;
|
|
|
|
|
|
const bool isMask1 = !hasSubpasses || config.passMask & flag;
|
|
|
|
|
|
const bool isMask2 = hasSubpasses && config.subpassMask & flag;
|
|
|
|
|
|
uint32_t index = 0;
|
|
|
|
|
|
if (isMask1) {
|
|
|
|
|
|
index = subpasses[0].colorAttachmentCount++;
|
|
|
|
|
|
colorAttachmentRefs[0][index].layout = layout;
|
|
|
|
|
|
colorAttachmentRefs[0][index].attachment = attachmentIndex;
|
|
|
|
|
|
if (sample) {
|
|
|
|
|
|
index = subpasses[0].colorAttachmentCount++;
|
|
|
|
|
|
colorAttachmentRefs[0][index].layout = layout;
|
|
|
|
|
|
colorAttachmentRefs[0][index].attachment = attachmentIndex + 1;
|
|
|
|
|
|
}
|
2024-09-15 11:31:27 +08:00
|
|
|
|
}
|
2024-12-21 15:32:22 +08:00
|
|
|
|
if (isMask2) {
|
|
|
|
|
|
if (isMask1) {
|
|
|
|
|
|
index = subpasses[1].inputAttachmentCount++;
|
|
|
|
|
|
inputAttachmentRef[index].layout = layout;
|
|
|
|
|
|
inputAttachmentRef[index].attachment = sample ? attachmentIndex + 1 : attachmentIndex;
|
|
|
|
|
|
if (isDepth) {
|
|
|
|
|
|
dependencies->srcStageMask |= VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT;
|
|
|
|
|
|
dependencies->dstStageMask |= VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
|
|
|
|
|
dependencies->srcAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
|
|
|
|
|
dependencies->dstAccessMask |= VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT;
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
dependencies->srcStageMask |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
|
|
|
|
|
dependencies->dstStageMask |= VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
|
|
|
|
|
dependencies->srcAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
|
|
|
|
|
dependencies->dstAccessMask |= VK_ACCESS_COLOR_ATTACHMENT_READ_BIT;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else {
|
|
|
|
|
|
index = subpasses[1].colorAttachmentCount++;
|
|
|
|
|
|
colorAttachmentRefs[1][index].layout = layout;
|
|
|
|
|
|
colorAttachmentRefs[1][index].attachment = attachmentIndex;
|
|
|
|
|
|
if (sample) {
|
|
|
|
|
|
index = subpasses[1].colorAttachmentCount++;
|
|
|
|
|
|
colorAttachmentRefs[1][index].layout = layout;
|
|
|
|
|
|
colorAttachmentRefs[1][index].attachment = attachmentIndex + 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isDepth) {
|
|
|
|
|
|
if (isMask1) {
|
|
|
|
|
|
depthAttachmentRef[0].layout = layout;
|
|
|
|
|
|
depthAttachmentRef[0].attachment = attachmentIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (isMask2) {
|
|
|
|
|
|
depthAttachmentRef[1].layout = layout;
|
|
|
|
|
|
depthAttachmentRef[1].attachment = attachmentIndex;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
attachmentIndex += sample ? 2 : 1;
|
2024-09-15 11:31:27 +08:00
|
|
|
|
}
|
2024-12-21 15:32:22 +08:00
|
|
|
|
renderPassInfo.pDependencies = dependencies->srcStageMask ? dependencies : nullptr;
|
2024-09-15 11:31:27 +08:00
|
|
|
|
renderPassInfo.attachmentCount = attachmentIndex;
|
2024-12-12 22:20:56 +08:00
|
|
|
|
VkRenderPass pass;
|
|
|
|
|
|
VkResult error = vkCreateRenderPass(backend.GetDevice().Ptr(), &renderPassInfo, nullptr, &pass);
|
2024-12-21 15:32:22 +08:00
|
|
|
|
RenderPassInfo info{pass, config};
|
2024-12-12 22:20:56 +08:00
|
|
|
|
backend.GetDevice().CreateSemaphores(info.semaphores, context.frameCount);
|
|
|
|
|
|
Backend::RenderWorker->GetCommandPool().PopList(info.commands, context.frameCount);
|
2024-12-21 15:32:22 +08:00
|
|
|
|
auto itr = RenderPassCache.emplace(hash, info);
|
|
|
|
|
|
return &itr.first->second;
|
2024-08-30 22:09:05 +08:00
|
|
|
|
}
|
2024-12-15 17:24:35 +08:00
|
|
|
|
void VulkanAPI::SetRenderPassInfo(Name name, VkRenderPass pass) {
|
2024-12-21 15:32:22 +08:00
|
|
|
|
RenderPassInfo info{pass};
|
2024-12-15 17:24:35 +08:00
|
|
|
|
backend.GetDevice().CreateSemaphores(info.semaphores, context.frameCount);
|
|
|
|
|
|
Backend::RenderWorker->GetCommandPool().PopList(info.commands, context.frameCount);
|
|
|
|
|
|
RenderPassNameCache.emplace(name, info);
|
|
|
|
|
|
}
|
2024-08-17 18:01:21 +08:00
|
|
|
|
}
|