shaders are at a good state. starting work on the graphics pipeline.

This commit is contained in:
Nepgfurmixpro 2025-06-01 13:22:44 -04:00
parent 6fe98cdb5b
commit 4e8f3292bd
16 changed files with 367 additions and 64 deletions

View File

@ -14,6 +14,7 @@ find_package(spirv_cross_hlsl CONFIG REQUIRED)
find_package(spirv_cross_msl CONFIG REQUIRED)
find_package(spirv_cross_reflect CONFIG REQUIRED)
find_package(spirv_cross_util CONFIG REQUIRED)
find_package(unofficial-shaderc CONFIG REQUIRED)
foreach (file ${sourceFiles})
message("Source File Found ${file}")
@ -27,3 +28,4 @@ target_link_libraries(Dyn PRIVATE Vulkan::Vulkan)
target_link_libraries(Dyn PRIVATE glfw)
target_link_libraries(Dyn PRIVATE Vulkan::SafeStruct Vulkan::LayerSettings Vulkan::UtilityHeaders Vulkan::CompilerConfiguration)
target_link_libraries(Dyn PRIVATE spirv-cross-core spirv-cross-glsl spirv-cross-hlsl spirv-cross-msl spirv-cross-reflect spirv-cross-util)
target_link_libraries(Dyn PRIVATE unofficial::shaderc::shaderc)

View File

