taisei/src/renderer/gl33/shader_object.c
Andrei Alexeyev fda8556a39
src: deprecate strdup(), use mem_strdup() explicitly
This fixes a nasty bug that manifests on windows when building without
precompiled headers. util/stringops.h used to silently replace strdup
with a macro that's compatible with mem_free(). This header would
typically be included everywhere due to PCH, but without it the strdup
from libc would sometimes be in scope. On most platforms mem_free() is
equivalent to free(), but not on windows, because we have to use
_aligned_free() there. Attempting to mem_free() the result of a libc
strdup() would segfault in such a configuration.

Avoid the footgun by banning strdup() entirely. Maybe redefining libc
names isn't such a great idea, who knew?
2024-09-10 14:31:55 +02:00

163 lines
3.9 KiB
C

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
*/
#include "shader_object.h"
#include "../glcommon/debug.h"
#include "../glcommon/shaders.h"
bool gl33_shader_language_supported(const ShaderLangInfo *lang, ShaderLangInfo *out_alternative) {
if(glcommon_shader_lang_table.data) {
dynarray_foreach_elem(&glcommon_shader_lang_table, ShaderLangInfo *l, {
if(!memcmp(l, lang, sizeof(*l))) {
return true;
}
});
if(out_alternative) {
*out_alternative = dynarray_get(&glcommon_shader_lang_table, 0);
}
return false;
}
// No table. Should never actually happen, but let's just hope it works, right?
bool supported = lang->lang == SHLANG_GLSL;
if(!supported && out_alternative) {
out_alternative->lang = SHLANG_GLSL;
out_alternative->glsl.version.version = 330;
out_alternative->glsl.version.profile = GLSL_PROFILE_CORE;
}
return supported;
}
static void print_info_log(GLuint shader) {
GLint len = 0, alen = 0;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &len);
if(len > 1) {
char log[len];
memset(log, 0, len);
glGetShaderInfoLog(shader, len, &alen, log);
log_warn(
"\n== Shader object compilation log (%u) ==\n%s\n== End of shader object compilation log (%u) ==",
shader, log, shader
);
}
}
ShaderObject *gl33_shader_object_compile(ShaderSource *source) {
assert(r_shader_language_supported(&source->lang, NULL));
GLuint gl_handle = glCreateShader(
source->stage == SHADER_STAGE_VERTEX
? GL_VERTEX_SHADER
: GL_FRAGMENT_SHADER
);
GLint status;
// log_debug("Source code for %s:\n%s", path, source->content);
glShaderSource(
gl_handle, 1,
(const GLchar*[]) { source->content },
(GLint[]) { source->content_size - 1 }
);
glCompileShader(gl_handle);
#if defined DEBUG && !defined STATIC_GLES3
if(GLAD_GL_ANGLE_translated_shader_source) {
GLint srclen;
glGetShaderiv(gl_handle, GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE, &srclen);
if(srclen > 0) {
char buf[srclen];
glGetTranslatedShaderSourceANGLE(gl_handle, sizeof(buf), NULL, buf);
log_debug("Final shader source (as translated by ANGLE):\n%s", buf);
}
}
#endif
glGetShaderiv(gl_handle, GL_COMPILE_STATUS, &status);
print_info_log(gl_handle);
ShaderObject *shobj = NULL;
if(status) {
uint nattribs = source->meta.glsl.num_attributes;
shobj = ALLOC(ShaderObject, {
.gl_handle = gl_handle,
.stage = source->stage,
.num_attribs = nattribs,
});
snprintf(shobj->debug_label, sizeof(shobj->debug_label), "Shader object #%i", gl_handle);
if(nattribs > 0) {
shobj->attribs = ALLOC_ARRAY(nattribs, typeof(*shobj->attribs));
}
for(uint i = 0; i < nattribs; ++i) {
GLSLAttribute *a = source->meta.glsl.attributes + i;
shobj->attribs[i].name = mem_strdup(a->name);
shobj->attribs[i].location = a->location;
}
} else {
glDeleteShader(gl_handle);
}
return shobj;
}
void gl33_shader_object_destroy(ShaderObject *shobj) {
glDeleteShader(shobj->gl_handle);
uint nattribs = shobj->num_attribs;
for(uint i = 0; i < nattribs; ++i) {
mem_free(shobj->attribs[i].name);
}
mem_free(shobj->attribs);
mem_free(shobj);
}
void gl33_shader_object_set_debug_label(ShaderObject *shobj, const char *label) {
glcommon_set_debug_label(shobj->debug_label, "Shader object", GL_SHADER, shobj->gl_handle, label);
}
const char *gl33_shader_object_get_debug_label(ShaderObject *shobj) {
return shobj->debug_label;
}
bool gl33_shader_object_transfer(ShaderObject *dst, ShaderObject *src) {
if(UNLIKELY(dst->stage != src->stage)) {
log_error("Shader object changed stage");
return false;
}
glDeleteShader(dst->gl_handle);
uint nattribs = dst->num_attribs;
for(uint i = 0; i < nattribs; ++i) {
mem_free(dst->attribs[i].name);
}
mem_free(dst->attribs);
*dst = *src;
mem_free(src);
return true;
}