shader_glsl.c 49.9 KB
Newer Older
Themaister's avatar
Themaister committed
1
/*  RetroArch - A frontend for libretro.
2
 *  Copyright (C) 2010-2014 - Hans-Kristian Arntzen
twinaphex's avatar
twinaphex committed
3
 *  Copyright (C) 2011-2017 - Daniel De Matteis
Higor Eurípedes's avatar
Higor Eurípedes committed
4
 *
Themaister's avatar
Themaister committed
5
 *  RetroArch is free software: you can redistribute it and/or modify it under the terms
Themaister's avatar
Themaister committed
6
7
8
 *  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.
 *
Themaister's avatar
Themaister committed
9
 *  RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
Themaister's avatar
Themaister committed
10
11
12
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
 *  PURPOSE.  See the GNU General Public License for more details.
 *
Themaister's avatar
Themaister committed
13
 *  You should have received a copy of the GNU General Public License along with RetroArch.
Themaister's avatar
Themaister committed
14
15
16
 *  If not, see <http://www.gnu.org/licenses/>.
 */

twinaphex's avatar
twinaphex committed
17
#include <stdlib.h>
Themaister's avatar
Themaister committed
18
#include <string.h>
twinaphex's avatar
twinaphex committed
19
20
21

#include <compat/strl.h>
#include <compat/posix_string.h>
twinaphex's avatar
twinaphex committed
22
#include <file/file_path.h>
twinaphex's avatar
twinaphex committed
23
#include <retro_assert.h>
twinaphex's avatar
twinaphex committed
24
#include <streams/file_stream.h>
twinaphex's avatar
twinaphex committed
25
#include <string/stdstring.h>
twinaphex's avatar
twinaphex committed
26

twinaphex's avatar
twinaphex committed
27
28
29
30
31
#ifdef HAVE_CONFIG_H
#include "../../config.h"
#endif

#ifdef HAVE_OPENGL
twinaphex's avatar
twinaphex committed
32
#include <gfx/gl_capabilities.h>
twinaphex's avatar
twinaphex committed
33
34
35
#include "../common/gl_common.h"
#endif

Themaister's avatar
Themaister committed
36
#include "shader_glsl.h"
37
#include "../../managers/state_manager.h"
38
#include "../../core.h"
39

40
#define PREV_TEXTURES (GFX_MAX_TEXTURES - 1)
41

twinaphex's avatar
twinaphex committed
42
/* Cache the VBO. */
Themaister's avatar
Themaister committed
43
44
45
46
struct cache_vbo
{
   GLuint vbo_primary;
   GLuint vbo_secondary;
twinaphex's avatar
Updates    
twinaphex committed
47
   size_t size_primary;
Themaister's avatar
Themaister committed
48
   size_t size_secondary;
twinaphex's avatar
Updates    
twinaphex committed
49
50
   GLfloat *buffer_primary;
   GLfloat *buffer_secondary;
Themaister's avatar
Themaister committed
51
52
};

twinaphex's avatar
twinaphex committed
53
struct shader_program_glsl_data
54
55
56
57
58
59
60
{
   GLuint vprg;
   GLuint fprg;

   GLuint id;
};

Themaister's avatar
Themaister committed
61
62
63
64
65
66
67
struct glsl_attrib
{
   GLint loc;
   GLsizei size;
   GLsizei offset;
};

68
69
static gfx_ctx_proc_t (*glsl_get_proc_address)(const char*);

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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;
   int frame_direction;

Themaister's avatar
Themaister committed
93
   int lut_texture[GFX_MAX_TEXTURES];
twinaphex's avatar
Updates    
twinaphex committed
94
   unsigned frame_count_mod;
Higor Eurípedes's avatar
Higor Eurípedes committed
95

96
   struct shader_uniforms_frame orig;
97
   struct shader_uniforms_frame feedback;
Themaister's avatar
Themaister committed
98
   struct shader_uniforms_frame pass[GFX_MAX_SHADERS];
99
100
101
102
   struct shader_uniforms_frame prev[PREV_TEXTURES];
};


Themaister's avatar
Themaister committed
103
104
105
106
107
static const char *glsl_prefixes[] = {
   "",
   "ruby",
};

108
109
110
111
112
113
114
115
116
117
118
#include "../drivers/gl_shaders/modern_opaque.glsl.vert.h"
#include "../drivers/gl_shaders/modern_opaque.glsl.frag.h"
#include "../drivers/gl_shaders/core_opaque.glsl.vert.h"
#include "../drivers/gl_shaders/core_opaque.glsl.frag.h"
#include "../drivers/gl_shaders/legacy_opaque.glsl.vert.h"
#include "../drivers/gl_shaders/legacy_opaque.glsl.frag.h"
#include "../drivers/gl_shaders/modern_alpha_blend.glsl.vert.h"
#include "../drivers/gl_shaders/modern_alpha_blend.glsl.frag.h"
#include "../drivers/gl_shaders/core_alpha_blend.glsl.vert.h"
#include "../drivers/gl_shaders/core_alpha_blend.glsl.frag.h"

