comparison src/render/opengl/SDL_shaders_gl.c @ 5233:811beeb698f9

Beginning of a framework for OpenGL shaders
author Sam Lantinga <slouken@libsdl.org>
date Tue, 08 Feb 2011 16:27:52 -0800
parents
children c015d3e63631
comparison
equal deleted inserted replaced
5232:9c0c4d767ef6 5233:811beeb698f9
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2010 Sam Lantinga
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 Sam Lantinga
20 slouken@libsdl.org
21 */
22 #include "SDL_config.h"
23
24 #if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
25
26 #include "SDL_stdinc.h"
27 #include "SDL_log.h"
28 #include "SDL_opengl.h"
29 #include "SDL_video.h"
30 #include "SDL_shaders_gl.h"
31
32 /* OpenGL shader implementation */
33
34 typedef struct
35 {
36 GLenum program;
37 GLenum vert_shader;
38 GLenum frag_shader;
39 } GL_ShaderData;
40
41 struct GL_ShaderContext
42 {
43 GLenum (*glGetError)(void);
44
45 PFNGLATTACHOBJECTARBPROC glAttachObjectARB;
46 PFNGLCOMPILESHADERARBPROC glCompileShaderARB;
47 PFNGLCREATEPROGRAMOBJECTARBPROC glCreateProgramObjectARB;
48 PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB;
49 PFNGLDELETEOBJECTARBPROC glDeleteObjectARB;
50 PFNGLGETINFOLOGARBPROC glGetInfoLogARB;
51 PFNGLGETOBJECTPARAMETERIVARBPROC glGetObjectParameterivARB;
52 PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB;
53 PFNGLLINKPROGRAMARBPROC glLinkProgramARB;
54 PFNGLSHADERSOURCEARBPROC glShaderSourceARB;
55 PFNGLUNIFORM1IARBPROC glUniform1iARB;
56 PFNGLUNIFORM1FARBPROC glUniform1fARB;
57 PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB;
58
59 GL_Shader current_shader;
60 GL_ShaderData shaders[NUM_SHADERS];
61 };
62
63 static const char *shader_source[NUM_SHADERS][2] =
64 {
65 /* SHADER_NONE */
66 { NULL, NULL },
67
68 /* SHADER_SOLID */
69 {
70 /* vertex shader */
71 " \
72 varying vec4 v_color; \
73 \
74 void main() \
75 { \
76 gl_Position = ftransform(); \
77 v_color = gl_Color; \
78 } \
79 ",
80 /* fragment shader */
81 " \
82 varying vec4 v_color; \
83 \
84 void main() \
85 { \
86 gl_FragColor = v_color; \
87 } \
88 "
89 },
90
91 /* SHADER_RGB */
92 {
93 /* vertex shader */
94 " \
95 varying vec4 v_color; \
96 varying vec2 v_texCoord; \
97 \
98 void main() \
99 { \
100 gl_Position = ftransform(); \
101 v_color = gl_Color; \
102 v_texCoord = vec2(gl_MultiTexCoord0); \
103 } \
104 ",
105 /* fragment shader */
106 " \
107 varying vec4 v_color; \
108 varying vec2 v_texCoord; \
109 uniform sampler2D tex0; \
110 \
111 void main() \
112 { \
113 gl_FragColor = texture2D(tex0, v_texCoord) * v_color; \
114 } \
115 "
116 },
117 };
118
119 static SDL_bool
120 CompileShader(GL_ShaderContext *ctx, GLenum shader, const char *source)
121 {
122 GLint status;
123
124 ctx->glShaderSourceARB(shader, 1, &source, NULL);
125 ctx->glCompileShaderARB(shader);
126 ctx->glGetObjectParameterivARB(shader, GL_OBJECT_COMPILE_STATUS_ARB, &status);
127 if (status == 0) {
128 GLint length;
129 char *info;
130
131 ctx->glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &length);
132 info = SDL_stack_alloc(char, length+1);
133 ctx->glGetInfoLogARB(shader, length, NULL, info);
134 SDL_LogError(SDL_LOG_CATEGORY_RENDER,
135 "Failed to compile shader:\n%s\n%s", source, info);
136 fprintf(stderr, "Failed to compile shader:\n%s\n%s", source, info);
137 SDL_stack_free(info);
138
139 return SDL_FALSE;
140 } else {
141 return SDL_TRUE;
142 }
143 }
144
145 static SDL_bool
146 CompileShaderProgram(GL_ShaderContext *ctx, int index, GL_ShaderData *data)
147 {
148 const int num_tmus_bound = 4;
149 GLint status;
150 int i;
151 GLint location;
152
153 if (index == SHADER_NONE) {
154 return SDL_TRUE;
155 }
156
157 ctx->glGetError();
158
159 /* Create one program object to rule them all */
160 data->program = ctx->glCreateProgramObjectARB();
161
162 /* Create the vertex shader */
163 data->vert_shader = ctx->glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
164 if (!CompileShader(ctx, data->vert_shader, shader_source[index][0])) {
165 return SDL_FALSE;
166 }
167
168 /* Create the fragment shader */
169 data->frag_shader = ctx->glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
170 if (!CompileShader(ctx, data->frag_shader, shader_source[index][1])) {
171 return SDL_FALSE;
172 }
173
174 /* ... and in the darkness bind them */
175 ctx->glAttachObjectARB(data->program, data->vert_shader);
176 ctx->glAttachObjectARB(data->program, data->frag_shader);
177 ctx->glLinkProgramARB(data->program);
178
179 /* Set up some uniform variables */
180 ctx->glUseProgramObjectARB(data->program);
181 for (i = 0; i < num_tmus_bound; ++i) {
182 char tex_name[5];
183 SDL_snprintf(tex_name, SDL_arraysize(tex_name), "tex%d", i);
184 location = ctx->glGetUniformLocationARB(data->program, tex_name);
185 if (location >= 0) {
186 ctx->glUniform1iARB(location, 1);
187 }
188 }
189 ctx->glUseProgramObjectARB(0);
190
191 return (ctx->glGetError() == GL_NO_ERROR);
192 }
193
194 static void
195 DestroyShaderProgram(GL_ShaderContext *ctx, GL_ShaderData *data)
196 {
197 if (index == SHADER_NONE) {
198 return;
199 }
200
201 ctx->glDeleteObjectARB(data->vert_shader);
202 ctx->glDeleteObjectARB(data->frag_shader);
203 ctx->glDeleteObjectARB(data->program);
204 }
205
206 GL_ShaderContext *
207 GL_CreateShaderContext()
208 {
209 GL_ShaderContext *ctx;
210 SDL_bool shaders_supported;
211 int i;
212
213 ctx = (GL_ShaderContext *)SDL_calloc(1, sizeof(*ctx));
214 if (!ctx) {
215 return NULL;
216 }
217
218 /* Check for shader support */
219 shaders_supported = SDL_FALSE;
220 if (SDL_GL_ExtensionSupported("GL_ARB_shader_objects") &&
221 SDL_GL_ExtensionSupported("GL_ARB_shading_language_100") &&
222 SDL_GL_ExtensionSupported("GL_ARB_vertex_shader") &&
223 SDL_GL_ExtensionSupported("GL_ARB_fragment_shader")) {
224 ctx->glGetError = (GLenum (*)(void)) SDL_GL_GetProcAddress("glGetError");
225 ctx->glAttachObjectARB = (PFNGLATTACHOBJECTARBPROC) SDL_GL_GetProcAddress("glAttachObjectARB");
226 ctx->glCompileShaderARB = (PFNGLCOMPILESHADERARBPROC) SDL_GL_GetProcAddress("glCompileShaderARB");
227 ctx->glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glCreateProgramObjectARB");
228 ctx->glCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC) SDL_GL_GetProcAddress("glCreateShaderObjectARB");
229 ctx->glDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC) SDL_GL_GetProcAddress("glDeleteObjectARB");
230 ctx->glGetInfoLogARB = (PFNGLGETINFOLOGARBPROC) SDL_GL_GetProcAddress("glGetInfoLogARB");
231 ctx->glGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC) SDL_GL_GetProcAddress("glGetObjectParameterivARB");
232 ctx->glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) SDL_GL_GetProcAddress("glGetUniformLocationARB");
233 ctx->glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) SDL_GL_GetProcAddress("glLinkProgramARB");
234 ctx->glShaderSourceARB = (PFNGLSHADERSOURCEARBPROC) SDL_GL_GetProcAddress("glShaderSourceARB");
235 ctx->glUniform1iARB = (PFNGLUNIFORM1IARBPROC) SDL_GL_GetProcAddress("glUniform1iARB");
236 ctx->glUniform1fARB = (PFNGLUNIFORM1FARBPROC) SDL_GL_GetProcAddress("glUniform1fARB");
237 ctx->glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) SDL_GL_GetProcAddress("glUseProgramObjectARB");
238 if (ctx->glGetError &&
239 ctx->glAttachObjectARB &&
240 ctx->glCompileShaderARB &&
241 ctx->glCreateProgramObjectARB &&
242 ctx->glCreateShaderObjectARB &&
243 ctx->glDeleteObjectARB &&
244 ctx->glGetInfoLogARB &&
245 ctx->glGetObjectParameterivARB &&
246 ctx->glGetUniformLocationARB &&
247 ctx->glLinkProgramARB &&
248 ctx->glShaderSourceARB &&
249 ctx->glUniform1iARB &&
250 ctx->glUniform1fARB &&
251 ctx->glUseProgramObjectARB) {
252 shaders_supported = SDL_TRUE;
253 }
254 }
255
256 if (!shaders_supported) {
257 GL_DestroyShaderContext(ctx);
258 return NULL;
259 }
260
261 /* Compile all the shaders */
262 for (i = 0; i < NUM_SHADERS; ++i) {
263 if (!CompileShaderProgram(ctx, i, &ctx->shaders[i])) {
264 fprintf(stderr, "Unable to compile shader!\n");
265 GL_DestroyShaderContext(ctx);
266 return NULL;
267 }
268 }
269
270 /* We're done! */
271 return ctx;
272 }
273
274 void
275 GL_SelectShader(GL_ShaderContext *ctx, GL_Shader shader)
276 {
277 /* Nothing to do if there's no shader support */
278 if (!ctx) {
279 return;
280 }
281
282 /* Nothing to do if there's no shader change */
283 if (shader == ctx->current_shader) {
284 return;
285 }
286
287 ctx->glUseProgramObjectARB(ctx->shaders[shader].program);
288 ctx->current_shader = shader;
289 }
290
291 void
292 GL_DestroyShaderContext(GL_ShaderContext *ctx)
293 {
294 int i;
295
296 for (i = 0; i < NUM_SHADERS; ++i) {
297 DestroyShaderProgram(ctx, &ctx->shaders[i]);
298 }
299 SDL_free(ctx);
300 }
301
302 #endif /* SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED */
303
304 /* vi: set ts=4 sw=4 expandtab: */