diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp index 4da241d83..a3ba16761 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.cpp +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp @@ -10,53 +10,85 @@ namespace GLShader { -GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) { - +GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader, + const char* fragment_shader, const std::vector& feedback_vars, + bool separable_program) { // Create the shaders - GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); - GLuint fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER); + GLuint vertex_shader_id = vertex_shader ? glCreateShader(GL_VERTEX_SHADER) : 0; + GLuint geometry_shader_id = geometry_shader ? glCreateShader(GL_GEOMETRY_SHADER) : 0; + GLuint fragment_shader_id = fragment_shader ? glCreateShader(GL_FRAGMENT_SHADER) : 0; GLint result = GL_FALSE; int info_log_length; - // Compile Vertex Shader - LOG_DEBUG(Render_OpenGL, "Compiling vertex shader..."); + if (vertex_shader) { + // Compile Vertex Shader + LOG_DEBUG(Render_OpenGL, "Compiling vertex shader..."); - glShaderSource(vertex_shader_id, 1, &vertex_shader, nullptr); - glCompileShader(vertex_shader_id); + glShaderSource(vertex_shader_id, 1, &vertex_shader, nullptr); + glCompileShader(vertex_shader_id); - // Check Vertex Shader - glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result); - glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); + // Check Vertex Shader + glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result); + glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); - if (info_log_length > 1) { - std::vector vertex_shader_error(info_log_length); - glGetShaderInfoLog(vertex_shader_id, info_log_length, nullptr, &vertex_shader_error[0]); - if (result == GL_TRUE) { - LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]); - } else { - LOG_ERROR(Render_OpenGL, "Error compiling vertex shader:\n%s", &vertex_shader_error[0]); + if (info_log_length > 1) { + std::vector vertex_shader_error(info_log_length); + glGetShaderInfoLog(vertex_shader_id, info_log_length, nullptr, &vertex_shader_error[0]); + if (result == GL_TRUE) { + LOG_DEBUG(Render_OpenGL, "%s", &vertex_shader_error[0]); + } else { + LOG_ERROR(Render_OpenGL, "Error compiling vertex shader:\n%s", + &vertex_shader_error[0]); + } } } - // Compile Fragment Shader - LOG_DEBUG(Render_OpenGL, "Compiling fragment shader..."); + if (geometry_shader) { + // Compile Geometry Shader + LOG_DEBUG(Render_OpenGL, "Compiling geometry shader..."); - glShaderSource(fragment_shader_id, 1, &fragment_shader, nullptr); - glCompileShader(fragment_shader_id); + glShaderSource(geometry_shader_id, 1, &geometry_shader, nullptr); + glCompileShader(geometry_shader_id); - // Check Fragment Shader - glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result); - glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); + // Check Geometry Shader + glGetShaderiv(geometry_shader_id, GL_COMPILE_STATUS, &result); + glGetShaderiv(geometry_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); - if (info_log_length > 1) { - std::vector fragment_shader_error(info_log_length); - glGetShaderInfoLog(fragment_shader_id, info_log_length, nullptr, &fragment_shader_error[0]); - if (result == GL_TRUE) { - LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]); - } else { - LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s", - &fragment_shader_error[0]); + if (info_log_length > 1) { + std::vector geometry_shader_error(info_log_length); + glGetShaderInfoLog(geometry_shader_id, info_log_length, nullptr, + &geometry_shader_error[0]); + if (result == GL_TRUE) { + LOG_DEBUG(Render_OpenGL, "%s", &geometry_shader_error[0]); + } else { + LOG_ERROR(Render_OpenGL, "Error compiling geometry shader:\n%s", + &geometry_shader_error[0]); + } + } + } + + if (fragment_shader) { + // Compile Fragment Shader + LOG_DEBUG(Render_OpenGL, "Compiling fragment shader..."); + + glShaderSource(fragment_shader_id, 1, &fragment_shader, nullptr); + glCompileShader(fragment_shader_id); + + // Check Fragment Shader + glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result); + glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); + + if (info_log_length > 1) { + std::vector fragment_shader_error(info_log_length); + glGetShaderInfoLog(fragment_shader_id, info_log_length, nullptr, + &fragment_shader_error[0]); + if (result == GL_TRUE) { + LOG_DEBUG(Render_OpenGL, "%s", &fragment_shader_error[0]); + } else { + LOG_ERROR(Render_OpenGL, "Error compiling fragment shader:\n%s", + &fragment_shader_error[0]); + } } } @@ -64,8 +96,25 @@ GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) { LOG_DEBUG(Render_OpenGL, "Linking program..."); GLuint program_id = glCreateProgram(); - glAttachShader(program_id, vertex_shader_id); - glAttachShader(program_id, fragment_shader_id); + if (vertex_shader) { + glAttachShader(program_id, vertex_shader_id); + } + if (geometry_shader) { + glAttachShader(program_id, geometry_shader_id); + } + if (fragment_shader) { + glAttachShader(program_id, fragment_shader_id); + } + + if (!feedback_vars.empty()) { + auto varyings = feedback_vars; + glTransformFeedbackVaryings(program_id, static_cast(feedback_vars.size()), + &varyings[0], GL_INTERLEAVED_ATTRIBS); + } + + if (separable_program) { + glProgramParameteri(program_id, GL_PROGRAM_SEPARABLE, GL_TRUE); + } glLinkProgram(program_id); @@ -85,13 +134,30 @@ GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader) { // If the program linking failed at least one of the shaders was probably bad if (result == GL_FALSE) { - LOG_ERROR(Render_OpenGL, "Vertex shader:\n%s", vertex_shader); - LOG_ERROR(Render_OpenGL, "Fragment shader:\n%s", fragment_shader); + if (vertex_shader) { + LOG_ERROR(Render_OpenGL, "Vertex shader:\n%s", vertex_shader); + } + if (geometry_shader) { + LOG_ERROR(Render_OpenGL, "Geometry shader:\n%s", geometry_shader); + } + if (fragment_shader) { + LOG_ERROR(Render_OpenGL, "Fragment shader:\n%s", fragment_shader); + } } ASSERT_MSG(result == GL_TRUE, "Shader not linked"); - glDeleteShader(vertex_shader_id); - glDeleteShader(fragment_shader_id); + if (vertex_shader) { + glDetachShader(program_id, vertex_shader_id); + glDeleteShader(vertex_shader_id); + } + if (geometry_shader) { + glDetachShader(program_id, geometry_shader_id); + glDeleteShader(geometry_shader_id); + } + if (fragment_shader) { + glDetachShader(program_id, fragment_shader_id); + glDeleteShader(fragment_shader_id); + } return program_id; } diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h index a4bcffdfa..fc7b5e080 100644 --- a/src/video_core/renderer_opengl/gl_shader_util.h +++ b/src/video_core/renderer_opengl/gl_shader_util.h @@ -4,6 +4,7 @@ #pragma once +#include #include namespace GLShader { @@ -11,9 +12,12 @@ namespace GLShader { /** * Utility function to create and compile an OpenGL GLSL shader program (vertex + fragment shader) * @param vertex_shader String of the GLSL vertex shader program + * @param geometry_shader String of the GLSL geometry shader program * @param fragment_shader String of the GLSL fragment shader program * @returns Handle of the newly created OpenGL shader object */ -GLuint LoadProgram(const char* vertex_shader, const char* fragment_shader); +GLuint LoadProgram(const char* vertex_shader, const char* geometry_shader, + const char* fragment_shader, const std::vector& feedback_vars = {}, + bool separable_program = false); } // namespace GLShader diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 7f921fa32..65d38ade5 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -318,7 +318,7 @@ void RendererOpenGL::InitOpenGLObjects() { 0.0f); // Link shaders and get variable locations - shader.Create(vertex_shader, fragment_shader); + shader.Create(vertex_shader, nullptr, fragment_shader); state.draw.shader_program = shader.handle; state.Apply(); uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix");