2 #include "yagl_gles2_shader.h"
3 #include "yagl_gles2_driver.h"
5 struct yagl_gles2_shader_strtok
12 static void yagl_gles2_shader_destroy(struct yagl_ref *ref)
14 struct yagl_gles2_shader *shader = (struct yagl_gles2_shader*)ref;
16 if (!shader->base.nodelete) {
17 shader->driver_ps->DeleteShader(shader->driver_ps, shader->global_name);
20 yagl_object_cleanup(&shader->base);
25 struct yagl_gles2_shader
26 *yagl_gles2_shader_create(struct yagl_gles2_driver_ps *driver_ps,
30 struct yagl_gles2_shader *shader;
32 global_name = driver_ps->CreateShader(driver_ps, type);
34 if (global_name == 0) {
38 shader = g_malloc0(sizeof(*shader));
40 yagl_object_init(&shader->base, &yagl_gles2_shader_destroy);
42 shader->driver_ps = driver_ps;
43 shader->global_name = global_name;
49 static const char *g_delim = " \t\n\r()[]{},;?:/%*&|^!+-=<>";
51 static const char *yagl_gles2_shader_opengl_strtok(struct yagl_gles2_shader_strtok *st,
56 if (!*(st->prev) || !*n) {
74 for (; *n && strchr(g_delim, *s); s++, (*n)--) {
75 if (*s == '/' && *n > 1) {
79 } while (*n > 1 && s[1] != '\n' && s[1] != '\r');
80 } else if (s[1] == '*') {
83 } while (*n > 2 && (s[1] != '*' || s[2] != '/'));
92 for (; *n && *e && !strchr(g_delim, *e); e++, (*n)--);
95 if (st->buffersize < e - s) {
96 st->buffersize = e - s;
100 st->buffer = g_malloc(st->buffersize + 1);
102 /* never return comment fields so caller does not need to handle them */
103 char *p = st->buffer;
106 if (*s == '/' && m > 1) {
110 } while (m > 1 && s[1] != '\n' && s[1] != '\r');
113 } else if (s[1] == '*') {
116 } while (m > 2 && (s[1] != '*' || s[2] != '/'));
121 *(p++) = *(s++), m--;
127 static char *yagl_gles2_shader_patch(const char *source,
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. */
139 struct yagl_gles2_shader_strtok st;
147 length = strlen(source);
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")) {
156 } else if (!strcmp(p, "precision")) {
157 while ((p = yagl_gles2_shader_opengl_strtok(&st, 0, &length)) && !strchr(p, ';'));
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)";
166 int new_len = strlen(p);
167 if (*patched_len + new_len > patched_size) {
169 patched = g_realloc(patched, patched_size + 1);
171 memcpy(patched + *patched_len, p, new_len);
172 *patched_len += new_len;
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 == '/') {
185 for (; *sp && *sp != '\n' && *sp != '\r'; sp++);
186 for (; *sp == '\n' || *sp == '\r'; sp++);
194 void yagl_gles2_shader_source(struct yagl_gles2_shader *shader,
197 bool strip_precision)
199 GLchar **processed_strings = NULL;
200 GLint *lengths = NULL;
203 if (strip_precision) {
204 processed_strings = g_malloc0(count * sizeof(*processed_strings));
207 lengths = g_malloc0(count * sizeof(*lengths));
209 for (i = 0; i < count; ++i) {
210 if (strip_precision) {
211 processed_strings[i] = yagl_gles2_shader_patch(strings[i],
216 lengths[i] = strlen(strings[i]);
220 shader->driver_ps->ShaderSource(shader->driver_ps,
223 (const GLchar**)(strip_precision ? processed_strings : strings),
227 if (processed_strings) {
228 for (i = 0; i < count; ++i) {
229 g_free(processed_strings[i]);
231 g_free(processed_strings);
235 void yagl_gles2_shader_compile(struct yagl_gles2_shader *shader)
237 shader->driver_ps->CompileShader(shader->driver_ps, shader->global_name);
240 void yagl_gles2_shader_get_param(struct yagl_gles2_shader *shader,
244 shader->driver_ps->GetShaderiv(shader->driver_ps,
250 void yagl_gles2_shader_get_source(struct yagl_gles2_shader *shader,
255 shader->driver_ps->GetShaderSource(shader->driver_ps,
262 void yagl_gles2_shader_get_info_log(struct yagl_gles2_shader *shader,
267 shader->driver_ps->GetShaderInfoLog(shader->driver_ps,
274 void yagl_gles2_shader_acquire(struct yagl_gles2_shader *shader)
277 yagl_object_acquire(&shader->base);
281 void yagl_gles2_shader_release(struct yagl_gles2_shader *shader)
284 yagl_object_release(&shader->base);