sync with tizen_2.2
[sdk/emulator/qemu.git] / hw / yagl_apis / gles2 / yagl_gles2_shader.c
1 #include <GLES2/gl2.h>
2 #include "yagl_gles2_shader.h"
3 #include "yagl_gles2_driver.h"
4
5 struct yagl_gles2_shader_strtok
6 {
7     char *buffer;
8     int buffersize;
9     const char *prev;
10 };
11
12 static void yagl_gles2_shader_destroy(struct yagl_ref *ref)
13 {
14     struct yagl_gles2_shader *shader = (struct yagl_gles2_shader*)ref;
15
16     if (!shader->base.nodelete) {
17         shader->driver_ps->DeleteShader(shader->driver_ps, shader->global_name);
18     }
19
20     yagl_object_cleanup(&shader->base);
21
22     g_free(shader);
23 }
24
25 struct yagl_gles2_shader
26     *yagl_gles2_shader_create(struct yagl_gles2_driver_ps *driver_ps,
27                               GLenum type)
28 {
29     GLuint global_name;
30     struct yagl_gles2_shader *shader;
31
32     global_name = driver_ps->CreateShader(driver_ps, type);
33
34     if (global_name == 0) {
35         return NULL;
36     }
37
38     shader = g_malloc0(sizeof(*shader));
39
40     yagl_object_init(&shader->base, &yagl_gles2_shader_destroy);
41
42     shader->driver_ps = driver_ps;
43     shader->global_name = global_name;
44     shader->type = type;
45
46     return shader;
47 }
48
49 static const char *g_delim = " \t\n\r()[]{},;?:/%*&|^!+-=<>";
50
51 static const char *yagl_gles2_shader_opengl_strtok(struct yagl_gles2_shader_strtok *st,
52                                                    const char *s,
53                                                    int *n)
54 {
55     if (!s) {
56         if (!*(st->prev) || !*n) {
57             if (st->buffer) {
58                 g_free(st->buffer);
59                 st->buffer = 0;
60                 st->buffersize = -1;
61             }
62             st->prev = 0;
63             return 0;
64         }
65         s = st->prev;
66     } else {
67         if (st->buffer) {
68             g_free(st->buffer);
69             st->buffer = 0;
70             st->buffersize = -1;
71         }
72         st->prev = s;
73     }
74     for (; *n && strchr(g_delim, *s); s++, (*n)--) {
75         if (*s == '/' && *n > 1) {
76             if (s[1] == '/') {
77                 do {
78                     s++, (*n)--;
79                 } while (*n > 1 && s[1] != '\n' && s[1] != '\r');
80             } else if (s[1] == '*') {
81                 do {
82                     s++, (*n)--;
83                 } while (*n > 2 && (s[1] != '*' || s[2] != '/'));
84                 s++, (*n)--;
85             }
86         }
87     }
88     const char *e = s;
89     if (s > st->prev) {
90         s = st->prev;
91     } else {
92         for (; *n && *e && !strchr(g_delim, *e); e++, (*n)--);
93     }
94     st->prev = e;
95     if (st->buffersize < e - s) {
96         st->buffersize = e - s;
97         if (st->buffer) {
98             g_free(st->buffer);
99         }
100         st->buffer = g_malloc(st->buffersize + 1);
101     }
102     /* never return comment fields so caller does not need to handle them */
103     char *p = st->buffer;
104     int m = e - s;
105     while (m > 0) {
106         if (*s == '/' && m > 1) {
107             if (s[1] == '/') {
108                 do {
109                     s++, m--;
110                 } while (m > 1 && s[1] != '\n' && s[1] != '\r');
111                 s++, m--;
112                 continue;
113             } else if (s[1] == '*') {
114                 do {
115                     s++, m--;
116                 } while (m > 2 && (s[1] != '*' || s[2] != '/'));
117                 s += 3, m -= 3;
118                 continue;
119             }
120         }
121         *(p++) = *(s++), m--;
122     }
123     *p = 0;
124     return st->buffer;
125 }
126
127 static char *yagl_gles2_shader_patch(const char *source,
128                                      int length,
129                                      int *patched_len)
130 {
131     /* DISCLAIMER: this is not a full-blown shader parser but a simple
132      * implementation which tries to remove the OpenGL ES shader
133      * "precision" statements and precision qualifiers "lowp", "mediump"
134      * and "highp" from the specified shader source. It also replaces
135      * OpenGL ES shading language built-in constants gl_MaxVertexUniformVectors,
136      * gl_MaxFragmentUniformVectors and gl_MaxVaryingVectors with corresponding
137      * values from OpenGL shading language. */
138
139     struct yagl_gles2_shader_strtok st;
140     char *sp;
141
142     st.buffer = NULL;
143     st.buffersize = -1;
144     st.prev = NULL;
145
146     if (!length) {
147         length = strlen(source);
148     }
149     *patched_len = 0;
150     int patched_size = length;
151     char *patched = g_malloc(patched_size + 1);
152     const char *p = yagl_gles2_shader_opengl_strtok(&st, source, &length);
153     for (; p; p = yagl_gles2_shader_opengl_strtok(&st, 0, &length)) {
154         if (!strcmp(p, "lowp") || !strcmp(p, "mediump") || !strcmp(p, "highp")) {
155             continue;
156         } else if (!strcmp(p, "precision")) {
157             while ((p = yagl_gles2_shader_opengl_strtok(&st, 0, &length)) && !strchr(p, ';'));
158         } else {
159             if (!strcmp(p, "gl_MaxVertexUniformVectors")) {
160                 p = "(gl_MaxVertexUniformComponents / 4)";
161             } else if (!strcmp(p, "gl_MaxFragmentUniformVectors")) {
162                 p = "(gl_MaxFragmentUniformComponents / 4)";
163             } else if (!strcmp(p, "gl_MaxVaryingVectors")) {
164                 p = "(gl_MaxVaryingFloats / 4)";
165             }
166             int new_len = strlen(p);
167             if (*patched_len + new_len > patched_size) {
168                 patched_size *= 2;
169                 patched = g_realloc(patched, patched_size + 1);
170             }
171             memcpy(patched + *patched_len, p, new_len);
172             *patched_len += new_len;
173         }
174     }
175     patched[*patched_len] = 0;
176     /* check that we don't leave dummy preprocessor lines */
177     for (sp = patched; *sp;) {
178         for (; *sp == ' ' || *sp == '\t'; sp++);
179         if (!strncmp(sp, "#define", 7)) {
180             for (p = sp + 7; *p == ' ' || *p == '\t'; p++);
181             if (*p == '\n' || *p == '\r' || *p == '/') {
182                 memset(sp, 0x20, 7);
183             }
184         }
185         for (; *sp && *sp != '\n' && *sp != '\r'; sp++);
186         for (; *sp == '\n' || *sp == '\r'; sp++);
187     }
188
189     g_free(st.buffer);
190
191     return patched;
192 }
193
194 void yagl_gles2_shader_source(struct yagl_gles2_shader *shader,
195                               GLchar **strings,
196                               int count,
197                               bool strip_precision)
198 {
199     GLchar **processed_strings = NULL;
200     GLint *lengths = NULL;
201     int i;
202
203     if (strip_precision) {
204         processed_strings = g_malloc0(count * sizeof(*processed_strings));
205     }
206
207     lengths = g_malloc0(count * sizeof(*lengths));
208
209     for (i = 0; i < count; ++i) {
210         if (strip_precision) {
211             processed_strings[i] = yagl_gles2_shader_patch(strings[i],
212                                                            strlen(strings[i]),
213                                                            &lengths[i]);
214
215         } else {
216             lengths[i] = strlen(strings[i]);
217         }
218     }
219
220     shader->driver_ps->ShaderSource(shader->driver_ps,
221                                     shader->global_name,
222                                     count,
223                                     (const GLchar**)(strip_precision ? processed_strings : strings),
224                                     lengths);
225
226     g_free(lengths);
227     if (processed_strings) {
228         for (i = 0; i < count; ++i) {
229             g_free(processed_strings[i]);
230         }
231         g_free(processed_strings);
232     }
233 }
234
235 void yagl_gles2_shader_compile(struct yagl_gles2_shader *shader)
236 {
237     shader->driver_ps->CompileShader(shader->driver_ps, shader->global_name);
238 }
239
240 void yagl_gles2_shader_get_param(struct yagl_gles2_shader *shader,
241                                  GLenum pname,
242                                  GLint *param)
243 {
244     shader->driver_ps->GetShaderiv(shader->driver_ps,
245                                    shader->global_name,
246                                    pname,
247                                    param);
248 }
249
250 void yagl_gles2_shader_get_source(struct yagl_gles2_shader *shader,
251                                   GLsizei bufsize,
252                                   GLsizei *length,
253                                   GLchar *source)
254 {
255     shader->driver_ps->GetShaderSource(shader->driver_ps,
256                                        shader->global_name,
257                                        bufsize,
258                                        length,
259                                        source);
260 }
261
262 void yagl_gles2_shader_get_info_log(struct yagl_gles2_shader *shader,
263                                     GLsizei bufsize,
264                                     GLsizei *length,
265                                     GLchar *infolog)
266 {
267     shader->driver_ps->GetShaderInfoLog(shader->driver_ps,
268                                         shader->global_name,
269                                         bufsize,
270                                         length,
271                                         infolog);
272 }
273
274 void yagl_gles2_shader_acquire(struct yagl_gles2_shader *shader)
275 {
276     if (shader) {
277         yagl_object_acquire(&shader->base);
278     }
279 }
280
281 void yagl_gles2_shader_release(struct yagl_gles2_shader *shader)
282 {
283     if (shader) {
284         yagl_object_release(&shader->base);
285     }
286 }