diff options
| -rw-r--r-- | src/Makefile.am | 50 | ||||
| -rw-r--r-- | src/engine.cpp | 222 | ||||
| -rw-r--r-- | src/shaders/shader.slang | 30 |
3 files changed, 281 insertions, 21 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index fd8f7fd..f7b34f3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,29 +1,33 @@ +shadersdir = $(datarootdir)/shaders +SLANGC = slangc + bin_PROGRAMS = engine +shaders_PROGRAMS = shader.spv engine_SOURCES = \ - engine.cpp \ - renderer.hpp renderer.cpp \ - obj_parser.hpp obj_parser.cpp \ - fb/chfb.hpp fb/chfb.cpp fb/pixfb.hpp fb/pixfb.cpp \ - math/vector.hpp \ - math/mat4.hpp \ - math/quat.hpp \ - math/tform.hpp \ - o3d/mesh.hpp o3d/mesh.cpp \ - o3d/obj3d.hpp \ - o3d/vertex_data.hpp \ - o3d/vertex.hpp \ - o3d/deriv_vertex.hpp \ - o3d/tri.hpp \ - o3d/tri_deriv.hpp o3d/tri_deriv.cpp \ - o3d/camera.hpp \ - o3d/scene.hpp \ - ctrl/keyboard.hpp \ - ctrl/mouse.hpp + engine.cpp \ + renderer.hpp renderer.cpp \ + obj_parser.hpp obj_parser.cpp \ + fb/chfb.hpp fb/chfb.cpp fb/pixfb.hpp fb/pixfb.cpp \ + math/vector.hpp \ + math/mat4.hpp \ + math/quat.hpp \ + math/tform.hpp \ + o3d/mesh.hpp o3d/mesh.cpp \ + o3d/obj3d.hpp \ + o3d/vertex_data.hpp \ + o3d/vertex.hpp \ + o3d/deriv_vertex.hpp \ + o3d/tri.hpp \ + o3d/tri_deriv.hpp o3d/tri_deriv.cpp \ + o3d/camera.hpp \ + o3d/scene.hpp \ + ctrl/keyboard.hpp \ + ctrl/mouse.hpp engine_CPPFLAGS = -std=gnu++23 -Wall -Wextra engine_LDFLAGS = -std=gnu++23 -Wall -Wextra -engine_CPPFLAGS += -DDATADIR='"$(datadir)"' +engine_CPPFLAGS += -DDATADIR='"$(datadir)"' -DSHADERSDIR='"$(shadersdir)"' # Not sure why they are needed engine_LDADD =# -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi @@ -36,3 +40,9 @@ if HAVE_NCURSES engine_CPPFLAGS += $(NCURSES_CFLAGS) engine_LDADD += $(NCURSES_LIBS) endif + +shader_spv_SOURCES = shaders/shader.slang +shader_spv_SPVFLAGS = -target spirv -profile spirv_1_4 -emit-spirv-directly -fvk-use-entrypoint-name -entry vert_main -entry frag_main + +shader.spv$(EXEEXT): shaders/shader.slang + $(SLANGC) $(shader_spv_SPVFLAGS) -o $@ $< diff --git a/src/engine.cpp b/src/engine.cpp index 204b2e9..1c9f109 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -18,6 +18,8 @@ #include <tuple> #include <limits> #include <array> +#include <ios> +#include <fstream> #define GLFW_INCLUDE_VULKAN #include <GLFW/glfw3.h> @@ -739,7 +741,7 @@ static int main_graphical() { device_create_info.pQueueCreateInfos = &deviceQueueCreateInfo; device_create_info.enabledExtensionCount = static_cast<uint32_t>(device_exts.size()); device_create_info.ppEnabledExtensionNames = device_exts.data(); - // we get device features while selection the physical device + // we get device features while selecting the physical device device_create_info.pNext = &device_features; VkPhysicalDeviceVulkan13Features device_vk13_features{}; @@ -880,9 +882,12 @@ static int main_graphical() { for (uint32_t i = 0; i < swapchain_imgs.size(); i++) { VkImageViewCreateInfo img_view_create_info { .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, + .pNext = {}, + .flags = {}, .image = swapchain_imgs[i], .viewType = VK_IMAGE_VIEW_TYPE_2D, .format = surface_format.format, + .components = {}, .subresourceRange = { // VkImageSubresourceRange .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, .baseMipLevel = 0, @@ -897,12 +902,227 @@ static int main_graphical() { } } + // reading shader file + VkShaderModule shader_module; + { + // shader code has to be 32-bits aligned, which is the case with the default allocator + std::vector<char> shader_code; + { + const char* shader_file_name = SHADERSDIR "/shader.spv"; + std::ifstream shader_file(shader_file_name, std::ios::ate | std::ios::binary); + if (!shader_file.is_open()) { + std::cerr << "file `" << shader_file_name << "'not found" << std::endl; // TODO: improve + std::exit(EXIT_SUCCESS); + } + shader_code.resize(shader_file.tellg()); + shader_file.seekg(0, std::ios::beg); + shader_file.read(shader_code.data(), static_cast<std::streamsize>(shader_code.size())); + } + + VkShaderModuleCreateInfo shader_module_create_info { + .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .codeSize = shader_code.size(), + .pCode = reinterpret_cast<const uint32_t*>(shader_code.data()), + }; + if (VkResult res = vkCreateShaderModule(logical_device, &shader_module_create_info, nullptr, &shader_module); res != VK_SUCCESS) { + std::cerr << "failed to create shader module, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + } + + std::array pl_shader_stage_create_infos { + VkPipelineShaderStageCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .stage = VK_SHADER_STAGE_VERTEX_BIT, + .module = shader_module, + .pName = "vert_main", + .pSpecializationInfo = nullptr, + }, + VkPipelineShaderStageCreateInfo { + .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .stage = VK_SHADER_STAGE_FRAGMENT_BIT, + .module = shader_module, + .pName = "frag_main", + .pSpecializationInfo = nullptr, + }, + }; + + std::array<VkDynamicState, 2> dynamic_states { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + }; + VkPipelineDynamicStateCreateInfo pl_dyn_state_create_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .dynamicStateCount = static_cast<uint32_t>(dynamic_states.size()), + .pDynamicStates = dynamic_states.data(), + }; + + VkPipelineVertexInputStateCreateInfo pl_vert_in_state_create_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .vertexBindingDescriptionCount = 0, + .pVertexBindingDescriptions = nullptr, + .vertexAttributeDescriptionCount = 0, + .pVertexAttributeDescriptions = nullptr, + }; + + VkPipelineInputAssemblyStateCreateInfo pl_in_asm_state_create_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, + .primitiveRestartEnable = VK_FALSE, + }; + + VkViewport viewport { + .x = 0.f, + .y = 0.f, + .width = static_cast<float>(swapchain_extent.width), + .height = static_cast<float>(swapchain_extent.height), + .minDepth = 0.f, + .maxDepth = 1.f, + }; + VkRect2D scissor { + .offset = { 0, 0 }, + .extent = swapchain_extent, + }; + VkPipelineViewportStateCreateInfo pl_viewport_state_create_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .viewportCount = 1, + .pViewports = {}, + .scissorCount = 1, + .pScissors = {}, + }; + + VkPipelineRasterizationStateCreateInfo pl_raster_state_create_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .depthClampEnable = VK_FALSE, + .rasterizerDiscardEnable = VK_FALSE, + .polygonMode = VK_POLYGON_MODE_FILL, + .cullMode = VK_CULL_MODE_BACK_BIT, + .frontFace = VK_FRONT_FACE_CLOCKWISE, + .depthBiasEnable = VK_FALSE, + .depthBiasConstantFactor = {}, + .depthBiasClamp = {}, + .depthBiasSlopeFactor = {}, + .lineWidth = 1.f, + }; + + VkPipelineMultisampleStateCreateInfo pl_ms_state_create_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, + .sampleShadingEnable = VK_FALSE, + .minSampleShading = {}, + .pSampleMask = {}, + .alphaToCoverageEnable = VK_FALSE, + .alphaToOneEnable = VK_FALSE, + }; + + VkPipelineColorBlendAttachmentState pl_col_blend_attachment_state { + .blendEnable = VK_FALSE, + .srcColorBlendFactor = {}, + .dstColorBlendFactor = {}, + .colorBlendOp = {}, + .srcAlphaBlendFactor = {}, + .dstAlphaBlendFactor = {}, + .alphaBlendOp = {}, + .colorWriteMask = VK_COLOR_COMPONENT_R_BIT + | VK_COLOR_COMPONENT_G_BIT + | VK_COLOR_COMPONENT_B_BIT + | VK_COLOR_COMPONENT_A_BIT, + }; + + VkPipelineColorBlendStateCreateInfo pl_col_blend_state_create_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .logicOpEnable = VK_FALSE, + .logicOp = {}, + .attachmentCount = 1, + .pAttachments = &pl_col_blend_attachment_state, + .blendConstants = { 0.f, 0.f, 0.f, 0.f }, + }; + + VkPipelineLayoutCreateInfo pl_layout_create_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, + .pNext = nullptr, + .flags = {}, + .setLayoutCount = 0, + .pSetLayouts = {}, + .pushConstantRangeCount = 0, + .pPushConstantRanges = {}, + }; + + VkPipelineLayout pl_layout; + if (VkResult res = vkCreatePipelineLayout(logical_device, &pl_layout_create_info, nullptr, &pl_layout); res != VK_SUCCESS) { + std::cerr << "failed to create pipeline layout, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + + VkPipelineRenderingCreateInfo pl_render_create_info { + .sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO, + .pNext = nullptr, + .viewMask = {}, + .colorAttachmentCount = 1, + .pColorAttachmentFormats = &surface_format.format, + .depthAttachmentFormat = {}, + .stencilAttachmentFormat = {}, + }; + + VkGraphicsPipelineCreateInfo graphics_pl_create_info { + .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, + .pNext = &pl_render_create_info, + .flags = {}, + .stageCount = 2, + .pStages = pl_shader_stage_create_infos.data(), + .pVertexInputState = &pl_vert_in_state_create_info, + .pInputAssemblyState = &pl_in_asm_state_create_info, + .pTessellationState = {}, + .pViewportState = &pl_viewport_state_create_info, + .pRasterizationState = &pl_raster_state_create_info, + .pMultisampleState = &pl_ms_state_create_info, + .pDepthStencilState = {}, + .pColorBlendState = &pl_col_blend_state_create_info, + .pDynamicState = &pl_dyn_state_create_info, + .layout = pl_layout, + .renderPass = nullptr, + .subpass = {}, + .basePipelineHandle = {}, + .basePipelineIndex = {}, + }; + + VkPipeline graphics_pl; + if (VkResult res = vkCreateGraphicsPipelines(logical_device, nullptr, 1, &graphics_pl_create_info, nullptr, &graphics_pl); res != VK_SUCCESS) { + std::cerr << "failed to pipeline, error code: " << string_VkResult(res) << std::endl; + std::exit(EXIT_FAILURE); + } + + // destroy when pipeline creation is finished + vkDestroyShaderModule(logical_device, shader_module, nullptr); + // main loop while (!glfwWindowShouldClose(window)) { glfwPollEvents(); } // cleanup + vkDestroyPipeline(logical_device, graphics_pl, nullptr); + vkDestroyPipelineLayout(logical_device, pl_layout, nullptr); for (const auto img_view : swapchain_img_views) vkDestroyImageView(logical_device, img_view, nullptr); vkDestroySwapchainKHR(logical_device, swapchain, nullptr); diff --git a/src/shaders/shader.slang b/src/shaders/shader.slang new file mode 100644 index 0000000..b5f7a54 --- /dev/null +++ b/src/shaders/shader.slang @@ -0,0 +1,30 @@ +static float2 positions[3] = float2[] ( + float2( 0.0, -0.5), + float2( 0.5, 0.5), + float2(-0.5, 0.5), +); + +static float3 colors[3] = float3[] ( + float3(1.0, 0.0, 0.0), + float3(0.0, 1.0, 0.0), + float3(0.0, 0.0, 1.0), +); + +struct VertexOutput { + float3 color; + float4 sv_position : SV_Position; +}; + +[shader("vertex")] +VertexOutput vert_main(uint vid : SV_VertexID) { + VertexOutput output; + output.color = colors[vid]; + output.sv_position = float4(positions[vid], 0.0, 1.0); + return output; +} + +[shader("fragment")] +float4 frag_main(VertexOutput vert) : SV_Target { + float3 color = vert.color; + return float4(color, 1.0); +} |
