diff options
Diffstat (limited to 'source/blender/gpu/opengl')
-rw-r--r-- | source/blender/gpu/opengl/gl_backend.cc | 13 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_compute.cc | 2 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_context.hh | 2 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_debug.cc | 10 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_debug_layer.cc | 4 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_framebuffer.cc | 7 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_framebuffer.hh | 2 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader.cc | 325 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader.hh | 9 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader_interface.cc | 65 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader_log.cc | 9 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_state.hh | 13 |
12 files changed, 428 insertions, 33 deletions
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 1a445ebd7eb..2ee7c0503f4 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -240,6 +240,7 @@ static void detect_workarounds() GLContext::unused_fb_slot_workaround = true; /* Turn off extensions. */ GCaps.shader_image_load_store_support = false; + GCaps.shader_storage_buffer_objects_support = false; GLContext::base_instance_support = false; GLContext::clear_texture_support = false; GLContext::copy_image_support = false; @@ -247,6 +248,8 @@ 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::native_barycentric_support = false; GLContext::multi_bind_support = false; GLContext::multi_draw_indirect_support = false; GLContext::shader_draw_parameters_support = false; @@ -419,6 +422,12 @@ static void detect_workarounds() strstr(renderer, "HD Graphics 4000")) { GLContext::generate_mipmap_workaround = true; } + + /* Buggy interface query functions cause crashes when handling SSBOs (T93680) */ + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY) && + (strstr(renderer, "HD Graphics 4400") || strstr(renderer, "HD Graphics 4600"))) { + GCaps.shader_storage_buffer_objects_support = false; + } } // namespace blender::gpu /** Internal capabilities. */ @@ -438,6 +447,8 @@ 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::native_barycentric_support = false; bool GLContext::multi_bind_support = false; bool GLContext::multi_draw_indirect_support = false; bool GLContext::shader_draw_parameters_support = false; @@ -498,6 +509,8 @@ 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::native_barycentric_support = GLEW_AMD_shader_explicit_vertex_parameter; 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_compute.cc b/source/blender/gpu/opengl/gl_compute.cc index fa8317dde4a..14164ee181b 100644 --- a/source/blender/gpu/opengl/gl_compute.cc +++ b/source/blender/gpu/opengl/gl_compute.cc @@ -28,8 +28,8 @@ namespace blender::gpu { void GLCompute::dispatch(int group_x_len, int group_y_len, int group_z_len) { + GL_CHECK_RESOURCES("Compute"); glDispatchCompute(group_x_len, group_y_len, group_z_len); - debug::check_gl_error("Dispatch Compute"); } } // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index dd22418972b..b7a74863ac4 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -72,6 +72,8 @@ 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 native_barycentric_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_debug.cc b/source/blender/gpu/opengl/gl_debug.cc index 0a06d9cdb7c..95dea43636d 100644 --- a/source/blender/gpu/opengl/gl_debug.cc +++ b/source/blender/gpu/opengl/gl_debug.cc @@ -108,6 +108,11 @@ static void APIENTRY debug_callback(GLenum UNUSED(source), GPU_debug_get_groups_names(sizeof(debug_groups), debug_groups); CLG_Severity clog_severity; + if (GPU_debug_group_match(GPU_DEBUG_SHADER_COMPILATION_GROUP)) { + /** Do not duplicate shader compilation error/warnings. */ + return; + } + switch (type) { case GL_DEBUG_TYPE_ERROR: case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: @@ -191,6 +196,9 @@ void init_gl_callbacks() void check_gl_error(const char *info) { + if (!(G.debug & G_DEBUG_GPU)) { + return; + } GLenum error = glGetError(); #define ERROR_CASE(err) \ @@ -339,7 +347,7 @@ void object_label(GLenum type, GLuint object, const char *name) char label[64]; SNPRINTF(label, "%s%s%s", to_str_prefix(type), name, to_str_suffix(type)); /* Small convenience for caller. */ - if (ELEM(type, GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_VERTEX_SHADER)) { + if (ELEM(type, GL_FRAGMENT_SHADER, GL_GEOMETRY_SHADER, GL_VERTEX_SHADER, GL_COMPUTE_SHADER)) { type = GL_SHADER; } if (ELEM(type, GL_UNIFORM_BUFFER)) { diff --git a/source/blender/gpu/opengl/gl_debug_layer.cc b/source/blender/gpu/opengl/gl_debug_layer.cc index e624cb9ee46..b82bf10ebe9 100644 --- a/source/blender/gpu/opengl/gl_debug_layer.cc +++ b/source/blender/gpu/opengl/gl_debug_layer.cc @@ -82,6 +82,8 @@ DEBUG_FUNC_DECLARE(PFNGLDRAWBUFFERSPROC, void, glDrawBuffers, GLsizei, n, const DEBUG_FUNC_DECLARE(PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXBASEINSTANCEPROC, void, glDrawElementsInstancedBaseVertexBaseInstance, GLenum, mode, GLsizei, count, GLenum, type, const void *, indices, GLsizei, primcount, GLint, basevertex, GLuint, baseinstance); DEBUG_FUNC_DECLARE(PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC, void, glDrawElementsInstancedBaseVertex, GLenum, mode, GLsizei, count, GLenum, type, const void *, indices, GLsizei, instancecount, GLint, basevertex); DEBUG_FUNC_DECLARE(PFNGLENDQUERYPROC, void, glEndQuery, GLenum, target); +DEBUG_FUNC_DECLARE(PFNGLDISPATCHCOMPUTEPROC, void, glDispatchCompute, GLuint, num_groups_x, GLuint, num_groups_y, GLuint, num_groups_z); +DEBUG_FUNC_DECLARE(PFNGLDISPATCHCOMPUTEINDIRECTPROC, void, glDispatchComputeIndirect, GLintptr, indirect); DEBUG_FUNC_DECLARE(PFNGLENDTRANSFORMFEEDBACKPROC, void, glEndTransformFeedback, void); DEBUG_FUNC_DECLARE(PFNGLFRAMEBUFFERTEXTURE2DPROC, void, glFramebufferTexture2D, GLenum, target, GLenum, attachment, GLenum, textarget, GLuint, texture, GLint, level); DEBUG_FUNC_DECLARE(PFNGLFRAMEBUFFERTEXTURELAYERPROC, void, glFramebufferTextureLayer, GLenum, target, GLenum, attachment, GLuint, texture, GLint, level, GLint, layer); @@ -130,6 +132,8 @@ void init_debug_layer() DEBUG_WRAP(glDeleteSamplers); DEBUG_WRAP(glDeleteShader); DEBUG_WRAP(glDeleteVertexArrays); + DEBUG_WRAP(glDispatchCompute); + DEBUG_WRAP(glDispatchComputeIndirect); DEBUG_WRAP(glDrawArraysInstanced); DEBUG_WRAP(glDrawArraysInstancedBaseInstance); DEBUG_WRAP(glDrawBuffers); diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc index 13f03195437..106a12bfefd 100644 --- a/source/blender/gpu/opengl/gl_framebuffer.cc +++ b/source/blender/gpu/opengl/gl_framebuffer.cc @@ -429,8 +429,15 @@ void GLFrameBuffer::read(eGPUFrameBufferBits plane, switch (plane) { case GPU_DEPTH_BIT: format = GL_DEPTH_COMPONENT; + BLI_assert_msg( + this->attachments_[GPU_FB_DEPTH_ATTACHMENT].tex != nullptr || + this->attachments_[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex != nullptr, + "GPUFramebuffer: Error: Trying to read depth without a depth buffer attached."); break; case GPU_COLOR_BIT: + BLI_assert_msg( + mode != GL_NONE, + "GPUFramebuffer: Error: Trying to read a color slot without valid attachment."); format = channel_len_to_gl(channel_len); /* TODO: needed for selection buffers to work properly, this should be handled better. */ if (format == GL_RED && type == GL_UNSIGNED_INT) { diff --git a/source/blender/gpu/opengl/gl_framebuffer.hh b/source/blender/gpu/opengl/gl_framebuffer.hh index 9ebe549efe7..00a7676dd3f 100644 --- a/source/blender/gpu/opengl/gl_framebuffer.hh +++ b/source/blender/gpu/opengl/gl_framebuffer.hh @@ -141,6 +141,8 @@ static inline GLenum to_gl(const GPUAttachmentType type) ATTACHMENT(COLOR_ATTACHMENT3); ATTACHMENT(COLOR_ATTACHMENT4); ATTACHMENT(COLOR_ATTACHMENT5); + ATTACHMENT(COLOR_ATTACHMENT6); + ATTACHMENT(COLOR_ATTACHMENT7); default: BLI_assert(0); return GL_COLOR_ATTACHMENT0; diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index cec85abae6f..9da35a2bc97 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -85,7 +85,7 @@ static const char *to_string(const Interpolation &interp) case Interpolation::NO_PERSPECTIVE: return "noperspective"; default: - return "unkown"; + return "unknown"; } } @@ -123,6 +123,74 @@ static const char *to_string(const Type &type) case Type::BOOL: return "bool"; default: + return "unknown"; + } +} + +static const char *to_string(const eGPUTextureFormat &type) +{ + switch (type) { + case GPU_RGBA8UI: + return "rgba8ui"; + case GPU_RGBA8I: + return "rgba8i"; + case GPU_RGBA8: + return "rgba8"; + case GPU_RGBA32UI: + return "rgba32ui"; + case GPU_RGBA32I: + return "rgba32i"; + case GPU_RGBA32F: + return "rgba32f"; + case GPU_RGBA16UI: + return "rgba16ui"; + case GPU_RGBA16I: + return "rgba16i"; + case GPU_RGBA16F: + return "rgba16f"; + case GPU_RGBA16: + return "rgba16"; + case GPU_RG8UI: + return "rg8ui"; + case GPU_RG8I: + return "rg8i"; + case GPU_RG8: + return "rg8"; + case GPU_RG32UI: + return "rg32ui"; + case GPU_RG32I: + return "rg32i"; + case GPU_RG32F: + return "rg32f"; + case GPU_RG16UI: + return "rg16ui"; + case GPU_RG16I: + return "rg16i"; + case GPU_RG16F: + return "rg16f"; + case GPU_RG16: + return "rg16"; + case GPU_R8UI: + return "r8ui"; + case GPU_R8I: + return "r8i"; + case GPU_R8: + return "r8"; + case GPU_R32UI: + return "r32ui"; + case GPU_R32I: + return "r32i"; + case GPU_R32F: + return "r32f"; + case GPU_R16UI: + return "r16ui"; + case GPU_R16I: + return "r16i"; + case GPU_R16F: + return "r16f"; + case GPU_R16: + return "r16"; + default: return "unkown"; } } @@ -217,6 +285,8 @@ static void print_image_type(std::ostream &os, case ImageType::UINT_2D_ARRAY: case ImageType::SHADOW_2D: case ImageType::SHADOW_2D_ARRAY: + case ImageType::DEPTH_2D: + case ImageType::DEPTH_2D_ARRAY: os << "2D"; break; case ImageType::FLOAT_3D: @@ -232,6 +302,8 @@ static void print_image_type(std::ostream &os, case ImageType::UINT_CUBE_ARRAY: case ImageType::SHADOW_CUBE: case ImageType::SHADOW_CUBE_ARRAY: + case ImageType::DEPTH_CUBE: + case ImageType::DEPTH_CUBE_ARRAY: os << "Cube"; break; default: @@ -250,6 +322,8 @@ static void print_image_type(std::ostream &os, case ImageType::UINT_CUBE_ARRAY: case ImageType::SHADOW_2D_ARRAY: case ImageType::SHADOW_CUBE_ARRAY: + case ImageType::DEPTH_2D_ARRAY: + case ImageType::DEPTH_CUBE_ARRAY: os << "Array"; break; default: @@ -271,16 +345,16 @@ static void print_image_type(std::ostream &os, static std::ostream &print_qualifier(std::ostream &os, const Qualifier &qualifiers) { - if ((qualifiers & Qualifier::RESTRICT) != Qualifier::RESTRICT) { - os << "restrict"; + if (bool(qualifiers & Qualifier::NO_RESTRICT) == false) { + os << "restrict "; } - if ((qualifiers & Qualifier::READ_ONLY) != Qualifier::READ_ONLY) { - os << "readonly"; + if (bool(qualifiers & Qualifier::READ) == false) { + os << "writeonly "; } - if ((qualifiers & Qualifier::WRITE_ONLY) != Qualifier::WRITE_ONLY) { - os << "writeonly"; + if (bool(qualifiers & Qualifier::WRITE) == false) { + os << "readonly "; } - return os << " "; + return os; } static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &res) @@ -288,7 +362,7 @@ static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &r if (GLContext::explicit_location_support) { os << "layout(binding = " << res.slot; if (res.bind_type == ShaderCreateInfo::Resource::BindType::IMAGE) { - os << ", " << res.image.format; + os << ", " << to_string(res.image.format); } else if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { os << ", std140"; @@ -328,8 +402,8 @@ static void print_resource(std::ostream &os, const ShaderCreateInfo::Resource &r array_offset = res.storagebuf.name.find_first_of("["); name_no_array = (array_offset == -1) ? res.storagebuf.name : StringRef(res.storagebuf.name.c_str(), array_offset); - os << "buffer "; print_qualifier(os, res.storagebuf.qualifiers); + os << "buffer "; os << name_no_array << " { " << res.storagebuf.type_name << " _" << res.storagebuf.name << "; };\n"; break; @@ -364,7 +438,7 @@ static void print_interface(std::ostream &os, const StageInterfaceInfo &iface, const StringRefNull &suffix = "") { - /* TODO(fclem) Move that to interface check. */ + /* TODO(@fclem): Move that to interface check. */ // if (iface.instance_name.is_empty()) { // BLI_assert_msg(0, "Interfaces require an instance name for geometry shader."); // std::cout << iface.name << ": Interfaces require an instance name for geometry shader.\n"; @@ -403,18 +477,37 @@ std::string GLShader::resources_declare(const ShaderCreateInfo &info) const } ss << "\n/* Push Constants. */\n"; for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) { - if (GLContext::explicit_location_support) { - ss << "layout(location = " << uniform.index << ") "; - } ss << "uniform " << to_string(uniform.type) << " " << uniform.name; if (uniform.array_size > 0) { ss << "[" << uniform.array_size << "]"; } ss << ";\n"; } +#if 0 /* T95278: This is not be enough to prevent some compilers think it is recursive. */ for (const ShaderCreateInfo::PushConst &uniform : info.push_constants_) { - ss << "#define " << uniform.name << " (" << uniform.name << ")\n"; + /* T95278: Double macro to avoid some compilers think it is recursive. */ + ss << "#define " << uniform.name << "_ " << uniform.name << "\n"; + ss << "#define " << uniform.name << " (" << uniform.name << "_)\n"; } +#endif + ss << "\n"; + return ss.str(); +} + +static std::string main_function_wrapper(std::string &pre_main, std::string &post_main) +{ + std::stringstream ss; + /* Prototype for the original main. */ + ss << "\n"; + ss << "void main_function_();\n"; + /* Wrapper to the main function in order to inject code processing on globals. */ + ss << "void main() {\n"; + ss << pre_main; + ss << " main_function_();\n"; + ss << post_main; + ss << "}\n"; + /* Rename the original main. */ + ss << "#define main main_function_\n"; ss << "\n"; return ss.str(); } @@ -422,10 +515,13 @@ std::string GLShader::resources_declare(const ShaderCreateInfo &info) const std::string GLShader::vertex_interface_declare(const ShaderCreateInfo &info) const { std::stringstream ss; + std::string post_main = ""; ss << "\n/* Inputs. */\n"; for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) { - if (GLContext::explicit_location_support) { + if (GLContext::explicit_location_support && + /* Fix issue with AMDGPU-PRO + workbench_prepass_mesh_vert.glsl being quantized. */ + GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL) == false) { ss << "layout(location = " << attr.index << ") "; } ss << "in " << to_string(attr.type) << " " << attr.name << ";\n"; @@ -434,13 +530,35 @@ 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"; + } + if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) { + if (!GLContext::native_barycentric_support) { + /* Disabled or unsupported. */ + } + else if (GLEW_AMD_shader_explicit_vertex_parameter) { + /* Need this for stable barycentric. */ + ss << "flat out vec4 gpu_pos_flat;\n"; + ss << "out vec4 gpu_pos;\n"; + + post_main += " gpu_pos = gpu_pos_flat = gl_Position;\n"; + } + } ss << "\n"; + + if (post_main.empty() == false) { + std::string pre_main = ""; + ss << main_function_wrapper(pre_main, post_main); + } return ss.str(); } std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) const { std::stringstream ss; + std::string pre_main = ""; + ss << "\n/* Interfaces. */\n"; const Vector<StageInterfaceInfo *> &in_interfaces = (info.geometry_source_.is_empty()) ? info.vertex_out_interfaces_ : @@ -448,6 +566,32 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c for (const StageInterfaceInfo *iface : in_interfaces) { print_interface(ss, "in", *iface); } + if (bool(info.builtins_ & BuiltinBits::BARYCENTRIC_COORD)) { + if (!GLContext::native_barycentric_support) { + ss << "smooth in vec3 gpu_BaryCoord;\n"; + ss << "noperspective in vec3 gpu_BaryCoordNoPersp;\n"; + } + else if (GLEW_AMD_shader_explicit_vertex_parameter) { + /* NOTE(fclem): This won't work with geometry shader. Hopefully, we don't need geometry + * shader workaround if this extension/feature is detected. */ + ss << "\n/* Stable Barycentric Coordinates. */\n"; + ss << "flat in vec4 gpu_pos_flat;\n"; + ss << "__explicitInterpAMD in vec4 gpu_pos;\n"; + /* Globals. */ + ss << "vec3 gpu_BaryCoord;\n"; + ss << "vec3 gpu_BaryCoordNoPersp;\n"; + ss << "\n"; + ss << "vec2 stable_bary_(vec2 in_bary) {\n"; + ss << " vec3 bary = vec3(in_bary, 1.0 - in_bary.x - in_bary.y);\n"; + ss << " if (interpolateAtVertexAMD(gpu_pos, 0) == gpu_pos_flat) { return bary.zxy; }\n"; + ss << " if (interpolateAtVertexAMD(gpu_pos, 2) == gpu_pos_flat) { return bary.yzx; }\n"; + ss << " return bary.xyz;\n"; + ss << "}\n"; + + pre_main += " gpu_BaryCoord = stable_bary_(gl_BaryCoordSmoothAMD);\n"; + pre_main += " gpu_BaryCoordNoPersp = stable_bary_(gl_BaryCoordNoPerspAMD);\n"; + } + } ss << "\n/* Outputs. */\n"; for (const ShaderCreateInfo::FragOut &output : info.fragment_outputs_) { ss << "layout(location = " << output.index; @@ -465,6 +609,11 @@ std::string GLShader::fragment_interface_declare(const ShaderCreateInfo &info) c ss << "out " << to_string(output.type) << " " << output.name << ";\n"; } ss << "\n"; + + if (pre_main.empty() == false) { + std::string post_main = ""; + ss << main_function_wrapper(pre_main, post_main); + } return ss.str(); } @@ -492,21 +641,125 @@ std::string GLShader::geometry_layout_declare(const ShaderCreateInfo &info) cons return ss.str(); } +static StageInterfaceInfo *find_interface_by_name(const Vector<StageInterfaceInfo *> &ifaces, + const StringRefNull &name) +{ + for (auto *iface : ifaces) { + if (iface->instance_name == name) { + return iface; + } + } + return nullptr; +} + 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_) { - print_interface(ss, "in", *iface, "[]"); + bool has_matching_output_iface = find_interface_by_name(info.geometry_out_interfaces_, + iface->instance_name) != nullptr; + const char *suffix = (has_matching_output_iface) ? "_in[]" : "[]"; + print_interface(ss, "in", *iface, suffix); } ss << "\n"; for (const StageInterfaceInfo *iface : info.geometry_out_interfaces_) { - print_interface(ss, "out", *iface); + bool has_matching_input_iface = find_interface_by_name(info.vertex_out_interfaces_, + iface->instance_name) != nullptr; + const char *suffix = (has_matching_input_iface) ? "_out" : ""; + print_interface(ss, "out", *iface, suffix); } ss << "\n"; return ss.str(); } +std::string GLShader::compute_layout_declare(const ShaderCreateInfo &info) const +{ + std::stringstream ss; + ss << "\n/* Compute Layout. */\n"; + ss << "layout(local_size_x = " << info.compute_layout_.local_size_x; + if (info.compute_layout_.local_size_y != -1) { + ss << ", local_size_y = " << info.compute_layout_.local_size_y; + } + if (info.compute_layout_.local_size_z != -1) { + ss << ", local_size_y = " << info.compute_layout_.local_size_z; + } + ss << ") in;\n"; + 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_barycentric_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"; + } + if (do_barycentric_workaround) { + ss << "smooth out vec3 gpu_BaryCoord;\n"; + ss << "noperspective out vec3 gpu_BaryCoordNoPersp;\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"; + } + } + if (do_barycentric_workaround) { + ss << " gpu_BaryCoordNoPersp = gpu_BaryCoord ="; + ss << " vec3(" << int(i == 0) << ", " << int(i == 1) << ", " << int(i == 2) << ");\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_barycentric_support && bool(builtins & BuiltinBits::BARYCENTRIC_COORD)) { + return true; + } + if (!GLContext::layered_rendering_support && bool(builtins & BuiltinBits::LAYER)) { + return true; + } + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -516,7 +769,7 @@ std::string GLShader::geometry_interface_declare(const ShaderCreateInfo &info) c static char *glsl_patch_default_get() { /** Used for shader patching. Init once. */ - static char patch[512] = "\0"; + static char patch[1024] = "\0"; if (patch[0] != '\0') { return patch; } @@ -543,6 +796,7 @@ static char *glsl_patch_default_get() if (GLContext::shader_draw_parameters_support) { STR_CONCAT(patch, slen, "#extension GL_ARB_shader_draw_parameters : enable\n"); STR_CONCAT(patch, slen, "#define GPU_ARB_shader_draw_parameters\n"); + STR_CONCAT(patch, slen, "#define gpu_BaseInstance gl_BaseInstanceARB\n"); } if (GLContext::geometry_shader_invocations) { STR_CONCAT(patch, slen, "#extension GL_ARB_gpu_shader5 : enable\n"); @@ -552,6 +806,31 @@ static char *glsl_patch_default_get() STR_CONCAT(patch, slen, "#extension GL_ARB_texture_cube_map_array : enable\n"); STR_CONCAT(patch, slen, "#define GPU_ARB_texture_cube_map_array\n"); } + if (!GLEW_VERSION_4_2 && GLEW_ARB_conservative_depth) { + STR_CONCAT(patch, slen, "#extension GL_ARB_conservative_depth : enable\n"); + } + if (GPU_shader_image_load_store_support()) { + 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"); + } + if (GLContext::native_barycentric_support) { + STR_CONCAT(patch, slen, "#extension GL_AMD_shader_explicit_vertex_parameter: enable\n"); + } + + /* Fallbacks. */ + if (!GLContext::shader_draw_parameters_support) { + STR_CONCAT(patch, slen, "uniform int gpu_BaseInstance;\n"); + } + + /* Vulkan GLSL compat. */ + STR_CONCAT(patch, slen, "#define gpu_InstanceIndex (gl_InstanceID + gpu_BaseInstance)\n"); + + /* Array compat. */ + STR_CONCAT(patch, slen, "#define array(_type) _type[]\n"); /* Derivative sign can change depending on implementation. */ STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]); @@ -660,6 +939,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 af92c77db54..cc1c93142f8 100644 --- a/source/blender/gpu/opengl/gl_shader.hh +++ b/source/blender/gpu/opengl/gl_shader.hh @@ -69,6 +69,7 @@ class GLShader : public Shader { std::string fragment_interface_declare(const shader::ShaderCreateInfo &info) const override; std::string geometry_interface_declare(const shader::ShaderCreateInfo &info) const override; std::string geometry_layout_declare(const shader::ShaderCreateInfo &info) const override; + std::string compute_layout_declare(const shader::ShaderCreateInfo &info) const override; /** Should be called before linking. */ void transform_feedback_names_set(Span<const char *> name_list, @@ -93,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"); }; diff --git a/source/blender/gpu/opengl/gl_shader_interface.cc b/source/blender/gpu/opengl/gl_shader_interface.cc index 2211c2fbb7c..0a31f8dee7f 100644 --- a/source/blender/gpu/opengl/gl_shader_interface.cc +++ b/source/blender/gpu/opengl/gl_shader_interface.cc @@ -117,7 +117,28 @@ static inline int image_binding(int32_t program, switch (type) { case GL_IMAGE_1D: case GL_IMAGE_2D: - case GL_IMAGE_3D: { + case GL_IMAGE_3D: + case GL_IMAGE_CUBE: + case GL_IMAGE_BUFFER: + case GL_IMAGE_1D_ARRAY: + case GL_IMAGE_2D_ARRAY: + case GL_IMAGE_CUBE_MAP_ARRAY: + case GL_INT_IMAGE_1D: + case GL_INT_IMAGE_2D: + case GL_INT_IMAGE_3D: + case GL_INT_IMAGE_CUBE: + case GL_INT_IMAGE_BUFFER: + case GL_INT_IMAGE_1D_ARRAY: + case GL_INT_IMAGE_2D_ARRAY: + case GL_INT_IMAGE_CUBE_MAP_ARRAY: + case GL_UNSIGNED_INT_IMAGE_1D: + case GL_UNSIGNED_INT_IMAGE_2D: + case GL_UNSIGNED_INT_IMAGE_3D: + case GL_UNSIGNED_INT_IMAGE_CUBE: + case GL_UNSIGNED_INT_IMAGE_BUFFER: + case GL_UNSIGNED_INT_IMAGE_1D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: + case GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY: { /* For now just assign a consecutive index. In the future, we should set it in * the shader using layout(binding = i) and query its value. */ int binding = *image_len; @@ -298,6 +319,7 @@ GLShaderInterface::GLShaderInterface(GLuint program) input->binding = input->location = binding; name_buffer_offset += this->set_input_name(input, name, name_len); + enabled_ssbo_mask_ |= (input->binding != -1) ? (1lu << input->binding) : 0lu; } /* Builtin Uniforms */ @@ -355,15 +377,33 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI } } + size_t workaround_names_size = 0; + Vector<StringRefNull> workaround_uniform_names; + auto check_enabled_uniform = [&](const char *uniform_name) { + if (glGetUniformLocation(program, uniform_name) != -1) { + workaround_uniform_names.append(uniform_name); + workaround_names_size += StringRefNull(uniform_name).size() + 1; + uniform_len_++; + } + }; + + if (!GLContext::shader_draw_parameters_support) { + check_enabled_uniform("gpu_BaseInstance"); + } + BLI_assert_msg(ubo_len_ <= 16, "enabled_ubo_mask_ is uint16_t"); int input_tot_len = attr_len_ + ubo_len_ + uniform_len_ + ssbo_len_; inputs_ = (ShaderInput *)MEM_callocN(sizeof(ShaderInput) * input_tot_len, __func__); ShaderInput *input = inputs_; - name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_, "name_buffer"); + name_buffer_ = (char *)MEM_mallocN(info.interface_names_size_ + workaround_names_size, + "name_buffer"); uint32_t name_buffer_offset = 0; + /* Necessary to make #glUniform works. TODO(fclem) Remove. */ + glUseProgram(program); + /* Attributes */ for (const ShaderCreateInfo::VertIn &attr : info.vertex_inputs_) { copy_input_name(input, attr.name, name_buffer_, name_buffer_offset); @@ -382,7 +422,7 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI if (res.bind_type == ShaderCreateInfo::Resource::BindType::UNIFORM_BUFFER) { copy_input_name(input, res.uniformbuf.name, name_buffer_, name_buffer_offset); if (true || !GLContext::explicit_location_support) { - input->location = glGetUniformBlockIndex(program, res.uniformbuf.name.c_str()); + input->location = glGetUniformBlockIndex(program, name_buffer_ + input->name_offset); glUniformBlockBinding(program, input->location, res.slot); } input->binding = res.slot; @@ -419,10 +459,15 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI } for (const ShaderCreateInfo::PushConst &uni : info.push_constants_) { copy_input_name(input, uni.name, name_buffer_, name_buffer_offset); - /* Until we make use of explicit uniform location. */ - if (true || !GLContext::explicit_location_support) { - input->location = glGetUniformLocation(program, uni.name.c_str()); - } + input->location = glGetUniformLocation(program, name_buffer_ + input->name_offset); + input->binding = -1; + input++; + } + + /* Compatibility uniforms. */ + for (auto &name : workaround_uniform_names) { + copy_input_name(input, name, name_buffer_, name_buffer_offset); + input->location = glGetUniformLocation(program, name_buffer_ + input->name_offset); input->binding = -1; input++; } @@ -432,7 +477,7 @@ GLShaderInterface::GLShaderInterface(GLuint program, const shader::ShaderCreateI if (res.bind_type == ShaderCreateInfo::Resource::BindType::STORAGE_BUFFER) { copy_input_name(input, res.storagebuf.name, name_buffer_, name_buffer_offset); input->location = input->binding = res.slot; - enabled_ubo_mask_ |= (1 << input->binding); + enabled_ssbo_mask_ |= (1 << input->binding); input++; } } @@ -474,7 +519,7 @@ GLShaderInterface::~GLShaderInterface() void GLShaderInterface::ref_add(GLVaoCache *ref) { for (int i = 0; i < refs_.size(); i++) { - if (refs_[i] == NULL) { + if (refs_[i] == nullptr) { refs_[i] = ref; return; } @@ -486,7 +531,7 @@ void GLShaderInterface::ref_remove(GLVaoCache *ref) { for (int i = 0; i < refs_.size(); i++) { if (refs_[i] == ref) { - refs_[i] = NULL; + refs_[i] = nullptr; break; /* cannot have duplicates */ } } diff --git a/source/blender/gpu/opengl/gl_shader_log.cc b/source/blender/gpu/opengl/gl_shader_log.cc index 174cc63ad81..ec13bc44136 100644 --- a/source/blender/gpu/opengl/gl_shader_log.cc +++ b/source/blender/gpu/opengl/gl_shader_log.cc @@ -60,6 +60,15 @@ char *GLLogParser::parse_line(char *log_line, GPULogItem &log_item) log_item.cursor.row = log_item.cursor.column; log_item.cursor.column = -1; } + else if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OFFICIAL) && + /* WORKAROUND(@fclem): Both Mesa and AMDGPU-PRO are reported as official. */ + StringRefNull(GPU_platform_version()).find(" Mesa ") == -1) { + /* source:row */ + log_item.cursor.source = log_item.cursor.row; + log_item.cursor.row = log_item.cursor.column; + log_item.cursor.column = -1; + log_item.source_base_row = true; + } else { /* line:char */ } diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh index 83ff3ffc9e9..5985f1583f2 100644 --- a/source/blender/gpu/opengl/gl_state.hh +++ b/source/blender/gpu/opengl/gl_state.hh @@ -124,11 +124,20 @@ static inline GLbitfield to_gl(eGPUBarrier barrier_bits) if (barrier_bits & GPU_BARRIER_SHADER_IMAGE_ACCESS) { barrier |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT; } + if (barrier_bits & GPU_BARRIER_SHADER_STORAGE) { + barrier |= GL_SHADER_STORAGE_BARRIER_BIT; + } if (barrier_bits & GPU_BARRIER_TEXTURE_FETCH) { barrier |= GL_TEXTURE_FETCH_BARRIER_BIT; } - if (barrier_bits & GPU_BARRIER_SHADER_STORAGE) { - barrier |= GL_SHADER_STORAGE_BARRIER_BIT; + if (barrier_bits & GPU_BARRIER_TEXTURE_UPDATE) { + barrier |= GL_TEXTURE_UPDATE_BARRIER_BIT; + } + if (barrier_bits & GPU_BARRIER_COMMAND) { + barrier |= GL_COMMAND_BARRIER_BIT; + } + if (barrier_bits & GPU_BARRIER_FRAMEBUFFER) { + barrier |= GL_FRAMEBUFFER_BARRIER_BIT; } if (barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY) { barrier |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT; |