From 66b5a575bd3c00d23ae9fdf5866b284510e1df15 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 6 May 2008 00:26:59 -0400 Subject: [PATCH] Sampler loading support in OpenGL glue. --HG-- branch : trunk --- mojoshader.c | 7 +++++ mojoshader.h | 31 +++++++++++++++++++ mojoshader_opengl.c | 75 ++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 108 insertions(+), 5 deletions(-) diff --git a/mojoshader.c b/mojoshader.c index 5d3a157b..dfa25a9b 100644 --- a/mojoshader.c +++ b/mojoshader.c @@ -3757,6 +3757,9 @@ static void state_DCL(Context *ctx) // !!! FIXME: fail if DCL opcode comes after real instructions. + // !!! FIXME: apparently vs_3_0 can use sampler registers now. + // !!! FIXME: (but only s0 through s3, not all 16 of them.) + if (shader_is_vertex(ctx)) { const MOJOSHADER_usage usage = (const MOJOSHADER_usage) ctx->dwords[0]; @@ -4986,6 +4989,10 @@ static MOJOSHADER_parseData *build_parsedata(Context *ctx) static void process_definitions(Context *ctx) { + // !!! FIXME: apparently, pre ps_3_0, sampler registers don't need to be + // !!! FIXME: DCL'd before use (default to 2d?). We aren't checking + // !!! FIXME: this at the moment, though. + RegisterList *uitem = &ctx->uniforms; RegisterList *prev = &ctx->used_registers; RegisterList *item = prev->next; diff --git a/mojoshader.h b/mojoshader.h index 648be95e..102c02a8 100644 --- a/mojoshader.h +++ b/mojoshader.h @@ -766,6 +766,37 @@ void MOJOSHADER_glSetVertexAttribute(MOJOSHADER_usage usage, int normalized, unsigned int stride, const void *ptr); +/* + * Set a sampler. + * + * There is a single array of samplers shared by all shaders. + * This is the "s" register file in Direct3D (s0, s1, s2, etc...), also + * known as the "sampler stages." MojoShader will take care of synchronizing + * this internal array with the appropriate variables in the GL shaders. + * + * Unlike the float and int counterparts, samplers are single values, not + * four-element vectors...so idx==1 is the second sampler in the internal + * array, not the fifth. + * + * (sampler) is the index into the internal array. + * (unit) is an OpenGL TEXTURE UNIT (not a texture name!). This is the + * unit's index, not the GLenum. So if you want GL_TEXTURE_0, use 0. + * + * Bind the texture unit, set state, call this to assign it to the internal + * array, where it will propagate to the shader during + * MOJOSHADER_glProgramReady(). + * + * This call is NOT thread safe! As most OpenGL implementations are not thread + * safe, you should probably only call this from the same thread that created + * the GL context. + * + * This call requires a valid MOJOSHADER_glContext to have been made current, + * or it will crash your program. See MOJOSHADER_glMakeContextCurrent(). + * + * Samplers are not shared between contexts. + */ +void MOJOSHADER_glSetSampler(unsigned int sampler, unsigned int unit); + /* * Inform MojoShader that it should commit any pending state to the GL. This * must be called after you bind a program and update any inputs, right diff --git a/mojoshader_opengl.c b/mojoshader_opengl.c index 722bc650..ab255bcb 100644 --- a/mojoshader_opengl.c +++ b/mojoshader_opengl.c @@ -59,6 +59,13 @@ typedef struct GLuint location; } UniformMap; +typedef struct +{ + MOJOSHADER_shaderType shader_type; + const MOJOSHADER_sampler *sampler; + GLuint location; +} SamplerMap; + typedef struct { const MOJOSHADER_attribute *attribute; @@ -74,6 +81,8 @@ struct MOJOSHADER_glProgram GLfloat *constants; // !!! FIXME: misnamed. uint32 uniform_count; UniformMap *uniforms; + uint32 sampler_count; + SamplerMap *samplers; uint32 attribute_count; AttributeMap *attributes; uint32 refcount; @@ -102,6 +111,7 @@ struct MOJOSHADER_glContext GLfloat ps_reg_file_f[8192 * 4]; GLint ps_reg_file_i[2047 * 4]; GLint ps_reg_file_b[2047]; + GLuint sampler_reg_file[16]; // GL stuff... int opengl_major; @@ -524,9 +534,10 @@ static void program_unref(MOJOSHADER_glProgram *program) ctx->glDeleteObject(program->handle); shader_unref(program->vertex); shader_unref(program->fragment); - Free(program->attributes); - Free(program->uniforms); Free(program->constants); + Free(program->samplers); + Free(program->uniforms); + Free(program->attributes); Free(program); } // else } // if @@ -556,6 +567,29 @@ static void lookup_uniforms(MOJOSHADER_glProgram *program, } // lookup_uniforms +static void lookup_samplers(MOJOSHADER_glProgram *program, + MOJOSHADER_glShader *shader) +{ + int i; + const MOJOSHADER_parseData *pd = shader->parseData; + const MOJOSHADER_sampler *s = pd->samplers; + const MOJOSHADER_shaderType shader_type = pd->shader_type; + + for (i = 0; i < pd->sampler_count; i++) + { + const GLint loc = ctx->glGetUniformLocation(program->handle, s[i].name); + if (loc != -1) // maybe the Sampler was optimized out? + { + SamplerMap *map = &program->samplers[program->sampler_count]; + map->shader_type = shader_type; + map->sampler = &s[i]; + map->location = (GLuint) loc; + program->sampler_count++; + } // if + } // for +} // lookup_samplers + + static void lookup_attributes(MOJOSHADER_glProgram *program) { int i; @@ -605,6 +639,7 @@ MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader, goto link_program_fail; memset(retval, '\0', sizeof (MOJOSHADER_glProgram)); + numregs = 0; if (vshader != NULL) numregs += vshader->parseData->uniform_count; if (pshader != NULL) numregs += pshader->parseData->uniform_count; retval->uniforms = (UniformMap *) Malloc(sizeof (UniformMap) * numregs); @@ -612,6 +647,14 @@ MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader, goto link_program_fail; memset(retval->uniforms, '\0', sizeof (UniformMap) * numregs); + numregs = 0; + if (vshader != NULL) numregs += vshader->parseData->sampler_count; + if (pshader != NULL) numregs += pshader->parseData->sampler_count; + retval->samplers = (SamplerMap *) Malloc(sizeof (SamplerMap) * numregs); + if (retval->samplers == NULL) + goto link_program_fail; + memset(retval->samplers, '\0', sizeof (SamplerMap) * numregs); + retval->handle = program; retval->vertex = vshader; retval->fragment = pshader; @@ -630,6 +673,7 @@ MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader, lookup_attributes(retval); lookup_uniforms(retval, vshader); + lookup_samplers(retval, vshader); vshader->refcount++; } // if @@ -639,6 +683,7 @@ MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader, const_count = pshader->parseData->constant_count; lookup_uniforms(retval, pshader); + lookup_samplers(retval, vshader); pshader->refcount++; } // if @@ -655,9 +700,10 @@ MOJOSHADER_glProgram *MOJOSHADER_glLinkProgram(MOJOSHADER_glShader *vshader, link_program_fail: if (retval != NULL) { + Free(retval->constants); + Free(retval->samplers); Free(retval->uniforms); Free(retval->attributes); - Free(retval->constants); Free(retval); } // if @@ -785,6 +831,14 @@ void MOJOSHADER_glSetPixelShaderUniformB(unsigned int idx, const int *data, } // MOJOSHADER_glSetPixelShaderUniformB +void MOJOSHADER_glSetSampler(unsigned int idx, unsigned int unit) +{ + const uint maxregs = STATICARRAYLEN(ctx->sampler_reg_file); + if (idx < maxregs) + ctx->sampler_reg_file[idx] = (GLuint) unit; +} // MOJOSHADER_glSetSampler + + static inline GLenum opengl_attr_type(const MOJOSHADER_attributeType type) { switch (type) @@ -809,6 +863,7 @@ static inline GLenum opengl_attr_type(const MOJOSHADER_attributeType type) } // opengl_attr_type +// !!! FIXME: shouldn't (index) be unsigned? void MOJOSHADER_glSetVertexAttribute(MOJOSHADER_usage usage, int index, unsigned int size, MOJOSHADER_attributeType type, @@ -857,14 +912,15 @@ void MOJOSHADER_glSetVertexAttribute(MOJOSHADER_usage usage, void MOJOSHADER_glProgramReady(void) { int i; + int count; if (ctx->bound_program == NULL) return; // nothing to do. - // !!! FIXME: don't push Uniforms if we know they haven't changed. + // !!! FIXME: don't push Uniforms/Samplers if they haven't changed. // push Uniforms to the program from our register files... - const int count = ctx->bound_program->uniform_count; + count = ctx->bound_program->uniform_count; for (i = 0; i < count; i++) { const UniformMap *map = &ctx->bound_program->uniforms[i]; @@ -980,6 +1036,15 @@ void MOJOSHADER_glProgramReady(void) ctx->glUniform1i(location, ctx->ps_reg_file_b[index]); } // else if } // for + + // push Samplers to the program from our register files... + count = ctx->bound_program->sampler_count; + for (i = 0; i < count; i++) + { + const SamplerMap *map = &ctx->bound_program->samplers[i]; + const MOJOSHADER_sampler *s = map->sampler; + ctx->glUniform1i(map->location, ctx->sampler_reg_file[s->index]); + } // for } // MOJOSHADER_glProgramReady