diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-09-07 19:52:30 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-09-07 20:37:04 +0300 |
commit | 171b36683a774d70a8f25529858b9c002a2a317e (patch) | |
tree | c87999c9f5ae85936d283868fc70f192af44263d /source/blender/gpu/opengl | |
parent | 360489c75167d47653bc34ad9ba9a65076bf384c (diff) |
GPUExtensions: GL backend isolation
This is part of the Vulkan task T68990.
This commits changes a few things:
- Rename extensions to capabilities (but left the file name untouched).
- Cubemap mip render workaround detection is rewritten using gl
commands to avoid using the GPU API before initialization.
- Put all the capabilities that are only relevant for the GL backend
inside GLContext as static variables.
- Cleanup the names of the limit variables.
- Separate all GL related workaround search inside the GL module.
Diffstat (limited to 'source/blender/gpu/opengl')
-rw-r--r-- | source/blender/gpu/opengl/gl_backend.cc | 220 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_backend.hh | 3 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_batch.cc | 7 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_context.hh | 13 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_drawlist.cc | 2 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_framebuffer.cc | 2 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_shader.cc | 7 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_texture.cc | 6 | ||||
-rw-r--r-- | source/blender/gpu/opengl/gl_uniform_buffer.cc | 5 |
9 files changed, 251 insertions, 14 deletions
diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index d44bb9ba481..317416ca355 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -21,6 +21,9 @@ * \ingroup gpu */ +#include "BKE_global.h" + +#include "gpu_extensions_private.hh" #include "gpu_platform_private.hh" #include "glew-mx.h" @@ -29,6 +32,10 @@ namespace blender::gpu { +/* -------------------------------------------------------------------- */ +/** \name Platform + * \{ */ + void GLBackend::platform_init(void) { BLI_assert(!GPG.initialized); @@ -132,4 +139,217 @@ void GLBackend::platform_exit(void) GPG.clear(); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Capabilities + * \{ */ + +static bool detect_mip_render_workaround(void) +{ + int cube_size = 2; + float clear_color[4] = {1.0f, 0.5f, 0.0f, 0.0f}; + float *source_pix = (float *)MEM_callocN(sizeof(float[4]) * cube_size * cube_size * 6, __func__); + + /* Not using GPU API since it is not yet fully initialized. */ + GLuint tex, fb; + /* Create cubemap with 2 mip level. */ + glGenTextures(1, &tex); + glBindTexture(GL_TEXTURE_CUBE_MAP, tex); + for (int mip = 0; mip < 2; mip++) { + for (int i = 0; i < 6; i++) { + GLenum target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; + glTexImage2D(target, mip, GL_RGBA16F, 2, 2, 0, GL_RGBA, GL_FLOAT, source_pix); + } + } + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0); + /* Attach and clear mip 1. */ + glGenFramebuffers(1, &fb); + glBindFramebuffer(GL_FRAMEBUFFER, fb); + glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 1); + glDrawBuffer(GL_COLOR_ATTACHMENT0); + glClearColor(UNPACK4(clear_color)); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + glClear(GL_COLOR_BUFFER_BIT); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDrawBuffer(GL_BACK); + /* Read mip 1. If color is not the same as the clear_color, the rendering failed. */ + glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 1, GL_RGBA, GL_FLOAT, source_pix); + bool enable_workaround = !equals_v4v4(clear_color, source_pix); + MEM_freeN(source_pix); + + glDeleteFramebuffers(1, &fb); + glDeleteTextures(1, &tex); + + return enable_workaround; +} + +static void detect_workarounds(void) +{ + const char *vendor = (const char *)glGetString(GL_VENDOR); + const char *renderer = (const char *)glGetString(GL_RENDERER); + const char *version = (const char *)glGetString(GL_VERSION); + + if (G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS) { + printf("\n"); + printf("GL: Forcing workaround usage and disabling extensions.\n"); + printf(" OpenGL identification strings\n"); + printf(" vendor: %s\n", vendor); + printf(" renderer: %s\n", renderer); + printf(" version: %s\n\n", version); + GCaps.depth_blitting_workaround = true; + GCaps.mip_render_workaround = true; + GLContext::unused_fb_slot_workaround = true; + GLContext::texture_copy_workaround = true; + /* Turn off extensions. */ + GLContext::base_instance_support = false; + GLContext::texture_cube_map_array_support = false; + return; + } + + /* Some Intel drivers have issues with using mips as framebuffer targets if + * GL_TEXTURE_MAX_LEVEL is higher than the target mip. + * Only check at the end after all other workarounds because this uses the drawing code. */ + GCaps.mip_render_workaround = detect_mip_render_workaround(); + /* Limit support for GLEW_ARB_base_instance to OpenGL 4.0 and higher. NVIDIA Quadro FX 4800 + * (TeraScale) report that they support GLEW_ARB_base_instance, but the driver does not support + * GLEW_ARB_draw_indirect as it has an OpenGL3 context what also matches the minimum needed + * requirements. + * + * We use it as a target for glMapBuffer(Range) what is part of the OpenGL 4 API. So better + * disable it when we don't have an OpenGL4 context (See T77657) */ + if (!GLEW_VERSION_4_0) { + GLContext::base_instance_support = false; + } + /* The renderers include: + * Mobility Radeon HD 5000; + * Radeon HD 7500M; + * Radeon HD 7570M; + * Radeon HD 7600M; + * And many others... */ + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && + (strstr(version, "4.5.13399") || strstr(version, "4.5.13417") || + strstr(version, "4.5.13422"))) { + GLContext::unused_fb_slot_workaround = true; + GCaps.broken_amd_driver = true; + } + /* We have issues with this specific renderer. (see T74024) */ + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) && + strstr(renderer, "AMD VERDE")) { + GLContext::unused_fb_slot_workaround = true; + GCaps.broken_amd_driver = true; + } + /* Fix slowdown on this particular driver. (see T77641) */ + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) && + strstr(version, "Mesa 19.3.4")) { + GCaps.broken_amd_driver = true; + } + /* There is an issue with the #glBlitFramebuffer on MacOS with radeon pro graphics. + * Blitting depth with#GL_DEPTH24_STENCIL8 is buggy so the workaround is to use + * #GPU_DEPTH32F_STENCIL8. Then Blitting depth will work but blitting stencil will + * still be broken. */ + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) { + if (strstr(renderer, "AMD Radeon Pro") || strstr(renderer, "AMD Radeon R9") || + strstr(renderer, "AMD Radeon RX")) { + GCaps.depth_blitting_workaround = true; + } + } + /* Limit this fix to older hardware with GL < 4.5. This means Broadwell GPUs are + * covered since they only support GL 4.4 on windows. + * This fixes some issues with workbench anti-aliasing on Win + Intel GPU. (see T76273) */ + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && !GLEW_VERSION_4_5) { + GLContext::texture_copy_workaround = true; + } + /* Special fix for theses specific GPUs. + * Without this workaround, blender crashes on startup. (see T72098) */ + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && + (strstr(renderer, "HD Graphics 620") || strstr(renderer, "HD Graphics 630"))) { + GCaps.mip_render_workaround = true; + } + /* Intel Ivy Bridge GPU's seems to have buggy cube-map array support. (see T75943) */ + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_OFFICIAL) && + (strstr(renderer, "HD Graphics 4000") || strstr(renderer, "HD Graphics 4400") || + strstr(renderer, "HD Graphics 2500"))) { + GLContext::texture_cube_map_array_support = false; + } + /* Maybe not all of these drivers have problems with `GLEW_ARB_base_instance`. + * But it's hard to test each case. + * We get crashes from some crappy Intel drivers don't work well with shaders created in + * different rendering contexts. */ + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY) && + (strstr(version, "Build 10.18.10.3") || strstr(version, "Build 10.18.10.4") || + strstr(version, "Build 10.18.10.5") || strstr(version, "Build 10.18.14.4") || + strstr(version, "Build 10.18.14.5"))) { + GLContext::base_instance_support = false; + GCaps.use_main_context_workaround = true; + } + /* Somehow fixes armature display issues (see T69743). */ + if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY) && + (strstr(version, "Build 20.19.15.4285"))) { + GCaps.use_main_context_workaround = true; + } + /* See T70187: merging vertices fail. This has been tested from 18.2.2 till 19.3.0~dev of the + * Mesa driver */ + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE) && + (strstr(version, "Mesa 18.") || strstr(version, "Mesa 19.0") || + strstr(version, "Mesa 19.1") || strstr(version, "Mesa 19.2"))) { + GLContext::unused_fb_slot_workaround = true; + } + + /* dFdx/dFdy calculation factors, those are dependent on driver. */ + if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY) && + strstr(version, "3.3.10750")) { + GLContext::derivative_signs[0] = 1.0; + GLContext::derivative_signs[1] = -1.0; + } + else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY)) { + if (strstr(version, "4.0.0 - Build 10.18.10.3308") || + strstr(version, "4.0.0 - Build 9.18.10.3186") || + strstr(version, "4.0.0 - Build 9.18.10.3165") || + strstr(version, "3.1.0 - Build 9.17.10.3347") || + strstr(version, "3.1.0 - Build 9.17.10.4101") || + strstr(version, "3.3.0 - Build 8.15.10.2618")) { + GLContext::derivative_signs[0] = -1.0; + GLContext::derivative_signs[1] = 1.0; + } + } +} + +/** Internal capabilities. */ +GLint GLContext::max_texture_3d_size; +GLint GLContext::max_cubemap_size; +GLint GLContext::max_ubo_size; +GLint GLContext::max_ubo_binds; +/** Extensions. */ +bool GLContext::base_instance_support = false; +bool GLContext::texture_cube_map_array_support = false; +/** Workarounds. */ +bool GLContext::texture_copy_workaround = false; +bool GLContext::unused_fb_slot_workaround = false; +float GLContext::derivative_signs[2] = {1.0f, 1.0f}; + +void GLBackend::capabilities_init(void) +{ + BLI_assert(GLEW_VERSION_3_3); + /* Common Capabilities. */ + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &GCaps.max_texture_size); + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &GCaps.max_texture_layers); + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &GCaps.max_textures_frag); + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &GCaps.max_textures_vert); + glGetIntegerv(GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS, &GCaps.max_textures_geom); + glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &GCaps.max_textures); + /* GL specific capabilities. */ + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &GLContext::max_texture_3d_size); + glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &GLContext::max_cubemap_size); + glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &GLContext::max_ubo_binds); + glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &GLContext::max_ubo_size); + GLContext::base_instance_support = GLEW_ARB_base_instance; + GLContext::texture_cube_map_array_support = GLEW_ARB_texture_cube_map_array; + + detect_workarounds(); +} + +/** \} */ + } // namespace blender::gpu
\ No newline at end of file diff --git a/source/blender/gpu/opengl/gl_backend.hh b/source/blender/gpu/opengl/gl_backend.hh index 9548aa9dd92..25f3ff38d8b 100644 --- a/source/blender/gpu/opengl/gl_backend.hh +++ b/source/blender/gpu/opengl/gl_backend.hh @@ -50,6 +50,7 @@ class GLBackend : public GPUBackend { /* platform_init needs to go first. */ GLBackend::platform_init(); + GLBackend::capabilities_init(); GLTexture::samplers_init(); } ~GLBackend() @@ -127,6 +128,8 @@ class GLBackend : public GPUBackend { private: static void platform_init(void); static void platform_exit(void); + + static void capabilities_init(void); }; } // namespace gpu diff --git a/source/blender/gpu/opengl/gl_batch.cc b/source/blender/gpu/opengl/gl_batch.cc index db30a57953d..f4ad7194ce1 100644 --- a/source/blender/gpu/opengl/gl_batch.cc +++ b/source/blender/gpu/opengl/gl_batch.cc @@ -34,6 +34,7 @@ #include "gpu_batch_private.hh" #include "gpu_shader_private.hh" +#include "gl_backend.hh" #include "gl_context.hh" #include "gl_debug.hh" #include "gl_index_buffer.hh" @@ -314,7 +315,7 @@ void GLBatch::bind(int i_first) #endif /* Can be removed if GL 4.2 is required. */ - if (!GPU_arb_base_instance_is_supported() && (i_first > 0)) { + if (!GLContext::base_instance_support && (i_first > 0)) { glBindVertexArray(vao_cache_.base_instance_vao_get(this, i_first)); } else { @@ -339,7 +340,7 @@ void GLBatch::draw(int v_first, int v_count, int i_first, int i_count) GLint base_index = el->index_base_; void *v_first_ofs = el->offset_ptr(v_first); - if (GPU_arb_base_instance_is_supported()) { + if (GLContext::base_instance_support) { glDrawElementsInstancedBaseVertexBaseInstance( gl_type, v_count, index_type, v_first_ofs, i_count, base_index, i_first); } @@ -353,7 +354,7 @@ void GLBatch::draw(int v_first, int v_count, int i_first, int i_count) #ifdef __APPLE__ glDisable(GL_PRIMITIVE_RESTART); #endif - if (GPU_arb_base_instance_is_supported()) { + if (GLContext::base_instance_support) { glDrawArraysInstancedBaseInstance(gl_type, v_first, v_count, i_count, i_first); } else { diff --git a/source/blender/gpu/opengl/gl_context.hh b/source/blender/gpu/opengl/gl_context.hh index 9e6359fabad..e2ae8bf24b2 100644 --- a/source/blender/gpu/opengl/gl_context.hh +++ b/source/blender/gpu/opengl/gl_context.hh @@ -55,6 +55,19 @@ class GLSharedOrphanLists { class GLContext : public GPUContext { public: + /** Capabilities. */ + static GLint max_texture_3d_size; + static GLint max_cubemap_size; + static GLint max_ubo_size; + static GLint max_ubo_binds; + /** Extensions. */ + static bool base_instance_support; + static bool texture_cube_map_array_support; + /** Workarounds. */ + static bool texture_copy_workaround; + static bool unused_fb_slot_workaround; + static float derivative_signs[2]; + /** Used for debugging purpose. Bitflags of all bound slots. */ uint16_t bound_ubo_slots; diff --git a/source/blender/gpu/opengl/gl_drawlist.cc b/source/blender/gpu/opengl/gl_drawlist.cc index d8c17084457..0768f7502ce 100644 --- a/source/blender/gpu/opengl/gl_drawlist.cc +++ b/source/blender/gpu/opengl/gl_drawlist.cc @@ -76,7 +76,7 @@ GLDrawList::GLDrawList(int length) data_ = NULL; if (USE_MULTI_DRAW_INDIRECT && GLEW_ARB_multi_draw_indirect && - GPU_arb_base_instance_is_supported()) { + GLContext::base_instance_support) { /* Alloc the biggest possible command list, which is indexed. */ buffer_size_ = sizeof(GLDrawCommandIndexed) * length; } diff --git a/source/blender/gpu/opengl/gl_framebuffer.cc b/source/blender/gpu/opengl/gl_framebuffer.cc index 4be471b236a..506a945d9d4 100644 --- a/source/blender/gpu/opengl/gl_framebuffer.cc +++ b/source/blender/gpu/opengl/gl_framebuffer.cc @@ -208,7 +208,7 @@ void GLFrameBuffer::update_attachments(void) } } - if (GPU_unused_fb_slot_workaround()) { + if (GLContext::unused_fb_slot_workaround) { /* Fill normally un-occupied slots to avoid rendering artifacts on some hardware. */ GLuint gl_tex = 0; /* NOTE: Inverse iteration to get the first color texture. */ diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index 9136a1d9714..f125afeb535 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -28,6 +28,7 @@ #include "GPU_extensions.h" #include "GPU_platform.h" +#include "gl_backend.hh" #include "gl_vertex_buffer.hh" #include "gl_shader.hh" @@ -118,10 +119,8 @@ char *GLShader::glsl_patch_get(void) } /* Derivative sign can change depending on implementation. */ - float derivatives[2]; - GPU_get_dfdy_factors(derivatives); - STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", derivatives[0]); - STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", derivatives[1]); + STR_CONCATF(patch, slen, "#define DFDX_SIGN %1.1f\n", GLContext::derivative_signs[0]); + STR_CONCATF(patch, slen, "#define DFDY_SIGN %1.1f\n", GLContext::derivative_signs[1]); BLI_assert(slen < sizeof(patch)); return patch; diff --git a/source/blender/gpu/opengl/gl_texture.cc b/source/blender/gpu/opengl/gl_texture.cc index 6cff97215e8..ba2e5844cc7 100644 --- a/source/blender/gpu/opengl/gl_texture.cc +++ b/source/blender/gpu/opengl/gl_texture.cc @@ -369,7 +369,7 @@ void GLTexture::copy_to(Texture *dst_) /* TODO support array / 3D textures. */ BLI_assert(dst->d_ == 0); - if (GLEW_ARB_copy_image && !GPU_texture_copy_workaround()) { + if (GLEW_ARB_copy_image && !GLContext::texture_copy_workaround) { /* Opengl 4.3 */ int mip = 0; /* NOTE: mip_size_get() won't override any dimension that is equal to 0. */ @@ -560,8 +560,8 @@ bool GLTexture::proxy_check(int mip) { /* Manual validation first, since some implementation have issues with proxy creation. */ int max_size = GPU_max_texture_size(); - int max_3d_size = GPU_max_texture_3d_size(); - int max_cube_size = GPU_max_cube_map_size(); + int max_3d_size = GLContext::max_texture_3d_size; + int max_cube_size = GLContext::max_cubemap_size; int size[3] = {1, 1, 1}; this->mip_size_get(mip, size); diff --git a/source/blender/gpu/opengl/gl_uniform_buffer.cc b/source/blender/gpu/opengl/gl_uniform_buffer.cc index 0e0c64e5c60..82b7341d145 100644 --- a/source/blender/gpu/opengl/gl_uniform_buffer.cc +++ b/source/blender/gpu/opengl/gl_uniform_buffer.cc @@ -42,6 +42,7 @@ namespace blender::gpu { GLUniformBuf::GLUniformBuf(size_t size, const char *name) : UniformBuf(size, name) { /* Do not create ubo GL buffer here to allow allocation from any thread. */ + BLI_assert(size <= GLContext::max_ubo_size); } GLUniformBuf::~GLUniformBuf() @@ -90,12 +91,12 @@ void GLUniformBuf::update(const void *data) void GLUniformBuf::bind(int slot) { - if (slot >= GPU_max_ubo_binds()) { + if (slot >= GLContext::max_ubo_binds) { fprintf(stderr, "Error: Trying to bind \"%s\" ubo to slot %d which is above the reported limit of %d.", name_, slot, - GPU_max_ubo_binds()); + GLContext::max_ubo_binds); return; } |