From a372abb81008cec52f55b34801e0706f0d38f4a2 Mon Sep 17 00:00:00 2001 From: bjorn Date: Sat, 28 Jul 2018 15:40:13 -0700 Subject: [PATCH] Reorganize uniform/block data structures; --- src/api/graphics.c | 30 +++++---- src/api/types/shader.c | 4 +- src/graphics/opengl.c | 133 +++++++++++++++++++++---------------- src/graphics/shader.h | 8 +-- src/graphics/shaderBlock.h | 2 +- 5 files changed, 98 insertions(+), 79 deletions(-) diff --git a/src/api/graphics.c b/src/api/graphics.c index 52f3b8ed..c023f2ad 100644 --- a/src/api/graphics.c +++ b/src/api/graphics.c @@ -854,7 +854,8 @@ int l_lovrGraphicsNewAnimator(lua_State* L) { } int l_lovrGraphicsNewShaderBlock(lua_State* L) { - Uniform uniforms[MAX_SHADER_BLOCK_UNIFORMS]; + vec_uniform_t uniforms; + vec_init(&uniforms); int count = 0; luaL_checktype(L, 1, LUA_TTABLE); @@ -872,44 +873,47 @@ int l_lovrGraphicsNewShaderBlock(lua_State* L) { luaL_checktype(L, -1, LUA_TTABLE); // Name - Uniform* uniform = &uniforms[count++]; - strncpy(uniform->name, lua_tostring(L, -2), LOVR_MAX_UNIFORM_LENGTH - 1); + Uniform uniform; + strncpy(uniform.name, lua_tostring(L, -2), LOVR_MAX_UNIFORM_LENGTH - 1); // Count lua_getfield(L, -1, "count"); - uniform->count = lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : 1; + uniform.count = lua_type(L, -1) == LUA_TNUMBER ? lua_tonumber(L, -1) : 1; lua_pop(L, 1); // Type size_t length; lua_getfield(L, -1, "type"); const char* type = lua_tolstring(L, -1, &length); - uniform->components = 1; + uniform.components = 1; if (strcmp(type, "float")) { - uniform->type = UNIFORM_FLOAT; + uniform.type = UNIFORM_FLOAT; } else if (strcmp(type, "int")) { - uniform->type = UNIFORM_INT; + uniform.type = UNIFORM_INT; } else { - uniform->components = type[length - 1] - '0'; - lovrAssert(uniform->components >= 2 && uniform->components <= 4, "Unknown uniform type '%s'", type); + uniform.components = type[length - 1] - '0'; + lovrAssert(uniform.components >= 2 && uniform.components <= 4, "Unknown uniform type '%s'", type); if (!strncmp(type, "vec", 3 * sizeof(char)) && length == 4) { - uniform->type = UNIFORM_FLOAT; + uniform.type = UNIFORM_FLOAT; } else if (!strncmp(type, "ivec", 4 * sizeof(char)) && length == 5) { - uniform->type = UNIFORM_INT; + uniform.type = UNIFORM_INT; } else if (!strncmp(type, "mat", 3 * sizeof(char)) && length == 4) { - uniform->type = UNIFORM_MATRIX; + uniform.type = UNIFORM_MATRIX; } else { lovrThrow("Unknown uniform type '%s'", type); } } lua_pop(L, 1); + vec_push(&uniforms, uniform); + // Pop the table, leaving the key for lua_next lua_pop(L, 1); } - ShaderBlock* block = lovrShaderBlockCreate(uniforms, count); + ShaderBlock* block = lovrShaderBlockCreate(&uniforms); luax_pushtype(L, ShaderBlock, block); + vec_deinit(&uniforms); return 1; } diff --git a/src/api/types/shader.c b/src/api/types/shader.c index a9baa0c9..f3bdf487 100644 --- a/src/api/types/shader.c +++ b/src/api/types/shader.c @@ -4,7 +4,7 @@ struct TempData { void* data; - size_t size; + int size; }; static struct TempData tempData; @@ -23,7 +23,7 @@ int l_lovrShaderSend(lua_State* L) { int count; int components; - size_t size; + int size; UniformType type; bool present = lovrShaderGetUniform(shader, name, &count, &components, &size, &type); diff --git a/src/graphics/opengl.c b/src/graphics/opengl.c index a994572a..06f30e7f 100644 --- a/src/graphics/opengl.c +++ b/src/graphics/opengl.c @@ -67,8 +67,7 @@ static struct { struct ShaderBlock { Ref ref; - Uniform uniforms[32]; - int uniformCount; + vec_uniform_t uniforms; uint32_t buffer; }; @@ -76,16 +75,19 @@ typedef struct { int index; int binding; ShaderBlock* source; + vec_uniform_t uniforms; } UniformBlock; -typedef map_t(UniformBlock) map_block_t; +typedef vec_t(UniformBlock) vec_block_t; struct Shader { Ref ref; uint32_t program; - map_uniform_t uniforms; - map_block_t blocks; + vec_uniform_t uniforms; + vec_block_t blocks; map_int_t attributes; + map_int_t uniformMap; + map_int_t blockMap; }; struct Texture { @@ -1239,12 +1241,28 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) { glVertexAttribI4iv(LOVR_SHADER_BONES, (int[4]) { 0., 0., 0., 0. }); glVertexAttrib4fv(LOVR_SHADER_BONE_WEIGHTS, (float[4]) { 1., 0., 0., 0. }); + // Uniform blocks + int32_t blockCount; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &blockCount); + map_init(&shader->blockMap); + vec_init(&shader->blocks); + vec_reserve(&shader->blocks, blockCount); + for (int i = 0; i < blockCount; i++) { + UniformBlock block = { .index = i, .binding = i + 1, .source = NULL }; + glUniformBlockBinding(program, block.index, block.binding); + vec_init(&block.uniforms); + + char name[LOVR_MAX_UNIFORM_LENGTH]; + glGetActiveUniformBlockName(program, i, LOVR_MAX_UNIFORM_LENGTH, NULL, name); + map_set(&shader->blockMap, name, i); + } + // Uniform introspection int32_t uniformCount; int textureSlot = 0; map_init(&shader->uniforms); glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniformCount); - for (int i = 0; i < uniformCount; i++) { + for (uint32_t i = 0; i < (uint32_t) uniformCount; i++) { Uniform uniform; GLenum glType; glGetActiveUniform(program, i, LOVR_MAX_UNIFORM_LENGTH, NULL, &uniform.count, &glType, uniform.name); @@ -1259,7 +1277,16 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) { uniform.components = getUniformComponents(glType); uniform.baseTextureSlot = (uniform.type == UNIFORM_SAMPLER) ? textureSlot : -1; - if (uniform.location == -1) { + int blockIndex; + glGetActiveUniformsiv(program, 1, &i, GL_UNIFORM_BLOCK_INDEX, &blockIndex); + + if (blockIndex != -1) { + UniformBlock* block = &shader->blocks.data[i]; + glGetActiveUniformsiv(program, 1, &i, GL_UNIFORM_OFFSET, &uniform.offset); + glGetActiveUniformsiv(program, 1, &i, GL_UNIFORM_SIZE, &uniform.size); + vec_push(&block->uniforms, uniform); + continue; + } else if (uniform.location == -1) { continue; } @@ -1322,22 +1349,11 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) { } } - map_set(&shader->uniforms, uniform.name, uniform); + map_set(&shader->uniformMap, uniform.name, shader->uniforms.length); + vec_push(&shader->uniforms, uniform); textureSlot += (uniform.type == UNIFORM_SAMPLER) ? uniform.count : 0; } - // Uniform blocks - int32_t blockCount; - glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &blockCount); - map_init(&shader->blocks); - for (int i = 0; i < blockCount; i++) { - char name[LOVR_MAX_UNIFORM_LENGTH]; - glGetActiveUniformBlockName(program, i, LOVR_MAX_UNIFORM_LENGTH, NULL, name); - UniformBlock block = { .index = i, .binding = i + 1, .source = NULL }; - glUniformBlockBinding(program, block.index, block.binding); - map_set(&shader->blocks, name, block); - } - // Attribute cache int32_t attributeCount; glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attributeCount); @@ -1367,23 +1383,21 @@ Shader* lovrShaderCreateDefault(DefaultShader type) { void lovrShaderDestroy(void* ref) { Shader* shader = ref; glDeleteProgram(shader->program); - const char* key; - map_iter_t iter = map_iter(&shader->uniforms); - while ((key = map_next(&shader->uniforms, &iter)) != NULL) { - Uniform* uniform = map_get(&shader->uniforms, key); - free(uniform->value.data); + for (int i = 0; i < shader->uniforms.length; i++) { + free(shader->uniforms.data[i].value.data); } - map_deinit(&shader->uniforms); + vec_deinit(&shader->uniforms); + vec_deinit(&shader->blocks); map_deinit(&shader->attributes); + map_deinit(&shader->uniformMap); + map_deinit(&shader->blockMap); free(shader); } void lovrShaderBind(Shader* shader) { - map_iter_t iter = map_iter(&shader->uniforms); - const char* key; - while ((key = map_next(&shader->uniforms, &iter)) != NULL) { - Uniform* uniform = map_get(&shader->uniforms, key); - + int i; + Uniform* uniform; + vec_foreach_ptr(&shader->uniforms, uniform, i) { if (uniform->type != UNIFORM_SAMPLER && !uniform->dirty) { continue; } @@ -1427,9 +1441,8 @@ void lovrShaderBind(Shader* shader) { } } - iter = map_iter(&shader->blocks); - while ((key = map_next(&shader->blocks, &iter)) != NULL) { - UniformBlock* block = map_get(&shader->blocks, key); + UniformBlock* block; + vec_foreach_ptr(&shader->blocks, block, i) { lovrGpuBindUniformBuffer(block->source ? block->source->buffer : 0, block->binding); } } @@ -1440,15 +1453,17 @@ int lovrShaderGetAttributeId(Shader* shader, const char* name) { } bool lovrShaderHasUniform(Shader* shader, const char* name) { - return map_get(&shader->uniforms, name) != NULL; + return map_get(&shader->uniformMap, name) != NULL; } -bool lovrShaderGetUniform(Shader* shader, const char* name, int* count, int* components, size_t* size, UniformType* type) { - Uniform* uniform = map_get(&shader->uniforms, name); - if (!uniform) { +bool lovrShaderGetUniform(Shader* shader, const char* name, int* count, int* components, int* size, UniformType* type) { + int* index = map_get(&shader->uniformMap, name); + if (!index) { return false; } + Uniform* uniform = &shader->uniforms.data[*index]; + *count = uniform->count; *components = uniform->components; *size = uniform->size; @@ -1456,15 +1471,16 @@ bool lovrShaderGetUniform(Shader* shader, const char* name, int* count, int* com return true; } -static void lovrShaderSetUniform(Shader* shader, const char* name, UniformType type, void* data, int count, size_t size, const char* debug) { - Uniform* uniform = map_get(&shader->uniforms, name); - if (!uniform) { +static void lovrShaderSetUniform(Shader* shader, const char* name, UniformType type, void* data, int count, int size, const char* debug) { + int* index = map_get(&shader->uniformMap, name); + if (!index) { return; } + Uniform* uniform = &shader->uniforms.data[*index]; const char* plural = (uniform->size / size) > 1 ? "s" : ""; - lovrAssert(uniform->type == type, "Unable to send %ss to uniform %s", debug, uniform->name); - lovrAssert(count * size <= uniform->size, "Expected at most %d %s%s for uniform %s, got %d", uniform->size / size, debug, plural, uniform->name, count); + lovrAssert(uniform->type == type, "Unable to send %ss to uniform %s", debug, name); + lovrAssert(count * size <= uniform->size, "Expected at most %d %s%s for uniform %s, got %d", uniform->size / size, debug, plural, name, count); if (!uniform->dirty && !memcmp(uniform->value.data, data, count * size)) { return; @@ -1492,37 +1508,36 @@ void lovrShaderSetTexture(Shader* shader, const char* name, Texture** data, int // ShaderBlock -ShaderBlock* lovrShaderBlockCreate(Uniform uniforms[MAX_SHADER_BLOCK_UNIFORMS], int uniformCount) { +ShaderBlock* lovrShaderBlockCreate(vec_uniform_t* uniforms) { ShaderBlock* block = lovrAlloc(sizeof(ShaderBlock), lovrShaderBlockDestroy); if (!block) return NULL; - memcpy(block->uniforms, uniforms, MAX_SHADER_BLOCK_UNIFORMS * sizeof(Uniform)); - block->uniformCount = uniformCount; + vec_init(&block->uniforms); + vec_extend(&block->uniforms, uniforms); - size_t offset = 0; - for (int i = 0; i < uniformCount; i++) { - uniforms[i].offset = offset; - if (uniforms[i].type != UNIFORM_MATRIX) { - if (uniforms[i].count == 1) { - offset += 4; - } else { - offset += uniforms[i].count * 16; - } + int i; + Uniform* uniform; + size_t size = 0; + vec_foreach_ptr(&block->uniforms, uniform, i) { + uniform->offset = size; + if (uniform->type == UNIFORM_MATRIX) { + size += uniform->components * uniform->components * 4; } else { - offset += uniforms[i].components * uniforms[i].components * 4; + size += uniform->count == 1 ? 4 : (uniform->count * 16); } } - size_t totalSize = offset; glGenBuffers(1, &block->buffer); lovrGpuBindUniformBuffer(block->buffer, 0); - glBufferData(GL_UNIFORM_BUFFER, totalSize, NULL, GL_STATIC_DRAW); + glBufferData(GL_UNIFORM_BUFFER, size, NULL, GL_STATIC_DRAW); return block; } void lovrShaderBlockDestroy(void* ref) { - free(ref); + UniformBlock* block = ref; + vec_deinit(&block->uniforms); + free(block); } // Mesh diff --git a/src/graphics/shader.h b/src/graphics/shader.h index 173cd139..e92fa063 100644 --- a/src/graphics/shader.h +++ b/src/graphics/shader.h @@ -30,8 +30,8 @@ typedef struct { int components; int count; int location; - size_t offset; - size_t size; + int offset; + int size; union { void* data; int* ints; @@ -42,7 +42,7 @@ typedef struct { bool dirty; } Uniform; -typedef map_t(Uniform) map_uniform_t; +typedef vec_t(Uniform) vec_uniform_t; typedef struct Shader Shader; @@ -52,7 +52,7 @@ void lovrShaderDestroy(void* ref); void lovrShaderBind(Shader* shader); int lovrShaderGetAttributeId(Shader* shader, const char* name); bool lovrShaderHasUniform(Shader* shader, const char* name); -bool lovrShaderGetUniform(Shader* shader, const char* name, int* count, int* components, size_t* size, UniformType* type); +bool lovrShaderGetUniform(Shader* shader, const char* name, int* count, int* components, int* size, UniformType* type); void lovrShaderSetFloat(Shader* shader, const char* name, float* data, int count); void lovrShaderSetInt(Shader* shader, const char* name, int* data, int count); void lovrShaderSetMatrix(Shader* shader, const char* name, float* data, int count); diff --git a/src/graphics/shaderBlock.h b/src/graphics/shaderBlock.h index d40e4ce4..d81017e2 100644 --- a/src/graphics/shaderBlock.h +++ b/src/graphics/shaderBlock.h @@ -6,5 +6,5 @@ typedef struct ShaderBlock ShaderBlock; -ShaderBlock* lovrShaderBlockCreate(Uniform uniforms[MAX_SHADER_BLOCK_UNIFORMS], int uniformCount); +ShaderBlock* lovrShaderBlockCreate(vec_uniform_t* uniforms); void lovrShaderBlockDestroy(void* ref);