renderer,gl33: fix texture management issues
Previously we assumed that we generally do not need to unbind textures from shader samplers: if a sampler had no Taisei-level texture binding, we would simply not update its OpenGL-level binding. This assumption is no longer valid after introduction of cubemap textures. Shader samplers always have an OpenGL-level binding to a texturing unit (0 by default). If the sampler type is not compatible with the type of texture bound to its texturing unit (e.g. 2D texture with a cube sampler), the draw call will raise an error, even if the shader does not actually use the invalid sampler. For that reason, we now make sure that all samplers without a Taisei-level texture binding are assigned a texturing unit with no OpenGL-level texture binding. The texunit juggling logic had to be fixed quite a bit to correctly handle unbinding textures. Additionally, some assertions have been added to prevent assigning incompatible textures to samplers via the renderer API, and the number of minimum required texturing units has been raised to 8 (we sometimes need more than 4 bound textures at a time).
This commit is contained in:
parent
087f1ab0d9
commit
b45b2c22ce
7 changed files with 199 additions and 89 deletions
|
@ -178,17 +178,18 @@ void r_blend_unpack(BlendMode mode, UnpackedBlendMode *dest) {
|
|||
|
||||
const UniformTypeInfo* r_uniform_type_info(UniformType type) {
|
||||
static UniformTypeInfo uniform_typemap[] = {
|
||||
[UNIFORM_FLOAT] = { 1, sizeof(float) },
|
||||
[UNIFORM_VEC2] = { 2, sizeof(float) },
|
||||
[UNIFORM_VEC3] = { 3, sizeof(float) },
|
||||
[UNIFORM_VEC4] = { 4, sizeof(float) },
|
||||
[UNIFORM_INT] = { 1, sizeof(int) },
|
||||
[UNIFORM_IVEC2] = { 2, sizeof(int) },
|
||||
[UNIFORM_IVEC3] = { 3, sizeof(int) },
|
||||
[UNIFORM_IVEC4] = { 4, sizeof(int) },
|
||||
[UNIFORM_SAMPLER] = { 1, sizeof(void*) },
|
||||
[UNIFORM_MAT3] = { 9, sizeof(float) },
|
||||
[UNIFORM_MAT4] = { 16, sizeof(float) },
|
||||
[UNIFORM_FLOAT] = { 1, sizeof(float) },
|
||||
[UNIFORM_VEC2] = { 2, sizeof(float) },
|
||||
[UNIFORM_VEC3] = { 3, sizeof(float) },
|
||||
[UNIFORM_VEC4] = { 4, sizeof(float) },
|
||||
[UNIFORM_INT] = { 1, sizeof(int) },
|
||||
[UNIFORM_IVEC2] = { 2, sizeof(int) },
|
||||
[UNIFORM_IVEC3] = { 3, sizeof(int) },
|
||||
[UNIFORM_IVEC4] = { 4, sizeof(int) },
|
||||
[UNIFORM_SAMPLER_2D] = { 1, sizeof(void*) },
|
||||
[UNIFORM_SAMPLER_CUBE] = { 1, sizeof(void*) },
|
||||
[UNIFORM_MAT3] = { 9, sizeof(float) },
|
||||
[UNIFORM_MAT4] = { 16, sizeof(float) },
|
||||
};
|
||||
|
||||
assert((uint)type < sizeof(uniform_typemap)/sizeof(UniformTypeInfo));
|
||||
|
@ -717,7 +718,20 @@ bool r_screenshot(Pixmap *out) {
|
|||
|
||||
// uniforms garbage; hope your compiler is smart enough to inline most of this
|
||||
|
||||
#define ASSERT_UTYPE(uniform, type) do { if(uniform) assert(r_uniform_type(uniform) == type); } while(0)
|
||||
// TODO: verify sampler-to-texture type consistency?
|
||||
|
||||
#define ASSERT_UTYPE(uniform, type) do { \
|
||||
if(uniform) { \
|
||||
assert(r_uniform_type(uniform) == type); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define ASSERT_UTYPE_SAMPLER(uniform) do { \
|
||||
if(uniform) { \
|
||||
attr_unused UniformType _utype = r_uniform_type(uniform); \
|
||||
assert(UNIFORM_TYPE_IS_SAMPLER(_utype)); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
void r_uniform_ptr_unsafe(Uniform *uniform, uint offset, uint count, void *data) {
|
||||
if(uniform) B.uniform(uniform, offset, count, data);
|
||||
|
@ -1001,7 +1015,7 @@ void _r_uniform_ivec4_array(const char *uniform, uint offset, uint count, ivec4_
|
|||
}
|
||||
|
||||
void _r_uniform_ptr_sampler_ptr(Uniform *uniform, Texture *tex) {
|
||||
ASSERT_UTYPE(uniform, UNIFORM_SAMPLER);
|
||||
ASSERT_UTYPE_SAMPLER(uniform);
|
||||
if(uniform) B.uniform(uniform, 0, 1, &tex);
|
||||
}
|
||||
|
||||
|
@ -1010,7 +1024,7 @@ void _r_uniform_sampler_ptr(const char *uniform, Texture *tex) {
|
|||
}
|
||||
|
||||
void _r_uniform_ptr_sampler(Uniform *uniform, const char *tex) {
|
||||
ASSERT_UTYPE(uniform, UNIFORM_SAMPLER);
|
||||
ASSERT_UTYPE_SAMPLER(uniform);
|
||||
if(uniform) B.uniform(uniform, 0, 1, (Texture*[]) { res_texture(tex) });
|
||||
}
|
||||
|
||||
|
@ -1019,7 +1033,7 @@ void _r_uniform_sampler(const char *uniform, const char *tex) {
|
|||
}
|
||||
|
||||
void _r_uniform_ptr_sampler_array_ptr(Uniform *uniform, uint offset, uint count, Texture *values[count]) {
|
||||
ASSERT_UTYPE(uniform, UNIFORM_SAMPLER);
|
||||
ASSERT_UTYPE_SAMPLER(uniform);
|
||||
if(uniform && count) B.uniform(uniform, offset, count, values);
|
||||
}
|
||||
|
||||
|
@ -1028,7 +1042,7 @@ void _r_uniform_sampler_array_ptr(const char *uniform, uint offset, uint count,
|
|||
}
|
||||
|
||||
void _r_uniform_ptr_sampler_array(Uniform *uniform, uint offset, uint count, const char *values[count]) {
|
||||
ASSERT_UTYPE(uniform, UNIFORM_SAMPLER);
|
||||
ASSERT_UTYPE_SAMPLER(uniform);
|
||||
if(uniform && count) {
|
||||
Texture *arr[count], **aptr = arr, **aend = aptr + count;
|
||||
const char **vptr = values;
|
||||
|
|
|
@ -280,12 +280,16 @@ typedef enum UniformType {
|
|||
UNIFORM_IVEC2,
|
||||
UNIFORM_IVEC3,
|
||||
UNIFORM_IVEC4,
|
||||
UNIFORM_SAMPLER,
|
||||
UNIFORM_SAMPLER_2D,
|
||||
UNIFORM_SAMPLER_CUBE,
|
||||
UNIFORM_MAT3,
|
||||
UNIFORM_MAT4,
|
||||
UNIFORM_UNKNOWN,
|
||||
} UniformType;
|
||||
|
||||
#define UNIFORM_TYPE_IS_SAMPLER(ut) \
|
||||
((ut) == UNIFORM_SAMPLER_2D || (ut) == UNIFORM_SAMPLER_CUBE)
|
||||
|
||||
typedef struct UniformTypeInfo {
|
||||
// Refers to vector elements, not array elements.
|
||||
uint8_t elements;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "util/env.h"
|
||||
|
||||
// #define GL33_DEBUG_TEXUNITS
|
||||
// #define GL33_DRAW_STATS
|
||||
|
||||
typedef struct TextureUnit {
|
||||
LIST_INTERFACE(struct TextureUnit);
|
||||
|
@ -37,6 +38,7 @@ typedef struct TextureUnit {
|
|||
Texture *pending;
|
||||
GLuint gl_handle;
|
||||
GLenum bind_target;
|
||||
int old_prio;
|
||||
bool locked;
|
||||
} TextureUnit;
|
||||
|
||||
|
@ -117,6 +119,7 @@ static struct {
|
|||
hrtime_t last_draw;
|
||||
hrtime_t draw_time;
|
||||
uint draw_calls;
|
||||
uint texture_rebinds;
|
||||
} stats;
|
||||
#endif
|
||||
} R;
|
||||
|
@ -184,13 +187,14 @@ static inline void gl33_stats_post_draw(void) {
|
|||
|
||||
static inline void gl33_stats_post_frame(void) {
|
||||
#ifdef GL33_DRAW_STATS
|
||||
log_debug("%.20gs spent in %u draw calls", (double)R.stats.draw_time, R.stats.draw_calls);
|
||||
log_debug("%.1fµs spent in %u draw calls", R.stats.draw_time / (HRTIME_RESOLUTION / 1000000.0) , R.stats.draw_calls);
|
||||
log_debug("%u texture rebinds", R.stats.texture_rebinds);
|
||||
memset(&R.stats, 0, sizeof(R.stats));
|
||||
#endif
|
||||
}
|
||||
|
||||
static void gl33_init_texunits(void) {
|
||||
GLint texunits_available, texunits_capped, texunits_max, texunits_min = 4;
|
||||
GLint texunits_available, texunits_capped, texunits_max, texunits_min = 8;
|
||||
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &texunits_available);
|
||||
|
||||
if(texunits_available < texunits_min) {
|
||||
|
@ -538,7 +542,6 @@ static void gl33_activate_texunit(TextureUnit *unit) {
|
|||
|
||||
static int gl33_texunit_priority(TextureUnit *u) {
|
||||
if(u->locked) {
|
||||
assert(u->pending);
|
||||
return 3;
|
||||
}
|
||||
|
||||
|
@ -566,20 +569,24 @@ attr_unused static void texture_str(Texture *tex, char *buf, size_t bufsize) {
|
|||
}
|
||||
}
|
||||
|
||||
attr_unused static void gl33_dump_texunit(TextureUnit *u) {
|
||||
char buf1[128], buf2[128];
|
||||
texture_str(u->active, buf1, sizeof(buf1));
|
||||
texture_str(u->pending, buf2, sizeof(buf2));
|
||||
log_debug("[Unit %u | prio=%i | target=0x%x] bound: %s; pending: %s",
|
||||
(uint)TU_INDEX(u),
|
||||
gl33_texunit_priority(u),
|
||||
u->bind_target,
|
||||
buf1,
|
||||
buf2
|
||||
);
|
||||
}
|
||||
|
||||
attr_unused static void gl33_dump_texunits(void) {
|
||||
log_debug("=== BEGIN DUMP ===");
|
||||
|
||||
for(TextureUnit *u = R.texunits.list.first; u; u = u->next) {
|
||||
char buf1[128], buf2[128];
|
||||
texture_str(u->active, buf1, sizeof(buf1));
|
||||
texture_str(u->pending, buf2, sizeof(buf2));
|
||||
log_debug("[Unit %u | %i | 0x%x] bound: %s; pending: %s",
|
||||
(uint)TU_INDEX(u),
|
||||
gl33_texunit_priority(u),
|
||||
u->bind_target,
|
||||
buf1,
|
||||
buf2
|
||||
);
|
||||
gl33_dump_texunit(u);
|
||||
}
|
||||
|
||||
log_debug("=== END DUMP ===");
|
||||
|
@ -588,6 +595,12 @@ attr_unused static void gl33_dump_texunits(void) {
|
|||
static void gl33_relocate_texuint(TextureUnit *unit) {
|
||||
int prio = gl33_texunit_priority(unit);
|
||||
|
||||
if(unit->old_prio == prio) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: optimize with a heap-based priority queue?
|
||||
|
||||
alist_unlink(&R.texunits.list, unit);
|
||||
|
||||
if(prio > 1) {
|
||||
|
@ -596,6 +609,8 @@ static void gl33_relocate_texuint(TextureUnit *unit) {
|
|||
alist_insert_at_priority_head(&R.texunits.list, unit, prio, gl33_texunit_priority_callback);
|
||||
}
|
||||
|
||||
unit->old_prio = prio;
|
||||
|
||||
#ifdef GL33_DEBUG_TEXUNITS
|
||||
// gl33_dump_texunits();
|
||||
// log_debug("Relocated unit %u", (uint)TU_INDEX(unit));
|
||||
|
@ -615,7 +630,7 @@ static void gl33_set_texunit_binding(TextureUnit *unit, Texture *tex, bool lock)
|
|||
unit->locked = true;
|
||||
}
|
||||
|
||||
// gl33_relocate_texuint(unit);
|
||||
gl33_relocate_texuint(unit);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -651,14 +666,30 @@ static void gl33_bind_handle_to_texunit(TextureUnit *u, GLenum target, GLuint ha
|
|||
* Therefore we maintain only 1 kind of texture per unit here.
|
||||
*/
|
||||
|
||||
#ifdef GL33_DEBUG_TEXUNITS
|
||||
if(target != u->bind_target) {
|
||||
log_debug("[%u] TYPE CHANGE: 0x%x -> 0x%x", (uint)TU_INDEX(u), u->bind_target, target);
|
||||
gl33_dump_texunit(u);
|
||||
}
|
||||
#endif
|
||||
|
||||
if(target != u->bind_target && u->bind_target != 0) {
|
||||
// If changing target, clear the old binding.
|
||||
// Probably not strictly necessary, but safer and more debuggable.
|
||||
glBindTexture(u->bind_target, 0);
|
||||
u->bind_target = target;
|
||||
|
||||
#ifdef GL33_DRAW_STATS
|
||||
++R.stats.texture_rebinds;
|
||||
#endif
|
||||
}
|
||||
|
||||
glBindTexture(target, handle);
|
||||
|
||||
#ifdef GL33_DRAW_STATS
|
||||
++R.stats.texture_rebinds;
|
||||
#endif
|
||||
|
||||
u->bind_target = target;
|
||||
u->gl_handle = handle;
|
||||
}
|
||||
|
||||
|
@ -670,7 +701,7 @@ void gl33_sync_texunit(TextureUnit *unit, bool prepare_rendering, bool ensure_ac
|
|||
attr_unused char buf1[128], buf2[128];
|
||||
texture_str(unit->active, buf1, sizeof(buf1));
|
||||
texture_str(unit->pending, buf2, sizeof(buf2));
|
||||
log_debug("[Unit %u] %s ===> %s", (uint)TU_INDEX(unit), buf1, buf2);
|
||||
log_debug("[Unit %u] %s ===> %s (render: %i)", (uint)TU_INDEX(unit), buf1, buf2, prepare_rendering);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -695,9 +726,13 @@ void gl33_sync_texunit(TextureUnit *unit, bool prepare_rendering, bool ensure_ac
|
|||
gl33_activate_texunit(unit);
|
||||
}
|
||||
|
||||
if(prepare_rendering && unit->active != NULL) {
|
||||
gl33_texture_prepare(unit->active);
|
||||
if(prepare_rendering) {
|
||||
if(unit->active != NULL) {
|
||||
gl33_texture_prepare(unit->active);
|
||||
}
|
||||
|
||||
unit->locked = false;
|
||||
gl33_relocate_texuint(unit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -837,7 +872,49 @@ void gl33_sync_blend_mode(void) {
|
|||
}
|
||||
}
|
||||
|
||||
static TextureUnit *gl33_get_free_texunit(void) {
|
||||
TextureUnit *u = R.texunits.list.first;
|
||||
|
||||
if(
|
||||
u->pending &&
|
||||
u->pending != u->active
|
||||
) {
|
||||
log_warn("Ran out of texturing units, expect rendering errors!");
|
||||
}
|
||||
|
||||
assert(!u->locked);
|
||||
return u;
|
||||
}
|
||||
|
||||
uint gl33_bind_texture(Texture *texture, bool for_rendering, int preferred_unit) {
|
||||
if(UNLIKELY(texture == NULL)) {
|
||||
TextureUnit *unit = NULL;
|
||||
|
||||
if(preferred_unit >= 0) {
|
||||
assert(preferred_unit < R.texunits.limit);
|
||||
unit = &R.texunits.array[preferred_unit];
|
||||
|
||||
if(unit->pending != NULL && unit->locked) {
|
||||
// someone else already took this unit for rendering
|
||||
unit = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(unit == NULL) {
|
||||
assert(!glext.issues.avoid_sampler_uniform_updates);
|
||||
unit = gl33_get_free_texunit();
|
||||
}
|
||||
|
||||
if(unit->locked) {
|
||||
gl33_relocate_texuint(unit);
|
||||
} else {
|
||||
gl33_set_texunit_binding(unit, NULL, for_rendering);
|
||||
}
|
||||
|
||||
assert(unit->pending == NULL);
|
||||
return TU_INDEX(unit);
|
||||
}
|
||||
|
||||
if(glext.issues.avoid_sampler_uniform_updates && preferred_unit >= 0) {
|
||||
assert(preferred_unit < R.texunits.limit);
|
||||
TextureUnit *u = &R.texunits.array[preferred_unit];
|
||||
|
@ -853,16 +930,7 @@ uint gl33_bind_texture(Texture *texture, bool for_rendering, int preferred_unit)
|
|||
// most recent binding.
|
||||
texture->binding_unit = u;
|
||||
} else if(!texture->binding_unit) {
|
||||
// assert(R.texunits.list.first->tex2d.pending != texture);
|
||||
|
||||
if(
|
||||
R.texunits.list.first->pending &&
|
||||
R.texunits.list.first->pending != R.texunits.list.first->active
|
||||
) {
|
||||
log_warn("Ran out of texturing units, expect rendering errors!");
|
||||
}
|
||||
|
||||
gl33_set_texunit_binding(R.texunits.list.first, texture, for_rendering);
|
||||
gl33_set_texunit_binding(gl33_get_free_texunit(), texture, for_rendering);
|
||||
} else /* if(for_rendering) */ {
|
||||
texture->binding_unit->locked |= for_rendering;
|
||||
gl33_relocate_texuint(texture->binding_unit);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "gl33.h"
|
||||
#include "shader_program.h"
|
||||
#include "shader_object.h"
|
||||
#include "texture.h"
|
||||
#include "../glcommon/debug.h"
|
||||
#include "../api.h"
|
||||
|
||||
|
@ -136,18 +137,19 @@ static void uget_mat4(Uniform *uniform, uint count, void *data) {
|
|||
static struct {
|
||||
void (*setter)(Uniform *uniform, uint offset, uint count, const void *data);
|
||||
void (*getter)(Uniform *uniform, uint count, void *data);
|
||||
} type_to_accessors[] = {
|
||||
[UNIFORM_FLOAT] = { uset_float, uget_float },
|
||||
[UNIFORM_VEC2] = { uset_vec2, uget_vec2 },
|
||||
[UNIFORM_VEC3] = { uset_vec3, uget_vec3 },
|
||||
[UNIFORM_VEC4] = { uset_vec4, uget_vec4 },
|
||||
[UNIFORM_INT] = { uset_int, uget_int },
|
||||
[UNIFORM_IVEC2] = { uset_ivec2, uget_ivec2 },
|
||||
[UNIFORM_IVEC3] = { uset_ivec3, uget_ivec3 },
|
||||
[UNIFORM_IVEC4] = { uset_ivec4, uget_ivec4 },
|
||||
[UNIFORM_SAMPLER] = { uset_int, uget_int },
|
||||
[UNIFORM_MAT3] = { uset_mat3, uget_mat3 },
|
||||
[UNIFORM_MAT4] = { uset_mat4, uget_mat4 },
|
||||
} type_to_accessors[] = {
|
||||
[UNIFORM_FLOAT] = { uset_float, uget_float },
|
||||
[UNIFORM_VEC2] = { uset_vec2, uget_vec2 },
|
||||
[UNIFORM_VEC3] = { uset_vec3, uget_vec3 },
|
||||
[UNIFORM_VEC4] = { uset_vec4, uget_vec4 },
|
||||
[UNIFORM_INT] = { uset_int, uget_int },
|
||||
[UNIFORM_IVEC2] = { uset_ivec2, uget_ivec2 },
|
||||
[UNIFORM_IVEC3] = { uset_ivec3, uget_ivec3 },
|
||||
[UNIFORM_IVEC4] = { uset_ivec4, uget_ivec4 },
|
||||
[UNIFORM_SAMPLER_2D] = { uset_int, uget_int },
|
||||
[UNIFORM_SAMPLER_CUBE] = { uset_int, uget_int },
|
||||
[UNIFORM_MAT3] = { uset_mat3, uget_mat3 },
|
||||
[UNIFORM_MAT4] = { uset_mat4, uget_mat4 },
|
||||
};
|
||||
|
||||
typedef struct MagicUniformSpec {
|
||||
|
@ -219,28 +221,27 @@ static void *gl33_sync_uniform(const char *key, void *value, void *arg) {
|
|||
Uniform *uniform = value;
|
||||
|
||||
// special case: for sampler uniforms, we have to construct the actual data from the texture pointers array.
|
||||
if(uniform->type == UNIFORM_SAMPLER) {
|
||||
if(UNIFORM_TYPE_IS_SAMPLER(uniform->type)) {
|
||||
Uniform *size_uniform = uniform->size_uniform;
|
||||
|
||||
for(uint i = 0; i < uniform->array_size; ++i) {
|
||||
Texture *tex = uniform->textures[i];
|
||||
GLuint preferred_unit = CASTPTR_ASSUME_ALIGNED(uniform->cache.pending, int)[i];
|
||||
GLuint unit = gl33_bind_texture(tex, true, preferred_unit);
|
||||
|
||||
if(tex == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(glext.issues.avoid_sampler_uniform_updates) {
|
||||
int preferred_unit = CASTPTR_ASSUME_ALIGNED(uniform->cache.pending, int)[i];
|
||||
attr_unused GLuint unit = gl33_bind_texture(tex, true, preferred_unit);
|
||||
assert(unit == preferred_unit);
|
||||
} else {
|
||||
GLuint unit = gl33_bind_texture(tex, true, -1);
|
||||
if(unit != preferred_unit) {
|
||||
gl33_update_uniform(uniform, i, 1, &unit);
|
||||
}
|
||||
|
||||
if(size_uniform) {
|
||||
uint w, h;
|
||||
r_texture_get_size(tex, 0, &w, &h);
|
||||
|
||||
if(tex) {
|
||||
r_texture_get_size(tex, 0, &w, &h);
|
||||
} else {
|
||||
w = h = 0;
|
||||
}
|
||||
|
||||
vec2_noalign size = { w, h };
|
||||
gl33_update_uniform(size_uniform, i, 1, &size);
|
||||
gl33_commit_uniform(size_uniform);
|
||||
|
@ -273,8 +274,15 @@ void gl33_uniform(Uniform *uniform, uint offset, uint count, const void *data) {
|
|||
}
|
||||
|
||||
// special case: for sampler uniforms, data is an array of Texture pointers that we'll have to bind later.
|
||||
if(uniform->type == UNIFORM_SAMPLER) {
|
||||
if(UNIFORM_TYPE_IS_SAMPLER(uniform->type)) {
|
||||
Texture **textures = (Texture**)data;
|
||||
|
||||
for(uint i = 0; i < count; ++i) {
|
||||
if(textures[i]) {
|
||||
assert(gl33_texture_sampler_compatible(textures[i], uniform->type));
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(uniform->textures + offset, textures, sizeof(Texture*) * count);
|
||||
} else {
|
||||
gl33_update_uniform(uniform, offset, count, data);
|
||||
|
@ -311,18 +319,18 @@ static bool cache_uniforms(ShaderProgram *prog) {
|
|||
}
|
||||
|
||||
switch(type) {
|
||||
case GL_FLOAT: uni.type = UNIFORM_FLOAT; break;
|
||||
case GL_FLOAT_VEC2: uni.type = UNIFORM_VEC2; break;
|
||||
case GL_FLOAT_VEC3: uni.type = UNIFORM_VEC3; break;
|
||||
case GL_FLOAT_VEC4: uni.type = UNIFORM_VEC4; break;
|
||||
case GL_INT: uni.type = UNIFORM_INT; break;
|
||||
case GL_INT_VEC2: uni.type = UNIFORM_IVEC2; break;
|
||||
case GL_INT_VEC3: uni.type = UNIFORM_IVEC3; break;
|
||||
case GL_INT_VEC4: uni.type = UNIFORM_IVEC4; break;
|
||||
case GL_SAMPLER_2D: uni.type = UNIFORM_SAMPLER; break;
|
||||
case GL_SAMPLER_CUBE: uni.type = UNIFORM_SAMPLER; break;
|
||||
case GL_FLOAT_MAT3: uni.type = UNIFORM_MAT3; break;
|
||||
case GL_FLOAT_MAT4: uni.type = UNIFORM_MAT4; break;
|
||||
case GL_FLOAT: uni.type = UNIFORM_FLOAT; break;
|
||||
case GL_FLOAT_VEC2: uni.type = UNIFORM_VEC2; break;
|
||||
case GL_FLOAT_VEC3: uni.type = UNIFORM_VEC3; break;
|
||||
case GL_FLOAT_VEC4: uni.type = UNIFORM_VEC4; break;
|
||||
case GL_INT: uni.type = UNIFORM_INT; break;
|
||||
case GL_INT_VEC2: uni.type = UNIFORM_IVEC2; break;
|
||||
case GL_INT_VEC3: uni.type = UNIFORM_IVEC3; break;
|
||||
case GL_INT_VEC4: uni.type = UNIFORM_IVEC4; break;
|
||||
case GL_SAMPLER_2D: uni.type = UNIFORM_SAMPLER_2D; break;
|
||||
case GL_SAMPLER_CUBE: uni.type = UNIFORM_SAMPLER_CUBE; break;
|
||||
case GL_FLOAT_MAT3: uni.type = UNIFORM_MAT3; break;
|
||||
case GL_FLOAT_MAT4: uni.type = UNIFORM_MAT4; break;
|
||||
|
||||
default:
|
||||
log_warn("Uniform '%s' is of an unsupported type 0x%04x and will be ignored.", name, type);
|
||||
|
@ -352,9 +360,9 @@ static bool cache_uniforms(ShaderProgram *prog) {
|
|||
uni.location = loc;
|
||||
uni.array_size = size;
|
||||
|
||||
if(uni.type == UNIFORM_SAMPLER) {
|
||||
if(UNIFORM_TYPE_IS_SAMPLER(uni.type)) {
|
||||
uni.elem_size = sizeof(GLint);
|
||||
uni.textures = calloc(uni.array_size, sizeof(Texture*));
|
||||
uni.textures = calloc(uni.array_size, sizeof(*uni.textures));
|
||||
} else {
|
||||
uni.elem_size = typeinfo->element_size * typeinfo->elements;
|
||||
}
|
||||
|
@ -380,7 +388,7 @@ static bool cache_uniforms(ShaderProgram *prog) {
|
|||
|
||||
Uniform *new_uni = memdup(&uni, sizeof(uni));
|
||||
|
||||
if(uni.type == UNIFORM_SAMPLER) {
|
||||
if(UNIFORM_TYPE_IS_SAMPLER(uni.type)) {
|
||||
list_push(&sampler_uniforms, new_uni);
|
||||
|
||||
if(glext.issues.avoid_sampler_uniform_updates) {
|
||||
|
@ -413,7 +421,7 @@ static bool cache_uniforms(ShaderProgram *prog) {
|
|||
while(iter.has_data) {
|
||||
Uniform *u = iter.value;
|
||||
|
||||
if(u->type == UNIFORM_SAMPLER) {
|
||||
if(UNIFORM_TYPE_IS_SAMPLER(u->type)) {
|
||||
const char *sampler_name = iter.key;
|
||||
const char size_suffix[] = "_SIZE";
|
||||
char size_uniform_name[strlen(sampler_name) + sizeof(size_suffix)];
|
||||
|
@ -446,7 +454,7 @@ static bool cache_uniforms(ShaderProgram *prog) {
|
|||
|
||||
void gl33_unref_texture_from_samplers(Texture *tex) {
|
||||
for(Uniform *u = sampler_uniforms; u; u = u->next) {
|
||||
assert(u->type == UNIFORM_SAMPLER);
|
||||
assert(UNIFORM_TYPE_IS_SAMPLER(u->type));
|
||||
assert(u->textures != NULL);
|
||||
|
||||
for(Texture **slot = u->textures; slot < u->textures + u->array_size; ++slot) {
|
||||
|
@ -476,7 +484,7 @@ static void print_info_log(GLuint prog) {
|
|||
static void *free_uniform(const char *key, void *data, void *arg) {
|
||||
Uniform *uniform = data;
|
||||
|
||||
if(uniform->type == UNIFORM_SAMPLER) {
|
||||
if(UNIFORM_TYPE_IS_SAMPLER(uniform->type)) {
|
||||
list_unlink(&sampler_uniforms, uniform);
|
||||
}
|
||||
|
||||
|
|
|
@ -576,3 +576,18 @@ const char *gl33_texture_get_debug_label(Texture *tex) {
|
|||
void gl33_texture_set_debug_label(Texture *tex, const char *label) {
|
||||
glcommon_set_debug_label(tex->debug_label, "Texture", GL_TEXTURE, tex->gl_handle, label);
|
||||
}
|
||||
|
||||
bool gl33_texture_sampler_compatible(Texture *tex, UniformType sampler_type) {
|
||||
assert(UNIFORM_TYPE_IS_SAMPLER(sampler_type));
|
||||
|
||||
switch(tex->bind_target) {
|
||||
case GL_TEXTURE_2D:
|
||||
return sampler_type == UNIFORM_SAMPLER_2D;
|
||||
|
||||
case GL_TEXTURE_CUBE_MAP:
|
||||
return sampler_type == UNIFORM_SAMPLER_CUBE;
|
||||
|
||||
default:
|
||||
UNREACHABLE;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,5 +44,6 @@ void gl44_texture_clear(Texture *tex, const Color *clr);
|
|||
void gl33_texture_clear(Texture *tex, const Color *clr);
|
||||
void gl33_texture_destroy(Texture *tex);
|
||||
bool gl33_texture_type_query(TextureType type, TextureFlags flags, PixmapFormat pxfmt, PixmapOrigin pxorigin, TextureTypeQueryResult *result);
|
||||
bool gl33_texture_sampler_compatible(Texture *tex, UniformType sampler_type) attr_nonnull(1);
|
||||
|
||||
#endif // IGUARD_renderer_gl33_texture_h
|
||||
|
|
|
@ -67,7 +67,7 @@ static bool postprocess_load_callback(const char *key, const char *value, void *
|
|||
UniformType type = r_uniform_type(uni);
|
||||
const UniformTypeInfo *type_info = r_uniform_type_info(type);
|
||||
|
||||
if(type == UNIFORM_SAMPLER) {
|
||||
if(UNIFORM_TYPE_IS_SAMPLER(type)) {
|
||||
Texture *tex = get_resource_data(RES_TEXTURE, value, ldata->resflags);
|
||||
|
||||
if(tex) {
|
||||
|
|
Loading…
Reference in a new issue