[Bf-committers] Occlusion Query based selection

Αντώνης Ρυακιωτάκης kalast at gmail.com
Sat Dec 3 14:04:51 CET 2011


Hi, recently I have become aware of a user complaint

http://blenderartists.org/forum/showthread.php?238426-why-is-gl_select-still-used-to-select-objects-in-Blender

 about slow selection. This is not a new issue and stems from the fact
that selection uses glRenderMode(GL_SELECT) under the hood. This runs
on the CPU and lags on heavy scenes since it effectively uses a
software rasterizer. There is a better way to do this, using GPU based
occlusion queries. This provides the same information but running
through the GPU so it should be no slower than navigating the view(In
theory). I thought of using some color encoded index+color buffer
readback to do this but I thought that occlusion queries would fit the
current scheme better. Unfortunately I have discovered that the
selection scheme is a bit more involved in the selection workings,
especially when it comes to armatures. I will have to look into this a
bit further but my first idea is maybe use a selection buffer-like
interface that uses occlusion queries behind the scenes. Thoughts?

Oh, I forgot the goodies:

build for windows:

graphicall.org/747/

And patch:

Index: release/scripts/startup/bl_ui/space_userpref.py
===================================================================
--- release/scripts/startup/bl_ui/space_userpref.py	(revision 42368)
+++ release/scripts/startup/bl_ui/space_userpref.py	(working copy)
@@ -436,6 +436,10 @@
         col.prop(system, "gl_texture_limit", text="Limit Size")
         col.prop(system, "texture_time_out", text="Time Out")
         col.prop(system, "texture_collection_rate", text="Collection Rate")
+        col.label(text="Selection")
+        sub = col.column()
+        sub.active = system.gpu_selection_support
+        sub.prop(system, "use_gpu_selection")

         col.separator()
         col.separator()
Index: source/blender/makesdna/DNA_userdef_types.h
===================================================================
--- source/blender/makesdna/DNA_userdef_types.h	(revision 42368)
+++ source/blender/makesdna/DNA_userdef_types.h	(working copy)
@@ -391,7 +391,8 @@
 	
 	short widget_unit;		/* defaults to 20 for 72 DPI setting */
 	short anisotropic_filter;
-	/*short pad[3];			*/
+	short gpu_selection;
+	short pad[3];

 	float ndof_sensitivity;	/* overall sensitivity of 3D mouse */
 	int ndof_flag;			/* flags for 3D mouse */
@@ -552,6 +553,10 @@
 #define USER_DISABLE_VBO		8
 #define USER_DISABLE_AA			16

+/* occlusion culling-based gpu selection */
+#define USER_GPU_SELECTION			1
+#define USER_GPU_SELECTION_DUMMY	2
+
 /* wm draw method */
 #define USER_DRAW_TRIPLE		0
 #define USER_DRAW_OVERLAP		1
Index: source/blender/makesrna/intern/rna_userdef.c
===================================================================
--- source/blender/makesrna/intern/rna_userdef.c	(revision 42368)
+++ source/blender/makesrna/intern/rna_userdef.c	(working copy)
@@ -46,6 +46,8 @@

 #include "BKE_sound.h"

+#include "GL/glew.h"
+
 #ifdef RNA_RUNTIME

 #include "DNA_object_types.h"
@@ -302,6 +304,11 @@
 	WM_main_add_notifier(NC_WINDOW, NULL);
 }

+static int rna_Scene_GPU_selection_supported(PointerRNA *ptr)
+{
+	return GLEW_ARB_occlusion_query;
+}
+
 #else

 static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna)
@@ -2850,6 +2857,14 @@
 	RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user
interface text anti-aliased");
 	RNA_def_property_update(prop, 0, "rna_userdef_text_update");
 	
+	prop= RNA_def_property(srna, "gpu_selection_support", PROP_BOOLEAN,
PROP_NONE);
+	RNA_def_property_boolean_sdna(prop, NULL, "gpu_selection",
USER_GPU_SELECTION_DUMMY);
+	RNA_def_property_boolean_funcs(prop,
"rna_Scene_GPU_selection_supported", NULL);
+
+	prop= RNA_def_property(srna, "use_gpu_selection", PROP_BOOLEAN, PROP_NONE);
+	RNA_def_property_boolean_sdna(prop, NULL, "gpu_selection",
USER_GPU_SELECTION);
+	RNA_def_property_ui_text(prop, "GPU selection support", "Use GPU
occlusion queries to accelerate selection");
+
 #if 0
 	prop= RNA_def_property(srna, "verse_master", PROP_STRING, PROP_NONE);
 	RNA_def_property_string_sdna(prop, NULL, "versemaster");
Index: source/blender/makesrna/intern/rna_scene.c
===================================================================
--- source/blender/makesrna/intern/rna_scene.c	(revision 42368)
+++ source/blender/makesrna/intern/rna_scene.c	(working copy)
@@ -1291,7 +1291,6 @@
 	if(camera)
 		DAG_id_tag_update(&camera->id, 0);
 }
