diff --git a/src/shader.cpp b/src/shader.cpp index 5cce26c..dcdd116 100644 --- a/src/shader.cpp +++ b/src/shader.cpp @@ -18,8 +18,13 @@ // NOTE: forward declarations const std::string dumpTextFile(const char* filepath); -void +bool parseShaderUniforms(memory_arena* arena, shader_program* s, GLContext* gl_ctx); +bool +parseUniformBlocks(memory_arena* arena, shader_program* s, GLContext* gl_ctx); +bool +parseAttributes(memory_arena* arena, shader_program* s, GLContext* gl_ctx); +void initCTXSizes(GLContext* gl_ctx); // NOTE: interface @@ -78,24 +83,21 @@ addShaderProgram(memory_arena* arena, initCTXSizes(gl_ctx); dumpShader(s->prog_id); s->model_xform_id = glGetUniformLocation(s->prog_id, "model_xform"); - - // FIXME: testing - // NOTE: set block binding for shader xforms uniform block - GLuint block_idx = glGetUniformBlockIndex(s->prog_id, "matrices"); - glUniformBlockBinding(s->prog_id, - block_idx, - gl_ctx->xform_ubo.binding_idx); - - //dumpShader(s->prog_id); - parseShaderUniforms(arena, s, gl_ctx); - /// - glDetachShader(s->prog_id, vs_id); glDetachShader(s->prog_id, fs_id); glDeleteShader(vs_id); glDeleteShader(fs_id); - return true; + if (parseShaderUniforms(arena, s, gl_ctx) + && parseUniformBlocks(arena, s, gl_ctx) + && parseAttributes(arena, s, gl_ctx)) + { + return true; + } else { + printf("%s(), Error parsing shader component\n", __FUNCTION__); + return false; + } + } printf("%s(), Error linking shader\n", __FUNCTION__); @@ -144,37 +146,35 @@ getGLTypeSize(GLenum e) case 0x8b51: return 4 * sizeof(GLfloat); // GL_FLOAT_VEC3 case 0x8b52: return 4 * sizeof(GLfloat); // GL_FLOAT_VEC4 case 0x8b5c: return 16 * sizeof(GLfloat); // GL_FLOAT_MAT4 - default: return 0; + default: + printf("%s(), unknown GLenum\n", __FUNCTION__); + return 0; } } -gl_uniform +const gl_uniform parseUniform(memory_arena* arena, shader_program* s, u32 uniform_idx) { - assert(uniform_idx < s->num_uniforms); - gl_uniform& unif = s->uniforms[uniform_idx]; - + gl_uniform unif = {0}; GLchar unif_name[256] = {0}; - GLsizei length; - GLint size; - GLenum type; - glGetActiveUniform(s->prog_id, uniform_idx, sizeof(unif_name), - &length, &size, &type, unif_name); + glGetActiveUniform(s->prog_id, + uniform_idx, + sizeof(unif_name), + &unif.name_len, + &unif.num_elements, + &unif.data_type, + unif_name); + glGetActiveUniformsiv(s->prog_id, 1, &uniform_idx, + GL_UNIFORM_BLOCK_INDEX, &unif.block_idx); - unif.data_type = type; - unif.name = (char*) arenaAllocateBlock( - arena, (length + 1) * sizeof(char)); - std::strncpy(unif.name, unif_name, length); - - // FIXME: testing idx == unif location unif.idx = uniform_idx; -#if 1 - GLuint location = glGetUniformLocation(s->prog_id, unif.name); - printf("uniform idx: %d, loc: %d, block idx: %d \n", - unif.idx, location, unif.block_idx); -#endif unif.data_size = getGLTypeSize(unif.data_type); + unif.name_len += 1; // NOTE: gl param dosen't account for null terminator + unif.name = + (char*) arenaAllocateBlock(arena, (unif.name_len) * sizeof(char)); + std::strncpy(unif.name, unif_name, unif.name_len); + unif.location = glGetUniformLocation(s->prog_id, unif.name); if (unif.data_size == 0) printf("%s(), error getting data_size\n", __FUNCTION__); @@ -182,21 +182,94 @@ parseUniform(memory_arena* arena, shader_program* s, u32 uniform_idx) return unif; } -void +bool parseShaderUniforms(memory_arena* arena, shader_program* s, GLContext* gl_ctx) { - GLint unif_count; - glGetProgramiv(s->prog_id, GL_ACTIVE_UNIFORMS, &unif_count); - s->num_uniforms = unif_count; + // NOTE: only add uniforms in the default block to the base uniform array + GLint num_uniforms_total = 0; + glGetProgramiv(s->prog_id, GL_ACTIVE_UNIFORMS, &num_uniforms_total); + GLint indices[num_uniforms_total]; + + for (u32 i = 0; i < (u32) num_uniforms_total; i++) { + GLint block_idx = 0; + glGetActiveUniformsiv(s->prog_id, 1, &i, + GL_UNIFORM_BLOCK_INDEX, &block_idx); + + if (block_idx == -1) { + indices[s->num_uniforms] = i; + s->num_uniforms++; + } + } + s->uniforms = (gl_uniform*) arenaAllocateBlock( arena, s->num_uniforms * sizeof(gl_uniform)); for (u32 i = 0; i < s->num_uniforms; i++) { - glGetActiveUniformsiv(s->prog_id, 1, &i, - GL_UNIFORM_BLOCK_INDEX, &s->uniforms[i].block_idx); + const gl_uniform unif = parseUniform(arena, s, indices[i]); + std::memcpy(&s->uniforms[i], &unif, sizeof(unif)); + } + + return true; +} + +i32 +ctxGetUniformBlockBinding(GLContext* gl_ctx, const char* name) +{ + for (u32 i = 0; i < gl_ctx->num_ubos; i++) { + gl_buffer& ubo = gl_ctx->uniform_buffers[i]; + + if (std::strstr(ubo.name, name)) + return ubo.binding_idx; + } + + printf("%s(), no buffer found with name: %s\n", __FUNCTION__, name); + return -1; +} - parseUniform(arena, s, i); +bool +parseUniformBlocks(memory_arena* arena, shader_program* s, GLContext* gl_ctx) +{ + glGetProgramiv(s->prog_id, GL_ACTIVE_UNIFORM_BLOCKS, + (GLint*) &s->num_blocks); + s->uniform_blocks = (GLUniformBlock*) arenaAllocateBlock(arena, + s->num_blocks * sizeof(GLUniformBlock)); + + for (u32 i = 0; i < s->num_blocks; i++) { + GLUniformBlock& ub = s->uniform_blocks[i]; + ub.block_id = i; + + GLchar block_name[256] = {0}; + glGetActiveUniformBlockName( + s->prog_id, i, 256, &ub.name_len, block_name); + ub.name_len++; // NOTE: space for null term + ub.name = (char*) arenaAllocateBlock(arena, ub.name_len * sizeof(char)); + std::strncpy(ub.name, block_name, ub.name_len); + + glGetActiveUniformBlockiv(s->prog_id, i, + GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, (GLint*) &ub.num_uniforms); + ub.uniforms = (gl_uniform*) + arenaAllocateBlock(arena, ub.num_uniforms * sizeof(gl_uniform)); + GLint indices[ub.num_uniforms] = {0}; + glGetActiveUniformBlockiv(s->prog_id, i, + GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, (GLint*) &indices); + + for (u32 j = 0; j < ub.num_uniforms; j++) { + const gl_uniform unif = parseUniform(arena, s, indices[j]); + std::memcpy(&ub.uniforms[j], &unif, sizeof(unif)); + } + + ub.binding_idx = ctxGetUniformBlockBinding(gl_ctx, ub.name); + +#if 0 + if (ub.binding_idx < 0) + return false; + + glUniformBlockBinding(s->prog_id, i, ub.binding_idx); +#endif } + + + return true; } bool diff --git a/src/shader.h b/src/shader.h index e7b0555..ce3bcd4 100644 --- a/src/shader.h +++ b/src/shader.h @@ -22,23 +22,33 @@ struct gl_buffer GLenum target; GLenum data_type; GLuint data_size; - GLuint binding_idx; // NOTE: set when used as backing for UBO + GLuint binding_idx; + char* name; }; struct gl_uniform { - GLuint idx; // NOTE: seems to map to location if not part of uniform block - //GLuint location; + // NOTE: would be nice to use idx as the location parameter because it seems + // to match when the uniform isn't part of a uniform block, at least with + // intel mesa driver, but apparently that's not guarantied + GLuint idx; + GLint location; GLint block_idx; GLenum data_type; GLint data_size; + GLint num_elements; + GLsizei name_len; char* name; }; struct GLUniformBlock { GLuint block_id; - GLuint prog_id; + GLint binding_idx; + GLuint num_uniforms; + gl_uniform* uniforms; + GLsizei name_len; + char* name; }; struct shader_program @@ -47,11 +57,10 @@ struct shader_program GLuint xforms_ubo_id; GLuint model_xform_id; - u32 num_uniform_blocks; + u32 num_blocks; GLUniformBlock* uniform_blocks; u32 num_uniforms; - // NOTE: contains individual uniforms, and uniforms part of a block gl_uniform* uniforms; u32 num_buffers; @@ -135,6 +144,9 @@ const glm::vec3 DEFAULT_CAM_POS = { 0, 0, -30.f }; const glm::vec3 DEFAULT_LOOK_POS = { 0, 0, 0 }; +// NOTE: every shader program is assumed to have one uniform block named +// "matrices" that contains the projection and view matrices, and one uniform +// named "model_xform" for the model matrix bool addShaderProgram(memory_arena* arena, GLContext* gl_ctx, const char* vs,