From a5d0deec0f567cb103b40e881ae91430ae511cf5 Mon Sep 17 00:00:00 2001 From: Andrei Alexeyev Date: Thu, 4 Feb 2021 01:50:10 +0200 Subject: [PATCH] renderer,gl33: expose new magic uniforms; see render_context.glslh Also optimize access to all magic uniforms slightly. --- .../shader/lib/render_context.glslh | 15 +++ src/renderer/api.h | 2 +- src/renderer/gl33/gl33.c | 91 +++++++++++++++++-- src/renderer/gl33/shader_program.c | 41 ++++++--- src/renderer/gl33/shader_program.h | 15 +++ 5 files changed, 144 insertions(+), 20 deletions(-) diff --git a/resources/00-taisei.pkgdir/shader/lib/render_context.glslh b/resources/00-taisei.pkgdir/shader/lib/render_context.glslh index f6751875..a130212e 100644 --- a/resources/00-taisei.pkgdir/shader/lib/render_context.glslh +++ b/resources/00-taisei.pkgdir/shader/lib/render_context.glslh @@ -9,4 +9,19 @@ UNIFORM(513) mat4 r_projectionMatrix; UNIFORM(514) mat4 r_textureMatrix; UNIFORM(515) vec4 r_color; +// Active viewport, i.e. the region we're rendering into. +// xy = offset, zw = width and height. +// Units are real pixels. +UNIFORM(516) vec4 r_viewport; + +// Size(s) of output buffer(s) we're rendering into, in real pixels. +// A size of 0,0 means the buffer is not attached. +// +// Note that r_colorOutputSizes is not a direct mapping to framebuffer attachments; +// it is affected by the output -> attachment mapping (see r_framebuffer_set_output_attachments). +// This means that r_colorOutputSizes[N] always corresponds to fragment shader output #N, which +// is probably what you'd expect. +UNIFORM(517) vec2 r_colorOutputSizes[4]; // NOTE: should match FRAMEBUFFER_MAX_OUTPUTS in renderer/api.h +UNIFORM(521) vec2 r_depthOutputSize; + #endif diff --git a/src/renderer/api.h b/src/renderer/api.h index 4142eae9..d93264df 100644 --- a/src/renderer/api.h +++ b/src/renderer/api.h @@ -547,7 +547,7 @@ void _r_uniform_ptr_float_array(Uniform *uniform, uint offset, uint count, float void _r_uniform_float_array(const char *uniform, uint offset, uint count, float elements[count]) attr_nonnull(1, 4); #define r_uniform_float_array(uniform, ...) _R_UNIFORM_GENERIC(float_array, uniform, __VA_ARGS__) -void _r_uniform_ptr_vec2(Uniform *uniform, float x, float y) attr_nonnull(1); +void _r_uniform_ptr_vec2(Uniform *uniform, float x, float y); void _r_uniform_vec2(const char *uniform, float x, float y) attr_nonnull(1); #define r_uniform_vec2(uniform, ...) _R_UNIFORM_GENERIC(vec2, uniform, __VA_ARGS__) diff --git a/src/renderer/gl33/gl33.c b/src/renderer/gl33/gl33.c index 064ce0a3..324fae41 100644 --- a/src/renderer/gl33/gl33.c +++ b/src/renderer/gl33/gl33.c @@ -383,17 +383,93 @@ static void gl33_sync_viewport(void) { } } +static IntExtent gl33_get_default_framebuffer_size(void) { + IntExtent s; + // TODO: cache this at window creation time and refresh on resize events? + SDL_GL_GetDrawableSize(R.window, &s.w, &s.h); + return s; +} + +static void gl33_get_output_size(Framebuffer *fb, FramebufferAttachment a, vec2_noalign out) { + if(a == FRAMEBUFFER_ATTACH_NONE) { + out[0] = 0; + out[1] = 0; + return; + } + + FramebufferAttachmentQueryResult q = gl33_framebuffer_query_attachment(fb, a); + + if(q.texture == NULL) { + out[0] = 0; + out[1] = 0; + return; + } + + uint w, h; + gl33_texture_get_size(q.texture, q.miplevel, &w, &h); + out[0] = w; + out[1] = h; +} + +static void gl33_sync_magic_uniforms(void) { + ShaderProgram *shader = NOT_NULL(R.progs.active); + Framebuffer *fb = R.framebuffer.active; + Uniform **u = shader->magic_uniforms; + + r_uniform_mat4(u[UMAGIC_MATRIX_MV], *_r_matrices.modelview.head); + r_uniform_mat4(u[UMAGIC_MATRIX_PROJ], *_r_matrices.projection.head); + r_uniform_mat4(u[UMAGIC_MATRIX_TEX], *_r_matrices.texture.head); + r_uniform_vec4_rgba(u[UMAGIC_COLOR], &R.color); + r_uniform_vec4_vec(u[UMAGIC_VIEWPORT], &R.viewport.active.x); + + int num_color_out; + + if(u[UMAGIC_COLOR_OUT_SIZES]) { + num_color_out = iclamp(u[UMAGIC_COLOR_OUT_SIZES]->array_size, 0, FRAMEBUFFER_MAX_OUTPUTS); + } else { + num_color_out = 0; + } + + if(fb) { + if(num_color_out > 0) { + vec2_noalign out[num_color_out]; + + for(int i = 0; i < num_color_out; ++i) { + gl33_get_output_size(fb, fb->output_mapping[i], out[i]); + } + + r_uniform_vec2_array(u[UMAGIC_COLOR_OUT_SIZES], 0, num_color_out, out); + } + + if(u[UMAGIC_DEPTH_OUT_SIZE]) { + vec2_noalign out; + gl33_get_output_size(fb, FRAMEBUFFER_ATTACH_DEPTH, out); + r_uniform_vec2_vec(u[UMAGIC_DEPTH_OUT_SIZE], out); + } + } else { // default framebuffer + // TODO: Maybe figure out whether we have the depth buffer? + // We don't request one for the default framebuffer, so pretend it's not there. + r_uniform_vec2(u[UMAGIC_DEPTH_OUT_SIZE], 0, 0); + + if(num_color_out > 0) { + IntExtent fb_size = gl33_get_default_framebuffer_size(); + vec2 out[num_color_out]; + out[0][0] = fb_size.w; + out[0][1] = fb_size.h; + memset(out + 1, 0, sizeof(out) - sizeof(out[0])); + r_uniform_vec2_array(u[UMAGIC_COLOR_OUT_SIZES], 0, num_color_out, out); + } + } +} + static void gl33_sync_state(void) { gl33_sync_capabilities(); + gl33_sync_framebuffer(); gl33_sync_shader(); - r_uniform_mat4("r_modelViewMatrix", *_r_matrices.modelview.head); - r_uniform_mat4("r_projectionMatrix", *_r_matrices.projection.head); - r_uniform_mat4("r_textureMatrix", *_r_matrices.texture.head); - r_uniform_vec4_rgba("r_color", &R.color); + gl33_sync_viewport(); + gl33_sync_magic_uniforms(); gl33_sync_uniforms(R.progs.active); gl33_sync_texunits(true); - gl33_sync_framebuffer(); - gl33_sync_viewport(); gl33_sync_vao(); gl33_sync_blend_mode(); @@ -1057,8 +1133,7 @@ static IntExtent gl33_framebuffer_get_size(Framebuffer *fb) { IntExtent fb_size; if(fb == NULL) { - // TODO: cache this at window creation time and refresh on resize events? - SDL_GL_GetDrawableSize(R.window, &fb_size.w, &fb_size.h); + fb_size = gl33_get_default_framebuffer_size(); } else { fb_size = gl33_framebuffer_get_effective_size(fb); } diff --git a/src/renderer/gl33/shader_program.c b/src/renderer/gl33/shader_program.c index bebf0f9d..e92ea0ce 100644 --- a/src/renderer/gl33/shader_program.c +++ b/src/renderer/gl33/shader_program.c @@ -151,18 +151,22 @@ static struct { [UNIFORM_MAT4] = { uset_mat4, uget_mat4 }, }; -typedef struct MagicalUniform { +typedef struct MagicUniformSpec { const char *name; const char *typename; UniformType type; -} MagicalUniform; +} MagicUniformSpec; -static MagicalUniform magical_unfiroms[] = { - { "r_modelViewMatrix", "mat4", UNIFORM_MAT4 }, - { "r_projectionMatrix", "mat4", UNIFORM_MAT4 }, - { "r_textureMatrix", "mat4", UNIFORM_MAT4 }, - { "r_color", "vec4", UNIFORM_VEC4 }, +static MagicUniformSpec magic_unfiroms[] = { + [UMAGIC_MATRIX_MV] = { "r_modelViewMatrix", "mat4", UNIFORM_MAT4 }, + [UMAGIC_MATRIX_PROJ] = { "r_projectionMatrix", "mat4", UNIFORM_MAT4 }, + [UMAGIC_MATRIX_TEX] = { "r_textureMatrix", "mat4", UNIFORM_MAT4 }, + [UMAGIC_COLOR] = { "r_color", "vec4", UNIFORM_VEC4 }, + [UMAGIC_VIEWPORT] = { "r_viewport", "vec4", UNIFORM_VEC4 }, + [UMAGIC_COLOR_OUT_SIZES] = { "r_colorOutputSizes[0]", "vec2", UNIFORM_VEC2 }, + [UMAGIC_DEPTH_OUT_SIZE] = { "r_depthOutputSize", "vec2", UNIFORM_VEC2 }, }; +static_assert_nomsg(ARRAY_SIZE(magic_unfiroms) == NUM_MAGIC_UNIFORMS); static void gl33_update_uniform(Uniform *uniform, uint offset, uint count, const void *data) { // these are validated properly in gl33_uniform @@ -325,13 +329,22 @@ static bool cache_uniforms(ShaderProgram *prog) { continue; } - for(int j = 0; j < sizeof(magical_unfiroms)/sizeof(MagicalUniform); ++j) { - MagicalUniform *m = magical_unfiroms + j; + MagicUniformIndex magic_index = UMAGIC_INVALID; - if(!strcmp(name, m->name) && uni.type != m->type) { - log_error("Magical uniform '%s' must be of type '%s'", name, m->typename); + for(int j = 0; j < ARRAY_SIZE(magic_unfiroms); ++j) { + MagicUniformSpec *m = magic_unfiroms + j; + + if(strcmp(name, m->name)) { + continue; + } + + if(uni.type != m->type) { + log_error("Magic uniform '%s' must be of type '%s'", name, m->typename); return false; } + + magic_index = j; + break; } const UniformTypeInfo *typeinfo = r_uniform_type_info(uni.type); @@ -385,6 +398,12 @@ static bool cache_uniforms(ShaderProgram *prog) { } } + if(magic_index != UMAGIC_INVALID) { + assume((uint)magic_index < ARRAY_SIZE(prog->magic_uniforms)); + assert(prog->magic_uniforms[magic_index] == NULL); + prog->magic_uniforms[magic_index] = new_uni; + } + ht_set(&prog->uniforms, name, new_uni); log_debug("%s = %i [array elements: %i; size: %zi bytes]", name, loc, uni.array_size, uni.array_size * uni.elem_size); } diff --git a/src/renderer/gl33/shader_program.h b/src/renderer/gl33/shader_program.h index 5b122862..615994d5 100644 --- a/src/renderer/gl33/shader_program.h +++ b/src/renderer/gl33/shader_program.h @@ -17,9 +17,24 @@ #include "opengl.h" #include "resource/shader_program.h" +typedef enum MagicUniformIndex { + UMAGIC_INVALID = -1, + + UMAGIC_MATRIX_MV, + UMAGIC_MATRIX_PROJ, + UMAGIC_MATRIX_TEX, + UMAGIC_COLOR, + UMAGIC_VIEWPORT, + UMAGIC_COLOR_OUT_SIZES, + UMAGIC_DEPTH_OUT_SIZE, + + NUM_MAGIC_UNIFORMS, +} MagicUniformIndex; + struct ShaderProgram { GLuint gl_handle; ht_str2ptr_t uniforms; + Uniform *magic_uniforms[NUM_MAGIC_UNIFORMS]; char debug_label[R_DEBUG_LABEL_SIZE]; };