[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [29558] branches/soc-2010-jwilkins/source/ blender/windowmanager/intern/wm_draw.c: * Optimization: Now uses GL_ARB_depth_texture and GLSL to speed up the saving and restoring of the depth buffer needed for On-Surface brush .

Jason Wilkins Jason.A.Wilkins at gmail.com
Sat Jun 19 12:24:06 CEST 2010


Revision: 29558
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=29558
Author:   jwilkins
Date:     2010-06-19 12:24:04 +0200 (Sat, 19 Jun 2010)

Log Message:
-----------
* Optimization: Now uses GL_ARB_depth_texture and GLSL to speed up the saving and restoring of the depth buffer needed for On-Surface brush.

Hopefully this restores the performance that was lost.

Modified Paths:
--------------
    branches/soc-2010-jwilkins/source/blender/windowmanager/intern/wm_draw.c

Modified: branches/soc-2010-jwilkins/source/blender/windowmanager/intern/wm_draw.c
===================================================================
--- branches/soc-2010-jwilkins/source/blender/windowmanager/intern/wm_draw.c	2010-06-19 06:49:59 UTC (rev 29557)
+++ branches/soc-2010-jwilkins/source/blender/windowmanager/intern/wm_draw.c	2010-06-19 10:24:04 UTC (rev 29558)
@@ -324,6 +324,15 @@
 
 	char* depth;
 	GLenum depth_type;
+
+	GLuint depth_bind[MAX_N_TEX*MAX_N_TEX];
+	int depth_x[MAX_N_TEX], depth_y[MAX_N_TEX];
+	int depth_nx, depth_ny;
+	GLenum depth_target;
+
+	GLenum depth_vertex_shader;
+	GLenum depth_fragment_shader;
+	GLenum depth_program;
 } wmDrawTriple;
 
 static int is_pow2(int n)
@@ -392,7 +401,17 @@
 		wmDrawTriple *triple= win->drawdata;
 
 		glDeleteTextures(triple->nx*triple->ny, triple->bind);
-		MEM_freeN(triple->depth);
+
+		if (GLEW_ARB_depth_texture && GLEW_ARB_shader_objects) {
+			glDeleteTextures(triple->depth_nx*triple->depth_ny, triple->depth_bind);
+			glDeleteObjectARB(triple->depth_vertex_shader);
+			glDeleteObjectARB(triple->depth_fragment_shader);
+			glDeleteObjectARB(triple->depth_program);
+		}
+
+		if (triple->depth)
+			MEM_freeN(triple->depth);
+
 		MEM_freeN(triple);
 
 		win->drawdata= NULL;
