src/render/opengl/SDL_shaders_gl.c
author Alfred Reynolds <alfred@valvesoftware.com>
Thu, 03 Jul 2014 10:22:12 -0700
changeset 8969 7fb90df60b99
parent 8149 681eb46b8ac4
child 9046 c3ec7c3e6c24
permissions -rw-r--r--
The YUV offset is 16 / 255, not 16 / 256
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "../../SDL_internal.h"
    22 
    23 #if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
    24 
    25 #include "SDL_stdinc.h"
    26 #include "SDL_log.h"
    27 #include "SDL_opengl.h"
    28 #include "SDL_video.h"
    29 #include "SDL_shaders_gl.h"
    30 
    31 /* OpenGL shader implementation */
    32 
    33 /* #define DEBUG_SHADERS */
    34 
    35 typedef struct
    36 {
    37     GLhandleARB program;
    38     GLhandleARB vert_shader;
    39     GLhandleARB frag_shader;
    40 } GL_ShaderData;
    41 
    42 struct GL_ShaderContext
    43 {
    44     GLenum (*glGetError)(void);
    45 
    46     PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
    47     PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
    48     PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
    49     PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
    50     PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
    51     PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
    52     PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
    53     PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
    54     PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
    55     PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
    56     PFNGLUNIFORM1IARBPROC glUniform1iARB;
    57     PFNGLUNIFORM1FARBPROC glUniform1fARB;
    58     PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
    59 
    60     SDL_bool GL_ARB_texture_rectangle_supported;
    61 
    62     GL_ShaderData shaders[NUM_SHADERS];
    63 };
    64 
    65 /*
    66  * NOTE: Always use sampler2D, etc here. We'll #define them to the
    67  *  texture_rectangle versions if we choose to use that extension.
    68  */
    69 static const char *shader_source[NUM_SHADERS][2] =
    70 {
    71     /* SHADER_NONE */
    72     { NULL, NULL },
    73 
    74     /* SHADER_SOLID */
    75     {
    76         /* vertex shader */
    77 "varying vec4 v_color;\n"
    78 "\n"
    79 "void main()\n"
    80 "{\n"
    81 "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
    82 "    v_color = gl_Color;\n"
    83 "}",
    84         /* fragment shader */
    85 "varying vec4 v_color;\n"
    86 "\n"
    87 "void main()\n"
    88 "{\n"
    89 "    gl_FragColor = v_color;\n"
    90 "}"
    91     },
    92 
    93     /* SHADER_RGB */
    94     {
    95         /* vertex shader */
    96 "varying vec4 v_color;\n"
    97 "varying vec2 v_texCoord;\n"
    98 "\n"
    99 "void main()\n"
   100 "{\n"
   101 "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
   102 "    v_color = gl_Color;\n"
   103 "    v_texCoord = vec2(gl_MultiTexCoord0);\n"
   104 "}",
   105         /* fragment shader */
   106 "varying vec4 v_color;\n"
   107 "varying vec2 v_texCoord;\n"
   108 "uniform sampler2D tex0;\n"
   109 "\n"
   110 "void main()\n"
   111 "{\n"
   112 "    gl_FragColor = texture2D(tex0, v_texCoord) * v_color;\n"
   113 "}"
   114     },
   115 
   116     /* SHADER_YV12 */
   117     {
   118         /* vertex shader */
   119 "varying vec4 v_color;\n"
   120 "varying vec2 v_texCoord;\n"
   121 "\n"
   122 "void main()\n"
   123 "{\n"
   124 "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
   125 "    v_color = gl_Color;\n"
   126 "    v_texCoord = vec2(gl_MultiTexCoord0);\n"
   127 "}",
   128         /* fragment shader */
   129 "varying vec4 v_color;\n"
   130 "varying vec2 v_texCoord;\n"
   131 "uniform sampler2D tex0; // Y \n"
   132 "uniform sampler2D tex1; // U \n"
   133 "uniform sampler2D tex2; // V \n"
   134 "\n"
   135 "// YUV offset \n"
   136 "const vec3 offset = vec3(-0.0627451017, -0.501960814, -0.501960814);\n"
   137 "\n"
   138 "// RGB coefficients \n"
   139 "const vec3 Rcoeff = vec3(1.164,  0.000,  1.596);\n"
   140 "const vec3 Gcoeff = vec3(1.164, -0.391, -0.813);\n"
   141 "const vec3 Bcoeff = vec3(1.164,  2.018,  0.000);\n"
   142 "\n"
   143 "void main()\n"
   144 "{\n"
   145 "    vec2 tcoord;\n"
   146 "    vec3 yuv, rgb;\n"
   147 "\n"
   148 "    // Get the Y value \n"
   149 "    tcoord = v_texCoord;\n"
   150 "    yuv.x = texture2D(tex0, tcoord).r;\n"
   151 "\n"
   152 "    // Get the U and V values \n"
   153 "    tcoord *= 0.5;\n"
   154 "    yuv.y = texture2D(tex1, tcoord).r;\n"
   155 "    yuv.z = texture2D(tex2, tcoord).r;\n"
   156 "\n"
   157 "    // Do the color transform \n"
   158 "    yuv += offset;\n"
   159 "    rgb.r = dot(yuv, Rcoeff);\n"
   160 "    rgb.g = dot(yuv, Gcoeff);\n"
   161 "    rgb.b = dot(yuv, Bcoeff);\n"
   162 "\n"
   163 "    // That was easy. :) \n"
   164 "    gl_FragColor = vec4(rgb, 1.0) * v_color;\n"
   165 "}"
   166     },
   167 };
   168 
   169 static SDL_bool
   170 CompileShader(GL_ShaderContext *ctx, GLhandleARB shader, const char *defines, const char *source)
   171 {
   172     GLint status;
   173     const char *sources[2];
   174 
   175     sources[0] = defines;
   176     sources[1] = source;
   177 
   178     ctx->glShaderSourceARB(shader, SDL_arraysize(sources), sources, NULL);
   179     ctx->glCompileShaderARB(shader);
   180     ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
   181     if (status == 0) {
   182         GLint length;
   183         char *info;
   184 
   185         ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
   186         info = SDL_stack_alloc(char, length+1);
   187         ctx->glGetInfoLogARB(shader, length, NULL, info);
   188         SDL_LogError(SDL_LOG_CATEGORY_RENDER,
   189             "Failed to compile shader:\n%s%s\n%s", defines, source, info);
   190 #ifdef DEBUG_SHADERS
   191         fprintf(stderr,
   192             "Failed to compile shader:\n%s%s\n%s", defines, source, info);
   193 #endif
   194         SDL_stack_free(info);
   195 
   196         return SDL_FALSE;
   197     } else {
   198         return SDL_TRUE;
   199     }
   200 }
   201 
   202 static SDL_bool
   203 CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data)
   204 {
   205     const int num_tmus_bound = 4;
   206     const char *vert_defines = "";
   207     const char *frag_defines = "";
   208     int i;
   209     GLint location;
   210 
   211     if (index == SHADER_NONE) {
   212         return SDL_TRUE;
   213     }
   214 
   215     ctx->glGetError();
   216 
   217     /* Make sure we use the correct sampler type for our texture type */
   218     if (ctx->GL_ARB_texture_rectangle_supported) {
   219         frag_defines =
   220 "#define sampler2D sampler2DRect\n"
   221 "#define texture2D texture2DRect\n";
   222     }
   223 
   224     /* Create one program object to rule them all */
   225     data->program = ctx->glCreateProgramObjectARB();
   226 
   227     /* Create the vertex shader */
   228     data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
   229     if (!CompileShader(ctx, data->vert_shader, vert_defines, shader_source[index][0])) {
   230         return SDL_FALSE;
   231     }
   232 
   233     /* Create the fragment shader */
   234     data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
   235     if (!CompileShader(ctx, data->frag_shader, frag_defines, shader_source[index][1])) {
   236         return SDL_FALSE;
   237     }
   238 
   239     /* ... and in the darkness bind them */
   240     ctx->glAttachObjectARB(data->program, data->vert_shader);
   241     ctx->glAttachObjectARB(data->program, data->frag_shader);
   242     ctx->glLinkProgramARB(data->program);
   243 
   244     /* Set up some uniform variables */
   245     ctx->glUseProgramObjectARB(data->program);
   246     for (i = 0; i < num_tmus_bound; ++i) {
   247         char tex_name[10];
   248         SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
   249         location = ctx->glGetUniformLocationARB(data->program, tex_name);
   250         if (location >= 0) {
   251             ctx->glUniform1iARB(location, i);
   252         }
   253     }
   254     ctx->glUseProgramObjectARB(0);
   255 
   256     return (ctx->glGetError() == GL_NO_ERROR);
   257 }
   258 
   259 static void
   260 DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data)
   261 {
   262     ctx->glDeleteObjectARB(data->vert_shader);
   263     ctx->glDeleteObjectARB(data->frag_shader);
   264     ctx->glDeleteObjectARB(data->program);
   265 }
   266 
   267 GL_ShaderContext *
   268 GL_CreateShaderContext()
   269 {
   270     GL_ShaderContext *ctx;
   271     SDL_bool shaders_supported;
   272     int i;
   273 
   274     ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx));
   275     if (!ctx) {
   276         return NULL;
   277     }
   278 
   279     if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
   280         || SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
   281         ctx->GL_ARB_texture_rectangle_supported = SDL_TRUE;
   282     }
   283 
   284     /* Check for shader support */
   285     shaders_supported = SDL_FALSE;
   286     if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
   287         SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
   288         SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
   289         SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
   290         ctx->glGetError = (GLenum (*)(void)) SDL_GL_GetProcAddress("glGetError");
   291         ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
   292         ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
   293         ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
   294         ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
   295         ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
   296         ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
   297         ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
   298         ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
   299         ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
   300         ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
   301         ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
   302         ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
   303         ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
   304         if (ctx->glGetError &&
   305             ctx->glAttachObjectARB &&
   306             ctx->glCompileShaderARB &&
   307             ctx->glCreateProgramObjectARB &&
   308             ctx->glCreateShaderObjectARB &&
   309             ctx->glDeleteObjectARB &&
   310             ctx->glGetInfoLogARB &&
   311             ctx->glGetObjectParameterivARB &&
   312             ctx->glGetUniformLocationARB &&
   313             ctx->glLinkProgramARB &&
   314             ctx->glShaderSourceARB &&
   315             ctx->glUniform1iARB &&
   316             ctx->glUniform1fARB &&
   317             ctx->glUseProgramObjectARB) {
   318             shaders_supported = SDL_TRUE;
   319         }
   320     }
   321 
   322     if (!shaders_supported) {
   323         SDL_free(ctx);
   324         return NULL;
   325     }
   326 
   327     /* Compile all the shaders */
   328     for (i = 0; i < NUM_SHADERS; ++i) {
   329         if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) {
   330             GL_DestroyShaderContext(ctx);
   331             return NULL;
   332         }
   333     }
   334 
   335     /* We're done! */
   336     return ctx;
   337 }
   338 
   339 void
   340 GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader)
   341 {
   342     ctx->glUseProgramObjectARB(ctx->shaders[shader].program);
   343 }
   344 
   345 void
   346 GL_DestroyShaderContext(GL_ShaderContext *ctx)
   347 {
   348     int i;
   349 
   350     for (i = 0; i < NUM_SHADERS; ++i) {
   351         DestroyShaderProgram(ctx, &ctx->shaders[i]);
   352     }
   353     SDL_free(ctx);
   354 }
   355 
   356 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
   357 
   358 /* vi: set ts=4 sw=4 expandtab: */