diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2021-09-25 16:01:54 -0700 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2021-09-26 18:05:06 -0700 |
commit | a59229b6d83057650b320e44ad1f2e74f6fceac7 (patch) | |
tree | 2e204f70a800fbf0837eae70be93cc03f317747f | |
parent | 6f1584f3d16ed04934da9bb1a7591ae3d4127b9a (diff) |
shader: introduce shader_active_uniforms()
The existing shader api only supports caller-provided uniforms
and attributes at instantiation time, with no ability to
introspect what uniforms are actually actively present in a given
shader.
This commit adds introspection of the active uniforms for a given
shader at creation time, as well as when reloaded, keeping the
information around to be accessed via shader_active_uniforms().
The immediate impetus for this is supporting runtime discovery of
uniforms present in the shader source, with the intention of
exposing these as sequencer tracks for external manipulation.
-rw-r--r-- | src/pig.c | 10 | ||||
-rw-r--r-- | src/shader.c | 75 | ||||
-rw-r--r-- | src/shader.h | 7 |
3 files changed, 80 insertions, 12 deletions
@@ -72,10 +72,12 @@ static void randomize_color(v3f_t *color) static void pig_uniforms_func(shader_t *shader, void *uniforms_ctxt, void *render_ctxt, unsigned n_uniforms, const int *uniforms, const m4f_t *model_x, float alpha) { - play_t *play = render_ctxt; - pig_t *pig = uniforms_ctxt; - unsigned t0, t1; - float r = randf(); + play_t *play = render_ctxt; + pig_t *pig = uniforms_ctxt; + unsigned t0, t1; + float r = randf(); + const shader_uniform_t *active_uniforms; + int n_active_uniforms; if (play_ticks_elapsed(play, PLAY_TICKS_TIMER2, 1000)) { if (shader_reload_files(shader) < 0) diff --git a/src/shader.c b/src/shader.c index 1cadc7f..83df512 100644 --- a/src/shader.c +++ b/src/shader.c @@ -22,16 +22,20 @@ #include "glad.h" #include "macros.h" +#include "shader.h" + typedef struct shader_t { - unsigned program, refcnt; - unsigned n_uniforms, n_attributes; - const char **uniforms, **attributes; - int *uniform_locations, *attribute_locations; - const char *vs_path, *fs_path; - struct timespec vs_mtime, fs_mtime; - - int locations[]; + unsigned program, refcnt; + unsigned n_uniforms, n_attributes; + const char **uniforms, **attributes; + int *uniform_locations, *attribute_locations; + const char *vs_path, *fs_path; + struct timespec vs_mtime, fs_mtime; + shader_uniform_t *active_uniforms; + int n_active_uniforms; + + int locations[]; } shader_t; @@ -81,6 +85,58 @@ unsigned int shader_pair_new_bare(const char *vs_src, const char *fs_src) return shader; } + +/* query a shader for its active uniforms, returns results in res_uniforms + * the returned results are owned by the shader, do not free them, they will be + * cleaned up with shader_free() or reallocated by shader_reload_files() + */ +void shader_active_uniforms(shader_t *shader, int *res_n_uniforms, const shader_uniform_t **res_uniforms) +{ + assert(shader); + assert(res_n_uniforms); + assert(res_uniforms); + + *res_n_uniforms = shader->n_active_uniforms; + *res_uniforms = shader->active_uniforms; +} + + +static void refresh_active_uniforms(shader_t *shader) +{ + int n, maxlen; + + assert(shader); + + if (shader->active_uniforms) { + for (int i = 0; i < shader->n_active_uniforms; i++) + free(shader->active_uniforms[i].name); + free(shader->active_uniforms); + shader->active_uniforms = NULL; + shader->n_active_uniforms = 0; + } + + glGetProgramiv(shader->program, GL_ACTIVE_UNIFORMS, &n); + glGetProgramiv(shader->program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &maxlen); + + /* FIXME: this is currently written such that allocation failures just cut the + * active uniforms short instead of throwing an error, but should probably + * be rewritten to fail and report the ENOMEM errors. + */ + shader->active_uniforms = calloc(n, sizeof(shader_uniform_t)); + if (shader->active_uniforms) { + for (int i = 0; i < n; i++) { + shader->active_uniforms[i].name = calloc(maxlen, sizeof(char)); + if (!shader->active_uniforms[i].name) + break; + + glGetActiveUniform(shader->program, i, maxlen, /* length */ NULL, /* size */ NULL, &shader->active_uniforms[i].type, shader->active_uniforms[i].name); + shader->active_uniforms[i].location = glGetUniformLocation(shader->program, shader->active_uniforms[i].name); + shader->n_active_uniforms++; + } + } +} + + static void get_locations(shader_t *shader) { for (unsigned i = 0; i < shader->n_uniforms; i++) @@ -90,6 +146,7 @@ static void get_locations(shader_t *shader) shader->attribute_locations[i] = glGetAttribLocation(shader->program, shader->attributes[i]); } + shader_t * shader_pair_new(const char *vs_src, const char *fs_src, unsigned n_uniforms, const char **uniforms, unsigned n_attributes, const char **attributes) { shader_t *shader; @@ -112,6 +169,7 @@ shader_t * shader_pair_new(const char *vs_src, const char *fs_src, unsigned n_un shader->attribute_locations = &shader->locations[n_uniforms]; get_locations(shader); + refresh_active_uniforms(shader); return shader; } @@ -178,6 +236,7 @@ int shader_reload_files(shader_t *shader) free(fs_src); get_locations(shader); + refresh_active_uniforms(shader); return ret; } diff --git a/src/shader.h b/src/shader.h index b52189a..a7df2ec 100644 --- a/src/shader.h +++ b/src/shader.h @@ -19,6 +19,12 @@ typedef struct shader_t shader_t; +typedef struct shader_uniform_t { + char *name; + GLenum type; + int location; +} shader_uniform_t; + unsigned int shader_pair_new_bare(const char *vs_src, const char *fs_src); shader_t * shader_pair_new(const char *vs_src, const char *fs_src, unsigned n_uniforms, const char **uniforms, unsigned n_attributes, const char **attributes); shader_t * shader_pair_new_files(const char *vs_path, const char *fs_path, unsigned n_uniforms, const char **uniforms, unsigned n_attributes, const char **attributes); @@ -26,5 +32,6 @@ void shader_ref(shader_t *shader); shader_t * shader_free(shader_t *shader); void shader_use(shader_t *shader, unsigned *res_n_uniforms, int **res_uniform_locations, unsigned *res_n_attributes, int **res_attribute_locations); int shader_reload_files(shader_t *shader); +void shader_active_uniforms(shader_t *shader, int *res_n_uniforms, const shader_uniform_t **res_uniforms); #endif |