blob: 5d35d06eaee2dd8200e477eac3841550bcac2efd [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
Nicolas Capensefdf1032018-05-08 16:03:16 -0400356 const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_3D_TEXTURE_SIZE >> level;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400357 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
Nicolas Capensefdf1032018-05-08 16:03:16 -0400526 const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_3D_TEXTURE_SIZE >> level;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400527 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
Nicolas Capensefdf1032018-05-08 16:03:16 -04001238 if(level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
1239 {
1240 return error(GL_INVALID_VALUE);
1241 }
1242
Nicolas Capens0bac2852016-05-07 06:09:58 -04001243 textarget = textureObject->getTarget();
1244 switch(textarget)
1245 {
1246 case GL_TEXTURE_3D:
Nicolas Capensefdf1032018-05-08 16:03:16 -04001247 if(layer >= es2::IMPLEMENTATION_MAX_3D_TEXTURE_SIZE)
1248 {
1249 return error(GL_INVALID_VALUE);
1250 }
1251 break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001252 case GL_TEXTURE_2D_ARRAY:
Nicolas Capensefdf1032018-05-08 16:03:16 -04001253 if(layer >= es2::IMPLEMENTATION_MAX_ARRAY_TEXTURE_LAYERS)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001254 {
1255 return error(GL_INVALID_VALUE);
1256 }
1257 break;
1258 default:
1259 return error(GL_INVALID_OPERATION);
1260 }
1261
1262 if(textureObject->isCompressed(textarget, level))
1263 {
1264 return error(GL_INVALID_OPERATION);
1265 }
1266 }
1267
1268 es2::Framebuffer *framebuffer = nullptr;
1269 switch(target)
1270 {
1271 case GL_DRAW_FRAMEBUFFER:
1272 case GL_FRAMEBUFFER:
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001273 if(context->getDrawFramebufferName() == 0)
1274 {
1275 return error(GL_INVALID_OPERATION);
1276 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001277 framebuffer = context->getDrawFramebuffer();
1278 break;
1279 case GL_READ_FRAMEBUFFER:
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001280 if(context->getReadFramebufferName() == 0)
1281 {
1282 return error(GL_INVALID_OPERATION);
1283 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001284 framebuffer = context->getReadFramebuffer();
1285 break;
1286 default:
1287 return error(GL_INVALID_ENUM);
1288 }
1289
1290 if(!framebuffer)
1291 {
1292 return error(GL_INVALID_OPERATION);
1293 }
1294
1295 switch(attachment)
1296 {
1297 case GL_COLOR_ATTACHMENT0:
1298 case GL_COLOR_ATTACHMENT1:
1299 case GL_COLOR_ATTACHMENT2:
1300 case GL_COLOR_ATTACHMENT3:
1301 case GL_COLOR_ATTACHMENT4:
1302 case GL_COLOR_ATTACHMENT5:
1303 case GL_COLOR_ATTACHMENT6:
1304 case GL_COLOR_ATTACHMENT7:
1305 case GL_COLOR_ATTACHMENT8:
1306 case GL_COLOR_ATTACHMENT9:
1307 case GL_COLOR_ATTACHMENT10:
1308 case GL_COLOR_ATTACHMENT11:
1309 case GL_COLOR_ATTACHMENT12:
1310 case GL_COLOR_ATTACHMENT13:
1311 case GL_COLOR_ATTACHMENT14:
1312 case GL_COLOR_ATTACHMENT15:
1313 case GL_COLOR_ATTACHMENT16:
1314 case GL_COLOR_ATTACHMENT17:
1315 case GL_COLOR_ATTACHMENT18:
1316 case GL_COLOR_ATTACHMENT19:
1317 case GL_COLOR_ATTACHMENT20:
1318 case GL_COLOR_ATTACHMENT21:
1319 case GL_COLOR_ATTACHMENT22:
1320 case GL_COLOR_ATTACHMENT23:
1321 case GL_COLOR_ATTACHMENT24:
1322 case GL_COLOR_ATTACHMENT25:
1323 case GL_COLOR_ATTACHMENT26:
1324 case GL_COLOR_ATTACHMENT27:
1325 case GL_COLOR_ATTACHMENT28:
1326 case GL_COLOR_ATTACHMENT29:
1327 case GL_COLOR_ATTACHMENT30:
1328 case GL_COLOR_ATTACHMENT31:
1329 framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0, level, layer);
1330 break;
1331 case GL_DEPTH_ATTACHMENT:
1332 framebuffer->setDepthbuffer(textarget, texture, level, layer);
1333 break;
1334 case GL_STENCIL_ATTACHMENT:
1335 framebuffer->setStencilbuffer(textarget, texture, level, layer);
1336 break;
1337 case GL_DEPTH_STENCIL_ATTACHMENT:
1338 framebuffer->setDepthbuffer(textarget, texture, level, layer);
1339 framebuffer->setStencilbuffer(textarget, texture, level, layer);
1340 break;
1341 default:
1342 return error(GL_INVALID_ENUM);
1343 }
1344 }
1345}
1346
1347GL_APICALL void *GL_APIENTRY glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
1348{
1349 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = %X)",
1350 target, offset, length, access);
1351
Alexis Hetu6e864492017-11-14 15:27:00 -05001352 if((offset < 0) || (length < 0))
1353 {
1354 return error(GL_INVALID_VALUE, nullptr);
1355 }
1356
1357 if(!(access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)))
1358 {
1359 // Must be able to read or write the buffer
1360 return error(GL_INVALID_OPERATION, nullptr);
1361 }
1362 else if((access & GL_MAP_READ_BIT) && (access & (GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT)))
1363 {
1364 // GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT and GL_MAP_UNSYNCHRONIZED_BIT can't be used with GL_MAP_READ_BIT
1365 return error(GL_INVALID_OPERATION, nullptr);
1366 }
1367 else if((!(access & GL_MAP_WRITE_BIT)) && (access & GL_MAP_FLUSH_EXPLICIT_BIT))
1368 {
1369 // GL_MAP_FLUSH_EXPLICIT_BIT can't be used without GL_MAP_WRITE_BIT
1370 return error(GL_INVALID_OPERATION, nullptr);
1371 }
1372
Nicolas Capens0bac2852016-05-07 06:09:58 -04001373 es2::Context *context = es2::getContext();
1374
1375 if(context)
1376 {
1377 es2::Buffer *buffer = nullptr;
1378 if(!context->getBuffer(target, &buffer))
1379 {
1380 return error(GL_INVALID_ENUM, nullptr);
1381 }
1382
1383 if(!buffer)
1384 {
1385 // A null buffer means that "0" is bound to the requested buffer target
1386 return error(GL_INVALID_OPERATION, nullptr);
1387 }
1388
Alexis Hetu1b4eb7f2017-11-14 13:24:37 -05001389 if(buffer->isMapped())
1390 {
1391 // It is an invalid operation to map an already mapped buffer
1392 return error(GL_INVALID_OPERATION, nullptr);
1393 }
1394
Nicolas Capens0bac2852016-05-07 06:09:58 -04001395 GLsizeiptr bufferSize = buffer->size();
Alexis Hetu6e864492017-11-14 15:27:00 -05001396 if((offset + length) > bufferSize)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001397 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001398 return error(GL_INVALID_VALUE, nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001399 }
1400
1401 if((access & ~(GL_MAP_READ_BIT |
1402 GL_MAP_WRITE_BIT |
1403 GL_MAP_INVALIDATE_RANGE_BIT |
1404 GL_MAP_INVALIDATE_BUFFER_BIT |
1405 GL_MAP_FLUSH_EXPLICIT_BIT |
1406 GL_MAP_UNSYNCHRONIZED_BIT)) != 0)
1407 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001408 return error(GL_INVALID_VALUE, nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001409 }
1410
1411 return buffer->mapRange(offset, length, access);
1412 }
1413
1414 return nullptr;
1415}
1416
1417GL_APICALL void GL_APIENTRY glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
1418{
1419 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)",
1420 target, offset, length);
1421
Alexis Hetu6e864492017-11-14 15:27:00 -05001422 if((offset < 0) || (length < 0))
1423 {
1424 return error(GL_INVALID_VALUE);
1425 }
1426
Nicolas Capens0bac2852016-05-07 06:09:58 -04001427 es2::Context *context = es2::getContext();
1428
1429 if(context)
1430 {
1431 es2::Buffer *buffer = nullptr;
1432 if(!context->getBuffer(target, &buffer))
1433 {
1434 return error(GL_INVALID_ENUM);
1435 }
1436
1437 if(!buffer)
1438 {
1439 // A null buffer means that "0" is bound to the requested buffer target
1440 return error(GL_INVALID_OPERATION);
1441 }
1442
Alexis Hetu6e864492017-11-14 15:27:00 -05001443 if(!buffer->isMapped())
Nicolas Capens0bac2852016-05-07 06:09:58 -04001444 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001445 // Buffer must be mapped
1446 return error(GL_INVALID_OPERATION);
1447 }
1448
1449 GLsizeiptr bufferSize = buffer->length();
1450 if((offset + length) > bufferSize)
1451 {
1452 return error(GL_INVALID_VALUE);
1453 }
1454
Alexis Hetua752b892017-11-22 14:00:37 -05001455 if(!(buffer->access() & GL_MAP_FLUSH_EXPLICIT_BIT))
Alexis Hetu6e864492017-11-14 15:27:00 -05001456 {
1457 // Flush must be explicitly allowed
1458 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001459 }
1460
1461 buffer->flushMappedRange(offset, length);
1462 }
1463}
1464
1465GL_APICALL void GL_APIENTRY glBindVertexArray(GLuint array)
1466{
1467 TRACE("(GLuint array = %d)", array);
1468
Nicolas Capens0bac2852016-05-07 06:09:58 -04001469 es2::Context *context = es2::getContext();
1470
1471 if(context)
1472 {
1473 if(!context->isVertexArray(array))
1474 {
1475 return error(GL_INVALID_OPERATION);
1476 }
1477
1478 context->bindVertexArray(array);
1479 }
1480}
1481
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001482GL_APICALL void GL_APIENTRY glBindVertexArrayOES(GLuint array)
1483{
1484 glBindVertexArray(array);
1485}
1486
Nicolas Capens0bac2852016-05-07 06:09:58 -04001487GL_APICALL void GL_APIENTRY glDeleteVertexArrays(GLsizei n, const GLuint *arrays)
1488{
1489 TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1490
1491 if(n < 0)
1492 {
1493 return error(GL_INVALID_VALUE);
1494 }
1495
1496 es2::Context *context = es2::getContext();
1497
1498 if(context)
1499 {
1500 for(int i = 0; i < n; i++)
1501 {
1502 context->deleteVertexArray(arrays[i]);
1503 }
1504 }
1505}
1506
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001507GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES(GLsizei n, const GLuint *arrays)
1508{
1509 glDeleteVertexArrays(n, arrays);
1510}
1511
Nicolas Capens0bac2852016-05-07 06:09:58 -04001512GL_APICALL void GL_APIENTRY glGenVertexArrays(GLsizei n, GLuint *arrays)
1513{
1514 TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1515
1516 if(n < 0)
1517 {
1518 return error(GL_INVALID_VALUE);
1519 }
1520
1521 es2::Context *context = es2::getContext();
1522
1523 if(context)
1524 {
1525 for(int i = 0; i < n; i++)
1526 {
1527 arrays[i] = context->createVertexArray();
1528 }
1529 }
1530}
1531
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001532GL_APICALL void GL_APIENTRY glGenVertexArraysOES(GLsizei n, GLuint *arrays)
1533{
1534 glGenVertexArrays(n, arrays);
1535}
1536
Nicolas Capens0bac2852016-05-07 06:09:58 -04001537GL_APICALL GLboolean GL_APIENTRY glIsVertexArray(GLuint array)
1538{
1539 TRACE("(GLuint array = %d)", array);
1540
1541 if(array == 0)
1542 {
1543 return GL_FALSE;
1544 }
1545
1546 es2::Context *context = es2::getContext();
1547
1548 if(context)
1549 {
1550 es2::VertexArray *arrayObject = context->getVertexArray(array);
1551
1552 if(arrayObject)
1553 {
1554 return GL_TRUE;
1555 }
1556 }
1557
1558 return GL_FALSE;
1559}
1560
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001561GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES(GLuint array)
1562{
1563 return glIsVertexArray(array);
1564}
1565
Nicolas Capens0bac2852016-05-07 06:09:58 -04001566GL_APICALL void GL_APIENTRY glGetIntegeri_v(GLenum target, GLuint index, GLint *data)
1567{
1568 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint* data = %p)",
1569 target, index, data);
1570
1571 es2::Context *context = es2::getContext();
1572
1573 if(context)
1574 {
1575 if(!context->getTransformFeedbackiv(index, target, data) &&
1576 !context->getUniformBufferiv(index, target, data) &&
1577 !context->getIntegerv(target, data))
1578 {
1579 GLenum nativeType;
1580 unsigned int numParams = 0;
1581 if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
1582 return error(GL_INVALID_ENUM);
1583
1584 if(numParams == 0)
1585 return; // it is known that target is valid, but there are no parameters to return
1586
1587 if(nativeType == GL_BOOL)
1588 {
1589 GLboolean *boolParams = nullptr;
1590 boolParams = new GLboolean[numParams];
1591
1592 context->getBooleanv(target, boolParams);
1593
1594 for(unsigned int i = 0; i < numParams; ++i)
1595 {
1596 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
1597 }
1598
1599 delete[] boolParams;
1600 }
1601 else if(nativeType == GL_FLOAT)
1602 {
1603 GLfloat *floatParams = nullptr;
1604 floatParams = new GLfloat[numParams];
1605
1606 context->getFloatv(target, floatParams);
1607
1608 for(unsigned int i = 0; i < numParams; ++i)
1609 {
1610 if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
1611 {
Alexis Hetu60e20282017-12-13 07:42:22 -05001612 data[i] = convert_float_fixed(floatParams[i]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001613 }
1614 else
1615 {
1616 data[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
1617 }
1618 }
1619
1620 delete[] floatParams;
1621 }
1622 }
1623 }
1624}
1625
1626GL_APICALL void GL_APIENTRY glBeginTransformFeedback(GLenum primitiveMode)
1627{
1628 TRACE("(GLenum primitiveMode = 0x%X)", primitiveMode);
1629
1630 switch(primitiveMode)
1631 {
1632 case GL_POINTS:
1633 case GL_LINES:
1634 case GL_TRIANGLES:
1635 break;
1636 default:
1637 return error(GL_INVALID_ENUM);
1638 }
1639
1640 es2::Context *context = es2::getContext();
1641
1642 if(context)
1643 {
1644 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1645
1646 if(transformFeedbackObject)
1647 {
1648 if(transformFeedbackObject->isActive())
1649 {
1650 return error(GL_INVALID_OPERATION);
1651 }
1652 transformFeedbackObject->begin(primitiveMode);
1653 }
1654 else
1655 {
1656 return error(GL_INVALID_OPERATION);
1657 }
1658 }
1659}
1660
1661GL_APICALL void GL_APIENTRY glEndTransformFeedback(void)
1662{
1663 TRACE("()");
1664
1665 es2::Context *context = es2::getContext();
1666
1667 if(context)
1668 {
1669 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1670
1671 if(transformFeedbackObject)
1672 {
1673 if(!transformFeedbackObject->isActive())
1674 {
1675 return error(GL_INVALID_OPERATION);
1676 }
1677 transformFeedbackObject->end();
1678 }
1679 else
1680 {
1681 return error(GL_INVALID_OPERATION);
1682 }
1683 }
1684}
1685
1686GL_APICALL void GL_APIENTRY glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
1687{
1688 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d, GLintptr offset = %d, GLsizeiptr size = %d)",
1689 target, index, buffer, offset, size);
1690
1691 if(buffer != 0 && size <= 0)
1692 {
1693 return error(GL_INVALID_VALUE);
1694 }
1695
1696 es2::Context *context = es2::getContext();
1697
1698 if(context)
1699 {
1700 switch(target)
1701 {
1702 case GL_TRANSFORM_FEEDBACK_BUFFER:
1703 if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1704 {
1705 return error(GL_INVALID_VALUE);
1706 }
1707 if(size & 0x3 || offset & 0x3) // size and offset must be multiples of 4
1708 {
1709 return error(GL_INVALID_VALUE);
1710 }
1711 context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size);
1712 context->bindGenericTransformFeedbackBuffer(buffer);
1713 break;
1714 case GL_UNIFORM_BUFFER:
1715 if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
1716 {
1717 return error(GL_INVALID_VALUE);
1718 }
1719 if(offset % UNIFORM_BUFFER_OFFSET_ALIGNMENT != 0)
1720 {
1721 return error(GL_INVALID_VALUE);
1722 }
1723 context->bindIndexedUniformBuffer(buffer, index, offset, size);
1724 context->bindGenericUniformBuffer(buffer);
1725 break;
1726 default:
1727 return error(GL_INVALID_ENUM);
1728 }
1729 }
1730}
1731
1732GL_APICALL void GL_APIENTRY glBindBufferBase(GLenum target, GLuint index, GLuint buffer)
1733{
1734 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d)",
1735 target, index, buffer);
1736
1737 es2::Context *context = es2::getContext();
1738
1739 if(context)
1740 {
1741 switch(target)
1742 {
1743 case GL_TRANSFORM_FEEDBACK_BUFFER:
1744 if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1745 {
1746 return error(GL_INVALID_VALUE);
1747 }
1748 context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0);
1749 context->bindGenericTransformFeedbackBuffer(buffer);
1750 break;
1751 case GL_UNIFORM_BUFFER:
1752 if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
1753 {
1754 return error(GL_INVALID_VALUE);
1755 }
1756 context->bindIndexedUniformBuffer(buffer, index, 0, 0);
1757 context->bindGenericUniformBuffer(buffer);
1758 break;
1759 default:
1760 return error(GL_INVALID_ENUM);
1761 }
1762 }
1763}
1764
1765GL_APICALL void GL_APIENTRY glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode)
1766{
1767 TRACE("(GLuint program = %d, GLsizei count = %d, const GLchar *const*varyings = %p, GLenum bufferMode = 0x%X)",
1768 program, count, varyings, bufferMode);
1769
1770 switch(bufferMode)
1771 {
1772 case GL_SEPARATE_ATTRIBS:
1773 if(count > MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1774 {
1775 return error(GL_INVALID_VALUE);
1776 }
1777 case GL_INTERLEAVED_ATTRIBS:
1778 break;
1779 default:
1780 return error(GL_INVALID_ENUM);
1781 }
1782
1783 es2::Context *context = es2::getContext();
1784
1785 if(context)
1786 {
1787 es2::Program *programObject = context->getProgram(program);
1788
1789 if(!programObject)
1790 {
1791 return error(GL_INVALID_VALUE);
1792 }
1793
1794 programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);
1795 }
1796}
1797
1798GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name)
1799{
1800 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
1801 program, index, bufSize, length, size, type, name);
1802
1803 if(bufSize < 0)
1804 {
1805 return error(GL_INVALID_VALUE);
1806 }
1807
1808 es2::Context *context = es2::getContext();
1809
1810 if(context)
1811 {
1812 es2::Program *programObject = context->getProgram(program);
1813
1814 if(!programObject)
1815 {
1816 return error(GL_INVALID_VALUE);
1817 }
1818
1819 if(index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount()))
1820 {
1821 return error(GL_INVALID_VALUE);
1822 }
1823
1824 programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name);
1825 }
1826}
1827
1828GL_APICALL void GL_APIENTRY glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)
1829{
1830 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
1831 index, size, type, stride, pointer);
1832
1833 if(index >= es2::MAX_VERTEX_ATTRIBS)
1834 {
1835 return error(GL_INVALID_VALUE);
1836 }
1837
1838 if(size < 1 || size > 4 || stride < 0)
1839 {
1840 return error(GL_INVALID_VALUE);
1841 }
1842
1843 switch(type)
1844 {
1845 case GL_BYTE:
1846 case GL_UNSIGNED_BYTE:
1847 case GL_SHORT:
1848 case GL_UNSIGNED_SHORT:
1849 case GL_INT:
1850 case GL_UNSIGNED_INT:
1851 break;
1852 default:
1853 return error(GL_INVALID_ENUM);
1854 }
1855
1856 es2::Context *context = es2::getContext();
1857
1858 if(context)
1859 {
Alexis Hetuc1ef1ad2017-11-15 10:50:10 -05001860 es2::VertexArray* vertexArray = context->getCurrentVertexArray();
1861 if((context->getArrayBufferName() == 0) && vertexArray && (vertexArray->name != 0) && pointer)
1862 {
1863 // GL_INVALID_OPERATION is generated if a non-zero vertex array object is bound, zero is bound
1864 // to the GL_ARRAY_BUFFER buffer object binding point and the pointer argument is not NULL.
1865 return error(GL_INVALID_OPERATION);
1866 }
1867
Alexis Hetu6f284032017-12-11 15:19:36 -05001868 context->setVertexAttribState(index, context->getArrayBuffer(), size, type, false, true, stride, pointer);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001869 }
1870}
1871
1872GL_APICALL void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
1873{
1874 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint *params = %p)",
1875 index, pname, params);
1876
1877 es2::Context *context = es2::getContext();
1878
1879 if(context)
1880 {
1881 if(index >= es2::MAX_VERTEX_ATTRIBS)
1882 {
1883 return error(GL_INVALID_VALUE);
1884 }
1885
1886 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
1887
1888 switch(pname)
1889 {
1890 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1891 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
1892 break;
1893 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1894 *params = attribState.mSize;
1895 break;
1896 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1897 *params = attribState.mStride;
1898 break;
1899 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1900 *params = attribState.mType;
1901 break;
1902 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1903 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
1904 break;
1905 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1906 *params = attribState.mBoundBuffer.name();
1907 break;
1908 case GL_CURRENT_VERTEX_ATTRIB:
1909 {
1910 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
1911 for(int i = 0; i < 4; ++i)
1912 {
1913 params[i] = attrib.getCurrentValueI(i);
1914 }
1915 }
1916 break;
1917 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Alexis Hetu6f284032017-12-11 15:19:36 -05001918 *params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001919 break;
1920 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1921 *params = attribState.mDivisor;
1922 break;
1923 default: return error(GL_INVALID_ENUM);
1924 }
1925 }
1926}
1927
1928GL_APICALL void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params)
1929{
1930 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLuint *params = %p)",
1931 index, pname, params);
1932
1933 es2::Context *context = es2::getContext();
1934
1935 if(context)
1936 {
1937 if(index >= es2::MAX_VERTEX_ATTRIBS)
1938 {
1939 return error(GL_INVALID_VALUE);
1940 }
1941
1942 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
1943
1944 switch(pname)
1945 {
1946 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1947 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
1948 break;
1949 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1950 *params = attribState.mSize;
1951 break;
1952 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1953 *params = attribState.mStride;
1954 break;
1955 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1956 *params = attribState.mType;
1957 break;
1958 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1959 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
1960 break;
1961 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1962 *params = attribState.mBoundBuffer.name();
1963 break;
1964 case GL_CURRENT_VERTEX_ATTRIB:
1965 {
1966 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
1967 for(int i = 0; i < 4; ++i)
1968 {
1969 params[i] = attrib.getCurrentValueUI(i);
1970 }
1971 }
1972 break;
1973 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Alexis Hetu6f284032017-12-11 15:19:36 -05001974 *params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001975 break;
1976 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1977 *params = attribState.mDivisor;
1978 break;
1979 default: return error(GL_INVALID_ENUM);
1980 }
1981 }
1982}
1983
1984GL_APICALL void GL_APIENTRY glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
1985{
1986 TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
1987 index, x, y, z, w);
1988
1989 if(index >= es2::MAX_VERTEX_ATTRIBS)
1990 {
1991 return error(GL_INVALID_VALUE);
1992 }
1993
1994 es2::Context *context = es2::getContext();
1995
1996 if(context)
1997 {
1998 GLint vals[4] = { x, y, z, w };
1999 context->setVertexAttrib(index, vals);
2000 }
2001}
2002
2003GL_APICALL void GL_APIENTRY glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
2004{
2005 TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
2006 index, x, y, z, w);
2007
2008 if(index >= es2::MAX_VERTEX_ATTRIBS)
2009 {
2010 return error(GL_INVALID_VALUE);
2011 }
2012
2013 es2::Context *context = es2::getContext();
2014
2015 if(context)
2016 {
2017 GLuint vals[4] = { x, y, z, w };
2018 context->setVertexAttrib(index, vals);
2019 }
2020}
2021
2022GL_APICALL void GL_APIENTRY glVertexAttribI4iv(GLuint index, const GLint *v)
2023{
2024 TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2025
2026 if(index >= es2::MAX_VERTEX_ATTRIBS)
2027 {
2028 return error(GL_INVALID_VALUE);
2029 }
2030
2031 es2::Context *context = es2::getContext();
2032
2033 if(context)
2034 {
2035 context->setVertexAttrib(index, v);
2036 }
2037}
2038
2039GL_APICALL void GL_APIENTRY glVertexAttribI4uiv(GLuint index, const GLuint *v)
2040{
2041 TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2042
2043 if(index >= es2::MAX_VERTEX_ATTRIBS)
2044 {
2045 return error(GL_INVALID_VALUE);
2046 }
2047
2048 es2::Context *context = es2::getContext();
2049
2050 if(context)
2051 {
2052 context->setVertexAttrib(index, v);
2053 }
2054}
2055
2056GL_APICALL void GL_APIENTRY glGetUniformuiv(GLuint program, GLint location, GLuint *params)
2057{
2058 TRACE("(GLuint program = %d, GLint location = %d, GLuint *params = %p)",
2059 program, location, params);
2060
2061 es2::Context *context = es2::getContext();
2062
2063 if(context)
2064 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04002065 es2::Program *programObject = context->getProgram(program);
2066
Alexis Hetu48280a42017-11-30 15:04:39 -05002067 if(!programObject)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002068 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002069 if(context->getShader(program))
2070 {
2071 return error(GL_INVALID_OPERATION);
2072 }
2073 else
2074 {
2075 return error(GL_INVALID_VALUE);
2076 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002077 }
2078
Alexis Hetu48280a42017-11-30 15:04:39 -05002079 if(!programObject->isLinked())
Nicolas Capens0bac2852016-05-07 06:09:58 -04002080 {
2081 return error(GL_INVALID_OPERATION);
2082 }
2083
2084 if(!programObject->getUniformuiv(location, nullptr, params))
2085 {
2086 return error(GL_INVALID_OPERATION);
2087 }
2088 }
2089}
2090
2091GL_APICALL GLint GL_APIENTRY glGetFragDataLocation(GLuint program, const GLchar *name)
2092{
2093 TRACE("(GLuint program = %d, const GLchar *name = %p)", program, name);
2094
2095 es2::Context *context = es2::getContext();
2096
Nicolas Capens0bac2852016-05-07 06:09:58 -04002097 if(context)
2098 {
2099 es2::Program *programObject = context->getProgram(program);
2100
2101 if(!programObject)
2102 {
2103 if(context->getShader(program))
2104 {
2105 return error(GL_INVALID_OPERATION, -1);
2106 }
2107 else
2108 {
2109 return error(GL_INVALID_VALUE, -1);
2110 }
2111 }
2112
2113 if(!programObject->isLinked())
2114 {
2115 return error(GL_INVALID_OPERATION, -1);
2116 }
Alexis Hetub3f5ed72017-08-16 16:37:19 -04002117
2118 return programObject->getFragDataLocation(name);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002119 }
2120
Nicolas Capens0bac2852016-05-07 06:09:58 -04002121 return -1;
2122}
2123
2124GL_APICALL void GL_APIENTRY glUniform1ui(GLint location, GLuint v0)
2125{
2126 glUniform1uiv(location, 1, &v0);
2127}
2128
2129GL_APICALL void GL_APIENTRY glUniform2ui(GLint location, GLuint v0, GLuint v1)
2130{
2131 GLuint xy[2] = { v0, v1 };
2132
2133 glUniform2uiv(location, 1, (GLuint*)&xy);
2134}
2135
2136GL_APICALL void GL_APIENTRY glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
2137{
2138 GLuint xyz[3] = { v0, v1, v2 };
2139
2140 glUniform3uiv(location, 1, (GLuint*)&xyz);
2141}
2142
2143GL_APICALL void GL_APIENTRY glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
2144{
2145 GLuint xyzw[4] = { v0, v1, v2, v3 };
2146
2147 glUniform4uiv(location, 1, (GLuint*)&xyzw);
2148}
2149
2150GL_APICALL void GL_APIENTRY glUniform1uiv(GLint location, GLsizei count, const GLuint *value)
2151{
2152 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2153 location, count, value);
2154
2155 if(count < 0)
2156 {
2157 return error(GL_INVALID_VALUE);
2158 }
2159
Nicolas Capens0bac2852016-05-07 06:09:58 -04002160 es2::Context *context = es2::getContext();
2161
2162 if(context)
2163 {
2164 es2::Program *program = context->getCurrentProgram();
2165
2166 if(!program)
2167 {
2168 return error(GL_INVALID_OPERATION);
2169 }
2170
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002171 if(location == -1)
2172 {
2173 return;
2174 }
2175
Nicolas Capens0bac2852016-05-07 06:09:58 -04002176 if(!program->setUniform1uiv(location, count, value))
2177 {
2178 return error(GL_INVALID_OPERATION);
2179 }
2180 }
2181}
2182
2183GL_APICALL void GL_APIENTRY glUniform2uiv(GLint location, GLsizei count, const GLuint *value)
2184{
2185 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2186 location, count, value);
2187
2188 if(count < 0)
2189 {
2190 return error(GL_INVALID_VALUE);
2191 }
2192
Nicolas Capens0bac2852016-05-07 06:09:58 -04002193 es2::Context *context = es2::getContext();
2194
2195 if(context)
2196 {
2197 es2::Program *program = context->getCurrentProgram();
2198
2199 if(!program)
2200 {
2201 return error(GL_INVALID_OPERATION);
2202 }
2203
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002204 if(location == -1)
2205 {
2206 return;
2207 }
2208
Nicolas Capens0bac2852016-05-07 06:09:58 -04002209 if(!program->setUniform2uiv(location, count, value))
2210 {
2211 return error(GL_INVALID_OPERATION);
2212 }
2213 }
2214}
2215
2216GL_APICALL void GL_APIENTRY glUniform3uiv(GLint location, GLsizei count, const GLuint *value)
2217{
2218 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2219 location, count, value);
2220
2221 if(count < 0)
2222 {
2223 return error(GL_INVALID_VALUE);
2224 }
2225
Nicolas Capens0bac2852016-05-07 06:09:58 -04002226 es2::Context *context = es2::getContext();
2227
2228 if(context)
2229 {
2230 es2::Program *program = context->getCurrentProgram();
2231
2232 if(!program)
2233 {
2234 return error(GL_INVALID_OPERATION);
2235 }
2236
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002237 if(location == -1)
2238 {
2239 return;
2240 }
2241
Nicolas Capens0bac2852016-05-07 06:09:58 -04002242 if(!program->setUniform3uiv(location, count, value))
2243 {
2244 return error(GL_INVALID_OPERATION);
2245 }
2246 }
2247}
2248
2249GL_APICALL void GL_APIENTRY glUniform4uiv(GLint location, GLsizei count, const GLuint *value)
2250{
2251 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2252 location, count, value);
2253
2254 if(count < 0)
2255 {
2256 return error(GL_INVALID_VALUE);
2257 }
2258
Nicolas Capens0bac2852016-05-07 06:09:58 -04002259 es2::Context *context = es2::getContext();
2260
2261 if(context)
2262 {
2263 es2::Program *program = context->getCurrentProgram();
2264
2265 if(!program)
2266 {
2267 return error(GL_INVALID_OPERATION);
2268 }
2269
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002270 if(location == -1)
2271 {
2272 return;
2273 }
2274
Nicolas Capens0bac2852016-05-07 06:09:58 -04002275 if(!program->setUniform4uiv(location, count, value))
2276 {
2277 return error(GL_INVALID_OPERATION);
2278 }
2279 }
2280}
2281
2282GL_APICALL void GL_APIENTRY glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
2283{
2284 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint *value = %p)",
2285 buffer, drawbuffer, value);
2286
2287 es2::Context *context = es2::getContext();
2288
2289 if(context)
2290 {
2291 switch(buffer)
2292 {
2293 case GL_COLOR:
2294 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2295 {
2296 return error(GL_INVALID_VALUE);
2297 }
2298 else
2299 {
2300 context->clearColorBuffer(drawbuffer, value);
2301 }
2302 break;
2303 case GL_STENCIL:
2304 if(drawbuffer != 0)
2305 {
2306 return error(GL_INVALID_VALUE);
2307 }
2308 else
2309 {
2310 context->clearStencilBuffer(value[0]);
2311 }
2312 break;
2313 default:
2314 return error(GL_INVALID_ENUM);
2315 }
2316 }
2317}
2318
2319GL_APICALL void GL_APIENTRY glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
2320{
2321 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint *value = %p)",
2322 buffer, drawbuffer, value);
2323
2324 es2::Context *context = es2::getContext();
2325
2326 if(context)
2327 {
2328 switch(buffer)
2329 {
2330 case GL_COLOR:
2331 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2332 {
2333 return error(GL_INVALID_VALUE);
2334 }
2335 else
2336 {
2337 context->clearColorBuffer(drawbuffer, value);
2338 }
2339 break;
2340 default:
2341 return error(GL_INVALID_ENUM);
2342 }
2343 }
2344}
2345
2346GL_APICALL void GL_APIENTRY glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
2347{
2348 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat *value = %p)",
2349 buffer, drawbuffer, value);
2350
2351 es2::Context *context = es2::getContext();
2352
2353 if(context)
2354 {
2355 switch(buffer)
2356 {
2357 case GL_COLOR:
2358 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2359 {
2360 return error(GL_INVALID_VALUE);
2361 }
2362 else
2363 {
2364 context->clearColorBuffer(drawbuffer, value);
2365 }
2366 break;
2367 case GL_DEPTH:
2368 if(drawbuffer != 0)
2369 {
2370 return error(GL_INVALID_VALUE);
2371 }
2372 else
2373 {
2374 context->clearDepthBuffer(value[0]);
2375 }
2376 break;
2377 default:
2378 return error(GL_INVALID_ENUM);
2379 }
2380 }
2381}
2382
2383GL_APICALL void GL_APIENTRY glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
2384{
2385 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth = %f, GLint stencil = %d)",
2386 buffer, drawbuffer, depth, stencil);
2387
2388 es2::Context *context = es2::getContext();
2389
2390 if(context)
2391 {
2392 switch(buffer)
2393 {
2394 case GL_DEPTH_STENCIL:
2395 if(drawbuffer != 0)
2396 {
2397 return error(GL_INVALID_VALUE);
2398 }
2399 else
2400 {
2401 context->clearDepthBuffer(depth);
2402 context->clearStencilBuffer(stencil);
2403 }
2404 break;
2405 default:
2406 return error(GL_INVALID_ENUM);
2407 }
2408 }
2409}
2410
2411GL_APICALL const GLubyte *GL_APIENTRY glGetStringi(GLenum name, GLuint index)
2412{
2413 TRACE("(GLenum name = 0x%X, GLuint index = %d)", name, index);
2414
2415 es2::Context *context = es2::getContext();
2416 if(context)
2417 {
2418 GLuint numExtensions;
2419 context->getExtensions(0, &numExtensions);
2420
2421 if(index >= numExtensions)
2422 {
2423 return error(GL_INVALID_VALUE, (GLubyte*)nullptr);
2424 }
2425
2426 switch(name)
2427 {
2428 case GL_EXTENSIONS:
2429 return context->getExtensions(index);
2430 default:
2431 return error(GL_INVALID_ENUM, (GLubyte*)nullptr);
2432 }
2433 }
2434
2435 return (GLubyte*)nullptr;
2436}
2437
2438GL_APICALL void GL_APIENTRY glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
2439{
2440 TRACE("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)",
2441 readTarget, writeTarget, readOffset, writeOffset, size);
2442
2443 if(readOffset < 0 || writeOffset < 0 || size < 0)
2444 {
2445 return error(GL_INVALID_VALUE);
2446 }
2447
2448 es2::Context *context = es2::getContext();
2449
2450 if(context)
2451 {
2452 es2::Buffer *readBuffer = nullptr, *writeBuffer = nullptr;
2453 if(!context->getBuffer(readTarget, &readBuffer) || !context->getBuffer(writeTarget, &writeBuffer))
2454 {
2455 return error(GL_INVALID_ENUM);
2456 }
2457 if(!readBuffer || readBuffer->isMapped() || !writeBuffer || writeBuffer->isMapped())
2458 {
2459 return error(GL_INVALID_OPERATION);
2460 }
2461 if(readBuffer == writeBuffer)
2462 {
2463 // If same buffer, check for overlap
2464 if(((readOffset >= writeOffset) && (readOffset < (writeOffset + size))) ||
2465 ((writeOffset >= readOffset) && (writeOffset < (readOffset + size))))
2466 {
2467 return error(GL_INVALID_VALUE);
2468 }
2469 }
2470
2471 if((static_cast<size_t>(readOffset + size) > readBuffer->size()) ||
2472 (static_cast<size_t>(writeOffset + size) > writeBuffer->size()))
2473 {
2474 return error(GL_INVALID_VALUE);
2475 }
2476
2477 writeBuffer->bufferSubData(((char*)readBuffer->data()) + readOffset, size, writeOffset);
2478 }
2479}
2480
2481GL_APICALL void GL_APIENTRY glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices)
2482{
2483 TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLuint *uniformIndices = %p)",
2484 program, uniformCount, uniformNames, uniformIndices);
2485
2486 if(uniformCount < 0)
2487 {
2488 return error(GL_INVALID_VALUE);
2489 }
2490
2491 es2::Context *context = es2::getContext();
2492
2493 if(context)
2494 {
2495 es2::Program *programObject = context->getProgram(program);
2496
2497 if(!programObject)
2498 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002499 if(context->getShader(program))
2500 {
2501 return error(GL_INVALID_OPERATION);
2502 }
2503 else
2504 {
2505 return error(GL_INVALID_VALUE);
2506 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002507 }
2508
2509 if(!programObject->isLinked())
2510 {
2511 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2512 {
2513 uniformIndices[uniformId] = GL_INVALID_INDEX;
2514 }
2515 }
2516 else
2517 {
2518 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2519 {
2520 uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]);
2521 }
2522 }
2523 }
2524}
2525
2526GL_APICALL void GL_APIENTRY glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params)
2527{
2528 TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLenum pname = 0x%X, GLuint *uniformIndices = %p)",
2529 program, uniformCount, uniformIndices, pname, uniformIndices);
2530
2531 switch(pname)
2532 {
2533 case GL_UNIFORM_TYPE:
2534 case GL_UNIFORM_SIZE:
2535 case GL_UNIFORM_NAME_LENGTH:
2536 case GL_UNIFORM_BLOCK_INDEX:
2537 case GL_UNIFORM_OFFSET:
2538 case GL_UNIFORM_ARRAY_STRIDE:
2539 case GL_UNIFORM_MATRIX_STRIDE:
2540 case GL_UNIFORM_IS_ROW_MAJOR:
2541 break;
2542 default:
2543 return error(GL_INVALID_ENUM);
2544 }
2545
2546 if(uniformCount < 0)
2547 {
2548 return error(GL_INVALID_VALUE);
2549 }
2550
2551 es2::Context *context = es2::getContext();
2552
2553 if(context)
2554 {
2555 es2::Program *programObject = context->getProgram(program);
2556
2557 if(!programObject)
2558 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002559 if(context->getShader(program))
2560 {
2561 return error(GL_INVALID_OPERATION);
2562 }
2563 else
2564 {
2565 return error(GL_INVALID_VALUE);
2566 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002567 }
2568
2569 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2570 {
2571 const GLuint index = uniformIndices[uniformId];
2572
2573 if(index >= programObject->getActiveUniformCount())
2574 {
2575 return error(GL_INVALID_VALUE);
2576 }
2577 }
2578
2579 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2580 {
2581 const GLuint index = uniformIndices[uniformId];
2582 params[uniformId] = programObject->getActiveUniformi(index, pname);
2583 }
2584 }
2585}
2586
2587GL_APICALL GLuint GL_APIENTRY glGetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName)
2588{
2589 TRACE("(GLuint program = %d, const GLchar *uniformBlockName = %p)",
2590 program, uniformBlockName);
2591
2592 es2::Context *context = es2::getContext();
2593
2594 if(context)
2595 {
2596 es2::Program *programObject = context->getProgram(program);
2597
2598 if(!programObject)
2599 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002600 if(context->getShader(program))
2601 {
2602 return error(GL_INVALID_OPERATION, GL_INVALID_INDEX);
2603 }
2604 else
2605 {
2606 return error(GL_INVALID_VALUE, GL_INVALID_INDEX);
2607 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002608 }
2609
2610 return programObject->getUniformBlockIndex(uniformBlockName);
2611 }
2612
2613 return GL_INVALID_INDEX;
2614}
2615
2616GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params)
2617{
2618 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLenum pname = 0x%X, GLint *params = %p)",
2619 program, uniformBlockIndex, pname, params);
2620
2621 es2::Context *context = es2::getContext();
2622
2623 if(context)
2624 {
2625 es2::Program *programObject = context->getProgram(program);
2626
2627 if(!programObject)
2628 {
2629 return error(GL_INVALID_OPERATION);
2630 }
2631
2632 switch(pname)
2633 {
2634 case GL_UNIFORM_BLOCK_BINDING:
2635 *params = static_cast<GLint>(programObject->getUniformBlockBinding(uniformBlockIndex));
2636 break;
2637 case GL_UNIFORM_BLOCK_DATA_SIZE:
2638 case GL_UNIFORM_BLOCK_NAME_LENGTH:
2639 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2640 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2641 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2642 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2643 programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
2644 break;
2645 default:
2646 return error(GL_INVALID_ENUM);
2647 }
2648 }
2649}
2650
2651GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName)
2652{
2653 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLchar *uniformBlockName = %p)",
2654 program, uniformBlockIndex, bufSize, length, uniformBlockName);
2655
2656 if(bufSize < 0)
2657 {
2658 return error(GL_INVALID_VALUE);
2659 }
2660
2661 es2::Context *context = es2::getContext();
2662
2663 if(context)
2664 {
2665 es2::Program *programObject = context->getProgram(program);
2666
2667 if(!programObject)
2668 {
2669 return error(GL_INVALID_OPERATION);
2670 }
2671
2672 programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
2673 }
2674}
2675
2676GL_APICALL void GL_APIENTRY glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
2677{
2678 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLuint uniformBlockBinding = %d)",
2679 program, uniformBlockIndex, uniformBlockBinding);
2680
2681 if(uniformBlockBinding >= MAX_UNIFORM_BUFFER_BINDINGS)
2682 {
2683 return error(GL_INVALID_VALUE);
2684 }
2685
2686 es2::Context *context = es2::getContext();
2687
2688 if(context)
2689 {
2690 es2::Program *programObject = context->getProgram(program);
2691
2692 if(!programObject)
2693 {
2694 return error(GL_INVALID_VALUE);
2695 }
2696
Nicolas Capens65dcbbd2016-08-12 16:59:04 -04002697 programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002698 }
2699}
2700
2701GL_APICALL void GL_APIENTRY glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
2702{
2703 TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
2704 mode, first, count, instanceCount);
2705
2706 switch(mode)
2707 {
2708 case GL_POINTS:
2709 case GL_LINES:
2710 case GL_LINE_LOOP:
2711 case GL_LINE_STRIP:
2712 case GL_TRIANGLES:
2713 case GL_TRIANGLE_FAN:
2714 case GL_TRIANGLE_STRIP:
2715 break;
2716 default:
2717 return error(GL_INVALID_ENUM);
2718 }
2719
2720 if(count < 0 || instanceCount < 0)
2721 {
2722 return error(GL_INVALID_VALUE);
2723 }
2724
2725 es2::Context *context = es2::getContext();
2726
2727 if(context)
2728 {
2729 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
2730 if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
2731 {
2732 return error(GL_INVALID_OPERATION);
2733 }
2734
2735 context->drawArrays(mode, first, count, instanceCount);
2736 }
2737}
2738
2739GL_APICALL void GL_APIENTRY glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
2740{
2741 TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = %p, GLsizei instanceCount = %d)",
2742 mode, count, type, indices, instanceCount);
2743
2744 switch(mode)
2745 {
2746 case GL_POINTS:
2747 case GL_LINES:
2748 case GL_LINE_LOOP:
2749 case GL_LINE_STRIP:
2750 case GL_TRIANGLES:
2751 case GL_TRIANGLE_FAN:
2752 case GL_TRIANGLE_STRIP:
2753 break;
2754 default:
2755 return error(GL_INVALID_ENUM);
2756 }
2757
2758 switch(type)
2759 {
2760 case GL_UNSIGNED_BYTE:
2761 case GL_UNSIGNED_SHORT:
2762 case GL_UNSIGNED_INT:
2763 break;
2764 default:
2765 return error(GL_INVALID_ENUM);
2766 }
2767
2768 if(count < 0 || instanceCount < 0)
2769 {
2770 return error(GL_INVALID_VALUE);
2771 }
2772
2773 es2::Context *context = es2::getContext();
2774
2775 if(context)
2776 {
2777 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
2778 if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
2779 {
2780 return error(GL_INVALID_OPERATION);
2781 }
2782
2783 context->drawElements(mode, 0, MAX_ELEMENT_INDEX, count, type, indices, instanceCount);
2784 }
2785}
2786
2787GL_APICALL GLsync GL_APIENTRY glFenceSync(GLenum condition, GLbitfield flags)
2788{
2789 TRACE("(GLenum condition = 0x%X, GLbitfield flags = %X)", condition, flags);
2790
2791 switch(condition)
2792 {
2793 case GL_SYNC_GPU_COMMANDS_COMPLETE:
2794 break;
2795 default:
2796 return error(GL_INVALID_ENUM, nullptr);
2797 }
2798
2799 if(flags != 0)
2800 {
2801 return error(GL_INVALID_VALUE, nullptr);
2802 }
2803
2804 es2::Context *context = es2::getContext();
2805
2806 if(context)
2807 {
2808 return context->createFenceSync(condition, flags);
2809 }
2810
2811 return nullptr;
2812}
2813
2814GL_APICALL GLboolean GL_APIENTRY glIsSync(GLsync sync)
2815{
2816 TRACE("(GLsync sync = %p)", sync);
2817
2818 es2::Context *context = es2::getContext();
2819
2820 if(context)
2821 {
2822 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2823
2824 if(fenceSyncObject)
2825 {
2826 return GL_TRUE;
2827 }
2828 }
2829
2830 return GL_FALSE;
2831}
2832
2833GL_APICALL void GL_APIENTRY glDeleteSync(GLsync sync)
2834{
2835 TRACE("(GLsync sync = %p)", sync);
2836
Alexis Hetuadd96ad2017-11-14 17:22:46 -05002837 if(!sync)
2838 {
2839 return;
2840 }
2841
Nicolas Capens0bac2852016-05-07 06:09:58 -04002842 es2::Context *context = es2::getContext();
2843
2844 if(context)
2845 {
Alexis Hetuadd96ad2017-11-14 17:22:46 -05002846 if(!context->getFenceSync(sync))
2847 {
2848 return error(GL_INVALID_VALUE);
2849 }
2850
Nicolas Capens0bac2852016-05-07 06:09:58 -04002851 context->deleteFenceSync(sync);
2852 }
2853}
2854
2855GL_APICALL GLenum GL_APIENTRY glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
2856{
2857 TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
2858
2859 if((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0)
2860 {
Alexis Hetu6e864492017-11-14 15:27:00 -05002861 return error(GL_INVALID_VALUE, GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002862 }
2863
2864 es2::Context *context = es2::getContext();
2865
2866 if(context)
2867 {
2868 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2869
2870 if(fenceSyncObject)
2871 {
2872 return fenceSyncObject->clientWait(flags, timeout);
2873 }
2874 else
2875 {
2876 return error(GL_INVALID_VALUE, GL_FALSE);
2877 }
2878 }
2879
2880 return GL_FALSE;
2881}
2882
2883GL_APICALL void GL_APIENTRY glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
2884{
2885 TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
2886
2887 if(flags != 0)
2888 {
2889 return error(GL_INVALID_VALUE);
2890 }
2891
2892 if(timeout != GL_TIMEOUT_IGNORED)
2893 {
2894 return error(GL_INVALID_VALUE);
2895 }
2896
2897 es2::Context *context = es2::getContext();
2898
2899 if(context)
2900 {
2901 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2902
2903 if(fenceSyncObject)
2904 {
2905 fenceSyncObject->serverWait(flags, timeout);
2906 }
2907 else
2908 {
2909 return error(GL_INVALID_VALUE);
2910 }
2911 }
2912}
2913
2914GL_APICALL void GL_APIENTRY glGetInteger64v(GLenum pname, GLint64 *data)
2915{
2916 TRACE("(GLenum pname = 0x%X, GLint64 *data = %p)", pname, data);
2917
2918 es2::Context *context = es2::getContext();
2919
2920 if(context)
2921 {
2922 if(!(context->getIntegerv(pname, data)))
2923 {
2924 GLenum nativeType;
2925 unsigned int numParams = 0;
2926 if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))
2927 return error(GL_INVALID_ENUM);
2928
2929 if(numParams == 0)
2930 return; // it is known that pname is valid, but there are no parameters to return
2931
2932 if(nativeType == GL_BOOL)
2933 {
2934 GLboolean *boolParams = nullptr;
2935 boolParams = new GLboolean[numParams];
2936
2937 context->getBooleanv(pname, boolParams);
2938
2939 for(unsigned int i = 0; i < numParams; ++i)
2940 {
2941 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
2942 }
2943
2944 delete[] boolParams;
2945 }
2946 else if(nativeType == GL_FLOAT)
2947 {
2948 GLfloat *floatParams = nullptr;
2949 floatParams = new GLfloat[numParams];
2950
2951 context->getFloatv(pname, floatParams);
2952
2953 for(unsigned int i = 0; i < numParams; ++i)
2954 {
2955 if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
2956 {
Alexis Hetu60e20282017-12-13 07:42:22 -05002957 data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002958 }
2959 else
2960 {
2961 data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
2962 }
2963 }
2964
2965 delete[] floatParams;
2966 }
2967 }
2968 }
2969}
2970
2971GL_APICALL void GL_APIENTRY glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
2972{
2973 TRACE("(GLsync sync = %p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei *length = %p, GLint *values = %p)",
2974 sync, pname, bufSize, length, values);
2975
2976 if(bufSize < 0)
2977 {
2978 return error(GL_INVALID_VALUE);
2979 }
2980
Alexis Hetu0f7c7b82017-02-17 17:07:50 -05002981 es2::Context *context = es2::getContext();
2982
2983 if(context)
2984 {
2985 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2986 if(!fenceSyncObject)
2987 {
2988 return error(GL_INVALID_VALUE);
2989 }
2990
2991 fenceSyncObject->getSynciv(pname, length, values);
2992 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002993}
2994
2995GL_APICALL void GL_APIENTRY glGetInteger64i_v(GLenum target, GLuint index, GLint64 *data)
2996{
2997 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint64 *data = %p)", target, index, data);
2998
2999 es2::Context *context = es2::getContext();
3000
3001 if(context)
3002 {
3003 if(!context->getTransformFeedbackiv(index, target, data) &&
3004 !context->getUniformBufferiv(index, target, data) &&
3005 !context->getIntegerv(target, data))
3006 {
3007 GLenum nativeType;
3008 unsigned int numParams = 0;
3009 if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
3010 return error(GL_INVALID_ENUM);
3011
3012 if(numParams == 0)
3013 return; // it is known that target is valid, but there are no parameters to return
3014
3015 if(nativeType == GL_BOOL)
3016 {
3017 GLboolean *boolParams = nullptr;
3018 boolParams = new GLboolean[numParams];
3019
3020 context->getBooleanv(target, boolParams);
3021
3022 for(unsigned int i = 0; i < numParams; ++i)
3023 {
3024 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
3025 }
3026
3027 delete[] boolParams;
3028 }
3029 else if(nativeType == GL_FLOAT)
3030 {
3031 GLfloat *floatParams = nullptr;
3032 floatParams = new GLfloat[numParams];
3033
3034 context->getFloatv(target, floatParams);
3035
3036 for(unsigned int i = 0; i < numParams; ++i)
3037 {
3038 if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
3039 {
Alexis Hetu60e20282017-12-13 07:42:22 -05003040 data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
Nicolas Capens0bac2852016-05-07 06:09:58 -04003041 }
3042 else
3043 {
3044 data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
3045 }
3046 }
3047
3048 delete[] floatParams;
3049 }
3050 }
3051 }
3052}
3053
3054GL_APICALL void GL_APIENTRY glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
3055{
3056 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64 *params = %p)", target, pname, params);
3057
3058 es2::Context *context = es2::getContext();
3059
3060 if(context)
3061 {
3062 es2::Buffer *buffer = nullptr;
3063
3064 if(!context->getBuffer(target, &buffer))
3065 {
3066 return error(GL_INVALID_ENUM);
3067 }
3068
3069 if(!buffer)
3070 {
3071 // A null buffer means that "0" is bound to the requested buffer target
3072 return error(GL_INVALID_OPERATION);
3073 }
3074
3075 switch(pname)
3076 {
3077 case GL_BUFFER_USAGE:
3078 *params = buffer->usage();
3079 break;
3080 case GL_BUFFER_SIZE:
3081 *params = buffer->size();
3082 break;
3083 case GL_BUFFER_ACCESS_FLAGS:
3084 *params = buffer->access();
3085 break;
3086 case GL_BUFFER_MAPPED:
3087 *params = buffer->isMapped();
3088 break;
3089 case GL_BUFFER_MAP_LENGTH:
3090 *params = buffer->length();
3091 break;
3092 case GL_BUFFER_MAP_OFFSET:
3093 *params = buffer->offset();
3094 break;
3095 default:
3096 return error(GL_INVALID_ENUM);
3097 }
3098 }
3099}
3100
3101GL_APICALL void GL_APIENTRY glGenSamplers(GLsizei count, GLuint *samplers)
3102{
3103 TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3104
3105 if(count < 0)
3106 {
3107 return error(GL_INVALID_VALUE);
3108 }
3109
3110 es2::Context *context = es2::getContext();
3111
3112 if(context)
3113 {
3114 for(int i = 0; i < count; i++)
3115 {
3116 samplers[i] = context->createSampler();
3117 }
3118 }
3119}
3120
3121GL_APICALL void GL_APIENTRY glDeleteSamplers(GLsizei count, const GLuint *samplers)
3122{
3123 TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3124
3125 if(count < 0)
3126 {
3127 return error(GL_INVALID_VALUE);
3128 }
3129
3130 es2::Context *context = es2::getContext();
3131
3132 if(context)
3133 {
3134 for(int i = 0; i < count; i++)
3135 {
3136 context->deleteSampler(samplers[i]);
3137 }
3138 }
3139}
3140
3141GL_APICALL GLboolean GL_APIENTRY glIsSampler(GLuint sampler)
3142{
3143 TRACE("(GLuint sampler = %d)", sampler);
3144
3145 if(sampler == 0)
3146 {
3147 return GL_FALSE;
3148 }
3149
3150 es2::Context *context = es2::getContext();
3151
3152 if(context)
3153 {
3154 if(context->isSampler(sampler))
3155 {
3156 return GL_TRUE;
3157 }
3158 }
3159
3160 return GL_FALSE;
3161}
3162
3163GL_APICALL void GL_APIENTRY glBindSampler(GLuint unit, GLuint sampler)
3164{
3165 TRACE("(GLuint unit = %d, GLuint sampler = %d)", unit, sampler);
3166
3167 if(unit >= es2::MAX_COMBINED_TEXTURE_IMAGE_UNITS)
3168 {
3169 return error(GL_INVALID_VALUE);
3170 }
3171
3172 es2::Context *context = es2::getContext();
3173
3174 if(context)
3175 {
3176 if(sampler != 0 && !context->isSampler(sampler))
3177 {
3178 return error(GL_INVALID_OPERATION);
3179 }
3180
3181 context->bindSampler(unit, sampler);
3182 }
3183}
3184
3185GL_APICALL void GL_APIENTRY glSamplerParameteri(GLuint sampler, GLenum pname, GLint param)
3186{
3187 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint param = %d)",
3188 sampler, pname, param);
3189
3190 glSamplerParameteriv(sampler, pname, &param);
3191}
3192
3193GL_APICALL void GL_APIENTRY glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param)
3194{
3195 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLint *param = %p)",
3196 sampler, pname, param);
3197
3198 if(!ValidateSamplerObjectParameter(pname))
3199 {
3200 return error(GL_INVALID_ENUM);
3201 }
3202
3203 if(!ValidateTexParamParameters(pname, *param))
3204 {
3205 return;
3206 }
3207
3208 es2::Context *context = es2::getContext();
3209
3210 if(context)
3211 {
3212 if(!context->isSampler(sampler))
3213 {
3214 return error(GL_INVALID_OPERATION);
3215 }
3216
3217 context->samplerParameteri(sampler, pname, *param);
3218 }
3219}
3220
3221GL_APICALL void GL_APIENTRY glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
3222{
3223 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat param = %f)",
3224 sampler, pname, param);
3225
3226 glSamplerParameterfv(sampler, pname, &param);
3227}
3228
3229GL_APICALL void GL_APIENTRY glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param)
3230{
3231 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLfloat *param = %p)",
3232 sampler, pname, param);
3233
3234 if(!ValidateSamplerObjectParameter(pname))
3235 {
3236 return error(GL_INVALID_ENUM);
3237 }
3238
Nicolas Capens0bac2852016-05-07 06:09:58 -04003239 es2::Context *context = es2::getContext();
3240
3241 if(context)
3242 {
3243 if(!context->isSampler(sampler))
3244 {
3245 return error(GL_INVALID_OPERATION);
3246 }
3247
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003248 if(ValidateTexParamParameters(pname, static_cast<GLint>(roundf(*param))))
3249 {
3250 context->samplerParameterf(sampler, pname, *param);
3251 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003252 }
3253}
3254
3255GL_APICALL void GL_APIENTRY glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
3256{
3257 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint *params = %p)",
3258 sampler, pname, params);
3259
3260 if(!ValidateSamplerObjectParameter(pname))
3261 {
3262 return error(GL_INVALID_ENUM);
3263 }
3264
3265 es2::Context *context = es2::getContext();
3266
3267 if(context)
3268 {
3269 if(!context->isSampler(sampler))
3270 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003271 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003272 }
3273
3274 *params = context->getSamplerParameteri(sampler, pname);
3275 }
3276}
3277
3278GL_APICALL void GL_APIENTRY glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
3279{
3280 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat *params = %p)",
3281 sampler, pname, params);
3282
3283 if(!ValidateSamplerObjectParameter(pname))
3284 {
3285 return error(GL_INVALID_ENUM);
3286 }
3287
3288 es2::Context *context = es2::getContext();
3289
3290 if(context)
3291 {
3292 if(!context->isSampler(sampler))
3293 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003294 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003295 }
3296
3297 *params = context->getSamplerParameterf(sampler, pname);
3298 }
3299}
3300
3301GL_APICALL void GL_APIENTRY glVertexAttribDivisor(GLuint index, GLuint divisor)
3302{
3303 TRACE("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
3304
3305 es2::Context *context = es2::getContext();
3306
3307 if(context)
3308 {
3309 if(index >= es2::MAX_VERTEX_ATTRIBS)
3310 {
3311 return error(GL_INVALID_VALUE);
3312 }
3313
3314 context->setVertexAttribDivisor(index, divisor);
3315 }
3316}
3317
3318GL_APICALL void GL_APIENTRY glBindTransformFeedback(GLenum target, GLuint id)
3319{
3320 TRACE("(GLenum target = 0x%X, GLuint id = %d)", target, id);
3321
3322 if(target != GL_TRANSFORM_FEEDBACK)
3323 {
3324 return error(GL_INVALID_ENUM);
3325 }
3326
3327 es2::Context *context = es2::getContext();
3328
3329 if(context)
3330 {
3331 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3332
3333 if(transformFeedbackObject && transformFeedbackObject->isActive() && !transformFeedbackObject->isPaused())
3334 {
3335 return error(GL_INVALID_OPERATION);
3336 }
3337
Alexis Hetu5bf97082017-11-14 11:06:03 -05003338 if(!context->isTransformFeedback(id))
3339 {
3340 return error(GL_INVALID_OPERATION);
3341 }
3342
Nicolas Capens0bac2852016-05-07 06:09:58 -04003343 context->bindTransformFeedback(id);
3344 }
3345}
3346
3347GL_APICALL void GL_APIENTRY glDeleteTransformFeedbacks(GLsizei n, const GLuint *ids)
3348{
3349 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3350
3351 if(n < 0)
3352 {
3353 return error(GL_INVALID_VALUE);
3354 }
3355
3356 es2::Context *context = es2::getContext();
3357
3358 if(context)
3359 {
3360 for(int i = 0; i < n; i++)
3361 {
3362 if(ids[i] != 0)
3363 {
Alexis Hetu5bf97082017-11-14 11:06:03 -05003364 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(ids[i]);
3365
3366 if(transformFeedbackObject && transformFeedbackObject->isActive())
3367 {
3368 return error(GL_INVALID_OPERATION);
3369 }
3370
Nicolas Capens0bac2852016-05-07 06:09:58 -04003371 context->deleteTransformFeedback(ids[i]);
3372 }
3373 }
3374 }
3375}
3376
3377GL_APICALL void GL_APIENTRY glGenTransformFeedbacks(GLsizei n, GLuint *ids)
3378{
3379 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3380
3381 if(n < 0)
3382 {
3383 return error(GL_INVALID_VALUE);
3384 }
3385
3386 es2::Context *context = es2::getContext();
3387
3388 if(context)
3389 {
3390 for(int i = 0; i < n; i++)
3391 {
3392 ids[i] = context->createTransformFeedback();
3393 }
3394 }
3395}
3396
3397GL_APICALL GLboolean GL_APIENTRY glIsTransformFeedback(GLuint id)
3398{
3399 TRACE("(GLuint id = %d)", id);
3400
3401 if(id == 0)
3402 {
3403 return GL_FALSE;
3404 }
3405
3406 es2::Context *context = es2::getContext();
3407
3408 if(context)
3409 {
3410 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(id);
3411
3412 if(transformFeedbackObject)
3413 {
3414 return GL_TRUE;
3415 }
3416 }
3417
3418 return GL_FALSE;
3419}
3420
3421GL_APICALL void GL_APIENTRY glPauseTransformFeedback(void)
3422{
3423 TRACE("()");
3424
3425 es2::Context *context = es2::getContext();
3426
3427 if(context)
3428 {
3429 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3430
3431 if(transformFeedbackObject)
3432 {
3433 if(!transformFeedbackObject->isActive() || transformFeedbackObject->isPaused())
3434 {
3435 return error(GL_INVALID_OPERATION);
3436 }
3437 transformFeedbackObject->setPaused(true);
3438 }
3439 }
3440}
3441
3442GL_APICALL void GL_APIENTRY glResumeTransformFeedback(void)
3443{
3444 TRACE("()");
3445
3446 es2::Context *context = es2::getContext();
3447
3448 if(context)
3449 {
3450 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3451
3452 if(transformFeedbackObject)
3453 {
3454 if(!transformFeedbackObject->isActive() || !transformFeedbackObject->isPaused())
3455 {
3456 return error(GL_INVALID_OPERATION);
3457 }
3458 transformFeedbackObject->setPaused(false);
3459 }
3460 }
3461}
3462
3463GL_APICALL void GL_APIENTRY glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
3464{
3465 TRACE("(GLuint program = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLenum *binaryFormat = %p, void *binary = %p)",
3466 program, bufSize, length, binaryFormat, binary);
3467
3468 if(bufSize < 0)
3469 {
3470 return error(GL_INVALID_VALUE);
3471 }
3472
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003473 es2::Context *context = es2::getContext();
3474
3475 if(context)
3476 {
3477 es2::Program *programObject = context->getProgram(program);
3478
3479 if(!programObject || !programObject->isLinked())
3480 {
3481 return error(GL_INVALID_OPERATION);
3482 }
3483 }
3484
Alexis Hetu0e92cca2017-12-19 10:53:31 -05003485 // SwiftShader doesn't return a program binary and sets the program binay size to 0, so any attempt at getting one is invalid.
3486 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003487}
3488
3489GL_APICALL void GL_APIENTRY glProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length)
3490{
3491 TRACE("(GLuint program = %d, GLenum binaryFormat = 0x%X, const void *binary = %p, GLsizei length = %d)",
3492 program, binaryFormat, binaryFormat, length);
3493
3494 if(length < 0)
3495 {
3496 return error(GL_INVALID_VALUE);
3497 }
3498
Alexis Hetu0e92cca2017-12-19 10:53:31 -05003499 es2::Context *context = es2::getContext();
3500
3501 if(context)
3502 {
3503 es2::Program *programObject = context->getProgram(program);
3504
3505 if(!programObject)
3506 {
3507 return error(GL_INVALID_OPERATION);
3508 }
3509 }
3510
3511 // Regardless of what the binaryFormat is, it is unrecognized by SwiftShader, since it supports no format.
3512 return error(GL_INVALID_ENUM);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003513}
3514
3515GL_APICALL void GL_APIENTRY glProgramParameteri(GLuint program, GLenum pname, GLint value)
3516{
3517 TRACE("(GLuint program = %d, GLenum pname = 0x%X, GLint value = %d)",
3518 program, pname, value);
3519
3520 es2::Context *context = es2::getContext();
3521
3522 if(context)
3523 {
3524 es2::Program *programObject = context->getProgram(program);
3525
3526 if(!programObject)
3527 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003528 return error(GL_INVALID_VALUE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003529 }
3530
3531 switch(pname)
3532 {
3533 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003534 if((value != GL_TRUE) && (value != GL_FALSE))
3535 {
3536 return error(GL_INVALID_VALUE);
3537 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003538 programObject->setBinaryRetrievable(value != GL_FALSE);
3539 break;
3540 default:
3541 return error(GL_INVALID_ENUM);
3542 }
3543 }
3544}
3545
3546GL_APICALL void GL_APIENTRY glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
3547{
3548 TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p)",
3549 target, numAttachments, attachments);
3550
3551 glInvalidateSubFramebuffer(target, numAttachments, attachments, 0, 0, std::numeric_limits<GLsizei>::max(), std::numeric_limits<GLsizei>::max());
3552}
3553
3554GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
3555{
3556 TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
3557 target, numAttachments, attachments, x, y, width, height);
3558
3559 es2::Context *context = es2::getContext();
3560
3561 if(context)
3562 {
3563 if(numAttachments < 0 || width < 0 || height < 0)
3564 {
3565 return error(GL_INVALID_VALUE);
3566 }
3567
3568 es2::Framebuffer *framebuffer = nullptr;
3569 switch(target)
3570 {
3571 case GL_DRAW_FRAMEBUFFER:
3572 case GL_FRAMEBUFFER:
3573 framebuffer = context->getDrawFramebuffer();
Nicolas Capens6c4564a2018-01-26 01:14:34 +00003574 break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04003575 case GL_READ_FRAMEBUFFER:
3576 framebuffer = context->getReadFramebuffer();
3577 break;
3578 default:
3579 return error(GL_INVALID_ENUM);
3580 }
3581
3582 if(framebuffer)
3583 {
3584 for(int i = 0; i < numAttachments; i++)
3585 {
3586 switch(attachments[i])
3587 {
3588 case GL_COLOR:
3589 case GL_DEPTH:
3590 case GL_STENCIL:
3591 if(!framebuffer->isDefaultFramebuffer())
3592 {
3593 return error(GL_INVALID_ENUM);
3594 }
3595 break;
3596 case GL_DEPTH_ATTACHMENT:
3597 case GL_STENCIL_ATTACHMENT:
3598 case GL_DEPTH_STENCIL_ATTACHMENT:
3599 break;
3600 default:
3601 if(attachments[i] >= GL_COLOR_ATTACHMENT0 &&
3602 attachments[i] <= GL_COLOR_ATTACHMENT31)
3603 {
3604 if(attachments[i] - GL_COLOR_ATTACHMENT0 >= MAX_DRAW_BUFFERS)
3605 {
3606 return error(GL_INVALID_OPERATION);
3607 }
3608 }
3609 else
3610 {
3611 return error(GL_INVALID_ENUM);
3612 }
3613 break;
3614 }
3615 }
3616 }
3617
3618 // UNIMPLEMENTED(); // It is valid for this function to be treated as a no-op
3619 }
3620}
3621
3622GL_APICALL void GL_APIENTRY glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
3623{
3624 TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
3625 target, levels, internalformat, width, height);
3626
Alexis Hetu0988fb82018-02-02 17:23:48 -05003627 if(width < 1 || height < 1 || levels < 1 || ((target == GL_TEXTURE_RECTANGLE_ARB) && (levels != 1)))
Nicolas Capens0bac2852016-05-07 06:09:58 -04003628 {
3629 return error(GL_INVALID_VALUE);
3630 }
3631
3632 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
3633 {
3634 return error(GL_INVALID_OPERATION);
3635 }
3636
Alexis Hetu0988fb82018-02-02 17:23:48 -05003637 bool isCompressed = IsCompressed(internalformat, egl::getClientVersion());
3638 if(!IsSizedInternalFormat(internalformat) && !isCompressed)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003639 {
3640 return error(GL_INVALID_ENUM);
3641 }
3642
3643 es2::Context *context = es2::getContext();
3644
3645 if(context)
3646 {
3647 switch(target)
3648 {
Alexis Hetu46768622018-01-16 22:09:28 -05003649 case GL_TEXTURE_RECTANGLE_ARB:
Alexis Hetu0988fb82018-02-02 17:23:48 -05003650 if(isCompressed) // Rectangle textures cannot be compressed
Nicolas Capens0bac2852016-05-07 06:09:58 -04003651 {
Alexis Hetu0988fb82018-02-02 17:23:48 -05003652 return error(GL_INVALID_ENUM);
3653 }
Nicolas Capens894858a2018-03-22 00:55:23 -04003654 // Fall through to GL_TEXTURE_2D case.
Alexis Hetu0988fb82018-02-02 17:23:48 -05003655 case GL_TEXTURE_2D:
3656 {
3657 if((width > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE) ||
3658 (height > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE))
3659 {
3660 return error(GL_INVALID_VALUE);
3661 }
3662
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003663 es2::Texture2D *texture = context->getTexture2D(target);
3664 if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
3665 {
3666 return error(GL_INVALID_OPERATION);
3667 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003668
Nicolas Capens648b5822018-01-18 00:04:26 -05003669 for(int level = 0; level < levels; level++)
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003670 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003671 texture->setImage(level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003672 width = std::max(1, (width / 2));
3673 height = std::max(1, (height / 2));
3674 }
3675 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003676 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003677 break;
3678 case GL_TEXTURE_CUBE_MAP:
Nicolas Capens0bac2852016-05-07 06:09:58 -04003679 {
Alexis Hetu0988fb82018-02-02 17:23:48 -05003680 if((width > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE) ||
3681 (height > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE))
3682 {
3683 return error(GL_INVALID_VALUE);
3684 }
3685
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003686 es2::TextureCubeMap *texture = context->getTextureCubeMap();
3687 if(!texture || texture->name == 0 || texture->getImmutableFormat())
Alexis Hetu46768622018-01-16 22:09:28 -05003688 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003689 return error(GL_INVALID_OPERATION);
Nicolas Capens648b5822018-01-18 00:04:26 -05003690 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003691
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003692 for(int level = 0; level < levels; level++)
3693 {
3694 for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
3695 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003696 texture->setImage(face, level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003697 }
3698 width = std::max(1, (width / 2));
3699 height = std::max(1, (height / 2));
3700 }
3701 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003702 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003703 break;
3704 default:
3705 return error(GL_INVALID_ENUM);
3706 }
3707 }
3708}
3709
3710GL_APICALL void GL_APIENTRY glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
3711{
3712 TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d)",
3713 target, levels, internalformat, width, height, depth);
3714
3715 if(width < 1 || height < 1 || depth < 1 || levels < 1)
3716 {
3717 return error(GL_INVALID_VALUE);
3718 }
3719
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003720 if(!IsSizedInternalFormat(internalformat) && !IsCompressed(internalformat, egl::getClientVersion()))
Nicolas Capens0bac2852016-05-07 06:09:58 -04003721 {
3722 return error(GL_INVALID_ENUM);
3723 }
3724
3725 es2::Context *context = es2::getContext();
3726
3727 if(context)
3728 {
3729 switch(target)
3730 {
3731 case GL_TEXTURE_3D:
Nicolas Capens0bac2852016-05-07 06:09:58 -04003732 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003733 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(std::max(width, height), depth)) + 1))
3734 {
3735 return error(GL_INVALID_OPERATION);
3736 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003737
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003738 es2::Texture3D *texture = context->getTexture3D();
3739 if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
3740 {
3741 return error(GL_INVALID_OPERATION);
3742 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003743
Nicolas Capens648b5822018-01-18 00:04:26 -05003744 for(int level = 0; level < levels; level++)
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003745 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003746 texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003747 width = std::max(1, (width / 2));
3748 height = std::max(1, (height / 2));
3749 depth = std::max(1, (depth / 2));
3750 }
3751 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003752 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003753 break;
3754 case GL_TEXTURE_2D_ARRAY:
Nicolas Capens0bac2852016-05-07 06:09:58 -04003755 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003756 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
Alexis Hetu46768622018-01-16 22:09:28 -05003757 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003758 return error(GL_INVALID_OPERATION);
Nicolas Capens648b5822018-01-18 00:04:26 -05003759 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003760
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003761 es2::Texture3D *texture = context->getTexture2DArray();
3762 if(!texture || texture->name == 0 || texture->getImmutableFormat())
3763 {
3764 return error(GL_INVALID_OPERATION);
3765 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003766
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003767 for(int level = 0; level < levels; level++)
3768 {
Nicolas Capens894858a2018-03-22 00:55:23 -04003769 texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
3770
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003771 width = std::max(1, (width / 2));
3772 height = std::max(1, (height / 2));
3773 }
3774 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003775 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003776 break;
3777 default:
3778 return error(GL_INVALID_ENUM);
3779 }
3780 }
3781}
3782
3783GL_APICALL void GL_APIENTRY glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params)
3784{
3785 TRACE("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, GLint *params = %p)",
3786 target, internalformat, pname, bufSize, params);
3787
3788 if(bufSize < 0)
3789 {
3790 return error(GL_INVALID_VALUE);
3791 }
3792
3793 if(bufSize == 0)
3794 {
3795 return;
3796 }
3797
Nicolas Capens2acbd262018-01-17 13:39:58 -05003798 // OpenGL ES 3.0, section 4.4.4: "An internal format is color-renderable if it is one of the formats
3799 // from table 3.13 noted as color-renderable or if it is unsized format RGBA or RGB."
3800 // Since we only use sized formats internally, replace them here (assuming type = GL_UNSIGNED_BYTE).
3801 if(internalformat == GL_RGB) internalformat = GL_RGB8;
3802 if(internalformat == GL_RGBA) internalformat = GL_RGBA8;
3803
Nicolas Capensd2faaa92017-12-04 11:15:51 -05003804 if(!IsColorRenderable(internalformat, egl::getClientVersion()) &&
Nicolas Capens400667e2017-03-29 14:40:14 -04003805 !IsDepthRenderable(internalformat, egl::getClientVersion()) &&
3806 !IsStencilRenderable(internalformat, egl::getClientVersion()))
Nicolas Capens0bac2852016-05-07 06:09:58 -04003807 {
3808 return error(GL_INVALID_ENUM);
3809 }
3810
3811 switch(target)
3812 {
3813 case GL_RENDERBUFFER:
3814 break;
3815 default:
3816 return error(GL_INVALID_ENUM);
3817 }
3818
Nicolas Capens0bac2852016-05-07 06:09:58 -04003819 GLint numMultisampleCounts = NUM_MULTISAMPLE_COUNTS;
Nicolas Capens135e2402018-01-17 14:02:55 -05003820
3821 // Integer types have no multisampling
3822 GLenum type = GetColorComponentType(internalformat);
3823 if(type != GL_UNSIGNED_NORMALIZED && type != GL_FLOAT)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003824 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04003825 numMultisampleCounts = 0;
Nicolas Capens0bac2852016-05-07 06:09:58 -04003826 }
3827
3828 switch(pname)
3829 {
3830 case GL_NUM_SAMPLE_COUNTS:
3831 *params = numMultisampleCounts;
3832 break;
3833 case GL_SAMPLES:
3834 for(int i = 0; i < numMultisampleCounts && i < bufSize; i++)
3835 {
3836 params[i] = multisampleCount[i];
3837 }
3838 break;
3839 default:
3840 return error(GL_INVALID_ENUM);
3841 }
3842}
3843
3844}