From e0a2bd43dda7490f495b11acdfa2ac7fec55b4ef Mon Sep 17 00:00:00 2001 From: Mike Erwin Date: Thu, 2 Mar 2017 21:27:51 -0500 Subject: Gawain: add ShaderInterface for GLSL introspection After a GLSL program is linked we can get all its inputs & never have to ask it again. Several uniforms are considered "built-in". Nothing special about these to OpenGL itself, they just follow conventions of our built-in shaders. This will help the matrix API, immediate & batch drawing APIs, and allow extra error/compatibility checking. --- source/blender/gpu/CMakeLists.txt | 2 + source/blender/gpu/gawain/shader_interface.c | 135 +++++++++++++++++++++++++++ source/blender/gpu/gawain/shader_interface.h | 49 ++++++++++ 3 files changed, 186 insertions(+) create mode 100644 source/blender/gpu/gawain/shader_interface.c create mode 100644 source/blender/gpu/gawain/shader_interface.h (limited to 'source') diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 148fb4fcb2f..82c9ce20a49 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -83,6 +83,8 @@ set(SRC gawain/imm_util.h gawain/primitive.h gawain/primitive.c + gawain/shader_interface.c + gawain/shader_interface.h gawain/vertex_buffer.c gawain/vertex_buffer.h gawain/vertex_format.c diff --git a/source/blender/gpu/gawain/shader_interface.c b/source/blender/gpu/gawain/shader_interface.c new file mode 100644 index 00000000000..b2218d07493 --- /dev/null +++ b/source/blender/gpu/gawain/shader_interface.c @@ -0,0 +1,135 @@ + +// Gawain shader interface (C --> GLSL) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2017 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#include "shader_interface.h" +#include + +#define DEBUG_SHADER_INTERFACE 0 + +#if DEBUG_SHADER_INTERFACE + #include +#endif + +static const char* BuiltinUniform_name(BuiltinUniform u) + { + static const char* names[] = + { + [UNIFORM_NONE] = NULL, + + [UNIFORM_MODELVIEW_3D] = "ModelViewMatrix", + [UNIFORM_PROJECTION_3D] = "ProjectionMatrix", + [UNIFORM_MVP_3D] = "ModelViewProjectionMatrix", + [UNIFORM_NORMAL_3D] = "NormalMatrix", + [UNIFORM_INV_NORMAL_3D] = "InverseNormalMatrix", + + [UNIFORM_MODELVIEW_2D] = "ModelViewMatrix", + [UNIFORM_PROJECTION_2D] = "ProjectionMatrix", + [UNIFORM_MVP_2D] = "ModelViewProjectionMatrix", + + [UNIFORM_COLOR] = "color", + + [UNIFORM_CUSTOM] = NULL + }; + + return names[u]; + } + +static bool setup_builtin_uniform(ShaderInput* input, const char* name) + { + // TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types + + // TODO: detect built-in uniforms (gl_type and name must match) + // if a match is found, use BuiltinUniform_name so name buffer space can be reclaimed + input->name = name; + input->builtin_type = UNIFORM_CUSTOM; + return false; + } + +ShaderInterface* ShaderInterface_create(GLint program) + { +#if DEBUG_SHADER_INTERFACE + printf("%s {\n", __func__); // enter function +#endif + + GLint uniform_ct, attrib_ct; + glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &uniform_ct); + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attrib_ct); + const GLint input_ct = uniform_ct + attrib_ct; + + GLint max_uniform_name_len, max_attrib_name_len; + glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_len); + glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_name_len); + const uint32_t name_buffer_len = uniform_ct * max_uniform_name_len + attrib_ct * max_attrib_name_len; + + // allocate enough space for input counts, details for each input, and a buffer for name strings + ShaderInterface* shaderface = calloc(1, offsetof(ShaderInterface, inputs) + input_ct * sizeof(ShaderInput) + name_buffer_len); + + char* name_buffer = (char*)shaderface + offsetof(ShaderInterface, inputs) + input_ct * sizeof(ShaderInput); + uint32_t name_buffer_offset = 0; + + for (uint32_t i = 0; i < uniform_ct; ++i) + { + ShaderInput* input = shaderface->inputs + i; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + char* name = name_buffer + name_buffer_offset; + GLsizei name_len = 0; + + glGetActiveUniform(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name); + + if (setup_builtin_uniform(input, name)) + ; // reclaim space from name buffer (don't advance offset) + else + name_buffer_offset += name_len + 1; // include NULL terminator + + input->location = glGetUniformLocation(program, name); + +#if DEBUG_SHADER_INTERFACE + printf("uniform[%u] '%s' at location %d\n", i, name, input->location); +#endif + } + + for (uint32_t i = 0; i < attrib_ct; ++i) + { + ShaderInput* input = shaderface->inputs + uniform_ct + i; + GLsizei remaining_buffer = name_buffer_len - name_buffer_offset; + char* name = name_buffer + name_buffer_offset; + GLsizei name_len = 0; + + glGetActiveAttrib(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name); + + // TODO: reject DOUBLE gl_types + + input->name = name; + name_buffer_offset += name_len + 1; // include NULL terminator + + input->location = glGetAttribLocation(program, name); + +#if DEBUG_SHADER_INTERFACE + printf("attrib[%u] '%s' at location %d\n", i, name, input->location); +#endif + } + + // TODO: realloc shaderface to shrink name buffer + // each input->name will need adjustment (except static built-in names) + +#if DEBUG_SHADER_INTERFACE + printf("using %u of %u bytes from name buffer\n", name_buffer_offset, name_buffer_len); + printf("}\n"); // exit function +#endif + + return shaderface; + } + +void ShaderInterface_discard(ShaderInterface* shaderface) + { + // allocated as one chunk, so discard is simple + free(shaderface); + } diff --git a/source/blender/gpu/gawain/shader_interface.h b/source/blender/gpu/gawain/shader_interface.h new file mode 100644 index 00000000000..bdb0bbf4a8c --- /dev/null +++ b/source/blender/gpu/gawain/shader_interface.h @@ -0,0 +1,49 @@ + +// Gawain shader interface (C --> GLSL) +// +// This code is part of the Gawain library, with modifications +// specific to integration with Blender. +// +// Copyright 2017 Mike Erwin +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of +// the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + +#pragma once + +#include "common.h" + +typedef enum { + UNIFORM_NONE, // uninitialized/unknown + + UNIFORM_MODELVIEW_3D, // mat4 ModelViewMatrix + UNIFORM_PROJECTION_3D, // mat4 ProjectionMatrix + UNIFORM_MVP_3D, // mat4 ModelViewProjectionMatrix + UNIFORM_NORMAL_3D, // mat3 NormalMatrix + UNIFORM_INV_NORMAL_3D, // mat3 InverseNormalMatrix + + UNIFORM_MODELVIEW_2D, // mat3 ModelViewMatrix + UNIFORM_PROJECTION_2D, // mat3 ProjectionMatrix + UNIFORM_MVP_2D, // mat3 ModelViewProjectionMatrix + + UNIFORM_COLOR, // vec4 color + + UNIFORM_CUSTOM // custom uniform, not one of the above built-ins +} BuiltinUniform; + +typedef struct { + const char* name; + GLenum gl_type; + BuiltinUniform builtin_type; // only for uniform inputs + GLint size; + GLint location; +} ShaderInput; + +typedef struct { + uint16_t uniform_ct; + uint16_t attrib_ct; + ShaderInput inputs[0]; // dynamic size, uniforms followed by attribs +} ShaderInterface; + +ShaderInterface* ShaderInterface_create(GLint program_id); +void ShaderInterface_discard(ShaderInterface*); -- cgit v1.2.3