Got the triangle working! It only took 10 hours.

This commit is contained in:
Zed A. Shaw 2025-12-14 10:19:24 -05:00
parent 3d36517b4f
commit 10fc100e2b
11 changed files with 352 additions and 4 deletions

View file

@ -13,6 +13,8 @@ shaders:
glslangValidator -V gradient.comp -o gradient.comp.spv
glslangValidator -V sky.comp -o sky.comp.spv
glslangValidator -V gradient_color.comp -o gradient_color.comp.spv
glslangValidator -V colored_triangle.frag -o colored_triangle.frag.spv
glslangValidator -V colored_triangle.vert -o colored_triangle.vert.spv
%.cpp : %.rl
ragel -I $(ROOT_DIR) -G1 -o $@ $<

13
colored_triangle.frag Normal file
View file

@ -0,0 +1,13 @@
#version 450
//shader input
layout (location = 0) in vec3 inColor;
//output write
layout (location = 0) out vec4 outFragColor;
void main()
{
//return red
outFragColor = vec4(inColor,1.0f);
}

BIN
colored_triangle.frag.spv Normal file

Binary file not shown.

24
colored_triangle.vert Normal file
View file

@ -0,0 +1,24 @@
#version 450
layout (location = 0) out vec3 outColor;
void main()
{
//const array of positions for the triangle
const vec3 positions[3] = vec3[3](
vec3(1.f,1.f, 0.0f),
vec3(-1.f,1.f, 0.0f),
vec3(0.f,-1.f, 0.0f)
);
//const array of colors for the triangle
const vec3 colors[3] = vec3[3](
vec3(1.0f, 0.0f, 0.0f), //red
vec3(0.0f, 1.0f, 0.0f), //green
vec3(00.f, 0.0f, 1.0f) //blue
);
//output the position of each vertex
gl_Position = vec4(positions[gl_VertexIndex], 1.0f);
outColor = colors[gl_VertexIndex];
}

BIN
colored_triangle.vert.spv Normal file

Binary file not shown.

View file