twinaphex's avatar
twinaphex committed
119
#ifdef HAVE_SHADERPIPELINE
120
121
#include "../drivers/gl_shaders/core_pipeline_snow.glsl.frag.h"
#include "../drivers/gl_shaders/core_pipeline_snow_simple.glsl.frag.h"
122
#include "../drivers/gl_shaders/core_pipeline_xmb_ribbon.glsl.frag.h"
twinaphex's avatar
twinaphex committed
123
#include "../drivers/gl_shaders/core_pipeline_xmb_ribbon_simple.glsl.frag.h"
124
125
#include "../drivers/gl_shaders/core_pipeline_bokeh.glsl.frag.h"
#include "../drivers/gl_shaders/core_pipeline_snowflake.glsl.frag.h"
126
127
#include "../drivers/gl_shaders/legacy_pipeline_xmb_ribbon_simple.glsl.vert.h"
#include "../drivers/gl_shaders/modern_pipeline_xmb_ribbon_simple.glsl.vert.h"
128
#include "../drivers/gl_shaders/pipeline_xmb_ribbon_simple.glsl.frag.h"
129
#include "../drivers/gl_shaders/pipeline_snow.glsl.frag.h"
130
131
#include "../drivers/gl_shaders/pipeline_snow.glsl.vert.h"
#include "../drivers/gl_shaders/pipeline_snow_core.glsl.vert.h"
132
#include "../drivers/gl_shaders/pipeline_snow_simple.glsl.frag.h"
133
#include "../drivers/gl_shaders/legacy_pipeline_snow.glsl.vert.h"
134
135
#include "../drivers/gl_shaders/legacy_pipeline_xmb_ribbon.glsl.vert.h"
#include "../drivers/gl_shaders/modern_pipeline_xmb_ribbon.glsl.vert.h"
136
#include "../drivers/gl_shaders/pipeline_xmb_ribbon.glsl.frag.h"
137
#include "../drivers/gl_shaders/pipeline_bokeh.glsl.frag.h"
radius's avatar
radius committed
138
#include "../drivers/gl_shaders/pipeline_snowflake.glsl.frag.h"
twinaphex's avatar
twinaphex committed
139
#endif
140

141
142
typedef struct glsl_shader_data
{
143
   char alias_define[1024];
twinaphex's avatar
Updates    
twinaphex committed
144
145
   GLint attribs_elems[32 * PREV_TEXTURES + 2 + 4 + GFX_MAX_SHADERS];
   unsigned attribs_index;
146
   unsigned active_idx;
twinaphex's avatar
Update    
twinaphex committed
147
   unsigned current_idx;
148
   GLuint lut_textures[GFX_MAX_TEXTURES];
twinaphex's avatar
Update    
twinaphex committed
149
150
   float  current_mat_data[GFX_MAX_SHADERS];
   float* current_mat_data_pointer[GFX_MAX_SHADERS];
twinaphex's avatar
Updates    
twinaphex committed
151
152
153
154
   struct shader_uniforms uniforms[GFX_MAX_SHADERS];
   struct cache_vbo vbo[GFX_MAX_SHADERS];
   struct shader_program_glsl_data prg[GFX_MAX_SHADERS];
   struct video_shader *shader;
155
   state_tracker_t *state_tracker;
156
157
} glsl_shader_data_t;

158
159
160
161
static bool glsl_core;
static unsigned glsl_major;
static unsigned glsl_minor;

twinaphex's avatar
Updates    
twinaphex committed
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
static bool gl_glsl_add_lut(
      const struct video_shader *shader,
      unsigned i, void *textures_data)
{
   struct texture_image img;
   GLuint *textures_lut                 = (GLuint*)textures_data;
   enum texture_filter_type filter_type = TEXTURE_FILTER_LINEAR;

   img.width         = 0;
   img.height        = 0;
   img.pixels        = NULL;
   img.supports_rgba = video_driver_supports_rgba();

   if (!image_texture_load(&img, shader->lut[i].path))
   {
      RARCH_ERR("[GL]: Failed to load texture image from: \"%s\"\n",
            shader->lut[i].path);
      return false;
   }

   RARCH_LOG("[GL]: Loaded texture image from: \"%s\" ...\n",
         shader->lut[i].path);

   if (shader->lut[i].filter == RARCH_FILTER_NEAREST)
      filter_type = TEXTURE_FILTER_NEAREST;

   if (shader->lut[i].mipmap)
   {
      if (filter_type == TEXTURE_FILTER_NEAREST)
         filter_type = TEXTURE_FILTER_MIPMAP_NEAREST;
      else
         filter_type = TEXTURE_FILTER_MIPMAP_LINEAR;
   }

   gl_load_texture_data(textures_lut[i],
         shader->lut[i].wrap,
         filter_type, 4,
         img.width, img.height,
         img.pixels, sizeof(uint32_t));
   image_texture_free(&img);

   return true;
}

