From 9b1e7d56a36cc69568616cfb13f06a5b327137d7 Mon Sep 17 00:00:00 2001 From: Caleb Burke Date: Sun, 6 Sep 2026 23:40:27 -0700 Subject: [PATCH] Updates --- engine/src/shader.cpp | 20 ++++- engine/src/shader.hpp | 5 ++ engine/src/shaders/fullscreen.vert | 18 +++++ engine/src/shaders/model_render_system.frag | 9 +++ engine/src/shaders/model_render_system.vert | 16 ++++ engine/src/systems/model_render_system.cpp | 88 +++++++++++++++++++++ engine/src/systems/model_render_system.hpp | 42 ++++++++++ 7 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 engine/src/shaders/fullscreen.vert create mode 100644 engine/src/shaders/model_render_system.frag create mode 100644 engine/src/shaders/model_render_system.vert create mode 100644 engine/src/systems/model_render_system.cpp create mode 100644 engine/src/systems/model_render_system.hpp diff --git a/engine/src/shader.cpp b/engine/src/shader.cpp index 178bf8b..1093a52 100644 --- a/engine/src/shader.cpp +++ b/engine/src/shader.cpp @@ -91,6 +91,19 @@ Shader::Builder& Shader::Builder::fromGLSL(const std::string& path) { Shader::Builder& Shader::Builder::fromSPIRV(const std::string& path) { this->path = path; this->precompiled = true; + this->embedded = false; + return *this; +} + +Shader::Builder& Shader::Builder::fromSPIRV(std::vector spirv) { + this->embeddedSpirv = std::move(spirv); + this->embedded = true; + return *this; +} + +Shader::Builder& Shader::Builder::fromSPIRV(std::span spirv) { + this->embeddedSpirv.assign(spirv.begin(), spirv.end()); + this->embedded = true; return *this; } @@ -101,7 +114,7 @@ Shader::Builder& Shader::Builder::setStage(ShaderStage shaderStage) { } std::unique_ptr Shader::Builder::build() { - if (this->path.empty()) { + if (!this->embedded && this->path.empty()) { log::fatal("failed to build shader: no source path provided"); throw std::runtime_error("failed to build shader: no source path provided"); } @@ -113,7 +126,10 @@ std::unique_ptr Shader::Builder::build() { auto shader = std::unique_ptr(new Shader()); - if (this->precompiled) { + if (this->embedded) { + shader->stage = this->stage; + shader->spirv = std::move(this->embeddedSpirv); + } else if (this->precompiled) { shader->load(this->path, this->stage); } else { shader->compile(this->path, this->stage); diff --git a/engine/src/shader.hpp b/engine/src/shader.hpp index 3f26717..1c0ca93 100644 --- a/engine/src/shader.hpp +++ b/engine/src/shader.hpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -37,15 +38,19 @@ class Shader::Builder { Builder& fromGLSL(const std::string& path); Builder& fromSPIRV(const std::string& path); + Builder& fromSPIRV(std::vector spirv); + Builder& fromSPIRV(std::span spirv); Builder& setStage(ShaderStage shaderStage); std::unique_ptr build(); private: std::string path; + std::vector embeddedSpirv; ShaderStage stage; bool stageSet = false; bool precompiled = false; + bool embedded = false; }; } // namespace sophia diff --git a/engine/src/shaders/fullscreen.vert b/engine/src/shaders/fullscreen.vert new file mode 100644 index 0000000..bfbaa6e --- /dev/null +++ b/engine/src/shaders/fullscreen.vert @@ -0,0 +1,18 @@ +#version 450 + +layout (location = 0) out vec2 uv; + +vec2 positions[6] = vec2[]( + vec2(-1.0, -1.0), + vec2( 1.0, -1.0), + vec2(-1.0, 1.0), + vec2(-1.0, 1.0), + vec2( 1.0, -1.0), + vec2( 1.0, 1.0) +); + +void main() { + vec2 pos = positions[gl_VertexIndex]; + gl_Position = vec4(pos, 0.0, 1.0); + uv = pos * 0.5 + 0.5; +} diff --git a/engine/src/shaders/model_render_system.frag b/engine/src/shaders/model_render_system.frag new file mode 100644 index 0000000..1eb43db --- /dev/null +++ b/engine/src/shaders/model_render_system.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/engine/src/shaders/model_render_system.vert b/engine/src/shaders/model_render_system.vert new file mode 100644 index 0000000..4895054 --- /dev/null +++ b/engine/src/shaders/model_render_system.vert @@ -0,0 +1,16 @@ +#version 450 + +layout (location = 0) in vec2 position; +layout (location = 1) in vec3 color; + +layout (location = 0) out vec3 fragColor; + +layout (push_constant) uniform Push { + mat4 transform; + vec4 color; +} push; + +void main() { + gl_Position = vec4(push.transform * vec4(position, 0.0, 1.0)); + fragColor = color; +} diff --git a/engine/src/systems/model_render_system.cpp b/engine/src/systems/model_render_system.cpp new file mode 100644 index 0000000..2897d23 --- /dev/null +++ b/engine/src/systems/model_render_system.cpp @@ -0,0 +1,88 @@ +#include "model_render_system.hpp" + +#include + +#include "shaders/model_render_system.frag.spv.h" +#include "shaders/model_render_system.vert.spv.h" + +namespace sophia { + +ModelRenderSystem::ModelRenderSystem(Device& device, + RenderContext& renderContext) + : device{device}, renderContext{renderContext} { + createPipelineLayout(); + + assert(this->pipelineLayout.get() != nullptr && + "Cannot create pipeline before pipeline layout"); + + auto vertexShader = Shader::Builder() + .fromSPIRV(shaders::model_render_system_vert_spv) + .setStage(ShaderStage::VERTEX) + .build(); + auto fragmentShader = Shader::Builder() + .fromSPIRV(shaders::model_render_system_frag_spv) + .setStage(ShaderStage::FRAGMENT) + .build(); + + auto bindingDescriptions = Model::Vertex::getBindingDescriptions(); + auto attributeDescriptions = Model::Vertex::getAttributeDescriptions(); + + this->graphicsPipeline = + GraphicsPipeline::Builder(device) + .setVertexShader(*vertexShader) + .setFragmentShader(*fragmentShader) + .setPipelineLayout(pipelineLayout.get()) + .setColorAttachmentFormats({renderContext.getImageFormat()}) + .setVertexInput(bindingDescriptions, attributeDescriptions) + .build(); +} + +ModelRenderSystem::~ModelRenderSystem() { + log::trace("destroyed sophia::ModelRenderSystem"); +} + +void ModelRenderSystem::render(vk::CommandBuffer commandBuffer, + std::span> models, + const FrameInfo& frameInfo) { + glm::mat4 viewProjection = frameInfo.camera.getViewProjection(); + + this->graphicsPipeline->bind(commandBuffer); + + for (const std::unique_ptr& model : models) { + PushConstantData push{}; + push.modelMatrix = viewProjection; + + commandBuffer.pushConstants( + this->pipelineLayout.get(), + vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, + 0, sizeof(PushConstantData), &push); + + model->bind(commandBuffer); + model->draw(commandBuffer); + } +} + +void ModelRenderSystem::createPipelineLayout() { + vk::PushConstantRange pushConstantRange{}; + + pushConstantRange.stageFlags = + vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment; + pushConstantRange.offset = 0; + pushConstantRange.size = sizeof(PushConstantData); + + vk::PipelineLayoutCreateInfo pipelineLayoutInfo = {}; + pipelineLayoutInfo.setLayoutCount = 0; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; + + try { + this->pipelineLayout = + this->device.get()->createPipelineLayoutUnique(pipelineLayoutInfo); + log::trace("created vk::PipelineLayout"); + } catch (const vk::SystemError& err) { + log::fatal("failed to create vk::PipelineLayout"); + throw std::runtime_error("failed to create vk::PipelineLayout"); + } +} + +} // namespace sophia diff --git a/engine/src/systems/model_render_system.hpp b/engine/src/systems/model_render_system.hpp new file mode 100644 index 0000000..8edb308 --- /dev/null +++ b/engine/src/systems/model_render_system.hpp @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include + +#include "device.hpp" +#include "model.hpp" +#include "pipelines/graphics_pipeline.hpp" +#include "render_context.hpp" + +namespace sophia { + +class ModelRenderSystem { + public: + struct PushConstantData { + glm::mat4 modelMatrix{1.f}; + glm::mat4 normalMatrix{1.f}; + }; + + ModelRenderSystem(const ModelRenderSystem&) = delete; + ModelRenderSystem& operator=(const ModelRenderSystem&) = delete; + + ModelRenderSystem(Device& device, RenderContext& renderContext); + ~ModelRenderSystem(); + + void render(vk::CommandBuffer commandBuffer, + std::span> models, + const FrameInfo& frameInfo); + + private: + void createPipelineLayout(); + void createPipeline(); + + Device& device; + RenderContext& renderContext; + + std::unique_ptr graphicsPipeline; + vk::UniquePipelineLayout pipelineLayout; +}; + +} // namespace sophia