From 620210cfc9f1b65d02f9dabf2af42821c9215270 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Sat, 2 May 2020 16:01:16 +1000 Subject: [PATCH] GPU/OpenGL: Use explicit bindings where possible --- src/core/gpu_hw_opengl.cpp | 126 ++++++++++++++++++++-------------- src/core/gpu_hw_shadergen.cpp | 86 ++++++++++++++++++++--- src/core/gpu_hw_shadergen.h | 25 ++++--- 3 files changed, 165 insertions(+), 72 deletions(-) diff --git a/src/core/gpu_hw_opengl.cpp b/src/core/gpu_hw_opengl.cpp index 4bea44cec..d7494e655 100644 --- a/src/core/gpu_hw_opengl.cpp +++ b/src/core/gpu_hw_opengl.cpp @@ -317,6 +317,7 @@ bool GPU_HW_OpenGL::CreateTextureBuffer() bool GPU_HW_OpenGL::CompilePrograms() { + const bool use_binding_layout = GPU_HW_ShaderGen::UseGLSLBindingLayout(); GPU_HW_ShaderGen shadergen(m_host_display->GetRenderAPI(), m_resolution_scale, m_true_color, m_scaled_dithering, m_texture_filtering, m_supports_dual_source_blend); @@ -336,25 +337,28 @@ bool GPU_HW_OpenGL::CompilePrograms() static_cast(render_mode), static_cast(texture_mode), ConvertToBoolUnchecked(dithering), ConvertToBoolUnchecked(interlacing)); - const auto link_callback = [this, textured](GL::Program& prog) { - prog.BindAttribute(0, "a_pos"); - prog.BindAttribute(1, "a_col0"); - if (textured) + const auto link_callback = [this, textured, use_binding_layout](GL::Program& prog) { + if (!use_binding_layout) { - prog.BindAttribute(2, "a_texcoord"); - prog.BindAttribute(3, "a_texpage"); - } - - if (!m_is_gles) - { - if (m_supports_dual_source_blend) + prog.BindAttribute(0, "a_pos"); + prog.BindAttribute(1, "a_col0"); + if (textured) { - prog.BindFragDataIndexed(0, "o_col0"); - prog.BindFragDataIndexed(1, "o_col1"); + prog.BindAttribute(2, "a_texcoord"); + prog.BindAttribute(3, "a_texpage"); } - else + + if (!m_is_gles || m_supports_dual_source_blend) { - prog.BindFragData(0, "o_col0"); + if (m_supports_dual_source_blend) + { + prog.BindFragDataIndexed(0, "o_col0"); + prog.BindFragDataIndexed(1, "o_col1"); + } + else + { + prog.BindFragData(0, "o_col0"); + } } } }; @@ -363,11 +367,14 @@ bool GPU_HW_OpenGL::CompilePrograms() if (!prog) return false; - prog->BindUniformBlock("UBOBlock", 1); - if (textured) + if (!use_binding_layout) { - prog->Bind(); - prog->Uniform1i("samp0", 0); + prog->BindUniformBlock("UBOBlock", 1); + if (textured) + { + prog->Bind(); + prog->Uniform1i("samp0", 0); + } } m_render_programs[render_mode][texture_mode][dithering][interlacing] = std::move(*prog); @@ -380,7 +387,8 @@ bool GPU_HW_OpenGL::CompilePrograms() if (!prog) return false; - prog->BindUniformBlock("UBOBlock", 1); + if (!use_binding_layout) + prog->BindUniformBlock("UBOBlock", 1); m_line_render_programs[render_mode][dithering][interlacing] = std::move(*prog); } } @@ -396,73 +404,89 @@ 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) { - if (!m_is_gles) - prog.BindFragData(0, "o_col0"); - }); + std::optional prog = + m_shader_cache.GetProgram(vs, {}, fs, [this, use_binding_layout](GL::Program& prog) { + if (!m_is_gles && !use_binding_layout) + prog.BindFragData(0, "o_col0"); + }); if (!prog) return false; - prog->BindUniformBlock("UBOBlock", 1); - - prog->Bind(); - prog->Uniform1i("samp0", 0); + if (!use_binding_layout) + { + prog->BindUniformBlock("UBOBlock", 1); + prog->Bind(); + prog->Uniform1i("samp0", 0); + } m_display_programs[depth_24bit][interlaced] = std::move(*prog); } } - std::optional prog = - m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), {}, - shadergen.GenerateInterlacedFillFragmentShader(), [this](GL::Program& prog) { - if (!m_is_gles) - prog.BindFragData(0, "o_col0"); - }); + std::optional prog = m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), {}, + shadergen.GenerateInterlacedFillFragmentShader(), + [this, use_binding_layout](GL::Program& prog) { + if (!m_is_gles && !use_binding_layout) + prog.BindFragData(0, "o_col0"); + }); if (!prog) return false; - prog->BindUniformBlock("UBOBlock", 1); - prog->Bind(); + if (!use_binding_layout) + prog->BindUniformBlock("UBOBlock", 1); + m_vram_interlaced_fill_program = std::move(*prog); prog = m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), {}, - shadergen.GenerateVRAMReadFragmentShader(), [this](GL::Program& prog) { - if (!m_is_gles) + shadergen.GenerateVRAMReadFragmentShader(), + [this, use_binding_layout](GL::Program& prog) { + if (!m_is_gles && !use_binding_layout) prog.BindFragData(0, "o_col0"); }); if (!prog) return false; - prog->BindUniformBlock("UBOBlock", 1); - prog->Bind(); - prog->Uniform1i("samp0", 0); + if (!use_binding_layout) + { + prog->BindUniformBlock("UBOBlock", 1); + prog->Bind(); + prog->Uniform1i("samp0", 0); + } m_vram_read_program = std::move(*prog); prog = m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), {}, - shadergen.GenerateVRAMCopyFragmentShader(), [this](GL::Program& prog) { - if (!m_is_gles) + shadergen.GenerateVRAMCopyFragmentShader(), + [this, use_binding_layout](GL::Program& prog) { + if (!m_is_gles && !use_binding_layout) prog.BindFragData(0, "o_col0"); }); if (!prog) return false; - prog->BindUniformBlock("UBOBlock", 1); - prog->Bind(); - prog->Uniform1i("samp0", 0); + if (!use_binding_layout) + { + prog->BindUniformBlock("UBOBlock", 1); + prog->Bind(); + prog->Uniform1i("samp0", 0); + } m_vram_copy_program = std::move(*prog); if (m_supports_texture_buffer) { prog = m_shader_cache.GetProgram(shadergen.GenerateScreenQuadVertexShader(), {}, - shadergen.GenerateVRAMWriteFragmentShader(), [this](GL::Program& prog) { - if (!m_is_gles) + shadergen.GenerateVRAMWriteFragmentShader(), + [this, use_binding_layout](GL::Program& prog) { + if (!m_is_gles && !use_binding_layout) prog.BindFragData(0, "o_col0"); }); if (!prog) return false; - prog->BindUniformBlock("UBOBlock", 1); - prog->Bind(); - prog->Uniform1i("samp0", 0); + if (!use_binding_layout) + { + prog->BindUniformBlock("UBOBlock", 1); + prog->Bind(); + prog->Uniform1i("samp0", 0); + } m_vram_write_program = std::move(*prog); } diff --git a/src/core/gpu_hw_shadergen.cpp b/src/core/gpu_hw_shadergen.cpp index e41936858..2f7b1988c 100644 --- a/src/core/gpu_hw_shadergen.cpp +++ b/src/core/gpu_hw_shadergen.cpp @@ -17,11 +17,19 @@ GPU_HW_ShaderGen::GPU_HW_ShaderGen(HostDisplay::RenderAPI render_api, u32 resolu SetGLSLVersionString(); m_use_glsl_interface_blocks = (GLAD_GL_ES_VERSION_3_2 || GLAD_GL_VERSION_3_2); + m_use_glsl_binding_layout = UseGLSLBindingLayout(); } } GPU_HW_ShaderGen::~GPU_HW_ShaderGen() = default; +bool GPU_HW_ShaderGen::UseGLSLBindingLayout() +{ + return (GLAD_GL_ES_VERSION_3_1 || GLAD_GL_VERSION_4_2 || + (GLAD_GL_ARB_explicit_attrib_location && GLAD_GL_ARB_explicit_uniform_location && + GLAD_GL_ARB_shading_language_420pack)); +} + static void DefineMacro(std::stringstream& ss, const char* name, bool enabled) { ss << "#define " << name << " " << BoolToUInt32(enabled) << "\n"; @@ -41,13 +49,13 @@ void GPU_HW_ShaderGen::SetGLSLVersionString() int major_version = 0, minor_version = 0; if (std::sscanf(glsl_version_start, "%d.%d", &major_version, &minor_version) == 2) { - // Cap at GLSL 3.3, we're not using anything newer for now. - if (!glsl_es && major_version >= 4) + // Cap at GLSL 4.3, we're not using anything newer for now. + if (!glsl_es && (major_version > 4 || (major_version == 4 && minor_version > 3))) { - major_version = 3; + major_version = 4; minor_version = 30; } - else if (glsl_es && (major_version > 3 || minor_version > 20)) + else if (glsl_es && (major_version > 3 || (major_version == 3 && minor_version > 20))) { major_version = 3; minor_version = 20; @@ -75,6 +83,24 @@ void GPU_HW_ShaderGen::WriteHeader(std::stringstream& ss) if (m_render_api == HostDisplay::RenderAPI::OpenGL || m_render_api == HostDisplay::RenderAPI::OpenGLES) ss << m_glsl_version_string << "\n\n"; + // Extension enabling for OpenGL. + if (m_render_api == HostDisplay::RenderAPI::OpenGLES) + { + // Enable EXT_blend_func_extended for dual-source blend on OpenGL ES. + if (GLAD_GL_EXT_blend_func_extended) + ss << "#extension GL_EXT_blend_func_extended : require\n"; + } + else if (m_render_api == HostDisplay::RenderAPI::OpenGL) + { + // Need extensions for binding layout if GL<4.3. + if (m_use_glsl_binding_layout && !GLAD_GL_VERSION_4_3) + { + ss << "#extension GL_ARB_explicit_attrib_location : require\n"; + ss << "#extension GL_ARB_explicit_uniform_location : require\n"; + ss << "#extension GL_ARB_shading_language_420pack : require\n"; + } + } + DefineMacro(ss, "API_OPENGL", m_render_api == HostDisplay::RenderAPI::OpenGL); DefineMacro(ss, "API_OPENGL_ES", m_render_api == HostDisplay::RenderAPI::OpenGLES); DefineMacro(ss, "API_D3D11", m_render_api == HostDisplay::RenderAPI::D3D11); @@ -185,9 +211,16 @@ float4 RGBA5551ToRGBA8(uint v) void GPU_HW_ShaderGen::DeclareUniformBuffer(std::stringstream& ss, const std::initializer_list& members) { if (m_glsl) - ss << "layout(std140) uniform UBOBlock\n"; + { + if (m_use_glsl_binding_layout) + ss << "layout(std140, binding = 1) uniform UBOBlock\n"; + else + ss << "layout(std140) uniform UBOBlock\n"; + } else + { ss << "cbuffer UBOBlock : register(b0)\n"; + } ss << "{\n"; for (const char* member : members) @@ -199,6 +232,9 @@ void GPU_HW_ShaderGen::DeclareTexture(std::stringstream& ss, const char* name, u { if (m_glsl) { + if (m_use_glsl_binding_layout) + ss << "layout(binding = " << index << ") "; + ss << "uniform sampler2D " << name << ";\n"; } else @@ -213,6 +249,9 @@ void GPU_HW_ShaderGen::DeclareTextureBuffer(std::stringstream& ss, const char* n { if (m_glsl) { + if (m_use_glsl_binding_layout) + ss << "layout(binding = " << index << ") "; + ss << "uniform " << (is_int ? (is_unsigned ? "u" : "i") : "") << "samplerBuffer " << name << ";\n"; } else @@ -229,8 +268,20 @@ void GPU_HW_ShaderGen::DeclareVertexEntryPoint( { if (m_glsl) { - for (const char* attribute : attributes) - ss << "in " << attribute << ";\n"; + if (m_use_glsl_binding_layout && 0) + { + u32 attribute_counter = 0; + for (const char* attribute : attributes) + { + ss << "layout(location = " << attribute_counter << ") " << attribute << ";\n"; + attribute_counter++; + } + } + else + { + for (const char* attribute : attributes) + ss << "in " << attribute << ";\n"; + } if (m_use_glsl_interface_blocks) { @@ -330,9 +381,24 @@ void GPU_HW_ShaderGen::DeclareFragmentEntryPoint( if (declare_fragcoord) ss << "#define v_pos gl_FragCoord\n"; - ss << "out float4 o_col0;\n"; - if (dual_color_output) - ss << "out float4 o_col1;\n"; + if (m_use_glsl_binding_layout) + { + if (dual_color_output) + { + ss << "layout(location = 0, index = 0) out float4 o_col0;\n"; + ss << "layout(location = 0, index = 1) out float4 o_col1;\n"; + } + else + { + ss << "layout(location = 0) out float4 o_col0;\n"; + } + } + else + { + ss << "out float4 o_col0;\n"; + if (dual_color_output) + ss << "out float4 o_col1;\n"; + } ss << "\n"; diff --git a/src/core/gpu_hw_shadergen.h b/src/core/gpu_hw_shadergen.h index 8bc91d951..c69eea47a 100644 --- a/src/core/gpu_hw_shadergen.h +++ b/src/core/gpu_hw_shadergen.h @@ -11,6 +11,8 @@ public: bool texture_filtering, bool supports_dual_source_blend); ~GPU_HW_ShaderGen(); + static bool UseGLSLBindingLayout(); + std::string GenerateBatchVertexShader(bool textured); std::string GenerateBatchFragmentShader(GPU_HW::BatchRenderMode transparency, GPU::TextureMode texture_mode, bool dithering, bool interlacing); @@ -24,17 +26,6 @@ public: std::string GenerateVRAMWriteFragmentShader(); std::string GenerateVRAMCopyFragmentShader(); - HostDisplay::RenderAPI m_render_api; - u32 m_resolution_scale; - bool m_true_color; - bool m_scaled_dithering; - bool m_texture_filering; - bool m_glsl; - bool m_supports_dual_source_blend; - bool m_use_glsl_interface_blocks; - - std::string m_glsl_version_string; - private: void SetGLSLVersionString(); void WriteHeader(std::stringstream& ss); @@ -51,4 +42,16 @@ private: void WriteCommonFunctions(std::stringstream& ss); void WriteBatchUniformBuffer(std::stringstream& ss); + + HostDisplay::RenderAPI m_render_api; + u32 m_resolution_scale; + bool m_true_color; + bool m_scaled_dithering; + bool m_texture_filering; + bool m_glsl; + bool m_supports_dual_source_blend; + bool m_use_glsl_interface_blocks; + bool m_use_glsl_binding_layout; + + std::string m_glsl_version_string; };