2017-03-02 21:27:51 -05:00
|
|
|
|
|
|
|
// 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/.
|
|
|
|
|
2018-02-22 12:39:57 +01:00
|
|
|
#include "gwn_batch_private.h"
|
2017-08-16 00:20:14 +10:00
|
|
|
#include "gwn_shader_interface.h"
|
2018-02-20 01:55:19 +01:00
|
|
|
#include "gwn_vertex_array_id.h"
|
2017-03-02 21:27:51 -05:00
|
|
|
#include <stdlib.h>
|
2017-03-03 14:50:35 -05:00
|
|
|
#include <stddef.h>
|
2017-04-12 17:56:26 -04:00
|
|
|
#include <string.h>
|
2017-03-02 21:27:51 -05:00
|
|
|
|
|
|
|
#define DEBUG_SHADER_INTERFACE 0
|
|
|
|
|
|
|
|
#if DEBUG_SHADER_INTERFACE
|
|
|
|
#include <stdio.h>
|
|
|
|
#endif
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
static const char* BuiltinUniform_name(Gwn_UniformBuiltin u)
|
2017-03-02 21:27:51 -05:00
|
|
|
{
|
|
|
|
static const char* names[] =
|
|
|
|
{
|
2017-06-19 20:18:04 +10:00
|
|
|
[GWN_UNIFORM_NONE] = NULL,
|
2017-03-02 21:27:51 -05:00
|
|
|
|
2017-10-08 15:49:25 +02:00
|
|
|
[GWN_UNIFORM_MODEL] = "ModelMatrix",
|
|
|
|
[GWN_UNIFORM_VIEW] = "ViewMatrix",
|
2017-06-19 20:18:04 +10:00
|
|
|
[GWN_UNIFORM_MODELVIEW] = "ModelViewMatrix",
|
|
|
|
[GWN_UNIFORM_PROJECTION] = "ProjectionMatrix",
|
2017-10-08 15:49:25 +02:00
|
|
|
[GWN_UNIFORM_VIEWPROJECTION] = "ViewProjectionMatrix",
|
2017-06-19 20:18:04 +10:00
|
|
|
[GWN_UNIFORM_MVP] = "ModelViewProjectionMatrix",
|
2017-04-12 17:56:26 -04:00
|
|
|
|
2017-10-08 15:49:25 +02:00
|
|
|
[GWN_UNIFORM_MODEL_INV] = "ModelMatrixInverse",
|
|
|
|
[GWN_UNIFORM_VIEW_INV] = "ViewMatrixInverse",
|
|
|
|
[GWN_UNIFORM_MODELVIEW_INV] = "ModelViewMatrixInverse",
|
|
|
|
[GWN_UNIFORM_PROJECTION_INV] = "ProjectionMatrixInverse",
|
|
|
|
[GWN_UNIFORM_VIEWPROJECTION_INV] = "ViewProjectionMatrixInverse",
|
2017-03-02 21:27:51 -05:00
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
[GWN_UNIFORM_NORMAL] = "NormalMatrix",
|
2017-10-08 15:49:25 +02:00
|
|
|
[GWN_UNIFORM_WORLDNORMAL] = "WorldNormalMatrix",
|
|
|
|
[GWN_UNIFORM_CAMERATEXCO] = "CameraTexCoFactors",
|
|
|
|
[GWN_UNIFORM_ORCO] = "OrcoTexCoFactors",
|
2017-04-15 19:19:00 -04:00
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
[GWN_UNIFORM_COLOR] = "color",
|
2017-10-08 15:49:25 +02:00
|
|
|
[GWN_UNIFORM_EYE] = "eye",
|
2018-04-16 19:26:54 +02:00
|
|
|
[GWN_UNIFORM_CALLID] = "callId",
|
2017-03-02 21:27:51 -05:00
|
|
|
|
2017-10-05 16:19:14 +05:00
|
|
|
[GWN_UNIFORM_CUSTOM] = NULL,
|
|
|
|
[GWN_NUM_UNIFORMS] = NULL,
|
2017-03-02 21:27:51 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
return names[u];
|
|
|
|
}
|
|
|
|
|
2017-10-04 16:53:02 +05:00
|
|
|
GWN_INLINE bool match(const char* a, const char* b)
|
2017-04-15 19:19:00 -04:00
|
|
|
{
|
|
|
|
return strcmp(a, b) == 0;
|
|
|
|
}
|
|
|
|
|
2017-10-04 16:53:02 +05:00
|
|
|
GWN_INLINE unsigned hash_string(const char *str)
|
2017-06-01 12:26:27 +02:00
|
|
|
{
|
|
|
|
unsigned i = 0, c;
|
|
|
|
|
|
|
|
while ((c = *str++))
|
|
|
|
{
|
|
|
|
i = i * 37 + c;
|
|
|
|
}
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
GWN_INLINE void set_input_name(Gwn_ShaderInterface* shaderface, Gwn_ShaderInput* input,
|
|
|
|
const char* name, uint32_t name_len)
|
2017-06-01 12:26:27 +02:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
input->name_offset = shaderface->name_buffer_offset;
|
2017-06-01 12:26:27 +02:00
|
|
|
input->name_hash = hash_string(name);
|
2017-10-05 18:26:50 +02:00
|
|
|
shaderface->name_buffer_offset += name_len + 1; // include NULL terminator
|
2017-06-01 12:26:27 +02:00
|
|
|
}
|
|
|
|
|
2017-10-04 17:36:52 +05:00
|
|
|
GWN_INLINE void shader_input_to_bucket(Gwn_ShaderInput* input,
|
2017-10-05 18:26:50 +02:00
|
|
|
Gwn_ShaderInput* buckets[GWN_NUM_SHADERINTERFACE_BUCKETS])
|
2017-10-04 17:36:52 +05:00
|
|
|
{
|
|
|
|
const unsigned bucket_index = input->name_hash % GWN_NUM_SHADERINTERFACE_BUCKETS;
|
2017-10-05 18:26:50 +02:00
|
|
|
input->next = buckets[bucket_index];
|
|
|
|
buckets[bucket_index] = input;
|
2017-10-04 17:36:52 +05:00
|
|
|
}
|
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
GWN_INLINE const Gwn_ShaderInput* buckets_lookup(Gwn_ShaderInput* const buckets[GWN_NUM_SHADERINTERFACE_BUCKETS],
|
|
|
|
const char *name_buffer, const char *name)
|
2017-10-04 17:36:52 +05:00
|
|
|
{
|
|
|
|
const unsigned name_hash = hash_string(name);
|
|
|
|
const unsigned bucket_index = name_hash % GWN_NUM_SHADERINTERFACE_BUCKETS;
|
2017-10-05 18:26:50 +02:00
|
|
|
const Gwn_ShaderInput* input = buckets[bucket_index];
|
|
|
|
if (input == NULL)
|
2017-10-04 17:36:52 +05:00
|
|
|
{
|
|
|
|
// Requested uniform is not found at all.
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
// Optimization bit: if there is no hash collision detected when constructing shader interface
|
|
|
|
// it means we can only request the single possible uniform. Surely, it's possible we request
|
|
|
|
// uniform which causes hash collision, but that will be detected in debug builds.
|
2017-10-05 18:26:50 +02:00
|
|
|
if (input->next == NULL)
|
2017-10-04 17:36:52 +05:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
if (name_hash == input->name_hash)
|
2017-10-04 17:36:52 +05:00
|
|
|
{
|
|
|
|
#if TRUST_NO_ONE
|
2017-10-05 18:26:50 +02:00
|
|
|
assert(match(name_buffer + input->name_offset, name));
|
2017-10-04 17:36:52 +05:00
|
|
|
#endif
|
2017-10-05 18:26:50 +02:00
|
|
|
return input;
|
2017-10-04 17:36:52 +05:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
// Work through possible collisions.
|
2017-10-05 18:26:50 +02:00
|
|
|
const Gwn_ShaderInput* next = input;
|
|
|
|
while (next != NULL)
|
2017-10-04 17:36:52 +05:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
input = next;
|
|
|
|
next = input->next;
|
|
|
|
|
|
|
|
if (input->name_hash != name_hash)
|
2017-10-04 17:36:52 +05:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
continue;
|
2017-10-04 17:36:52 +05:00
|
|
|
}
|
2017-10-05 18:26:50 +02:00
|
|
|
if (match(name_buffer + input->name_offset, name))
|
2017-10-04 17:36:52 +05:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
return input;
|
2017-10-04 17:36:52 +05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL; // not found
|
|
|
|
}
|
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
GWN_INLINE void buckets_free(Gwn_ShaderInput* buckets[GWN_NUM_SHADERINTERFACE_BUCKETS])
|
2017-10-06 01:50:16 +02:00
|
|
|
{
|
|
|
|
for (unsigned bucket_index = 0; bucket_index < GWN_NUM_SHADERINTERFACE_BUCKETS; ++bucket_index)
|
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
Gwn_ShaderInput *input = buckets[bucket_index];
|
|
|
|
while (input != NULL)
|
2017-10-06 01:50:16 +02:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
Gwn_ShaderInput *input_next = input->next;
|
|
|
|
free(input);
|
|
|
|
input = input_next;
|
2017-10-06 01:50:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
static bool setup_builtin_uniform(Gwn_ShaderInput* input, const char* name)
|
2017-03-02 21:27:51 -05:00
|
|
|
{
|
|
|
|
// TODO: reject DOUBLE, IMAGE, ATOMIC_COUNTER gl_types
|
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
// detect built-in uniforms (name must match)
|
2017-10-08 15:49:25 +02:00
|
|
|
for (Gwn_UniformBuiltin u = GWN_UNIFORM_NONE + 1; u < GWN_UNIFORM_CUSTOM; ++u)
|
2017-04-15 19:19:00 -04:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
const char* builtin_name = BuiltinUniform_name(u);
|
|
|
|
if (match(name, builtin_name))
|
2017-04-15 19:19:00 -04:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
input->builtin_type = u;
|
|
|
|
return true;
|
2017-04-15 19:19:00 -04:00
|
|
|
}
|
2017-10-05 18:26:50 +02:00
|
|
|
}
|
2017-04-15 19:19:00 -04:00
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
input->builtin_type = GWN_UNIFORM_CUSTOM;
|
2017-03-02 21:27:51 -05:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
static const Gwn_ShaderInput* add_uniform(Gwn_ShaderInterface* shaderface, const char* name)
|
2017-03-02 21:27:51 -05:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
Gwn_ShaderInput* input = malloc(sizeof(Gwn_ShaderInput));
|
2017-03-02 21:27:51 -05:00
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
input->location = glGetUniformLocation(shaderface->program, name);
|
2017-03-02 21:27:51 -05:00
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
unsigned name_len = strlen(name);
|
|
|
|
shaderface->name_buffer = realloc(shaderface->name_buffer, shaderface->name_buffer_offset + name_len + 1); // include NULL terminator
|
|
|
|
char* name_buffer = shaderface->name_buffer + shaderface->name_buffer_offset;
|
|
|
|
strcpy(name_buffer, name);
|
2017-03-02 21:27:51 -05:00
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
set_input_name(shaderface, input, name, name_len);
|
|
|
|
setup_builtin_uniform(input, name);
|
2017-03-02 21:27:51 -05:00
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
shader_input_to_bucket(input, shaderface->uniform_buckets);
|
|
|
|
if (input->builtin_type != GWN_UNIFORM_NONE &&
|
|
|
|
input->builtin_type != GWN_UNIFORM_CUSTOM)
|
2017-04-12 18:03:18 -04:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
shaderface->builtin_uniforms[input->builtin_type] = input;
|
2017-04-12 17:56:26 -04:00
|
|
|
}
|
2017-10-05 18:26:50 +02:00
|
|
|
#if DEBUG_SHADER_INTERFACE
|
|
|
|
printf("Gwn_ShaderInterface %p, program %d, uniform[] '%s' at location %d\n", shaderface, shaderface->program, name, input->location);
|
2017-04-12 18:03:18 -04:00
|
|
|
#endif
|
2017-10-05 18:26:50 +02:00
|
|
|
return input;
|
|
|
|
}
|
|
|
|
|
2018-06-16 12:44:20 -06:00
|
|
|
Gwn_ShaderInterface* GWN_shaderinterface_create(int32_t program)
|
2017-10-05 18:26:50 +02:00
|
|
|
{
|
|
|
|
Gwn_ShaderInterface* shaderface = calloc(1, sizeof(Gwn_ShaderInterface));
|
|
|
|
shaderface->program = program;
|
2017-03-02 21:27:51 -05:00
|
|
|
|
|
|
|
#if DEBUG_SHADER_INTERFACE
|
2017-10-05 18:26:50 +02:00
|
|
|
printf("%s {\n", __func__); // enter function
|
|
|
|
printf("Gwn_ShaderInterface %p, program %d\n", shaderface, program);
|
2017-03-02 21:27:51 -05:00
|
|
|
#endif
|
2017-10-05 18:26:50 +02:00
|
|
|
|
2018-07-08 13:05:41 +02:00
|
|
|
GLint max_attrib_name_len, attr_len;
|
2017-10-05 18:26:50 +02:00
|
|
|
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &max_attrib_name_len);
|
2018-07-08 13:05:41 +02:00
|
|
|
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &attr_len);
|
2017-10-05 18:26:50 +02:00
|
|
|
|
2018-07-08 13:05:41 +02:00
|
|
|
GLint max_ubo_name_len, ubo_len;
|
2017-10-06 14:57:21 +02:00
|
|
|
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &max_ubo_name_len);
|
2018-07-08 13:05:41 +02:00
|
|
|
glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &ubo_len);
|
2017-10-06 14:57:21 +02:00
|
|
|
|
2018-07-08 13:05:41 +02:00
|
|
|
const uint32_t name_buffer_len = attr_len * max_attrib_name_len + ubo_len * max_ubo_name_len;
|
2017-10-05 18:26:50 +02:00
|
|
|
shaderface->name_buffer = malloc(name_buffer_len);
|
2017-03-02 21:27:51 -05:00
|
|
|
|
2017-10-06 14:57:21 +02:00
|
|
|
// Attributes
|
2018-07-08 13:05:41 +02:00
|
|
|
for (uint32_t i = 0; i < attr_len; ++i)
|
2017-03-02 21:27:51 -05:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
Gwn_ShaderInput* input = malloc(sizeof(Gwn_ShaderInput));
|
|
|
|
GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
|
|
|
|
char* name = shaderface->name_buffer + shaderface->name_buffer_offset;
|
2017-03-02 21:27:51 -05:00
|
|
|
GLsizei name_len = 0;
|
|
|
|
|
|
|
|
glGetActiveAttrib(program, i, remaining_buffer, &name_len, &input->size, &input->gl_type, name);
|
|
|
|
|
2018-02-15 19:14:46 +01:00
|
|
|
// remove "[0]" from array name
|
|
|
|
if (name[name_len-1] == ']')
|
|
|
|
{
|
|
|
|
name[name_len-3] = '\0';
|
|
|
|
name_len -= 3;
|
|
|
|
}
|
|
|
|
|
2017-03-02 21:27:51 -05:00
|
|
|
// TODO: reject DOUBLE gl_types
|
|
|
|
|
2017-04-12 17:56:26 -04:00
|
|
|
input->location = glGetAttribLocation(program, name);
|
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
set_input_name(shaderface, input, name, name_len);
|
2017-04-12 17:56:26 -04:00
|
|
|
|
2017-10-05 18:26:50 +02:00
|
|
|
shader_input_to_bucket(input, shaderface->attrib_buckets);
|
2017-03-02 21:27:51 -05:00
|
|
|
|
2017-10-06 14:57:21 +02:00
|
|
|
#if DEBUG_SHADER_INTERFACE
|
|
|
|
printf("attrib[%u] '%s' at location %d\n", i, name, input->location);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Uniform Blocks
|
2018-07-08 13:05:41 +02:00
|
|
|
for (uint32_t i = 0; i < ubo_len; ++i)
|
2017-10-06 14:57:21 +02:00
|
|
|
{
|
|
|
|
Gwn_ShaderInput* input = malloc(sizeof(Gwn_ShaderInput));
|
|
|
|
GLsizei remaining_buffer = name_buffer_len - shaderface->name_buffer_offset;
|
|
|
|
char* name = shaderface->name_buffer + shaderface->name_buffer_offset;
|
|
|
|
GLsizei name_len = 0;
|
|
|
|
|
|
|
|
glGetActiveUniformBlockName(program, i, remaining_buffer, &name_len, name);
|
|
|
|
|
|
|
|
input->location = i;
|
|
|
|
|
|
|
|
set_input_name(shaderface, input, name, name_len);
|
|
|
|
|
|
|
|
shader_input_to_bucket(input, shaderface->ubo_buckets);
|
|
|
|
|
2017-03-02 21:27:51 -05:00
|
|
|
#if DEBUG_SHADER_INTERFACE
|
2018-02-15 19:15:11 +01:00
|
|
|
printf("ubo '%s' at location %d\n", name, input->location);
|
2017-03-02 21:27:51 -05:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2018-02-26 20:50:11 +01:00
|
|
|
// Builtin Uniforms
|
|
|
|
for (Gwn_UniformBuiltin u = GWN_UNIFORM_NONE + 1; u < GWN_UNIFORM_CUSTOM; ++u)
|
|
|
|
{
|
|
|
|
const char* builtin_name = BuiltinUniform_name(u);
|
|
|
|
if (glGetUniformLocation(program, builtin_name) != -1)
|
|
|
|
add_uniform((Gwn_ShaderInterface*)shaderface, builtin_name);
|
|
|
|
}
|
|
|
|
|
2018-02-20 01:55:19 +01:00
|
|
|
// Batches ref buffer
|
2018-07-08 13:05:41 +02:00
|
|
|
shaderface->batches_len = GWN_SHADERINTERFACE_REF_ALLOC_COUNT;
|
|
|
|
shaderface->batches = calloc(shaderface->batches_len, sizeof(Gwn_Batch*));
|
2018-02-20 01:55:19 +01:00
|
|
|
|
2017-03-02 21:27:51 -05:00
|
|
|
return shaderface;
|
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
void GWN_shaderinterface_discard(Gwn_ShaderInterface* shaderface)
|
2017-03-02 21:27:51 -05:00
|
|
|
{
|
2017-10-06 01:50:16 +02:00
|
|
|
// Free memory used by buckets and has entries.
|
|
|
|
buckets_free(shaderface->uniform_buckets);
|
|
|
|
buckets_free(shaderface->attrib_buckets);
|
2017-10-06 14:57:21 +02:00
|
|
|
buckets_free(shaderface->ubo_buckets);
|
2017-10-05 18:26:50 +02:00
|
|
|
// Free memory used by name_buffer.
|
|
|
|
free(shaderface->name_buffer);
|
2018-02-20 01:55:19 +01:00
|
|
|
// Remove this interface from all linked Batches vao cache.
|
2018-07-08 13:05:41 +02:00
|
|
|
for (int i = 0; i < shaderface->batches_len; ++i)
|
2018-02-20 01:55:19 +01:00
|
|
|
if (shaderface->batches[i] != NULL)
|
2018-02-22 12:39:57 +01:00
|
|
|
gwn_batch_remove_interface_ref(shaderface->batches[i], shaderface);
|
2018-02-20 01:55:19 +01:00
|
|
|
|
|
|
|
free(shaderface->batches);
|
2017-10-04 17:36:52 +05:00
|
|
|
// Free memory used by shader interface by its self.
|
2017-03-02 21:27:51 -05:00
|
|
|
free(shaderface);
|
|
|
|
}
|
2017-04-12 17:56:26 -04:00
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
const Gwn_ShaderInput* GWN_shaderinterface_uniform(const Gwn_ShaderInterface* shaderface, const char* name)
|
2017-04-12 17:56:26 -04:00
|
|
|
{
|
2017-10-04 17:36:52 +05:00
|
|
|
// TODO: Warn if we find a matching builtin, since these can be looked up much quicker.
|
2017-10-05 18:26:50 +02:00
|
|
|
const Gwn_ShaderInput* input = buckets_lookup(shaderface->uniform_buckets, shaderface->name_buffer, name);
|
|
|
|
|
|
|
|
// If input is not found add it so it's found next time.
|
|
|
|
if (input == NULL)
|
|
|
|
input = add_uniform((Gwn_ShaderInterface*)shaderface, name);
|
|
|
|
|
|
|
|
return (input->location != -1) ? input : NULL;
|
2017-04-12 17:56:26 -04:00
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
const Gwn_ShaderInput* GWN_shaderinterface_uniform_builtin(const Gwn_ShaderInterface* shaderface, Gwn_UniformBuiltin builtin)
|
2017-04-12 17:56:26 -04:00
|
|
|
{
|
2017-06-04 22:09:39 -04:00
|
|
|
#if TRUST_NO_ONE
|
2017-06-19 20:18:04 +10:00
|
|
|
assert(builtin != GWN_UNIFORM_NONE);
|
|
|
|
assert(builtin != GWN_UNIFORM_CUSTOM);
|
2017-10-05 16:19:14 +05:00
|
|
|
assert(builtin != GWN_NUM_UNIFORMS);
|
2017-06-04 22:09:39 -04:00
|
|
|
#endif
|
2018-02-26 20:50:11 +01:00
|
|
|
return shaderface->builtin_uniforms[builtin];
|
2017-04-12 17:56:26 -04:00
|
|
|
}
|
2017-04-15 18:06:54 -04:00
|
|
|
|
2017-10-06 14:57:21 +02:00
|
|
|
const Gwn_ShaderInput* GWN_shaderinterface_ubo(const Gwn_ShaderInterface* shaderface, const char* name)
|
|
|
|
{
|
|
|
|
return buckets_lookup(shaderface->ubo_buckets, shaderface->name_buffer, name);
|
|
|
|
}
|
|
|
|
|
2017-06-19 20:18:04 +10:00
|
|
|
const Gwn_ShaderInput* GWN_shaderinterface_attr(const Gwn_ShaderInterface* shaderface, const char* name)
|
2017-04-15 18:06:54 -04:00
|
|
|
{
|
2017-10-05 18:26:50 +02:00
|
|
|
return buckets_lookup(shaderface->attrib_buckets, shaderface->name_buffer, name);
|
2017-04-15 18:06:54 -04:00
|
|
|
}
|
2018-02-20 01:55:19 +01:00
|
|
|
|
|
|
|
void GWN_shaderinterface_add_batch_ref(Gwn_ShaderInterface* shaderface, Gwn_Batch* batch)
|
|
|
|
{
|
|
|
|
int i; // find first unused slot
|
2018-07-08 13:05:41 +02:00
|
|
|
for (i = 0; i < shaderface->batches_len; ++i)
|
2018-02-20 01:55:19 +01:00
|
|
|
if (shaderface->batches[i] == NULL)
|
|
|
|
break;
|
|
|
|
|
2018-07-08 13:05:41 +02:00
|
|
|
if (i == shaderface->batches_len)
|
2018-02-20 01:55:19 +01:00
|
|
|
{
|
|
|
|
// Not enough place, realloc the array.
|
2018-07-08 13:05:41 +02:00
|
|
|
i = shaderface->batches_len;
|
|
|
|
shaderface->batches_len += GWN_SHADERINTERFACE_REF_ALLOC_COUNT;
|
|
|
|
shaderface->batches = realloc(shaderface->batches, sizeof(Gwn_Batch*) * shaderface->batches_len);
|
2018-02-20 01:55:19 +01:00
|
|
|
memset(shaderface->batches + i, 0, sizeof(Gwn_Batch*) * GWN_SHADERINTERFACE_REF_ALLOC_COUNT);
|
|
|
|
}
|
|
|
|
|
|
|
|
shaderface->batches[i] = batch;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GWN_shaderinterface_remove_batch_ref(Gwn_ShaderInterface* shaderface, Gwn_Batch* batch)
|
|
|
|
{
|
2018-07-08 13:05:41 +02:00
|
|
|
for (int i = 0; i < shaderface->batches_len; ++i)
|
2018-02-20 01:55:19 +01:00
|
|
|
{
|
|
|
|
if (shaderface->batches[i] == batch)
|
|
|
|
{
|
|
|
|
shaderface->batches[i] = NULL;
|
|
|
|
break; // cannot have duplicates
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|