From 8b2640f08858f200eda84e19f74ed234a2833eb2 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 3 May 2017 08:20:11 +1000 Subject: Draw Manager: fix draw-state switching logic Changing states didn't properly reset between shading groups causing the GL state to be wrong based on draw order. States are now only set when changed. --- source/blender/draw/intern/DRW_render.h | 3 +- source/blender/draw/intern/draw_common.c | 6 +- source/blender/draw/intern/draw_manager.c | 326 ++++++++++++++++--------- source/blender/draw/intern/draw_view.c | 2 + source/blender/draw/modes/edit_armature_mode.c | 2 +- source/blender/draw/modes/object_mode.c | 2 +- 6 files changed, 224 insertions(+), 117 deletions(-) (limited to 'source/blender') diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 15ed8aeb979..53fbd22e7ab 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -249,6 +249,7 @@ typedef enum { DRW_STATE_TEST_STENCIL_ACTIVE = (1 << 17), } DRWState; + DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass); DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass); DRWShadingGroup *DRW_shgroup_material_instance_create(struct GPUMaterial *material, DRWPass *pass, struct Batch *geom); @@ -267,7 +268,7 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at DRW_shgroup_call_dynamic_add_array(shgroup, NULL, 0); \ } while (0) -void DRW_shgroup_state_set(DRWShadingGroup *shgroup, DRWState state); +void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_attrib_int(DRWShadingGroup *shgroup, const char *name, int size); void DRW_shgroup_attrib_float(DRWShadingGroup *shgroup, const char *name, int size); diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index e50d21e0eb0..c266c45e71c 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -131,7 +131,7 @@ DRWShadingGroup *shgroup_dynpoints_uniform_color(DRWPass *pass, float color[4], DRWShadingGroup *grp = DRW_shgroup_point_batch_create(sh, pass); DRW_shgroup_uniform_vec4(grp, "color", color, 1); DRW_shgroup_uniform_float(grp, "size", size, 1); - DRW_shgroup_state_set(grp, DRW_STATE_POINT); + DRW_shgroup_state_enable(grp, DRW_STATE_POINT); return grp; } @@ -152,7 +152,7 @@ DRWShadingGroup *shgroup_groundpoints_uniform_color(DRWPass *pass, float color[4 DRWShadingGroup *grp = DRW_shgroup_point_batch_create(sh, pass); DRW_shgroup_uniform_vec4(grp, "color", color, 1); - DRW_shgroup_state_set(grp, DRW_STATE_POINT); + DRW_shgroup_state_enable(grp, DRW_STATE_POINT); return grp; } @@ -167,7 +167,7 @@ DRWShadingGroup *shgroup_instance_screenspace(DRWPass *pass, struct Batch *geom, DRW_shgroup_uniform_float(grp, "size", size, 1); DRW_shgroup_uniform_float(grp, "pixel_size", DRW_viewport_pixelsize_get(), 1); DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); - DRW_shgroup_state_set(grp, DRW_STATE_STIPPLE_3); + DRW_shgroup_state_enable(grp, DRW_STATE_STIPPLE_3); return grp; } diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 06cebab1c72..196f239119e 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -196,7 +196,7 @@ struct DRWShadingGroup { GPUShader *shader; /* Shader to bind */ DRWInterface *interface; /* Uniforms pointers */ ListBase calls; /* DRWCall or DRWCallDynamic depending of type */ - DRWState state; /* State changes for this batch only */ + DRWState state_extra; /* State changes for this batch only (or'd with the pass's state) */ int type; Batch *instance_geom; /* Geometry to instance */ @@ -229,6 +229,9 @@ static struct DRWGlobalState { ListBase bound_texs; int tex_bind_id; + /* Managed by `DRW_state_set`, `DRW_state_reset` */ + DRWState state; + /* Per viewport */ GPUViewport *viewport; struct GPUFrameBuffer *default_framebuffer; @@ -608,7 +611,7 @@ DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) shgroup->type = DRW_SHG_NORMAL; shgroup->shader = shader; shgroup->interface = DRW_interface_create(shader); - shgroup->state = 0; + shgroup->state_extra = 0; shgroup->batch_geom = NULL; shgroup->instance_geom = NULL; @@ -797,9 +800,10 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at /* Make sure you know what you do when using this, * State is not revert back at the end of the shgroup */ -void DRW_shgroup_state_set(DRWShadingGroup *shgroup, DRWState state) + +void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state) { - shgroup->state = state; + shgroup->state_extra |= state; } void DRW_shgroup_attrib_float(DRWShadingGroup *shgroup, const char *name, int size) @@ -1027,127 +1031,226 @@ void DRW_pass_free(DRWPass *pass) /** \name Draw (DRW_draw) * \{ */ -static void set_state(DRWState flag, const bool reset) +static void DRW_state_set(DRWState state) { - /* TODO Keep track of the state and only revert what is needed */ + if (DST.state == state) { + return; + } - if (reset) { - /* Depth Write */ - if (flag & DRW_STATE_WRITE_DEPTH) - glDepthMask(GL_TRUE); - else - glDepthMask(GL_FALSE); - /* Color Write */ - if (flag & DRW_STATE_WRITE_COLOR) - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - else - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); +#define CHANGED_TO(f) \ + ((DST.state & (f)) ? \ + ((state & (f)) ? 0 : -1) : \ + ((state & (f)) ? 1 : 0)) - /* Backface Culling */ - if (flag & DRW_STATE_CULL_BACK || - flag & DRW_STATE_CULL_FRONT) - { - glEnable(GL_CULL_FACE); +#define CHANGED_ANY(f) \ + ((DST.state & (f)) != (state & (f))) - if (flag & DRW_STATE_CULL_BACK) - glCullFace(GL_BACK); - else if (flag & DRW_STATE_CULL_FRONT) - glCullFace(GL_FRONT); +#define CHANGED_ANY_STORE_VAR(f, enabled) \ + ((DST.state & (f)) != (enabled = (state & (f)))) + + /* Depth Write */ + { + int test; + if ((test = CHANGED_TO(DRW_STATE_WRITE_DEPTH))) { + if (test == 1) { + glDepthMask(GL_TRUE); + } + else { + glDepthMask(GL_FALSE); + } } - else { - glDisable(GL_CULL_FACE); + } + + /* Color Write */ + { + int test; + if ((test = CHANGED_TO(DRW_STATE_WRITE_COLOR))) { + if (test == 1) { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + else { + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } } + } - /* Depth Test */ - if ((flag & (DRW_STATE_DEPTH_LESS | DRW_STATE_DEPTH_EQUAL | DRW_STATE_DEPTH_GREATER)) != 0) { - glEnable(GL_DEPTH_TEST); + /* Cull */ + { + DRWState test; + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_CULL_BACK | DRW_STATE_CULL_FRONT, + test)) + { + if (test) { + glEnable(GL_CULL_FACE); - if (flag & DRW_STATE_DEPTH_LESS) - glDepthFunc(GL_LEQUAL); - else if (flag & DRW_STATE_DEPTH_EQUAL) - glDepthFunc(GL_EQUAL); - else if (flag & DRW_STATE_DEPTH_GREATER) - glDepthFunc(GL_GREATER); + if ((state & DRW_STATE_CULL_BACK) != 0) { + glCullFace(GL_BACK); + } + else if ((state & DRW_STATE_CULL_FRONT) != 0) { + glCullFace(GL_FRONT); + } + else { + BLI_assert(0); + } + } + else { + glDisable(GL_CULL_FACE); + } } - else { - glDisable(GL_DEPTH_TEST); + } + + /* Depth Test */ + { + DRWState test; + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_DEPTH_LESS | DRW_STATE_DEPTH_EQUAL | DRW_STATE_DEPTH_GREATER, + test)) + { + if (test) { + glEnable(GL_DEPTH_TEST); + + if (state & DRW_STATE_DEPTH_LESS) { + glDepthFunc(GL_LEQUAL); + } + else if (state & DRW_STATE_DEPTH_EQUAL) { + glDepthFunc(GL_EQUAL); + } + else if (state & DRW_STATE_DEPTH_GREATER) { + glDepthFunc(GL_GREATER); + } + else { + BLI_assert(0); + } + } + else { + glDisable(GL_DEPTH_TEST); + } } } /* Wire Width */ - if ((flag & DRW_STATE_WIRE) != 0) { - glLineWidth(1.0f); - } - else if ((flag & DRW_STATE_WIRE_LARGE) != 0) { - glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + { + if (CHANGED_ANY(DRW_STATE_WIRE | DRW_STATE_WIRE_LARGE)) { + if ((state & DRW_STATE_WIRE) != 0) { + glLineWidth(1.0f); + } + else if ((state & DRW_STATE_WIRE_LARGE) != 0) { + glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); + } + else { + /* do nothing */ + } + } } /* Points Size */ - if ((flag & DRW_STATE_POINT) != 0) { - GPU_enable_program_point_size(); - glPointSize(5.0f); - } - else if (reset) { - GPU_disable_program_point_size(); + { + int test; + if ((test = CHANGED_TO(DRW_STATE_POINT))) { + if (test == 1) { + GPU_enable_program_point_size(); + glPointSize(5.0f); + } + else { + GPU_disable_program_point_size(); + } + } } /* Blending (all buffer) */ - if ((flag & DRW_STATE_BLEND) != 0) { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - else if (reset) { - glDisable(GL_BLEND); + { + int test; + if ((test = CHANGED_TO(DRW_STATE_BLEND))) { + if (test == 1) { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + else { + glDisable(GL_BLEND); + } + } } /* Line Stipple */ - if ((flag & DRW_STATE_STIPPLE_2) != 0) { - setlinestyle(2); - } - else if ((flag & DRW_STATE_STIPPLE_3) != 0) { - setlinestyle(3); - } - else if ((flag & DRW_STATE_STIPPLE_4) != 0) { - setlinestyle(4); - } - else if (reset) { - setlinestyle(0); + { + int test; + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_STIPPLE_2 | DRW_STATE_STIPPLE_3 | DRW_STATE_STIPPLE_4, + test)) + { + if (test) { + if ((state & DRW_STATE_STIPPLE_2) != 0) { + setlinestyle(2); + } + else if ((state & DRW_STATE_STIPPLE_3) != 0) { + setlinestyle(3); + } + else if ((state & DRW_STATE_STIPPLE_4) != 0) { + setlinestyle(4); + } + else { + BLI_assert(0); + } + } + else { + setlinestyle(0); + } + } } /* Stencil */ - if ((flag & (DRW_STATE_WRITE_STENCIL_SELECT | DRW_STATE_WRITE_STENCIL_ACTIVE | - DRW_STATE_TEST_STENCIL_SELECT | DRW_STATE_TEST_STENCIL_ACTIVE)) != 0) { - glEnable(GL_STENCIL_TEST); - - /* Stencil Write */ - if ((flag & DRW_STATE_WRITE_STENCIL_SELECT) != 0) { - glStencilMask(STENCIL_SELECT); - glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - glStencilFunc(GL_ALWAYS, 0xFF, STENCIL_SELECT); - } - else if ((flag & DRW_STATE_WRITE_STENCIL_ACTIVE) != 0) { - glStencilMask(STENCIL_ACTIVE); - glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); - glStencilFunc(GL_ALWAYS, 0xFF, STENCIL_ACTIVE); - } - /* Stencil Test */ - else if ((flag & DRW_STATE_TEST_STENCIL_SELECT) != 0) { - glStencilMask(0x00); /* disable write */ - glStencilFunc(GL_NOTEQUAL, 0xFF, STENCIL_SELECT); - } - else if ((flag & DRW_STATE_TEST_STENCIL_ACTIVE) != 0) { - glStencilMask(0x00); /* disable write */ - glStencilFunc(GL_NOTEQUAL, 0xFF, STENCIL_ACTIVE); + DRWState test; + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_WRITE_STENCIL_SELECT | + DRW_STATE_WRITE_STENCIL_ACTIVE | + DRW_STATE_TEST_STENCIL_SELECT | + DRW_STATE_TEST_STENCIL_ACTIVE, + test)) + { + if (test) { + glEnable(GL_STENCIL_TEST); + + /* Stencil Write */ + if ((state & DRW_STATE_WRITE_STENCIL_SELECT) != 0) { + glStencilMask(STENCIL_SELECT); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 0xFF, STENCIL_SELECT); + } + else if ((state & DRW_STATE_WRITE_STENCIL_ACTIVE) != 0) { + glStencilMask(STENCIL_ACTIVE); + glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); + glStencilFunc(GL_ALWAYS, 0xFF, STENCIL_ACTIVE); + } + /* Stencil Test */ + else if ((state & DRW_STATE_TEST_STENCIL_SELECT) != 0) { + glStencilMask(0x00); /* disable write */ + glStencilFunc(GL_NOTEQUAL, 0xFF, STENCIL_SELECT); + } + else if ((state & DRW_STATE_TEST_STENCIL_ACTIVE) != 0) { + glStencilMask(0x00); /* disable write */ + glStencilFunc(GL_NOTEQUAL, 0xFF, STENCIL_ACTIVE); + } + else { + BLI_assert(0); + } + } + else { + /* disable write & test */ + glStencilMask(0x00); + glStencilFunc(GL_ALWAYS, 1, 0xFF); + glDisable(GL_STENCIL_TEST); + } } } - else if (reset) { - /* disable write & test */ - glStencilMask(0x00); - glStencilFunc(GL_ALWAYS, 1, 0xFF); - glDisable(GL_STENCIL_TEST); - } + +#undef CHANGED_TO +#undef CHANGED_ANY +#undef CHANGED_ANY_STORE_VAR + + DST.state = state; } typedef struct DRWBoundTexture { @@ -1237,7 +1340,7 @@ static void draw_geometry(DRWShadingGroup *shgroup, Batch *geom, const float (*o } } -static void draw_shgroup(DRWShadingGroup *shgroup) +static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) { BLI_assert(shgroup->shader); BLI_assert(shgroup->interface); @@ -1256,9 +1359,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup) shgroup_dynamic_batch_from_calls(shgroup); } - if (shgroup->state != 0) { - set_state(shgroup->state, false); - } + DRW_state_set(pass_state | shgroup->state_extra); /* Binding Uniform */ /* Don't check anything, Interface should already contain the least uniform as possible */ @@ -1355,10 +1456,7 @@ static void draw_shgroup(DRWShadingGroup *shgroup) } } - /* reset the state for the next group, note - we could only reset states we changed! */ - if (shgroup->state != 0) { - DRW_state_reset(); - } + DRW_state_reset(); } void DRW_draw_pass(DRWPass *pass) @@ -1367,7 +1465,7 @@ void DRW_draw_pass(DRWPass *pass) DST.shader = NULL; DST.tex_bind_id = 0; - set_state(pass->state, true); + DRW_state_set(pass->state); BLI_listbase_clear(&DST.bound_texs); pass->wasdrawn = true; @@ -1394,7 +1492,7 @@ void DRW_draw_pass(DRWPass *pass) glBeginQuery(GL_TIME_ELAPSED, pass->timer_queries[pass->back_idx]); for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { - draw_shgroup(shgroup); + draw_shgroup(shgroup, pass->state); } /* Clear Bound textures */ @@ -1431,11 +1529,12 @@ void DRW_draw_callbacks_post_scene(void) /* Reset state to not interfer with other UI drawcall */ void DRW_state_reset(void) { - DRWState state = 0; - state |= DRW_STATE_WRITE_DEPTH; - state |= DRW_STATE_WRITE_COLOR; - state |= DRW_STATE_DEPTH_LESS; - set_state(state, true); + DRWState state = + DRW_STATE_WRITE_DEPTH | + DRW_STATE_WRITE_COLOR | + DRW_STATE_DEPTH_LESS; + DST.state = ~state; + DRW_state_set(state); } /** \} */ @@ -2238,6 +2337,7 @@ void DRW_draw_render_loop( } /* Start Drawing */ + DRW_state_reset(); DRW_engines_draw_background(); DRW_draw_callbacks_pre_scene(); @@ -2252,6 +2352,8 @@ void DRW_draw_render_loop( ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.ar, REGION_DRAW_POST_VIEW); } + DRW_state_reset(); + DRW_engines_draw_text(); /* needed so manipulator isn't obscured */ @@ -2400,6 +2502,7 @@ void DRW_draw_select_loop( } /* Start Drawing */ + DRW_state_reset(); DRW_draw_callbacks_pre_scene(); DRW_engines_draw_scene(); DRW_draw_callbacks_post_scene(); @@ -2482,6 +2585,7 @@ void DRW_draw_depth_loop( } /* Start Drawing */ + DRW_state_reset(); DRW_draw_callbacks_pre_scene(); DRW_engines_draw_scene(); DRW_draw_callbacks_post_scene(); diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c index db8edf1b33d..c6a0d6ed5b1 100644 --- a/source/blender/draw/intern/draw_view.c +++ b/source/blender/draw/intern/draw_view.c @@ -591,6 +591,8 @@ void DRW_draw_background(void) gpuPopMatrix(); glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + + glEnable(GL_DEPTH_TEST); } else { /* Solid background Color */ diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c index 87570c35c70..7d13dbd78ee 100644 --- a/source/blender/draw/modes/edit_armature_mode.c +++ b/source/blender/draw/modes/edit_armature_mode.c @@ -90,7 +90,7 @@ static void EDIT_ARMATURE_cache_init(void *vedata) /* Relationship Lines */ stl->g_data->relationship_lines = shgroup_dynlines_uniform_color(psl->relationship, ts.colorWire); - DRW_shgroup_state_set(stl->g_data->relationship_lines, DRW_STATE_STIPPLE_3); + DRW_shgroup_state_enable(stl->g_data->relationship_lines, DRW_STATE_STIPPLE_3); } } diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 70f8e734b99..f28b0af5eb1 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -752,7 +752,7 @@ static void OBJECT_cache_init(void *vedata) /* Relationship Lines */ stl->g_data->relationship_lines = shgroup_dynlines_uniform_color(psl->non_meshes, ts.colorWire); - DRW_shgroup_state_set(stl->g_data->relationship_lines, DRW_STATE_STIPPLE_3); + DRW_shgroup_state_enable(stl->g_data->relationship_lines, DRW_STATE_STIPPLE_3); /* Force Field Curve Guide End (here because of stipple) */ geom = DRW_cache_screenspace_circle_get(); -- cgit v1.2.3