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.
This commit is contained in:
Clément Foucault 2020-09-18 19:59:51 +02:00
parent f17302be6b
commit 649b0ccac8
Notes: blender-bot 2023-02-14 09:19:09 +01:00
Referenced by issue #80974, Axes overlay when moving an object has become very large (Thick Line Width preference)
Referenced by issue #79523, Weight Paint hard to see red circle too thinner
4 changed files with 100 additions and 0 deletions

View File

@ -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);

View File

@ -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])

View File

@ -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(){};

View File

@ -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);