static bool gl_glsl_load_luts(
      const struct video_shader *shader,
      GLuint *textures_lut)
{
   unsigned i;
   unsigned num_luts = MIN(shader->luts, GFX_MAX_TEXTURES);

   if (!shader->luts)
      return true;

   glGenTextures(num_luts, textures_lut);

   for (i = 0; i < num_luts; i++)
   {
      if (!gl_glsl_add_lut(shader, i, textures_lut))
         return false;
   }

   glBindTexture(GL_TEXTURE_2D, 0);
   return true;
}

228
static GLint gl_glsl_get_uniform(glsl_shader_data_t *glsl,
twinaphex's avatar
twinaphex committed
229
      GLuint prog, const char *base)
230
{
231
   unsigned i;
232
   GLint loc;
233
   char buf[80];
twinaphex's avatar
twinaphex committed
234
235

   buf[0] = '\0';
236

twinaphex's avatar
twinaphex committed
237
   snprintf(buf, sizeof(buf), "%s%s", glsl->shader->prefix, base);
238
   loc = glGetUniformLocation(prog, buf);
Themaister's avatar
Themaister committed
239
240
   if (loc >= 0)
      return loc;
241

242
   for (i = 0; i < ARRAY_SIZE(glsl_prefixes); i++)
243
244
   {
      snprintf(buf, sizeof(buf), "%s%s", glsl_prefixes[i], base);
245
      loc = glGetUniformLocation(prog, buf);
246
247
248
249
250
251
252
      if (loc >= 0)
         return loc;
   }

   return -1;
}

253
static GLint gl_glsl_get_attrib(glsl_shader_data_t *glsl,
twinaphex's avatar
twinaphex committed
254
      GLuint prog, const char *base)
255
{
256
   unsigned i;
257
   GLint loc;
258
   char buf[80];
twinaphex's avatar
twinaphex committed
259
260

   buf[0] = '\0';
261

twinaphex's avatar
twinaphex committed
262
   snprintf(buf, sizeof(buf), "%s%s", glsl->shader->prefix, base);
263
   loc = glGetUniformLocation(prog, buf);
Themaister's avatar
Themaister committed
264
265
266
   if (loc >= 0)
      return loc;

267
   for (i = 0; i < ARRAY_SIZE(glsl_prefixes); i++)
268
269
   {
      snprintf(buf, sizeof(buf), "%s%s", glsl_prefixes[i], base);
270
      loc = glGetAttribLocation(prog, buf);
271
272
273
274
275
276
277
      if (loc >= 0)
         return loc;
   }

   return -1;
}

278
static void gl_glsl_print_shader_log(GLuint obj)
279
{
twinaphex's avatar
twinaphex committed
280
   char *info_log = NULL;
281
   GLint max_len, info_len = 0;
282

283
   glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &max_len);
284

Themaister's avatar
Themaister committed
285
286
287
   if (max_len == 0)
      return;

288
   info_log = (char*)malloc(max_len);
Themaister's avatar
Themaister committed
289
290
291
   if (!info_log)
      return;

292
   glGetShaderInfoLog(obj, max_len, &info_len, info_log);
293
294

   if (info_len > 0)
Themaister's avatar
Themaister committed
295
      RARCH_LOG("Shader log: %s\n", info_log);
Themaister's avatar
Themaister committed
296
297

   free(info_log);
298
299
}

300
static void gl_glsl_print_linker_log(GLuint obj)
301
{
twinaphex's avatar
twinaphex committed
302
   char *info_log = NULL;
303
   GLint max_len, info_len = 0;
304

305
   glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &max_len);
306

Themaister's avatar
Themaister committed
307
308
309
   if (max_len == 0)
      return;

310
   info_log = (char*)malloc(max_len);
Themaister's avatar
Themaister committed
311
312
313
   if (!info_log)
      return;

314
   glGetProgramInfoLog(obj, max_len, &info_len, info_log);
315
316

   if (info_len > 0)
Themaister's avatar
Themaister committed
317
      RARCH_LOG("Linker log: %s\n", info_log);
Themaister's avatar
Themaister committed
318
319

   free(info_log);
320
321
}

322
static bool gl_glsl_compile_shader(glsl_shader_data_t *glsl,
twinaphex's avatar
twinaphex committed
323
324
      GLuint shader,
      const char *define, const char *program)
