Vertex attributes are now bound automatically to shaders using spirv reflection.
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user