cOMS/gpuapi/vulkan/ShaderUtils.h

448 lines
16 KiB
C

/**
* Jingga
*
* @copyright Jingga
* @license OMS License 2.0
* @version 1.0.0
* @link https://jingga.app
*/
#ifndef TOS_GPUAPI_VULKAN_SHADER_UTILS_H
#define TOS_GPUAPI_VULKAN_SHADER_UTILS_H
#include <vulkan/vulkan.h>
#include "../../stdlib/Types.h"
#include "../../memory/RingMemory.h"
#include "../GpuAttributeType.h"
#include "../../object/Vertex.h"
#include "../../log/Log.h"
inline
uint32_t shader_get_uniform_location(
VkWriteDescriptorSet* descriptor,
VkDescriptorSet descriptorSet, uint32_t binding, VkDescriptorType descriptorType
) {
descriptor->sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptor->dstSet = descriptorSet;
descriptor->dstBinding = binding;
descriptor->dstArrayElement = 0;
descriptor->descriptorType = descriptorType;
descriptor->descriptorCount = 1;
}
inline
void shader_set_value(VkDevice device, VkDescriptorSet descriptorSet, uint32_t binding, VkDescriptorType descriptorType, int32_t value)
{
VkDescriptorBufferInfo bufferInfo = {};
bufferInfo.buffer = {}; // You should have a buffer holding the value
bufferInfo.offset = 0;
bufferInfo.range = sizeof(value);
VkWriteDescriptorSet descriptorWrite = {};
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
descriptorWrite.dstSet = descriptorSet;
descriptorWrite.dstBinding = binding;
descriptorWrite.dstArrayElement = 0;
descriptorWrite.descriptorType = descriptorType;
descriptorWrite.descriptorCount = 1;
descriptorWrite.pBufferInfo = &bufferInfo;
vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, NULL);
}
inline
VkShaderModule shader_make(VkDevice device, const char* source, int32 source_size)
{
LOG_1("Create shader");
// Create shader module create info
VkShaderModuleCreateInfo create_info = {};
create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
create_info.codeSize = source_size;
create_info.pCode = (uint32 *) source;
// Create shader module
VkShaderModule shader_module;
VkResult result = vkCreateShaderModule(device, &create_info, NULL, &shader_module);
if (result != VK_SUCCESS) {
LOG_FORMAT_1("Vulkan vkCreateShaderModule: %d", {{LOG_DATA_INT32, (int32 *) &result}});
ASSERT_SIMPLE(false);
return VK_NULL_HANDLE;
}
LOG_1("Created shader");
return shader_module;
}
inline
void vulkan_vertex_binding_description(uint32 size, VkVertexInputBindingDescription* binding) {
binding->binding = 0;
binding->stride = size;
binding->inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
}
void gpuapi_attribute_info_create(GpuAttributeType type, VkVertexInputAttributeDescription* attr)
{
switch (type) {
case GPU_ATTRIBUTE_TYPE_VERTEX_3D: {
attr[0] = {
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex3D, position)
};
attr[1] = {
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex3D, normal)
};
attr[2] = {
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex3D, tex_coord)
};
attr[3] = {
.location = 3,
.binding = 0,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(Vertex3D, color)
};
} return;
case GPU_ATTRIBUTE_TYPE_VERTEX_3D_NORMAL: {
attr[0] = {
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex3DNormal, position)
};
attr[1] = {
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex3DNormal, normal)
};
} return;
case GPU_ATTRIBUTE_TYPE_VERTEX_3D_COLOR: {
attr[0] = {
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex3DColor, position)
};
attr[1] = {
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32B32_SFLOAT,
.offset = offsetof(Vertex3DColor, color)
};
} return;
case GPU_ATTRIBUTE_TYPE_VERTEX_3D_TEXTURE_COLOR: {
attr[0] = {
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex3DTextureColor, position)
};
attr[1] = {
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex3DTextureColor, texture_color)
};
} return;
case GPU_ATTRIBUTE_TYPE_VERTEX_3D_SAMPLER_TEXTURE_COLOR: {
attr[0] = {
.location = 0,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex3DSamplerTextureColor, position)
};
attr[1] = {
.location = 1,
.binding = 0,
.format = VK_FORMAT_R32_UINT,
.offset = offsetof(Vertex3DSamplerTextureColor, sampler)
};
attr[2] = {
.location = 2,
.binding = 0,
.format = VK_FORMAT_R32G32_SFLOAT,
.offset = offsetof(Vertex3DSamplerTextureColor, texture_color)
};
} return;
default:
UNREACHABLE();
};
}
inline
void pipeline_use(VkCommandBuffer command_buffer, VkPipeline pipeline)
{
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
}
VkPipeline pipeline_make(
VkDevice device, VkRenderPass render_pass, VkPipelineLayout* __restrict pipeline_layout, VkPipeline* __restrict pipeline,
VkDescriptorSetLayout* descriptor_set_layouts,
VkShaderModule vertex_shader, VkShaderModule fragment_shader,
VkShaderModule
) {
PROFILE_VERBOSE(PROFILE_PIPELINE_MAKE, "");
LOG_1("Create pipeline");
VkPipelineShaderStageCreateInfo vertex_shader_stage_info = {};
vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
vertex_shader_stage_info.module = vertex_shader;
vertex_shader_stage_info.pName = "main";
VkPipelineShaderStageCreateInfo fragment_shader_stage_info = {};
fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
fragment_shader_stage_info.module = fragment_shader;
fragment_shader_stage_info.pName = "main";
VkPipelineShaderStageCreateInfo shader_stages[] = {vertex_shader_stage_info, fragment_shader_stage_info};
VkVertexInputBindingDescription binding_description;
vulkan_vertex_binding_description(sizeof(Vertex3DTextureColor), &binding_description);
VkVertexInputAttributeDescription input_attribute_description[2];
gpuapi_attribute_info_create(GPU_ATTRIBUTE_TYPE_VERTEX_3D_TEXTURE_COLOR, input_attribute_description);
VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
vertex_input_info.vertexBindingDescriptionCount = 1;
vertex_input_info.pVertexBindingDescriptions = &binding_description;
vertex_input_info.vertexAttributeDescriptionCount = ARRAY_COUNT(input_attribute_description);
vertex_input_info.pVertexAttributeDescriptions = input_attribute_description;
VkPipelineInputAssemblyStateCreateInfo input_assembly = {};
input_assembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
input_assembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
input_assembly.primitiveRestartEnable = VK_FALSE;
VkPipelineViewportStateCreateInfo viewport_state = {};
viewport_state.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
viewport_state.viewportCount = 1;
viewport_state.scissorCount = 1;
VkPipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
rasterizer.depthClampEnable = VK_FALSE;
rasterizer.rasterizerDiscardEnable = VK_FALSE;
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
rasterizer.lineWidth = 1.0f;
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE;
rasterizer.depthBiasEnable = VK_FALSE;
VkPipelineMultisampleStateCreateInfo multisampling = {};
multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
multisampling.sampleShadingEnable = VK_FALSE;
multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
color_blend_attachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
color_blend_attachment.blendEnable = VK_FALSE;
VkPipelineColorBlendStateCreateInfo color_blending = {};
color_blending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
color_blending.logicOpEnable = VK_FALSE;
color_blending.logicOp = VK_LOGIC_OP_COPY;
color_blending.attachmentCount = 1;
color_blending.pAttachments = &color_blend_attachment;
color_blending.blendConstants[0] = 0.0f;
color_blending.blendConstants[1] = 0.0f;
color_blending.blendConstants[2] = 0.0f;
color_blending.blendConstants[3] = 0.0f;
const VkDynamicState dynamic_states[] = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR
};
VkPipelineDynamicStateCreateInfo dynamic_state = {};
dynamic_state.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
dynamic_state.dynamicStateCount = ARRAY_COUNT(dynamic_states);
dynamic_state.pDynamicStates = dynamic_states;
VkPipelineLayoutCreateInfo pipeline_info_layout = {};
pipeline_info_layout.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipeline_info_layout.setLayoutCount = 1;
pipeline_info_layout.pSetLayouts = descriptor_set_layouts;
pipeline_info_layout.pushConstantRangeCount = 0;
VkResult result;
if ((result = vkCreatePipelineLayout(device, &pipeline_info_layout, NULL, pipeline_layout)) != VK_SUCCESS) {
LOG_FORMAT_1("Vulkan vkCreatePipelineLayout: %d", {{LOG_DATA_INT32, (int32 *) &result}});
ASSERT_SIMPLE(false);
return NULL;
}
VkGraphicsPipelineCreateInfo pipeline_info = {};
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
pipeline_info.stageCount = 2;
pipeline_info.pStages = shader_stages;
pipeline_info.pVertexInputState = &vertex_input_info;
pipeline_info.pInputAssemblyState = &input_assembly;
pipeline_info.pViewportState = &viewport_state;
pipeline_info.pRasterizationState = &rasterizer;
pipeline_info.pMultisampleState = &multisampling;
pipeline_info.pColorBlendState = &color_blending;
pipeline_info.pDynamicState = &dynamic_state;
pipeline_info.layout = *pipeline_layout;
pipeline_info.renderPass = render_pass;
pipeline_info.subpass = 0;
pipeline_info.basePipelineHandle = VK_NULL_HANDLE;
if ((result = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipeline_info, NULL, pipeline)) != VK_SUCCESS) {
LOG_FORMAT_1("Vulkan vkCreateGraphicsPipelines: %d", {{LOG_DATA_INT32, (int32 *) &result}});
ASSERT_SIMPLE(false);
return NULL;
}
vkDestroyShaderModule(device, fragment_shader, NULL);
vkDestroyShaderModule(device, vertex_shader, NULL);
LOG_1("Created pipeline");
// @question Do we want to return the value or the pointer?
// I think the value is already a pointer?
return *pipeline;
}
inline
void pipeline_cleanup(VkDevice device, VkPipeline pipeline, VkPipelineLayout pipeline_layout) {
vkDestroyPipeline(device, pipeline, NULL);
vkDestroyPipelineLayout(device, pipeline_layout, NULL);
}
inline
void gpuapi_descriptor_set_layout_create(
VkDevice device,
VkDescriptorSetLayout* descriptor_set_layout, VkDescriptorSetLayoutBinding* bindings, int32 binding_length
) {
VkDescriptorSetLayoutCreateInfo layout_info = {};
layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
layout_info.bindingCount = binding_length;
layout_info.pBindings = bindings;
VkResult result;
if ((result = vkCreateDescriptorSetLayout(device, &layout_info, NULL, descriptor_set_layout)) != VK_SUCCESS) {
LOG_FORMAT_1("Vulkan vkCreateDescriptorSetLayout: %d", {{LOG_DATA_INT32, (int32 *) &result}});
ASSERT_SIMPLE(false);
}
}
inline
void vulkan_descriptor_pool_create(
VkDevice device, VkDescriptorPool* descriptor_pool,
uint32 frames_in_flight
)
{
// @question Why is the pool size 2?
// @todo Isn't this shader specific?
VkDescriptorPoolSize poolSizes[2] = {
{
.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = frames_in_flight,
},
{
.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.descriptorCount = frames_in_flight,
}
};
VkDescriptorPoolCreateInfo poolInfo{};
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
poolInfo.poolSizeCount = ARRAY_COUNT(poolSizes);
poolInfo.pPoolSizes = poolSizes;
poolInfo.maxSets = frames_in_flight;
VkResult result;
if ((result = vkCreateDescriptorPool(device, &poolInfo, NULL, descriptor_pool)) != VK_SUCCESS) {
LOG_FORMAT_1("Vulkan vkCreateDescriptorPool: %d", {{LOG_DATA_INT32, (int32 *) &result}});
ASSERT_SIMPLE(false);
}
}
void vulkan_descriptor_sets_create(
VkDevice device, VkDescriptorPool descriptor_pool,
VkDescriptorSetLayout descriptor_set_layout, VkDescriptorSet* descriptor_sets,
VkImageView texture_image_view, VkSampler& texture_sampler,
VkBuffer* __restrict uniform_buffers,
size_t uniform_buffer_object_size,
uint32 frames_in_flight, RingMemory* ring
)
{
VkDescriptorSetLayout* layouts = (VkDescriptorSetLayout *) ring_get_memory(ring, sizeof(VkDescriptorSetLayout), 64);
for (uint32 i = 0; i < frames_in_flight; ++i) {
layouts[i] = descriptor_set_layout;
}
VkDescriptorSetAllocateInfo alloc_info = {};
alloc_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
alloc_info.descriptorPool = descriptor_pool;
alloc_info.descriptorSetCount = frames_in_flight;
alloc_info.pSetLayouts = layouts;
VkResult result;
if ((result = vkAllocateDescriptorSets(device, &alloc_info, descriptor_sets)) != VK_SUCCESS) {
LOG_FORMAT_1("Vulkan vkAllocateDescriptorSets: %d", {{LOG_DATA_INT32, (int32 *) &result}});
ASSERT_SIMPLE(false);
return;
}
// @todo this is shader specific, it shouldn't be here
for (uint32 i = 0; i < frames_in_flight; ++i) {
VkDescriptorBufferInfo buffer_info = {};
buffer_info.buffer = uniform_buffers[i];
buffer_info.offset = 0;
buffer_info.range = uniform_buffer_object_size;
VkDescriptorImageInfo image_info = {};
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
image_info.imageView = texture_image_view;
image_info.sampler = texture_sampler;
VkWriteDescriptorSet descriptor_writes[2] = {
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor_sets[i],
.dstBinding = 0,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.pBufferInfo = &buffer_info,
},
{
.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor_sets[i],
.dstBinding = 1,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
.pImageInfo = &image_info,
}
};
vkUpdateDescriptorSets(device, ARRAY_COUNT(descriptor_writes), descriptor_writes, 0, NULL);
}
}
#endif