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// libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions.
15
16#include "main.h"
17#include "mathutil.h"
18#include "utilities.h"
19#include "Buffer.h"
20#include "Context.h"
21#include "Fence.h"
22#include "Framebuffer.h"
23#include "Program.h"
24#include "Renderbuffer.h"
25#include "Shader.h"
26#include "Texture.h"
27#include "Query.h"
28#include "TransformFeedback.h"
29#include "VertexArray.h"
30#include "common/debug.h"
31#include "Common/Version.h"
32
33#include <GLES2/gl2.h>
34#include <GLES2/gl2ext.h>
35#include <GLES3/gl3.h>
36
37#include <algorithm>
38#include <limits>
39
40namespace es2
41{
42
43static bool validImageSize(GLint level, GLsizei width, GLsizei height)
44{
45 if(level < 0 || level >= IMPLEMENTATION_MAX_TEXTURE_LEVELS || width < 0 || height < 0)
46 {
47 return false;
48 }
49
50 return true;
51}
52
53}
54
55namespace gl
56{
57
58using namespace es2;
59
60void GL_APIENTRY ActiveTexture(GLenum texture)
61{
62 TRACE("(GLenum texture = 0x%X)", texture);
63
64 auto context = es2::getContext();
65
66 if(context)
67 {
68 if(texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + es2::MAX_COMBINED_TEXTURE_IMAGE_UNITS - 1)
69 {
70 return error(GL_INVALID_ENUM);
71 }
72
73 context->setActiveSampler(texture - GL_TEXTURE0);
74 }
75}
76
77void GL_APIENTRY AttachShader(GLuint program, GLuint shader)
78{
79 TRACE("(GLuint program = %d, GLuint shader = %d)", program, shader);
80
81 auto context = es2::getContext();
82
83 if(context)
84 {
85 es2::Program *programObject = context->getProgram(program);
86 es2::Shader *shaderObject = context->getShader(shader);
87
88 if(!programObject)
89 {
90 if(context->getShader(program))
91 {
92 return error(GL_INVALID_OPERATION);
93 }
94 else
95 {
96 return error(GL_INVALID_VALUE);
97 }
98 }
99
100 if(!shaderObject)
101 {
102 if(context->getProgram(shader))
103 {
104 return error(GL_INVALID_OPERATION);
105 }
106 else
107 {
108 return error(GL_INVALID_VALUE);
109 }
110 }
111
112 if(!programObject->attachShader(shaderObject))
113 {
114 return error(GL_INVALID_OPERATION);
115 }
116 }
117}
118
119void GL_APIENTRY BeginQueryEXT(GLenum target, GLuint name)
120{
121 TRACE("(GLenum target = 0x%X, GLuint name = %d)", target, name);
122
123 switch(target)
124 {
125 case GL_ANY_SAMPLES_PASSED_EXT:
126 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
127 break;
128 default:
129 return error(GL_INVALID_ENUM);
130 }
131
132 if(name == 0)
133 {
134 return error(GL_INVALID_OPERATION);
135 }
136
137 auto context = es2::getContext();
138
139 if(context)
140 {
141 context->beginQuery(target, name);
142 }
143}
144
145void GL_APIENTRY BindAttribLocation(GLuint program, GLuint index, const GLchar* name)
146{
147 TRACE("(GLuint program = %d, GLuint index = %d, const GLchar* name = %s)", program, index, name);
148
149 if(index >= es2::MAX_VERTEX_ATTRIBS)
150 {
151 return error(GL_INVALID_VALUE);
152 }
153
154 auto context = es2::getContext();
155
156 if(context)
157 {
158 es2::Program *programObject = context->getProgram(program);
159
160 if(!programObject)
161 {
162 if(context->getShader(program))
163 {
164 return error(GL_INVALID_OPERATION);
165 }
166 else
167 {
168 return error(GL_INVALID_VALUE);
169 }
170 }
171
172 if(strncmp(name, "gl_", 3) == 0)
173 {
174 return error(GL_INVALID_OPERATION);
175 }
176
177 programObject->bindAttributeLocation(index, name);
178 }
179}
180
181void GL_APIENTRY BindBuffer(GLenum target, GLuint buffer)
182{
183 TRACE("(GLenum target = 0x%X, GLuint buffer = %d)", target, buffer);
184
185 auto context = es2::getContext();
186
187 if(context)
188 {
189 switch(target)
190 {
191 case GL_ARRAY_BUFFER:
192 context->bindArrayBuffer(buffer);
193 return;
194 case GL_ELEMENT_ARRAY_BUFFER:
195 context->bindElementArrayBuffer(buffer);
196 return;
197 case GL_COPY_READ_BUFFER:
198 context->bindCopyReadBuffer(buffer);
199 return;
200 case GL_COPY_WRITE_BUFFER:
201 context->bindCopyWriteBuffer(buffer);
202 return;
203 case GL_PIXEL_PACK_BUFFER:
204 context->bindPixelPackBuffer(buffer);
205 return;
206 case GL_PIXEL_UNPACK_BUFFER:
207 context->bindPixelUnpackBuffer(buffer);
208 return;
209 case GL_TRANSFORM_FEEDBACK_BUFFER:
210 context->bindTransformFeedbackBuffer(buffer);
211 return;
212 case GL_UNIFORM_BUFFER:
213 context->bindGenericUniformBuffer(buffer);
214 return;
215 default:
216 return error(GL_INVALID_ENUM);
217 }
218 }
219}
220
221void GL_APIENTRY BindFramebuffer(GLenum target, GLuint framebuffer)
222{
223 TRACE("(GLenum target = 0x%X, GLuint framebuffer = %d)", target, framebuffer);
224
225 if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
226 {
227 return error(GL_INVALID_ENUM);
228 }
229
230 auto context = es2::getContext();
231
232 if(context)
233 {
234 if(target == GL_READ_FRAMEBUFFER || target == GL_FRAMEBUFFER)
235 {
236 context->bindReadFramebuffer(framebuffer);
237 }
238
239 if(target == GL_DRAW_FRAMEBUFFER || target == GL_FRAMEBUFFER)
240 {
241 context->bindDrawFramebuffer(framebuffer);
242 }
243 }
244}
245
246void GL_APIENTRY BindRenderbuffer(GLenum target, GLuint renderbuffer)
247{
248 TRACE("(GLenum target = 0x%X, GLuint renderbuffer = %d)", target, renderbuffer);
249
250 if(target != GL_RENDERBUFFER)
251 {
252 return error(GL_INVALID_ENUM);
253 }
254
255 auto context = es2::getContext();
256
257 if(context)
258 {
259 // [OpenGL ES 2.0.25] Section 4.4.3 page 110
260 // [OpenGL ES 3.0.4] Section 4.4.2 page 204
261 // If renderbuffer is not zero, then the resulting renderbuffer object
262 // is a new state vector, initialized with a zero-sized memory buffer.
263 context->bindRenderbuffer(renderbuffer);
264 }
265}
266
267void GL_APIENTRY BindTexture(GLenum target, GLuint texture)
268{
269 TRACE("(GLenum target = 0x%X, GLuint texture = %d)", target, texture);
270
271 auto context = es2::getContext();
272
273 if(context)
274 {
275 es2::Texture *textureObject = context->getTexture(texture);
276
277 if(textureObject && textureObject->getTarget() != target && texture != 0)
278 {
279 return error(GL_INVALID_OPERATION);
280 }
281
282 switch(target)
283 {
284 case GL_TEXTURE_2D:
285 context->bindTexture(TEXTURE_2D, texture);
286 break;
287 case GL_TEXTURE_CUBE_MAP:
288 context->bindTexture(TEXTURE_CUBE, texture);
289 break;
290 case GL_TEXTURE_EXTERNAL_OES:
291 context->bindTexture(TEXTURE_EXTERNAL, texture);
292 break;
293 case GL_TEXTURE_2D_ARRAY:
294 context->bindTexture(TEXTURE_2D_ARRAY, texture);
295 break;
296 case GL_TEXTURE_3D:
297 context->bindTexture(TEXTURE_3D, texture);
298 break;
299 case GL_TEXTURE_RECTANGLE_ARB:
300 context->bindTexture(TEXTURE_2D_RECT, texture);
301 break;
302 default:
303 return error(GL_INVALID_ENUM);
304 }
305 }
306}
307
308void GL_APIENTRY BlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
309{
310 TRACE("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
311 red, green, blue, alpha);
312
313 auto context = es2::getContext();
314
315 if(context)
316 {
317 context->setBlendColor(es2::clamp01(red), es2::clamp01(green), es2::clamp01(blue), es2::clamp01(alpha));
318 }
319}
320
321void GL_APIENTRY BlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
322{
323 TRACE("(GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X)", modeRGB, modeAlpha);
324
325 switch(modeRGB)
326 {
327 case GL_FUNC_ADD:
328 case GL_FUNC_SUBTRACT:
329 case GL_FUNC_REVERSE_SUBTRACT:
330 case GL_MIN_EXT:
331 case GL_MAX_EXT:
332 break;
333 default:
334 return error(GL_INVALID_ENUM);
335 }
336
337 switch(modeAlpha)
338 {
339 case GL_FUNC_ADD:
340 case GL_FUNC_SUBTRACT:
341 case GL_FUNC_REVERSE_SUBTRACT:
342 case GL_MIN_EXT:
343 case GL_MAX_EXT:
344 break;
345 default:
346 return error(GL_INVALID_ENUM);
347 }
348
349 auto context = es2::getContext();
350
351 if(context)
352 {
353 context->setBlendEquation(modeRGB, modeAlpha);
354 }
355}
356
357void GL_APIENTRY BlendEquation(GLenum mode)
358{
359 BlendEquationSeparate(mode, mode);
360}
361
362void GL_APIENTRY BlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
363{
364 TRACE("(GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X)",
365 srcRGB, dstRGB, srcAlpha, dstAlpha);
366
367 switch(srcRGB)
368 {
369 case GL_ZERO:
370 case GL_ONE:
371 case GL_SRC_COLOR:
372 case GL_ONE_MINUS_SRC_COLOR:
373 case GL_DST_COLOR:
374 case GL_ONE_MINUS_DST_COLOR:
375 case GL_SRC_ALPHA:
376 case GL_ONE_MINUS_SRC_ALPHA:
377 case GL_DST_ALPHA:
378 case GL_ONE_MINUS_DST_ALPHA:
379 case GL_CONSTANT_COLOR:
380 case GL_ONE_MINUS_CONSTANT_COLOR:
381 case GL_CONSTANT_ALPHA:
382 case GL_ONE_MINUS_CONSTANT_ALPHA:
383 case GL_SRC_ALPHA_SATURATE:
384 break;
385 default:
386 return error(GL_INVALID_ENUM);
387 }
388
389 switch(dstRGB)
390 {
391 case GL_ZERO:
392 case GL_ONE:
393 case GL_SRC_COLOR:
394 case GL_ONE_MINUS_SRC_COLOR:
395 case GL_DST_COLOR:
396 case GL_ONE_MINUS_DST_COLOR:
397 case GL_SRC_ALPHA:
398 case GL_ONE_MINUS_SRC_ALPHA:
399 case GL_DST_ALPHA:
400 case GL_ONE_MINUS_DST_ALPHA:
401 case GL_CONSTANT_COLOR:
402 case GL_ONE_MINUS_CONSTANT_COLOR:
403 case GL_CONSTANT_ALPHA:
404 case GL_ONE_MINUS_CONSTANT_ALPHA:
405 break;
406 case GL_SRC_ALPHA_SATURATE:
407 break;
408 default:
409 return error(GL_INVALID_ENUM);
410 }
411
412 switch(srcAlpha)
413 {
414 case GL_ZERO:
415 case GL_ONE:
416 case GL_SRC_COLOR:
417 case GL_ONE_MINUS_SRC_COLOR:
418 case GL_DST_COLOR:
419 case GL_ONE_MINUS_DST_COLOR:
420 case GL_SRC_ALPHA:
421 case GL_ONE_MINUS_SRC_ALPHA:
422 case GL_DST_ALPHA:
423 case GL_ONE_MINUS_DST_ALPHA:
424 case GL_CONSTANT_COLOR:
425 case GL_ONE_MINUS_CONSTANT_COLOR:
426 case GL_CONSTANT_ALPHA:
427 case GL_ONE_MINUS_CONSTANT_ALPHA:
428 case GL_SRC_ALPHA_SATURATE:
429 break;
430 default:
431 return error(GL_INVALID_ENUM);
432 }
433
434 switch(dstAlpha)
435 {
436 case GL_ZERO:
437 case GL_ONE:
438 case GL_SRC_COLOR:
439 case GL_ONE_MINUS_SRC_COLOR:
440 case GL_DST_COLOR:
441 case GL_ONE_MINUS_DST_COLOR:
442 case GL_SRC_ALPHA:
443 case GL_ONE_MINUS_SRC_ALPHA:
444 case GL_DST_ALPHA:
445 case GL_ONE_MINUS_DST_ALPHA:
446 case GL_CONSTANT_COLOR:
447 case GL_ONE_MINUS_CONSTANT_COLOR:
448 case GL_CONSTANT_ALPHA:
449 case GL_ONE_MINUS_CONSTANT_ALPHA:
450 break;
451 case GL_SRC_ALPHA_SATURATE:
452 break;
453 default:
454 return error(GL_INVALID_ENUM);
455 }
456
457 auto context = es2::getContext();
458
459 if(context)
460 {
461 context->setBlendFactors(srcRGB, dstRGB, srcAlpha, dstAlpha);
462 }
463}
464
465void GL_APIENTRY BlendFunc(GLenum sfactor, GLenum dfactor)
466{
467 BlendFuncSeparate(sfactor, dfactor, sfactor, dfactor);
468}
469
470void GL_APIENTRY BufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
471{
472 size = static_cast<GLint>(size); // Work around issues with some 64-bit applications
473
474 TRACE("(GLenum target = 0x%X, GLsizeiptr size = %d, const GLvoid* data = %p, GLenum usage = %d)",
475 target, size, data, usage);
476
477 if(size < 0)
478 {
479 return error(GL_INVALID_VALUE);
480 }
481
482 switch(usage)
483 {
484 case GL_STREAM_DRAW:
485 case GL_STATIC_DRAW:
486 case GL_DYNAMIC_DRAW:
487 break;
488 case GL_STREAM_READ:
489 case GL_STREAM_COPY:
490 case GL_STATIC_READ:
491 case GL_STATIC_COPY:
492 case GL_DYNAMIC_READ:
493 case GL_DYNAMIC_COPY:
494 break;
495 default:
496 return error(GL_INVALID_ENUM);
497 }
498
499 auto context = es2::getContext();
500
501 if(context)
502 {
503 es2::Buffer *buffer = nullptr;
504 if(!context->getBuffer(target, &buffer))
505 {
506 return error(GL_INVALID_ENUM);
507 }
508
509 if(!buffer)
510 {
511 // A null buffer means that "0" is bound to the requested buffer target
512 return error(GL_INVALID_OPERATION);
513 }
514
515 buffer->bufferData(data, size, usage);
516 }
517}
518
519void GL_APIENTRY BufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
520{
521 size = static_cast<GLint>(size); // Work around issues with some 64-bit applications
522 offset = static_cast<GLint>(offset);
523
524 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const GLvoid* data = %p)",
525 target, offset, size, data);
526
527 if(size < 0 || offset < 0)
528 {
529 return error(GL_INVALID_VALUE);
530 }
531
532 auto context = es2::getContext();
533
534 if(context)
535 {
536 es2::Buffer *buffer = nullptr;
537 if(!context->getBuffer(target, &buffer))
538 {
539 return error(GL_INVALID_ENUM);
540 }
541
542 if(!buffer)
543 {
544 // A null buffer means that "0" is bound to the requested buffer target
545 return error(GL_INVALID_OPERATION);
546 }
547
548 if(buffer->isMapped())
549 {
550 // It is an invalid operation to update an already mapped buffer
551 return error(GL_INVALID_OPERATION);
552 }
553
554 if((size_t)size + offset > buffer->size())
555 {
556 return error(GL_INVALID_VALUE);
557 }
558
559 buffer->bufferSubData(data, size, offset);
560 }
561}
562
563GLenum GL_APIENTRY CheckFramebufferStatus(GLenum target)
564{
565 TRACE("(GLenum target = 0x%X)", target);
566
567 if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
568 {
569 return error(GL_INVALID_ENUM, 0);
570 }
571
572 auto context = es2::getContext();
573
574 if(context)
575 {
576 es2::Framebuffer *framebuffer = nullptr;
577 if(target == GL_READ_FRAMEBUFFER)
578 {
579 framebuffer = context->getReadFramebuffer();
580 }
581 else
582 {
583 framebuffer = context->getDrawFramebuffer();
584 }
585
586 if(!framebuffer)
587 {
588 return GL_FRAMEBUFFER_UNDEFINED_OES;
589 }
590
591 return framebuffer->completeness();
592 }
593
594 return 0;
595}
596
597void GL_APIENTRY Clear(GLbitfield mask)
598{
599 TRACE("(GLbitfield mask = %X)", mask);
600
601 if((mask & ~(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT)) != 0)
602 {
603 return error(GL_INVALID_VALUE);
604 }
605
606 auto context = es2::getContext();
607
608 if(context)
609 {
610 context->clear(mask);
611 }
612}
613
614void GL_APIENTRY ClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
615{
616 TRACE("(GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f)",
617 red, green, blue, alpha);
618
619 auto context = es2::getContext();
620
621 if(context)
622 {
623 context->setClearColor(red, green, blue, alpha);
624 }
625}
626
627void GL_APIENTRY ClearDepthf(GLclampf depth)
628{
629 TRACE("(GLclampf depth = %f)", depth);
630
631 auto context = es2::getContext();
632
633 if(context)
634 {
635 context->setClearDepth(depth);
636 }
637}
638
639void GL_APIENTRY ClearStencil(GLint s)
640{
641 TRACE("(GLint s = %d)", s);
642
643 auto context = es2::getContext();
644
645 if(context)
646 {
647 context->setClearStencil(s);
648 }
649}
650
651void GL_APIENTRY ColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
652{
653 TRACE("(GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d)",
654 red, green, blue, alpha);
655
656 auto context = es2::getContext();
657
658 if(context)
659 {
660 context->setColorMask(red != GL_FALSE, green != GL_FALSE, blue != GL_FALSE, alpha != GL_FALSE);
661 }
662}
663
664void GL_APIENTRY CompileShader(GLuint shader)
665{
666 TRACE("(GLuint shader = %d)", shader);
667
668 auto context = es2::getContext();
669
670 if(context)
671 {
672 es2::Shader *shaderObject = context->getShader(shader);
673
674 if(!shaderObject)
675 {
676 if(context->getProgram(shader))
677 {
678 return error(GL_INVALID_OPERATION);
679 }
680 else
681 {
682 return error(GL_INVALID_VALUE);
683 }
684 }
685
686 shaderObject->compile();
687 }
688}
689
690void GL_APIENTRY CompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height,
691 GLint border, GLsizei imageSize, const GLvoid* data)
692{
693 TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
694 "GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = %p)",
695 target, level, internalformat, width, height, border, imageSize, data);
696
697 if(!validImageSize(level, width, height) || border != 0 || imageSize < 0)
698 {
699 return error(GL_INVALID_VALUE);
700 }
701
702 if(!IsCompressed(internalformat))
703 {
704 return error(GL_INVALID_ENUM);
705 }
706
707 if(border != 0)
708 {
709 return error(GL_INVALID_VALUE);
710 }
711
712 auto context = es2::getContext();
713
714 if(context)
715 {
716 if(level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
717 {
718 return error(GL_INVALID_VALUE);
719 }
720
721 switch(target)
722 {
723 case GL_TEXTURE_2D:
724 if(width > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
725 height > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))
726 {
727 return error(GL_INVALID_VALUE);
728 }
729 break;
730 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
731 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
732 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
733 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
734 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
735 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
736 if(width != height)
737 {
738 return error(GL_INVALID_VALUE);
739 }
740
741 if(width > (es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level) ||
742 height > (es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level))
743 {
744 return error(GL_INVALID_VALUE);
745 }
746 break;
747 case GL_TEXTURE_RECTANGLE_ARB: // Rectangle textures cannot be compressed
748 default:
749 return error(GL_INVALID_ENUM);
750 }
751
752 if(imageSize != gl::ComputeCompressedSize(width, height, internalformat))
753 {
754 return error(GL_INVALID_VALUE);
755 }
756
757 GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
758 if(validationError != GL_NO_ERROR)
759 {
760 return error(validationError);
761 }
762
763 if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
764 {
765 es2::Texture2D *texture = context->getTexture2D(target);
766
767 if(!texture)
768 {
769 return error(GL_INVALID_OPERATION);
770 }
771
772 texture->setCompressedImage(level, internalformat, width, height, imageSize, data);
773 }
774 else if(es2::IsCubemapTextureTarget(target))
775 {
776 es2::TextureCubeMap *texture = context->getTextureCubeMap();
777
778 if(!texture)
779 {
780 return error(GL_INVALID_OPERATION);
781 }
782
783 texture->setCompressedImage(target, level, internalformat, width, height, imageSize, data);
784 }
785 else UNREACHABLE(target);
786 }
787}
788
789void GL_APIENTRY CompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
790 GLenum format, GLsizei imageSize, const GLvoid* data)
791{
792 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
793 "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, "
794 "GLsizei imageSize = %d, const GLvoid* data = %p)",
795 target, level, xoffset, yoffset, width, height, format, imageSize, data);
796
797 if(!es2::IsTexImageTarget(target))
798 {
799 return error(GL_INVALID_ENUM);
800 }
801
802 if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
803 {
804 return error(GL_INVALID_VALUE);
805 }
806
807 if(xoffset < 0 || yoffset < 0 || !validImageSize(level, width, height) || imageSize < 0)
808 {
809 return error(GL_INVALID_VALUE);
810 }
811
812 if(!IsCompressed(format))
813 {
814 return error(GL_INVALID_ENUM);
815 }
816
817 if(imageSize != gl::ComputeCompressedSize(width, height, format))
818 {
819 return error(GL_INVALID_VALUE);
820 }
821
822 auto context = es2::getContext();
823
824 if(context)
825 {
826 if(xoffset % 4 != 0 || yoffset % 4 != 0)
827 {
828 // We wait to check the offsets until this point, because the multiple-of-four restriction does not exist unless DXT1 textures are supported
829 return error(GL_INVALID_OPERATION);
830 }
831
832 GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
833 if(validationError != GL_NO_ERROR)
834 {
835 return error(validationError);
836 }
837
838 if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
839 {
840 es2::Texture2D *texture = context->getTexture2D(target);
841
842 GLenum validationError = ValidateSubImageParams(true, false, target, level, xoffset, yoffset, width, height, format, GL_NONE, texture);
843 if(validationError != GL_NO_ERROR)
844 {
845 return error(validationError);
846 }
847
848 texture->subImageCompressed(level, xoffset, yoffset, width, height, format, imageSize, data);
849 }
850 else if(es2::IsCubemapTextureTarget(target))
851 {
852 es2::TextureCubeMap *texture = context->getTextureCubeMap();
853
854 GLenum validationError = ValidateSubImageParams(true, false, target, level, xoffset, yoffset, width, height, format, GL_NONE, texture);
855 if(validationError != GL_NO_ERROR)
856 {
857 return error(validationError);
858 }
859
860 texture->subImageCompressed(target, level, xoffset, yoffset, width, height, format, imageSize, data);
861 }
862 else UNREACHABLE(target);
863 }
864}
865
866void GL_APIENTRY CopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
867{
868 TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
869 "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d)",
870 target, level, internalformat, x, y, width, height, border);
871
872 if(!validImageSize(level, width, height))
873 {
874 return error(GL_INVALID_VALUE);
875 }
876
877 if(border != 0)
878 {
879 return error(GL_INVALID_VALUE);
880 }
881
882 auto context = es2::getContext();
883
884 if(context)
885 {
886 switch(target)
887 {
888 case GL_TEXTURE_RECTANGLE_ARB:
889 if(level != 0)
890 {
891 return error(GL_INVALID_VALUE);
892 }
893 // Fall through to GL_TEXTURE_2D case.
894 case GL_TEXTURE_2D:
895 if(width > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
896 height > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))
897 {
898 return error(GL_INVALID_VALUE);
899 }
900 break;
901 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
902 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
903 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
904 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
905 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
906 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
907 if(width != height)
908 {
909 return error(GL_INVALID_VALUE);
910 }
911
912 if(width > (es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level) ||
913 height > (es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level))
914 {
915 return error(GL_INVALID_VALUE);
916 }
917 break;
918 default:
919 return error(GL_INVALID_ENUM);
920 }
921
922 es2::Framebuffer *framebuffer = context->getReadFramebuffer();
923
924 if(!framebuffer || (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE))
925 {
926 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
927 }
928
929 es2::Renderbuffer *source = framebuffer->getReadColorbuffer();
930
931 if(context->getReadFramebufferName() != 0 && (!source || source->getSamples() > 1))
932 {
933 return error(GL_INVALID_OPERATION);
934 }
935
936 GLenum colorbufferFormat = source->getFormat();
937
938 // Determine the sized internal format.
939 if(gl::IsUnsizedInternalFormat(internalformat))
940 {
941 if(colorbufferFormat == GL_RGB10_A2)
942 {
943 // Not supported with unsized internalformat.
944 // https://www.khronos.org/members/login/bugzilla/show_bug.cgi?id=9807#c56
945 return error(GL_INVALID_OPERATION);
946 }
947
948 if(gl::GetBaseInternalFormat(colorbufferFormat) == internalformat)
949 {
950 internalformat = colorbufferFormat;
951 }
952 else if(GetColorComponentType(colorbufferFormat) == GL_UNSIGNED_NORMALIZED && GetRedSize(colorbufferFormat) <= 8)
953 {
954 // TODO: Convert to the smallest format that fits all components.
955 // e.g. Copying RGBA4 to RGB should result in RGB565, not RGB8.
956
957 internalformat = gl::GetSizedInternalFormat(internalformat, GL_UNSIGNED_BYTE);
958 }
959 else if(GetColorComponentType(colorbufferFormat) == GL_INT)
960 {
961 internalformat = gl::GetSizedInternalFormat(internalformat, GL_INT);
962 }
963 else if(GetColorComponentType(colorbufferFormat) == GL_UNSIGNED_INT)
964 {
965 internalformat = gl::GetSizedInternalFormat(internalformat, GL_UNSIGNED_INT);
966 }
967 else if(GetColorComponentType(colorbufferFormat) == GL_FLOAT && GetRedSize(colorbufferFormat) == 16) // GL_EXT_color_buffer_half_float
968 {
969 internalformat = gl::GetSizedInternalFormat(internalformat, GL_HALF_FLOAT_OES);
970 }
971 else if(GetColorComponentType(colorbufferFormat) == GL_FLOAT && GetRedSize(colorbufferFormat) == 32) // GL_EXT_color_buffer_float
972 {
973 internalformat = gl::GetSizedInternalFormat(internalformat, GL_FLOAT);
974 }
975 else
976 {
977 UNIMPLEMENTED("internalformat = %x, colorbufferFormat = %X", internalformat, colorbufferFormat);
978
979 return error(GL_INVALID_OPERATION);
980 }
981 }
982
983 if(!ValidateCopyFormats(internalformat, colorbufferFormat))
984 {
985 return;
986 }
987
988 if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
989 {
990 es2::Texture2D *texture = context->getTexture2D(target);
991
992 if(!texture)
993 {
994 return error(GL_INVALID_OPERATION);
995 }
996
997 texture->copyImage(level, internalformat, x, y, width, height, source);
998 }
999 else if(es2::IsCubemapTextureTarget(target))
1000 {
1001 es2::TextureCubeMap *texture = context->getTextureCubeMap();
1002
1003 if(!texture)
1004 {
1005 return error(GL_INVALID_OPERATION);
1006 }
1007
1008 texture->copyImage(target, level, internalformat, x, y, width, height, source);
1009 }
1010 else UNREACHABLE(target);
1011 }
1012}
1013
1014void GL_APIENTRY CopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
1015{
1016 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
1017 "GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
1018 target, level, xoffset, yoffset, x, y, width, height);
1019
1020 if(!es2::IsTexImageTarget(target))
1021 {
1022 return error(GL_INVALID_ENUM);
1023 }
1024
1025 if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1026 {
1027 return error(GL_INVALID_VALUE);
1028 }
1029
1030 if(xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
1031 {
1032 return error(GL_INVALID_VALUE);
1033 }
1034
1035 if(std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
1036 {
1037 return error(GL_INVALID_VALUE);
1038 }
1039
1040 auto context = es2::getContext();
1041
1042 if(context)
1043 {
1044 es2::Framebuffer *framebuffer = context->getReadFramebuffer();
1045
1046 if(!framebuffer || (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE))
1047 {
1048 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
1049 }
1050
1051 es2::Renderbuffer *source = framebuffer->getReadColorbuffer();
1052
1053 if(context->getReadFramebufferName() != 0 && (!source || source->getSamples() > 1))
1054 {
1055 return error(GL_INVALID_OPERATION);
1056 }
1057
1058 es2::Texture *texture = nullptr;
1059
1060 if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
1061 {
1062 texture = context->getTexture2D(target);
1063 }
1064 else if(es2::IsCubemapTextureTarget(target))
1065 {
1066 texture = context->getTextureCubeMap();
1067 }
1068 else UNREACHABLE(target);
1069
1070 GLenum validationError = ValidateSubImageParams(false, true, target, level, xoffset, yoffset, width, height, GL_NONE, GL_NONE, texture);
1071 if(validationError != GL_NO_ERROR)
1072 {
1073 return error(validationError);
1074 }
1075
1076 texture->copySubImage(target, level, xoffset, yoffset, 0, x, y, width, height, source);
1077 }
1078}
1079
1080GLuint GL_APIENTRY CreateProgram(void)
1081{
1082 TRACE("()");
1083
1084 auto context = es2::getContext();
1085
1086 if(context)
1087 {
1088 return context->createProgram();
1089 }
1090
1091 return 0;
1092}
1093
1094GLuint GL_APIENTRY CreateShader(GLenum type)
1095{
1096 TRACE("(GLenum type = 0x%X)", type);
1097
1098 auto context = es2::getContext();
1099
1100 if(context)
1101 {
1102 switch(type)
1103 {
1104 case GL_FRAGMENT_SHADER:
1105 case GL_VERTEX_SHADER:
1106 return context->createShader(type);
1107 default:
1108 return error(GL_INVALID_ENUM, 0);
1109 }
1110 }
1111
1112 return 0;
1113}
1114
1115void GL_APIENTRY CullFace(GLenum mode)
1116{
1117 TRACE("(GLenum mode = 0x%X)", mode);
1118
1119 switch(mode)
1120 {
1121 case GL_FRONT:
1122 case GL_BACK:
1123 case GL_FRONT_AND_BACK:
1124 {
1125 auto context = es2::getContext();
1126
1127 if(context)
1128 {
1129 context->setCullMode(mode);
1130 }
1131 }
1132 break;
1133 default:
1134 return error(GL_INVALID_ENUM);
1135 }
1136}
1137
1138void GL_APIENTRY DeleteBuffers(GLsizei n, const GLuint* buffers)
1139{
1140 TRACE("(GLsizei n = %d, const GLuint* buffers = %p)", n, buffers);
1141
1142 if(n < 0)
1143 {
1144 return error(GL_INVALID_VALUE);
1145 }
1146
1147 auto context = es2::getContext();
1148
1149 if(context)
1150 {
1151 for(int i = 0; i < n; i++)
1152 {
1153 context->deleteBuffer(buffers[i]);
1154 }
1155 }
1156}
1157
1158void GL_APIENTRY DeleteFencesNV(GLsizei n, const GLuint* fences)
1159{
1160 TRACE("(GLsizei n = %d, const GLuint* fences = %p)", n, fences);
1161
1162 if(n < 0)
1163 {
1164 return error(GL_INVALID_VALUE);
1165 }
1166
1167 auto context = es2::getContext();
1168
1169 if(context)
1170 {
1171 for(int i = 0; i < n; i++)
1172 {
1173 context->deleteFence(fences[i]);
1174 }
1175 }
1176}
1177
1178void GL_APIENTRY DeleteFramebuffers(GLsizei n, const GLuint* framebuffers)
1179{
1180 TRACE("(GLsizei n = %d, const GLuint* framebuffers = %p)", n, framebuffers);
1181
1182 if(n < 0)
1183 {
1184 return error(GL_INVALID_VALUE);
1185 }
1186
1187 auto context = es2::getContext();
1188
1189 if(context)
1190 {
1191 for(int i = 0; i < n; i++)
1192 {
1193 if(framebuffers[i] != 0) // Attempts to delete default framebuffer silently ignored.
1194 {
1195 context->deleteFramebuffer(framebuffers[i]);
1196 }
1197 }
1198 }
1199}
1200
1201void GL_APIENTRY DeleteProgram(GLuint program)
1202{
1203 TRACE("(GLuint program = %d)", program);
1204
1205 if(program == 0)
1206 {
1207 return;
1208 }
1209
1210 auto context = es2::getContext();
1211
1212 if(context)
1213 {
1214 if(!context->getProgram(program))
1215 {
1216 if(context->getShader(program))
1217 {
1218 return error(GL_INVALID_OPERATION);
1219 }
1220 else
1221 {
1222 return error(GL_INVALID_VALUE);
1223 }
1224 }
1225
1226 context->deleteProgram(program);
1227 }
1228}
1229
1230void GL_APIENTRY DeleteQueriesEXT(GLsizei n, const GLuint *ids)
1231{
1232 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
1233
1234 if(n < 0)
1235 {
1236 return error(GL_INVALID_VALUE);
1237 }
1238
1239 auto context = es2::getContext();
1240
1241 if(context)
1242 {
1243 for(int i = 0; i < n; i++)
1244 {
1245 context->deleteQuery(ids[i]);
1246 }
1247 }
1248}
1249
1250void GL_APIENTRY DeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers)
1251{
1252 TRACE("(GLsizei n = %d, const GLuint* renderbuffers = %p)", n, renderbuffers);
1253
1254 if(n < 0)
1255 {
1256 return error(GL_INVALID_VALUE);
1257 }
1258
1259 auto context = es2::getContext();
1260
1261 if(context)
1262 {
1263 for(int i = 0; i < n; i++)
1264 {
1265 context->deleteRenderbuffer(renderbuffers[i]);
1266 }
1267 }
1268}
1269
1270void GL_APIENTRY DeleteShader(GLuint shader)
1271{
1272 TRACE("(GLuint shader = %d)", shader);
1273
1274 if(shader == 0)
1275 {
1276 return;
1277 }
1278
1279 auto context = es2::getContext();
1280
1281 if(context)
1282 {
1283 if(!context->getShader(shader))
1284 {
1285 if(context->getProgram(shader))
1286 {
1287 return error(GL_INVALID_OPERATION);
1288 }
1289 else
1290 {
1291 return error(GL_INVALID_VALUE);
1292 }
1293 }
1294
1295 context->deleteShader(shader);
1296 }
1297}
1298
1299void GL_APIENTRY DeleteTextures(GLsizei n, const GLuint* textures)
1300{
1301 TRACE("(GLsizei n = %d, const GLuint* textures = %p)", n, textures);
1302
1303 if(n < 0)
1304 {
1305 return error(GL_INVALID_VALUE);
1306 }
1307
1308 auto context = es2::getContext();
1309
1310 if(context)
1311 {
1312 for(int i = 0; i < n; i++)
1313 {
1314 if(textures[i] != 0) // Attempts to delete default texture silently ignored.
1315 {
1316 context->deleteTexture(textures[i]);
1317 }
1318 }
1319 }
1320}
1321
1322void GL_APIENTRY DepthFunc(GLenum func)
1323{
1324 TRACE("(GLenum func = 0x%X)", func);
1325
1326 switch(func)
1327 {
1328 case GL_NEVER:
1329 case GL_ALWAYS:
1330 case GL_LESS:
1331 case GL_LEQUAL:
1332 case GL_EQUAL:
1333 case GL_GREATER:
1334 case GL_GEQUAL:
1335 case GL_NOTEQUAL:
1336 break;
1337 default:
1338 return error(GL_INVALID_ENUM);
1339 }
1340
1341 auto context = es2::getContext();
1342
1343 if(context)
1344 {
1345 context->setDepthFunc(func);
1346 }
1347}
1348
1349void GL_APIENTRY DepthMask(GLboolean flag)
1350{
1351 TRACE("(GLboolean flag = %d)", flag);
1352
1353 auto context = es2::getContext();
1354
1355 if(context)
1356 {
1357 context->setDepthMask(flag != GL_FALSE);
1358 }
1359}
1360
1361void GL_APIENTRY DepthRangef(GLclampf zNear, GLclampf zFar)
1362{
1363 TRACE("(GLclampf zNear = %f, GLclampf zFar = %f)", zNear, zFar);
1364
1365 auto context = es2::getContext();
1366
1367 if(context)
1368 {
1369 context->setDepthRange(zNear, zFar);
1370 }
1371}
1372
1373void GL_APIENTRY DetachShader(GLuint program, GLuint shader)
1374{
1375 TRACE("(GLuint program = %d, GLuint shader = %d)", program, shader);
1376
1377 auto context = es2::getContext();
1378
1379 if(context)
1380 {
1381
1382 es2::Program *programObject = context->getProgram(program);
1383 es2::Shader *shaderObject = context->getShader(shader);
1384
1385 if(!programObject)
1386 {
1387 es2::Shader *shaderByProgramHandle;
1388 shaderByProgramHandle = context->getShader(program);
1389 if(!shaderByProgramHandle)
1390 {
1391 return error(GL_INVALID_VALUE);
1392 }
1393 else
1394 {
1395 return error(GL_INVALID_OPERATION);
1396 }
1397 }
1398
1399 if(!shaderObject)
1400 {
1401 es2::Program *programByShaderHandle = context->getProgram(shader);
1402 if(!programByShaderHandle)
1403 {
1404 return error(GL_INVALID_VALUE);
1405 }
1406 else
1407 {
1408 return error(GL_INVALID_OPERATION);
1409 }
1410 }
1411
1412 if(!programObject->detachShader(shaderObject))
1413 {
1414 return error(GL_INVALID_OPERATION);
1415 }
1416 }
1417}
1418
1419void GL_APIENTRY Disable(GLenum cap)
1420{
1421 TRACE("(GLenum cap = 0x%X)", cap);
1422
1423 auto context = es2::getContext();
1424
1425 if(context)
1426 {
1427 switch(cap)
1428 {
1429 case GL_CULL_FACE: context->setCullFaceEnabled(false); break;
1430 case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFillEnabled(false); break;
1431 case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverageEnabled(false); break;
1432 case GL_SAMPLE_COVERAGE: context->setSampleCoverageEnabled(false); break;
1433 case GL_SCISSOR_TEST: context->setScissorTestEnabled(false); break;
1434 case GL_STENCIL_TEST: context->setStencilTestEnabled(false); break;
1435 case GL_DEPTH_TEST: context->setDepthTestEnabled(false); break;
1436 case GL_BLEND: context->setBlendEnabled(false); break;
1437 case GL_DITHER: context->setDitherEnabled(false); break;
1438 case GL_PRIMITIVE_RESTART_FIXED_INDEX: context->setPrimitiveRestartFixedIndexEnabled(false); break;
1439 case GL_RASTERIZER_DISCARD: context->setRasterizerDiscardEnabled(false); break;
1440 default:
1441 return error(GL_INVALID_ENUM);
1442 }
1443 }
1444}
1445
1446void GL_APIENTRY DisableVertexAttribArray(GLuint index)
1447{
1448 TRACE("(GLuint index = %d)", index);
1449
1450 if(index >= es2::MAX_VERTEX_ATTRIBS)
1451 {
1452 return error(GL_INVALID_VALUE);
1453 }
1454
1455 auto context = es2::getContext();
1456
1457 if(context)
1458 {
1459 context->setVertexAttribArrayEnabled(index, false);
1460 }
1461}
1462
1463void GL_APIENTRY DrawArrays(GLenum mode, GLint first, GLsizei count)
1464{
1465 TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d)", mode, first, count);
1466
1467 switch(mode)
1468 {
1469 case GL_POINTS:
1470 case GL_LINES:
1471 case GL_LINE_LOOP:
1472 case GL_LINE_STRIP:
1473 case GL_TRIANGLES:
1474 case GL_TRIANGLE_FAN:
1475 case GL_TRIANGLE_STRIP:
1476 break;
1477 default:
1478 return error(GL_INVALID_ENUM);
1479 }
1480
1481 if(count < 0 || first < 0)
1482 {
1483 return error(GL_INVALID_VALUE);
1484 }
1485
1486 auto context = es2::getContext();
1487
1488 if(context)
1489 {
1490 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
1491 if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
1492 {
1493 return error(GL_INVALID_OPERATION);
1494 }
1495
1496 context->drawArrays(mode, first, count);
1497 }
1498}
1499
1500void GL_APIENTRY DrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
1501{
1502 TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const GLvoid* indices = %p)",
1503 mode, count, type, indices);
1504
1505 switch(mode)
1506 {
1507 case GL_POINTS:
1508 case GL_LINES:
1509 case GL_LINE_LOOP:
1510 case GL_LINE_STRIP:
1511 case GL_TRIANGLES:
1512 case GL_TRIANGLE_FAN:
1513 case GL_TRIANGLE_STRIP:
1514 break;
1515 default:
1516 return error(GL_INVALID_ENUM);
1517 }
1518
1519 if(count < 0)
1520 {
1521 return error(GL_INVALID_VALUE);
1522 }
1523
1524 auto context = es2::getContext();
1525
1526 if(context)
1527 {
1528 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
1529 if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
1530 {
1531 return error(GL_INVALID_OPERATION);
1532 }
1533
1534 switch(type)
1535 {
1536 case GL_UNSIGNED_BYTE:
1537 case GL_UNSIGNED_SHORT:
1538 case GL_UNSIGNED_INT:
1539 break;
1540 default:
1541 return error(GL_INVALID_ENUM);
1542 }
1543
1544 context->drawElements(mode, 0, MAX_ELEMENT_INDEX, count, type, indices);
1545 }
1546}
1547
1548void GL_APIENTRY DrawArraysInstancedEXT(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
1549{
1550 TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
1551 mode, first, count, instanceCount);
1552
1553 switch(mode)
1554 {
1555 case GL_POINTS:
1556 case GL_LINES:
1557 case GL_LINE_LOOP:
1558 case GL_LINE_STRIP:
1559 case GL_TRIANGLES:
1560 case GL_TRIANGLE_FAN:
1561 case GL_TRIANGLE_STRIP:
1562 break;
1563 default:
1564 return error(GL_INVALID_ENUM);
1565 }
1566
1567 if(count < 0 || instanceCount < 0)
1568 {
1569 return error(GL_INVALID_VALUE);
1570 }
1571
1572 auto context = es2::getContext();
1573
1574 if(context)
1575 {
1576 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
1577 if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
1578 {
1579 return error(GL_INVALID_OPERATION);
1580 }
1581
1582 context->drawArrays(mode, first, count, instanceCount);
1583 }
1584}
1585
1586void GL_APIENTRY DrawElementsInstancedEXT(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
1587{
1588 TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = %p, GLsizei instanceCount = %d)",
1589 mode, count, type, indices, instanceCount);
1590
1591 switch(mode)
1592 {
1593 case GL_POINTS:
1594 case GL_LINES:
1595 case GL_LINE_LOOP:
1596 case GL_LINE_STRIP:
1597 case GL_TRIANGLES:
1598 case GL_TRIANGLE_FAN:
1599 case GL_TRIANGLE_STRIP:
1600 break;
1601 default:
1602 return error(GL_INVALID_ENUM);
1603 }
1604
1605 switch(type)
1606 {
1607 case GL_UNSIGNED_BYTE:
1608 case GL_UNSIGNED_SHORT:
1609 case GL_UNSIGNED_INT:
1610 break;
1611 default:
1612 return error(GL_INVALID_ENUM);
1613 }
1614
1615 if(count < 0 || instanceCount < 0)
1616 {
1617 return error(GL_INVALID_VALUE);
1618 }
1619
1620 auto context = es2::getContext();
1621
1622 if(context)
1623 {
1624 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
1625 if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
1626 {
1627 return error(GL_INVALID_OPERATION);
1628 }
1629
1630 context->drawElements(mode, 0, MAX_ELEMENT_INDEX, count, type, indices, instanceCount);
1631 }
1632}
1633
1634void GL_APIENTRY VertexAttribDivisorEXT(GLuint index, GLuint divisor)
1635{
1636 TRACE("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
1637
1638 auto context = es2::getContext();
1639
1640 if(context)
1641 {
1642 if(index >= es2::MAX_VERTEX_ATTRIBS)
1643 {
1644 return error(GL_INVALID_VALUE);
1645 }
1646
1647 context->setVertexAttribDivisor(index, divisor);
1648 }
1649}
1650
1651void GL_APIENTRY DrawArraysInstancedANGLE(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
1652{
1653 TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
1654 mode, first, count, instanceCount);
1655
1656 switch(mode)
1657 {
1658 case GL_POINTS:
1659 case GL_LINES:
1660 case GL_LINE_LOOP:
1661 case GL_LINE_STRIP:
1662 case GL_TRIANGLES:
1663 case GL_TRIANGLE_FAN:
1664 case GL_TRIANGLE_STRIP:
1665 break;
1666 default:
1667 return error(GL_INVALID_ENUM);
1668 }
1669
1670 if(count < 0 || instanceCount < 0)
1671 {
1672 return error(GL_INVALID_VALUE);
1673 }
1674
1675 auto context = es2::getContext();
1676
1677 if(context)
1678 {
1679 if(!context->hasZeroDivisor())
1680 {
1681 return error(GL_INVALID_OPERATION);
1682 }
1683
1684 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
1685 if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
1686 {
1687 return error(GL_INVALID_OPERATION);
1688 }
1689
1690 context->drawArrays(mode, first, count, instanceCount);
1691 }
1692}
1693
1694void GL_APIENTRY DrawElementsInstancedANGLE(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
1695{
1696 TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = %p, GLsizei instanceCount = %d)",
1697 mode, count, type, indices, instanceCount);
1698
1699 switch(mode)
1700 {
1701 case GL_POINTS:
1702 case GL_LINES:
1703 case GL_LINE_LOOP:
1704 case GL_LINE_STRIP:
1705 case GL_TRIANGLES:
1706 case GL_TRIANGLE_FAN:
1707 case GL_TRIANGLE_STRIP:
1708 break;
1709 default:
1710 return error(GL_INVALID_ENUM);
1711 }
1712
1713 switch(type)
1714 {
1715 case GL_UNSIGNED_BYTE:
1716 case GL_UNSIGNED_SHORT:
1717 case GL_UNSIGNED_INT:
1718 break;
1719 default:
1720 return error(GL_INVALID_ENUM);
1721 }
1722
1723 if(count < 0 || instanceCount < 0)
1724 {
1725 return error(GL_INVALID_VALUE);
1726 }
1727
1728 auto context = es2::getContext();
1729
1730 if(context)
1731 {
1732 if(!context->hasZeroDivisor())
1733 {
1734 return error(GL_INVALID_OPERATION);
1735 }
1736
1737 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
1738 if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
1739 {
1740 return error(GL_INVALID_OPERATION);
1741 }
1742
1743 context->drawElements(mode, 0, MAX_ELEMENT_INDEX, count, type, indices, instanceCount);
1744 }
1745}
1746
1747void GL_APIENTRY VertexAttribDivisorANGLE(GLuint index, GLuint divisor)
1748{
1749 TRACE("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
1750
1751 auto context = es2::getContext();
1752
1753 if(context)
1754 {
1755 if(index >= MAX_VERTEX_ATTRIBS)
1756 {
1757 return error(GL_INVALID_VALUE);
1758 }
1759
1760 context->setVertexAttribDivisor(index, divisor);
1761 }
1762}
1763
1764void GL_APIENTRY Enable(GLenum cap)
1765{
1766 TRACE("(GLenum cap = 0x%X)", cap);
1767
1768 auto context = es2::getContext();
1769
1770 if(context)
1771 {
1772 switch(cap)
1773 {
1774 case GL_CULL_FACE: context->setCullFaceEnabled(true); break;
1775 case GL_POLYGON_OFFSET_FILL: context->setPolygonOffsetFillEnabled(true); break;
1776 case GL_SAMPLE_ALPHA_TO_COVERAGE: context->setSampleAlphaToCoverageEnabled(true); break;
1777 case GL_SAMPLE_COVERAGE: context->setSampleCoverageEnabled(true); break;
1778 case GL_SCISSOR_TEST: context->setScissorTestEnabled(true); break;
1779 case GL_STENCIL_TEST: context->setStencilTestEnabled(true); break;
1780 case GL_DEPTH_TEST: context->setDepthTestEnabled(true); break;
1781 case GL_BLEND: context->setBlendEnabled(true); break;
1782 case GL_DITHER: context->setDitherEnabled(true); break;
1783 case GL_PRIMITIVE_RESTART_FIXED_INDEX: context->setPrimitiveRestartFixedIndexEnabled(true); break;
1784 case GL_RASTERIZER_DISCARD: context->setRasterizerDiscardEnabled(true); break;
1785 default:
1786 return error(GL_INVALID_ENUM);
1787 }
1788 }
1789}
1790
1791void GL_APIENTRY EnableVertexAttribArray(GLuint index)
1792{
1793 TRACE("(GLuint index = %d)", index);
1794
1795 if(index >= es2::MAX_VERTEX_ATTRIBS)
1796 {
1797 return error(GL_INVALID_VALUE);
1798 }
1799
1800 auto context = es2::getContext();
1801
1802 if(context)
1803 {
1804 context->setVertexAttribArrayEnabled(index, true);
1805 }
1806}
1807
1808void GL_APIENTRY EndQueryEXT(GLenum target)
1809{
1810 TRACE("GLenum target = 0x%X)", target);
1811
1812 switch(target)
1813 {
1814 case GL_ANY_SAMPLES_PASSED_EXT:
1815 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE_EXT:
1816 break;
1817 default:
1818 return error(GL_INVALID_ENUM);
1819 }
1820
1821 auto context = es2::getContext();
1822
1823 if(context)
1824 {
1825 context->endQuery(target);
1826 }
1827}
1828
1829void GL_APIENTRY FinishFenceNV(GLuint fence)
1830{
1831 TRACE("(GLuint fence = %d)", fence);
1832
1833 auto context = es2::getContext();
1834
1835 if(context)
1836 {
1837 es2::Fence *fenceObject = context->getFence(fence);
1838
1839 if(!fenceObject)
1840 {
1841 return error(GL_INVALID_OPERATION);
1842 }
1843
1844 fenceObject->finishFence();
1845 }
1846}
1847
1848void GL_APIENTRY Finish(void)
1849{
1850 TRACE("()");
1851
1852 auto context = es2::getContext();
1853
1854 if(context)
1855 {
1856 context->finish();
1857 }
1858}
1859
1860void GL_APIENTRY Flush(void)
1861{
1862 TRACE("()");
1863
1864 auto context = es2::getContext();
1865
1866 if(context)
1867 {
1868 context->flush();
1869 }
1870}
1871
1872void GL_APIENTRY FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
1873{
1874 TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, "
1875 "GLuint renderbuffer = %d)", target, attachment, renderbuffertarget, renderbuffer);
1876
1877 if((target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER) ||
1878 (renderbuffertarget != GL_RENDERBUFFER && renderbuffer != 0))
1879 {
1880 return error(GL_INVALID_ENUM);
1881 }
1882
1883 auto context = es2::getContext();
1884
1885 if(context)
1886 {
1887 es2::Framebuffer *framebuffer = nullptr;
1888 GLuint framebufferName = 0;
1889 if(target == GL_READ_FRAMEBUFFER)
1890 {
1891 framebuffer = context->getReadFramebuffer();
1892 framebufferName = context->getReadFramebufferName();
1893 }
1894 else
1895 {
1896 framebuffer = context->getDrawFramebuffer();
1897 framebufferName = context->getDrawFramebufferName();
1898 }
1899
1900 if(!framebuffer || framebufferName == 0)
1901 {
1902 return error(GL_INVALID_OPERATION);
1903 }
1904
1905 // [OpenGL ES 2.0.25] Section 4.4.3 page 112
1906 // [OpenGL ES 3.0.2] Section 4.4.2 page 201
1907 // 'renderbuffer' must be either zero or the name of an existing renderbuffer object of
1908 // type 'renderbuffertarget', otherwise an INVALID_OPERATION error is generated.
1909 if(renderbuffer != 0)
1910 {
1911 if(!context->getRenderbuffer(renderbuffer))
1912 {
1913 return error(GL_INVALID_OPERATION);
1914 }
1915 }
1916
1917 switch(attachment)
1918 {
1919 case GL_DEPTH_ATTACHMENT:
1920 framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer);
1921 break;
1922 case GL_STENCIL_ATTACHMENT:
1923 framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer);
1924 break;
1925 case GL_DEPTH_STENCIL_ATTACHMENT:
1926 framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer);
1927 framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer);
1928 break;
1929 default:
1930 if(attachment < GL_COLOR_ATTACHMENT0 || attachment > GL_COLOR_ATTACHMENT31)
1931 {
1932 return error(GL_INVALID_ENUM);
1933 }
1934
1935 if((attachment - GL_COLOR_ATTACHMENT0) >= MAX_COLOR_ATTACHMENTS)
1936 {
1937 return error(GL_INVALID_OPERATION);
1938 }
1939
1940 framebuffer->setColorbuffer(GL_RENDERBUFFER, renderbuffer, attachment - GL_COLOR_ATTACHMENT0);
1941 break;
1942 }
1943 }
1944}
1945
1946void GL_APIENTRY FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
1947{
1948 TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, "
1949 "GLuint texture = %d, GLint level = %d)", target, attachment, textarget, texture, level);
1950
1951 if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
1952 {
1953 return error(GL_INVALID_ENUM);
1954 }
1955
1956 auto context = es2::getContext();
1957
1958 if(context)
1959 {
1960 if(texture == 0)
1961 {
1962 textarget = GL_NONE;
1963 }
1964 else
1965 {
1966 es2::Texture *tex = context->getTexture(texture);
1967
1968 if(!tex)
1969 {
1970 return error(GL_INVALID_OPERATION);
1971 }
1972
1973 switch(textarget)
1974 {
1975 case GL_TEXTURE_2D:
1976 if(tex->getTarget() != GL_TEXTURE_2D)
1977 {
1978 return error(GL_INVALID_OPERATION);
1979 }
1980 break;
1981 case GL_TEXTURE_RECTANGLE_ARB:
1982 if(tex->getTarget() != GL_TEXTURE_RECTANGLE_ARB)
1983 {
1984 return error(GL_INVALID_OPERATION);
1985 }
1986 break;
1987 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
1988 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
1989 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
1990 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
1991 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
1992 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
1993 if(tex->getTarget() != GL_TEXTURE_CUBE_MAP)
1994 {
1995 return error(GL_INVALID_OPERATION);
1996 }
1997 break;
1998 default:
1999 return error(GL_INVALID_ENUM);
2000 }
2001
2002 if((textarget == GL_TEXTURE_RECTANGLE_ARB) && (level != 0))
2003 {
2004 return error(GL_INVALID_VALUE);
2005 }
2006
2007 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
2008 {
2009 return error(GL_INVALID_VALUE);
2010 }
2011
2012 if(tex->isCompressed(textarget, level))
2013 {
2014 return error(GL_INVALID_OPERATION);
2015 }
2016 }
2017
2018 es2::Framebuffer *framebuffer = nullptr;
2019 GLuint framebufferName = 0;
2020 if(target == GL_READ_FRAMEBUFFER)
2021 {
2022 framebuffer = context->getReadFramebuffer();
2023 framebufferName = context->getReadFramebufferName();
2024 }
2025 else
2026 {
2027 framebuffer = context->getDrawFramebuffer();
2028 framebufferName = context->getDrawFramebufferName();
2029 }
2030
2031 if(framebufferName == 0 || !framebuffer)
2032 {
2033 return error(GL_INVALID_OPERATION);
2034 }
2035
2036 switch(attachment)
2037 {
2038 case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture, level); break;
2039 case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture, level); break;
2040 case GL_DEPTH_STENCIL_ATTACHMENT:
2041 framebuffer->setDepthbuffer(textarget, texture, level);
2042 framebuffer->setStencilbuffer(textarget, texture, level);
2043 break;
2044 default:
2045 if(attachment < GL_COLOR_ATTACHMENT0 || attachment > GL_COLOR_ATTACHMENT31)
2046 {
2047 return error(GL_INVALID_ENUM);
2048 }
2049
2050 if((attachment - GL_COLOR_ATTACHMENT0) >= MAX_COLOR_ATTACHMENTS)
2051 {
2052 return error(GL_INVALID_OPERATION);
2053 }
2054
2055 framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0, level);
2056 break;
2057 }
2058 }
2059}
2060
2061void GL_APIENTRY FrontFace(GLenum mode)
2062{
2063 TRACE("(GLenum mode = 0x%X)", mode);
2064
2065 switch(mode)
2066 {
2067 case GL_CW:
2068 case GL_CCW:
2069 {
2070 auto context = es2::getContext();
2071
2072 if(context)
2073 {
2074 context->setFrontFace(mode);
2075 }
2076 }
2077 break;
2078 default:
2079 return error(GL_INVALID_ENUM);
2080 }
2081}
2082
2083void GL_APIENTRY GenBuffers(GLsizei n, GLuint* buffers)
2084{
2085 TRACE("(GLsizei n = %d, GLuint* buffers = %p)", n, buffers);
2086
2087 if(n < 0)
2088 {
2089 return error(GL_INVALID_VALUE);
2090 }
2091
2092 auto context = es2::getContext();
2093
2094 if(context)
2095 {
2096 for(int i = 0; i < n; i++)
2097 {
2098 buffers[i] = context->createBuffer();
2099 }
2100 }
2101}
2102
2103void GL_APIENTRY GenerateMipmap(GLenum target)
2104{
2105 TRACE("(GLenum target = 0x%X)", target);
2106
2107 auto context = es2::getContext();
2108
2109 if(context)
2110 {
2111 es2::Texture *texture = context->getTargetTexture(target);
2112
2113 if(!texture)
2114 {
2115 return;
2116 }
2117
2118 if(!IsMipmappable(texture->getFormat(target, texture->getBaseLevel())))
2119 {
2120 return error(GL_INVALID_OPERATION);
2121 }
2122
2123 if(target == GL_TEXTURE_CUBE_MAP)
2124 {
2125 TextureCubeMap *cube = context->getTextureCubeMap();
2126
2127 if(!cube->isCubeComplete())
2128 {
2129 return error(GL_INVALID_OPERATION);
2130 }
2131 }
2132
2133 // [OpenGL ES 3.2]: "Otherwise, if levelbase is not defined, or if any dimension
2134 // is zero, all mipmap levels are left unchanged. This is not an error."
2135 if(!texture->isBaseLevelDefined())
2136 {
2137 return;
2138 }
2139
2140 texture->generateMipmaps();
2141 }
2142}
2143
2144void GL_APIENTRY GenFencesNV(GLsizei n, GLuint* fences)
2145{
2146 TRACE("(GLsizei n = %d, GLuint* fences = %p)", n, fences);
2147
2148 if(n < 0)
2149 {
2150 return error(GL_INVALID_VALUE);
2151 }
2152
2153 auto context = es2::getContext();
2154
2155 if(context)
2156 {
2157 for(int i = 0; i < n; i++)
2158 {
2159 fences[i] = context->createFence();
2160 }
2161 }
2162}
2163
2164void GL_APIENTRY GenFramebuffers(GLsizei n, GLuint* framebuffers)
2165{
2166 TRACE("(GLsizei n = %d, GLuint* framebuffers = %p)", n, framebuffers);
2167
2168 if(n < 0)
2169 {
2170 return error(GL_INVALID_VALUE);
2171 }
2172
2173 auto context = es2::getContext();
2174
2175 if(context)
2176 {
2177 for(int i = 0; i < n; i++)
2178 {
2179 framebuffers[i] = context->createFramebuffer();
2180 }
2181 }
2182}
2183
2184void GL_APIENTRY GenQueriesEXT(GLsizei n, GLuint* ids)
2185{
2186 TRACE("(GLsizei n = %d, GLuint* ids = %p)", n, ids);
2187
2188 if(n < 0)
2189 {
2190 return error(GL_INVALID_VALUE);
2191 }
2192
2193 auto context = es2::getContext();
2194
2195 if(context)
2196 {
2197 for(int i = 0; i < n; i++)
2198 {
2199 ids[i] = context->createQuery();
2200 }
2201 }
2202}
2203
2204void GL_APIENTRY GenRenderbuffers(GLsizei n, GLuint* renderbuffers)
2205{
2206 TRACE("(GLsizei n = %d, GLuint* renderbuffers = %p)", n, renderbuffers);
2207
2208 if(n < 0)
2209 {
2210 return error(GL_INVALID_VALUE);
2211 }
2212
2213 auto context = es2::getContext();
2214
2215 if(context)
2216 {
2217 for(int i = 0; i < n; i++)
2218 {
2219 renderbuffers[i] = context->createRenderbuffer();
2220 }
2221 }
2222}
2223
2224void GL_APIENTRY GenTextures(GLsizei n, GLuint* textures)
2225{
2226 TRACE("(GLsizei n = %d, GLuint* textures = %p)", n, textures);
2227
2228 if(n < 0)
2229 {
2230 return error(GL_INVALID_VALUE);
2231 }
2232
2233 auto context = es2::getContext();
2234
2235 if(context)
2236 {
2237 for(int i = 0; i < n; i++)
2238 {
2239 textures[i] = context->createTexture();
2240 }
2241 }
2242}
2243
2244void GL_APIENTRY GetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, GLchar *name)
2245{
2246 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei *length = %p, "
2247 "GLint *size = %p, GLenum *type = %p, GLchar *name = %p)",
2248 program, index, bufsize, length, size, type, name);
2249
2250 if(bufsize < 0)
2251 {
2252 return error(GL_INVALID_VALUE);
2253 }
2254
2255 auto context = es2::getContext();
2256
2257 if(context)
2258 {
2259 es2::Program *programObject = context->getProgram(program);
2260
2261 if(!programObject)
2262 {
2263 if(context->getShader(program))
2264 {
2265 return error(GL_INVALID_OPERATION);
2266 }
2267 else
2268 {
2269 return error(GL_INVALID_VALUE);
2270 }
2271 }
2272
2273 if(index >= programObject->getActiveAttributeCount())
2274 {
2275 return error(GL_INVALID_VALUE);
2276 }
2277
2278 programObject->getActiveAttribute(index, bufsize, length, size, type, name);
2279 }
2280}
2281
2282void GL_APIENTRY GetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
2283{
2284 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, "
2285 "GLsizei* length = %p, GLint* size = %p, GLenum* type = %p, GLchar* name = %s)",
2286 program, index, bufsize, length, size, type, name);
2287
2288 if(bufsize < 0)
2289 {
2290 return error(GL_INVALID_VALUE);
2291 }
2292
2293 auto context = es2::getContext();
2294
2295 if(context)
2296 {
2297 es2::Program *programObject = context->getProgram(program);
2298
2299 if(!programObject)
2300 {
2301 if(context->getShader(program))
2302 {
2303 return error(GL_INVALID_OPERATION);
2304 }
2305 else
2306 {
2307 return error(GL_INVALID_VALUE);
2308 }
2309 }
2310
2311 if(index >= programObject->getActiveUniformCount())
2312 {
2313 return error(GL_INVALID_VALUE);
2314 }
2315
2316 programObject->getActiveUniform(index, bufsize, length, size, type, name);
2317 }
2318}
2319
2320void GL_APIENTRY GetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
2321{
2322 TRACE("(GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = %p, GLuint* shaders = %p)",
2323 program, maxcount, count, shaders);
2324
2325 if(maxcount < 0)
2326 {
2327 return error(GL_INVALID_VALUE);
2328 }
2329
2330 auto context = es2::getContext();
2331
2332 if(context)
2333 {
2334 es2::Program *programObject = context->getProgram(program);
2335
2336 if(!programObject)
2337 {
2338 if(context->getShader(program))
2339 {
2340 return error(GL_INVALID_OPERATION);
2341 }
2342 else
2343 {
2344 return error(GL_INVALID_VALUE);
2345 }
2346 }
2347
2348 return programObject->getAttachedShaders(maxcount, count, shaders);
2349 }
2350}
2351
2352int GL_APIENTRY GetAttribLocation(GLuint program, const GLchar* name)
2353{
2354 TRACE("(GLuint program = %d, const GLchar* name = %s)", program, name);
2355
2356 auto context = es2::getContext();
2357
2358 if(context)
2359 {
2360 es2::Program *programObject = context->getProgram(program);
2361
2362 if(!programObject)
2363 {
2364 if(context->getShader(program))
2365 {
2366 return error(GL_INVALID_OPERATION, -1);
2367 }
2368 else
2369 {
2370 return error(GL_INVALID_VALUE, -1);
2371 }
2372 }
2373
2374 if(!programObject->isLinked())
2375 {
2376 return error(GL_INVALID_OPERATION, -1);
2377 }
2378
2379 return programObject->getAttributeLocation(name);
2380 }
2381
2382 return -1;
2383}
2384
2385void GL_APIENTRY GetBooleanv(GLenum pname, GLboolean* params)
2386{
2387 TRACE("(GLenum pname = 0x%X, GLboolean* params = %p)", pname, params);
2388
2389 auto context = es2::getContext();
2390
2391 if(context)
2392 {
2393 if(!(context->getBooleanv(pname, params)))
2394 {
2395 GLenum nativeType;
2396 unsigned int numParams = 0;
2397 if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))
2398 return error(GL_INVALID_ENUM);
2399
2400 if(numParams == 0)
2401 return; // it is known that the pname is valid, but there are no parameters to return
2402
2403 if(nativeType == GL_FLOAT)
2404 {
2405 GLfloat *floatParams = nullptr;
2406 floatParams = new GLfloat[numParams];
2407
2408 context->getFloatv(pname, floatParams);
2409
2410 for(unsigned int i = 0; i < numParams; ++i)
2411 {
2412 if(floatParams[i] == 0.0f)
2413 params[i] = GL_FALSE;
2414 else
2415 params[i] = GL_TRUE;
2416 }
2417
2418 delete [] floatParams;
2419 }
2420 else if(nativeType == GL_INT)
2421 {
2422 GLint *intParams = nullptr;
2423 intParams = new GLint[numParams];
2424
2425 context->getIntegerv(pname, intParams);
2426
2427 for(unsigned int i = 0; i < numParams; ++i)
2428 {
2429 if(intParams[i] == 0)
2430 params[i] = GL_FALSE;
2431 else
2432 params[i] = GL_TRUE;
2433 }
2434
2435 delete [] intParams;
2436 }
2437 }
2438 }
2439}
2440
2441void GL_APIENTRY GetBufferParameteriv(GLenum target, GLenum pname, GLint* params)
2442{
2443 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = %p)", target, pname, params);
2444
2445 auto context = es2::getContext();
2446
2447 if(context)
2448 {
2449 es2::Buffer *buffer;
2450 if(!context->getBuffer(target, &buffer))
2451 {
2452 return error(GL_INVALID_ENUM);
2453 }
2454
2455 if(!buffer)
2456 {
2457 // A null buffer means that "0" is bound to the requested buffer target
2458 return error(GL_INVALID_OPERATION);
2459 }
2460
2461 switch(pname)
2462 {
2463 case GL_BUFFER_USAGE:
2464 *params = buffer->usage();
2465 break;
2466 case GL_BUFFER_SIZE:
2467 *params = (GLint)buffer->size();
2468 break;
2469 case GL_BUFFER_ACCESS_FLAGS:
2470 *params = buffer->access();
2471 break;
2472 case GL_BUFFER_MAPPED:
2473 *params = buffer->isMapped();
2474 break;
2475 case GL_BUFFER_MAP_LENGTH:
2476 *params = (GLint)buffer->length();
2477 break;
2478 case GL_BUFFER_MAP_OFFSET:
2479 *params = (GLint)buffer->offset();
2480 break;
2481 default:
2482 return error(GL_INVALID_ENUM);
2483 }
2484 }
2485}
2486
2487GLenum GL_APIENTRY GetError(void)
2488{
2489 TRACE("()");
2490
2491 auto context = es2::getContext();
2492
2493 if(context)
2494 {
2495 return context->getError();
2496 }
2497
2498 return GL_NO_ERROR;
2499}
2500
2501void GL_APIENTRY GetFenceivNV(GLuint fence, GLenum pname, GLint *params)
2502{
2503 TRACE("(GLuint fence = %d, GLenum pname = 0x%X, GLint *params = %p)", fence, pname, params);
2504
2505 auto context = es2::getContext();
2506
2507 if(context)
2508 {
2509 es2::Fence *fenceObject = context->getFence(fence);
2510
2511 if(!fenceObject)
2512 {
2513 return error(GL_INVALID_OPERATION);
2514 }
2515
2516 fenceObject->getFenceiv(pname, params);
2517 }
2518}
2519
2520void GL_APIENTRY GetFloatv(GLenum pname, GLfloat* params)
2521{
2522 TRACE("(GLenum pname = 0x%X, GLfloat* params = %p)", pname, params);
2523
2524 auto context = es2::getContext();
2525
2526 if(context)
2527 {
2528 if(!(context->getFloatv(pname, params)))
2529 {
2530 GLenum nativeType;
2531 unsigned int numParams = 0;
2532 if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))
2533 return error(GL_INVALID_ENUM);
2534
2535 if(numParams == 0)
2536 return; // it is known that the pname is valid, but that there are no parameters to return.
2537
2538 if(nativeType == GL_BOOL)
2539 {
2540 GLboolean *boolParams = nullptr;
2541 boolParams = new GLboolean[numParams];
2542
2543 context->getBooleanv(pname, boolParams);
2544
2545 for(unsigned int i = 0; i < numParams; ++i)
2546 {
2547 if(boolParams[i] == GL_FALSE)
2548 params[i] = 0.0f;
2549 else
2550 params[i] = 1.0f;
2551 }
2552
2553 delete [] boolParams;
2554 }
2555 else if(nativeType == GL_INT)
2556 {
2557 GLint *intParams = nullptr;
2558 intParams = new GLint[numParams];
2559
2560 context->getIntegerv(pname, intParams);
2561
2562 for(unsigned int i = 0; i < numParams; ++i)
2563 {
2564 params[i] = (GLfloat)intParams[i];
2565 }
2566
2567 delete [] intParams;
2568 }
2569 }
2570 }
2571}
2572
2573void GL_APIENTRY GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params)
2574{
2575 TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = %p)",
2576 target, attachment, pname, params);
2577
2578 auto context = es2::getContext();
2579
2580 if(context)
2581 {
2582 if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
2583 {
2584 return error(GL_INVALID_ENUM);
2585 }
2586
2587 GLuint framebufferName = 0;
2588
2589 if(target == GL_READ_FRAMEBUFFER)
2590 {
2591 framebufferName = context->getReadFramebufferName();
2592 }
2593 else
2594 {
2595 framebufferName = context->getDrawFramebufferName();
2596 }
2597
2598 switch(attachment)
2599 {
2600 case GL_BACK:
2601 case GL_DEPTH:
2602 case GL_STENCIL:
2603 if(framebufferName != 0)
2604 {
2605 return error(GL_INVALID_OPERATION);
2606 }
2607 break;
2608 case GL_DEPTH_ATTACHMENT:
2609 case GL_STENCIL_ATTACHMENT:
2610 if(framebufferName == 0)
2611 {
2612 return error(GL_INVALID_OPERATION);
2613 }
2614 break;
2615 case GL_DEPTH_STENCIL_ATTACHMENT:
2616 if(framebufferName == 0)
2617 {
2618 return error(GL_INVALID_OPERATION);
2619 }
2620 break;
2621 default:
2622 if(framebufferName == 0)
2623 {
2624 return error(GL_INVALID_OPERATION);
2625 }
2626
2627 if(attachment < GL_COLOR_ATTACHMENT0 || attachment > GL_COLOR_ATTACHMENT31)
2628 {
2629 return error(GL_INVALID_ENUM);
2630 }
2631
2632 if((attachment - GL_COLOR_ATTACHMENT0) >= MAX_COLOR_ATTACHMENTS)
2633 {
2634 return error(GL_INVALID_OPERATION);
2635 }
2636 break;
2637 }
2638
2639 es2::Framebuffer *framebuffer = context->getFramebuffer(framebufferName);
2640
2641 if(!framebuffer)
2642 {
2643 return error(GL_INVALID_OPERATION);
2644 }
2645
2646 GLenum attachmentType;
2647 GLuint attachmentHandle;
2648 GLint attachmentLayer;
2649 Renderbuffer *renderbuffer = nullptr;
2650 switch(attachment)
2651 {
2652 case GL_BACK:
2653 attachmentType = framebuffer->getColorbufferType(0);
2654 attachmentHandle = framebuffer->getColorbufferName(0);
2655 attachmentLayer = framebuffer->getColorbufferLayer(0);
2656 renderbuffer = framebuffer->getColorbuffer(0);
2657 break;
2658 case GL_DEPTH:
2659 case GL_DEPTH_ATTACHMENT:
2660 attachmentType = framebuffer->getDepthbufferType();
2661 attachmentHandle = framebuffer->getDepthbufferName();
2662 attachmentLayer = framebuffer->getDepthbufferLayer();
2663 renderbuffer = framebuffer->getDepthbuffer();
2664 break;
2665 case GL_STENCIL:
2666 case GL_STENCIL_ATTACHMENT:
2667 attachmentType = framebuffer->getStencilbufferType();
2668 attachmentHandle = framebuffer->getStencilbufferName();
2669 attachmentLayer = framebuffer->getStencilbufferLayer();
2670 renderbuffer = framebuffer->getStencilbuffer();
2671 break;
2672 case GL_DEPTH_STENCIL_ATTACHMENT:
2673 attachmentType = framebuffer->getDepthbufferType();
2674 attachmentHandle = framebuffer->getDepthbufferName();
2675 attachmentLayer = framebuffer->getDepthbufferLayer();
2676 renderbuffer = framebuffer->getDepthbuffer();
2677
2678 if(attachmentHandle != framebuffer->getStencilbufferName())
2679 {
2680 // Different attachments to DEPTH and STENCIL, query fails
2681 return error(GL_INVALID_OPERATION);
2682 }
2683 break;
2684 default:
2685 ASSERT((unsigned int)(attachment - GL_COLOR_ATTACHMENT0) < MAX_COLOR_ATTACHMENTS);
2686 attachmentType = framebuffer->getColorbufferType(attachment - GL_COLOR_ATTACHMENT0);
2687 attachmentHandle = framebuffer->getColorbufferName(attachment - GL_COLOR_ATTACHMENT0);
2688 attachmentLayer = framebuffer->getColorbufferLayer(attachment - GL_COLOR_ATTACHMENT0);
2689 renderbuffer = framebuffer->getColorbuffer(attachment - GL_COLOR_ATTACHMENT0);
2690 break;
2691 }
2692
2693 GLenum attachmentObjectType = GL_NONE; // Type category
2694 if(framebufferName == 0)
2695 {
2696 attachmentObjectType = GL_FRAMEBUFFER_DEFAULT;
2697 }
2698 else if(attachmentType == GL_NONE || Framebuffer::IsRenderbuffer(attachmentType))
2699 {
2700 attachmentObjectType = attachmentType;
2701 }
2702 else if(es2::IsTextureTarget(attachmentType))
2703 {
2704 attachmentObjectType = GL_TEXTURE;
2705 }
2706 else UNREACHABLE(attachmentType);
2707
2708 if(attachmentObjectType != GL_NONE)
2709 {
2710 switch(pname)
2711 {
2712 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2713 *params = attachmentObjectType;
2714 break;
2715 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2716 if(attachmentObjectType == GL_RENDERBUFFER || attachmentObjectType == GL_TEXTURE)
2717 {
2718 *params = attachmentHandle;
2719 }
2720 else
2721 {
2722 return error(GL_INVALID_ENUM);
2723 }
2724 break;
2725 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL:
2726 if(attachmentObjectType == GL_TEXTURE)
2727 {
2728 *params = renderbuffer->getLevel();
2729 }
2730 else
2731 {
2732 return error(GL_INVALID_ENUM);
2733 }
2734 break;
2735 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE:
2736 if(attachmentObjectType == GL_TEXTURE)
2737 {
2738 if(es2::IsCubemapTextureTarget(attachmentType))
2739 {
2740 *params = attachmentType;
2741 }
2742 else
2743 {
2744 *params = 0;
2745 }
2746 }
2747 else
2748 {
2749 return error(GL_INVALID_ENUM);
2750 }
2751 break;
2752 case GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER:
2753 *params = attachmentLayer;
2754 break;
2755 case GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE:
2756 *params = renderbuffer->getRedSize();
2757 break;
2758 case GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE:
2759 *params = renderbuffer->getGreenSize();
2760 break;
2761 case GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE:
2762 *params = renderbuffer->getBlueSize();
2763 break;
2764 case GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE:
2765 *params = renderbuffer->getAlphaSize();
2766 break;
2767 case GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE:
2768 *params = renderbuffer->getDepthSize();
2769 break;
2770 case GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE:
2771 *params = renderbuffer->getStencilSize();
2772 break;
2773 case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE:
2774 // case GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE_EXT: // GL_EXT_color_buffer_half_float
2775 if(attachment == GL_DEPTH_STENCIL_ATTACHMENT)
2776 {
2777 return error(GL_INVALID_OPERATION);
2778 }
2779
2780 *params = GetComponentType(renderbuffer->getFormat(), attachment);
2781 break;
2782 case GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING:
2783 *params = GetColorEncoding(renderbuffer->getFormat());
2784 break;
2785 default:
2786 return error(GL_INVALID_ENUM);
2787 }
2788 }
2789 else
2790 {
2791 // ES 2.0.25 spec pg 127 states that if the value of FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
2792 // is NONE, then querying any other pname will generate INVALID_ENUM.
2793
2794 // ES 3.0.2 spec pg 235 states that if the attachment type is none,
2795 // GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME will return zero and be an
2796 // INVALID_OPERATION for all other pnames
2797
2798 switch(pname)
2799 {
2800 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE:
2801 *params = GL_NONE;
2802 break;
2803 case GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME:
2804 *params = 0;
2805 break;
2806 default:
2807 return error(GL_INVALID_OPERATION);
2808 }
2809 }
2810 }
2811}
2812
2813GLenum GL_APIENTRY GetGraphicsResetStatusEXT(void)
2814{
2815 TRACE("()");
2816
2817 return GL_NO_ERROR;
2818}
2819
2820void GL_APIENTRY GetIntegerv(GLenum pname, GLint* params)
2821{
2822 TRACE("(GLenum pname = 0x%X, GLint* params = %p)", pname, params);
2823
2824 auto context = es2::getContext();
2825
2826 if(!context)
2827 {
2828 // Not strictly an error, but probably unintended or attempting to rely on non-compliant behavior
2829 ERR("glGetIntegerv() called without current context.");
2830
2831 // This is not spec compliant! When there is no current GL context, functions should
2832 // have no side effects. Google Maps queries these values before creating a context,
2833 // so we need this as a bug-compatible workaround.
2834 switch(pname)
2835 {
2836 case GL_MAX_TEXTURE_SIZE: *params = es2::IMPLEMENTATION_MAX_TEXTURE_SIZE; return;
2837 case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = es2::MAX_VERTEX_TEXTURE_IMAGE_UNITS; return;
2838 case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = es2::MAX_COMBINED_TEXTURE_IMAGE_UNITS; return;
2839 case GL_STENCIL_BITS: *params = 8; return;
2840 case GL_ALIASED_LINE_WIDTH_RANGE:
2841 params[0] = (GLint)es2::ALIASED_LINE_WIDTH_RANGE_MIN;
2842 params[1] = (GLint)es2::ALIASED_LINE_WIDTH_RANGE_MAX;
2843 return;
2844 }
2845 }
2846
2847 if(context)
2848 {
2849 if(!(context->getIntegerv(pname, params)))
2850 {
2851 GLenum nativeType;
2852 unsigned int numParams = 0;
2853 if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))
2854 return error(GL_INVALID_ENUM);
2855
2856 if(numParams == 0)
2857 return; // it is known that pname is valid, but there are no parameters to return
2858
2859 if(nativeType == GL_BOOL)
2860 {
2861 GLboolean *boolParams = nullptr;
2862 boolParams = new GLboolean[numParams];
2863
2864 context->getBooleanv(pname, boolParams);
2865
2866 for(unsigned int i = 0; i < numParams; ++i)
2867 {
2868 params[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
2869 }
2870
2871 delete [] boolParams;
2872 }
2873 else if(nativeType == GL_FLOAT)
2874 {
2875 GLfloat *floatParams = nullptr;
2876 floatParams = new GLfloat[numParams];
2877
2878 context->getFloatv(pname, floatParams);
2879
2880 for(unsigned int i = 0; i < numParams; ++i)
2881 {
2882 if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
2883 {
2884 params[i] = convert_float_fixed(floatParams[i]);
2885 }
2886 else
2887 {
2888 params[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
2889 }
2890 }
2891
2892 delete [] floatParams;
2893 }
2894 }
2895 }
2896}
2897
2898void GL_APIENTRY GetProgramiv(GLuint program, GLenum pname, GLint* params)
2899{
2900 TRACE("(GLuint program = %d, GLenum pname = 0x%X, GLint* params = %p)", program, pname, params);
2901
2902 auto context = es2::getContext();
2903
2904 if(context)
2905 {
2906 es2::Program *programObject = context->getProgram(program);
2907
2908 if(!programObject)
2909 {
2910 if(context->getShader(program))
2911 {
2912 return error(GL_INVALID_OPERATION);
2913 }
2914 else
2915 {
2916 return error(GL_INVALID_VALUE);
2917 }
2918 }
2919
2920 switch(pname)
2921 {
2922 case GL_DELETE_STATUS:
2923 *params = programObject->isFlaggedForDeletion();
2924 return;
2925 case GL_LINK_STATUS:
2926 *params = programObject->isLinked();
2927 return;
2928 case GL_VALIDATE_STATUS:
2929 *params = programObject->isValidated();
2930 return;
2931 case GL_INFO_LOG_LENGTH:
2932 *params = (GLint)programObject->getInfoLogLength();
2933 return;
2934 case GL_ATTACHED_SHADERS:
2935 *params = programObject->getAttachedShadersCount();
2936 return;
2937 case GL_ACTIVE_ATTRIBUTES:
2938 *params = (GLint)programObject->getActiveAttributeCount();
2939 return;
2940 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
2941 *params = programObject->getActiveAttributeMaxLength();
2942 return;
2943 case GL_ACTIVE_UNIFORMS:
2944 *params = (GLint)programObject->getActiveUniformCount();
2945 return;
2946 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
2947 *params = programObject->getActiveUniformMaxLength();
2948 return;
2949 case GL_ACTIVE_UNIFORM_BLOCKS:
2950 *params = (GLint)programObject->getActiveUniformBlockCount();
2951 return;
2952 case GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH:
2953 *params = programObject->getActiveUniformBlockMaxLength();
2954 return;
2955 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
2956 *params = programObject->getTransformFeedbackBufferMode();
2957 return;
2958 case GL_TRANSFORM_FEEDBACK_VARYINGS:
2959 *params = programObject->getTransformFeedbackVaryingCount();
2960 return;
2961 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
2962 *params = programObject->getTransformFeedbackVaryingMaxLength();
2963 return;
2964 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
2965 *params = programObject->getBinaryRetrievableHint();
2966 return;
2967 case GL_PROGRAM_BINARY_LENGTH:
2968 *params = programObject->getBinaryLength();
2969 return;
2970 default:
2971 return error(GL_INVALID_ENUM);
2972 }
2973 }
2974}
2975
2976void GL_APIENTRY GetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
2977{
2978 TRACE("(GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = %p, GLchar* infolog = %p)",
2979 program, bufsize, length, infolog);
2980
2981 if(bufsize < 0)
2982 {
2983 return error(GL_INVALID_VALUE);
2984 }
2985
2986 auto context = es2::getContext();
2987
2988 if(context)
2989 {
2990 es2::Program *programObject = context->getProgram(program);
2991
2992 if(!programObject)
2993 {
2994 if(context->getShader(program))
2995 {
2996 return error(GL_INVALID_OPERATION);
2997 }
2998 else
2999 {
3000 return error(GL_INVALID_VALUE);
3001 }
3002 }
3003
3004 programObject->getInfoLog(bufsize, length, infolog);
3005 }
3006}
3007
3008void GL_APIENTRY GetQueryivEXT(GLenum target, GLenum pname, GLint *params)
3009{
3010 TRACE("GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = %p)", target, pname, params);
3011
3012 switch(pname)
3013 {
3014 case GL_CURRENT_QUERY_EXT:
3015 break;
3016 default:
3017 return error(GL_INVALID_ENUM);
3018 }
3019
3020 auto context = es2::getContext();
3021
3022 if(context)
3023 {
3024 params[0] = context->getActiveQuery(target);
3025 }
3026}
3027
3028void GL_APIENTRY GetQueryObjectuivEXT(GLuint name, GLenum pname, GLuint *params)
3029{
3030 TRACE("(GLuint name = %d, GLenum pname = 0x%X, GLuint *params = %p)", name, pname, params);
3031
3032 switch(pname)
3033 {
3034 case GL_QUERY_RESULT_EXT:
3035 case GL_QUERY_RESULT_AVAILABLE_EXT:
3036 break;
3037 default:
3038 return error(GL_INVALID_ENUM);
3039 }
3040
3041 auto context = es2::getContext();
3042
3043 if(context)
3044 {
3045 es2::Query *queryObject = context->getQuery(name);
3046
3047 if(!queryObject)
3048 {
3049 return error(GL_INVALID_OPERATION);
3050 }
3051
3052 if(context->getActiveQuery(queryObject->getType()) == name)
3053 {
3054 return error(GL_INVALID_OPERATION);
3055 }
3056
3057 switch(pname)
3058 {
3059 case GL_QUERY_RESULT_EXT:
3060 params[0] = queryObject->getResult();
3061 break;
3062 case GL_QUERY_RESULT_AVAILABLE_EXT:
3063 params[0] = queryObject->isResultAvailable();
3064 break;
3065 default:
3066 ASSERT(false);
3067 }
3068 }
3069}
3070
3071void GL_APIENTRY GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
3072{
3073 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = %p)", target, pname, params);
3074
3075 auto context = es2::getContext();
3076
3077 if(context)
3078 {
3079 if(target != GL_RENDERBUFFER)
3080 {
3081 return error(GL_INVALID_ENUM);
3082 }
3083
3084 if(context->getRenderbufferName() == 0)
3085 {
3086 return error(GL_INVALID_OPERATION);
3087 }
3088
3089 es2::Renderbuffer *renderbuffer = context->getRenderbuffer(context->getRenderbufferName());
3090
3091 switch(pname)
3092 {
3093 case GL_RENDERBUFFER_WIDTH: *params = renderbuffer->getWidth(); break;
3094 case GL_RENDERBUFFER_HEIGHT: *params = renderbuffer->getHeight(); break;
3095 case GL_RENDERBUFFER_INTERNAL_FORMAT:
3096 {
3097 GLint internalformat = renderbuffer->getFormat();
3098 *params = (internalformat == GL_NONE) ? GL_RGBA4 : internalformat;
3099 }
3100 break;
3101 case GL_RENDERBUFFER_RED_SIZE: *params = renderbuffer->getRedSize(); break;
3102 case GL_RENDERBUFFER_GREEN_SIZE: *params = renderbuffer->getGreenSize(); break;
3103 case GL_RENDERBUFFER_BLUE_SIZE: *params = renderbuffer->getBlueSize(); break;
3104 case GL_RENDERBUFFER_ALPHA_SIZE: *params = renderbuffer->getAlphaSize(); break;
3105 case GL_RENDERBUFFER_DEPTH_SIZE: *params = renderbuffer->getDepthSize(); break;
3106 case GL_RENDERBUFFER_STENCIL_SIZE: *params = renderbuffer->getStencilSize(); break;
3107 case GL_RENDERBUFFER_SAMPLES: *params = renderbuffer->getSamples(); break;
3108 default:
3109 return error(GL_INVALID_ENUM);
3110 }
3111 }
3112}
3113
3114void GL_APIENTRY GetShaderiv(GLuint shader, GLenum pname, GLint* params)
3115{
3116 TRACE("(GLuint shader = %d, GLenum pname = %d, GLint* params = %p)", shader, pname, params);
3117
3118 auto context = es2::getContext();
3119
3120 if(context)
3121 {
3122 es2::Shader *shaderObject = context->getShader(shader);
3123
3124 if(!shaderObject)
3125 {
3126 if(context->getProgram(shader))
3127 {
3128 return error(GL_INVALID_OPERATION);
3129 }
3130 else
3131 {
3132 return error(GL_INVALID_VALUE);
3133 }
3134 }
3135
3136 switch(pname)
3137 {
3138 case GL_SHADER_TYPE:
3139 *params = shaderObject->getType();
3140 return;
3141 case GL_DELETE_STATUS:
3142 *params = shaderObject->isFlaggedForDeletion();
3143 return;
3144 case GL_COMPILE_STATUS:
3145 *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE;
3146 return;
3147 case GL_INFO_LOG_LENGTH:
3148 *params = (GLint)shaderObject->getInfoLogLength();
3149 return;
3150 case GL_SHADER_SOURCE_LENGTH:
3151 *params = (GLint)shaderObject->getSourceLength();
3152 return;
3153 default:
3154 return error(GL_INVALID_ENUM);
3155 }
3156 }
3157}
3158
3159void GL_APIENTRY GetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
3160{
3161 TRACE("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = %p, GLchar* infolog = %p)",
3162 shader, bufsize, length, infolog);
3163
3164 if(bufsize < 0)
3165 {
3166 return error(GL_INVALID_VALUE);
3167 }
3168
3169 auto context = es2::getContext();
3170
3171 if(context)
3172 {
3173 es2::Shader *shaderObject = context->getShader(shader);
3174
3175 if(!shaderObject)
3176 {
3177 if(context->getProgram(shader))
3178 {
3179 return error(GL_INVALID_OPERATION);
3180 }
3181 else
3182 {
3183 return error(GL_INVALID_VALUE);
3184 }
3185 }
3186
3187 shaderObject->getInfoLog(bufsize, length, infolog);
3188 }
3189}
3190
3191void GL_APIENTRY GetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
3192{
3193 TRACE("(GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = %p, GLint* precision = %p)",
3194 shadertype, precisiontype, range, precision);
3195
3196 switch(shadertype)
3197 {
3198 case GL_VERTEX_SHADER:
3199 case GL_FRAGMENT_SHADER:
3200 break;
3201 default:
3202 return error(GL_INVALID_ENUM);
3203 }
3204
3205 switch(precisiontype)
3206 {
3207 case GL_LOW_FLOAT:
3208 case GL_MEDIUM_FLOAT:
3209 case GL_HIGH_FLOAT:
3210 // IEEE 754 single-precision
3211 range[0] = 127;
3212 range[1] = 127;
3213 *precision = 23;
3214 break;
3215 case GL_LOW_INT:
3216 case GL_MEDIUM_INT:
3217 case GL_HIGH_INT:
3218 // Full integer precision is supported
3219 range[0] = 31;
3220 range[1] = 30;
3221 *precision = 0;
3222 break;
3223 default:
3224 return error(GL_INVALID_ENUM);
3225 }
3226}
3227
3228void GL_APIENTRY GetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
3229{
3230 TRACE("(GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = %p, GLchar* source = %p)",
3231 shader, bufsize, length, source);
3232
3233 if(bufsize < 0)
3234 {
3235 return error(GL_INVALID_VALUE);
3236 }
3237
3238 auto context = es2::getContext();
3239
3240 if(context)
3241 {
3242 es2::Shader *shaderObject = context->getShader(shader);
3243
3244 if(!shaderObject)
3245 {
3246 if(context->getProgram(shader))
3247 {
3248 return error(GL_INVALID_OPERATION);
3249 }
3250 else
3251 {
3252 return error(GL_INVALID_VALUE);
3253 }
3254 }
3255
3256 shaderObject->getSource(bufsize, length, source);
3257 }
3258}
3259
3260const GLubyte* GL_APIENTRY GetString(GLenum name)
3261{
3262 TRACE("(GLenum name = 0x%X)", name);
3263
3264 switch(name)
3265 {
3266 case GL_VENDOR:
3267 return (GLubyte*)"Google Inc.";
3268 case GL_RENDERER:
3269 return (GLubyte*)"Google SwiftShader";
3270 case GL_VERSION:
3271 return (GLubyte*)"OpenGL ES 3.0 SwiftShader " VERSION_STRING;
3272 case GL_SHADING_LANGUAGE_VERSION:
3273 return (GLubyte*)"OpenGL ES GLSL ES 3.00 SwiftShader " VERSION_STRING;
3274 case GL_EXTENSIONS:
3275 {
3276 auto context = es2::getContext();
3277 return context ? context->getExtensions(GL_INVALID_INDEX) : (GLubyte*)nullptr;
3278 }
3279 default:
3280 return error(GL_INVALID_ENUM, (GLubyte*)nullptr);
3281 }
3282}
3283
3284void GL_APIENTRY GetTexParameterfv(GLenum target, GLenum pname, GLfloat* params)
3285{
3286 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = %p)", target, pname, params);
3287
3288 auto context = es2::getContext();
3289
3290 if(context)
3291 {
3292 es2::Texture *texture = context->getTargetTexture(target);
3293
3294 if(!texture)
3295 {
3296 return;
3297 }
3298
3299 switch(pname)
3300 {
3301 case GL_TEXTURE_MAG_FILTER:
3302 *params = (GLfloat)texture->getMagFilter();
3303 break;
3304 case GL_TEXTURE_MIN_FILTER:
3305 *params = (GLfloat)texture->getMinFilter();
3306 break;
3307 case GL_TEXTURE_WRAP_S:
3308 *params = (GLfloat)texture->getWrapS();
3309 break;
3310 case GL_TEXTURE_WRAP_T:
3311 *params = (GLfloat)texture->getWrapT();
3312 break;
3313 case GL_TEXTURE_WRAP_R_OES:
3314 *params = (GLfloat)texture->getWrapR();
3315 break;
3316 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
3317 *params = texture->getMaxAnisotropy();
3318 break;
3319 case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES:
3320 *params = (GLfloat)1;
3321 break;
3322 case GL_TEXTURE_BASE_LEVEL:
3323 *params = (GLfloat)texture->getBaseLevel();
3324 break;
3325 case GL_TEXTURE_COMPARE_FUNC:
3326 *params = (GLfloat)texture->getCompareFunc();
3327 break;
3328 case GL_TEXTURE_COMPARE_MODE:
3329 *params = (GLfloat)texture->getCompareMode();
3330 break;
3331 case GL_TEXTURE_IMMUTABLE_FORMAT:
3332 *params = (GLfloat)texture->getImmutableFormat();
3333 break;
3334 case GL_TEXTURE_IMMUTABLE_LEVELS:
3335 *params = (GLfloat)texture->getImmutableLevels();
3336 break;
3337 case GL_TEXTURE_MAX_LEVEL:
3338 *params = (GLfloat)texture->getMaxLevel();
3339 break;
3340 case GL_TEXTURE_MAX_LOD:
3341 *params = texture->getMaxLOD();
3342 break;
3343 case GL_TEXTURE_MIN_LOD:
3344 *params = texture->getMinLOD();
3345 break;
3346 case GL_TEXTURE_SWIZZLE_R:
3347 *params = (GLfloat)texture->getSwizzleR();
3348 break;
3349 case GL_TEXTURE_SWIZZLE_G:
3350 *params = (GLfloat)texture->getSwizzleG();
3351 break;
3352 case GL_TEXTURE_SWIZZLE_B:
3353 *params = (GLfloat)texture->getSwizzleB();
3354 break;
3355 case GL_TEXTURE_SWIZZLE_A:
3356 *params = (GLfloat)texture->getSwizzleA();
3357 break;
3358 default:
3359 return error(GL_INVALID_ENUM);
3360 }
3361 }
3362}
3363
3364void GL_APIENTRY GetTexParameteriv(GLenum target, GLenum pname, GLint* params)
3365{
3366 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = %p)", target, pname, params);
3367
3368 auto context = es2::getContext();
3369
3370 if(context)
3371 {
3372 es2::Texture *texture = context->getTargetTexture(target);
3373
3374 if(!texture)
3375 {
3376 return;
3377 }
3378
3379 switch(pname)
3380 {
3381 case GL_TEXTURE_MAG_FILTER:
3382 *params = texture->getMagFilter();
3383 break;
3384 case GL_TEXTURE_MIN_FILTER:
3385 *params = texture->getMinFilter();
3386 break;
3387 case GL_TEXTURE_WRAP_S:
3388 *params = texture->getWrapS();
3389 break;
3390 case GL_TEXTURE_WRAP_T:
3391 *params = texture->getWrapT();
3392 break;
3393 case GL_TEXTURE_WRAP_R_OES:
3394 *params = texture->getWrapR();
3395 break;
3396 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
3397 *params = (GLint)texture->getMaxAnisotropy();
3398 break;
3399 case GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES:
3400 *params = 1;
3401 break;
3402 case GL_TEXTURE_BASE_LEVEL:
3403 *params = texture->getBaseLevel();
3404 break;
3405 case GL_TEXTURE_COMPARE_FUNC:
3406 *params = (GLint)texture->getCompareFunc();
3407 break;
3408 case GL_TEXTURE_COMPARE_MODE:
3409 *params = (GLint)texture->getCompareMode();
3410 break;
3411 case GL_TEXTURE_IMMUTABLE_FORMAT:
3412 *params = (GLint)texture->getImmutableFormat();
3413 break;
3414 case GL_TEXTURE_IMMUTABLE_LEVELS:
3415 *params = (GLint)texture->getImmutableLevels();
3416 break;
3417 case GL_TEXTURE_MAX_LEVEL:
3418 *params = texture->getMaxLevel();
3419 break;
3420 case GL_TEXTURE_MAX_LOD:
3421 *params = (GLint)roundf(texture->getMaxLOD());
3422 break;
3423 case GL_TEXTURE_MIN_LOD:
3424 *params = (GLint)roundf(texture->getMinLOD());
3425 break;
3426 case GL_TEXTURE_SWIZZLE_R:
3427 *params = (GLint)texture->getSwizzleR();
3428 break;
3429 case GL_TEXTURE_SWIZZLE_G:
3430 *params = (GLint)texture->getSwizzleG();
3431 break;
3432 case GL_TEXTURE_SWIZZLE_B:
3433 *params = (GLint)texture->getSwizzleB();
3434 break;
3435 case GL_TEXTURE_SWIZZLE_A:
3436 *params = (GLint)texture->getSwizzleA();
3437 break;
3438 default:
3439 return error(GL_INVALID_ENUM);
3440 }
3441 }
3442}
3443
3444void GL_APIENTRY GetnUniformfvEXT(GLuint program, GLint location, GLsizei bufSize, GLfloat* params)
3445{
3446 TRACE("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLfloat* params = %p)",
3447 program, location, bufSize, params);
3448
3449 if(bufSize < 0)
3450 {
3451 return error(GL_INVALID_VALUE);
3452 }
3453
3454 auto context = es2::getContext();
3455
3456 if(context)
3457 {
3458 es2::Program *programObject = context->getProgram(program);
3459
3460 if(!programObject)
3461 {
3462 if(context->getShader(program))
3463 {
3464 return error(GL_INVALID_OPERATION);
3465 }
3466 else
3467 {
3468 return error(GL_INVALID_VALUE);
3469 }
3470 }
3471
3472 if(!programObject->isLinked())
3473 {
3474 return error(GL_INVALID_OPERATION);
3475 }
3476
3477 if(!programObject->getUniformfv(location, &bufSize, params))
3478 {
3479 return error(GL_INVALID_OPERATION);
3480 }
3481 }
3482}
3483
3484void GL_APIENTRY GetUniformfv(GLuint program, GLint location, GLfloat* params)
3485{
3486 TRACE("(GLuint program = %d, GLint location = %d, GLfloat* params = %p)", program, location, params);
3487
3488 auto context = es2::getContext();
3489
3490 if(context)
3491 {
3492 es2::Program *programObject = context->getProgram(program);
3493
3494 if(!programObject)
3495 {
3496 if(context->getShader(program))
3497 {
3498 return error(GL_INVALID_OPERATION);
3499 }
3500 else
3501 {
3502 return error(GL_INVALID_VALUE);
3503 }
3504 }
3505
3506 if(!programObject->isLinked())
3507 {
3508 return error(GL_INVALID_OPERATION);
3509 }
3510
3511 if(!programObject->getUniformfv(location, nullptr, params))
3512 {
3513 return error(GL_INVALID_OPERATION);
3514 }
3515 }
3516}
3517
3518void GL_APIENTRY GetnUniformivEXT(GLuint program, GLint location, GLsizei bufSize, GLint* params)
3519{
3520 TRACE("(GLuint program = %d, GLint location = %d, GLsizei bufSize = %d, GLint* params = %p)",
3521 program, location, bufSize, params);
3522
3523 if(bufSize < 0)
3524 {
3525 return error(GL_INVALID_VALUE);
3526 }
3527
3528 auto context = es2::getContext();
3529
3530 if(context)
3531 {
3532 es2::Program *programObject = context->getProgram(program);
3533
3534 if(!programObject)
3535 {
3536 if(context->getShader(program))
3537 {
3538 return error(GL_INVALID_OPERATION);
3539 }
3540 else
3541 {
3542 return error(GL_INVALID_VALUE);
3543 }
3544 }
3545
3546 if(!programObject->isLinked())
3547 {
3548 return error(GL_INVALID_OPERATION);
3549 }
3550
3551 if(!programObject->getUniformiv(location, &bufSize, params))
3552 {
3553 return error(GL_INVALID_OPERATION);
3554 }
3555 }
3556}
3557
3558void GL_APIENTRY GetUniformiv(GLuint program, GLint location, GLint* params)
3559{
3560 TRACE("(GLuint program = %d, GLint location = %d, GLint* params = %p)", program, location, params);
3561
3562 auto context = es2::getContext();
3563
3564 if(context)
3565 {
3566 es2::Program *programObject = context->getProgram(program);
3567
3568 if(!programObject)
3569 {
3570 if(context->getShader(program))
3571 {
3572 return error(GL_INVALID_OPERATION);
3573 }
3574 else
3575 {
3576 return error(GL_INVALID_VALUE);
3577 }
3578 }
3579
3580 if(!programObject->isLinked())
3581 {
3582 return error(GL_INVALID_OPERATION);
3583 }
3584
3585 if(!programObject->getUniformiv(location, nullptr, params))
3586 {
3587 return error(GL_INVALID_OPERATION);
3588 }
3589 }
3590}
3591
3592int GL_APIENTRY GetUniformLocation(GLuint program, const GLchar* name)
3593{
3594 TRACE("(GLuint program = %d, const GLchar* name = %s)", program, name);
3595
3596 auto context = es2::getContext();
3597
3598 if(strstr(name, "gl_") == name)
3599 {
3600 return -1;
3601 }
3602
3603 if(context)
3604 {
3605 es2::Program *programObject = context->getProgram(program);
3606
3607 if(!programObject)
3608 {
3609 if(context->getShader(program))
3610 {
3611 return error(GL_INVALID_OPERATION, -1);
3612 }
3613 else
3614 {
3615 return error(GL_INVALID_VALUE, -1);
3616 }
3617 }
3618
3619 if(!programObject->isLinked())
3620 {
3621 return error(GL_INVALID_OPERATION, -1);
3622 }
3623
3624 return programObject->getUniformLocation(name);
3625 }
3626
3627 return -1;
3628}
3629
3630void GL_APIENTRY GetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params)
3631{
3632 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = %p)", index, pname, params);
3633
3634 auto context = es2::getContext();
3635
3636 if(context)
3637 {
3638 if(index >= es2::MAX_VERTEX_ATTRIBS)
3639 {
3640 return error(GL_INVALID_VALUE);
3641 }
3642
3643 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
3644
3645 switch(pname)
3646 {
3647 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
3648 *params = (GLfloat)(attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
3649 break;
3650 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
3651 *params = (GLfloat)attribState.mSize;
3652 break;
3653 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
3654 *params = (GLfloat)attribState.mStride;
3655 break;
3656 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
3657 *params = (GLfloat)attribState.mType;
3658 break;
3659 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
3660 *params = (GLfloat)(attribState.mNormalized ? GL_TRUE : GL_FALSE);
3661 break;
3662 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
3663 *params = (GLfloat)attribState.mBoundBuffer.name();
3664 break;
3665 case GL_CURRENT_VERTEX_ATTRIB:
3666 {
3667 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
3668 for(int i = 0; i < 4; ++i)
3669 {
3670 params[i] = attrib.getCurrentValueF(i);
3671 }
3672 }
3673 break;
3674 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
3675 *params = (GLfloat)(attribState.mPureInteger ? GL_TRUE : GL_FALSE);
3676 break;
3677 default:
3678 return error(GL_INVALID_ENUM);
3679 }
3680 }
3681}
3682
3683void GL_APIENTRY GetVertexAttribiv(GLuint index, GLenum pname, GLint* params)
3684{
3685 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint* params = %p)", index, pname, params);
3686
3687 auto context = es2::getContext();
3688
3689 if(context)
3690 {
3691 if(index >= es2::MAX_VERTEX_ATTRIBS)
3692 {
3693 return error(GL_INVALID_VALUE);
3694 }
3695
3696 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
3697
3698 switch(pname)
3699 {
3700 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
3701 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
3702 break;
3703 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
3704 *params = attribState.mSize;
3705 break;
3706 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
3707 *params = attribState.mStride;
3708 break;
3709 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
3710 *params = attribState.mType;
3711 break;
3712 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
3713 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
3714 break;
3715 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
3716 *params = attribState.mBoundBuffer.name();
3717 break;
3718 case GL_CURRENT_VERTEX_ATTRIB:
3719 {
3720 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
3721 for(int i = 0; i < 4; ++i)
3722 {
3723 float currentValue = attrib.getCurrentValueF(i);
3724 params[i] = (GLint)(currentValue > 0.0f ? floor(currentValue + 0.5f) : ceil(currentValue - 0.5f));
3725 }
3726 }
3727 break;
3728 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
3729 *params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
3730 break;
3731 default:
3732 return error(GL_INVALID_ENUM);
3733 }
3734 }
3735}
3736
3737void GL_APIENTRY GetVertexAttribPointerv(GLuint index, GLenum pname, GLvoid** pointer)
3738{
3739 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLvoid** pointer = %p)", index, pname, pointer);
3740
3741 auto context = es2::getContext();
3742
3743 if(context)
3744 {
3745 if(index >= es2::MAX_VERTEX_ATTRIBS)
3746 {
3747 return error(GL_INVALID_VALUE);
3748 }
3749
3750 if(pname != GL_VERTEX_ATTRIB_ARRAY_POINTER)
3751 {
3752 return error(GL_INVALID_ENUM);
3753 }
3754
3755 *pointer = const_cast<GLvoid*>(context->getVertexAttribPointer(index));
3756 }
3757}
3758
3759void GL_APIENTRY Hint(GLenum target, GLenum mode)
3760{
3761 TRACE("(GLenum target = 0x%X, GLenum mode = 0x%X)", target, mode);
3762
3763 switch(mode)
3764 {
3765 case GL_FASTEST:
3766 case GL_NICEST:
3767 case GL_DONT_CARE:
3768 break;
3769 default:
3770 return error(GL_INVALID_ENUM);
3771 }
3772
3773 auto context = es2::getContext();
3774
3775 if(context)
3776 {
3777 switch(target)
3778 {
3779 case GL_GENERATE_MIPMAP_HINT:
3780 context->setGenerateMipmapHint(mode);
3781 break;
3782 case GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES:
3783 context->setFragmentShaderDerivativeHint(mode);
3784 break;
3785 case GL_TEXTURE_FILTERING_HINT_CHROMIUM:
3786 context->setTextureFilteringHint(mode);
3787 break;
3788 default:
3789 return error(GL_INVALID_ENUM);
3790 }
3791 }
3792}
3793
3794GLboolean GL_APIENTRY IsBuffer(GLuint buffer)
3795{
3796 TRACE("(GLuint buffer = %d)", buffer);
3797
3798 auto context = es2::getContext();
3799
3800 if(context && buffer)
3801 {
3802 es2::Buffer *bufferObject = context->getBuffer(buffer);
3803
3804 if(bufferObject)
3805 {
3806 return GL_TRUE;
3807 }
3808 }
3809
3810 return GL_FALSE;
3811}
3812
3813GLboolean GL_APIENTRY IsEnabled(GLenum cap)
3814{
3815 TRACE("(GLenum cap = 0x%X)", cap);
3816
3817 auto context = es2::getContext();
3818
3819 if(context)
3820 {
3821 switch(cap)
3822 {
3823 case GL_CULL_FACE: return context->isCullFaceEnabled();
3824 case GL_POLYGON_OFFSET_FILL: return context->isPolygonOffsetFillEnabled();
3825 case GL_SAMPLE_ALPHA_TO_COVERAGE: return context->isSampleAlphaToCoverageEnabled();
3826 case GL_SAMPLE_COVERAGE: return context->isSampleCoverageEnabled();
3827 case GL_SCISSOR_TEST: return context->isScissorTestEnabled();
3828 case GL_STENCIL_TEST: return context->isStencilTestEnabled();
3829 case GL_DEPTH_TEST: return context->isDepthTestEnabled();
3830 case GL_BLEND: return context->isBlendEnabled();
3831 case GL_DITHER: return context->isDitherEnabled();
3832 case GL_PRIMITIVE_RESTART_FIXED_INDEX: return context->isPrimitiveRestartFixedIndexEnabled();
3833 case GL_RASTERIZER_DISCARD: return context->isRasterizerDiscardEnabled();
3834 default:
3835 return error(GL_INVALID_ENUM, false);
3836 }
3837 }
3838
3839 return false;
3840}
3841
3842GLboolean GL_APIENTRY IsFenceNV(GLuint fence)
3843{
3844 TRACE("(GLuint fence = %d)", fence);
3845
3846 auto context = es2::getContext();
3847
3848 if(context)
3849 {
3850 es2::Fence *fenceObject = context->getFence(fence);
3851
3852 if(!fenceObject)
3853 {
3854 return GL_FALSE;
3855 }
3856
3857 return fenceObject->isFence();
3858 }
3859
3860 return GL_FALSE;
3861}
3862
3863GLboolean GL_APIENTRY IsFramebuffer(GLuint framebuffer)
3864{
3865 TRACE("(GLuint framebuffer = %d)", framebuffer);
3866
3867 auto context = es2::getContext();
3868
3869 if(context && framebuffer)
3870 {
3871 es2::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer);
3872
3873 if(framebufferObject)
3874 {
3875 return GL_TRUE;
3876 }
3877 }
3878
3879 return GL_FALSE;
3880}
3881
3882GLboolean GL_APIENTRY IsProgram(GLuint program)
3883{
3884 TRACE("(GLuint program = %d)", program);
3885
3886 auto context = es2::getContext();
3887
3888 if(context && program)
3889 {
3890 es2::Program *programObject = context->getProgram(program);
3891
3892 if(programObject)
3893 {
3894 return GL_TRUE;
3895 }
3896 }
3897
3898 return GL_FALSE;
3899}
3900
3901GLboolean GL_APIENTRY IsQueryEXT(GLuint name)
3902{
3903 TRACE("(GLuint name = %d)", name);
3904
3905 if(name == 0)
3906 {
3907 return GL_FALSE;
3908 }
3909
3910 auto context = es2::getContext();
3911
3912 if(context)
3913 {
3914 es2::Query *queryObject = context->getQuery(name);
3915
3916 if(queryObject)
3917 {
3918 return GL_TRUE;
3919 }
3920 }
3921
3922 return GL_FALSE;
3923}
3924
3925GLboolean GL_APIENTRY IsRenderbuffer(GLuint renderbuffer)
3926{
3927 TRACE("(GLuint renderbuffer = %d)", renderbuffer);
3928
3929 auto context = es2::getContext();
3930
3931 if(context && renderbuffer)
3932 {
3933 es2::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer);
3934
3935 if(renderbufferObject)
3936 {
3937 return GL_TRUE;
3938 }
3939 }
3940
3941 return GL_FALSE;
3942}
3943
3944GLboolean GL_APIENTRY IsShader(GLuint shader)
3945{
3946 TRACE("(GLuint shader = %d)", shader);
3947
3948 auto context = es2::getContext();
3949
3950 if(context && shader)
3951 {
3952 es2::Shader *shaderObject = context->getShader(shader);
3953
3954 if(shaderObject)
3955 {
3956 return GL_TRUE;
3957 }
3958 }
3959
3960 return GL_FALSE;
3961}
3962
3963GLboolean GL_APIENTRY IsTexture(GLuint texture)
3964{
3965 TRACE("(GLuint texture = %d)", texture);
3966
3967 auto context = es2::getContext();
3968
3969 if(context && texture)
3970 {
3971 es2::Texture *textureObject = context->getTexture(texture);
3972
3973 if(textureObject)
3974 {
3975 return GL_TRUE;
3976 }
3977 }
3978
3979 return GL_FALSE;
3980}
3981
3982void GL_APIENTRY LineWidth(GLfloat width)
3983{
3984 TRACE("(GLfloat width = %f)", width);
3985
3986 if(width <= 0.0f)
3987 {
3988 return error(GL_INVALID_VALUE);
3989 }
3990
3991 auto context = es2::getContext();
3992
3993 if(context)
3994 {
3995 context->setLineWidth(width);
3996 }
3997}
3998
3999void GL_APIENTRY LinkProgram(GLuint program)
4000{
4001 TRACE("(GLuint program = %d)", program);
4002
4003 auto context = es2::getContext();
4004
4005 if(context)
4006 {
4007 es2::Program *programObject = context->getProgram(program);
4008
4009 if(!programObject)
4010 {
4011 if(context->getShader(program))
4012 {
4013 return error(GL_INVALID_OPERATION);
4014 }
4015 else
4016 {
4017 return error(GL_INVALID_VALUE);
4018 }
4019 }
4020
4021 if(programObject == context->getCurrentProgram())
4022 {
4023 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
4024 if(transformFeedback && transformFeedback->isActive())
4025 {
4026 return error(GL_INVALID_OPERATION);
4027 }
4028 }
4029
4030 programObject->link();
4031 }
4032}
4033
4034void GL_APIENTRY PixelStorei(GLenum pname, GLint param)
4035{
4036 TRACE("(GLenum pname = 0x%X, GLint param = %d)", pname, param);
4037
4038 auto context = es2::getContext();
4039
4040 if(context)
4041 {
4042 switch(pname)
4043 {
4044 case GL_UNPACK_ALIGNMENT:
4045 if(param != 1 && param != 2 && param != 4 && param != 8)
4046 {
4047 return error(GL_INVALID_VALUE);
4048 }
4049 context->setUnpackAlignment(param);
4050 break;
4051 case GL_PACK_ALIGNMENT:
4052 if(param != 1 && param != 2 && param != 4 && param != 8)
4053 {
4054 return error(GL_INVALID_VALUE);
4055 }
4056 context->setPackAlignment(param);
4057 break;
4058 case GL_PACK_ROW_LENGTH:
4059 if(param < 0)
4060 {
4061 return error(GL_INVALID_VALUE);
4062 }
4063 context->setPackRowLength(param);
4064 break;
4065 case GL_PACK_SKIP_PIXELS:
4066 if(param < 0)
4067 {
4068 return error(GL_INVALID_VALUE);
4069 }
4070 context->setPackSkipPixels(param);
4071 break;
4072 case GL_PACK_SKIP_ROWS:
4073 if(param < 0)
4074 {
4075 return error(GL_INVALID_VALUE);
4076 }
4077 context->setPackSkipRows(param);
4078 break;
4079 case GL_UNPACK_ROW_LENGTH:
4080 if(param < 0)
4081 {
4082 return error(GL_INVALID_VALUE);
4083 }
4084 context->setUnpackRowLength(param);
4085 break;
4086 case GL_UNPACK_IMAGE_HEIGHT:
4087 if(param < 0)
4088 {
4089 return error(GL_INVALID_VALUE);
4090 }
4091 context->setUnpackImageHeight(param);
4092 break;
4093 case GL_UNPACK_SKIP_PIXELS:
4094 if(param < 0)
4095 {
4096 return error(GL_INVALID_VALUE);
4097 }
4098 context->setUnpackSkipPixels(param);
4099 break;
4100 case GL_UNPACK_SKIP_ROWS:
4101 if(param < 0)
4102 {
4103 return error(GL_INVALID_VALUE);
4104 }
4105 context->setUnpackSkipRows(param);
4106 break;
4107 case GL_UNPACK_SKIP_IMAGES:
4108 if(param < 0)
4109 {
4110 return error(GL_INVALID_VALUE);
4111 }
4112 context->setUnpackSkipImages(param);
4113 break;
4114 default:
4115 return error(GL_INVALID_ENUM);
4116 }
4117 }
4118}
4119
4120void GL_APIENTRY PolygonOffset(GLfloat factor, GLfloat units)
4121{
4122 TRACE("(GLfloat factor = %f, GLfloat units = %f)", factor, units);
4123
4124 auto context = es2::getContext();
4125
4126 if(context)
4127 {
4128 context->setPolygonOffsetParams(factor, units);
4129 }
4130}
4131
4132void GL_APIENTRY ReadnPixelsEXT(GLint x, GLint y, GLsizei width, GLsizei height,
4133 GLenum format, GLenum type, GLsizei bufSize, GLvoid *data)
4134{
4135 TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, "
4136 "GLenum format = 0x%X, GLenum type = 0x%X, GLsizei bufSize = 0x%d, GLvoid *data = %p)",
4137 x, y, width, height, format, type, bufSize, data);
4138
4139 if(width < 0 || height < 0 || bufSize < 0)
4140 {
4141 return error(GL_INVALID_VALUE);
4142 }
4143
4144 auto context = es2::getContext();
4145
4146 if(context)
4147 {
4148 context->readPixels(x, y, width, height, format, type, &bufSize, data);
4149 }
4150}
4151
4152void GL_APIENTRY ReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
4153{
4154 TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, "
4155 "GLenum format = 0x%X, GLenum type = 0x%X, GLvoid* pixels = %p)",
4156 x, y, width, height, format, type, pixels);
4157
4158 if(width < 0 || height < 0)
4159 {
4160 return error(GL_INVALID_VALUE);
4161 }
4162
4163 auto context = es2::getContext();
4164
4165 if(context)
4166 {
4167 context->readPixels(x, y, width, height, format, type, nullptr, pixels);
4168 }
4169}
4170
4171void GL_APIENTRY ReleaseShaderCompiler(void)
4172{
4173 TRACE("()");
4174
4175 es2::Shader::releaseCompiler();
4176}
4177
4178void GL_APIENTRY RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
4179{
4180 TRACE("(GLenum target = 0x%X, GLsizei samples = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
4181 target, samples, internalformat, width, height);
4182
4183 switch(target)
4184 {
4185 case GL_RENDERBUFFER:
4186 break;
4187 default:
4188 return error(GL_INVALID_ENUM);
4189 }
4190
4191 if(width < 0 || height < 0 || samples < 0 ||
4192 width > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE ||
4193 height > es2::IMPLEMENTATION_MAX_RENDERBUFFER_SIZE)
4194 {
4195 return error(GL_INVALID_VALUE);
4196 }
4197
4198 if(samples > es2::IMPLEMENTATION_MAX_SAMPLES ||
4199 (IsNonNormalizedInteger(internalformat) && samples > 0))
4200 {
4201 return error(GL_INVALID_OPERATION);
4202 }
4203
4204 auto context = es2::getContext();
4205
4206 if(context)
4207 {
4208 GLuint handle = context->getRenderbufferName();
4209 if(handle == 0)
4210 {
4211 return error(GL_INVALID_OPERATION);
4212 }
4213
4214 if(IsColorRenderable(internalformat))
4215 {
4216 context->setRenderbufferStorage(new es2::Colorbuffer(width, height, internalformat, samples));
4217 }
4218 else if(IsDepthRenderable(internalformat) && IsStencilRenderable(internalformat))
4219 {
4220 context->setRenderbufferStorage(new es2::DepthStencilbuffer(width, height, internalformat, samples));
4221 }
4222 else if(IsDepthRenderable(internalformat))
4223 {
4224 context->setRenderbufferStorage(new es2::Depthbuffer(width, height, internalformat, samples));
4225 }
4226 else if(IsStencilRenderable(internalformat))
4227 {
4228 context->setRenderbufferStorage(new es2::Stencilbuffer(width, height, samples));
4229 }
4230 else error(GL_INVALID_ENUM);
4231 }
4232}
4233
4234void GL_APIENTRY RenderbufferStorageMultisampleANGLE(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height)
4235{
4236 RenderbufferStorageMultisample(target, samples, internalformat, width, height);
4237}
4238
4239void GL_APIENTRY RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
4240{
4241 RenderbufferStorageMultisample(target, 0, internalformat, width, height);
4242}
4243
4244void GL_APIENTRY SampleCoverage(GLclampf value, GLboolean invert)
4245{
4246 TRACE("(GLclampf value = %f, GLboolean invert = %d)", value, invert);
4247
4248 auto context = es2::getContext();
4249
4250 if(context)
4251 {
4252 context->setSampleCoverageParams(es2::clamp01(value), invert != GL_FALSE);
4253 }
4254}
4255
4256void GL_APIENTRY SetFenceNV(GLuint fence, GLenum condition)
4257{
4258 TRACE("(GLuint fence = %d, GLenum condition = 0x%X)", fence, condition);
4259
4260 if(condition != GL_ALL_COMPLETED_NV)
4261 {
4262 return error(GL_INVALID_ENUM);
4263 }
4264
4265 auto context = es2::getContext();
4266
4267 if(context)
4268 {
4269 es2::Fence *fenceObject = context->getFence(fence);
4270
4271 if(!fenceObject)
4272 {
4273 return error(GL_INVALID_OPERATION);
4274 }
4275
4276 fenceObject->setFence(condition);
4277 }
4278}
4279
4280void GL_APIENTRY Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
4281{
4282 TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
4283
4284 if(width < 0 || height < 0)
4285 {
4286 return error(GL_INVALID_VALUE);
4287 }
4288
4289 auto context = es2::getContext();
4290
4291 if(context)
4292 {
4293 context->setScissorParams(x, y, width, height);
4294 }
4295}
4296
4297void GL_APIENTRY ShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
4298{
4299 TRACE("(GLsizei n = %d, const GLuint* shaders = %p, GLenum binaryformat = 0x%X, "
4300 "const GLvoid* binary = %p, GLsizei length = %d)",
4301 n, shaders, binaryformat, binary, length);
4302
4303 // No binary shader formats are supported.
4304 return error(GL_INVALID_ENUM);
4305}
4306
4307void GL_APIENTRY ShaderSource(GLuint shader, GLsizei count, const GLchar *const *string, const GLint *length)
4308{
4309 TRACE("(GLuint shader = %d, GLsizei count = %d, const GLchar** string = %p, const GLint* length = %p)",
4310 shader, count, string, length);
4311
4312 if(count < 0)
4313 {
4314 return error(GL_INVALID_VALUE);
4315 }
4316
4317 auto context = es2::getContext();
4318
4319 if(context)
4320 {
4321 es2::Shader *shaderObject = context->getShader(shader);
4322
4323 if(!shaderObject)
4324 {
4325 if(context->getProgram(shader))
4326 {
4327 return error(GL_INVALID_OPERATION);
4328 }
4329 else
4330 {
4331 return error(GL_INVALID_VALUE);
4332 }
4333 }
4334
4335 shaderObject->setSource(count, string, length);
4336 }
4337}
4338
4339void GL_APIENTRY StencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask)
4340{
4341 TRACE("(GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d)", face, func, ref, mask);
4342
4343 switch(face)
4344 {
4345 case GL_FRONT:
4346 case GL_BACK:
4347 case GL_FRONT_AND_BACK:
4348 break;
4349 default:
4350 return error(GL_INVALID_ENUM);
4351 }
4352
4353 switch(func)
4354 {
4355 case GL_NEVER:
4356 case GL_ALWAYS:
4357 case GL_LESS:
4358 case GL_LEQUAL:
4359 case GL_EQUAL:
4360 case GL_GEQUAL:
4361 case GL_GREATER:
4362 case GL_NOTEQUAL:
4363 break;
4364 default:
4365 return error(GL_INVALID_ENUM);
4366 }
4367
4368 auto context = es2::getContext();
4369
4370 if(context)
4371 {
4372 if(face == GL_FRONT || face == GL_FRONT_AND_BACK)
4373 {
4374 context->setStencilParams(func, ref, mask);
4375 }
4376
4377 if(face == GL_BACK || face == GL_FRONT_AND_BACK)
4378 {
4379 context->setStencilBackParams(func, ref, mask);
4380 }
4381 }
4382}
4383
4384void GL_APIENTRY StencilFunc(GLenum func, GLint ref, GLuint mask)
4385{
4386 StencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask);
4387}
4388
4389void GL_APIENTRY StencilMaskSeparate(GLenum face, GLuint mask)
4390{
4391 TRACE("(GLenum face = 0x%X, GLuint mask = %d)", face, mask);
4392
4393 switch(face)
4394 {
4395 case GL_FRONT:
4396 case GL_BACK:
4397 case GL_FRONT_AND_BACK:
4398 break;
4399 default:
4400 return error(GL_INVALID_ENUM);
4401 }
4402
4403 auto context = es2::getContext();
4404
4405 if(context)
4406 {
4407 if(face == GL_FRONT || face == GL_FRONT_AND_BACK)
4408 {
4409 context->setStencilWritemask(mask);
4410 }
4411
4412 if(face == GL_BACK || face == GL_FRONT_AND_BACK)
4413 {
4414 context->setStencilBackWritemask(mask);
4415 }
4416 }
4417}
4418
4419void GL_APIENTRY StencilMask(GLuint mask)
4420{
4421 StencilMaskSeparate(GL_FRONT_AND_BACK, mask);
4422}
4423
4424void GL_APIENTRY StencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
4425{
4426 TRACE("(GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs)",
4427 face, fail, zfail, zpass);
4428
4429 switch(face)
4430 {
4431 case GL_FRONT:
4432 case GL_BACK:
4433 case GL_FRONT_AND_BACK:
4434 break;
4435 default:
4436 return error(GL_INVALID_ENUM);
4437 }
4438
4439 switch(fail)
4440 {
4441 case GL_ZERO:
4442 case GL_KEEP:
4443 case GL_REPLACE:
4444 case GL_INCR:
4445 case GL_DECR:
4446 case GL_INVERT:
4447 case GL_INCR_WRAP:
4448 case GL_DECR_WRAP:
4449 break;
4450 default:
4451 return error(GL_INVALID_ENUM);
4452 }
4453
4454 switch(zfail)
4455 {
4456 case GL_ZERO:
4457 case GL_KEEP:
4458 case GL_REPLACE:
4459 case GL_INCR:
4460 case GL_DECR:
4461 case GL_INVERT:
4462 case GL_INCR_WRAP:
4463 case GL_DECR_WRAP:
4464 break;
4465 default:
4466 return error(GL_INVALID_ENUM);
4467 }
4468
4469 switch(zpass)
4470 {
4471 case GL_ZERO:
4472 case GL_KEEP:
4473 case GL_REPLACE:
4474 case GL_INCR:
4475 case GL_DECR:
4476 case GL_INVERT:
4477 case GL_INCR_WRAP:
4478 case GL_DECR_WRAP:
4479 break;
4480 default:
4481 return error(GL_INVALID_ENUM);
4482 }
4483
4484 auto context = es2::getContext();
4485
4486 if(context)
4487 {
4488 if(face == GL_FRONT || face == GL_FRONT_AND_BACK)
4489 {
4490 context->setStencilOperations(fail, zfail, zpass);
4491 }
4492
4493 if(face == GL_BACK || face == GL_FRONT_AND_BACK)
4494 {
4495 context->setStencilBackOperations(fail, zfail, zpass);
4496 }
4497 }
4498}
4499
4500void GL_APIENTRY StencilOp(GLenum fail, GLenum zfail, GLenum zpass)
4501{
4502 StencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass);
4503}
4504
4505GLboolean GL_APIENTRY TestFenceNV(GLuint fence)
4506{
4507 TRACE("(GLuint fence = %d)", fence);
4508
4509 auto context = es2::getContext();
4510
4511 if(context)
4512 {
4513 es2::Fence *fenceObject = context->getFence(fence);
4514
4515 if(!fenceObject)
4516 {
4517 return error(GL_INVALID_OPERATION, GL_TRUE);
4518 }
4519
4520 return fenceObject->testFence();
4521 }
4522
4523 return GL_TRUE;
4524}
4525
4526void GL_APIENTRY TexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height,
4527 GLint border, GLenum format, GLenum type, const GLvoid* data)
4528{
4529 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, "
4530 "GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const GLvoid* data = %p)",
4531 target, level, internalformat, width, height, border, format, type, data);
4532
4533 if(!validImageSize(level, width, height))
4534 {
4535 return error(GL_INVALID_VALUE);
4536 }
4537
4538 auto context = es2::getContext();
4539
4540 if(context)
4541 {
4542 // GL_APPLE_texture_format_BGRA8888 allows (only) GL_BGRA_EXT / GL_RGBA, while
4543 // GL_EXT_texture_format_BGRA8888 also allows GL_BGRA_EXT / GL_BGRA_EXT.
4544 if(format == GL_BGRA_EXT && internalformat == GL_RGBA)
4545 {
4546 internalformat = GL_BGRA_EXT;
4547 }
4548
4549 GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target);
4550 if(validationError != GL_NO_ERROR)
4551 {
4552 return error(validationError);
4553 }
4554
4555 if(border != 0)
4556 {
4557 return error(GL_INVALID_VALUE);
4558 }
4559
4560 switch(target)
4561 {
4562 case GL_TEXTURE_RECTANGLE_ARB:
4563 if(level != 0)
4564 {
4565 return error(GL_INVALID_VALUE); // Defining level other than 0 is not allowed
4566 }
4567 // Fall through to GL_TEXTURE_2D case.
4568 case GL_TEXTURE_2D:
4569 if(width > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level) ||
4570 height > (es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level))
4571 {
4572 return error(GL_INVALID_VALUE);
4573 }
4574 break;
4575 case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
4576 case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
4577 case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
4578 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
4579 case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
4580 case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
4581 if(width != height)
4582 {
4583 return error(GL_INVALID_VALUE);
4584 }
4585
4586 if(width > (es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level) ||
4587 height > (es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE >> level))
4588 {
4589 return error(GL_INVALID_VALUE);
4590 }
4591 break;
4592 default:
4593 return error(GL_INVALID_ENUM);
4594 }
4595
4596 validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, format, type));
4597 if(validationError != GL_NO_ERROR)
4598 {
4599 return error(validationError);
4600 }
4601
4602 GLint sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
4603
4604 if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
4605 {
4606 es2::Texture2D *texture = context->getTexture2D(target);
4607
4608 if(!texture)
4609 {
4610 return error(GL_INVALID_OPERATION);
4611 }
4612
4613 texture->setImage(level, width, height, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
4614 }
4615 else
4616 {
4617 es2::TextureCubeMap *texture = context->getTextureCubeMap();
4618
4619 if(!texture)
4620 {
4621 return error(GL_INVALID_OPERATION);
4622 }
4623
4624 texture->setImage(target, level, width, height, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
4625 }
4626 }
4627}
4628
4629void GL_APIENTRY TexParameterf(GLenum target, GLenum pname, GLfloat param)
4630{
4631 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat param = %f)", target, pname, param);
4632
4633 auto context = es2::getContext();
4634
4635 if(context)
4636 {
4637 es2::Texture *texture = context->getTargetTexture(target);
4638
4639 if(!texture)
4640 {
4641 return;
4642 }
4643
4644 switch(pname)
4645 {
4646 case GL_TEXTURE_WRAP_S:
4647 if(!texture->setWrapS((GLenum)param))
4648 {
4649 return error(GL_INVALID_ENUM);
4650 }
4651 break;
4652 case GL_TEXTURE_WRAP_T:
4653 if(!texture->setWrapT((GLenum)param))
4654 {
4655 return error(GL_INVALID_ENUM);
4656 }
4657 break;
4658 case GL_TEXTURE_WRAP_R_OES:
4659 if(!texture->setWrapR((GLenum)param))
4660 {
4661 return error(GL_INVALID_ENUM);
4662 }
4663 break;
4664 case GL_TEXTURE_MIN_FILTER:
4665 if(!texture->setMinFilter((GLenum)param))
4666 {
4667 return error(GL_INVALID_ENUM);
4668 }
4669 break;
4670 case GL_TEXTURE_MAG_FILTER:
4671 if(!texture->setMagFilter((GLenum)param))
4672 {
4673 return error(GL_INVALID_ENUM);
4674 }
4675 break;
4676 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
4677 if(!texture->setMaxAnisotropy(param))
4678 {
4679 return error(GL_INVALID_VALUE);
4680 }
4681 break;
4682 case GL_TEXTURE_BASE_LEVEL:
4683 if(!texture->setBaseLevel((GLint)(roundf(param))))
4684 {
4685 return error(GL_INVALID_VALUE);
4686 }
4687 break;
4688 case GL_TEXTURE_COMPARE_FUNC:
4689 if(!texture->setCompareFunc((GLenum)param))
4690 {
4691 return error(GL_INVALID_VALUE);
4692 }
4693 break;
4694 case GL_TEXTURE_COMPARE_MODE:
4695 if(!texture->setCompareMode((GLenum)param))
4696 {
4697 return error(GL_INVALID_VALUE);
4698 }
4699 break;
4700 case GL_TEXTURE_MAX_LEVEL:
4701 if(!texture->setMaxLevel((GLint)(roundf(param))))
4702 {
4703 return error(GL_INVALID_VALUE);
4704 }
4705 break;
4706 case GL_TEXTURE_MAX_LOD:
4707 if(!texture->setMaxLOD(param))
4708 {
4709 return error(GL_INVALID_VALUE);
4710 }
4711 break;
4712 case GL_TEXTURE_MIN_LOD:
4713 if(!texture->setMinLOD(param))
4714 {
4715 return error(GL_INVALID_VALUE);
4716 }
4717 break;
4718 case GL_TEXTURE_SWIZZLE_R:
4719 if(!texture->setSwizzleR((GLenum)param))
4720 {
4721 return error(GL_INVALID_VALUE);
4722 }
4723 break;
4724 case GL_TEXTURE_SWIZZLE_G:
4725 if(!texture->setSwizzleG((GLenum)param))
4726 {
4727 return error(GL_INVALID_VALUE);
4728 }
4729 break;
4730 case GL_TEXTURE_SWIZZLE_B:
4731 if(!texture->setSwizzleB((GLenum)param))
4732 {
4733 return error(GL_INVALID_VALUE);
4734 }
4735 break;
4736 case GL_TEXTURE_SWIZZLE_A:
4737 if(!texture->setSwizzleA((GLenum)param))
4738 {
4739 return error(GL_INVALID_VALUE);
4740 }
4741 break;
4742 default:
4743 return error(GL_INVALID_ENUM);
4744 }
4745 }
4746}
4747
4748void GL_APIENTRY TexParameterfv(GLenum target, GLenum pname, const GLfloat* params)
4749{
4750 TexParameterf(target, pname, *params);
4751}
4752
4753void GL_APIENTRY TexParameteri(GLenum target, GLenum pname, GLint param)
4754{
4755 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint param = %d)", target, pname, param);
4756
4757 auto context = es2::getContext();
4758
4759 if(context)
4760 {
4761 es2::Texture *texture = context->getTargetTexture(target);
4762
4763 if(!texture)
4764 {
4765 return;
4766 }
4767
4768 switch(pname)
4769 {
4770 case GL_TEXTURE_WRAP_S:
4771 if(!texture->setWrapS((GLenum)param))
4772 {
4773 return error(GL_INVALID_ENUM);
4774 }
4775 break;
4776 case GL_TEXTURE_WRAP_T:
4777 if(!texture->setWrapT((GLenum)param))
4778 {
4779 return error(GL_INVALID_ENUM);
4780 }
4781 break;
4782 case GL_TEXTURE_WRAP_R_OES:
4783 if(!texture->setWrapR((GLenum)param))
4784 {
4785 return error(GL_INVALID_ENUM);
4786 }
4787 break;
4788 case GL_TEXTURE_MIN_FILTER:
4789 if(!texture->setMinFilter((GLenum)param))
4790 {
4791 return error(GL_INVALID_ENUM);
4792 }
4793 break;
4794 case GL_TEXTURE_MAG_FILTER:
4795 if(!texture->setMagFilter((GLenum)param))
4796 {
4797 return error(GL_INVALID_ENUM);
4798 }
4799 break;
4800 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
4801 if(!texture->setMaxAnisotropy((GLfloat)param))
4802 {
4803 return error(GL_INVALID_VALUE);
4804 }
4805 break;
4806 case GL_TEXTURE_BASE_LEVEL:
4807 if((texture->getTarget() == GL_TEXTURE_RECTANGLE_ARB) && (param != 0))
4808 {
4809 return error(GL_INVALID_OPERATION); // Base level has to be 0
4810 }
4811 if(!texture->setBaseLevel(param))
4812 {
4813 return error(GL_INVALID_VALUE);
4814 }
4815 break;
4816 case GL_TEXTURE_COMPARE_FUNC:
4817 if(!texture->setCompareFunc((GLenum)param))
4818 {
4819 return error(GL_INVALID_VALUE);
4820 }
4821 break;
4822 case GL_TEXTURE_COMPARE_MODE:
4823 if(!texture->setCompareMode((GLenum)param))
4824 {
4825 return error(GL_INVALID_VALUE);
4826 }
4827 break;
4828 case GL_TEXTURE_MAX_LEVEL:
4829 if(!texture->setMaxLevel(param))
4830 {
4831 return error(GL_INVALID_VALUE);
4832 }
4833 break;
4834 case GL_TEXTURE_MAX_LOD:
4835 if(!texture->setMaxLOD((GLfloat)param))
4836 {
4837 return error(GL_INVALID_VALUE);
4838 }
4839 break;
4840 case GL_TEXTURE_MIN_LOD:
4841 if(!texture->setMinLOD((GLfloat)param))
4842 {
4843 return error(GL_INVALID_VALUE);
4844 }
4845 break;
4846 case GL_TEXTURE_SWIZZLE_R:
4847 if(!texture->setSwizzleR((GLenum)param))
4848 {
4849 return error(GL_INVALID_VALUE);
4850 }
4851 break;
4852 case GL_TEXTURE_SWIZZLE_G:
4853 if(!texture->setSwizzleG((GLenum)param))
4854 {
4855 return error(GL_INVALID_VALUE);
4856 }
4857 break;
4858 case GL_TEXTURE_SWIZZLE_B:
4859 if(!texture->setSwizzleB((GLenum)param))
4860 {
4861 return error(GL_INVALID_VALUE);
4862 }
4863 break;
4864 case GL_TEXTURE_SWIZZLE_A:
4865 if(!texture->setSwizzleA((GLenum)param))
4866 {
4867 return error(GL_INVALID_VALUE);
4868 }
4869 break;
4870 default:
4871 return error(GL_INVALID_ENUM);
4872 }
4873 }
4874}
4875
4876void GL_APIENTRY TexParameteriv(GLenum target, GLenum pname, const GLint* params)
4877{
4878 TexParameteri(target, pname, *params);
4879}
4880
4881void GL_APIENTRY TexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
4882 GLenum format, GLenum type, const GLvoid* data)
4883{
4884 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
4885 "GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, "
4886 "const GLvoid* data = %p)",
4887 target, level, xoffset, yoffset, width, height, format, type, data);
4888
4889 if(!es2::IsTexImageTarget(target))
4890 {
4891 return error(GL_INVALID_ENUM);
4892 }
4893
4894 if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
4895 {
4896 return error(GL_INVALID_VALUE);
4897 }
4898
4899 if(xoffset < 0 || yoffset < 0 || width < 0 || height < 0)
4900 {
4901 return error(GL_INVALID_VALUE);
4902 }
4903
4904 if(std::numeric_limits<GLsizei>::max() - xoffset < width || std::numeric_limits<GLsizei>::max() - yoffset < height)
4905 {
4906 return error(GL_INVALID_VALUE);
4907 }
4908
4909 auto context = es2::getContext();
4910
4911 if(context)
4912 {
4913 if(target == GL_TEXTURE_2D || target == GL_TEXTURE_RECTANGLE_ARB)
4914 {
4915 es2::Texture2D *texture = context->getTexture2D(target);
4916
4917 GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, width, height, format, type, texture);
4918 if(validationError != GL_NO_ERROR)
4919 {
4920 return error(validationError);
4921 }
4922
4923 validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, format, type));
4924 if(validationError != GL_NO_ERROR)
4925 {
4926 return error(validationError);
4927 }
4928
4929 texture->subImage(level, xoffset, yoffset, width, height, format, type, context->getUnpackParameters(), data);
4930 }
4931 else if(es2::IsCubemapTextureTarget(target))
4932 {
4933 es2::TextureCubeMap *texture = context->getTextureCubeMap();
4934
4935 GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, width, height, format, type, texture);
4936 if(validationError != GL_NO_ERROR)
4937 {
4938 return error(validationError);
4939 }
4940
4941 validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, 1, format, type));
4942 if(validationError != GL_NO_ERROR)
4943 {
4944 return error(validationError);
4945 }
4946
4947 texture->subImage(target, level, xoffset, yoffset, width, height, format, type, context->getUnpackParameters(), data);
4948 }
4949 else UNREACHABLE(target);
4950 }
4951}
4952
4953void GL_APIENTRY Uniform1fv(GLint location, GLsizei count, const GLfloat* v)
4954{
4955 TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = %p)", location, count, v);
4956
4957 if(count < 0)
4958 {
4959 return error(GL_INVALID_VALUE);
4960 }
4961
4962 auto context = es2::getContext();
4963
4964 if(context)
4965 {
4966 es2::Program *program = context->getCurrentProgram();
4967
4968 if(!program)
4969 {
4970 return error(GL_INVALID_OPERATION);
4971 }
4972
4973 if(location == -1)
4974 {
4975 return;
4976 }
4977
4978 if(!program->setUniform1fv(location, count, v))
4979 {
4980 return error(GL_INVALID_OPERATION);
4981 }
4982 }
4983}
4984
4985void GL_APIENTRY Uniform1f(GLint location, GLfloat x)
4986{
4987 Uniform1fv(location, 1, &x);
4988}
4989
4990void GL_APIENTRY Uniform1iv(GLint location, GLsizei count, const GLint* v)
4991{
4992 TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = %p)", location, count, v);
4993
4994 if(count < 0)
4995 {
4996 return error(GL_INVALID_VALUE);
4997 }
4998
4999 auto context = es2::getContext();
5000
5001 if(context)
5002 {
5003 es2::Program *program = context->getCurrentProgram();
5004
5005 if(!program)
5006 {
5007 return error(GL_INVALID_OPERATION);
5008 }
5009
5010 if(location == -1)
5011 {
5012 return;
5013 }
5014
5015 if(!program->setUniform1iv(location, count, v))
5016 {
5017 return error(GL_INVALID_OPERATION);
5018 }
5019 }
5020}
5021
5022void GL_APIENTRY Uniform1i(GLint location, GLint x)
5023{
5024 Uniform1iv(location, 1, &x);
5025}
5026
5027void GL_APIENTRY Uniform2fv(GLint location, GLsizei count, const GLfloat* v)
5028{
5029 TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = %p)", location, count, v);
5030
5031 if(count < 0)
5032 {
5033 return error(GL_INVALID_VALUE);
5034 }
5035
5036 auto context = es2::getContext();
5037
5038 if(context)
5039 {
5040 es2::Program *program = context->getCurrentProgram();
5041
5042 if(!program)
5043 {
5044 return error(GL_INVALID_OPERATION);
5045 }
5046
5047 if(location == -1)
5048 {
5049 return;
5050 }
5051
5052 if(!program->setUniform2fv(location, count, v))
5053 {
5054 return error(GL_INVALID_OPERATION);
5055 }
5056 }
5057}
5058
5059void GL_APIENTRY Uniform2f(GLint location, GLfloat x, GLfloat y)
5060{
5061 GLfloat xy[2] = {x, y};
5062
5063 Uniform2fv(location, 1, (GLfloat*)&xy);
5064}
5065
5066void GL_APIENTRY Uniform2iv(GLint location, GLsizei count, const GLint* v)
5067{
5068 TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = %p)", location, count, v);
5069
5070 if(count < 0)
5071 {
5072 return error(GL_INVALID_VALUE);
5073 }
5074
5075 auto context = es2::getContext();
5076
5077 if(context)
5078 {
5079 es2::Program *program = context->getCurrentProgram();
5080
5081 if(!program)
5082 {
5083 return error(GL_INVALID_OPERATION);
5084 }
5085
5086 if(location == -1)
5087 {
5088 return;
5089 }
5090
5091 if(!program->setUniform2iv(location, count, v))
5092 {
5093 return error(GL_INVALID_OPERATION);
5094 }
5095 }
5096}
5097
5098void GL_APIENTRY Uniform2i(GLint location, GLint x, GLint y)
5099{
5100 GLint xy[4] = {x, y};
5101
5102 Uniform2iv(location, 1, (GLint*)&xy);
5103}
5104
5105void GL_APIENTRY Uniform3fv(GLint location, GLsizei count, const GLfloat* v)
5106{
5107 TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = %p)", location, count, v);
5108
5109 if(count < 0)
5110 {
5111 return error(GL_INVALID_VALUE);
5112 }
5113
5114 auto context = es2::getContext();
5115
5116 if(context)
5117 {
5118 es2::Program *program = context->getCurrentProgram();
5119
5120 if(!program)
5121 {
5122 return error(GL_INVALID_OPERATION);
5123 }
5124
5125 if(location == -1)
5126 {
5127 return;
5128 }
5129
5130 if(!program->setUniform3fv(location, count, v))
5131 {
5132 return error(GL_INVALID_OPERATION);
5133 }
5134 }
5135}
5136
5137void GL_APIENTRY Uniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z)
5138{
5139 GLfloat xyz[3] = {x, y, z};
5140
5141 Uniform3fv(location, 1, (GLfloat*)&xyz);
5142}
5143
5144void GL_APIENTRY Uniform3iv(GLint location, GLsizei count, const GLint* v)
5145{
5146 TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = %p)", location, count, v);
5147
5148 if(count < 0)
5149 {
5150 return error(GL_INVALID_VALUE);
5151 }
5152
5153 auto context = es2::getContext();
5154
5155 if(context)
5156 {
5157 es2::Program *program = context->getCurrentProgram();
5158
5159 if(!program)
5160 {
5161 return error(GL_INVALID_OPERATION);
5162 }
5163
5164 if(location == -1)
5165 {
5166 return;
5167 }
5168
5169 if(!program->setUniform3iv(location, count, v))
5170 {
5171 return error(GL_INVALID_OPERATION);
5172 }
5173 }
5174}
5175
5176void GL_APIENTRY Uniform3i(GLint location, GLint x, GLint y, GLint z)
5177{
5178 GLint xyz[3] = {x, y, z};
5179
5180 Uniform3iv(location, 1, (GLint*)&xyz);
5181}
5182
5183void GL_APIENTRY Uniform4fv(GLint location, GLsizei count, const GLfloat* v)
5184{
5185 TRACE("(GLint location = %d, GLsizei count = %d, const GLfloat* v = %p)", location, count, v);
5186
5187 if(count < 0)
5188 {
5189 return error(GL_INVALID_VALUE);
5190 }
5191
5192 auto context = es2::getContext();
5193
5194 if(context)
5195 {
5196 es2::Program *program = context->getCurrentProgram();
5197
5198 if(!program)
5199 {
5200 return error(GL_INVALID_OPERATION);
5201 }
5202
5203 if(location == -1)
5204 {
5205 return;
5206 }
5207
5208 if(!program->setUniform4fv(location, count, v))
5209 {
5210 return error(GL_INVALID_OPERATION);
5211 }
5212 }
5213}
5214
5215void GL_APIENTRY Uniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
5216{
5217 GLfloat xyzw[4] = {x, y, z, w};
5218
5219 Uniform4fv(location, 1, (GLfloat*)&xyzw);
5220}
5221
5222void GL_APIENTRY Uniform4iv(GLint location, GLsizei count, const GLint* v)
5223{
5224 TRACE("(GLint location = %d, GLsizei count = %d, const GLint* v = %p)", location, count, v);
5225
5226 if(count < 0)
5227 {
5228 return error(GL_INVALID_VALUE);
5229 }
5230
5231 auto context = es2::getContext();
5232
5233 if(context)
5234 {
5235 es2::Program *program = context->getCurrentProgram();
5236
5237 if(!program)
5238 {
5239 return error(GL_INVALID_OPERATION);
5240 }
5241
5242 if(location == -1)
5243 {
5244 return;
5245 }
5246
5247 if(!program->setUniform4iv(location, count, v))
5248 {
5249 return error(GL_INVALID_OPERATION);
5250 }
5251 }
5252}
5253
5254void GL_APIENTRY Uniform4i(GLint location, GLint x, GLint y, GLint z, GLint w)
5255{
5256 GLint xyzw[4] = {x, y, z, w};
5257
5258 Uniform4iv(location, 1, (GLint*)&xyzw);
5259}
5260
5261void GL_APIENTRY UniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
5262{
5263 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = %p)",
5264 location, count, transpose, value);
5265
5266 if(count < 0)
5267 {
5268 return error(GL_INVALID_VALUE);
5269 }
5270
5271 auto context = es2::getContext();
5272
5273 if(context)
5274 {
5275 es2::Program *program = context->getCurrentProgram();
5276
5277 if(!program)
5278 {
5279 return error(GL_INVALID_OPERATION);
5280 }
5281
5282 if(location == -1)
5283 {
5284 return;
5285 }
5286
5287 if(!program->setUniformMatrix2fv(location, count, transpose, value))
5288 {
5289 return error(GL_INVALID_OPERATION);
5290 }
5291 }
5292}
5293
5294void GL_APIENTRY UniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
5295{
5296 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = %p)",
5297 location, count, transpose, value);
5298
5299 if(count < 0)
5300 {
5301 return error(GL_INVALID_VALUE);
5302 }
5303
5304 auto context = es2::getContext();
5305
5306 if(context)
5307 {
5308 es2::Program *program = context->getCurrentProgram();
5309
5310 if(!program)
5311 {
5312 return error(GL_INVALID_OPERATION);
5313 }
5314
5315 if(location == -1)
5316 {
5317 return;
5318 }
5319
5320 if(!program->setUniformMatrix3fv(location, count, transpose, value))
5321 {
5322 return error(GL_INVALID_OPERATION);
5323 }
5324 }
5325}
5326
5327void GL_APIENTRY UniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
5328{
5329 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = %p)",
5330 location, count, transpose, value);
5331
5332 if(count < 0)
5333 {
5334 return error(GL_INVALID_VALUE);
5335 }
5336
5337 auto context = es2::getContext();
5338
5339 if(context)
5340 {
5341 es2::Program *program = context->getCurrentProgram();
5342
5343 if(!program)
5344 {
5345 return error(GL_INVALID_OPERATION);
5346 }
5347
5348 if(location == -1)
5349 {
5350 return;
5351 }
5352
5353 if(!program->setUniformMatrix4fv(location, count, transpose, value))
5354 {
5355 return error(GL_INVALID_OPERATION);
5356 }
5357 }
5358}
5359
5360void GL_APIENTRY UseProgram(GLuint program)
5361{
5362 TRACE("(GLuint program = %d)", program);
5363
5364 auto context = es2::getContext();
5365
5366 if(context)
5367 {
5368 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
5369 if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
5370 {
5371 return error(GL_INVALID_OPERATION);
5372 }
5373
5374 es2::Program *programObject = context->getProgram(program);
5375
5376 if(!programObject && program != 0)
5377 {
5378 if(context->getShader(program))
5379 {
5380 return error(GL_INVALID_OPERATION);
5381 }
5382 else
5383 {
5384 return error(GL_INVALID_VALUE);
5385 }
5386 }
5387
5388 if(program != 0 && !programObject->isLinked())
5389 {
5390 return error(GL_INVALID_OPERATION);
5391 }
5392
5393 context->useProgram(program);
5394 }
5395}
5396
5397void GL_APIENTRY ValidateProgram(GLuint program)
5398{
5399 TRACE("(GLuint program = %d)", program);
5400
5401 auto context = es2::getContext();
5402
5403 if(context)
5404 {
5405 es2::Program *programObject = context->getProgram(program);
5406
5407 if(!programObject)
5408 {
5409 if(context->getShader(program))
5410 {
5411 return error(GL_INVALID_OPERATION);
5412 }
5413 else
5414 {
5415 return error(GL_INVALID_VALUE);
5416 }
5417 }
5418
5419 programObject->validate(context->getDevice());
5420 }
5421}
5422
5423void GL_APIENTRY VertexAttrib1f(GLuint index, GLfloat x)
5424{
5425 TRACE("(GLuint index = %d, GLfloat x = %f)", index, x);
5426
5427 if(index >= es2::MAX_VERTEX_ATTRIBS)
5428 {
5429 return error(GL_INVALID_VALUE);
5430 }
5431
5432 auto context = es2::getContext();
5433
5434 if(context)
5435 {
5436 GLfloat vals[4] = { x, 0, 0, 1 };
5437 context->setVertexAttrib(index, vals);
5438 }
5439}
5440
5441void GL_APIENTRY VertexAttrib1fv(GLuint index, const GLfloat* values)
5442{
5443 TRACE("(GLuint index = %d, const GLfloat* values = %p)", index, values);
5444
5445 if(index >= es2::MAX_VERTEX_ATTRIBS)
5446 {
5447 return error(GL_INVALID_VALUE);
5448 }
5449
5450 auto context = es2::getContext();
5451
5452 if(context)
5453 {
5454 GLfloat vals[4] = { values[0], 0, 0, 1 };
5455 context->setVertexAttrib(index, vals);
5456 }
5457}
5458
5459void GL_APIENTRY VertexAttrib2f(GLuint index, GLfloat x, GLfloat y)
5460{
5461 TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f)", index, x, y);
5462
5463 if(index >= es2::MAX_VERTEX_ATTRIBS)
5464 {
5465 return error(GL_INVALID_VALUE);
5466 }
5467
5468 auto context = es2::getContext();
5469
5470 if(context)
5471 {
5472 GLfloat vals[4] = { x, y, 0, 1 };
5473 context->setVertexAttrib(index, vals);
5474 }
5475}
5476
5477void GL_APIENTRY VertexAttrib2fv(GLuint index, const GLfloat* values)
5478{
5479 TRACE("(GLuint index = %d, const GLfloat* values = %p)", index, values);
5480
5481 if(index >= es2::MAX_VERTEX_ATTRIBS)
5482 {
5483 return error(GL_INVALID_VALUE);
5484 }
5485
5486 auto context = es2::getContext();
5487
5488 if(context)
5489 {
5490 GLfloat vals[4] = { values[0], values[1], 0, 1 };
5491 context->setVertexAttrib(index, vals);
5492 }
5493}
5494
5495void GL_APIENTRY VertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z)
5496{
5497 TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f)", index, x, y, z);
5498
5499 if(index >= es2::MAX_VERTEX_ATTRIBS)
5500 {
5501 return error(GL_INVALID_VALUE);
5502 }
5503
5504 auto context = es2::getContext();
5505
5506 if(context)
5507 {
5508 GLfloat vals[4] = { x, y, z, 1 };
5509 context->setVertexAttrib(index, vals);
5510 }
5511}
5512
5513void GL_APIENTRY VertexAttrib3fv(GLuint index, const GLfloat* values)
5514{
5515 TRACE("(GLuint index = %d, const GLfloat* values = %p)", index, values);
5516
5517 if(index >= es2::MAX_VERTEX_ATTRIBS)
5518 {
5519 return error(GL_INVALID_VALUE);
5520 }
5521
5522 auto context = es2::getContext();
5523
5524 if(context)
5525 {
5526 GLfloat vals[4] = { values[0], values[1], values[2], 1 };
5527 context->setVertexAttrib(index, vals);
5528 }
5529}
5530
5531void GL_APIENTRY VertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
5532{
5533 TRACE("(GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f)", index, x, y, z, w);
5534
5535 if(index >= es2::MAX_VERTEX_ATTRIBS)
5536 {
5537 return error(GL_INVALID_VALUE);
5538 }
5539
5540 auto context = es2::getContext();
5541
5542 if(context)
5543 {
5544 GLfloat vals[4] = { x, y, z, w };
5545 context->setVertexAttrib(index, vals);
5546 }
5547}
5548
5549void GL_APIENTRY VertexAttrib4fv(GLuint index, const GLfloat* values)
5550{
5551 TRACE("(GLuint index = %d, const GLfloat* values = %p)", index, values);
5552
5553 if(index >= es2::MAX_VERTEX_ATTRIBS)
5554 {
5555 return error(GL_INVALID_VALUE);
5556 }
5557
5558 auto context = es2::getContext();
5559
5560 if(context)
5561 {
5562 context->setVertexAttrib(index, values);
5563 }
5564}
5565
5566void GL_APIENTRY VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr)
5567{
5568 TRACE("(GLuint index = %d, GLint size = %d, GLenum type = 0x%X, "
5569 "GLboolean normalized = %d, GLsizei stride = %d, const GLvoid* ptr = %p)",
5570 index, size, type, normalized, stride, ptr);
5571
5572 if(index >= es2::MAX_VERTEX_ATTRIBS)
5573 {
5574 return error(GL_INVALID_VALUE);
5575 }
5576
5577 if(size < 1 || size > 4)
5578 {
5579 return error(GL_INVALID_VALUE);
5580 }
5581
5582 switch(type)
5583 {
5584 case GL_BYTE:
5585 case GL_UNSIGNED_BYTE:
5586 case GL_SHORT:
5587 case GL_UNSIGNED_SHORT:
5588 case GL_FIXED:
5589 case GL_FLOAT:
5590 case GL_HALF_FLOAT_OES: // GL_OES_vertex_half_float
5591 case GL_HALF_FLOAT:
5592 case GL_INT:
5593 case GL_UNSIGNED_INT:
5594 break;
5595 case GL_INT_2_10_10_10_REV:
5596 case GL_UNSIGNED_INT_2_10_10_10_REV:
5597 if(size != 4)
5598 {
5599 return error(GL_INVALID_OPERATION);
5600 }
5601 break;
5602 default:
5603 return error(GL_INVALID_ENUM);
5604 }
5605
5606 if(stride < 0)
5607 {
5608 return error(GL_INVALID_VALUE);
5609 }
5610
5611 auto context = es2::getContext();
5612
5613 if(context)
5614 {
5615 es2::VertexArray* vertexArray = context->getCurrentVertexArray();
5616 if((context->getArrayBufferName() == 0) && vertexArray && (vertexArray->name != 0) && ptr)
5617 {
5618 // GL_INVALID_OPERATION is generated if a non-zero vertex array object is bound, zero is bound
5619 // to the GL_ARRAY_BUFFER buffer object binding point and the pointer argument is not NULL.
5620 return error(GL_INVALID_OPERATION);
5621 }
5622
5623 context->setVertexAttribState(index, context->getArrayBuffer(), size, type, (normalized != GL_FALSE), false, stride, ptr);
5624 }
5625}
5626
5627void GL_APIENTRY Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
5628{
5629 TRACE("(GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)", x, y, width, height);
5630
5631 if(width < 0 || height < 0)
5632 {
5633 return error(GL_INVALID_VALUE);
5634 }
5635
5636 auto context = es2::getContext();
5637
5638 if(context)
5639 {
5640 context->setViewportParams(x, y, width, height);
5641 }
5642}
5643
5644static void GL_APIENTRY BlitFramebufferSW(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter, bool allowPartialDepthStencilBlit)
5645{
5646 TRACE("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
5647 "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "
5648 "GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
5649 srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);
5650
5651 switch(filter)
5652 {
5653 case GL_NEAREST:
5654 break;
5655 default:
5656 return error(GL_INVALID_ENUM);
5657 }
5658
5659 if((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
5660 {
5661 return error(GL_INVALID_VALUE);
5662 }
5663
5664 auto context = es2::getContext();
5665
5666 if(context)
5667 {
5668 if(context->getReadFramebufferName() == context->getDrawFramebufferName())
5669 {
5670 ERR("Blits with the same source and destination framebuffer are not supported by this implementation.");
5671 return error(GL_INVALID_OPERATION);
5672 }
5673
5674 context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, false, allowPartialDepthStencilBlit);
5675 }
5676}
5677
5678void GL_APIENTRY BlitFramebufferNV(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
5679{
5680 BlitFramebufferSW(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter, true);
5681}
5682
5683void GL_APIENTRY BlitFramebufferANGLE(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
5684 GLbitfield mask, GLenum filter)
5685{
5686 if(srcX1 - srcX0 != dstX1 - dstX0 || srcY1 - srcY0 != dstY1 - dstY0)
5687 {
5688 ERR("Scaling and flipping in BlitFramebufferANGLE not supported by this implementation");
5689 return error(GL_INVALID_OPERATION);
5690 }
5691
5692 BlitFramebufferSW(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter, false);
5693}
5694
5695void GL_APIENTRY TexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth,
5696 GLint border, GLenum format, GLenum type, const GLvoid* data)
5697{
5698 TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
5699 "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, "
5700 "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* data = %p)",
5701 target, level, internalformat, width, height, depth, border, format, type, data);
5702
5703 switch(target)
5704 {
5705 case GL_TEXTURE_3D:
5706 switch(format)
5707 {
5708 case GL_DEPTH_COMPONENT:
5709 case GL_DEPTH_STENCIL_OES:
5710 return error(GL_INVALID_OPERATION);
5711 default:
5712 break;
5713 }
5714 break;
5715 default:
5716 return error(GL_INVALID_ENUM);
5717 }
5718
5719 if(internalformat != format)
5720 {
5721 return error(GL_INVALID_OPERATION);
5722 }
5723
5724 GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target);
5725 if(validationError != GL_NO_ERROR)
5726 {
5727 return error(validationError);
5728 }
5729
5730 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
5731 {
5732 return error(GL_INVALID_VALUE);
5733 }
5734
5735 const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_3D_TEXTURE_SIZE >> level;
5736 if((width < 0) || (height < 0) || (depth < 0) || (width > maxSize3D) || (height > maxSize3D) || (depth > maxSize3D))
5737 {
5738 return error(GL_INVALID_VALUE);
5739 }
5740
5741 if(border != 0)
5742 {
5743 return error(GL_INVALID_VALUE);
5744 }
5745
5746 auto context = es2::getContext();
5747
5748 if(context)
5749 {
5750 es2::Texture3D *texture = context->getTexture3D();
5751
5752 if(!texture)
5753 {
5754 return error(GL_INVALID_OPERATION);
5755 }
5756
5757 GLenum validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
5758 if(validationError != GL_NO_ERROR)
5759 {
5760 return error(validationError);
5761 }
5762
5763 GLint sizedInternalFormat = gl::GetSizedInternalFormat(internalformat, type);
5764 texture->setImage(level, width, height, depth, sizedInternalFormat, format, type, context->getUnpackParameters(), data);
5765 }
5766}
5767
5768void GL_APIENTRY TexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data)
5769{
5770 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
5771 "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
5772 "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* data = %p)",
5773 target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);
5774
5775 switch(target)
5776 {
5777 case GL_TEXTURE_3D:
5778 break;
5779 default:
5780 return error(GL_INVALID_ENUM);
5781 }
5782
5783 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
5784 {
5785 return error(GL_INVALID_VALUE);
5786 }
5787
5788 if((width < 0) || (height < 0) || (depth < 0))
5789 {
5790 return error(GL_INVALID_VALUE);
5791 }
5792
5793 auto context = es2::getContext();
5794
5795 if(context)
5796 {
5797 es2::Texture3D *texture = context->getTexture3D();
5798
5799 GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texture);
5800 if(validationError != GL_NO_ERROR)
5801 {
5802 return error(validationError);
5803 }
5804
5805 validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, format, type));
5806 if(validationError != GL_NO_ERROR)
5807 {
5808 return error(validationError);
5809 }
5810
5811 texture->subImage(level, xoffset, yoffset, zoffset, width, height, depth, format, type, context->getUnpackParameters(), data);
5812 }
5813}
5814
5815void GL_APIENTRY CopyTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
5816{
5817 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
5818 "GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
5819 target, level, xoffset, yoffset, zoffset, x, y, width, height);
5820
5821 switch(target)
5822 {
5823 case GL_TEXTURE_3D:
5824 break;
5825 default:
5826 return error(GL_INVALID_ENUM);
5827 }
5828
5829 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
5830 {
5831 return error(GL_INVALID_VALUE);
5832 }
5833
5834 auto context = es2::getContext();
5835
5836 if(context)
5837 {
5838 es2::Framebuffer *framebuffer = context->getReadFramebuffer();
5839
5840 if(!framebuffer || (framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE))
5841 {
5842 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
5843 }
5844
5845 es2::Renderbuffer *source = framebuffer->getReadColorbuffer();
5846
5847 if(context->getReadFramebufferName() != 0 && (!source || source->getSamples() > 1))
5848 {
5849 return error(GL_INVALID_OPERATION);
5850 }
5851
5852 es2::Texture3D *texture = context->getTexture3D();
5853
5854 GLenum validationError = ValidateSubImageParams(false, true, target, level, xoffset, yoffset, zoffset, width, height, 1, GL_NONE, GL_NONE, texture);
5855 if(validationError != GL_NO_ERROR)
5856 {
5857 return error(validationError);
5858 }
5859
5860 texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, source);
5861 }
5862}
5863
5864void GL_APIENTRY CompressedTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data)
5865{
5866 TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
5867 "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = %p)",
5868 target, level, internalformat, width, height, depth, border, imageSize, data);
5869
5870 switch(target)
5871 {
5872 case GL_TEXTURE_3D:
5873 break;
5874 default:
5875 return error(GL_INVALID_ENUM);
5876 }
5877
5878 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
5879 {
5880 return error(GL_INVALID_VALUE);
5881 }
5882
5883 const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_3D_TEXTURE_SIZE >> level;
5884 if((width < 0) || (height < 0) || (depth < 0) || (width > maxSize3D) || (height > maxSize3D) || (depth > maxSize3D) ||(border != 0) || (imageSize < 0))
5885 {
5886 return error(GL_INVALID_VALUE);
5887 }
5888
5889 if(!IsCompressed(internalformat))
5890 {
5891 return error(GL_INVALID_ENUM);
5892 }
5893
5894 if(imageSize != gl::ComputeCompressedSize(width, height, internalformat) * depth)
5895 {
5896 return error(GL_INVALID_VALUE);
5897 }
5898
5899 auto context = es2::getContext();
5900
5901 if(context)
5902 {
5903 es2::Texture3D *texture = context->getTexture3D();
5904
5905 if(!texture)
5906 {
5907 return error(GL_INVALID_OPERATION);
5908 }
5909
5910 GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
5911
5912 if(validationError != GL_NO_ERROR)
5913 {
5914 return error(validationError);
5915 }
5916
5917 texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data);
5918 }
5919}
5920
5921void GL_APIENTRY CompressedTexSubImage3DOES(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data)
5922{
5923 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
5924 "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
5925 "GLenum format = 0x%X, GLsizei imageSize = %d, const void *data = %p)",
5926 target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
5927
5928 switch(target)
5929 {
5930 case GL_TEXTURE_3D:
5931 break;
5932 default:
5933 return error(GL_INVALID_ENUM);
5934 }
5935
5936 if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
5937 {
5938 return error(GL_INVALID_VALUE);
5939 }
5940
5941 if(xoffset < 0 || yoffset < 0 || zoffset < 0 || !validImageSize(level, width, height) || depth < 0 || imageSize < 0)
5942 {
5943 return error(GL_INVALID_VALUE);
5944 }
5945
5946 if(!IsCompressed(format))
5947 {
5948 return error(GL_INVALID_ENUM);
5949 }
5950
5951 if(imageSize != gl::ComputeCompressedSize(width, height, format) * depth)
5952 {
5953 return error(GL_INVALID_VALUE);
5954 }
5955
5956 auto context = es2::getContext();
5957
5958 if(context)
5959 {
5960 es2::Texture3D *texture = context->getTexture3D();
5961
5962 if(!texture)
5963 {
5964 return error(GL_INVALID_OPERATION);
5965 }
5966
5967 GLenum validationError = context->getPixels(&data, GL_UNSIGNED_BYTE, imageSize);
5968 if(validationError != GL_NO_ERROR)
5969 {
5970 return error(validationError);
5971 }
5972
5973 texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
5974 }
5975}
5976
5977void GL_APIENTRY FramebufferTexture3DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset)
5978{
5979 TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, "
5980 "GLuint texture = %d, GLint level = %d, GLint zoffset = %d)", target, attachment, textarget, texture, level, zoffset);
5981
5982 if(target != GL_FRAMEBUFFER && target != GL_DRAW_FRAMEBUFFER && target != GL_READ_FRAMEBUFFER)
5983 {
5984 return error(GL_INVALID_ENUM);
5985 }
5986
5987 auto context = es2::getContext();
5988
5989 if(context)
5990 {
5991 if(texture == 0)
5992 {
5993 textarget = GL_NONE;
5994 }
5995 else
5996 {
5997 es2::Texture *tex = context->getTexture(texture);
5998
5999 if(!tex)
6000 {
6001 return error(GL_INVALID_OPERATION);
6002 }
6003
6004 switch(textarget)
6005 {
6006 case GL_TEXTURE_3D:
6007 if(tex->getTarget() != GL_TEXTURE_3D)
6008 {
6009 return error(GL_INVALID_OPERATION);
6010 }
6011 break;
6012 default:
6013 return error(GL_INVALID_ENUM);
6014 }
6015
6016 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
6017 {
6018 return error(GL_INVALID_VALUE);
6019 }
6020
6021 if(tex->isCompressed(textarget, level))
6022 {
6023 return error(GL_INVALID_OPERATION);
6024 }
6025 }
6026
6027 es2::Framebuffer *framebuffer = nullptr;
6028 GLuint framebufferName = 0;
6029 if(target == GL_READ_FRAMEBUFFER)
6030 {
6031 framebuffer = context->getReadFramebuffer();
6032 framebufferName = context->getReadFramebufferName();
6033 }
6034 else
6035 {
6036 framebuffer = context->getDrawFramebuffer();
6037 framebufferName = context->getDrawFramebufferName();
6038 }
6039
6040 if(framebufferName == 0 || !framebuffer)
6041 {
6042 return error(GL_INVALID_OPERATION);
6043 }
6044
6045 switch(attachment)
6046 {
6047 case GL_DEPTH_ATTACHMENT: framebuffer->setDepthbuffer(textarget, texture, level); break;
6048 case GL_STENCIL_ATTACHMENT: framebuffer->setStencilbuffer(textarget, texture, level); break;
6049 default:
6050 if(attachment < GL_COLOR_ATTACHMENT0 || attachment > GL_COLOR_ATTACHMENT31)
6051 {
6052 return error(GL_INVALID_ENUM);
6053 }
6054
6055 if((attachment - GL_COLOR_ATTACHMENT0) >= MAX_COLOR_ATTACHMENTS)
6056 {
6057 return error(GL_INVALID_OPERATION);
6058 }
6059
6060 framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0, level);
6061 break;
6062 }
6063 }
6064}
6065
6066void GL_APIENTRY EGLImageTargetTexture2DOES(GLenum target, GLeglImageOES image)
6067{
6068 if(egl::getClientVersion() == 1)
6069 {
6070 return libGLES_CM->glEGLImageTargetTexture2DOES(target, image);
6071 }
6072
6073 TRACE("(GLenum target = 0x%X, GLeglImageOES image = %p)", target, image);
6074
6075 switch(target)
6076 {
6077 case GL_TEXTURE_2D:
6078 case GL_TEXTURE_RECTANGLE_ARB:
6079 case GL_TEXTURE_EXTERNAL_OES:
6080 break;
6081 default:
6082 return error(GL_INVALID_ENUM);
6083 }
6084
6085 auto context = es2::getContext();
6086
6087 if(context)
6088 {
6089 es2::Texture2D *texture = context->getTexture2D(target);
6090
6091 if(!texture)
6092 {
6093 return error(GL_INVALID_OPERATION);
6094 }
6095
6096 egl::Image *eglImage = context->getSharedImage(image);
6097
6098 if(!eglImage)
6099 {
6100 return error(GL_INVALID_OPERATION);
6101 }
6102
6103 texture->setSharedImage(eglImage);
6104 }
6105}
6106
6107void GL_APIENTRY EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image)
6108{
6109 TRACE("(GLenum target = 0x%X, GLeglImageOES image = %p)", target, image);
6110
6111 UNIMPLEMENTED();
6112}
6113
6114GLboolean GL_APIENTRY IsRenderbufferOES(GLuint renderbuffer)
6115{
6116 return IsRenderbuffer(renderbuffer);
6117}
6118
6119void GL_APIENTRY BindRenderbufferOES(GLenum target, GLuint renderbuffer)
6120{
6121 BindRenderbuffer(target, renderbuffer);
6122}
6123
6124void GL_APIENTRY DeleteRenderbuffersOES(GLsizei n, const GLuint* renderbuffers)
6125{
6126 DeleteRenderbuffers(n, renderbuffers);
6127}
6128
6129void GL_APIENTRY GenRenderbuffersOES(GLsizei n, GLuint* renderbuffers)
6130{
6131 GenRenderbuffers(n, renderbuffers);
6132}
6133
6134void GL_APIENTRY RenderbufferStorageOES(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
6135{
6136 RenderbufferStorage(target, internalformat, width, height);
6137}
6138
6139void GL_APIENTRY GetRenderbufferParameterivOES(GLenum target, GLenum pname, GLint* params)
6140{
6141 GetRenderbufferParameteriv(target, pname, params);
6142}
6143
6144GLboolean GL_APIENTRY IsFramebufferOES(GLuint framebuffer)
6145{
6146 return IsFramebuffer(framebuffer);
6147}
6148
6149void GL_APIENTRY BindFramebufferOES(GLenum target, GLuint framebuffer)
6150{
6151 BindFramebuffer(target, framebuffer);
6152}
6153
6154void GL_APIENTRY DeleteFramebuffersOES(GLsizei n, const GLuint* framebuffers)
6155{
6156 DeleteFramebuffers(n, framebuffers);
6157}
6158
6159void GL_APIENTRY GenFramebuffersOES(GLsizei n, GLuint* framebuffers)
6160{
6161 GenFramebuffers(n, framebuffers);
6162}
6163
6164GLenum GL_APIENTRY CheckFramebufferStatusOES(GLenum target)
6165{
6166 return CheckFramebufferStatus(target);
6167}
6168
6169void GL_APIENTRY FramebufferRenderbufferOES(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
6170{
6171 FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
6172}
6173
6174void GL_APIENTRY FramebufferTexture2DOES(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
6175{
6176 FramebufferTexture2D(target, attachment, textarget, texture, level);
6177}
6178
6179void GL_APIENTRY GetFramebufferAttachmentParameterivOES(GLenum target, GLenum attachment, GLenum pname, GLint* params)
6180{
6181 GetFramebufferAttachmentParameteriv(target, attachment, pname, params);
6182}
6183
6184void GL_APIENTRY GenerateMipmapOES(GLenum target)
6185{
6186 GenerateMipmap(target);
6187}
6188
6189void GL_APIENTRY DrawBuffersEXT(GLsizei n, const GLenum *bufs)
6190{
6191 TRACE("(GLsizei n = %d, const GLenum *bufs = %p)", n, bufs);
6192
6193 if(n < 0 || n > MAX_DRAW_BUFFERS)
6194 {
6195 return error(GL_INVALID_VALUE);
6196 }
6197
6198 auto context = es2::getContext();
6199
6200 if(context)
6201 {
6202 GLuint drawFramebufferName = context->getDrawFramebufferName();
6203
6204 if((drawFramebufferName == 0) && (n != 1))
6205 {
6206 return error(GL_INVALID_OPERATION);
6207 }
6208
6209 for(unsigned int i = 0; i < (unsigned)n; i++)
6210 {
6211 switch(bufs[i])
6212 {
6213 case GL_BACK:
6214 if(drawFramebufferName != 0)
6215 {
6216 return error(GL_INVALID_OPERATION);
6217 }
6218 break;
6219 case GL_NONE:
6220 break;
6221 case GL_COLOR_ATTACHMENT0_EXT:
6222 case GL_COLOR_ATTACHMENT1_EXT:
6223 case GL_COLOR_ATTACHMENT2_EXT:
6224 case GL_COLOR_ATTACHMENT3_EXT:
6225 case GL_COLOR_ATTACHMENT4_EXT:
6226 case GL_COLOR_ATTACHMENT5_EXT:
6227 case GL_COLOR_ATTACHMENT6_EXT:
6228 case GL_COLOR_ATTACHMENT7_EXT:
6229 case GL_COLOR_ATTACHMENT8_EXT:
6230 case GL_COLOR_ATTACHMENT9_EXT:
6231 case GL_COLOR_ATTACHMENT10_EXT:
6232 case GL_COLOR_ATTACHMENT11_EXT:
6233 case GL_COLOR_ATTACHMENT12_EXT:
6234 case GL_COLOR_ATTACHMENT13_EXT:
6235 case GL_COLOR_ATTACHMENT14_EXT:
6236 case GL_COLOR_ATTACHMENT15_EXT:
6237 {
6238 GLuint index = (bufs[i] - GL_COLOR_ATTACHMENT0_EXT);
6239
6240 if(index >= MAX_COLOR_ATTACHMENTS)
6241 {
6242 return error(GL_INVALID_OPERATION);
6243 }
6244
6245 if(index != i)
6246 {
6247 return error(GL_INVALID_OPERATION);
6248 }
6249
6250 if(drawFramebufferName == 0)
6251 {
6252 return error(GL_INVALID_OPERATION);
6253 }
6254 }
6255 break;
6256 default:
6257 return error(GL_INVALID_ENUM);
6258 }
6259 }
6260
6261 context->setFramebufferDrawBuffers(n, bufs);
6262 }
6263}
6264
6265}
6266
6267#include "entry_points.h"
6268
6269extern "C" NO_SANITIZE_FUNCTION __eglMustCastToProperFunctionPointerType es2GetProcAddress(const char *procname)
6270{
6271 struct Function
6272 {
6273 const char *name;
6274 __eglMustCastToProperFunctionPointerType address;
6275 };
6276
6277 static const Function glFunctions[] =
6278 {
6279 #define FUNCTION(name) {"gl" #name, (__eglMustCastToProperFunctionPointerType)gl::name}
6280
6281 FUNCTION(ActiveTexture),
6282 FUNCTION(AttachShader),
6283 FUNCTION(BeginQuery),
6284 FUNCTION(BeginQueryEXT),
6285 FUNCTION(BeginTransformFeedback),
6286 FUNCTION(BindAttribLocation),
6287 FUNCTION(BindBuffer),
6288 FUNCTION(BindBufferBase),
6289 FUNCTION(BindBufferRange),
6290 FUNCTION(BindFramebuffer),
6291 FUNCTION(BindFramebufferOES),
6292 FUNCTION(BindRenderbuffer),
6293 FUNCTION(BindRenderbufferOES),
6294 FUNCTION(BindSampler),
6295 FUNCTION(BindTexture),
6296 FUNCTION(BindTransformFeedback),
6297 FUNCTION(BindVertexArray),
6298 FUNCTION(BindVertexArrayOES),
6299 FUNCTION(BlendColor),
6300 FUNCTION(BlendEquation),
6301 FUNCTION(BlendEquationSeparate),
6302 FUNCTION(BlendFunc),
6303 FUNCTION(BlendFuncSeparate),
6304 FUNCTION(BlitFramebuffer),
6305 FUNCTION(BlitFramebufferANGLE),
6306 FUNCTION(BufferData),
6307 FUNCTION(BufferSubData),
6308 FUNCTION(CheckFramebufferStatus),
6309 FUNCTION(CheckFramebufferStatusOES),
6310 FUNCTION(Clear),
6311 FUNCTION(ClearBufferfi),
6312 FUNCTION(ClearBufferfv),
6313 FUNCTION(ClearBufferiv),
6314 FUNCTION(ClearBufferuiv),
6315 FUNCTION(ClearColor),
6316 FUNCTION(ClearDepthf),
6317 FUNCTION(ClearStencil),
6318 FUNCTION(ClientWaitSync),
6319 FUNCTION(ColorMask),
6320 FUNCTION(CompileShader),
6321 FUNCTION(CompressedTexImage2D),
6322 FUNCTION(CompressedTexImage3D),
6323 FUNCTION(CompressedTexSubImage2D),
6324 FUNCTION(CompressedTexSubImage3D),
6325 FUNCTION(CopyBufferSubData),
6326 FUNCTION(CopyTexImage2D),
6327 FUNCTION(CopyTexSubImage2D),
6328 FUNCTION(CopyTexSubImage3D),
6329 FUNCTION(CreateProgram),
6330 FUNCTION(CreateShader),
6331 FUNCTION(CullFace),
6332 FUNCTION(DeleteBuffers),
6333 FUNCTION(DeleteFencesNV),
6334 FUNCTION(DeleteFramebuffers),
6335 FUNCTION(DeleteFramebuffersOES),
6336 FUNCTION(DeleteProgram),
6337 FUNCTION(DeleteQueries),
6338 FUNCTION(DeleteQueriesEXT),
6339 FUNCTION(DeleteRenderbuffers),
6340 FUNCTION(DeleteRenderbuffersOES),
6341 FUNCTION(DeleteSamplers),
6342 FUNCTION(DeleteShader),
6343 FUNCTION(DeleteSync),
6344 FUNCTION(DeleteTextures),
6345 FUNCTION(DeleteTransformFeedbacks),
6346 FUNCTION(DeleteVertexArrays),
6347 FUNCTION(DeleteVertexArraysOES),
6348 FUNCTION(DepthFunc),
6349 FUNCTION(DepthMask),
6350 FUNCTION(DepthRangef),
6351 FUNCTION(DetachShader),
6352 FUNCTION(Disable),
6353 FUNCTION(DisableVertexAttribArray),
6354 FUNCTION(DrawArrays),
6355 FUNCTION(DrawArraysInstanced),
6356 FUNCTION(DrawBuffers),
6357 FUNCTION(DrawBuffersEXT),
6358 FUNCTION(DrawElements),
6359 FUNCTION(DrawElementsInstanced),
6360 FUNCTION(DrawRangeElements),
6361 FUNCTION(EGLImageTargetRenderbufferStorageOES),
6362 FUNCTION(EGLImageTargetTexture2DOES),
6363 FUNCTION(Enable),
6364 FUNCTION(EnableVertexAttribArray),
6365 FUNCTION(EndQuery),
6366 FUNCTION(EndQueryEXT),
6367 FUNCTION(EndTransformFeedback),
6368 FUNCTION(FenceSync),
6369 FUNCTION(Finish),
6370 FUNCTION(FinishFenceNV),
6371 FUNCTION(Flush),
6372 FUNCTION(FlushMappedBufferRange),
6373 FUNCTION(FramebufferRenderbuffer),
6374 FUNCTION(FramebufferRenderbufferOES),
6375 FUNCTION(FramebufferTexture2D),
6376 FUNCTION(FramebufferTexture2DOES),
6377 FUNCTION(FramebufferTextureLayer),
6378 FUNCTION(FrontFace),
6379 FUNCTION(GenBuffers),
6380 FUNCTION(GenFencesNV),
6381 FUNCTION(GenFramebuffers),
6382 FUNCTION(GenFramebuffersOES),
6383 FUNCTION(GenQueries),
6384 FUNCTION(GenQueriesEXT),
6385 FUNCTION(GenRenderbuffers),
6386 FUNCTION(GenRenderbuffersOES),
6387 FUNCTION(GenSamplers),
6388 FUNCTION(GenTextures),
6389 FUNCTION(GenTransformFeedbacks),
6390 FUNCTION(GenVertexArrays),
6391 FUNCTION(GenVertexArraysOES),
6392 FUNCTION(GenerateMipmap),
6393 FUNCTION(GenerateMipmapOES),
6394 FUNCTION(GetActiveAttrib),
6395 FUNCTION(GetActiveUniform),
6396 FUNCTION(GetActiveUniformBlockName),
6397 FUNCTION(GetActiveUniformBlockiv),
6398 FUNCTION(GetActiveUniformsiv),
6399 FUNCTION(GetAttachedShaders),
6400 FUNCTION(GetAttribLocation),
6401 FUNCTION(GetBooleanv),
6402 FUNCTION(GetBufferParameteri64v),
6403 FUNCTION(GetBufferParameteriv),
6404 FUNCTION(GetBufferPointerv),
6405 FUNCTION(GetError),
6406 FUNCTION(GetFenceivNV),
6407 FUNCTION(GetFloatv),
6408 FUNCTION(GetFragDataLocation),
6409 FUNCTION(GetFramebufferAttachmentParameteriv),
6410 FUNCTION(GetFramebufferAttachmentParameterivOES),
6411 FUNCTION(GetGraphicsResetStatusEXT),
6412 FUNCTION(GetInteger64i_v),
6413 FUNCTION(GetInteger64v),
6414 FUNCTION(GetIntegeri_v),
6415 FUNCTION(GetIntegerv),
6416 FUNCTION(GetInternalformativ),
6417 FUNCTION(GetProgramBinary),
6418 FUNCTION(GetProgramInfoLog),
6419 FUNCTION(GetProgramiv),
6420 FUNCTION(GetQueryObjectuiv),
6421 FUNCTION(GetQueryObjectuivEXT),
6422 FUNCTION(GetQueryiv),
6423 FUNCTION(GetQueryivEXT),
6424 FUNCTION(GetRenderbufferParameteriv),
6425 FUNCTION(GetRenderbufferParameterivOES),
6426 FUNCTION(GetSamplerParameterfv),
6427 FUNCTION(GetSamplerParameteriv),
6428 FUNCTION(GetShaderInfoLog),
6429 FUNCTION(GetShaderPrecisionFormat),
6430 FUNCTION(GetShaderSource),
6431 FUNCTION(GetShaderiv),
6432 FUNCTION(GetString),
6433 FUNCTION(GetStringi),
6434 FUNCTION(GetSynciv),
6435 FUNCTION(GetTexParameterfv),
6436 FUNCTION(GetTexParameteriv),
6437 FUNCTION(GetTransformFeedbackVarying),
6438 FUNCTION(GetUniformBlockIndex),
6439 FUNCTION(GetUniformIndices),
6440 FUNCTION(GetUniformLocation),
6441 FUNCTION(GetUniformfv),
6442 FUNCTION(GetUniformiv),
6443 FUNCTION(GetUniformuiv),
6444 FUNCTION(GetVertexAttribIiv),
6445 FUNCTION(GetVertexAttribIuiv),
6446 FUNCTION(GetVertexAttribPointerv),
6447 FUNCTION(GetVertexAttribfv),
6448 FUNCTION(GetVertexAttribiv),
6449 FUNCTION(GetnUniformfvEXT),
6450 FUNCTION(GetnUniformivEXT),
6451 FUNCTION(Hint),
6452 FUNCTION(InvalidateFramebuffer),
6453 FUNCTION(InvalidateSubFramebuffer),
6454 FUNCTION(IsBuffer),
6455 FUNCTION(IsEnabled),
6456 FUNCTION(IsFenceNV),
6457 FUNCTION(IsFramebuffer),
6458 FUNCTION(IsFramebufferOES),
6459 FUNCTION(IsProgram),
6460 FUNCTION(IsQuery),
6461 FUNCTION(IsQueryEXT),
6462 FUNCTION(IsRenderbuffer),
6463 FUNCTION(IsRenderbufferOES),
6464 FUNCTION(IsSampler),
6465 FUNCTION(IsShader),
6466 FUNCTION(IsSync),
6467 FUNCTION(IsTexture),
6468 FUNCTION(IsTransformFeedback),
6469 FUNCTION(IsVertexArray),
6470 FUNCTION(IsVertexArrayOES),
6471 FUNCTION(LineWidth),
6472 FUNCTION(LinkProgram),
6473 FUNCTION(MapBufferRange),
6474 FUNCTION(PauseTransformFeedback),
6475 FUNCTION(PixelStorei),
6476 FUNCTION(PolygonOffset),
6477 FUNCTION(ProgramBinary),
6478 FUNCTION(ProgramParameteri),
6479 FUNCTION(ReadBuffer),
6480 FUNCTION(ReadPixels),
6481 FUNCTION(ReadnPixelsEXT),
6482 FUNCTION(ReleaseShaderCompiler),
6483 FUNCTION(RenderbufferStorage),
6484 FUNCTION(RenderbufferStorageMultisample),
6485 FUNCTION(RenderbufferStorageMultisampleANGLE),
6486 FUNCTION(RenderbufferStorageOES),
6487 FUNCTION(ResumeTransformFeedback),
6488 FUNCTION(SampleCoverage),
6489 FUNCTION(SamplerParameterf),
6490 FUNCTION(SamplerParameterfv),
6491 FUNCTION(SamplerParameteri),
6492 FUNCTION(SamplerParameteriv),
6493 FUNCTION(Scissor),
6494 FUNCTION(SetFenceNV),
6495 FUNCTION(ShaderBinary),
6496 FUNCTION(ShaderSource),
6497 FUNCTION(StencilFunc),
6498 FUNCTION(StencilFuncSeparate),
6499 FUNCTION(StencilMask),
6500 FUNCTION(StencilMaskSeparate),
6501 FUNCTION(StencilOp),
6502 FUNCTION(StencilOpSeparate),
6503 FUNCTION(TestFenceNV),
6504 FUNCTION(TexImage2D),
6505 FUNCTION(TexImage3D),
6506 FUNCTION(TexImage3DOES),
6507 FUNCTION(TexParameterf),
6508 FUNCTION(TexParameterfv),
6509 FUNCTION(TexParameteri),
6510 FUNCTION(TexParameteriv),
6511 FUNCTION(TexStorage2D),
6512 FUNCTION(TexStorage3D),
6513 FUNCTION(TexSubImage2D),
6514 FUNCTION(TexSubImage3D),
6515 FUNCTION(TransformFeedbackVaryings),
6516 FUNCTION(Uniform1f),
6517 FUNCTION(Uniform1fv),
6518 FUNCTION(Uniform1i),
6519 FUNCTION(Uniform1iv),
6520 FUNCTION(Uniform1ui),
6521 FUNCTION(Uniform1uiv),
6522 FUNCTION(Uniform2f),
6523 FUNCTION(Uniform2fv),
6524 FUNCTION(Uniform2i),
6525 FUNCTION(Uniform2iv),
6526 FUNCTION(Uniform2ui),
6527 FUNCTION(Uniform2uiv),
6528 FUNCTION(Uniform3f),
6529 FUNCTION(Uniform3fv),
6530 FUNCTION(Uniform3i),
6531 FUNCTION(Uniform3iv),
6532 FUNCTION(Uniform3ui),
6533 FUNCTION(Uniform3uiv),
6534 FUNCTION(Uniform4f),
6535 FUNCTION(Uniform4fv),
6536 FUNCTION(Uniform4i),
6537 FUNCTION(Uniform4iv),
6538 FUNCTION(Uniform4ui),
6539 FUNCTION(Uniform4uiv),
6540 FUNCTION(UniformBlockBinding),
6541 FUNCTION(UniformMatrix2fv),
6542 FUNCTION(UniformMatrix2x3fv),
6543 FUNCTION(UniformMatrix2x4fv),
6544 FUNCTION(UniformMatrix3fv),
6545 FUNCTION(UniformMatrix3x2fv),
6546 FUNCTION(UniformMatrix3x4fv),
6547 FUNCTION(UniformMatrix4fv),
6548 FUNCTION(UniformMatrix4x2fv),
6549 FUNCTION(UniformMatrix4x3fv),
6550 FUNCTION(UnmapBuffer),
6551 FUNCTION(UseProgram),
6552 FUNCTION(ValidateProgram),
6553 FUNCTION(VertexAttrib1f),
6554 FUNCTION(VertexAttrib1fv),
6555 FUNCTION(VertexAttrib2f),
6556 FUNCTION(VertexAttrib2fv),
6557 FUNCTION(VertexAttrib3f),
6558 FUNCTION(VertexAttrib3fv),
6559 FUNCTION(VertexAttrib4f),
6560 FUNCTION(VertexAttrib4fv),
6561 FUNCTION(VertexAttribDivisor),
6562 FUNCTION(VertexAttribDivisorANGLE),
6563 FUNCTION(VertexAttribDivisorEXT),
6564 FUNCTION(VertexAttribI4i),
6565 FUNCTION(VertexAttribI4iv),
6566 FUNCTION(VertexAttribI4ui),
6567 FUNCTION(VertexAttribI4uiv),
6568 FUNCTION(VertexAttribIPointer),
6569 FUNCTION(VertexAttribPointer),
6570 FUNCTION(Viewport),
6571 FUNCTION(WaitSync),
6572
6573 #undef FUNCTION
6574 };
6575
6576 static const size_t numFunctions = sizeof glFunctions / sizeof(Function);
6577 static const Function *const glFunctionsEnd = glFunctions + numFunctions;
6578
6579 // The array must be kept sorted with respect to strcmp(), so that binary search works correctly.
6580 // The Unix command "LC_COLLATE=C sort" will generate the correct order.
6581 #ifndef NDEBUG
6582 for(size_t i = 0; i < numFunctions - 1; i++)
6583 {
6584 ASSERT(strcmp(glFunctions[i].name, glFunctions[i + 1].name) < 0);
6585 }
6586 #endif
6587
6588 if(procname && strncmp("gl", procname, 2) == 0)
6589 {
6590 struct CompareFunctor
6591 {
6592 bool operator()(const Function &a, const Function &b) const
6593 {
6594 return strcmp(a.name, b.name) < 0;
6595 }
6596 };
6597
6598 Function needle;
6599 needle.name = procname;
6600 const Function *result = std::lower_bound(glFunctions, glFunctionsEnd, needle, CompareFunctor());
6601
6602 if(result != glFunctionsEnd && strcmp(procname, result->name) == 0)
6603 {
6604 return (__eglMustCastToProperFunctionPointerType)result->address;
6605 }
6606 }
6607
6608 return nullptr;
6609}
6610