From b45b70970b999c027e341e1e67efa62a4d64f123 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Thu, 16 Apr 2020 20:41:27 +1000 Subject: [PATCH] GL/ShaderCache: Support geometry shaders --- src/common/gl/program.cpp | 43 +++++++++---- src/common/gl/program.h | 3 +- src/common/gl/shader_cache.cpp | 68 +++++++++++++++------ src/common/gl/shader_cache.h | 19 ++++-- src/core/gpu_hw_opengl.cpp | 10 +-- src/duckstation-qt/opengldisplaywidget.cpp | 2 +- src/duckstation-sdl/opengl_host_display.cpp | 2 +- 7 files changed, 103 insertions(+), 44 deletions(-) diff --git a/src/common/gl/program.cpp b/src/common/gl/program.cpp index 4859d96eb..39618b117 100644 --- a/src/common/gl/program.cpp +++ b/src/common/gl/program.cpp @@ -81,22 +81,43 @@ void Program::ResetLastProgram() s_last_program_id = 0; } -bool Program::Compile(const std::string_view vertex_shader, const std::string_view fragment_shader) +bool Program::Compile(const std::string_view vertex_shader, const std::string_view geometry_shader, + const std::string_view fragment_shader) { - GLuint vertex_shader_id = CompileShader(GL_VERTEX_SHADER, vertex_shader); - if (vertex_shader_id == 0) - return false; - - GLuint fragment_shader_id = CompileShader(GL_FRAGMENT_SHADER, fragment_shader); - if (fragment_shader_id == 0) + GLuint vertex_shader_id = 0; + if (!vertex_shader.empty()) { - glDeleteShader(vertex_shader_id); - return false; + vertex_shader_id = CompileShader(GL_VERTEX_SHADER, vertex_shader); + if (vertex_shader_id == 0) + return false; + } + + GLuint geometry_shader_id = 0; + if (!geometry_shader.empty()) + { + geometry_shader_id = CompileShader(GL_GEOMETRY_SHADER, geometry_shader); + if (geometry_shader_id == 0) + return false; + } + + GLuint fragment_shader_id = 0; + if (!fragment_shader.empty()) + { + fragment_shader_id = CompileShader(GL_FRAGMENT_SHADER, fragment_shader); + if (fragment_shader_id == 0) + { + glDeleteShader(vertex_shader_id); + return false; + } } m_program_id = glCreateProgram(); - glAttachShader(m_program_id, vertex_shader_id); - glAttachShader(m_program_id, fragment_shader_id); + if (vertex_shader_id != 0) + glAttachShader(m_program_id, vertex_shader_id); + if (geometry_shader_id != 0) + glAttachShader(m_program_id, geometry_shader_id); + if (fragment_shader_id != 0) + glAttachShader(m_program_id, fragment_shader_id); return true; } diff --git a/src/common/gl/program.h b/src/common/gl/program.h index 6c4beefa0..d877a4622 100644 --- a/src/common/gl/program.h +++ b/src/common/gl/program.h @@ -19,7 +19,8 @@ public: bool IsVaild() const { return m_program_id != 0; } bool IsBound() const { return s_last_program_id == m_program_id; } - bool Compile(const std::string_view vertex_shader, const std::string_view fragment_shader); + bool Compile(const std::string_view vertex_shader, const std::string_view geometry_shader, + const std::string_view fragment_shader); bool CreateFromBinary(const void* data, u32 data_length, u32 data_format); diff --git a/src/common/gl/shader_cache.cpp b/src/common/gl/shader_cache.cpp index 5c09a2274..b2bd5ad3a 100644 --- a/src/common/gl/shader_cache.cpp +++ b/src/common/gl/shader_cache.cpp @@ -13,6 +13,9 @@ struct CacheIndexEntry u64 vertex_source_hash_low; u64 vertex_source_hash_high; u32 vertex_source_length; + u64 geometry_source_hash_low; + u64 geometry_source_hash_high; + u32 geometry_source_length; u64 fragment_source_hash_low; u64 fragment_source_hash_high; u32 fragment_source_length; @@ -33,7 +36,9 @@ bool ShaderCache::CacheIndexKey::operator==(const CacheIndexKey& key) const { return ( vertex_source_hash_low == key.vertex_source_hash_low && vertex_source_hash_high == key.vertex_source_hash_high && - vertex_source_length == key.vertex_source_length && fragment_source_hash_low == key.fragment_source_hash_low && + vertex_source_length == key.vertex_source_length && geometry_source_hash_low == key.geometry_source_hash_low && + geometry_source_hash_high == key.geometry_source_hash_high && + geometry_source_length == key.geometry_source_length && fragment_source_hash_low == key.fragment_source_hash_low && fragment_source_hash_high == key.fragment_source_hash_high && fragment_source_length == key.fragment_source_length); } @@ -41,7 +46,9 @@ bool ShaderCache::CacheIndexKey::operator!=(const CacheIndexKey& key) const { return ( vertex_source_hash_low != key.vertex_source_hash_low || vertex_source_hash_high != key.vertex_source_hash_high || - vertex_source_length != key.vertex_source_length || fragment_source_hash_low != key.fragment_source_hash_low || + vertex_source_length != key.vertex_source_length || geometry_source_hash_low != key.geometry_source_hash_low || + geometry_source_hash_high != key.geometry_source_hash_high || + geometry_source_length != key.geometry_source_length || fragment_source_hash_low != key.fragment_source_hash_low || fragment_source_hash_high != key.fragment_source_hash_high || fragment_source_length != key.fragment_source_length); } @@ -160,9 +167,10 @@ bool ShaderCache::ReadExisting(const std::string& index_filename, const std::str return false; } - const CacheIndexKey key{entry.vertex_source_hash_low, entry.vertex_source_hash_high, - entry.vertex_source_length, entry.fragment_source_hash_low, - entry.fragment_source_hash_high, entry.fragment_source_length}; + const CacheIndexKey key{ + entry.vertex_source_hash_low, entry.vertex_source_hash_high, entry.vertex_source_length, + entry.geometry_source_hash_low, entry.geometry_source_hash_high, entry.geometry_source_length, + entry.fragment_source_hash_low, entry.fragment_source_hash_high, entry.fragment_source_length}; const CacheIndexData data{entry.file_offset, entry.blob_size, entry.blob_format}; m_index.emplace(key, data); } @@ -191,6 +199,7 @@ bool ShaderCache::Recreate() } ShaderCache::CacheIndexKey ShaderCache::GetCacheKey(const std::string_view& vertex_shader, + const std::string_view& geometry_shader, const std::string_view& fragment_shader) { union ShaderHash @@ -203,18 +212,33 @@ ShaderCache::CacheIndexKey ShaderCache::GetCacheKey(const std::string_view& vert u8 bytes[16]; }; - ShaderHash vertex_hash; - ShaderHash fragment_hash; + ShaderHash vertex_hash = {}; + ShaderHash geometry_hash = {}; + ShaderHash fragment_hash = {}; MD5Digest digest; - digest.Update(vertex_shader.data(), static_cast(vertex_shader.length())); - digest.Final(vertex_hash.bytes); + if (!vertex_shader.empty()) + { + digest.Update(vertex_shader.data(), static_cast(vertex_shader.length())); + digest.Final(vertex_hash.bytes); + } - digest.Reset(); - digest.Update(fragment_shader.data(), static_cast(fragment_shader.length())); - digest.Final(fragment_hash.bytes); + if (!geometry_shader.empty()) + { + digest.Reset(); + digest.Update(geometry_shader.data(), static_cast(geometry_shader.length())); + digest.Final(geometry_hash.bytes); + } + + if (!fragment_shader.empty()) + { + digest.Reset(); + digest.Update(fragment_shader.data(), static_cast(fragment_shader.length())); + digest.Final(fragment_hash.bytes); + } return CacheIndexKey{vertex_hash.low, vertex_hash.high, static_cast(vertex_shader.length()), + geometry_hash.low, geometry_hash.high, static_cast(geometry_shader.length()), fragment_hash.low, fragment_hash.high, static_cast(fragment_shader.length())}; } @@ -229,15 +253,16 @@ std::string ShaderCache::GetBlobFileName() const } std::optional ShaderCache::GetProgram(const std::string_view vertex_shader, + const std::string_view geometry_shader, const std::string_view fragment_shader, const PreLinkCallback& callback) { if (!m_program_binary_supported) - return CompileProgram(vertex_shader, fragment_shader, callback, false); + return CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, false); - const auto key = GetCacheKey(vertex_shader, fragment_shader); + const auto key = GetCacheKey(vertex_shader, geometry_shader, fragment_shader); auto iter = m_index.find(key); if (iter == m_index.end()) - return CompileAndAddProgram(key, vertex_shader, fragment_shader, callback); + return CompileAndAddProgram(key, vertex_shader, geometry_shader, fragment_shader, callback); std::vector data(iter->second.blob_size); if (std::fseek(m_blob_file, iter->second.file_offset, SEEK_SET) != 0 || @@ -254,17 +279,18 @@ std::optional ShaderCache::GetProgram(const std::string_view vertex_sha Log_WarningPrintf( "Failed to create program from binary, this may be due to a driver or GPU Change. Recreating cache."); if (!Recreate()) - return CompileProgram(vertex_shader, fragment_shader, callback, false); + return CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, false); else - return CompileAndAddProgram(key, vertex_shader, fragment_shader, callback); + return CompileAndAddProgram(key, vertex_shader, geometry_shader, fragment_shader, callback); } std::optional ShaderCache::CompileProgram(const std::string_view& vertex_shader, + const std::string_view& geometry_shader, const std::string_view& fragment_shader, const PreLinkCallback& callback, bool set_retrievable) { Program prog; - if (!prog.Compile(vertex_shader, fragment_shader)) + if (!prog.Compile(vertex_shader, geometry_shader, fragment_shader)) return std::nullopt; if (callback) @@ -281,10 +307,11 @@ std::optional ShaderCache::CompileProgram(const std::string_view& verte std::optional ShaderCache::CompileAndAddProgram(const CacheIndexKey& key, const std::string_view& vertex_shader, + const std::string_view& geometry_shader, const std::string_view& fragment_shader, const PreLinkCallback& callback) { - std::optional prog = CompileProgram(vertex_shader, fragment_shader, callback, true); + std::optional prog = CompileProgram(vertex_shader, geometry_shader, fragment_shader, callback, true); if (!prog) return std::nullopt; @@ -305,6 +332,9 @@ std::optional ShaderCache::CompileAndAddProgram(const CacheIndexKey& ke entry.vertex_source_hash_low = key.vertex_source_hash_low; entry.vertex_source_hash_high = key.vertex_source_hash_high; entry.vertex_source_length = key.vertex_source_length; + entry.geometry_source_hash_low = key.geometry_source_hash_low; + entry.geometry_source_hash_high = key.geometry_source_hash_high; + entry.geometry_source_length = key.geometry_source_length; entry.fragment_source_hash_low = key.fragment_source_hash_low; entry.fragment_source_hash_high = key.fragment_source_hash_high; entry.fragment_source_length = key.fragment_source_length; diff --git a/src/common/gl/shader_cache.h b/src/common/gl/shader_cache.h index 12410c1e7..304c6a5f0 100644 --- a/src/common/gl/shader_cache.h +++ b/src/common/gl/shader_cache.h @@ -22,17 +22,20 @@ public: void Open(bool is_gles, std::string_view base_path); - std::optional GetProgram(const std::string_view vertex_shader, const std::string_view fragment_shader, - const PreLinkCallback& callback = {}); + std::optional GetProgram(const std::string_view vertex_shader, const std::string_view geometry_shader, + const std::string_view fragment_shader, const PreLinkCallback& callback = {}); private: - static constexpr u32 FILE_VERSION = 1; + static constexpr u32 FILE_VERSION = 2; struct CacheIndexKey { u64 vertex_source_hash_low; u64 vertex_source_hash_high; u32 vertex_source_length; + u64 geometry_source_hash_low; + u64 geometry_source_hash_high; + u32 geometry_source_length; u64 fragment_source_hash_low; u64 fragment_source_hash_high; u32 fragment_source_length; @@ -47,6 +50,7 @@ private: { std::size_t h = 0; hash_combine(h, e.vertex_source_hash_low, e.vertex_source_hash_high, e.vertex_source_length, + e.geometry_source_hash_low, e.geometry_source_hash_high, e.geometry_source_length, e.fragment_source_hash_low, e.fragment_source_hash_high, e.fragment_source_length); return h; } @@ -61,7 +65,8 @@ private: using CacheIndex = std::unordered_map; - static CacheIndexKey GetCacheKey(const std::string_view& vertex_shader, const std::string_view& fragment_shader); + static CacheIndexKey GetCacheKey(const std::string_view& vertex_shader, const std::string_view& geometry_shader, + const std::string_view& fragment_shader); std::string GetIndexFileName() const; std::string GetBlobFileName() const; @@ -71,9 +76,11 @@ private: void Close(); bool Recreate(); - std::optional CompileProgram(const std::string_view& vertex_shader, const std::string_view& fragment_shader, - const PreLinkCallback& callback, bool set_retrievable); + std::optional CompileProgram(const std::string_view& vertex_shader, const std::string_view& geometry_shader, + const std::string_view& fragment_shader, const PreLinkCallback& callback, + bool set_retrievable); std::optional CompileAndAddProgram(const CacheIndexKey& key, const std::string_view& vertex_shader, + const std::string_view& geometry_shader, const std::string_view& fragment_shader, const PreLinkCallback& callback); std::string m_base_path; diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp index 8b29fabe1..e9d65e117 100644 --- a/src/core/gpu_hw_opengl.cpp +++ b/src/core/gpu_hw_opengl.cpp @@ -311,7 +311,7 @@ bool GPU_HW_OpenGL::CompilePrograms() static_cast(render_mode), static_cast(texture_mode), ConvertToBoolUnchecked(dithering), ConvertToBoolUnchecked(interlacing)); - std::optional prog = m_shader_cache.GetProgram(vs, fs, [this, textured](GL::Program& prog) { + std::optional prog = m_shader_cache.GetProgram(vs, {}, fs, [this, textured](GL::Program& prog) { prog.BindAttribute(0, "a_pos"); prog.BindAttribute(1, "a_col0"); if (textured) @@ -347,7 +347,7 @@ bool GPU_HW_OpenGL::CompilePrograms() const std::string fs = shadergen.GenerateDisplayFragmentShader(ConvertToBoolUnchecked(depth_24bit), ConvertToBoolUnchecked(interlaced)); - std::optional prog = m_shader_cache.GetProgram(vs, fs, [this](GL::Program& prog) { + std::optional prog = m_shader_cache.GetProgram(vs, {}, fs, [this](GL::Program& prog) { if (!m_is_gles) { if (m_supports_dual_source_blend) @@ -373,7 +373,7 @@ bool GPU_HW_OpenGL::CompilePrograms() } std::optional prog = - m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), + m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), {}, shadergen.GenerateInterlacedFillFragmentShader(), [this](GL::Program& prog) { if (!m_is_gles) prog.BindFragData(0, "o_col0"); @@ -385,7 +385,7 @@ bool GPU_HW_OpenGL::CompilePrograms() prog->Bind(); m_vram_interlaced_fill_program = std::move(*prog); - prog = m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), + prog = m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), {}, shadergen.GenerateVRAMReadFragmentShader(), [this](GL::Program& prog) { if (!m_is_gles) prog.BindFragData(0, "o_col0"); @@ -400,7 +400,7 @@ bool GPU_HW_OpenGL::CompilePrograms() if (m_supports_texture_buffer) { - prog = m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), + prog = m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), {}, shadergen.GenerateVRAMWriteFragmentShader(), [this](GL::Program& prog) { if (!m_is_gles) prog.BindFragData(0, "o_col0"); diff --git a/src/duckstation-qt/opengldisplaywidget.cpp b/src/duckstation-qt/opengldisplaywidget.cpp index c0131ab5b..906d8fbae 100644 --- a/src/duckstation-qt/opengldisplaywidget.cpp +++ b/src/duckstation-qt/opengldisplaywidget.cpp @@ -419,7 +419,7 @@ void main() } )"; - if (!m_display_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, + if (!m_display_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, {}, GetGLSLVersionHeader() + display_fragment_shader)) { Log_ErrorPrintf("Failed to compile display shaders"); diff --git a/src/duckstation-sdl/opengl_host_display.cpp b/src/duckstation-sdl/opengl_host_display.cpp index 281400c0d..fbdd875b3 100644 --- a/src/duckstation-sdl/opengl_host_display.cpp +++ b/src/duckstation-sdl/opengl_host_display.cpp @@ -332,7 +332,7 @@ void main() } )"; - if (!m_display_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, + if (!m_display_program.Compile(GetGLSLVersionHeader() + fullscreen_quad_vertex_shader, {}, GetGLSLVersionHeader() + display_fragment_shader)) { Log_ErrorPrintf("Failed to compile display shaders");