diff --git a/.gitmodules b/.gitmodules index cd98acb..494af93 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,6 @@ [submodule "third_party/spdlog"] path = third_party/spdlog url = https://github.com/gabime/spdlog.git +[submodule "third_party/glslang"] + path = third_party/glslang + url = https://github.com/KhronosGroup/glslang.git diff --git a/CMakeLists.txt b/CMakeLists.txt index abbdbd5..089a3b1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,6 +63,7 @@ add_subdirectory(third_party/portaudio) add_subdirectory(third_party/spdlog) add_subdirectory(third_party/slang) add_subdirectory(third_party/glad) +add_subdirectory(third_party/glslang) # setup portaudio set(PA_USE_ASIO ON CACHE BOOL "" FORCE) @@ -140,5 +141,8 @@ set(SPDLOG_WCHAR_SUPPORT ON CACHE BOOL "" FORCE) set(SPDLOG_ENABLE_PCH ON CACHE BOOL "" FORCE) set(SPDLOG_USE_STD_FORMAT OFF CACHE BOOL "" FORCE) +# setup glslang +set(ENABLE_OPT OFF CACHE BOOL "" FORCE) + # install install(DIRECTORY ${CMAKE_SOURCE_DIR}/third_party/imgui/imgui/misc/fonts DESTINATION ${CMAKE_BINARY_DIR}/bin) diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 939cb00..e64a099 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -8,10 +8,10 @@ retrieve_files(ALL_FILES) add_library(${PROJECT_NAME} SHARED ${ALL_FILES}) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} spdlog imgui slang glad) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} spdlog imgui slang glad glslang) -target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} spdlog imgui glad) -target_link_libraries(${PROJECT_NAME} PUBLIC imgui spdlog ${SDL2_LIBRARIES} slang glad) +target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} spdlog imgui glad glslang) +target_link_libraries(${PROJECT_NAME} PUBLIC imgui spdlog ${SDL2_LIBRARIES} slang glad glslang) target_precompile_headers(${PROJECT_NAME} PUBLIC extern.h) diff --git a/core/application/application.cpp b/core/application/application.cpp index b163372..15f61fa 100644 --- a/core/application/application.cpp +++ b/core/application/application.cpp @@ -19,21 +19,16 @@ bool g_is_running = true; bool g_exit_requested = false; -slang::IGlobalSession* g_slang_global_session = nullptr; +Slang::ComPtr<slang::IGlobalSession> g_slang_global_session = nullptr; application* g_app_instance = nullptr; -application::~application() -{ - application::shutdown(); -} - void application::init(window_params in_window_params, int argc, char** argv) { - slang::createGlobalSession(&g_slang_global_session); + slang::createGlobalSession(g_slang_global_session.writeRef()); try { - auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/log.txt"); + async_spdlog_ = spdlog::basic_logger_mt<spdlog::async_factory>("async_file_logger", "logs/log.txt"); } catch (const spdlog::spdlog_ex &ex) { @@ -208,15 +203,28 @@ int application::run() draw_gui(); renderer_->end_frame(window_); } + + shutdown(); return 0; } void application::shutdown() { + init_imgui(nullptr); renderer_->shutdown(); ImGui::DestroyContext(); + SDL_HideWindow(window_); + SDL_DestroyWindow(window_); + window_ = nullptr; + + renderer_->post_shutdown(); + delete renderer_; + renderer_ = nullptr; + + + SDL_Quit(); } std::shared_ptr<texture> application::load_texture(const std::string& path) const diff --git a/core/application/application.h b/core/application/application.h index 5378ff4..813cab7 100644 --- a/core/application/application.h +++ b/core/application/application.h @@ -2,6 +2,7 @@ #include <string> #include "SDL.h" #include "imgui.h" +#include "slang-com-ptr.h" #include "slang.h" class render_target; @@ -11,7 +12,7 @@ class application; extern bool g_is_running; extern bool g_exit_requested; -extern slang::IGlobalSession* g_slang_global_session; +extern Slang::ComPtr<slang::IGlobalSession>g_slang_global_session; extern application* g_app_instance; struct window_params @@ -35,7 +36,7 @@ public: { g_app_instance = this; } - virtual ~application(); + virtual ~application() = default; application(const application&) = delete; application(application&&) = delete; static application* get() @@ -60,4 +61,5 @@ public: protected: renderer* renderer_ = nullptr; SDL_Window* window_ = nullptr; + std::shared_ptr<spdlog::logger> async_spdlog_; }; diff --git a/core/misc/likely.h b/core/misc/likely.h new file mode 100644 index 0000000..86ee836 --- /dev/null +++ b/core/misc/likely.h @@ -0,0 +1,21 @@ +#pragma once + + +/** Branch prediction hints */ +#ifndef LIKELY /* Hints compiler that expression is likely to be true, much softer than UE_ASSUME - allows (penalized by worse performance) expression to be false */ + #if ( defined(__clang__) || defined(__GNUC__) ) && defined(PLATFORM_UNIX) // effect of these on non-Linux platform has not been analyzed as of 2016-03-21 + #define LIKELY(x) __builtin_expect(!!(x), 1) + #else + // the additional "!!" is added to silence "warning: equality comparison with exteraneous parenthese" messages on android + #define LIKELY(x) (!!(x)) + #endif +#endif + +#ifndef UNLIKELY /* Hints compiler that expression is unlikely to be true, allows (penalized by worse performance) expression to be true */ + #if ( defined(__clang__) || defined(__GNUC__) ) && defined(PLATFORM_UNIX) // effect of these on non-Linux platform has not been analyzed as of 2016-03-21 + #define UNLIKELY(x) __builtin_expect(!!(x), 0) + #else + // the additional "!!" is added to silence "warning: equality comparison with exteraneous parenthese" messages on android + #define UNLIKELY(x) (!!(x)) + #endif +#endif \ No newline at end of file diff --git a/core/rhi/opengl/opengl_def.h b/core/rhi/opengl/opengl_def.h index 3752cb4..63a030e 100644 --- a/core/rhi/opengl/opengl_def.h +++ b/core/rhi/opengl/opengl_def.h @@ -6,25 +6,3 @@ if (Error != 0)\ spdlog::critical("GL error: 0x{:x}", Error);\ } - -struct im_gui_impl_open_gl3_data -{ - GLuint GlVersion; // Extracted at runtime using GL_MAJOR_VERSION, GL_MINOR_VERSION queries (e.g. 320 for GL 3.2) - char GlslVersionString[32]; // Specified by user or detected based on compile time GL settings. - bool GlProfileIsES2; - bool GlProfileIsES3; - bool GlProfileIsCompat; - GLint GlProfileMask; - GLuint FontTexture; - GLuint ShaderHandle; - GLint AttribLocationTex; // Uniforms location - GLint AttribLocationProjMtx; - GLuint AttribLocationVtxPos; // Vertex attributes location - GLuint AttribLocationVtxUV; - GLuint AttribLocationVtxColor; - unsigned int VboHandle, ElementsHandle; - GLsizeiptr VertexBufferSize; - GLsizeiptr IndexBufferSize; - bool HasClipOrigin; - bool UseBufferSubData; -}; diff --git a/core/rhi/opengl/render_target_opengl.cpp b/core/rhi/opengl/render_target_opengl.cpp index 10738d7..1c3d491 100644 --- a/core/rhi/opengl/render_target_opengl.cpp +++ b/core/rhi/opengl/render_target_opengl.cpp @@ -2,11 +2,84 @@ #include "opengl_def.h" +GLint to_internal_format(texture_format format) +{ + switch (format) + { + case texture_format::RGBA8: + return GL_RGBA8; + case texture_format::RGBA16_FLOAT: + return GL_RGBA16F; + case texture_format::RGBA32_FLOAT: + return GL_RGBA32F; + case texture_format::R32_FLOAT: + return GL_R32F; + case texture_format::RG32_FLOAT: + return GL_RG32F; + case texture_format::R11F_G11F_B10F: + return GL_R11F_G11F_B10F; + case texture_format::R16_FLOAT: + return GL_R16F; + case texture_format::RGBA16: + return GL_RGBA16; + case texture_format::RGB10_A2: + return GL_RGB10_A2; + case texture_format::RG16: + return GL_RG16; + case texture_format::RG8: + return GL_RG8; + case texture_format::R16: + return GL_R16; + case texture_format::R8: + return GL_R8; + case texture_format::RG16_SNORM: + return GL_RG16_SNORM; + case texture_format::RG8_SNORM: + return GL_RG8_SNORM; + case texture_format::R16_SNORM: + return GL_R16_SNORM; + case texture_format::R8_SNORM: + return GL_R8_SNORM; + case texture_format::R32I: + return GL_R32I; + case texture_format::R32UI: + return GL_R32UI; + case texture_format::R8I: + return GL_R8I; + case texture_format::R16I: + return GL_R16I; + case texture_format::R32F: + return GL_R32F; + case texture_format::R8UI: + return GL_R8UI; + case texture_format::R16UI: + return GL_R16UI; + case texture_format::RG32I: + return GL_RG32I; + case texture_format::RG32UI: + return GL_RG32UI; + case texture_format::RG8I: + return GL_RG8I; + case texture_format::RG16I: + return GL_RG16I; + case texture_format::RGB10_A2UI: + return GL_RGB10_A2UI; + case texture_format::RG16UI: + return GL_RG16UI; + default: + return GL_RGBA8; + } + return 0; +} + void render_target_opengl::init(int width, int height, texture_format format) { + width_ = width; + height_ = height; + glGenFramebuffers(1, &fbo_); CHECK_GL_ERRORS - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_); + glBindFramebuffer(GL_FRAMEBUFFER, fbo_); CHECK_GL_ERRORS #if defined(__APPLE__) @@ -21,17 +94,27 @@ LockGLContext([NSOpenGLContext currentContext]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + internal_format_ = to_internal_format(format); + glTexImage2D(GL_TEXTURE_2D, 0, internal_format_, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); CHECK_GL_ERRORS + + glBindFramebuffer(GL_FRAMEBUFFER, fbo_); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0); + + CHECK_GL_ERRORS + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + #if defined(__APPLE__) UnlockGLContext([NSOpenGLContext currentContext]); #endif - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0); - CHECK_GL_ERRORS +} - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +render_target_opengl::~render_target_opengl() +{ + glDeleteFramebuffers(1, &fbo_); + glDeleteTextures(1, &texture_); } void* render_target_opengl::lock(lock_state state) @@ -79,16 +162,32 @@ void render_target_opengl::on_resize(int width, int height) width_ = width; height_ = height; glDeleteTextures(1, &texture_); + glDeleteFramebuffers(1, &fbo_); + texture_ = 0; + fbo_ = 0; #if defined(__APPLE__) LockGLContext([NSOpenGLContext currentContext]); #endif - + glGenTextures(1, &texture_); + CHECK_GL_ERRORS + glBindTexture(GL_TEXTURE_2D, texture_); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width_, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); + CHECK_GL_ERRORS + + glGenFramebuffers(1, &fbo_); + glBindFramebuffer(GL_FRAMEBUFFER, fbo_); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture_, 0); + + CHECK_GL_ERRORS + + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); #if defined(__APPLE__) UnlockGLContext([NSOpenGLContext currentContext]); diff --git a/core/rhi/opengl/render_target_opengl.h b/core/rhi/opengl/render_target_opengl.h index 9a95ad7..63400b9 100644 --- a/core/rhi/opengl/render_target_opengl.h +++ b/core/rhi/opengl/render_target_opengl.h @@ -6,10 +6,14 @@ class render_target_opengl : public render_target { public: - - void init(int width, int height, texture_format format) override; - ImTextureID get_texture_id() override { return (void*)static_cast<intptr_t>(fbo_); } + ~render_target_opengl() override; + + ImTextureID get_texture_id() override { return (void*)static_cast<intptr_t>(texture_); } + [[nodiscard]] GLuint get_fbo() const { return fbo_; } + [[nodiscard]] GLuint get_texture() const { return texture_; } + [[nodiscard]] GLint get_internal_format() const { return internal_format_; } + void* lock(lock_state state) override; void unlock() override; protected: @@ -17,5 +21,6 @@ protected: private: GLuint fbo_ = 0; GLuint texture_ = 0; + GLint internal_format_ = 0; void* locked_texture_ = nullptr; }; diff --git a/core/rhi/opengl/renderer_opengl.cpp b/core/rhi/opengl/renderer_opengl.cpp index e3b7c15..771c0de 100644 --- a/core/rhi/opengl/renderer_opengl.cpp +++ b/core/rhi/opengl/renderer_opengl.cpp @@ -62,13 +62,19 @@ bool renderer_opengl::init(SDL_Window* window_handle) void renderer_opengl::shutdown() { + renderer::shutdown(); ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplSDL3_Shutdown(); - - SDL_GL_DeleteContext(g_gl_context); } -Slang::ComPtr<slang::ISession> renderer_opengl::create_slang_session(const std::string& shader_path) +void renderer_opengl::post_shutdown() +{ + SDL_GL_DeleteContext(g_gl_context); + g_gl_context = nullptr; + renderer::post_shutdown(); +} + +void renderer_opengl::create_slang_session(const std::string& shader_path, slang::ISession** out_session) { slang::TargetDesc target_desc; target_desc.format = SLANG_GLSL; @@ -80,10 +86,9 @@ Slang::ComPtr<slang::ISession> renderer_opengl::create_slang_session(const std:: session_desc.searchPathCount = 1; session_desc.targets = &target_desc; session_desc.targetCount = 1; + session_desc.defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_COLUMN_MAJOR; // in OpenGL, matrices are row-major by default - Slang::ComPtr<slang::ISession> out; - g_slang_global_session->createSession(session_desc, out.writeRef()); - return out; + g_slang_global_session->createSession(session_desc, out_session); } std::shared_ptr<shader> renderer_opengl::load_shader(const std::string& entry_name) diff --git a/core/rhi/opengl/renderer_opengl.h b/core/rhi/opengl/renderer_opengl.h index 047772a..f2aeaa1 100644 --- a/core/rhi/opengl/renderer_opengl.h +++ b/core/rhi/opengl/renderer_opengl.h @@ -8,8 +8,9 @@ public: void pre_init() override; bool init(SDL_Window* window_handle) override; void shutdown() override; + void post_shutdown() override; - Slang::ComPtr<slang::ISession> create_slang_session(const std::string& shader_path) override; + void create_slang_session(const std::string& shader_path, slang::ISession** out_session) override; std::shared_ptr<shader> load_shader(const std::string& entry_name) override; void new_frame(SDL_Window* window_handle) override; diff --git a/core/rhi/opengl/shader/shader_cs_opengl.cpp b/core/rhi/opengl/shader/shader_cs_opengl.cpp index 4147239..68034b9 100644 --- a/core/rhi/opengl/shader/shader_cs_opengl.cpp +++ b/core/rhi/opengl/shader/shader_cs_opengl.cpp @@ -1 +1,26 @@ #include "shader_cs_opengl.h" + +#include "shader_program_opengl.h" + + +shader_cs_opengl::shader_cs_opengl(const std::shared_ptr<slang_handle>& handle): shader_opengl(handle) +{ + +} + +bool shader_cs_opengl::init() +{ + if (!shader_opengl::init()) + return false; + program_ = std::make_shared<shader_program_opengl>(); + std::shared_ptr<shader_opengl> in_compute_shader = std::static_pointer_cast<shader_opengl>(shared_from_this()); + program_->create_program(in_compute_shader); + return true; +} + +void shader_cs_opengl::compute(int x, int y, int z) +{ + program_->use_program(); + glDispatchCompute(x, y, z); + program_->unuse_program(); +} diff --git a/core/rhi/opengl/shader/shader_cs_opengl.h b/core/rhi/opengl/shader/shader_cs_opengl.h index 93b0ec7..0bb4b21 100644 --- a/core/rhi/opengl/shader/shader_cs_opengl.h +++ b/core/rhi/opengl/shader/shader_cs_opengl.h @@ -1,10 +1,14 @@ #pragma once #include "shader_opengl.h" -#include "rhi/opengl/opengl_def.h" class shader_cs_opengl : public shader_opengl { public: - shader_cs_opengl(const std::shared_ptr<slang_handle>& handle) : shader_opengl(handle) {} - GLenum get_shader_type() const override { return GL_COMPUTE_SHADER; } + explicit shader_cs_opengl(const std::shared_ptr<slang_handle>& handle); + bool init() override; + [[nodiscard]] GLenum get_shader_type() const override { return GL_COMPUTE_SHADER; } + + void compute(int x, int y, int z) override; +private: + std::shared_ptr<shader_program_opengl> program_; }; diff --git a/core/rhi/opengl/shader/shader_gs_opengl.h b/core/rhi/opengl/shader/shader_gs_opengl.h index a3110bc..8278b07 100644 --- a/core/rhi/opengl/shader/shader_gs_opengl.h +++ b/core/rhi/opengl/shader/shader_gs_opengl.h @@ -7,5 +7,5 @@ class shader_gs_opengl : public shader_opengl public: shader_gs_opengl(const std::shared_ptr<slang_handle>& handle) : shader_opengl(handle) {} - GLenum get_shader_type() const override { return GL_GEOMETRY_SHADER; } + [[nodiscard]] GLenum get_shader_type() const override { return GL_GEOMETRY_SHADER; } }; diff --git a/core/rhi/opengl/shader/shader_opengl.cpp b/core/rhi/opengl/shader/shader_opengl.cpp index 0b5dee7..c59b746 100644 --- a/core/rhi/opengl/shader/shader_opengl.cpp +++ b/core/rhi/opengl/shader/shader_opengl.cpp @@ -1,8 +1,204 @@ #include "shader_opengl.h" -#include "imgui.h" +#include "shader_program_opengl.h" #include "rhi/slang_handle.h" -#include "rhi/opengl/opengl_def.h" + +#include "glslang/Include/intermediate.h" +#include "glslang/MachineIndependent/localintermediate.h" +#include "glslang/Public/ShaderLang.h" + +#include <string> + +GLint to_internal_format(glslang::TLayoutFormat format) +{ + switch (format) + { + case glslang::TLayoutFormat::ElfR32f: + return GL_R32F; + case glslang::TLayoutFormat::ElfRg32f: + return GL_RG32F; + case glslang::TLayoutFormat::ElfRgba32f: + return GL_RGBA32F; + case glslang::TLayoutFormat::ElfRgba8: + return GL_RGBA8; + case glslang::TLayoutFormat::ElfRgba16f: + return GL_RGBA16F; + case glslang::TLayoutFormat::ElfRgba32i: + return GL_RGBA32I; + case glslang::TLayoutFormat::ElfRgba32ui: + return GL_RGBA32UI; + case glslang::TLayoutFormat::ElfRgba8i: + return GL_RGBA8I; + case glslang::TLayoutFormat::ElfRgba8ui: + return GL_RGBA8UI; + case glslang::TLayoutFormat::ElfRgba16i: + return GL_RGBA16I; + case glslang::TLayoutFormat::ElfRgba16ui: + return GL_RGBA16UI; + case glslang::TLayoutFormat::ElfRgba8Snorm: + return GL_RGBA8_SNORM; + case glslang::TLayoutFormat::ElfRgba16Snorm: + return GL_RGBA16_SNORM; + case glslang::ElfEsFloatGuard: + return GL_R32F; + case glslang::ElfRg16f: + return GL_RG16F; + case glslang::ElfR11fG11fB10f: + return GL_R11F_G11F_B10F; + case glslang::ElfR16f: + return GL_R16F; + case glslang::ElfRgba16: + return GL_RGBA16; + case glslang::ElfRgb10A2: + return GL_RGB10_A2; + case glslang::ElfRg16: + return GL_RG16; + case glslang::ElfRg8: + return GL_RG8; + case glslang::ElfR16: + return GL_R16; + case glslang::ElfR8: + return GL_R8; + case glslang::ElfRg16Snorm: + return GL_RG16_SNORM; + case glslang::ElfRg8Snorm: + return GL_RG8_SNORM; + case glslang::ElfR16Snorm: + return GL_R16_SNORM; + case glslang::ElfR8Snorm: + return GL_R8_SNORM; + case glslang::ElfFloatGuard: + return GL_R32F; + case glslang::ElfR32i: + return GL_R32I; + case glslang::ElfEsIntGuard: + return GL_R32I; + case glslang::ElfRg32i: + return GL_RG32I; + case glslang::ElfRg16i: + return GL_RG16I; + case glslang::ElfRg8i: + return GL_RG8I; + case glslang::ElfR16i: + return GL_R16I; + case glslang::ElfR8i: + return GL_R8I; + case glslang::ElfIntGuard: + return GL_R32I; + case glslang::ElfR32ui: + return GL_R32UI; + case glslang::ElfEsUintGuard: + return GL_R32UI; + case glslang::ElfRg32ui: + return GL_RG32UI; + case glslang::ElfRg16ui: + return GL_RG16UI; + case glslang::ElfRgb10a2ui: + return GL_RGB10_A2UI; + case glslang::ElfRg8ui: + return GL_RG8UI; + case glslang::ElfR16ui: + return GL_R16UI; + case glslang::ElfR8ui: + return GL_R8UI; + } + return 0; +} + +// return uniform map +void opengl_get_refletion_data(const std::string& src, std::map<std::string, opengl_uniform_data>& out_uniform, std::map<std::string, opengl_texture_data>& out_texture) +{ + glslang::InitializeProcess(); + { + const char* const sources[] = { src.c_str() }; + const int source_lengths[] = {static_cast<int>(src.size())}; + const char* source_names[] = {""}; + const int sources_num = 1; + const auto shader_stage = EShLanguage::EShLangCompute; + + glslang::TShader shader { shader_stage }; + shader.setStringsWithLengthsAndNames(sources, source_lengths, source_names, sources_num); + shader.setEnvClient(glslang::EShClientOpenGL, glslang::EShTargetOpenGL_450); + shader.setEnvTarget(glslang::EShTargetSpv, glslang::EShTargetSpv_1_0); + + TBuiltInResource default_builtin_resources{}; + shader.parse(&default_builtin_resources, 450, ECoreProfile, false, true, EShMsgDefault); + + class RefrectionTraverser : public glslang::TIntermTraverser + { + public: + std::map<std::string, opengl_uniform_data> uniform_map; + std::map<std::string, opengl_texture_data> texture_map; + + virtual void visitSymbol(glslang::TIntermSymbol* symbol) override + { + if (symbol->getQualifier().isUniformOrBuffer()) + { + auto t_name = symbol->getName(); + std::string name = t_name.c_str(); + auto basic_type = symbol->getBasicType(); + const glslang::TType& type = symbol->getType(); + if (basic_type == glslang::EbtSampler) + { + auto qualifier = symbol->getQualifier(); + opengl_texture_data data; + data.sampler_name = name; + + if (qualifier.hasBinding()) + { + data.binding = qualifier.layoutBinding; + } + if (qualifier.hasFormat()) + { + data.format = to_internal_format(qualifier.layoutFormat); + } + + const size_t& clean_name_index = name.find('_'); + std::string clean_name = name.substr(0, clean_name_index); + + texture_map.insert(std::pair(clean_name, data)); + } + else + { + auto qualifier = symbol->getQualifier(); + + opengl_uniform_data data; + data.name = name; + data.type_name = type.getTypeName(); + + if (qualifier.hasLocation()) + { + data.location = qualifier.layoutLocation; + } + if (qualifier.hasBinding()) + { + data.binding = qualifier.layoutBinding; + } + if (qualifier.hasFormat()) + { + data.format = to_internal_format(qualifier.layoutFormat); + } + + const size_t& clean_name_index = name.find('_'); + std::string clean_name = name.substr(0, clean_name_index); + + uniform_map.insert(std::pair(clean_name, data)); + } + } + } + }; + + RefrectionTraverser traverser; + + auto root = shader.getIntermediate()->getTreeRoot(); + root->traverse(&traverser); + + out_uniform = traverser.uniform_map; + out_texture = traverser.texture_map; + } + + glslang::FinalizeProcess(); +} bool shader_opengl::init() { @@ -17,6 +213,8 @@ bool shader_opengl::init() const GLint code_size = static_cast<GLint>(code_blob->getBufferSize()); glShaderSource(shader_id_, 1, &code_array, &code_size); + opengl_get_refletion_data(code_array, uniform_map_, texture_map_); // slow + glCompileShader(shader_id_); GLint compile_status = GL_FALSE; glGetShaderiv(shader_id_, GL_COMPILE_STATUS, &compile_status); @@ -32,18 +230,39 @@ bool shader_opengl::init() shader_id_ = 0; return false; } - return true; } -void shader_opengl::bind() +void shader_opengl::set_using_program(std::shared_ptr<shader_program_opengl> in_program) { - glUseProgram(shader_id_); + if (using_program_.lock()) + { + spdlog::error("Shader is already used by another program"); + return; + } + using_program_ = in_program; } -void shader_opengl::unbind() +void shader_opengl::set_cbuffer(const char* name, void* buffer, int size) { - const ImGuiIO& io = ImGui::GetIO(); - const auto open_gl3_data = static_cast<im_gui_impl_open_gl3_data*>(io.BackendRendererUserData); - glUseProgram(open_gl3_data->ShaderHandle); + if (const auto program = using_program_.lock()) + program->set_uniform(name, buffer, size); +} + +void shader_opengl::set_uav_buffer(const char* name, void* buffer, int size, int element_size) +{ + if (const auto program = using_program_.lock()) + program->set_ssbo(name, buffer, size, element_size); +} + +void shader_opengl::set_render_target(const char* name, std::shared_ptr<render_target> in_render_target) +{ + if (const auto program = using_program_.lock()) + program->set_render_target(name, in_render_target); +} + +void shader_opengl::set_texture(const char* name, std::shared_ptr<texture> in_texture) +{ + if (const auto program = using_program_.lock()) + program->set_texture(name, in_texture); } diff --git a/core/rhi/opengl/shader/shader_opengl.h b/core/rhi/opengl/shader/shader_opengl.h index 3d64e22..72c54f4 100644 --- a/core/rhi/opengl/shader/shader_opengl.h +++ b/core/rhi/opengl/shader/shader_opengl.h @@ -1,21 +1,55 @@ #pragma once +#include <map> + +#include "slang.h" #include "rhi/shader.h" +class shader_program_opengl; + +struct opengl_uniform_data +{ + std::string type_name; + std::string name; + GLuint location = 0; + GLuint binding = 0; + GLint format = 0; +}; + +struct opengl_texture_data +{ + std::string sampler_name; + GLuint binding = 0; + GLint format = 0; +}; + class shader_opengl : public shader { public: - shader_opengl(const std::shared_ptr<slang_handle>& handle) : shader(handle) {} - + explicit shader_opengl(const std::shared_ptr<slang_handle>& handle) : shader(handle), shader_id_(0) + { + } + bool init() override; [[nodiscard]] bool is_initialized() const override { return shader_id_ != 0; } - void bind() override; - void unbind() override; + + void bind() override {} + void unbind() override {} - void set_constant_buffer(const char* name, void* buffer, int size) override {} - void set_render_target(const char* name, std::shared_ptr<render_target> in_render_target) override {} - void set_texture(const char* name, std::shared_ptr<texture> in_texture) override {} + void set_using_program(std::shared_ptr<shader_program_opengl> in_program); + void set_cbuffer(const char* name, void* buffer, int size) override; + void set_uav_buffer(const char* name, void* buffer, int size, int element_size) override; + void set_render_target(const char* name, std::shared_ptr<render_target> in_render_target) override; + void set_texture(const char* name, std::shared_ptr<texture> in_texture) override; + [[nodiscard]] virtual GLenum get_shader_type() const = 0; + [[nodiscard]] GLuint get_shader_id() const { return shader_id_; } + + [[nodiscard]] const std::map<std::string, opengl_uniform_data>& get_uniform_map() const { return uniform_map_; } + [[nodiscard]] const std::map<std::string, opengl_texture_data>& get_texture_map() const { return texture_map_; } protected: GLuint shader_id_; + std::weak_ptr<shader_program_opengl> using_program_; + std::map<std::string, opengl_uniform_data> uniform_map_; + std::map<std::string, opengl_texture_data> texture_map_; }; diff --git a/core/rhi/opengl/shader/shader_program_opengl.cpp b/core/rhi/opengl/shader/shader_program_opengl.cpp new file mode 100644 index 0000000..cfb713d --- /dev/null +++ b/core/rhi/opengl/shader/shader_program_opengl.cpp @@ -0,0 +1,214 @@ +#include "shader_program_opengl.h" + +#include <ranges> + +#include "shader_opengl.h" +#include "rhi/slang_handle.h" +#include "rhi/opengl/render_target_opengl.h" +#include "rhi/opengl/texture_opengl.h" + +bool shader_program_opengl::create_program(std::shared_ptr<shader_opengl> in_pixel_shader, std::shared_ptr<shader_opengl> in_vertex_shader) +{ + if (program_id_) + { + destroy_program(); + } + if (!in_pixel_shader || !in_pixel_shader->is_initialized()) + { + spdlog::error("Pixel shader is not initialized"); + return false; + } + if (!in_vertex_shader || !in_vertex_shader->is_initialized()) + { + spdlog::error("Vertex shader is not initialized"); + return false; + } + const GLuint pixel_id = in_pixel_shader->get_shader_id(); + const GLuint vertex_id = in_vertex_shader->get_shader_id(); + + program_id_ = glCreateProgram(); + if (program_id_ == 0) + { + spdlog::error("Failed to create program"); + return false; + } + + glAttachShader(program_id_, vertex_id); + glAttachShader(program_id_, pixel_id); + + glLinkProgram(program_id_); + GLint link_status = GL_FALSE; + glGetProgramiv(program_id_, GL_LINK_STATUS, &link_status); + if (link_status == GL_FALSE) + { + GLint log_length = 0; + glGetProgramiv(program_id_, GL_INFO_LOG_LENGTH, &log_length); + std::vector<GLchar> log(log_length); + glGetProgramInfoLog(program_id_, log_length, nullptr, log.data()); + spdlog::error("Failed to link program: {}", log.data()); + + glDeleteProgram(program_id_); + program_id_ = 0; + return false; + } + + glDetachShader(program_id_, vertex_id); + glDetachShader(program_id_, pixel_id); + + pixel_shader_ = in_pixel_shader; + vertex_shader_ = in_vertex_shader; + in_pixel_shader->set_using_program(shared_from_this()); + in_vertex_shader->set_using_program(shared_from_this()); + + uniform_map_.clear(); + texture_map_.clear(); + update_param_map(in_pixel_shader); + update_param_map(in_vertex_shader); + return true; +} + +bool shader_program_opengl::create_program(std::shared_ptr<shader_opengl> in_compute_shader) +{ + if (program_id_) + { + destroy_program(); + } + if (!in_compute_shader || !in_compute_shader->is_initialized()) + { + spdlog::error("Compute shader is not initialized"); + return false; + } + const GLuint compute_id = in_compute_shader->get_shader_id(); + + program_id_ = glCreateProgram(); + if (program_id_ == 0) + { + spdlog::error("Failed to create program"); + return false; + } + + glAttachShader(program_id_, compute_id); + + glLinkProgram(program_id_); + GLint link_status = GL_FALSE; + glGetProgramiv(program_id_, GL_LINK_STATUS, &link_status); + if (link_status == GL_FALSE) + { + GLint log_length = 0; + glGetProgramiv(program_id_, GL_INFO_LOG_LENGTH, &log_length); + std::vector<GLchar> log(log_length); + glGetProgramInfoLog(program_id_, log_length, nullptr, log.data()); + spdlog::error("Failed to link program: {}", log.data()); + + glDeleteProgram(program_id_); + program_id_ = 0; + return false; + } + + glDetachShader(program_id_, compute_id); + compute_shader_ = in_compute_shader; + in_compute_shader->set_using_program(shared_from_this()); + + uniform_map_.clear(); + texture_map_.clear(); + update_param_map(in_compute_shader); + return true; +} + +void shader_program_opengl::destroy_program() +{ + for (const auto& val : ubo_map_ | std::views::values) + glDeleteBuffers(1, &val); + + if (const auto shader = pixel_shader_.lock()) + shader->set_using_program(nullptr); + if (const auto shader = vertex_shader_.lock()) + shader->set_using_program(nullptr); + if (const auto shader = compute_shader_.lock()) + shader->set_using_program(nullptr); + if (!program_id_) + return; + glDeleteProgram(program_id_); + program_id_ = 0; + ubo_map_.clear(); + uniform_map_.clear(); + texture_map_.clear(); +} + +void shader_program_opengl::set_uniform(const char* slang_name, void* buffer, int size) +{ + const auto& uniform_name = uniform_map_.find(slang_name); + if (uniform_name == uniform_map_.end()) + return; + + const auto& uniform_data = uniform_name->second; + GLuint using_bind_point = uniform_data.binding; + const auto find_ubo = ubo_map_.find(using_bind_point); + if (find_ubo != ubo_map_.end()) + { + glBindBuffer(GL_UNIFORM_BUFFER, find_ubo->second); + glBufferSubData(GL_UNIFORM_BUFFER, 0, size, buffer); + return; + } + + const GLint block_index = glGetUniformBlockIndex(program_id_, uniform_data.type_name.c_str()); + glUniformBlockBinding(program_id_, block_index, uniform_data.binding); + + // Create a buffer and copy the projection matrix to it. + GLuint ubo = 0; + glGenBuffers(1, &ubo); + + glBindBuffer(GL_UNIFORM_BUFFER, ubo); + glBufferData(GL_UNIFORM_BUFFER, size, buffer, GL_STATIC_DRAW); + + glBindBufferBase(GL_UNIFORM_BUFFER, using_bind_point, ubo); + + ubo_map_.insert(std::pair(using_bind_point, ubo)); +} + +void shader_program_opengl::set_ssbo(const char* slang_name, void* buffer, int size, int element_size) +{ + const auto& uniform_name = uniform_map_.find(slang_name); + if (uniform_name == uniform_map_.end()) + return; + const auto& uniform_data = uniform_name->second; + const GLint location = glGetProgramResourceIndex(program_id_, GL_SHADER_STORAGE_BLOCK, uniform_data.name.c_str()); + if (location == -1) + { + spdlog::error("Failed to find ssbo: {}", slang_name); + return; + } +} + +void shader_program_opengl::set_render_target(const char* name, std::shared_ptr<render_target> in_render_target) +{ + const auto& texture_name = texture_map_.find(name); + if (texture_name == texture_map_.end()) + return; + + std::shared_ptr<render_target_opengl> rt = std::static_pointer_cast<render_target_opengl>(in_render_target); + const opengl_texture_data& texture_data = texture_name->second; + if (texture_data.format != rt->get_internal_format()) + spdlog::error("Mismatched texture format: {}, need{}, yours {}", name, texture_data.format, rt->get_internal_format()); + glBindImageTexture(texture_data.binding, rt->get_texture(), 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); +} + +void shader_program_opengl::set_texture(const char* name, std::shared_ptr<texture> in_texture) +{ + const auto& texture_name = texture_map_.find(name); + if (texture_name == texture_map_.end()) + return; + + std::shared_ptr<texture_opengl> t = std::static_pointer_cast<texture_opengl>(in_texture); + const opengl_texture_data& texture_data = texture_name->second; + glBindImageTexture(texture_data.binding, t->get_texture(), 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F); +} + +void shader_program_opengl::update_param_map(std::shared_ptr<shader_opengl> in_shader) +{ + const auto& uniform_pairs = in_shader->get_uniform_map(); + const auto& texture_pairs = in_shader->get_texture_map(); + + uniform_map_.insert(uniform_pairs.begin(), uniform_pairs.end()); + texture_map_.insert(texture_pairs.begin(), texture_pairs.end()); +} diff --git a/core/rhi/opengl/shader/shader_program_opengl.h b/core/rhi/opengl/shader/shader_program_opengl.h new file mode 100644 index 0000000..9c27bd9 --- /dev/null +++ b/core/rhi/opengl/shader/shader_program_opengl.h @@ -0,0 +1,77 @@ +#pragma once +#include <map> +#include <memory> +#include <SDL_opengl.h> + +#include "shader_opengl.h" + +class texture; +class render_target; +class shader; +class shader_opengl; + +class shader_program_opengl : public std::enable_shared_from_this<shader_program_opengl> +{ +public: + ~shader_program_opengl() + { + destroy_program(); + } + + void use_program() + { + GLint prev_program_id = 0; + glGetIntegerv(GL_CURRENT_PROGRAM, &prev_program_id); + prev_program_id_ = prev_program_id; + glUseProgram(program_id_); + } + void unuse_program() const { glUseProgram(prev_program_id_); } + + [[nodiscard]] GLuint get_program_id() const { return program_id_; } + bool create_program(std::shared_ptr<shader_opengl> in_pixel_shader, std::shared_ptr<shader_opengl> in_vertex_shader); + bool create_program(std::shared_ptr<shader_opengl> in_compute_shader); + void destroy_program(); + + void set_uniform(const char* slang_name, void* buffer, int size); + void set_ssbo(const char* slang_name, void* buffer, int size, int element_size); + void set_render_target(const char* name, std::shared_ptr<render_target> in_render_target); + void set_texture(const char* name, std::shared_ptr<texture> in_texture); + + template<typename T> + void set_uniform(const char* name, const T& buffer) + { + set_uniform(name, (void*)&buffer, sizeof(T)); + } + template<typename T> + void set_uniform(const char* name, const std::vector<T>& buffer) + { + set_uniform(name, (void*)buffer.data(), sizeof(T) * buffer.size()); + } + + template<typename T> + void set_ssbo(const char* name, const T& buffer) + { + set_ssbo(name, (void*)&buffer, sizeof(T)); + } + template<typename T> + void set_ssbo(const char* name, const std::vector<T>& buffer) + { + set_ssbo(name, (void*)buffer.data(), sizeof(T) * buffer.size()); + } + + [[nodiscard]] bool is_initialized() const { return program_id_ != 0; } +private: + void update_param_map(std::shared_ptr<shader_opengl> in_shader); + + + std::map<std::string, opengl_uniform_data> uniform_map_; // slang_name -> uniform_data + std::map<std::string, opengl_texture_data> texture_map_; // slang_name -> uniform_data + std::map<GLuint, GLuint> ubo_map_; // binding -> ubo + + GLuint program_id_ = 0; + GLuint prev_program_id_ = 0; + + std::weak_ptr<shader_opengl> pixel_shader_; + std::weak_ptr<shader_opengl> vertex_shader_; + std::weak_ptr<shader_opengl> compute_shader_; +}; diff --git a/core/rhi/opengl/shader/shader_ps_opengl.cpp b/core/rhi/opengl/shader/shader_ps_opengl.cpp index 6b33561..55da2b7 100644 --- a/core/rhi/opengl/shader/shader_ps_opengl.cpp +++ b/core/rhi/opengl/shader/shader_ps_opengl.cpp @@ -1 +1,133 @@ #include "shader_ps_opengl.h" + +#include "shader_program_opengl.h" +#include "shader_vs_opengl.h" +#include "application/application.h" +#include "misc/likely.h" +#include "rhi/renderer.h" + +void ps_opengl_compute_callback(const ImDrawList* parent_list, const ImDrawCmd* cmd) +{ + const auto data = (shader_ps_opengl::ps_data*)cmd->UserCallbackData; + std::shared_ptr<render_target_opengl>& rt = data->rt; + const auto program = data->program; + program->use_program(); + + // do on callback + float x = 0; + float width = rt->get_width(); + float y = 0; + float height = rt->get_height(); + + const float ortho_projection[4][4] = + { + { 2.0f/(width-x), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(y-height), 0.0f, 0.0f }, + { 0.0f, 0.0f, -1.0f, 0.0f }, + { (width+x)/(x-width), (y+height)/(height-y), 0.0f, 1.0f }, + }; + // glUseProgram(bd->ShaderHandle); + // glUniform1i(bd->AttribLocationTex, 0); + // glUniformMatrix4fv(bd->AttribLocationProjMtx, 1, GL_FALSE, &ortho_projection[0][0]); + program->set_uniform("viewMatrix", ortho_projection); + + ImVec2 clip_min(x, y); + ImVec2 clip_max(width, height); + glViewport(0, 0, width, height); + + // Apply scissor/clipping rectangle (Y is inverted in OpenGL) + glScissor(0, 0, width, height); + // glScissor((int)clip_min.x, (int)(0 - clip_max.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y)); + + ImDrawVert& vert1 = data->vtx_buffer[0]; + ImDrawVert& vert2 = data->vtx_buffer[1]; + ImDrawVert& vert3 = data->vtx_buffer[2]; + ImDrawVert& vert4 = data->vtx_buffer[3]; + vert1.pos = ImVec2(0, 0); + vert2.pos = ImVec2(width, 0); + vert3.pos = ImVec2(width, height); + vert4.pos = ImVec2(0, height); + vert1.uv = ImVec2(0, 0); + vert2.uv = ImVec2(1, 0); + vert3.uv = ImVec2(1, 1); + vert4.uv = ImVec2(0, 1); + vert1.col = 0xFFFFFFFF; + vert2.col = 0xFFFFFFFF; + vert3.col = 0xFFFFFFFF; + vert4.col = 0xFFFFFFFF; + + + const size_t vtx_size = data->vtx_buffer.size() * sizeof(ImDrawVert); + const size_t idx_size = data->idx_buffer.size() * sizeof(ImDrawIdx); + glBufferSubData(GL_ARRAY_BUFFER, 0, vtx_size, data->vtx_buffer.data()); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, idx_size, data->idx_buffer.data()); + + glBindBuffer(GL_ARRAY_BUFFER, data->vbo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data->ibo); + + glBindFramebuffer(GL_FRAMEBUFFER, rt->get_fbo()); + + glDrawElementsBaseVertex(GL_TRIANGLES, 6, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, 0, 0); + // glDrawElements(GL_TRIANGLES, 6, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, 0); + + program->unuse_program(); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} + +void shader_ps_opengl::draw(int width, int height, std::shared_ptr<shader> in_vertex_shader) +{ + const bool is_default_vtx_shader = in_vertex_shader == nullptr; + if (is_default_vtx_shader) + { + in_vertex_shader = application::get()->get_renderer()->get_pixel_shader_render_default_vs(); + } + const std::shared_ptr<shader_vs_opengl> vs = std::static_pointer_cast<shader_vs_opengl>(in_vertex_shader); + const std::shared_ptr<shader_ps_opengl> ps = std::static_pointer_cast<shader_ps_opengl>(shared_from_this()); + + if (draw_data.fragment_shader_id != get_shader_id() || draw_data.vertex_shader_id != vs->get_shader_id()) + { + if (!draw_data.program) + draw_data.program = std::make_shared<shader_program_opengl>(); + + draw_data.program->create_program(ps, vs); + draw_data.fragment_shader_id = get_shader_id(); + draw_data.vertex_shader_id = vs->get_shader_id(); + } + + if (UNLIKELY(!draw_data.rt)) + { + draw_data.rt = std::static_pointer_cast<render_target_opengl>(application::get()->create_render_target(width, height, texture_format::RGBA8)); + } + + draw_data.rt->resize(width, height); + + if (draw_data.vbo == 0) + { + glGenBuffers(1, &draw_data.vbo); + glGenBuffers(1, &draw_data.ibo); + glBindBuffer(GL_ARRAY_BUFFER, draw_data.vbo); + const size_t vtx_size = draw_data.vtx_buffer.size() * sizeof(ImDrawVert); + glBufferData(GL_ARRAY_BUFFER, vtx_size, draw_data.vtx_buffer.data(), GL_STREAM_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, draw_data.ibo); + const size_t idx_size = draw_data.idx_buffer.size() * sizeof(ImDrawIdx); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, idx_size, draw_data.idx_buffer.data(), GL_STREAM_DRAW); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } + + ImGui::GetWindowDrawList()->AddCallback(ps_opengl_compute_callback, &draw_data); + ImGui::GetWindowDrawList()->AddCallback(ImDrawCallback_ResetRenderState, nullptr); + draw_data.rt->draw(); +} + +shader_ps_opengl::ps_data::~ps_data() +{ + if (vbo) + glDeleteBuffers(1, &vbo); + if (ibo) + glDeleteBuffers(1, &ibo); +} diff --git a/core/rhi/opengl/shader/shader_ps_opengl.h b/core/rhi/opengl/shader/shader_ps_opengl.h index 944b861..97d51d3 100644 --- a/core/rhi/opengl/shader/shader_ps_opengl.h +++ b/core/rhi/opengl/shader/shader_ps_opengl.h @@ -1,9 +1,33 @@ #pragma once #include "shader_opengl.h" +#include "rhi/opengl/render_target_opengl.h" + +class shader_vs_opengl; class shader_ps_opengl : public shader_opengl { public: - shader_ps_opengl(const std::shared_ptr<slang_handle>& handle) : shader_opengl(handle) {} - GLenum get_shader_type() const override { return GL_FRAGMENT_SHADER; } + explicit shader_ps_opengl(const std::shared_ptr<slang_handle>& handle) : shader_opengl(handle), draw_data({}) + { + draw_data.idx_buffer = {0, 1, 2, 0, 2, 3}; + draw_data.vtx_buffer.resize(4); + } + + [[nodiscard]] GLenum get_shader_type() const override { return GL_FRAGMENT_SHADER; } + + void draw(int width, int height, std::shared_ptr<shader> in_vertex_shader) override; + + struct ps_data + { + ~ps_data(); + std::shared_ptr<render_target_opengl> rt; + std::shared_ptr<shader_program_opengl> program; + std::vector<ImDrawVert> vtx_buffer; + std::vector<ImDrawIdx> idx_buffer; + GLuint vbo = 0; + GLuint ibo = 0; + + GLuint vertex_shader_id; + GLuint fragment_shader_id; + } draw_data; }; diff --git a/core/rhi/opengl/texture_opengl.cpp b/core/rhi/opengl/texture_opengl.cpp index 97b5605..f079d29 100644 --- a/core/rhi/opengl/texture_opengl.cpp +++ b/core/rhi/opengl/texture_opengl.cpp @@ -2,6 +2,14 @@ #include "opengl_def.h" +texture_opengl::~texture_opengl() +{ + if (texture_id_ != 0) + { + glDeleteTextures(1, &texture_id_); + } +} + bool texture_opengl::init_data(const unsigned char* data, int width, int height) { width_ = width; diff --git a/core/rhi/opengl/texture_opengl.h b/core/rhi/opengl/texture_opengl.h index cb0f2e9..b047b04 100644 --- a/core/rhi/opengl/texture_opengl.h +++ b/core/rhi/opengl/texture_opengl.h @@ -6,7 +6,9 @@ class texture_opengl : public texture { public: + ~texture_opengl() override; ImTextureID get_texture_id() override { return (void*)static_cast<intptr_t>(texture_id_); } + GLuint get_texture() const { return texture_id_; } bool init_data(const unsigned char* data, int width, int height) override; [[nodiscard]] bool is_valid() const override { return texture_id_ != 0; } private: diff --git a/core/rhi/renderer.cpp b/core/rhi/renderer.cpp index f8d9350..44703b1 100644 --- a/core/rhi/renderer.cpp +++ b/core/rhi/renderer.cpp @@ -2,9 +2,15 @@ #include "application/application.h" +void renderer::shutdown() +{ + default_vs_ = nullptr; + session_ = nullptr; +} + void renderer::init_slang(const std::string& shader_path) { - session_ = create_slang_session(shader_path); + create_slang_session(shader_path, session_.writeRef()); } std::shared_ptr<shader> renderer::get_pixel_shader_render_default_vs() diff --git a/core/rhi/renderer.h b/core/rhi/renderer.h index d9677af..ac074ce 100644 --- a/core/rhi/renderer.h +++ b/core/rhi/renderer.h @@ -16,10 +16,11 @@ public: virtual ~renderer() = default; virtual void pre_init() {} virtual bool init(SDL_Window* window_handle) = 0; - virtual void shutdown() = 0; + virtual void shutdown(); + virtual void post_shutdown() {} void init_slang(const std::string& shader_path); - virtual Slang::ComPtr<slang::ISession> create_slang_session(const std::string& shader_path) = 0; + virtual void create_slang_session(const std::string& shader_path, slang::ISession** out_session) = 0; virtual Slang::ComPtr<slang::ISession> get_slang_session() { return session_; } virtual std::shared_ptr<shader> load_shader(const std::string& entry_name) = 0; virtual std::shared_ptr<shader> get_pixel_shader_render_default_vs(); diff --git a/core/rhi/rhi_defintion.h b/core/rhi/rhi_defintion.h index 6fe7fc5..fa79b86 100644 --- a/core/rhi/rhi_defintion.h +++ b/core/rhi/rhi_defintion.h @@ -5,4 +5,31 @@ enum class texture_format RGBA8, RGBA16_FLOAT, RGBA32_FLOAT, + R32_FLOAT, + RG32_FLOAT, + R11F_G11F_B10F, + R16_FLOAT, + RGBA16, + RGB10_A2, + RG16, + RG8, + R16, + R8, + RG16_SNORM, + RG8_SNORM, + R16_SNORM, + R8_SNORM, + R32I, + R32UI, + R8I, + R16I, + R32F, + R8UI, + R16UI, + RG32I, + RG32UI, + RG8I, + RG16I, + RGB10_A2UI, + RG16UI, }; diff --git a/core/rhi/shader.h b/core/rhi/shader.h index 76f930e..52787a7 100644 --- a/core/rhi/shader.h +++ b/core/rhi/shader.h @@ -4,7 +4,7 @@ class render_target; class texture; class slang_handle; -class shader +class shader : public std::enable_shared_from_this<shader> { public: virtual ~shader() = default; @@ -13,6 +13,7 @@ public: virtual bool init() { return false; } [[nodiscard]] virtual bool is_initialized() const = 0; [[nodiscard]] virtual bool is_valid() const { return handle_ != nullptr && is_initialized(); } + [[nodiscard]] std::shared_ptr<slang_handle> get_handle() { return handle_; } virtual void bind() = 0; virtual void unbind() = 0; @@ -20,20 +21,20 @@ public: virtual void draw(int width, int height, std::shared_ptr<shader> in_vertex_shader = nullptr) {} // param setters - virtual void set_constant_buffer(const char* name, void* buffer, int size) = 0; + virtual void set_cbuffer(const char* name, void* buffer, int size) = 0; virtual void set_uav_buffer(const char* name, void* buffer, int size, int element_size) {} virtual void set_texture(const char* name, std::shared_ptr<texture> in_texture) = 0; virtual void set_render_target(const char* name, std::shared_ptr<render_target> in_render_target) = 0; template<typename T> - void set_constant_buffer(const char* name, const T& buffer) + void set_cbuffer(const char* name, const T& buffer) { - set_constant_buffer(name, (void*)&buffer, sizeof(T)); + set_cbuffer(name, (void*)&buffer, sizeof(T)); } template<typename T> - void set_constant_buffer(const char* name, const std::vector<T>& buffer) + void set_cbuffer(const char* name, const std::vector<T>& buffer) { - set_constant_buffer(name, (void*)buffer.data(), sizeof(T) * buffer.size()); + set_cbuffer(name, (void*)buffer.data(), sizeof(T) * buffer.size()); } template<typename T> diff --git a/core/rhi/slang_handle.cpp b/core/rhi/slang_handle.cpp index 9a92580..726ff49 100644 --- a/core/rhi/slang_handle.cpp +++ b/core/rhi/slang_handle.cpp @@ -59,6 +59,7 @@ Slang::ComPtr<slang::IBlob> slang_handle::get_entry_point_code() const { Slang::ComPtr<slang::IBlob> diagnostics; Slang::ComPtr<slang::IBlob> code_blob; + program->getEntryPointCode( entry_point_index_, target_index, @@ -72,3 +73,27 @@ Slang::ComPtr<slang::IBlob> slang_handle::get_entry_point_code() const } return code_blob; } + +std::map<std::string, slang::BindingType> slang_handle::get_binding_types() const +{ + std::map<std::string, slang::BindingType> out; + slang::ProgramLayout* layout = program->getLayout(target_index); + layout->getGlobalConstantBufferBinding(); + return out; +} + +unsigned int slang_handle::get_bind_index(const char* param_name) const +{ + slang::ProgramLayout* layout = program->getLayout(target_index); + // const auto entry_reflection = layout->getEntryPointByIndex(entry_point_index_); + const auto param_reflection = layout->getParameterCount(); + for (unsigned int i = 0; i < param_reflection; ++i) + { + const auto param = layout->getParameterByIndex(i); + if (strcmp(param->getName(), param_name) == 0) + { + return param->getBindingIndex(); + } + } + return -1; +} diff --git a/core/rhi/slang_handle.h b/core/rhi/slang_handle.h index 64fd88f..93013cb 100644 --- a/core/rhi/slang_handle.h +++ b/core/rhi/slang_handle.h @@ -1,4 +1,6 @@ #pragma once +#include <map> + #include "slang-com-ptr.h" #include <string> @@ -19,6 +21,8 @@ public: return entry_reflection->getName(); } [[nodiscard]] SlangStage get_shader_type() const { return shader_type_; } + [[nodiscard]] std::map<std::string, slang::BindingType> get_binding_types() const; + [[nodiscard]] unsigned int get_bind_index(const char* param_name) const; private: int entry_point_index_ = -1; SlangStage shader_type_ = SLANG_STAGE_NONE; diff --git a/core/rhi/windows/dx11/dx_format.h b/core/rhi/windows/dx11/dx_format.h index 462c128..bc74552 100644 --- a/core/rhi/windows/dx11/dx_format.h +++ b/core/rhi/windows/dx11/dx_format.h @@ -13,6 +13,60 @@ inline DXGI_FORMAT to_dx_format(texture_format format) return DXGI_FORMAT_R16G16B16A16_FLOAT; case texture_format::RGBA32_FLOAT: return DXGI_FORMAT_R32G32B32A32_FLOAT; + case texture_format::R32_FLOAT: + return DXGI_FORMAT_R32_FLOAT; + case texture_format::RG32_FLOAT: + return DXGI_FORMAT_R32G32_FLOAT; + case texture_format::R11F_G11F_B10F: + return DXGI_FORMAT_R11G11B10_FLOAT; + case texture_format::R16_FLOAT: + return DXGI_FORMAT_R16_FLOAT; + case texture_format::RGBA16: + return DXGI_FORMAT_R16G16B16A16_UNORM; + case texture_format::RGB10_A2: + return DXGI_FORMAT_R10G10B10A2_UNORM; + case texture_format::RG16: + return DXGI_FORMAT_R16G16_UNORM; + case texture_format::RG8: + return DXGI_FORMAT_R8G8_UNORM; + case texture_format::R16: + return DXGI_FORMAT_R16_UNORM; + case texture_format::R8: + return DXGI_FORMAT_R8_UNORM; + case texture_format::RG16_SNORM: + return DXGI_FORMAT_R16G16_SNORM; + case texture_format::RG8_SNORM: + return DXGI_FORMAT_R8G8_SNORM; + case texture_format::R16_SNORM: + return DXGI_FORMAT_R16_SNORM; + case texture_format::R8_SNORM: + return DXGI_FORMAT_R8_SNORM; + case texture_format::R32I: + return DXGI_FORMAT_R32_SINT; + case texture_format::R32UI: + return DXGI_FORMAT_R32_UINT; + case texture_format::R8I: + return DXGI_FORMAT_R8_SINT; + case texture_format::R16I: + return DXGI_FORMAT_R16_SINT; + case texture_format::R32F: + return DXGI_FORMAT_R32_FLOAT; + case texture_format::R8UI: + return DXGI_FORMAT_R8_UINT; + case texture_format::R16UI: + return DXGI_FORMAT_R16_UINT; + case texture_format::RG32I: + return DXGI_FORMAT_R32G32_SINT; + case texture_format::RG32UI: + return DXGI_FORMAT_R32G32_UINT; + case texture_format::RG8I: + return DXGI_FORMAT_R8G8_SINT; + case texture_format::RG16I: + return DXGI_FORMAT_R16G16_SINT; + case texture_format::RGB10_A2UI: + return DXGI_FORMAT_R10G10B10A2_UINT; + case texture_format::RG16UI: + return DXGI_FORMAT_R16G16_UINT; } return DXGI_FORMAT_UNKNOWN; } diff --git a/core/rhi/windows/dx11/find_best_device_dx11.cpp b/core/rhi/windows/dx11/find_best_device_dx11.cpp index 4a295d7..66d220f 100644 --- a/core/rhi/windows/dx11/find_best_device_dx11.cpp +++ b/core/rhi/windows/dx11/find_best_device_dx11.cpp @@ -138,6 +138,7 @@ void find_best_device_dx11::select_adapter() for (unsigned int adapter_index = 0; enumerate_adapters(adapter_index, testing_adapter.get_init_reference()) != DXGI_ERROR_NOT_FOUND; ++adapter_index) { DXGI_ADAPTER_DESC adapter_desc; + const HRESULT desc_result = testing_adapter->GetDesc(&adapter_desc); if (FAILED(desc_result)) { diff --git a/core/rhi/windows/dx11/renderer_dx11.cpp b/core/rhi/windows/dx11/renderer_dx11.cpp index b252eef..025db35 100644 --- a/core/rhi/windows/dx11/renderer_dx11.cpp +++ b/core/rhi/windows/dx11/renderer_dx11.cpp @@ -47,6 +47,7 @@ bool renderer_dx11::init(SDL_Window* window_handle) void renderer_dx11::shutdown() { + renderer::shutdown(); // Cleanup ImGui_ImplDX11_Shutdown(); ImGui_ImplSDL3_Shutdown(); @@ -56,7 +57,7 @@ void renderer_dx11::shutdown() g_d3d11_swap_chain.safe_release(); } -Slang::ComPtr<slang::ISession> renderer_dx11::create_slang_session(const std::string& shader_path) +void renderer_dx11::create_slang_session(const std::string& shader_path, slang::ISession** out_session) { slang::TargetDesc target_desc; target_desc.format = SLANG_HLSL; @@ -68,10 +69,9 @@ Slang::ComPtr<slang::ISession> renderer_dx11::create_slang_session(const std::st session_desc.searchPathCount = 1; session_desc.targets = &target_desc; session_desc.targetCount = 1; + session_desc.defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_COLUMN_MAJOR; - Slang::ComPtr<slang::ISession> out; - g_slang_global_session->createSession(session_desc, out.writeRef()); - return out; + g_slang_global_session->createSession(session_desc, out_session); } std::shared_ptr<shader> renderer_dx11::load_shader(const std::string& entry_name) diff --git a/core/rhi/windows/dx11/renderer_dx11.h b/core/rhi/windows/dx11/renderer_dx11.h index 97dbd79..c9bd2f2 100644 --- a/core/rhi/windows/dx11/renderer_dx11.h +++ b/core/rhi/windows/dx11/renderer_dx11.h @@ -19,8 +19,8 @@ public: renderer_dx11(); bool init(SDL_Window* window_handle) override; void shutdown() override; - - Slang::ComPtr<slang::ISession> create_slang_session(const std::string& shader_path) override; + + void create_slang_session(const std::string& shader_path, slang::ISession** out_session) override; std::shared_ptr<shader> load_shader(const std::string& entry_name) override; void new_frame(SDL_Window* window_handle) override; diff --git a/core/rhi/windows/dx11/shader/constant_buffer_dx11.h b/core/rhi/windows/dx11/shader/constant_buffer_dx11.h index 2a69ab9..b501791 100644 --- a/core/rhi/windows/dx11/shader/constant_buffer_dx11.h +++ b/core/rhi/windows/dx11/shader/constant_buffer_dx11.h @@ -15,7 +15,7 @@ public: malloc_size_ = (malloc_size_ + 15) & ~15; // and less than D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT malloc_size_ = min(malloc_size_, D3D11_REQ_CONSTANT_BUFFER_ELEMENT_COUNT); - D3D11_BUFFER_DESC desc; + D3D11_BUFFER_DESC desc = {}; desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; desc.Usage = D3D11_USAGE_DYNAMIC; desc.ByteWidth = malloc_size_; @@ -39,6 +39,7 @@ public: void set_buffer_data(const void* in_buffer_data) const { memcpy(buffer_data_, in_buffer_data, element_size_); + // g_d3d11_device_context->UpdateSubresource(buffer_, 0, nullptr, in_buffer_data, 0, 0); } void update_buffer() const { diff --git a/core/rhi/windows/dx11/shader/shader_dx11.cpp b/core/rhi/windows/dx11/shader/shader_dx11.cpp index 5121188..f842d41 100644 --- a/core/rhi/windows/dx11/shader/shader_dx11.cpp +++ b/core/rhi/windows/dx11/shader/shader_dx11.cpp @@ -65,7 +65,7 @@ bool shader_dx11::init() return true; } -void shader_dx11::set_constant_buffer(const char* name, void* buffer, int size) +void shader_dx11::set_cbuffer(const char* name, void* buffer, int size) { auto find = constant_buffers_.find(name); if (find == constant_buffers_.end()) diff --git a/core/rhi/windows/dx11/shader/shader_dx11.h b/core/rhi/windows/dx11/shader/shader_dx11.h index 3acd6bf..9c38a3f 100644 --- a/core/rhi/windows/dx11/shader/shader_dx11.h +++ b/core/rhi/windows/dx11/shader/shader_dx11.h @@ -23,7 +23,7 @@ public: [[nodiscard]] virtual ID3D11DeviceChild* get_shader() = 0; [[nodiscard]] virtual const char* get_shader_model() const = 0; - void set_constant_buffer(const char* name, void* buffer, int size) override; + void set_cbuffer(const char* name, void* buffer, int size) override; void set_texture(const char* name, std::shared_ptr<texture> in_texture) override; void set_render_target(const char* name, std::shared_ptr<render_target> in_render_target) override; protected: diff --git a/core/rhi/windows/dx11/shader/shader_ps_dx11.cpp b/core/rhi/windows/dx11/shader/shader_ps_dx11.cpp index de16d55..8f134f8 100644 --- a/core/rhi/windows/dx11/shader/shader_ps_dx11.cpp +++ b/core/rhi/windows/dx11/shader/shader_ps_dx11.cpp @@ -177,14 +177,22 @@ void shader_ps_dx11::draw(int width, int height, std::shared_ptr<shader> in_vert const float R = width; const float T = 0; const float B = height; + // float mvp[4][4] = + // { + // { 2.0f/(R-L), 0.0f, 0.0f, (R+L)/(L-R) }, + // { 0.0f, 2.0f/(T-B), 0.0f, (T+B)/(B-T) }, + // { 0.0f, 0.0f, 0.5f, 0.5f }, + // { 0.0f, 0.0f, 0.0f, 1.0f }, + // }; + float mvp[4][4] = { - { 2.0f/(R-L), 0.0f, 0.0f, (R+L)/(L-R) }, - { 0.0f, 2.0f/(T-B), 0.0f, (T+B)/(B-T) }, - { 0.0f, 0.0f, 0.5f, 0.5f }, - { 0.0f, 0.0f, 0.0f, 1.0f }, + { 2.0f/(R-L), 0.0f, 0.0f, 0.0f }, + { 0.0f, 2.0f/(T-B), 0.0f, 0.0f }, + { 0.0f, 0.0f, -1.0f, 0.0f }, + { (R+L)/(L-R), (T+B)/(B-T), 0.0f, 1.0f }, }; - in_vertex_shader->set_constant_buffer("ProjectionMatrix", mvp, sizeof(mvp)); + in_vertex_shader->set_cbuffer("viewMatrix", mvp, sizeof(mvp)); } draw_data.vertex_shader = in_vertex_shader; diff --git a/third_party/glslang b/third_party/glslang new file mode 160000 index 0000000..8c3dbb3 --- /dev/null +++ b/third_party/glslang @@ -0,0 +1 @@ +Subproject commit 8c3dbb3596e552d8e89c16350b07373ac36262bb diff --git a/third_party/slang/inc/slang-tag-version.h b/third_party/slang/inc/slang-tag-version.h index e0ef88a..1a78860 100644 --- a/third_party/slang/inc/slang-tag-version.h +++ b/third_party/slang/inc/slang-tag-version.h @@ -1 +1 @@ -#define SLANG_TAG_VERSION "v2024.0.0" +#define SLANG_TAG_VERSION "v2024.0.1" diff --git a/third_party/slang/inc/slang.h b/third_party/slang/inc/slang.h index c4fb555..54466ca 100644 --- a/third_party/slang/inc/slang.h +++ b/third_party/slang/inc/slang.h @@ -4179,6 +4179,8 @@ namespace slang virtual SLANG_NO_THROW void SLANG_MCALL setReportPerfBenchmark(bool value) = 0; + virtual SLANG_NO_THROW void SLANG_MCALL setSkipSPIRVValidation(bool value) = 0; + }; #define SLANG_UUID_ICompileRequest ICompileRequest::getTypeGuid() diff --git a/third_party/slang/lib/win64/gfx.dll b/third_party/slang/lib/win64/gfx.dll index adb4c7a..8d04770 100644 Binary files a/third_party/slang/lib/win64/gfx.dll and b/third_party/slang/lib/win64/gfx.dll differ diff --git a/third_party/slang/lib/win64/slang-rt.dll b/third_party/slang/lib/win64/slang-rt.dll index 3f8a76c..80c19b1 100644 Binary files a/third_party/slang/lib/win64/slang-rt.dll and b/third_party/slang/lib/win64/slang-rt.dll differ diff --git a/third_party/slang/lib/win64/slang.dll b/third_party/slang/lib/win64/slang.dll index 23e3ae2..93fb079 100644 Binary files a/third_party/slang/lib/win64/slang.dll and b/third_party/slang/lib/win64/slang.dll differ diff --git a/third_party/slang/lib/win64/slangc.exe b/third_party/slang/lib/win64/slangc.exe index f6835d3..a9f9948 100644 Binary files a/third_party/slang/lib/win64/slangc.exe and b/third_party/slang/lib/win64/slangc.exe differ diff --git a/third_party/slang/lib/win64/slangd.exe b/third_party/slang/lib/win64/slangd.exe index fbe9386..eef6804 100644 Binary files a/third_party/slang/lib/win64/slangd.exe and b/third_party/slang/lib/win64/slangd.exe differ