-
 #else

 static void rna_def_transform_orientation(BlenderRNA *brna)
Index: source/blender/editors/space_view3d/view3d_view.c
===================================================================
--- source/blender/editors/space_view3d/view3d_view.c	(revision 42368)
+++ source/blender/editors/space_view3d/view3d_view.c	(working copy)
@@ -1178,6 +1178,10 @@
 	rctf rect;
 	short code, hits;
 	char dt, dtx;
+	char use_gpu_selection = GLEW_ARB_occlusion_query &&
(U.gpu_selection & USER_GPU_SELECTION);
+	// count issued queries (number of objects in scene)
+	int num_of_queries = 0;
+	unsigned int *queries;
 	
 	G.f |= G_PICKSEL;
 	
@@ -1206,10 +1210,30 @@
 	if(vc->rv3d->rflag & RV3D_CLIPPING)
 		view3d_set_clipping(vc->rv3d);
 	
-	glSelectBuffer( bufsize, (GLuint *)buffer);
-	glRenderMode(GL_SELECT);
-	glInitNames();	/* these two calls whatfor? It doesnt work otherwise */
-	glPushName(-1);
+	if(!use_gpu_selection){
+		glSelectBuffer( bufsize, (GLuint *)buffer);
+		glRenderMode(GL_SELECT);
+		glInitNames();	/* these two calls whatfor? It doesnt work otherwise */
+		glPushName(-1);
+	}else{
+		/* count number of objects */
+		Base *base;
+
+		for(base= scene->base.first; base; base= base->next) {
+			if(base->lay & v3d->lay) {
+				num_of_queries++;
+			}
+		}
+
+		queries = MEM_mallocN(num_of_queries*sizeof(*queries) , "gpu
selection queries");
+		glGenQueriesARB(num_of_queries, queries);
+
+		/* occlusion queries operates on fragments that pass tests and
since we are interested on all
+		 * objects in the view frustum independently of their order, we
need to disable the depth test */
+		glPushAttrib(GL_DEPTH_BUFFER_BIT);
+		glDisable(GL_DEPTH_TEST);
+	}
+
 	code= 1;
 	
 	if(vc->obedit && vc->obedit->type==OB_MBALL) {
@@ -1232,7 +1256,11 @@
 					base->selcol= 0;
 				else {
 					base->selcol= code;
-					glLoadName(code);
+					if(!use_gpu_selection){
+						glLoadName(code);
+					}else{
+						glBeginQueryARB(GL_SAMPLES_PASSED_ARB, queries[code-1]);
+					}
 					draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
 					
 					/* we draw group-duplicators for selection too */
@@ -1263,15 +1291,45 @@
 						free_object_duplilist(lb);
 					}
 					code++;
+					if(use_gpu_selection){
+						glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+					}
 				}				
 			}
 		}
 		v3d->xray= FALSE;	// restore
 	}
+	if(!use_gpu_selection){
+		glPopName();	/* see above (pushname) */
+		hits= glRenderMode(GL_RENDER);
+	}else{
+		int i;
+		hits = 0;
+
+		for(i = 0; i < num_of_queries; i++)
+		{
+			unsigned int result;
+			glGetQueryObjectuivARB(queries[i], GL_QUERY_RESULT_ARB, &result);
+			if(result > 0){
+				if(hits < bufsize){
+					buffer[hits*4] = hits;
+					buffer[hits*4+1] = 0;
+					buffer[hits*4+2] = 0;
+					buffer[hits*4+3] = i+1;
+
+					hits++;
+				}else{
+					hits = -1;
+					break;
+				}
+			}
+		}
+
+		glDeleteQueriesARB(num_of_queries, queries);
+		MEM_freeN(queries);
+		glPopAttrib();
+	}
 	
-	glPopName();	/* see above (pushname) */
-	hits= glRenderMode(GL_RENDER);
-	
 	G.f &= ~G_PICKSEL;
 	setwinmatrixview3d(ar, v3d, NULL);
 	mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
Index: source/blender/editors/interface/resources.c
===================================================================
--- source/blender/editors/interface/resources.c	(revision 42368)
+++ source/blender/editors/interface/resources.c	(working copy)
@@ -1679,6 +1679,10 @@
 		}
 	}

+	if (bmain->versionfile < 260 || (bmain->versionfile == 260 &&
bmain->subversionfile < 5)) {
+		U.gpu_selection = 1;
+	}
+
 	/* GL Texture Garbage Collection (variable abused above!) */
 	if (U.textimeout == 0) {
 		U.texcollectrate = 60;


More information about the Bf-committers mailing list