@ -144,8 +144,12 @@ void VulkanEngine::draw()
draw_background(t.cmd);
vkutil::transition_image(t.cmd, _drawImage.image, VK_IMAGE_LAYOUT_GENERAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
draw_geometry(t.cmd);
// ZED: ?
vkutil::transition_image(t.cmd, _drawImage.image, VK_IMAGE_LAYOUT_GENERAL,
vkutil::transition_image(t.cmd, _drawImage.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL);
// ZED: ?
@ -159,15 +163,47 @@ void VulkanEngine::draw()
// ZED: ?
vkutil::transition_image(t.cmd, _swapchainImages[t.swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
_gui.draw_imgui(_swapchainExtent, t.cmd, _swapchainImageViews[t.swapchainImageIndex]);
// ZED: end drawing the things
_gui.draw_imgui(_swapchainExtent, t.cmd, _swapchainImageViews[t.swapchainImageIndex]);
// ZED: finalize image and commit command buffer
vkutil::transition_image(t.cmd, _swapchainImages[t.swapchainImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
vkutil::transition_image(t.cmd, _swapchainImages[t.swapchainImageIndex], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
commit_transaction(t);
}
void VulkanEngine::draw_geometry(VkCommandBuffer cmd)
{
VkRenderingAttachmentInfo colorAttachment = vkinit::attachment_info(_drawImage.imageView, nullptr, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
VkRenderingInfo renderInfo = vkinit::rendering_info(_drawExtent, &colorAttachment, nullptr);
vkCmdBeginRendering(cmd, &renderInfo);
vkCmdBindPipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, _trianglePipeline);
VkViewport viewport{
.x = 0,
.y = 0,
.width = (float)_drawExtent.width,
.height = (float)_drawExtent.height,
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
vkCmdSetViewport(cmd, 0, 1, &viewport);
VkRect2D scissor{
.offset = { .x = 0, .y = 0, },
.extent = _drawExtent
};
vkCmdSetScissor(cmd, 0, 1, &scissor);
vkCmdDraw(cmd, 3, 1, 0, 0);
vkCmdEndRendering(cmd);
}
void VulkanEngine::run()
{
//main loop
@ -428,6 +464,7 @@ void VulkanEngine::init_descriptors() {
void VulkanEngine::init_pipelines()
{
init_background_pipelines();
init_triangle_pipelines();
init_shaders();
}
@ -530,4 +567,49 @@ void VulkanEngine::immediate_submit(std::function<void(VkCommandBuffer cmd)>&& f
}
void VulkanEngine::init_triangle_pipelines()
{
VkShaderModule triangleFragShader;
if(!vkutil::load_shader_module("colored_triangle.frag.spv",_device, &triangleFragShader)) {
std::print("Error when building the triangle fragment shaders module");
} else {
std::print("Triangle fragment shader successfully loaded");
}
VkShaderModule triangleVertexShader;
if(!vkutil::load_shader_module("colored_triangle.vert.spv", _device, &triangleVertexShader)) {
std::println("Error when building the triangle, vertex shader module");
} else {
std::println("Triangle vertex shader successfully loaded");
}
VkPipelineLayoutCreateInfo pipeline_layout_info = vkinit::pipeline_layout_create_info();
VK_CHECK(vkCreatePipelineLayout(_device, &pipeline_layout_info, nullptr, &_trianglePipelineLayout));
PipelineBuilder pipelineBuilder;
pipelineBuilder._pipelineLayout = _trianglePipelineLayout;
pipelineBuilder.set_shaders(triangleVertexShader, triangleFragShader);
pipelineBuilder.set_input_topology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST);
pipelineBuilder.set_polygon_mode(VK_POLYGON_MODE_FILL);
pipelineBuilder.set_cull_mode(VK_CULL_MODE_NONE, VK_FRONT_FACE_CLOCKWISE);
pipelineBuilder.set_multisampling_none();
pipelineBuilder.disable_blending();
pipelineBuilder.disable_depthtest();
// connect the image format we will drw into, from draw image
pipelineBuilder.set_color_attachment_format(_drawImage.imageFormat);
pipelineBuilder.set_depth_format(VK_FORMAT_UNDEFINED);
_trianglePipeline = pipelineBuilder.build_pipeline(_device);
vkDestroyShaderModule(_device, triangleFragShader, nullptr);
vkDestroyShaderModule(_device, triangleVertexShader, nullptr);
_mainDeletionQueue.push_function([&]() {
vkDestroyPipelineLayout(_device, _trianglePipelineLayout, nullptr);
vkDestroyPipeline(_device, _trianglePipeline, nullptr);
});
}

View file

@ -66,6 +66,7 @@ public:
std::vector<VkImageView> _swapchainImageViews;
VkExtent2D _swapchainExtent;
// VMA stuff
VmaAllocator _allocator;
@ -93,6 +94,8 @@ public:
// imgui shader stuff
std::vector<ComputeEffect> backgroundEffects;
int currentBackgroundEffect{0};
VkPipelineLayout _trianglePipelineLayout;
VkPipeline _trianglePipeline;
// ZED's REFACTOR
VkGUI _gui;
@ -126,8 +129,10 @@ private:
void init_background_pipelines();
void init_shaders();
void load_shader(const char *file_name, const char *entry_point, ComputeEffect data);
void init_triangle_pipelines();
void create_swapchain(uint32_t width, uint32_t height);
void destroy_swapchain();
void draw_background(VkCommandBuffer cmd);
void draw_geometry(VkCommandBuffer cmd);
};

View file

@ -156,3 +156,28 @@ VkRenderingInfo vkinit::rendering_info(VkExtent2D renderExtent, VkRenderingAttac
.pStencilAttachment = nullptr,
};
}
VkPipelineShaderStageCreateInfo vkinit::pipeline_shader_stage_create_info(VkShaderStageFlagBits stage, VkShaderModule shader, const char* entry) {
return {
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
.stage = stage,
.module = shader,
.pName = entry,
};
}
VkPipelineLayoutCreateInfo vkinit::pipeline_layout_create_info()
{
return {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
.setLayoutCount = 0,
.pSetLayouts = nullptr,
.pushConstantRangeCount = 0,
.pPushConstantRanges = nullptr,
};
}

View file

@ -35,5 +35,9 @@ namespace vkinit {
VkImageView view, VkClearValue* clear ,VkImageLayout layout=VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
VkRenderingInfo rendering_info(VkExtent2D renderExtent, VkRenderingAttachmentInfo* colorAttachment, VkRenderingAttachmentInfo* depthAttachment);
VkPipelineShaderStageCreateInfo pipeline_shader_stage_create_info(VkShaderStageFlagBits stage, VkShaderModule shader, const char* entry="main");
VkPipelineLayoutCreateInfo pipeline_layout_create_info();
}

View file

@ -40,3 +40,165 @@ bool vkutil::load_shader_module(const char* filePath,
*outShaderModule = shaderModule;
return true;
}
void PipelineBuilder::clear() {
// clear all of the structs we need back to 0 with their correct stype
_inputAssembly = { .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO };
_rasterizer = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
_colorBlendAttachment = {};
_multisampling = { .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
_pipelineLayout = {};
_depthStencil = { .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO };
_renderInfo = { .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO };
_shaderStages.clear();
}
VkPipeline PipelineBuilder::build_pipeline(VkDevice device)
{
VkPipelineViewportStateCreateInfo viewportState{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
.viewportCount = 1,
.scissorCount = 1,
};
VkPipelineColorBlendStateCreateInfo colorBlending{
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
.logicOpEnable = VK_FALSE,
.logicOp = VK_LOGIC_OP_COPY,
.attachmentCount = 1,
.pAttachments = &_colorBlendAttachment,
};
VkPipelineVertexInputStateCreateInfo _vertexInputInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
};
VkDynamicState state[] = {
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR
};
VkPipelineDynamicStateCreateInfo dynamicInfo{
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
.dynamicStateCount = 2,
// ZED: we don't need to do this? state is also &state[0]
.pDynamicStates = &state[0],
};
// build the actual pipeline
VkGraphicsPipelineCreateInfo pipelineInfo = {
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
.pNext = &_renderInfo,
.stageCount = (uint32_t)_shaderStages.size(),
.pStages = _shaderStages.data(),
.pVertexInputState = &_vertexInputInfo,
.pInputAssemblyState = &_inputAssembly,
.pViewportState = &viewportState,
.pRasterizationState = &_rasterizer,
.pMultisampleState = &_multisampling,
.pDepthStencilState = &_depthStencil,
.pColorBlendState = &colorBlending,
.pDynamicState = &dynamicInfo,
.layout = _pipelineLayout,
};
// its easy to error out on create graphics pipeline, so we handle it a bit
// better than the common VK_CHECK case
VkPipeline newPipeline;
auto works = vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, nullptr, &newPipeline);
if(works != VK_SUCCESS) {
std::println("failed to create pipeline");
return VK_NULL_HANDLE;
} else {
return newPipeline;
}
}
void PipelineBuilder::set_shaders(VkShaderModule vertexShader, VkShaderModule fragmentShader)
{
_shaderStages.clear();
_shaderStages.push_back(
vkinit::pipeline_shader_stage_create_info(
VK_SHADER_STAGE_VERTEX_BIT,
vertexShader));
_shaderStages.push_back(
vkinit::pipeline_shader_stage_create_info(
VK_SHADER_STAGE_FRAGMENT_BIT,
fragmentShader));
}
void PipelineBuilder::set_input_topology(VkPrimitiveTopology topology)
{
_inputAssembly.topology = topology;
_inputAssembly.primitiveRestartEnable = VK_FALSE;
}
void PipelineBuilder::set_polygon_mode(VkPolygonMode mode)
{
_rasterizer.polygonMode = mode;
_rasterizer.lineWidth = 1.0f;
}
void PipelineBuilder::set_cull_mode(VkCullModeFlags cullMode, VkFrontFace frontFace)
{
_rasterizer.cullMode = cullMode;
_rasterizer.frontFace = frontFace;
}
void PipelineBuilder::set_multisampling_none()
{
_multisampling.sampleShadingEnable = VK_FALSE;
_multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
_multisampling.minSampleShading = 1.0f;
_multisampling.pSampleMask = nullptr;
_multisampling.alphaToCoverageEnable = VK_FALSE;
_multisampling.alphaToOneEnable = VK_FALSE;
}
void PipelineBuilder::disable_blending()
{
_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_FALSE;
}
void PipelineBuilder::set_color_attachment_format(VkFormat format)
{
_colorAttachmentFormat = format;
_renderInfo.colorAttachmentCount = 1;
_renderInfo.pColorAttachmentFormats = &_colorAttachmentFormat;
}
void PipelineBuilder::set_depth_format(VkFormat format)
{
_renderInfo.depthAttachmentFormat = format;
}
void PipelineBuilder::disable_depthtest()
{
_depthStencil.depthTestEnable = VK_FALSE;
_depthStencil.depthWriteEnable = VK_FALSE;
_depthStencil.depthCompareOp = VK_COMPARE_OP_NEVER;
_depthStencil.depthBoundsTestEnable = VK_FALSE;
_depthStencil.stencilTestEnable = VK_FALSE;
_depthStencil.front = {};
_depthStencil.back = {};
_depthStencil.minDepthBounds = 0.0f;
_depthStencil.maxDepthBounds = 1.0f;
}

View file

@ -2,6 +2,37 @@
#include "vk_types.h"
class PipelineBuilder {
public:
std::vector<VkPipelineShaderStageCreateInfo> _shaderStages;
VkPipelineInputAssemblyStateCreateInfo _inputAssembly;
VkPipelineRasterizationStateCreateInfo _rasterizer;
VkPipelineColorBlendAttachmentState _colorBlendAttachment;
VkPipelineMultisampleStateCreateInfo _multisampling;
VkPipelineLayout _pipelineLayout;
VkPipelineDepthStencilStateCreateInfo _depthStencil;
VkPipelineRenderingCreateInfo _renderInfo;
VkFormat _colorAttachmentFormat;
PipelineBuilder() {
clear();
}
void clear();
VkPipeline build_pipeline(VkDevice device);
void set_shaders(VkShaderModule vertexShader, VkShaderModule fragmentShader);
void set_input_topology(VkPrimitiveTopology topology);
void set_polygon_mode(VkPolygonMode mode);
void set_cull_mode(VkCullModeFlags cullMode, VkFrontFace frontFace);
void set_multisampling_none();
void disable_blending();
void set_color_attachment_format(VkFormat format);
void set_depth_format(VkFormat format);
void disable_depthtest();
};
namespace vkutil {
bool load_shader_module(const char* filePath,
VkDevice device,