Add basic shader editing system
POC, only registered shader is the sky shader
This commit is contained in:
parent
e8032b8cf2
commit
e8fc757d99
18 changed files with 239 additions and 61 deletions
|
@ -1,3 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
void draw_debug_ui();
|
void draw_debug_ui();
|
||||||
|
|
||||||
|
void load_debug_options();
|
||||||
|
void save_debug_options();
|
||||||
|
|
||||||
|
std::string_view get_shader_source_directory();
|
||||||
|
|
|
@ -11,6 +11,13 @@
|
||||||
#include "imgui_utility.hpp"
|
#include "imgui_utility.hpp"
|
||||||
#include "scene.hpp"
|
#include "scene.hpp"
|
||||||
#include "renderer.hpp"
|
#include "renderer.hpp"
|
||||||
|
#include "file.hpp"
|
||||||
|
|
||||||
|
struct Options {
|
||||||
|
std::string shader_source_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline Options options;
|
||||||
|
|
||||||
void draw_general() {
|
void draw_general() {
|
||||||
ImGui::Text("Platform: %s", platform::get_name());
|
ImGui::Text("Platform: %s", platform::get_name());
|
||||||
|
@ -145,6 +152,51 @@ void draw_renderer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline std::string selected_shader;
|
||||||
|
static inline std::string loaded_shader_string;
|
||||||
|
|
||||||
|
void draw_shader_editor() {
|
||||||
|
if(options.shader_source_path.empty()) {
|
||||||
|
ImGui::Text("You haven't specified a shader source path yet. Please select one below:");
|
||||||
|
if(ImGui::Button("Select Path")) {
|
||||||
|
platform::open_dialog(false, [](std::string path) {
|
||||||
|
// open_dialog() can't select folders yet, so use this as a workaround
|
||||||
|
options.shader_source_path = file::Path(path).parent_path().string();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(ImGui::BeginCombo("Select", nullptr)) {
|
||||||
|
for(auto& shader : engine->get_renderer()->registered_shaders) {
|
||||||
|
if(ImGui::Selectable(shader.filename.data())) {
|
||||||
|
selected_shader = shader.filename;
|
||||||
|
loaded_shader_string.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::EndCombo();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!selected_shader.empty()) {
|
||||||
|
if(loaded_shader_string.empty()) {
|
||||||
|
file::Path base_shader_path = options.shader_source_path;
|
||||||
|
|
||||||
|
shader_compiler.set_include_path(base_shader_path.string());
|
||||||
|
|
||||||
|
file::Path shader_path = file::Path(selected_shader);
|
||||||
|
|
||||||
|
auto file = file::open(base_shader_path / shader_path.replace_extension(shader_path.extension().string() + ".glsl"));
|
||||||
|
|
||||||
|
loaded_shader_string = file->read_as_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::InputTextMultiline("Source", &loaded_shader_string);
|
||||||
|
|
||||||
|
if(ImGui::Button("Reload"))
|
||||||
|
engine->get_renderer()->reload_shader(selected_shader, loaded_shader_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void draw_debug_ui() {
|
void draw_debug_ui() {
|
||||||
if(ImGui::Begin("General"))
|
if(ImGui::Begin("General"))
|
||||||
draw_general();
|
draw_general();
|
||||||
|
@ -165,4 +217,21 @@ void draw_debug_ui() {
|
||||||
draw_renderer();
|
draw_renderer();
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
|
if(ImGui::Begin("Shader Editor"))
|
||||||
|
draw_shader_editor();
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_debug_options() {
|
||||||
|
// stub
|
||||||
|
}
|
||||||
|
|
||||||
|
void save_debug_options() {
|
||||||
|
// stub
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string_view get_shader_source_directory() {
|
||||||
|
return options.shader_source_path;
|
||||||
}
|
}
|
||||||
|
|
|
@ -443,17 +443,17 @@ GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateI
|
||||||
|
|
||||||
MTLRenderPipelineDescriptor *pipelineDescriptor = [MTLRenderPipelineDescriptor new];
|
MTLRenderPipelineDescriptor *pipelineDescriptor = [MTLRenderPipelineDescriptor new];
|
||||||
|
|
||||||
const bool has_vertex_stage = !info.shaders.vertex_path.empty() || !info.shaders.vertex_src.empty();
|
const bool has_vertex_stage = !info.shaders.vertex_src.empty();
|
||||||
const bool has_fragment_stage = !info.shaders.fragment_path.empty() || !info.shaders.fragment_src.empty();
|
const bool has_fragment_stage = !info.shaders.fragment_src.empty();
|
||||||
|
|
||||||
if(has_vertex_stage) {
|
if(has_vertex_stage) {
|
||||||
id<MTLLibrary> vertexLibrary;
|
id<MTLLibrary> vertexLibrary;
|
||||||
{
|
{
|
||||||
std::string vertex_src;
|
std::string vertex_src;
|
||||||
if(info.shaders.vertex_path.empty()) {
|
if(info.shaders.vertex_src.is_string()) {
|
||||||
vertex_src = info.shaders.vertex_src.as_string();
|
vertex_src = info.shaders.vertex_src.as_string();
|
||||||
} else {
|
} else {
|
||||||
const auto vertex_path = utility::format("{}.msl", info.shaders.vertex_path);
|
const auto vertex_path = utility::format("{}.msl", info.shaders.vertex_src.as_path().string());
|
||||||
|
|
||||||
auto file = file::open(file::internal_domain / vertex_path);
|
auto file = file::open(file::internal_domain / vertex_path);
|
||||||
if(file != std::nullopt) {
|
if(file != std::nullopt) {
|
||||||
|
@ -471,8 +471,8 @@ GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateI
|
||||||
|
|
||||||
id<MTLFunction> vertexFunc = [vertexLibrary newFunctionWithName:@"main0" constantValues:vertex_constants error:nil];
|
id<MTLFunction> vertexFunc = [vertexLibrary newFunctionWithName:@"main0" constantValues:vertex_constants error:nil];
|
||||||
|
|
||||||
if(debug_enabled)
|
if(debug_enabled && info.shaders.vertex_src.is_path())
|
||||||
vertexFunc.label = [NSString stringWithFormat:@"%s", info.shaders.vertex_path.data()];
|
vertexFunc.label = [NSString stringWithFormat:@"%s", info.shaders.vertex_src.as_path().string().data()];
|
||||||
|
|
||||||
pipelineDescriptor.vertexFunction = vertexFunc;
|
pipelineDescriptor.vertexFunction = vertexFunc;
|
||||||
}
|
}
|
||||||
|
@ -482,10 +482,10 @@ GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateI
|
||||||
id<MTLLibrary> fragmentLibrary;
|
id<MTLLibrary> fragmentLibrary;
|
||||||
{
|
{
|
||||||
std::string fragment_src;
|
std::string fragment_src;
|
||||||
if(info.shaders.fragment_path.empty()) {
|
if(info.shaders.fragment_src.is_string()) {
|
||||||
fragment_src = info.shaders.fragment_src.as_string();
|
fragment_src = info.shaders.fragment_src.as_string();
|
||||||
} else {
|
} else {
|
||||||
const auto fragment_path = utility::format("{}.msl", info.shaders.fragment_path);
|
const auto fragment_path = utility::format("{}.msl", info.shaders.fragment_src.as_path().string());
|
||||||
|
|
||||||
auto file = file::open(file::internal_domain / fragment_path);
|
auto file = file::open(file::internal_domain / fragment_path);
|
||||||
if(file != std::nullopt) {
|
if(file != std::nullopt) {
|
||||||
|
@ -504,8 +504,8 @@ GFXPipeline* GFXMetal::create_graphics_pipeline(const GFXGraphicsPipelineCreateI
|
||||||
|
|
||||||
id<MTLFunction> fragmentFunc = [fragmentLibrary newFunctionWithName:@"main0" constantValues:fragment_constants error:nil];
|
id<MTLFunction> fragmentFunc = [fragmentLibrary newFunctionWithName:@"main0" constantValues:fragment_constants error:nil];
|
||||||
|
|
||||||
if(debug_enabled)
|
if(debug_enabled && info.shaders.fragment_src.is_path())
|
||||||
fragmentFunc.label = [NSString stringWithFormat:@"%s", info.shaders.fragment_path.data()];
|
fragmentFunc.label = [NSString stringWithFormat:@"%s", info.shaders.fragment_src.as_path().string().data()];
|
||||||
|
|
||||||
pipelineDescriptor.fragmentFunction = fragmentFunc;
|
pipelineDescriptor.fragmentFunction = fragmentFunc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,8 +157,6 @@ struct GFXGraphicsPipelineCreateInfo {
|
||||||
std::string label; // only used for debug
|
std::string label; // only used for debug
|
||||||
|
|
||||||
struct Shaders {
|
struct Shaders {
|
||||||
std::string_view vertex_path, fragment_path;
|
|
||||||
|
|
||||||
ShaderSource vertex_src, fragment_src;
|
ShaderSource vertex_src, fragment_src;
|
||||||
|
|
||||||
GFXShaderConstants vertex_constants, fragment_constants;
|
GFXShaderConstants vertex_constants, fragment_constants;
|
||||||
|
|
3
engine/platform/CMakeLists.txt
Executable file
3
engine/platform/CMakeLists.txt
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
add_library(Platform INTERFACE)
|
||||||
|
target_include_directories(Platform INTERFACE include)
|
||||||
|
target_link_libraries(Platform INTERFACE Utility)
|
|
@ -10,6 +10,7 @@
|
||||||
#include "common.hpp"
|
#include "common.hpp"
|
||||||
#include "render_options.hpp"
|
#include "render_options.hpp"
|
||||||
#include "path.hpp"
|
#include "path.hpp"
|
||||||
|
#include "shadercompiler.hpp"
|
||||||
|
|
||||||
namespace ui {
|
namespace ui {
|
||||||
class Screen;
|
class Screen;
|
||||||
|
@ -128,7 +129,21 @@ public:
|
||||||
GFXRenderPass* unormRenderPass = nullptr;
|
GFXRenderPass* unormRenderPass = nullptr;
|
||||||
GFXPipeline* renderToUnormTexturePipeline = nullptr;
|
GFXPipeline* renderToUnormTexturePipeline = nullptr;
|
||||||
GFXRenderPass* viewportRenderPass = nullptr;
|
GFXRenderPass* viewportRenderPass = nullptr;
|
||||||
|
|
||||||
|
ShaderSource register_shader(const std::string_view shader_file);
|
||||||
|
void associate_shader_reload(const std::string_view shader_file, const std::function<void()> reload_function);
|
||||||
|
void reload_shader(const std::string_view shader_file, const std::string_view shader_source);
|
||||||
|
|
||||||
|
struct RegisteredShader {
|
||||||
|
std::string filename;
|
||||||
|
std::string injected_shader_source;
|
||||||
|
std::function<void()> reload_function;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<RegisteredShader> registered_shaders;
|
||||||
|
|
||||||
|
bool reloading_shader = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void createDummyTexture();
|
void createDummyTexture();
|
||||||
void createOffscreenResources();
|
void createOffscreenResources();
|
||||||
|
|
|
@ -27,9 +27,9 @@ DoFPass::DoFPass(GFX* gfx, Renderer* renderer) : renderer(renderer) {
|
||||||
height_constant.value = extent.height;
|
height_constant.value = extent.height;
|
||||||
|
|
||||||
GFXGraphicsPipelineCreateInfo create_info = {};
|
GFXGraphicsPipelineCreateInfo create_info = {};
|
||||||
create_info.shaders.vertex_path = "dof.vert";
|
create_info.shaders.vertex_src = file::Path("dof.vert");
|
||||||
create_info.shaders.vertex_constants = {width_constant, height_constant};
|
create_info.shaders.vertex_constants = {width_constant, height_constant};
|
||||||
create_info.shaders.fragment_path = "dof.frag";
|
create_info.shaders.fragment_src = file::Path("dof.frag");
|
||||||
|
|
||||||
create_info.shader_input.bindings = {
|
create_info.shader_input.bindings = {
|
||||||
{0, GFXBindingType::StorageImage},
|
{0, GFXBindingType::StorageImage},
|
||||||
|
|
|
@ -14,8 +14,8 @@ GaussianHelper::GaussianHelper(GFX* gfx, const prism::Extent extent) : extent(ex
|
||||||
// pipeline
|
// pipeline
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.label = "Gaussian";
|
pipelineInfo.label = "Gaussian";
|
||||||
pipelineInfo.shaders.vertex_path = "gaussian.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("gaussian.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "gaussian.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("gaussian.frag");
|
||||||
|
|
||||||
pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip;
|
pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip;
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ void ImGuiPass::initialize() {
|
||||||
void ImGuiPass::resize(const prism::Extent extent) {
|
void ImGuiPass::resize(const prism::Extent extent) {
|
||||||
GFXGraphicsPipelineCreateInfo createInfo;
|
GFXGraphicsPipelineCreateInfo createInfo;
|
||||||
createInfo.label = "ImGui";
|
createInfo.label = "ImGui";
|
||||||
createInfo.shaders.vertex_path = "imgui.vert";
|
createInfo.shaders.vertex_src = file::Path("imgui.vert");
|
||||||
createInfo.shaders.fragment_path = "imgui.frag";
|
createInfo.shaders.fragment_src = file::Path("imgui.frag");
|
||||||
|
|
||||||
GFXVertexInput vertexInput = {};
|
GFXVertexInput vertexInput = {};
|
||||||
vertexInput.stride = sizeof(ImDrawVert);
|
vertexInput.stride = sizeof(ImDrawVert);
|
||||||
|
|
|
@ -36,7 +36,7 @@ ShaderSource get_shader(std::string filename, bool skinned, bool cubemap) {
|
||||||
|
|
||||||
GFXPipeline* MaterialCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only, bool cubemap) {
|
GFXPipeline* MaterialCompiler::create_static_pipeline(GFXGraphicsPipelineCreateInfo createInfo, bool positions_only, bool cubemap) {
|
||||||
// take vertex src
|
// take vertex src
|
||||||
std::string vertex_path = createInfo.shaders.vertex_path.data();
|
std::string vertex_path = createInfo.shaders.vertex_src.as_path().string();
|
||||||
vertex_path += ".glsl";
|
vertex_path += ".glsl";
|
||||||
|
|
||||||
if (positions_only)
|
if (positions_only)
|
||||||
|
@ -46,7 +46,6 @@ GFXPipeline* MaterialCompiler::create_static_pipeline(GFXGraphicsPipelineCreateI
|
||||||
createInfo.label += "cubemap ver";
|
createInfo.label += "cubemap ver";
|
||||||
|
|
||||||
createInfo.shaders.vertex_src = get_shader(vertex_path, false, cubemap);
|
createInfo.shaders.vertex_src = get_shader(vertex_path, false, cubemap);
|
||||||
createInfo.shaders.vertex_path = "";
|
|
||||||
|
|
||||||
if(positions_only) {
|
if(positions_only) {
|
||||||
createInfo.vertex_input.inputs = {
|
createInfo.vertex_input.inputs = {
|
||||||
|
@ -81,11 +80,10 @@ GFXPipeline* MaterialCompiler::create_skinned_pipeline(GFXGraphicsPipelineCreate
|
||||||
createInfo.label += " (Skinned)";
|
createInfo.label += " (Skinned)";
|
||||||
|
|
||||||
// take vertex src
|
// take vertex src
|
||||||
std::string vertex_path = createInfo.shaders.vertex_path.data();
|
std::string vertex_path = createInfo.shaders.vertex_src.as_path().string();
|
||||||
vertex_path += ".glsl";
|
vertex_path += ".glsl";
|
||||||
|
|
||||||
createInfo.shaders.vertex_src = get_shader(vertex_path, true, false);
|
createInfo.shaders.vertex_src = get_shader(vertex_path, true, false);
|
||||||
createInfo.shaders.vertex_path = "";
|
|
||||||
|
|
||||||
createInfo.shader_input.bindings.push_back({ 14, GFXBindingType::StorageBuffer });
|
createInfo.shader_input.bindings.push_back({ 14, GFXBindingType::StorageBuffer });
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "frustum.hpp"
|
#include "frustum.hpp"
|
||||||
#include "shadercompiler.hpp"
|
#include "shadercompiler.hpp"
|
||||||
#include "asset.hpp"
|
#include "asset.hpp"
|
||||||
|
#include "debug.hpp"
|
||||||
|
|
||||||
struct ElementInstance {
|
struct ElementInstance {
|
||||||
Vector4 color;
|
Vector4 color;
|
||||||
|
@ -710,8 +711,8 @@ void Renderer::create_mesh_pipeline(Material& material) {
|
||||||
|
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.label = "Mesh";
|
pipelineInfo.label = "Mesh";
|
||||||
pipelineInfo.shaders.vertex_path = "mesh.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("mesh.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "mesh.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("mesh.frag");
|
||||||
|
|
||||||
pipelineInfo.shaders.vertex_constants = {materials_constant, lights_constant, spot_lights_constant, probes_constant};
|
pipelineInfo.shaders.vertex_constants = {materials_constant, lights_constant, spot_lights_constant, probes_constant};
|
||||||
pipelineInfo.shaders.fragment_constants = {materials_constant, lights_constant, spot_lights_constant, probes_constant};
|
pipelineInfo.shaders.fragment_constants = {materials_constant, lights_constant, spot_lights_constant, probes_constant};
|
||||||
|
@ -738,7 +739,6 @@ void Renderer::create_mesh_pipeline(Material& material) {
|
||||||
pipelineInfo.blending.dst_rgb = GFXBlendFactor::OneMinusSrcAlpha;
|
pipelineInfo.blending.dst_rgb = GFXBlendFactor::OneMinusSrcAlpha;
|
||||||
|
|
||||||
pipelineInfo.shaders.fragment_src = material_compiler.compile_material_fragment(material);
|
pipelineInfo.shaders.fragment_src = material_compiler.compile_material_fragment(material);
|
||||||
pipelineInfo.shaders.fragment_path = "";
|
|
||||||
|
|
||||||
for (auto [index, texture] : material.bound_textures) {
|
for (auto [index, texture] : material.bound_textures) {
|
||||||
GFXShaderBinding binding;
|
GFXShaderBinding binding;
|
||||||
|
@ -852,8 +852,8 @@ void Renderer::createPostPipeline() {
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.label = "Post";
|
pipelineInfo.label = "Post";
|
||||||
|
|
||||||
pipelineInfo.shaders.vertex_path = "post.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("post.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "post.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("post.frag");
|
||||||
|
|
||||||
pipelineInfo.shader_input.bindings = {
|
pipelineInfo.shader_input.bindings = {
|
||||||
{4, GFXBindingType::PushConstant},
|
{4, GFXBindingType::PushConstant},
|
||||||
|
@ -904,8 +904,8 @@ void Renderer::createFontPipeline() {
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.label = "Text";
|
pipelineInfo.label = "Text";
|
||||||
|
|
||||||
pipelineInfo.shaders.vertex_path = "text.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("text.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "text.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("text.frag");
|
||||||
|
|
||||||
pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip;
|
pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip;
|
||||||
|
|
||||||
|
@ -950,8 +950,8 @@ void Renderer::createSkyPipeline() {
|
||||||
pipelineInfo.label = "Sky";
|
pipelineInfo.label = "Sky";
|
||||||
pipelineInfo.render_pass = offscreenRenderPass;
|
pipelineInfo.render_pass = offscreenRenderPass;
|
||||||
|
|
||||||
pipelineInfo.shaders.vertex_path = "sky.vert";
|
pipelineInfo.shaders.vertex_src = register_shader("sky.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "sky.frag";
|
pipelineInfo.shaders.fragment_src = register_shader("sky.frag");
|
||||||
|
|
||||||
pipelineInfo.shader_input.bindings = {
|
pipelineInfo.shader_input.bindings = {
|
||||||
{1, GFXBindingType::PushConstant}
|
{1, GFXBindingType::PushConstant}
|
||||||
|
@ -964,14 +964,22 @@ void Renderer::createSkyPipeline() {
|
||||||
pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual;
|
pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual;
|
||||||
|
|
||||||
skyPipeline = gfx->create_graphics_pipeline(pipelineInfo);
|
skyPipeline = gfx->create_graphics_pipeline(pipelineInfo);
|
||||||
|
|
||||||
|
associate_shader_reload("sky.vert", [this] {
|
||||||
|
createSkyPipeline();
|
||||||
|
});
|
||||||
|
|
||||||
|
associate_shader_reload("sky.frag", [this] {
|
||||||
|
createSkyPipeline();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::createUIPipeline() {
|
void Renderer::createUIPipeline() {
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.label = "UI";
|
pipelineInfo.label = "UI";
|
||||||
|
|
||||||
pipelineInfo.shaders.vertex_path = "ui.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("ui.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "ui.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("ui.frag");
|
||||||
|
|
||||||
pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip;
|
pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip;
|
||||||
|
|
||||||
|
@ -1026,8 +1034,8 @@ void Renderer::createBRDF() {
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.label = "BRDF";
|
pipelineInfo.label = "BRDF";
|
||||||
|
|
||||||
pipelineInfo.shaders.vertex_path = "brdf.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("brdf.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "brdf.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("brdf.frag");
|
||||||
|
|
||||||
pipelineInfo.render_pass = brdfRenderPass;
|
pipelineInfo.render_pass = brdfRenderPass;
|
||||||
|
|
||||||
|
@ -1100,3 +1108,64 @@ void Renderer::create_histogram_resources() {
|
||||||
|
|
||||||
average_luminance_texture = gfx->create_texture(texture_info);
|
average_luminance_texture = gfx->create_texture(texture_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShaderSource Renderer::register_shader(const std::string_view shader_file) {
|
||||||
|
if(!reloading_shader) {
|
||||||
|
RegisteredShader shader;
|
||||||
|
shader.filename = shader_file;
|
||||||
|
|
||||||
|
registered_shaders.push_back(shader);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string found_shader_source;
|
||||||
|
for(auto& shader : registered_shaders) {
|
||||||
|
if(shader.filename == shader_file) {
|
||||||
|
found_shader_source = shader.injected_shader_source;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file::Path base_shader_path = get_shader_source_directory();
|
||||||
|
|
||||||
|
// if shader editor system is not initialized, use prebuilt shaders
|
||||||
|
if(base_shader_path.empty())
|
||||||
|
return file::Path(shader_file);
|
||||||
|
|
||||||
|
shader_compiler.set_include_path(base_shader_path.string());
|
||||||
|
|
||||||
|
file::Path shader_path = file::Path(shader_file);
|
||||||
|
|
||||||
|
ShaderStage stage;
|
||||||
|
if(shader_path.extension() == ".vert")
|
||||||
|
stage = ShaderStage::Vertex;
|
||||||
|
else if(shader_path.extension() == ".frag")
|
||||||
|
stage = ShaderStage::Fragment;
|
||||||
|
|
||||||
|
if(found_shader_source.empty()) {
|
||||||
|
auto file = file::open(base_shader_path / shader_path.replace_extension(shader_path.extension().string() + ".glsl"));
|
||||||
|
|
||||||
|
return shader_compiler.compile(ShaderLanguage::GLSL, stage, file->read_as_string(), ShaderLanguage::MSL).value();
|
||||||
|
} else {
|
||||||
|
return shader_compiler.compile(ShaderLanguage::GLSL, stage, found_shader_source, ShaderLanguage::MSL).value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::associate_shader_reload(const std::string_view shader_file, const std::function<void()> reload_function) {
|
||||||
|
if(reloading_shader)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for(auto& shader : registered_shaders) {
|
||||||
|
if(shader.filename == shader_file)
|
||||||
|
shader.reload_function = reload_function;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::reload_shader(const std::string_view shader_file, const std::string_view shader_source) {
|
||||||
|
for(auto& shader : registered_shaders) {
|
||||||
|
if(shader.filename == shader_file) {
|
||||||
|
shader.injected_shader_source = shader_source;
|
||||||
|
reloading_shader = true;
|
||||||
|
shader.reload_function();
|
||||||
|
reloading_shader = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -399,8 +399,8 @@ void SceneCapture::createSkyResources() {
|
||||||
pipelineInfo.label = "Sky Scene Capture";
|
pipelineInfo.label = "Sky Scene Capture";
|
||||||
pipelineInfo.render_pass = renderPass;
|
pipelineInfo.render_pass = renderPass;
|
||||||
|
|
||||||
pipelineInfo.shaders.vertex_path = "sky.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("sky.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "sky.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("sky.frag");
|
||||||
|
|
||||||
pipelineInfo.shader_input.bindings = {
|
pipelineInfo.shader_input.bindings = {
|
||||||
{1, GFXBindingType::PushConstant}
|
{1, GFXBindingType::PushConstant}
|
||||||
|
@ -443,8 +443,8 @@ void SceneCapture::createIrradianceResources() {
|
||||||
|
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.label = "Irradiance Convolution";
|
pipelineInfo.label = "Irradiance Convolution";
|
||||||
pipelineInfo.shaders.vertex_path = "irradiance.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("irradiance.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "irradiance.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("irradiance.frag");
|
||||||
|
|
||||||
GFXVertexInput input;
|
GFXVertexInput input;
|
||||||
input.stride = sizeof(Vector3);
|
input.stride = sizeof(Vector3);
|
||||||
|
@ -495,8 +495,8 @@ void SceneCapture::createPrefilterResources() {
|
||||||
|
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.label = "Prefilter";
|
pipelineInfo.label = "Prefilter";
|
||||||
pipelineInfo.shaders.vertex_path = "filter.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("filter.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "filter.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("filter.frag");
|
||||||
|
|
||||||
pipelineInfo.shaders.fragment_constants = {size_constant};
|
pipelineInfo.shaders.fragment_constants = {size_constant};
|
||||||
|
|
||||||
|
|
|
@ -315,7 +315,7 @@ void ShadowPass::create_pipelines() {
|
||||||
|
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.shaders.vertex_constants = {point_light_max_constant};
|
pipelineInfo.shaders.vertex_constants = {point_light_max_constant};
|
||||||
pipelineInfo.shaders.vertex_path = "shadow.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("shadow.vert");
|
||||||
|
|
||||||
pipelineInfo.shaders.fragment_constants = { point_light_max_constant };
|
pipelineInfo.shaders.fragment_constants = { point_light_max_constant };
|
||||||
//pipelineInfo.shaders.fragment_path = "shadow.frag";
|
//pipelineInfo.shaders.fragment_path = "shadow.frag";
|
||||||
|
@ -360,7 +360,7 @@ void ShadowPass::create_pipelines() {
|
||||||
{
|
{
|
||||||
pipelineInfo.label = "Point Shadow";
|
pipelineInfo.label = "Point Shadow";
|
||||||
|
|
||||||
pipelineInfo.shaders.fragment_path = "omnishadow.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("omnishadow.frag");
|
||||||
|
|
||||||
auto [static_pipeline, skinned_pipeline] = material_compiler.create_pipeline_permutations(pipelineInfo, true);
|
auto [static_pipeline, skinned_pipeline] = material_compiler.create_pipeline_permutations(pipelineInfo, true);
|
||||||
|
|
||||||
|
|
|
@ -112,8 +112,8 @@ void SMAAPass::create_pipelines() {
|
||||||
|
|
||||||
GFXGraphicsPipelineCreateInfo createInfo = {};
|
GFXGraphicsPipelineCreateInfo createInfo = {};
|
||||||
createInfo.label = "SMAA Edge";
|
createInfo.label = "SMAA Edge";
|
||||||
createInfo.shaders.vertex_path = "edge.vert";
|
createInfo.shaders.vertex_src = file::Path("edge.vert");
|
||||||
createInfo.shaders.fragment_path = "edge.frag";
|
createInfo.shaders.fragment_src = file::Path("edge.frag");
|
||||||
|
|
||||||
createInfo.render_pass = render_pass;
|
createInfo.render_pass = render_pass;
|
||||||
|
|
||||||
|
@ -130,8 +130,8 @@ void SMAAPass::create_pipelines() {
|
||||||
edge_pipeline = gfx->create_graphics_pipeline(createInfo);
|
edge_pipeline = gfx->create_graphics_pipeline(createInfo);
|
||||||
|
|
||||||
createInfo.label = "SMAA Blend";
|
createInfo.label = "SMAA Blend";
|
||||||
createInfo.shaders.vertex_path = "blend.vert";
|
createInfo.shaders.vertex_src = file::Path("blend.vert");
|
||||||
createInfo.shaders.fragment_path = "blend.frag";
|
createInfo.shaders.fragment_src = file::Path("blend.frag");
|
||||||
createInfo.shader_input.bindings.push_back({3, GFXBindingType::Texture});
|
createInfo.shader_input.bindings.push_back({3, GFXBindingType::Texture});
|
||||||
|
|
||||||
blend_pipeline = gfx->create_graphics_pipeline(createInfo);
|
blend_pipeline = gfx->create_graphics_pipeline(createInfo);
|
||||||
|
|
|
@ -7,6 +7,8 @@ set(SRC
|
||||||
|
|
||||||
add_library(ShaderCompiler STATIC ${SRC})
|
add_library(ShaderCompiler STATIC ${SRC})
|
||||||
target_link_libraries(ShaderCompiler
|
target_link_libraries(ShaderCompiler
|
||||||
|
PUBLIC
|
||||||
|
Platform
|
||||||
PRIVATE
|
PRIVATE
|
||||||
Utility
|
Utility
|
||||||
Log
|
Log
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include "file.hpp"
|
||||||
|
|
||||||
/// The shader stage that the shader is written in.
|
/// The shader stage that the shader is written in.
|
||||||
enum class ShaderStage {
|
enum class ShaderStage {
|
||||||
Vertex,
|
Vertex,
|
||||||
|
@ -41,8 +43,14 @@ public:
|
||||||
ShaderSource(const ShaderSource& rhs) : source (rhs.source) {}
|
ShaderSource(const ShaderSource& rhs) : source (rhs.source) {}
|
||||||
ShaderSource(const std::string source_string) : source(source_string) {}
|
ShaderSource(const std::string source_string) : source(source_string) {}
|
||||||
ShaderSource(const std::vector<uint32_t> source_bytecode) : source(source_bytecode) {}
|
ShaderSource(const std::vector<uint32_t> source_bytecode) : source(source_bytecode) {}
|
||||||
|
ShaderSource(const file::Path shader_path) : source(shader_path) {}
|
||||||
std::variant<std::monostate, std::string, std::vector<uint32_t>> source;
|
|
||||||
|
std::variant<std::monostate, file::Path, std::string, std::vector<uint32_t>> source;
|
||||||
|
|
||||||
|
/// Returns a view of the shader source as a path.
|
||||||
|
file::Path as_path() const {
|
||||||
|
return std::get<file::Path>(source);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a view of the shader source as plaintext.
|
/// Returns a view of the shader source as plaintext.
|
||||||
std::string_view as_string() const {
|
std::string_view as_string() const {
|
||||||
|
@ -57,6 +65,14 @@ public:
|
||||||
bool empty() const {
|
bool empty() const {
|
||||||
return std::holds_alternative<std::monostate>(source);
|
return std::holds_alternative<std::monostate>(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_path() const {
|
||||||
|
return std::holds_alternative<file::Path>(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_string() const {
|
||||||
|
return std::holds_alternative<std::string>(source);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Compiles GLSL shaders to a specified shader language offline or at runtime.
|
/// Compiles GLSL shaders to a specified shader language offline or at runtime.
|
||||||
|
|
|
@ -9,14 +9,14 @@
|
||||||
#include "includer.hpp"
|
#include "includer.hpp"
|
||||||
#include "defaultresources.hpp"
|
#include "defaultresources.hpp"
|
||||||
|
|
||||||
static inline std::string include_path;
|
static inline std::vector<std::string> include_path;
|
||||||
|
|
||||||
ShaderCompiler::ShaderCompiler() {
|
ShaderCompiler::ShaderCompiler() {
|
||||||
glslang::InitializeProcess();
|
glslang::InitializeProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderCompiler::set_include_path(const std::string_view path) {
|
void ShaderCompiler::set_include_path(const std::string_view path) {
|
||||||
include_path = path;
|
include_path.push_back(path.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<uint32_t> compile_glsl_to_spv(const std::string_view source_string, const EShLanguage shader_language, const CompileOptions& options) {
|
const std::vector<uint32_t> compile_glsl_to_spv(const std::string_view source_string, const EShLanguage shader_language, const CompileOptions& options) {
|
||||||
|
@ -50,7 +50,8 @@ const std::vector<uint32_t> compile_glsl_to_spv(const std::string_view source_st
|
||||||
EShMessages messages = (EShMessages) (EShMsgDefault);
|
EShMessages messages = (EShMessages) (EShMsgDefault);
|
||||||
|
|
||||||
DirStackFileIncluder includer;
|
DirStackFileIncluder includer;
|
||||||
includer.pushExternalLocalDirectory(include_path);
|
for(auto path : include_path)
|
||||||
|
includer.pushExternalLocalDirectory(path);
|
||||||
|
|
||||||
if (!Shader.parse(&Resources, 100, false, messages, includer)) {
|
if (!Shader.parse(&Resources, 100, false, messages, includer)) {
|
||||||
console::error(System::Renderer, "{}", Shader.getInfoLog());
|
console::error(System::Renderer, "{}", Shader.getInfoLog());
|
||||||
|
|
|
@ -21,8 +21,8 @@ void DebugPass::initialize() {
|
||||||
|
|
||||||
{
|
{
|
||||||
GFXGraphicsPipelineCreateInfo createInfo;
|
GFXGraphicsPipelineCreateInfo createInfo;
|
||||||
createInfo.shaders.vertex_path = "debug.vert";
|
createInfo.shaders.vertex_src = file::Path("debug.vert");
|
||||||
createInfo.shaders.fragment_path = "debug.frag";
|
createInfo.shaders.fragment_src = file::Path("debug.frag");
|
||||||
|
|
||||||
GFXVertexInput vertexInput = {};
|
GFXVertexInput vertexInput = {};
|
||||||
vertexInput.stride = sizeof(Vector3);
|
vertexInput.stride = sizeof(Vector3);
|
||||||
|
@ -69,8 +69,8 @@ void DebugPass::initialize() {
|
||||||
// pipeline
|
// pipeline
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
|
|
||||||
pipelineInfo.shaders.vertex_path = "color.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("color.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "color.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("color.frag");
|
||||||
|
|
||||||
GFXVertexInput input;
|
GFXVertexInput input;
|
||||||
input.stride = sizeof(Vector3);
|
input.stride = sizeof(Vector3);
|
||||||
|
@ -110,8 +110,8 @@ void DebugPass::initialize() {
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.label = "Sobel";
|
pipelineInfo.label = "Sobel";
|
||||||
|
|
||||||
pipelineInfo.shaders.vertex_path = "color.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("color.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "color.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("color.frag");
|
||||||
|
|
||||||
GFXVertexInput input;
|
GFXVertexInput input;
|
||||||
input.stride = sizeof(Vector3);
|
input.stride = sizeof(Vector3);
|
||||||
|
@ -142,8 +142,8 @@ void DebugPass::initialize() {
|
||||||
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
||||||
pipelineInfo.label = "Billboard";
|
pipelineInfo.label = "Billboard";
|
||||||
|
|
||||||
pipelineInfo.shaders.vertex_path = "billboard.vert";
|
pipelineInfo.shaders.vertex_src = file::Path("billboard.vert");
|
||||||
pipelineInfo.shaders.fragment_path = "billboard.frag";
|
pipelineInfo.shaders.fragment_src = file::Path("billboard.frag");
|
||||||
|
|
||||||
pipelineInfo.shader_input.bindings = {
|
pipelineInfo.shader_input.bindings = {
|
||||||
{1, GFXBindingType::PushConstant},
|
{1, GFXBindingType::PushConstant},
|
||||||
|
|
Reference in a new issue