RetroArch/gfx/drivers_shader/shader_glsl.c

1692 lines
46 KiB
C
Raw Normal View History

2012-04-21 23:13:50 +02:00
/* RetroArch - A frontend for libretro.
2014-01-01 01:50:59 +01:00
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
2011-01-05 19:07:12 +01:00
*
2012-04-21 23:13:50 +02:00
* RetroArch is free software: you can redistribute it and/or modify it under the terms
2011-01-05 19:07:12 +01:00
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
2012-04-21 23:13:50 +02:00
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
2011-01-05 19:07:12 +01:00
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
2012-04-21 23:31:57 +02:00
* You should have received a copy of the GNU General Public License along with RetroArch.
2011-01-05 19:07:12 +01:00
* If not, see <http://www.gnu.org/licenses/>.
*/
2015-10-31 20:53:08 +01:00
#include <stdlib.h>
2011-01-05 19:07:12 +01:00
#include <string.h>
2015-10-31 20:53:08 +01:00
#include <compat/strl.h>
#include <compat/posix_string.h>
2014-10-22 00:23:06 +02:00
#include <file/file_path.h>
2016-02-05 13:51:30 +01:00
#include <retro_assert.h>
2016-03-20 16:29:14 +01:00
#include <streams/file_stream.h>
2016-01-20 06:16:55 +01:00
#include <string/stdstring.h>
2015-10-31 20:53:08 +01:00
2014-10-02 00:45:11 +02:00
#include "../../general.h"
2011-03-16 21:48:44 +01:00
#include "shader_glsl.h"
2015-01-12 16:00:13 +01:00
#include "../video_state_tracker.h"
2014-10-02 00:45:11 +02:00
#include "../../dynamic.h"
#include "../../rewind.h"
2016-01-28 03:22:23 +01:00
#include "../../libretro_version_1.h"
2011-05-18 20:22:27 +02:00
#ifdef HAVE_CONFIG_H
2014-10-02 00:45:11 +02:00
#include "../../config.h"
#endif
#ifdef HAVE_OPENGL
2015-11-17 08:01:33 +01:00
#include "../common/gl_common.h"
#endif
2011-05-18 20:22:27 +02:00
2012-09-15 15:17:34 +02:00
#ifdef HAVE_OPENGLES2
#define BORDER_FUNC GL_CLAMP_TO_EDGE
#else
#define BORDER_FUNC GL_CLAMP_TO_BORDER
#endif
2011-01-05 19:07:12 +01:00
#define PREV_TEXTURES (GFX_MAX_TEXTURES - 1)
2014-05-23 15:19:32 +02:00
2014-09-08 17:57:18 +02:00
/* Cache the VBO. */
struct cache_vbo
{
GLuint vbo_primary;
GLfloat *buffer_primary;
size_t size_primary;
GLuint vbo_secondary;
GLfloat *buffer_secondary;
size_t size_secondary;
};
struct glsl_attrib
{
GLint loc;
GLsizei size;
GLsizei offset;
};
2012-09-25 01:26:22 +02:00
static gfx_ctx_proc_t (*glsl_get_proc_address)(const char*);
2012-10-21 02:58:51 +02:00
struct shader_uniforms_frame
{
int texture;
int input_size;
int texture_size;
int tex_coord;
};
struct shader_uniforms
{
int mvp;
int tex_coord;
int vertex_coord;
int color;
int lut_tex_coord;
int input_size;
int output_size;
int texture_size;
int frame_count;
unsigned frame_count_mod;
2012-10-21 02:58:51 +02:00
int frame_direction;
int lut_texture[GFX_MAX_TEXTURES];
2012-10-21 02:58:51 +02:00
struct shader_uniforms_frame orig;
struct shader_uniforms_frame feedback;
struct shader_uniforms_frame pass[GFX_MAX_SHADERS];
2012-10-21 02:58:51 +02:00
struct shader_uniforms_frame prev[PREV_TEXTURES];
};
static const char *glsl_prefixes[] = {
"",
"ruby",
};
2014-09-08 17:57:18 +02:00
/* Need to duplicate these to work around broken stuff on Android.
* Must enforce alpha = 1.0 or 32-bit games can potentially go black. */
static const char *stock_vertex_modern =
"attribute vec2 TexCoord;\n"
"attribute vec2 VertexCoord;\n"
"attribute vec4 Color;\n"
"uniform mat4 MVPMatrix;\n"
"varying vec2 tex_coord;\n"
"void main() {\n"
" gl_Position = MVPMatrix * vec4(VertexCoord, 0.0, 1.0);\n"
" tex_coord = TexCoord;\n"
"}";
static const char *stock_fragment_modern =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"uniform sampler2D Texture;\n"
"varying vec2 tex_coord;\n"
"void main() {\n"
" gl_FragColor = vec4(texture2D(Texture, tex_coord).rgb, 1.0);\n"
"}";
2013-06-30 22:58:22 +02:00
static const char *stock_vertex_core =
"in vec2 TexCoord;\n"
"in vec2 VertexCoord;\n"
"in vec4 Color;\n"
"uniform mat4 MVPMatrix;\n"
"out vec2 tex_coord;\n"
"void main() {\n"
" gl_Position = MVPMatrix * vec4(VertexCoord, 0.0, 1.0);\n"
" tex_coord = TexCoord;\n"
"}";
static const char *stock_fragment_core =
"uniform sampler2D Texture;\n"
"in vec2 tex_coord;\n"
"out vec4 FragColor;\n"
"void main() {\n"
" FragColor = vec4(texture(Texture, tex_coord).rgb, 1.0);\n"
"}";
static const char *stock_vertex_legacy =
2011-11-12 15:26:24 +01:00
"varying vec4 color;\n"
"void main() {\n"
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
" gl_TexCoord[0] = gl_MultiTexCoord0;\n"
" color = gl_Color;\n"
"}";
static const char *stock_fragment_legacy =
"uniform sampler2D Texture;\n"
2011-11-12 15:26:24 +01:00
"varying vec4 color;\n"
"void main() {\n"
" gl_FragColor = color * texture2D(Texture, gl_TexCoord[0].xy);\n"
2011-11-12 15:26:24 +01:00
"}";
static const char *stock_vertex_modern_blend =
2015-10-29 01:38:43 +01:00
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"attribute vec2 TexCoord;\n"
"attribute vec2 VertexCoord;\n"
"attribute vec4 Color;\n"
"uniform mat4 MVPMatrix;\n"
"varying vec2 tex_coord;\n"
"varying vec4 color;\n"
"void main() {\n"
" gl_Position = MVPMatrix * vec4(VertexCoord, 0.0, 1.0);\n"
" tex_coord = TexCoord;\n"
" color = Color;\n"
"}";
static const char *stock_fragment_modern_blend =
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
"uniform sampler2D Texture;\n"
"varying vec2 tex_coord;\n"
"varying vec4 color;\n"
"void main() {\n"
" gl_FragColor = color * texture2D(Texture, tex_coord);\n"
"}";
2013-06-30 22:58:22 +02:00
static const char *stock_vertex_core_blend =
"in vec2 TexCoord;\n"
"in vec2 VertexCoord;\n"
"in vec4 Color;\n"
"uniform mat4 MVPMatrix;\n"
"out vec2 tex_coord;\n"
"out vec4 color;\n"
"void main() {\n"
" gl_Position = MVPMatrix * vec4(VertexCoord, 0.0, 1.0);\n"
" tex_coord = TexCoord;\n"
" color = Color;\n"
"}";
static const char *stock_fragment_core_blend =
"uniform sampler2D Texture;\n"
"in vec2 tex_coord;\n"
"in vec4 color;\n"
"out vec4 FragColor;\n"
"void main() {\n"
" FragColor = color * texture(Texture, tex_coord);\n"
2013-06-30 22:58:22 +02:00
"}";
static const char *stock_vertex_xmb =
"attribute vec3 vPosition;\n"
"uniform float time;\n"
"varying vec3 v;\n"
"float iqhash( float n )\n"
"{\n"
" return fract(sin(n)*43758.5453);\n"
"}\n"
"float noise( vec3 x )\n"
"{\n"
" vec3 p = floor(x);\n"
" vec3 f = fract(x);\n"
" f = f*f*(3.0-2.0*f);\n"
" float n = p.x + p.y*57.0 + 113.0*p.z;\n"
" return mix(mix(mix( iqhash(n+0.0 ), iqhash(n+1.0 ),f.x),\n"
" mix( iqhash(n+57.0 ), iqhash(n+58.0 ),f.x),f.y),\n"
" mix(mix( iqhash(n+113.0), iqhash(n+114.0),f.x),\n"
" mix( iqhash(n+170.0), iqhash(n+171.0),f.x),f.y),f.z);\n"
"}\n"
"void main()\n"
"{\n"
" v = vPosition;\n"
" vec3 v2 = v;\n"
" v2.x = v2.x + time/2.0;\n"
" v2.z = v.z * 3.0;\n"
" v.y = -cos((v.x+v.z/3.0+time)*2.0)/10.0 - noise(v2.xyz)/4.0;\n"
" gl_Position = vec4(v, 1.0);\n"
"}\n";
static const char *stock_fragment_xmb =
"uniform float time;\n"
"varying vec3 v;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(1.0, 1.0, 1.0, 0.05);\n"
"}\n";
typedef struct glsl_shader_data
{
2015-07-10 19:17:26 +02:00
struct video_shader *shader;
2016-04-13 02:36:00 +02:00
struct shader_uniforms uniforms[GFX_MAX_SHADERS];
struct cache_vbo vbo[GFX_MAX_SHADERS];
char glsl_alias_define[1024];
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 + 2 + 4 + GFX_MAX_SHADERS];
state_tracker_t *gl_state_tracker;
} glsl_shader_data_t;
static bool glsl_core;
static unsigned glsl_major;
static unsigned glsl_minor;
static GLint gl_glsl_get_uniform(glsl_shader_data_t *glsl,
2015-12-01 07:12:26 +01:00
GLuint prog, const char *base)
{
unsigned i;
GLint loc;
2015-06-13 02:10:06 +02:00
char buf[64] = {0};
2015-12-01 07:12:26 +01:00
snprintf(buf, sizeof(buf), "%s%s", glsl->shader->prefix, base);
loc = glGetUniformLocation(prog, buf);
if (loc >= 0)
return loc;
for (i = 0; i < ARRAY_SIZE(glsl_prefixes); i++)
{
snprintf(buf, sizeof(buf), "%s%s", glsl_prefixes[i], base);
loc = glGetUniformLocation(prog, buf);
if (loc >= 0)
return loc;
}
return -1;
}
static GLint gl_glsl_get_attrib(glsl_shader_data_t *glsl,
2015-12-01 07:12:26 +01:00
GLuint prog, const char *base)
{
unsigned i;
GLint loc;
2015-06-13 02:10:06 +02:00
char buf[64] = {0};
2015-12-01 07:12:26 +01:00
snprintf(buf, sizeof(buf), "%s%s", glsl->shader->prefix, base);
loc = glGetUniformLocation(prog, buf);
if (loc >= 0)
return loc;
for (i = 0; i < ARRAY_SIZE(glsl_prefixes); i++)
{
snprintf(buf, sizeof(buf), "%s%s", glsl_prefixes[i], base);
loc = glGetAttribLocation(prog, buf);
if (loc >= 0)
return loc;
}
return -1;
}
static void gl_glsl_print_shader_log(GLuint obj)
{
2015-06-13 02:10:06 +02:00
char *info_log = NULL;
GLint max_len, info_len = 0;
glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &max_len);
2011-12-24 13:46:12 +01:00
if (max_len == 0)
return;
info_log = (char*)malloc(max_len);
2011-12-24 13:46:12 +01:00
if (!info_log)
return;
glGetShaderInfoLog(obj, max_len, &info_len, info_log);
if (info_len > 0)
2012-04-21 23:25:32 +02:00
RARCH_LOG("Shader log: %s\n", info_log);
2011-12-24 13:46:12 +01:00
free(info_log);
}
static void gl_glsl_print_linker_log(GLuint obj)
{
2015-06-13 02:10:06 +02:00
char *info_log = NULL;
GLint max_len, info_len = 0;
glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &max_len);
2011-12-24 13:46:12 +01:00
if (max_len == 0)
return;
info_log = (char*)malloc(max_len);
2011-12-24 13:46:12 +01:00
if (!info_log)
return;
glGetProgramInfoLog(obj, max_len, &info_len, info_log);
if (info_len > 0)
2012-04-21 23:25:32 +02:00
RARCH_LOG("Linker log: %s\n", info_log);
2011-12-24 13:46:12 +01:00
free(info_log);
}
static bool gl_glsl_compile_shader(glsl_shader_data_t *glsl,
2015-12-01 07:12:26 +01:00
GLuint shader,
const char *define, const char *program)
2011-06-02 13:49:22 +02:00
{
2015-04-12 19:29:38 +02:00
GLint status;
2015-06-30 14:37:11 +02:00
const char *source[4];
2013-06-30 22:58:22 +02:00
char version[32] = {0};
2015-06-30 14:37:11 +02:00
if (glsl_core && !strstr(program, "#version"))
2013-06-30 22:58:22 +02:00
{
unsigned version_no = 0;
unsigned gl_ver = glsl_major * 100 + glsl_minor * 10;
2013-06-30 22:58:22 +02:00
switch (gl_ver)
{
case 300:
version_no = 130;
break;
case 310:
version_no = 140;
break;
case 320:
version_no = 150;
break;
default:
version_no = gl_ver;
break;
2013-06-30 22:58:22 +02:00
}
snprintf(version, sizeof(version), "#version %u\n", version_no);
RARCH_LOG("[GL]: Using GLSL version %u.\n", version_no);
}
2016-02-07 16:23:36 +01:00
source[0] = version;
2015-06-30 14:37:11 +02:00
source[1] = define;
2015-12-01 07:12:26 +01:00
source[2] = glsl->glsl_alias_define;
2015-06-30 14:37:11 +02:00
source[3] = program;
glShaderSource(shader, ARRAY_SIZE(source), source, NULL);
glCompileShader(shader);
2011-06-02 13:49:22 +02:00
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
gl_glsl_print_shader_log(shader);
2011-06-02 13:49:22 +02:00
return status == GL_TRUE;
}
static bool gl_glsl_link_program(GLuint prog)
2011-06-07 15:58:30 +02:00
{
2015-06-26 17:46:13 +02:00
GLint status;
glLinkProgram(prog);
2011-06-07 15:58:30 +02:00
glGetProgramiv(prog, GL_LINK_STATUS, &status);
gl_glsl_print_linker_log(prog);
2011-06-07 15:58:30 +02:00
if (status != GL_TRUE)
return false;
glUseProgram(prog);
return true;
2011-06-07 15:58:30 +02:00
}
static GLuint gl_glsl_compile_program(glsl_shader_data_t *glsl,
2016-04-13 19:58:40 +02:00
unsigned idx,
2015-12-01 07:12:26 +01:00
const char *vertex,
2016-04-13 19:58:40 +02:00
const char *fragment)
2011-01-05 19:07:12 +01:00
{
2016-04-13 06:52:36 +02:00
GLuint vert = 0;
GLuint frag = 0;
GLuint prog = glCreateProgram();
if (!prog)
2016-04-13 06:52:36 +02:00
goto error;
if (vertex)
2011-03-12 15:30:57 +01:00
{
RARCH_LOG("Found GLSL vertex shader.\n");
vert = glCreateShader(GL_VERTEX_SHADER);
if (!gl_glsl_compile_shader(
2015-12-01 07:12:26 +01:00
glsl,
2014-09-08 17:57:18 +02:00
vert, "#define VERTEX\n#define PARAMETER_UNIFORM\n", vertex))
{
2016-04-13 19:58:40 +02:00
RARCH_ERR("Failed to compile vertex shader #%u\n", idx);
2016-04-13 06:52:36 +02:00
goto error;
}
glAttachShader(prog, vert);
}
2011-03-12 15:30:57 +01:00
if (fragment)
{
RARCH_LOG("Found GLSL fragment shader.\n");
frag = glCreateShader(GL_FRAGMENT_SHADER);
if (!gl_glsl_compile_shader(glsl, frag,
2014-09-08 17:57:18 +02:00
"#define FRAGMENT\n#define PARAMETER_UNIFORM\n", fragment))
2011-03-12 15:30:57 +01:00
{
2016-04-13 19:58:40 +02:00
RARCH_ERR("Failed to compile fragment shader #%u\n", idx);
2016-04-13 06:52:36 +02:00
goto error;
2011-03-12 15:30:57 +01:00
}
glAttachShader(prog, frag);
}
2011-03-12 15:30:57 +01:00
if (vertex || fragment)
{
RARCH_LOG("Linking GLSL program.\n");
if (!gl_glsl_link_program(prog))
2016-04-13 06:52:36 +02:00
goto error;
2014-09-08 17:57:18 +02:00
/* Clean up dead memory. We're not going to relink the program.
* Detaching first seems to kill some mobile drivers
* (according to the intertubes anyways). */
if (vert)
glDeleteShader(vert);
if (frag)
glDeleteShader(frag);
glUseProgram(prog);
glUniform1i(gl_glsl_get_uniform(glsl, prog, "Texture"), 0);
glUseProgram(0);
2011-03-12 15:30:57 +01:00
}
2011-03-30 00:10:16 +02:00
return prog;
2016-04-13 06:52:36 +02:00
error:
2016-04-13 19:58:40 +02:00
RARCH_ERR("Failed to link program #%u.\n", idx);
2016-04-13 06:52:36 +02:00
return 0;
}
static void gl_glsl_strip_parameter_pragmas(char *source)
{
/* #pragma parameter lines tend to have " characters in them,
* which is not legal GLSL. */
char *s = strstr(source, "#pragma parameter");
while (s)
{
/* #pragmas have to be on a single line,
* so we can just replace the entire line with spaces. */
while (*s != '\0' && *s != '\n')
*s++ = ' ';
s = strstr(s, "#pragma parameter");
}
}
static bool gl_glsl_load_source_path(struct video_shader_pass *pass,
2014-09-08 17:57:18 +02:00
const char *path)
{
2015-02-16 03:46:27 +01:00
ssize_t len;
2016-03-24 04:09:25 +01:00
bool ret = filestream_read_file(path,
2016-01-30 03:58:33 +01:00
(void**)&pass->source.string.vertex, &len);
2015-02-16 03:31:37 +01:00
if (!ret || len <= 0)
return false;
gl_glsl_strip_parameter_pragmas(pass->source.string.vertex);
pass->source.string.fragment = strdup(pass->source.string.vertex);
return pass->source.string.fragment && pass->source.string.vertex;
}
2016-01-30 03:58:33 +01:00
static bool gl_glsl_compile_programs(
glsl_shader_data_t *glsl, GLuint *gl_prog)
{
unsigned i;
2015-12-01 07:12:26 +01:00
for (i = 0; i < glsl->shader->passes; i++)
{
const char *vertex = NULL;
const char *fragment = NULL;
2015-01-19 21:24:08 +01:00
struct video_shader_pass *pass = (struct video_shader_pass*)
2015-12-01 07:12:26 +01:00
&glsl->shader->pass[i];
2014-09-08 17:57:18 +02:00
/* If we load from GLSLP (CGP),
* load the file here, and pretend
* we were really using XML all along.
*/
2016-01-30 03:58:33 +01:00
if (*pass->source.path && !gl_glsl_load_source_path(
pass, pass->source.path))
{
2016-01-30 03:58:33 +01:00
RARCH_ERR("Failed to load GLSL shader: %s.\n",
pass->source.path);
return false;
}
*pass->source.path = '\0';
vertex = pass->source.string.vertex;
fragment = pass->source.string.fragment;
2016-04-13 19:58:40 +02:00
gl_prog[i] = gl_glsl_compile_program(glsl, i, vertex, fragment);
if (!gl_prog[i])
{
RARCH_ERR("Failed to create GL program #%u.\n", i);
return false;
}
}
return true;
2011-03-12 15:30:57 +01:00
}
2011-02-22 16:43:00 -06:00
2015-12-01 07:12:26 +01:00
static void gl_glsl_reset_attrib(glsl_shader_data_t *glsl)
{
unsigned i;
2014-09-08 17:57:18 +02:00
/* Add sanity check that we did not overflow. */
2015-12-01 07:12:26 +01:00
retro_assert(glsl->gl_attrib_index <= ARRAY_SIZE(glsl->gl_attribs));
2015-12-01 07:12:26 +01:00
for (i = 0; i < glsl->gl_attrib_index; i++)
glDisableVertexAttribArray(glsl->gl_attribs[i]);
glsl->gl_attrib_index = 0;
}
2014-09-08 17:57:18 +02:00
static void gl_glsl_set_vbo(GLfloat **buffer, size_t *buffer_elems,
const GLfloat *data, size_t elems)
{
2014-09-08 17:57:18 +02:00
if (elems != *buffer_elems ||
memcmp(data, *buffer, elems * sizeof(GLfloat)))
{
if (elems > *buffer_elems)
{
2014-09-08 17:57:18 +02:00
GLfloat *new_buffer = (GLfloat*)
realloc(*buffer, elems * sizeof(GLfloat));
retro_assert(new_buffer);
*buffer = new_buffer;
}
memcpy(*buffer, data, elems * sizeof(GLfloat));
2014-09-08 17:57:18 +02:00
glBufferData(GL_ARRAY_BUFFER, elems * sizeof(GLfloat),
data, GL_STATIC_DRAW);
*buffer_elems = elems;
}
}
2015-12-01 07:12:26 +01:00
static void gl_glsl_set_attribs(glsl_shader_data_t *glsl,
GLuint vbo,
2014-09-08 17:57:18 +02:00
GLfloat **buffer, size_t *buffer_elems,
const GLfloat *data, size_t elems,
const struct glsl_attrib *attrs, size_t num_attrs)
{
size_t i;
glBindBuffer(GL_ARRAY_BUFFER, vbo);
gl_glsl_set_vbo(buffer, buffer_elems, data, elems);
for (i = 0; i < num_attrs; i++)
{
GLint loc = attrs[i].loc;
2015-12-01 07:12:26 +01:00
if (glsl->gl_attrib_index < ARRAY_SIZE(glsl->gl_attribs))
{
glEnableVertexAttribArray(loc);
glVertexAttribPointer(loc, attrs[i].size, GL_FLOAT, GL_FALSE, 0,
(const GLvoid*)(uintptr_t)attrs[i].offset);
2015-12-01 07:12:26 +01:00
glsl->gl_attribs[glsl->gl_attrib_index++] = loc;
}
else
RARCH_WARN("Attrib array buffer was overflown!\n");
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
static void gl_glsl_clear_uniforms_frame(struct shader_uniforms_frame *frame)
{
frame->texture = -1;
frame->texture_size = -1;
frame->input_size = -1;
frame->tex_coord = -1;
}
static void gl_glsl_find_uniforms_frame(glsl_shader_data_t *glsl,
2015-12-01 07:12:26 +01:00
GLuint prog,
2014-09-08 17:57:18 +02:00
struct shader_uniforms_frame *frame, const char *base)
2012-10-21 02:58:51 +02:00
{
2015-06-13 02:10:06 +02:00
char texture[64] = {0};
char texture_size[64] = {0};
char input_size[64] = {0};
char tex_coord[64] = {0};
2012-10-21 02:58:51 +02:00
snprintf(texture, sizeof(texture), "%s%s", base, "Texture");
snprintf(texture_size, sizeof(texture_size), "%s%s", base, "TextureSize");
snprintf(input_size, sizeof(input_size), "%s%s", base, "InputSize");
snprintf(tex_coord, sizeof(tex_coord), "%s%s", base, "TexCoord");
if (frame->texture < 0)
frame->texture = gl_glsl_get_uniform(glsl, prog, texture);
if (frame->texture_size < 0)
frame->texture_size = gl_glsl_get_uniform(glsl, prog, texture_size);
if (frame->input_size < 0)
frame->input_size = gl_glsl_get_uniform(glsl, prog, input_size);
if (frame->tex_coord < 0)
frame->tex_coord = gl_glsl_get_attrib(glsl, prog, tex_coord);
2012-10-21 02:58:51 +02:00
}
static void gl_glsl_find_uniforms(glsl_shader_data_t *glsl,
unsigned pass, GLuint prog,
2014-09-08 17:57:18 +02:00
struct shader_uniforms *uni)
2012-10-21 02:58:51 +02:00
{
unsigned i;
2015-06-13 02:10:06 +02:00
char frame_base[64] = {0};
glUseProgram(prog);
2012-10-21 02:58:51 +02:00
uni->mvp = gl_glsl_get_uniform(glsl, prog, "MVPMatrix");
uni->tex_coord = gl_glsl_get_attrib(glsl, prog, "TexCoord");
uni->vertex_coord = gl_glsl_get_attrib(glsl, prog, "VertexCoord");
uni->color = gl_glsl_get_attrib(glsl, prog, "Color");
uni->lut_tex_coord = gl_glsl_get_attrib(glsl, prog, "LUTTexCoord");
2012-10-21 02:58:51 +02:00
uni->input_size = gl_glsl_get_uniform(glsl, prog, "InputSize");
uni->output_size = gl_glsl_get_uniform(glsl, prog, "OutputSize");
uni->texture_size = gl_glsl_get_uniform(glsl, prog, "TextureSize");
2012-10-21 02:58:51 +02:00
uni->frame_count = gl_glsl_get_uniform(glsl, prog, "FrameCount");
uni->frame_direction = gl_glsl_get_uniform(glsl, prog, "FrameDirection");
2012-10-21 02:58:51 +02:00
2015-12-01 07:12:26 +01:00
for (i = 0; i < glsl->shader->luts; i++)
uni->lut_texture[i] = glGetUniformLocation(prog, glsl->shader->lut[i].id);
2012-10-21 02:58:51 +02:00
gl_glsl_clear_uniforms_frame(&uni->orig);
gl_glsl_find_uniforms_frame(glsl, prog, &uni->orig, "Orig");
gl_glsl_clear_uniforms_frame(&uni->feedback);
gl_glsl_find_uniforms_frame(glsl, prog, &uni->feedback, "Feedback");
if (pass > 1)
{
snprintf(frame_base, sizeof(frame_base), "PassPrev%u", pass);
gl_glsl_find_uniforms_frame(glsl, prog, &uni->orig, frame_base);
}
2012-10-21 02:58:51 +02:00
2014-05-16 18:11:47 +02:00
for (i = 0; i + 1 < pass; i++)
2012-10-21 02:58:51 +02:00
{
2014-05-16 18:11:47 +02:00
snprintf(frame_base, sizeof(frame_base), "Pass%u", i + 1);
gl_glsl_clear_uniforms_frame(&uni->pass[i]);
gl_glsl_find_uniforms_frame(glsl, prog, &uni->pass[i], frame_base);
2014-05-16 18:11:47 +02:00
snprintf(frame_base, sizeof(frame_base), "PassPrev%u", pass - (i + 1));
gl_glsl_find_uniforms_frame(glsl, prog, &uni->pass[i], frame_base);
2015-12-01 07:12:26 +01:00
if (*glsl->shader->pass[i].alias)
gl_glsl_find_uniforms_frame(glsl, prog, &uni->pass[i], glsl->shader->pass[i].alias);
2014-05-16 18:11:47 +02:00
}
2012-10-21 02:58:51 +02:00
gl_glsl_clear_uniforms_frame(&uni->prev[0]);
gl_glsl_find_uniforms_frame(glsl, prog, &uni->prev[0], "Prev");
2014-05-16 18:11:47 +02:00
for (i = 1; i < PREV_TEXTURES; i++)
{
snprintf(frame_base, sizeof(frame_base), "Prev%u", i);
gl_glsl_clear_uniforms_frame(&uni->prev[i]);
gl_glsl_find_uniforms_frame(glsl, prog, &uni->prev[i], frame_base);
2012-10-21 02:58:51 +02:00
}
glUseProgram(0);
2012-10-21 02:58:51 +02:00
}
2015-12-01 07:12:26 +01:00
static void gl_glsl_deinit_shader(glsl_shader_data_t *glsl)
{
unsigned i;
2015-12-01 07:12:26 +01:00
if (!glsl || !glsl->shader)
return;
2015-12-01 07:12:26 +01:00
for (i = 0; i < glsl->shader->passes; i++)
{
2015-12-01 07:12:26 +01:00
free(glsl->shader->pass[i].source.string.vertex);
free(glsl->shader->pass[i].source.string.fragment);
}
2015-12-01 07:12:26 +01:00
free(glsl->shader->script);
free(glsl->shader);
glsl->shader = NULL;
}
2015-12-01 07:12:26 +01:00
static void gl_glsl_destroy_resources(glsl_shader_data_t *glsl)
{
unsigned i;
2015-12-01 07:12:26 +01:00
if (!glsl)
return;
glUseProgram(0);
for (i = 0; i < GFX_MAX_SHADERS; i++)
{
2015-12-01 07:12:26 +01:00
if (glsl->gl_program[i] == 0 || (i && glsl->gl_program[i] == glsl->gl_program[0]))
continue;
if (!glIsProgram(glsl->gl_program[i]))
continue;
2015-12-01 07:12:26 +01:00
glDeleteProgram(glsl->gl_program[i]);
}
2015-12-01 07:12:26 +01:00
if (glsl->shader && glsl->shader->luts)
glDeleteTextures(glsl->shader->luts, glsl->gl_teximage);
2015-12-01 07:12:26 +01:00
memset(glsl->gl_program, 0, sizeof(glsl->gl_program));
2016-04-13 02:36:00 +02:00
memset(glsl->uniforms, 0, sizeof(glsl->uniforms));
2015-12-01 07:12:26 +01:00
glsl->glsl_active_index = 0;
2015-12-01 07:12:26 +01:00
gl_glsl_deinit_shader(glsl);
2015-12-01 07:12:26 +01:00
if (glsl->gl_state_tracker)
state_tracker_free(glsl->gl_state_tracker);
glsl->gl_state_tracker = NULL;
2015-12-01 07:12:26 +01:00
gl_glsl_reset_attrib(glsl);
for (i = 0; i < GFX_MAX_SHADERS; i++)
{
2016-04-13 02:36:00 +02:00
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);
2016-04-13 02:36:00 +02:00
free(glsl->vbo[i].buffer_primary);
free(glsl->vbo[i].buffer_secondary);
}
2016-04-13 02:36:00 +02:00
memset(&glsl->vbo, 0, sizeof(glsl->vbo));
}
2015-12-05 07:33:21 +01:00
static void gl_glsl_deinit(void *data)
{
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
2015-12-01 07:12:26 +01:00
if (!glsl)
return;
2015-12-01 07:12:26 +01:00
gl_glsl_destroy_resources(glsl);
2015-12-06 14:23:41 -03:00
free(glsl);
}
2015-12-05 07:33:21 +01:00
static void *gl_glsl_init(void *data, const char *path)
2011-03-12 15:30:57 +01:00
{
unsigned i;
config_file_t *conf = NULL;
const char *stock_vertex = NULL;
const char *stock_fragment = NULL;
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)
calloc(1, sizeof(glsl_shader_data_t));
2015-12-01 07:12:26 +01:00
if (!glsl)
2015-12-05 07:33:21 +01:00
return NULL;
#ifndef HAVE_OPENGLES2
2012-04-21 23:25:32 +02:00
RARCH_LOG("Checking GLSL shader support ...\n");
bool shader_support = glCreateProgram && glUseProgram && glCreateShader
&& glDeleteShader && glShaderSource && glCompileShader && glAttachShader
&& glDetachShader && glLinkProgram && glGetUniformLocation
2014-09-08 17:57:18 +02:00
&& glUniform1i && glUniform1f && glUniform2fv && glUniform4fv
&& glUniformMatrix4fv
&& glGetShaderiv && glGetShaderInfoLog && glGetProgramiv
&& glGetProgramInfoLog
&& glDeleteProgram && glGetAttachedShaders
2014-09-08 17:57:18 +02:00
&& glGetAttribLocation && glEnableVertexAttribArray
&& glDisableVertexAttribArray
&& glVertexAttribPointer
&& glGenBuffers && glBufferData && glDeleteBuffers && glBindBuffer;
2011-01-05 19:07:12 +01:00
if (!shader_support)
{
2012-04-21 23:25:32 +02:00
RARCH_ERR("GLSL shaders aren't supported by your OpenGL driver.\n");
2015-12-05 07:33:21 +01:00
goto error;
2011-01-05 19:07:12 +01:00
}
2012-09-15 15:17:34 +02:00
#endif
2011-01-05 19:07:12 +01:00
2015-12-01 07:12:26 +01:00
glsl->shader = (struct video_shader*)calloc(1, sizeof(*glsl->shader));
if (!glsl->shader)
2015-12-05 07:33:21 +01:00
goto error;
2012-09-15 15:37:08 +02:00
2013-04-07 12:51:26 +02:00
if (path)
{
bool ret;
2015-06-15 06:01:54 +02:00
const char *path_ext = path_get_extension(path);
2016-01-20 06:16:55 +01:00
if (string_is_equal(path_ext, "glsl"))
{
2015-12-01 07:12:26 +01:00
strlcpy(glsl->shader->pass[0].source.path, path,
sizeof(glsl->shader->pass[0].source.path));
glsl->shader->passes = 1;
glsl->shader->modern = true;
ret = true;
}
2016-01-20 06:16:55 +01:00
else if (string_is_equal(path_ext, "glslp"))
{
2014-05-22 21:24:52 +02:00
conf = config_file_new(path);
if (conf)
{
2015-12-01 07:12:26 +01:00
ret = video_shader_read_conf_cgp(conf, glsl->shader);
glsl->shader->modern = true;
}
else
ret = false;
}
else
ret = false;
if (!ret)
2013-04-07 12:51:26 +02:00
{
RARCH_ERR("[GL]: Failed to parse GLSL shader.\n");
2015-12-05 07:33:21 +01:00
goto error;
2013-04-07 12:51:26 +02:00
}
2011-03-12 15:30:57 +01:00
}
2012-09-15 15:37:08 +02:00
else
{
RARCH_WARN("[GL]: Stock GLSL shaders will be used.\n");
2015-12-01 07:12:26 +01:00
glsl->shader->passes = 1;
glsl->shader->pass[0].source.string.vertex =
strdup(glsl_core ? stock_vertex_core : stock_vertex_modern);
2015-12-01 07:12:26 +01:00
glsl->shader->pass[0].source.string.fragment =
strdup(glsl_core ? stock_fragment_core : stock_fragment_modern);
2015-12-01 07:12:26 +01:00
glsl->shader->modern = true;
2012-09-15 15:37:08 +02:00
}
2011-01-05 19:07:12 +01:00
2015-12-01 07:12:26 +01:00
video_shader_resolve_relative(glsl->shader, path);
video_shader_resolve_parameters(conf, glsl->shader);
2014-05-22 21:24:52 +02:00
if (conf)
{
config_file_free(conf);
conf = NULL;
}
2015-12-01 07:12:26 +01:00
stock_vertex = (glsl->shader->modern) ?
stock_vertex_modern : stock_vertex_legacy;
2015-12-01 07:12:26 +01:00
stock_fragment = (glsl->shader->modern) ?
stock_fragment_modern : stock_fragment_legacy;
if (glsl_core)
{
stock_vertex = stock_vertex_core;
stock_fragment = stock_fragment_core;
}
2012-09-15 15:46:02 +02:00
#ifdef HAVE_OPENGLES2
2015-12-01 07:12:26 +01:00
if (!glsl->shader->modern)
2012-09-15 15:46:02 +02:00
{
RARCH_ERR("[GL]: GLES context is used, but shader is not modern. Cannot use it.\n");
goto error;
2012-09-15 15:46:02 +02:00
}
2013-06-30 22:58:22 +02:00
#else
2015-12-01 07:12:26 +01:00
if (glsl_core && !glsl->shader->modern)
2013-06-30 22:58:22 +02:00
{
RARCH_ERR("[GL]: GL core context is used, but shader is not core compatible. Cannot use it.\n");
goto error;
}
2012-09-15 15:46:02 +02:00
#endif
2014-09-08 17:57:18 +02:00
/* 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. */
2015-12-01 07:12:26 +01:00
*glsl->glsl_alias_define = '\0';
for (i = 0; i < glsl->shader->passes; i++)
2014-05-23 15:19:32 +02:00
{
2015-12-01 07:12:26 +01:00
if (*glsl->shader->pass[i].alias)
2014-05-23 15:19:32 +02:00
{
2015-06-13 02:10:06 +02:00
char define[128] = {0};
2014-09-08 17:57:18 +02:00
snprintf(define, sizeof(define), "#define %s_ALIAS\n",
2015-12-01 07:12:26 +01:00
glsl->shader->pass[i].alias);
strlcat(glsl->glsl_alias_define, define, sizeof(glsl->glsl_alias_define));
2014-05-23 15:19:32 +02:00
}
}
2016-04-13 19:58:40 +02:00
if (!(glsl->gl_program[0] = gl_glsl_compile_program(glsl, 0, stock_vertex, stock_fragment)))
{
RARCH_ERR("GLSL stock programs failed to compile.\n");
goto error;
}
if (!gl_glsl_compile_programs(glsl, &glsl->gl_program[1]))
goto error;
2011-03-14 21:28:30 +01:00
2015-12-01 07:12:26 +01:00
if (!gl_load_luts(glsl->shader, glsl->gl_teximage))
{
RARCH_ERR("[GL]: Failed to load LUTs.\n");
goto error;
}
2011-03-06 19:56:35 +01:00
2015-12-01 07:12:26 +01:00
for (i = 0; i <= glsl->shader->passes; i++)
2016-04-13 02:36:00 +02:00
gl_glsl_find_uniforms(glsl, i, glsl->gl_program[i], &glsl->uniforms[i]);
2012-10-21 02:58:51 +02:00
#ifdef GLSL_DEBUG
if (!gl_check_error())
2012-10-21 02:58:51 +02:00
RARCH_WARN("Detected GL error in GLSL.\n");
#endif
2015-12-01 07:12:26 +01:00
if (glsl->shader->variables)
{
2016-01-28 03:22:23 +01:00
retro_ctx_memory_info_t mem_info;
2012-04-07 12:17:40 +02:00
struct state_tracker_info info = {0};
2016-01-28 03:22:23 +01:00
mem_info.id = RETRO_MEMORY_SYSTEM_RAM;
core_ctl(CORE_CTL_RETRO_GET_MEMORY, &mem_info);
info.wram = (uint8_t*)mem_info.data;
2015-12-01 07:12:26 +01:00
info.info = glsl->shader->variable;
info.info_elem = glsl->shader->variables;
2011-06-07 15:33:29 +02:00
2011-06-06 18:50:36 +02:00
#ifdef HAVE_PYTHON
2015-12-01 07:12:26 +01:00
info.script = glsl->shader->script;
info.script_class = *glsl->shader->script_class ?
glsl->shader->script_class : NULL;
2011-06-06 18:50:36 +02:00
#endif
2011-06-07 15:33:29 +02:00
2015-12-01 07:12:26 +01:00
glsl->gl_state_tracker = state_tracker_init(&info);
if (!glsl->gl_state_tracker)
2012-04-21 23:25:32 +02:00
RARCH_WARN("Failed to init state tracker.\n");
}
2015-12-01 07:12:26 +01:00
glsl->gl_program[glsl->shader->passes + 1] = glsl->gl_program[0];
2016-04-13 02:36:00 +02:00
glsl->uniforms[glsl->shader->passes + 1] = glsl->uniforms[0];
2015-12-01 07:12:26 +01:00
if (glsl->shader->modern)
{
glsl->gl_program[GL_SHADER_STOCK_BLEND] = gl_glsl_compile_program(
2015-12-01 07:12:26 +01:00
glsl,
2016-04-13 19:58:40 +02:00
GL_SHADER_STOCK_BLEND,
glsl_core ?
2014-09-08 17:57:18 +02:00
stock_vertex_core_blend : stock_vertex_modern_blend,
glsl_core ?
2016-04-13 19:58:40 +02:00
stock_fragment_core_blend : stock_fragment_modern_blend
);
gl_glsl_find_uniforms(glsl, 0, glsl->gl_program[GL_SHADER_STOCK_BLEND],
2016-04-13 02:36:00 +02:00
&glsl->uniforms[GL_SHADER_STOCK_BLEND]);
}
else
{
2015-12-01 07:12:26 +01:00
glsl->gl_program [GL_SHADER_STOCK_BLEND] = glsl->gl_program[0];
2016-04-13 02:36:00 +02:00
glsl->uniforms[GL_SHADER_STOCK_BLEND] = glsl->uniforms[0];
}
glsl->gl_program[GL_SHADER_STOCK_XMB] = gl_glsl_compile_program(
glsl,
2016-04-13 19:58:40 +02:00
GL_SHADER_STOCK_XMB,
stock_vertex_xmb,
2016-04-13 19:58:40 +02:00
stock_fragment_xmb);
2015-12-01 07:12:26 +01:00
gl_glsl_reset_attrib(glsl);
for (i = 0; i < GFX_MAX_SHADERS; i++)
{
2016-04-13 02:36:00 +02:00
glGenBuffers(1, &glsl->vbo[i].vbo_primary);
glGenBuffers(1, &glsl->vbo[i].vbo_secondary);
}
2015-12-05 07:33:21 +01:00
return glsl;
2011-01-05 19:07:12 +01:00
error:
2015-12-01 07:12:26 +01:00
gl_glsl_destroy_resources(glsl);
2015-12-01 07:12:26 +01:00
if (glsl)
free(glsl);
2015-12-05 07:33:21 +01:00
return NULL;
}
2011-01-05 19:07:12 +01:00
#if 0
static float t = 0;
2016-04-13 04:16:49 +02:00
#endif
2016-04-13 04:16:49 +02:00
static void glsl_uniform_set_parameter(void *data, void *uniform_data)
{
struct uniform_info *param = (struct uniform_info*)data;
if (!param)
return;
switch (param->type)
{
case UNIFORM_1F:
glUniform1f(param->location, param->result.f.v0);
2016-04-13 04:16:49 +02:00
break;
case UNIFORM_2F:
glUniform2f(param->location, param->result.f.v0,
param->result.f.v1);
2016-04-13 04:16:49 +02:00
break;
case UNIFORM_3F:
glUniform3f(param->location, param->result.f.v0,
param->result.f.v1, param->result.f.v2);
2016-04-13 04:16:49 +02:00
break;
case UNIFORM_4F:
glUniform4f(param->location, param->result.f.v0,
param->result.f.v1, param->result.f.v2,
param->result.f.v3);
2016-04-13 04:16:49 +02:00
break;
case UNIFORM_1FV:
glUniform1fv(param->location, 1, param->result.floatv);
2016-04-13 04:16:49 +02:00
break;
case UNIFORM_2FV:
glUniform2fv(param->location, 1, param->result.floatv);
2016-04-13 04:16:49 +02:00
break;
case UNIFORM_3FV:
glUniform3fv(param->location, 1, param->result.floatv);
2016-04-13 04:16:49 +02:00
break;
case UNIFORM_4FV:
glUniform4fv(param->location, 1, param->result.floatv);
break;
case UNIFORM_1I:
glUniform1i(param->location, param->result.integer.v0);
2016-04-13 04:16:49 +02:00
break;
}
}
2015-12-05 07:33:21 +01:00
static void gl_glsl_set_params(void *data, void *shader_data,
unsigned width, unsigned height,
2011-01-05 19:07:12 +01:00
unsigned tex_width, unsigned tex_height,
unsigned out_width, unsigned out_height,
unsigned frame_count,
const void *_info,
const void *_prev_info,
const void *_feedback_info,
const void *_fbo_info, unsigned fbo_info_cnt)
2011-01-05 19:07:12 +01:00
{
unsigned i;
2016-04-13 04:16:49 +02:00
struct uniform_info uniform_params[10];
GLfloat buffer[512];
struct glsl_attrib attribs[32];
float input_size[2], output_size[2], texture_size[2];
unsigned uniform_count = 0;
unsigned texunit = 1;
const struct shader_uniforms *uni = NULL;
size_t size = 0, attribs_size = 0;
2015-07-12 04:16:40 +02:00
const struct gfx_tex_info *info = (const struct gfx_tex_info*)_info;
const struct gfx_tex_info *prev_info = (const struct gfx_tex_info*)_prev_info;
const struct gfx_tex_info *feedback_info = (const struct gfx_tex_info*)_feedback_info;
2015-07-12 04:16:40 +02:00
const struct gfx_tex_info *fbo_info = (const struct gfx_tex_info*)_fbo_info;
struct glsl_attrib *attr = (struct glsl_attrib*)attribs;
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)shader_data;
2015-12-01 07:12:26 +01:00
if (!glsl)
return;
2016-04-13 02:36:00 +02:00
uni = (const struct shader_uniforms*)&glsl->uniforms[glsl->glsl_active_index];
(void)data;
2015-12-01 07:12:26 +01:00
if (glsl->gl_program[glsl->glsl_active_index] == 0)
2011-11-12 14:18:10 +01:00
return;
2011-01-05 19:07:12 +01:00
#if 0
t += 0.004;
glUseProgram(glsl->gl_program[GL_SHADER_STOCK_XMB]);
int location = glGetUniformLocation(glsl->gl_program[GL_SHADER_STOCK_XMB], "time");
glUniform1f(location, t);
glUseProgram(0);
#endif
input_size [0] = (float)width;
input_size [1] = (float)height;
output_size[0] = (float)out_width;
output_size[1] = (float)out_height;
texture_size[0] = (float)tex_width;
texture_size[1] = (float)tex_height;
2011-01-05 19:07:12 +01:00
uniform_params[0].enabled = false;
uniform_params[0].location = uni->input_size;
uniform_params[0].type = UNIFORM_2FV;
uniform_params[0].result.floatv = input_size;
2012-10-21 02:58:51 +02:00
if (uni->input_size >= 0)
uniform_params[0].enabled = true;
uniform_params[1].enabled = false;
uniform_params[1].location = uni->output_size;
uniform_params[1].type = UNIFORM_2FV;
uniform_params[1].result.floatv = output_size;
2011-01-05 19:07:12 +01:00
2012-10-21 02:58:51 +02:00
if (uni->output_size >= 0)
uniform_params[1].enabled = true;
uniform_params[2].enabled = false;
uniform_params[2].location = uni->texture_size;
uniform_params[2].type = UNIFORM_2FV;
uniform_params[2].result.floatv = texture_size;
2012-10-21 02:58:51 +02:00
if (uni->texture_size >= 0)
uniform_params[2].enabled = true;
2011-05-18 20:22:27 +02:00
uniform_count += 3;
2015-12-01 07:12:26 +01:00
if (uni->frame_count >= 0 && glsl->glsl_active_index)
{
2015-12-01 07:12:26 +01:00
unsigned modulo = glsl->shader->pass[glsl->glsl_active_index - 1].frame_count_mod;
if (modulo)
frame_count %= modulo;
uniform_params[uniform_count].enabled = true;
uniform_params[uniform_count].location = uni->frame_count;
uniform_params[uniform_count].type = UNIFORM_1I;
uniform_params[uniform_count].result.integer.v0 = frame_count;
uniform_count++;
}
uniform_params[uniform_count].enabled = true;
uniform_params[uniform_count].location = uni->frame_direction;
uniform_params[uniform_count].type = UNIFORM_1I;
uniform_params[uniform_count].result.integer.v0 =
state_manager_frame_is_reversed() ? -1 : 1;
uniform_count++;
2016-04-13 19:27:04 +02:00
for (i = 0; i < uniform_count; i++)
glsl_uniform_set_parameter(&uniform_params[i], NULL);
2011-11-12 14:18:10 +01:00
2016-04-13 01:42:40 +02:00
/* Set lookup textures. */
2015-12-01 07:12:26 +01:00
for (i = 0; i < glsl->shader->luts; i++)
2011-11-12 14:18:10 +01:00
{
2016-04-13 05:06:24 +02:00
struct uniform_info lut_uniform;
2015-01-11 19:52:02 +01:00
if (uni->lut_texture[i] < 0)
continue;
/* Have to rebind as HW render could override this. */
glActiveTexture(GL_TEXTURE0 + texunit);
2015-12-01 07:12:26 +01:00
glBindTexture(GL_TEXTURE_2D, glsl->gl_teximage[i]);
2016-04-13 05:06:24 +02:00
lut_uniform.enabled = true;
lut_uniform.location = uni->lut_texture[i];
lut_uniform.type = UNIFORM_1I;
lut_uniform.result.integer.v0 = texunit;
glsl_uniform_set_parameter(&lut_uniform, NULL);
2015-01-11 19:52:02 +01:00
texunit++;
2011-11-12 14:18:10 +01:00
}
2015-12-01 07:12:26 +01:00
if (glsl->glsl_active_index)
2011-11-12 14:18:10 +01:00
{
2016-04-13 06:04:29 +02:00
unsigned j;
struct uniform_info orig_uniforms[2];
2016-04-13 06:18:53 +02:00
struct uniform_info feedback_uniforms[2];
2016-04-13 06:04:29 +02:00
/* Set original texture. */
2012-10-21 02:58:51 +02:00
if (uni->orig.texture >= 0)
{
2016-04-13 05:06:24 +02:00
struct uniform_info orig_tex_uniform;
2014-09-08 17:57:18 +02:00
/* Bind original texture. */
glActiveTexture(GL_TEXTURE0 + texunit);
2016-04-13 05:06:24 +02:00
orig_tex_uniform.enabled = true;
orig_tex_uniform.location = uni->orig.texture;
orig_tex_uniform.type = UNIFORM_1I;
orig_tex_uniform.result.integer.v0 = texunit;
glsl_uniform_set_parameter(&orig_tex_uniform, NULL);
2012-10-21 02:58:51 +02:00
glBindTexture(GL_TEXTURE_2D, info->tex);
texunit++;
2012-10-21 02:58:51 +02:00
}
2016-04-13 06:04:29 +02:00
orig_uniforms[0].enabled = false;
orig_uniforms[0].location = uni->orig.texture_size;
orig_uniforms[0].type = UNIFORM_2FV;
orig_uniforms[0].result.floatv = (float*)info->tex_size;
2012-10-21 02:58:51 +02:00
if (uni->orig.texture_size >= 0)
2016-04-13 06:04:29 +02:00
orig_uniforms[0].enabled = true;
orig_uniforms[1].enabled = false;
orig_uniforms[1].location = uni->orig.input_size;
orig_uniforms[1].type = UNIFORM_2FV;
orig_uniforms[1].result.floatv = (float*)info->input_size;
2011-11-12 14:18:10 +01:00
2012-10-21 02:58:51 +02:00
if (uni->orig.input_size >= 0)
2016-04-13 06:04:29 +02:00
orig_uniforms[1].enabled = true;
for (j = 0; j < 2; j++)
glsl_uniform_set_parameter(&orig_uniforms[i], NULL);
2014-09-08 17:57:18 +02:00
/* Pass texture coordinates. */
2012-10-21 02:58:51 +02:00
if (uni->orig.tex_coord >= 0)
{
2016-04-13 05:11:22 +02:00
attr->loc = uni->orig.tex_coord;
attr->size = 2;
attr->offset = size * sizeof(GLfloat);
attribs_size++;
attr++;
memcpy(buffer + size, info->coord, 8 * sizeof(GLfloat));
size += 8;
}
/* Set feedback texture. */
if (uni->feedback.texture >= 0)
{
2016-04-13 06:40:40 +02:00
struct uniform_info feedback_texture_param;
/* Bind original texture. */
glActiveTexture(GL_TEXTURE0 + texunit);
2016-04-13 06:40:40 +02:00
feedback_texture_param.enabled = true;
feedback_texture_param.location = uni->pass[i].texture;
feedback_texture_param.type = UNIFORM_1I;
feedback_texture_param.result.integer.v0 = texunit;
glsl_uniform_set_parameter(&feedback_texture_param, NULL);
glBindTexture(GL_TEXTURE_2D, feedback_info->tex);
texunit++;
}
2016-04-13 06:18:53 +02:00
feedback_uniforms[0].enabled = false;
feedback_uniforms[0].location = uni->feedback.texture_size;
feedback_uniforms[0].type = UNIFORM_2FV;
feedback_uniforms[0].result.floatv = (float*)feedback_info->tex_size;
if (uni->feedback.texture_size >= 0)
2016-04-13 06:18:53 +02:00
feedback_uniforms[0].enabled = true;
feedback_uniforms[1].enabled = false;
feedback_uniforms[1].location = uni->feedback.input_size;
feedback_uniforms[1].type = UNIFORM_2FV;
feedback_uniforms[1].result.floatv = (float*)feedback_info->input_size;
if (uni->feedback.input_size >= 0)
2016-04-13 06:18:53 +02:00
feedback_uniforms[1].enabled = true;
for (j = 0; j < 2; j++)
glsl_uniform_set_parameter(&feedback_uniforms[i], NULL);
/* Pass texture coordinates. */
if (uni->feedback.tex_coord >= 0)
{
2016-04-13 05:11:22 +02:00
attr->loc = uni->feedback.tex_coord;
attr->size = 2;
attr->offset = size * sizeof(GLfloat);
attribs_size++;
attr++;
memcpy(buffer + size, feedback_info->coord, 8 * sizeof(GLfloat));
size += 8;
}
2014-09-08 17:57:18 +02:00
/* Bind FBO textures. */
for (i = 0; i < fbo_info_cnt; i++)
2011-11-12 14:18:10 +01:00
{
2016-04-13 06:25:49 +02:00
unsigned j;
struct uniform_info fbo_tex_params[3];
2012-10-21 02:58:51 +02:00
if (uni->pass[i].texture)
{
glActiveTexture(GL_TEXTURE0 + texunit);
glBindTexture(GL_TEXTURE_2D, fbo_info[i].tex);
2016-04-13 06:25:49 +02:00
fbo_tex_params[0].enabled = true;
fbo_tex_params[0].location = uni->pass[i].texture;
fbo_tex_params[0].type = UNIFORM_1I;
fbo_tex_params[0].result.integer.v0 = texunit;
texunit++;
}
2016-04-13 06:25:49 +02:00
fbo_tex_params[1].enabled = false;
fbo_tex_params[1].location = uni->pass[i].texture_size;
fbo_tex_params[1].type = UNIFORM_2FV;
fbo_tex_params[1].result.floatv = (float*)fbo_info[i].tex_size;
2012-10-21 02:58:51 +02:00
if (uni->pass[i].texture_size >= 0)
2016-04-13 06:25:49 +02:00
fbo_tex_params[1].enabled = true;
fbo_tex_params[2].enabled = false;
fbo_tex_params[2].location = uni->pass[i].input_size;
fbo_tex_params[2].type = UNIFORM_2FV;
fbo_tex_params[2].result.floatv = (float*)fbo_info[i].input_size;
2012-10-21 02:58:51 +02:00
if (uni->pass[i].input_size >= 0)
2016-04-13 06:25:49 +02:00
fbo_tex_params[2].enabled = true;
for (j = 0; j < 3; j++)
glsl_uniform_set_parameter(&fbo_tex_params[i], NULL);
2012-10-21 02:58:51 +02:00
if (uni->pass[i].tex_coord >= 0)
{
2016-04-13 05:11:22 +02:00
attr->loc = uni->pass[i].tex_coord;
attr->size = 2;
attr->offset = size * sizeof(GLfloat);
attribs_size++;
attr++;
memcpy(buffer + size, fbo_info[i].coord, 8 * sizeof(GLfloat));
size += 8;
}
}
2011-11-12 14:18:10 +01:00
}
2014-09-08 17:57:18 +02:00
/* Set previous textures. Only bind if they're actually used. */
for (i = 0; i < PREV_TEXTURES; i++)
2011-11-12 14:18:10 +01:00
{
2016-04-13 06:30:00 +02:00
unsigned j;
struct uniform_info prev_tex_params[3];
2012-10-21 02:58:51 +02:00
if (uni->prev[i].texture >= 0)
2011-11-12 14:18:10 +01:00
{
glActiveTexture(GL_TEXTURE0 + texunit);
2011-11-12 14:18:10 +01:00
glBindTexture(GL_TEXTURE_2D, prev_info[i].tex);
2016-04-13 06:30:00 +02:00
prev_tex_params[0].enabled = true;
prev_tex_params[0].location = uni->prev[i].texture;
prev_tex_params[0].type = UNIFORM_1I;
prev_tex_params[0].result.integer.v0 = texunit;
texunit++;
}
2016-04-13 06:30:00 +02:00
prev_tex_params[1].enabled = false;
prev_tex_params[1].location = uni->prev[i].texture_size;
prev_tex_params[1].type = UNIFORM_2FV;
prev_tex_params[1].result.floatv = (float*)prev_info[i].tex_size;
2012-10-21 02:58:51 +02:00
if (uni->prev[i].texture_size >= 0)
2016-04-13 06:30:00 +02:00
prev_tex_params[1].enabled = true;
prev_tex_params[2].enabled = false;
prev_tex_params[2].location = uni->prev[i].input_size;
prev_tex_params[2].type = UNIFORM_2FV;
prev_tex_params[2].result.floatv = (float*)prev_info[i].input_size;
2012-10-21 02:58:51 +02:00
if (uni->prev[i].input_size >= 0)
2016-04-13 06:30:00 +02:00
prev_tex_params[2].enabled = true;
for (j = 0; j < 3; j++)
glsl_uniform_set_parameter(&prev_tex_params[i], NULL);
2014-09-08 17:57:18 +02:00
/* Pass texture coordinates. */
2012-10-21 02:58:51 +02:00
if (uni->prev[i].tex_coord >= 0)
{
2016-04-13 05:11:22 +02:00
attr->loc = uni->prev[i].tex_coord;
attr->size = 2;
attr->offset = size * sizeof(GLfloat);
attribs_size++;
attr++;
memcpy(buffer + size, prev_info[i].coord, 8 * sizeof(GLfloat));
size += 8;
2011-11-12 14:18:10 +01:00
}
}
if (size)
2016-04-13 02:36:00 +02:00
gl_glsl_set_attribs(glsl, glsl->vbo[glsl->glsl_active_index].vbo_secondary,
&glsl->vbo[glsl->glsl_active_index].buffer_secondary,
&glsl->vbo[glsl->glsl_active_index].size_secondary,
buffer, size, attribs, attribs_size);
glActiveTexture(GL_TEXTURE0);
2011-11-12 14:18:10 +01:00
2014-09-08 17:57:18 +02:00
/* #pragma parameters. */
2015-12-01 07:12:26 +01:00
for (i = 0; i < glsl->shader->num_parameters; i++)
2014-05-23 12:09:57 +02:00
{
2016-04-13 06:40:40 +02:00
struct uniform_info pragma_param;
int location = glGetUniformLocation(
2015-12-01 07:12:26 +01:00
glsl->gl_program[glsl->glsl_active_index],
glsl->shader->parameters[i].id);
2016-04-13 06:40:40 +02:00
pragma_param.enabled = true;
pragma_param.location = location;
pragma_param.type = UNIFORM_1F;
pragma_param.result.f.v0 = glsl->shader->parameters[i].current;
glsl_uniform_set_parameter(&pragma_param, NULL);
2014-05-23 12:09:57 +02:00
}
2014-09-08 17:57:18 +02:00
/* Set state parameters. */
2015-12-01 07:12:26 +01:00
if (glsl->gl_state_tracker)
2011-11-12 14:18:10 +01:00
{
static struct state_tracker_uniform state_info[GFX_MAX_VARIABLES];
2011-11-12 14:18:10 +01:00
static unsigned cnt = 0;
2015-12-01 07:12:26 +01:00
if (glsl->glsl_active_index == 1)
cnt = state_tracker_get_uniform(glsl->gl_state_tracker, state_info,
2014-09-08 17:57:18 +02:00
GFX_MAX_VARIABLES, frame_count);
2011-11-12 14:18:10 +01:00
for (i = 0; i < cnt; i++)
2011-11-12 14:18:10 +01:00
{
2016-04-13 06:40:40 +02:00
struct uniform_info state_param;
int location = glGetUniformLocation(
2015-12-01 07:12:26 +01:00
glsl->gl_program[glsl->glsl_active_index],
state_info[i].id);
2016-04-13 06:40:40 +02:00
state_param.enabled = true;
state_param.location = location;
state_param.type = UNIFORM_1F;
state_param.result.f.v0 = state_info[i].value;
glsl_uniform_set_parameter(&state_param, NULL);
}
2011-01-05 19:07:12 +01:00
}
}
2015-12-05 07:33:21 +01:00
static bool gl_glsl_set_mvp(void *data, void *shader_data, const math_matrix_4x4 *mat)
{
int loc;
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)shader_data;
2015-12-01 07:12:26 +01:00
(void)data;
if (!glsl || !glsl->shader->modern)
2014-11-29 21:07:12 +01:00
{
gl_ff_matrix(mat);
return false;
}
2016-04-13 02:36:00 +02:00
loc = glsl->uniforms[glsl->glsl_active_index].mvp;
if (loc >= 0)
glUniformMatrix4fv(loc, 1, GL_FALSE, mat->data);
2012-10-21 02:58:51 +02:00
return true;
}
2015-12-05 07:33:21 +01:00
static bool gl_glsl_set_coords(void *handle_data, void *shader_data, const void *data)
{
/* Avoid hitting malloc on every single regular quad draw. */
GLfloat short_buffer[4 * (2 + 2 + 4 + 2)];
GLfloat *buffer;
struct glsl_attrib attribs[4];
size_t attribs_size = 0, size = 0;
struct glsl_attrib *attr = NULL;
const struct shader_uniforms *uni = NULL;
2015-07-12 03:57:06 +02:00
const struct gfx_coords *coords = (const struct gfx_coords*)data;
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)shader_data;
2015-12-01 07:12:26 +01:00
if (!glsl || !glsl->shader->modern || !coords)
2014-11-29 21:07:12 +01:00
{
gl_ff_vertex(coords);
return false;
}
buffer = short_buffer;
if (coords->vertices > 4)
2014-09-08 17:57:18 +02:00
buffer = (GLfloat*)calloc(coords->vertices *
(2 + 2 + 4 + 2), sizeof(*buffer));
if (!buffer)
2014-11-29 21:07:12 +01:00
{
gl_ff_vertex(coords);
return false;
}
attr = attribs;
2016-04-13 02:36:00 +02:00
uni = &glsl->uniforms[glsl->glsl_active_index];
2012-10-21 02:58:51 +02:00
if (uni->tex_coord >= 0)
{
attr->loc = uni->tex_coord;
attr->size = 2;
attr->offset = size * sizeof(GLfloat);
attribs_size++;
attr++;
2014-09-08 17:57:18 +02:00
memcpy(buffer + size, coords->tex_coord,
2 * coords->vertices * sizeof(GLfloat));
size += 2 * coords->vertices;
}
2012-10-21 02:58:51 +02:00
if (uni->vertex_coord >= 0)
{
attr->loc = uni->vertex_coord;
attr->size = 2;
attr->offset = size * sizeof(GLfloat);
attribs_size++;
attr++;
2014-09-08 17:57:18 +02:00
memcpy(buffer + size, coords->vertex,
2 * coords->vertices * sizeof(GLfloat));
size += 2 * coords->vertices;
}
2012-10-21 02:58:51 +02:00
if (uni->color >= 0)
{
attr->loc = uni->color;
attr->size = 4;
attr->offset = size * sizeof(GLfloat);
attribs_size++;
attr++;
2014-09-08 17:57:18 +02:00
memcpy(buffer + size, coords->color,
4 * coords->vertices * sizeof(GLfloat));
size += 4 * coords->vertices;
}
2012-10-21 02:58:51 +02:00
if (uni->lut_tex_coord >= 0)
{
attr->loc = uni->lut_tex_coord;
attr->size = 2;
attr->offset = size * sizeof(GLfloat);
attribs_size++;
attr++;
2014-09-08 17:57:18 +02:00
memcpy(buffer + size, coords->lut_tex_coord,
2 * coords->vertices * sizeof(GLfloat));
size += 2 * coords->vertices;
}
if (size)
2015-12-01 07:12:26 +01:00
gl_glsl_set_attribs(glsl,
2016-04-13 02:36:00 +02:00
glsl->vbo[glsl->glsl_active_index].vbo_primary,
&glsl->vbo[glsl->glsl_active_index].buffer_primary,
&glsl->vbo[glsl->glsl_active_index].size_primary,
buffer, size,
attribs, attribs_size);
if (buffer != short_buffer)
free(buffer);
return true;
}
2015-12-05 07:33:21 +01:00
static void gl_glsl_use(void *data, void *shader_data, unsigned idx)
{
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)shader_data;
2015-12-01 07:12:26 +01:00
(void)data;
if (!glsl)
return;
2015-12-01 07:12:26 +01:00
gl_glsl_reset_attrib(glsl);
2015-12-01 07:12:26 +01:00
glsl->glsl_active_index = idx;
glUseProgram(glsl->gl_program[idx]);
}
2011-03-12 15:30:57 +01:00
2015-12-05 07:33:21 +01:00
static unsigned gl_glsl_num(void *data)
2011-03-12 15:30:57 +01:00
{
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
2015-12-01 07:12:26 +01:00
if (glsl && glsl->shader)
return glsl->shader->passes;
2014-10-04 22:24:14 +02:00
return 0;
2011-03-12 15:30:57 +01:00
}
2011-03-14 21:28:30 +01:00
2015-12-05 07:33:21 +01:00
static bool gl_glsl_filter_type(void *data, unsigned idx, bool *smooth)
2011-03-14 21:28:30 +01:00
{
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
2015-12-01 07:12:26 +01:00
if (glsl && idx
&& (glsl->shader->pass[idx - 1].filter != RARCH_FILTER_UNSPEC)
)
2011-03-14 21:28:30 +01:00
{
2015-12-01 07:12:26 +01:00
*smooth = (glsl->shader->pass[idx - 1].filter == RARCH_FILTER_LINEAR);
return true;
2011-03-14 21:28:30 +01:00
}
2014-08-27 03:28:22 +02:00
return false;
2011-03-14 21:28:30 +01:00
}
2015-12-05 07:33:21 +01:00
static enum gfx_wrap_type gl_glsl_wrap_type(void *data, unsigned idx)
{
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
2015-12-01 07:12:26 +01:00
if (glsl && idx)
return glsl->shader->pass[idx - 1].wrap;
2014-08-27 03:28:22 +02:00
return RARCH_WRAP_BORDER;
}
2015-12-05 07:33:21 +01:00
static void gl_glsl_shader_scale(void *data, unsigned idx, struct gfx_fbo_scale *scale)
{
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
2015-12-01 07:12:26 +01:00
if (glsl && idx)
*scale = glsl->shader->pass[idx - 1].fbo;
else
scale->valid = false;
}
2012-09-25 01:26:22 +02:00
2015-12-05 07:33:21 +01:00
static unsigned gl_glsl_get_prev_textures(void *data)
{
unsigned i, j;
unsigned max_prev = 0;
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
2015-12-01 07:12:26 +01:00
if (!glsl)
return 0;
2015-12-01 07:12:26 +01:00
for (i = 1; i <= glsl->shader->passes; i++)
for (j = 0; j < PREV_TEXTURES; j++)
2016-04-13 02:36:00 +02:00
if (glsl->uniforms[i].prev[j].texture >= 0)
2016-03-02 00:07:31 +01:00
max_prev = MAX(j + 1, max_prev);
return max_prev;
}
2015-12-05 07:33:21 +01:00
static bool gl_glsl_mipmap_input(void *data, unsigned idx)
2014-05-11 13:13:38 +02:00
{
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
2015-12-01 07:12:26 +01:00
if (glsl && idx)
return glsl->shader->pass[idx - 1].mipmap;
2014-08-27 03:28:22 +02:00
return false;
2014-05-11 13:13:38 +02:00
}
2015-12-05 07:33:21 +01:00
static bool gl_glsl_get_feedback_pass(void *data, unsigned *index)
{
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
2015-12-01 07:12:26 +01:00
if (!glsl || glsl->shader->feedback_pass < 0)
return false;
2015-12-01 07:12:26 +01:00
*index = glsl->shader->feedback_pass;
return true;
}
2015-12-05 07:33:21 +01:00
static struct video_shader *gl_glsl_get_current_shader(void *data)
{
2015-12-05 07:33:21 +01:00
glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
2015-12-01 07:12:26 +01:00
if (!glsl)
return NULL;
2015-12-01 07:12:26 +01:00
return glsl->shader;
}
2012-09-25 01:26:22 +02:00
void gl_glsl_set_get_proc_address(gfx_ctx_proc_t (*proc)(const char*))
{
glsl_get_proc_address = proc;
}
2014-09-08 17:57:18 +02:00
void gl_glsl_set_context_type(bool core_profile,
unsigned major, unsigned minor)
2013-06-30 22:58:22 +02:00
{
glsl_core = core_profile;
glsl_major = major;
glsl_minor = minor;
2013-06-30 22:58:22 +02:00
}
const shader_backend_t gl_glsl_backend = {
gl_glsl_init,
gl_glsl_deinit,
gl_glsl_set_params,
gl_glsl_use,
gl_glsl_num,
gl_glsl_filter_type,
gl_glsl_wrap_type,
gl_glsl_shader_scale,
gl_glsl_set_coords,
gl_glsl_set_mvp,
gl_glsl_get_prev_textures,
gl_glsl_get_feedback_pass,
2014-05-11 13:13:38 +02:00
gl_glsl_mipmap_input,
gl_glsl_get_current_shader,
RARCH_SHADER_GLSL,
"glsl"
};