diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index a857736acd5..04cf7bc54ba 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -156,6 +156,7 @@ eGPUDepthTest GPU_depth_test_get(void); eGPUWriteMask GPU_write_mask_get(void); uint GPU_stencil_mask_get(void); eGPUStencilTest GPU_stencil_test_get(void); +float GPU_line_width_get(void); void GPU_flush(void); void GPU_finish(void); 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);