From fcdda06d91aa6e53058436a226176eb6542c7099 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Tue, 8 Feb 2011 16:27:52 -0800 Subject: [PATCH] Beginning of a framework for OpenGL shaders --- src/render/opengl/SDL_render_gl.c | 33 ++++ src/render/opengl/SDL_shaders_gl.c | 304 +++++++++++++++++++++++++++++ src/render/opengl/SDL_shaders_gl.h | 40 ++++ 3 files changed, 377 insertions(+) create mode 100644 src/render/opengl/SDL_shaders_gl.c create mode 100644 src/render/opengl/SDL_shaders_gl.h diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c index 25cd42156..cd9831301 100644 --- a/src/render/opengl/SDL_render_gl.c +++ b/src/render/opengl/SDL_render_gl.c @@ -25,6 +25,7 @@ #include "SDL_opengl.h" #include "../SDL_sysrender.h" +#include "SDL_shaders_gl.h" #ifdef __MACOSX__ #include @@ -94,6 +95,15 @@ typedef struct void (*glTextureRangeAPPLE) (GLenum target, GLsizei length, const GLvoid * pointer); + + /* Multitexture support */ + SDL_bool GL_ARB_multitexture_supported; + PFNGLACTIVETEXTUREARBPROC glActiveTextureARB; + int num_texture_units; + + /* Shader support */ + GL_ShaderContext *shaders; + } GL_RenderData; typedef struct @@ -262,6 +272,25 @@ GL_CreateRenderer(SDL_Window * window, Uint32 flags) SDL_GL_GetProcAddress("glTextureRangeAPPLE"); } + /* Check for multitexture support */ + if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) { + data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB"); + if (data->glActiveTextureARB) { + data->GL_ARB_multitexture_supported = SDL_TRUE; + data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units); + } + } + + /* Check for shader support */ + //data->shaders = GL_CreateShaderContext(); + +#if 0 + /* We support YV12 textures using 3 textures and a shader */ + if (data->shaders && data->num_texture_units >= 3) { + renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12; + } +#endif + /* Set up parameters for rendering */ data->blendMode = -1; data->glDisable(GL_DEPTH_TEST); @@ -579,6 +608,7 @@ GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points, GL_ActivateRenderer(renderer); GL_SetBlendMode(data, renderer->blendMode); + GL_SelectShader(data->shaders, SHADER_SOLID); data->glColor4f((GLfloat) renderer->r * inv255f, (GLfloat) renderer->g * inv255f, @@ -604,6 +634,7 @@ GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points, GL_ActivateRenderer(renderer); GL_SetBlendMode(data, renderer->blendMode); + GL_SelectShader(data->shaders, SHADER_SOLID); data->glColor4f((GLfloat) renderer->r * inv255f, (GLfloat) renderer->g * inv255f, @@ -674,6 +705,7 @@ GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect ** rects, int count) GL_ActivateRenderer(renderer); GL_SetBlendMode(data, renderer->blendMode); + GL_SelectShader(data->shaders, SHADER_SOLID); data->glColor4f((GLfloat) renderer->r * inv255f, (GLfloat) renderer->g * inv255f, @@ -727,6 +759,7 @@ GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, } GL_SetBlendMode(data, texture->blendMode); + GL_SelectShader(data->shaders, SHADER_RGB); data->glBegin(GL_TRIANGLE_STRIP); data->glTexCoord2f(minu, minv); diff --git a/src/render/opengl/SDL_shaders_gl.c b/src/render/opengl/SDL_shaders_gl.c new file mode 100644 index 000000000..f62d6d783 --- /dev/null +++ b/src/render/opengl/SDL_shaders_gl.c @@ -0,0 +1,304 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +#if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED + +#include "SDL_stdinc.h" +#include "SDL_log.h" +#include "SDL_opengl.h" +#include "SDL_video.h" +#include "SDL_shaders_gl.h" + +/* OpenGL shader implementation */ + +typedef struct +{ + GLenum program; + GLenum vert_shader; + GLenum frag_shader; +} GL_ShaderData; + +struct GL_ShaderContext +{ + GLenum (*glGetError)(void); + + PFNGLATTACHOBJECTARBPROC glAttachObjectARB; + PFNGLCOMPILESHADERARBPROC glCompileShaderARB; + PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB; + PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB; + PFNGLDELETEOBJECTARBPROC glDeleteObjectARB; + PFNGLGETINFOLOGARBPROC glGetInfoLogARB; + PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB; + PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB; + PFNGLLINKPROGRAMARBPROC glLinkProgramARB; + PFNGLSHADERSOURCEARBPROC glShaderSourceARB; + PFNGLUNIFORM1IARBPROC glUniform1iARB; + PFNGLUNIFORM1FARBPROC glUniform1fARB; + PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB; + + GL_Shader current_shader; + GL_ShaderData shaders[NUM_SHADERS]; +}; + +static const char *shader_source[NUM_SHADERS][2] = +{ + /* SHADER_NONE */ + { NULL, NULL }, + + /* SHADER_SOLID */ + { + /* vertex shader */ + " \ +varying vec4 v_color; \ + \ +void main() \ +{ \ + gl_Position = ftransform(); \ + v_color = gl_Color; \ +} \ +", + /* fragment shader */ + " \ +varying vec4 v_color; \ + \ +void main() \ +{ \ + gl_FragColor = v_color; \ +} \ +" + }, + + /* SHADER_RGB */ + { + /* vertex shader */ + " \ +varying vec4 v_color; \ +varying vec2 v_texCoord; \ + \ +void main() \ +{ \ + gl_Position = ftransform(); \ + v_color = gl_Color; \ + v_texCoord = vec2(gl_MultiTexCoord0); \ +} \ +", + /* fragment shader */ + " \ +varying vec4 v_color; \ +varying vec2 v_texCoord; \ +uniform sampler2D tex0; \ + \ +void main() \ +{ \ + gl_FragColor = texture2D(tex0, v_texCoord) * v_color; \ +} \ +" + }, +}; + +static SDL_bool +CompileShader(GL_ShaderContext *ctx, GLenum shader, const char *source) +{ + GLint status; + + ctx->glShaderSourceARB(shader, 1, &source, NULL); + ctx->glCompileShaderARB(shader); + ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status); + if (status == 0) { + GLint length; + char *info; + + ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length); + info = SDL_stack_alloc(char, length+1); + ctx->glGetInfoLogARB(shader, length, NULL, info); + SDL_LogError(SDL_LOG_CATEGORY_RENDER, + "Failed to compile shader:\n%s\n%s", source, info); +fprintf(stderr, "Failed to compile shader:\n%s\n%s", source, info); + SDL_stack_free(info); + + return SDL_FALSE; + } else { + return SDL_TRUE; + } +} + +static SDL_bool +CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data) +{ + const int num_tmus_bound = 4; + GLint status; + int i; + GLint location; + + if (index == SHADER_NONE) { + return SDL_TRUE; + } + + ctx->glGetError(); + + /* Create one program object to rule them all */ + data->program = ctx->glCreateProgramObjectARB(); + + /* Create the vertex shader */ + data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB); + if (!CompileShader(ctx, data->vert_shader, shader_source[index][0])) { + return SDL_FALSE; + } + + /* Create the fragment shader */ + data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); + if (!CompileShader(ctx, data->frag_shader, shader_source[index][1])) { + return SDL_FALSE; + } + + /* ... and in the darkness bind them */ + ctx->glAttachObjectARB(data->program, data->vert_shader); + ctx->glAttachObjectARB(data->program, data->frag_shader); + ctx->glLinkProgramARB(data->program); + + /* Set up some uniform variables */ + ctx->glUseProgramObjectARB(data->program); + for (i = 0; i < num_tmus_bound; ++i) { + char tex_name[5]; + SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i); + location = ctx->glGetUniformLocationARB(data->program, tex_name); + if (location >= 0) { + ctx->glUniform1iARB(location, 1); + } + } + ctx->glUseProgramObjectARB(0); + + return (ctx->glGetError() == GL_NO_ERROR); +} + +static void +DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data) +{ + if (index == SHADER_NONE) { + return; + } + + ctx->glDeleteObjectARB(data->vert_shader); + ctx->glDeleteObjectARB(data->frag_shader); + ctx->glDeleteObjectARB(data->program); +} + +GL_ShaderContext * +GL_CreateShaderContext() +{ + GL_ShaderContext *ctx; + SDL_bool shaders_supported; + int i; + + ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx)); + if (!ctx) { + return NULL; + } + + /* Check for shader support */ + shaders_supported = SDL_FALSE; + if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") && + SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") && + SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") && + SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) { + ctx->glGetError = (GLenum (*)(void)) SDL_GL_GetProcAddress("glGetError"); + ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB"); + ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB"); + ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB"); + ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB"); + ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB"); + ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB"); + ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB"); + ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB"); + ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB"); + ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB"); + ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB"); + ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB"); + ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB"); + if (ctx->glGetError && + ctx->glAttachObjectARB && + ctx->glCompileShaderARB && + ctx->glCreateProgramObjectARB && + ctx->glCreateShaderObjectARB && + ctx->glDeleteObjectARB && + ctx->glGetInfoLogARB && + ctx->glGetObjectParameterivARB && + ctx->glGetUniformLocationARB && + ctx->glLinkProgramARB && + ctx->glShaderSourceARB && + ctx->glUniform1iARB && + ctx->glUniform1fARB && + ctx->glUseProgramObjectARB) { + shaders_supported = SDL_TRUE; + } + } + + if (!shaders_supported) { + GL_DestroyShaderContext(ctx); + return NULL; + } + + /* Compile all the shaders */ + for (i = 0; i < NUM_SHADERS; ++i) { + if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) { +fprintf(stderr, "Unable to compile shader!\n"); + GL_DestroyShaderContext(ctx); + return NULL; + } + } + + /* We're done! */ + return ctx; +} + +void +GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader) +{ + /* Nothing to do if there's no shader support */ + if (!ctx) { + return; + } + + /* Nothing to do if there's no shader change */ + if (shader == ctx->current_shader) { + return; + } + + ctx->glUseProgramObjectARB(ctx->shaders[shader].program); + ctx->current_shader = shader; +} + +void +GL_DestroyShaderContext(GL_ShaderContext *ctx) +{ + int i; + + for (i = 0; i < NUM_SHADERS; ++i) { + DestroyShaderProgram(ctx, &ctx->shaders[i]); + } + SDL_free(ctx); +} + +#endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/opengl/SDL_shaders_gl.h b/src/render/opengl/SDL_shaders_gl.h new file mode 100644 index 000000000..dfb821ba2 --- /dev/null +++ b/src/render/opengl/SDL_shaders_gl.h @@ -0,0 +1,40 @@ +/* + SDL - Simple DirectMedia Layer + Copyright (C) 1997-2010 Sam Lantinga + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + Sam Lantinga + slouken@libsdl.org +*/ +#include "SDL_config.h" + +/* OpenGL shader implementation */ + +typedef enum { + SHADER_NONE, + SHADER_SOLID, + SHADER_RGB, + //SHADER_YV12, + NUM_SHADERS +} GL_Shader; + +typedef struct GL_ShaderContext GL_ShaderContext; + +extern GL_ShaderContext * GL_CreateShaderContext(); +extern void GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader); +extern void GL_DestroyShaderContext(GL_ShaderContext *ctx); + +/* vi: set ts=4 sw=4 expandtab: */