325
{
twinaphex's avatar
twinaphex committed
326
   GLint status;
twinaphex's avatar
twinaphex committed
327
   const char *source[4];
twinaphex's avatar
twinaphex committed
328
   char version[32];
twinaphex's avatar
Cleanup    
twinaphex committed
329
   const char *existing_version = strstr(program, "#version");
twinaphex's avatar
twinaphex committed
330

twinaphex's avatar
Cleanup    
twinaphex committed
331
   version[0]                   = '\0';
twinaphex's avatar
twinaphex committed
332

333
   if (existing_version)
334
   {
335
      const char* version_extra = "";
twinaphex's avatar
twinaphex committed
336
      unsigned version_no = (unsigned)strtoul(existing_version + 8, (char**)&program, 10);
337
338
339
340
#ifdef HAVE_OPENGLES
      if (version_no < 130)
         version_no = 100;
      else
341
342
      {
         version_extra = " es";
343
         version_no = 300;
344
      }
345
#endif
346
      snprintf(version, sizeof(version), "#version %u%s\n", version_no, version_extra);
347
348
   }
   else if (glsl_core)
Themaister's avatar
Themaister committed
349
350
   {
      unsigned version_no = 0;
351
      unsigned gl_ver = glsl_major * 100 + glsl_minor * 10;
352

Themaister's avatar
Themaister committed
353
354
      switch (gl_ver)
      {
355
356
357
358
359
360
361
362
363
364
365
366
         case 300:
            version_no = 130;
            break;
         case 310:
            version_no = 140;
            break;
         case 320:
            version_no = 150;
            break;
         default:
            version_no = gl_ver;
            break;
Themaister's avatar
Themaister committed
367
368
369
      }

      snprintf(version, sizeof(version), "#version %u\n", version_no);
Alfrix's avatar
Alfrix committed
370
371
372
373
374
   }
   else
   {
      /* Don't leave version empty, prevent the compiler warning */
      snprintf(version, sizeof(version), "#version 110\n");
Themaister's avatar
Themaister committed
375
376
   }

Alfrix's avatar
Alfrix committed
377
   RARCH_LOG("[GLSL]: Using GLSL %s", version);
Alcaro's avatar
Alcaro committed
378
   source[0] = version;
twinaphex's avatar
twinaphex committed
379
   source[1] = define;
380
   source[2] = glsl->alias_define;
twinaphex's avatar
twinaphex committed
381
382
383
384
   source[3] = program;

   glShaderSource(shader, ARRAY_SIZE(source), source, NULL);
   glCompileShader(shader);
385

386
   glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
387
   gl_glsl_print_shader_log(shader);
388
389
390
391

   return status == GL_TRUE;
}

392
static bool gl_glsl_link_program(GLuint prog)
Themaister's avatar
Themaister committed
393
{
Alcaro's avatar
Alcaro committed
394
   GLint status;
Higor Eurípedes's avatar
Higor Eurípedes committed
395

396
   glLinkProgram(prog);
Themaister's avatar
Themaister committed
397

398
   glGetProgramiv(prog, GL_LINK_STATUS, &status);
399
   gl_glsl_print_linker_log(prog);
Themaister's avatar
Themaister committed
400

401
402
403
404
405
   if (status != GL_TRUE)
      return false;

   glUseProgram(prog);
   return true;
Themaister's avatar
Themaister committed
406
407
}

408
409

static bool gl_glsl_compile_program(
410
      void *data,
twinaphex's avatar
twinaphex committed
411
      unsigned idx,
twinaphex's avatar
twinaphex committed
412
      void *program_data,
twinaphex's avatar
twinaphex committed
413
      struct shader_program_info *program_info)
Themaister's avatar
Themaister committed
414
{
415
   glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
twinaphex's avatar
twinaphex committed
416
   struct shader_program_glsl_data *program = (struct shader_program_glsl_data*)program_data;
twinaphex's avatar
twinaphex committed
417
418
   GLuint prog = glCreateProgram();

twinaphex's avatar
twinaphex committed
419
420
421
   if (!program)
      program = &glsl->prg[idx];

Themaister's avatar
Themaister committed
422
   if (!prog)
twinaphex's avatar
twinaphex committed
423
      goto error;
424

twinaphex's avatar
twinaphex committed
425
   if (program_info->vertex)
426
   {
twinaphex's avatar
twinaphex committed
427
      RARCH_LOG("[GLSL]: Found GLSL vertex shader.\n");
428
429
      program->vprg = glCreateShader(GL_VERTEX_SHADER);

430
      if (!gl_glsl_compile_shader(
twinaphex's avatar
twinaphex committed
431
               glsl,
432
433
               program->vprg,
               "#define VERTEX\n#define PARAMETER_UNIFORM\n", program_info->vertex))
434
      {
twinaphex's avatar
twinaphex committed
435
         RARCH_ERR("Failed to compile vertex shader #%u\n", idx);
twinaphex's avatar
twinaphex committed
436
         goto error;
437
438
      }

439
      glAttachShader(prog, program->vprg);
Themaister's avatar
Themaister committed
440
   }
441

twinaphex's avatar
twinaphex committed
442
   if (program_info->fragment)
Themaister's avatar
Themaister committed
443
   {
twinaphex's avatar
twinaphex committed
444
      RARCH_LOG("[GLSL]: Found GLSL fragment shader.\n");
445
446
      program->fprg = glCreateShader(GL_FRAGMENT_SHADER);
      if (!gl_glsl_compile_shader(glsl, program->fprg,
twinaphex's avatar
twinaphex committed
447
               "#define FRAGMENT\n#define PARAMETER_UNIFORM\n", program_info->fragment))
448
      {
twinaphex's avatar
twinaphex committed
449
         RARCH_ERR("Failed to compile fragment shader #%u\n", idx);
twinaphex's avatar
twinaphex committed
450
         goto error;
451
452
      }

453
      glAttachShader(prog, program->fprg);
Themaister's avatar
Themaister committed
454
   }
455

twinaphex's avatar
twinaphex committed
456
   if (program_info->vertex || program_info->fragment)
Themaister's avatar
Themaister committed
457
   {
twinaphex's avatar
twinaphex committed
458
      RARCH_LOG("[GLSL]: Linking GLSL program.\n");
459
      if (!gl_glsl_link_program(prog))
twinaphex's avatar
twinaphex committed
460
         goto error;
Themaister's avatar
Themaister committed
461

twinaphex's avatar
twinaphex committed
462
      /* Clean up dead memory. We're not going to relink the program.
Higor Eurípedes's avatar
Higor Eurípedes committed
463
       * Detaching first seems to kill some mobile drivers
twinaphex's avatar
twinaphex committed
464
       * (according to the intertubes anyways). */
465
466
467
468
469
470
      if (program->vprg)
         glDeleteShader(program->vprg);
      if (program->fprg)
         glDeleteShader(program->fprg);
      program->vprg = 0;
      program->fprg = 0;
471

472
      glUseProgram(prog);
473
      glUniform1i(gl_glsl_get_uniform(glsl, prog, "Texture"), 0);
474
      glUseProgram(0);
475
   }
Themaister's avatar
Themaister committed
476

477
478
479
   program->id = prog;

   return true;
twinaphex's avatar
twinaphex committed
480
481

error:
twinaphex's avatar
twinaphex committed
482
   RARCH_ERR("Failed to link program #%u.\n", idx);
483
484
   program->id = 0;
   return false;
Themaister's avatar
Themaister committed
485
486
}

