[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [15252] branches/apricot/source/blender/ gpu: Apricot Branch: GLSL

Brecht Van Lommel brechtvanlommel at pandora.be
Tue Jun 17 20:37:32 CEST 2008


Revision: 15252
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=15252
Author:   blendix
Date:     2008-06-17 20:36:29 +0200 (Tue, 17 Jun 2008)

Log Message:
-----------
Apricot Branch: GLSL
====================

* Internal change only: now it compiles the functions separately
  once and then links them together with the generated code, instead
  of appending the code and compiling them again for each material.
  Gives only slight compilation speedup unfortunately.

Modified Paths:
--------------
    branches/apricot/source/blender/gpu/GPU_extensions.h
    branches/apricot/source/blender/gpu/intern/gpu_codegen.c
    branches/apricot/source/blender/gpu/intern/gpu_codegen.h
    branches/apricot/source/blender/gpu/intern/gpu_extensions.c

Modified: branches/apricot/source/blender/gpu/GPU_extensions.h
===================================================================
--- branches/apricot/source/blender/gpu/GPU_extensions.h	2008-06-17 17:32:12 UTC (rev 15251)
+++ branches/apricot/source/blender/gpu/GPU_extensions.h	2008-06-17 18:36:29 UTC (rev 15252)
@@ -114,7 +114,8 @@
    - only for fragment shaders now
    - must call texture bind before setting a texture as uniform! */
 
-GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode);
+GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, GPUShader *lib);
+GPUShader *GPU_shader_create_lib(const char *code);
 void GPU_shader_free(GPUShader *shader);
 
 void GPU_shader_bind(GPUShader *shader);

Modified: branches/apricot/source/blender/gpu/intern/gpu_codegen.c
===================================================================
--- branches/apricot/source/blender/gpu/intern/gpu_codegen.c	2008-06-17 17:32:12 UTC (rev 15251)
+++ branches/apricot/source/blender/gpu/intern/gpu_codegen.c	2008-06-17 18:36:29 UTC (rev 15252)
@@ -152,10 +152,31 @@
 	struct GPUShader *shader;
 };
 
+/* Strings utility */
+
+static void BLI_dynstr_printf(DynStr *dynstr, const char *format, ...)
+{
+	va_list args;
+	int retval;
+	char str[2048];
+
+	/* todo: windows support */
+	va_start(args, format);
+	retval = vsnprintf(str, sizeof(str), format, args);
+	va_end(args);
+
+	if (retval >= sizeof(str))
+		fprintf(stderr, "BLI_dynstr_printf: limit exceeded\n");
+	else
+		BLI_dynstr_append(dynstr, str);
+}
+
 /* GLSL code parsing for finding function definitions.
  * These are stored in a hash for lookup when creating a material. */
 
 static GHash *FUNCTION_HASH= NULL;
