LCOV - code coverage report
Current view: top level - src/opengl - ogl_shader.c (source / functions) Hit Total Coverage
Test: allegro_auto.info Lines: 9 213 4.2 %
Date: 2018-08-11 00:50:28 Functions: 2 20 10.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*         ______   ___    ___
       2             :  *        /\  _  \ /\_ \  /\_ \
       3             :  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
       4             :  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
       5             :  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
       6             :  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
       7             :  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
       8             :  *                                           /\____/
       9             :  *                                           \_/__/
      10             :  *
      11             :  *      OpenGL shader support.
      12             :  *
      13             :  *      See LICENSE.txt for copyright information.
      14             :  */
      15             : 
      16             : #include <stdio.h>
      17             : 
      18             : #include "allegro5/allegro.h"
      19             : #include "allegro5/allegro_opengl.h"
      20             : #include "allegro5/internal/aintern_bitmap.h"
      21             : #include "allegro5/internal/aintern_display.h"
      22             : #include "allegro5/internal/aintern_opengl.h"
      23             : #include "allegro5/internal/aintern_shader.h"
      24             : 
      25             : #ifdef ALLEGRO_MSVC
      26             :    #define snprintf _snprintf
      27             : #endif
      28             : 
      29             : #ifdef ALLEGRO_CFG_SHADER_GLSL
      30             : 
      31             : ALLEGRO_DEBUG_CHANNEL("shader")
      32             : 
      33             : static _AL_VECTOR shaders;
      34             : static ALLEGRO_MUTEX *shaders_mutex;
      35             : 
      36             : typedef struct ALLEGRO_SHADER_GLSL_S ALLEGRO_SHADER_GLSL_S;
      37             : 
      38             : struct ALLEGRO_SHADER_GLSL_S
      39             : {
      40             :    ALLEGRO_SHADER shader;
      41             :    GLuint vertex_shader;
      42             :    GLuint pixel_shader;
      43             :    GLuint program_object;
      44             :    ALLEGRO_OGL_VARLOCS varlocs;
      45             : };
      46             : 
      47             : 
      48             : /* forward declarations */
      49             : static struct ALLEGRO_SHADER_INTERFACE shader_glsl_vt;
      50             : static void lookup_varlocs(ALLEGRO_OGL_VARLOCS *varlocs, GLuint program);
      51             : 
      52             : 
      53           0 : static bool check_gl_error(const char* name)
      54             : {
      55           0 :    GLenum err = glGetError();
      56           0 :    if (err != 0) {
      57           0 :       ALLEGRO_WARN("%s (%s)\n", name, _al_gl_error_string(err));
      58             :       return false;
      59             :    }
      60             :    return true;
      61             : }
      62             : 
      63             : 
      64           0 : ALLEGRO_SHADER *_al_create_shader_glsl(ALLEGRO_SHADER_PLATFORM platform)
      65             : {
      66           0 :    ALLEGRO_SHADER_GLSL_S *shader = al_calloc(1, sizeof(ALLEGRO_SHADER_GLSL_S));
      67             : 
      68           0 :    if (!shader)
      69             :       return NULL;
      70             : 
      71           0 :    shader->shader.platform = platform;
      72           0 :    shader->shader.vt = &shader_glsl_vt;
      73           0 :    _al_vector_init(&shader->shader.bitmaps, sizeof(ALLEGRO_BITMAP *));
      74             : 
      75           0 :    al_lock_mutex(shaders_mutex);
      76             :    {
      77           0 :       ALLEGRO_SHADER **back = (ALLEGRO_SHADER **)_al_vector_alloc_back(&shaders);
      78           0 :       *back = (ALLEGRO_SHADER *)shader;
      79             :    }
      80           0 :    al_unlock_mutex(shaders_mutex);
      81             : 
      82           0 :    return (ALLEGRO_SHADER *)shader;
      83             : }
      84             : 
      85           0 : static bool glsl_attach_shader_source(ALLEGRO_SHADER *shader,
      86             :    ALLEGRO_SHADER_TYPE type, const char *source)
      87             : {
      88             :    GLint status;
      89             :    GLchar error_buf[4096];
      90           0 :    ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader;
      91           0 :    ALLEGRO_DISPLAY *display = al_get_current_display();
      92             :    ASSERT(display);
      93             :    ASSERT(display->flags & ALLEGRO_OPENGL);
      94             : 
      95           0 :    if (source == NULL) {
      96           0 :       if (type == ALLEGRO_VERTEX_SHADER) {
      97           0 :          if (gl_shader->vertex_shader) {
      98           0 :             glDetachShader(gl_shader->program_object, gl_shader->vertex_shader);
      99           0 :             glDeleteShader(gl_shader->vertex_shader);
     100           0 :             gl_shader->vertex_shader = 0;
     101             :          }
     102             :       }
     103             :       else {
     104           0 :          if (gl_shader->pixel_shader) {
     105           0 :             glDetachShader(gl_shader->program_object, gl_shader->pixel_shader);
     106           0 :             glDeleteShader(gl_shader->pixel_shader);
     107           0 :             gl_shader->pixel_shader = 0;
     108             :          }
     109             :       }
     110             :       return true;
     111             :    }
     112             :    else {
     113             :       GLuint *handle;
     114             :       GLenum gl_type;
     115           0 :       if (type == ALLEGRO_VERTEX_SHADER) {
     116           0 :          handle = &(gl_shader->vertex_shader);
     117           0 :          gl_type = GL_VERTEX_SHADER;
     118             :       }
     119             :       else {
     120           0 :          handle = &(gl_shader->pixel_shader);
     121           0 :          gl_type = GL_FRAGMENT_SHADER;
     122             :       }
     123           0 :       *handle = glCreateShader(gl_type);
     124           0 :       if ((*handle) == 0) {
     125             :          return false;
     126             :       }
     127           0 :       glShaderSource(*handle, 1, &source, NULL);
     128           0 :       glCompileShader(*handle);
     129           0 :       glGetShaderiv(*handle, GL_COMPILE_STATUS, &status);
     130           0 :       if (status == 0) {
     131           0 :          glGetShaderInfoLog(*handle, sizeof(error_buf), NULL, error_buf);
     132           0 :          if (shader->log) {
     133           0 :             al_ustr_truncate(shader->log, 0);
     134           0 :             al_ustr_append_cstr(shader->log, error_buf);
     135             :          }
     136             :          else {
     137           0 :             shader->log = al_ustr_new(error_buf);
     138             :          }
     139           0 :          ALLEGRO_ERROR("Compile error: %s\n", error_buf);
     140           0 :          glDeleteShader(*handle);
     141           0 :          return false;
     142             :       }
     143             :    }
     144             : 
     145             :    return true;
     146             : }
     147             : 
     148           0 : static bool glsl_build_shader(ALLEGRO_SHADER *shader)
     149             : {
     150             :    GLint status;
     151           0 :    ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader;
     152             :    GLchar error_buf[4096];
     153             : 
     154           0 :    if (gl_shader->vertex_shader == 0 && gl_shader->pixel_shader == 0)
     155             :       return false;
     156             : 
     157           0 :    if (gl_shader->program_object != 0) {
     158           0 :       glDeleteProgram(gl_shader->program_object);
     159             :    }
     160             : 
     161           0 :    gl_shader->program_object = glCreateProgram();
     162           0 :    if (gl_shader->program_object == 0)
     163             :       return false;
     164             : 
     165           0 :    if (gl_shader->vertex_shader)
     166           0 :       glAttachShader(gl_shader->program_object, gl_shader->vertex_shader);
     167           0 :    if (gl_shader->pixel_shader)
     168           0 :       glAttachShader(gl_shader->program_object, gl_shader->pixel_shader);
     169             : 
     170           0 :    glLinkProgram(gl_shader->program_object);
     171             : 
     172           0 :    glGetProgramiv(gl_shader->program_object, GL_LINK_STATUS, &status);
     173             : 
     174           0 :    if (status == 0) {
     175           0 :       glGetProgramInfoLog(gl_shader->program_object, sizeof(error_buf), NULL,
     176             :          error_buf);
     177           0 :       if (shader->log) {
     178           0 :          al_ustr_truncate(shader->log, 0);
     179           0 :          al_ustr_append_cstr(shader->log, error_buf);
     180             :       }
     181             :       else {
     182           0 :          shader->log = al_ustr_new(error_buf);
     183             :       }
     184           0 :       ALLEGRO_ERROR("Link error: %s\n", error_buf);
     185           0 :       glDeleteProgram(gl_shader->program_object);
     186           0 :       return false;
     187             :    }
     188             : 
     189             :    /* Look up variable locations. */
     190           0 :    lookup_varlocs(&gl_shader->varlocs, gl_shader->program_object);
     191             : 
     192           0 :    return true;
     193             : }
     194             : 
     195           0 : static bool glsl_use_shader(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *display,
     196             :    bool set_projview_matrix_from_display)
     197             : {
     198             :    ALLEGRO_SHADER_GLSL_S *gl_shader;
     199             :    GLuint program_object;
     200             :    GLenum err;
     201             : 
     202           0 :    if (!(display->flags & ALLEGRO_OPENGL)) {
     203             :       return false;
     204             :    }
     205             : 
     206           0 :    gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader;
     207           0 :    program_object = gl_shader->program_object;
     208             : 
     209           0 :    glGetError(); /* clear error */
     210           0 :    glUseProgram(program_object);
     211           0 :    err = glGetError();
     212           0 :    if (err != GL_NO_ERROR) {
     213           0 :       ALLEGRO_WARN("glUseProgram(%u) failed: %s\n", program_object,
     214             :          _al_gl_error_string(err));
     215           0 :       display->ogl_extras->program_object = 0;
     216           0 :       return false;
     217             :    }
     218             : 
     219           0 :    display->ogl_extras->program_object = program_object;
     220             : 
     221             :    /* Copy variable locations. */
     222           0 :    display->ogl_extras->varlocs = gl_shader->varlocs;
     223             : 
     224             :    /* Optionally set projview matrix.  We skip this when it is known that the
     225             :     * matrices in the display are out of date and are about to be clobbered
     226             :     * itself.
     227             :     */
     228           0 :    if (set_projview_matrix_from_display) {
     229           0 :       _al_glsl_set_projview_matrix(
     230           0 :          display->ogl_extras->varlocs.projview_matrix_loc, &display->projview_transform);
     231             :    }
     232             : 
     233             :    return true;
     234             : }
     235             : 
     236           0 : static void glsl_unuse_shader(ALLEGRO_SHADER *shader, ALLEGRO_DISPLAY *display)
     237             : {
     238             :    (void)shader;
     239             :    (void)display;
     240           0 :    glUseProgram(0);
     241           0 : }
     242             : 
     243           0 : static void glsl_destroy_shader(ALLEGRO_SHADER *shader)
     244             : {
     245           0 :    ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader;
     246             : 
     247           0 :    al_lock_mutex(shaders_mutex);
     248           0 :    _al_vector_find_and_delete(&shaders, &shader);
     249           0 :    al_unlock_mutex(shaders_mutex);
     250             : 
     251           0 :    glDeleteShader(gl_shader->vertex_shader);
     252           0 :    glDeleteShader(gl_shader->pixel_shader);
     253           0 :    glDeleteProgram(gl_shader->program_object);
     254           0 :    al_free(shader);
     255           0 : }
     256             : 
     257           0 : static bool glsl_set_shader_sampler(ALLEGRO_SHADER *shader,
     258             :    const char *name, ALLEGRO_BITMAP *bitmap, int unit)
     259             : {
     260           0 :    ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader;
     261             :    GLint handle;
     262             :    GLuint texture;
     263             : 
     264           0 :    if (bitmap && al_get_bitmap_flags(bitmap) & ALLEGRO_MEMORY_BITMAP) {
     265           0 :       ALLEGRO_WARN("Cannot use memory bitmap for sampler\n");
     266             :       return false;
     267             :    }
     268             : 
     269           0 :    handle = glGetUniformLocation(gl_shader->program_object, name);
     270             : 
     271           0 :    if (handle < 0) {
     272           0 :       ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name);
     273             :       return false;
     274             :    }
     275             : 
     276           0 :    glActiveTexture(GL_TEXTURE0 + unit);
     277             : 
     278           0 :    texture = bitmap ? al_get_opengl_texture(bitmap) : 0;
     279           0 :    glBindTexture(GL_TEXTURE_2D, texture);
     280             : 
     281           0 :    glUniform1i(handle, unit);
     282             : 
     283           0 :    return check_gl_error(name);
     284             : }
     285             : 
     286           0 : static bool glsl_set_shader_matrix(ALLEGRO_SHADER *shader,
     287             :    const char *name, const ALLEGRO_TRANSFORM *matrix)
     288             : {
     289           0 :    ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader;
     290             :    GLint handle;
     291             : 
     292           0 :    handle = glGetUniformLocation(gl_shader->program_object, name);
     293             : 
     294           0 :    if (handle < 0) {
     295           0 :       ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name);
     296             :       return false;
     297             :    }
     298             : 
     299           0 :    glUniformMatrix4fv(handle, 1, false, (const float *)matrix->m);
     300             : 
     301           0 :    return check_gl_error(name);
     302             : }
     303             : 
     304           0 : static bool glsl_set_shader_int(ALLEGRO_SHADER *shader,
     305             :    const char *name, int i)
     306             : {
     307           0 :    ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader;
     308             :    GLint handle;
     309             : 
     310           0 :    handle = glGetUniformLocation(gl_shader->program_object, name);
     311             : 
     312           0 :    if (handle < 0) {
     313           0 :       ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name);
     314             :       return false;
     315             :    }
     316             : 
     317           0 :    glUniform1i(handle, i);
     318             : 
     319           0 :    return check_gl_error(name);
     320             : }
     321             : 
     322           0 : static bool glsl_set_shader_float(ALLEGRO_SHADER *shader,
     323             :    const char *name, float f)
     324             : {
     325           0 :    ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader;
     326             :    GLint handle;
     327             : 
     328           0 :    handle = glGetUniformLocation(gl_shader->program_object, name);
     329             : 
     330           0 :    if (handle < 0) {
     331           0 :       ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name);
     332             :       return false;
     333             :    }
     334             : 
     335           0 :    glUniform1f(handle, f);
     336             : 
     337           0 :    return check_gl_error(name);
     338             : }
     339             : 
     340           0 : static bool glsl_set_shader_int_vector(ALLEGRO_SHADER *shader,
     341             :    const char *name, int num_components, const int *i, int num_elems)
     342             : {
     343           0 :    ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader;
     344             :    GLint handle;
     345             : 
     346           0 :    handle = glGetUniformLocation(gl_shader->program_object, name);
     347             : 
     348           0 :    if (handle < 0) {
     349           0 :       ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name);
     350             :       return false;
     351             :    }
     352             : 
     353           0 :    switch (num_components) {
     354           0 :       case 1:
     355           0 :          glUniform1iv(handle, num_elems, i);
     356           0 :          break;
     357           0 :       case 2:
     358           0 :          glUniform2iv(handle, num_elems, i);
     359           0 :          break;
     360           0 :       case 3:
     361           0 :          glUniform3iv(handle, num_elems, i);
     362           0 :          break;
     363           0 :       case 4:
     364           0 :          glUniform4iv(handle, num_elems, i);
     365           0 :          break;
     366             :       default:
     367             :          ASSERT(false);
     368             :          break;
     369             :    }
     370             : 
     371           0 :    return check_gl_error(name);
     372             : }
     373             : 
     374           0 : static bool glsl_set_shader_float_vector(ALLEGRO_SHADER *shader,
     375             :    const char *name, int num_components, const float *f, int num_elems)
     376             : {
     377           0 :    ALLEGRO_SHADER_GLSL_S *gl_shader = (ALLEGRO_SHADER_GLSL_S *)shader;
     378             :    GLint handle;
     379             : 
     380           0 :    handle = glGetUniformLocation(gl_shader->program_object, name);
     381             : 
     382           0 :    if (handle < 0) {
     383           0 :       ALLEGRO_WARN("No uniform variable '%s' in shader program\n", name);
     384             :       return false;
     385             :    }
     386             : 
     387           0 :    switch (num_components) {
     388           0 :       case 1:
     389           0 :          glUniform1fv(handle, num_elems, f);
     390           0 :          break;
     391           0 :       case 2:
     392           0 :          glUniform2fv(handle, num_elems, f);
     393           0 :          break;
     394           0 :       case 3:
     395           0 :          glUniform3fv(handle, num_elems, f);
     396           0 :          break;
     397           0 :       case 4:
     398           0 :          glUniform4fv(handle, num_elems, f);
     399           0 :          break;
     400             :       default:
     401             :          ASSERT(false);
     402             :          break;
     403             :    }
     404             : 
     405           0 :    return check_gl_error(name);
     406             : }
     407             : 
     408           0 : static bool glsl_set_shader_bool(ALLEGRO_SHADER *shader,
     409             :    const char *name, bool b)
     410             : {
     411           0 :    return glsl_set_shader_int(shader, name, b);
     412             : }
     413             : 
     414             : static struct ALLEGRO_SHADER_INTERFACE shader_glsl_vt =
     415             : {
     416             :    glsl_attach_shader_source,
     417             :    glsl_build_shader,
     418             :    glsl_use_shader,
     419             :    glsl_unuse_shader,
     420             :    glsl_destroy_shader,
     421             :    NULL, /* on_lost_device */
     422             :    NULL, /* on_reset_device */
     423             :    glsl_set_shader_sampler,
     424             :    glsl_set_shader_matrix,
     425             :    glsl_set_shader_int,
     426             :    glsl_set_shader_float,
     427             :    glsl_set_shader_int_vector,
     428             :    glsl_set_shader_float_vector,
     429             :    glsl_set_shader_bool
     430             : };
     431             : 
     432           0 : static void lookup_varlocs(ALLEGRO_OGL_VARLOCS *varlocs, GLuint program)
     433             : {
     434             :    unsigned i;
     435             : 
     436           0 :    varlocs->pos_loc = glGetAttribLocation(program, ALLEGRO_SHADER_VAR_POS);
     437           0 :    varlocs->color_loc = glGetAttribLocation(program, ALLEGRO_SHADER_VAR_COLOR);
     438           0 :    varlocs->projview_matrix_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_PROJVIEW_MATRIX);
     439           0 :    varlocs->texcoord_loc = glGetAttribLocation(program, ALLEGRO_SHADER_VAR_TEXCOORD);
     440           0 :    varlocs->use_tex_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_USE_TEX);
     441           0 :    varlocs->tex_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_TEX);
     442           0 :    varlocs->use_tex_matrix_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_USE_TEX_MATRIX);
     443           0 :    varlocs->tex_matrix_loc = glGetUniformLocation(program, ALLEGRO_SHADER_VAR_TEX_MATRIX);
     444             : 
     445           0 :    for (i = 0; i < _ALLEGRO_PRIM_MAX_USER_ATTR; i++) {
     446             :       /* al_user_attr_##0 */
     447             :       char user_attr_name[sizeof(ALLEGRO_SHADER_VAR_USER_ATTR "999")];
     448             : 
     449           0 :       snprintf(user_attr_name, sizeof(user_attr_name), ALLEGRO_SHADER_VAR_USER_ATTR "%d", i);
     450           0 :       varlocs->user_attr_loc[i] = glGetAttribLocation(program, user_attr_name);
     451             :    }
     452             : 
     453           0 :    check_gl_error("glGetAttribLocation, glGetUniformLocation");
     454           0 : }
     455             : 
     456           0 : bool _al_glsl_set_projview_matrix(GLint projview_matrix_loc,
     457             :    const ALLEGRO_TRANSFORM *t)
     458             : {
     459           0 :    if (projview_matrix_loc >= 0) {
     460           0 :       glUniformMatrix4fv(projview_matrix_loc, 1, false, (float *)t->m);
     461           0 :       return true;
     462             :    }
     463             : 
     464             :    return false;
     465             : }
     466             : 
     467           6 : void _al_glsl_init_shaders(void)
     468             : {
     469           6 :    _al_vector_init(&shaders, sizeof(ALLEGRO_SHADER *));
     470           6 :    shaders_mutex = al_create_mutex();
     471           6 : }
     472             : 
     473           5 : void _al_glsl_shutdown_shaders(void)
     474             : {
     475           5 :    _al_vector_free(&shaders);
     476           5 :    al_destroy_mutex(shaders_mutex);
     477           5 :    shaders_mutex = NULL;
     478           5 : }
     479             : 
     480             : /* Look through all the bitmaps associated with all the shaders and c;ear their
     481             :  * shader field */
     482           0 : void _al_glsl_unuse_shaders(void)
     483             : {
     484             :    unsigned i;
     485           0 :    al_lock_mutex(shaders_mutex);
     486           0 :    for (i = 0; i < _al_vector_size(&shaders); i++) {
     487             :       unsigned j;
     488           0 :       ALLEGRO_SHADER *shader = *((ALLEGRO_SHADER **)_al_vector_ref(&shaders, i));
     489             : 
     490           0 :       for (j = 0; j < _al_vector_size(&shader->bitmaps); j++) {
     491           0 :          ALLEGRO_BITMAP *bitmap =
     492           0 :             *((ALLEGRO_BITMAP **)_al_vector_ref(&shader->bitmaps, j));
     493           0 :          _al_set_bitmap_shader_field(bitmap, NULL);
     494             :       }
     495             :    }
     496           0 :    al_unlock_mutex(shaders_mutex);
     497           0 : }
     498             : 
     499             : #endif
     500             : 
     501             : /* Function: al_get_opengl_program_object
     502             :  */
     503           0 : GLuint al_get_opengl_program_object(ALLEGRO_SHADER *shader)
     504             : {
     505             :    ASSERT(shader);
     506             : #ifdef ALLEGRO_CFG_SHADER_GLSL
     507           0 :    if (shader->platform != ALLEGRO_SHADER_GLSL)
     508             :       return 0;
     509             : 
     510           0 :    return ((ALLEGRO_SHADER_GLSL_S *)shader)->program_object;
     511             : #else
     512             :    return 0;
     513             : #endif
     514             : }
     515             : 
     516             : 
     517             : /* vim: set sts=3 sw=3 et: */

Generated by: LCOV version 1.13