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