"Initial commit to Gerrit"
[profile/ivi/cogl.git] / cogl / cogl-shader.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2007,2008,2009,2010 Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include "cogl-shader-private.h"
29 #include "cogl-shader-boilerplate.h"
30 #include "cogl-internal.h"
31 #include "cogl-context-private.h"
32 #include "cogl-handle.h"
33
34 #include <glib.h>
35
36 #include <string.h>
37
38 static void _cogl_shader_free (CoglShader *shader);
39
40 COGL_HANDLE_DEFINE (Shader, shader);
41 COGL_OBJECT_DEFINE_DEPRECATED_REF_COUNTING (shader);
42
43 #ifndef GL_FRAGMENT_SHADER
44 #define GL_FRAGMENT_SHADER 0x8B30
45 #endif
46 #ifndef GL_VERTEX_SHADER
47 #define GL_VERTEX_SHADER 0x8B31
48 #endif
49
50 static void
51 _cogl_shader_free (CoglShader *shader)
52 {
53   /* Frees shader resources but its handle is not
54      released! Do that separately before this! */
55   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
56
57 #ifdef HAVE_COGL_GL
58   if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
59     {
60       if (shader->gl_handle)
61         GE (ctx, glDeletePrograms (1, &shader->gl_handle));
62     }
63   else
64 #endif
65     if (shader->gl_handle)
66       GE (ctx, glDeleteShader (shader->gl_handle));
67
68   g_slice_free (CoglShader, shader);
69 }
70
71 CoglHandle
72 cogl_create_shader (CoglShaderType type)
73 {
74   CoglShader *shader;
75
76   _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
77
78   switch (type)
79     {
80     case COGL_SHADER_TYPE_VERTEX:
81     case COGL_SHADER_TYPE_FRAGMENT:
82       break;
83     default:
84       g_warning ("Unexpected shader type (0x%08lX) given to "
85                  "cogl_create_shader", (unsigned long) type);
86       return COGL_INVALID_HANDLE;
87     }
88
89   shader = g_slice_new (CoglShader);
90   shader->language = COGL_SHADER_LANGUAGE_GLSL;
91   shader->gl_handle = 0;
92 #ifdef HAVE_COGL_GLES2
93   shader->n_tex_coord_attribs = 0;
94 #endif
95   shader->type = type;
96
97   return _cogl_shader_handle_new (shader);
98 }
99
100 static void
101 delete_shader (CoglShader *shader)
102 {
103   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
104
105 #ifdef HAVE_COGL_GL
106   if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
107     {
108       if (shader->gl_handle)
109         GE (ctx, glDeletePrograms (1, &shader->gl_handle));
110     }
111   else
112 #endif
113     {
114       if (shader->gl_handle)
115         GE (ctx, glDeleteShader (shader->gl_handle));
116     }
117
118   shader->gl_handle = 0;
119 }
120
121 void
122 cogl_shader_source (CoglHandle   handle,
123                     const char  *source)
124 {
125   CoglShader *shader;
126   CoglShaderLanguage language;
127
128   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
129
130   if (!cogl_is_shader (handle))
131     return;
132
133   shader = handle;
134
135 #ifdef HAVE_COGL_GL
136   if (strncmp (source, "!!ARBfp1.0", 10) == 0)
137     language = COGL_SHADER_LANGUAGE_ARBFP;
138   else
139 #endif
140     language = COGL_SHADER_LANGUAGE_GLSL;
141
142   /* Delete the old object if the language is changing... */
143   if (G_UNLIKELY (language != shader->language) &&
144       shader->gl_handle)
145     delete_shader (shader);
146
147   shader->source = g_strdup (source);
148
149   shader->language = language;
150 }
151
152 void
153 cogl_shader_compile (CoglHandle handle)
154 {
155   CoglShader *shader = handle;
156
157   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
158
159   if (!cogl_is_shader (handle))
160     return;
161
162   if (ctx->driver == COGL_DRIVER_GL)
163     _cogl_shader_compile_real (shader, 0 /* ignored */);
164
165   /* XXX: For GLES2 we don't actually compile anything until the
166    * shader gets used so we have an opportunity to add some
167    * boilerplate to the shader.
168    *
169    * At the end of the day this is obviously a badly designed API
170    * given that we are having to lie to the user. It was a mistake to
171    * so thinly wrap the OpenGL shader API and the current plan is to
172    * replace it with a pipeline snippets API. */
173 }
174
175 void
176 _cogl_shader_set_source_with_boilerplate (GLuint shader_gl_handle,
177                                           GLenum shader_gl_type,
178                                           int n_tex_coord_attribs,
179                                           GLsizei count_in,
180                                           const char **strings_in,
181                                           const GLint *lengths_in)
182 {
183   const char *vertex_boilerplate;
184   const char *fragment_boilerplate;
185
186   const char **strings = g_alloca (sizeof (char *) * (count_in + 3));
187   GLint *lengths = g_alloca (sizeof (GLint) * (count_in + 3));
188   int count = 0;
189   char *tex_coord_declarations = NULL;
190
191   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
192
193   if (ctx->driver == COGL_DRIVER_GLES2)
194     {
195       vertex_boilerplate = _COGL_VERTEX_SHADER_BOILERPLATE_GLES2;
196       fragment_boilerplate = _COGL_FRAGMENT_SHADER_BOILERPLATE_GLES2;
197     }
198   else
199     {
200       vertex_boilerplate = _COGL_VERTEX_SHADER_BOILERPLATE_GL;
201       fragment_boilerplate = _COGL_FRAGMENT_SHADER_BOILERPLATE_GL;
202     }
203
204   if (ctx->driver == COGL_DRIVER_GLES2 &&
205       cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D))
206     {
207       static const char texture_3d_extension[] =
208         "#extension GL_OES_texture_3D : enable\n";
209       strings[count] = texture_3d_extension;
210       lengths[count++] = sizeof (texture_3d_extension) - 1;
211     }
212
213   if (shader_gl_type == GL_VERTEX_SHADER)
214     {
215       strings[count] = vertex_boilerplate;
216       lengths[count++] = strlen (vertex_boilerplate);
217     }
218   else if (shader_gl_type == GL_FRAGMENT_SHADER)
219     {
220       strings[count] = fragment_boilerplate;
221       lengths[count++] = strlen (fragment_boilerplate);
222     }
223
224   if (ctx->driver == COGL_DRIVER_GLES2 &&
225       n_tex_coord_attribs)
226     {
227       GString *declarations = g_string_new (NULL);
228
229       g_string_append_printf (declarations,
230                               "varying vec4 _cogl_tex_coord[%d];\n",
231                               n_tex_coord_attribs);
232
233       if (shader_gl_type == GL_VERTEX_SHADER)
234         {
235           int i;
236
237           g_string_append_printf (declarations,
238                                   "uniform mat4 cogl_texture_matrix[%d];\n",
239                                   n_tex_coord_attribs);
240
241           for (i = 0; i < n_tex_coord_attribs; i++)
242             g_string_append_printf (declarations,
243                                     "attribute vec4 cogl_tex_coord%d_in;\n",
244                                     i);
245         }
246
247       tex_coord_declarations = g_string_free (declarations, FALSE);
248       strings[count] = tex_coord_declarations;
249       lengths[count++] = -1; /* null terminated */
250     }
251
252   memcpy (strings + count, strings_in, sizeof (char *) * count_in);
253   if (lengths_in)
254     memcpy (lengths + count, lengths_in, sizeof (GLint) * count_in);
255   else
256     {
257       int i;
258
259       for (i = 0; i < count_in; i++)
260         lengths[count + i] = -1; /* null terminated */
261     }
262   count += count_in;
263
264   if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
265     {
266       GString *buf = g_string_new (NULL);
267       int i;
268
269       g_string_append_printf (buf,
270                               "%s shader:\n",
271                               shader_gl_type == GL_VERTEX_SHADER ?
272                               "vertex" : "fragment");
273       for (i = 0; i < count; i++)
274         if (lengths[i] != -1)
275           g_string_append_len (buf, strings[i], lengths[i]);
276         else
277           g_string_append (buf, strings[i]);
278
279       g_message ("%s", buf->str);
280
281       g_string_free (buf, TRUE);
282     }
283
284   GE( ctx, glShaderSource (shader_gl_handle, count,
285                            (const char **) strings, lengths) );
286
287   g_free (tex_coord_declarations);
288 }
289
290 void
291 _cogl_shader_compile_real (CoglHandle handle,
292                            int n_tex_coord_attribs)
293 {
294   CoglShader *shader = handle;
295
296   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
297
298 #ifdef HAVE_COGL_GL
299   if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
300     {
301 #ifdef COGL_GL_DEBUG
302       GLenum gl_error;
303 #endif
304
305       if (shader->gl_handle)
306         return;
307
308       GE (ctx, glGenPrograms (1, &shader->gl_handle));
309
310       GE (ctx, glBindProgram (GL_FRAGMENT_PROGRAM_ARB, shader->gl_handle));
311
312       if (G_UNLIKELY (COGL_DEBUG_ENABLED (COGL_DEBUG_SHOW_SOURCE)))
313         g_message ("user ARBfp program:\n%s", shader->source);
314
315 #ifdef COGL_GL_DEBUG
316       while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
317         ;
318 #endif
319       ctx->glProgramString (GL_FRAGMENT_PROGRAM_ARB,
320                             GL_PROGRAM_FORMAT_ASCII_ARB,
321                             strlen (shader->source),
322                             shader->source);
323 #ifdef COGL_GL_DEBUG
324       gl_error = ctx->glGetError ();
325       if (gl_error != GL_NO_ERROR)
326         {
327           g_warning ("%s: GL error (%d): Failed to compile ARBfp:\n%s\n%s",
328                      G_STRLOC,
329                      gl_error,
330                      shader->source,
331                      ctx->glGetString (GL_PROGRAM_ERROR_STRING_ARB));
332         }
333 #endif
334     }
335   else
336 #endif
337     {
338       GLenum gl_type;
339
340       if (shader->gl_handle
341 #ifdef HAVE_COGL_GLES2
342           &&
343           (ctx->driver != COGL_DRIVER_GLES2 ||
344            shader->n_tex_coord_attribs == n_tex_coord_attribs)
345 #endif
346          )
347         return;
348
349       if (shader->gl_handle)
350         delete_shader (shader);
351
352       switch (shader->type)
353         {
354         case COGL_SHADER_TYPE_VERTEX:
355           gl_type = GL_VERTEX_SHADER;
356           break;
357         case COGL_SHADER_TYPE_FRAGMENT:
358           gl_type = GL_FRAGMENT_SHADER;
359           break;
360         default:
361           g_assert_not_reached ();
362           break;
363         }
364
365       shader->gl_handle = ctx->glCreateShader (gl_type);
366
367       _cogl_shader_set_source_with_boilerplate (shader->gl_handle,
368                                                 gl_type,
369                                                 n_tex_coord_attribs,
370                                                 1,
371                                                 (const char **) &shader->source,
372                                                 NULL);
373
374       GE (ctx, glCompileShader (shader->gl_handle));
375
376 #ifdef HAVE_COGL_GLES2
377       shader->n_tex_coord_attribs = n_tex_coord_attribs;
378 #endif
379
380 #ifdef COGL_GL_DEBUG
381       if (!cogl_shader_is_compiled (handle))
382         {
383           char *log = cogl_shader_get_info_log (handle);
384           g_warning ("Failed to compile GLSL program:\nsrc:\n%s\nerror:\n%s\n",
385                      shader->source,
386                      log);
387           g_free (log);
388         }
389 #endif
390     }
391 }
392
393 char *
394 cogl_shader_get_info_log (CoglHandle handle)
395 {
396   CoglShader *shader;
397
398   _COGL_GET_CONTEXT (ctx, NULL);
399
400   if (!cogl_is_shader (handle))
401     return NULL;
402
403   shader = handle;
404
405 #ifdef HAVE_COGL_GL
406   if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
407     {
408       /* ARBfp exposes a program error string, but since cogl_program
409        * doesn't have any API to query an error log it is not currently
410        * exposed. */
411       return g_strdup ("");
412     }
413   else
414 #endif
415     {
416       char buffer[512];
417       int len = 0;
418
419       /* We don't normally compile the shader when the user calls
420        * cogl_shader_compile() because we want to be able to add
421        * boilerplate code that depends on how it ends up finally being
422        * used.
423        *
424        * Here we force an early compile if the user is interested in
425        * log information to increase the chance that the log will be
426        * useful! We have to guess the number of texture coordinate
427        * attributes that may be used since that affects the
428        * boilerplate. We use four so that the shader will still
429        * compile if the user is using more than one
430        * layer. Unfortunately this is likely to end up causing it to
431        * be compiled again when we know the actual number of layers */
432       if (!shader->gl_handle)
433         _cogl_shader_compile_real (handle, 4);
434
435       ctx->glGetShaderInfoLog (shader->gl_handle, 511, &len, buffer);
436       buffer[len] = '\0';
437       return g_strdup (buffer);
438     }
439 }
440
441 CoglShaderType
442 cogl_shader_get_type (CoglHandle  handle)
443 {
444   CoglShader *shader;
445
446   _COGL_GET_CONTEXT (ctx, COGL_SHADER_TYPE_VERTEX);
447
448   if (!cogl_is_shader (handle))
449     {
450       g_warning ("Non shader handle type passed to cogl_shader_get_type");
451       return COGL_SHADER_TYPE_VERTEX;
452     }
453
454   shader = handle;
455   return shader->type;
456 }
457
458 gboolean
459 cogl_shader_is_compiled (CoglHandle handle)
460 {
461 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES2)
462   GLint status;
463   CoglShader *shader;
464
465   _COGL_GET_CONTEXT (ctx, FALSE);
466
467   if (!cogl_is_shader (handle))
468     return FALSE;
469
470   shader = handle;
471
472 #ifdef HAVE_COGL_GL
473   if (shader->language == COGL_SHADER_LANGUAGE_ARBFP)
474     return TRUE;
475   else
476 #endif
477     {
478       /* FIXME: We currently have an arbitrary limit of 4 texture
479        * coordinate attributes since our API means we have to add
480        * some boilerplate to the users GLSL program (for GLES2)
481        * before we actually know how many attributes are in use.
482        *
483        * 4 will probably be enough (or at least that limitation should
484        * be enough until we can replace this API with the pipeline
485        * snippets API) but if it isn't then the shader won't compile,
486        * through no fault of the user.
487        *
488        * To some extent this is just a symptom of bad API design; it
489        * was a mistake for Cogl to so thinly wrap the OpenGL shader
490        * API. Eventually we plan for this whole API will be deprecated
491        * by the pipeline snippets framework.
492        */
493       if (!shader->gl_handle)
494         _cogl_shader_compile_real (handle, 4);
495
496       GE (ctx, glGetShaderiv (shader->gl_handle, GL_COMPILE_STATUS, &status));
497       if (status == GL_TRUE)
498         return TRUE;
499       else
500         return FALSE;
501     }
502 #else
503   return FALSE;
504 #endif
505 }