487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
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");
   }
}

503
static bool gl_glsl_load_source_path(struct video_shader_pass *pass,
twinaphex's avatar
twinaphex committed
504
      const char *path)
Themaister's avatar
Themaister committed
505
{
twinaphex's avatar
twinaphex committed
506
507
   int64_t len    = 0;
   int64_t nitems = pass ? filestream_read_file(path,
twinaphex's avatar
twinaphex committed
508
         (void**)&pass->source.string.vertex, &len) : 0;
twinaphex's avatar
twinaphex committed
509
510

   if (nitems <= 0 || len <= 0)
Themaister's avatar
Themaister committed
511
512
      return false;

513
   gl_glsl_strip_parameter_pragmas(pass->source.string.vertex);
Themaister's avatar
Themaister committed
514
515
   pass->source.string.fragment = strdup(pass->source.string.vertex);
   return pass->source.string.fragment && pass->source.string.vertex;
Themaister's avatar
Themaister committed
516
517
}

twinaphex's avatar
twinaphex committed
518
static bool gl_glsl_compile_programs(
twinaphex's avatar
twinaphex committed
519
      glsl_shader_data_t *glsl, struct shader_program_glsl_data *program)
Themaister's avatar
Themaister committed
520
{
521
   unsigned i;
522

twinaphex's avatar
twinaphex committed
523
   for (i = 0; i < glsl->shader->passes; i++)
524
   {
twinaphex's avatar
twinaphex committed
525
      struct shader_program_info shader_prog_info;
526
527
      const char *vertex           = NULL;
      const char *fragment         = NULL;
528
      struct video_shader_pass *pass = (struct video_shader_pass*)
twinaphex's avatar
twinaphex committed
529
         &glsl->shader->pass[i];
Themaister's avatar
Themaister committed
530

531
532
533
      if (!pass)
         continue;

twinaphex's avatar
twinaphex committed
534
535
536
537
      /* If we load from GLSLP (CGP),
       * load the file here, and pretend
       * we were really using XML all along.
       */
gblues's avatar
gblues committed
538
      if (     !string_is_empty(pass->source.path)
twinaphex's avatar
twinaphex committed
539
            && !gl_glsl_load_source_path(pass, pass->source.path))
Themaister's avatar
Themaister committed
540
      {
twinaphex's avatar
twinaphex committed
541
542
         RARCH_ERR("Failed to load GLSL shader: %s.\n",
               pass->source.path);
Themaister's avatar
Themaister committed
543
544
545
         return false;
      }

twinaphex's avatar
twinaphex committed
546
547
      vertex                    = pass->source.string.vertex;
      fragment                  = pass->source.string.fragment;
Themaister's avatar
Themaister committed
548

twinaphex's avatar
twinaphex committed
549
550
551
552
      shader_prog_info.vertex   = vertex;
      shader_prog_info.fragment = fragment;
      shader_prog_info.is_file  = false;

Higor Eurípedes's avatar
Higor Eurípedes committed
553
554
      if (!gl_glsl_compile_program(glsl, i,
            &program[i],
555
            &shader_prog_info))
Themaister's avatar
Themaister committed
556
557
558
559
      {
         RARCH_ERR("Failed to create GL program #%u.\n", i);
         return false;
      }
560
561
   }

Themaister's avatar
Themaister committed
562
   return true;
563
}
Themaister's avatar
Themaister committed
564

