diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 508d6e41ed..3d4aeea2fc 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -65,6 +65,8 @@ static std::string GetGLSLVersionString() return "#version 330"; case GLSL_400: return "#version 400"; + case GLSL_430: + return "#version 430"; default: // Shouldn't ever hit this return "#version ERROR"; @@ -103,27 +105,30 @@ void SHADER::SetProgramVariables() } } -void SHADER::SetProgramBindings() +void SHADER::SetProgramBindings(bool is_compute) { - if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend) + if (!is_compute) { - // So we do support extended blending - // So we need to set a few more things here. - // Bind our out locations - glBindFragDataLocationIndexed(glprogid, 0, 0, "ocol0"); - glBindFragDataLocationIndexed(glprogid, 0, 1, "ocol1"); + if (g_ActiveConfig.backend_info.bSupportsDualSourceBlend) + { + // So we do support extended blending + // So we need to set a few more things here. + // Bind our out locations + glBindFragDataLocationIndexed(glprogid, 0, 0, "ocol0"); + glBindFragDataLocationIndexed(glprogid, 0, 1, "ocol1"); + } + // Need to set some attribute locations + glBindAttribLocation(glprogid, SHADER_POSITION_ATTRIB, "rawpos"); + + glBindAttribLocation(glprogid, SHADER_POSMTX_ATTRIB, "posmtx"); + + glBindAttribLocation(glprogid, SHADER_COLOR0_ATTRIB, "color0"); + glBindAttribLocation(glprogid, SHADER_COLOR1_ATTRIB, "color1"); + + glBindAttribLocation(glprogid, SHADER_NORM0_ATTRIB, "rawnorm0"); + glBindAttribLocation(glprogid, SHADER_NORM1_ATTRIB, "rawnorm1"); + glBindAttribLocation(glprogid, SHADER_NORM2_ATTRIB, "rawnorm2"); } - // Need to set some attribute locations - glBindAttribLocation(glprogid, SHADER_POSITION_ATTRIB, "rawpos"); - - glBindAttribLocation(glprogid, SHADER_POSMTX_ATTRIB, "posmtx"); - - glBindAttribLocation(glprogid, SHADER_COLOR0_ATTRIB, "color0"); - glBindAttribLocation(glprogid, SHADER_COLOR1_ATTRIB, "color1"); - - glBindAttribLocation(glprogid, SHADER_NORM0_ATTRIB, "rawnorm0"); - glBindAttribLocation(glprogid, SHADER_NORM1_ATTRIB, "rawnorm1"); - glBindAttribLocation(glprogid, SHADER_NORM2_ATTRIB, "rawnorm2"); for (int i = 0; i < 8; i++) { @@ -281,7 +286,7 @@ bool ProgramShaderCache::CompileShader(SHADER& shader, const std::string& vcode, if (g_ogl_config.bSupportsGLSLCache) glProgramParameteri(pid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); - shader.SetProgramBindings(); + shader.SetProgramBindings(false); glLinkProgram(pid); @@ -296,10 +301,10 @@ bool ProgramShaderCache::CompileShader(SHADER& shader, const std::string& vcode, glGetProgramiv(pid, GL_INFO_LOG_LENGTH, &length); if (linkStatus != GL_TRUE || (length > 1 && DEBUG_GLSL)) { - GLsizei charsWritten; - GLchar* infoLog = new GLchar[length]; - glGetProgramInfoLog(pid, length, &charsWritten, infoLog); - ERROR_LOG(VIDEO, "Program info log:\n%s", infoLog); + std::string info_log; + info_log.resize(length); + glGetProgramInfoLog(pid, length, &length, &info_log[0]); + ERROR_LOG(VIDEO, "Program info log:\n%s", info_log.c_str()); std::string filename = StringFromFormat("%sbad_p_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); @@ -308,7 +313,7 @@ bool ProgramShaderCache::CompileShader(SHADER& shader, const std::string& vcode, file << s_glsl_header << vcode << s_glsl_header << pcode; if (!gcode.empty()) file << s_glsl_header << gcode; - file << infoLog; + file << info_log; file.close(); if (linkStatus != GL_TRUE) @@ -316,10 +321,8 @@ bool ProgramShaderCache::CompileShader(SHADER& shader, const std::string& vcode, PanicAlert("Failed to link shaders: %s\n" "Debug info (%s, %s, %s):\n%s", filename.c_str(), g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, - g_ogl_config.gl_version, infoLog); + g_ogl_config.gl_version, info_log.c_str()); } - - delete[] infoLog; } if (linkStatus != GL_TRUE) { @@ -336,6 +339,73 @@ bool ProgramShaderCache::CompileShader(SHADER& shader, const std::string& vcode, return true; } +bool ProgramShaderCache::CompileComputeShader(SHADER& shader, const std::string& code) +{ + // We need to enable GL_ARB_compute_shader for drivers that support the extension, + // but not GLSL 4.3. Mesa is one example. + std::string header; + if (g_ActiveConfig.backend_info.bSupportsComputeShaders && + g_ogl_config.eSupportedGLSLVersion < GLSL_430) + { + header = "#extension GL_ARB_compute_shader : enable\n"; + } + + GLuint shader_id = CompileSingleShader(GL_COMPUTE_SHADER, header + code); + if (!shader_id) + return false; + + GLuint pid = shader.glprogid = glCreateProgram(); + glAttachShader(pid, shader_id); + if (g_ogl_config.bSupportsGLSLCache) + glProgramParameteri(pid, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, GL_TRUE); + + shader.SetProgramBindings(true); + + glLinkProgram(pid); + + // original shaders aren't needed any more + glDeleteShader(shader_id); + + GLint linkStatus; + glGetProgramiv(pid, GL_LINK_STATUS, &linkStatus); + GLsizei length = 0; + glGetProgramiv(pid, GL_INFO_LOG_LENGTH, &length); + if (linkStatus != GL_TRUE || (length > 1 && DEBUG_GLSL)) + { + std::string info_log; + info_log.resize(length); + glGetProgramInfoLog(pid, length, &length, &info_log[0]); + ERROR_LOG(VIDEO, "Program info log:\n%s", info_log.c_str()); + + std::string filename = + StringFromFormat("%sbad_p_%d.txt", File::GetUserPath(D_DUMP_IDX).c_str(), num_failures++); + std::ofstream file; + OpenFStream(file, filename, std::ios_base::out); + file << s_glsl_header << code; + file << info_log; + file.close(); + + if (linkStatus != GL_TRUE) + { + PanicAlert("Failed to link shaders: %s\n" + "Debug info (%s, %s, %s):\n%s", + filename.c_str(), g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, + g_ogl_config.gl_version, info_log.c_str()); + } + } + if (linkStatus != GL_TRUE) + { + // Compile failed + ERROR_LOG(VIDEO, "Program linking failed; see info log"); + + // Don't try to use this shader + glDeleteProgram(pid); + return false; + } + + return true; +} + GLuint ProgramShaderCache::CompileSingleShader(GLuint type, const std::string& code) { GLuint result = glCreateShader(type); @@ -351,31 +421,43 @@ GLuint ProgramShaderCache::CompileSingleShader(GLuint type, const std::string& c if (compileStatus != GL_TRUE || (length > 1 && DEBUG_GLSL)) { - GLsizei charsWritten; - GLchar* infoLog = new GLchar[length]; - glGetShaderInfoLog(result, length, &charsWritten, infoLog); - ERROR_LOG(VIDEO, "%s Shader info log:\n%s", - type == GL_VERTEX_SHADER ? "VS" : type == GL_FRAGMENT_SHADER ? "PS" : "GS", infoLog); + std::string info_log; + info_log.resize(length); + glGetShaderInfoLog(result, length, &length, &info_log[0]); + + const char* prefix = ""; + switch (type) + { + case GL_VERTEX_SHADER: + prefix = "vs"; + break; + case GL_GEOMETRY_SHADER: + prefix = "gs"; + break; + case GL_FRAGMENT_SHADER: + prefix = "ps"; + break; + case GL_COMPUTE_SHADER: + prefix = "cs"; + break; + } + + ERROR_LOG(VIDEO, "%s Shader info log:\n%s", prefix, info_log.c_str()); std::string filename = StringFromFormat( - "%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), - type == GL_VERTEX_SHADER ? "vs" : type == GL_FRAGMENT_SHADER ? "ps" : "gs", num_failures++); + "%sbad_%s_%04i.txt", File::GetUserPath(D_DUMP_IDX).c_str(), prefix, num_failures++); std::ofstream file; OpenFStream(file, filename, std::ios_base::out); - file << s_glsl_header << code << infoLog; + file << s_glsl_header << code << info_log; file.close(); if (compileStatus != GL_TRUE) { PanicAlert("Failed to compile %s shader: %s\n" "Debug info (%s, %s, %s):\n%s", - type == GL_VERTEX_SHADER ? "vertex" : type == GL_FRAGMENT_SHADER ? "pixel" : - "geometry", - filename.c_str(), g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, - g_ogl_config.gl_version, infoLog); + prefix, filename.c_str(), g_ogl_config.gl_vendor, g_ogl_config.gl_renderer, + g_ogl_config.gl_version, info_log.c_str()); } - - delete[] infoLog; } if (compileStatus != GL_TRUE) { @@ -539,11 +621,9 @@ void ProgramShaderCache::CreateHeader() std::string earlyz_string = ""; if (g_ActiveConfig.backend_info.bSupportsEarlyZ) { - if (g_ogl_config.bSupportsEarlyFragmentTests) + if (g_ogl_config.bSupportsImageLoadStore) { earlyz_string = "#define FORCE_EARLY_Z layout(early_fragment_tests) in\n"; - if (!is_glsles) // GLES supports this by default - earlyz_string += "#extension GL_ARB_shader_image_load_store : enable\n"; } else if (g_ogl_config.bSupportsConservativeDepth) { @@ -569,6 +649,7 @@ void ProgramShaderCache::CreateHeader() "%s\n" // texture buffer "%s\n" // ES texture buffer "%s\n" // ES dual source blend + "%s\n" // shader image load store // Precision defines for GLSL ES "%s\n" @@ -576,6 +657,7 @@ void ProgramShaderCache::CreateHeader() "%s\n" "%s\n" "%s\n" + "%s\n" // Silly differences "#define float2 vec2\n" @@ -638,12 +720,17 @@ void ProgramShaderCache::CreateHeader() "" , + g_ogl_config.bSupportsImageLoadStore && + ((!is_glsles && v < GLSL_430) || (is_glsles && v < GLSLES_310)) ? + "#extension GL_ARB_shader_image_load_store : enable" : + "", is_glsles ? "precision highp float;" : "", is_glsles ? "precision highp int;" : "", is_glsles ? "precision highp sampler2DArray;" : "", (is_glsles && g_ActiveConfig.backend_info.bSupportsPaletteConversion) ? "precision highp usamplerBuffer;" : "", - v > GLSLES_300 ? "precision highp sampler2DMS;" : ""); + v > GLSLES_300 ? "precision highp sampler2DMS;" : "", + v >= GLSLES_310 ? "precision highp image2DArray;" : ""); } void ProgramShaderCache::ProgramShaderCacheInserter::Read(const SHADERUID& key, const u8* value, diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h index c471db63ed..a8b2bfcbc1 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h @@ -46,7 +46,7 @@ struct SHADER std::string strvprog, strpprog, strgprog; void SetProgramVariables(); - void SetProgramBindings(); + void SetProgramBindings(bool is_compute); void Bind(); }; @@ -67,6 +67,7 @@ public: static bool CompileShader(SHADER& shader, const std::string& vcode, const std::string& pcode, const std::string& gcode = ""); + static bool CompileComputeShader(SHADER& shader, const std::string& code); static GLuint CompileSingleShader(GLuint type, const std::string& code); static void UploadConstants(); diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 60ae27a3dc..df2d7cb790 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -457,10 +457,10 @@ Renderer::Renderer() GLExtensions::Supports("GL_OES_texture_storage_multisample_2d_array"); g_ogl_config.bSupports2DTextureStorageMultisample = GLExtensions::Supports("GL_ARB_texture_storage_multisample"); - g_ogl_config.bSupportsEarlyFragmentTests = - GLExtensions::Supports("GL_ARB_shader_image_load_store"); + g_ogl_config.bSupportsImageLoadStore = GLExtensions::Supports("GL_ARB_shader_image_load_store"); g_ogl_config.bSupportsConservativeDepth = GLExtensions::Supports("GL_ARB_conservative_depth"); g_ogl_config.bSupportsAniso = GLExtensions::Supports("GL_EXT_texture_filter_anisotropic"); + g_Config.backend_info.bSupportsComputeShaders = GLExtensions::Supports("GL_ARB_compute_shader"); if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3) { @@ -495,8 +495,9 @@ Renderer::Renderer() g_ogl_config.eSupportedGLSLVersion = GLSLES_310; g_ogl_config.bSupportsAEP = GLExtensions::Supports("GL_ANDROID_extension_pack_es31a"); g_Config.backend_info.bSupportsBindingLayout = true; - g_ogl_config.bSupportsEarlyFragmentTests = true; + g_ogl_config.bSupportsImageLoadStore = true; g_Config.backend_info.bSupportsGeometryShaders = g_ogl_config.bSupportsAEP; + g_Config.backend_info.bSupportsComputeShaders = true; g_Config.backend_info.bSupportsGSInstancing = g_Config.backend_info.bSupportsGeometryShaders && g_ogl_config.SupportedESPointSize > 0; g_Config.backend_info.bSupportsSSAA = g_ogl_config.bSupportsAEP; @@ -517,8 +518,9 @@ Renderer::Renderer() g_ogl_config.eSupportedGLSLVersion = GLSLES_320; g_ogl_config.bSupportsAEP = GLExtensions::Supports("GL_ANDROID_extension_pack_es31a"); g_Config.backend_info.bSupportsBindingLayout = true; - g_ogl_config.bSupportsEarlyFragmentTests = true; + g_ogl_config.bSupportsImageLoadStore = true; g_Config.backend_info.bSupportsGeometryShaders = true; + g_Config.backend_info.bSupportsComputeShaders = true; g_Config.backend_info.bSupportsGSInstancing = g_ogl_config.SupportedESPointSize > 0; g_Config.backend_info.bSupportsPaletteConversion = true; g_Config.backend_info.bSupportsSSAA = true; @@ -545,8 +547,7 @@ Renderer::Renderer() else if (GLExtensions::Version() == 300) { g_ogl_config.eSupportedGLSLVersion = GLSL_130; - g_ogl_config.bSupportsEarlyFragmentTests = - false; // layout keyword is only supported on glsl150+ + g_ogl_config.bSupportsImageLoadStore = false; // layout keyword is only supported on glsl150+ g_ogl_config.bSupportsConservativeDepth = false; // layout keyword is only supported on glsl150+ g_Config.backend_info.bSupportsGeometryShaders = @@ -555,8 +556,7 @@ Renderer::Renderer() else if (GLExtensions::Version() == 310) { g_ogl_config.eSupportedGLSLVersion = GLSL_140; - g_ogl_config.bSupportsEarlyFragmentTests = - false; // layout keyword is only supported on glsl150+ + g_ogl_config.bSupportsImageLoadStore = false; // layout keyword is only supported on glsl150+ g_ogl_config.bSupportsConservativeDepth = false; // layout keyword is only supported on glsl150+ g_Config.backend_info.bSupportsGeometryShaders = @@ -570,10 +570,28 @@ Renderer::Renderer() { g_ogl_config.eSupportedGLSLVersion = GLSL_330; } + else if (GLExtensions::Version() >= 430) + { + // TODO: We should really parse the GL_SHADING_LANGUAGE_VERSION token. + g_ogl_config.eSupportedGLSLVersion = GLSL_430; + g_ogl_config.bSupportsTextureStorage = true; + g_ogl_config.bSupportsImageLoadStore = true; + g_Config.backend_info.bSupportsSSAA = true; + + // Compute shaders are core in GL4.3. + g_Config.backend_info.bSupportsComputeShaders = true; + } else { g_ogl_config.eSupportedGLSLVersion = GLSL_400; g_Config.backend_info.bSupportsSSAA = true; + + if (GLExtensions::Version() == 420) + { + // Texture storage and shader image load/store are core in GL4.2. + g_ogl_config.bSupportsTextureStorage = true; + g_ogl_config.bSupportsImageLoadStore = true; + } } // Desktop OpenGL can't have the Android Extension Pack @@ -582,7 +600,7 @@ Renderer::Renderer() // Either method can do early-z tests. See PixelShaderGen for details. g_Config.backend_info.bSupportsEarlyZ = - g_ogl_config.bSupportsEarlyFragmentTests || g_ogl_config.bSupportsConservativeDepth; + g_ogl_config.bSupportsImageLoadStore || g_ogl_config.bSupportsConservativeDepth; glGetIntegerv(GL_MAX_SAMPLES, &g_ogl_config.max_samples); if (g_ogl_config.max_samples < 1 || !g_ogl_config.bSupportsMSAA) diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index af223d3649..8ec6a21e0d 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -22,7 +22,8 @@ enum GLSL_VERSION GLSL_140, GLSL_150, GLSL_330, - GLSL_400, // and above + GLSL_400, // and above + GLSL_430, GLSLES_300, // GLES 3.0 GLSLES_310, // GLES 3.1 GLSLES_320, // GLES 3.2 @@ -54,8 +55,8 @@ struct VideoConfig bool bSupportsTextureStorage; bool bSupports2DTextureStorageMultisample; bool bSupports3DTextureStorageMultisample; - bool bSupportsEarlyFragmentTests; bool bSupportsConservativeDepth; + bool bSupportsImageLoadStore; bool bSupportsAniso; const char* gl_vendor;