Reorganize uniform/block data structures;

This commit is contained in:
bjorn 2018-07-28 15:40:13 -07:00
parent e8afcb9b71
commit a372abb810
5 changed files with 98 additions and 79 deletions

View File

@ -854,7 +854,8 @@ int l_lovrGraphicsNewAnimator(lua_State* L) {
} }
int l_lovrGraphicsNewShaderBlock(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; int count = 0;
luaL_checktype(L, 1, LUA_TTABLE); luaL_checktype(L, 1, LUA_TTABLE);
@ -872,44 +873,47 @@ int l_lovrGraphicsNewShaderBlock(lua_State* L) {
luaL_checktype(L, -1, LUA_TTABLE); luaL_checktype(L, -1, LUA_TTABLE);
// Name // Name
Uniform* uniform = &uniforms[count++]; Uniform uniform;
strncpy(uniform->name, lua_tostring(L, -2), LOVR_MAX_UNIFORM_LENGTH - 1); strncpy(uniform.name, lua_tostring(L, -2), LOVR_MAX_UNIFORM_LENGTH - 1);
// Count // Count
lua_getfield(L, -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); lua_pop(L, 1);
// Type // Type
size_t length; size_t length;
lua_getfield(L, -1, "type"); lua_getfield(L, -1, "type");
const char* type = lua_tolstring(L, -1, &length); const char* type = lua_tolstring(L, -1, &length);
uniform->components = 1; uniform.components = 1;
if (strcmp(type, "float")) { if (strcmp(type, "float")) {
uniform->type = UNIFORM_FLOAT; uniform.type = UNIFORM_FLOAT;
} else if (strcmp(type, "int")) { } else if (strcmp(type, "int")) {
uniform->type = UNIFORM_INT; uniform.type = UNIFORM_INT;
} else { } else {
uniform->components = type[length - 1] - '0'; uniform.components = type[length - 1] - '0';
lovrAssert(uniform->components >= 2 && uniform->components <= 4, "Unknown uniform type '%s'", type); lovrAssert(uniform.components >= 2 && uniform.components <= 4, "Unknown uniform type '%s'", type);
if (!strncmp(type, "vec", 3 * sizeof(char)) && length == 4) { 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) { } 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) { } else if (!strncmp(type, "mat", 3 * sizeof(char)) && length == 4) {
uniform->type = UNIFORM_MATRIX; uniform.type = UNIFORM_MATRIX;
} else { } else {
lovrThrow("Unknown uniform type '%s'", type); lovrThrow("Unknown uniform type '%s'", type);
} }
} }
lua_pop(L, 1); lua_pop(L, 1);
vec_push(&uniforms, uniform);
// Pop the table, leaving the key for lua_next // Pop the table, leaving the key for lua_next
lua_pop(L, 1); lua_pop(L, 1);
} }
ShaderBlock* block = lovrShaderBlockCreate(uniforms, count); ShaderBlock* block = lovrShaderBlockCreate(&uniforms);
luax_pushtype(L, ShaderBlock, block); luax_pushtype(L, ShaderBlock, block);
vec_deinit(&uniforms);
return 1; return 1;
} }

View File

