hostsupport/hostopengles20/src/GLES2/shader.c
branchbug235_bringup_0
changeset 53 c2ef9095503a
parent 20 d2d6724aef32
equal deleted inserted replaced
52:39e5f73667ba 53:c2ef9095503a
       
     1 /* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2  *
       
     3  * Permission is hereby granted, free of charge, to any person obtaining a
       
     4  * copy of this software and associated documentation files (the "Software"),
       
     5  * to deal in the Software without restriction, including without limitation
       
     6  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
       
     7  * and/or sell copies of the Software, and to permit persons to whom the
       
     8  * Software is furnished to do so, subject to the following conditions:
       
     9  *
       
    10  * The above copyright notice and this permission notice shall be included
       
    11  * in all copies or substantial portions of the Software.
       
    12  *
       
    13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
       
    14  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
       
    16  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
       
    17  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
       
    18  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
       
    19  *
       
    20  * Initial Contributors:
       
    21  * Nokia Corporation - initial contribution.
       
    22  *
       
    23  * Contributors:
       
    24  *
       
    25  * Description:
       
    26  *
       
    27  */
       
    28 
       
    29 #include "common.h"
       
    30 #include "hgl.h"
       
    31 #include "context.h"
       
    32 #include <string.h>
       
    33 
       
    34 DGLShader* DGLShader_create(GLuint name)
       
    35 {
       
    36 	DGLShader* shader = malloc(sizeof(DGLShader));
       
    37 	if(shader == NULL)
       
    38 	{
       
    39 		return NULL;
       
    40 	}
       
    41 
       
    42 	shader->obj.name = name;
       
    43 	shader->obj.next = NULL;
       
    44 
       
    45 	shader->source = NULL;
       
    46 	shader->length = 0;
       
    47 
       
    48 	return shader;
       
    49 }
       
    50 
       
    51 void DGLShader_destroy(DGLShader *shader)
       
    52 {
       
    53 	DGLES2_ASSERT(shader != NULL);
       
    54 	if(shader->source != NULL)
       
    55 	{
       
    56 		free(shader->source);
       
    57 		shader->source = NULL;
       
    58 	}
       
    59 	free(shader);
       
    60 }
       
    61 
       
    62 GL_APICALL_BUILD void GL_APIENTRY glCompileShader(GLuint shader)
       
    63 {
       
    64 	DGLES2_ENTER();
       
    65 	ctx->hgl.CompileShader(shader);
       
    66 	DGLES2_LEAVE();
       
    67 }
       
    68 
       
    69 GL_APICALL_BUILD GLuint GL_APIENTRY glCreateShader(GLenum type)
       
    70 {
       
    71 	DGLES2_ENTER_RET(0);
       
    72 	DGLES2_ERROR_IF_RET(type != GL_VERTEX_SHADER && type != GL_FRAGMENT_SHADER, GL_INVALID_ENUM, 0);
       
    73 	{
       
    74 		GLuint name = ctx->hgl.CreateShader(type);
       
    75 		if(DGLContext_getHostError(ctx) == GL_NO_ERROR && name != 0)
       
    76 		{
       
    77 			DGLContext_createShader(ctx, name);
       
    78 		}
       
    79 
       
    80 		DGLES2_LEAVE_RET(name);
       
    81 	}
       
    82 }
       
    83 
       
    84 GL_APICALL_BUILD void GL_APIENTRY glDeleteShader(GLuint shader)
       
    85 {
       
    86 	DGLES2_ENTER();
       
    87 	if(shader != 0)
       
    88 	{
       
    89 		DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
       
    90 		DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
       
    91 		ctx->hgl.DeleteShader(shader);
       
    92 		if(DGLContext_getHostError(ctx) == GL_NO_ERROR)
       
    93 		{
       
    94 			DGLContext_destroyShader(ctx, shader);
       
    95 		}
       
    96 	}
       
    97 	DGLES2_LEAVE();
       
    98 }
       
    99 
       
   100 GL_APICALL_BUILD void GL_APIENTRY glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
       
   101 {
       
   102 	DGLES2_ENTER();
       
   103 	DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
       
   104 	DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
       
   105 	if(pname == GL_SHADER_SOURCE_LENGTH)
       
   106 	{
       
   107 		DGLShader* shader_obj = DGLContext_findShader(ctx, shader);
       
   108 		DGLES2_ASSERT(shader_obj != NULL);
       
   109 		*params = shader_obj->length + 1;
       
   110 	}
       
   111 	else
       
   112 	{
       
   113 		ctx->hgl.GetShaderiv(shader, pname, params);
       
   114 	}
       
   115 	DGLES2_LEAVE();
       
   116 }
       
   117 
       
   118 GL_APICALL_BUILD void GL_APIENTRY glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog)
       
   119 {
       
   120 	DGLES2_ENTER();
       
   121 	DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
       
   122 	DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
       
   123 	ctx->hgl.GetShaderInfoLog(shader, bufsize, length, infolog);
       
   124 	DGLES2_LEAVE();
       
   125 }
       
   126 
       
   127 GL_APICALL_BUILD void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
       
   128 {
       
   129 	DGLES2_ENTER();
       
   130 	DGLES2_ERROR_IF(shadertype != GL_VERTEX_SHADER && shadertype != GL_FRAGMENT_SHADER, GL_INVALID_ENUM);
       
   131 	// Values from the GL ES and GLSL specifications.
       
   132 	switch(precisiontype)
       
   133 	{
       
   134 		case GL_LOW_FLOAT:
       
   135 		case GL_MEDIUM_FLOAT:
       
   136 		case GL_HIGH_FLOAT:
       
   137 			range[0] = 127;
       
   138 			range[1] = 127;
       
   139 			*precision = 23;
       
   140 			break;
       
   141 
       
   142 		case GL_LOW_INT:
       
   143 		case GL_MEDIUM_INT:
       
   144 		case GL_HIGH_INT:
       
   145 			range[0] = 15;
       
   146 			range[1] = 14;
       
   147 			*precision = 0;
       
   148 			break;
       
   149 	}
       
   150 	DGLES2_LEAVE();
       
   151 }
       
   152 
       
   153 GL_APICALL_BUILD void GL_APIENTRY glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source)
       
   154 {
       
   155 	DGLES2_ENTER();
       
   156 	DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
       
   157 	DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
       
   158 	DGLES2_ERROR_IF(bufsize < 0, GL_INVALID_VALUE);
       
   159 	{
       
   160 		DGLShader* shader_obj = DGLContext_findShader(ctx, shader);
       
   161 		DGLES2_ASSERT(shader_obj != NULL);
       
   162 		
       
   163 		if(length != NULL)
       
   164 		{
       
   165 			*length = 0;
       
   166 		}
       
   167 
       
   168 		if(source != NULL)
       
   169 		{
       
   170 			GLsizei num_chars = shader_obj->length < bufsize - 1 ? shader_obj->length : bufsize - 1;
       
   171 			if(num_chars > 0)
       
   172 			{
       
   173 				strncpy(source, shader_obj->source, num_chars);
       
   174 				source[num_chars] = 0;
       
   175 				if(length != NULL)
       
   176 				{
       
   177 					*length = num_chars;
       
   178 				}
       
   179 			}
       
   180 		}
       
   181 	}
       
   182 	DGLES2_LEAVE();
       
   183 }
       
   184 
       
   185 GL_APICALL_BUILD GLboolean GL_APIENTRY glIsShader(GLuint shader)
       
   186 {
       
   187 	DGLES2_ENTER_RET(GL_FALSE);
       
   188 	DGLES2_LEAVE_RET(ctx->hgl.IsShader(shader));
       
   189 }
       
   190 
       
   191 GL_APICALL_BUILD void GL_APIENTRY glReleaseShaderCompiler(void)
       
   192 {
       
   193 	DGLES2_ENTER();
       
   194 	// No-op.
       
   195 	DGLES2_LEAVE();
       
   196 }
       
   197 
       
   198 GL_APICALL_BUILD void GL_APIENTRY glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length)
       
   199 {
       
   200 	DGLES2_ENTER();
       
   201 	// No supported formats.
       
   202 	DGLES2_ERROR(GL_INVALID_ENUM);
       
   203 	DGLES2_LEAVE();
       
   204 }
       
   205 
       
   206 static const char *opengl_strtok(const char *s, int *n)
       
   207 {
       
   208     static char *buffer = 0;
       
   209     static int buffersize = -1;
       
   210     static const char *delim = " \t\n\r()[]{},;:";
       
   211     static const char *prev = 0;
       
   212     int cComment = 0;
       
   213     int cppComment = 0;
       
   214 
       
   215     if (!s) {
       
   216         if (!*prev || !*n) {
       
   217             if (buffer) {
       
   218                 free(buffer);
       
   219                 buffer = 0;
       
   220                 buffersize = -1;
       
   221             }
       
   222             prev = 0;
       
   223             return 0;
       
   224         }
       
   225         s = prev;
       
   226     } else {
       
   227         if (buffer) {
       
   228             free(buffer);
       
   229             buffer = 0;
       
   230             buffersize = -1;
       
   231         }
       
   232 		prev = s;
       
   233     }
       
   234 
       
   235     if( *n && *s == '/') {
       
   236         if(*(s+1) == '*') cComment = 1;
       
   237         if(*(s+1) == '/') cppComment = 1;        
       
   238     }
       
   239     if( cComment == 1 || cppComment == 1) {
       
   240         for(; *n && (cComment == 1 || cppComment == 1); s++, (*n)--) {
       
   241             if(cComment == 1 && *s == '*' && *(s+1) == '/' ) {
       
   242                 cComment = 0;
       
   243             }
       
   244             if(cppComment == 1 && *s == '\n') {
       
   245                 cppComment = 0;
       
   246             }
       
   247         }
       
   248     } else {
       
   249         for (; *n && strchr(delim, *s); s++, (*n)--);
       
   250     }
       
   251 
       
   252 	if(s - prev > 0) {
       
   253 		if (buffersize < s - prev) {
       
   254 			buffersize = s - prev;
       
   255 			if (buffer) {
       
   256 				free(buffer);
       
   257 			}
       
   258 			buffer = malloc(buffersize + 1);
       
   259 		}
       
   260 		memcpy(buffer, prev, s - prev);
       
   261 		buffer[s - prev] = 0;
       
   262 		prev = s;
       
   263 	} else {
       
   264 		const char *e = s;
       
   265 		for (; *n && *e && !strchr(delim, *e); e++, (*n)--);
       
   266 		prev = e;
       
   267 		if (buffersize < e - s) {
       
   268 			buffersize = e - s;
       
   269 			if (buffer) {
       
   270 				free(buffer);
       
   271 			}
       
   272 			buffer = malloc(buffersize + 1);
       
   273 		}
       
   274 		memcpy(buffer, s, e - s);
       
   275 		buffer[e - s] = 0;
       
   276 	}
       
   277     return buffer;
       
   278 }
       
   279 
       
   280 static char* do_eglShaderPatch(char *source, int len, int *patched_len)
       
   281 {
       
   282     /* DISCLAIMER: this is not a full-blown shader parser but a simple
       
   283      * implementation which tries to remove the OpenGL ES shader
       
   284      * "precision" statements and precision qualifiers "lowp", "mediump"
       
   285      * and "highp" from the specified shader source, replace built-in
       
   286 	 * constants that were renamed in GLSL ES ("gl_MaxVertexUniformVectors",
       
   287 	 * "gl_MaxFragmentUniformVectors" and "gl_MaxVaryingVectors")
       
   288 	 * and insert a "#version 120" directive in the beginning of the source
       
   289 	 * or replace an existing "#version 100" directive. */
       
   290 	DGLES2_ASSERT(source != NULL);
       
   291 	DGLES2_ASSERT(len >= 0);
       
   292 	{
       
   293 #ifndef DGLES2_ALLOW_GLSL_110
       
   294 		GLboolean version_found = GL_FALSE;
       
   295 #endif
       
   296 		int buffer_size;
       
   297 		char *patched;
       
   298 		const char *p;
       
   299 		
       
   300 		*patched_len = 0;
       
   301 		buffer_size = len;
       
   302 		patched = malloc(buffer_size + 1);
       
   303 		if(patched == NULL)	{
       
   304 			return NULL;
       
   305 		}
       
   306 
       
   307 		p = opengl_strtok(source, &len);
       
   308 		for (; p; p = opengl_strtok(0, &len)) {
       
   309 			if (!strcmp(p, "lowp") || !strcmp(p, "mediump") || !strcmp(p, "highp")) {
       
   310 				continue;
       
   311 			} else if (!strcmp(p, "precision")) {
       
   312 				do {
       
   313 					p = opengl_strtok(0, &len);
       
   314 				} while(p && !strchr(p, ';'));
       
   315 			} else {
       
   316 				int tok_len;
       
   317 				if (!strcmp(p, "gl_MaxVertexUniformVectors")) {
       
   318 					p = "(gl_MaxVertexUniformComponents / 4)";
       
   319 				} else if (!strcmp(p, "gl_MaxFragmentUniformVectors")) {
       
   320 					p = "(gl_MaxFragmentUniformComponents / 4)";
       
   321 				} else if (!strcmp(p, "gl_MaxVaryingVectors")) {
       
   322 					p = "(gl_MaxVaryingFloats / 4)";
       
   323 				}
       
   324 #ifndef DGLES2_ALLOW_GLSL_110
       
   325 				else if (!strcmp(p, "#version")) {
       
   326 					p = opengl_strtok(0, &len);
       
   327 					if (!strcmp(p, "100")) {
       
   328 						p = "#version 120";
       
   329 						version_found = GL_TRUE;
       
   330 					}
       
   331 				} else if (!strcmp(p, "#")) {
       
   332 					p = opengl_strtok(0, &len);
       
   333 					if (!strcmp(p, "version")) {
       
   334 						p = opengl_strtok(0, &len);
       
   335 						if (!strcmp(p, "100")) {
       
   336 							p = "#version 120";
       
   337 							version_found = GL_TRUE;
       
   338 						}
       
   339 					}
       
   340 				} 
       
   341 #endif // !DGLES2_ALLOW_GLSL_110
       
   342 				tok_len = strlen(p);
       
   343 				if(*patched_len + tok_len > buffer_size) {
       
   344 					buffer_size *= 2;
       
   345 					patched = realloc(patched, buffer_size + 1);
       
   346 					if(patched == NULL) {
       
   347 						return NULL;
       
   348 					}
       
   349 				}
       
   350 				memcpy(patched + *patched_len, p, tok_len);
       
   351 				*patched_len += tok_len;
       
   352 			}
       
   353 		}
       
   354 		patched[*patched_len] = 0;
       
   355 #ifndef DGLES2_ALLOW_GLSL_110
       
   356 		/* add version directive is one was not found */
       
   357 		if (!version_found) {
       
   358 			char* new_patched;
       
   359 			*patched_len += strlen("#version 120\n");
       
   360 			new_patched = malloc(*patched_len + 1);
       
   361 			if (new_patched == NULL) {
       
   362 				return NULL;
       
   363 			}
       
   364 			strcpy(new_patched, "#version 120\n");
       
   365 			strcat(new_patched, patched);
       
   366 			free(patched);
       
   367 			patched = new_patched;
       
   368 		}
       
   369 #endif // !DGLES2_ALLOW_GLSL_110
       
   370 		{
       
   371 			/* check that we don't leave dummy preprocessor lines */
       
   372 			char *sp;
       
   373 			for (sp = patched; *sp;) {
       
   374 				for (; *sp == ' ' || *sp == '\t'; sp++);
       
   375 				if (!strncmp(sp, "#define", 7)) {
       
   376 					for (p = sp + 7; *p == ' ' || *p == '\t'; p++);
       
   377 					if (*p == '\n' || *p == '\r' || *p == '/') {
       
   378 						memset(sp, 0x20, 7);
       
   379 					}
       
   380 				}
       
   381 				for (; *sp && *sp != '\n' && *sp != '\r'; sp++);
       
   382 				for (; *sp == '\n' || *sp == '\r'; sp++);
       
   383 			}
       
   384 		}
       
   385 
       
   386 		return patched;
       
   387 	}
       
   388 }
       
   389 
       
   390 GL_APICALL_BUILD void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length)
       
   391 {
       
   392 	DGLES2_ENTER();
       
   393 	DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
       
   394 	DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
       
   395 	DGLES2_ERROR_IF(count < 0, GL_INVALID_VALUE);
       
   396 /*
       
   397 #if(CONFIG_DEBUG == 1)
       
   398 	Dprintf("Editing shader:\n--ORIGINAL-SHADER--\n");
       
   399 	for(unsigned i = 0; i < count; ++i)
       
   400 	{
       
   401 		if(length)
       
   402 			Dprintf("%*s", length[i], string[i]);
       
   403 		else
       
   404 			Dprintf("%s", string[i]);
       
   405 	}
       
   406 	Dprintf("---END-ORIGINAL-SHADER---\n");
       
   407 #endif // !NDEBUG
       
   408 	char** string_dgl = malloc(sizeof(char*)*count);
       
   409 	GLint* length_dgl = malloc(sizeof(GLint)*count);
       
   410 
       
   411 	// Remove the non OpenGL 2.x compilant keywords.
       
   412 	for(unsigned i = 0; i < count; ++i)
       
   413 	{
       
   414 		static const char* removables[] =
       
   415 		{
       
   416 			"precision highp float;",
       
   417 			"precision mediump float;",
       
   418 			"precision lowp float;",
       
   419 			"highp",
       
   420 			"lowp",
       
   421 			"mediump",
       
   422 			"precision"
       
   423 		};
       
   424 
       
   425 		length_dgl[i] = length ? length[i] : strlen(string[i]);
       
   426 		string_dgl[i] = malloc(length_dgl[i] + 1);
       
   427 		memcpy(string_dgl[i], string[i], length_dgl[i]);
       
   428 		string_dgl[i][length_dgl[i]] = 0;
       
   429 
       
   430 		for(unsigned j = 0; j < sizeof(removables)/sizeof(removables[0]); ++j)
       
   431 		{
       
   432 			char const* p;
       
   433 			while((p = strstr(string_dgl[i], removables[j])))
       
   434 			{
       
   435 				memmove(p, p + strlen(removables[j]), strlen(p + strlen(removables[j])) + 1);
       
   436 			}
       
   437 		}
       
   438 	}
       
   439 #if(CONFIG_DEBUG == 1)
       
   440 	Dprintf("Loading shader:\n--DESKTOP-GL-SHADER--\n");
       
   441 	for(unsigned i = 0; i < count; ++i)
       
   442 	{
       
   443 		Dprintf("%*s", length_dgl[i], string_dgl[i]);
       
   444 	}
       
   445 	Dprintf("---END-DESKTOP-GL-SHADER---\n");
       
   446 #endif // !NDEBUG
       
   447     
       
   448 	ctx->hgl.ShaderSource(shader, count, string_dgl, length_dgl);
       
   449 
       
   450 	for(unsigned i = 0; i < count; ++i)
       
   451 		free(string_dgl[i]);
       
   452 	free(string_dgl);
       
   453 	free(length_dgl);
       
   454  */
       
   455 
       
   456 	if(count > 0 && string != NULL)
       
   457 	{
       
   458 		char* source = NULL;
       
   459 		int total_len = 0;
       
   460 
       
   461 		if(count > 1)
       
   462 		{
       
   463 			int i;
       
   464 
       
   465 			// Concatenate the passed strings into one source string.
       
   466 			for(i = 0; i < count; i++)
       
   467 			{
       
   468 				int len;
       
   469 
       
   470 				if(string[i] == NULL)
       
   471 				{
       
   472 					continue;
       
   473 				}
       
   474 
       
   475 				if(length == NULL || length[i] < 0)
       
   476 				{
       
   477 					len = strlen(string[i]);
       
   478 				}
       
   479 				else
       
   480 				{
       
   481 					len = length[i];
       
   482 				}
       
   483 
       
   484 				if(len > 0)
       
   485 				{
       
   486 					total_len += len;
       
   487 
       
   488 					if(source == NULL)
       
   489 					{
       
   490 						source = malloc(total_len + 1);
       
   491 						if(source == NULL)
       
   492 						{
       
   493 							DGLES2_ERROR(GL_OUT_OF_MEMORY);
       
   494 						}
       
   495 						source[0] = 0;
       
   496 					}
       
   497 					else
       
   498 					{
       
   499 						source = realloc(source, total_len + 1);
       
   500 						if(source == NULL)
       
   501 						{
       
   502 							DGLES2_ERROR(GL_OUT_OF_MEMORY);
       
   503 						}
       
   504 					}
       
   505 
       
   506 					strncat(source, string[i], len);
       
   507 				}
       
   508 			}
       
   509 		}
       
   510 		else
       
   511 		{
       
   512 			source = (char*)string[0];
       
   513 			if(length == NULL || length[0] < 0)
       
   514 			{
       
   515 				total_len = strlen(source);
       
   516 			}
       
   517 			else
       
   518 			{
       
   519 				total_len = length[0];
       
   520 			}
       
   521 		}
       
   522 
       
   523 		{
       
   524 			// FIXME: This will fail with real constant data!
       
   525 			int patched_len;
       
   526 			const GLchar* patched = do_eglShaderPatch(source, total_len, &patched_len);
       
   527 			if(patched == NULL)
       
   528 			{
       
   529 				DGLES2_ERROR(GL_OUT_OF_MEMORY);
       
   530 			}
       
   531 			ctx->hgl.ShaderSource(shader, 1, &patched, &patched_len);
       
   532 			free((void*)patched);
       
   533 		}
       
   534 
       
   535 		if(DGLContext_getHostError(ctx) == GL_NO_ERROR)
       
   536 		{
       
   537 			if(!DGLContext_setShaderSource(ctx, shader, source, total_len))
       
   538 			{
       
   539 				DGLES2_ERROR(GL_OUT_OF_MEMORY);
       
   540 			}
       
   541 		}
       
   542 
       
   543 		if(count > 1)
       
   544 		{
       
   545 			free(source);
       
   546 		}
       
   547 	}
       
   548 	else
       
   549 	{
       
   550 		ctx->hgl.ShaderSource(shader, count, string, length);
       
   551 	}
       
   552 
       
   553 	DGLES2_LEAVE();
       
   554 }