diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2020-09-18 20:59:51 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2020-09-18 23:41:49 +0300 |
commit | 649b0ccac8b514b471cdeede97b1a2839c2176b9 (patch) | |
tree | c76ff75bb16c3e022d1df201639d407ea531611d /source/blender/gpu/intern | |
parent | f17302be6b716ea5bc6b1ddfd09a2cf3b4969e37 (diff) |
GPUImmediate: Add system wide workaround for wide line
This makes wide line supported on MacOS and other implementation that
does not support wide line by default.
This workaround works for all Line types but only if using one of the 5
default shaders.
The workaround is completely isolated and invisible to the outside. It has
no side effect.
Note: This does not affect the GPUBatch drawing.
Diffstat (limited to 'source/blender/gpu/intern')
-rw-r--r-- | source/blender/gpu/intern/gpu_immediate.cc | 83 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_immediate_private.hh | 9 | ||||
-rw-r--r-- | source/blender/gpu/intern/gpu_state.cc | 7 |
3 files changed, 99 insertions, 0 deletions
diff --git a/source/blender/gpu/intern/gpu_immediate.cc b/source/blender/gpu/intern/gpu_immediate.cc index 8d781978857..38d206ec3ad 100644 --- a/source/blender/gpu/intern/gpu_immediate.cc +++ b/source/blender/gpu/intern/gpu_immediate.cc @@ -62,6 +62,7 @@ void immBindShader(GPUShader *shader) BLI_assert(imm->shader == NULL); imm->shader = shader; + imm->builtin_shader_bound = GPU_SHADER_TEXT; /* Default value. */ if (!imm->vertex_format.packed) { VertexFormat_pack(&imm->vertex_format); @@ -77,6 +78,7 @@ void immBindBuiltinProgram(eGPUBuiltinShader shader_id) { GPUShader *shader = GPU_shader_get_builtin_shader(shader_id); immBindShader(shader); + imm->builtin_shader_bound = shader_id; } void immUnbindProgram(void) @@ -122,11 +124,88 @@ static bool vertex_count_makes_sense_for_primitive(uint vertex_len, GPUPrimType } #endif +/* -------------------------------------------------------------------- */ +/** \name Wide line workaround + * + * Some systems do not support wide lines. + * We workaround this by using specialized shaders. + * \{ */ + +static void wide_line_workaround_start(GPUPrimType prim_type) +{ + if (!ELEM(prim_type, GPU_PRIM_LINES, GPU_PRIM_LINE_STRIP, GPU_PRIM_LINE_LOOP)) { + return; + } + + float line_width = GPU_line_width_get(); + + if (line_width == 1.0f) { + /* No need to change the shader. */ + return; + } + + eGPUBuiltinShader polyline_sh; + switch (imm->builtin_shader_bound) { + case GPU_SHADER_3D_CLIPPED_UNIFORM_COLOR: + polyline_sh = GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR; + break; + case GPU_SHADER_2D_UNIFORM_COLOR: + case GPU_SHADER_3D_UNIFORM_COLOR: + polyline_sh = GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR; + break; + case GPU_SHADER_2D_FLAT_COLOR: + case GPU_SHADER_3D_FLAT_COLOR: + polyline_sh = GPU_SHADER_3D_POLYLINE_FLAT_COLOR; + break; + case GPU_SHADER_2D_SMOOTH_COLOR: + case GPU_SHADER_3D_SMOOTH_COLOR: + polyline_sh = GPU_SHADER_3D_POLYLINE_SMOOTH_COLOR; + break; + default: + /* Cannot replace the current shader with a polyline shader. */ + return; + } + + imm->prev_shader = imm->shader; + + immUnbindProgram(); + + /* TODO(fclem) Don't use geometry shader and use quad instancing with double load. */ + // GPU_vertformat_multiload_enable(imm->vertex_format, 2); + + immBindBuiltinProgram(polyline_sh); + + float viewport[4]; + GPU_viewport_size_get_f(viewport); + immUniform2fv("viewportSize", &viewport[2]); + immUniform1f("lineWidth", line_width); + + if (ELEM(polyline_sh, + GPU_SHADER_3D_POLYLINE_CLIPPED_UNIFORM_COLOR, + GPU_SHADER_3D_POLYLINE_UNIFORM_COLOR)) { + immUniformColor4fv(imm->uniform_color); + } +} + +static void wide_line_workaround_end(void) +{ + if (imm->prev_shader) { + immUnbindProgram(); + + immBindShader(imm->prev_shader); + imm->prev_shader = NULL; + } +} + +/** \} */ + void immBegin(GPUPrimType prim_type, uint vertex_len) { BLI_assert(imm->prim_type == GPU_PRIM_NONE); /* Make sure we haven't already begun. */ BLI_assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type)); + wide_line_workaround_start(prim_type); + imm->prim_type = prim_type; imm->vertex_len = vertex_len; imm->vertex_idx = 0; @@ -201,6 +280,8 @@ void immEnd(void) imm->prim_type = GPU_PRIM_NONE; imm->strict_vertex_len = true; imm->vertex_data = NULL; + + wide_line_workaround_end(); } static void setAttrValueBit(uint attr_id) @@ -549,6 +630,8 @@ void immUniformColor4f(float r, float g, float b, float a) BLI_assert(uniform_loc != -1); float data[4] = {r, g, b, a}; GPU_shader_uniform_vector(imm->shader, uniform_loc, 4, 1, data); + /* For wide Line workaround. */ + copy_v4_v4(imm->uniform_color, data); } void immUniformColor4fv(const float rgba[4]) diff --git a/source/blender/gpu/intern/gpu_immediate_private.hh b/source/blender/gpu/intern/gpu_immediate_private.hh index 38db8131942..b867a85bb8b 100644 --- a/source/blender/gpu/intern/gpu_immediate_private.hh +++ b/source/blender/gpu/intern/gpu_immediate_private.hh @@ -55,6 +55,15 @@ class Immediate { /** Batch in construction when using immBeginBatch. */ GPUBatch *batch = NULL; + /** Wide Line workaround. */ + + /** Previously bound shader to restore after drawing. */ + GPUShader *prev_shader = NULL; + /** Builtin shader index. Used to test if the workaround can be done. */ + eGPUBuiltinShader builtin_shader_bound = GPU_SHADER_TEXT; + /** Uniform color: Kept here to update the wideline shader just before immBegin. */ + float uniform_color[4]; + public: Immediate(){}; virtual ~Immediate(){}; diff --git a/source/blender/gpu/intern/gpu_state.cc b/source/blender/gpu/intern/gpu_state.cc index 1dc8b106029..9621aeeda7c 100644 --- a/source/blender/gpu/intern/gpu_state.cc +++ b/source/blender/gpu/intern/gpu_state.cc @@ -258,6 +258,13 @@ eGPUStencilTest GPU_stencil_test_get() return (eGPUStencilTest)state.stencil_test; } +/* NOTE: Already premultiplied by U.pixelsize. */ +float GPU_line_width_get(void) +{ + GPUStateMutable &state = Context::get()->state_manager->mutable_state; + return state.line_width; +} + void GPU_scissor_get(int coords[4]) { Context::get()->active_fb->scissor_get(coords); |