diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2022-02-01 15:53:11 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2022-02-01 21:05:22 +0300 |
commit | 9e42b9827aca935214d5cc60453b78acac53da17 (patch) | |
tree | 92c4b2a797897f962160924eee841e0b898d1155 | |
parent | 9bbfade772152032985e7492393dffce2500f676 (diff) |
GPUShader: Add support for vertex shader gl_Layer and fallback
This adds the possibility to use the `gpu_Layer` builtin to
support layered rendering without geometry shader.
The `BuiltinBits::LAYER` builtin needs to be manually added
to the `GPUShaderCreateInfo` in order to use this feature.
Note: This is only available for shaders using `GPUShaderCreateInfo`.
A geometry shader fallback is generated if the extension
`AMD_shader_explicit_vertex_parameter` is not available.
-rw-r--r-- | source/blender/gpu/opengl/gl_backend.cc | 3 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_context.hh | 1 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader.cc | 80 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader.hh | 8 |
4 files changed, 89 insertions, 3 deletions
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 92d180f1140..2ced2639c02 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -248,6 +248,7 @@ static void detect_workarounds() GLContext::direct_state_access_support = false; GLContext::fixed_restart_index_support = false; GLContext::geometry_shader_invocations = false; + GLContext::layered_rendering_support = false; GLContext::multi_bind_support = false; GLContext::multi_draw_indirect_support = false; GLContext::shader_draw_parameters_support = false; @@ -445,6 +446,7 @@ bool GLContext::direct_state_access_support = false; bool GLContext::explicit_location_support = false; bool GLContext::geometry_shader_invocations = false; bool GLContext::fixed_restart_index_support = false; +bool GLContext::layered_rendering_support = false; bool GLContext::multi_bind_support = false; bool GLContext::multi_draw_indirect_support = false; bool GLContext::shader_draw_parameters_support = false; @@ -505,6 +507,7 @@ void GLBackend::capabilities_init() GLContext::explicit_location_support = GLEW_VERSION_4_3; GLContext::geometry_shader_invocations = GLEW_ARB_gpu_shader5; GLContext::fixed_restart_index_support = GLEW_ARB_ES3_compatibility; + GLContext::layered_rendering_support = GLEW_AMD_vertex_shader_layer; GLContext::multi_bind_support = GLEW_ARB_multi_bind; GLContext::multi_draw_indirect_support = GLEW_ARB_multi_draw_indirect; GLContext::shader_draw_parameters_support = GLEW_ARB_shader_draw_parameters; diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index dd22418972b..20a7417b358 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -72,6 +72,7 @@ class GLContext : public Context { static bool explicit_location_support; static bool geometry_shader_invocations; static bool fixed_restart_index_support; + static bool layered_rendering_support; static bool multi_bind_support; static bool multi_draw_indirect_support; static bool shader_draw_parameters_support; diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 810d07e6ef1..4649d32deee 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -439,6 +439,9 @@ std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) con for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) { print_interface(ss, "out", *iface); } + if (!GLContext::layered_rendering_support && bool(info.builtins_ & BuiltinBits::LAYER)) { + ss << "out int gpu_Layer;\n"; + } ss << "\n"; return ss.str(); } @@ -501,7 +504,7 @@ static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInf const StringRefNull &name) { for (auto *iface : ifaces) { - if (iface->name == name) { + if (iface->instance_name == name) { return iface; } } @@ -510,8 +513,8 @@ static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInf std::string GLShader::geometry_interface_declare(const ShaderCreateInfo &info) const { - std::stringstream ss; + ss << "\n/* Interfaces. */\n"; for (const StageInterfaceInfo *iface : info.vertex_out_interfaces_) { bool has_matching_output_iface = find_interface_by_name(info.geometry_out_interfaces_, @@ -545,6 +548,65 @@ std::string GLShader::compute_layout_declare(const ShaderCreateInfo &info) const ss << "\n"; return ss.str(); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Passthrough geometry shader emulation + * + * \{ */ + +std::string GLShader::workaround_geometry_shader_source_create( + const shader::ShaderCreateInfo &info) +{ + std::stringstream ss; + + const bool do_layer_workaround = !GLContext::layered_rendering_support && + bool(info.builtins_ & BuiltinBits::LAYER); + const bool do_barycentric_workaround = !GLContext::native_barycentrics_support && + bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD); + + shader::ShaderCreateInfo info_modified = info; + info_modified.geometry_out_interfaces_ = info_modified.vertex_out_interfaces_; + /** + * NOTE(@fclem): Assuming we will render TRIANGLES. This will not work with other primitive + * types. In this case, it might not trigger an error on some implementations. + */ + info_modified.geometry_layout(PrimitiveIn::TRIANGLES, PrimitiveOut::TRIANGLE_STRIP, 3); + + ss << geometry_layout_declare(info_modified); + ss << geometry_interface_declare(info_modified); + if (do_layer_workaround) { + ss << "in int gpu_Layer[];\n"; + } + ss << "\n"; + + ss << "void main()\n"; + ss << "{\n"; + if (do_layer_workaround) { + ss << " gl_Layer = gpu_Layer[0];\n"; + } + for (auto i : IndexRange(3)) { + for (auto iface : info_modified.vertex_out_interfaces_) { + for (auto &inout : iface->inouts) { + ss << " " << iface->instance_name << "_out." << inout.name; + ss << " = " << iface->instance_name << "_in[" << i << "]." << inout.name << ";\n"; + } + } + ss << " gl_Position = gl_in[" << i << "].gl_Position;\n"; + ss << " EmitVertex();\n"; + } + ss << "}\n"; + return ss.str(); +} + +bool GLShader::do_geometry_shader_injection(const shader::ShaderCreateInfo *info) +{ + BuiltinBits builtins = info->builtins_; + if (!GLContext::native_barycentrics_support && bool(builtins & BuiltinBits::BARYCENTRIC_COORD)) { + return true; + } + return false; +} /** \} */ @@ -555,7 +617,7 @@ std::string GLShader::compute_layout_declare(const ShaderCreateInfo &info) const static char *glsl_patch_default_get() { /** Used for shader patching. Init once. */ - static char patch[700] = "\0"; + static char patch[1024] = "\0"; if (patch[0] != '\0') { return patch; } @@ -599,6 +661,10 @@ static char *glsl_patch_default_get() STR_CONCAT(patch, slen, "#extension GL_ARB_shader_image_load_store: enable\n"); STR_CONCAT(patch, slen, "#extension GL_ARB_shading_language_420pack: enable\n"); } + if (GLContext::layered_rendering_support) { + STR_CONCAT(patch, slen, "#extension GL_AMD_vertex_shader_layer: enable\n"); + STR_CONCAT(patch, slen, "#define gpu_Layer gl_Layer\n"); + } /* Fallbacks. */ if (!GLContext::shader_draw_parameters_support) { @@ -715,6 +781,14 @@ bool GLShader::finalize(const shader::ShaderCreateInfo *info) return false; } + if (info && do_geometry_shader_injection(info)) { + std::string source = workaround_geometry_shader_source_create(*info); + Vector<const char *> sources; + sources.append("version"); + sources.append(source.c_str()); + geometry_shader_from_glsl(sources); + } + glLinkProgram(shader_program_); GLint status; diff --git a/source/blender/gpu/opengl/gl_shader.hh b/source/blender/gpu/opengl/gl_shader.hh index a82ab026c16..cc1c93142f8 100644 --- a/source/blender/gpu/opengl/gl_shader.hh +++ b/source/blender/gpu/opengl/gl_shader.hh @@ -94,6 +94,14 @@ class GLShader : public Shader { /** Create, compile and attach the shader stage to the shader program. */ GLuint create_shader_stage(GLenum gl_stage, MutableSpan<const char *> sources); + /** + * \brief features available on newer implementation such as native barycentric coordinates + * and layered rendering, necessitate a geometry shader to work on older hardware. + */ + std::string workaround_geometry_shader_source_create(const shader::ShaderCreateInfo &info); + + bool do_geometry_shader_injection(const shader::ShaderCreateInfo *info); + MEM_CXX_CLASS_ALLOC_FUNCS("GLShader"); }; |