• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
validImageSize(GLint level,GLsizei width,GLsizei height)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 
ValidateQueryTarget(GLenum target)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 
ValidateTexParamParameters(GLenum pname,GLint param)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 
ValidateSamplerObjectParameter(GLenum pname)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 
glReadBuffer(GLenum src)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 
glDrawRangeElements(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const void * indices)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 
glTexImage3D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,const void * data)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 
glTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const void * data)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 
glCopyTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height)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 
glCompressedTexImage3D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLsizei imageSize,const void * data)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 
glCompressedTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLsizei imageSize,const void * data)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 
glGenQueries(GLsizei n,GLuint * ids)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 
glDeleteQueries(GLsizei n,const GLuint * ids)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 
glIsQuery(GLuint id)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 
glBeginQuery(GLenum target,GLuint id)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 
glEndQuery(GLenum target)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 
glGetQueryiv(GLenum target,GLenum pname,GLint * params)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 
glGetQueryObjectuiv(GLuint id,GLenum pname,GLuint * params)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 
glUnmapBuffer(GLenum target)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 
glGetBufferPointerv(GLenum target,GLenum pname,void ** params)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 
glDrawBuffers(GLsizei n,const GLenum * bufs)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 
glUniformMatrix2x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)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 
glUniformMatrix3x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)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 
glUniformMatrix2x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)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 
glUniformMatrix4x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)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 
glUniformMatrix3x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)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 
glUniformMatrix4x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)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 
glBlitFramebuffer(GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield mask,GLenum filter)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 
glFramebufferTextureLayer(GLenum target,GLenum attachment,GLuint texture,GLint level,GLint layer)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 
glMapBufferRange(GLenum target,GLintptr offset,GLsizeiptr length,GLbitfield access)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 
glFlushMappedBufferRange(GLenum target,GLintptr offset,GLsizeiptr length)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 
glBindVertexArray(GLuint array)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 
glDeleteVertexArrays(GLsizei n,const GLuint * arrays)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 
glGenVertexArrays(GLsizei n,GLuint * arrays)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 
glIsVertexArray(GLuint array)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 
glGetIntegeri_v(GLenum target,GLuint index,GLint * data)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 
glBeginTransformFeedback(GLenum primitiveMode)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 
glEndTransformFeedback(void)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 
glBindBufferRange(GLenum target,GLuint index,GLuint buffer,GLintptr offset,GLsizeiptr size)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 
glBindBufferBase(GLenum target,GLuint index,GLuint buffer)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 
glTransformFeedbackVaryings(GLuint program,GLsizei count,const GLchar * const * varyings,GLenum bufferMode)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 
glGetTransformFeedbackVarying(GLuint program,GLuint index,GLsizei bufSize,GLsizei * length,GLsizei * size,GLenum * type,GLchar * name)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 
glVertexAttribIPointer(GLuint index,GLint size,GLenum type,GLsizei stride,const void * pointer)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 
glGetVertexAttribIiv(GLuint index,GLenum pname,GLint * params)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 
glGetVertexAttribIuiv(GLuint index,GLenum pname,GLuint * params)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 
glVertexAttribI4i(GLuint index,GLint x,GLint y,GLint z,GLint w)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 
glVertexAttribI4ui(GLuint index,GLuint x,GLuint y,GLuint z,GLuint w)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 
glVertexAttribI4iv(GLuint index,const GLint * v)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 
glVertexAttribI4uiv(GLuint index,const GLuint * v)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 
glGetUniformuiv(GLuint program,GLint location,GLuint * params)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 
glGetFragDataLocation(GLuint program,const GLchar * name)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 
glUniform1ui(GLint location,GLuint v0)2094 GL_APICALL void GL_APIENTRY glUniform1ui(GLint location, GLuint v0)
2095 {
2096 	glUniform1uiv(location, 1, &v0);
2097 }
2098 
glUniform2ui(GLint location,GLuint v0,GLuint v1)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 
glUniform3ui(GLint location,GLuint v0,GLuint v1,GLuint v2)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 
glUniform4ui(GLint location,GLuint v0,GLuint v1,GLuint v2,GLuint v3)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 
glUniform1uiv(GLint location,GLsizei count,const GLuint * value)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 
glUniform2uiv(GLint location,GLsizei count,const GLuint * value)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 
glUniform3uiv(GLint location,GLsizei count,const GLuint * value)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 
glUniform4uiv(GLint location,GLsizei count,const GLuint * value)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 
glClearBufferiv(GLenum buffer,GLint drawbuffer,const GLint * value)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 
glClearBufferuiv(GLenum buffer,GLint drawbuffer,const GLuint * value)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 
glClearBufferfv(GLenum buffer,GLint drawbuffer,const GLfloat * value)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 
glClearBufferfi(GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)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 
glGetStringi(GLenum name,GLuint index)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 
glCopyBufferSubData(GLenum readTarget,GLenum writeTarget,GLintptr readOffset,GLintptr writeOffset,GLsizeiptr size)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 
glGetUniformIndices(GLuint program,GLsizei uniformCount,const GLchar * const * uniformNames,GLuint * uniformIndices)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 
glGetActiveUniformsiv(GLuint program,GLsizei uniformCount,const GLuint * uniformIndices,GLenum pname,GLint * params)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 
glGetUniformBlockIndex(GLuint program,const GLchar * uniformBlockName)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 
glGetActiveUniformBlockiv(GLuint program,GLuint uniformBlockIndex,GLenum pname,GLint * params)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 
glGetActiveUniformBlockName(GLuint program,GLuint uniformBlockIndex,GLsizei bufSize,GLsizei * length,GLchar * uniformBlockName)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 
glUniformBlockBinding(GLuint program,GLuint uniformBlockIndex,GLuint uniformBlockBinding)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 
glDrawArraysInstanced(GLenum mode,GLint first,GLsizei count,GLsizei instanceCount)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 
glDrawElementsInstanced(GLenum mode,GLsizei count,GLenum type,const void * indices,GLsizei instanceCount)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 
glFenceSync(GLenum condition,GLbitfield flags)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 
glIsSync(GLsync sync)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 
glDeleteSync(GLsync sync)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 
glClientWaitSync(GLsync sync,GLbitfield flags,GLuint64 timeout)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 
glWaitSync(GLsync sync,GLbitfield flags,GLuint64 timeout)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 
glGetInteger64v(GLenum pname,GLint64 * data)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 
glGetSynciv(GLsync sync,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * values)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 
glGetInteger64i_v(GLenum target,GLuint index,GLint64 * data)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 
glGetBufferParameteri64v(GLenum target,GLenum pname,GLint64 * params)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 
glGenSamplers(GLsizei count,GLuint * samplers)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 
glDeleteSamplers(GLsizei count,const GLuint * samplers)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 
glIsSampler(GLuint sampler)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 
glBindSampler(GLuint unit,GLuint sampler)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 
glSamplerParameteri(GLuint sampler,GLenum pname,GLint param)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 
glSamplerParameteriv(GLuint sampler,GLenum pname,const GLint * param)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 
glSamplerParameterf(GLuint sampler,GLenum pname,GLfloat param)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 
glSamplerParameterfv(GLuint sampler,GLenum pname,const GLfloat * param)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 
glGetSamplerParameteriv(GLuint sampler,GLenum pname,GLint * params)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 
glGetSamplerParameterfv(GLuint sampler,GLenum pname,GLfloat * params)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 
glVertexAttribDivisor(GLuint index,GLuint divisor)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 
glBindTransformFeedback(GLenum target,GLuint id)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 
glDeleteTransformFeedbacks(GLsizei n,const GLuint * ids)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 
glGenTransformFeedbacks(GLsizei n,GLuint * ids)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 
glIsTransformFeedback(GLuint id)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 
glPauseTransformFeedback(void)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 
glResumeTransformFeedback(void)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 
glGetProgramBinary(GLuint program,GLsizei bufSize,GLsizei * length,GLenum * binaryFormat,void * binary)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 
glProgramBinary(GLuint program,GLenum binaryFormat,const void * binary,GLsizei length)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 
glProgramParameteri(GLuint program,GLenum pname,GLint value)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 
glInvalidateFramebuffer(GLenum target,GLsizei numAttachments,const GLenum * attachments)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 
glInvalidateSubFramebuffer(GLenum target,GLsizei numAttachments,const GLenum * attachments,GLint x,GLint y,GLsizei width,GLsizei height)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 
glTexStorage2D(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height)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 
glTexStorage3D(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth)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 
glGetInternalformativ(GLenum target,GLenum internalformat,GLenum pname,GLsizei bufSize,GLint * params)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