From e414a2d9e0095e51636beaed92b8d25cbf864bef Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Thu, 31 Jul 2008 17:48:36 -0400 Subject: [PATCH] Expose true constant arrays in parseData, load them at link time for GLSL. --HG-- branch : trunk --- mojoshader.c | 24 ++++--------------- mojoshader.h | 5 ++++ mojoshader_opengl.c | 58 ++++++++++++++++++++++++++++++++++++++++----- testparse.c | 5 ++-- 4 files changed, 65 insertions(+), 27 deletions(-) diff --git a/mojoshader.c b/mojoshader.c index 366ea256..11324aa2 100644 --- a/mojoshader.c +++ b/mojoshader.c @@ -2377,25 +2377,10 @@ static void emit_GLSL_const_array(Context *ctx, const ConstantsList *clist, else #endif { - // stock GLSL 1.0 can't do constant arrays, so make a global array - // and assign all entries at the start of the mainline... + // stock GLSL 1.0 can't do constant arrays, so make a uniform array + // and have the OpenGL glue assign it at link time. Lame! push_output(ctx, &ctx->globals); - output_line(ctx, "vec4 %s[%d];", varname, size); - pop_output(ctx); - - push_output(ctx, &ctx->mainline_intro); - ctx->indent++; - for (i = 0; i < size; i++) - { - while (clist->constant.type != MOJOSHADER_UNIFORM_FLOAT) - clist = clist->next; - assert(clist->constant.index == (base + i)); - cstr = get_GLSL_varname(ctx, REG_TYPE_CONST, clist->constant.index); - output_line(ctx, "%s[%d] = %s;", varname, i, cstr); - clist = clist->next; - ctx->scratchidx = origscratch; - } // for - ctx->indent--; + output_line(ctx, "uniform vec4 %s[%d];", varname, size); pop_output(ctx); } // else } // emit_GLSL_const_array @@ -7112,7 +7097,7 @@ static MOJOSHADER_uniform *build_uniforms(Context *ctx) int written = 0; for (var = ctx->variables; var != NULL; var = var->next) { - if ((!var->constant) && (var->used)) + if (var->used) { const char *name = ctx->profile->get_const_array_varname(ctx, var->index, var->count); @@ -7123,6 +7108,7 @@ static MOJOSHADER_uniform *build_uniforms(Context *ctx) wptr->type = MOJOSHADER_UNIFORM_FLOAT; wptr->index = var->index; wptr->array_count = var->count; + wptr->constant = (var->constant != NULL) ? 1 : 0; wptr->name = namecpy; wptr++; written++; diff --git a/mojoshader.h b/mojoshader.h index 3eb66284..bd8c7b66 100644 --- a/mojoshader.h +++ b/mojoshader.h @@ -92,6 +92,10 @@ typedef enum * just a single uniform. To be extra difficult, you'll need to fill in the * correct values from the MOJOSHADER_constant data into the appropriate * parts of the array, overriding the constant register file. Fun! + * (constant) says whether this is a constant array; these need to be loaded + * once at creation time, from the constant list and not ever updated from + * the constant register file. This is a workaround for limitations in some + * profiles. * (name) is a profile-specific variable name; it may be NULL if it isn't * applicable to the requested profile. */ @@ -100,6 +104,7 @@ typedef struct MOJOSHADER_uniformType type; int index; int array_count; + int constant; const char *name; } MOJOSHADER_uniform; diff --git a/mojoshader_opengl.c b/mojoshader_opengl.c index eff88249..853da95a 100644 --- a/mojoshader_opengl.c +++ b/mojoshader_opengl.c @@ -196,6 +196,7 @@ struct MOJOSHADER_glContext void (*profileUniform4iv)(const MOJOSHADER_parseData *, GLint, GLsizei, GLint *); void (*profileUniform1i)(const MOJOSHADER_parseData *, GLint, GLint); void (*profileSetSampler)(GLint loc, GLuint sampler); + int (*profileMustLoadConstantArrays)(void); }; @@ -259,6 +260,8 @@ static inline GLenum glsl_shader_type(const MOJOSHADER_shaderType t) } // glsl_shader_type +static int impl_GLSL_MustLoadConstantArrays(void) { return 1; } + static int impl_GLSL_MaxUniforms(MOJOSHADER_shaderType shader_type) { GLenum pname = GL_NONE; @@ -407,6 +410,7 @@ static inline GLenum arb1_shader_type(const MOJOSHADER_shaderType t) return GL_NONE; } // arb1_shader_type +static int impl_ARB1_MustLoadConstantArrays(void) { return 0; } static int impl_ARB1_MaxUniforms(MOJOSHADER_shaderType shader_type) { @@ -942,6 +946,7 @@ MOJOSHADER_glContext *MOJOSHADER_glCreateContext(const char *profile, ctx->profileUniform4iv = impl_GLSL_Uniform4iv; ctx->profileUniform1i = impl_GLSL_Uniform1i; ctx->profileSetSampler = impl_GLSL_SetSampler; + ctx->profileMustLoadConstantArrays = impl_GLSL_MustLoadConstantArrays; } // if #endif @@ -964,6 +969,7 @@ MOJOSHADER_glContext *MOJOSHADER_glCreateContext(const char *profile, ctx->profileUniform4iv = impl_ARB1_Uniform4iv; ctx->profileUniform1i = impl_ARB1_Uniform1i; ctx->profileSetSampler = impl_ARB1_SetSampler; + ctx->profileMustLoadConstantArrays = impl_ARB1_MustLoadConstantArrays; // GL_NV_gpu_program4 has integer uniform loading support. if (strcmp(profile, MOJOSHADER_PROFILE_NV4) == 0) @@ -988,6 +994,7 @@ MOJOSHADER_glContext *MOJOSHADER_glCreateContext(const char *profile, assert(ctx->profileUniform4iv != NULL); assert(ctx->profileUniform1i != NULL); assert(ctx->profileSetSampler != NULL); + assert(ctx->profileMustLoadConstantArrays != NULL); retval = ctx; ctx = current_ctx; @@ -1097,24 +1104,59 @@ static void program_unref(MOJOSHADER_glProgram *program) } // program_unref +static void fill_constant_array(GLfloat *f, const int base, const int size, + const MOJOSHADER_parseData *pd) +{ + int i; + int filled = 0; + for (i = 0; i < pd->constant_count; i++) + { + const MOJOSHADER_constant *c = &pd->constants[i]; + if (c->type != MOJOSHADER_UNIFORM_FLOAT) + continue; + else if (c->index < base) + continue; + else if (c->index >= (base+size)) + continue; + memcpy(&f[(c->index-base) * 4], &c->value.f, sizeof (c->value.f)); + filled++; + } // for + + assert(filled == size); +} // fill_constant_array + + static void lookup_uniforms(MOJOSHADER_glProgram *program, MOJOSHADER_glShader *shader) { const MOJOSHADER_parseData *pd = shader->parseData; - const MOJOSHADER_uniform *u = pd->uniforms; const MOJOSHADER_shaderType shader_type = pd->shader_type; int i; for (i = 0; i < pd->uniform_count; i++) { + const MOJOSHADER_uniform *u = &pd->uniforms[i]; const GLint loc = ctx->profileGetUniformLocation(program, shader, i); if (loc != -1) // maybe the Uniform was optimized out? { - UniformMap *map = &program->uniforms[program->uniform_count]; - map->shader_type = shader_type; - map->uniform = &u[i]; - map->location = (GLuint) loc; - program->uniform_count++; + // only do constants once, at link time. These aren't changed ever. + if ( (u->constant) && (ctx->profileMustLoadConstantArrays()) ) + { + const int base = u->index; + const int size = u->array_count; + GLfloat *f = (GLfloat *) alloca(sizeof (GLfloat) * size * 4); + fill_constant_array(f, base, size, pd); + ctx->profileUseProgramObject(program); + ctx->profileUniform4fv(pd, loc, size, f); + } // if + else + { + UniformMap *map = &program->uniforms[program->uniform_count]; + map->shader_type = shader_type; + map->uniform = u; + map->location = (GLuint) loc; + program->uniform_count++; + } // else } // if } // for } // lookup_uniforms @@ -1177,6 +1219,8 @@ static int build_constants_lists(MOJOSHADER_glProgram *program) const MOJOSHADER_uniform *u = map->uniform; const int size = u->array_count; + assert(!u->constant); + if (size == 0) continue; // nothing to see here. @@ -1506,6 +1550,8 @@ void MOJOSHADER_glProgramReady(void) GLint *regi; GLint *regb; + assert(!u->constant); + if (shader_type == MOJOSHADER_TYPE_VERTEX) { pd = ctx->bound_program->vertex->parseData; diff --git a/testparse.c b/testparse.c index 6d0a504b..932d5587 100644 --- a/testparse.c +++ b/testparse.c @@ -141,6 +141,7 @@ static int do_parse(const unsigned char *buf, const int len, const char *prof) static const char *typenames[] = { "float", "int", "bool" }; const MOJOSHADER_uniform *u = &pd->uniforms[i]; const char *arrayof = ""; + const char *constant = u->constant ? "const " : ""; char arrayrange[64] = { '\0' }; if (u->array_count > 0) { @@ -149,8 +150,8 @@ static int do_parse(const unsigned char *buf, const int len, const char *prof) u->array_count); } // if - printf(" * %d: %s%s%s", u->index, arrayof, arrayrange, - typenames[(int) u->type]); + printf(" * %d: %s%s%s%s", u->index, constant, arrayof, + arrayrange, typenames[(int) u->type]); if (u->name != NULL) printf(" (\"%s\")", u->name); printf("\n");