diff --git a/.envrc b/.envrc index c4b17d7..78f3220 100644 --- a/.envrc +++ b/.envrc @@ -1 +1,2 @@ +PATH_add ./src/shaders use_flake diff --git a/flake.nix b/flake.nix index 913b99a..33adc34 100644 --- a/flake.nix +++ b/flake.nix @@ -42,6 +42,7 @@ fmt glfw glm + shaderc vulkan-extension-layer vulkan-memory-allocator vulkan-utility-libraries diff --git a/src/main.cpp b/src/main.cpp index b83d866..3d12239 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -61,6 +62,10 @@ class VulkanApp { vk::Extent2D mSwapChainExtent; std::vector mSwapChainImageViews; + vk::UniqueRenderPass mRenderPass; + vk::UniquePipelineLayout mPipelineLayout; + vk::UniquePipeline mGraphicsPipeline; + struct QueueFamilyIndices { std::optional graphics_family; std::optional present_family; @@ -74,6 +79,23 @@ class VulkanApp { std::vector present_modes; }; + static fn readFile(const std::string& filename) -> std::vector { + std::ifstream file(filename, std::ios::ate | std::ios::binary); + + if (!file.is_open()) + throw std::runtime_error("Failed to open file! " + filename); + + usize fileSize = static_cast(file.tellg()); + std::vector buffer(fileSize); + + file.seekg(0); + file.read(buffer.data(), static_cast(fileSize)); + + file.close(); + + return buffer; + } + fn initWindow() -> void { mGLFWInstance = vkfw::initUnique(); @@ -93,6 +115,8 @@ class VulkanApp { createLogicalDevice(); createSwapChain(); createImageViews(); + createRenderPass(); + createGraphicsPipeline(); } fn mainLoop() -> void { @@ -254,7 +278,7 @@ class VulkanApp { .preTransform = swapChainSupport.capabilities.currentTransform, .compositeAlpha = vk::CompositeAlphaFlagBitsKHR::eOpaque, .presentMode = presentMode, - .clipped = VK_TRUE, + .clipped = vk::True, .oldSwapchain = nullptr, }; @@ -274,20 +298,159 @@ class VulkanApp { .viewType = vk::ImageViewType::e2D, .format = mSwapChainImageFormat, .components = { .r = vk::ComponentSwizzle::eIdentity, - .g = vk::ComponentSwizzle::eIdentity, - .b = vk::ComponentSwizzle::eIdentity, - .a = vk::ComponentSwizzle::eIdentity }, + .g = vk::ComponentSwizzle::eIdentity, + .b = vk::ComponentSwizzle::eIdentity, + .a = vk::ComponentSwizzle::eIdentity }, .subresourceRange = { .aspectMask = vk::ImageAspectFlagBits::eColor, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1 }, + .baseMipLevel = 0, + .levelCount = 1, + .baseArrayLayer = 0, + .layerCount = 1 }, }; mSwapChainImageViews[i] = mDevice->createImageViewUnique(createInfo); } } + fn createRenderPass() -> void { + vk::AttachmentDescription colorAttachment { + .format = mSwapChainImageFormat, + .samples = vk::SampleCountFlagBits::e1, + .loadOp = vk::AttachmentLoadOp::eClear, + .storeOp = vk::AttachmentStoreOp::eStore, + .stencilLoadOp = vk::AttachmentLoadOp::eDontCare, + .stencilStoreOp = vk::AttachmentStoreOp::eDontCare, + .initialLayout = vk::ImageLayout::eUndefined, + .finalLayout = vk::ImageLayout::ePresentSrcKHR, + }; + + vk::AttachmentReference colorAttachmentRef { + .attachment = 0, + .layout = vk::ImageLayout::eColorAttachmentOptimal, + }; + + vk::SubpassDescription subpass { + .pipelineBindPoint = vk::PipelineBindPoint::eGraphics, + .colorAttachmentCount = 1, + .pColorAttachments = &colorAttachmentRef, + }; + + vk::RenderPassCreateInfo renderPassInfo { + .attachmentCount = 1, + .pAttachments = &colorAttachment, + .subpassCount = 1, + .pSubpasses = &subpass, + }; + + mRenderPass = mDevice->createRenderPassUnique(renderPassInfo); + } + + fn createGraphicsPipeline() -> void { + std::vector vertShaderCode = readFile("src/shaders/vert.spv"); + std::vector fragShaderCode = readFile("src/shaders/frag.spv"); + + vk::UniqueShaderModule vertShaderModule = createShaderModule(vertShaderCode); + vk::UniqueShaderModule fragShaderModule = createShaderModule(fragShaderCode); + + vk::PipelineShaderStageCreateInfo vertShaderStageInfo { + .stage = vk::ShaderStageFlagBits::eVertex, + .module = vertShaderModule.get(), + .pName = "main", + }; + + vk::PipelineShaderStageCreateInfo fragShaderStageInfo { + .stage = vk::ShaderStageFlagBits::eFragment, + .module = fragShaderModule.get(), + .pName = "main", + }; + + std::array shaderStages = { vertShaderStageInfo, + fragShaderStageInfo }; + + vk::PipelineVertexInputStateCreateInfo vertexInputInfo { + .vertexBindingDescriptionCount = 0, + .pVertexBindingDescriptions = nullptr, + .vertexAttributeDescriptionCount = 0, + .pVertexAttributeDescriptions = nullptr, + }; + + vk::PipelineInputAssemblyStateCreateInfo inputAssembly { + .topology = vk::PrimitiveTopology::eTriangleList, + .primitiveRestartEnable = vk::False, + }; + + vk::PipelineViewportStateCreateInfo viewportState { + .viewportCount = 1, + .scissorCount = 1, + }; + + vk::PipelineRasterizationStateCreateInfo rasterizer { + .depthClampEnable = vk::False, + .rasterizerDiscardEnable = vk::False, + .polygonMode = vk::PolygonMode::eFill, + .cullMode = vk::CullModeFlagBits::eBack, + .frontFace = vk::FrontFace::eClockwise, + .depthBiasEnable = vk::False, + .lineWidth = 1.0F, + }; + + vk::PipelineMultisampleStateCreateInfo multisampling { + .rasterizationSamples = vk::SampleCountFlagBits::e1, + .sampleShadingEnable = vk::False, + }; + + vk::PipelineColorBlendAttachmentState colorBlendAttachment { + .blendEnable = vk::False, + .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | + vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, + }; + + vk::PipelineColorBlendStateCreateInfo colorBlending { + .logicOpEnable = vk::False, + .logicOp = vk::LogicOp::eCopy, + .attachmentCount = 1, + .pAttachments = &colorBlendAttachment, + .blendConstants = std::array { 0.0F, 0.0F, 0.0F, 0.0F }, + }; + std::vector dynamicStates = { vk::DynamicState::eViewport, vk::DynamicState::eScissor }; + + vk::PipelineDynamicStateCreateInfo dynamicState { + .dynamicStateCount = static_cast(dynamicStates.size()), + .pDynamicStates = dynamicStates.data(), + }; + + vk::PipelineLayoutCreateInfo pipelineLayoutInfo { + .setLayoutCount = 0, + .pushConstantRangeCount = 0, + }; + + mPipelineLayout = mDevice->createPipelineLayoutUnique(pipelineLayoutInfo); + + vk::GraphicsPipelineCreateInfo pipelineInfo { + .stageCount = static_cast(shaderStages.size()), + .pStages = shaderStages.data(), + .pVertexInputState = &vertexInputInfo, + .pInputAssemblyState = &inputAssembly, + .pViewportState = &viewportState, + .pRasterizationState = &rasterizer, + .pMultisampleState = &multisampling, + .pColorBlendState = &colorBlending, + .pDynamicState = &dynamicState, + .layout = mPipelineLayout.get(), + .renderPass = mRenderPass.get(), + .subpass = 0, + }; + + mGraphicsPipeline = mDevice->createGraphicsPipelineUnique(nullptr, pipelineInfo).value; + } + + fn createShaderModule(const std::vector& code) -> vk::UniqueShaderModule { + vk::ShaderModuleCreateInfo createInfo { .codeSize = code.size(), + .pCode = std::bit_cast(code.data()) }; + + return mDevice->createShaderModuleUnique(createInfo); + } + static fn chooseSwapSurfaceFormat(const std::vector& availableFormats ) -> vk::SurfaceFormatKHR { for (const auto& availableFormat : availableFormats) diff --git a/src/shaders/frag.spv b/src/shaders/frag.spv new file mode 100644 index 0000000..da37f7e Binary files /dev/null and b/src/shaders/frag.spv differ diff --git a/src/shaders/shader.frag b/src/shaders/shader.frag new file mode 100644 index 0000000..7c5b0e7 --- /dev/null +++ b/src/shaders/shader.frag @@ -0,0 +1,9 @@ +#version 450 + +layout(location = 0) in vec3 fragColor; + +layout(location = 0) out vec4 outColor; + +void main() { + outColor = vec4(fragColor, 1.0); +} diff --git a/src/shaders/shader.vert b/src/shaders/shader.vert new file mode 100644 index 0000000..f5b2f8d --- /dev/null +++ b/src/shaders/shader.vert @@ -0,0 +1,20 @@ +#version 450 + +layout(location = 0) out vec3 fragColor; + +vec2 positions[3] = vec2[]( + vec2(0.0, -0.5), + vec2(0.5, 0.5), + vec2(-0.5, 0.5) +); + +vec3 colors[3] = vec3[]( + vec3(1.0, 0.0, 0.0), + vec3(0.0, 1.0, 0.0), + vec3(0.0, 0.0, 1.0) +); + +void main() { + gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); + fragColor = colors[gl_VertexIndex]; +} diff --git a/src/shaders/shaderc b/src/shaders/shaderc new file mode 100755 index 0000000..9f7e6e5 --- /dev/null +++ b/src/shaders/shaderc @@ -0,0 +1,7 @@ +#!/usr/bin/env sh + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" || exit + +glslc -c ./shader.vert -o ./vert.spv +glslc -c ./shader.frag -o ./frag.spv \ No newline at end of file diff --git a/src/shaders/vert.spv b/src/shaders/vert.spv new file mode 100644 index 0000000..a41dd2c Binary files /dev/null and b/src/shaders/vert.spv differ