twinaphex's avatar
twinaphex committed
565
static void gl_glsl_reset_attrib(glsl_shader_data_t *glsl)
566
{
567
   unsigned i;
568

twinaphex's avatar
twinaphex committed
569
   /* Add sanity check that we did not overflow. */
twinaphex's avatar
Updates    
twinaphex committed
570
   retro_assert(glsl->attribs_index <= ARRAY_SIZE(glsl->attribs_elems));
571

twinaphex's avatar
Updates    
twinaphex committed
572
573
574
   for (i = 0; i < glsl->attribs_index; i++)
      glDisableVertexAttribArray(glsl->attribs_elems[i]);
   glsl->attribs_index = 0;
575
576
}

twinaphex's avatar
twinaphex committed
577
578
static void gl_glsl_set_vbo(GLfloat **buffer, size_t *buffer_elems,
      const GLfloat *data, size_t elems)
Themaister's avatar
Themaister committed
579
{
twinaphex's avatar
twinaphex committed
580
   if (elems > *buffer_elems)
Themaister's avatar
Themaister committed
581
   {
twinaphex's avatar
twinaphex committed
582
583
584
585
      GLfloat *new_buffer = (GLfloat*)
         realloc(*buffer, elems * sizeof(GLfloat));
      retro_assert(new_buffer);
      *buffer = new_buffer;
Themaister's avatar
Themaister committed
586
   }
twinaphex's avatar
twinaphex committed
587
588
589
590
591

   memcpy(*buffer, data, elems * sizeof(GLfloat));
   glBufferData(GL_ARRAY_BUFFER, elems * sizeof(GLfloat),
         data, GL_STATIC_DRAW);
   *buffer_elems = elems;
Themaister's avatar
Themaister committed
592
593
}

twinaphex's avatar
twinaphex committed
594
static INLINE void gl_glsl_set_attribs(glsl_shader_data_t *glsl,
595
      GLuint vbo,
twinaphex's avatar
twinaphex committed
596
597
598
      GLfloat **buffer, size_t *buffer_elems,
      const GLfloat *data, size_t elems,
      const struct glsl_attrib *attrs, size_t num_attrs)
Themaister's avatar
Themaister committed
599
{
600
   size_t i;
601

602
   glBindBuffer(GL_ARRAY_BUFFER, vbo);
Themaister's avatar
Themaister committed
603

twinaphex's avatar
twinaphex committed
604
605
606
   if (elems != *buffer_elems ||
         memcmp(data, *buffer, elems * sizeof(GLfloat)))
      gl_glsl_set_vbo(buffer, buffer_elems, data, elems);
Themaister's avatar
Themaister committed
607

608
   for (i = 0; i < num_attrs; i++)
Themaister's avatar
Themaister committed
609
   {
twinaphex's avatar
Updates    
twinaphex committed
610
      if (glsl->attribs_index < ARRAY_SIZE(glsl->attribs_elems))
611
      {
twinaphex's avatar
twinaphex committed
612
613
         GLint loc = attrs[i].loc;

614
615
616
         glEnableVertexAttribArray(loc);
         glVertexAttribPointer(loc, attrs[i].size, GL_FLOAT, GL_FALSE, 0,
               (const GLvoid*)(uintptr_t)attrs[i].offset);
twinaphex's avatar
Updates    
twinaphex committed
617
         glsl->attribs_elems[glsl->attribs_index++] = loc;
618
619
620
      }
      else
         RARCH_WARN("Attrib array buffer was overflown!\n");
Themaister's avatar
Themaister committed
621
622
   }

623
   glBindBuffer(GL_ARRAY_BUFFER, 0);
Themaister's avatar
Themaister committed
624
625
}

626
static void gl_glsl_clear_uniforms_frame(struct shader_uniforms_frame *frame)
627
628
629
630
631
632
633
{
   frame->texture      = -1;
   frame->texture_size = -1;
   frame->input_size   = -1;
   frame->tex_coord    = -1;
}

634
static void gl_glsl_find_uniforms_frame(glsl_shader_data_t *glsl,
twinaphex's avatar
twinaphex committed
635
      GLuint prog,
twinaphex's avatar
twinaphex committed
636
      struct shader_uniforms_frame *frame, const char *base)
637
{
twinaphex's avatar
twinaphex committed
638
639
640
641
642
643
   char texture[64];
   char texture_size[64];
   char input_size[64];
   char tex_coord[64];

   texture[0] = texture_size[0] = input_size[0] = tex_coord[0] = '\0';
644

twinaphex's avatar
twinaphex committed
645
   snprintf(texture,      sizeof(texture),      "%s%s", base, "Texture");
646
   snprintf(texture_size, sizeof(texture_size), "%s%s", base, "TextureSize");
twinaphex's avatar
twinaphex committed
647
648
   snprintf(input_size,   sizeof(input_size),   "%s%s", base, "InputSize");
   snprintf(tex_coord,    sizeof(tex_coord),    "%s%s", base, "TexCoord");
649

650
   if (frame->texture < 0)
651
      frame->texture = gl_glsl_get_uniform(glsl, prog, texture);
652
   if (frame->texture_size < 0)
653
      frame->texture_size = gl_glsl_get_uniform(glsl, prog, texture_size);
654
   if (frame->input_size < 0)
655
      frame->input_size = gl_glsl_get_uniform(glsl, prog, input_size);
656
   if (frame->tex_coord < 0)
657
      frame->tex_coord = gl_glsl_get_attrib(glsl, prog, tex_coord);
658
659
}

