(GLSL) Allocate struct dynamically for shader glsl backend

This commit is contained in:
twinaphex 2014-10-26 06:16:30 +01:00
parent 6c193836a5
commit a5a9d914b1
1 changed files with 296 additions and 220 deletions

View File

@ -42,23 +42,6 @@
#define PREV_TEXTURES (MAX_TEXTURES - 1) #define PREV_TEXTURES (MAX_TEXTURES - 1)
static struct gfx_shader *glsl_shader;
static bool glsl_core;
static unsigned glsl_major;
static unsigned glsl_minor;
static bool glsl_enable;
static GLuint gl_program[GFX_MAX_SHADERS];
static unsigned glsl_active_index;
static GLuint gl_teximage[GFX_MAX_TEXTURES];
static state_tracker_t *gl_state_tracker;
static GLint gl_attribs[PREV_TEXTURES + 1 + 4 + GFX_MAX_SHADERS];
static unsigned gl_attrib_index;
static char glsl_alias_define[1024];
/* Cache the VBO. */ /* Cache the VBO. */
struct cache_vbo struct cache_vbo
@ -71,7 +54,6 @@ struct cache_vbo
GLfloat *buffer_secondary; GLfloat *buffer_secondary;
size_t size_secondary; size_t size_secondary;
}; };
static struct cache_vbo glsl_vbo[GFX_MAX_SHADERS];
struct glsl_attrib struct glsl_attrib
{ {
@ -113,7 +95,6 @@ struct shader_uniforms
struct shader_uniforms_frame prev[PREV_TEXTURES]; struct shader_uniforms_frame prev[PREV_TEXTURES];
}; };
static struct shader_uniforms gl_uniforms[GFX_MAX_SHADERS];
static const char *glsl_prefixes[] = { static const char *glsl_prefixes[] = {
"", "",
@ -223,12 +204,30 @@ static const char *stock_fragment_core_blend =
" FragColor = color * texture(Texture, tex_coord);\n" " FragColor = color * texture(Texture, tex_coord);\n"
"}"; "}";
static GLint get_uniform(GLuint prog, const char *base) typedef struct glsl_shader_data
{
struct gfx_shader *glsl_shader;
struct shader_uniforms gl_uniforms[GFX_MAX_SHADERS];
struct cache_vbo glsl_vbo[GFX_MAX_SHADERS];
bool glsl_core;
char glsl_alias_define[1024];
unsigned glsl_major;
unsigned glsl_minor;
unsigned glsl_active_index;
unsigned gl_attrib_index;
GLuint gl_program[GFX_MAX_SHADERS];
GLuint gl_teximage[GFX_MAX_TEXTURES];
GLint gl_attribs[PREV_TEXTURES + 1 + 4 + GFX_MAX_SHADERS];
state_tracker_t *gl_state_tracker;
} glsl_shader_data_t;
static GLint get_uniform(glsl_shader_data_t *glsl,
GLuint prog, const char *base)
{ {
unsigned i; unsigned i;
char buf[64]; char buf[64];
snprintf(buf, sizeof(buf), "%s%s", glsl_shader->prefix, base); snprintf(buf, sizeof(buf), "%s%s", glsl->glsl_shader->prefix, base);
GLint loc = glGetUniformLocation(prog, buf); GLint loc = glGetUniformLocation(prog, buf);
if (loc >= 0) if (loc >= 0)
return loc; return loc;
@ -244,11 +243,12 @@ static GLint get_uniform(GLuint prog, const char *base)
return -1; return -1;
} }
static GLint get_attrib(GLuint prog, const char *base) static GLint get_attrib(glsl_shader_data_t *glsl,
GLuint prog, const char *base)
{ {
unsigned i; unsigned i;
char buf[64]; char buf[64];
snprintf(buf, sizeof(buf), "%s%s", glsl_shader->prefix, base); snprintf(buf, sizeof(buf), "%s%s", glsl->glsl_shader->prefix, base);
GLint loc = glGetUniformLocation(prog, buf); GLint loc = glGetUniformLocation(prog, buf);
if (loc >= 0) if (loc >= 0)
return loc; return loc;
@ -308,27 +308,36 @@ static void print_linker_log(GLuint obj)
free(info_log); free(info_log);
} }
static bool compile_shader(GLuint shader, static bool compile_shader(glsl_shader_data_t *glsl,
GLuint shader,
const char *define, const char *program) const char *define, const char *program)
{ {
char version[32] = {0}; char version[32] = {0};
if (glsl_core && !strstr(program, "#version")) if (glsl->glsl_core && !strstr(program, "#version"))
{ {
unsigned version_no = 0; unsigned version_no = 0;
unsigned gl_ver = glsl_major * 100 + glsl_minor * 10; unsigned gl_ver = glsl->glsl_major * 100 + glsl->glsl_minor * 10;
switch (gl_ver) switch (gl_ver)
{ {
case 300: version_no = 130; break; case 300:
case 310: version_no = 140; break; version_no = 130;
case 320: version_no = 150; break; break;
default: version_no = gl_ver; break; case 310:
version_no = 140;
break;
case 320:
version_no = 150;
break;
default:
version_no = gl_ver;
break;
} }
snprintf(version, sizeof(version), "#version %u\n", version_no); snprintf(version, sizeof(version), "#version %u\n", version_no);
RARCH_LOG("[GL]: Using GLSL version %u.\n", version_no); RARCH_LOG("[GL]: Using GLSL version %u.\n", version_no);
} }
const char *source[] = { version, define, glsl_alias_define, program }; const char *source[] = { version, define, glsl->glsl_alias_define, program };
glShaderSource(shader, ARRAY_SIZE(source), source, NULL); glShaderSource(shader, ARRAY_SIZE(source), source, NULL);
glCompileShader(shader); glCompileShader(shader);
@ -355,7 +364,8 @@ static bool link_program(GLuint prog)
return false; return false;
} }
static GLuint compile_program(const char *vertex, static GLuint compile_program(glsl_shader_data_t *glsl,
const char *vertex,
const char *fragment, unsigned i) const char *fragment, unsigned i)
{ {
GLuint prog = glCreateProgram(); GLuint prog = glCreateProgram();
@ -370,6 +380,7 @@ static GLuint compile_program(const char *vertex,
RARCH_LOG("Found GLSL vertex shader.\n"); RARCH_LOG("Found GLSL vertex shader.\n");
vert = glCreateShader(GL_VERTEX_SHADER); vert = glCreateShader(GL_VERTEX_SHADER);
if (!compile_shader( if (!compile_shader(
glsl,
vert, "#define VERTEX\n#define PARAMETER_UNIFORM\n", vertex)) vert, "#define VERTEX\n#define PARAMETER_UNIFORM\n", vertex))
{ {
RARCH_ERR("Failed to compile vertex shader #%u\n", i); RARCH_ERR("Failed to compile vertex shader #%u\n", i);
@ -383,7 +394,7 @@ static GLuint compile_program(const char *vertex,
{ {
RARCH_LOG("Found GLSL fragment shader.\n"); RARCH_LOG("Found GLSL fragment shader.\n");
frag = glCreateShader(GL_FRAGMENT_SHADER); frag = glCreateShader(GL_FRAGMENT_SHADER);
if (!compile_shader(frag, if (!compile_shader(glsl, frag,
"#define FRAGMENT\n#define PARAMETER_UNIFORM\n", fragment)) "#define FRAGMENT\n#define PARAMETER_UNIFORM\n", fragment))
{ {
RARCH_ERR("Failed to compile fragment shader #%u\n", i); RARCH_ERR("Failed to compile fragment shader #%u\n", i);
@ -411,7 +422,7 @@ static GLuint compile_program(const char *vertex,
glDeleteShader(frag); glDeleteShader(frag);
glUseProgram(prog); glUseProgram(prog);
GLint location = get_uniform(prog, "Texture"); GLint location = get_uniform(glsl, prog, "Texture");
glUniform1i(location, 0); glUniform1i(location, 0);
glUseProgram(0); glUseProgram(0);
} }
@ -429,12 +440,13 @@ static bool load_source_path(struct gfx_shader_pass *pass,
return pass->source.string.fragment && pass->source.string.vertex; return pass->source.string.fragment && pass->source.string.vertex;
} }
static bool compile_programs(GLuint *gl_prog) static bool compile_programs(glsl_shader_data_t *glsl, GLuint *gl_prog)
{ {
unsigned i; unsigned i;
for (i = 0; i < glsl_shader->passes; i++) for (i = 0; i < glsl->glsl_shader->passes; i++)
{ {
struct gfx_shader_pass *pass = &glsl_shader->pass[i]; struct gfx_shader_pass *pass = (struct gfx_shader_pass*)
&glsl->glsl_shader->pass[i];
/* If we load from GLSLP (CGP), /* If we load from GLSLP (CGP),
* load the file here, and pretend * load the file here, and pretend
@ -450,7 +462,7 @@ static bool compile_programs(GLuint *gl_prog)
const char *vertex = pass->source.string.vertex; const char *vertex = pass->source.string.vertex;
const char *fragment = pass->source.string.fragment; const char *fragment = pass->source.string.fragment;
gl_prog[i] = compile_program(vertex, fragment, i); gl_prog[i] = compile_program(glsl, vertex, fragment, i);
if (!gl_prog[i]) if (!gl_prog[i])
{ {
@ -462,15 +474,15 @@ static bool compile_programs(GLuint *gl_prog)
return true; return true;
} }
static void gl_glsl_reset_attrib(void) static void gl_glsl_reset_attrib(glsl_shader_data_t *glsl)
{ {
unsigned i; unsigned i;
/* Add sanity check that we did not overflow. */ /* Add sanity check that we did not overflow. */
rarch_assert(gl_attrib_index <= ARRAY_SIZE(gl_attribs)); rarch_assert(glsl->gl_attrib_index <= ARRAY_SIZE(glsl->gl_attribs));
for (i = 0; i < gl_attrib_index; i++) for (i = 0; i < glsl->gl_attrib_index; i++)
glDisableVertexAttribArray(gl_attribs[i]); glDisableVertexAttribArray(glsl->gl_attribs[i]);
gl_attrib_index = 0; glsl->gl_attrib_index = 0;
} }
static void gl_glsl_set_vbo(GLfloat **buffer, size_t *buffer_elems, static void gl_glsl_set_vbo(GLfloat **buffer, size_t *buffer_elems,
@ -494,7 +506,8 @@ static void gl_glsl_set_vbo(GLfloat **buffer, size_t *buffer_elems,
} }
} }
static void gl_glsl_set_attribs(GLuint vbo, static void gl_glsl_set_attribs(glsl_shader_data_t *glsl,
GLuint vbo,
GLfloat **buffer, size_t *buffer_elems, GLfloat **buffer, size_t *buffer_elems,
const GLfloat *data, size_t elems, const GLfloat *data, size_t elems,
const struct glsl_attrib *attrs, size_t num_attrs) const struct glsl_attrib *attrs, size_t num_attrs)
@ -508,12 +521,12 @@ static void gl_glsl_set_attribs(GLuint vbo,
{ {
GLint loc = attrs[i].loc; GLint loc = attrs[i].loc;
if (gl_attrib_index < ARRAY_SIZE(gl_attribs)) if (glsl->gl_attrib_index < ARRAY_SIZE(glsl->gl_attribs))
{ {
glEnableVertexAttribArray(loc); glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, attrs[i].size, GL_FLOAT, GL_FALSE, 0, glVertexAttribPointer(loc, attrs[i].size, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*)(uintptr_t)attrs[i].offset); (const GLvoid*)(uintptr_t)attrs[i].offset);
gl_attribs[gl_attrib_index++] = loc; glsl->gl_attribs[glsl->gl_attrib_index++] = loc;
} }
else else
RARCH_WARN("Attrib array buffer was overflown!\n"); RARCH_WARN("Attrib array buffer was overflown!\n");
@ -530,7 +543,8 @@ static void clear_uniforms_frame(struct shader_uniforms_frame *frame)
frame->tex_coord = -1; frame->tex_coord = -1;
} }
static void find_uniforms_frame(GLuint prog, static void find_uniforms_frame(glsl_shader_data_t *glsl,
GLuint prog,
struct shader_uniforms_frame *frame, const char *base) struct shader_uniforms_frame *frame, const char *base)
{ {
char texture[64]; char texture[64];
@ -544,132 +558,157 @@ static void find_uniforms_frame(GLuint prog,
snprintf(tex_coord, sizeof(tex_coord), "%s%s", base, "TexCoord"); snprintf(tex_coord, sizeof(tex_coord), "%s%s", base, "TexCoord");
if (frame->texture < 0) if (frame->texture < 0)
frame->texture = get_uniform(prog, texture); frame->texture = get_uniform(glsl, prog, texture);
if (frame->texture_size < 0) if (frame->texture_size < 0)
frame->texture_size = get_uniform(prog, texture_size); frame->texture_size = get_uniform(glsl, prog, texture_size);
if (frame->input_size < 0) if (frame->input_size < 0)
frame->input_size = get_uniform(prog, input_size); frame->input_size = get_uniform(glsl, prog, input_size);
if (frame->tex_coord < 0) if (frame->tex_coord < 0)
frame->tex_coord = get_attrib(prog, tex_coord); frame->tex_coord = get_attrib(glsl, prog, tex_coord);
} }
static void find_uniforms(unsigned pass, GLuint prog, static void find_uniforms(glsl_shader_data_t *glsl,
unsigned pass, GLuint prog,
struct shader_uniforms *uni) struct shader_uniforms *uni)
{ {
unsigned i; unsigned i;
glUseProgram(prog); glUseProgram(prog);
uni->mvp = get_uniform(prog, "MVPMatrix"); uni->mvp = get_uniform(glsl, prog, "MVPMatrix");
uni->tex_coord = get_attrib(prog, "TexCoord"); uni->tex_coord = get_attrib(glsl, prog, "TexCoord");
uni->vertex_coord = get_attrib(prog, "VertexCoord"); uni->vertex_coord = get_attrib(glsl, prog, "VertexCoord");
uni->color = get_attrib(prog, "Color"); uni->color = get_attrib(glsl, prog, "Color");
uni->lut_tex_coord = get_attrib(prog, "LUTTexCoord"); uni->lut_tex_coord = get_attrib(glsl, prog, "LUTTexCoord");
uni->input_size = get_uniform(prog, "InputSize"); uni->input_size = get_uniform(glsl, prog, "InputSize");
uni->output_size = get_uniform(prog, "OutputSize"); uni->output_size = get_uniform(glsl, prog, "OutputSize");
uni->texture_size = get_uniform(prog, "TextureSize"); uni->texture_size = get_uniform(glsl, prog, "TextureSize");
uni->frame_count = get_uniform(prog, "FrameCount"); uni->frame_count = get_uniform(glsl, prog, "FrameCount");
uni->frame_direction = get_uniform(prog, "FrameDirection"); uni->frame_direction = get_uniform(glsl, prog, "FrameDirection");
for (i = 0; i < glsl_shader->luts; i++) for (i = 0; i < glsl->glsl_shader->luts; i++)
uni->lut_texture[i] = glGetUniformLocation(prog, glsl_shader->lut[i].id); uni->lut_texture[i] = glGetUniformLocation(prog, glsl->glsl_shader->lut[i].id);
char frame_base[64]; char frame_base[64];
clear_uniforms_frame(&uni->orig); clear_uniforms_frame(&uni->orig);
find_uniforms_frame(prog, &uni->orig, "Orig"); find_uniforms_frame(glsl, prog, &uni->orig, "Orig");
if (pass > 1) if (pass > 1)
{ {
snprintf(frame_base, sizeof(frame_base), "PassPrev%u", pass); snprintf(frame_base, sizeof(frame_base), "PassPrev%u", pass);
find_uniforms_frame(prog, &uni->orig, frame_base); find_uniforms_frame(glsl, prog, &uni->orig, frame_base);
} }
for (i = 0; i + 1 < pass; i++) for (i = 0; i + 1 < pass; i++)
{ {
snprintf(frame_base, sizeof(frame_base), "Pass%u", i + 1); snprintf(frame_base, sizeof(frame_base), "Pass%u", i + 1);
clear_uniforms_frame(&uni->pass[i]); clear_uniforms_frame(&uni->pass[i]);
find_uniforms_frame(prog, &uni->pass[i], frame_base); find_uniforms_frame(glsl, prog, &uni->pass[i], frame_base);
snprintf(frame_base, sizeof(frame_base), "PassPrev%u", pass - (i + 1)); snprintf(frame_base, sizeof(frame_base), "PassPrev%u", pass - (i + 1));
find_uniforms_frame(prog, &uni->pass[i], frame_base); find_uniforms_frame(glsl, prog, &uni->pass[i], frame_base);
if (*glsl_shader->pass[i].alias) if (*glsl->glsl_shader->pass[i].alias)
find_uniforms_frame(prog, &uni->pass[i], glsl_shader->pass[i].alias); find_uniforms_frame(glsl, prog, &uni->pass[i], glsl->glsl_shader->pass[i].alias);
} }
clear_uniforms_frame(&uni->prev[0]); clear_uniforms_frame(&uni->prev[0]);
find_uniforms_frame(prog, &uni->prev[0], "Prev"); find_uniforms_frame(glsl, prog, &uni->prev[0], "Prev");
for (i = 1; i < PREV_TEXTURES; i++) for (i = 1; i < PREV_TEXTURES; i++)
{ {
snprintf(frame_base, sizeof(frame_base), "Prev%u", i); snprintf(frame_base, sizeof(frame_base), "Prev%u", i);
clear_uniforms_frame(&uni->prev[i]); clear_uniforms_frame(&uni->prev[i]);
find_uniforms_frame(prog, &uni->prev[i], frame_base); find_uniforms_frame(glsl, prog, &uni->prev[i], frame_base);
} }
glUseProgram(0); glUseProgram(0);
} }
static void gl_glsl_free_shader(void) static void gl_glsl_deinit_shader(glsl_shader_data_t *glsl)
{ {
unsigned i; unsigned i;
if (!glsl_shader) if (!glsl || !glsl->glsl_shader)
return; return;
for (i = 0; i < glsl_shader->passes; i++) for (i = 0; i < glsl->glsl_shader->passes; i++)
{ {
free(glsl_shader->pass[i].source.string.vertex); free(glsl->glsl_shader->pass[i].source.string.vertex);
free(glsl_shader->pass[i].source.string.fragment); free(glsl->glsl_shader->pass[i].source.string.fragment);
} }
free(glsl_shader->script); free(glsl->glsl_shader->script);
free(glsl_shader); free(glsl->glsl_shader);
glsl_shader = NULL; glsl->glsl_shader = NULL;
}
static void gl_glsl_destroy_resources(glsl_shader_data_t *glsl)
{
unsigned i;
if (!glsl)
return;
glUseProgram(0);
for (i = 0; i < GFX_MAX_SHADERS; i++)
{
if (glsl->gl_program[i] == 0 || (i && glsl->gl_program[i] == glsl->gl_program[0]))
continue;
glDeleteProgram(glsl->gl_program[i]);
}
if (glsl->glsl_shader && glsl->glsl_shader->luts)
glDeleteTextures(glsl->glsl_shader->luts, glsl->gl_teximage);
memset(glsl->gl_program, 0, sizeof(glsl->gl_program));
memset(glsl->gl_uniforms, 0, sizeof(glsl->gl_uniforms));
glsl->glsl_active_index = 0;
gl_glsl_deinit_shader(glsl);
if (glsl->gl_state_tracker)
state_tracker_free(glsl->gl_state_tracker);
glsl->gl_state_tracker = NULL;
gl_glsl_reset_attrib(glsl);
for (i = 0; i < GFX_MAX_SHADERS; i++)
{
if (glsl->glsl_vbo[i].vbo_primary)
glDeleteBuffers(1, &glsl->glsl_vbo[i].vbo_primary);
if (glsl->glsl_vbo[i].vbo_secondary)
glDeleteBuffers(1, &glsl->glsl_vbo[i].vbo_secondary);
free(glsl->glsl_vbo[i].buffer_primary);
free(glsl->glsl_vbo[i].buffer_secondary);
}
memset(&glsl->glsl_vbo, 0, sizeof(glsl->glsl_vbo));
} }
static void gl_glsl_deinit(void) static void gl_glsl_deinit(void)
{ {
unsigned i; glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
glUseProgram(0);
for (i = 0; i < GFX_MAX_SHADERS; i++)
{
if (gl_program[i] == 0 || (i && gl_program[i] == gl_program[0]))
continue;
glDeleteProgram(gl_program[i]); if (!glsl)
} return;
if (glsl_shader && glsl_shader->luts) gl_glsl_destroy_resources(glsl);
glDeleteTextures(glsl_shader->luts, gl_teximage);
memset(gl_program, 0, sizeof(gl_program)); if (driver.video_shader_data)
memset(gl_uniforms, 0, sizeof(gl_uniforms)); free(driver.video_shader_data);
glsl_enable = false; driver.video_shader_data = NULL;
glsl_active_index = 0;
gl_glsl_free_shader();
if (gl_state_tracker)
state_tracker_free(gl_state_tracker);
gl_state_tracker = NULL;
gl_glsl_reset_attrib();
for (i = 0; i < GFX_MAX_SHADERS; i++)
{
if (glsl_vbo[i].vbo_primary)
glDeleteBuffers(1, &glsl_vbo[i].vbo_primary);
if (glsl_vbo[i].vbo_secondary)
glDeleteBuffers(1, &glsl_vbo[i].vbo_secondary);
free(glsl_vbo[i].buffer_primary);
free(glsl_vbo[i].buffer_secondary);
}
memset(&glsl_vbo, 0, sizeof(glsl_vbo));
} }
static bool gl_glsl_init(void *data, const char *path) static bool gl_glsl_init(void *data, const char *path)
{ {
unsigned i; unsigned i;
config_file_t *conf = NULL;
glsl_shader_data_t *glsl = NULL;
(void)data; (void)data;
glsl = (glsl_shader_data_t*)calloc(1, sizeof(glsl_shader_data_t));
if (!glsl)
return false;
#ifndef HAVE_OPENGLES2 #ifndef HAVE_OPENGLES2
RARCH_LOG("Checking GLSL shader support ...\n"); RARCH_LOG("Checking GLSL shader support ...\n");
bool shader_support = glCreateProgram && glUseProgram && glCreateShader bool shader_support = glCreateProgram && glUseProgram && glCreateShader
@ -688,25 +727,24 @@ static bool gl_glsl_init(void *data, const char *path)
if (!shader_support) if (!shader_support)
{ {
RARCH_ERR("GLSL shaders aren't supported by your OpenGL driver.\n"); RARCH_ERR("GLSL shaders aren't supported by your OpenGL driver.\n");
free(glsl);
return false; return false;
} }
#endif #endif
glsl_shader = (struct gfx_shader*)calloc(1, sizeof(*glsl_shader)); glsl->glsl_shader = (struct gfx_shader*)calloc(1, sizeof(*glsl->glsl_shader));
if (!glsl_shader) if (!glsl->glsl_shader)
return false; return false;
config_file_t *conf = NULL;
if (path) if (path)
{ {
bool ret; bool ret;
if (strcmp(path_get_extension(path), "glsl") == 0) if (strcmp(path_get_extension(path), "glsl") == 0)
{ {
strlcpy(glsl_shader->pass[0].source.path, path, strlcpy(glsl->glsl_shader->pass[0].source.path, path,
sizeof(glsl_shader->pass[0].source.path)); sizeof(glsl->glsl_shader->pass[0].source.path));
glsl_shader->passes = 1; glsl->glsl_shader->passes = 1;
glsl_shader->modern = true; glsl->glsl_shader->modern = true;
ret = true; ret = true;
} }
else if (strcmp(path_get_extension(path), "glslp") == 0) else if (strcmp(path_get_extension(path), "glslp") == 0)
@ -714,8 +752,8 @@ static bool gl_glsl_init(void *data, const char *path)
conf = config_file_new(path); conf = config_file_new(path);
if (conf) if (conf)
{ {
ret = gfx_shader_read_conf_cgp(conf, glsl_shader); ret = gfx_shader_read_conf_cgp(conf, glsl->glsl_shader);
glsl_shader->modern = true; glsl->glsl_shader->modern = true;
} }
else else
ret = false; ret = false;
@ -732,16 +770,16 @@ static bool gl_glsl_init(void *data, const char *path)
else else
{ {
RARCH_WARN("[GL]: Stock GLSL shaders will be used.\n"); RARCH_WARN("[GL]: Stock GLSL shaders will be used.\n");
glsl_shader->passes = 1; glsl->glsl_shader->passes = 1;
glsl_shader->pass[0].source.string.vertex = glsl->glsl_shader->pass[0].source.string.vertex =
strdup(glsl_core ? stock_vertex_core : stock_vertex_modern); strdup(glsl->glsl_core ? stock_vertex_core : stock_vertex_modern);
glsl_shader->pass[0].source.string.fragment = glsl->glsl_shader->pass[0].source.string.fragment =
strdup(glsl_core ? stock_fragment_core : stock_fragment_modern); strdup(glsl->glsl_core ? stock_fragment_core : stock_fragment_modern);
glsl_shader->modern = true; glsl->glsl_shader->modern = true;
} }
gfx_shader_resolve_relative(glsl_shader, path); gfx_shader_resolve_relative(glsl->glsl_shader, path);
gfx_shader_resolve_parameters(conf, glsl_shader); gfx_shader_resolve_parameters(conf, glsl->glsl_shader);
if (conf) if (conf)
{ {
@ -749,25 +787,25 @@ static bool gl_glsl_init(void *data, const char *path)
conf = NULL; conf = NULL;
} }
const char *stock_vertex = glsl_shader->modern ? const char *stock_vertex = glsl->glsl_shader->modern ?
stock_vertex_modern : stock_vertex_legacy; stock_vertex_modern : stock_vertex_legacy;
const char *stock_fragment = glsl_shader->modern ? const char *stock_fragment = glsl->glsl_shader->modern ?
stock_fragment_modern : stock_fragment_legacy; stock_fragment_modern : stock_fragment_legacy;
if (glsl_core) if (glsl->glsl_core)
{ {
stock_vertex = stock_vertex_core; stock_vertex = stock_vertex_core;
stock_fragment = stock_fragment_core; stock_fragment = stock_fragment_core;
} }
#ifdef HAVE_OPENGLES2 #ifdef HAVE_OPENGLES2
if (!glsl_shader->modern) if (!glsl->glsl_shader->modern)
{ {
RARCH_ERR("[GL]: GLES context is used, but shader is not modern. Cannot use it.\n"); RARCH_ERR("[GL]: GLES context is used, but shader is not modern. Cannot use it.\n");
goto error; goto error;
} }
#else #else
if (glsl_core && !glsl_shader->modern) if (glsl->glsl_core && !glsl->glsl_shader->modern)
{ {
RARCH_ERR("[GL]: GL core context is used, but shader is not core compatible. Cannot use it.\n"); RARCH_ERR("[GL]: GL core context is used, but shader is not core compatible. Cannot use it.\n");
goto error; goto error;
@ -776,91 +814,98 @@ static bool gl_glsl_init(void *data, const char *path)
/* Find all aliases we use in our GLSLP and add #defines for them so /* Find all aliases we use in our GLSLP and add #defines for them so
* that a shader can choose a fallback if we are not using a preset. */ * that a shader can choose a fallback if we are not using a preset. */
*glsl_alias_define = '\0'; *glsl->glsl_alias_define = '\0';
for (i = 0; i < glsl_shader->passes; i++) for (i = 0; i < glsl->glsl_shader->passes; i++)
{ {
if (*glsl_shader->pass[i].alias) if (*glsl->glsl_shader->pass[i].alias)
{ {
char define[128]; char define[128];
snprintf(define, sizeof(define), "#define %s_ALIAS\n", snprintf(define, sizeof(define), "#define %s_ALIAS\n",
glsl_shader->pass[i].alias); glsl->glsl_shader->pass[i].alias);
strlcat(glsl_alias_define, define, sizeof(glsl_alias_define)); strlcat(glsl->glsl_alias_define, define, sizeof(glsl->glsl_alias_define));
} }
} }
if (!(gl_program[0] = compile_program(stock_vertex, stock_fragment, 0))) if (!(glsl->gl_program[0] = compile_program(glsl, stock_vertex, stock_fragment, 0)))
{ {
RARCH_ERR("GLSL stock programs failed to compile.\n"); RARCH_ERR("GLSL stock programs failed to compile.\n");
goto error; goto error;
} }
if (!compile_programs(&gl_program[1])) if (!compile_programs(glsl, &glsl->gl_program[1]))
goto error; goto error;
if (!gl_load_luts(glsl_shader, gl_teximage)) if (!gl_load_luts(glsl->glsl_shader, glsl->gl_teximage))
{ {
RARCH_ERR("[GL]: Failed to load LUTs.\n"); RARCH_ERR("[GL]: Failed to load LUTs.\n");
goto error; goto error;
} }
for (i = 0; i <= glsl_shader->passes; i++) for (i = 0; i <= glsl->glsl_shader->passes; i++)
find_uniforms(i, gl_program[i], &gl_uniforms[i]); find_uniforms(glsl, i, glsl->gl_program[i], &glsl->gl_uniforms[i]);
#ifdef GLSL_DEBUG #ifdef GLSL_DEBUG
if (!gl_check_error()) if (!gl_check_error())
RARCH_WARN("Detected GL error in GLSL.\n"); RARCH_WARN("Detected GL error in GLSL.\n");
#endif #endif
if (glsl_shader->variables) if (glsl->glsl_shader->variables)
{ {
struct state_tracker_info info = {0}; struct state_tracker_info info = {0};
info.wram = (uint8_t*)pretro_get_memory_data(RETRO_MEMORY_SYSTEM_RAM); info.wram = (uint8_t*)pretro_get_memory_data(RETRO_MEMORY_SYSTEM_RAM);
info.info = glsl_shader->variable; info.info = glsl->glsl_shader->variable;
info.info_elem = glsl_shader->variables; info.info_elem = glsl->glsl_shader->variables;
#ifdef HAVE_PYTHON #ifdef HAVE_PYTHON
info.script = glsl_shader->script; info.script = glsl->glsl_shader->script;
info.script_class = *glsl_shader->script_class ? info.script_class = *glsl->glsl_shader->script_class ?
glsl_shader->script_class : NULL; glsl->glsl_shader->script_class : NULL;
#endif #endif
gl_state_tracker = state_tracker_init(&info); glsl->gl_state_tracker = state_tracker_init(&info);
if (!gl_state_tracker) if (!glsl->gl_state_tracker)
RARCH_WARN("Failed to init state tracker.\n"); RARCH_WARN("Failed to init state tracker.\n");
} }
glsl_enable = true; glsl->gl_program[glsl->glsl_shader->passes + 1] = glsl->gl_program[0];
gl_program[glsl_shader->passes + 1] = gl_program[0]; glsl->gl_uniforms[glsl->glsl_shader->passes + 1] = glsl->gl_uniforms[0];
gl_uniforms[glsl_shader->passes + 1] = gl_uniforms[0];
if (glsl_shader->modern) if (glsl->glsl_shader->modern)
{ {
gl_program[GL_SHADER_STOCK_BLEND] = compile_program(glsl_core ? glsl->gl_program[GL_SHADER_STOCK_BLEND] = compile_program(
glsl,
glsl->glsl_core ?
stock_vertex_core_blend : stock_vertex_modern_blend, stock_vertex_core_blend : stock_vertex_modern_blend,
glsl_core ? glsl->glsl_core ?
stock_fragment_core_blend : stock_fragment_modern_blend, stock_fragment_core_blend : stock_fragment_modern_blend,
GL_SHADER_STOCK_BLEND); GL_SHADER_STOCK_BLEND);
find_uniforms(0, gl_program[GL_SHADER_STOCK_BLEND], find_uniforms(glsl, 0, glsl->gl_program[GL_SHADER_STOCK_BLEND],
&gl_uniforms[GL_SHADER_STOCK_BLEND]); &glsl->gl_uniforms[GL_SHADER_STOCK_BLEND]);
} }
else else
{ {
gl_program[GL_SHADER_STOCK_BLEND] = gl_program[0]; glsl->gl_program [GL_SHADER_STOCK_BLEND] = glsl->gl_program[0];
gl_uniforms[GL_SHADER_STOCK_BLEND] = gl_uniforms[0]; glsl->gl_uniforms[GL_SHADER_STOCK_BLEND] = glsl->gl_uniforms[0];
} }
gl_glsl_reset_attrib(); gl_glsl_reset_attrib(glsl);
for (i = 0; i < GFX_MAX_SHADERS; i++) for (i = 0; i < GFX_MAX_SHADERS; i++)
{ {
glGenBuffers(1, &glsl_vbo[i].vbo_primary); glGenBuffers(1, &glsl->glsl_vbo[i].vbo_primary);
glGenBuffers(1, &glsl_vbo[i].vbo_secondary); glGenBuffers(1, &glsl->glsl_vbo[i].vbo_secondary);
} }
driver.video_shader_data = glsl;
return true; return true;
error: error:
gl_glsl_deinit(); gl_glsl_destroy_resources(glsl);
if (glsl)
free(glsl);
return false; return false;
} }
@ -875,17 +920,22 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height,
GLfloat buffer[512]; GLfloat buffer[512];
struct glsl_attrib attribs[32]; struct glsl_attrib attribs[32];
unsigned i; unsigned i;
const struct shader_uniforms *uni = NULL;
size_t size = 0, attribs_size = 0; size_t size = 0, attribs_size = 0;
const struct gl_tex_info *info = (const struct gl_tex_info*)_info; const struct gl_tex_info *info = (const struct gl_tex_info*)_info;
const struct gl_tex_info *prev_info = (const struct gl_tex_info*)_prev_info; const struct gl_tex_info *prev_info = (const struct gl_tex_info*)_prev_info;
const struct gl_tex_info *fbo_info = (const struct gl_tex_info*)_fbo_info; const struct gl_tex_info *fbo_info = (const struct gl_tex_info*)_fbo_info;
struct glsl_attrib *attr = (struct glsl_attrib*)attribs; struct glsl_attrib *attr = (struct glsl_attrib*)attribs;
const struct shader_uniforms *uni = (const struct shader_uniforms*) glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
&gl_uniforms[glsl_active_index];
if (!glsl)
return;
uni = (const struct shader_uniforms*)&glsl->gl_uniforms[glsl->glsl_active_index];
(void)data; (void)data;
if (!glsl_enable || (gl_program[glsl_active_index] == 0)) if (!glsl || (glsl->gl_program[glsl->glsl_active_index] == 0))
return; return;
float input_size[2] = {(float)width, (float)height}; float input_size[2] = {(float)width, (float)height};
@ -901,9 +951,9 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height,
if (uni->texture_size >= 0) if (uni->texture_size >= 0)
glUniform2fv(uni->texture_size, 1, texture_size); glUniform2fv(uni->texture_size, 1, texture_size);
if (uni->frame_count >= 0 && glsl_active_index) if (uni->frame_count >= 0 && glsl->glsl_active_index)
{ {
unsigned modulo = glsl_shader->pass[glsl_active_index - 1].frame_count_mod; unsigned modulo = glsl->glsl_shader->pass[glsl->glsl_active_index - 1].frame_count_mod;
if (modulo) if (modulo)
frame_count %= modulo; frame_count %= modulo;
glUniform1i(uni->frame_count, frame_count); glUniform1i(uni->frame_count, frame_count);
@ -914,20 +964,20 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height,
unsigned texunit = 1; unsigned texunit = 1;
for (i = 0; i < glsl_shader->luts; i++) for (i = 0; i < glsl->glsl_shader->luts; i++)
{ {
if (uni->lut_texture[i] >= 0) if (uni->lut_texture[i] >= 0)
{ {
/* Have to rebind as HW render could override this. */ /* Have to rebind as HW render could override this. */
glActiveTexture(GL_TEXTURE0 + texunit); glActiveTexture(GL_TEXTURE0 + texunit);
glBindTexture(GL_TEXTURE_2D, gl_teximage[i]); glBindTexture(GL_TEXTURE_2D, glsl->gl_teximage[i]);
glUniform1i(uni->lut_texture[i], texunit); glUniform1i(uni->lut_texture[i], texunit);
texunit++; texunit++;
} }
} }
/* Set original texture. */ /* Set original texture. */
if (glsl_active_index) if (glsl->glsl_active_index)
{ {
if (uni->orig.texture >= 0) if (uni->orig.texture >= 0)
{ {
@ -1021,35 +1071,37 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height,
if (size) if (size)
{ {
gl_glsl_set_attribs(glsl_vbo[glsl_active_index].vbo_secondary, gl_glsl_set_attribs(glsl, glsl->glsl_vbo[glsl->glsl_active_index].vbo_secondary,
&glsl_vbo[glsl_active_index].buffer_secondary, &glsl->glsl_vbo[glsl->glsl_active_index].buffer_secondary,
&glsl_vbo[glsl_active_index].size_secondary, &glsl->glsl_vbo[glsl->glsl_active_index].size_secondary,
buffer, size, attribs, attribs_size); buffer, size, attribs, attribs_size);
} }
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
/* #pragma parameters. */ /* #pragma parameters. */
for (i = 0; i < glsl_shader->num_parameters; i++) for (i = 0; i < glsl->glsl_shader->num_parameters; i++)
{ {
int location = glGetUniformLocation(gl_program[glsl_active_index], int location = glGetUniformLocation(
glsl_shader->parameters[i].id); glsl->gl_program[glsl->glsl_active_index],
glUniform1f(location, glsl_shader->parameters[i].current); glsl->glsl_shader->parameters[i].id);
glUniform1f(location, glsl->glsl_shader->parameters[i].current);
} }
/* Set state parameters. */ /* Set state parameters. */
if (gl_state_tracker) if (glsl->gl_state_tracker)
{ {
static struct state_tracker_uniform state_info[GFX_MAX_VARIABLES]; static struct state_tracker_uniform state_info[GFX_MAX_VARIABLES];
static unsigned cnt = 0; static unsigned cnt = 0;
if (glsl_active_index == 1) if (glsl->glsl_active_index == 1)
cnt = state_get_uniform(gl_state_tracker, state_info, cnt = state_get_uniform(glsl->gl_state_tracker, state_info,
GFX_MAX_VARIABLES, frame_count); GFX_MAX_VARIABLES, frame_count);
for (i = 0; i < cnt; i++) for (i = 0; i < cnt; i++)
{ {
int location = glGetUniformLocation(gl_program[glsl_active_index], int location = glGetUniformLocation(
glsl->gl_program[glsl->glsl_active_index],
state_info[i].id); state_info[i].id);
glUniform1f(location, state_info[i].value); glUniform1f(location, state_info[i].value);
} }
@ -1058,11 +1110,14 @@ static void gl_glsl_set_params(void *data, unsigned width, unsigned height,
static bool gl_glsl_set_mvp(void *data, const math_matrix_4x4 *mat) static bool gl_glsl_set_mvp(void *data, const math_matrix_4x4 *mat)
{ {
glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
(void)data; (void)data;
if (!glsl_enable || !glsl_shader->modern)
if (!glsl || !glsl->glsl_shader->modern)
goto fallback; goto fallback;
int loc = gl_uniforms[glsl_active_index].mvp; int loc = glsl->gl_uniforms[glsl->glsl_active_index].mvp;
if (loc >= 0) if (loc >= 0)
glUniformMatrix4fv(loc, 1, GL_FALSE, mat->data); glUniformMatrix4fv(loc, 1, GL_FALSE, mat->data);
@ -1077,8 +1132,9 @@ fallback:
static bool gl_glsl_set_coords(const void *data) static bool gl_glsl_set_coords(const void *data)
{ {
const struct gl_coords *coords = (const struct gl_coords*)data; const struct gl_coords *coords = (const struct gl_coords*)data;
glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
if (!glsl_enable || !glsl_shader->modern || !coords) if (!glsl || !glsl->glsl_shader->modern || !coords)
goto fallback; goto fallback;
/* Avoid hitting malloc on every single regular quad draw. */ /* Avoid hitting malloc on every single regular quad draw. */
@ -1097,7 +1153,8 @@ static bool gl_glsl_set_coords(const void *data)
size_t attribs_size = 0; size_t attribs_size = 0;
struct glsl_attrib *attr = attribs; struct glsl_attrib *attr = attribs;
const struct shader_uniforms *uni = &gl_uniforms[glsl_active_index]; const struct shader_uniforms *uni = &glsl->gl_uniforms[glsl->glsl_active_index];
if (uni->tex_coord >= 0) if (uni->tex_coord >= 0)
{ {
attr->loc = uni->tex_coord; attr->loc = uni->tex_coord;
@ -1152,9 +1209,10 @@ static bool gl_glsl_set_coords(const void *data)
if (size) if (size)
{ {
gl_glsl_set_attribs(glsl_vbo[glsl_active_index].vbo_primary, gl_glsl_set_attribs(glsl,
&glsl_vbo[glsl_active_index].buffer_primary, glsl->glsl_vbo[glsl->glsl_active_index].vbo_primary,
&glsl_vbo[glsl_active_index].size_primary, &glsl->glsl_vbo[glsl->glsl_active_index].buffer_primary,
&glsl->glsl_vbo[glsl->glsl_active_index].size_primary,
buffer, size, buffer, size,
attribs, attribs_size); attribs, attribs_size);
} }
@ -1171,30 +1229,35 @@ fallback:
static void gl_glsl_use(void *data, unsigned idx) static void gl_glsl_use(void *data, unsigned idx)
{ {
(void)data; glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
if (glsl_enable)
{
gl_glsl_reset_attrib();
glsl_active_index = idx; (void)data;
glUseProgram(gl_program[idx]);
} if (!glsl)
return;
gl_glsl_reset_attrib(glsl);
glsl->glsl_active_index = idx;
glUseProgram(glsl->gl_program[idx]);
} }
static unsigned gl_glsl_num(void) static unsigned gl_glsl_num(void)
{ {
if (glsl_shader) glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
return glsl_shader->passes; if (glsl && glsl->glsl_shader)
return glsl->glsl_shader->passes;
return 0; return 0;
} }
static bool gl_glsl_filter_type(unsigned idx, bool *smooth) static bool gl_glsl_filter_type(unsigned idx, bool *smooth)
{ {
if (glsl_enable && idx glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
&& (glsl_shader->pass[idx - 1].filter != RARCH_FILTER_UNSPEC) if (glsl && idx
&& (glsl->glsl_shader->pass[idx - 1].filter != RARCH_FILTER_UNSPEC)
) )
{ {
*smooth = (glsl_shader->pass[idx - 1].filter == RARCH_FILTER_LINEAR); *smooth = (glsl->glsl_shader->pass[idx - 1].filter == RARCH_FILTER_LINEAR);
return true; return true;
} }
return false; return false;
@ -1202,15 +1265,17 @@ static bool gl_glsl_filter_type(unsigned idx, bool *smooth)
static enum gfx_wrap_type gl_glsl_wrap_type(unsigned idx) static enum gfx_wrap_type gl_glsl_wrap_type(unsigned idx)
{ {
if (glsl_enable && idx) glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
return glsl_shader->pass[idx - 1].wrap; if (glsl && idx)
return glsl->glsl_shader->pass[idx - 1].wrap;
return RARCH_WRAP_BORDER; return RARCH_WRAP_BORDER;
} }
static void gl_glsl_shader_scale(unsigned idx, struct gfx_fbo_scale *scale) static void gl_glsl_shader_scale(unsigned idx, struct gfx_fbo_scale *scale)
{ {
if (glsl_enable && idx) glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
*scale = glsl_shader->pass[idx - 1].fbo; if (glsl && idx)
*scale = glsl->glsl_shader->pass[idx - 1].fbo;
else else
scale->valid = false; scale->valid = false;
} }
@ -1218,13 +1283,15 @@ static void gl_glsl_shader_scale(unsigned idx, struct gfx_fbo_scale *scale)
static unsigned gl_glsl_get_prev_textures(void) static unsigned gl_glsl_get_prev_textures(void)
{ {
unsigned i, j; unsigned i, j;
if (!glsl_enable) glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
if (!glsl)
return 0; return 0;
unsigned max_prev = 0; unsigned max_prev = 0;
for (i = 1; i <= glsl_shader->passes; i++) for (i = 1; i <= glsl->glsl_shader->passes; i++)
for (j = 0; j < PREV_TEXTURES; j++) for (j = 0; j < PREV_TEXTURES; j++)
if (gl_uniforms[i].prev[j].texture >= 0) if (glsl->gl_uniforms[i].prev[j].texture >= 0)
max_prev = max(j + 1, max_prev); max_prev = max(j + 1, max_prev);
return max_prev; return max_prev;
@ -1232,14 +1299,18 @@ static unsigned gl_glsl_get_prev_textures(void)
static bool gl_glsl_mipmap_input(unsigned idx) static bool gl_glsl_mipmap_input(unsigned idx)
{ {
if (glsl_enable && idx) glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
return glsl_shader->pass[idx - 1].mipmap; if (glsl && idx)
return glsl->glsl_shader->pass[idx - 1].mipmap;
return false; return false;
} }
static struct gfx_shader *gl_glsl_get_current_shader(void) static struct gfx_shader *gl_glsl_get_current_shader(void)
{ {
return glsl_enable ? glsl_shader : NULL; glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
if (glsl)
return glsl->glsl_shader;
return NULL;
} }
void gl_glsl_set_get_proc_address(gfx_ctx_proc_t (*proc)(const char*)) void gl_glsl_set_get_proc_address(gfx_ctx_proc_t (*proc)(const char*))
@ -1250,9 +1321,14 @@ void gl_glsl_set_get_proc_address(gfx_ctx_proc_t (*proc)(const char*))
void gl_glsl_set_context_type(bool core_profile, void gl_glsl_set_context_type(bool core_profile,
unsigned major, unsigned minor) unsigned major, unsigned minor)
{ {
glsl_core = core_profile; glsl_shader_data_t *glsl = (glsl_shader_data_t*)driver.video_shader_data;
glsl_major = major;
glsl_minor = minor; if (!glsl)
return;
glsl->glsl_core = core_profile;
glsl->glsl_major = major;
glsl->glsl_minor = minor;
} }
const shader_backend_t gl_glsl_backend = { const shader_backend_t gl_glsl_backend = {