@ -4,7 +4,7 @@
struct TempData { struct TempData {
void* data; void* data;
size_t size; int size;
}; };
static struct TempData tempData; static struct TempData tempData;
@ -23,7 +23,7 @@ int l_lovrShaderSend(lua_State* L) {
int count; int count;
int components; int components;
size_t size; int size;
UniformType type; UniformType type;
bool present = lovrShaderGetUniform(shader, name, &count, &components, &size, &type); bool present = lovrShaderGetUniform(shader, name, &count, &components, &size, &type);

View File

@ -67,8 +67,7 @@ static struct {
struct ShaderBlock { struct ShaderBlock {
Ref ref; Ref ref;
Uniform uniforms[32]; vec_uniform_t uniforms;
int uniformCount;
uint32_t buffer; uint32_t buffer;
}; };
@ -76,16 +75,19 @@ typedef struct {
int index; int index;
int binding; int binding;
ShaderBlock* source; ShaderBlock* source;
vec_uniform_t uniforms;
} UniformBlock; } UniformBlock;
typedef map_t(UniformBlock) map_block_t; typedef vec_t(UniformBlock) vec_block_t;
struct Shader { struct Shader {
Ref ref; Ref ref;
uint32_t program; uint32_t program;
map_uniform_t uniforms; vec_uniform_t uniforms;
map_block_t blocks; vec_block_t blocks;
map_int_t attributes; map_int_t attributes;
map_int_t uniformMap;
map_int_t blockMap;
}; };
struct Texture { struct Texture {
@ -1239,12 +1241,28 @@ Shader* lovrShaderCreate(const char* vertexSource, const char* fragmentSource) {
glVertexAttribI4iv(LOVR_SHADER_BONES, (int[4]) { 0., 0., 0., 0. }); glVertexAttribI4iv(LOVR_SHADER_BONES, (int[4]) { 0., 0., 0., 0. });
glVertexAttrib4fv(LOVR_SHADER_BONE_WEIGHTS, (float[4]) { 1., 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 // Uniform introspection
int32_t uniformCount; int32_t uniformCount;
int textureSlot = 0; int textureSlot = 0;
map_init(&shader->uniforms); map_init(&shader->uniforms);
glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniformCount); 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; Uniform uniform;
GLenum glType; GLenum glType;
glGetActiveUniform(program, i, LOVR_MAX_UNIFORM_LENGTH, NULL, &uniform.count, &glType, uniform.name); 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.components = getUniformComponents(glType);
uniform.baseTextureSlot = (uniform.type == UNIFORM_SAMPLER) ? textureSlot : -1; 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; 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; 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 // Attribute cache
int32_t attributeCount; int32_t attributeCount;
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attributeCount); glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attributeCount);
@ -1367,23 +1383,21 @@ Shader* lovrShaderCreateDefault(DefaultShader type) {
void lovrShaderDestroy(void* ref) { void lovrShaderDestroy(void* ref) {
Shader* shader = ref; Shader* shader = ref;
glDeleteProgram(shader->program); glDeleteProgram(shader->program);
const char* key; for (int i = 0; i < shader->uniforms.length; i++) {
map_iter_t iter = map_iter(&shader->uniforms); free(shader->uniforms.data[i].value.data);
while ((key = map_next(&shader->uniforms, &iter)) != NULL) {
Uniform* uniform = map_get(&shader->uniforms, key);
free(uniform->value.data);
} }
map_deinit(&shader->uniforms); vec_deinit(&shader->uniforms);
vec_deinit(&shader->blocks);
map_deinit(&shader->attributes); map_deinit(&shader->attributes);
map_deinit(&shader->uniformMap);
map_deinit(&shader->blockMap);
free(shader); free(shader);
} }
void lovrShaderBind(Shader* shader) { void lovrShaderBind(Shader* shader) {
map_iter_t iter = map_iter(&shader->uniforms); int i;
const char* key; Uniform* uniform;
while ((key = map_next(&shader->uniforms, &iter)) != NULL) { vec_foreach_ptr(&shader->uniforms, uniform, i) {
Uniform* uniform = map_get(&shader->uniforms, key);
if (uniform->type != UNIFORM_SAMPLER && !uniform->dirty) { if (uniform->type != UNIFORM_SAMPLER && !uniform->dirty) {
continue; continue;
} }
@ -1427,9 +1441,8 @@ void lovrShaderBind(Shader* shader) {
} }
} }
iter = map_iter(&shader->blocks); UniformBlock* block;
while ((key = map_next(&shader->blocks, &iter)) != NULL) { vec_foreach_ptr(&shader->blocks, block, i) {
UniformBlock* block = map_get(&shader->blocks, key);
lovrGpuBindUniformBuffer(block->source ? block->source->buffer : 0, block->binding); 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) { 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) { bool lovrShaderGetUniform(Shader* shader, const char* name, int* count, int* components, int* size, UniformType* type) {
Uniform* uniform = map_get(&shader->uniforms, name); int* index = map_get(&shader->uniformMap, name);
if (!uniform) { if (!index) {
return false; return false;
} }
Uniform* uniform = &shader->uniforms.data[*index];
*count = uniform->count; *count = uniform->count;
*components = uniform->components; *components = uniform->components;
*size = uniform->size; *size = uniform->size;
@ -1456,15 +1471,16 @@ bool lovrShaderGetUniform(Shader* shader, const char* name, int* count, int* com
return true; return true;
} }
static void lovrShaderSetUniform(Shader* shader, const char* name, UniformType type, void* data, int count, size_t size, const char* debug) { static void lovrShaderSetUniform(Shader* shader, const char* name, UniformType type, void* data, int count, int size, const char* debug) {
Uniform* uniform = map_get(&shader->uniforms, name); int* index = map_get(&shader->uniformMap, name);
if (!uniform) { if (!index) {
return; return;
} }
Uniform* uniform = &shader->uniforms.data[*index];
const char* plural = (uniform->size / size) > 1 ? "s" : ""; const char* plural = (uniform->size / size) > 1 ? "s" : "";
lovrAssert(uniform->type == type, "Unable to send %ss to uniform %s", debug, uniform->name); 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, uniform->name, count); 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)) { if (!uniform->dirty && !memcmp(uniform->value.data, data, count * size)) {
return; return;
@ -1492,37 +1508,36 @@ void lovrShaderSetTexture(Shader* shader, const char* name, Texture** data, int
// ShaderBlock // ShaderBlock
ShaderBlock* lovrShaderBlockCreate(Uniform uniforms[MAX_SHADER_BLOCK_UNIFORMS], int uniformCount) { ShaderBlock* lovrShaderBlockCreate(vec_uniform_t* uniforms) {
ShaderBlock* block = lovrAlloc(sizeof(ShaderBlock), lovrShaderBlockDestroy); ShaderBlock* block = lovrAlloc(sizeof(ShaderBlock), lovrShaderBlockDestroy);
if (!block) return NULL; if (!block) return NULL;
memcpy(block->uniforms, uniforms, MAX_SHADER_BLOCK_UNIFORMS * sizeof(Uniform)); vec_init(&block->uniforms);
block->uniformCount = uniformCount; vec_extend(&block->uniforms, uniforms);
size_t offset = 0; int i;
for (int i = 0; i < uniformCount; i++) { Uniform* uniform;
uniforms[i].offset = offset; size_t size = 0;
if (uniforms[i].type != UNIFORM_MATRIX) { vec_foreach_ptr(&block->uniforms, uniform, i) {
if (uniforms[i].count == 1) { uniform->offset = size;
offset += 4; if (uniform->type == UNIFORM_MATRIX) {
} else { size += uniform->components * uniform->components * 4;
offset += uniforms[i].count * 16;
}
} else { } 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); glGenBuffers(1, &block->buffer);
lovrGpuBindUniformBuffer(block->buffer, 0); lovrGpuBindUniformBuffer(block->buffer, 0);
glBufferData(GL_UNIFORM_BUFFER, totalSize, NULL, GL_STATIC_DRAW); glBufferData(GL_UNIFORM_BUFFER, size, NULL, GL_STATIC_DRAW);
return block; return block;
} }
void lovrShaderBlockDestroy(void* ref) { void lovrShaderBlockDestroy(void* ref) {
free(ref); UniformBlock* block = ref;
vec_deinit(&block->uniforms);
free(block);
} }
// Mesh // Mesh

View File

@ -30,8 +30,8 @@ typedef struct {
int components; int components;
int count; int count;
int location; int location;
size_t offset; int offset;
size_t size; int size;
union { union {
void* data; void* data;
int* ints; int* ints;
@ -42,7 +42,7 @@ typedef struct {
bool dirty; bool dirty;
} Uniform; } Uniform;
typedef map_t(Uniform) map_uniform_t; typedef vec_t(Uniform) vec_uniform_t;
typedef struct Shader Shader; typedef struct Shader Shader;
@ -52,7 +52,7 @@ void lovrShaderDestroy(void* ref);
void lovrShaderBind(Shader* shader); void lovrShaderBind(Shader* shader);
int lovrShaderGetAttributeId(Shader* shader, const char* name); int lovrShaderGetAttributeId(Shader* shader, const char* name);
bool lovrShaderHasUniform(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 lovrShaderSetFloat(Shader* shader, const char* name, float* data, int count);
void lovrShaderSetInt(Shader* shader, const char* name, int* 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); void lovrShaderSetMatrix(Shader* shader, const char* name, float* data, int count);

View File

@ -6,5 +6,5 @@
typedef struct ShaderBlock ShaderBlock; typedef struct ShaderBlock ShaderBlock;
ShaderBlock* lovrShaderBlockCreate(Uniform uniforms[MAX_SHADER_BLOCK_UNIFORMS], int uniformCount); ShaderBlock* lovrShaderBlockCreate(vec_uniform_t* uniforms);
void lovrShaderBlockDestroy(void* ref); void lovrShaderBlockDestroy(void* ref);