diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 9c0f10a41..d7a2afa3d 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -61,6 +61,37 @@ layout (std140) uniform shader_data { }; )"; +static std::string GetVertexInterfaceDeclaration(bool is_output, bool separable_shader) { + std::string out; + + auto append_variable = [&](const char* var, int location) { + if (separable_shader) { + out += "layout (location=" + std::to_string(location) + ") "; + } + out += std::string(is_output ? "out " : "in ") + var + ";\n"; + }; + + append_variable("vec4 primary_color", ATTRIBUTE_COLOR); + append_variable("vec2 texcoord0", ATTRIBUTE_TEXCOORD0); + append_variable("vec2 texcoord1", ATTRIBUTE_TEXCOORD1); + append_variable("vec2 texcoord2", ATTRIBUTE_TEXCOORD2); + append_variable("float texcoord0_w", ATTRIBUTE_TEXCOORD0_W); + append_variable("vec4 normquat", ATTRIBUTE_NORMQUAT); + append_variable("vec3 view", ATTRIBUTE_VIEW); + + if (is_output && separable_shader) { + // gl_PerVertex redeclaration is required for separate shader object + out += R"( +out gl_PerVertex { + vec4 gl_Position; + float gl_ClipDistance[2]; +}; +)"; + } + + return out; +} + PicaShaderConfig PicaShaderConfig::BuildFromRegs(const Pica::Regs& regs) { PicaShaderConfig res; @@ -206,11 +237,11 @@ static std::string SampleTexture(const PicaShaderConfig& config, unsigned textur // Only unit 0 respects the texturing type switch (state.texture0_type) { case TexturingRegs::TextureConfig::Texture2D: - return "texture(tex[0], texcoord[0])"; + return "texture(tex0, texcoord0)"; case TexturingRegs::TextureConfig::Projection2D: - return "textureProj(tex[0], vec3(texcoord[0], texcoord0_w))"; + return "textureProj(tex0, vec3(texcoord0, texcoord0_w))"; case TexturingRegs::TextureConfig::TextureCube: - return "texture(tex_cube, vec3(texcoord[0], texcoord0_w))"; + return "texture(tex_cube, vec3(texcoord0, texcoord0_w))"; case TexturingRegs::TextureConfig::Shadow2D: case TexturingRegs::TextureConfig::ShadowCube: NGLOG_CRITICAL(HW_GPU, "Unhandled shadow texture"); @@ -220,15 +251,15 @@ static std::string SampleTexture(const PicaShaderConfig& config, unsigned textur LOG_CRITICAL(HW_GPU, "Unhandled texture type %x", static_cast(state.texture0_type)); UNIMPLEMENTED(); - return "texture(tex[0], texcoord[0])"; + return "texture(tex0, texcoord0)"; } case 1: - return "texture(tex[1], texcoord[1])"; + return "texture(tex1, texcoord1)"; case 2: if (state.texture2_use_coord1) - return "texture(tex[2], texcoord[1])"; + return "texture(tex2, texcoord1)"; else - return "texture(tex[2], texcoord[2])"; + return "texture(tex2, texcoord2)"; case 3: if (state.proctex.enable) { return "ProcTex()"; @@ -1019,7 +1050,12 @@ float ProcTexNoiseCoef(vec2 x) { } out += "vec4 ProcTex() {\n"; - out += "vec2 uv = abs(texcoord[" + std::to_string(config.state.proctex.coord) + "]);\n"; + if (config.state.proctex.coord < 3) { + out += "vec2 uv = abs(texcoord" + std::to_string(config.state.proctex.coord) + ");\n"; + } else { + NGLOG_CRITICAL(Render_OpenGL, "Unexpected proctex.coord >= 3"); + out += "vec2 uv = abs(texcoord0);\n"; + } // Get shift offset before noise generation out += "float u_shift = "; @@ -1084,23 +1120,24 @@ float ProcTexNoiseCoef(vec2 x) { } } -std::string GenerateFragmentShader(const PicaShaderConfig& config) { +std::string GenerateFragmentShader(const PicaShaderConfig& config, bool separable_shader) { const auto& state = config.state; - std::string out = R"( -#version 330 core + std::string out = "#version 330 core\n"; + if (separable_shader) { + out += "#extension GL_ARB_separate_shader_objects : enable\n"; + } -in vec4 primary_color; -in vec2 texcoord[3]; -in float texcoord0_w; -in vec4 normquat; -in vec3 view; + out += GetVertexInterfaceDeclaration(false, separable_shader); + out += R"( in vec4 gl_FragCoord; out vec4 color; -uniform sampler2D tex[3]; +uniform sampler2D tex0; +uniform sampler2D tex1; +uniform sampler2D tex2; uniform samplerCube tex_cube; uniform samplerBuffer lighting_lut; uniform samplerBuffer fog_lut; @@ -1228,8 +1265,11 @@ vec4 secondary_fragment_color = vec4(0.0); return out; } -std::string GenerateVertexShader() { +std::string GenerateTrivialVertexShader(bool separable_shader) { std::string out = "#version 330 core\n"; + if (separable_shader) { + out += "#extension GL_ARB_separate_shader_objects : enable\n"; + } out += "layout(location = " + std::to_string((int)ATTRIBUTE_POSITION) + ") in vec4 vert_position;\n"; @@ -1246,14 +1286,7 @@ std::string GenerateVertexShader() { ") in vec4 vert_normquat;\n"; out += "layout(location = " + std::to_string((int)ATTRIBUTE_VIEW) + ") in vec3 vert_view;\n"; - out += R"( -out vec4 primary_color; -out vec2 texcoord[3]; -out float texcoord0_w; -out vec4 normquat; -out vec3 view; - -)"; + out += GetVertexInterfaceDeclaration(true, separable_shader); out += UniformBlockDef; @@ -1261,9 +1294,9 @@ out vec3 view; void main() { primary_color = vert_color; - texcoord[0] = vert_texcoord0; - texcoord[1] = vert_texcoord1; - texcoord[2] = vert_texcoord2; + texcoord0 = vert_texcoord0; + texcoord1 = vert_texcoord1; + texcoord2 = vert_texcoord2; texcoord0_w = vert_texcoord0_w; normquat = vert_normquat; view = vert_view; diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index 929c3c015..f900e3091 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h @@ -9,7 +9,9 @@ #include #include #include +#include "common/hash.h" #include "video_core/regs.h" +#include "video_core/shader/shader.h" namespace GLShader { @@ -132,18 +134,21 @@ struct PicaShaderConfig : Common::HashableStruct { }; /** - * Generates the GLSL vertex shader program source code for the current Pica state + * Generates the GLSL vertex shader program source code that accepts vertices from software shader + * and directly passes them to the fragment shader. + * @param separable_shader generates shader that can be used for separate shader object * @returns String of the shader source code */ -std::string GenerateVertexShader(); +std::string GenerateTrivialVertexShader(bool separable_shader); /** * Generates the GLSL fragment shader program source code for the current Pica state * @param config ShaderCacheKey object generated for the current Pica state, used for the shader * configuration (NOTE: Use state in this struct only, not the Pica registers!) + * @param separable_shader generates shader that can be used for separate shader object * @returns String of the shader source code */ -std::string GenerateFragmentShader(const PicaShaderConfig& config); +std::string GenerateFragmentShader(const PicaShaderConfig& config, bool separable_shader); } // namespace GLShader