From a8cbb97fd0146fc7d732b12f25c4d69fb340d612 Mon Sep 17 00:00:00 2001 From: Lillian Salehi Date: Mon, 7 Oct 2024 17:02:47 -0500 Subject: [PATCH] Fixed Function pipeline settings, prepping for Render passes then rendering to the screen --- Makefile | 12 ++- src/devicelibrary.h | 2 +- src/graphics/graphicspipeline.cpp | 145 ++++++++++++++++++++++++++++++ src/graphics/graphicspipeline.h | 10 +++ src/main.cpp | 5 +- src/shaders/frag.spv | Bin 0 -> 572 bytes src/shaders/shader.frag | 9 ++ src/shaders/shader.vert | 20 +++++ src/shaders/vert.spv | Bin 0 -> 1504 bytes 9 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 src/graphics/graphicspipeline.cpp create mode 100644 src/graphics/graphicspipeline.h create mode 100644 src/shaders/frag.spv create mode 100644 src/shaders/shader.frag create mode 100644 src/shaders/shader.vert create mode 100644 src/shaders/vert.spv diff --git a/Makefile b/Makefile index c1fd1df..d4d17b8 100644 --- a/Makefile +++ b/Makefile @@ -2,8 +2,10 @@ CPPFLAGS=-g LDFLAGS=-lglfw -lvulkan -ldl -lpthread -lX11 -lXxf86vm -lXrandr -lXi DEBUGFLAGS=-DDEBUG -fsanitize=address GDBFLAGS= -SRC=$(shell find . -name *.cpp) -OBJ=$(SRC:%.cpp=%.o) +SRC = $(shell find . -name *.cpp) +OBJ = $(SRC:%.cpp=%.o) +VERTEX = $(src/shaders/%.vert=%.spv) +FRAGMENT = $(src/shaders/%.frag=%.spv) BIN=build/agnosiaengine @@ -26,7 +28,7 @@ debug: $(BIN) .PHONY: dep dep: - sudo pacman -S gcc glfw glm shaderc libxi libxxf86vm gdb + sudo pacman -S gcc glfw glm shaderc libxi libxxf86vm gdb glslc .PHONY: info info: @echo "make: Build executable" @@ -35,12 +37,14 @@ info: @echo "make clean: Clean all files" @echo "make run: Run the executable after building" -$(BIN): $(OBJ) +$(BIN): $(OBJ) $(VERTEX) $(FRAGMENT) mkdir -p build g++ $(CPPFLAGS) -o $(BIN) $(OBJ) $(LDFLAGS) %.o: %.cpp g++ -c -g $< -o $@ $(LDFLAGS) +%.spv: %.vert %.frag + glslc $< -o $@ .PHONY: clean clean: diff --git a/src/devicelibrary.h b/src/devicelibrary.h index 13029af..a4fcbd4 100644 --- a/src/devicelibrary.h +++ b/src/devicelibrary.h @@ -1,7 +1,7 @@ #pragma once #include "global.h" namespace DeviceControl { - class devicelibrary { +class devicelibrary { public: void pickPhysicalDevice(VkInstance& instance); diff --git a/src/graphics/graphicspipeline.cpp b/src/graphics/graphicspipeline.cpp new file mode 100644 index 0000000..367fb69 --- /dev/null +++ b/src/graphics/graphicspipeline.cpp @@ -0,0 +1,145 @@ +#include "graphicspipeline.h" +#include +namespace Graphics { + std::vector dynamicStates = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR + }; + VkPipelineLayout pipelineLayout; + + static std::vector readFile(const std::string& filename) { + std::ifstream file(filename, std::ios::ate | std::ios::binary); + if (!file.is_open()) { + throw std::runtime_error("failed to open file!"); + } + + size_t fileSize = (size_t) file.tellg(); + std::vector buffer(fileSize); + + file.seekg(0); + file.read(buffer.data(), fileSize); + + file.close(); + + return buffer; + } + VkShaderModule createShaderModule(const std::vector& code, VkDevice& device) { + VkShaderModuleCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = code.size(); + createInfo.pCode = reinterpret_cast(code.data()); + + VkShaderModule shaderModule; + if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) { + throw std::runtime_error("failed to create shader module!"); + } + return shaderModule; + } + + void graphicspipeline::destroyGraphicsPipeline(VkDevice& device) { + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + if(Global::enableValidationLayers) std::cout << "Destroyed Layout Pipeline safely\n" << std::endl; + } + + void graphicspipeline::createGraphicsPipeline(VkDevice& device) { + // Note to self, for some reason the working directory is not where a read file is called from, but the project folder! + auto vertShaderCode = readFile("src/shaders/vert.spv"); + auto fragShaderCode = readFile("src/shaders/frag.spv"); + VkShaderModule vertShaderModule = createShaderModule(vertShaderCode, device); + VkShaderModule fragShaderModule = createShaderModule(fragShaderCode, device); + + // ------------------ STAGE 1 - INPUT ASSEMBLER ---------------- // + // This can get a little complicated, normally, vertices are loaded in sequential order, with an element buffer however, you can specify the indices yourself! + // Using an element buffer means you can reuse vertices, which can lead to optimizations. If you set PrimRestart to TRUE, you can utilize the _STRIP modes with special indices + VkPipelineInputAssemblyStateCreateInfo inputAssembly{}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + inputAssembly.primitiveRestartEnable = VK_FALSE; + + // ------------------ STAGE 2 - VERTEX SHADER ------------------ // + // this will be revisited, right now we are hardcoding shader data, so we tell it to not load anything, but that will change. + VkPipelineShaderStageCreateInfo vertShaderStageInfo{}; + vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertShaderStageInfo.module = vertShaderModule; + vertShaderStageInfo.pName = "main"; + VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; + vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputInfo.vertexBindingDescriptionCount = 0; + vertexInputInfo.pVertexBindingDescriptions = nullptr; + vertexInputInfo.vertexAttributeDescriptionCount = 0; + vertexInputInfo.pVertexAttributeDescriptions = nullptr; + + // ------------------- STAGE 5 - RASTERIZATION ----------------- // + // Take Vertex shader vertices and fragmentize them for the frament shader. The rasterizer also can perform depth testing, face culling, and scissor testing. + // In addition, it can also be configured for wireframe rendering. + VkPipelineRasterizationStateCreateInfo rasterizer{}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + // Render regardless of the near and far planes, useful for shadow maps, requires GPU feature *depthClamp* + rasterizer.depthClampEnable = VK_FALSE; + rasterizer.rasterizerDiscardEnable = VK_FALSE; + // MODE_FILL, fill polygons, MODE_LINE, draw wireframe, MODE_POINT, draw vertices. Anything other than fill requires GPU feature *fillModeNonSolid* + rasterizer.polygonMode = VK_POLYGON_MODE_FILL; + rasterizer.lineWidth = 1.0f; + // How to cull the faces, right here we cull the back faces and tell the rasterizer front facing vertices are ordered clockwise. + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + // Whether or not to add depth values. e.x. for shadow maps. + rasterizer.depthBiasEnable = VK_FALSE; + + // ------------------ STAGE 6 - FRAGMENT SHADER ---------------- // + VkPipelineShaderStageCreateInfo fragShaderStageInfo{}; + fragShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragShaderStageInfo.module = fragShaderModule; + fragShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo shaderStages[] = {vertShaderStageInfo, fragShaderStageInfo}; + + // ------------------ STAGE 7 - COLOR BLENDING ----------------- // + VkPipelineColorBlendAttachmentState colorBlendAttachment{}; + 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; + + VkPipelineColorBlendStateCreateInfo colorBlending{}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.logicOpEnable = VK_FALSE; + colorBlending.logicOp = VK_LOGIC_OP_COPY; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + + // ---------------------- STATE CONTROLS ---------------------- // + VkPipelineViewportStateCreateInfo viewportState{}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.scissorCount = 1; + // Again, this will be revisited, multisampling can be very useful for anti-aliasing, since it is fast, but we won't implement it for now. + // Requires GPU feature UNKNOWN eanbled. + VkPipelineMultisampleStateCreateInfo multisampling{}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.sampleShadingEnable = VK_FALSE; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + // Most of the graphics pipeline is set in stone, some of the pipeline state can be modified without recreating it at runtime though! + // There are TONS of settings, this would be another TODO to see what else we can mess with dynamically, but right now we just allow dynamic size of the viewport + // and dynamic scissor states. Scissors are pretty straightforward, they are basically pixel masks for the rasterizer. + // Scissors describe what regions pixels will be stored, it doesnt cut them after being rendered, it stops them from ever being rendered in that area in the first place. + VkPipelineDynamicStateCreateInfo dynamicState{}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.dynamicStateCount = static_cast(dynamicStates.size()); + dynamicState.pDynamicStates = dynamicStates.data(); + + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 0; + pipelineLayoutInfo.pushConstantRangeCount = 0; + + if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { + throw std::runtime_error("failed to create pipeline layout!"); + } + + vkDestroyShaderModule(device, fragShaderModule, nullptr); + vkDestroyShaderModule(device, vertShaderModule, nullptr); + + if(Global::enableValidationLayers) std::cout << "Pipeline Layout created successfully\n" << std::endl; + } +} diff --git a/src/graphics/graphicspipeline.h b/src/graphics/graphicspipeline.h new file mode 100644 index 0000000..7599d6a --- /dev/null +++ b/src/graphics/graphicspipeline.h @@ -0,0 +1,10 @@ +#pragma once +#include "../global.h" + +namespace Graphics { + class graphicspipeline { + public: + void createGraphicsPipeline(VkDevice& device); + void destroyGraphicsPipeline(VkDevice& device); + }; +} diff --git a/src/main.cpp b/src/main.cpp index 98badef..7937d92 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,5 +1,6 @@ #include "devicelibrary.h" // Device Library includes global, redundant to include with it here #include "debug/vulkandebuglibs.h" +#include "graphics/graphicspipeline.h" #include #include @@ -23,7 +24,7 @@ public: private: DeviceControl::devicelibrary deviceLibs; Debug::vulkandebuglibs debugController; - + Graphics::graphicspipeline graphicsPipeline; GLFWwindow* window; VkInstance instance; VkDevice device; @@ -47,6 +48,7 @@ private: deviceLibs.createLogicalDevice(device); deviceLibs.createSwapChain(window, device); deviceLibs.createImageViews(device); + graphicsPipeline.createGraphicsPipeline(device); } void createInstance() { @@ -76,6 +78,7 @@ private: } void cleanup() { // Similar to the last handoff, destroy the utils in a safe manner in the library! + graphicsPipeline.destroyGraphicsPipeline(device); deviceLibs.destroyImageViews(device); deviceLibs.destroySwapChain(device); vkDestroyDevice(device, nullptr); diff --git a/src/shaders/frag.spv b/src/shaders/frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..da37f7ede672fe162b5322c32f5938a7836409a7 GIT binary patch literal 572 zcmYk2PfNo<6vUrx)7IAhv!FMrcod2U6+zU4NG^dYet=MtD1q3NHWj@2+5A*q1n0LV z(uK*}H#=`OEEHA71Yeo8+BI6MPEqd}+{a8uKdhAl0+aGA( z6gLqLrRPob_)qk0tMXUiuge|}IP@J=^z`Vvs`?d4G32BH#;R0mT<^MFnDF)EG3?WD_tXer-10N+zk@OW-Q!$6U%CCwBbK=EWe5;z^DZB6pD_lbols z;A~j*!x>3aHS;kY(h;+8ZeOy&`7ymK{vghmXU$b^!qFcb-s$KIjvgFG49B?z%J}l= z0x|SK?oo}|e?!JvmI~dbYWN26s-mvEFI!W+9#DzNtqAiXd>L!E#+MXRzb-s0PYs+e z%-(zt{$-81PdMuF^D>sh3l;pmr?cT(i!wCuPIE=E)*Gi;5`e=TcU3Vp71u3$SQh4c z=*ctVHF^4QGps0vb2F^gd3a_3^ZuGMTo*Rxm-^|JwKs&|=o@qV%^JI$<8L*zhH;ugQp(6Q*-1WD5ekY5ZsgJ+w=n7uQ6v$J(%~2hWvAR>d7DJE${}JnT6)B z7*GDS5O0dRCFX88w^vfr+kF{*y_K4t9?H(LSvj4QYY=-~< literal 0 HcmV?d00001