660
static void gl_glsl_find_uniforms(glsl_shader_data_t *glsl,
661
      unsigned pass, GLuint prog,
twinaphex's avatar
twinaphex committed
662
      struct shader_uniforms *uni)
663
{
664
   unsigned i;
twinaphex's avatar
twinaphex committed
665
666
667
   char frame_base[64];

   frame_base[0] = '\0';
668

669
   glUseProgram(prog);
670

671
672
673
674
675
   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");
676

677
678
679
   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");
680

681
682
   uni->frame_count     = gl_glsl_get_uniform(glsl, prog, "FrameCount");
   uni->frame_direction = gl_glsl_get_uniform(glsl, prog, "FrameDirection");
683

twinaphex's avatar
twinaphex committed
684
685
   for (i = 0; i < glsl->shader->luts; i++)
      uni->lut_texture[i] = glGetUniformLocation(prog, glsl->shader->lut[i].id);
686

687
688
689
690
   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");
691

692
693
694
   if (pass > 1)
   {
      snprintf(frame_base, sizeof(frame_base), "PassPrev%u", pass);
695
      gl_glsl_find_uniforms_frame(glsl, prog, &uni->orig, frame_base);
696
   }
697

Themaister's avatar
Themaister committed
698
   for (i = 0; i + 1 < pass; i++)
699
   {
Themaister's avatar
Themaister committed
700
      snprintf(frame_base, sizeof(frame_base), "Pass%u", i + 1);
701
702
      gl_glsl_clear_uniforms_frame(&uni->pass[i]);
      gl_glsl_find_uniforms_frame(glsl, prog, &uni->pass[i], frame_base);
Themaister's avatar
Themaister committed
703
      snprintf(frame_base, sizeof(frame_base), "PassPrev%u", pass - (i + 1));
704
      gl_glsl_find_uniforms_frame(glsl, prog, &uni->pass[i], frame_base);
705

twinaphex's avatar
twinaphex committed
706
      if (*glsl->shader->pass[i].alias)
707
         gl_glsl_find_uniforms_frame(glsl, prog, &uni->pass[i], glsl->shader->pass[i].alias);
Themaister's avatar
Themaister committed
708
   }
709

710
711
   gl_glsl_clear_uniforms_frame(&uni->prev[0]);
   gl_glsl_find_uniforms_frame(glsl, prog, &uni->prev[0], "Prev");
Themaister's avatar
Themaister committed
712
713
714
   for (i = 1; i < PREV_TEXTURES; i++)
   {
      snprintf(frame_base, sizeof(frame_base), "Prev%u", i);
715
716
      gl_glsl_clear_uniforms_frame(&uni->prev[i]);
      gl_glsl_find_uniforms_frame(glsl, prog, &uni->prev[i], frame_base);
717
718
   }

719
   glUseProgram(0);
720
721
}

twinaphex's avatar
twinaphex committed
722
static void gl_glsl_deinit_shader(glsl_shader_data_t *glsl)
Themaister's avatar
Themaister committed
723
{
724
   unsigned i;
725

twinaphex's avatar
twinaphex committed
726
   if (!glsl || !glsl->shader)
Themaister's avatar
Themaister committed
727
728
      return;

twinaphex's avatar
twinaphex committed
729
   for (i = 0; i < glsl->shader->passes; i++)
Themaister's avatar
Themaister committed
730
   {
twinaphex's avatar
twinaphex committed
731
732
      free(glsl->shader->pass[i].source.string.vertex);
      free(glsl->shader->pass[i].source.string.fragment);
Themaister's avatar
Themaister committed
733
734
   }

twinaphex's avatar
twinaphex committed
735
736
737
   free(glsl->shader->script);
   free(glsl->shader);
   glsl->shader = NULL;
Themaister's avatar
Themaister committed
738
739
}