+static char *FUNCTION_PROTOTYPES= NULL;
+static GPUShader *FUNCTION_LIB= NULL;
 
 static int gpu_str_prefix(char *str, char *prefix)
 {
@@ -206,7 +227,7 @@
 static void gpu_parse_functions_string(GHash *hash, char *code)
 {
 	GPUFunction *function;
-	int i, type, out;
+	int i, type, qual;
 
 	while((code = strstr(code, "void "))) {
 		function = MEM_callocN(sizeof(GPUFunction), "GPUFunction");
@@ -217,8 +238,12 @@
 		/* get parameters */
 		while(*code && *code != ')') {
 			/* test if it's an input or output */
-			out= gpu_str_prefix(code, "out ");
-			if(out || gpu_str_prefix(code, "in ") || gpu_str_prefix(code, "inout "))
+			qual = FUNCTION_QUAL_IN;
+			if(gpu_str_prefix(code, "out "))
+				qual = FUNCTION_QUAL_OUT;
+			if(gpu_str_prefix(code, "inout "))
+				qual = FUNCTION_QUAL_INOUT;
+			if((qual != FUNCTION_QUAL_IN) || gpu_str_prefix(code, "in "))
 				code = gpu_str_skip_token(code, NULL, 0);
 
 			/* test for type */
@@ -239,7 +264,7 @@
 				/* add paramater */
 				code = gpu_str_skip_token(code, NULL, 0);
 				code = gpu_str_skip_token(code, NULL, 0);
-				function->paramout[function->totparam]= out;
+				function->paramqual[function->totparam]= qual;
 				function->paramtype[function->totparam]= type;
 				function->totparam++;
 			}
@@ -259,11 +284,59 @@
 	}
 }
 
+static char *gpu_generate_function_prototyps(GHash *hash)
+{
+	DynStr *ds = BLI_dynstr_new();
+	GHashIterator *ghi;
+	GPUFunction *function;
+	char *name, *prototypes;
+	int a;
+	
+	/* automatically generate function prototypes to add to the top of the
+	 * generated code, to avoid have to add the actual code & recompile all */
+	ghi = BLI_ghashIterator_new(hash);
+
+	for(; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)) {
+		name = BLI_ghashIterator_getValue(ghi);
+		function = BLI_ghashIterator_getValue(ghi);
+
+		BLI_dynstr_printf(ds, "void %s(", name);
+		for(a=0; a<function->totparam; a++) {
+			if(function->paramqual[a] == FUNCTION_QUAL_OUT)
+				BLI_dynstr_append(ds, "out ");
+			else if(function->paramqual[a] == FUNCTION_QUAL_INOUT)
+				BLI_dynstr_append(ds, "inout ");
+
+			if(function->paramtype[a] == GPU_TEX1D)
+				BLI_dynstr_append(ds, "sampler1D");
+			else if(function->paramtype[a] == GPU_TEX2D)
+				BLI_dynstr_append(ds, "sampler2D");
+			else
+				BLI_dynstr_append(ds, GPU_DATATYPE_STR[function->paramtype[a]]);
+				
+			BLI_dynstr_printf(ds, " param%d", a);
+			
+			if(a != function->totparam-1)
+				BLI_dynstr_append(ds, ", ");
+		}
+		BLI_dynstr_append(ds, ");\n");
+	}
+
+	BLI_dynstr_append(ds, "\n");
+
+	prototypes = BLI_dynstr_get_cstring(ds);
+	BLI_dynstr_free(ds);
+
+	return prototypes;
+}
+
 GPUFunction *GPU_lookup_function(char *name)
 {
 	if(!FUNCTION_HASH) {
 		FUNCTION_HASH= BLI_ghash_new(BLI_ghashutil_strhash, BLI_ghashutil_strcmp);
 		gpu_parse_functions_string(FUNCTION_HASH, datatoc_material_shaders_glsl);
+		FUNCTION_PROTOTYPES = gpu_generate_function_prototyps(FUNCTION_HASH);
+		FUNCTION_LIB = GPU_shader_create_lib(datatoc_material_shaders_glsl);
 	}
 
 	return (GPUFunction*)BLI_ghash_lookup(FUNCTION_HASH, name);
@@ -273,27 +346,12 @@
 {
 	if(FUNCTION_HASH)
 		BLI_ghash_free(FUNCTION_HASH, NULL, (GHashValFreeFP)MEM_freeN);
+	if(FUNCTION_PROTOTYPES)
+		MEM_freeN(FUNCTION_PROTOTYPES);
+	if(FUNCTION_LIB)
+		GPU_shader_free(FUNCTION_LIB);
 }
 
-/* Strings utility */
-
-static void BLI_dynstr_printf(DynStr *dynstr, const char *format, ...)
-{
-	va_list args;
-	int retval;
-	char str[2048];
-
-	/* todo: windows support */
-	va_start(args, format);
-	retval = vsnprintf(str, sizeof(str), format, args);
-	va_end(args);
-
-	if (retval >= sizeof(str))
-		fprintf(stderr, "BLI_dynstr_printf: limit exceeded\n");
-	else
-		BLI_dynstr_append(dynstr, str);
-}
-
 /* GLSL code generation */
 
 static void codegen_convert_datatype(DynStr *ds, int from, int to, char *tmp, int id)
@@ -478,8 +536,6 @@
 	}
 
 	BLI_dynstr_append(ds, "\n");
-
-	BLI_dynstr_append(ds, datatoc_material_shaders_glsl);
 }
 
 static void codegen_declare_tmps(DynStr *ds, ListBase *nodes)
@@ -560,6 +616,8 @@
 	DynStr *ds = BLI_dynstr_new();
 	char *code;
 
+	BLI_dynstr_append(ds, FUNCTION_PROTOTYPES);
+
 	codegen_set_unique_ids(nodes);
 	codegen_print_uniforms_functions(ds, nodes);
 
