--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/holdingarea/libGLESv2/src/GLES2/shader.c Thu Sep 16 09:43:14 2010 +0100
@@ -0,0 +1,554 @@
+/* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Initial Contributors:
+ * Nokia Corporation - initial contribution.
+ *
+ * Contributors:
+ *
+ * Description:
+ *
+ */
+
+#include "common.h"
+#include "hgl.h"
+#include "context.h"
+#include <string.h>
+
+DGLShader* DGLShader_create(GLuint name)
+{
+ DGLShader* shader = malloc(sizeof(DGLShader));
+ if(shader == NULL)
+ {
+ return NULL;
+ }
+
+ shader->obj.name = name;
+ shader->obj.next = NULL;
+
+ shader->source = NULL;
+ shader->length = 0;
+
+ return shader;
+}
+
+void DGLShader_destroy(DGLShader *shader)
+{
+ DGLES2_ASSERT(shader != NULL);
+ if(shader->source != NULL)
+ {
+ free(shader->source);
+ shader->source = NULL;
+ }
+ free(shader);
+}
+
+GL_APICALL_BUILD void GL_APIENTRY glCompileShader(GLuint shader)
+{
+ DGLES2_ENTER();
+ ctx->hgl.CompileShader(shader);
+ DGLES2_LEAVE();
+}
+
+GL_APICALL_BUILD GLuint GL_APIENTRY glCreateShader(GLenum type)
+{
+ DGLES2_ENTER_RET(0);
+ DGLES2_ERROR_IF_RET(type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER, GL_INVALID_ENUM, 0);
+ {
+ GLuint name = ctx->hgl.CreateShader(type);
+ if(DGLContext_getHostError(ctx) == GL_NO_ERROR && name != 0)
+ {
+ DGLContext_createShader(ctx, name);
+ }
+
+ DGLES2_LEAVE_RET(name);
+ }
+}
+
+GL_APICALL_BUILD void GL_APIENTRY glDeleteShader(GLuint shader)
+{
+ DGLES2_ENTER();
+ if(shader != 0)
+ {
+ DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
+ DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
+ ctx->hgl.DeleteShader(shader);
+ if(DGLContext_getHostError(ctx) == GL_NO_ERROR)
+ {
+ DGLContext_destroyShader(ctx, shader);
+ }
+ }
+ DGLES2_LEAVE();
+}
+
+GL_APICALL_BUILD void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
+{
+ DGLES2_ENTER();
+ DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
+ DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
+ if(pname == GL_SHADER_SOURCE_LENGTH)
+ {
+ DGLShader* shader_obj = DGLContext_findShader(ctx, shader);
+ DGLES2_ASSERT(shader_obj != NULL);
+ *params = shader_obj->length + 1;
+ }
+ else
+ {
+ ctx->hgl.GetShaderiv(shader, pname, params);
+ }
+ DGLES2_LEAVE();
+}
+
+GL_APICALL_BUILD void GL_APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
+{
+ DGLES2_ENTER();
+ DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
+ DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
+ ctx->hgl.GetShaderInfoLog(shader, bufsize, length, infolog);
+ DGLES2_LEAVE();
+}
+
+GL_APICALL_BUILD void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
+{
+ DGLES2_ENTER();
+ DGLES2_ERROR_IF(shadertype != GL_VERTEX_SHADER && shadertype != GL_FRAGMENT_SHADER, GL_INVALID_ENUM);
+ // Values from the GL ES and GLSL specifications.
+ switch(precisiontype)
+ {
+ case GL_LOW_FLOAT:
+ case GL_MEDIUM_FLOAT:
+ case GL_HIGH_FLOAT:
+ range[0] = 127;
+ range[1] = 127;
+ *precision = 23;
+ break;
+
+ case GL_LOW_INT:
+ case GL_MEDIUM_INT:
+ case GL_HIGH_INT:
+ range[0] = 15;
+ range[1] = 14;
+ *precision = 0;
+ break;
+ }
+ DGLES2_LEAVE();
+}
+
+GL_APICALL_BUILD void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
+{
+ DGLES2_ENTER();
+ DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
+ DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
+ DGLES2_ERROR_IF(bufsize < 0, GL_INVALID_VALUE);
+ {
+ DGLShader* shader_obj = DGLContext_findShader(ctx, shader);
+ DGLES2_ASSERT(shader_obj != NULL);
+
+ if(length != NULL)
+ {
+ *length = 0;
+ }
+
+ if(source != NULL)
+ {
+ GLsizei num_chars = shader_obj->length < bufsize - 1 ? shader_obj->length : bufsize - 1;
+ if(num_chars > 0)
+ {
+ strncpy(source, shader_obj->source, num_chars);
+ source[num_chars] = 0;
+ if(length != NULL)
+ {
+ *length = num_chars;
+ }
+ }
+ }
+ }
+ DGLES2_LEAVE();
+}
+
+GL_APICALL_BUILD GLboolean GL_APIENTRY glIsShader(GLuint shader)
+{
+ DGLES2_ENTER_RET(GL_FALSE);
+ DGLES2_LEAVE_RET(ctx->hgl.IsShader(shader));
+}
+
+GL_APICALL_BUILD void GL_APIENTRY glReleaseShaderCompiler(void)
+{
+ DGLES2_ENTER();
+ // No-op.
+ DGLES2_LEAVE();
+}
+
+GL_APICALL_BUILD void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length)
+{
+ DGLES2_ENTER();
+ // No supported formats.
+ DGLES2_ERROR(GL_INVALID_ENUM);
+ DGLES2_LEAVE();
+}
+
+static const char *opengl_strtok(const char *s, int *n)
+{
+ static char *buffer = 0;
+ static int buffersize = -1;
+ static const char *delim = " \t\n\r()[]{},;:";
+ static const char *prev = 0;
+ int cComment = 0;
+ int cppComment = 0;
+
+ if (!s) {
+ if (!*prev || !*n) {
+ if (buffer) {
+ free(buffer);
+ buffer = 0;
+ buffersize = -1;
+ }
+ prev = 0;
+ return 0;
+ }
+ s = prev;
+ } else {
+ if (buffer) {
+ free(buffer);
+ buffer = 0;
+ buffersize = -1;
+ }
+ prev = s;
+ }
+
+ if( *n && *s == '/') {
+ if(*(s+1) == '*') cComment = 1;
+ if(*(s+1) == '/') cppComment = 1;
+ }
+ if( cComment == 1 || cppComment == 1) {
+ for(; *n && (cComment == 1 || cppComment == 1); s++, (*n)--) {
+ if(cComment == 1 && *s == '*' && *(s+1) == '/' ) {
+ cComment = 0;
+ }
+ if(cppComment == 1 && *s == '\n') {
+ cppComment = 0;
+ }
+ }
+ } else {
+ for (; *n && strchr(delim, *s); s++, (*n)--);
+ }
+
+ if(s - prev > 0) {
+ if (buffersize < s - prev) {
+ buffersize = s - prev;
+ if (buffer) {
+ free(buffer);
+ }
+ buffer = malloc(buffersize + 1);
+ }
+ memcpy(buffer, prev, s - prev);
+ buffer[s - prev] = 0;
+ prev = s;
+ } else {
+ const char *e = s;
+ for (; *n && *e && !strchr(delim, *e); e++, (*n)--);
+ prev = e;
+ if (buffersize < e - s) {
+ buffersize = e - s;
+ if (buffer) {
+ free(buffer);
+ }
+ buffer = malloc(buffersize + 1);
+ }
+ memcpy(buffer, s, e - s);
+ buffer[e - s] = 0;
+ }
+ return buffer;
+}
+
+static char* do_eglShaderPatch(char *source, int len, int *patched_len)
+{
+ /* DISCLAIMER: this is not a full-blown shader parser but a simple
+ * implementation which tries to remove the OpenGL ES shader
+ * "precision" statements and precision qualifiers "lowp", "mediump"
+ * and "highp" from the specified shader source, replace built-in
+ * constants that were renamed in GLSL ES ("gl_MaxVertexUniformVectors",
+ * "gl_MaxFragmentUniformVectors" and "gl_MaxVaryingVectors")
+ * and insert a "#version 120" directive in the beginning of the source
+ * or replace an existing "#version 100" directive. */
+ DGLES2_ASSERT(source != NULL);
+ DGLES2_ASSERT(len >= 0);
+ {
+#ifndef DGLES2_ALLOW_GLSL_110
+ GLboolean version_found = GL_FALSE;
+#endif
+ int buffer_size;
+ char *patched;
+ const char *p;
+
+ *patched_len = 0;
+ buffer_size = len;
+ patched = malloc(buffer_size + 1);
+ if(patched == NULL) {
+ return NULL;
+ }
+
+ p = opengl_strtok(source, &len);
+ for (; p; p = opengl_strtok(0, &len)) {
+ if (!strcmp(p, "lowp") || !strcmp(p, "mediump") || !strcmp(p, "highp")) {
+ continue;
+ } else if (!strcmp(p, "precision")) {
+ do {
+ p = opengl_strtok(0, &len);
+ } while(p && !strchr(p, ';'));
+ } else {
+ int tok_len;
+ if (!strcmp(p, "gl_MaxVertexUniformVectors")) {
+ p = "(gl_MaxVertexUniformComponents / 4)";
+ } else if (!strcmp(p, "gl_MaxFragmentUniformVectors")) {
+ p = "(gl_MaxFragmentUniformComponents / 4)";
+ } else if (!strcmp(p, "gl_MaxVaryingVectors")) {
+ p = "(gl_MaxVaryingFloats / 4)";
+ }
+#ifndef DGLES2_ALLOW_GLSL_110
+ else if (!strcmp(p, "#version")) {
+ p = opengl_strtok(0, &len);
+ if (!strcmp(p, "100")) {
+ p = "#version 120";
+ version_found = GL_TRUE;
+ }
+ } else if (!strcmp(p, "#")) {
+ p = opengl_strtok(0, &len);
+ if (!strcmp(p, "version")) {
+ p = opengl_strtok(0, &len);
+ if (!strcmp(p, "100")) {
+ p = "#version 120";
+ version_found = GL_TRUE;
+ }
+ }
+ }
+#endif // !DGLES2_ALLOW_GLSL_110
+ tok_len = strlen(p);
+ if(*patched_len + tok_len > buffer_size) {
+ buffer_size *= 2;
+ patched = realloc(patched, buffer_size + 1);
+ if(patched == NULL) {
+ return NULL;
+ }
+ }
+ memcpy(patched + *patched_len, p, tok_len);
+ *patched_len += tok_len;
+ }
+ }
+ patched[*patched_len] = 0;
+#ifndef DGLES2_ALLOW_GLSL_110
+ /* add version directive is one was not found */
+ if (!version_found) {
+ char* new_patched;
+ *patched_len += strlen("#version 120\n");
+ new_patched = malloc(*patched_len + 1);
+ if (new_patched == NULL) {
+ return NULL;
+ }
+ strcpy(new_patched, "#version 120\n");
+ strcat(new_patched, patched);
+ free(patched);
+ patched = new_patched;
+ }
+#endif // !DGLES2_ALLOW_GLSL_110
+ {
+ /* check that we don't leave dummy preprocessor lines */
+ char *sp;
+ for (sp = patched; *sp;) {
+ for (; *sp == ' ' || *sp == '\t'; sp++);
+ if (!strncmp(sp, "#define", 7)) {
+ for (p = sp + 7; *p == ' ' || *p == '\t'; p++);
+ if (*p == '\n' || *p == '\r' || *p == '/') {
+ memset(sp, 0x20, 7);
+ }
+ }
+ for (; *sp && *sp != '\n' && *sp != '\r'; sp++);
+ for (; *sp == '\n' || *sp == '\r'; sp++);
+ }
+ }
+
+ return patched;
+ }
+}
+
+GL_APICALL_BUILD void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length)
+{
+ DGLES2_ENTER();
+ DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
+ DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
+ DGLES2_ERROR_IF(count < 0, GL_INVALID_VALUE);
+/*
+#if(CONFIG_DEBUG == 1)
+ Dprintf("Editing shader:\n--ORIGINAL-SHADER--\n");
+ for(unsigned i = 0; i < count; ++i)
+ {
+ if(length)
+ Dprintf("%*s", length[i], string[i]);
+ else
+ Dprintf("%s", string[i]);
+ }
+ Dprintf("---END-ORIGINAL-SHADER---\n");
+#endif // !NDEBUG
+ char** string_dgl = malloc(sizeof(char*)*count);
+ GLint* length_dgl = malloc(sizeof(GLint)*count);
+
+ // Remove the non OpenGL 2.x compilant keywords.
+ for(unsigned i = 0; i < count; ++i)
+ {
+ static const char* removables[] =
+ {
+ "precision highp float;",
+ "precision mediump float;",
+ "precision lowp float;",
+ "highp",
+ "lowp",
+ "mediump",
+ "precision"
+ };
+
+ length_dgl[i] = length ? length[i] : strlen(string[i]);
+ string_dgl[i] = malloc(length_dgl[i] + 1);
+ memcpy(string_dgl[i], string[i], length_dgl[i]);
+ string_dgl[i][length_dgl[i]] = 0;
+
+ for(unsigned j = 0; j < sizeof(removables)/sizeof(removables[0]); ++j)
+ {
+ char const* p;
+ while((p = strstr(string_dgl[i], removables[j])))
+ {
+ memmove(p, p + strlen(removables[j]), strlen(p + strlen(removables[j])) + 1);
+ }
+ }
+ }
+#if(CONFIG_DEBUG == 1)
+ Dprintf("Loading shader:\n--DESKTOP-GL-SHADER--\n");
+ for(unsigned i = 0; i < count; ++i)
+ {
+ Dprintf("%*s", length_dgl[i], string_dgl[i]);
+ }
+ Dprintf("---END-DESKTOP-GL-SHADER---\n");
+#endif // !NDEBUG
+
+ ctx->hgl.ShaderSource(shader, count, string_dgl, length_dgl);
+
+ for(unsigned i = 0; i < count; ++i)
+ free(string_dgl[i]);
+ free(string_dgl);
+ free(length_dgl);
+ */
+
+ if(count > 0 && string != NULL)
+ {
+ char* source = NULL;
+ int total_len = 0;
+
+ if(count > 1)
+ {
+ int i;
+
+ // Concatenate the passed strings into one source string.
+ for(i = 0; i < count; i++)
+ {
+ int len;
+
+ if(string[i] == NULL)
+ {
+ continue;
+ }
+
+ if(length == NULL || length[i] < 0)
+ {
+ len = strlen(string[i]);
+ }
+ else
+ {
+ len = length[i];
+ }
+
+ if(len > 0)
+ {
+ total_len += len;
+
+ if(source == NULL)
+ {
+ source = malloc(total_len + 1);
+ if(source == NULL)
+ {
+ DGLES2_ERROR(GL_OUT_OF_MEMORY);
+ }
+ source[0] = 0;
+ }
+ else
+ {
+ source = realloc(source, total_len + 1);
+ if(source == NULL)
+ {
+ DGLES2_ERROR(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ strncat(source, string[i], len);
+ }
+ }
+ }
+ else
+ {
+ source = (char*)string[0];
+ if(length == NULL || length[0] < 0)
+ {
+ total_len = strlen(source);
+ }
+ else
+ {
+ total_len = length[0];
+ }
+ }
+
+ {
+ // FIXME: This will fail with real constant data!
+ int patched_len;
+ const GLchar* patched = do_eglShaderPatch(source, total_len, &patched_len);
+ if(patched == NULL)
+ {
+ DGLES2_ERROR(GL_OUT_OF_MEMORY);
+ }
+ ctx->hgl.ShaderSource(shader, 1, &patched, &patched_len);
+ free((void*)patched);
+ }
+
+ if(DGLContext_getHostError(ctx) == GL_NO_ERROR)
+ {
+ if(!DGLContext_setShaderSource(ctx, shader, source, total_len))
+ {
+ DGLES2_ERROR(GL_OUT_OF_MEMORY);
+ }
+ }
+
+ if(count > 1)
+ {
+ free(source);
+ }
+ }
+ else
+ {
+ ctx->hgl.ShaderSource(shader, count, string, length);
+ }
+
+ DGLES2_LEAVE();
+}