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

@@ -1082,6 +1082,29 @@ size_t KRMesh::AttributeOffset(__int32_t vertex_attrib, __int32_t vertex_attrib_
return VertexSizeForAttributes(mask);
}
VkFormat KRMesh::AttributeVulkanFormat(__int32 vertex_attrib)
{
switch (vertex_attrib) {
case KRENGINE_ATTRIB_VERTEX:
case KRENGINE_ATTRIB_NORMAL:
case KRENGINE_ATTRIB_TANGENT:
case KRENGINE_ATTRIB_BONEWEIGHTS:
return VK_FORMAT_R32G32B32_SFLOAT;
case KRENGINE_ATTRIB_TEXUVA:
case KRENGINE_ATTRIB_TEXUVB:
return VK_FORMAT_R32G32_SFLOAT;
case KRENGINE_ATTRIB_BONEINDEXES:
return VK_FORMAT_R8G8B8A8_UINT;
case KRENGINE_ATTRIB_VERTEX_SHORT:
case KRENGINE_ATTRIB_NORMAL_SHORT:
case KRENGINE_ATTRIB_TANGENT_SHORT:
return VK_FORMAT_R16G16B16_SFLOAT;
case KRENGINE_ATTRIB_TEXUVA_SHORT:
case KRENGINE_ATTRIB_TEXUVB_SHORT:
return VK_FORMAT_R16G16_SFLOAT;
}
}
int KRMesh::getBoneCount()
{
pack_header *header = getHeader();

View File

@@ -203,6 +203,7 @@ public:
static size_t VertexSizeForAttributes(__int32_t vertex_attrib_flags);
static size_t AttributeOffset(__int32_t vertex_attrib, __int32_t vertex_attrib_flags);
static VkFormat AttributeVulkanFormat(__int32 vertex_attrib);
int getBoneCount();
char *getBoneName(int bone_index);

View File

@@ -878,3 +878,9 @@ VkBuffer& KRMeshManager::KRVBOData::getIndexBuffer()
assert(m_is_vbo_ready);
return m_allocations->index_buffer;
}
uint32_t KRMeshManager::KRVBOData::getVertexAttributes()
{
return m_vertex_attrib_flags;
}

View File

@@ -114,6 +114,7 @@ public:
VkBuffer& getVertexBuffer();
VkBuffer& getIndexBuffer();
uint32_t getVertexAttributes();
private:
KRMeshManager *m_manager;

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;

View File

@@ -41,10 +41,11 @@
#include "KRViewport.h"
class KRShader;
class KRSurface;
class KRPipeline : public KRContextObject {
public:
KRPipeline(KRContext& context, KrDeviceHandle deviceHandle, VkFormat swapChainImageFormat, uint32_t swapChainWidth, uint32_t swapChainHeight, const char* szKey, const std::vector<KRShader*>& shaders);
KRPipeline(KRContext& context, KRSurface& surface, const char* szKey, const std::vector<KRShader*>& shaders, uint32_t vertexAttributes);
KRPipeline(KRContext &context, char *szKey, std::string options, std::string vertShaderSource, const std::string fragShaderSource);
virtual ~KRPipeline();
const char *getKey() const;
@@ -145,12 +146,10 @@ public:
void setUniform(int location, const Vector4 &value);
void setUniform(int location, const Matrix4 &value);
VkRenderPass& getRenderPass();
VkPipeline& getPipeline();
private:
GLuint m_iProgram;
VkRenderPass m_renderPass;
VkPipelineLayout m_pipelineLayout;
VkPipeline m_graphicsPipeline;

View File

@@ -52,9 +52,9 @@ class KRPipelineManager : public KRContextObject {
public:
KRPipelineManager(KRContext &context);
virtual ~KRPipelineManager();
void createPipelines(KRSurface& surface);
KRPipeline* get(const char* szKey);
KRPipeline *getPipeline(KRSurface& surface, const std::string& shader_name, uint32_t vertexAttributes);
KRPipeline *getPipeline(const std::string &pipeline_name, KRCamera *pCamera, const std::vector<KRPointLight *> &point_lights, const std::vector<KRDirectionalLight *> &directional_lights, const std::vector<KRSpotLight *>&spot_lights, int bone_count, bool bDiffuseMap, bool bNormalMap, bool bSpecMap, bool bReflectionMap, bool bReflectionCubeMap, bool bLightMap, bool bDiffuseMapScale,bool bSpecMapScale, bool bNormalMapScale, bool bReflectionMapScale, bool bDiffuseMapOffset, bool bSpecMapOffset, bool bNormalMapOffset, bool bReflectionMapOffset, bool bAlphaTest, bool bAlphaBlend, KRNode::RenderPass renderPass, bool bRimColor = false);
bool selectPipeline(KRCamera &camera, KRPipeline *pPipeline, const KRViewport &viewport, const Matrix4 &matModel, const std::vector<KRPointLight *> &point_lights, const std::vector<KRDirectionalLight *> &directional_lights, const std::vector<KRSpotLight *>&spot_lights, int bone_count, const KRNode::RenderPass &renderPass, const Vector3 &rim_color, float rim_power, const Vector4 &fade_color);
@@ -66,7 +66,8 @@ public:
KRPipeline *m_active_pipeline;
private:
std::map<std::pair<std::string, std::vector<int> >, KRPipeline *> m_pipelines;
typedef std::map<std::pair<std::string, std::vector<int> >, KRPipeline*> PipelineMap;
PipelineMap m_pipelines;
};
#endif

View File

@@ -121,6 +121,7 @@ void KRShader::parseReflection()
return;
}
m_reflectionValid = true;
m_pData->unlock();
}