@@ -1045,7 +1103,7 @@
 
 	va_start(params, name);
 	for(i=0; i<function->totparam; i++) {
-		if(function->paramout[i]) {
+		if(function->paramqual[i] != FUNCTION_QUAL_IN) {
 			linkptr= va_arg(params, GPUNodeLink**);
 			GPU_node_output(node, function->paramtype[i], "", linkptr);
 		}
@@ -1097,7 +1155,7 @@
 
 	va_start(params, out);
 	for(i=0; i<function->totparam; i++) {
-		if(function->paramout[i]) {
+		if(function->paramqual[i] != FUNCTION_QUAL_IN) {
 			if(totout == 0) {
 				linkptr= va_arg(params, GPUNodeLink**);
 				GPU_node_output(node, function->paramtype[i], "", linkptr);
@@ -1168,13 +1226,18 @@
 	GPUPass *pass;
 	char *vertexcode, *fragmentcode;
 
+	if(!FUNCTION_LIB) {
+		GPU_nodes_free(nodes);
+		return NULL;
+	}
+
 	/* prune unused nodes */
 	gpu_nodes_prune(nodes, outlink);
 
 	/* generate code and compile with opengl */
 	fragmentcode = code_generate_fragment(nodes, outlink->source);
 	vertexcode = (vertexshader)? code_generate_vertex(nodes, profile): NULL;
-	shader = GPU_shader_create(vertexcode, fragmentcode);
+	shader = GPU_shader_create(vertexcode, fragmentcode, FUNCTION_LIB);
 	MEM_freeN(fragmentcode);
 	MEM_freeN(vertexcode);
 

Modified: branches/apricot/source/blender/gpu/intern/gpu_codegen.h
===================================================================
--- branches/apricot/source/blender/gpu/intern/gpu_codegen.h	2008-06-17 17:32:12 UTC (rev 15251)
+++ branches/apricot/source/blender/gpu/intern/gpu_codegen.h	2008-06-17 18:36:29 UTC (rev 15252)
@@ -44,10 +44,14 @@
 #define MAX_FUNCTION_NAME	64
 #define MAX_PARAMETER		32
 
+#define FUNCTION_QUAL_IN	0
+#define FUNCTION_QUAL_OUT	1
+#define FUNCTION_QUAL_INOUT	2
+
 typedef struct GPUFunction {
 	char name[MAX_FUNCTION_NAME];
 	int paramtype[MAX_PARAMETER];
-	int paramout[MAX_PARAMETER];
+	int paramqual[MAX_PARAMETER];
 	int totparam;
 } GPUFunction;
 

Modified: branches/apricot/source/blender/gpu/intern/gpu_extensions.c
===================================================================
--- branches/apricot/source/blender/gpu/intern/gpu_extensions.c	2008-06-17 17:32:12 UTC (rev 15251)
+++ branches/apricot/source/blender/gpu/intern/gpu_extensions.c	2008-06-17 18:36:29 UTC (rev 15252)
@@ -823,6 +823,7 @@
 	GLhandleARB object;		/* handle for full shader */
 	GLhandleARB vertex;		/* handle for vertex shader */
 	GLhandleARB fragment;	/* handle for fragment shader */
+	GLhandleARB lib;		/* handle for libment shader */
 	int totattrib;			/* total number of attributes */
 };
 
@@ -846,7 +847,7 @@
 	fprintf(stderr, "%s\n", log);
 }
 
-GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode)
+GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, GPUShader *lib)
 {
 	GLint status;
 	GLcharARB log[5000];
@@ -906,6 +907,9 @@
 		}
 	}
 
+	if(lib && lib->lib)
+		glAttachObjectARB(shader->object, lib->lib);
+
 	glLinkProgramARB(shader->object);
 	glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
 	if (!status) {
@@ -919,6 +923,44 @@
 	return shader;
 }
 
+GPUShader *GPU_shader_create_lib(const char *code)
+{
+	GLint status;
+	GLcharARB log[5000];
+	GLsizei length = 0;
+	GPUShader *shader;
+
+	if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
+		return NULL;
+
+	shader = MEM_callocN(sizeof(GPUShader), "GPUShader");
+
+	shader->lib = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
+
+	if (!shader->lib) {
+		fprintf(stderr, "GPUShader, object creation failed.\n");
+		GPU_shader_free(shader);
+		return NULL;
+	}
+
+	glShaderSourceARB(shader->lib, 1, (const char**)&code, NULL);
+
+	glCompileShaderARB(shader->lib);
+	glGetObjectParameterivARB(shader->lib, GL_OBJECT_COMPILE_STATUS_ARB, &status);
+
+	if (!status) {
+		glValidateProgramARB(shader->lib);
+		glGetInfoLogARB(shader->lib, sizeof(log), &length, log);
+		shader_print_errors("compile", log, code);
+
+		GPU_shader_free(shader);
+		return NULL;
+	}
+
+	return shader;
+}
+
+
 void GPU_shader_bind(GPUShader *shader)
 {
 	GPU_print_error("Pre Shader Bind");
@@ -935,6 +977,10 @@
 
 void GPU_shader_free(GPUShader *shader)
 {
+	if (shader->lib)
+		glDeleteObjectARB(shader->lib);
+	if (shader->vertex)
+		glDeleteObjectARB(shader->vertex);
 	if (shader->fragment)
 		glDeleteObjectARB(shader->fragment);
 	if (shader->object)





More information about the Bf-blender-cvs mailing list