holdingarea/libGLESv2/src/GLES2/shader.c
branchbug235_bringup_0
changeset 20 d2d6724aef32
--- /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();
+}