summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2021-09-25 16:01:54 -0700
committerVito Caputo <vcaputo@pengaru.com>2021-09-26 18:05:06 -0700
commita59229b6d83057650b320e44ad1f2e74f6fceac7 (patch)
tree2e204f70a800fbf0837eae70be93cc03f317747f /src
parent6f1584f3d16ed04934da9bb1a7591ae3d4127b9a (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.
Diffstat (limited to 'src')
-rw-r--r--src/pig.c10
-rw-r--r--src/shader.c75
-rw-r--r--src/shader.h7
3 files changed, 80 insertions, 12 deletions
diff --git a/src/pig.c b/src/pig.c
index 6c11c67..6161b8d 100644
--- a/src/pig.c
+++ b/src/pig.c
@@ -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
© All Rights Reserved