@ -20,6 +20,19 @@ namespace dyn {
return std::make_shared<T>(std::forward<Args>(args)...);
}
template <typename T>
using scoped = std::unique_ptr<T>;
template <typename To, typename From>
scoped<To> scoped_as(scoped<From> from) {
return std::unique_ptr<To>(static_cast<To*>(from.release()));
}
template <typename T, typename ...Args>
scoped<T> create_scoped(Args&&... args) {
return std::make_unique<T>(std::forward<Args>(args)...);
}
namespace core {
enum class RenderPlatform {
None,

View File

@ -13,10 +13,14 @@ namespace dyn::core {
class file {
public:
file(const std::string& path);
file(const std::filesystem::path& path);
~file() = default;
[[nodiscard]] std::string text() const { return _contents; }
[[nodiscard]] std::vector<uint8_t> bytes() const { return std::vector<uint8_t>(_contents.begin(), _contents.end()); }
[[nodiscard]] size_t size() const { return _contents.size(); }
[[nodiscard]] bool empty() const { return _contents.empty(); }
[[nodiscard]] std::string path() const { return _file_path; }
[[nodiscard]] static bool exists(const std::string& path);

View File

@ -0,0 +1,43 @@
//
// Created by nepge on 6/1/2025.
//
#pragma once
#include "dyn/renderer/graphics_pipeline.h"
namespace dyn::core {
inline static std::vector<VkDynamicState> g_vulkan_dynamic_states = {
VK_DYNAMIC_STATE_VIEWPORT,
VK_DYNAMIC_STATE_SCISSOR,
};
class vulkan_graphics_pipeline : public graphics_pipeline {
public:
vulkan_graphics_pipeline();
~vulkan_graphics_pipeline();
void set_polygon_mode(PolygonMode mode) override;
void set_line_width(float line_width) override;
void set_msaa_samples(MSAASamples samples) override;
void set_cull_mode(CullMode mode, FrontFace face) override;
void set_depth_bias_enabled(bool enable) override;
void set_depth_bias_options(float constant, float clamp, float slope) override;
void attach_shader(const ref<shader> &shader) override;
void build(const ref<render_context> &ctx) override;
private:
VkPipelineDynamicStateCreateInfo _dynamic_state_ci{};
VkPipelineVertexInputStateCreateInfo _vertex_input_ci{};
VkPipelineInputAssemblyStateCreateInfo _input_assembly_ci{};
VkViewport _viewport{};
VkRect2D _scissor{};
VkPipelineViewportStateCreateInfo _viewport_state_ci{};
VkPipelineRasterizationStateCreateInfo _rasterization_state_ci{};
VkPipelineMultisampleStateCreateInfo _multisample_state_ci{};
VkPipelineColorBlendStateCreateInfo _color_blend_state_ci{};
VkPipeline _pipleine = VK_NULL_HANDLE;
};
}

View File

@ -14,18 +14,25 @@ namespace dyn::core {
class vulkan_shader : public shader {
public:
vulkan_shader(const std::string& source, const std::string& filename, shader_type type, const ref<vulkan_context>& ctx);
vulkan_shader(const std::vector<uint32_t>& source, const std::string& filename, ShaderType type);
~vulkan_shader();
[[nodiscard]] static VkShaderStageFlagBits vulkan_stage_from_type(ShaderType type);
[[nodiscard]] VkShaderModule get_handle() const { return _shader; }
[[nodiscard]] VkPipelineShaderStageCreateInfo get_stage_info() const { return _pipeline_ci; }
[[nodiscard]] bool is_usable() const override { return _usable; }
void build(const ref<render_context> &context) override;
private:
std::vector<uint32_t> _binary;
ref<vulkan_context> _ctx;
ref<vulkan_context> _ctx = nullptr;
bool _usable = false;
std::string _filename;
ShaderType _type;
VkShaderStageFlagBits _stage;
VkShaderModule _shader = VK_NULL_HANDLE;
VkPipelineShaderStageCreateInfo _pipeline_ci = {};
};

View File

@ -27,7 +27,7 @@ namespace dyn::core {
void prepare() override {}
void present() override {}
void resize(uint32_t width, uint32_t height) override {}
void resize(uint32_t _width, uint32_t _height) override {}
[[nodiscard]] VkCommandBuffer current_cmd_buffer() const { return _command_buffers[_current_frame]; }

View File

@ -0,0 +1,50 @@
//
// Created by nepge on 6/1/2025.
//
#pragma once
#include <vulkan/vulkan_core.h>
#include <dyn/renderer/shader.h>
namespace dyn::core {
enum class PolygonMode {
FILL,
LINE,
POINT
};
enum class MSAASamples {
SAMPLES_1,
SAMPLES_2,
SAMPLES_4,
SAMPLES_8,
};
enum class CullMode {
FRONT,
BACK,
FRONT_AND_BACK,
};
enum class FrontFace {
CLOCKWISE,
COUNTERCLOCKWISE,
};
class graphics_pipeline {
public:
virtual ~graphics_pipeline() = default;
virtual void set_polygon_mode(PolygonMode mode) = 0;
virtual void set_line_width(float line_width = 1.0f) = 0;
virtual void set_msaa_samples(MSAASamples samples) = 0;
virtual void set_cull_mode(CullMode mode, FrontFace face) = 0;
virtual void set_depth_bias_enabled(bool enable) = 0;
virtual void set_depth_bias_options(float constant, float clamp, float slope) = 0;
virtual void attach_shader(const ref<shader>& shader) = 0;
virtual void build(const ref<render_context>& ctx) = 0;
};
}

View File

@ -6,30 +6,53 @@
#include <string>
#ifndef DYN_SHADER_INCLUDE_PATH
#define DYN_SHADER_INCLUDE_PATH "resources/shaders/"
#endif
#include "dyn/core/base.h"
#include "dyn/core/debug.h"
#include "dyn/core/file.h"
#include <shaderc/shaderc.hpp>
namespace dyn::core {
class render_context;
class shader_includer : public shaderc::CompileOptions::IncluderInterface {
public:
struct inclusion_data {
std::string path;
std::string contents;
};
explicit shader_includer(const std::string& base) : _base(base) {}
shaderc_include_result* GetInclude(const char *requested_source, shaderc_include_type type,
const char *requesting_source, size_t include_depth) override;
void ReleaseInclude(shaderc_include_result *data) override;
private:
std::filesystem::path _base;
};
class shader {
public:
enum shader_type {
SHADER_VERTEX,
SHADER_FRAGMENT,
SHADER_GEOMETRY,
SHADER_COMPUTE
virtual ~shader() = default;
enum ShaderType {
VERTEX,
FRAGMENT,
GEOMETRY,
COMPUTE
};
[[nodiscard]] shaderc_shader_kind convert_shader_type(shader_type type) const noexcept {
[[nodiscard]] static shaderc_shader_kind convert_shader_type(ShaderType type) noexcept {
switch (type) {
case SHADER_VERTEX:
case VERTEX:
return shaderc_vertex_shader;
case SHADER_FRAGMENT:
case FRAGMENT:
return shaderc_fragment_shader;
case SHADER_GEOMETRY:
case GEOMETRY:
return shaderc_geometry_shader;
case SHADER_COMPUTE:
case COMPUTE:
return shaderc_compute_shader;
}
return shaderc_vertex_shader;
@ -37,7 +60,11 @@ namespace dyn::core {
[[nodiscard]] virtual bool is_usable() const = 0;
static ref<shader> create_from_string(const std::string& code, shader_type type, const ref<render_context>& context);
static ref<shader> create_from_file(const std::string& filename, shader_type type, const ref<render_context>& context);
virtual void build(const ref<render_context>& context) = 0;
static ref<shader> create_from_string(const std::string& code, ShaderType type, const std::string& filename = "inline-source");
static ref<shader> create_from_file(const std::string& filename, ShaderType type);
static std::vector<uint32_t> compile_hlsl(const std::string& code, ShaderType type, const std::string& filename, std::string include_path);
};
}

View File

@ -0,0 +1,9 @@
#version 450
#extension GL_GOOGLE_include_directive : require
#include "test.glsl"
layout(location = 0) out vec3 fragColor;
void main() {
gl_Position = vec4(1.0, 1.0, 0.0, 1.0);
}

View File

@ -0,0 +1,3 @@
float add(float a, float b) {
return a + b;
}

View File

@ -7,7 +7,12 @@
namespace dyn::core {
file::file(const std::string &path) : _file(path, std::ios::in | std::ios::binary | std::ios::out), _file_path(path) {
_file >> _contents;
std::stringstream ss;
ss << _file.rdbuf();
_contents = ss.str();
}
file::file(const std::filesystem::path &path) : file(path.string()) {
}
void file::write(const std::string &text) {

View File

@ -20,6 +20,14 @@ namespace dyn::core {
static_cast<int>(spec.height),
spec.title.c_str(),
nullptr, nullptr);
auto monitor = glfwGetPrimaryMonitor();
auto vidMode = glfwGetVideoMode(monitor);
auto x = (vidMode->width/2) - spec.width/2;
auto y = (vidMode->height/2) - spec.height/2;
glfwSetWindowPos(_window, x, y);
DYN_ASSERT(_window != nullptr, "Failed to create GLFW window");
}

View File

@ -1,23 +1,13 @@
#include <functional>
#include <iostream>
#include <dyn/core/logging.h>
#include <dyn/core/command_queue.h>
#include "../inc/dyn/core/debug.h"
#include "dyn/core/window.h"
#include "dyn/platform/vulkan/vulkan.h"
#include "dyn/platform/vulkan/vulkan_context.h"
#include "dyn/renderer/render_context.h"
#include "dyn/renderer/shader.h"
using namespace dyn;
using namespace dyn::core;
int main() {
render_context::set_api(RenderPlatform::Vulkan);
// ref<render_context> ctx = render_context::create();
//
// ctx->init();
ref<window> win = window::create({
.width = 1280,
@ -29,4 +19,9 @@ int main() {
ref<render_context> ctx = render_context::create(win);
ctx->init();
ref<shader> test_shader = shader::create_from_file("resources/shaders/basic.vert.glsl", shader::VERTEX);
if (test_shader != nullptr) {
test_shader->build(ctx);
}
}

View File

@ -0,0 +1,43 @@
//
// Created by nepge on 6/1/2025.
//
#include <dyn/platform/vulkan/vulkan_graphics_pipeline.h>
namespace dyn::core {
vulkan_graphics_pipeline::vulkan_graphics_pipeline() {
_dynamic_state_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
_dynamic_state_ci.dynamicStateCount = static_cast<uint32_t>(g_vulkan_dynamic_states.size());
_dynamic_state_ci.pDynamicStates = g_vulkan_dynamic_states.data();
_vertex_input_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
_vertex_input_ci.vertexBindingDescriptionCount = 0;
}
vulkan_graphics_pipeline::~vulkan_graphics_pipeline() {
}
void vulkan_graphics_pipeline::set_polygon_mode(PolygonMode mode) {
}
void vulkan_graphics_pipeline::set_line_width(float line_width) {
}
void vulkan_graphics_pipeline::set_msaa_samples(MSAASamples samples) {
}
void vulkan_graphics_pipeline::set_cull_mode(CullMode mode, FrontFace face) {
}
void vulkan_graphics_pipeline::set_depth_bias_enabled(bool enable) {
}
void vulkan_graphics_pipeline::set_depth_bias_options(float constant, float clamp, float slope) {
}
void vulkan_graphics_pipeline::attach_shader(const ref<shader> &shader) {
}
void vulkan_graphics_pipeline::build(const ref<render_context> &ctx) {
}
}

View File

@ -8,44 +8,52 @@
#include "dyn/platform/vulkan/vulkan.h"
namespace dyn::core {
vulkan_shader::vulkan_shader(const std::string &source, const std::string& filename, shader_type type, const ref<vulkan_context>& ctx) : _ctx(ctx) {
shaderc::Compiler compiler;
auto compile_result = compiler.CompileGlslToSpv(
source.data(), source.length(),
shader::convert_shader_type(type),
filename.data());
auto result = compile_result.GetCompilationStatus();
if (result != shaderc_compilation_status_success) {
DYN_ERROR_LOG("Failed to compile shader: {}", filename);
DYN_ERROR_LOG("Shader Errors: {}", compile_result.GetNumErrors());
DYN_ERROR_LOG("Shader Warnings: {}", compile_result.GetNumWarnings());
DYN_ERROR_LOG("Shader Compilation Error Message:");
DYN_ERROR_LOG(compile_result.GetErrorMessage());
return;
}
_binary = std::vector(compile_result.begin(), compile_result.end());
VkShaderModuleCreateInfo module_create_info = {};
module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
module_create_info.pNext = nullptr;
module_create_info.codeSize = _binary.size();
module_create_info.pCode = _binary.data();
auto vk_res = vkCreateShaderModule(ctx->get_current_device()->get_handle(), &module_create_info, nullptr, &_shader);
if (vk_res != VK_SUCCESS) {
DYN_ERROR_LOG("Failed to create shader module: {}", string_VkResult(vk_res));
return;
}
_usable = true;
}
vulkan_shader::vulkan_shader(
const std::vector<uint32_t>&source,
const std::string& filename, ShaderType type)
: _binary(source.begin(), source.end()), _filename(filename), _type(type), _stage(vulkan_stage_from_type(type)) {}
vulkan_shader::~vulkan_shader() {
if (_shader != VK_NULL_HANDLE) {
vkDestroyShaderModule(_ctx->get_current_device()->get_handle(), _shader, nullptr);
}
}
VkShaderStageFlagBits vulkan_shader::vulkan_stage_from_type(ShaderType type) {
switch (type) {
case VERTEX:
return VK_SHADER_STAGE_VERTEX_BIT;
case FRAGMENT:
return VK_SHADER_STAGE_FRAGMENT_BIT;
case GEOMETRY:
return VK_SHADER_STAGE_GEOMETRY_BIT;
case COMPUTE:
return VK_SHADER_STAGE_COMPUTE_BIT;
}
return static_cast<VkShaderStageFlagBits>(0);
}
void vulkan_shader::build(const ref<render_context> &ctx) {
_ctx = ref_as<vulkan_context>(ctx);
VkShaderModuleCreateInfo module_create_info = {};
module_create_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
module_create_info.pNext = nullptr;
// times by four as thats the requirement for vulkan shaders
module_create_info.codeSize = _binary.size()*4;
module_create_info.pCode = static_cast<const uint32_t*>(_binary.data());
auto vk_res = vkCreateShaderModule(_ctx->get_current_device()->get_handle(), &module_create_info, nullptr, &_shader);
if (vk_res != VK_SUCCESS) {
DYN_ERROR_LOG("Failed to create shader module: {}", string_VkResult(vk_res));
return;
}
_pipeline_ci.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
_pipeline_ci.stage = _stage;
_pipeline_ci.module = _shader;
_pipeline_ci.pName = "main";
_usable = true;
}
}

View File

@ -4,6 +4,92 @@
#include <dyn/renderer/shader.h>
namespace dyn::core {
#include "dyn/platform/vulkan/vulkan_shader.h"
#include "dyn/renderer/render_context.h"
namespace dyn::core {
shaderc_include_result * shader_includer::GetInclude(const char *requested_source, shaderc_include_type type,
const char *requesting_source, size_t) {
auto path = _base / requested_source;
DYN_DEBUG_LOG("Source file \"", requesting_source, "\" included/requested file: \"", path.string(), "\".");
if (file::exists(path.string())) {
file source{ path };
inclusion_data* data = new inclusion_data{
source.path(),
source.text()
};
return new shaderc_include_result {
data->path.data(), data->path.size(),
data->contents.data(), data->contents.size(),
data
};
}
DYN_ERROR_LOG("Requested file to include \"", requested_source, "\" not found.");
return new shaderc_include_result {
"", 0, "", 0,
nullptr
};
}
void shader_includer::ReleaseInclude(shaderc_include_result *data) {
if (data->user_data != nullptr) {
delete static_cast<inclusion_data*>(data->user_data);
}
delete data;
}
ref<shader> shader::create_from_string(const std::string &code, ShaderType type, const std::string &filename) {
auto compiled = compile_hlsl(code, type, filename, DYN_SHADER_INCLUDE_PATH);
if (compiled.empty()) {
DYN_ERROR_LOG("Shader compiled code is empty. Returning nullptr");
return nullptr;
}
DYN_PLATFORM_CREATE_BEGIN(render_context::get_api())
DYN_PLATFORM_CREATE_VK(vulkan_shader, compiled, filename, type);
DYN_PLATFORM_CREATE_END(shader)
}
ref<shader> shader::create_from_file(const std::string &filename, ShaderType type) {
file source { filename };
return shader::create_from_string(source.text(), type, filename);
}
std::vector<uint32_t> shader::compile_hlsl(const std::string &code, ShaderType type, const std::string& filename, std::string include_path) {
DYN_DEBUG_LOG("Compiling Shader \"", filename, "\".");
shaderc::Compiler compiler;
shaderc::CompileOptions options;
options.SetSourceLanguage(shaderc_source_language_glsl);
switch (render_context::get_api()) {
case RenderPlatform::Vulkan:
options.SetTargetEnvironment(shaderc_target_env_vulkan, VK_VERSION_1_2);
break;
default:;
}
options.SetIncluder(create_scoped<shader_includer>(DYN_SHADER_INCLUDE_PATH));
auto compile_result = compiler.CompileGlslToSpv(
code.data(), code.length(),
convert_shader_type(type),
filename.data(), options);
auto result = compile_result.GetCompilationStatus();
if (result != shaderc_compilation_status_success) {
DYN_ERROR_LOG("Failed to compile shader:", filename);
DYN_ERROR_LOG("Shader Errors:", compile_result.GetNumErrors());
DYN_ERROR_LOG("Shader Warnings:", compile_result.GetNumWarnings());
DYN_ERROR_LOG("Shader Compilation Error Message:");
DYN_ERROR_LOG(compile_result.GetErrorMessage());
return std::vector<uint32_t>();
}
DYN_INFO_LOG("Successfully compiled shader:", filename);
return {compile_result.begin(), compile_result.end()};
}
}