hostsupport/hostopengles20/src/GLES2/program.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 
       
    33 const char* const DGLES2_INFO_LOG_INVALID_SHADERS = \
       
    34 	"A program must have exactly one vertex shader and one fragment shader.";
       
    35 
       
    36 DGLProgram* DGLProgram_create(GLuint name)
       
    37 {
       
    38 	DGLProgram* program = malloc(sizeof(DGLProgram));
       
    39 	if(program == NULL)
       
    40 	{
       
    41 		return NULL;
       
    42 	}
       
    43 
       
    44 	program->obj.name = name;
       
    45 	program->obj.next = NULL;
       
    46 
       
    47 	// Defer everything to the host GL by default.
       
    48 	program->link_status = GL_TRUE;
       
    49 	program->validate_status = GL_TRUE;
       
    50 
       
    51 	return program;
       
    52 }
       
    53 
       
    54 void DGLProgram_destroy(DGLProgram *program)
       
    55 {
       
    56 	DGLES2_ASSERT(program != NULL);
       
    57 	free(program);
       
    58 }
       
    59 
       
    60 GL_APICALL_BUILD void GL_APIENTRY glAttachShader (GLuint program, GLuint shader)
       
    61 {
       
    62 	DGLES2_ENTER();
       
    63 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
    64 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
    65 	DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
       
    66 	DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
       
    67     ctx->hgl.AttachShader(program, shader);
       
    68 	DGLES2_LEAVE();
       
    69 }
       
    70 
       
    71 GL_APICALL_BUILD void GL_APIENTRY glBindAttribLocation(GLuint program, GLuint index, const char* name)
       
    72 {
       
    73 	DGLES2_ENTER();
       
    74 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
    75 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
    76 	DGLES2_ERROR_IF(index >= ctx->max_vertex_attribs, GL_INVALID_VALUE);
       
    77 	DGLES2_ERROR_IF(strncmp(name, "gl_", 3) == 0, GL_INVALID_OPERATION);
       
    78     ctx->hgl.BindAttribLocation(program, index, name);
       
    79 	DGLES2_LEAVE();
       
    80 }
       
    81 
       
    82 GL_APICALL_BUILD GLuint GL_APIENTRY glCreateProgram(void)
       
    83 {
       
    84 	DGLES2_ENTER_RET(0);
       
    85 	{
       
    86 		GLuint name;
       
    87 		DGLContext_getHostError(ctx);
       
    88 		name = ctx->hgl.CreateProgram();
       
    89 		if(DGLContext_getHostError(ctx) == GL_NO_ERROR && name != 0)
       
    90 		{
       
    91 			DGLContext_createProgram(ctx, name);
       
    92 		}
       
    93 
       
    94 		DGLES2_LEAVE_RET(name);
       
    95 	}
       
    96 }
       
    97 
       
    98 GL_APICALL_BUILD void GL_APIENTRY glDeleteProgram(GLuint program)
       
    99 {
       
   100 	DGLES2_ENTER();
       
   101 	if(program != 0)
       
   102 	{
       
   103 		DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   104 		DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   105 		ctx->hgl.DeleteProgram(program);
       
   106 		if(DGLContext_getHostError(ctx) == GL_NO_ERROR)
       
   107 		{
       
   108 			DGLContext_destroyProgram(ctx, program);
       
   109 		}
       
   110 	}
       
   111 	DGLES2_LEAVE();
       
   112 }
       
   113 
       
   114 GL_APICALL_BUILD void GL_APIENTRY glDetachShader(GLuint program, GLuint shader)
       
   115 {
       
   116 	DGLES2_ENTER();
       
   117 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   118 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   119 	DGLES2_ERROR_IF(ctx->hgl.IsProgram(shader), GL_INVALID_OPERATION);
       
   120 	DGLES2_ERROR_IF(!ctx->hgl.IsShader(shader), GL_INVALID_VALUE);
       
   121 	ctx->hgl.DetachShader(program, shader);
       
   122 	DGLES2_LEAVE();
       
   123 }
       
   124 
       
   125 GL_APICALL_BUILD void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
       
   126 {
       
   127 	DGLES2_ENTER();
       
   128 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   129 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   130 	ctx->hgl.GetActiveAttrib(program, index, bufsize, length, size, type, name);
       
   131 	DGLES2_LEAVE();
       
   132 }
       
   133 
       
   134 GL_APICALL_BUILD void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name)
       
   135 {
       
   136 	DGLES2_ENTER();
       
   137 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   138 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   139 	ctx->hgl.GetActiveUniform(program, index, bufsize, length, size, type, name);
       
   140 	DGLES2_LEAVE();
       
   141 }
       
   142 
       
   143 GL_APICALL_BUILD void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
       
   144 {
       
   145 	DGLES2_ENTER();
       
   146 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   147 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   148 	ctx->hgl.GetAttachedShaders(program, maxcount, count, shaders);
       
   149 	DGLES2_LEAVE();
       
   150 }
       
   151 
       
   152 GL_APICALL_BUILD int GL_APIENTRY glGetAttribLocation (GLuint program, const char* name)
       
   153 {
       
   154 	DGLES2_ENTER_RET(-1);
       
   155 	DGLES2_ERROR_IF_RET(ctx->hgl.IsShader(program), GL_INVALID_OPERATION, -1);
       
   156 	DGLES2_ERROR_IF_RET(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE, -1);
       
   157 	DGLES2_LEAVE_RET(ctx->hgl.GetAttribLocation(program, name););
       
   158 }
       
   159 
       
   160 GL_APICALL_BUILD void GL_APIENTRY glGetProgramiv(GLuint program, GLenum pname, GLint* params)
       
   161 {
       
   162 	DGLES2_ENTER();
       
   163 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   164 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   165 	switch(pname)
       
   166 	{
       
   167 		case GL_LINK_STATUS:
       
   168 			{
       
   169 				const DGLProgram* program_obj = DGLContext_findProgram(ctx, program);
       
   170 				DGLES2_ASSERT(program_obj != NULL);
       
   171 				if(program_obj->link_status)
       
   172 				{
       
   173 					// Our requirement for linking was fulfilled, ask the host.
       
   174 					ctx->hgl.GetProgramiv(program, GL_LINK_STATUS, params);
       
   175 				}
       
   176 				else
       
   177 				{
       
   178 					*params = GL_FALSE;
       
   179 				}
       
   180 			}
       
   181 			break;
       
   182 
       
   183 		case GL_VALIDATE_STATUS:
       
   184 			{
       
   185 				const DGLProgram* program_obj = DGLContext_findProgram(ctx, program);
       
   186 				DGLES2_ASSERT(program_obj != NULL);
       
   187 				if(program_obj->validate_status)
       
   188 				{
       
   189 					// Our requirement for validation was fulfilled, ask the host.
       
   190 					ctx->hgl.GetProgramiv(program, GL_VALIDATE_STATUS, params);
       
   191 				}
       
   192 				else
       
   193 				{
       
   194 					*params = GL_FALSE;
       
   195 				}
       
   196 			}
       
   197 			break;
       
   198 
       
   199 		case GL_INFO_LOG_LENGTH:
       
   200 			{
       
   201 				const DGLProgram* program_obj = DGLContext_findProgram(ctx, program);
       
   202 				DGLES2_ASSERT(program_obj != NULL);
       
   203 				if(!program_obj->link_status || !program_obj->validate_status)
       
   204 				{
       
   205 					// Use our own info log.
       
   206 					*params = strlen(DGLES2_INFO_LOG_INVALID_SHADERS);
       
   207 				}
       
   208 				else
       
   209 				{
       
   210 					ctx->hgl.GetProgramiv(program, GL_INFO_LOG_LENGTH, params);
       
   211 				}
       
   212 			}
       
   213 			break;
       
   214 
       
   215 		default:
       
   216 			ctx->hgl.GetProgramiv(program, pname, params);
       
   217 			break;
       
   218 	}
       
   219 	DGLES2_LEAVE();
       
   220 }
       
   221 
       
   222 GL_APICALL_BUILD void GL_APIENTRY glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog)
       
   223 {
       
   224 	DGLES2_ENTER();
       
   225 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   226 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   227 	{
       
   228 		const DGLProgram* program_obj = DGLContext_findProgram(ctx, program);
       
   229 		DGLES2_ASSERT(program_obj != NULL);
       
   230 		if(!program_obj->link_status || !program_obj->validate_status)
       
   231 		{
       
   232 			// Use our own info log.
       
   233 
       
   234 			if(length != NULL)
       
   235 			{
       
   236 				*length = 0;
       
   237 			}
       
   238 
       
   239 			if(infolog != NULL)
       
   240 			{
       
   241 				int log_length = strlen(DGLES2_INFO_LOG_INVALID_SHADERS);
       
   242 				int num_chars = log_length < bufsize - 1 ? log_length : bufsize - 1;
       
   243 
       
   244 				strncpy(infolog, DGLES2_INFO_LOG_INVALID_SHADERS, num_chars);
       
   245 				infolog[num_chars] = 0;
       
   246 
       
   247 				if(length != NULL)
       
   248 				{
       
   249 					*length = num_chars;
       
   250 				}
       
   251 			}
       
   252 		}
       
   253 		else
       
   254 		{
       
   255 			ctx->hgl.GetProgramInfoLog(program, bufsize, length, infolog);
       
   256 		}
       
   257 	}
       
   258 	DGLES2_LEAVE();
       
   259 }
       
   260 
       
   261 GL_APICALL_BUILD void GL_APIENTRY glGetUniformfv(GLuint program, GLint location, GLfloat* params)
       
   262 {
       
   263 	DGLES2_ENTER();
       
   264 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   265 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   266 	ctx->hgl.GetUniformfv(program, location, params);
       
   267 	DGLES2_LEAVE();
       
   268 }
       
   269 
       
   270 GL_APICALL_BUILD void GL_APIENTRY glGetUniformiv(GLuint program, GLint location, GLint* params)
       
   271 {
       
   272 	DGLES2_ENTER();
       
   273 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   274 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   275 	ctx->hgl.GetUniformiv(program, location, params);
       
   276 	DGLES2_LEAVE();
       
   277 }
       
   278 
       
   279 GL_APICALL_BUILD int GL_APIENTRY glGetUniformLocation(GLuint program, const char* name)
       
   280 {
       
   281 	DGLES2_ENTER_RET(-1);
       
   282 	DGLES2_ERROR_IF_RET(ctx->hgl.IsShader(program), GL_INVALID_OPERATION, -1);
       
   283 	DGLES2_ERROR_IF_RET(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE, -1);
       
   284 	DGLES2_LEAVE_RET(ctx->hgl.GetUniformLocation(program, name));
       
   285 }
       
   286 
       
   287 GL_APICALL_BUILD GLboolean GL_APIENTRY glIsProgram(GLuint program)
       
   288 {
       
   289 	DGLES2_ENTER_RET(GL_FALSE);
       
   290 	DGLES2_LEAVE_RET(ctx->hgl.IsProgram(program));
       
   291 }
       
   292 
       
   293 GL_APICALL_BUILD void GL_APIENTRY glLinkProgram(GLuint program)
       
   294 {
       
   295 	DGLES2_ENTER();
       
   296 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   297 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   298 	{
       
   299 		GLint num_shaders;
       
   300 
       
   301 		DGLProgram* program_obj = DGLContext_findProgram(ctx, program);
       
   302 		DGLES2_ASSERT(program_obj != NULL);
       
   303 
       
   304 		ctx->hgl.GetProgramiv(program, GL_ATTACHED_SHADERS, &num_shaders);
       
   305 
       
   306 		// Linked programs must have both a vertex and a fragment shader in GL ES.
       
   307 		// Multiple shaders of the same type may not be attached to a single program object.
       
   308 		if(num_shaders != 2)
       
   309 		{
       
   310 			program_obj->link_status = GL_FALSE;
       
   311 		}
       
   312 		else
       
   313 		{
       
   314 			// Check that the shaders are of different type.
       
   315 
       
   316 			GLuint shaders[2];
       
   317 			GLint types[2];
       
   318 			ctx->hgl.GetAttachedShaders(program, 2, NULL, shaders);
       
   319 			ctx->hgl.GetShaderiv(shaders[0], GL_SHADER_TYPE, &types[0]);
       
   320 			ctx->hgl.GetShaderiv(shaders[1], GL_SHADER_TYPE, &types[1]);
       
   321 			
       
   322 			if(types[0] == types[1])
       
   323 			{
       
   324 				program_obj->link_status = GL_FALSE;
       
   325 			}
       
   326 			else
       
   327 			{
       
   328 				program_obj->link_status = GL_TRUE;
       
   329 				ctx->hgl.LinkProgram(program);
       
   330 			}
       
   331 		}
       
   332 	}
       
   333 	DGLES2_LEAVE();
       
   334 }
       
   335 
       
   336 GL_APICALL_BUILD void GL_APIENTRY glUniform1f (GLint location, GLfloat x)
       
   337 {
       
   338 	DGLES2_ENTER();
       
   339 	ctx->hgl.Uniform1f(location, x);
       
   340 	DGLES2_LEAVE();
       
   341 }
       
   342 
       
   343 GL_APICALL_BUILD void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v)
       
   344 {
       
   345 	DGLES2_ENTER();
       
   346 	ctx->hgl.Uniform1fv(location, count, v);
       
   347 	DGLES2_LEAVE();
       
   348 }
       
   349 
       
   350 GL_APICALL_BUILD void GL_APIENTRY glUniform1i (GLint location, GLint x)
       
   351 {
       
   352 	DGLES2_ENTER();
       
   353 	ctx->hgl.Uniform1i(location, x);
       
   354 	DGLES2_LEAVE();
       
   355 }
       
   356 
       
   357 GL_APICALL_BUILD void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v)
       
   358 {
       
   359 	DGLES2_ENTER();
       
   360 	ctx->hgl.Uniform1iv(location, count, v);
       
   361 	DGLES2_LEAVE();
       
   362 }
       
   363 
       
   364 GL_APICALL_BUILD void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y)
       
   365 {
       
   366 	DGLES2_ENTER();
       
   367 	ctx->hgl.Uniform2f(location, x, y);
       
   368 	DGLES2_LEAVE();
       
   369 }
       
   370 
       
   371 GL_APICALL_BUILD void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v)
       
   372 {
       
   373 	DGLES2_ENTER();
       
   374 	ctx->hgl.Uniform2fv(location, count, v);
       
   375 	DGLES2_LEAVE();
       
   376 }
       
   377 
       
   378 GL_APICALL_BUILD void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y)
       
   379 {
       
   380 	DGLES2_ENTER();
       
   381 	ctx->hgl.Uniform2i(location, x, y);
       
   382 	DGLES2_LEAVE();
       
   383 }
       
   384 
       
   385 GL_APICALL_BUILD void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v)
       
   386 {
       
   387 	DGLES2_ENTER();
       
   388 	ctx->hgl.Uniform2iv(location, count, v);
       
   389 	DGLES2_LEAVE();
       
   390 }
       
   391 
       
   392 GL_APICALL_BUILD void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z)
       
   393 {
       
   394 	DGLES2_ENTER();
       
   395 	ctx->hgl.Uniform3f(location, x, y, z);
       
   396 	DGLES2_LEAVE();
       
   397 }
       
   398 
       
   399 GL_APICALL_BUILD void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v)
       
   400 {
       
   401 	DGLES2_ENTER();
       
   402 	ctx->hgl.Uniform3fv(location, count, v);
       
   403 	DGLES2_LEAVE();
       
   404 }
       
   405 
       
   406 GL_APICALL_BUILD void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z)
       
   407 {
       
   408 	DGLES2_ENTER();
       
   409 	ctx->hgl.Uniform3i(location, x, y, z);
       
   410 	DGLES2_LEAVE();
       
   411 }
       
   412 
       
   413 GL_APICALL_BUILD void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v)
       
   414 {
       
   415 	DGLES2_ENTER();
       
   416 	ctx->hgl.Uniform3iv(location, count, v);
       
   417 	DGLES2_LEAVE();
       
   418 }
       
   419 
       
   420 GL_APICALL_BUILD void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
       
   421 {
       
   422 	DGLES2_ENTER();
       
   423 	ctx->hgl.Uniform4f(location, x, y, z, w);
       
   424 	DGLES2_LEAVE();
       
   425 }
       
   426 
       
   427 GL_APICALL_BUILD void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v)
       
   428 {
       
   429 	DGLES2_ENTER();
       
   430 	ctx->hgl.Uniform4fv(location, count, v);
       
   431 	DGLES2_LEAVE();
       
   432 }
       
   433 
       
   434 GL_APICALL_BUILD void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w)
       
   435 {
       
   436 	DGLES2_ENTER();
       
   437 	ctx->hgl.Uniform4i(location, x, y, z, w);
       
   438 	DGLES2_LEAVE();
       
   439 }
       
   440 
       
   441 GL_APICALL_BUILD void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v)
       
   442 {
       
   443 	DGLES2_ENTER();
       
   444 	ctx->hgl.Uniform4iv(location, count, v);
       
   445 	DGLES2_LEAVE();
       
   446 }
       
   447 
       
   448 GL_APICALL_BUILD void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
       
   449 {
       
   450 	DGLES2_ENTER();
       
   451 	ctx->hgl.UniformMatrix2fv(location, count, transpose, value);
       
   452 	DGLES2_LEAVE();
       
   453 }
       
   454 
       
   455 GL_APICALL_BUILD void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
       
   456 {
       
   457 	DGLES2_ENTER();
       
   458 	ctx->hgl.UniformMatrix3fv(location, count, transpose, value);
       
   459 	DGLES2_LEAVE();
       
   460 }
       
   461 
       
   462 GL_APICALL_BUILD void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
       
   463 {
       
   464 	DGLES2_ENTER();
       
   465 	ctx->hgl.UniformMatrix4fv(location, count, transpose, value);
       
   466 	DGLES2_LEAVE();
       
   467 }
       
   468 
       
   469 GL_APICALL_BUILD void GL_APIENTRY glUseProgram (GLuint program)
       
   470 {
       
   471 	DGLES2_ENTER();
       
   472 	ctx->hgl.UseProgram(program);
       
   473 	DGLES2_LEAVE();
       
   474 }
       
   475 
       
   476 GL_APICALL_BUILD void GL_APIENTRY glValidateProgram (GLuint program)
       
   477 {
       
   478 	DGLES2_ENTER();
       
   479 	DGLES2_ERROR_IF(ctx->hgl.IsShader(program), GL_INVALID_OPERATION);
       
   480 	DGLES2_ERROR_IF(!ctx->hgl.IsProgram(program), GL_INVALID_VALUE);
       
   481 	{
       
   482 		GLint num_shaders;
       
   483 
       
   484 		DGLProgram* program_obj = DGLContext_findProgram(ctx, program);
       
   485 		DGLES2_ASSERT(program_obj != NULL);
       
   486 
       
   487 		// The program must no be empty.
       
   488 		ctx->hgl.GetProgramiv(program, GL_ATTACHED_SHADERS, &num_shaders);
       
   489 		if(num_shaders == 0)
       
   490 		{
       
   491 			program_obj->validate_status = GL_FALSE;
       
   492 		}
       
   493 		else
       
   494 		{
       
   495 			program_obj->validate_status = GL_TRUE;
       
   496 			ctx->hgl.ValidateProgram(program);
       
   497 		}
       
   498 	}
       
   499 	DGLES2_LEAVE();
       
   500 }
       
   501