From 17988fc7dea2c298bc26c559a534364ad697d198 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Wed, 1 Jun 2016 17:33:44 +0200 Subject: [PATCH] gsdx ogl: add code to compile a single shader --- plugins/GSdx/GLState.cpp | 2 + plugins/GSdx/GLState.h | 1 + plugins/GSdx/GSShaderOGL.cpp | 106 +++++++++++++++++++++++++++++++++++ plugins/GSdx/GSShaderOGL.h | 10 ++++ 4 files changed, 119 insertions(+) diff --git a/plugins/GSdx/GLState.cpp b/plugins/GSdx/GLState.cpp index 96953a0640..39f7a7c6f1 100644 --- a/plugins/GSdx/GLState.cpp +++ b/plugins/GSdx/GLState.cpp @@ -54,6 +54,7 @@ namespace GLState { GLuint ps; GLuint gs; GLuint vs; + GLuint program; GLuint pipeline; void Clear() { @@ -90,6 +91,7 @@ namespace GLState { ps = 0; gs = 0; vs = 0; + program = 0; pipeline = 0; } } diff --git a/plugins/GSdx/GLState.h b/plugins/GSdx/GLState.h index 34a508de79..5203526207 100644 --- a/plugins/GSdx/GLState.h +++ b/plugins/GSdx/GLState.h @@ -56,6 +56,7 @@ namespace GLState { extern GLuint ps; extern GLuint gs; extern GLuint vs; + extern GLuint program; extern GLuint pipeline; extern void Clear(); diff --git a/plugins/GSdx/GSShaderOGL.cpp b/plugins/GSdx/GSShaderOGL.cpp index 4972619b05..072560ea93 100644 --- a/plugins/GSdx/GSShaderOGL.cpp +++ b/plugins/GSdx/GSShaderOGL.cpp @@ -36,6 +36,10 @@ GSShaderOGL::GSShaderOGL(bool debug) : GSShaderOGL::~GSShaderOGL() { + printf("Delete %d Shaders, %d Programs, %d Pipelines\n", + m_shad_to_delete.size(), m_prog_to_delete.size(), m_pipe_to_delete.size()); + + for (auto s : m_shad_to_delete) glDeleteShader(s); for (auto p : m_prog_to_delete) glDeleteProgram(p); glDeleteProgramPipelines(m_pipe_to_delete.size(), &m_pipe_to_delete[0]); } @@ -53,6 +57,46 @@ GLuint GSShaderOGL::LinkPipeline(GLuint vs, GLuint gs, GLuint ps) return p; } +GLuint GSShaderOGL::LinkProgram(GLuint vs, GLuint gs, GLuint ps) +{ + uint32 hash = ((vs ^ gs) << 24) ^ ps; + auto it = m_program.find(hash); + if (it != m_program.end()) + return it->second; + + GLuint p = glCreateProgram(); + if (vs) glAttachShader(p, vs); + if (ps) glAttachShader(p, ps); + if (gs) glAttachShader(p, gs); + + glLinkProgram(p); + + ValidateProgram(p); + + m_prog_to_delete.push_back(p); + m_program[hash] = p; + + return p; +} + +void GSShaderOGL::BindProgram(GLuint vs, GLuint gs, GLuint ps) +{ + GLuint p = LinkProgram(vs, gs, ps); + + if (GLState::program != p) { + GLState::program = p; + glUseProgram(p); + } +} + +void GSShaderOGL::BindProgram(GLuint p) +{ + if (GLState::program != p) { + GLState::program = p; + glUseProgram(p); + } +} + void GSShaderOGL::BindPipeline(GLuint vs, GLuint gs, GLuint ps) { BindPipeline(m_pipeline); @@ -85,6 +129,32 @@ void GSShaderOGL::BindPipeline(GLuint pipe) GLState::pipeline = pipe; glBindProgramPipeline(pipe); } + + if (GLState::program) { + GLState::program = 0; + glUseProgram(0); + } +} + +bool GSShaderOGL::ValidateShader(GLuint s) +{ + if (!m_debug_shader) return true; + + GLint status = 0; + glGetShaderiv(s, GL_COMPILE_STATUS, &status); + if (status) return true; + + GLint log_length = 0; + glGetShaderiv(s, GL_INFO_LOG_LENGTH, &log_length); + if (log_length > 0) { + char* log = new char[log_length]; + glGetShaderInfoLog(s, log_length, NULL, log); + fprintf(stderr, "%s", log); + delete[] log; + } + fprintf(stderr, "\n"); + + return false; } bool GSShaderOGL::ValidateProgram(GLuint p) @@ -208,6 +278,42 @@ GLuint GSShaderOGL::Compile(const std::string& glsl_file, const std::string& ent return program; } +// Same as above but for not-separated build +GLuint GSShaderOGL::CompileShader(const std::string& glsl_file, const std::string& entry, GLenum type, const char* glsl_h_code, const std::string& macro_sel) +{ + ASSERT(glsl_h_code != NULL); + + GLuint shader = 0; + + // Note it is better to separate header and source file to have the good line number + // in the glsl compiler report + const int shader_nb = 3; + const char* sources[shader_nb]; + + std::string header = GenGlslHeader(entry, type, macro_sel); + + sources[0] = header.c_str(); + sources[1] = common_header_glsl; + sources[2] = glsl_h_code; + + shader = glCreateShader(type); + glShaderSource(shader, shader_nb, sources, NULL); + glCompileShader(shader); + + bool status = ValidateShader(shader); + + if (!status) { + // print extra info + fprintf(stderr, "%s (entry %s, prog %d) :", glsl_file.c_str(), entry.c_str(), shader); + fprintf(stderr, "\n%s", macro_sel.c_str()); + fprintf(stderr, "\n"); + } + + m_shad_to_delete.push_back(shader); + + return shader; +} + // This function will get the binary program. Normally it must be used a caching // solution but Nvidia also incorporates the ASM dump. Asm is nice because it allow // to have an overview of the program performance based on the instruction number diff --git a/plugins/GSdx/GSShaderOGL.h b/plugins/GSdx/GSShaderOGL.h index 84c0d45ed1..b0d61a6686 100644 --- a/plugins/GSdx/GSShaderOGL.h +++ b/plugins/GSdx/GSShaderOGL.h @@ -23,11 +23,14 @@ class GSShaderOGL { GLuint m_pipeline; + hash_map m_program; const bool m_debug_shader; + std::vector m_shad_to_delete; std::vector m_prog_to_delete; std::vector m_pipe_to_delete; + bool ValidateShader(GLuint s); bool ValidateProgram(GLuint p); bool ValidatePipeline(GLuint p); @@ -43,5 +46,12 @@ class GSShaderOGL { GLuint Compile(const std::string& glsl_file, const std::string& entry, GLenum type, const char* glsl_h_code, const std::string& macro_sel = ""); GLuint LinkPipeline(GLuint vs, GLuint gs, GLuint ps); + // Same as above but for not separated build + void BindProgram(GLuint vs, GLuint gs, GLuint ps); + void BindProgram(GLuint p); + + GLuint CompileShader(const std::string& glsl_file, const std::string& entry, GLenum type, const char* glsl_h_code, const std::string& macro_sel = ""); + GLuint LinkProgram(GLuint vs, GLuint gs, GLuint ps); + int DumpAsm(const std::string& file, GLuint p); };