blob: 6ba4c9d1630fc8d83907e8771d8f5d54c36e7554 [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
Nicolas Capens805d7612018-08-02 13:56:32 -0400210namespace gl
Nicolas Capens0bac2852016-05-07 06:09:58 -0400211{
212
Nicolas Capens805d7612018-08-02 13:56:32 -0400213void ReadBuffer(GLenum src)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400214{
215 TRACE("(GLenum src = 0x%X)", src);
216
Chris Forbes108f3e12018-08-30 19:41:59 -0700217 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400218
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400286void DrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400287{
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
Chris Forbes108f3e12018-08-30 19:41:59 -0700321 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400322
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400335void TexImage3D(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
Chris Forbes108f3e12018-08-30 19:41:59 -0700367 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400368
369 if(context)
370 {
Nicolas Capens83463112018-06-12 23:55:16 -0400371 GLenum validationError = ValidateTextureFormatType(format, type, internalformat, target);
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400395void TexSubImage3D(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
Chris Forbes108f3e12018-08-30 19:41:59 -0700421 auto 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 Capens83463112018-06-12 23:55:16 -0400427 GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texture);
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400443void CopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400444{
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
Chris Forbes108f3e12018-08-30 19:41:59 -0700468 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400469
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 Capens83463112018-06-12 23:55:16 -0400489 GLenum validationError = ValidateSubImageParams(false, true, target, level, xoffset, yoffset, zoffset, width, height, 1, GL_NONE, GL_NONE, texture);
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400506void CompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400507{
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 Capens83463112018-06-12 23:55:16 -0400532 if(!IsCompressed(internalformat))
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
Chris Forbes108f3e12018-08-30 19:41:59 -0700542 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400543
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400563void CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400564{
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 Capens83463112018-06-12 23:55:16 -0400589 if(!IsCompressed(format))
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
Chris Forbes108f3e12018-08-30 19:41:59 -0700629 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400630
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400660void GenQueries(GLsizei n, GLuint *ids)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400661{
662 TRACE("(GLsizei n = %d, GLuint* ids = %p)", n, ids);
663
664 if(n < 0)
665 {
666 return error(GL_INVALID_VALUE);
667 }
668
Chris Forbes108f3e12018-08-30 19:41:59 -0700669 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400670
671 if(context)
672 {
673 for(int i = 0; i < n; i++)
674 {
675 ids[i] = context->createQuery();
676 }
677 }
678}
679
Nicolas Capens805d7612018-08-02 13:56:32 -0400680void DeleteQueries(GLsizei n, const GLuint *ids)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400681{
682 TRACE("(GLsizei n = %d, GLuint* ids = %p)", n, ids);
683
684 if(n < 0)
685 {
686 return error(GL_INVALID_VALUE);
687 }
688
Chris Forbes108f3e12018-08-30 19:41:59 -0700689 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400690
691 if(context)
692 {
693 for(int i = 0; i < n; i++)
694 {
695 context->deleteQuery(ids[i]);
696 }
697 }
698}
699
Nicolas Capens805d7612018-08-02 13:56:32 -0400700GLboolean IsQuery(GLuint id)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400701{
702 TRACE("(GLuint id = %d)", id);
703
704 if(id == 0)
705 {
706 return GL_FALSE;
707 }
708
Chris Forbes108f3e12018-08-30 19:41:59 -0700709 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400710
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400724void BeginQuery(GLenum target, GLuint id)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400725{
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
Chris Forbes108f3e12018-08-30 19:41:59 -0700738 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400739
740 if(context)
741 {
742 context->beginQuery(target, id);
743 }
744}
745
Nicolas Capens805d7612018-08-02 13:56:32 -0400746void EndQuery(GLenum target)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400747{
748 TRACE("(GLenum target = 0x%X)", target);
749
750 if(!ValidateQueryTarget(target))
751 {
752 return error(GL_INVALID_ENUM);
753 }
754
Chris Forbes108f3e12018-08-30 19:41:59 -0700755 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400756
757 if(context)
758 {
759 context->endQuery(target);
760 }
761}
762
Nicolas Capens805d7612018-08-02 13:56:32 -0400763void GetQueryiv(GLenum target, GLenum pname, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400764{
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
Chris Forbes108f3e12018-08-30 19:41:59 -0700773 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400774
775 if(context)
776 {
777 params[0] = context->getActiveQuery(target);
778 }
779}
780
Nicolas Capens805d7612018-08-02 13:56:32 -0400781void GetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400782{
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
Chris Forbes108f3e12018-08-30 19:41:59 -0700795 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400796
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400825GLboolean UnmapBuffer(GLenum target)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400826{
827 TRACE("(GLenum target = 0x%X)", target);
828
Chris Forbes108f3e12018-08-30 19:41:59 -0700829 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400830
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400857void GetBufferPointerv(GLenum target, GLenum pname, void **params)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400858{
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
Chris Forbes108f3e12018-08-30 19:41:59 -0700867 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400868
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400887void DrawBuffers(GLsizei n, const GLenum *bufs)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400888{
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
Chris Forbes108f3e12018-08-30 19:41:59 -0700896 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400897
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
Nicolas Capens805d7612018-08-02 13:56:32 -0400979void UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400980{
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
Chris Forbes108f3e12018-08-30 19:41:59 -0700988 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -0400989
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
Nicolas Capens805d7612018-08-02 13:56:32 -04001011void UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001012{
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
Chris Forbes108f3e12018-08-30 19:41:59 -07001020 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001021
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
Nicolas Capens805d7612018-08-02 13:56:32 -04001043void UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001044{
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
Chris Forbes108f3e12018-08-30 19:41:59 -07001052 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001053
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
Nicolas Capens805d7612018-08-02 13:56:32 -04001075void UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001076{
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
Chris Forbes108f3e12018-08-30 19:41:59 -07001084 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001085
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
Nicolas Capens805d7612018-08-02 13:56:32 -04001107void UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001108{
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
Chris Forbes108f3e12018-08-30 19:41:59 -07001116 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001117
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
Nicolas Capens805d7612018-08-02 13:56:32 -04001139void UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001140{
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
Chris Forbes108f3e12018-08-30 19:41:59 -07001148 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001149
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
Nicolas Capens805d7612018-08-02 13:56:32 -04001171void BlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001172{
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
Chris Forbes108f3e12018-08-30 19:41:59 -07001197 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001198
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 Capens805d7612018-08-02 13:56:32 -04001211void FramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001212{
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
Chris Forbes108f3e12018-08-30 19:41:59 -07001225 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001226
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 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04001297 case GL_DEPTH_ATTACHMENT:
1298 framebuffer->setDepthbuffer(textarget, texture, level, layer);
1299 break;
1300 case GL_STENCIL_ATTACHMENT:
1301 framebuffer->setStencilbuffer(textarget, texture, level, layer);
1302 break;
1303 case GL_DEPTH_STENCIL_ATTACHMENT:
1304 framebuffer->setDepthbuffer(textarget, texture, level, layer);
1305 framebuffer->setStencilbuffer(textarget, texture, level, layer);
1306 break;
1307 default:
Nicolas Capens4e344192018-10-24 21:01:17 -04001308 if(attachment < GL_COLOR_ATTACHMENT0 || attachment > GL_COLOR_ATTACHMENT31)
1309 {
1310 return error(GL_INVALID_ENUM);
1311 }
1312
1313 if((attachment - GL_COLOR_ATTACHMENT0) >= MAX_COLOR_ATTACHMENTS)
1314 {
1315 return error(GL_INVALID_OPERATION);
1316 }
1317
1318 framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0, level, layer);
1319 break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001320 }
1321 }
1322}
1323
Nicolas Capens805d7612018-08-02 13:56:32 -04001324void *MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001325{
1326 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = %X)",
1327 target, offset, length, access);
1328
Alexis Hetu6e864492017-11-14 15:27:00 -05001329 if((offset < 0) || (length < 0))
1330 {
1331 return error(GL_INVALID_VALUE, nullptr);
1332 }
1333
1334 if(!(access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)))
1335 {
1336 // Must be able to read or write the buffer
1337 return error(GL_INVALID_OPERATION, nullptr);
1338 }
1339 else if((access & GL_MAP_READ_BIT) && (access & (GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT)))
1340 {
1341 // GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT and GL_MAP_UNSYNCHRONIZED_BIT can't be used with GL_MAP_READ_BIT
1342 return error(GL_INVALID_OPERATION, nullptr);
1343 }
1344 else if((!(access & GL_MAP_WRITE_BIT)) && (access & GL_MAP_FLUSH_EXPLICIT_BIT))
1345 {
1346 // GL_MAP_FLUSH_EXPLICIT_BIT can't be used without GL_MAP_WRITE_BIT
1347 return error(GL_INVALID_OPERATION, nullptr);
1348 }
1349
Chris Forbes108f3e12018-08-30 19:41:59 -07001350 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001351
1352 if(context)
1353 {
1354 es2::Buffer *buffer = nullptr;
1355 if(!context->getBuffer(target, &buffer))
1356 {
1357 return error(GL_INVALID_ENUM, nullptr);
1358 }
1359
1360 if(!buffer)
1361 {
1362 // A null buffer means that "0" is bound to the requested buffer target
1363 return error(GL_INVALID_OPERATION, nullptr);
1364 }
1365
Alexis Hetu1b4eb7f2017-11-14 13:24:37 -05001366 if(buffer->isMapped())
1367 {
1368 // It is an invalid operation to map an already mapped buffer
1369 return error(GL_INVALID_OPERATION, nullptr);
1370 }
1371
Nicolas Capens0bac2852016-05-07 06:09:58 -04001372 GLsizeiptr bufferSize = buffer->size();
Alexis Hetu6e864492017-11-14 15:27:00 -05001373 if((offset + length) > bufferSize)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001374 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001375 return error(GL_INVALID_VALUE, nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001376 }
1377
1378 if((access & ~(GL_MAP_READ_BIT |
1379 GL_MAP_WRITE_BIT |
1380 GL_MAP_INVALIDATE_RANGE_BIT |
1381 GL_MAP_INVALIDATE_BUFFER_BIT |
1382 GL_MAP_FLUSH_EXPLICIT_BIT |
1383 GL_MAP_UNSYNCHRONIZED_BIT)) != 0)
1384 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001385 return error(GL_INVALID_VALUE, nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001386 }
1387
1388 return buffer->mapRange(offset, length, access);
1389 }
1390
1391 return nullptr;
1392}
1393
Nicolas Capens805d7612018-08-02 13:56:32 -04001394void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001395{
1396 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)",
1397 target, offset, length);
1398
Alexis Hetu6e864492017-11-14 15:27:00 -05001399 if((offset < 0) || (length < 0))
1400 {
1401 return error(GL_INVALID_VALUE);
1402 }
1403
Chris Forbes108f3e12018-08-30 19:41:59 -07001404 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001405
1406 if(context)
1407 {
1408 es2::Buffer *buffer = nullptr;
1409 if(!context->getBuffer(target, &buffer))
1410 {
1411 return error(GL_INVALID_ENUM);
1412 }
1413
1414 if(!buffer)
1415 {
1416 // A null buffer means that "0" is bound to the requested buffer target
1417 return error(GL_INVALID_OPERATION);
1418 }
1419
Alexis Hetu6e864492017-11-14 15:27:00 -05001420 if(!buffer->isMapped())
Nicolas Capens0bac2852016-05-07 06:09:58 -04001421 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001422 // Buffer must be mapped
1423 return error(GL_INVALID_OPERATION);
1424 }
1425
1426 GLsizeiptr bufferSize = buffer->length();
1427 if((offset + length) > bufferSize)
1428 {
1429 return error(GL_INVALID_VALUE);
1430 }
1431
Alexis Hetua752b892017-11-22 14:00:37 -05001432 if(!(buffer->access() & GL_MAP_FLUSH_EXPLICIT_BIT))
Alexis Hetu6e864492017-11-14 15:27:00 -05001433 {
1434 // Flush must be explicitly allowed
1435 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001436 }
1437
1438 buffer->flushMappedRange(offset, length);
1439 }
1440}
1441
Nicolas Capens805d7612018-08-02 13:56:32 -04001442void BindVertexArray(GLuint array)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001443{
1444 TRACE("(GLuint array = %d)", array);
1445
Chris Forbes108f3e12018-08-30 19:41:59 -07001446 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001447
1448 if(context)
1449 {
1450 if(!context->isVertexArray(array))
1451 {
1452 return error(GL_INVALID_OPERATION);
1453 }
1454
1455 context->bindVertexArray(array);
1456 }
1457}
1458
Nicolas Capens805d7612018-08-02 13:56:32 -04001459void BindVertexArrayOES(GLuint array)
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001460{
Nicolas Capens805d7612018-08-02 13:56:32 -04001461 BindVertexArray(array);
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001462}
1463
Nicolas Capens805d7612018-08-02 13:56:32 -04001464void DeleteVertexArrays(GLsizei n, const GLuint *arrays)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001465{
1466 TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1467
1468 if(n < 0)
1469 {
1470 return error(GL_INVALID_VALUE);
1471 }
1472
Chris Forbes108f3e12018-08-30 19:41:59 -07001473 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001474
1475 if(context)
1476 {
1477 for(int i = 0; i < n; i++)
1478 {
Nicolas Capens56eacf02018-09-27 13:54:27 -04001479 if(arrays[i] != 0) // Attempts to delete default vertex array silently ignored.
1480 {
1481 context->deleteVertexArray(arrays[i]);
1482 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001483 }
1484 }
1485}
1486
Nicolas Capens805d7612018-08-02 13:56:32 -04001487void DeleteVertexArraysOES(GLsizei n, const GLuint *arrays)
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001488{
Nicolas Capens805d7612018-08-02 13:56:32 -04001489 DeleteVertexArrays(n, arrays);
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001490}
1491
Nicolas Capens805d7612018-08-02 13:56:32 -04001492void GenVertexArrays(GLsizei n, GLuint *arrays)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001493{
1494 TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1495
1496 if(n < 0)
1497 {
1498 return error(GL_INVALID_VALUE);
1499 }
1500
Chris Forbes108f3e12018-08-30 19:41:59 -07001501 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001502
1503 if(context)
1504 {
1505 for(int i = 0; i < n; i++)
1506 {
1507 arrays[i] = context->createVertexArray();
1508 }
1509 }
1510}
1511
Nicolas Capens805d7612018-08-02 13:56:32 -04001512void GenVertexArraysOES(GLsizei n, GLuint *arrays)
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001513{
Nicolas Capens805d7612018-08-02 13:56:32 -04001514 GenVertexArrays(n, arrays);
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001515}
1516
Nicolas Capens805d7612018-08-02 13:56:32 -04001517GLboolean IsVertexArray(GLuint array)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001518{
1519 TRACE("(GLuint array = %d)", array);
1520
1521 if(array == 0)
1522 {
1523 return GL_FALSE;
1524 }
1525
Chris Forbes108f3e12018-08-30 19:41:59 -07001526 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001527
1528 if(context)
1529 {
1530 es2::VertexArray *arrayObject = context->getVertexArray(array);
1531
1532 if(arrayObject)
1533 {
1534 return GL_TRUE;
1535 }
1536 }
1537
1538 return GL_FALSE;
1539}
1540
Nicolas Capens805d7612018-08-02 13:56:32 -04001541GLboolean IsVertexArrayOES(GLuint array)
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001542{
Nicolas Capens805d7612018-08-02 13:56:32 -04001543 return IsVertexArray(array);
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001544}
1545
Nicolas Capens805d7612018-08-02 13:56:32 -04001546void GetIntegeri_v(GLenum target, GLuint index, GLint *data)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001547{
1548 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint* data = %p)",
1549 target, index, data);
1550
Chris Forbes108f3e12018-08-30 19:41:59 -07001551 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001552
1553 if(context)
1554 {
1555 if(!context->getTransformFeedbackiv(index, target, data) &&
1556 !context->getUniformBufferiv(index, target, data) &&
1557 !context->getIntegerv(target, data))
1558 {
1559 GLenum nativeType;
1560 unsigned int numParams = 0;
1561 if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
1562 return error(GL_INVALID_ENUM);
1563
1564 if(numParams == 0)
1565 return; // it is known that target is valid, but there are no parameters to return
1566
1567 if(nativeType == GL_BOOL)
1568 {
1569 GLboolean *boolParams = nullptr;
1570 boolParams = new GLboolean[numParams];
1571
1572 context->getBooleanv(target, boolParams);
1573
1574 for(unsigned int i = 0; i < numParams; ++i)
1575 {
1576 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
1577 }
1578
1579 delete[] boolParams;
1580 }
1581 else if(nativeType == GL_FLOAT)
1582 {
1583 GLfloat *floatParams = nullptr;
1584 floatParams = new GLfloat[numParams];
1585
1586 context->getFloatv(target, floatParams);
1587
1588 for(unsigned int i = 0; i < numParams; ++i)
1589 {
1590 if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
1591 {
Alexis Hetu60e20282017-12-13 07:42:22 -05001592 data[i] = convert_float_fixed(floatParams[i]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001593 }
1594 else
1595 {
1596 data[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
1597 }
1598 }
1599
1600 delete[] floatParams;
1601 }
1602 }
1603 }
1604}
1605
Nicolas Capens805d7612018-08-02 13:56:32 -04001606void BeginTransformFeedback(GLenum primitiveMode)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001607{
1608 TRACE("(GLenum primitiveMode = 0x%X)", primitiveMode);
1609
1610 switch(primitiveMode)
1611 {
1612 case GL_POINTS:
1613 case GL_LINES:
1614 case GL_TRIANGLES:
1615 break;
1616 default:
1617 return error(GL_INVALID_ENUM);
1618 }
1619
Chris Forbes108f3e12018-08-30 19:41:59 -07001620 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001621
1622 if(context)
1623 {
1624 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1625
1626 if(transformFeedbackObject)
1627 {
1628 if(transformFeedbackObject->isActive())
1629 {
1630 return error(GL_INVALID_OPERATION);
1631 }
1632 transformFeedbackObject->begin(primitiveMode);
1633 }
1634 else
1635 {
1636 return error(GL_INVALID_OPERATION);
1637 }
1638 }
1639}
1640
Nicolas Capens805d7612018-08-02 13:56:32 -04001641void EndTransformFeedback(void)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001642{
1643 TRACE("()");
1644
Chris Forbes108f3e12018-08-30 19:41:59 -07001645 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001646
1647 if(context)
1648 {
1649 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1650
1651 if(transformFeedbackObject)
1652 {
1653 if(!transformFeedbackObject->isActive())
1654 {
1655 return error(GL_INVALID_OPERATION);
1656 }
1657 transformFeedbackObject->end();
1658 }
1659 else
1660 {
1661 return error(GL_INVALID_OPERATION);
1662 }
1663 }
1664}
1665
Nicolas Capens805d7612018-08-02 13:56:32 -04001666void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001667{
1668 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d, GLintptr offset = %d, GLsizeiptr size = %d)",
1669 target, index, buffer, offset, size);
1670
1671 if(buffer != 0 && size <= 0)
1672 {
1673 return error(GL_INVALID_VALUE);
1674 }
1675
Chris Forbes108f3e12018-08-30 19:41:59 -07001676 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001677
1678 if(context)
1679 {
1680 switch(target)
1681 {
1682 case GL_TRANSFORM_FEEDBACK_BUFFER:
1683 if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1684 {
1685 return error(GL_INVALID_VALUE);
1686 }
1687 if(size & 0x3 || offset & 0x3) // size and offset must be multiples of 4
1688 {
1689 return error(GL_INVALID_VALUE);
1690 }
1691 context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size);
1692 context->bindGenericTransformFeedbackBuffer(buffer);
1693 break;
1694 case GL_UNIFORM_BUFFER:
1695 if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
1696 {
1697 return error(GL_INVALID_VALUE);
1698 }
1699 if(offset % UNIFORM_BUFFER_OFFSET_ALIGNMENT != 0)
1700 {
1701 return error(GL_INVALID_VALUE);
1702 }
1703 context->bindIndexedUniformBuffer(buffer, index, offset, size);
1704 context->bindGenericUniformBuffer(buffer);
1705 break;
1706 default:
1707 return error(GL_INVALID_ENUM);
1708 }
1709 }
1710}
1711
Nicolas Capens805d7612018-08-02 13:56:32 -04001712void BindBufferBase(GLenum target, GLuint index, GLuint buffer)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001713{
1714 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d)",
1715 target, index, buffer);
1716
Chris Forbes108f3e12018-08-30 19:41:59 -07001717 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001718
1719 if(context)
1720 {
1721 switch(target)
1722 {
1723 case GL_TRANSFORM_FEEDBACK_BUFFER:
1724 if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1725 {
1726 return error(GL_INVALID_VALUE);
1727 }
1728 context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0);
1729 context->bindGenericTransformFeedbackBuffer(buffer);
1730 break;
1731 case GL_UNIFORM_BUFFER:
1732 if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
1733 {
1734 return error(GL_INVALID_VALUE);
1735 }
1736 context->bindIndexedUniformBuffer(buffer, index, 0, 0);
1737 context->bindGenericUniformBuffer(buffer);
1738 break;
1739 default:
1740 return error(GL_INVALID_ENUM);
1741 }
1742 }
1743}
1744
Nicolas Capens805d7612018-08-02 13:56:32 -04001745void TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001746{
1747 TRACE("(GLuint program = %d, GLsizei count = %d, const GLchar *const*varyings = %p, GLenum bufferMode = 0x%X)",
1748 program, count, varyings, bufferMode);
1749
1750 switch(bufferMode)
1751 {
1752 case GL_SEPARATE_ATTRIBS:
1753 if(count > MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1754 {
1755 return error(GL_INVALID_VALUE);
1756 }
1757 case GL_INTERLEAVED_ATTRIBS:
1758 break;
1759 default:
1760 return error(GL_INVALID_ENUM);
1761 }
1762
Chris Forbes108f3e12018-08-30 19:41:59 -07001763 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001764
1765 if(context)
1766 {
1767 es2::Program *programObject = context->getProgram(program);
1768
1769 if(!programObject)
1770 {
1771 return error(GL_INVALID_VALUE);
1772 }
1773
1774 programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);
1775 }
1776}
1777
Nicolas Capens805d7612018-08-02 13:56:32 -04001778void GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001779{
1780 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
1781 program, index, bufSize, length, size, type, name);
1782
1783 if(bufSize < 0)
1784 {
1785 return error(GL_INVALID_VALUE);
1786 }
1787
Chris Forbes108f3e12018-08-30 19:41:59 -07001788 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001789
1790 if(context)
1791 {
1792 es2::Program *programObject = context->getProgram(program);
1793
1794 if(!programObject)
1795 {
1796 return error(GL_INVALID_VALUE);
1797 }
1798
1799 if(index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount()))
1800 {
1801 return error(GL_INVALID_VALUE);
1802 }
1803
1804 programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name);
1805 }
1806}
1807
Nicolas Capens805d7612018-08-02 13:56:32 -04001808void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001809{
1810 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
1811 index, size, type, stride, pointer);
1812
1813 if(index >= es2::MAX_VERTEX_ATTRIBS)
1814 {
1815 return error(GL_INVALID_VALUE);
1816 }
1817
1818 if(size < 1 || size > 4 || stride < 0)
1819 {
1820 return error(GL_INVALID_VALUE);
1821 }
1822
1823 switch(type)
1824 {
1825 case GL_BYTE:
1826 case GL_UNSIGNED_BYTE:
1827 case GL_SHORT:
1828 case GL_UNSIGNED_SHORT:
1829 case GL_INT:
1830 case GL_UNSIGNED_INT:
1831 break;
1832 default:
1833 return error(GL_INVALID_ENUM);
1834 }
1835
Chris Forbes108f3e12018-08-30 19:41:59 -07001836 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001837
1838 if(context)
1839 {
Alexis Hetuc1ef1ad2017-11-15 10:50:10 -05001840 es2::VertexArray* vertexArray = context->getCurrentVertexArray();
1841 if((context->getArrayBufferName() == 0) && vertexArray && (vertexArray->name != 0) && pointer)
1842 {
1843 // GL_INVALID_OPERATION is generated if a non-zero vertex array object is bound, zero is bound
1844 // to the GL_ARRAY_BUFFER buffer object binding point and the pointer argument is not NULL.
1845 return error(GL_INVALID_OPERATION);
1846 }
1847
Alexis Hetu6f284032017-12-11 15:19:36 -05001848 context->setVertexAttribState(index, context->getArrayBuffer(), size, type, false, true, stride, pointer);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001849 }
1850}
1851
Nicolas Capens805d7612018-08-02 13:56:32 -04001852void GetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001853{
1854 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint *params = %p)",
1855 index, pname, params);
1856
Chris Forbes108f3e12018-08-30 19:41:59 -07001857 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001858
1859 if(context)
1860 {
1861 if(index >= es2::MAX_VERTEX_ATTRIBS)
1862 {
1863 return error(GL_INVALID_VALUE);
1864 }
1865
1866 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
1867
1868 switch(pname)
1869 {
1870 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1871 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
1872 break;
1873 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1874 *params = attribState.mSize;
1875 break;
1876 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1877 *params = attribState.mStride;
1878 break;
1879 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1880 *params = attribState.mType;
1881 break;
1882 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1883 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
1884 break;
1885 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1886 *params = attribState.mBoundBuffer.name();
1887 break;
1888 case GL_CURRENT_VERTEX_ATTRIB:
1889 {
1890 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
1891 for(int i = 0; i < 4; ++i)
1892 {
1893 params[i] = attrib.getCurrentValueI(i);
1894 }
1895 }
1896 break;
1897 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Alexis Hetu6f284032017-12-11 15:19:36 -05001898 *params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001899 break;
1900 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1901 *params = attribState.mDivisor;
1902 break;
1903 default: return error(GL_INVALID_ENUM);
1904 }
1905 }
1906}
1907
Nicolas Capens805d7612018-08-02 13:56:32 -04001908void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001909{
1910 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLuint *params = %p)",
1911 index, pname, params);
1912
Chris Forbes108f3e12018-08-30 19:41:59 -07001913 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001914
1915 if(context)
1916 {
1917 if(index >= es2::MAX_VERTEX_ATTRIBS)
1918 {
1919 return error(GL_INVALID_VALUE);
1920 }
1921
1922 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
1923
1924 switch(pname)
1925 {
1926 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1927 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
1928 break;
1929 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1930 *params = attribState.mSize;
1931 break;
1932 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1933 *params = attribState.mStride;
1934 break;
1935 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1936 *params = attribState.mType;
1937 break;
1938 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1939 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
1940 break;
1941 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1942 *params = attribState.mBoundBuffer.name();
1943 break;
1944 case GL_CURRENT_VERTEX_ATTRIB:
1945 {
1946 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
1947 for(int i = 0; i < 4; ++i)
1948 {
1949 params[i] = attrib.getCurrentValueUI(i);
1950 }
1951 }
1952 break;
1953 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Alexis Hetu6f284032017-12-11 15:19:36 -05001954 *params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001955 break;
1956 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1957 *params = attribState.mDivisor;
1958 break;
1959 default: return error(GL_INVALID_ENUM);
1960 }
1961 }
1962}
1963
Nicolas Capens805d7612018-08-02 13:56:32 -04001964void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001965{
1966 TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
1967 index, x, y, z, w);
1968
1969 if(index >= es2::MAX_VERTEX_ATTRIBS)
1970 {
1971 return error(GL_INVALID_VALUE);
1972 }
1973
Chris Forbes108f3e12018-08-30 19:41:59 -07001974 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001975
1976 if(context)
1977 {
1978 GLint vals[4] = { x, y, z, w };
1979 context->setVertexAttrib(index, vals);
1980 }
1981}
1982
Nicolas Capens805d7612018-08-02 13:56:32 -04001983void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001984{
1985 TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
1986 index, x, y, z, w);
1987
1988 if(index >= es2::MAX_VERTEX_ATTRIBS)
1989 {
1990 return error(GL_INVALID_VALUE);
1991 }
1992
Chris Forbes108f3e12018-08-30 19:41:59 -07001993 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001994
1995 if(context)
1996 {
1997 GLuint vals[4] = { x, y, z, w };
1998 context->setVertexAttrib(index, vals);
1999 }
2000}
2001
Nicolas Capens805d7612018-08-02 13:56:32 -04002002void VertexAttribI4iv(GLuint index, const GLint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002003{
2004 TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2005
2006 if(index >= es2::MAX_VERTEX_ATTRIBS)
2007 {
2008 return error(GL_INVALID_VALUE);
2009 }
2010
Chris Forbes108f3e12018-08-30 19:41:59 -07002011 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002012
2013 if(context)
2014 {
2015 context->setVertexAttrib(index, v);
2016 }
2017}
2018
Nicolas Capens805d7612018-08-02 13:56:32 -04002019void VertexAttribI4uiv(GLuint index, const GLuint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002020{
2021 TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2022
2023 if(index >= es2::MAX_VERTEX_ATTRIBS)
2024 {
2025 return error(GL_INVALID_VALUE);
2026 }
2027
Chris Forbes108f3e12018-08-30 19:41:59 -07002028 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002029
2030 if(context)
2031 {
2032 context->setVertexAttrib(index, v);
2033 }
2034}
2035
Nicolas Capens805d7612018-08-02 13:56:32 -04002036void GetUniformuiv(GLuint program, GLint location, GLuint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002037{
2038 TRACE("(GLuint program = %d, GLint location = %d, GLuint *params = %p)",
2039 program, location, params);
2040
Chris Forbes108f3e12018-08-30 19:41:59 -07002041 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002042
2043 if(context)
2044 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04002045 es2::Program *programObject = context->getProgram(program);
2046
Alexis Hetu48280a42017-11-30 15:04:39 -05002047 if(!programObject)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002048 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002049 if(context->getShader(program))
2050 {
2051 return error(GL_INVALID_OPERATION);
2052 }
2053 else
2054 {
2055 return error(GL_INVALID_VALUE);
2056 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002057 }
2058
Alexis Hetu48280a42017-11-30 15:04:39 -05002059 if(!programObject->isLinked())
Nicolas Capens0bac2852016-05-07 06:09:58 -04002060 {
2061 return error(GL_INVALID_OPERATION);
2062 }
2063
2064 if(!programObject->getUniformuiv(location, nullptr, params))
2065 {
2066 return error(GL_INVALID_OPERATION);
2067 }
2068 }
2069}
2070
Nicolas Capens805d7612018-08-02 13:56:32 -04002071GLint GetFragDataLocation(GLuint program, const GLchar *name)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002072{
2073 TRACE("(GLuint program = %d, const GLchar *name = %p)", program, name);
2074
Chris Forbes108f3e12018-08-30 19:41:59 -07002075 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002076
Nicolas Capens0bac2852016-05-07 06:09:58 -04002077 if(context)
2078 {
2079 es2::Program *programObject = context->getProgram(program);
2080
2081 if(!programObject)
2082 {
2083 if(context->getShader(program))
2084 {
2085 return error(GL_INVALID_OPERATION, -1);
2086 }
2087 else
2088 {
2089 return error(GL_INVALID_VALUE, -1);
2090 }
2091 }
2092
2093 if(!programObject->isLinked())
2094 {
2095 return error(GL_INVALID_OPERATION, -1);
2096 }
Alexis Hetub3f5ed72017-08-16 16:37:19 -04002097
2098 return programObject->getFragDataLocation(name);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002099 }
2100
Nicolas Capens0bac2852016-05-07 06:09:58 -04002101 return -1;
2102}
2103
Nicolas Capens805d7612018-08-02 13:56:32 -04002104void Uniform1uiv(GLint location, GLsizei count, const GLuint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002105{
2106 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2107 location, count, value);
2108
2109 if(count < 0)
2110 {
2111 return error(GL_INVALID_VALUE);
2112 }
2113
Chris Forbes108f3e12018-08-30 19:41:59 -07002114 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002115
2116 if(context)
2117 {
2118 es2::Program *program = context->getCurrentProgram();
2119
2120 if(!program)
2121 {
2122 return error(GL_INVALID_OPERATION);
2123 }
2124
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002125 if(location == -1)
2126 {
2127 return;
2128 }
2129
Nicolas Capens0bac2852016-05-07 06:09:58 -04002130 if(!program->setUniform1uiv(location, count, value))
2131 {
2132 return error(GL_INVALID_OPERATION);
2133 }
2134 }
2135}
2136
Nicolas Capens805d7612018-08-02 13:56:32 -04002137void Uniform2uiv(GLint location, GLsizei count, const GLuint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002138{
2139 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2140 location, count, value);
2141
2142 if(count < 0)
2143 {
2144 return error(GL_INVALID_VALUE);
2145 }
2146
Chris Forbes108f3e12018-08-30 19:41:59 -07002147 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002148
2149 if(context)
2150 {
2151 es2::Program *program = context->getCurrentProgram();
2152
2153 if(!program)
2154 {
2155 return error(GL_INVALID_OPERATION);
2156 }
2157
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002158 if(location == -1)
2159 {
2160 return;
2161 }
2162
Nicolas Capens0bac2852016-05-07 06:09:58 -04002163 if(!program->setUniform2uiv(location, count, value))
2164 {
2165 return error(GL_INVALID_OPERATION);
2166 }
2167 }
2168}
2169
Nicolas Capens805d7612018-08-02 13:56:32 -04002170void Uniform3uiv(GLint location, GLsizei count, const GLuint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002171{
2172 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2173 location, count, value);
2174
2175 if(count < 0)
2176 {
2177 return error(GL_INVALID_VALUE);
2178 }
2179
Chris Forbes108f3e12018-08-30 19:41:59 -07002180 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002181
2182 if(context)
2183 {
2184 es2::Program *program = context->getCurrentProgram();
2185
2186 if(!program)
2187 {
2188 return error(GL_INVALID_OPERATION);
2189 }
2190
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002191 if(location == -1)
2192 {
2193 return;
2194 }
2195
Nicolas Capens0bac2852016-05-07 06:09:58 -04002196 if(!program->setUniform3uiv(location, count, value))
2197 {
2198 return error(GL_INVALID_OPERATION);
2199 }
2200 }
2201}
2202
Nicolas Capens805d7612018-08-02 13:56:32 -04002203void Uniform4uiv(GLint location, GLsizei count, const GLuint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002204{
2205 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2206 location, count, value);
2207
2208 if(count < 0)
2209 {
2210 return error(GL_INVALID_VALUE);
2211 }
2212
Chris Forbes108f3e12018-08-30 19:41:59 -07002213 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002214
2215 if(context)
2216 {
2217 es2::Program *program = context->getCurrentProgram();
2218
2219 if(!program)
2220 {
2221 return error(GL_INVALID_OPERATION);
2222 }
2223
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002224 if(location == -1)
2225 {
2226 return;
2227 }
2228
Nicolas Capens0bac2852016-05-07 06:09:58 -04002229 if(!program->setUniform4uiv(location, count, value))
2230 {
2231 return error(GL_INVALID_OPERATION);
2232 }
2233 }
2234}
2235
Nicolas Capens805d7612018-08-02 13:56:32 -04002236void Uniform1ui(GLint location, GLuint v0)
2237{
2238 Uniform1uiv(location, 1, &v0);
2239}
2240
2241void Uniform2ui(GLint location, GLuint v0, GLuint v1)
2242{
2243 GLuint xy[2] = { v0, v1 };
2244
2245 Uniform2uiv(location, 1, (GLuint*)&xy);
2246}
2247
2248void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
2249{
2250 GLuint xyz[3] = { v0, v1, v2 };
2251
2252 Uniform3uiv(location, 1, (GLuint*)&xyz);
2253}
2254
2255void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
2256{
2257 GLuint xyzw[4] = { v0, v1, v2, v3 };
2258
2259 Uniform4uiv(location, 1, (GLuint*)&xyzw);
2260}
2261
2262void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002263{
2264 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint *value = %p)",
2265 buffer, drawbuffer, value);
2266
Chris Forbes108f3e12018-08-30 19:41:59 -07002267 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002268
2269 if(context)
2270 {
2271 switch(buffer)
2272 {
2273 case GL_COLOR:
2274 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2275 {
2276 return error(GL_INVALID_VALUE);
2277 }
2278 else
2279 {
2280 context->clearColorBuffer(drawbuffer, value);
2281 }
2282 break;
2283 case GL_STENCIL:
2284 if(drawbuffer != 0)
2285 {
2286 return error(GL_INVALID_VALUE);
2287 }
2288 else
2289 {
2290 context->clearStencilBuffer(value[0]);
2291 }
2292 break;
2293 default:
2294 return error(GL_INVALID_ENUM);
2295 }
2296 }
2297}
2298
Nicolas Capens805d7612018-08-02 13:56:32 -04002299void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002300{
2301 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint *value = %p)",
2302 buffer, drawbuffer, value);
2303
Chris Forbes108f3e12018-08-30 19:41:59 -07002304 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002305
2306 if(context)
2307 {
2308 switch(buffer)
2309 {
2310 case GL_COLOR:
2311 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2312 {
2313 return error(GL_INVALID_VALUE);
2314 }
2315 else
2316 {
2317 context->clearColorBuffer(drawbuffer, value);
2318 }
2319 break;
2320 default:
2321 return error(GL_INVALID_ENUM);
2322 }
2323 }
2324}
2325
Nicolas Capens805d7612018-08-02 13:56:32 -04002326void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002327{
2328 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat *value = %p)",
2329 buffer, drawbuffer, value);
2330
Chris Forbes108f3e12018-08-30 19:41:59 -07002331 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002332
2333 if(context)
2334 {
2335 switch(buffer)
2336 {
2337 case GL_COLOR:
2338 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2339 {
2340 return error(GL_INVALID_VALUE);
2341 }
2342 else
2343 {
2344 context->clearColorBuffer(drawbuffer, value);
2345 }
2346 break;
2347 case GL_DEPTH:
2348 if(drawbuffer != 0)
2349 {
2350 return error(GL_INVALID_VALUE);
2351 }
2352 else
2353 {
2354 context->clearDepthBuffer(value[0]);
2355 }
2356 break;
2357 default:
2358 return error(GL_INVALID_ENUM);
2359 }
2360 }
2361}
2362
Nicolas Capens805d7612018-08-02 13:56:32 -04002363void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002364{
2365 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth = %f, GLint stencil = %d)",
2366 buffer, drawbuffer, depth, stencil);
2367
Chris Forbes108f3e12018-08-30 19:41:59 -07002368 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002369
2370 if(context)
2371 {
2372 switch(buffer)
2373 {
2374 case GL_DEPTH_STENCIL:
2375 if(drawbuffer != 0)
2376 {
2377 return error(GL_INVALID_VALUE);
2378 }
2379 else
2380 {
2381 context->clearDepthBuffer(depth);
2382 context->clearStencilBuffer(stencil);
2383 }
2384 break;
2385 default:
2386 return error(GL_INVALID_ENUM);
2387 }
2388 }
2389}
2390
Nicolas Capens805d7612018-08-02 13:56:32 -04002391const GLubyte *GetStringi(GLenum name, GLuint index)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002392{
2393 TRACE("(GLenum name = 0x%X, GLuint index = %d)", name, index);
2394
Chris Forbes108f3e12018-08-30 19:41:59 -07002395 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002396 if(context)
2397 {
2398 GLuint numExtensions;
2399 context->getExtensions(0, &numExtensions);
2400
2401 if(index >= numExtensions)
2402 {
2403 return error(GL_INVALID_VALUE, (GLubyte*)nullptr);
2404 }
2405
2406 switch(name)
2407 {
2408 case GL_EXTENSIONS:
2409 return context->getExtensions(index);
2410 default:
2411 return error(GL_INVALID_ENUM, (GLubyte*)nullptr);
2412 }
2413 }
2414
2415 return (GLubyte*)nullptr;
2416}
2417
Nicolas Capens805d7612018-08-02 13:56:32 -04002418void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002419{
2420 TRACE("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)",
2421 readTarget, writeTarget, readOffset, writeOffset, size);
2422
2423 if(readOffset < 0 || writeOffset < 0 || size < 0)
2424 {
2425 return error(GL_INVALID_VALUE);
2426 }
2427
Chris Forbes108f3e12018-08-30 19:41:59 -07002428 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002429
2430 if(context)
2431 {
2432 es2::Buffer *readBuffer = nullptr, *writeBuffer = nullptr;
2433 if(!context->getBuffer(readTarget, &readBuffer) || !context->getBuffer(writeTarget, &writeBuffer))
2434 {
2435 return error(GL_INVALID_ENUM);
2436 }
2437 if(!readBuffer || readBuffer->isMapped() || !writeBuffer || writeBuffer->isMapped())
2438 {
2439 return error(GL_INVALID_OPERATION);
2440 }
2441 if(readBuffer == writeBuffer)
2442 {
2443 // If same buffer, check for overlap
2444 if(((readOffset >= writeOffset) && (readOffset < (writeOffset + size))) ||
2445 ((writeOffset >= readOffset) && (writeOffset < (readOffset + size))))
2446 {
2447 return error(GL_INVALID_VALUE);
2448 }
2449 }
2450
2451 if((static_cast<size_t>(readOffset + size) > readBuffer->size()) ||
2452 (static_cast<size_t>(writeOffset + size) > writeBuffer->size()))
2453 {
2454 return error(GL_INVALID_VALUE);
2455 }
2456
2457 writeBuffer->bufferSubData(((char*)readBuffer->data()) + readOffset, size, writeOffset);
2458 }
2459}
2460
Nicolas Capens805d7612018-08-02 13:56:32 -04002461void GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002462{
2463 TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLuint *uniformIndices = %p)",
2464 program, uniformCount, uniformNames, uniformIndices);
2465
2466 if(uniformCount < 0)
2467 {
2468 return error(GL_INVALID_VALUE);
2469 }
2470
Chris Forbes108f3e12018-08-30 19:41:59 -07002471 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002472
2473 if(context)
2474 {
2475 es2::Program *programObject = context->getProgram(program);
2476
2477 if(!programObject)
2478 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002479 if(context->getShader(program))
2480 {
2481 return error(GL_INVALID_OPERATION);
2482 }
2483 else
2484 {
2485 return error(GL_INVALID_VALUE);
2486 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002487 }
2488
2489 if(!programObject->isLinked())
2490 {
2491 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2492 {
2493 uniformIndices[uniformId] = GL_INVALID_INDEX;
2494 }
2495 }
2496 else
2497 {
2498 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2499 {
2500 uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]);
2501 }
2502 }
2503 }
2504}
2505
Nicolas Capens805d7612018-08-02 13:56:32 -04002506void GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002507{
2508 TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLenum pname = 0x%X, GLuint *uniformIndices = %p)",
2509 program, uniformCount, uniformIndices, pname, uniformIndices);
2510
2511 switch(pname)
2512 {
2513 case GL_UNIFORM_TYPE:
2514 case GL_UNIFORM_SIZE:
2515 case GL_UNIFORM_NAME_LENGTH:
2516 case GL_UNIFORM_BLOCK_INDEX:
2517 case GL_UNIFORM_OFFSET:
2518 case GL_UNIFORM_ARRAY_STRIDE:
2519 case GL_UNIFORM_MATRIX_STRIDE:
2520 case GL_UNIFORM_IS_ROW_MAJOR:
2521 break;
2522 default:
2523 return error(GL_INVALID_ENUM);
2524 }
2525
2526 if(uniformCount < 0)
2527 {
2528 return error(GL_INVALID_VALUE);
2529 }
2530
Chris Forbes108f3e12018-08-30 19:41:59 -07002531 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002532
2533 if(context)
2534 {
2535 es2::Program *programObject = context->getProgram(program);
2536
2537 if(!programObject)
2538 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002539 if(context->getShader(program))
2540 {
2541 return error(GL_INVALID_OPERATION);
2542 }
2543 else
2544 {
2545 return error(GL_INVALID_VALUE);
2546 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002547 }
2548
2549 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2550 {
2551 const GLuint index = uniformIndices[uniformId];
2552
2553 if(index >= programObject->getActiveUniformCount())
2554 {
2555 return error(GL_INVALID_VALUE);
2556 }
2557 }
2558
2559 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2560 {
2561 const GLuint index = uniformIndices[uniformId];
2562 params[uniformId] = programObject->getActiveUniformi(index, pname);
2563 }
2564 }
2565}
2566
Nicolas Capens805d7612018-08-02 13:56:32 -04002567GLuint GetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002568{
2569 TRACE("(GLuint program = %d, const GLchar *uniformBlockName = %p)",
2570 program, uniformBlockName);
2571
Chris Forbes108f3e12018-08-30 19:41:59 -07002572 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002573
2574 if(context)
2575 {
2576 es2::Program *programObject = context->getProgram(program);
2577
2578 if(!programObject)
2579 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002580 if(context->getShader(program))
2581 {
2582 return error(GL_INVALID_OPERATION, GL_INVALID_INDEX);
2583 }
2584 else
2585 {
2586 return error(GL_INVALID_VALUE, GL_INVALID_INDEX);
2587 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002588 }
2589
2590 return programObject->getUniformBlockIndex(uniformBlockName);
2591 }
2592
2593 return GL_INVALID_INDEX;
2594}
2595
Nicolas Capens805d7612018-08-02 13:56:32 -04002596void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002597{
2598 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLenum pname = 0x%X, GLint *params = %p)",
2599 program, uniformBlockIndex, pname, params);
2600
Chris Forbes108f3e12018-08-30 19:41:59 -07002601 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002602
2603 if(context)
2604 {
2605 es2::Program *programObject = context->getProgram(program);
2606
2607 if(!programObject)
2608 {
2609 return error(GL_INVALID_OPERATION);
2610 }
2611
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04002612 if(uniformBlockIndex >= programObject->getActiveUniformBlockCount())
2613 {
2614 return error(GL_INVALID_VALUE);
2615 }
2616
Nicolas Capens0bac2852016-05-07 06:09:58 -04002617 switch(pname)
2618 {
2619 case GL_UNIFORM_BLOCK_BINDING:
2620 *params = static_cast<GLint>(programObject->getUniformBlockBinding(uniformBlockIndex));
2621 break;
2622 case GL_UNIFORM_BLOCK_DATA_SIZE:
2623 case GL_UNIFORM_BLOCK_NAME_LENGTH:
2624 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2625 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2626 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2627 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2628 programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
2629 break;
2630 default:
2631 return error(GL_INVALID_ENUM);
2632 }
2633 }
2634}
2635
Nicolas Capens805d7612018-08-02 13:56:32 -04002636void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002637{
2638 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLchar *uniformBlockName = %p)",
2639 program, uniformBlockIndex, bufSize, length, uniformBlockName);
2640
2641 if(bufSize < 0)
2642 {
2643 return error(GL_INVALID_VALUE);
2644 }
2645
Chris Forbes108f3e12018-08-30 19:41:59 -07002646 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002647
2648 if(context)
2649 {
2650 es2::Program *programObject = context->getProgram(program);
2651
2652 if(!programObject)
2653 {
2654 return error(GL_INVALID_OPERATION);
2655 }
2656
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04002657 if(uniformBlockIndex >= programObject->getActiveUniformBlockCount())
2658 {
2659 return error(GL_INVALID_VALUE);
2660 }
2661
Nicolas Capens0bac2852016-05-07 06:09:58 -04002662 programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
2663 }
2664}
2665
Nicolas Capens805d7612018-08-02 13:56:32 -04002666void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002667{
2668 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLuint uniformBlockBinding = %d)",
2669 program, uniformBlockIndex, uniformBlockBinding);
2670
2671 if(uniformBlockBinding >= MAX_UNIFORM_BUFFER_BINDINGS)
2672 {
2673 return error(GL_INVALID_VALUE);
2674 }
2675
Chris Forbes108f3e12018-08-30 19:41:59 -07002676 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002677
2678 if(context)
2679 {
2680 es2::Program *programObject = context->getProgram(program);
2681
2682 if(!programObject)
2683 {
2684 return error(GL_INVALID_VALUE);
2685 }
2686
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04002687 if(uniformBlockIndex >= programObject->getActiveUniformBlockCount())
2688 {
2689 return error(GL_INVALID_VALUE);
2690 }
2691
Nicolas Capens65dcbbd2016-08-12 16:59:04 -04002692 programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002693 }
2694}
2695
Nicolas Capens805d7612018-08-02 13:56:32 -04002696void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002697{
2698 TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
2699 mode, first, count, instanceCount);
2700
2701 switch(mode)
2702 {
2703 case GL_POINTS:
2704 case GL_LINES:
2705 case GL_LINE_LOOP:
2706 case GL_LINE_STRIP:
2707 case GL_TRIANGLES:
2708 case GL_TRIANGLE_FAN:
2709 case GL_TRIANGLE_STRIP:
2710 break;
2711 default:
2712 return error(GL_INVALID_ENUM);
2713 }
2714
2715 if(count < 0 || instanceCount < 0)
2716 {
2717 return error(GL_INVALID_VALUE);
2718 }
2719
Chris Forbes108f3e12018-08-30 19:41:59 -07002720 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002721
2722 if(context)
2723 {
2724 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
2725 if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
2726 {
2727 return error(GL_INVALID_OPERATION);
2728 }
2729
2730 context->drawArrays(mode, first, count, instanceCount);
2731 }
2732}
2733
Nicolas Capens805d7612018-08-02 13:56:32 -04002734void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002735{
2736 TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = %p, GLsizei instanceCount = %d)",
2737 mode, count, type, indices, instanceCount);
2738
2739 switch(mode)
2740 {
2741 case GL_POINTS:
2742 case GL_LINES:
2743 case GL_LINE_LOOP:
2744 case GL_LINE_STRIP:
2745 case GL_TRIANGLES:
2746 case GL_TRIANGLE_FAN:
2747 case GL_TRIANGLE_STRIP:
2748 break;
2749 default:
2750 return error(GL_INVALID_ENUM);
2751 }
2752
2753 switch(type)
2754 {
2755 case GL_UNSIGNED_BYTE:
2756 case GL_UNSIGNED_SHORT:
2757 case GL_UNSIGNED_INT:
2758 break;
2759 default:
2760 return error(GL_INVALID_ENUM);
2761 }
2762
2763 if(count < 0 || instanceCount < 0)
2764 {
2765 return error(GL_INVALID_VALUE);
2766 }
2767
Chris Forbes108f3e12018-08-30 19:41:59 -07002768 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002769
2770 if(context)
2771 {
2772 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
2773 if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
2774 {
2775 return error(GL_INVALID_OPERATION);
2776 }
2777
2778 context->drawElements(mode, 0, MAX_ELEMENT_INDEX, count, type, indices, instanceCount);
2779 }
2780}
2781
Nicolas Capens805d7612018-08-02 13:56:32 -04002782GLsync FenceSync(GLenum condition, GLbitfield flags)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002783{
2784 TRACE("(GLenum condition = 0x%X, GLbitfield flags = %X)", condition, flags);
2785
2786 switch(condition)
2787 {
2788 case GL_SYNC_GPU_COMMANDS_COMPLETE:
2789 break;
2790 default:
2791 return error(GL_INVALID_ENUM, nullptr);
2792 }
2793
2794 if(flags != 0)
2795 {
2796 return error(GL_INVALID_VALUE, nullptr);
2797 }
2798
Chris Forbes108f3e12018-08-30 19:41:59 -07002799 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002800
2801 if(context)
2802 {
2803 return context->createFenceSync(condition, flags);
2804 }
2805
2806 return nullptr;
2807}
2808
Nicolas Capens805d7612018-08-02 13:56:32 -04002809GLboolean IsSync(GLsync sync)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002810{
2811 TRACE("(GLsync sync = %p)", sync);
2812
Chris Forbes108f3e12018-08-30 19:41:59 -07002813 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002814
2815 if(context)
2816 {
2817 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2818
2819 if(fenceSyncObject)
2820 {
2821 return GL_TRUE;
2822 }
2823 }
2824
2825 return GL_FALSE;
2826}
2827
Nicolas Capens805d7612018-08-02 13:56:32 -04002828void DeleteSync(GLsync sync)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002829{
2830 TRACE("(GLsync sync = %p)", sync);
2831
Alexis Hetuadd96ad2017-11-14 17:22:46 -05002832 if(!sync)
2833 {
2834 return;
2835 }
2836
Chris Forbes108f3e12018-08-30 19:41:59 -07002837 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002838
2839 if(context)
2840 {
Alexis Hetuadd96ad2017-11-14 17:22:46 -05002841 if(!context->getFenceSync(sync))
2842 {
2843 return error(GL_INVALID_VALUE);
2844 }
2845
Nicolas Capens0bac2852016-05-07 06:09:58 -04002846 context->deleteFenceSync(sync);
2847 }
2848}
2849
Nicolas Capens805d7612018-08-02 13:56:32 -04002850GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002851{
2852 TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
2853
2854 if((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0)
2855 {
Alexis Hetu6e864492017-11-14 15:27:00 -05002856 return error(GL_INVALID_VALUE, GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002857 }
2858
Chris Forbes108f3e12018-08-30 19:41:59 -07002859 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002860
2861 if(context)
2862 {
2863 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2864
2865 if(fenceSyncObject)
2866 {
2867 return fenceSyncObject->clientWait(flags, timeout);
2868 }
2869 else
2870 {
2871 return error(GL_INVALID_VALUE, GL_FALSE);
2872 }
2873 }
2874
2875 return GL_FALSE;
2876}
2877
Nicolas Capens805d7612018-08-02 13:56:32 -04002878void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002879{
2880 TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
2881
2882 if(flags != 0)
2883 {
2884 return error(GL_INVALID_VALUE);
2885 }
2886
2887 if(timeout != GL_TIMEOUT_IGNORED)
2888 {
2889 return error(GL_INVALID_VALUE);
2890 }
2891
Chris Forbes108f3e12018-08-30 19:41:59 -07002892 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002893
2894 if(context)
2895 {
2896 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2897
2898 if(fenceSyncObject)
2899 {
2900 fenceSyncObject->serverWait(flags, timeout);
2901 }
2902 else
2903 {
2904 return error(GL_INVALID_VALUE);
2905 }
2906 }
2907}
2908
Nicolas Capens805d7612018-08-02 13:56:32 -04002909void GetInteger64v(GLenum pname, GLint64 *data)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002910{
2911 TRACE("(GLenum pname = 0x%X, GLint64 *data = %p)", pname, data);
2912
Chris Forbes108f3e12018-08-30 19:41:59 -07002913 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002914
2915 if(context)
2916 {
2917 if(!(context->getIntegerv(pname, data)))
2918 {
2919 GLenum nativeType;
2920 unsigned int numParams = 0;
2921 if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))
2922 return error(GL_INVALID_ENUM);
2923
2924 if(numParams == 0)
2925 return; // it is known that pname is valid, but there are no parameters to return
2926
2927 if(nativeType == GL_BOOL)
2928 {
2929 GLboolean *boolParams = nullptr;
2930 boolParams = new GLboolean[numParams];
2931
2932 context->getBooleanv(pname, boolParams);
2933
2934 for(unsigned int i = 0; i < numParams; ++i)
2935 {
2936 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
2937 }
2938
2939 delete[] boolParams;
2940 }
2941 else if(nativeType == GL_FLOAT)
2942 {
2943 GLfloat *floatParams = nullptr;
2944 floatParams = new GLfloat[numParams];
2945
2946 context->getFloatv(pname, floatParams);
2947
2948 for(unsigned int i = 0; i < numParams; ++i)
2949 {
2950 if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
2951 {
Alexis Hetu60e20282017-12-13 07:42:22 -05002952 data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002953 }
2954 else
2955 {
2956 data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
2957 }
2958 }
2959
2960 delete[] floatParams;
2961 }
2962 }
2963 }
2964}
2965
Nicolas Capens805d7612018-08-02 13:56:32 -04002966void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002967{
2968 TRACE("(GLsync sync = %p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei *length = %p, GLint *values = %p)",
2969 sync, pname, bufSize, length, values);
2970
2971 if(bufSize < 0)
2972 {
2973 return error(GL_INVALID_VALUE);
2974 }
2975
Chris Forbes108f3e12018-08-30 19:41:59 -07002976 auto context = es2::getContext();
Alexis Hetu0f7c7b82017-02-17 17:07:50 -05002977
2978 if(context)
2979 {
2980 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2981 if(!fenceSyncObject)
2982 {
2983 return error(GL_INVALID_VALUE);
2984 }
2985
2986 fenceSyncObject->getSynciv(pname, length, values);
2987 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002988}
2989
Nicolas Capens805d7612018-08-02 13:56:32 -04002990void GetInteger64i_v(GLenum target, GLuint index, GLint64 *data)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002991{
2992 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint64 *data = %p)", target, index, data);
2993
Chris Forbes108f3e12018-08-30 19:41:59 -07002994 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002995
2996 if(context)
2997 {
2998 if(!context->getTransformFeedbackiv(index, target, data) &&
2999 !context->getUniformBufferiv(index, target, data) &&
3000 !context->getIntegerv(target, data))
3001 {
3002 GLenum nativeType;
3003 unsigned int numParams = 0;
3004 if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
3005 return error(GL_INVALID_ENUM);
3006
3007 if(numParams == 0)
3008 return; // it is known that target is valid, but there are no parameters to return
3009
3010 if(nativeType == GL_BOOL)
3011 {
3012 GLboolean *boolParams = nullptr;
3013 boolParams = new GLboolean[numParams];
3014
3015 context->getBooleanv(target, boolParams);
3016
3017 for(unsigned int i = 0; i < numParams; ++i)
3018 {
3019 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
3020 }
3021
3022 delete[] boolParams;
3023 }
3024 else if(nativeType == GL_FLOAT)
3025 {
3026 GLfloat *floatParams = nullptr;
3027 floatParams = new GLfloat[numParams];
3028
3029 context->getFloatv(target, floatParams);
3030
3031 for(unsigned int i = 0; i < numParams; ++i)
3032 {
3033 if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
3034 {
Alexis Hetu60e20282017-12-13 07:42:22 -05003035 data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
Nicolas Capens0bac2852016-05-07 06:09:58 -04003036 }
3037 else
3038 {
3039 data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
3040 }
3041 }
3042
3043 delete[] floatParams;
3044 }
3045 }
3046 }
3047}
3048
Nicolas Capens805d7612018-08-02 13:56:32 -04003049void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003050{
3051 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64 *params = %p)", target, pname, params);
3052
Chris Forbes108f3e12018-08-30 19:41:59 -07003053 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003054
3055 if(context)
3056 {
3057 es2::Buffer *buffer = nullptr;
3058
3059 if(!context->getBuffer(target, &buffer))
3060 {
3061 return error(GL_INVALID_ENUM);
3062 }
3063
3064 if(!buffer)
3065 {
3066 // A null buffer means that "0" is bound to the requested buffer target
3067 return error(GL_INVALID_OPERATION);
3068 }
3069
3070 switch(pname)
3071 {
3072 case GL_BUFFER_USAGE:
3073 *params = buffer->usage();
3074 break;
3075 case GL_BUFFER_SIZE:
3076 *params = buffer->size();
3077 break;
3078 case GL_BUFFER_ACCESS_FLAGS:
3079 *params = buffer->access();
3080 break;
3081 case GL_BUFFER_MAPPED:
3082 *params = buffer->isMapped();
3083 break;
3084 case GL_BUFFER_MAP_LENGTH:
3085 *params = buffer->length();
3086 break;
3087 case GL_BUFFER_MAP_OFFSET:
3088 *params = buffer->offset();
3089 break;
3090 default:
3091 return error(GL_INVALID_ENUM);
3092 }
3093 }
3094}
3095
Nicolas Capens805d7612018-08-02 13:56:32 -04003096void GenSamplers(GLsizei count, GLuint *samplers)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003097{
3098 TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3099
3100 if(count < 0)
3101 {
3102 return error(GL_INVALID_VALUE);
3103 }
3104
Chris Forbes108f3e12018-08-30 19:41:59 -07003105 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003106
3107 if(context)
3108 {
3109 for(int i = 0; i < count; i++)
3110 {
3111 samplers[i] = context->createSampler();
3112 }
3113 }
3114}
3115
Nicolas Capens805d7612018-08-02 13:56:32 -04003116void DeleteSamplers(GLsizei count, const GLuint *samplers)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003117{
3118 TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3119
3120 if(count < 0)
3121 {
3122 return error(GL_INVALID_VALUE);
3123 }
3124
Chris Forbes108f3e12018-08-30 19:41:59 -07003125 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003126
3127 if(context)
3128 {
3129 for(int i = 0; i < count; i++)
3130 {
3131 context->deleteSampler(samplers[i]);
3132 }
3133 }
3134}
3135
Nicolas Capens805d7612018-08-02 13:56:32 -04003136GLboolean IsSampler(GLuint sampler)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003137{
3138 TRACE("(GLuint sampler = %d)", sampler);
3139
3140 if(sampler == 0)
3141 {
3142 return GL_FALSE;
3143 }
3144
Chris Forbes108f3e12018-08-30 19:41:59 -07003145 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003146
3147 if(context)
3148 {
3149 if(context->isSampler(sampler))
3150 {
3151 return GL_TRUE;
3152 }
3153 }
3154
3155 return GL_FALSE;
3156}
3157
Nicolas Capens805d7612018-08-02 13:56:32 -04003158void BindSampler(GLuint unit, GLuint sampler)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003159{
3160 TRACE("(GLuint unit = %d, GLuint sampler = %d)", unit, sampler);
3161
3162 if(unit >= es2::MAX_COMBINED_TEXTURE_IMAGE_UNITS)
3163 {
3164 return error(GL_INVALID_VALUE);
3165 }
3166
Chris Forbes108f3e12018-08-30 19:41:59 -07003167 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003168
3169 if(context)
3170 {
3171 if(sampler != 0 && !context->isSampler(sampler))
3172 {
3173 return error(GL_INVALID_OPERATION);
3174 }
3175
3176 context->bindSampler(unit, sampler);
3177 }
3178}
3179
Nicolas Capens805d7612018-08-02 13:56:32 -04003180void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003181{
3182 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLint *param = %p)",
3183 sampler, pname, param);
3184
3185 if(!ValidateSamplerObjectParameter(pname))
3186 {
3187 return error(GL_INVALID_ENUM);
3188 }
3189
3190 if(!ValidateTexParamParameters(pname, *param))
3191 {
3192 return;
3193 }
3194
Chris Forbes108f3e12018-08-30 19:41:59 -07003195 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003196
3197 if(context)
3198 {
3199 if(!context->isSampler(sampler))
3200 {
3201 return error(GL_INVALID_OPERATION);
3202 }
3203
3204 context->samplerParameteri(sampler, pname, *param);
3205 }
3206}
3207
Nicolas Capens805d7612018-08-02 13:56:32 -04003208void SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003209{
Nicolas Capens805d7612018-08-02 13:56:32 -04003210 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint param = %d)",
Nicolas Capens0bac2852016-05-07 06:09:58 -04003211 sampler, pname, param);
3212
Nicolas Capens805d7612018-08-02 13:56:32 -04003213 SamplerParameteriv(sampler, pname, &param);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003214}
3215
Nicolas Capens805d7612018-08-02 13:56:32 -04003216void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003217{
3218 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLfloat *param = %p)",
3219 sampler, pname, param);
3220
3221 if(!ValidateSamplerObjectParameter(pname))
3222 {
3223 return error(GL_INVALID_ENUM);
3224 }
3225
Chris Forbes108f3e12018-08-30 19:41:59 -07003226 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003227
3228 if(context)
3229 {
3230 if(!context->isSampler(sampler))
3231 {
3232 return error(GL_INVALID_OPERATION);
3233 }
3234
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003235 if(ValidateTexParamParameters(pname, static_cast<GLint>(roundf(*param))))
3236 {
3237 context->samplerParameterf(sampler, pname, *param);
3238 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003239 }
3240}
3241
Nicolas Capens805d7612018-08-02 13:56:32 -04003242void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
3243{
3244 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat param = %f)",
3245 sampler, pname, param);
3246
3247 SamplerParameterfv(sampler, pname, &param);
3248}
3249
3250void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003251{
3252 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint *params = %p)",
3253 sampler, pname, params);
3254
3255 if(!ValidateSamplerObjectParameter(pname))
3256 {
3257 return error(GL_INVALID_ENUM);
3258 }
3259
Chris Forbes108f3e12018-08-30 19:41:59 -07003260 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003261
3262 if(context)
3263 {
3264 if(!context->isSampler(sampler))
3265 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003266 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003267 }
3268
3269 *params = context->getSamplerParameteri(sampler, pname);
3270 }
3271}
3272
Nicolas Capens805d7612018-08-02 13:56:32 -04003273void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003274{
3275 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat *params = %p)",
3276 sampler, pname, params);
3277
3278 if(!ValidateSamplerObjectParameter(pname))
3279 {
3280 return error(GL_INVALID_ENUM);
3281 }
3282
Chris Forbes108f3e12018-08-30 19:41:59 -07003283 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003284
3285 if(context)
3286 {
3287 if(!context->isSampler(sampler))
3288 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003289 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003290 }
3291
3292 *params = context->getSamplerParameterf(sampler, pname);
3293 }
3294}
3295
Nicolas Capens805d7612018-08-02 13:56:32 -04003296void VertexAttribDivisor(GLuint index, GLuint divisor)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003297{
3298 TRACE("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
3299
Chris Forbes108f3e12018-08-30 19:41:59 -07003300 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003301
3302 if(context)
3303 {
3304 if(index >= es2::MAX_VERTEX_ATTRIBS)
3305 {
3306 return error(GL_INVALID_VALUE);
3307 }
3308
3309 context->setVertexAttribDivisor(index, divisor);
3310 }
3311}
3312
Nicolas Capens805d7612018-08-02 13:56:32 -04003313void BindTransformFeedback(GLenum target, GLuint id)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003314{
3315 TRACE("(GLenum target = 0x%X, GLuint id = %d)", target, id);
3316
3317 if(target != GL_TRANSFORM_FEEDBACK)
3318 {
3319 return error(GL_INVALID_ENUM);
3320 }
3321
Chris Forbes108f3e12018-08-30 19:41:59 -07003322 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003323
3324 if(context)
3325 {
3326 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3327
3328 if(transformFeedbackObject && transformFeedbackObject->isActive() && !transformFeedbackObject->isPaused())
3329 {
3330 return error(GL_INVALID_OPERATION);
3331 }
3332
Alexis Hetu5bf97082017-11-14 11:06:03 -05003333 if(!context->isTransformFeedback(id))
3334 {
3335 return error(GL_INVALID_OPERATION);
3336 }
3337
Nicolas Capens0bac2852016-05-07 06:09:58 -04003338 context->bindTransformFeedback(id);
3339 }
3340}
3341
Nicolas Capens805d7612018-08-02 13:56:32 -04003342void DeleteTransformFeedbacks(GLsizei n, const GLuint *ids)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003343{
3344 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3345
3346 if(n < 0)
3347 {
3348 return error(GL_INVALID_VALUE);
3349 }
3350
Chris Forbes108f3e12018-08-30 19:41:59 -07003351 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003352
3353 if(context)
3354 {
3355 for(int i = 0; i < n; i++)
3356 {
Nicolas Capens56eacf02018-09-27 13:54:27 -04003357 if(ids[i] != 0) // Attempts to delete default transform feedback silently ignored.
Nicolas Capens0bac2852016-05-07 06:09:58 -04003358 {
Alexis Hetu5bf97082017-11-14 11:06:03 -05003359 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(ids[i]);
3360
3361 if(transformFeedbackObject && transformFeedbackObject->isActive())
3362 {
3363 return error(GL_INVALID_OPERATION);
3364 }
3365
Nicolas Capens0bac2852016-05-07 06:09:58 -04003366 context->deleteTransformFeedback(ids[i]);
3367 }
3368 }
3369 }
3370}
3371
Nicolas Capens805d7612018-08-02 13:56:32 -04003372void GenTransformFeedbacks(GLsizei n, GLuint *ids)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003373{
3374 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3375
3376 if(n < 0)
3377 {
3378 return error(GL_INVALID_VALUE);
3379 }
3380
Chris Forbes108f3e12018-08-30 19:41:59 -07003381 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003382
3383 if(context)
3384 {
3385 for(int i = 0; i < n; i++)
3386 {
3387 ids[i] = context->createTransformFeedback();
3388 }
3389 }
3390}
3391
Nicolas Capens805d7612018-08-02 13:56:32 -04003392GLboolean IsTransformFeedback(GLuint id)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003393{
3394 TRACE("(GLuint id = %d)", id);
3395
3396 if(id == 0)
3397 {
3398 return GL_FALSE;
3399 }
3400
Chris Forbes108f3e12018-08-30 19:41:59 -07003401 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003402
3403 if(context)
3404 {
3405 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(id);
3406
3407 if(transformFeedbackObject)
3408 {
3409 return GL_TRUE;
3410 }
3411 }
3412
3413 return GL_FALSE;
3414}
3415
Nicolas Capens805d7612018-08-02 13:56:32 -04003416void PauseTransformFeedback(void)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003417{
3418 TRACE("()");
3419
Chris Forbes108f3e12018-08-30 19:41:59 -07003420 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003421
3422 if(context)
3423 {
3424 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3425
3426 if(transformFeedbackObject)
3427 {
3428 if(!transformFeedbackObject->isActive() || transformFeedbackObject->isPaused())
3429 {
3430 return error(GL_INVALID_OPERATION);
3431 }
3432 transformFeedbackObject->setPaused(true);
3433 }
3434 }
3435}
3436
Nicolas Capens805d7612018-08-02 13:56:32 -04003437void ResumeTransformFeedback(void)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003438{
3439 TRACE("()");
3440
Chris Forbes108f3e12018-08-30 19:41:59 -07003441 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003442
3443 if(context)
3444 {
3445 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3446
3447 if(transformFeedbackObject)
3448 {
3449 if(!transformFeedbackObject->isActive() || !transformFeedbackObject->isPaused())
3450 {
3451 return error(GL_INVALID_OPERATION);
3452 }
3453 transformFeedbackObject->setPaused(false);
3454 }
3455 }
3456}
3457
Nicolas Capens805d7612018-08-02 13:56:32 -04003458void GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003459{
3460 TRACE("(GLuint program = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLenum *binaryFormat = %p, void *binary = %p)",
3461 program, bufSize, length, binaryFormat, binary);
3462
3463 if(bufSize < 0)
3464 {
3465 return error(GL_INVALID_VALUE);
3466 }
3467
Chris Forbes108f3e12018-08-30 19:41:59 -07003468 auto context = es2::getContext();
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003469
3470 if(context)
3471 {
3472 es2::Program *programObject = context->getProgram(program);
3473
3474 if(!programObject || !programObject->isLinked())
3475 {
3476 return error(GL_INVALID_OPERATION);
3477 }
3478 }
3479
Alexis Hetu0e92cca2017-12-19 10:53:31 -05003480 // SwiftShader doesn't return a program binary and sets the program binay size to 0, so any attempt at getting one is invalid.
3481 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003482}
3483
Nicolas Capens805d7612018-08-02 13:56:32 -04003484void ProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003485{
3486 TRACE("(GLuint program = %d, GLenum binaryFormat = 0x%X, const void *binary = %p, GLsizei length = %d)",
3487 program, binaryFormat, binaryFormat, length);
3488
3489 if(length < 0)
3490 {
3491 return error(GL_INVALID_VALUE);
3492 }
3493
Chris Forbes108f3e12018-08-30 19:41:59 -07003494 auto context = es2::getContext();
Alexis Hetu0e92cca2017-12-19 10:53:31 -05003495
3496 if(context)
3497 {
3498 es2::Program *programObject = context->getProgram(program);
3499
3500 if(!programObject)
3501 {
3502 return error(GL_INVALID_OPERATION);
3503 }
3504 }
3505
3506 // Regardless of what the binaryFormat is, it is unrecognized by SwiftShader, since it supports no format.
3507 return error(GL_INVALID_ENUM);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003508}
3509
Nicolas Capens805d7612018-08-02 13:56:32 -04003510void ProgramParameteri(GLuint program, GLenum pname, GLint value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003511{
3512 TRACE("(GLuint program = %d, GLenum pname = 0x%X, GLint value = %d)",
3513 program, pname, value);
3514
Chris Forbes108f3e12018-08-30 19:41:59 -07003515 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003516
3517 if(context)
3518 {
3519 es2::Program *programObject = context->getProgram(program);
3520
3521 if(!programObject)
3522 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003523 return error(GL_INVALID_VALUE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003524 }
3525
3526 switch(pname)
3527 {
3528 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003529 if((value != GL_TRUE) && (value != GL_FALSE))
3530 {
3531 return error(GL_INVALID_VALUE);
3532 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003533 programObject->setBinaryRetrievable(value != GL_FALSE);
3534 break;
3535 default:
3536 return error(GL_INVALID_ENUM);
3537 }
3538 }
3539}
3540
Nicolas Capens805d7612018-08-02 13:56:32 -04003541void InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003542{
3543 TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
3544 target, numAttachments, attachments, x, y, width, height);
3545
Chris Forbes108f3e12018-08-30 19:41:59 -07003546 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003547
3548 if(context)
3549 {
3550 if(numAttachments < 0 || width < 0 || height < 0)
3551 {
3552 return error(GL_INVALID_VALUE);
3553 }
3554
3555 es2::Framebuffer *framebuffer = nullptr;
3556 switch(target)
3557 {
3558 case GL_DRAW_FRAMEBUFFER:
3559 case GL_FRAMEBUFFER:
3560 framebuffer = context->getDrawFramebuffer();
Nicolas Capens6c4564a2018-01-26 01:14:34 +00003561 break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04003562 case GL_READ_FRAMEBUFFER:
3563 framebuffer = context->getReadFramebuffer();
3564 break;
3565 default:
3566 return error(GL_INVALID_ENUM);
3567 }
3568
3569 if(framebuffer)
3570 {
3571 for(int i = 0; i < numAttachments; i++)
3572 {
3573 switch(attachments[i])
3574 {
3575 case GL_COLOR:
3576 case GL_DEPTH:
3577 case GL_STENCIL:
3578 if(!framebuffer->isDefaultFramebuffer())
3579 {
3580 return error(GL_INVALID_ENUM);
3581 }
3582 break;
3583 case GL_DEPTH_ATTACHMENT:
3584 case GL_STENCIL_ATTACHMENT:
3585 case GL_DEPTH_STENCIL_ATTACHMENT:
3586 break;
3587 default:
3588 if(attachments[i] >= GL_COLOR_ATTACHMENT0 &&
3589 attachments[i] <= GL_COLOR_ATTACHMENT31)
3590 {
3591 if(attachments[i] - GL_COLOR_ATTACHMENT0 >= MAX_DRAW_BUFFERS)
3592 {
3593 return error(GL_INVALID_OPERATION);
3594 }
3595 }
3596 else
3597 {
3598 return error(GL_INVALID_ENUM);
3599 }
3600 break;
3601 }
3602 }
3603 }
3604
3605 // UNIMPLEMENTED(); // It is valid for this function to be treated as a no-op
3606 }
3607}
3608
Nicolas Capens805d7612018-08-02 13:56:32 -04003609void InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
3610{
3611 TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p)",
3612 target, numAttachments, attachments);
3613
3614 InvalidateSubFramebuffer(target, numAttachments, attachments, 0, 0, std::numeric_limits<GLsizei>::max(), std::numeric_limits<GLsizei>::max());
3615}
3616
3617void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003618{
3619 TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
3620 target, levels, internalformat, width, height);
3621
Alexis Hetu0988fb82018-02-02 17:23:48 -05003622 if(width < 1 || height < 1 || levels < 1 || ((target == GL_TEXTURE_RECTANGLE_ARB) && (levels != 1)))
Nicolas Capens0bac2852016-05-07 06:09:58 -04003623 {
3624 return error(GL_INVALID_VALUE);
3625 }
3626
3627 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
3628 {
3629 return error(GL_INVALID_OPERATION);
3630 }
3631
Nicolas Capens83463112018-06-12 23:55:16 -04003632 bool isCompressed = IsCompressed(internalformat);
Alexis Hetu0988fb82018-02-02 17:23:48 -05003633 if(!IsSizedInternalFormat(internalformat) && !isCompressed)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003634 {
3635 return error(GL_INVALID_ENUM);
3636 }
3637
Chris Forbes108f3e12018-08-30 19:41:59 -07003638 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003639
3640 if(context)
3641 {
3642 switch(target)
3643 {
Alexis Hetu46768622018-01-16 22:09:28 -05003644 case GL_TEXTURE_RECTANGLE_ARB:
Alexis Hetu0988fb82018-02-02 17:23:48 -05003645 if(isCompressed) // Rectangle textures cannot be compressed
Nicolas Capens0bac2852016-05-07 06:09:58 -04003646 {
Alexis Hetu0988fb82018-02-02 17:23:48 -05003647 return error(GL_INVALID_ENUM);
3648 }
Nicolas Capens894858a2018-03-22 00:55:23 -04003649 // Fall through to GL_TEXTURE_2D case.
Alexis Hetu0988fb82018-02-02 17:23:48 -05003650 case GL_TEXTURE_2D:
3651 {
3652 if((width > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE) ||
3653 (height > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE))
3654 {
3655 return error(GL_INVALID_VALUE);
3656 }
3657
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003658 es2::Texture2D *texture = context->getTexture2D(target);
Nicolas Capens51814272018-10-15 13:01:22 -04003659 if(!texture || texture->name == 0 || texture->getImmutableFormat() != GL_FALSE)
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003660 {
3661 return error(GL_INVALID_OPERATION);
3662 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003663
Nicolas Capens648b5822018-01-18 00:04:26 -05003664 for(int level = 0; level < levels; level++)
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003665 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003666 texture->setImage(level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003667 width = std::max(1, (width / 2));
3668 height = std::max(1, (height / 2));
3669 }
3670 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003671 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003672 break;
3673 case GL_TEXTURE_CUBE_MAP:
Nicolas Capens0bac2852016-05-07 06:09:58 -04003674 {
Alexis Hetu0988fb82018-02-02 17:23:48 -05003675 if((width > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE) ||
3676 (height > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE))
3677 {
3678 return error(GL_INVALID_VALUE);
3679 }
3680
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003681 es2::TextureCubeMap *texture = context->getTextureCubeMap();
3682 if(!texture || texture->name == 0 || texture->getImmutableFormat())
Alexis Hetu46768622018-01-16 22:09:28 -05003683 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003684 return error(GL_INVALID_OPERATION);
Nicolas Capens648b5822018-01-18 00:04:26 -05003685 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003686
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003687 for(int level = 0; level < levels; level++)
3688 {
3689 for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
3690 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003691 texture->setImage(face, level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003692 }
3693 width = std::max(1, (width / 2));
3694 height = std::max(1, (height / 2));
3695 }
3696 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003697 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003698 break;
3699 default:
3700 return error(GL_INVALID_ENUM);
3701 }
3702 }
3703}
3704
Nicolas Capens805d7612018-08-02 13:56:32 -04003705void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003706{
3707 TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d)",
3708 target, levels, internalformat, width, height, depth);
3709
3710 if(width < 1 || height < 1 || depth < 1 || levels < 1)
3711 {
3712 return error(GL_INVALID_VALUE);
3713 }
3714
Nicolas Capens83463112018-06-12 23:55:16 -04003715 if(!IsSizedInternalFormat(internalformat) && !IsCompressed(internalformat))
Nicolas Capens0bac2852016-05-07 06:09:58 -04003716 {
3717 return error(GL_INVALID_ENUM);
3718 }
3719
Chris Forbes108f3e12018-08-30 19:41:59 -07003720 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003721
3722 if(context)
3723 {
3724 switch(target)
3725 {
3726 case GL_TEXTURE_3D:
Nicolas Capens0bac2852016-05-07 06:09:58 -04003727 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003728 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(std::max(width, height), depth)) + 1))
3729 {
3730 return error(GL_INVALID_OPERATION);
3731 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003732
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003733 es2::Texture3D *texture = context->getTexture3D();
Nicolas Capens51814272018-10-15 13:01:22 -04003734 if(!texture || texture->name == 0 || texture->getImmutableFormat() != GL_FALSE)
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003735 {
3736 return error(GL_INVALID_OPERATION);
3737 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003738
Nicolas Capens648b5822018-01-18 00:04:26 -05003739 for(int level = 0; level < levels; level++)
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003740 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003741 texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003742 width = std::max(1, (width / 2));
3743 height = std::max(1, (height / 2));
3744 depth = std::max(1, (depth / 2));
3745 }
3746 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003747 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003748 break;
3749 case GL_TEXTURE_2D_ARRAY:
Nicolas Capens0bac2852016-05-07 06:09:58 -04003750 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003751 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
Alexis Hetu46768622018-01-16 22:09:28 -05003752 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003753 return error(GL_INVALID_OPERATION);
Nicolas Capens648b5822018-01-18 00:04:26 -05003754 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003755
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003756 es2::Texture3D *texture = context->getTexture2DArray();
3757 if(!texture || texture->name == 0 || texture->getImmutableFormat())
3758 {
3759 return error(GL_INVALID_OPERATION);
3760 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003761
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003762 for(int level = 0; level < levels; level++)
3763 {
Nicolas Capens894858a2018-03-22 00:55:23 -04003764 texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
3765
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003766 width = std::max(1, (width / 2));
3767 height = std::max(1, (height / 2));
3768 }
3769 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003770 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003771 break;
3772 default:
3773 return error(GL_INVALID_ENUM);
3774 }
3775 }
3776}
3777
Nicolas Capens805d7612018-08-02 13:56:32 -04003778void GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003779{
3780 TRACE("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, GLint *params = %p)",
3781 target, internalformat, pname, bufSize, params);
3782
3783 if(bufSize < 0)
3784 {
3785 return error(GL_INVALID_VALUE);
3786 }
3787
3788 if(bufSize == 0)
3789 {
3790 return;
3791 }
3792
Nicolas Capens2acbd262018-01-17 13:39:58 -05003793 // OpenGL ES 3.0, section 4.4.4: "An internal format is color-renderable if it is one of the formats
3794 // from table 3.13 noted as color-renderable or if it is unsized format RGBA or RGB."
3795 // Since we only use sized formats internally, replace them here (assuming type = GL_UNSIGNED_BYTE).
3796 if(internalformat == GL_RGB) internalformat = GL_RGB8;
3797 if(internalformat == GL_RGBA) internalformat = GL_RGBA8;
3798
Nicolas Capens83463112018-06-12 23:55:16 -04003799 if(!IsColorRenderable(internalformat) &&
3800 !IsDepthRenderable(internalformat) &&
3801 !IsStencilRenderable(internalformat))
Nicolas Capens0bac2852016-05-07 06:09:58 -04003802 {
3803 return error(GL_INVALID_ENUM);
3804 }
3805
3806 switch(target)
3807 {
3808 case GL_RENDERBUFFER:
3809 break;
3810 default:
3811 return error(GL_INVALID_ENUM);
3812 }
3813
Nicolas Capens0bac2852016-05-07 06:09:58 -04003814 GLint numMultisampleCounts = NUM_MULTISAMPLE_COUNTS;
Nicolas Capens135e2402018-01-17 14:02:55 -05003815
3816 // Integer types have no multisampling
3817 GLenum type = GetColorComponentType(internalformat);
3818 if(type != GL_UNSIGNED_NORMALIZED && type != GL_FLOAT)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003819 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04003820 numMultisampleCounts = 0;
Nicolas Capens0bac2852016-05-07 06:09:58 -04003821 }
3822
3823 switch(pname)
3824 {
3825 case GL_NUM_SAMPLE_COUNTS:
3826 *params = numMultisampleCounts;
3827 break;
3828 case GL_SAMPLES:
3829 for(int i = 0; i < numMultisampleCounts && i < bufSize; i++)
3830 {
3831 params[i] = multisampleCount[i];
3832 }
3833 break;
3834 default:
3835 return error(GL_INVALID_ENUM);
3836 }
3837}
3838
3839}