Fix T54190: Occlusion query select failed
authorCampbell Barton <ideasman42@gmail.com>
Thu, 1 Mar 2018 05:31:36 +0000 (16:31 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 1 Mar 2018 05:37:39 +0000 (16:37 +1100)
By default select wasn't picking the nearest object,
this could have been fixed by not clearing the depth buffer,
but calling GPU_select_(begin/end) without the binded frame-buffer
caused issues for depth-picking. So move GPU_select begin/end to a
callback.

This also has the advantage that only needs to populate the engines once
to draw two passes.

Note that cycling through objects fails with occlusion queries still,
will fix shortly.

source/blender/draw/DRW_engine.h
source/blender/draw/intern/draw_manager.c
source/blender/editors/space_view3d/view3d_view.c

index 9ed8f776f34a5d0b4c3f3447fea23f2a51de9d25..4043f39b46d97c1f849af8b1da5d179a5bbac030 100644 (file)
@@ -88,6 +88,11 @@ typedef struct DRWUpdateContext {
 void DRW_notify_view_update(const DRWUpdateContext *update_ctx);
 void DRW_notify_id_update(const DRWUpdateContext *update_ctx, struct ID *id);
 
+
+typedef enum eDRWSelectStage { DRW_SELECT_PASS_PRE = 1, DRW_SELECT_PASS_POST, } eDRWSelectStage;
+typedef bool (*DRW_SelectPassFn)(
+        eDRWSelectStage stage, void *user_data);
+
 void DRW_draw_view(const struct bContext *C);
 
 void DRW_draw_render_loop_ex(
@@ -108,7 +113,8 @@ void DRW_draw_render_loop_offscreen(
 void DRW_draw_select_loop(
         struct Depsgraph *depsgraph,
         struct ARegion *ar, struct View3D *v3d, const eObjectMode object_mode,
-        bool use_obedit_skip, bool use_nearest, const struct rcti *rect);
+        bool use_obedit_skip, bool use_nearest, const struct rcti *rect,
+        DRW_SelectPassFn select_pass_fn, void *select_pass_user_data);
 void DRW_draw_depth_loop(
         struct Depsgraph *depsgraph,
         struct ARegion *ar, struct View3D *v3d, const eObjectMode object_mode);
index 62042a44434cda3f03d5781fbc339e47364bd5ae..037053399c7797e24164a02cc2b8802e5ade7804 100644 (file)
@@ -1384,7 +1384,8 @@ void DRW_render_instance_buffer_finish(void)
 void DRW_draw_select_loop(
         struct Depsgraph *depsgraph,
         ARegion *ar, View3D *v3d, const eObjectMode object_mode,
-        bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect)
+        bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect,
+        DRW_SelectPassFn select_pass_fn, void *select_pass_user_data)
 {
        Scene *scene = DEG_get_evaluated_scene(depsgraph);
        RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id);
@@ -1484,12 +1485,21 @@ void DRW_draw_select_loop(
        /* Start Drawing */
        DRW_state_reset();
        DRW_draw_callbacks_pre_scene();
-       drw_engines_draw_scene();
-       DRW_draw_callbacks_post_scene();
 
-#ifdef USE_GPU_SELECT
-       GPU_select_finalize();
-#endif
+       /* Only 1-2 passes. */
+       while (true) {
+               if (!select_pass_fn(DRW_SELECT_PASS_PRE, select_pass_user_data)) {
+                       break;
+               }
+
+               drw_engines_draw_scene();
+
+               if (!select_pass_fn(DRW_SELECT_PASS_POST, select_pass_user_data)) {
+                       break;
+               }
+       }
+
+       DRW_draw_callbacks_post_scene();
 
        DRW_state_reset();
        drw_engines_disable();
index cb329e62e964e52cf7b58d995d009f0737d6315d..0afef34194c624d95b7f2941f39fc9983ff3283d 100644 (file)
@@ -861,6 +861,45 @@ void view3d_opengl_select_cache_end(void)
        GPU_select_cache_end();
 }
 
+#ifndef WITH_OPENGL_LEGACY
+struct DrawSelectLoopUserData {
+       uint  pass;
+       uint  hits;
+       uint *buffer;
+       uint  buffer_len;
+       const rcti *rect;
+       char gpu_select_mode;
+};
+
+static bool drw_select_loop_pass(eDRWSelectStage stage, void *user_data)
+{
+       bool continue_pass = false;
+       struct DrawSelectLoopUserData *data = user_data;
+       if (stage == DRW_SELECT_PASS_PRE) {
+               GPU_select_begin(data->buffer, data->buffer_len, data->rect, data->gpu_select_mode, data->hits);
+               /* always run POST after PRE. */
+               continue_pass = true;
+       }
+       else if (stage == DRW_SELECT_PASS_POST) {
+               int hits = GPU_select_end();
+               if (data->pass == 0) {
+                       /* quirk of GPU_select_end, only take hits value from first call. */
+                       data->hits = hits;
+               }
+               if (data->gpu_select_mode == GPU_SELECT_NEAREST_FIRST_PASS) {
+                       data->gpu_select_mode = GPU_SELECT_NEAREST_SECOND_PASS;
+                       continue_pass = true;
+               }
+               data->pass += 1;
+       }
+       else {
+               BLI_assert(0);
+       }
+       return continue_pass;
+
+}
+#endif /* WITH_OPENGL_LEGACY */
+
 /**
  * \warning be sure to account for a negative return value
  * This is an error, "Too many objects in select buffer"
@@ -950,43 +989,40 @@ int view3d_opengl_select(
        if (vc->rv3d->rflag & RV3D_CLIPPING)
                ED_view3d_clipping_set(vc->rv3d);
        
-       GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
 
 #ifdef WITH_OPENGL_LEGACY
        if (IS_VIEWPORT_LEGACY(vc->v3d)) {
+               GPU_select_begin(buffer, bufsize, &rect, gpu_select_mode, 0);
                ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest);
+               hits = GPU_select_end();
+
+               if (do_passes && (hits > 0)) {
+                       GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+                       ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest);
+                       GPU_select_end();
+               }
        }
        else
 #else
        {
+               /* We need to call "GPU_select_*" API's inside DRW_draw_select_loop
+                * because the OpenGL context created & destroyed inside this function. */
+               struct DrawSelectLoopUserData drw_select_loop_user_data = {
+                       .pass = 0,
+                       .hits = 0,
+                       .buffer = buffer,
+                       .buffer_len = bufsize,
+                       .rect = &rect,
+                       .gpu_select_mode = gpu_select_mode,
+               };
                DRW_draw_select_loop(
                        graph, ar, v3d, eval_ctx->object_mode,
-                       use_obedit_skip, use_nearest, &rect);
+                       use_obedit_skip, use_nearest, &rect,
+                       drw_select_loop_pass, &drw_select_loop_user_data);
+               hits = drw_select_loop_user_data.hits;
        }
 #endif /* WITH_OPENGL_LEGACY */
 
-       hits = GPU_select_end();
-       
-       /* second pass, to get the closest object to camera */
-       if (do_passes && (hits > 0)) {
-               GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
-
-#ifdef WITH_OPENGL_LEGACY
-               if (IS_VIEWPORT_LEGACY(vc->v3d)) {
-                       ED_view3d_draw_select_loop(vc, scene, sl, v3d, ar, use_obedit_skip, use_nearest);
-               }
-               else
-#else
-               {
-                       DRW_draw_select_loop(
-                               graph, ar, v3d, eval_ctx->object_mode,
-                               use_obedit_skip, use_nearest, &rect);
-               }
-#endif /* WITH_OPENGL_LEGACY */
-
-               GPU_select_end();
-       }
-
        G.f &= ~G_PICKSEL;
        ED_view3d_draw_setup_view(vc->win, eval_ctx, scene, ar, v3d, vc->rv3d->viewmat, NULL, NULL);