twinaphex's avatar
twinaphex committed
740
static void gl_glsl_destroy_resources(glsl_shader_data_t *glsl)
741
{
742
   unsigned i;
743

twinaphex's avatar
twinaphex committed
744
   if (!glsl)
745
746
      return;

twinaphex's avatar
Update    
twinaphex committed
747
   glsl->current_idx = 0;
gblues's avatar
gblues committed
748

749
   glUseProgram(0);
twinaphex's avatar
Update    
twinaphex committed
750

751
   for (i = 0; i < GFX_MAX_SHADERS; i++)
752
   {
753
      if (glsl->prg[i].id == 0 || (i && glsl->prg[i].id == glsl->prg[0].id))
754
         continue;
755
      if (!glIsProgram(glsl->prg[i].id))
756
         continue;
757

758
      glDeleteProgram(glsl->prg[i].id);
759
760
   }

twinaphex's avatar
twinaphex committed
761
   if (glsl->shader && glsl->shader->luts)
762
      glDeleteTextures(glsl->shader->luts, glsl->lut_textures);
763

764
   memset(glsl->prg, 0, sizeof(glsl->prg));
765
   memset(glsl->uniforms, 0, sizeof(glsl->uniforms));
766
   glsl->active_idx = 0;
767

twinaphex's avatar
twinaphex committed
768
   gl_glsl_deinit_shader(glsl);
769

770
771
772
   if (glsl->state_tracker)
      state_tracker_free(glsl->state_tracker);
   glsl->state_tracker = NULL;
773

twinaphex's avatar
twinaphex committed
774
   gl_glsl_reset_attrib(glsl);
775

776
   for (i = 0; i < GFX_MAX_SHADERS; i++)
777
   {
778
779
780
781
      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);
Themaister's avatar
Themaister committed
782

783
784
      free(glsl->vbo[i].buffer_primary);
      free(glsl->vbo[i].buffer_secondary);
785
   }
786
   memset(&glsl->vbo, 0, sizeof(glsl->vbo));
787
788
}

twinaphex's avatar
twinaphex committed
789
static void gl_glsl_deinit(void *data)
790
{
twinaphex's avatar
twinaphex committed
791
   glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;
twinaphex's avatar
twinaphex committed
792
793

   if (!glsl)
794
795
      return;

twinaphex's avatar
twinaphex committed
796
   gl_glsl_destroy_resources(glsl);
797
798

   free(glsl);
799
800
}

801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
static void gl_glsl_init_menu_shaders(void *data)
{
#ifdef HAVE_SHADERPIPELINE
   struct shader_program_info shader_prog_info;
   glsl_shader_data_t *glsl = (glsl_shader_data_t*)data;

   if (!glsl)
      return;

#ifdef HAVE_OPENGLES
   if (gl_query_extension("GL_OES_standard_derivatives"))
   {
      shader_prog_info.vertex = glsl_core ? stock_vertex_xmb_ribbon_modern : stock_vertex_xmb_ribbon_legacy;
      shader_prog_info.fragment = glsl_core ? core_stock_fragment_xmb : stock_fragment_xmb;
   }
   else
   {
      shader_prog_info.vertex = stock_vertex_xmb_ribbon_simple_legacy;
      shader_prog_info.fragment = stock_fragment_xmb_ribbon_simple;
   }
#else
   shader_prog_info.vertex = glsl_core ? stock_vertex_xmb_ribbon_modern : stock_vertex_xmb_ribbon_legacy;
   shader_prog_info.fragment = glsl_core ? core_stock_fragment_xmb : stock_fragment_xmb;
#endif
   shader_prog_info.is_file = false;

827
   RARCH_LOG("[GLSL]: Compiling ribbon shader..\n");
828
829
830
831
832
833
834
835
836
   gl_glsl_compile_program(
         glsl,
         VIDEO_SHADER_MENU,
         &glsl->prg[VIDEO_SHADER_MENU],
         &shader_prog_info);
   gl_glsl_find_uniforms(glsl, 0, glsl->prg[VIDEO_SHADER_MENU].id,
         &glsl->uniforms[VIDEO_SHADER_MENU]);

   shader_prog_info.vertex = glsl_core ? stock_vertex_xmb_simple_modern : stock_vertex_xmb_ribbon_simple_legacy;
twinaphex's avatar
twinaphex committed
837
   shader_prog_info.fragment = glsl_core ? stock_fragment_xmb_ribbon_simple_core : stock_fragment_xmb_ribbon_simple;
838

839
   RARCH_LOG("[GLSL]: Compiling simple ribbon shader..\n");
840
841
842
843
844
845
846
847
848
   gl_glsl_compile_program(
         glsl,
         VIDEO_SHADER_MENU_2,
         &glsl->prg[VIDEO_SHADER_MENU_2],
         &shader_prog_info);
   gl_glsl_find_uniforms(glsl, 0, glsl->prg[VIDEO_SHADER_MENU_2].id,
         &glsl->uniforms[VIDEO_SHADER_MENU_2]);

#if defined(HAVE_OPENGLES)
849
   shader_prog_info.vertex   = stock_vertex_xmb_snow;
850
   shader_prog_info.fragment = stock_fragment_xmb_simple_snow;
851
#else
852
   shader_prog_info.vertex   = glsl_core ? stock_vertex_xmb_snow_core : stock_vertex_xmb_snow_legacy;
853
   shader_prog_info.fragment = glsl_core ? stock_fragment_xmb_simple_snow_core : stock_fragment_xmb_simple_snow;
854
855
#endif

856
   RARCH_LOG("[GLSL]: Compiling snow shader..\n");
857
858
859
860
861
862
863
864
865
   gl_glsl_compile_program(
         glsl,
         VIDEO_SHADER_MENU_3,
         &glsl->prg[VIDEO_SHADER_MENU_3],
         &shader_prog_info);
   gl_glsl_find_uniforms(glsl, 0, glsl->prg[VIDEO_SHADER_MENU_3].id,
         &glsl<