Home | History | Annotate | Download | only in libGLESv2
      1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //    http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // libGLESv3.cpp: Implements the exported OpenGL ES 3.0 functions.
     16 
     17 #include "main.h"
     18 #include "Buffer.h"
     19 #include "Fence.h"
     20 #include "Framebuffer.h"
     21 #include "Program.h"
     22 #include "Query.h"
     23 #include "Sampler.h"
     24 #include "Texture.h"
     25 #include "mathutil.h"
     26 #include "TransformFeedback.h"
     27 #include "VertexArray.h"
     28 #include "common/debug.h"
     29 
     30 #include <GLES3/gl3.h>
     31 #include <GLES2/gl2ext.h>
     32 
     33 #include <limits.h>
     34 
     35 using namespace es2;
     36 
     37 static bool validImageSize(GLint level, GLsizei width, GLsizei height)
     38 {
     39 	if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || width < 0 || height < 0)
     40 	{
     41 		return false;
     42 	}
     43 
     44 	return true;
     45 }
     46 
     47 static bool ValidateQueryTarget(GLenum target)
     48 {
     49 	switch(target)
     50 	{
     51 	case GL_ANY_SAMPLES_PASSED:
     52 	case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
     53 	case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
     54 		break;
     55 	default:
     56 		return false;
     57 	}
     58 
     59 	return true;
     60 }
     61 
     62 bool ValidateTexParamParameters(GLenum pname, GLint param)
     63 {
     64 	switch(pname)
     65 	{
     66 	case GL_TEXTURE_WRAP_S:
     67 	case GL_TEXTURE_WRAP_T:
     68 	case GL_TEXTURE_WRAP_R:
     69 		switch(param)
     70 		{
     71 		case GL_REPEAT:
     72 		case GL_CLAMP_TO_EDGE:
     73 		case GL_MIRRORED_REPEAT:
     74 			return true;
     75 		default:
     76 			return error(GL_INVALID_ENUM, false);
     77 		}
     78 
     79 	case GL_TEXTURE_MIN_FILTER:
     80 		switch(param)
     81 		{
     82 		case GL_NEAREST:
     83 		case GL_LINEAR:
     84 		case GL_NEAREST_MIPMAP_NEAREST:
     85 		case GL_LINEAR_MIPMAP_NEAREST:
     86 		case GL_NEAREST_MIPMAP_LINEAR:
     87 		case GL_LINEAR_MIPMAP_LINEAR:
     88 			return true;
     89 		default:
     90 			return error(GL_INVALID_ENUM, false);
     91 		}
     92 		break;
     93 
     94 	case GL_TEXTURE_MAG_FILTER:
     95 		switch(param)
     96 		{
     97 		case GL_NEAREST:
     98 		case GL_LINEAR:
     99 			return true;
    100 		default:
    101 			return error(GL_INVALID_ENUM, false);
    102 		}
    103 		break;
    104 
    105 	case GL_TEXTURE_USAGE_ANGLE:
    106 		switch(param)
    107 		{
    108 		case GL_NONE:
    109 		case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
    110 			return true;
    111 		default:
    112 			return error(GL_INVALID_ENUM, false);
    113 		}
    114 		break;
    115 
    116 	case GL_TEXTURE_MAX_ANISOTROPY_EXT:
    117 		// we assume the parameter passed to this validation method is truncated, not rounded
    118 		if(param < 1)
    119 		{
    120 			return error(GL_INVALID_VALUE, false);
    121 		}
    122 		return true;
    123 
    124 	case GL_TEXTURE_MIN_LOD:
    125 	case GL_TEXTURE_MAX_LOD:
    126 		// any value is permissible
    127 		return true;
    128 
    129 	case GL_TEXTURE_COMPARE_MODE:
    130 		// Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
    131 		switch(param)
    132 		{
    133 		case GL_NONE:
    134 		case GL_COMPARE_REF_TO_TEXTURE:
    135 			return true;
    136 		default:
    137 			return error(GL_INVALID_ENUM, false);
    138 		}
    139 		break;
    140 
    141 	case GL_TEXTURE_COMPARE_FUNC:
    142 		// Acceptable function parameters from GLES 3.0.2 spec, table 3.17
    143 		switch(param)
    144 		{
    145 		case GL_LEQUAL:
    146 		case GL_GEQUAL:
    147 		case GL_LESS:
    148 		case GL_GREATER:
    149 		case GL_EQUAL:
    150 		case GL_NOTEQUAL:
    151 		case GL_ALWAYS:
    152 		case GL_NEVER:
    153 			return true;
    154 		default:
    155 			return error(GL_INVALID_ENUM, false);
    156 		}
    157 		break;
    158 
    159 	case GL_TEXTURE_SWIZZLE_R:
    160 	case GL_TEXTURE_SWIZZLE_G:
    161 	case GL_TEXTURE_SWIZZLE_B:
    162 	case GL_TEXTURE_SWIZZLE_A:
    163 		switch(param)
    164 		{
    165 		case GL_RED:
    166 		case GL_GREEN:
    167 		case GL_BLUE:
    168 		case GL_ALPHA:
    169 		case GL_ZERO:
    170 		case GL_ONE:
    171 			return true;
    172 		default:
    173 			return error(GL_INVALID_ENUM, false);
    174 		}
    175 		break;
    176 
    177 	case GL_TEXTURE_BASE_LEVEL:
    178 	case GL_TEXTURE_MAX_LEVEL:
    179 		if(param < 0)
    180 		{
    181 			return error(GL_INVALID_VALUE, false);
    182 		}
    183 		return true;
    184 
    185 	default:
    186 		return error(GL_INVALID_ENUM, false);
    187 	}
    188 }
    189 
    190 static bool ValidateSamplerObjectParameter(GLenum pname)
    191 {
    192 	switch(pname)
    193 	{
    194 	case GL_TEXTURE_MIN_FILTER:
    195 	case GL_TEXTURE_MAG_FILTER:
    196 	case GL_TEXTURE_WRAP_S:
    197 	case GL_TEXTURE_WRAP_T:
    198 	case GL_TEXTURE_WRAP_R:
    199 	case GL_TEXTURE_MIN_LOD:
    200 	case GL_TEXTURE_MAX_LOD:
    201 	case GL_TEXTURE_COMPARE_MODE:
    202 	case GL_TEXTURE_COMPARE_FUNC:
    203 	case GL_TEXTURE_MAX_ANISOTROPY_EXT:
    204 		return true;
    205 	default:
    206 		return false;
    207 	}
    208 }
    209 
    210 extern "C"
    211 {
    212 
    213 GL_APICALL void GL_APIENTRY glReadBuffer(GLenum src)
    214 {
    215 	TRACE("(GLenum src = 0x%X)", src);
    216 
    217 	es2::Context *context = es2::getContext();
    218 
    219 	if(context)
    220 	{
    221 		GLuint readFramebufferName = context->getReadFramebufferName();
    222 
    223 		switch(src)
    224 		{
    225 		case GL_BACK:
    226 			if(readFramebufferName != 0)
    227 			{
    228 				return error(GL_INVALID_OPERATION);
    229 			}
    230 			context->setFramebufferReadBuffer(src);
    231 			break;
    232 		case GL_NONE:
    233 			context->setFramebufferReadBuffer(src);
    234 			break;
    235 		case GL_COLOR_ATTACHMENT0:
    236 		case GL_COLOR_ATTACHMENT1:
    237 		case GL_COLOR_ATTACHMENT2:
    238 		case GL_COLOR_ATTACHMENT3:
    239 		case GL_COLOR_ATTACHMENT4:
    240 		case GL_COLOR_ATTACHMENT5:
    241 		case GL_COLOR_ATTACHMENT6:
    242 		case GL_COLOR_ATTACHMENT7:
    243 		case GL_COLOR_ATTACHMENT8:
    244 		case GL_COLOR_ATTACHMENT9:
    245 		case GL_COLOR_ATTACHMENT10:
    246 		case GL_COLOR_ATTACHMENT11:
    247 		case GL_COLOR_ATTACHMENT12:
    248 		case GL_COLOR_ATTACHMENT13:
    249 		case GL_COLOR_ATTACHMENT14:
    250 		case GL_COLOR_ATTACHMENT15:
    251 		case GL_COLOR_ATTACHMENT16:
    252 		case GL_COLOR_ATTACHMENT17:
    253 		case GL_COLOR_ATTACHMENT18:
    254 		case GL_COLOR_ATTACHMENT19:
    255 		case GL_COLOR_ATTACHMENT20:
    256 		case GL_COLOR_ATTACHMENT21:
    257 		case GL_COLOR_ATTACHMENT22:
    258 		case GL_COLOR_ATTACHMENT23:
    259 		case GL_COLOR_ATTACHMENT24:
    260 		case GL_COLOR_ATTACHMENT25:
    261 		case GL_COLOR_ATTACHMENT26:
    262 		case GL_COLOR_ATTACHMENT27:
    263 		case GL_COLOR_ATTACHMENT28:
    264 		case GL_COLOR_ATTACHMENT29:
    265 		case GL_COLOR_ATTACHMENT30:
    266 		case GL_COLOR_ATTACHMENT31:
    267 			{
    268 				GLuint index = (src - GL_COLOR_ATTACHMENT0);
    269 				if(index >= MAX_COLOR_ATTACHMENTS)
    270 				{
    271 					return error(GL_INVALID_OPERATION);
    272 				}
    273 				if(readFramebufferName == 0)
    274 				{
    275 					return error(GL_INVALID_OPERATION);
    276 				}
    277 				context->setFramebufferReadBuffer(src);
    278 			}
    279 			break;
    280 		default:
    281 			return error(GL_INVALID_ENUM);
    282 		}
    283 	}
    284 }
    285 
    286 GL_APICALL void GL_APIENTRY glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices)
    287 {
    288 	TRACE("(GLenum mode = 0x%X, GLuint start = %d, GLuint end = %d, "
    289 		  "GLsizei count = %d, GLenum type = 0x%x, const void* indices = %p)",
    290 		  mode, start, end, count, type, indices);
    291 
    292 	switch(mode)
    293 	{
    294 	case GL_POINTS:
    295 	case GL_LINES:
    296 	case GL_LINE_LOOP:
    297 	case GL_LINE_STRIP:
    298 	case GL_TRIANGLES:
    299 	case GL_TRIANGLE_FAN:
    300 	case GL_TRIANGLE_STRIP:
    301 		break;
    302 	default:
    303 		return error(GL_INVALID_ENUM);
    304 	}
    305 
    306 	switch(type)
    307 	{
    308 	case GL_UNSIGNED_BYTE:
    309 	case GL_UNSIGNED_SHORT:
    310 	case GL_UNSIGNED_INT:
    311 		break;
    312 	default:
    313 		return error(GL_INVALID_ENUM);
    314 	}
    315 
    316 	if((count < 0) || (end < start))
    317 	{
    318 		return error(GL_INVALID_VALUE);
    319 	}
    320 
    321 	es2::Context *context = es2::getContext();
    322 
    323 	if(context)
    324 	{
    325 		es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
    326 		if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
    327 		{
    328 			return error(GL_INVALID_OPERATION);
    329 		}
    330 
    331 		context->drawElements(mode, start, end, count, type, indices);
    332 	}
    333 }
    334 
    335 GL_APICALL void GL_APIENTRY glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *data)
    336 {
    337 	TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
    338 	      "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, "
    339 	      "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* data = %p)",
    340 	      target, level, internalformat, width, height, depth, border, format, type, data);
    341 
    342 	switch(target)
    343 	{
    344 	case GL_TEXTURE_3D:
    345 	case GL_TEXTURE_2D_ARRAY:
    346 		break;
    347 	default:
    348 		return error(GL_INVALID_ENUM);
    349 	}
    350 
    351 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
    352 	{
    353 		return error(GL_INVALID_VALUE);
    354 	}
    355 
    356 	const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level;
    357 	if((width < 0) || (height < 0) || (depth < 0) || (width > maxSize3D) || (height > maxSize3D) || (depth > maxSize3D))
    358 	{
    359 		return error(GL_INVALID_VALUE);
    360 	}
    361 
    362 	if(border != 0)
    363 	{
    364 		return error(GL_INVALID_VALUE);
    365 	}
    366 
    367 	es2::Context *context = es2::getContext();
    368 
    369 	if(context)
    370 	{
    371 		GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target, context->getClientVersion());
    372 		if(validationError != GL_NO_ERROR)
    373 		{
    374 			return error(validationError);
    375 		}
    376 
    377 		es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
    378 
    379 		if(!texture)
    380 		{
    381 			return error(GL_INVALID_OPERATION);
    382 		}
    383 
    384 		validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
    385 		if(validationError != GL_NO_ERROR)
    386 		{
    387 			return error(validationError);
    388 		}
    389 
    390 		GLint sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
    391 		texture->setImage(level, width, height, depth, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
    392 	}
    393 }
    394 
    395 GL_APICALL void GL_APIENTRY glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data)
    396 {
    397 	TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
    398 		"GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
    399 		"GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* data = %p)",
    400 		target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);
    401 
    402 	switch(target)
    403 	{
    404 	case GL_TEXTURE_3D:
    405 	case GL_TEXTURE_2D_ARRAY:
    406 		break;
    407 	default:
    408 		return error(GL_INVALID_ENUM);
    409 	}
    410 
    411 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
    412 	{
    413 		return error(GL_INVALID_VALUE);
    414 	}
    415 
    416 	if((width < 0) || (height < 0) || (depth < 0) || (xoffset < 0) || (yoffset < 0) || (zoffset < 0))
    417 	{
    418 		return error(GL_INVALID_VALUE);
    419 	}
    420 
    421 	es2::Context *context = es2::getContext();
    422 
    423 	if(context)
    424 	{
    425 		es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
    426 
    427 		GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texture, context->getClientVersion());
    428 		if(validationError != GL_NO_ERROR)
    429 		{
    430 			return error(validationError);
    431 		}
    432 
    433 		validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
    434 		if(validationError != GL_NO_ERROR)
    435 		{
    436 			return error(validationError);
    437 		}
    438 
    439 		texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getUnpackParameters(), data);
    440 	}
    441 }
    442 
    443 GL_APICALL void GL_APIENTRY glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
    444 {
    445 	TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
    446 		"GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
    447 		target, level, xoffset, yoffset, zoffset, x, y, width, height);
    448 
    449 	switch(target)
    450 	{
    451 	case GL_TEXTURE_3D:
    452 	case GL_TEXTURE_2D_ARRAY:
    453 		break;
    454 	default:
    455 		return error(GL_INVALID_ENUM);
    456 	}
    457 
    458 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
    459 	{
    460 		return error(GL_INVALID_VALUE);
    461 	}
    462 
    463 	if((width < 0) || (height < 0) || (xoffset < 0) || (yoffset < 0) || (zoffset < 0))
    464 	{
    465 		return error(GL_INVALID_VALUE);
    466 	}
    467 
    468 	es2::Context *context = es2::getContext();
    469 
    470 	if(context)
    471 	{
    472 		es2::Framebuffer *framebuffer = context->getReadFramebuffer();
    473 
    474 		if(!framebuffer || (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE))
    475 		{
    476 			return error(GL_INVALID_FRAMEBUFFER_OPERATION);
    477 		}
    478 
    479 		es2::Renderbuffer *source = framebuffer->getReadColorbuffer();
    480 
    481 		if(context->getReadFramebufferName() != 0 && (!source || source->getSamples() > 1))
    482 		{
    483 			return error(GL_INVALID_OPERATION);
    484 		}
    485 
    486 		GLenum colorbufferFormat = source->getFormat();
    487 		es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
    488 
    489 		GLenum validationError = ValidateSubImageParams(false, true, target, level, xoffset, yoffset, zoffset, width, height, 1, GL_NONE, GL_NONE, texture, context->getClientVersion());
    490 		if(validationError != GL_NO_ERROR)
    491 		{
    492 			return error(validationError);
    493 		}
    494 
    495 		GLenum textureFormat = texture->getFormat(target, level);
    496 
    497 		if(!ValidateCopyFormats(textureFormat, colorbufferFormat))
    498 		{
    499 			return;
    500 		}
    501 
    502 		texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source);
    503 	}
    504 }
    505 
    506 GL_APICALL void GL_APIENTRY glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data)
    507 {
    508 	TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
    509 		"GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = %p)",
    510 		target, level, internalformat, width, height, depth, border, imageSize, data);
    511 
    512 	switch(target)
    513 	{
    514 	case GL_TEXTURE_3D:
    515 	case GL_TEXTURE_2D_ARRAY:
    516 		break;
    517 	default:
    518 		return error(GL_INVALID_ENUM);
    519 	}
    520 
    521 	if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
    522 	{
    523 		return error(GL_INVALID_VALUE);
    524 	}
    525 
    526 	const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level;
    527 	if((width < 0) || (height < 0) || (depth < 0) || (width > maxSize3D) || (height > maxSize3D) || (depth > maxSize3D) || (border != 0) || (imageSize < 0))
    528 	{
    529 		return error(GL_INVALID_VALUE);
    530 	}
    531 
    532 	if(!IsCompressed(internalformat, egl::getClientVersion()))
    533 	{
    534 		return error(GL_INVALID_ENUM);
    535 	}
    536 
    537 	if(imageSize != gl::ComputeCompressedSize(width, height, internalformat) * depth)
    538 	{
    539 		return error(GL_INVALID_VALUE);
    540 	}
    541 
    542 	es2::Context *context = es2::getContext();
    543 
    544 	if(context)
    545 	{
    546 		es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
    547 
    548 		if(!texture)
    549 		{
    550 			return error(GL_INVALID_OPERATION);
    551 		}
    552 
    553 		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
    554 		if(validationError != GL_NO_ERROR)
    555 		{
    556 			return error(validationError);
    557 		}
    558 
    559 		texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data);
    560 	}
    561 }
    562 
    563 GL_APICALL void GL_APIENTRY glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data)
    564 {
    565 	TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
    566 	      "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
    567 	      "GLenum format = 0x%X, GLsizei imageSize = %d, const void *data = %p)",
    568 	      target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
    569 
    570 	switch(target)
    571 	{
    572 	case GL_TEXTURE_3D:
    573 	case GL_TEXTURE_2D_ARRAY:
    574 		break;
    575 	default:
    576 		return error(GL_INVALID_ENUM);
    577 	}
    578 
    579 	if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
    580 	{
    581 		return error(GL_INVALID_VALUE);
    582 	}
    583 
    584 	if(xoffset < 0 || yoffset < 0 || zoffset < 0 || !validImageSize(level, width, height) || depth < 0 || imageSize < 0)
    585 	{
    586 		return error(GL_INVALID_VALUE);
    587 	}
    588 
    589 	if(!IsCompressed(format, egl::getClientVersion()))
    590 	{
    591 		return error(GL_INVALID_ENUM);
    592 	}
    593 
    594 	if(imageSize != gl::ComputeCompressedSize(width, height, format) * depth)
    595 	{
    596 		return error(GL_INVALID_VALUE);
    597 	}
    598 
    599 	bool is_ETC2_EAC = false;
    600 	switch(format)
    601 	{
    602 	case GL_COMPRESSED_R11_EAC:
    603 	case GL_COMPRESSED_SIGNED_R11_EAC:
    604 	case GL_COMPRESSED_RG11_EAC:
    605 	case GL_COMPRESSED_SIGNED_RG11_EAC:
    606 	case GL_COMPRESSED_RGB8_ETC2:
    607 	case GL_COMPRESSED_SRGB8_ETC2:
    608 	case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
    609 	case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
    610 	case GL_COMPRESSED_RGBA8_ETC2_EAC:
    611 	case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
    612 		if(target != GL_TEXTURE_2D_ARRAY)
    613 		{
    614 			return error(GL_INVALID_OPERATION);
    615 		}
    616 
    617 		if(((width % 4) != 0) || ((height % 4) != 0) ||
    618 		   ((xoffset % 4) != 0) || ((yoffset % 4) != 0))
    619 		{
    620 			return error(GL_INVALID_OPERATION);
    621 		}
    622 
    623 		is_ETC2_EAC = true;
    624 		break;
    625 	default:
    626 		break;
    627 	}
    628 
    629 	es2::Context *context = es2::getContext();
    630 
    631 	if(context)
    632 	{
    633 		es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
    634 
    635 		if(!texture)
    636 		{
    637 			return error(GL_INVALID_OPERATION);
    638 		}
    639 
    640 		GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
    641 		if(validationError != GL_NO_ERROR)
    642 		{
    643 			return error(validationError);
    644 		}
    645 
    646 		if(is_ETC2_EAC)
    647 		{
    648 			if(((width + xoffset) != texture->getWidth(target, level)) ||
    649 			   ((height + yoffset) != texture->getHeight(target, level)) ||
    650 			   ((depth + zoffset) != texture->getDepth(target, level)))
    651 			{
    652 				return error(GL_INVALID_OPERATION);
    653 			}
    654 		}
    655 
    656 		texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
    657 	}
    658 }
    659 
    660 GL_APICALL void GL_APIENTRY glGenQueries(GLsizei n, GLuint *ids)
    661 {
    662 	TRACE("(GLsizei n = %d, GLuint* ids = %p)", n, ids);
    663 
    664 	if(n < 0)
    665 	{
    666 		return error(GL_INVALID_VALUE);
    667 	}
    668 
    669 	es2::Context *context = es2::getContext();
    670 
    671 	if(context)
    672 	{
    673 		for(int i = 0; i < n; i++)
    674 		{
    675 			ids[i] = context->createQuery();
    676 		}
    677 	}
    678 }
    679 
    680 GL_APICALL void GL_APIENTRY glDeleteQueries(GLsizei n, const GLuint *ids)
    681 {
    682 	TRACE("(GLsizei n = %d, GLuint* ids = %p)", n, ids);
    683 
    684 	if(n < 0)
    685 	{
    686 		return error(GL_INVALID_VALUE);
    687 	}
    688 
    689 	es2::Context *context = es2::getContext();
    690 
    691 	if(context)
    692 	{
    693 		for(int i = 0; i < n; i++)
    694 		{
    695 			context->deleteQuery(ids[i]);
    696 		}
    697 	}
    698 }
    699 
    700 GL_APICALL GLboolean GL_APIENTRY glIsQuery(GLuint id)
    701 {
    702 	TRACE("(GLuint id = %d)", id);
    703 
    704 	if(id == 0)
    705 	{
    706 		return GL_FALSE;
    707 	}
    708 
    709 	es2::Context *context = es2::getContext();
    710 
    711 	if(context)
    712 	{
    713 		es2::Query *queryObject = context->getQuery(id);
    714 
    715 		if(queryObject)
    716 		{
    717 			return GL_TRUE;
    718 		}
    719 	}
    720 
    721 	return GL_FALSE;
    722 }
    723 
    724 GL_APICALL void GL_APIENTRY glBeginQuery(GLenum target, GLuint id)
    725 {
    726 	TRACE("(GLenum target = 0x%X, GLuint id = %d)", target, id);
    727 
    728 	if(!ValidateQueryTarget(target))
    729 	{
    730 		return error(GL_INVALID_ENUM);
    731 	}
    732 
    733 	if(id == 0)
    734 	{
    735 		return error(GL_INVALID_OPERATION);
    736 	}
    737 
    738 	es2::Context *context = es2::getContext();
    739 
    740 	if(context)
    741 	{
    742 		context->beginQuery(target, id);
    743 	}
    744 }
    745 
    746 GL_APICALL void GL_APIENTRY glEndQuery(GLenum target)
    747 {
    748 	TRACE("(GLenum target = 0x%X)", target);
    749 
    750 	if(!ValidateQueryTarget(target))
    751 	{
    752 		return error(GL_INVALID_ENUM);
    753 	}
    754 
    755 	es2::Context *context = es2::getContext();
    756 
    757 	if(context)
    758 	{
    759 		context->endQuery(target);
    760 	}
    761 }
    762 
    763 GL_APICALL void GL_APIENTRY glGetQueryiv(GLenum target, GLenum pname, GLint *params)
    764 {
    765 	TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = %p)",
    766 		  target, pname, params);
    767 
    768 	if(!ValidateQueryTarget(target) || (pname != GL_CURRENT_QUERY))
    769 	{
    770 		return error(GL_INVALID_ENUM);
    771 	}
    772 
    773 	es2::Context *context = es2::getContext();
    774 
    775 	if(context)
    776 	{
    777 		params[0] = context->getActiveQuery(target);
    778 	}
    779 }
    780 
    781 GL_APICALL void GL_APIENTRY glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
    782 {
    783 	TRACE("(GLuint id = %d, GLenum pname = 0x%X, GLint *params = %p)",
    784 	      id, pname, params);
    785 
    786 	switch(pname)
    787 	{
    788 	case GL_QUERY_RESULT:
    789 	case GL_QUERY_RESULT_AVAILABLE:
    790 		break;
    791 	default:
    792 		return error(GL_INVALID_ENUM);
    793 	}
    794 
    795 	es2::Context *context = es2::getContext();
    796 
    797 	if(context)
    798 	{
    799 		es2::Query *queryObject = context->getQuery(id);
    800 
    801 		if(!queryObject)
    802 		{
    803 			return error(GL_INVALID_OPERATION);
    804 		}
    805 
    806 		if(context->getActiveQuery(queryObject->getType()) == id)
    807 		{
    808 			return error(GL_INVALID_OPERATION);
    809 		}
    810 
    811 		switch(pname)
    812 		{
    813 		case GL_QUERY_RESULT:
    814 			params[0] = queryObject->getResult();
    815 			break;
    816 		case GL_QUERY_RESULT_AVAILABLE:
    817 			params[0] = queryObject->isResultAvailable();
    818 			break;
    819 		default:
    820 			ASSERT(false);
    821 		}
    822 	}
    823 }
    824 
    825 GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer(GLenum target)
    826 {
    827 	TRACE("(GLenum target = 0x%X)", target);
    828 
    829 	es2::Context *context = es2::getContext();
    830 
    831 	if(context)
    832 	{
    833 		es2::Buffer *buffer = nullptr;
    834 		if(!context->getBuffer(target, &buffer))
    835 		{
    836 			return error(GL_INVALID_ENUM, GL_TRUE);
    837 		}
    838 
    839 		if(!buffer)
    840 		{
    841 			// A null buffer means that "0" is bound to the requested buffer target
    842 			return error(GL_INVALID_OPERATION, GL_TRUE);
    843 		}
    844 
    845 		if(!buffer->isMapped())
    846 		{
    847 			// Already unmapped
    848 			return error(GL_INVALID_OPERATION, GL_TRUE);
    849 		}
    850 
    851 		return buffer->unmap() ? GL_TRUE : GL_FALSE;
    852 	}
    853 
    854 	return GL_TRUE;
    855 }
    856 
    857 GL_APICALL void GL_APIENTRY glGetBufferPointerv(GLenum target, GLenum pname, void **params)
    858 {
    859 	TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = %p)",
    860 	      target, pname, params);
    861 
    862 	if(pname != GL_BUFFER_MAP_POINTER)
    863 	{
    864 		return error(GL_INVALID_ENUM);
    865 	}
    866 
    867 	es2::Context *context = es2::getContext();
    868 
    869 	if(context)
    870 	{
    871 		es2::Buffer *buffer = nullptr;
    872 		if(!context->getBuffer(target, &buffer))
    873 		{
    874 			return error(GL_INVALID_ENUM);
    875 		}
    876 
    877 		if(!buffer)
    878 		{
    879 			// A null buffer means that "0" is bound to the requested buffer target
    880 			return error(GL_INVALID_OPERATION);
    881 		}
    882 
    883 		*params = buffer->isMapped() ? (void*)(((const char*)buffer->data()) + buffer->offset()) : nullptr;
    884 	}
    885 }
    886 
    887 GL_APICALL void GL_APIENTRY glDrawBuffers(GLsizei n, const GLenum *bufs)
    888 {
    889 	TRACE("(GLsizei n = %d, const GLenum *bufs = %p)", n, bufs);
    890 
    891 	if(n < 0 || n > MAX_DRAW_BUFFERS)
    892 	{
    893 		return error(GL_INVALID_VALUE);
    894 	}
    895 
    896 	es2::Context *context = es2::getContext();
    897 
    898 	if(context)
    899 	{
    900 		GLuint drawFramebufferName = context->getDrawFramebufferName();
    901 
    902 		if((drawFramebufferName == 0) && (n != 1))
    903 		{
    904 			return error(GL_INVALID_OPERATION);
    905 		}
    906 
    907 		for(unsigned int i = 0; i < (unsigned)n; i++)
    908 		{
    909 			switch(bufs[i])
    910 			{
    911 			case GL_BACK:
    912 				if(drawFramebufferName != 0)
    913 				{
    914 					return error(GL_INVALID_OPERATION);
    915 				}
    916 				break;
    917 			case GL_NONE:
    918 				break;
    919 			case GL_COLOR_ATTACHMENT0:
    920 			case GL_COLOR_ATTACHMENT1:
    921 			case GL_COLOR_ATTACHMENT2:
    922 			case GL_COLOR_ATTACHMENT3:
    923 			case GL_COLOR_ATTACHMENT4:
    924 			case GL_COLOR_ATTACHMENT5:
    925 			case GL_COLOR_ATTACHMENT6:
    926 			case GL_COLOR_ATTACHMENT7:
    927 			case GL_COLOR_ATTACHMENT8:
    928 			case GL_COLOR_ATTACHMENT9:
    929 			case GL_COLOR_ATTACHMENT10:
    930 			case GL_COLOR_ATTACHMENT11:
    931 			case GL_COLOR_ATTACHMENT12:
    932 			case GL_COLOR_ATTACHMENT13:
    933 			case GL_COLOR_ATTACHMENT14:
    934 			case GL_COLOR_ATTACHMENT15:
    935 			case GL_COLOR_ATTACHMENT16:
    936 			case GL_COLOR_ATTACHMENT17:
    937 			case GL_COLOR_ATTACHMENT18:
    938 			case GL_COLOR_ATTACHMENT19:
    939 			case GL_COLOR_ATTACHMENT20:
    940 			case GL_COLOR_ATTACHMENT21:
    941 			case GL_COLOR_ATTACHMENT22:
    942 			case GL_COLOR_ATTACHMENT23:
    943 			case GL_COLOR_ATTACHMENT24:
    944 			case GL_COLOR_ATTACHMENT25:
    945 			case GL_COLOR_ATTACHMENT26:
    946 			case GL_COLOR_ATTACHMENT27:
    947 			case GL_COLOR_ATTACHMENT28:
    948 			case GL_COLOR_ATTACHMENT29:
    949 			case GL_COLOR_ATTACHMENT30:
    950 			case GL_COLOR_ATTACHMENT31:
    951 				{
    952 					GLuint index = (bufs[i] - GL_COLOR_ATTACHMENT0);
    953 
    954 					if(index >= MAX_COLOR_ATTACHMENTS)
    955 					{
    956 						return error(GL_INVALID_OPERATION);
    957 					}
    958 
    959 					if(index != i)
    960 					{
    961 						return error(GL_INVALID_OPERATION);
    962 					}
    963 
    964 					if(drawFramebufferName == 0)
    965 					{
    966 						return error(GL_INVALID_OPERATION);
    967 					}
    968 				}
    969 				break;
    970 			default:
    971 				return error(GL_INVALID_ENUM);
    972 			}
    973 		}
    974 
    975 		context->setFramebufferDrawBuffers(n, bufs);
    976 	}
    977 }
    978 
    979 GL_APICALL void GL_APIENTRY glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
    980 {
    981 	TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
    982 
    983 	if(count < 0)
    984 	{
    985 		return error(GL_INVALID_VALUE);
    986 	}
    987 
    988 	es2::Context *context = es2::getContext();
    989 
    990 	if(context)
    991 	{
    992 		es2::Program *program = context->getCurrentProgram();
    993 
    994 		if(!program)
    995 		{
    996 			return error(GL_INVALID_OPERATION);
    997 		}
    998 
    999 		if(location == -1)
   1000 		{
   1001 			return;
   1002 		}
   1003 
   1004 		if(!program->setUniformMatrix2x3fv(location, count, transpose, value))
   1005 		{
   1006 			return error(GL_INVALID_OPERATION);
   1007 		}
   1008 	}
   1009 }
   1010 
   1011 GL_APICALL void GL_APIENTRY glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
   1012 {
   1013 	TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
   1014 
   1015 	if(count < 0)
   1016 	{
   1017 		return error(GL_INVALID_VALUE);
   1018 	}
   1019 
   1020 	es2::Context *context = es2::getContext();
   1021 
   1022 	if(context)
   1023 	{
   1024 		es2::Program *program = context->getCurrentProgram();
   1025 
   1026 		if(!program)
   1027 		{
   1028 			return error(GL_INVALID_OPERATION);
   1029 		}
   1030 
   1031 		if(location == -1)
   1032 		{
   1033 			return;
   1034 		}
   1035 
   1036 		if(!program->setUniformMatrix3x2fv(location, count, transpose, value))
   1037 		{
   1038 			return error(GL_INVALID_OPERATION);
   1039 		}
   1040 	}
   1041 }
   1042 
   1043 GL_APICALL void GL_APIENTRY glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
   1044 {
   1045 	TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
   1046 
   1047 	if(count < 0)
   1048 	{
   1049 		return error(GL_INVALID_VALUE);
   1050 	}
   1051 
   1052 	es2::Context *context = es2::getContext();
   1053 
   1054 	if(context)
   1055 	{
   1056 		es2::Program *program = context->getCurrentProgram();
   1057 
   1058 		if(!program)
   1059 		{
   1060 			return error(GL_INVALID_OPERATION);
   1061 		}
   1062 
   1063 		if(location == -1)
   1064 		{
   1065 			return;
   1066 		}
   1067 
   1068 		if(!program->setUniformMatrix2x4fv(location, count, transpose, value))
   1069 		{
   1070 			return error(GL_INVALID_OPERATION);
   1071 		}
   1072 	}
   1073 }
   1074 
   1075 GL_APICALL void GL_APIENTRY glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
   1076 {
   1077 	TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
   1078 
   1079 	if(count < 0)
   1080 	{
   1081 		return error(GL_INVALID_VALUE);
   1082 	}
   1083 
   1084 	es2::Context *context = es2::getContext();
   1085 
   1086 	if(context)
   1087 	{
   1088 		es2::Program *program = context->getCurrentProgram();
   1089 
   1090 		if(!program)
   1091 		{
   1092 			return error(GL_INVALID_OPERATION);
   1093 		}
   1094 
   1095 		if(location == -1)
   1096 		{
   1097 			return;
   1098 		}
   1099 
   1100 		if(!program->setUniformMatrix4x2fv(location, count, transpose, value))
   1101 		{
   1102 			return error(GL_INVALID_OPERATION);
   1103 		}
   1104 	}
   1105 }
   1106 
   1107 GL_APICALL void GL_APIENTRY glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
   1108 {
   1109 	TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
   1110 
   1111 	if(count < 0)
   1112 	{
   1113 		return error(GL_INVALID_VALUE);
   1114 	}
   1115 
   1116 	es2::Context *context = es2::getContext();
   1117 
   1118 	if(context)
   1119 	{
   1120 		es2::Program *program = context->getCurrentProgram();
   1121 
   1122 		if(!program)
   1123 		{
   1124 			return error(GL_INVALID_OPERATION);
   1125 		}
   1126 
   1127 		if(location == -1)
   1128 		{
   1129 			return;
   1130 		}
   1131 
   1132 		if(!program->setUniformMatrix3x4fv(location, count, transpose, value))
   1133 		{
   1134 			return error(GL_INVALID_OPERATION);
   1135 		}
   1136 	}
   1137 }
   1138 
   1139 GL_APICALL void GL_APIENTRY glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
   1140 {
   1141 	TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
   1142 
   1143 	if(count < 0)
   1144 	{
   1145 		return error(GL_INVALID_VALUE);
   1146 	}
   1147 
   1148 	es2::Context *context = es2::getContext();
   1149 
   1150 	if(context)
   1151 	{
   1152 		es2::Program *program = context->getCurrentProgram();
   1153 
   1154 		if(!program)
   1155 		{
   1156 			return error(GL_INVALID_OPERATION);
   1157 		}
   1158 
   1159 		if(location == -1)
   1160 		{
   1161 			return;
   1162 		}
   1163 
   1164 		if(!program->setUniformMatrix4x3fv(location, count, transpose, value))
   1165 		{
   1166 			return error(GL_INVALID_OPERATION);
   1167 		}
   1168 	}
   1169 }
   1170 
   1171 GL_APICALL void GL_APIENTRY glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
   1172 {
   1173 	TRACE("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
   1174 	      "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "
   1175 	      "GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
   1176 	      srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);
   1177 
   1178 	switch(filter)
   1179 	{
   1180 	case GL_NEAREST:
   1181 		break;
   1182 	case GL_LINEAR:
   1183 		if((mask & GL_DEPTH_BUFFER_BIT) || (mask & GL_STENCIL_BUFFER_BIT))
   1184 		{
   1185 			return error(GL_INVALID_OPERATION);
   1186 		}
   1187 		break;
   1188 	default:
   1189 		return error(GL_INVALID_ENUM);
   1190 	}
   1191 
   1192 	if((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
   1193 	{
   1194 		return error(GL_INVALID_VALUE);
   1195 	}
   1196 
   1197 	es2::Context *context = es2::getContext();
   1198 
   1199 	if(context)
   1200 	{
   1201 		if(context->getReadFramebufferName() == context->getDrawFramebufferName())
   1202 		{
   1203 			ERR("Blits with the same source and destination framebuffer are not supported by this implementation.");
   1204 			return error(GL_INVALID_OPERATION);
   1205 		}
   1206 
   1207 		context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter == GL_LINEAR, true);
   1208 	}
   1209 }
   1210 
   1211 GL_APICALL void GL_APIENTRY glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
   1212 {
   1213 	TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %d, GLint level = %d, GLint layer = %d)",
   1214 	      target, attachment, texture, level, layer);
   1215 
   1216 	// GLES 3.0.4 spec, p.209, section 4.4.2
   1217 	// If texture is zero, any image or array of images attached to the attachment point
   1218 	// named by attachment is detached. Any additional parameters(level, textarget,
   1219 	// and / or layer) are ignored when texture is zero.
   1220 	if(texture != 0 && (layer < 0 || level < 0))
   1221 	{
   1222 		return error(GL_INVALID_VALUE);
   1223 	}
   1224 
   1225 	es2::Context *context = es2::getContext();
   1226 
   1227 	if(context)
   1228 	{
   1229 		Texture* textureObject = context->getTexture(texture);
   1230 		GLenum textarget = GL_NONE;
   1231 		if(texture != 0)
   1232 		{
   1233 			if(!textureObject)
   1234 			{
   1235 				return error(GL_INVALID_OPERATION);
   1236 			}
   1237 
   1238 			textarget = textureObject->getTarget();
   1239 			switch(textarget)
   1240 			{
   1241 			case GL_TEXTURE_3D:
   1242 			case GL_TEXTURE_2D_ARRAY:
   1243 				if(layer >= es2::IMPLEMENTATION_MAX_TEXTURE_SIZE || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
   1244 				{
   1245 					return error(GL_INVALID_VALUE);
   1246 				}
   1247 				break;
   1248 			default:
   1249 				return error(GL_INVALID_OPERATION);
   1250 			}
   1251 
   1252 			if(textureObject->isCompressed(textarget, level))
   1253 			{
   1254 				return error(GL_INVALID_OPERATION);
   1255 			}
   1256 		}
   1257 
   1258 		es2::Framebuffer *framebuffer = nullptr;
   1259 		switch(target)
   1260 		{
   1261 		case GL_DRAW_FRAMEBUFFER:
   1262 		case GL_FRAMEBUFFER:
   1263 			if(context->getDrawFramebufferName() == 0)
   1264 			{
   1265 				return error(GL_INVALID_OPERATION);
   1266 			}
   1267 			framebuffer = context->getDrawFramebuffer();
   1268 			break;
   1269 		case GL_READ_FRAMEBUFFER:
   1270 			if(context->getReadFramebufferName() == 0)
   1271 			{
   1272 				return error(GL_INVALID_OPERATION);
   1273 			}
   1274 			framebuffer = context->getReadFramebuffer();
   1275 			break;
   1276 		default:
   1277 			return error(GL_INVALID_ENUM);
   1278 		}
   1279 
   1280 		if(!framebuffer)
   1281 		{
   1282 			return error(GL_INVALID_OPERATION);
   1283 		}
   1284 
   1285 		switch(attachment)
   1286 		{
   1287 		case GL_COLOR_ATTACHMENT0:
   1288 		case GL_COLOR_ATTACHMENT1:
   1289 		case GL_COLOR_ATTACHMENT2:
   1290 		case GL_COLOR_ATTACHMENT3:
   1291 		case GL_COLOR_ATTACHMENT4:
   1292 		case GL_COLOR_ATTACHMENT5:
   1293 		case GL_COLOR_ATTACHMENT6:
   1294 		case GL_COLOR_ATTACHMENT7:
   1295 		case GL_COLOR_ATTACHMENT8:
   1296 		case GL_COLOR_ATTACHMENT9:
   1297 		case GL_COLOR_ATTACHMENT10:
   1298 		case GL_COLOR_ATTACHMENT11:
   1299 		case GL_COLOR_ATTACHMENT12:
   1300 		case GL_COLOR_ATTACHMENT13:
   1301 		case GL_COLOR_ATTACHMENT14:
   1302 		case GL_COLOR_ATTACHMENT15:
   1303 		case GL_COLOR_ATTACHMENT16:
   1304 		case GL_COLOR_ATTACHMENT17:
   1305 		case GL_COLOR_ATTACHMENT18:
   1306 		case GL_COLOR_ATTACHMENT19:
   1307 		case GL_COLOR_ATTACHMENT20:
   1308 		case GL_COLOR_ATTACHMENT21:
   1309 		case GL_COLOR_ATTACHMENT22:
   1310 		case GL_COLOR_ATTACHMENT23:
   1311 		case GL_COLOR_ATTACHMENT24:
   1312 		case GL_COLOR_ATTACHMENT25:
   1313 		case GL_COLOR_ATTACHMENT26:
   1314 		case GL_COLOR_ATTACHMENT27:
   1315 		case GL_COLOR_ATTACHMENT28:
   1316 		case GL_COLOR_ATTACHMENT29:
   1317 		case GL_COLOR_ATTACHMENT30:
   1318 		case GL_COLOR_ATTACHMENT31:
   1319 			framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0, level, layer);
   1320 			break;
   1321 		case GL_DEPTH_ATTACHMENT:
   1322 			framebuffer->setDepthbuffer(textarget, texture, level, layer);
   1323 			break;
   1324 		case GL_STENCIL_ATTACHMENT:
   1325 			framebuffer->setStencilbuffer(textarget, texture, level, layer);
   1326 			break;
   1327 		case GL_DEPTH_STENCIL_ATTACHMENT:
   1328 			framebuffer->setDepthbuffer(textarget, texture, level, layer);
   1329 			framebuffer->setStencilbuffer(textarget, texture, level, layer);
   1330 			break;
   1331 		default:
   1332 			return error(GL_INVALID_ENUM);
   1333 		}
   1334 	}
   1335 }
   1336 
   1337 GL_APICALL void *GL_APIENTRY glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
   1338 {
   1339 	TRACE("(GLenum target = 0x%X,  GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = %X)",
   1340 	      target, offset, length, access);
   1341 
   1342 	if((offset < 0) || (length < 0))
   1343 	{
   1344 		return error(GL_INVALID_VALUE, nullptr);
   1345 	}
   1346 
   1347 	if(!(access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)))
   1348 	{
   1349 		// Must be able to read or write the buffer
   1350 		return error(GL_INVALID_OPERATION, nullptr);
   1351 	}
   1352 	else if((access & GL_MAP_READ_BIT) && (access & (GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT)))
   1353 	{
   1354 		// GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT and GL_MAP_UNSYNCHRONIZED_BIT can't be used with GL_MAP_READ_BIT
   1355 		return error(GL_INVALID_OPERATION, nullptr);
   1356 	}
   1357 	else if((!(access & GL_MAP_WRITE_BIT)) && (access & GL_MAP_FLUSH_EXPLICIT_BIT))
   1358 	{
   1359 		// GL_MAP_FLUSH_EXPLICIT_BIT can't be used without GL_MAP_WRITE_BIT
   1360 		return error(GL_INVALID_OPERATION, nullptr);
   1361 	}
   1362 
   1363 	es2::Context *context = es2::getContext();
   1364 
   1365 	if(context)
   1366 	{
   1367 		es2::Buffer *buffer = nullptr;
   1368 		if(!context->getBuffer(target, &buffer))
   1369 		{
   1370 			return error(GL_INVALID_ENUM, nullptr);
   1371 		}
   1372 
   1373 		if(!buffer)
   1374 		{
   1375 			// A null buffer means that "0" is bound to the requested buffer target
   1376 			return error(GL_INVALID_OPERATION, nullptr);
   1377 		}
   1378 
   1379 		if(buffer->isMapped())
   1380 		{
   1381 			// It is an invalid operation to map an already mapped buffer
   1382 			return error(GL_INVALID_OPERATION, nullptr);
   1383 		}
   1384 
   1385 		GLsizeiptr bufferSize = buffer->size();
   1386 		if((offset + length) > bufferSize)
   1387 		{
   1388 			return error(GL_INVALID_VALUE, nullptr);
   1389 		}
   1390 
   1391 		if((access & ~(GL_MAP_READ_BIT |
   1392 		               GL_MAP_WRITE_BIT |
   1393 		               GL_MAP_INVALIDATE_RANGE_BIT |
   1394 		               GL_MAP_INVALIDATE_BUFFER_BIT |
   1395 		               GL_MAP_FLUSH_EXPLICIT_BIT |
   1396 		               GL_MAP_UNSYNCHRONIZED_BIT)) != 0)
   1397 		{
   1398 			return error(GL_INVALID_VALUE, nullptr);
   1399 		}
   1400 
   1401 		return buffer->mapRange(offset, length, access);
   1402 	}
   1403 
   1404 	return nullptr;
   1405 }
   1406 
   1407 GL_APICALL void GL_APIENTRY glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
   1408 {
   1409 	TRACE("(GLenum target = 0x%X,  GLintptr offset = %d, GLsizeiptr length = %d)",
   1410 	      target, offset, length);
   1411 
   1412 	if((offset < 0) || (length < 0))
   1413 	{
   1414 		return error(GL_INVALID_VALUE);
   1415 	}
   1416 
   1417 	es2::Context *context = es2::getContext();
   1418 
   1419 	if(context)
   1420 	{
   1421 		es2::Buffer *buffer = nullptr;
   1422 		if(!context->getBuffer(target, &buffer))
   1423 		{
   1424 			return error(GL_INVALID_ENUM);
   1425 		}
   1426 
   1427 		if(!buffer)
   1428 		{
   1429 			// A null buffer means that "0" is bound to the requested buffer target
   1430 			return error(GL_INVALID_OPERATION);
   1431 		}
   1432 
   1433 		if(!buffer->isMapped())
   1434 		{
   1435 			// Buffer must be mapped
   1436 			return error(GL_INVALID_OPERATION);
   1437 		}
   1438 
   1439 		GLsizeiptr bufferSize = buffer->length();
   1440 		if((offset + length) > bufferSize)
   1441 		{
   1442 			return error(GL_INVALID_VALUE);
   1443 		}
   1444 
   1445 		if(!(buffer->access() & GL_MAP_FLUSH_EXPLICIT_BIT))
   1446 		{
   1447 			// Flush must be explicitly allowed
   1448 			return error(GL_INVALID_OPERATION);
   1449 		}
   1450 
   1451 		buffer->flushMappedRange(offset, length);
   1452 	}
   1453 }
   1454 
   1455 GL_APICALL void GL_APIENTRY glBindVertexArray(GLuint array)
   1456 {
   1457 	TRACE("(GLuint array = %d)", array);
   1458 
   1459 	es2::Context *context = es2::getContext();
   1460 
   1461 	if(context)
   1462 	{
   1463 		if(!context->isVertexArray(array))
   1464 		{
   1465 			return error(GL_INVALID_OPERATION);
   1466 		}
   1467 
   1468 		context->bindVertexArray(array);
   1469 	}
   1470 }
   1471 
   1472 GL_APICALL void GL_APIENTRY glDeleteVertexArrays(GLsizei n, const GLuint *arrays)
   1473 {
   1474 	TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
   1475 
   1476 	if(n < 0)
   1477 	{
   1478 		return error(GL_INVALID_VALUE);
   1479 	}
   1480 
   1481 	es2::Context *context = es2::getContext();
   1482 
   1483 	if(context)
   1484 	{
   1485 		for(int i = 0; i < n; i++)
   1486 		{
   1487 			context->deleteVertexArray(arrays[i]);
   1488 		}
   1489 	}
   1490 }
   1491 
   1492 GL_APICALL void GL_APIENTRY glGenVertexArrays(GLsizei n, GLuint *arrays)
   1493 {
   1494 	TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
   1495 
   1496 	if(n < 0)
   1497 	{
   1498 		return error(GL_INVALID_VALUE);
   1499 	}
   1500 
   1501 	es2::Context *context = es2::getContext();
   1502 
   1503 	if(context)
   1504 	{
   1505 		for(int i = 0; i < n; i++)
   1506 		{
   1507 			arrays[i] = context->createVertexArray();
   1508 		}
   1509 	}
   1510 }
   1511 
   1512 GL_APICALL GLboolean GL_APIENTRY glIsVertexArray(GLuint array)
   1513 {
   1514 	TRACE("(GLuint array = %d)", array);
   1515 
   1516 	if(array == 0)
   1517 	{
   1518 		return GL_FALSE;
   1519 	}
   1520 
   1521 	es2::Context *context = es2::getContext();
   1522 
   1523 	if(context)
   1524 	{
   1525 		es2::VertexArray *arrayObject = context->getVertexArray(array);
   1526 
   1527 		if(arrayObject)
   1528 		{
   1529 			return GL_TRUE;
   1530 		}
   1531 	}
   1532 
   1533 	return GL_FALSE;
   1534 }
   1535 
   1536 GL_APICALL void GL_APIENTRY glGetIntegeri_v(GLenum target, GLuint index, GLint *data)
   1537 {
   1538 	TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint* data = %p)",
   1539 	      target, index, data);
   1540 
   1541 	es2::Context *context = es2::getContext();
   1542 
   1543 	if(context)
   1544 	{
   1545 		if(!context->getTransformFeedbackiv(index, target, data) &&
   1546 		   !context->getUniformBufferiv(index, target, data) &&
   1547 		   !context->getIntegerv(target, data))
   1548 		{
   1549 			GLenum nativeType;
   1550 			unsigned int numParams = 0;
   1551 			if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
   1552 				return error(GL_INVALID_ENUM);
   1553 
   1554 			if(numParams == 0)
   1555 				return; // it is known that target is valid, but there are no parameters to return
   1556 
   1557 			if(nativeType == GL_BOOL)
   1558 			{
   1559 				GLboolean *boolParams = nullptr;
   1560 				boolParams = new GLboolean[numParams];
   1561 
   1562 				context->getBooleanv(target, boolParams);
   1563 
   1564 				for(unsigned int i = 0; i < numParams; ++i)
   1565 				{
   1566 					data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
   1567 				}
   1568 
   1569 				delete[] boolParams;
   1570 			}
   1571 			else if(nativeType == GL_FLOAT)
   1572 			{
   1573 				GLfloat *floatParams = nullptr;
   1574 				floatParams = new GLfloat[numParams];
   1575 
   1576 				context->getFloatv(target, floatParams);
   1577 
   1578 				for(unsigned int i = 0; i < numParams; ++i)
   1579 				{
   1580 					if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
   1581 					{
   1582 						data[i] = convert_float_fixed(floatParams[i]);
   1583 					}
   1584 					else
   1585 					{
   1586 						data[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
   1587 					}
   1588 				}
   1589 
   1590 				delete[] floatParams;
   1591 			}
   1592 		}
   1593 	}
   1594 }
   1595 
   1596 GL_APICALL void GL_APIENTRY glBeginTransformFeedback(GLenum primitiveMode)
   1597 {
   1598 	TRACE("(GLenum primitiveMode = 0x%X)", primitiveMode);
   1599 
   1600 	switch(primitiveMode)
   1601 	{
   1602 	case GL_POINTS:
   1603 	case GL_LINES:
   1604 	case GL_TRIANGLES:
   1605 		break;
   1606 	default:
   1607 		return error(GL_INVALID_ENUM);
   1608 	}
   1609 
   1610 	es2::Context *context = es2::getContext();
   1611 
   1612 	if(context)
   1613 	{
   1614 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
   1615 
   1616 		if(transformFeedbackObject)
   1617 		{
   1618 			if(transformFeedbackObject->isActive())
   1619 			{
   1620 				return error(GL_INVALID_OPERATION);
   1621 			}
   1622 			transformFeedbackObject->begin(primitiveMode);
   1623 		}
   1624 		else
   1625 		{
   1626 			return error(GL_INVALID_OPERATION);
   1627 		}
   1628 	}
   1629 }
   1630 
   1631 GL_APICALL void GL_APIENTRY glEndTransformFeedback(void)
   1632 {
   1633 	TRACE("()");
   1634 
   1635 	es2::Context *context = es2::getContext();
   1636 
   1637 	if(context)
   1638 	{
   1639 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
   1640 
   1641 		if(transformFeedbackObject)
   1642 		{
   1643 			if(!transformFeedbackObject->isActive())
   1644 			{
   1645 				return error(GL_INVALID_OPERATION);
   1646 			}
   1647 			transformFeedbackObject->end();
   1648 		}
   1649 		else
   1650 		{
   1651 			return error(GL_INVALID_OPERATION);
   1652 		}
   1653 	}
   1654 }
   1655 
   1656 GL_APICALL void GL_APIENTRY glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
   1657 {
   1658 	TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d, GLintptr offset = %d, GLsizeiptr size = %d)",
   1659 	      target, index, buffer, offset, size);
   1660 
   1661 	if(buffer != 0 && size <= 0)
   1662 	{
   1663 		return error(GL_INVALID_VALUE);
   1664 	}
   1665 
   1666 	es2::Context *context = es2::getContext();
   1667 
   1668 	if(context)
   1669 	{
   1670 		switch(target)
   1671 		{
   1672 		case GL_TRANSFORM_FEEDBACK_BUFFER:
   1673 			if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
   1674 			{
   1675 				return error(GL_INVALID_VALUE);
   1676 			}
   1677 			if(size & 0x3 || offset & 0x3) // size and offset must be multiples of 4
   1678 			{
   1679 				return error(GL_INVALID_VALUE);
   1680 			}
   1681 			context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size);
   1682 			context->bindGenericTransformFeedbackBuffer(buffer);
   1683 			break;
   1684 		case GL_UNIFORM_BUFFER:
   1685 			if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
   1686 			{
   1687 				return error(GL_INVALID_VALUE);
   1688 			}
   1689 			if(offset % UNIFORM_BUFFER_OFFSET_ALIGNMENT != 0)
   1690 			{
   1691 				return error(GL_INVALID_VALUE);
   1692 			}
   1693 			context->bindIndexedUniformBuffer(buffer, index, offset, size);
   1694 			context->bindGenericUniformBuffer(buffer);
   1695 			break;
   1696 		default:
   1697 			return error(GL_INVALID_ENUM);
   1698 		}
   1699 	}
   1700 }
   1701 
   1702 GL_APICALL void GL_APIENTRY glBindBufferBase(GLenum target, GLuint index, GLuint buffer)
   1703 {
   1704 	TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d)",
   1705 	      target, index, buffer);
   1706 
   1707 	es2::Context *context = es2::getContext();
   1708 
   1709 	if(context)
   1710 	{
   1711 		switch(target)
   1712 		{
   1713 		case GL_TRANSFORM_FEEDBACK_BUFFER:
   1714 			if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
   1715 			{
   1716 				return error(GL_INVALID_VALUE);
   1717 			}
   1718 			context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0);
   1719 			context->bindGenericTransformFeedbackBuffer(buffer);
   1720 			break;
   1721 		case GL_UNIFORM_BUFFER:
   1722 			if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
   1723 			{
   1724 				return error(GL_INVALID_VALUE);
   1725 			}
   1726 			context->bindIndexedUniformBuffer(buffer, index, 0, 0);
   1727 			context->bindGenericUniformBuffer(buffer);
   1728 			break;
   1729 		default:
   1730 			return error(GL_INVALID_ENUM);
   1731 		}
   1732 	}
   1733 }
   1734 
   1735 GL_APICALL void GL_APIENTRY glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode)
   1736 {
   1737 	TRACE("(GLuint program = %d, GLsizei count = %d, const GLchar *const*varyings = %p, GLenum bufferMode = 0x%X)",
   1738 	      program, count, varyings, bufferMode);
   1739 
   1740 	switch(bufferMode)
   1741 	{
   1742 	case GL_SEPARATE_ATTRIBS:
   1743 		if(count > MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
   1744 		{
   1745 			return error(GL_INVALID_VALUE);
   1746 		}
   1747 	case GL_INTERLEAVED_ATTRIBS:
   1748 		break;
   1749 	default:
   1750 		return error(GL_INVALID_ENUM);
   1751 	}
   1752 
   1753 	es2::Context *context = es2::getContext();
   1754 
   1755 	if(context)
   1756 	{
   1757 		es2::Program *programObject = context->getProgram(program);
   1758 
   1759 		if(!programObject)
   1760 		{
   1761 			return error(GL_INVALID_VALUE);
   1762 		}
   1763 
   1764 		programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);
   1765 	}
   1766 }
   1767 
   1768 GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name)
   1769 {
   1770 	TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
   1771 	      program, index, bufSize, length, size, type, name);
   1772 
   1773 	if(bufSize < 0)
   1774 	{
   1775 		return error(GL_INVALID_VALUE);
   1776 	}
   1777 
   1778 	es2::Context *context = es2::getContext();
   1779 
   1780 	if(context)
   1781 	{
   1782 		es2::Program *programObject = context->getProgram(program);
   1783 
   1784 		if(!programObject)
   1785 		{
   1786 			return error(GL_INVALID_VALUE);
   1787 		}
   1788 
   1789 		if(index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount()))
   1790 		{
   1791 			return error(GL_INVALID_VALUE);
   1792 		}
   1793 
   1794 		programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name);
   1795 	}
   1796 }
   1797 
   1798 GL_APICALL void GL_APIENTRY glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)
   1799 {
   1800 	TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
   1801 	      index, size, type, stride, pointer);
   1802 
   1803 	if(index >= es2::MAX_VERTEX_ATTRIBS)
   1804 	{
   1805 		return error(GL_INVALID_VALUE);
   1806 	}
   1807 
   1808 	if(size < 1 || size > 4 || stride < 0)
   1809 	{
   1810 		return error(GL_INVALID_VALUE);
   1811 	}
   1812 
   1813 	switch(type)
   1814 	{
   1815 	case GL_BYTE:
   1816 	case GL_UNSIGNED_BYTE:
   1817 	case GL_SHORT:
   1818 	case GL_UNSIGNED_SHORT:
   1819 	case GL_INT:
   1820 	case GL_UNSIGNED_INT:
   1821 		break;
   1822 	default:
   1823 		return error(GL_INVALID_ENUM);
   1824 	}
   1825 
   1826 	es2::Context *context = es2::getContext();
   1827 
   1828 	if(context)
   1829 	{
   1830 		es2::VertexArray* vertexArray = context->getCurrentVertexArray();
   1831 		if((context->getArrayBufferName() == 0) && vertexArray && (vertexArray->name != 0) && pointer)
   1832 		{
   1833 			// GL_INVALID_OPERATION is generated if a non-zero vertex array object is bound, zero is bound
   1834 			// to the GL_ARRAY_BUFFER buffer object binding point and the pointer argument is not NULL.
   1835 			return error(GL_INVALID_OPERATION);
   1836 		}
   1837 
   1838 		context->setVertexAttribState(index, context->getArrayBuffer(), size, type, false, true, stride, pointer);
   1839 	}
   1840 }
   1841 
   1842 GL_APICALL void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
   1843 {
   1844 	TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint *params = %p)",
   1845 	      index, pname, params);
   1846 
   1847 	es2::Context *context = es2::getContext();
   1848 
   1849 	if(context)
   1850 	{
   1851 		if(index >= es2::MAX_VERTEX_ATTRIBS)
   1852 		{
   1853 			return error(GL_INVALID_VALUE);
   1854 		}
   1855 
   1856 		const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
   1857 
   1858 		switch(pname)
   1859 		{
   1860 		case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
   1861 			*params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
   1862 			break;
   1863 		case GL_VERTEX_ATTRIB_ARRAY_SIZE:
   1864 			*params = attribState.mSize;
   1865 			break;
   1866 		case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
   1867 			*params = attribState.mStride;
   1868 			break;
   1869 		case GL_VERTEX_ATTRIB_ARRAY_TYPE:
   1870 			*params = attribState.mType;
   1871 			break;
   1872 		case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
   1873 			*params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
   1874 			break;
   1875 		case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
   1876 			*params = attribState.mBoundBuffer.name();
   1877 			break;
   1878 		case GL_CURRENT_VERTEX_ATTRIB:
   1879 			{
   1880 				const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
   1881 				for(int i = 0; i < 4; ++i)
   1882 				{
   1883 					params[i] = attrib.getCurrentValueI(i);
   1884 				}
   1885 			}
   1886 			break;
   1887 		case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
   1888 			*params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
   1889 			break;
   1890 		case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
   1891 			*params = attribState.mDivisor;
   1892 			break;
   1893 		default: return error(GL_INVALID_ENUM);
   1894 		}
   1895 	}
   1896 }
   1897 
   1898 GL_APICALL void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params)
   1899 {
   1900 	TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLuint *params = %p)",
   1901 		index, pname, params);
   1902 
   1903 	es2::Context *context = es2::getContext();
   1904 
   1905 	if(context)
   1906 	{
   1907 		if(index >= es2::MAX_VERTEX_ATTRIBS)
   1908 		{
   1909 			return error(GL_INVALID_VALUE);
   1910 		}
   1911 
   1912 		const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
   1913 
   1914 		switch(pname)
   1915 		{
   1916 		case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
   1917 			*params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
   1918 			break;
   1919 		case GL_VERTEX_ATTRIB_ARRAY_SIZE:
   1920 			*params = attribState.mSize;
   1921 			break;
   1922 		case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
   1923 			*params = attribState.mStride;
   1924 			break;
   1925 		case GL_VERTEX_ATTRIB_ARRAY_TYPE:
   1926 			*params = attribState.mType;
   1927 			break;
   1928 		case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
   1929 			*params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
   1930 			break;
   1931 		case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
   1932 			*params = attribState.mBoundBuffer.name();
   1933 			break;
   1934 		case GL_CURRENT_VERTEX_ATTRIB:
   1935 			{
   1936 				const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
   1937 				for(int i = 0; i < 4; ++i)
   1938 				{
   1939 					params[i] = attrib.getCurrentValueUI(i);
   1940 				}
   1941 			}
   1942 			break;
   1943 		case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
   1944 			*params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
   1945 			break;
   1946 		case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
   1947 			*params = attribState.mDivisor;
   1948 			break;
   1949 		default: return error(GL_INVALID_ENUM);
   1950 		}
   1951 	}
   1952 }
   1953 
   1954 GL_APICALL void GL_APIENTRY glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
   1955 {
   1956 	TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
   1957 	      index, x, y, z, w);
   1958 
   1959 	if(index >= es2::MAX_VERTEX_ATTRIBS)
   1960 	{
   1961 		return error(GL_INVALID_VALUE);
   1962 	}
   1963 
   1964 	es2::Context *context = es2::getContext();
   1965 
   1966 	if(context)
   1967 	{
   1968 		GLint vals[4] = { x, y, z, w };
   1969 		context->setVertexAttrib(index, vals);
   1970 	}
   1971 }
   1972 
   1973 GL_APICALL void GL_APIENTRY glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
   1974 {
   1975 	TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
   1976 	      index, x, y, z, w);
   1977 
   1978 	if(index >= es2::MAX_VERTEX_ATTRIBS)
   1979 	{
   1980 		return error(GL_INVALID_VALUE);
   1981 	}
   1982 
   1983 	es2::Context *context = es2::getContext();
   1984 
   1985 	if(context)
   1986 	{
   1987 		GLuint vals[4] = { x, y, z, w };
   1988 		context->setVertexAttrib(index, vals);
   1989 	}
   1990 }
   1991 
   1992 GL_APICALL void GL_APIENTRY glVertexAttribI4iv(GLuint index, const GLint *v)
   1993 {
   1994 	TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
   1995 
   1996 	if(index >= es2::MAX_VERTEX_ATTRIBS)
   1997 	{
   1998 		return error(GL_INVALID_VALUE);
   1999 	}
   2000 
   2001 	es2::Context *context = es2::getContext();
   2002 
   2003 	if(context)
   2004 	{
   2005 		context->setVertexAttrib(index, v);
   2006 	}
   2007 }
   2008 
   2009 GL_APICALL void GL_APIENTRY glVertexAttribI4uiv(GLuint index, const GLuint *v)
   2010 {
   2011 	TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
   2012 
   2013 	if(index >= es2::MAX_VERTEX_ATTRIBS)
   2014 	{
   2015 		return error(GL_INVALID_VALUE);
   2016 	}
   2017 
   2018 	es2::Context *context = es2::getContext();
   2019 
   2020 	if(context)
   2021 	{
   2022 		context->setVertexAttrib(index, v);
   2023 	}
   2024 }
   2025 
   2026 GL_APICALL void GL_APIENTRY glGetUniformuiv(GLuint program, GLint location, GLuint *params)
   2027 {
   2028 	TRACE("(GLuint program = %d, GLint location = %d, GLuint *params = %p)",
   2029 	      program, location, params);
   2030 
   2031 	es2::Context *context = es2::getContext();
   2032 
   2033 	if(context)
   2034 	{
   2035 		es2::Program *programObject = context->getProgram(program);
   2036 
   2037 		if(!programObject)
   2038 		{
   2039 			if(context->getShader(program))
   2040 			{
   2041 				return error(GL_INVALID_OPERATION);
   2042 			}
   2043 			else
   2044 			{
   2045 				return error(GL_INVALID_VALUE);
   2046 			}
   2047 		}
   2048 
   2049 		if(!programObject->isLinked())
   2050 		{
   2051 			return error(GL_INVALID_OPERATION);
   2052 		}
   2053 
   2054 		if(!programObject->getUniformuiv(location, nullptr, params))
   2055 		{
   2056 			return error(GL_INVALID_OPERATION);
   2057 		}
   2058 	}
   2059 }
   2060 
   2061 GL_APICALL GLint GL_APIENTRY glGetFragDataLocation(GLuint program, const GLchar *name)
   2062 {
   2063 	TRACE("(GLuint program = %d, const GLchar *name = %p)", program, name);
   2064 
   2065 	es2::Context *context = es2::getContext();
   2066 
   2067 	if(context)
   2068 	{
   2069 		es2::Program *programObject = context->getProgram(program);
   2070 
   2071 		if(!programObject)
   2072 		{
   2073 			if(context->getShader(program))
   2074 			{
   2075 				return error(GL_INVALID_OPERATION, -1);
   2076 			}
   2077 			else
   2078 			{
   2079 				return error(GL_INVALID_VALUE, -1);
   2080 			}
   2081 		}
   2082 
   2083 		if(!programObject->isLinked())
   2084 		{
   2085 			return error(GL_INVALID_OPERATION, -1);
   2086 		}
   2087 
   2088 		return programObject->getFragDataLocation(name);
   2089 	}
   2090 
   2091 	return -1;
   2092 }
   2093 
   2094 GL_APICALL void GL_APIENTRY glUniform1ui(GLint location, GLuint v0)
   2095 {
   2096 	glUniform1uiv(location, 1, &v0);
   2097 }
   2098 
   2099 GL_APICALL void GL_APIENTRY glUniform2ui(GLint location, GLuint v0, GLuint v1)
   2100 {
   2101 	GLuint xy[2] = { v0, v1 };
   2102 
   2103 	glUniform2uiv(location, 1, (GLuint*)&xy);
   2104 }
   2105 
   2106 GL_APICALL void GL_APIENTRY glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
   2107 {
   2108 	GLuint xyz[3] = { v0, v1, v2 };
   2109 
   2110 	glUniform3uiv(location, 1, (GLuint*)&xyz);
   2111 }
   2112 
   2113 GL_APICALL void GL_APIENTRY glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
   2114 {
   2115 	GLuint xyzw[4] = { v0, v1, v2, v3 };
   2116 
   2117 	glUniform4uiv(location, 1, (GLuint*)&xyzw);
   2118 }
   2119 
   2120 GL_APICALL void GL_APIENTRY glUniform1uiv(GLint location, GLsizei count, const GLuint *value)
   2121 {
   2122 	TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
   2123 	      location, count, value);
   2124 
   2125 	if(count < 0)
   2126 	{
   2127 		return error(GL_INVALID_VALUE);
   2128 	}
   2129 
   2130 	es2::Context *context = es2::getContext();
   2131 
   2132 	if(context)
   2133 	{
   2134 		es2::Program *program = context->getCurrentProgram();
   2135 
   2136 		if(!program)
   2137 		{
   2138 			return error(GL_INVALID_OPERATION);
   2139 		}
   2140 
   2141 		if(location == -1)
   2142 		{
   2143 			return;
   2144 		}
   2145 
   2146 		if(!program->setUniform1uiv(location, count, value))
   2147 		{
   2148 			return error(GL_INVALID_OPERATION);
   2149 		}
   2150 	}
   2151 }
   2152 
   2153 GL_APICALL void GL_APIENTRY glUniform2uiv(GLint location, GLsizei count, const GLuint *value)
   2154 {
   2155 	TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
   2156 	      location, count, value);
   2157 
   2158 	if(count < 0)
   2159 	{
   2160 		return error(GL_INVALID_VALUE);
   2161 	}
   2162 
   2163 	es2::Context *context = es2::getContext();
   2164 
   2165 	if(context)
   2166 	{
   2167 		es2::Program *program = context->getCurrentProgram();
   2168 
   2169 		if(!program)
   2170 		{
   2171 			return error(GL_INVALID_OPERATION);
   2172 		}
   2173 
   2174 		if(location == -1)
   2175 		{
   2176 			return;
   2177 		}
   2178 
   2179 		if(!program->setUniform2uiv(location, count, value))
   2180 		{
   2181 			return error(GL_INVALID_OPERATION);
   2182 		}
   2183 	}
   2184 }
   2185 
   2186 GL_APICALL void GL_APIENTRY glUniform3uiv(GLint location, GLsizei count, const GLuint *value)
   2187 {
   2188 	TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
   2189 	      location, count, value);
   2190 
   2191 	if(count < 0)
   2192 	{
   2193 		return error(GL_INVALID_VALUE);
   2194 	}
   2195 
   2196 	es2::Context *context = es2::getContext();
   2197 
   2198 	if(context)
   2199 	{
   2200 		es2::Program *program = context->getCurrentProgram();
   2201 
   2202 		if(!program)
   2203 		{
   2204 			return error(GL_INVALID_OPERATION);
   2205 		}
   2206 
   2207 		if(location == -1)
   2208 		{
   2209 			return;
   2210 		}
   2211 
   2212 		if(!program->setUniform3uiv(location, count, value))
   2213 		{
   2214 			return error(GL_INVALID_OPERATION);
   2215 		}
   2216 	}
   2217 }
   2218 
   2219 GL_APICALL void GL_APIENTRY glUniform4uiv(GLint location, GLsizei count, const GLuint *value)
   2220 {
   2221 	TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
   2222 	      location, count, value);
   2223 
   2224 	if(count < 0)
   2225 	{
   2226 		return error(GL_INVALID_VALUE);
   2227 	}
   2228 
   2229 	es2::Context *context = es2::getContext();
   2230 
   2231 	if(context)
   2232 	{
   2233 		es2::Program *program = context->getCurrentProgram();
   2234 
   2235 		if(!program)
   2236 		{
   2237 			return error(GL_INVALID_OPERATION);
   2238 		}
   2239 
   2240 		if(location == -1)
   2241 		{
   2242 			return;
   2243 		}
   2244 
   2245 		if(!program->setUniform4uiv(location, count, value))
   2246 		{
   2247 			return error(GL_INVALID_OPERATION);
   2248 		}
   2249 	}
   2250 }
   2251 
   2252 GL_APICALL void GL_APIENTRY glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
   2253 {
   2254 	TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint *value = %p)",
   2255 	      buffer, drawbuffer, value);
   2256 
   2257 	es2::Context *context = es2::getContext();
   2258 
   2259 	if(context)
   2260 	{
   2261 		switch(buffer)
   2262 		{
   2263 		case GL_COLOR:
   2264 			if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
   2265 			{
   2266 				return error(GL_INVALID_VALUE);
   2267 			}
   2268 			else
   2269 			{
   2270 				context->clearColorBuffer(drawbuffer, value);
   2271 			}
   2272 			break;
   2273 		case GL_STENCIL:
   2274 			if(drawbuffer != 0)
   2275 			{
   2276 				return error(GL_INVALID_VALUE);
   2277 			}
   2278 			else
   2279 			{
   2280 				context->clearStencilBuffer(value[0]);
   2281 			}
   2282 			break;
   2283 		default:
   2284 			return error(GL_INVALID_ENUM);
   2285 		}
   2286 	}
   2287 }
   2288 
   2289 GL_APICALL void GL_APIENTRY glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
   2290 {
   2291 	TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint *value = %p)",
   2292 	      buffer, drawbuffer, value);
   2293 
   2294 	es2::Context *context = es2::getContext();
   2295 
   2296 	if(context)
   2297 	{
   2298 		switch(buffer)
   2299 		{
   2300 		case GL_COLOR:
   2301 			if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
   2302 			{
   2303 				return error(GL_INVALID_VALUE);
   2304 			}
   2305 			else
   2306 			{
   2307 				context->clearColorBuffer(drawbuffer, value);
   2308 			}
   2309 			break;
   2310 		default:
   2311 			return error(GL_INVALID_ENUM);
   2312 		}
   2313 	}
   2314 }
   2315 
   2316 GL_APICALL void GL_APIENTRY glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
   2317 {
   2318 	TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat *value = %p)",
   2319 	      buffer, drawbuffer, value);
   2320 
   2321 	es2::Context *context = es2::getContext();
   2322 
   2323 	if(context)
   2324 	{
   2325 		switch(buffer)
   2326 		{
   2327 		case GL_COLOR:
   2328 			if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
   2329 			{
   2330 				return error(GL_INVALID_VALUE);
   2331 			}
   2332 			else
   2333 			{
   2334 				context->clearColorBuffer(drawbuffer, value);
   2335 			}
   2336 			break;
   2337 		case GL_DEPTH:
   2338 			if(drawbuffer != 0)
   2339 			{
   2340 				return error(GL_INVALID_VALUE);
   2341 			}
   2342 			else
   2343 			{
   2344 				context->clearDepthBuffer(value[0]);
   2345 			}
   2346 			break;
   2347 		default:
   2348 			return error(GL_INVALID_ENUM);
   2349 		}
   2350 	}
   2351 }
   2352 
   2353 GL_APICALL void GL_APIENTRY glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
   2354 {
   2355 	TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth = %f, GLint stencil = %d)",
   2356 	      buffer, drawbuffer, depth, stencil);
   2357 
   2358 	es2::Context *context = es2::getContext();
   2359 
   2360 	if(context)
   2361 	{
   2362 		switch(buffer)
   2363 		{
   2364 		case GL_DEPTH_STENCIL:
   2365 			if(drawbuffer != 0)
   2366 			{
   2367 				return error(GL_INVALID_VALUE);
   2368 			}
   2369 			else
   2370 			{
   2371 				context->clearDepthBuffer(depth);
   2372 				context->clearStencilBuffer(stencil);
   2373 			}
   2374 			break;
   2375 		default:
   2376 			return error(GL_INVALID_ENUM);
   2377 		}
   2378 	}
   2379 }
   2380 
   2381 GL_APICALL const GLubyte *GL_APIENTRY glGetStringi(GLenum name, GLuint index)
   2382 {
   2383 	TRACE("(GLenum name = 0x%X, GLuint index = %d)", name, index);
   2384 
   2385 	es2::Context *context = es2::getContext();
   2386 	if(context)
   2387 	{
   2388 		GLuint numExtensions;
   2389 		context->getExtensions(0, &numExtensions);
   2390 
   2391 		if(index >= numExtensions)
   2392 		{
   2393 			return error(GL_INVALID_VALUE, (GLubyte*)nullptr);
   2394 		}
   2395 
   2396 		switch(name)
   2397 		{
   2398 		case GL_EXTENSIONS:
   2399 			return context->getExtensions(index);
   2400 		default:
   2401 			return error(GL_INVALID_ENUM, (GLubyte*)nullptr);
   2402 		}
   2403 	}
   2404 
   2405 	return (GLubyte*)nullptr;
   2406 }
   2407 
   2408 GL_APICALL void GL_APIENTRY glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
   2409 {
   2410 	TRACE("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X,  GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)",
   2411 	      readTarget, writeTarget, readOffset, writeOffset, size);
   2412 
   2413 	if(readOffset < 0 || writeOffset < 0 || size < 0)
   2414 	{
   2415 		return error(GL_INVALID_VALUE);
   2416 	}
   2417 
   2418 	es2::Context *context = es2::getContext();
   2419 
   2420 	if(context)
   2421 	{
   2422 		es2::Buffer *readBuffer = nullptr, *writeBuffer = nullptr;
   2423 		if(!context->getBuffer(readTarget, &readBuffer) || !context->getBuffer(writeTarget, &writeBuffer))
   2424 		{
   2425 			return error(GL_INVALID_ENUM);
   2426 		}
   2427 		if(!readBuffer || readBuffer->isMapped() || !writeBuffer || writeBuffer->isMapped())
   2428 		{
   2429 			return error(GL_INVALID_OPERATION);
   2430 		}
   2431 		if(readBuffer == writeBuffer)
   2432 		{
   2433 			// If same buffer, check for overlap
   2434 			if(((readOffset >= writeOffset) && (readOffset < (writeOffset + size))) ||
   2435 			   ((writeOffset >= readOffset) && (writeOffset < (readOffset + size))))
   2436 			{
   2437 				return error(GL_INVALID_VALUE);
   2438 			}
   2439 		}
   2440 
   2441 		if((static_cast<size_t>(readOffset + size) > readBuffer->size()) ||
   2442 		   (static_cast<size_t>(writeOffset + size) > writeBuffer->size()))
   2443 		{
   2444 			return error(GL_INVALID_VALUE);
   2445 		}
   2446 
   2447 		writeBuffer->bufferSubData(((char*)readBuffer->data()) + readOffset, size, writeOffset);
   2448 	}
   2449 }
   2450 
   2451 GL_APICALL void GL_APIENTRY glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices)
   2452 {
   2453 	TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLuint *uniformIndices = %p)",
   2454 	      program, uniformCount, uniformNames, uniformIndices);
   2455 
   2456 	if(uniformCount < 0)
   2457 	{
   2458 		return error(GL_INVALID_VALUE);
   2459 	}
   2460 
   2461 	es2::Context *context = es2::getContext();
   2462 
   2463 	if(context)
   2464 	{
   2465 		es2::Program *programObject = context->getProgram(program);
   2466 
   2467 		if(!programObject)
   2468 		{
   2469 			if(context->getShader(program))
   2470 			{
   2471 				return error(GL_INVALID_OPERATION);
   2472 			}
   2473 			else
   2474 			{
   2475 				return error(GL_INVALID_VALUE);
   2476 			}
   2477 		}
   2478 
   2479 		if(!programObject->isLinked())
   2480 		{
   2481 			for(int uniformId = 0; uniformId < uniformCount; uniformId++)
   2482 			{
   2483 				uniformIndices[uniformId] = GL_INVALID_INDEX;
   2484 			}
   2485 		}
   2486 		else
   2487 		{
   2488 			for(int uniformId = 0; uniformId < uniformCount; uniformId++)
   2489 			{
   2490 				uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]);
   2491 			}
   2492 		}
   2493 	}
   2494 }
   2495 
   2496 GL_APICALL void GL_APIENTRY glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params)
   2497 {
   2498 	TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLenum pname = 0x%X, GLuint *uniformIndices = %p)",
   2499 	      program, uniformCount, uniformIndices, pname, uniformIndices);
   2500 
   2501 	switch(pname)
   2502 	{
   2503 	case GL_UNIFORM_TYPE:
   2504 	case GL_UNIFORM_SIZE:
   2505 	case GL_UNIFORM_NAME_LENGTH:
   2506 	case GL_UNIFORM_BLOCK_INDEX:
   2507 	case GL_UNIFORM_OFFSET:
   2508 	case GL_UNIFORM_ARRAY_STRIDE:
   2509 	case GL_UNIFORM_MATRIX_STRIDE:
   2510 	case GL_UNIFORM_IS_ROW_MAJOR:
   2511 		break;
   2512 	default:
   2513 		return error(GL_INVALID_ENUM);
   2514 	}
   2515 
   2516 	if(uniformCount < 0)
   2517 	{
   2518 		return error(GL_INVALID_VALUE);
   2519 	}
   2520 
   2521 	es2::Context *context = es2::getContext();
   2522 
   2523 	if(context)
   2524 	{
   2525 		es2::Program *programObject = context->getProgram(program);
   2526 
   2527 		if(!programObject)
   2528 		{
   2529 			if(context->getShader(program))
   2530 			{
   2531 				return error(GL_INVALID_OPERATION);
   2532 			}
   2533 			else
   2534 			{
   2535 				return error(GL_INVALID_VALUE);
   2536 			}
   2537 		}
   2538 
   2539 		for(int uniformId = 0; uniformId < uniformCount; uniformId++)
   2540 		{
   2541 			const GLuint index = uniformIndices[uniformId];
   2542 
   2543 			if(index >= programObject->getActiveUniformCount())
   2544 			{
   2545 				return error(GL_INVALID_VALUE);
   2546 			}
   2547 		}
   2548 
   2549 		for(int uniformId = 0; uniformId < uniformCount; uniformId++)
   2550 		{
   2551 			const GLuint index = uniformIndices[uniformId];
   2552 			params[uniformId] = programObject->getActiveUniformi(index, pname);
   2553 		}
   2554 	}
   2555 }
   2556 
   2557 GL_APICALL GLuint GL_APIENTRY glGetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName)
   2558 {
   2559 	TRACE("(GLuint program = %d, const GLchar *uniformBlockName = %p)",
   2560 	      program, uniformBlockName);
   2561 
   2562 	es2::Context *context = es2::getContext();
   2563 
   2564 	if(context)
   2565 	{
   2566 		es2::Program *programObject = context->getProgram(program);
   2567 
   2568 		if(!programObject)
   2569 		{
   2570 			if(context->getShader(program))
   2571 			{
   2572 				return error(GL_INVALID_OPERATION, GL_INVALID_INDEX);
   2573 			}
   2574 			else
   2575 			{
   2576 				return error(GL_INVALID_VALUE, GL_INVALID_INDEX);
   2577 			}
   2578 		}
   2579 
   2580 		return programObject->getUniformBlockIndex(uniformBlockName);
   2581 	}
   2582 
   2583 	return GL_INVALID_INDEX;
   2584 }
   2585 
   2586 GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params)
   2587 {
   2588 	TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLenum pname = 0x%X, GLint *params = %p)",
   2589 	      program, uniformBlockIndex, pname, params);
   2590 
   2591 	es2::Context *context = es2::getContext();
   2592 
   2593 	if(context)
   2594 	{
   2595 		es2::Program *programObject = context->getProgram(program);
   2596 
   2597 		if(!programObject)
   2598 		{
   2599 			return error(GL_INVALID_OPERATION);
   2600 		}
   2601 
   2602 		switch(pname)
   2603 		{
   2604 		case GL_UNIFORM_BLOCK_BINDING:
   2605 			*params = static_cast<GLint>(programObject->getUniformBlockBinding(uniformBlockIndex));
   2606 			break;
   2607 		case GL_UNIFORM_BLOCK_DATA_SIZE:
   2608 		case GL_UNIFORM_BLOCK_NAME_LENGTH:
   2609 		case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
   2610 		case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
   2611 		case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
   2612 		case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
   2613 			programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
   2614 			break;
   2615 		default:
   2616 			return error(GL_INVALID_ENUM);
   2617 		}
   2618 	}
   2619 }
   2620 
   2621 GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName)
   2622 {
   2623 	TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLchar *uniformBlockName = %p)",
   2624 	      program, uniformBlockIndex, bufSize, length, uniformBlockName);
   2625 
   2626 	if(bufSize < 0)
   2627 	{
   2628 		return error(GL_INVALID_VALUE);
   2629 	}
   2630 
   2631 	es2::Context *context = es2::getContext();
   2632 
   2633 	if(context)
   2634 	{
   2635 		es2::Program *programObject = context->getProgram(program);
   2636 
   2637 		if(!programObject)
   2638 		{
   2639 			return error(GL_INVALID_OPERATION);
   2640 		}
   2641 
   2642 		programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
   2643 	}
   2644 }
   2645 
   2646 GL_APICALL void GL_APIENTRY glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
   2647 {
   2648 	TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLuint uniformBlockBinding = %d)",
   2649 	      program, uniformBlockIndex, uniformBlockBinding);
   2650 
   2651 	if(uniformBlockBinding >= MAX_UNIFORM_BUFFER_BINDINGS)
   2652 	{
   2653 		return error(GL_INVALID_VALUE);
   2654 	}
   2655 
   2656 	es2::Context *context = es2::getContext();
   2657 
   2658 	if(context)
   2659 	{
   2660 		es2::Program *programObject = context->getProgram(program);
   2661 
   2662 		if(!programObject)
   2663 		{
   2664 			return error(GL_INVALID_VALUE);
   2665 		}
   2666 
   2667 		programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding);
   2668 	}
   2669 }
   2670 
   2671 GL_APICALL void GL_APIENTRY glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
   2672 {
   2673 	TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
   2674 	      mode, first, count, instanceCount);
   2675 
   2676 	switch(mode)
   2677 	{
   2678 	case GL_POINTS:
   2679 	case GL_LINES:
   2680 	case GL_LINE_LOOP:
   2681 	case GL_LINE_STRIP:
   2682 	case GL_TRIANGLES:
   2683 	case GL_TRIANGLE_FAN:
   2684 	case GL_TRIANGLE_STRIP:
   2685 		break;
   2686 	default:
   2687 		return error(GL_INVALID_ENUM);
   2688 	}
   2689 
   2690 	if(count < 0 || instanceCount < 0)
   2691 	{
   2692 		return error(GL_INVALID_VALUE);
   2693 	}
   2694 
   2695 	es2::Context *context = es2::getContext();
   2696 
   2697 	if(context)
   2698 	{
   2699 		es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
   2700 		if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
   2701 		{
   2702 			return error(GL_INVALID_OPERATION);
   2703 		}
   2704 
   2705 		context->drawArrays(mode, first, count, instanceCount);
   2706 	}
   2707 }
   2708 
   2709 GL_APICALL void GL_APIENTRY glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
   2710 {
   2711 	TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = %p, GLsizei instanceCount = %d)",
   2712 	      mode, count, type, indices, instanceCount);
   2713 
   2714 	switch(mode)
   2715 	{
   2716 	case GL_POINTS:
   2717 	case GL_LINES:
   2718 	case GL_LINE_LOOP:
   2719 	case GL_LINE_STRIP:
   2720 	case GL_TRIANGLES:
   2721 	case GL_TRIANGLE_FAN:
   2722 	case GL_TRIANGLE_STRIP:
   2723 		break;
   2724 	default:
   2725 		return error(GL_INVALID_ENUM);
   2726 	}
   2727 
   2728 	switch(type)
   2729 	{
   2730 	case GL_UNSIGNED_BYTE:
   2731 	case GL_UNSIGNED_SHORT:
   2732 	case GL_UNSIGNED_INT:
   2733 		break;
   2734 	default:
   2735 		return error(GL_INVALID_ENUM);
   2736 	}
   2737 
   2738 	if(count < 0 || instanceCount < 0)
   2739 	{
   2740 		return error(GL_INVALID_VALUE);
   2741 	}
   2742 
   2743 	es2::Context *context = es2::getContext();
   2744 
   2745 	if(context)
   2746 	{
   2747 		es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
   2748 		if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
   2749 		{
   2750 			return error(GL_INVALID_OPERATION);
   2751 		}
   2752 
   2753 		context->drawElements(mode, 0, MAX_ELEMENT_INDEX, count, type, indices, instanceCount);
   2754 	}
   2755 }
   2756 
   2757 GL_APICALL GLsync GL_APIENTRY glFenceSync(GLenum condition, GLbitfield flags)
   2758 {
   2759 	TRACE("(GLenum condition = 0x%X, GLbitfield flags = %X)", condition, flags);
   2760 
   2761 	switch(condition)
   2762 	{
   2763 	case GL_SYNC_GPU_COMMANDS_COMPLETE:
   2764 		break;
   2765 	default:
   2766 		return error(GL_INVALID_ENUM, nullptr);
   2767 	}
   2768 
   2769 	if(flags != 0)
   2770 	{
   2771 		return error(GL_INVALID_VALUE, nullptr);
   2772 	}
   2773 
   2774 	es2::Context *context = es2::getContext();
   2775 
   2776 	if(context)
   2777 	{
   2778 		return context->createFenceSync(condition, flags);
   2779 	}
   2780 
   2781 	return nullptr;
   2782 }
   2783 
   2784 GL_APICALL GLboolean GL_APIENTRY glIsSync(GLsync sync)
   2785 {
   2786 	TRACE("(GLsync sync = %p)", sync);
   2787 
   2788 	es2::Context *context = es2::getContext();
   2789 
   2790 	if(context)
   2791 	{
   2792 		es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
   2793 
   2794 		if(fenceSyncObject)
   2795 		{
   2796 			return GL_TRUE;
   2797 		}
   2798 	}
   2799 
   2800 	return GL_FALSE;
   2801 }
   2802 
   2803 GL_APICALL void GL_APIENTRY glDeleteSync(GLsync sync)
   2804 {
   2805 	TRACE("(GLsync sync = %p)", sync);
   2806 
   2807 	if(!sync)
   2808 	{
   2809 		return;
   2810 	}
   2811 
   2812 	es2::Context *context = es2::getContext();
   2813 
   2814 	if(context)
   2815 	{
   2816 		if(!context->getFenceSync(sync))
   2817 		{
   2818 			return error(GL_INVALID_VALUE);
   2819 		}
   2820 
   2821 		context->deleteFenceSync(sync);
   2822 	}
   2823 }
   2824 
   2825 GL_APICALL GLenum GL_APIENTRY glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
   2826 {
   2827 	TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
   2828 
   2829 	if((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0)
   2830 	{
   2831 		return error(GL_INVALID_VALUE, GL_FALSE);
   2832 	}
   2833 
   2834 	es2::Context *context = es2::getContext();
   2835 
   2836 	if(context)
   2837 	{
   2838 		es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
   2839 
   2840 		if(fenceSyncObject)
   2841 		{
   2842 			return fenceSyncObject->clientWait(flags, timeout);
   2843 		}
   2844 		else
   2845 		{
   2846 			return error(GL_INVALID_VALUE, GL_FALSE);
   2847 		}
   2848 	}
   2849 
   2850 	return GL_FALSE;
   2851 }
   2852 
   2853 GL_APICALL void GL_APIENTRY glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
   2854 {
   2855 	TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
   2856 
   2857 	if(flags != 0)
   2858 	{
   2859 		return error(GL_INVALID_VALUE);
   2860 	}
   2861 
   2862 	if(timeout != GL_TIMEOUT_IGNORED)
   2863 	{
   2864 		return error(GL_INVALID_VALUE);
   2865 	}
   2866 
   2867 	es2::Context *context = es2::getContext();
   2868 
   2869 	if(context)
   2870 	{
   2871 		es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
   2872 
   2873 		if(fenceSyncObject)
   2874 		{
   2875 			fenceSyncObject->serverWait(flags, timeout);
   2876 		}
   2877 		else
   2878 		{
   2879 			return error(GL_INVALID_VALUE);
   2880 		}
   2881 	}
   2882 }
   2883 
   2884 GL_APICALL void GL_APIENTRY glGetInteger64v(GLenum pname, GLint64 *data)
   2885 {
   2886 	TRACE("(GLenum pname = 0x%X, GLint64 *data = %p)", pname, data);
   2887 
   2888 	es2::Context *context = es2::getContext();
   2889 
   2890 	if(context)
   2891 	{
   2892 		if(!(context->getIntegerv(pname, data)))
   2893 		{
   2894 			GLenum nativeType;
   2895 			unsigned int numParams = 0;
   2896 			if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))
   2897 				return error(GL_INVALID_ENUM);
   2898 
   2899 			if(numParams == 0)
   2900 				return; // it is known that pname is valid, but there are no parameters to return
   2901 
   2902 			if(nativeType == GL_BOOL)
   2903 			{
   2904 				GLboolean *boolParams = nullptr;
   2905 				boolParams = new GLboolean[numParams];
   2906 
   2907 				context->getBooleanv(pname, boolParams);
   2908 
   2909 				for(unsigned int i = 0; i < numParams; ++i)
   2910 				{
   2911 					data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
   2912 				}
   2913 
   2914 				delete[] boolParams;
   2915 			}
   2916 			else if(nativeType == GL_FLOAT)
   2917 			{
   2918 				GLfloat *floatParams = nullptr;
   2919 				floatParams = new GLfloat[numParams];
   2920 
   2921 				context->getFloatv(pname, floatParams);
   2922 
   2923 				for(unsigned int i = 0; i < numParams; ++i)
   2924 				{
   2925 					if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
   2926 					{
   2927 						data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
   2928 					}
   2929 					else
   2930 					{
   2931 						data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
   2932 					}
   2933 				}
   2934 
   2935 				delete[] floatParams;
   2936 			}
   2937 		}
   2938 	}
   2939 }
   2940 
   2941 GL_APICALL void GL_APIENTRY glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
   2942 {
   2943 	TRACE("(GLsync sync = %p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei *length = %p, GLint *values = %p)",
   2944 	      sync, pname, bufSize, length, values);
   2945 
   2946 	if(bufSize < 0)
   2947 	{
   2948 		return error(GL_INVALID_VALUE);
   2949 	}
   2950 
   2951 	es2::Context *context = es2::getContext();
   2952 
   2953 	if(context)
   2954 	{
   2955 		es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
   2956 		if(!fenceSyncObject)
   2957 		{
   2958 			return error(GL_INVALID_VALUE);
   2959 		}
   2960 
   2961 		fenceSyncObject->getSynciv(pname, length, values);
   2962 	}
   2963 }
   2964 
   2965 GL_APICALL void GL_APIENTRY glGetInteger64i_v(GLenum target, GLuint index, GLint64 *data)
   2966 {
   2967 	TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint64 *data = %p)", target, index, data);
   2968 
   2969 	es2::Context *context = es2::getContext();
   2970 
   2971 	if(context)
   2972 	{
   2973 		if(!context->getTransformFeedbackiv(index, target, data) &&
   2974 		   !context->getUniformBufferiv(index, target, data) &&
   2975 		   !context->getIntegerv(target, data))
   2976 		{
   2977 			GLenum nativeType;
   2978 			unsigned int numParams = 0;
   2979 			if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
   2980 				return error(GL_INVALID_ENUM);
   2981 
   2982 			if(numParams == 0)
   2983 				return; // it is known that target is valid, but there are no parameters to return
   2984 
   2985 			if(nativeType == GL_BOOL)
   2986 			{
   2987 				GLboolean *boolParams = nullptr;
   2988 				boolParams = new GLboolean[numParams];
   2989 
   2990 				context->getBooleanv(target, boolParams);
   2991 
   2992 				for(unsigned int i = 0; i < numParams; ++i)
   2993 				{
   2994 					data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
   2995 				}
   2996 
   2997 				delete[] boolParams;
   2998 			}
   2999 			else if(nativeType == GL_FLOAT)
   3000 			{
   3001 				GLfloat *floatParams = nullptr;
   3002 				floatParams = new GLfloat[numParams];
   3003 
   3004 				context->getFloatv(target, floatParams);
   3005 
   3006 				for(unsigned int i = 0; i < numParams; ++i)
   3007 				{
   3008 					if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
   3009 					{
   3010 						data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
   3011 					}
   3012 					else
   3013 					{
   3014 						data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
   3015 					}
   3016 				}
   3017 
   3018 				delete[] floatParams;
   3019 			}
   3020 		}
   3021 	}
   3022 }
   3023 
   3024 GL_APICALL void GL_APIENTRY glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
   3025 {
   3026 	TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64 *params = %p)", target, pname, params);
   3027 
   3028 	es2::Context *context = es2::getContext();
   3029 
   3030 	if(context)
   3031 	{
   3032 		es2::Buffer *buffer = nullptr;
   3033 
   3034 		if(!context->getBuffer(target, &buffer))
   3035 		{
   3036 			return error(GL_INVALID_ENUM);
   3037 		}
   3038 
   3039 		if(!buffer)
   3040 		{
   3041 			// A null buffer means that "0" is bound to the requested buffer target
   3042 			return error(GL_INVALID_OPERATION);
   3043 		}
   3044 
   3045 		switch(pname)
   3046 		{
   3047 		case GL_BUFFER_USAGE:
   3048 			*params = buffer->usage();
   3049 			break;
   3050 		case GL_BUFFER_SIZE:
   3051 			*params = buffer->size();
   3052 			break;
   3053 		case GL_BUFFER_ACCESS_FLAGS:
   3054 			*params = buffer->access();
   3055 			break;
   3056 		case GL_BUFFER_MAPPED:
   3057 			*params = buffer->isMapped();
   3058 			break;
   3059 		case GL_BUFFER_MAP_LENGTH:
   3060 			*params = buffer->length();
   3061 			break;
   3062 		case GL_BUFFER_MAP_OFFSET:
   3063 			*params = buffer->offset();
   3064 			break;
   3065 		default:
   3066 			return error(GL_INVALID_ENUM);
   3067 		}
   3068 	}
   3069 }
   3070 
   3071 GL_APICALL void GL_APIENTRY glGenSamplers(GLsizei count, GLuint *samplers)
   3072 {
   3073 	TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
   3074 
   3075 	if(count < 0)
   3076 	{
   3077 		return error(GL_INVALID_VALUE);
   3078 	}
   3079 
   3080 	es2::Context *context = es2::getContext();
   3081 
   3082 	if(context)
   3083 	{
   3084 		for(int i = 0; i < count; i++)
   3085 		{
   3086 			samplers[i] = context->createSampler();
   3087 		}
   3088 	}
   3089 }
   3090 
   3091 GL_APICALL void GL_APIENTRY glDeleteSamplers(GLsizei count, const GLuint *samplers)
   3092 {
   3093 	TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
   3094 
   3095 	if(count < 0)
   3096 	{
   3097 		return error(GL_INVALID_VALUE);
   3098 	}
   3099 
   3100 	es2::Context *context = es2::getContext();
   3101 
   3102 	if(context)
   3103 	{
   3104 		for(int i = 0; i < count; i++)
   3105 		{
   3106 			context->deleteSampler(samplers[i]);
   3107 		}
   3108 	}
   3109 }
   3110 
   3111 GL_APICALL GLboolean GL_APIENTRY glIsSampler(GLuint sampler)
   3112 {
   3113 	TRACE("(GLuint sampler = %d)", sampler);
   3114 
   3115 	if(sampler == 0)
   3116 	{
   3117 		return GL_FALSE;
   3118 	}
   3119 
   3120 	es2::Context *context = es2::getContext();
   3121 
   3122 	if(context)
   3123 	{
   3124 		if(context->isSampler(sampler))
   3125 		{
   3126 			return GL_TRUE;
   3127 		}
   3128 	}
   3129 
   3130 	return GL_FALSE;
   3131 }
   3132 
   3133 GL_APICALL void GL_APIENTRY glBindSampler(GLuint unit, GLuint sampler)
   3134 {
   3135 	TRACE("(GLuint unit = %d, GLuint sampler = %d)", unit, sampler);
   3136 
   3137 	if(unit >= es2::MAX_COMBINED_TEXTURE_IMAGE_UNITS)
   3138 	{
   3139 		return error(GL_INVALID_VALUE);
   3140 	}
   3141 
   3142 	es2::Context *context = es2::getContext();
   3143 
   3144 	if(context)
   3145 	{
   3146 		if(sampler != 0 && !context->isSampler(sampler))
   3147 		{
   3148 			return error(GL_INVALID_OPERATION);
   3149 		}
   3150 
   3151 		context->bindSampler(unit, sampler);
   3152 	}
   3153 }
   3154 
   3155 GL_APICALL void GL_APIENTRY glSamplerParameteri(GLuint sampler, GLenum pname, GLint param)
   3156 {
   3157 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint param = %d)",
   3158 	      sampler, pname, param);
   3159 
   3160 	glSamplerParameteriv(sampler, pname, &param);
   3161 }
   3162 
   3163 GL_APICALL void GL_APIENTRY glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param)
   3164 {
   3165 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLint *param = %p)",
   3166 	      sampler, pname, param);
   3167 
   3168 	if(!ValidateSamplerObjectParameter(pname))
   3169 	{
   3170 		return error(GL_INVALID_ENUM);
   3171 	}
   3172 
   3173 	if(!ValidateTexParamParameters(pname, *param))
   3174 	{
   3175 		return;
   3176 	}
   3177 
   3178 	es2::Context *context = es2::getContext();
   3179 
   3180 	if(context)
   3181 	{
   3182 		if(!context->isSampler(sampler))
   3183 		{
   3184 			return error(GL_INVALID_OPERATION);
   3185 		}
   3186 
   3187 		context->samplerParameteri(sampler, pname, *param);
   3188 	}
   3189 }
   3190 
   3191 GL_APICALL void GL_APIENTRY glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
   3192 {
   3193 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat param = %f)",
   3194 	      sampler, pname, param);
   3195 
   3196 	glSamplerParameterfv(sampler, pname, &param);
   3197 }
   3198 
   3199 GL_APICALL void GL_APIENTRY glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param)
   3200 {
   3201 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLfloat *param = %p)",
   3202 	      sampler, pname, param);
   3203 
   3204 	if(!ValidateSamplerObjectParameter(pname))
   3205 	{
   3206 		return error(GL_INVALID_ENUM);
   3207 	}
   3208 
   3209 	es2::Context *context = es2::getContext();
   3210 
   3211 	if(context)
   3212 	{
   3213 		if(!context->isSampler(sampler))
   3214 		{
   3215 			return error(GL_INVALID_OPERATION);
   3216 		}
   3217 
   3218 		if(ValidateTexParamParameters(pname, static_cast<GLint>(roundf(*param))))
   3219 		{
   3220 			context->samplerParameterf(sampler, pname, *param);
   3221 		}
   3222 	}
   3223 }
   3224 
   3225 GL_APICALL void GL_APIENTRY glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
   3226 {
   3227 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint *params = %p)",
   3228 	      sampler, pname, params);
   3229 
   3230 	if(!ValidateSamplerObjectParameter(pname))
   3231 	{
   3232 		return error(GL_INVALID_ENUM);
   3233 	}
   3234 
   3235 	es2::Context *context = es2::getContext();
   3236 
   3237 	if(context)
   3238 	{
   3239 		if(!context->isSampler(sampler))
   3240 		{
   3241 			return error(GL_INVALID_OPERATION);
   3242 		}
   3243 
   3244 		*params = context->getSamplerParameteri(sampler, pname);
   3245 	}
   3246 }
   3247 
   3248 GL_APICALL void GL_APIENTRY glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
   3249 {
   3250 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat *params = %p)",
   3251 	      sampler, pname, params);
   3252 
   3253 	if(!ValidateSamplerObjectParameter(pname))
   3254 	{
   3255 		return error(GL_INVALID_ENUM);
   3256 	}
   3257 
   3258 	es2::Context *context = es2::getContext();
   3259 
   3260 	if(context)
   3261 	{
   3262 		if(!context->isSampler(sampler))
   3263 		{
   3264 			return error(GL_INVALID_OPERATION);
   3265 		}
   3266 
   3267 		*params = context->getSamplerParameterf(sampler, pname);
   3268 	}
   3269 }
   3270 
   3271 GL_APICALL void GL_APIENTRY glVertexAttribDivisor(GLuint index, GLuint divisor)
   3272 {
   3273 	TRACE("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
   3274 
   3275 	es2::Context *context = es2::getContext();
   3276 
   3277 	if(context)
   3278 	{
   3279 		if(index >= es2::MAX_VERTEX_ATTRIBS)
   3280 		{
   3281 			return error(GL_INVALID_VALUE);
   3282 		}
   3283 
   3284 		context->setVertexAttribDivisor(index, divisor);
   3285 	}
   3286 }
   3287 
   3288 GL_APICALL void GL_APIENTRY glBindTransformFeedback(GLenum target, GLuint id)
   3289 {
   3290 	TRACE("(GLenum target = 0x%X, GLuint id = %d)", target, id);
   3291 
   3292 	if(target != GL_TRANSFORM_FEEDBACK)
   3293 	{
   3294 		return error(GL_INVALID_ENUM);
   3295 	}
   3296 
   3297 	es2::Context *context = es2::getContext();
   3298 
   3299 	if(context)
   3300 	{
   3301 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
   3302 
   3303 		if(transformFeedbackObject && transformFeedbackObject->isActive() && !transformFeedbackObject->isPaused())
   3304 		{
   3305 			return error(GL_INVALID_OPERATION);
   3306 		}
   3307 
   3308 		if(!context->isTransformFeedback(id))
   3309 		{
   3310 			return error(GL_INVALID_OPERATION);
   3311 		}
   3312 
   3313 		context->bindTransformFeedback(id);
   3314 	}
   3315 }
   3316 
   3317 GL_APICALL void GL_APIENTRY glDeleteTransformFeedbacks(GLsizei n, const GLuint *ids)
   3318 {
   3319 	TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
   3320 
   3321 	if(n < 0)
   3322 	{
   3323 		return error(GL_INVALID_VALUE);
   3324 	}
   3325 
   3326 	es2::Context *context = es2::getContext();
   3327 
   3328 	if(context)
   3329 	{
   3330 		for(int i = 0; i < n; i++)
   3331 		{
   3332 			if(ids[i] != 0)
   3333 			{
   3334 				es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(ids[i]);
   3335 
   3336 				if(transformFeedbackObject && transformFeedbackObject->isActive())
   3337 				{
   3338 					return error(GL_INVALID_OPERATION);
   3339 				}
   3340 
   3341 				context->deleteTransformFeedback(ids[i]);
   3342 			}
   3343 		}
   3344 	}
   3345 }
   3346 
   3347 GL_APICALL void GL_APIENTRY glGenTransformFeedbacks(GLsizei n, GLuint *ids)
   3348 {
   3349 	TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
   3350 
   3351 	if(n < 0)
   3352 	{
   3353 		return error(GL_INVALID_VALUE);
   3354 	}
   3355 
   3356 	es2::Context *context = es2::getContext();
   3357 
   3358 	if(context)
   3359 	{
   3360 		for(int i = 0; i < n; i++)
   3361 		{
   3362 			ids[i] = context->createTransformFeedback();
   3363 		}
   3364 	}
   3365 }
   3366 
   3367 GL_APICALL GLboolean GL_APIENTRY glIsTransformFeedback(GLuint id)
   3368 {
   3369 	TRACE("(GLuint id = %d)", id);
   3370 
   3371 	if(id == 0)
   3372 	{
   3373 		return GL_FALSE;
   3374 	}
   3375 
   3376 	es2::Context *context = es2::getContext();
   3377 
   3378 	if(context)
   3379 	{
   3380 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(id);
   3381 
   3382 		if(transformFeedbackObject)
   3383 		{
   3384 			return GL_TRUE;
   3385 		}
   3386 	}
   3387 
   3388 	return GL_FALSE;
   3389 }
   3390 
   3391 GL_APICALL void GL_APIENTRY glPauseTransformFeedback(void)
   3392 {
   3393 	TRACE("()");
   3394 
   3395 	es2::Context *context = es2::getContext();
   3396 
   3397 	if(context)
   3398 	{
   3399 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
   3400 
   3401 		if(transformFeedbackObject)
   3402 		{
   3403 			if(!transformFeedbackObject->isActive() || transformFeedbackObject->isPaused())
   3404 			{
   3405 				return error(GL_INVALID_OPERATION);
   3406 			}
   3407 			transformFeedbackObject->setPaused(true);
   3408 		}
   3409 	}
   3410 }
   3411 
   3412 GL_APICALL void GL_APIENTRY glResumeTransformFeedback(void)
   3413 {
   3414 	TRACE("()");
   3415 
   3416 	es2::Context *context = es2::getContext();
   3417 
   3418 	if(context)
   3419 	{
   3420 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
   3421 
   3422 		if(transformFeedbackObject)
   3423 		{
   3424 			if(!transformFeedbackObject->isActive() || !transformFeedbackObject->isPaused())
   3425 			{
   3426 				return error(GL_INVALID_OPERATION);
   3427 			}
   3428 			transformFeedbackObject->setPaused(false);
   3429 		}
   3430 	}
   3431 }
   3432 
   3433 GL_APICALL void GL_APIENTRY glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
   3434 {
   3435 	TRACE("(GLuint program = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLenum *binaryFormat = %p, void *binary = %p)",
   3436 	      program, bufSize, length, binaryFormat, binary);
   3437 
   3438 	if(bufSize < 0)
   3439 	{
   3440 		return error(GL_INVALID_VALUE);
   3441 	}
   3442 
   3443 	es2::Context *context = es2::getContext();
   3444 
   3445 	if(context)
   3446 	{
   3447 		es2::Program *programObject = context->getProgram(program);
   3448 
   3449 		if(!programObject || !programObject->isLinked())
   3450 		{
   3451 			return error(GL_INVALID_OPERATION);
   3452 		}
   3453 	}
   3454 
   3455 	// SwiftShader doesn't return a program binary and sets the program binay size to 0, so any attempt at getting one is invalid.
   3456 	return error(GL_INVALID_OPERATION);
   3457 }
   3458 
   3459 GL_APICALL void GL_APIENTRY glProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length)
   3460 {
   3461 	TRACE("(GLuint program = %d, GLenum binaryFormat = 0x%X, const void *binary = %p, GLsizei length = %d)",
   3462 	      program, binaryFormat, binaryFormat, length);
   3463 
   3464 	if(length < 0)
   3465 	{
   3466 		return error(GL_INVALID_VALUE);
   3467 	}
   3468 
   3469 	es2::Context *context = es2::getContext();
   3470 
   3471 	if(context)
   3472 	{
   3473 		es2::Program *programObject = context->getProgram(program);
   3474 
   3475 		if(!programObject)
   3476 		{
   3477 			return error(GL_INVALID_OPERATION);
   3478 		}
   3479 	}
   3480 
   3481 	// Regardless of what the binaryFormat is, it is unrecognized by SwiftShader, since it supports no format.
   3482 	return error(GL_INVALID_ENUM);
   3483 }
   3484 
   3485 GL_APICALL void GL_APIENTRY glProgramParameteri(GLuint program, GLenum pname, GLint value)
   3486 {
   3487 	TRACE("(GLuint program = %d, GLenum pname = 0x%X, GLint value = %d)",
   3488 	      program, pname, value);
   3489 
   3490 	es2::Context *context = es2::getContext();
   3491 
   3492 	if(context)
   3493 	{
   3494 		es2::Program *programObject = context->getProgram(program);
   3495 
   3496 		if(!programObject)
   3497 		{
   3498 			return error(GL_INVALID_VALUE);
   3499 		}
   3500 
   3501 		switch(pname)
   3502 		{
   3503 		case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
   3504 			if((value != GL_TRUE) && (value != GL_FALSE))
   3505 			{
   3506 				return error(GL_INVALID_VALUE);
   3507 			}
   3508 			programObject->setBinaryRetrievable(value != GL_FALSE);
   3509 			break;
   3510 		default:
   3511 			return error(GL_INVALID_ENUM);
   3512 		}
   3513 	}
   3514 }
   3515 
   3516 GL_APICALL void GL_APIENTRY glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
   3517 {
   3518 	TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p)",
   3519 	      target, numAttachments, attachments);
   3520 
   3521 	glInvalidateSubFramebuffer(target, numAttachments, attachments, 0, 0, std::numeric_limits<GLsizei>::max(), std::numeric_limits<GLsizei>::max());
   3522 }
   3523 
   3524 GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
   3525 {
   3526 	TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
   3527 	      target, numAttachments, attachments, x, y, width, height);
   3528 
   3529 	es2::Context *context = es2::getContext();
   3530 
   3531 	if(context)
   3532 	{
   3533 		if(numAttachments < 0 || width < 0 || height < 0)
   3534 		{
   3535 			return error(GL_INVALID_VALUE);
   3536 		}
   3537 
   3538 		es2::Framebuffer *framebuffer = nullptr;
   3539 		switch(target)
   3540 		{
   3541 		case GL_DRAW_FRAMEBUFFER:
   3542 		case GL_FRAMEBUFFER:
   3543 			framebuffer = context->getDrawFramebuffer();
   3544 			break;
   3545 		case GL_READ_FRAMEBUFFER:
   3546 			framebuffer = context->getReadFramebuffer();
   3547 			break;
   3548 		default:
   3549 			return error(GL_INVALID_ENUM);
   3550 		}
   3551 
   3552 		if(framebuffer)
   3553 		{
   3554 			for(int i = 0; i < numAttachments; i++)
   3555 			{
   3556 				switch(attachments[i])
   3557 				{
   3558 				case GL_COLOR:
   3559 				case GL_DEPTH:
   3560 				case GL_STENCIL:
   3561 					if(!framebuffer->isDefaultFramebuffer())
   3562 					{
   3563 						return error(GL_INVALID_ENUM);
   3564 					}
   3565 					break;
   3566 				case GL_DEPTH_ATTACHMENT:
   3567 				case GL_STENCIL_ATTACHMENT:
   3568 				case GL_DEPTH_STENCIL_ATTACHMENT:
   3569 					break;
   3570 				default:
   3571 					if(attachments[i] >= GL_COLOR_ATTACHMENT0 &&
   3572 					   attachments[i] <= GL_COLOR_ATTACHMENT31)
   3573 					{
   3574 						if(attachments[i] - GL_COLOR_ATTACHMENT0 >= MAX_DRAW_BUFFERS)
   3575 						{
   3576 							return error(GL_INVALID_OPERATION);
   3577 						}
   3578 					}
   3579 					else
   3580 					{
   3581 						return error(GL_INVALID_ENUM);
   3582 					}
   3583 					break;
   3584 				}
   3585 			}
   3586 		}
   3587 
   3588 		// UNIMPLEMENTED();   // It is valid for this function to be treated as a no-op
   3589 	}
   3590 }
   3591 
   3592 GL_APICALL void GL_APIENTRY glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
   3593 {
   3594 	TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
   3595 	      target, levels, internalformat, width, height);
   3596 
   3597 	if(width < 1 || height < 1 || levels < 1 || ((target == GL_TEXTURE_RECTANGLE_ARB) && (levels != 1)))
   3598 	{
   3599 		return error(GL_INVALID_VALUE);
   3600 	}
   3601 
   3602 	if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
   3603 	{
   3604 		return error(GL_INVALID_OPERATION);
   3605 	}
   3606 
   3607 	bool isCompressed = IsCompressed(internalformat, egl::getClientVersion());
   3608 	if(!IsSizedInternalFormat(internalformat) && !isCompressed)
   3609 	{
   3610 		return error(GL_INVALID_ENUM);
   3611 	}
   3612 
   3613 	es2::Context *context = es2::getContext();
   3614 
   3615 	if(context)
   3616 	{
   3617 		switch(target)
   3618 		{
   3619 		case GL_TEXTURE_RECTANGLE_ARB:
   3620 			if(isCompressed) // Rectangle textures cannot be compressed
   3621 			{
   3622 				return error(GL_INVALID_ENUM);
   3623 			}
   3624 			// Fall through to GL_TEXTURE_2D case.
   3625 		case GL_TEXTURE_2D:
   3626 			{
   3627 				if((width > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE) ||
   3628 				   (height > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE))
   3629 				{
   3630 					return error(GL_INVALID_VALUE);
   3631 				}
   3632 
   3633 				es2::Texture2D *texture = context->getTexture2D(target);
   3634 				if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
   3635 				{
   3636 					return error(GL_INVALID_OPERATION);
   3637 				}
   3638 
   3639 				for(int level = 0; level < levels; level++)
   3640 				{
   3641 					texture->setImage(level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
   3642 					width = std::max(1, (width / 2));
   3643 					height = std::max(1, (height / 2));
   3644 				}
   3645 				texture->makeImmutable(levels);
   3646 			}
   3647 			break;
   3648 		case GL_TEXTURE_CUBE_MAP:
   3649 			{
   3650 				if((width > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE) ||
   3651 				   (height > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE))
   3652 				{
   3653 					return error(GL_INVALID_VALUE);
   3654 				}
   3655 
   3656 				es2::TextureCubeMap *texture = context->getTextureCubeMap();
   3657 				if(!texture || texture->name == 0 || texture->getImmutableFormat())
   3658 				{
   3659 					return error(GL_INVALID_OPERATION);
   3660 				}
   3661 
   3662 				for(int level = 0; level < levels; level++)
   3663 				{
   3664 					for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
   3665 					{
   3666 						texture->setImage(face, level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
   3667 					}
   3668 					width = std::max(1, (width / 2));
   3669 					height = std::max(1, (height / 2));
   3670 				}
   3671 				texture->makeImmutable(levels);
   3672 			}
   3673 			break;
   3674 		default:
   3675 			return error(GL_INVALID_ENUM);
   3676 		}
   3677 	}
   3678 }
   3679 
   3680 GL_APICALL void GL_APIENTRY glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
   3681 {
   3682 	TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d)",
   3683 	      target, levels, internalformat, width, height, depth);
   3684 
   3685 	if(width < 1 || height < 1 || depth < 1 || levels < 1)
   3686 	{
   3687 		return error(GL_INVALID_VALUE);
   3688 	}
   3689 
   3690 	if(!IsSizedInternalFormat(internalformat) && !IsCompressed(internalformat, egl::getClientVersion()))
   3691 	{
   3692 		return error(GL_INVALID_ENUM);
   3693 	}
   3694 
   3695 	es2::Context *context = es2::getContext();
   3696 
   3697 	if(context)
   3698 	{
   3699 		switch(target)
   3700 		{
   3701 		case GL_TEXTURE_3D:
   3702 			{
   3703 				if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(std::max(width, height), depth)) + 1))
   3704 				{
   3705 					return error(GL_INVALID_OPERATION);
   3706 				}
   3707 
   3708 				es2::Texture3D *texture = context->getTexture3D();
   3709 				if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
   3710 				{
   3711 					return error(GL_INVALID_OPERATION);
   3712 				}
   3713 
   3714 				for(int level = 0; level < levels; level++)
   3715 				{
   3716 					texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
   3717 					width = std::max(1, (width / 2));
   3718 					height = std::max(1, (height / 2));
   3719 					depth = std::max(1, (depth / 2));
   3720 				}
   3721 				texture->makeImmutable(levels);
   3722 			}
   3723 			break;
   3724 		case GL_TEXTURE_2D_ARRAY:
   3725 			{
   3726 				if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
   3727 				{
   3728 					return error(GL_INVALID_OPERATION);
   3729 				}
   3730 
   3731 				es2::Texture3D *texture = context->getTexture2DArray();
   3732 				if(!texture || texture->name == 0 || texture->getImmutableFormat())
   3733 				{
   3734 					return error(GL_INVALID_OPERATION);
   3735 				}
   3736 
   3737 				for(int level = 0; level < levels; level++)
   3738 				{
   3739 					texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
   3740 
   3741 					width = std::max(1, (width / 2));
   3742 					height = std::max(1, (height / 2));
   3743 				}
   3744 				texture->makeImmutable(levels);
   3745 			}
   3746 			break;
   3747 		default:
   3748 			return error(GL_INVALID_ENUM);
   3749 		}
   3750 	}
   3751 }
   3752 
   3753 GL_APICALL void GL_APIENTRY glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params)
   3754 {
   3755 	TRACE("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, GLint *params = %p)",
   3756 	      target, internalformat, pname, bufSize, params);
   3757 
   3758 	if(bufSize < 0)
   3759 	{
   3760 		return error(GL_INVALID_VALUE);
   3761 	}
   3762 
   3763 	if(bufSize == 0)
   3764 	{
   3765 		return;
   3766 	}
   3767 
   3768 	// OpenGL ES 3.0, section 4.4.4: "An internal format is color-renderable if it is one of the formats
   3769 	// from table 3.13 noted as color-renderable or if it is unsized format RGBA or RGB."
   3770 	// Since we only use sized formats internally, replace them here (assuming type = GL_UNSIGNED_BYTE).
   3771 	if(internalformat == GL_RGB)  internalformat = GL_RGB8;
   3772 	if(internalformat == GL_RGBA) internalformat = GL_RGBA8;
   3773 
   3774 	if(!IsColorRenderable(internalformat, egl::getClientVersion()) &&
   3775 	   !IsDepthRenderable(internalformat, egl::getClientVersion()) &&
   3776 	   !IsStencilRenderable(internalformat, egl::getClientVersion()))
   3777 	{
   3778 		return error(GL_INVALID_ENUM);
   3779 	}
   3780 
   3781 	switch(target)
   3782 	{
   3783 	case GL_RENDERBUFFER:
   3784 		break;
   3785 	default:
   3786 		return error(GL_INVALID_ENUM);
   3787 	}
   3788 
   3789 	GLint numMultisampleCounts = NUM_MULTISAMPLE_COUNTS;
   3790 
   3791 	// Integer types have no multisampling
   3792 	GLenum type = GetColorComponentType(internalformat);
   3793 	if(type != GL_UNSIGNED_NORMALIZED && type != GL_FLOAT)
   3794 	{
   3795 		numMultisampleCounts = 0;
   3796 	}
   3797 
   3798 	switch(pname)
   3799 	{
   3800 	case GL_NUM_SAMPLE_COUNTS:
   3801 		*params = numMultisampleCounts;
   3802 		break;
   3803 	case GL_SAMPLES:
   3804 		for(int i = 0; i < numMultisampleCounts && i < bufSize; i++)
   3805 		{
   3806 			params[i] = multisampleCount[i];
   3807 		}
   3808 		break;
   3809 	default:
   3810 		return error(GL_INVALID_ENUM);
   3811 	}
   3812 }
   3813 
   3814 }
   3815