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