Vertex attributes are now bound automatically to shaders using spirv reflection.

This commit is contained in:
2022-02-27 23:51:29 -08:00
parent 3c948e2337
commit df344d0d7b
8 changed files with 103 additions and 79 deletions

View File

@@ -109,14 +109,14 @@ const char *KRPipeline::KRENGINE_UNIFORM_NAMES[] = {
"fade_color", // KRENGINE_UNIFORM_FADE_COLOR
};
KRPipeline::KRPipeline(KRContext& context, KrDeviceHandle deviceHandle, VkFormat swapChainImageFormat, uint32_t swapChainWidth, uint32_t swapChainHeight, const char* szKey, const std::vector<KRShader*>& shaders)
KRPipeline::KRPipeline(KRContext& context, KRSurface& surface, const char* szKey, const std::vector<KRShader*>& shaders, uint32_t vertexAttributes)
: KRContextObject(context)
, m_iProgram(0) // not used for Vulkan
{
m_pipelineLayout = nullptr;
m_graphicsPipeline = nullptr;
m_renderPass = nullptr;
KRDevice& device = *m_pContext->getDeviceManager()->getDevice(deviceHandle);
std::unique_ptr<KRDevice>& device = surface.getDevice();
// TODO - Handle device removal
strcpy(m_szKey, szKey);
@@ -126,15 +126,55 @@ KRPipeline::KRPipeline(KRContext& context, KrDeviceHandle deviceHandle, VkFormat
memset(static_cast<void*>(stages), 0, sizeof(VkPipelineShaderStageCreateInfo) * kMaxStages);
size_t stage_count = 0;
// TODO - Refactor this... These lookup tables should be in KRMesh...
static const KRMesh::vertex_attrib_t attribute_mapping[KRMesh::KRENGINE_NUM_ATTRIBUTES] = {
KRMesh::KRENGINE_ATTRIB_VERTEX,
KRMesh::KRENGINE_ATTRIB_NORMAL,
KRMesh::KRENGINE_ATTRIB_TANGENT,
KRMesh::KRENGINE_ATTRIB_TEXUVA,
KRMesh::KRENGINE_ATTRIB_TEXUVB,
KRMesh::KRENGINE_ATTRIB_BONEINDEXES,
KRMesh::KRENGINE_ATTRIB_BONEWEIGHTS,
KRMesh::KRENGINE_ATTRIB_VERTEX,
KRMesh::KRENGINE_ATTRIB_NORMAL,
KRMesh::KRENGINE_ATTRIB_TANGENT,
KRMesh::KRENGINE_ATTRIB_TEXUVA,
KRMesh::KRENGINE_ATTRIB_TEXUVB,
};
uint32_t attribute_locations[KRMesh::KRENGINE_NUM_ATTRIBUTES] = {};
for (KRShader* shader : shaders) {
VkShaderModule shaderModule;
if (!shader->createShaderModule(device.m_logicalDevice, shaderModule)) {
if (!shader->createShaderModule(device->m_logicalDevice, shaderModule)) {
// failed! TODO - Error handling
}
const SpvReflectShaderModule* reflection = shader->getReflection();
VkPipelineShaderStageCreateInfo& stageInfo = stages[stage_count++];
stageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
if (shader->getSubExtension().compare("vert") == 0) {
stageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT;
for (uint32_t i = 0; i < reflection->input_variable_count; i++) {
// TODO - We should have an interface to allow classes such as KRMesh to expose bindings
SpvReflectInterfaceVariable& input_var = *reflection->input_variables[i];
if (strcmp(input_var.name, "vertex_position") == 0) {
attribute_locations[KRMesh::KRENGINE_ATTRIB_VERTEX] = input_var.location + 1;
} else if (strcmp(input_var.name, "vertex_normal") == 0) {
attribute_locations[KRMesh::KRENGINE_ATTRIB_NORMAL] = input_var.location + 1;
} else if (strcmp(input_var.name, "vertex_tangent") == 0) {
attribute_locations[KRMesh::KRENGINE_ATTRIB_TANGENT] = input_var.location + 1;
} else if (strcmp(input_var.name, "vertex_uv") == 0) {
attribute_locations[KRMesh::KRENGINE_ATTRIB_TEXUVA] = input_var.location + 1;
} else if (strcmp(input_var.name, "vertex_lightmap_uv") == 0) {
attribute_locations[KRMesh::KRENGINE_ATTRIB_TEXUVB] = input_var.location + 1;
} else if (strcmp(input_var.name, "bone_indexes") == 0) {
attribute_locations[KRMesh::KRENGINE_ATTRIB_BONEINDEXES] = input_var.location + 1;
} else if (strcmp(input_var.name, "bone_weights") == 0) {
attribute_locations[KRMesh::KRENGINE_ATTRIB_BONEWEIGHTS] = input_var.location + 1;
}
}
} else if (shader->getSubExtension().compare("frag") == 0) {
stageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
} else {
@@ -144,71 +184,31 @@ KRPipeline::KRPipeline(KRContext& context, KrDeviceHandle deviceHandle, VkFormat
stageInfo.pName = "main";
}
VkAttachmentDescription colorAttachment{};
colorAttachment.format = swapChainImageFormat;
colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
VkAttachmentReference colorAttachmentRef{};
colorAttachmentRef.attachment = 0;
colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
VkSubpassDescription subpass{};
subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
subpass.colorAttachmentCount = 1;
subpass.pColorAttachments = &colorAttachmentRef;
VkSubpassDependency dependency{};
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
dependency.dstSubpass = 0;
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.srcAccessMask = 0;
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkRenderPassCreateInfo renderPassInfo{};
renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
renderPassInfo.attachmentCount = 1;
renderPassInfo.pAttachments = &colorAttachment;
renderPassInfo.subpassCount = 1;
renderPassInfo.pSubpasses = &subpass;
renderPassInfo.dependencyCount = 1;
renderPassInfo.pDependencies = &dependency;
if (vkCreateRenderPass(device.m_logicalDevice, &renderPassInfo, nullptr, &m_renderPass) != VK_SUCCESS) {
// failed! TODO - Error handling
}
// TODO - Make bindings dynamic...
VkVertexInputBindingDescription bindingDescription{};
bindingDescription.binding = 0;
bindingDescription.stride = sizeof(float) * 3 + sizeof(uint16_t) * 2;
bindingDescription.stride = KRMesh::VertexSizeForAttributes(vertexAttributes);
bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
const int kMaxVertexDescriptions = 16;
VkVertexInputAttributeDescription vertexAttributeDescriptions[kMaxVertexDescriptions]{};
// position
vertexAttributeDescriptions[0].binding = 0;
vertexAttributeDescriptions[0].location = 0;
vertexAttributeDescriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
vertexAttributeDescriptions[0].offset = 0;
uint32_t vertexAttributeCount = 0;
VkVertexInputAttributeDescription vertexAttributeDescriptions[KRMesh::KRENGINE_NUM_ATTRIBUTES]{};
// uv
vertexAttributeDescriptions[1].binding = 0;
vertexAttributeDescriptions[1].location = 1;
vertexAttributeDescriptions[1].format = VK_FORMAT_R32G32_SFLOAT;
vertexAttributeDescriptions[1].offset = sizeof(float) * 3;
for (int i = KRMesh::KRENGINE_ATTRIB_VERTEX; i < KRMesh::KRENGINE_NUM_ATTRIBUTES; i++) {
KRMesh::vertex_attrib_t mesh_attrib = static_cast<KRMesh::vertex_attrib_t>(i);
int location_attrib = attribute_mapping[i];
if (KRMesh::has_vertex_attribute(vertexAttributes, (KRMesh::vertex_attrib_t)i) && attribute_locations[location_attrib]) {
VkVertexInputAttributeDescription& desc = vertexAttributeDescriptions[vertexAttributeCount++];
desc.binding = 0;
desc.location = attribute_locations[location_attrib] - 1;
desc.format = KRMesh::AttributeVulkanFormat(mesh_attrib);
desc.offset = KRMesh::AttributeOffset(mesh_attrib, vertexAttributes);
}
}
VkPipelineVertexInputStateCreateInfo vertexInputInfo{};
vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertexInputInfo.vertexBindingDescriptionCount = 1;
vertexInputInfo.pVertexBindingDescriptions = &bindingDescription;
vertexInputInfo.vertexAttributeDescriptionCount = 2;
vertexInputInfo.vertexAttributeDescriptionCount = vertexAttributeCount;
vertexInputInfo.pVertexAttributeDescriptions = vertexAttributeDescriptions;
VkPipelineInputAssemblyStateCreateInfo inputAssembly{};
@@ -219,15 +219,15 @@ KRPipeline::KRPipeline(KRContext& context, KrDeviceHandle deviceHandle, VkFormat
VkViewport viewport{};
viewport.x = 0.0f;
viewport.y = 0.0f;
viewport.width = static_cast<float>(swapChainWidth);
viewport.height = static_cast<float>(swapChainHeight);
viewport.width = static_cast<float>(surface.getWidth());
viewport.height = static_cast<float>(surface.getHeight());
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkRect2D scissor{};
scissor.offset = { 0, 0 };
scissor.extent.width = swapChainWidth;
scissor.extent.height = swapChainHeight;
scissor.extent.width = surface.getWidth();
scissor.extent.height = surface.getHeight();
VkPipelineViewportStateCreateInfo viewportState{};
viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
@@ -286,7 +286,7 @@ KRPipeline::KRPipeline(KRContext& context, KrDeviceHandle deviceHandle, VkFormat
pipelineLayoutInfo.pushConstantRangeCount = 0;
pipelineLayoutInfo.pPushConstantRanges = nullptr;
if (vkCreatePipelineLayout(device.m_logicalDevice, &pipelineLayoutInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) {
if (vkCreatePipelineLayout(device->m_logicalDevice, &pipelineLayoutInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) {
// failed! TODO - Error handling
}
@@ -303,12 +303,12 @@ KRPipeline::KRPipeline(KRContext& context, KrDeviceHandle deviceHandle, VkFormat
pipelineInfo.pColorBlendState = &colorBlending;
pipelineInfo.pDynamicState = nullptr;
pipelineInfo.layout = m_pipelineLayout;
pipelineInfo.renderPass = m_renderPass;
pipelineInfo.renderPass = surface.getRenderPass();
pipelineInfo.subpass = 0;
pipelineInfo.basePipelineHandle = VK_NULL_HANDLE;
pipelineInfo.basePipelineIndex = -1;
if (vkCreateGraphicsPipelines(device.m_logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_graphicsPipeline) != VK_SUCCESS) {
if (vkCreateGraphicsPipelines(device->m_logicalDevice, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &m_graphicsPipeline) != VK_SUCCESS) {
// Failed! TODO - Error handling
}
}
@@ -428,9 +428,6 @@ KRPipeline::~KRPipeline() {
if (m_pipelineLayout) {
// TODO: vkDestroyPipelineLayout(device, m_pipelineLayout, nullptr);
}
if (m_renderPass) {
// TODO: vkDestroyRenderPass(device, m_renderPass, nullptr);
}
if(m_iProgram) {
GLDEBUG(glDeleteProgram(m_iProgram));
@@ -795,11 +792,6 @@ const char *KRPipeline::getKey() const {
return m_szKey;
}
VkRenderPass& KRPipeline::getRenderPass()
{
return m_renderPass;
}
VkPipeline& KRPipeline::getPipeline()
{
return m_graphicsPipeline;