@@ -544,18 +563,204 @@
 
 static int wm_triple_gen_depth_buffer(wmWindow *win, wmDrawTriple *triple)
 {
-	const int count = win->sizex * win->sizey;
-	const int size = count*sizeof(GLfloat);
+	if (GLEW_ARB_depth_texture &&
+		GLEW_ARB_shader_objects &&
+		GLEW_ARB_vertex_shader &&
+		GLEW_ARB_fragment_shader &&
+		GLEW_ARB_shading_language_100)
+	{
+		GLint maxsize;
+		int x, y;
 
-	triple->depth_type = GL_FLOAT;
-	triple->depth = MEM_mallocN(size, "wm_triple_gen_depth_buffer");
+		/* compute texture sizes */
+		if(GLEW_ARB_texture_rectangle) {
+			triple->depth_target= GL_TEXTURE_RECTANGLE_ARB;
+			triple->depth_nx= 1;
+			triple->depth_ny= 1;
+			triple->depth_x[0]= win->sizex;
+			triple->depth_y[0]= win->sizey;
+		}
+		else if(GPU_non_power_of_two_support()) {
+			triple->depth_target= GL_TEXTURE_2D;
+			triple->depth_nx= 1;
+			triple->depth_ny= 1;
+			triple->depth_x[0]= win->sizex;
+			triple->depth_y[0]= win->sizey;
+		}
+		else {
+			triple->depth_target= GL_TEXTURE_2D;
+			triple->depth_nx= 0;
+			triple->depth_ny= 0;
+			split_width(win->sizex, MAX_N_TEX, triple->depth_x, &triple->depth_nx);
+			split_width(win->sizey, MAX_N_TEX, triple->depth_y, &triple->depth_ny);
+		}
 
+		/* generate texture names */
+		glGenTextures(triple->depth_nx*triple->depth_ny, triple->depth_bind);
+
+		if(!triple->depth_bind[0]) {
+			/* not the typical failure case but we handle it anyway */
+			printf("WM: failed to allocate depth texture for triple buffer drawing (glGenTextures).\n");
+			return 0;
+		}
+
+		for(y=0; y<triple->depth_ny; y++) {
+			for(x=0; x<triple->depth_nx; x++) {
+				/* proxy texture is only guaranteed to test for the cases that
+				 * there is only one texture in use, which may not be the case */
+				glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxsize);
+
+				if(triple->depth_x[x] > maxsize || triple->depth_y[y] > maxsize) {
+					glBindTexture(triple->depth_target, 0);
+					printf("WM: failed to allocate texture for triple buffer drawing (texture too large for graphics card).\n");
+					return 0;
+				}
+
+				/* setup actual texture */
+				glBindTexture(triple->depth_target, triple->depth_bind[x + y*triple->depth_nx]);
+				glTexImage2D(triple->depth_target, 0, GL_DEPTH_COMPONENT, triple->depth_x[x], triple->depth_y[y], 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
+				glTexParameteri(triple->depth_target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+				glTexParameteri(triple->depth_target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+				glTexParameteri(triple->depth_target, GL_TEXTURE_COMPARE_MODE, GL_NONE);
+				glBindTexture(triple->depth_target, 0);
+
+				/* not sure if this works everywhere .. */
+				if(glGetError() == GL_OUT_OF_MEMORY) {
+					printf("WM: failed to allocate depth texture for triple buffer drawing (out of memory).\n");
+					return 0;
+				}
+			}
+		}
+
+		{
+			int success;
+			GLsizei len;
+
+			static const GLcharARB* depth_vertex_shader_source[] = { 
+//				"varying vec2 texture_coordinate;\n",
+				"void main()\n",
+				"{\n",
+				"gl_TexCoord[0] = gl_MultiTexCoord0;\n",
+				"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n",
+				"}\n",
+			};
+
+			static const GLcharARB* depth_fragment_shader_source[] = {
+//				"varying vec2 texture_coordinate;\n",
+				"uniform sampler2DRect depth_texture;\n",
+				"void main()\n",
+				"{\n",
+				"gl_FragDepth = texture2D(depth_texture, gl_TexCoord[0].xy).x;\n",
+				"}\n",
+			};
+
+			static const GLcharARB* depth_fragment_shader_rect_source[] = {
+				"#extension GL_ARB_texture_rectangle : enable\n",
+//				"varying vec2 texture_coordinate;\n",
+				"uniform sampler2DRect depth_texture;\n",
+				"void main()\n",
+				"{\n",
+				"gl_FragDepth = texture2DRect(depth_texture, gl_TexCoord[0].xy).x;\n",
+				"}\n",
+			};
+
+			triple->depth_vertex_shader = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
+			glShaderSourceARB(triple->depth_vertex_shader, sizeof(depth_vertex_shader_source)/sizeof(GLcharARB*), depth_vertex_shader_source, NULL);
+			glCompileShaderARB(triple->depth_vertex_shader);
+
+			glGetObjectParameterivARB(triple->depth_vertex_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success);
+			
+			/*if (!success)*/ {
+				GLbyte infoLog[1000];
+				len = 1000;
+
+				glGetInfoLogARB(triple->depth_vertex_shader, 1000, &len, infoLog);
+
+				//fprintf(stderr, "Error in vertex shader compilation!\n");
+
+				if (len > 0)
+					fprintf(stderr, "vertex:\n%s\n", infoLog);
+			}
+
+			triple->depth_fragment_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+
+			if (GLEW_ARB_texture_rectangle)
+				glShaderSourceARB(triple->depth_fragment_shader, sizeof(depth_fragment_shader_rect_source)/sizeof(GLcharARB*), depth_fragment_shader_rect_source, NULL);
+			else
+				glShaderSourceARB(triple->depth_fragment_shader, sizeof(depth_fragment_shader_source)/sizeof(GLcharARB*), depth_fragment_shader_source, NULL);
+
+			glCompileShaderARB(triple->depth_fragment_shader);
+
+			glGetObjectParameterivARB(triple->depth_fragment_shader, GL_OBJECT_COMPILE_STATUS_ARB, &success);
+
+			/*if (!success)*/ {
+				GLbyte infoLog[1000];
+
+				glGetInfoLogARB(triple->depth_fragment_shader, 1000, &len, infoLog);
+
+				//fprintf(stderr, "Error in fragment shader compilation!\n");
+
+				if (len > 0)
+					fprintf(stderr, "fragment:\n%s\n", infoLog);
+			}
+
+			triple->depth_program = glCreateProgramObjectARB();
+
+			glAttachObjectARB(triple->depth_program, triple->depth_vertex_shader);
+			glAttachObjectARB(triple->depth_program, triple->depth_fragment_shader);
+
+			glLinkProgramARB(triple->depth_program);
+
+			glGetObjectParameterivARB(triple->depth_program, GL_OBJECT_LINK_STATUS_ARB, &success);
+
+			/*if (!success)*/ {
+				GLbyte infoLog[1000];
+
+				glGetInfoLogARB(triple->depth_program, 1000, &len, infoLog);
+
+				//fprintf(stderr, "Error in linking!\n");
+
+				if (len > 0)
+					fprintf(stderr, "GLSL linking:\n%s\n", infoLog);
+			}
+		}
+	}
+	else {
+		const int count = win->sizex * win->sizey;
+		const int size = count*sizeof(GLfloat);
+
+		triple->depth_type = GL_FLOAT;
+		triple->depth = MEM_mallocN(size, "wm_triple_gen_depth_buffer");
+	}
+
 	return 1;
 }
 
 static void wm_triple_copy_depth_buffer(wmWindow *win, wmDrawTriple *triple)
 {
-	if (triple->depth) {
+	if (GLEW_ARB_depth_texture &&
+		GLEW_ARB_shader_objects &&
+		GLEW_ARB_vertex_shader &&
+		GLEW_ARB_fragment_shader &&
+		GLEW_ARB_shading_language_100)
+	{
+		int x, y, sizex, sizey, offx, offy;
+
+		for(y=0, offy=0; y<triple->depth_ny; offy+=triple->depth_y[y], y++) {
+			for(x=0, offx=0; x<triple->depth_nx; offx+=triple->depth_x[x], x++) {
+				sizex= (x == triple->depth_nx-1)? win->sizex-offx: triple->depth_x[x];
+				sizey= (y == triple->depth_ny-1)? win->sizey-offy: triple->depth_y[y];
+
+				glBindTexture(triple->depth_target, triple->depth_bind[x + y*triple->depth_nx]);
+				glCopyTexSubImage2D(triple->depth_target, 0, 0, 0, offx, offy, sizex, sizey);
+			}
+		}
+
+		glBindTexture(triple->depth_target, 0);
+	}
+	else if (triple->depth) {
+		glPushAttrib(GL_PIXEL_MODE_BIT);
+
 		glPixelStorei(GL_PACK_SWAP_BYTES,  GL_FALSE);
 		glPixelStorei(GL_PACK_ROW_LENGTH,  0);
 		glPixelStorei(GL_PACK_SKIP_ROWS,   0);
@@ -566,41 +771,119 @@
 		glPixelTransferi(GL_DEPTH_BIAS, 0);
 
 		glReadPixels(0, 0, win->sizex, win->sizey, GL_DEPTH_COMPONENT, triple->depth_type, triple->depth);
+
+		glPopAttrib();
 	}
 }
 
 static void wm_triple_draw_depth_buffer(wmWindow *win, wmDrawTriple *triple)
 {
-	// This state changing is probably overkill, but I had a lot of trouble figuring out exactly what state was keeping this from working.
+	if (GLEW_ARB_depth_texture &&
+		GLEW_ARB_shader_objects &&
+		GLEW_ARB_vertex_shader &&
+		GLEW_ARB_fragment_shader &&
+		GLEW_ARB_shading_language_100)
+	{
+		float halfx, halfy, ratiox, ratioy;
+		int x, y, sizex, sizey, offx, offy;
+		GLint depth_texture;
 
-	if (triple->depth) {
-		glPixelStorei(GL_UNPACK_SWAP_BYTES,  GL_FALSE);
-		glPixelStorei(GL_UNPACK_ROW_LENGTH,  0);
-		glPixelStorei(GL_UNPACK_SKIP_ROWS,   0);
-		glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
-		glPixelStorei(GL_UNPACK_ALIGNMENT,   4);
+		glPushAttrib(
+			GL_COLOR_BUFFER_BIT|
+			GL_DEPTH_BUFFER_BIT);
 
-		glPixelTransferi(GL_DEPTH_SCALE, 1);
-		glPixelTransferi(GL_DEPTH_BIAS, 0);
-
-		glPixelZoom(1.0, 1.0);
-
 		glEnable(GL_DEPTH_TEST);
+		glDepthFunc(GL_ALWAYS);
+		glDepthMask(GL_TRUE);
 
-		glDepthMask(GL_TRUE);
 		glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 
-		glDepthFunc(GL_ALWAYS);
+		glUseProgramObjectARB(triple->depth_program);
+		depth_texture = glGetUniformLocationARB(triple->depth_program, "depth_texture");
 
-		glRasterPos2i(0, 0);
-		glDrawPixels(win->sizex, win->sizey, GL_DEPTH_COMPONENT, triple->depth_type, triple->depth);
+		glActiveTextureARB(GL_TEXTURE0_ARB);
 
-		glDepthFunc(GL_LEQUAL);
+		glEnable(triple->depth_target);
 
-		glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+		for(y=0, offy=0; y<triple->depth_ny; offy+=triple->depth_y[y], y++) {
+			for(x=0, offx=0; x<triple->depth_nx; offx+=triple->depth_x[x], x++) {
+				sizex= (x == triple->depth_nx-1)? win->sizex-offx: triple->depth_x[x];
+				sizey= (y == triple->depth_ny-1)? win->sizey-offy: triple->depth_y[y];
 
-		glDisable(GL_DEPTH_TEST);
+				/* wmOrtho for the screen has this same offset */

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list