• 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 namespace gl
211 {
212 
ReadBuffer(GLenum src)213 void ReadBuffer(GLenum src)
214 {
215 	TRACE("(GLenum src = 0x%X)", src);
216 
217 	auto 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 
DrawRangeElements(GLenum mode,GLuint start,GLuint end,GLsizei count,GLenum type,const void * indices)286 void DrawRangeElements(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 	auto 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 
TexImage3D(GLenum target,GLint level,GLint internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,const void * data)335 void TexImage3D(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_3D_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 	auto context = es2::getContext();
368 
369 	if(context)
370 	{
371 		GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target);
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 
TexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLenum type,const void * data)395 void TexSubImage3D(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 	auto 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);
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 
CopyTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLint x,GLint y,GLsizei width,GLsizei height)443 void CopyTexSubImage3D(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 	auto 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);
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 
CompressedTexImage3D(GLenum target,GLint level,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth,GLint border,GLsizei imageSize,const void * data)506 void CompressedTexImage3D(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_3D_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))
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 	auto 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 
CompressedTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yoffset,GLint zoffset,GLsizei width,GLsizei height,GLsizei depth,GLenum format,GLsizei imageSize,const void * data)563 void CompressedTexSubImage3D(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))
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 	auto 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 
GenQueries(GLsizei n,GLuint * ids)660 void GenQueries(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 	auto 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 
DeleteQueries(GLsizei n,const GLuint * ids)680 void DeleteQueries(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 	auto 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 
IsQuery(GLuint id)700 GLboolean IsQuery(GLuint id)
701 {
702 	TRACE("(GLuint id = %d)", id);
703 
704 	if(id == 0)
705 	{
706 		return GL_FALSE;
707 	}
708 
709 	auto 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 
BeginQuery(GLenum target,GLuint id)724 void BeginQuery(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 	auto context = es2::getContext();
739 
740 	if(context)
741 	{
742 		context->beginQuery(target, id);
743 	}
744 }
745 
EndQuery(GLenum target)746 void EndQuery(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 	auto context = es2::getContext();
756 
757 	if(context)
758 	{
759 		context->endQuery(target);
760 	}
761 }
762 
GetQueryiv(GLenum target,GLenum pname,GLint * params)763 void GetQueryiv(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 	auto context = es2::getContext();
774 
775 	if(context)
776 	{
777 		params[0] = context->getActiveQuery(target);
778 	}
779 }
780 
GetQueryObjectuiv(GLuint id,GLenum pname,GLuint * params)781 void GetQueryObjectuiv(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 	auto 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 
UnmapBuffer(GLenum target)825 GLboolean UnmapBuffer(GLenum target)
826 {
827 	TRACE("(GLenum target = 0x%X)", target);
828 
829 	auto 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 
GetBufferPointerv(GLenum target,GLenum pname,void ** params)857 void GetBufferPointerv(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 	auto 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 
DrawBuffers(GLsizei n,const GLenum * bufs)887 void DrawBuffers(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 	auto 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 
UniformMatrix2x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)979 void UniformMatrix2x3fv(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 	auto 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 
UniformMatrix3x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)1011 void UniformMatrix3x2fv(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 	auto 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 
UniformMatrix2x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)1043 void UniformMatrix2x4fv(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 	auto 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 
UniformMatrix4x2fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)1075 void UniformMatrix4x2fv(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 	auto 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 
UniformMatrix3x4fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)1107 void UniformMatrix3x4fv(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 	auto 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 
UniformMatrix4x3fv(GLint location,GLsizei count,GLboolean transpose,const GLfloat * value)1139 void UniformMatrix4x3fv(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 	auto 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 
BlitFramebuffer(GLint srcX0,GLint srcY0,GLint srcX1,GLint srcY1,GLint dstX0,GLint dstY0,GLint dstX1,GLint dstY1,GLbitfield mask,GLenum filter)1171 void BlitFramebuffer(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 	auto 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 
FramebufferTextureLayer(GLenum target,GLenum attachment,GLuint texture,GLint level,GLint layer)1211 void FramebufferTextureLayer(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 	auto 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 			if(level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1239 			{
1240 				return error(GL_INVALID_VALUE);
1241 			}
1242 
1243 			textarget = textureObject->getTarget();
1244 			switch(textarget)
1245 			{
1246 			case GL_TEXTURE_3D:
1247 				if(layer >= es2::IMPLEMENTATION_MAX_3D_TEXTURE_SIZE)
1248 				{
1249 					return error(GL_INVALID_VALUE);
1250 				}
1251 				break;
1252 			case GL_TEXTURE_2D_ARRAY:
1253 				if(layer >= es2::IMPLEMENTATION_MAX_ARRAY_TEXTURE_LAYERS)
1254 				{
1255 					return error(GL_INVALID_VALUE);
1256 				}
1257 				break;
1258 			default:
1259 				return error(GL_INVALID_OPERATION);
1260 			}
1261 
1262 			if(textureObject->isCompressed(textarget, level))
1263 			{
1264 				return error(GL_INVALID_OPERATION);
1265 			}
1266 		}
1267 
1268 		es2::Framebuffer *framebuffer = nullptr;
1269 		switch(target)
1270 		{
1271 		case GL_DRAW_FRAMEBUFFER:
1272 		case GL_FRAMEBUFFER:
1273 			if(context->getDrawFramebufferName() == 0)
1274 			{
1275 				return error(GL_INVALID_OPERATION);
1276 			}
1277 			framebuffer = context->getDrawFramebuffer();
1278 			break;
1279 		case GL_READ_FRAMEBUFFER:
1280 			if(context->getReadFramebufferName() == 0)
1281 			{
1282 				return error(GL_INVALID_OPERATION);
1283 			}
1284 			framebuffer = context->getReadFramebuffer();
1285 			break;
1286 		default:
1287 			return error(GL_INVALID_ENUM);
1288 		}
1289 
1290 		if(!framebuffer)
1291 		{
1292 			return error(GL_INVALID_OPERATION);
1293 		}
1294 
1295 		switch(attachment)
1296 		{
1297 		case GL_DEPTH_ATTACHMENT:
1298 			framebuffer->setDepthbuffer(textarget, texture, level, layer);
1299 			break;
1300 		case GL_STENCIL_ATTACHMENT:
1301 			framebuffer->setStencilbuffer(textarget, texture, level, layer);
1302 			break;
1303 		case GL_DEPTH_STENCIL_ATTACHMENT:
1304 			framebuffer->setDepthbuffer(textarget, texture, level, layer);
1305 			framebuffer->setStencilbuffer(textarget, texture, level, layer);
1306 			break;
1307 		default:
1308 			if(attachment < GL_COLOR_ATTACHMENT0 || attachment > GL_COLOR_ATTACHMENT31)
1309 			{
1310 				return error(GL_INVALID_ENUM);
1311 			}
1312 
1313 			if((attachment - GL_COLOR_ATTACHMENT0) >= MAX_COLOR_ATTACHMENTS)
1314 			{
1315 				return error(GL_INVALID_OPERATION);
1316 			}
1317 
1318 			framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0, level, layer);
1319 			break;
1320 		}
1321 	}
1322 }
1323 
MapBufferRange(GLenum target,GLintptr offset,GLsizeiptr length,GLbitfield access)1324 void *MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
1325 {
1326 	TRACE("(GLenum target = 0x%X,  GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = %X)",
1327 	      target, offset, length, access);
1328 
1329 	if((offset < 0) || (length < 0))
1330 	{
1331 		return error(GL_INVALID_VALUE, nullptr);
1332 	}
1333 
1334 	if(!(access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)))
1335 	{
1336 		// Must be able to read or write the buffer
1337 		return error(GL_INVALID_OPERATION, nullptr);
1338 	}
1339 	else if((access & GL_MAP_READ_BIT) && (access & (GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT)))
1340 	{
1341 		// GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT and GL_MAP_UNSYNCHRONIZED_BIT can't be used with GL_MAP_READ_BIT
1342 		return error(GL_INVALID_OPERATION, nullptr);
1343 	}
1344 	else if((!(access & GL_MAP_WRITE_BIT)) && (access & GL_MAP_FLUSH_EXPLICIT_BIT))
1345 	{
1346 		// GL_MAP_FLUSH_EXPLICIT_BIT can't be used without GL_MAP_WRITE_BIT
1347 		return error(GL_INVALID_OPERATION, nullptr);
1348 	}
1349 
1350 	auto context = es2::getContext();
1351 
1352 	if(context)
1353 	{
1354 		es2::Buffer *buffer = nullptr;
1355 		if(!context->getBuffer(target, &buffer))
1356 		{
1357 			return error(GL_INVALID_ENUM, nullptr);
1358 		}
1359 
1360 		if(!buffer)
1361 		{
1362 			// A null buffer means that "0" is bound to the requested buffer target
1363 			return error(GL_INVALID_OPERATION, nullptr);
1364 		}
1365 
1366 		if(buffer->isMapped())
1367 		{
1368 			// It is an invalid operation to map an already mapped buffer
1369 			return error(GL_INVALID_OPERATION, nullptr);
1370 		}
1371 
1372 		GLsizeiptr bufferSize = buffer->size();
1373 		if((offset + length) > bufferSize)
1374 		{
1375 			return error(GL_INVALID_VALUE, nullptr);
1376 		}
1377 
1378 		if((access & ~(GL_MAP_READ_BIT |
1379 		               GL_MAP_WRITE_BIT |
1380 		               GL_MAP_INVALIDATE_RANGE_BIT |
1381 		               GL_MAP_INVALIDATE_BUFFER_BIT |
1382 		               GL_MAP_FLUSH_EXPLICIT_BIT |
1383 		               GL_MAP_UNSYNCHRONIZED_BIT)) != 0)
1384 		{
1385 			return error(GL_INVALID_VALUE, nullptr);
1386 		}
1387 
1388 		return buffer->mapRange(offset, length, access);
1389 	}
1390 
1391 	return nullptr;
1392 }
1393 
FlushMappedBufferRange(GLenum target,GLintptr offset,GLsizeiptr length)1394 void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
1395 {
1396 	TRACE("(GLenum target = 0x%X,  GLintptr offset = %d, GLsizeiptr length = %d)",
1397 	      target, offset, length);
1398 
1399 	if((offset < 0) || (length < 0))
1400 	{
1401 		return error(GL_INVALID_VALUE);
1402 	}
1403 
1404 	auto context = es2::getContext();
1405 
1406 	if(context)
1407 	{
1408 		es2::Buffer *buffer = nullptr;
1409 		if(!context->getBuffer(target, &buffer))
1410 		{
1411 			return error(GL_INVALID_ENUM);
1412 		}
1413 
1414 		if(!buffer)
1415 		{
1416 			// A null buffer means that "0" is bound to the requested buffer target
1417 			return error(GL_INVALID_OPERATION);
1418 		}
1419 
1420 		if(!buffer->isMapped())
1421 		{
1422 			// Buffer must be mapped
1423 			return error(GL_INVALID_OPERATION);
1424 		}
1425 
1426 		GLsizeiptr bufferSize = buffer->length();
1427 		if((offset + length) > bufferSize)
1428 		{
1429 			return error(GL_INVALID_VALUE);
1430 		}
1431 
1432 		if(!(buffer->access() & GL_MAP_FLUSH_EXPLICIT_BIT))
1433 		{
1434 			// Flush must be explicitly allowed
1435 			return error(GL_INVALID_OPERATION);
1436 		}
1437 
1438 		buffer->flushMappedRange(offset, length);
1439 	}
1440 }
1441 
BindVertexArray(GLuint array)1442 void BindVertexArray(GLuint array)
1443 {
1444 	TRACE("(GLuint array = %d)", array);
1445 
1446 	auto context = es2::getContext();
1447 
1448 	if(context)
1449 	{
1450 		if(!context->isVertexArray(array))
1451 		{
1452 			return error(GL_INVALID_OPERATION);
1453 		}
1454 
1455 		context->bindVertexArray(array);
1456 	}
1457 }
1458 
BindVertexArrayOES(GLuint array)1459 void BindVertexArrayOES(GLuint array)
1460 {
1461 	BindVertexArray(array);
1462 }
1463 
DeleteVertexArrays(GLsizei n,const GLuint * arrays)1464 void DeleteVertexArrays(GLsizei n, const GLuint *arrays)
1465 {
1466 	TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1467 
1468 	if(n < 0)
1469 	{
1470 		return error(GL_INVALID_VALUE);
1471 	}
1472 
1473 	auto context = es2::getContext();
1474 
1475 	if(context)
1476 	{
1477 		for(int i = 0; i < n; i++)
1478 		{
1479 			if(arrays[i] != 0)   // Attempts to delete default vertex array silently ignored.
1480 			{
1481 				context->deleteVertexArray(arrays[i]);
1482 			}
1483 		}
1484 	}
1485 }
1486 
DeleteVertexArraysOES(GLsizei n,const GLuint * arrays)1487 void DeleteVertexArraysOES(GLsizei n, const GLuint *arrays)
1488 {
1489 	DeleteVertexArrays(n, arrays);
1490 }
1491 
GenVertexArrays(GLsizei n,GLuint * arrays)1492 void GenVertexArrays(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 	auto 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 
GenVertexArraysOES(GLsizei n,GLuint * arrays)1512 void GenVertexArraysOES(GLsizei n, GLuint *arrays)
1513 {
1514 	GenVertexArrays(n, arrays);
1515 }
1516 
IsVertexArray(GLuint array)1517 GLboolean IsVertexArray(GLuint array)
1518 {
1519 	TRACE("(GLuint array = %d)", array);
1520 
1521 	if(array == 0)
1522 	{
1523 		return GL_FALSE;
1524 	}
1525 
1526 	auto context = es2::getContext();
1527 
1528 	if(context)
1529 	{
1530 		es2::VertexArray *arrayObject = context->getVertexArray(array);
1531 
1532 		if(arrayObject)
1533 		{
1534 			return GL_TRUE;
1535 		}
1536 	}
1537 
1538 	return GL_FALSE;
1539 }
1540 
IsVertexArrayOES(GLuint array)1541 GLboolean IsVertexArrayOES(GLuint array)
1542 {
1543 	return IsVertexArray(array);
1544 }
1545 
GetIntegeri_v(GLenum target,GLuint index,GLint * data)1546 void GetIntegeri_v(GLenum target, GLuint index, GLint *data)
1547 {
1548 	TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint* data = %p)",
1549 	      target, index, data);
1550 
1551 	auto context = es2::getContext();
1552 
1553 	if(context)
1554 	{
1555 		if(!context->getTransformFeedbackiv(index, target, data) &&
1556 		   !context->getUniformBufferiv(index, target, data) &&
1557 		   !context->getIntegerv(target, data))
1558 		{
1559 			GLenum nativeType;
1560 			unsigned int numParams = 0;
1561 			if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
1562 				return error(GL_INVALID_ENUM);
1563 
1564 			if(numParams == 0)
1565 				return; // it is known that target is valid, but there are no parameters to return
1566 
1567 			if(nativeType == GL_BOOL)
1568 			{
1569 				GLboolean *boolParams = nullptr;
1570 				boolParams = new GLboolean[numParams];
1571 
1572 				context->getBooleanv(target, boolParams);
1573 
1574 				for(unsigned int i = 0; i < numParams; ++i)
1575 				{
1576 					data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
1577 				}
1578 
1579 				delete[] boolParams;
1580 			}
1581 			else if(nativeType == GL_FLOAT)
1582 			{
1583 				GLfloat *floatParams = nullptr;
1584 				floatParams = new GLfloat[numParams];
1585 
1586 				context->getFloatv(target, floatParams);
1587 
1588 				for(unsigned int i = 0; i < numParams; ++i)
1589 				{
1590 					if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
1591 					{
1592 						data[i] = convert_float_fixed(floatParams[i]);
1593 					}
1594 					else
1595 					{
1596 						data[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
1597 					}
1598 				}
1599 
1600 				delete[] floatParams;
1601 			}
1602 		}
1603 	}
1604 }
1605 
BeginTransformFeedback(GLenum primitiveMode)1606 void BeginTransformFeedback(GLenum primitiveMode)
1607 {
1608 	TRACE("(GLenum primitiveMode = 0x%X)", primitiveMode);
1609 
1610 	switch(primitiveMode)
1611 	{
1612 	case GL_POINTS:
1613 	case GL_LINES:
1614 	case GL_TRIANGLES:
1615 		break;
1616 	default:
1617 		return error(GL_INVALID_ENUM);
1618 	}
1619 
1620 	auto context = es2::getContext();
1621 
1622 	if(context)
1623 	{
1624 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1625 
1626 		if(transformFeedbackObject)
1627 		{
1628 			if(transformFeedbackObject->isActive())
1629 			{
1630 				return error(GL_INVALID_OPERATION);
1631 			}
1632 			transformFeedbackObject->begin(primitiveMode);
1633 		}
1634 		else
1635 		{
1636 			return error(GL_INVALID_OPERATION);
1637 		}
1638 	}
1639 }
1640 
EndTransformFeedback(void)1641 void EndTransformFeedback(void)
1642 {
1643 	TRACE("()");
1644 
1645 	auto context = es2::getContext();
1646 
1647 	if(context)
1648 	{
1649 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1650 
1651 		if(transformFeedbackObject)
1652 		{
1653 			if(!transformFeedbackObject->isActive())
1654 			{
1655 				return error(GL_INVALID_OPERATION);
1656 			}
1657 			transformFeedbackObject->end();
1658 		}
1659 		else
1660 		{
1661 			return error(GL_INVALID_OPERATION);
1662 		}
1663 	}
1664 }
1665 
BindBufferRange(GLenum target,GLuint index,GLuint buffer,GLintptr offset,GLsizeiptr size)1666 void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
1667 {
1668 	TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d, GLintptr offset = %d, GLsizeiptr size = %d)",
1669 	      target, index, buffer, offset, size);
1670 
1671 	if(buffer != 0 && size <= 0)
1672 	{
1673 		return error(GL_INVALID_VALUE);
1674 	}
1675 
1676 	auto context = es2::getContext();
1677 
1678 	if(context)
1679 	{
1680 		switch(target)
1681 		{
1682 		case GL_TRANSFORM_FEEDBACK_BUFFER:
1683 			if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1684 			{
1685 				return error(GL_INVALID_VALUE);
1686 			}
1687 			if(size & 0x3 || offset & 0x3) // size and offset must be multiples of 4
1688 			{
1689 				return error(GL_INVALID_VALUE);
1690 			}
1691 			context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size);
1692 			context->bindGenericTransformFeedbackBuffer(buffer);
1693 			break;
1694 		case GL_UNIFORM_BUFFER:
1695 			if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
1696 			{
1697 				return error(GL_INVALID_VALUE);
1698 			}
1699 			if(offset % UNIFORM_BUFFER_OFFSET_ALIGNMENT != 0)
1700 			{
1701 				return error(GL_INVALID_VALUE);
1702 			}
1703 			context->bindIndexedUniformBuffer(buffer, index, offset, size);
1704 			context->bindGenericUniformBuffer(buffer);
1705 			break;
1706 		default:
1707 			return error(GL_INVALID_ENUM);
1708 		}
1709 	}
1710 }
1711 
BindBufferBase(GLenum target,GLuint index,GLuint buffer)1712 void BindBufferBase(GLenum target, GLuint index, GLuint buffer)
1713 {
1714 	TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d)",
1715 	      target, index, buffer);
1716 
1717 	auto context = es2::getContext();
1718 
1719 	if(context)
1720 	{
1721 		switch(target)
1722 		{
1723 		case GL_TRANSFORM_FEEDBACK_BUFFER:
1724 			if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1725 			{
1726 				return error(GL_INVALID_VALUE);
1727 			}
1728 			context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0);
1729 			context->bindGenericTransformFeedbackBuffer(buffer);
1730 			break;
1731 		case GL_UNIFORM_BUFFER:
1732 			if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
1733 			{
1734 				return error(GL_INVALID_VALUE);
1735 			}
1736 			context->bindIndexedUniformBuffer(buffer, index, 0, 0);
1737 			context->bindGenericUniformBuffer(buffer);
1738 			break;
1739 		default:
1740 			return error(GL_INVALID_ENUM);
1741 		}
1742 	}
1743 }
1744 
TransformFeedbackVaryings(GLuint program,GLsizei count,const GLchar * const * varyings,GLenum bufferMode)1745 void TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode)
1746 {
1747 	TRACE("(GLuint program = %d, GLsizei count = %d, const GLchar *const*varyings = %p, GLenum bufferMode = 0x%X)",
1748 	      program, count, varyings, bufferMode);
1749 
1750 	switch(bufferMode)
1751 	{
1752 	case GL_SEPARATE_ATTRIBS:
1753 		if(count > MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1754 		{
1755 			return error(GL_INVALID_VALUE);
1756 		}
1757 	case GL_INTERLEAVED_ATTRIBS:
1758 		break;
1759 	default:
1760 		return error(GL_INVALID_ENUM);
1761 	}
1762 
1763 	auto context = es2::getContext();
1764 
1765 	if(context)
1766 	{
1767 		es2::Program *programObject = context->getProgram(program);
1768 
1769 		if(!programObject)
1770 		{
1771 			return error(GL_INVALID_VALUE);
1772 		}
1773 
1774 		programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);
1775 	}
1776 }
1777 
GetTransformFeedbackVarying(GLuint program,GLuint index,GLsizei bufSize,GLsizei * length,GLsizei * size,GLenum * type,GLchar * name)1778 void GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name)
1779 {
1780 	TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
1781 	      program, index, bufSize, length, size, type, name);
1782 
1783 	if(bufSize < 0)
1784 	{
1785 		return error(GL_INVALID_VALUE);
1786 	}
1787 
1788 	auto context = es2::getContext();
1789 
1790 	if(context)
1791 	{
1792 		es2::Program *programObject = context->getProgram(program);
1793 
1794 		if(!programObject)
1795 		{
1796 			return error(GL_INVALID_VALUE);
1797 		}
1798 
1799 		if(index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount()))
1800 		{
1801 			return error(GL_INVALID_VALUE);
1802 		}
1803 
1804 		programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name);
1805 	}
1806 }
1807 
VertexAttribIPointer(GLuint index,GLint size,GLenum type,GLsizei stride,const void * pointer)1808 void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)
1809 {
1810 	TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
1811 	      index, size, type, stride, pointer);
1812 
1813 	if(index >= es2::MAX_VERTEX_ATTRIBS)
1814 	{
1815 		return error(GL_INVALID_VALUE);
1816 	}
1817 
1818 	if(size < 1 || size > 4 || stride < 0)
1819 	{
1820 		return error(GL_INVALID_VALUE);
1821 	}
1822 
1823 	switch(type)
1824 	{
1825 	case GL_BYTE:
1826 	case GL_UNSIGNED_BYTE:
1827 	case GL_SHORT:
1828 	case GL_UNSIGNED_SHORT:
1829 	case GL_INT:
1830 	case GL_UNSIGNED_INT:
1831 		break;
1832 	default:
1833 		return error(GL_INVALID_ENUM);
1834 	}
1835 
1836 	auto context = es2::getContext();
1837 
1838 	if(context)
1839 	{
1840 		es2::VertexArray* vertexArray = context->getCurrentVertexArray();
1841 		if((context->getArrayBufferName() == 0) && vertexArray && (vertexArray->name != 0) && pointer)
1842 		{
1843 			// GL_INVALID_OPERATION is generated if a non-zero vertex array object is bound, zero is bound
1844 			// to the GL_ARRAY_BUFFER buffer object binding point and the pointer argument is not NULL.
1845 			return error(GL_INVALID_OPERATION);
1846 		}
1847 
1848 		context->setVertexAttribState(index, context->getArrayBuffer(), size, type, false, true, stride, pointer);
1849 	}
1850 }
1851 
GetVertexAttribIiv(GLuint index,GLenum pname,GLint * params)1852 void GetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
1853 {
1854 	TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint *params = %p)",
1855 	      index, pname, params);
1856 
1857 	auto context = es2::getContext();
1858 
1859 	if(context)
1860 	{
1861 		if(index >= es2::MAX_VERTEX_ATTRIBS)
1862 		{
1863 			return error(GL_INVALID_VALUE);
1864 		}
1865 
1866 		const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
1867 
1868 		switch(pname)
1869 		{
1870 		case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1871 			*params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
1872 			break;
1873 		case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1874 			*params = attribState.mSize;
1875 			break;
1876 		case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1877 			*params = attribState.mStride;
1878 			break;
1879 		case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1880 			*params = attribState.mType;
1881 			break;
1882 		case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1883 			*params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
1884 			break;
1885 		case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1886 			*params = attribState.mBoundBuffer.name();
1887 			break;
1888 		case GL_CURRENT_VERTEX_ATTRIB:
1889 			{
1890 				const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
1891 				for(int i = 0; i < 4; ++i)
1892 				{
1893 					params[i] = attrib.getCurrentValueI(i);
1894 				}
1895 			}
1896 			break;
1897 		case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
1898 			*params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
1899 			break;
1900 		case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1901 			*params = attribState.mDivisor;
1902 			break;
1903 		default: return error(GL_INVALID_ENUM);
1904 		}
1905 	}
1906 }
1907 
GetVertexAttribIuiv(GLuint index,GLenum pname,GLuint * params)1908 void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params)
1909 {
1910 	TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLuint *params = %p)",
1911 		index, pname, params);
1912 
1913 	auto context = es2::getContext();
1914 
1915 	if(context)
1916 	{
1917 		if(index >= es2::MAX_VERTEX_ATTRIBS)
1918 		{
1919 			return error(GL_INVALID_VALUE);
1920 		}
1921 
1922 		const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
1923 
1924 		switch(pname)
1925 		{
1926 		case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1927 			*params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
1928 			break;
1929 		case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1930 			*params = attribState.mSize;
1931 			break;
1932 		case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1933 			*params = attribState.mStride;
1934 			break;
1935 		case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1936 			*params = attribState.mType;
1937 			break;
1938 		case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1939 			*params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
1940 			break;
1941 		case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1942 			*params = attribState.mBoundBuffer.name();
1943 			break;
1944 		case GL_CURRENT_VERTEX_ATTRIB:
1945 			{
1946 				const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
1947 				for(int i = 0; i < 4; ++i)
1948 				{
1949 					params[i] = attrib.getCurrentValueUI(i);
1950 				}
1951 			}
1952 			break;
1953 		case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
1954 			*params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
1955 			break;
1956 		case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1957 			*params = attribState.mDivisor;
1958 			break;
1959 		default: return error(GL_INVALID_ENUM);
1960 		}
1961 	}
1962 }
1963 
VertexAttribI4i(GLuint index,GLint x,GLint y,GLint z,GLint w)1964 void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
1965 {
1966 	TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
1967 	      index, x, y, z, w);
1968 
1969 	if(index >= es2::MAX_VERTEX_ATTRIBS)
1970 	{
1971 		return error(GL_INVALID_VALUE);
1972 	}
1973 
1974 	auto context = es2::getContext();
1975 
1976 	if(context)
1977 	{
1978 		GLint vals[4] = { x, y, z, w };
1979 		context->setVertexAttrib(index, vals);
1980 	}
1981 }
1982 
VertexAttribI4ui(GLuint index,GLuint x,GLuint y,GLuint z,GLuint w)1983 void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
1984 {
1985 	TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
1986 	      index, x, y, z, w);
1987 
1988 	if(index >= es2::MAX_VERTEX_ATTRIBS)
1989 	{
1990 		return error(GL_INVALID_VALUE);
1991 	}
1992 
1993 	auto context = es2::getContext();
1994 
1995 	if(context)
1996 	{
1997 		GLuint vals[4] = { x, y, z, w };
1998 		context->setVertexAttrib(index, vals);
1999 	}
2000 }
2001 
VertexAttribI4iv(GLuint index,const GLint * v)2002 void VertexAttribI4iv(GLuint index, const GLint *v)
2003 {
2004 	TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2005 
2006 	if(index >= es2::MAX_VERTEX_ATTRIBS)
2007 	{
2008 		return error(GL_INVALID_VALUE);
2009 	}
2010 
2011 	auto context = es2::getContext();
2012 
2013 	if(context)
2014 	{
2015 		context->setVertexAttrib(index, v);
2016 	}
2017 }
2018 
VertexAttribI4uiv(GLuint index,const GLuint * v)2019 void VertexAttribI4uiv(GLuint index, const GLuint *v)
2020 {
2021 	TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2022 
2023 	if(index >= es2::MAX_VERTEX_ATTRIBS)
2024 	{
2025 		return error(GL_INVALID_VALUE);
2026 	}
2027 
2028 	auto context = es2::getContext();
2029 
2030 	if(context)
2031 	{
2032 		context->setVertexAttrib(index, v);
2033 	}
2034 }
2035 
GetUniformuiv(GLuint program,GLint location,GLuint * params)2036 void GetUniformuiv(GLuint program, GLint location, GLuint *params)
2037 {
2038 	TRACE("(GLuint program = %d, GLint location = %d, GLuint *params = %p)",
2039 	      program, location, params);
2040 
2041 	auto context = es2::getContext();
2042 
2043 	if(context)
2044 	{
2045 		es2::Program *programObject = context->getProgram(program);
2046 
2047 		if(!programObject)
2048 		{
2049 			if(context->getShader(program))
2050 			{
2051 				return error(GL_INVALID_OPERATION);
2052 			}
2053 			else
2054 			{
2055 				return error(GL_INVALID_VALUE);
2056 			}
2057 		}
2058 
2059 		if(!programObject->isLinked())
2060 		{
2061 			return error(GL_INVALID_OPERATION);
2062 		}
2063 
2064 		if(!programObject->getUniformuiv(location, nullptr, params))
2065 		{
2066 			return error(GL_INVALID_OPERATION);
2067 		}
2068 	}
2069 }
2070 
GetFragDataLocation(GLuint program,const GLchar * name)2071 GLint GetFragDataLocation(GLuint program, const GLchar *name)
2072 {
2073 	TRACE("(GLuint program = %d, const GLchar *name = %p)", program, name);
2074 
2075 	auto context = es2::getContext();
2076 
2077 	if(context)
2078 	{
2079 		es2::Program *programObject = context->getProgram(program);
2080 
2081 		if(!programObject)
2082 		{
2083 			if(context->getShader(program))
2084 			{
2085 				return error(GL_INVALID_OPERATION, -1);
2086 			}
2087 			else
2088 			{
2089 				return error(GL_INVALID_VALUE, -1);
2090 			}
2091 		}
2092 
2093 		if(!programObject->isLinked())
2094 		{
2095 			return error(GL_INVALID_OPERATION, -1);
2096 		}
2097 
2098 		return programObject->getFragDataLocation(name);
2099 	}
2100 
2101 	return -1;
2102 }
2103 
Uniform1uiv(GLint location,GLsizei count,const GLuint * value)2104 void Uniform1uiv(GLint location, GLsizei count, const GLuint *value)
2105 {
2106 	TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2107 	      location, count, value);
2108 
2109 	if(count < 0)
2110 	{
2111 		return error(GL_INVALID_VALUE);
2112 	}
2113 
2114 	auto context = es2::getContext();
2115 
2116 	if(context)
2117 	{
2118 		es2::Program *program = context->getCurrentProgram();
2119 
2120 		if(!program)
2121 		{
2122 			return error(GL_INVALID_OPERATION);
2123 		}
2124 
2125 		if(location == -1)
2126 		{
2127 			return;
2128 		}
2129 
2130 		if(!program->setUniform1uiv(location, count, value))
2131 		{
2132 			return error(GL_INVALID_OPERATION);
2133 		}
2134 	}
2135 }
2136 
Uniform2uiv(GLint location,GLsizei count,const GLuint * value)2137 void Uniform2uiv(GLint location, GLsizei count, const GLuint *value)
2138 {
2139 	TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2140 	      location, count, value);
2141 
2142 	if(count < 0)
2143 	{
2144 		return error(GL_INVALID_VALUE);
2145 	}
2146 
2147 	auto context = es2::getContext();
2148 
2149 	if(context)
2150 	{
2151 		es2::Program *program = context->getCurrentProgram();
2152 
2153 		if(!program)
2154 		{
2155 			return error(GL_INVALID_OPERATION);
2156 		}
2157 
2158 		if(location == -1)
2159 		{
2160 			return;
2161 		}
2162 
2163 		if(!program->setUniform2uiv(location, count, value))
2164 		{
2165 			return error(GL_INVALID_OPERATION);
2166 		}
2167 	}
2168 }
2169 
Uniform3uiv(GLint location,GLsizei count,const GLuint * value)2170 void Uniform3uiv(GLint location, GLsizei count, const GLuint *value)
2171 {
2172 	TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2173 	      location, count, value);
2174 
2175 	if(count < 0)
2176 	{
2177 		return error(GL_INVALID_VALUE);
2178 	}
2179 
2180 	auto context = es2::getContext();
2181 
2182 	if(context)
2183 	{
2184 		es2::Program *program = context->getCurrentProgram();
2185 
2186 		if(!program)
2187 		{
2188 			return error(GL_INVALID_OPERATION);
2189 		}
2190 
2191 		if(location == -1)
2192 		{
2193 			return;
2194 		}
2195 
2196 		if(!program->setUniform3uiv(location, count, value))
2197 		{
2198 			return error(GL_INVALID_OPERATION);
2199 		}
2200 	}
2201 }
2202 
Uniform4uiv(GLint location,GLsizei count,const GLuint * value)2203 void Uniform4uiv(GLint location, GLsizei count, const GLuint *value)
2204 {
2205 	TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2206 	      location, count, value);
2207 
2208 	if(count < 0)
2209 	{
2210 		return error(GL_INVALID_VALUE);
2211 	}
2212 
2213 	auto context = es2::getContext();
2214 
2215 	if(context)
2216 	{
2217 		es2::Program *program = context->getCurrentProgram();
2218 
2219 		if(!program)
2220 		{
2221 			return error(GL_INVALID_OPERATION);
2222 		}
2223 
2224 		if(location == -1)
2225 		{
2226 			return;
2227 		}
2228 
2229 		if(!program->setUniform4uiv(location, count, value))
2230 		{
2231 			return error(GL_INVALID_OPERATION);
2232 		}
2233 	}
2234 }
2235 
Uniform1ui(GLint location,GLuint v0)2236 void Uniform1ui(GLint location, GLuint v0)
2237 {
2238 	Uniform1uiv(location, 1, &v0);
2239 }
2240 
Uniform2ui(GLint location,GLuint v0,GLuint v1)2241 void Uniform2ui(GLint location, GLuint v0, GLuint v1)
2242 {
2243 	GLuint xy[2] = { v0, v1 };
2244 
2245 	Uniform2uiv(location, 1, (GLuint*)&xy);
2246 }
2247 
Uniform3ui(GLint location,GLuint v0,GLuint v1,GLuint v2)2248 void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
2249 {
2250 	GLuint xyz[3] = { v0, v1, v2 };
2251 
2252 	Uniform3uiv(location, 1, (GLuint*)&xyz);
2253 }
2254 
Uniform4ui(GLint location,GLuint v0,GLuint v1,GLuint v2,GLuint v3)2255 void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
2256 {
2257 	GLuint xyzw[4] = { v0, v1, v2, v3 };
2258 
2259 	Uniform4uiv(location, 1, (GLuint*)&xyzw);
2260 }
2261 
ClearBufferiv(GLenum buffer,GLint drawbuffer,const GLint * value)2262 void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
2263 {
2264 	TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint *value = %p)",
2265 	      buffer, drawbuffer, value);
2266 
2267 	auto context = es2::getContext();
2268 
2269 	if(context)
2270 	{
2271 		switch(buffer)
2272 		{
2273 		case GL_COLOR:
2274 			if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2275 			{
2276 				return error(GL_INVALID_VALUE);
2277 			}
2278 			else
2279 			{
2280 				context->clearColorBuffer(drawbuffer, value);
2281 			}
2282 			break;
2283 		case GL_STENCIL:
2284 			if(drawbuffer != 0)
2285 			{
2286 				return error(GL_INVALID_VALUE);
2287 			}
2288 			else
2289 			{
2290 				context->clearStencilBuffer(value[0]);
2291 			}
2292 			break;
2293 		default:
2294 			return error(GL_INVALID_ENUM);
2295 		}
2296 	}
2297 }
2298 
ClearBufferuiv(GLenum buffer,GLint drawbuffer,const GLuint * value)2299 void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
2300 {
2301 	TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint *value = %p)",
2302 	      buffer, drawbuffer, value);
2303 
2304 	auto context = es2::getContext();
2305 
2306 	if(context)
2307 	{
2308 		switch(buffer)
2309 		{
2310 		case GL_COLOR:
2311 			if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2312 			{
2313 				return error(GL_INVALID_VALUE);
2314 			}
2315 			else
2316 			{
2317 				context->clearColorBuffer(drawbuffer, value);
2318 			}
2319 			break;
2320 		default:
2321 			return error(GL_INVALID_ENUM);
2322 		}
2323 	}
2324 }
2325 
ClearBufferfv(GLenum buffer,GLint drawbuffer,const GLfloat * value)2326 void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
2327 {
2328 	TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat *value = %p)",
2329 	      buffer, drawbuffer, value);
2330 
2331 	auto context = es2::getContext();
2332 
2333 	if(context)
2334 	{
2335 		switch(buffer)
2336 		{
2337 		case GL_COLOR:
2338 			if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2339 			{
2340 				return error(GL_INVALID_VALUE);
2341 			}
2342 			else
2343 			{
2344 				context->clearColorBuffer(drawbuffer, value);
2345 			}
2346 			break;
2347 		case GL_DEPTH:
2348 			if(drawbuffer != 0)
2349 			{
2350 				return error(GL_INVALID_VALUE);
2351 			}
2352 			else
2353 			{
2354 				context->clearDepthBuffer(value[0]);
2355 			}
2356 			break;
2357 		default:
2358 			return error(GL_INVALID_ENUM);
2359 		}
2360 	}
2361 }
2362 
ClearBufferfi(GLenum buffer,GLint drawbuffer,GLfloat depth,GLint stencil)2363 void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
2364 {
2365 	TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth = %f, GLint stencil = %d)",
2366 	      buffer, drawbuffer, depth, stencil);
2367 
2368 	auto context = es2::getContext();
2369 
2370 	if(context)
2371 	{
2372 		switch(buffer)
2373 		{
2374 		case GL_DEPTH_STENCIL:
2375 			if(drawbuffer != 0)
2376 			{
2377 				return error(GL_INVALID_VALUE);
2378 			}
2379 			else
2380 			{
2381 				context->clearDepthBuffer(depth);
2382 				context->clearStencilBuffer(stencil);
2383 			}
2384 			break;
2385 		default:
2386 			return error(GL_INVALID_ENUM);
2387 		}
2388 	}
2389 }
2390 
GetStringi(GLenum name,GLuint index)2391 const GLubyte *GetStringi(GLenum name, GLuint index)
2392 {
2393 	TRACE("(GLenum name = 0x%X, GLuint index = %d)", name, index);
2394 
2395 	auto context = es2::getContext();
2396 	if(context)
2397 	{
2398 		GLuint numExtensions;
2399 		context->getExtensions(0, &numExtensions);
2400 
2401 		if(index >= numExtensions)
2402 		{
2403 			return error(GL_INVALID_VALUE, (GLubyte*)nullptr);
2404 		}
2405 
2406 		switch(name)
2407 		{
2408 		case GL_EXTENSIONS:
2409 			return context->getExtensions(index);
2410 		default:
2411 			return error(GL_INVALID_ENUM, (GLubyte*)nullptr);
2412 		}
2413 	}
2414 
2415 	return (GLubyte*)nullptr;
2416 }
2417 
CopyBufferSubData(GLenum readTarget,GLenum writeTarget,GLintptr readOffset,GLintptr writeOffset,GLsizeiptr size)2418 void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
2419 {
2420 	TRACE("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X,  GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)",
2421 	      readTarget, writeTarget, readOffset, writeOffset, size);
2422 
2423 	if(readOffset < 0 || writeOffset < 0 || size < 0)
2424 	{
2425 		return error(GL_INVALID_VALUE);
2426 	}
2427 
2428 	auto context = es2::getContext();
2429 
2430 	if(context)
2431 	{
2432 		es2::Buffer *readBuffer = nullptr, *writeBuffer = nullptr;
2433 		if(!context->getBuffer(readTarget, &readBuffer) || !context->getBuffer(writeTarget, &writeBuffer))
2434 		{
2435 			return error(GL_INVALID_ENUM);
2436 		}
2437 		if(!readBuffer || readBuffer->isMapped() || !writeBuffer || writeBuffer->isMapped())
2438 		{
2439 			return error(GL_INVALID_OPERATION);
2440 		}
2441 		if(readBuffer == writeBuffer)
2442 		{
2443 			// If same buffer, check for overlap
2444 			if(((readOffset >= writeOffset) && (readOffset < (writeOffset + size))) ||
2445 			   ((writeOffset >= readOffset) && (writeOffset < (readOffset + size))))
2446 			{
2447 				return error(GL_INVALID_VALUE);
2448 			}
2449 		}
2450 
2451 		if((static_cast<size_t>(readOffset + size) > readBuffer->size()) ||
2452 		   (static_cast<size_t>(writeOffset + size) > writeBuffer->size()))
2453 		{
2454 			return error(GL_INVALID_VALUE);
2455 		}
2456 
2457 		writeBuffer->bufferSubData(((char*)readBuffer->data()) + readOffset, size, writeOffset);
2458 	}
2459 }
2460 
GetUniformIndices(GLuint program,GLsizei uniformCount,const GLchar * const * uniformNames,GLuint * uniformIndices)2461 void GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices)
2462 {
2463 	TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLuint *uniformIndices = %p)",
2464 	      program, uniformCount, uniformNames, uniformIndices);
2465 
2466 	if(uniformCount < 0)
2467 	{
2468 		return error(GL_INVALID_VALUE);
2469 	}
2470 
2471 	auto context = es2::getContext();
2472 
2473 	if(context)
2474 	{
2475 		es2::Program *programObject = context->getProgram(program);
2476 
2477 		if(!programObject)
2478 		{
2479 			if(context->getShader(program))
2480 			{
2481 				return error(GL_INVALID_OPERATION);
2482 			}
2483 			else
2484 			{
2485 				return error(GL_INVALID_VALUE);
2486 			}
2487 		}
2488 
2489 		if(!programObject->isLinked())
2490 		{
2491 			for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2492 			{
2493 				uniformIndices[uniformId] = GL_INVALID_INDEX;
2494 			}
2495 		}
2496 		else
2497 		{
2498 			for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2499 			{
2500 				uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]);
2501 			}
2502 		}
2503 	}
2504 }
2505 
GetActiveUniformsiv(GLuint program,GLsizei uniformCount,const GLuint * uniformIndices,GLenum pname,GLint * params)2506 void GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params)
2507 {
2508 	TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLenum pname = 0x%X, GLuint *uniformIndices = %p)",
2509 	      program, uniformCount, uniformIndices, pname, uniformIndices);
2510 
2511 	switch(pname)
2512 	{
2513 	case GL_UNIFORM_TYPE:
2514 	case GL_UNIFORM_SIZE:
2515 	case GL_UNIFORM_NAME_LENGTH:
2516 	case GL_UNIFORM_BLOCK_INDEX:
2517 	case GL_UNIFORM_OFFSET:
2518 	case GL_UNIFORM_ARRAY_STRIDE:
2519 	case GL_UNIFORM_MATRIX_STRIDE:
2520 	case GL_UNIFORM_IS_ROW_MAJOR:
2521 		break;
2522 	default:
2523 		return error(GL_INVALID_ENUM);
2524 	}
2525 
2526 	if(uniformCount < 0)
2527 	{
2528 		return error(GL_INVALID_VALUE);
2529 	}
2530 
2531 	auto context = es2::getContext();
2532 
2533 	if(context)
2534 	{
2535 		es2::Program *programObject = context->getProgram(program);
2536 
2537 		if(!programObject)
2538 		{
2539 			if(context->getShader(program))
2540 			{
2541 				return error(GL_INVALID_OPERATION);
2542 			}
2543 			else
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 
2553 			if(index >= programObject->getActiveUniformCount())
2554 			{
2555 				return error(GL_INVALID_VALUE);
2556 			}
2557 		}
2558 
2559 		for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2560 		{
2561 			const GLuint index = uniformIndices[uniformId];
2562 			params[uniformId] = programObject->getActiveUniformi(index, pname);
2563 		}
2564 	}
2565 }
2566 
GetUniformBlockIndex(GLuint program,const GLchar * uniformBlockName)2567 GLuint GetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName)
2568 {
2569 	TRACE("(GLuint program = %d, const GLchar *uniformBlockName = %p)",
2570 	      program, uniformBlockName);
2571 
2572 	auto context = es2::getContext();
2573 
2574 	if(context)
2575 	{
2576 		es2::Program *programObject = context->getProgram(program);
2577 
2578 		if(!programObject)
2579 		{
2580 			if(context->getShader(program))
2581 			{
2582 				return error(GL_INVALID_OPERATION, GL_INVALID_INDEX);
2583 			}
2584 			else
2585 			{
2586 				return error(GL_INVALID_VALUE, GL_INVALID_INDEX);
2587 			}
2588 		}
2589 
2590 		return programObject->getUniformBlockIndex(uniformBlockName);
2591 	}
2592 
2593 	return GL_INVALID_INDEX;
2594 }
2595 
GetActiveUniformBlockiv(GLuint program,GLuint uniformBlockIndex,GLenum pname,GLint * params)2596 void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params)
2597 {
2598 	TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLenum pname = 0x%X, GLint *params = %p)",
2599 	      program, uniformBlockIndex, pname, params);
2600 
2601 	auto context = es2::getContext();
2602 
2603 	if(context)
2604 	{
2605 		es2::Program *programObject = context->getProgram(program);
2606 
2607 		if(!programObject)
2608 		{
2609 			return error(GL_INVALID_OPERATION);
2610 		}
2611 
2612 		if(uniformBlockIndex >= programObject->getActiveUniformBlockCount())
2613 		{
2614 			return error(GL_INVALID_VALUE);
2615 		}
2616 
2617 		switch(pname)
2618 		{
2619 		case GL_UNIFORM_BLOCK_BINDING:
2620 			*params = static_cast<GLint>(programObject->getUniformBlockBinding(uniformBlockIndex));
2621 			break;
2622 		case GL_UNIFORM_BLOCK_DATA_SIZE:
2623 		case GL_UNIFORM_BLOCK_NAME_LENGTH:
2624 		case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2625 		case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2626 		case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2627 		case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2628 			programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
2629 			break;
2630 		default:
2631 			return error(GL_INVALID_ENUM);
2632 		}
2633 	}
2634 }
2635 
GetActiveUniformBlockName(GLuint program,GLuint uniformBlockIndex,GLsizei bufSize,GLsizei * length,GLchar * uniformBlockName)2636 void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName)
2637 {
2638 	TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLchar *uniformBlockName = %p)",
2639 	      program, uniformBlockIndex, bufSize, length, uniformBlockName);
2640 
2641 	if(bufSize < 0)
2642 	{
2643 		return error(GL_INVALID_VALUE);
2644 	}
2645 
2646 	auto context = es2::getContext();
2647 
2648 	if(context)
2649 	{
2650 		es2::Program *programObject = context->getProgram(program);
2651 
2652 		if(!programObject)
2653 		{
2654 			return error(GL_INVALID_OPERATION);
2655 		}
2656 
2657 		if(uniformBlockIndex >= programObject->getActiveUniformBlockCount())
2658 		{
2659 			return error(GL_INVALID_VALUE);
2660 		}
2661 
2662 		programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
2663 	}
2664 }
2665 
UniformBlockBinding(GLuint program,GLuint uniformBlockIndex,GLuint uniformBlockBinding)2666 void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
2667 {
2668 	TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLuint uniformBlockBinding = %d)",
2669 	      program, uniformBlockIndex, uniformBlockBinding);
2670 
2671 	if(uniformBlockBinding >= MAX_UNIFORM_BUFFER_BINDINGS)
2672 	{
2673 		return error(GL_INVALID_VALUE);
2674 	}
2675 
2676 	auto context = es2::getContext();
2677 
2678 	if(context)
2679 	{
2680 		es2::Program *programObject = context->getProgram(program);
2681 
2682 		if(!programObject)
2683 		{
2684 			return error(GL_INVALID_VALUE);
2685 		}
2686 
2687 		if(uniformBlockIndex >= programObject->getActiveUniformBlockCount())
2688 		{
2689 			return error(GL_INVALID_VALUE);
2690 		}
2691 
2692 		programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding);
2693 	}
2694 }
2695 
DrawArraysInstanced(GLenum mode,GLint first,GLsizei count,GLsizei instanceCount)2696 void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
2697 {
2698 	TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
2699 	      mode, first, count, instanceCount);
2700 
2701 	switch(mode)
2702 	{
2703 	case GL_POINTS:
2704 	case GL_LINES:
2705 	case GL_LINE_LOOP:
2706 	case GL_LINE_STRIP:
2707 	case GL_TRIANGLES:
2708 	case GL_TRIANGLE_FAN:
2709 	case GL_TRIANGLE_STRIP:
2710 		break;
2711 	default:
2712 		return error(GL_INVALID_ENUM);
2713 	}
2714 
2715 	if(count < 0 || instanceCount < 0)
2716 	{
2717 		return error(GL_INVALID_VALUE);
2718 	}
2719 
2720 	auto context = es2::getContext();
2721 
2722 	if(context)
2723 	{
2724 		es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
2725 		if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
2726 		{
2727 			return error(GL_INVALID_OPERATION);
2728 		}
2729 
2730 		context->drawArrays(mode, first, count, instanceCount);
2731 	}
2732 }
2733 
DrawElementsInstanced(GLenum mode,GLsizei count,GLenum type,const void * indices,GLsizei instanceCount)2734 void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
2735 {
2736 	TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = %p, GLsizei instanceCount = %d)",
2737 	      mode, count, type, indices, instanceCount);
2738 
2739 	switch(mode)
2740 	{
2741 	case GL_POINTS:
2742 	case GL_LINES:
2743 	case GL_LINE_LOOP:
2744 	case GL_LINE_STRIP:
2745 	case GL_TRIANGLES:
2746 	case GL_TRIANGLE_FAN:
2747 	case GL_TRIANGLE_STRIP:
2748 		break;
2749 	default:
2750 		return error(GL_INVALID_ENUM);
2751 	}
2752 
2753 	switch(type)
2754 	{
2755 	case GL_UNSIGNED_BYTE:
2756 	case GL_UNSIGNED_SHORT:
2757 	case GL_UNSIGNED_INT:
2758 		break;
2759 	default:
2760 		return error(GL_INVALID_ENUM);
2761 	}
2762 
2763 	if(count < 0 || instanceCount < 0)
2764 	{
2765 		return error(GL_INVALID_VALUE);
2766 	}
2767 
2768 	auto context = es2::getContext();
2769 
2770 	if(context)
2771 	{
2772 		es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
2773 		if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
2774 		{
2775 			return error(GL_INVALID_OPERATION);
2776 		}
2777 
2778 		context->drawElements(mode, 0, MAX_ELEMENT_INDEX, count, type, indices, instanceCount);
2779 	}
2780 }
2781 
FenceSync(GLenum condition,GLbitfield flags)2782 GLsync FenceSync(GLenum condition, GLbitfield flags)
2783 {
2784 	TRACE("(GLenum condition = 0x%X, GLbitfield flags = %X)", condition, flags);
2785 
2786 	switch(condition)
2787 	{
2788 	case GL_SYNC_GPU_COMMANDS_COMPLETE:
2789 		break;
2790 	default:
2791 		return error(GL_INVALID_ENUM, nullptr);
2792 	}
2793 
2794 	if(flags != 0)
2795 	{
2796 		return error(GL_INVALID_VALUE, nullptr);
2797 	}
2798 
2799 	auto context = es2::getContext();
2800 
2801 	if(context)
2802 	{
2803 		return context->createFenceSync(condition, flags);
2804 	}
2805 
2806 	return nullptr;
2807 }
2808 
IsSync(GLsync sync)2809 GLboolean IsSync(GLsync sync)
2810 {
2811 	TRACE("(GLsync sync = %p)", sync);
2812 
2813 	auto context = es2::getContext();
2814 
2815 	if(context)
2816 	{
2817 		es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2818 
2819 		if(fenceSyncObject)
2820 		{
2821 			return GL_TRUE;
2822 		}
2823 	}
2824 
2825 	return GL_FALSE;
2826 }
2827 
DeleteSync(GLsync sync)2828 void DeleteSync(GLsync sync)
2829 {
2830 	TRACE("(GLsync sync = %p)", sync);
2831 
2832 	if(!sync)
2833 	{
2834 		return;
2835 	}
2836 
2837 	auto context = es2::getContext();
2838 
2839 	if(context)
2840 	{
2841 		if(!context->getFenceSync(sync))
2842 		{
2843 			return error(GL_INVALID_VALUE);
2844 		}
2845 
2846 		context->deleteFenceSync(sync);
2847 	}
2848 }
2849 
ClientWaitSync(GLsync sync,GLbitfield flags,GLuint64 timeout)2850 GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
2851 {
2852 	TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
2853 
2854 	if((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0)
2855 	{
2856 		return error(GL_INVALID_VALUE, GL_FALSE);
2857 	}
2858 
2859 	auto context = es2::getContext();
2860 
2861 	if(context)
2862 	{
2863 		es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2864 
2865 		if(fenceSyncObject)
2866 		{
2867 			return fenceSyncObject->clientWait(flags, timeout);
2868 		}
2869 		else
2870 		{
2871 			return error(GL_INVALID_VALUE, GL_FALSE);
2872 		}
2873 	}
2874 
2875 	return GL_FALSE;
2876 }
2877 
WaitSync(GLsync sync,GLbitfield flags,GLuint64 timeout)2878 void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
2879 {
2880 	TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
2881 
2882 	if(flags != 0)
2883 	{
2884 		return error(GL_INVALID_VALUE);
2885 	}
2886 
2887 	if(timeout != GL_TIMEOUT_IGNORED)
2888 	{
2889 		return error(GL_INVALID_VALUE);
2890 	}
2891 
2892 	auto context = es2::getContext();
2893 
2894 	if(context)
2895 	{
2896 		es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2897 
2898 		if(fenceSyncObject)
2899 		{
2900 			fenceSyncObject->serverWait(flags, timeout);
2901 		}
2902 		else
2903 		{
2904 			return error(GL_INVALID_VALUE);
2905 		}
2906 	}
2907 }
2908 
GetInteger64v(GLenum pname,GLint64 * data)2909 void GetInteger64v(GLenum pname, GLint64 *data)
2910 {
2911 	TRACE("(GLenum pname = 0x%X, GLint64 *data = %p)", pname, data);
2912 
2913 	auto context = es2::getContext();
2914 
2915 	if(context)
2916 	{
2917 		if(!(context->getIntegerv(pname, data)))
2918 		{
2919 			GLenum nativeType;
2920 			unsigned int numParams = 0;
2921 			if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))
2922 				return error(GL_INVALID_ENUM);
2923 
2924 			if(numParams == 0)
2925 				return; // it is known that pname is valid, but there are no parameters to return
2926 
2927 			if(nativeType == GL_BOOL)
2928 			{
2929 				GLboolean *boolParams = nullptr;
2930 				boolParams = new GLboolean[numParams];
2931 
2932 				context->getBooleanv(pname, boolParams);
2933 
2934 				for(unsigned int i = 0; i < numParams; ++i)
2935 				{
2936 					data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
2937 				}
2938 
2939 				delete[] boolParams;
2940 			}
2941 			else if(nativeType == GL_FLOAT)
2942 			{
2943 				GLfloat *floatParams = nullptr;
2944 				floatParams = new GLfloat[numParams];
2945 
2946 				context->getFloatv(pname, floatParams);
2947 
2948 				for(unsigned int i = 0; i < numParams; ++i)
2949 				{
2950 					if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
2951 					{
2952 						data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
2953 					}
2954 					else
2955 					{
2956 						data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
2957 					}
2958 				}
2959 
2960 				delete[] floatParams;
2961 			}
2962 		}
2963 	}
2964 }
2965 
GetSynciv(GLsync sync,GLenum pname,GLsizei bufSize,GLsizei * length,GLint * values)2966 void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
2967 {
2968 	TRACE("(GLsync sync = %p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei *length = %p, GLint *values = %p)",
2969 	      sync, pname, bufSize, length, values);
2970 
2971 	if(bufSize < 0)
2972 	{
2973 		return error(GL_INVALID_VALUE);
2974 	}
2975 
2976 	auto context = es2::getContext();
2977 
2978 	if(context)
2979 	{
2980 		es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2981 		if(!fenceSyncObject)
2982 		{
2983 			return error(GL_INVALID_VALUE);
2984 		}
2985 
2986 		fenceSyncObject->getSynciv(pname, length, values);
2987 	}
2988 }
2989 
GetInteger64i_v(GLenum target,GLuint index,GLint64 * data)2990 void GetInteger64i_v(GLenum target, GLuint index, GLint64 *data)
2991 {
2992 	TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint64 *data = %p)", target, index, data);
2993 
2994 	auto context = es2::getContext();
2995 
2996 	if(context)
2997 	{
2998 		if(!context->getTransformFeedbackiv(index, target, data) &&
2999 		   !context->getUniformBufferiv(index, target, data) &&
3000 		   !context->getIntegerv(target, data))
3001 		{
3002 			GLenum nativeType;
3003 			unsigned int numParams = 0;
3004 			if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
3005 				return error(GL_INVALID_ENUM);
3006 
3007 			if(numParams == 0)
3008 				return; // it is known that target is valid, but there are no parameters to return
3009 
3010 			if(nativeType == GL_BOOL)
3011 			{
3012 				GLboolean *boolParams = nullptr;
3013 				boolParams = new GLboolean[numParams];
3014 
3015 				context->getBooleanv(target, boolParams);
3016 
3017 				for(unsigned int i = 0; i < numParams; ++i)
3018 				{
3019 					data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
3020 				}
3021 
3022 				delete[] boolParams;
3023 			}
3024 			else if(nativeType == GL_FLOAT)
3025 			{
3026 				GLfloat *floatParams = nullptr;
3027 				floatParams = new GLfloat[numParams];
3028 
3029 				context->getFloatv(target, floatParams);
3030 
3031 				for(unsigned int i = 0; i < numParams; ++i)
3032 				{
3033 					if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
3034 					{
3035 						data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
3036 					}
3037 					else
3038 					{
3039 						data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
3040 					}
3041 				}
3042 
3043 				delete[] floatParams;
3044 			}
3045 		}
3046 	}
3047 }
3048 
GetBufferParameteri64v(GLenum target,GLenum pname,GLint64 * params)3049 void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
3050 {
3051 	TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64 *params = %p)", target, pname, params);
3052 
3053 	auto context = es2::getContext();
3054 
3055 	if(context)
3056 	{
3057 		es2::Buffer *buffer = nullptr;
3058 
3059 		if(!context->getBuffer(target, &buffer))
3060 		{
3061 			return error(GL_INVALID_ENUM);
3062 		}
3063 
3064 		if(!buffer)
3065 		{
3066 			// A null buffer means that "0" is bound to the requested buffer target
3067 			return error(GL_INVALID_OPERATION);
3068 		}
3069 
3070 		switch(pname)
3071 		{
3072 		case GL_BUFFER_USAGE:
3073 			*params = buffer->usage();
3074 			break;
3075 		case GL_BUFFER_SIZE:
3076 			*params = buffer->size();
3077 			break;
3078 		case GL_BUFFER_ACCESS_FLAGS:
3079 			*params = buffer->access();
3080 			break;
3081 		case GL_BUFFER_MAPPED:
3082 			*params = buffer->isMapped();
3083 			break;
3084 		case GL_BUFFER_MAP_LENGTH:
3085 			*params = buffer->length();
3086 			break;
3087 		case GL_BUFFER_MAP_OFFSET:
3088 			*params = buffer->offset();
3089 			break;
3090 		default:
3091 			return error(GL_INVALID_ENUM);
3092 		}
3093 	}
3094 }
3095 
GenSamplers(GLsizei count,GLuint * samplers)3096 void GenSamplers(GLsizei count, GLuint *samplers)
3097 {
3098 	TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3099 
3100 	if(count < 0)
3101 	{
3102 		return error(GL_INVALID_VALUE);
3103 	}
3104 
3105 	auto context = es2::getContext();
3106 
3107 	if(context)
3108 	{
3109 		for(int i = 0; i < count; i++)
3110 		{
3111 			samplers[i] = context->createSampler();
3112 		}
3113 	}
3114 }
3115 
DeleteSamplers(GLsizei count,const GLuint * samplers)3116 void DeleteSamplers(GLsizei count, const GLuint *samplers)
3117 {
3118 	TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3119 
3120 	if(count < 0)
3121 	{
3122 		return error(GL_INVALID_VALUE);
3123 	}
3124 
3125 	auto context = es2::getContext();
3126 
3127 	if(context)
3128 	{
3129 		for(int i = 0; i < count; i++)
3130 		{
3131 			context->deleteSampler(samplers[i]);
3132 		}
3133 	}
3134 }
3135 
IsSampler(GLuint sampler)3136 GLboolean IsSampler(GLuint sampler)
3137 {
3138 	TRACE("(GLuint sampler = %d)", sampler);
3139 
3140 	if(sampler == 0)
3141 	{
3142 		return GL_FALSE;
3143 	}
3144 
3145 	auto context = es2::getContext();
3146 
3147 	if(context)
3148 	{
3149 		if(context->isSampler(sampler))
3150 		{
3151 			return GL_TRUE;
3152 		}
3153 	}
3154 
3155 	return GL_FALSE;
3156 }
3157 
BindSampler(GLuint unit,GLuint sampler)3158 void BindSampler(GLuint unit, GLuint sampler)
3159 {
3160 	TRACE("(GLuint unit = %d, GLuint sampler = %d)", unit, sampler);
3161 
3162 	if(unit >= es2::MAX_COMBINED_TEXTURE_IMAGE_UNITS)
3163 	{
3164 		return error(GL_INVALID_VALUE);
3165 	}
3166 
3167 	auto context = es2::getContext();
3168 
3169 	if(context)
3170 	{
3171 		if(sampler != 0 && !context->isSampler(sampler))
3172 		{
3173 			return error(GL_INVALID_OPERATION);
3174 		}
3175 
3176 		context->bindSampler(unit, sampler);
3177 	}
3178 }
3179 
SamplerParameteriv(GLuint sampler,GLenum pname,const GLint * param)3180 void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param)
3181 {
3182 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLint *param = %p)",
3183 	      sampler, pname, param);
3184 
3185 	if(!ValidateSamplerObjectParameter(pname))
3186 	{
3187 		return error(GL_INVALID_ENUM);
3188 	}
3189 
3190 	if(!ValidateTexParamParameters(pname, *param))
3191 	{
3192 		return;
3193 	}
3194 
3195 	auto context = es2::getContext();
3196 
3197 	if(context)
3198 	{
3199 		if(!context->isSampler(sampler))
3200 		{
3201 			return error(GL_INVALID_OPERATION);
3202 		}
3203 
3204 		context->samplerParameteri(sampler, pname, *param);
3205 	}
3206 }
3207 
SamplerParameteri(GLuint sampler,GLenum pname,GLint param)3208 void SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
3209 {
3210 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint param = %d)",
3211 	      sampler, pname, param);
3212 
3213 	SamplerParameteriv(sampler, pname, &param);
3214 }
3215 
SamplerParameterfv(GLuint sampler,GLenum pname,const GLfloat * param)3216 void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param)
3217 {
3218 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLfloat *param = %p)",
3219 	      sampler, pname, param);
3220 
3221 	if(!ValidateSamplerObjectParameter(pname))
3222 	{
3223 		return error(GL_INVALID_ENUM);
3224 	}
3225 
3226 	auto context = es2::getContext();
3227 
3228 	if(context)
3229 	{
3230 		if(!context->isSampler(sampler))
3231 		{
3232 			return error(GL_INVALID_OPERATION);
3233 		}
3234 
3235 		if(ValidateTexParamParameters(pname, static_cast<GLint>(roundf(*param))))
3236 		{
3237 			context->samplerParameterf(sampler, pname, *param);
3238 		}
3239 	}
3240 }
3241 
SamplerParameterf(GLuint sampler,GLenum pname,GLfloat param)3242 void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
3243 {
3244 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat param = %f)",
3245 	      sampler, pname, param);
3246 
3247 	SamplerParameterfv(sampler, pname, &param);
3248 }
3249 
GetSamplerParameteriv(GLuint sampler,GLenum pname,GLint * params)3250 void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
3251 {
3252 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint *params = %p)",
3253 	      sampler, pname, params);
3254 
3255 	if(!ValidateSamplerObjectParameter(pname))
3256 	{
3257 		return error(GL_INVALID_ENUM);
3258 	}
3259 
3260 	auto context = es2::getContext();
3261 
3262 	if(context)
3263 	{
3264 		if(!context->isSampler(sampler))
3265 		{
3266 			return error(GL_INVALID_OPERATION);
3267 		}
3268 
3269 		*params = context->getSamplerParameteri(sampler, pname);
3270 	}
3271 }
3272 
GetSamplerParameterfv(GLuint sampler,GLenum pname,GLfloat * params)3273 void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
3274 {
3275 	TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat *params = %p)",
3276 	      sampler, pname, params);
3277 
3278 	if(!ValidateSamplerObjectParameter(pname))
3279 	{
3280 		return error(GL_INVALID_ENUM);
3281 	}
3282 
3283 	auto context = es2::getContext();
3284 
3285 	if(context)
3286 	{
3287 		if(!context->isSampler(sampler))
3288 		{
3289 			return error(GL_INVALID_OPERATION);
3290 		}
3291 
3292 		*params = context->getSamplerParameterf(sampler, pname);
3293 	}
3294 }
3295 
VertexAttribDivisor(GLuint index,GLuint divisor)3296 void VertexAttribDivisor(GLuint index, GLuint divisor)
3297 {
3298 	TRACE("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
3299 
3300 	auto context = es2::getContext();
3301 
3302 	if(context)
3303 	{
3304 		if(index >= es2::MAX_VERTEX_ATTRIBS)
3305 		{
3306 			return error(GL_INVALID_VALUE);
3307 		}
3308 
3309 		context->setVertexAttribDivisor(index, divisor);
3310 	}
3311 }
3312 
BindTransformFeedback(GLenum target,GLuint id)3313 void BindTransformFeedback(GLenum target, GLuint id)
3314 {
3315 	TRACE("(GLenum target = 0x%X, GLuint id = %d)", target, id);
3316 
3317 	if(target != GL_TRANSFORM_FEEDBACK)
3318 	{
3319 		return error(GL_INVALID_ENUM);
3320 	}
3321 
3322 	auto context = es2::getContext();
3323 
3324 	if(context)
3325 	{
3326 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3327 
3328 		if(transformFeedbackObject && transformFeedbackObject->isActive() && !transformFeedbackObject->isPaused())
3329 		{
3330 			return error(GL_INVALID_OPERATION);
3331 		}
3332 
3333 		if(!context->isTransformFeedback(id))
3334 		{
3335 			return error(GL_INVALID_OPERATION);
3336 		}
3337 
3338 		context->bindTransformFeedback(id);
3339 	}
3340 }
3341 
DeleteTransformFeedbacks(GLsizei n,const GLuint * ids)3342 void DeleteTransformFeedbacks(GLsizei n, const GLuint *ids)
3343 {
3344 	TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3345 
3346 	if(n < 0)
3347 	{
3348 		return error(GL_INVALID_VALUE);
3349 	}
3350 
3351 	auto context = es2::getContext();
3352 
3353 	if(context)
3354 	{
3355 		for(int i = 0; i < n; i++)
3356 		{
3357 			if(ids[i] != 0)   // Attempts to delete default transform feedback silently ignored.
3358 			{
3359 				es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(ids[i]);
3360 
3361 				if(transformFeedbackObject && transformFeedbackObject->isActive())
3362 				{
3363 					return error(GL_INVALID_OPERATION);
3364 				}
3365 
3366 				context->deleteTransformFeedback(ids[i]);
3367 			}
3368 		}
3369 	}
3370 }
3371 
GenTransformFeedbacks(GLsizei n,GLuint * ids)3372 void GenTransformFeedbacks(GLsizei n, GLuint *ids)
3373 {
3374 	TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3375 
3376 	if(n < 0)
3377 	{
3378 		return error(GL_INVALID_VALUE);
3379 	}
3380 
3381 	auto context = es2::getContext();
3382 
3383 	if(context)
3384 	{
3385 		for(int i = 0; i < n; i++)
3386 		{
3387 			ids[i] = context->createTransformFeedback();
3388 		}
3389 	}
3390 }
3391 
IsTransformFeedback(GLuint id)3392 GLboolean IsTransformFeedback(GLuint id)
3393 {
3394 	TRACE("(GLuint id = %d)", id);
3395 
3396 	if(id == 0)
3397 	{
3398 		return GL_FALSE;
3399 	}
3400 
3401 	auto context = es2::getContext();
3402 
3403 	if(context)
3404 	{
3405 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(id);
3406 
3407 		if(transformFeedbackObject)
3408 		{
3409 			return GL_TRUE;
3410 		}
3411 	}
3412 
3413 	return GL_FALSE;
3414 }
3415 
PauseTransformFeedback(void)3416 void PauseTransformFeedback(void)
3417 {
3418 	TRACE("()");
3419 
3420 	auto context = es2::getContext();
3421 
3422 	if(context)
3423 	{
3424 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3425 
3426 		if(transformFeedbackObject)
3427 		{
3428 			if(!transformFeedbackObject->isActive() || transformFeedbackObject->isPaused())
3429 			{
3430 				return error(GL_INVALID_OPERATION);
3431 			}
3432 			transformFeedbackObject->setPaused(true);
3433 		}
3434 	}
3435 }
3436 
ResumeTransformFeedback(void)3437 void ResumeTransformFeedback(void)
3438 {
3439 	TRACE("()");
3440 
3441 	auto context = es2::getContext();
3442 
3443 	if(context)
3444 	{
3445 		es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3446 
3447 		if(transformFeedbackObject)
3448 		{
3449 			if(!transformFeedbackObject->isActive() || !transformFeedbackObject->isPaused())
3450 			{
3451 				return error(GL_INVALID_OPERATION);
3452 			}
3453 			transformFeedbackObject->setPaused(false);
3454 		}
3455 	}
3456 }
3457 
GetProgramBinary(GLuint program,GLsizei bufSize,GLsizei * length,GLenum * binaryFormat,void * binary)3458 void GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
3459 {
3460 	TRACE("(GLuint program = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLenum *binaryFormat = %p, void *binary = %p)",
3461 	      program, bufSize, length, binaryFormat, binary);
3462 
3463 	if(bufSize < 0)
3464 	{
3465 		return error(GL_INVALID_VALUE);
3466 	}
3467 
3468 	auto context = es2::getContext();
3469 
3470 	if(context)
3471 	{
3472 		es2::Program *programObject = context->getProgram(program);
3473 
3474 		if(!programObject || !programObject->isLinked())
3475 		{
3476 			return error(GL_INVALID_OPERATION);
3477 		}
3478 	}
3479 
3480 	// SwiftShader doesn't return a program binary and sets the program binay size to 0, so any attempt at getting one is invalid.
3481 	return error(GL_INVALID_OPERATION);
3482 }
3483 
ProgramBinary(GLuint program,GLenum binaryFormat,const void * binary,GLsizei length)3484 void ProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length)
3485 {
3486 	TRACE("(GLuint program = %d, GLenum binaryFormat = 0x%X, const void *binary = %p, GLsizei length = %d)",
3487 	      program, binaryFormat, binaryFormat, length);
3488 
3489 	if(length < 0)
3490 	{
3491 		return error(GL_INVALID_VALUE);
3492 	}
3493 
3494 	auto context = es2::getContext();
3495 
3496 	if(context)
3497 	{
3498 		es2::Program *programObject = context->getProgram(program);
3499 
3500 		if(!programObject)
3501 		{
3502 			return error(GL_INVALID_OPERATION);
3503 		}
3504 	}
3505 
3506 	// Regardless of what the binaryFormat is, it is unrecognized by SwiftShader, since it supports no format.
3507 	return error(GL_INVALID_ENUM);
3508 }
3509 
ProgramParameteri(GLuint program,GLenum pname,GLint value)3510 void ProgramParameteri(GLuint program, GLenum pname, GLint value)
3511 {
3512 	TRACE("(GLuint program = %d, GLenum pname = 0x%X, GLint value = %d)",
3513 	      program, pname, value);
3514 
3515 	auto context = es2::getContext();
3516 
3517 	if(context)
3518 	{
3519 		es2::Program *programObject = context->getProgram(program);
3520 
3521 		if(!programObject)
3522 		{
3523 			return error(GL_INVALID_VALUE);
3524 		}
3525 
3526 		switch(pname)
3527 		{
3528 		case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
3529 			if((value != GL_TRUE) && (value != GL_FALSE))
3530 			{
3531 				return error(GL_INVALID_VALUE);
3532 			}
3533 			programObject->setBinaryRetrievable(value != GL_FALSE);
3534 			break;
3535 		default:
3536 			return error(GL_INVALID_ENUM);
3537 		}
3538 	}
3539 }
3540 
InvalidateSubFramebuffer(GLenum target,GLsizei numAttachments,const GLenum * attachments,GLint x,GLint y,GLsizei width,GLsizei height)3541 void InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
3542 {
3543 	TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
3544 	      target, numAttachments, attachments, x, y, width, height);
3545 
3546 	auto context = es2::getContext();
3547 
3548 	if(context)
3549 	{
3550 		if(numAttachments < 0 || width < 0 || height < 0)
3551 		{
3552 			return error(GL_INVALID_VALUE);
3553 		}
3554 
3555 		es2::Framebuffer *framebuffer = nullptr;
3556 		switch(target)
3557 		{
3558 		case GL_DRAW_FRAMEBUFFER:
3559 		case GL_FRAMEBUFFER:
3560 			framebuffer = context->getDrawFramebuffer();
3561 			break;
3562 		case GL_READ_FRAMEBUFFER:
3563 			framebuffer = context->getReadFramebuffer();
3564 			break;
3565 		default:
3566 			return error(GL_INVALID_ENUM);
3567 		}
3568 
3569 		if(framebuffer)
3570 		{
3571 			for(int i = 0; i < numAttachments; i++)
3572 			{
3573 				switch(attachments[i])
3574 				{
3575 				case GL_COLOR:
3576 				case GL_DEPTH:
3577 				case GL_STENCIL:
3578 					if(!framebuffer->isDefaultFramebuffer())
3579 					{
3580 						return error(GL_INVALID_ENUM);
3581 					}
3582 					break;
3583 				case GL_DEPTH_ATTACHMENT:
3584 				case GL_STENCIL_ATTACHMENT:
3585 				case GL_DEPTH_STENCIL_ATTACHMENT:
3586 					break;
3587 				default:
3588 					if(attachments[i] >= GL_COLOR_ATTACHMENT0 &&
3589 					   attachments[i] <= GL_COLOR_ATTACHMENT31)
3590 					{
3591 						if(attachments[i] - GL_COLOR_ATTACHMENT0 >= MAX_DRAW_BUFFERS)
3592 						{
3593 							return error(GL_INVALID_OPERATION);
3594 						}
3595 					}
3596 					else
3597 					{
3598 						return error(GL_INVALID_ENUM);
3599 					}
3600 					break;
3601 				}
3602 			}
3603 		}
3604 
3605 		// UNIMPLEMENTED();   // It is valid for this function to be treated as a no-op
3606 	}
3607 }
3608 
InvalidateFramebuffer(GLenum target,GLsizei numAttachments,const GLenum * attachments)3609 void InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
3610 {
3611 	TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p)",
3612 	      target, numAttachments, attachments);
3613 
3614 	InvalidateSubFramebuffer(target, numAttachments, attachments, 0, 0, std::numeric_limits<GLsizei>::max(), std::numeric_limits<GLsizei>::max());
3615 }
3616 
TexStorage2D(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height)3617 void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
3618 {
3619 	TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
3620 	      target, levels, internalformat, width, height);
3621 
3622 	if(width < 1 || height < 1 || levels < 1 || ((target == GL_TEXTURE_RECTANGLE_ARB) && (levels != 1)))
3623 	{
3624 		return error(GL_INVALID_VALUE);
3625 	}
3626 
3627 	if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
3628 	{
3629 		return error(GL_INVALID_OPERATION);
3630 	}
3631 
3632 	bool isCompressed = IsCompressed(internalformat);
3633 	if(!IsSizedInternalFormat(internalformat) && !isCompressed)
3634 	{
3635 		return error(GL_INVALID_ENUM);
3636 	}
3637 
3638 	auto context = es2::getContext();
3639 
3640 	if(context)
3641 	{
3642 		switch(target)
3643 		{
3644 		case GL_TEXTURE_RECTANGLE_ARB:
3645 			if(isCompressed) // Rectangle textures cannot be compressed
3646 			{
3647 				return error(GL_INVALID_ENUM);
3648 			}
3649 			// Fall through to GL_TEXTURE_2D case.
3650 		case GL_TEXTURE_2D:
3651 			{
3652 				if((width > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE) ||
3653 				   (height > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE))
3654 				{
3655 					return error(GL_INVALID_VALUE);
3656 				}
3657 
3658 				es2::Texture2D *texture = context->getTexture2D(target);
3659 				if(!texture || texture->name == 0 || texture->getImmutableFormat() != GL_FALSE)
3660 				{
3661 					return error(GL_INVALID_OPERATION);
3662 				}
3663 
3664 				for(int level = 0; level < levels; level++)
3665 				{
3666 					texture->setImage(level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
3667 					width = std::max(1, (width / 2));
3668 					height = std::max(1, (height / 2));
3669 				}
3670 				texture->makeImmutable(levels);
3671 			}
3672 			break;
3673 		case GL_TEXTURE_CUBE_MAP:
3674 			{
3675 				if((width > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE) ||
3676 				   (height > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE))
3677 				{
3678 					return error(GL_INVALID_VALUE);
3679 				}
3680 
3681 				es2::TextureCubeMap *texture = context->getTextureCubeMap();
3682 				if(!texture || texture->name == 0 || texture->getImmutableFormat())
3683 				{
3684 					return error(GL_INVALID_OPERATION);
3685 				}
3686 
3687 				for(int level = 0; level < levels; level++)
3688 				{
3689 					for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
3690 					{
3691 						texture->setImage(face, level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
3692 					}
3693 					width = std::max(1, (width / 2));
3694 					height = std::max(1, (height / 2));
3695 				}
3696 				texture->makeImmutable(levels);
3697 			}
3698 			break;
3699 		default:
3700 			return error(GL_INVALID_ENUM);
3701 		}
3702 	}
3703 }
3704 
TexStorage3D(GLenum target,GLsizei levels,GLenum internalformat,GLsizei width,GLsizei height,GLsizei depth)3705 void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
3706 {
3707 	TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d)",
3708 	      target, levels, internalformat, width, height, depth);
3709 
3710 	if(width < 1 || height < 1 || depth < 1 || levels < 1)
3711 	{
3712 		return error(GL_INVALID_VALUE);
3713 	}
3714 
3715 	if(!IsSizedInternalFormat(internalformat) && !IsCompressed(internalformat))
3716 	{
3717 		return error(GL_INVALID_ENUM);
3718 	}
3719 
3720 	auto context = es2::getContext();
3721 
3722 	if(context)
3723 	{
3724 		switch(target)
3725 		{
3726 		case GL_TEXTURE_3D:
3727 			{
3728 				if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(std::max(width, height), depth)) + 1))
3729 				{
3730 					return error(GL_INVALID_OPERATION);
3731 				}
3732 
3733 				es2::Texture3D *texture = context->getTexture3D();
3734 				if(!texture || texture->name == 0 || texture->getImmutableFormat() != GL_FALSE)
3735 				{
3736 					return error(GL_INVALID_OPERATION);
3737 				}
3738 
3739 				for(int level = 0; level < levels; level++)
3740 				{
3741 					texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
3742 					width = std::max(1, (width / 2));
3743 					height = std::max(1, (height / 2));
3744 					depth = std::max(1, (depth / 2));
3745 				}
3746 				texture->makeImmutable(levels);
3747 			}
3748 			break;
3749 		case GL_TEXTURE_2D_ARRAY:
3750 			{
3751 				if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
3752 				{
3753 					return error(GL_INVALID_OPERATION);
3754 				}
3755 
3756 				es2::Texture3D *texture = context->getTexture2DArray();
3757 				if(!texture || texture->name == 0 || texture->getImmutableFormat())
3758 				{
3759 					return error(GL_INVALID_OPERATION);
3760 				}
3761 
3762 				for(int level = 0; level < levels; level++)
3763 				{
3764 					texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
3765 
3766 					width = std::max(1, (width / 2));
3767 					height = std::max(1, (height / 2));
3768 				}
3769 				texture->makeImmutable(levels);
3770 			}
3771 			break;
3772 		default:
3773 			return error(GL_INVALID_ENUM);
3774 		}
3775 	}
3776 }
3777 
GetInternalformativ(GLenum target,GLenum internalformat,GLenum pname,GLsizei bufSize,GLint * params)3778 void GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params)
3779 {
3780 	TRACE("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, GLint *params = %p)",
3781 	      target, internalformat, pname, bufSize, params);
3782 
3783 	if(bufSize < 0)
3784 	{
3785 		return error(GL_INVALID_VALUE);
3786 	}
3787 
3788 	if(bufSize == 0)
3789 	{
3790 		return;
3791 	}
3792 
3793 	// OpenGL ES 3.0, section 4.4.4: "An internal format is color-renderable if it is one of the formats
3794 	// from table 3.13 noted as color-renderable or if it is unsized format RGBA or RGB."
3795 	// Since we only use sized formats internally, replace them here (assuming type = GL_UNSIGNED_BYTE).
3796 	if(internalformat == GL_RGB)  internalformat = GL_RGB8;
3797 	if(internalformat == GL_RGBA) internalformat = GL_RGBA8;
3798 
3799 	if(!IsColorRenderable(internalformat) &&
3800 	   !IsDepthRenderable(internalformat) &&
3801 	   !IsStencilRenderable(internalformat))
3802 	{
3803 		return error(GL_INVALID_ENUM);
3804 	}
3805 
3806 	switch(target)
3807 	{
3808 	case GL_RENDERBUFFER:
3809 		break;
3810 	default:
3811 		return error(GL_INVALID_ENUM);
3812 	}
3813 
3814 	GLint numMultisampleCounts = NUM_MULTISAMPLE_COUNTS;
3815 
3816 	// Integer types have no multisampling
3817 	GLenum type = GetColorComponentType(internalformat);
3818 	if(type != GL_UNSIGNED_NORMALIZED && type != GL_FLOAT)
3819 	{
3820 		numMultisampleCounts = 0;
3821 	}
3822 
3823 	switch(pname)
3824 	{
3825 	case GL_NUM_SAMPLE_COUNTS:
3826 		*params = numMultisampleCounts;
3827 		break;
3828 	case GL_SAMPLES:
3829 		for(int i = 0; i < numMultisampleCounts && i < bufSize; i++)
3830 		{
3831 			params[i] = multisampleCount[i];
3832 		}
3833 		break;
3834 	default:
3835 		return error(GL_INVALID_ENUM);
3836 	}
3837 }
3838 
3839 }
3840