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