blob: 2669739fdadef9b6afa5934681f4774fa44f131d [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 {
1297 case GL_COLOR_ATTACHMENT0:
1298 case GL_COLOR_ATTACHMENT1:
1299 case GL_COLOR_ATTACHMENT2:
1300 case GL_COLOR_ATTACHMENT3:
1301 case GL_COLOR_ATTACHMENT4:
1302 case GL_COLOR_ATTACHMENT5:
1303 case GL_COLOR_ATTACHMENT6:
1304 case GL_COLOR_ATTACHMENT7:
1305 case GL_COLOR_ATTACHMENT8:
1306 case GL_COLOR_ATTACHMENT9:
1307 case GL_COLOR_ATTACHMENT10:
1308 case GL_COLOR_ATTACHMENT11:
1309 case GL_COLOR_ATTACHMENT12:
1310 case GL_COLOR_ATTACHMENT13:
1311 case GL_COLOR_ATTACHMENT14:
1312 case GL_COLOR_ATTACHMENT15:
1313 case GL_COLOR_ATTACHMENT16:
1314 case GL_COLOR_ATTACHMENT17:
1315 case GL_COLOR_ATTACHMENT18:
1316 case GL_COLOR_ATTACHMENT19:
1317 case GL_COLOR_ATTACHMENT20:
1318 case GL_COLOR_ATTACHMENT21:
1319 case GL_COLOR_ATTACHMENT22:
1320 case GL_COLOR_ATTACHMENT23:
1321 case GL_COLOR_ATTACHMENT24:
1322 case GL_COLOR_ATTACHMENT25:
1323 case GL_COLOR_ATTACHMENT26:
1324 case GL_COLOR_ATTACHMENT27:
1325 case GL_COLOR_ATTACHMENT28:
1326 case GL_COLOR_ATTACHMENT29:
1327 case GL_COLOR_ATTACHMENT30:
1328 case GL_COLOR_ATTACHMENT31:
1329 framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0, level, layer);
1330 break;
1331 case GL_DEPTH_ATTACHMENT:
1332 framebuffer->setDepthbuffer(textarget, texture, level, layer);
1333 break;
1334 case GL_STENCIL_ATTACHMENT:
1335 framebuffer->setStencilbuffer(textarget, texture, level, layer);
1336 break;
1337 case GL_DEPTH_STENCIL_ATTACHMENT:
1338 framebuffer->setDepthbuffer(textarget, texture, level, layer);
1339 framebuffer->setStencilbuffer(textarget, texture, level, layer);
1340 break;
1341 default:
1342 return error(GL_INVALID_ENUM);
1343 }
1344 }
1345}
1346
Nicolas Capens805d7612018-08-02 13:56:32 -04001347void *MapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001348{
1349 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = %X)",
1350 target, offset, length, access);
1351
Alexis Hetu6e864492017-11-14 15:27:00 -05001352 if((offset < 0) || (length < 0))
1353 {
1354 return error(GL_INVALID_VALUE, nullptr);
1355 }
1356
1357 if(!(access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)))
1358 {
1359 // Must be able to read or write the buffer
1360 return error(GL_INVALID_OPERATION, nullptr);
1361 }
1362 else if((access & GL_MAP_READ_BIT) && (access & (GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT)))
1363 {
1364 // GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT and GL_MAP_UNSYNCHRONIZED_BIT can't be used with GL_MAP_READ_BIT
1365 return error(GL_INVALID_OPERATION, nullptr);
1366 }
1367 else if((!(access & GL_MAP_WRITE_BIT)) && (access & GL_MAP_FLUSH_EXPLICIT_BIT))
1368 {
1369 // GL_MAP_FLUSH_EXPLICIT_BIT can't be used without GL_MAP_WRITE_BIT
1370 return error(GL_INVALID_OPERATION, nullptr);
1371 }
1372
Chris Forbes108f3e12018-08-30 19:41:59 -07001373 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001374
1375 if(context)
1376 {
1377 es2::Buffer *buffer = nullptr;
1378 if(!context->getBuffer(target, &buffer))
1379 {
1380 return error(GL_INVALID_ENUM, nullptr);
1381 }
1382
1383 if(!buffer)
1384 {
1385 // A null buffer means that "0" is bound to the requested buffer target
1386 return error(GL_INVALID_OPERATION, nullptr);
1387 }
1388
Alexis Hetu1b4eb7f2017-11-14 13:24:37 -05001389 if(buffer->isMapped())
1390 {
1391 // It is an invalid operation to map an already mapped buffer
1392 return error(GL_INVALID_OPERATION, nullptr);
1393 }
1394
Nicolas Capens0bac2852016-05-07 06:09:58 -04001395 GLsizeiptr bufferSize = buffer->size();
Alexis Hetu6e864492017-11-14 15:27:00 -05001396 if((offset + length) > bufferSize)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001397 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001398 return error(GL_INVALID_VALUE, nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001399 }
1400
1401 if((access & ~(GL_MAP_READ_BIT |
1402 GL_MAP_WRITE_BIT |
1403 GL_MAP_INVALIDATE_RANGE_BIT |
1404 GL_MAP_INVALIDATE_BUFFER_BIT |
1405 GL_MAP_FLUSH_EXPLICIT_BIT |
1406 GL_MAP_UNSYNCHRONIZED_BIT)) != 0)
1407 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001408 return error(GL_INVALID_VALUE, nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001409 }
1410
1411 return buffer->mapRange(offset, length, access);
1412 }
1413
1414 return nullptr;
1415}
1416
Nicolas Capens805d7612018-08-02 13:56:32 -04001417void FlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001418{
1419 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)",
1420 target, offset, length);
1421
Alexis Hetu6e864492017-11-14 15:27:00 -05001422 if((offset < 0) || (length < 0))
1423 {
1424 return error(GL_INVALID_VALUE);
1425 }
1426
Chris Forbes108f3e12018-08-30 19:41:59 -07001427 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001428
1429 if(context)
1430 {
1431 es2::Buffer *buffer = nullptr;
1432 if(!context->getBuffer(target, &buffer))
1433 {
1434 return error(GL_INVALID_ENUM);
1435 }
1436
1437 if(!buffer)
1438 {
1439 // A null buffer means that "0" is bound to the requested buffer target
1440 return error(GL_INVALID_OPERATION);
1441 }
1442
Alexis Hetu6e864492017-11-14 15:27:00 -05001443 if(!buffer->isMapped())
Nicolas Capens0bac2852016-05-07 06:09:58 -04001444 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001445 // Buffer must be mapped
1446 return error(GL_INVALID_OPERATION);
1447 }
1448
1449 GLsizeiptr bufferSize = buffer->length();
1450 if((offset + length) > bufferSize)
1451 {
1452 return error(GL_INVALID_VALUE);
1453 }
1454
Alexis Hetua752b892017-11-22 14:00:37 -05001455 if(!(buffer->access() & GL_MAP_FLUSH_EXPLICIT_BIT))
Alexis Hetu6e864492017-11-14 15:27:00 -05001456 {
1457 // Flush must be explicitly allowed
1458 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001459 }
1460
1461 buffer->flushMappedRange(offset, length);
1462 }
1463}
1464
Nicolas Capens805d7612018-08-02 13:56:32 -04001465void BindVertexArray(GLuint array)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001466{
1467 TRACE("(GLuint array = %d)", array);
1468
Chris Forbes108f3e12018-08-30 19:41:59 -07001469 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001470
1471 if(context)
1472 {
1473 if(!context->isVertexArray(array))
1474 {
1475 return error(GL_INVALID_OPERATION);
1476 }
1477
1478 context->bindVertexArray(array);
1479 }
1480}
1481
Nicolas Capens805d7612018-08-02 13:56:32 -04001482void BindVertexArrayOES(GLuint array)
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001483{
Nicolas Capens805d7612018-08-02 13:56:32 -04001484 BindVertexArray(array);
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001485}
1486
Nicolas Capens805d7612018-08-02 13:56:32 -04001487void DeleteVertexArrays(GLsizei n, const GLuint *arrays)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001488{
1489 TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1490
1491 if(n < 0)
1492 {
1493 return error(GL_INVALID_VALUE);
1494 }
1495
Chris Forbes108f3e12018-08-30 19:41:59 -07001496 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001497
1498 if(context)
1499 {
1500 for(int i = 0; i < n; i++)
1501 {
Nicolas Capens56eacf02018-09-27 13:54:27 -04001502 if(arrays[i] != 0) // Attempts to delete default vertex array silently ignored.
1503 {
1504 context->deleteVertexArray(arrays[i]);
1505 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001506 }
1507 }
1508}
1509
Nicolas Capens805d7612018-08-02 13:56:32 -04001510void DeleteVertexArraysOES(GLsizei n, const GLuint *arrays)
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001511{
Nicolas Capens805d7612018-08-02 13:56:32 -04001512 DeleteVertexArrays(n, arrays);
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001513}
1514
Nicolas Capens805d7612018-08-02 13:56:32 -04001515void GenVertexArrays(GLsizei n, GLuint *arrays)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001516{
1517 TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1518
1519 if(n < 0)
1520 {
1521 return error(GL_INVALID_VALUE);
1522 }
1523
Chris Forbes108f3e12018-08-30 19:41:59 -07001524 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001525
1526 if(context)
1527 {
1528 for(int i = 0; i < n; i++)
1529 {
1530 arrays[i] = context->createVertexArray();
1531 }
1532 }
1533}
1534
Nicolas Capens805d7612018-08-02 13:56:32 -04001535void GenVertexArraysOES(GLsizei n, GLuint *arrays)
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001536{
Nicolas Capens805d7612018-08-02 13:56:32 -04001537 GenVertexArrays(n, arrays);
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001538}
1539
Nicolas Capens805d7612018-08-02 13:56:32 -04001540GLboolean IsVertexArray(GLuint array)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001541{
1542 TRACE("(GLuint array = %d)", array);
1543
1544 if(array == 0)
1545 {
1546 return GL_FALSE;
1547 }
1548
Chris Forbes108f3e12018-08-30 19:41:59 -07001549 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001550
1551 if(context)
1552 {
1553 es2::VertexArray *arrayObject = context->getVertexArray(array);
1554
1555 if(arrayObject)
1556 {
1557 return GL_TRUE;
1558 }
1559 }
1560
1561 return GL_FALSE;
1562}
1563
Nicolas Capens805d7612018-08-02 13:56:32 -04001564GLboolean IsVertexArrayOES(GLuint array)
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001565{
Nicolas Capens805d7612018-08-02 13:56:32 -04001566 return IsVertexArray(array);
Krzysztof Kosińskie4756742018-05-10 21:55:05 -07001567}
1568
Nicolas Capens805d7612018-08-02 13:56:32 -04001569void GetIntegeri_v(GLenum target, GLuint index, GLint *data)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001570{
1571 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint* data = %p)",
1572 target, index, data);
1573
Chris Forbes108f3e12018-08-30 19:41:59 -07001574 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001575
1576 if(context)
1577 {
1578 if(!context->getTransformFeedbackiv(index, target, data) &&
1579 !context->getUniformBufferiv(index, target, data) &&
1580 !context->getIntegerv(target, data))
1581 {
1582 GLenum nativeType;
1583 unsigned int numParams = 0;
1584 if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
1585 return error(GL_INVALID_ENUM);
1586
1587 if(numParams == 0)
1588 return; // it is known that target is valid, but there are no parameters to return
1589
1590 if(nativeType == GL_BOOL)
1591 {
1592 GLboolean *boolParams = nullptr;
1593 boolParams = new GLboolean[numParams];
1594
1595 context->getBooleanv(target, boolParams);
1596
1597 for(unsigned int i = 0; i < numParams; ++i)
1598 {
1599 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
1600 }
1601
1602 delete[] boolParams;
1603 }
1604 else if(nativeType == GL_FLOAT)
1605 {
1606 GLfloat *floatParams = nullptr;
1607 floatParams = new GLfloat[numParams];
1608
1609 context->getFloatv(target, floatParams);
1610
1611 for(unsigned int i = 0; i < numParams; ++i)
1612 {
1613 if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
1614 {
Alexis Hetu60e20282017-12-13 07:42:22 -05001615 data[i] = convert_float_fixed(floatParams[i]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001616 }
1617 else
1618 {
1619 data[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
1620 }
1621 }
1622
1623 delete[] floatParams;
1624 }
1625 }
1626 }
1627}
1628
Nicolas Capens805d7612018-08-02 13:56:32 -04001629void BeginTransformFeedback(GLenum primitiveMode)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001630{
1631 TRACE("(GLenum primitiveMode = 0x%X)", primitiveMode);
1632
1633 switch(primitiveMode)
1634 {
1635 case GL_POINTS:
1636 case GL_LINES:
1637 case GL_TRIANGLES:
1638 break;
1639 default:
1640 return error(GL_INVALID_ENUM);
1641 }
1642
Chris Forbes108f3e12018-08-30 19:41:59 -07001643 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001644
1645 if(context)
1646 {
1647 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1648
1649 if(transformFeedbackObject)
1650 {
1651 if(transformFeedbackObject->isActive())
1652 {
1653 return error(GL_INVALID_OPERATION);
1654 }
1655 transformFeedbackObject->begin(primitiveMode);
1656 }
1657 else
1658 {
1659 return error(GL_INVALID_OPERATION);
1660 }
1661 }
1662}
1663
Nicolas Capens805d7612018-08-02 13:56:32 -04001664void EndTransformFeedback(void)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001665{
1666 TRACE("()");
1667
Chris Forbes108f3e12018-08-30 19:41:59 -07001668 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001669
1670 if(context)
1671 {
1672 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1673
1674 if(transformFeedbackObject)
1675 {
1676 if(!transformFeedbackObject->isActive())
1677 {
1678 return error(GL_INVALID_OPERATION);
1679 }
1680 transformFeedbackObject->end();
1681 }
1682 else
1683 {
1684 return error(GL_INVALID_OPERATION);
1685 }
1686 }
1687}
1688
Nicolas Capens805d7612018-08-02 13:56:32 -04001689void BindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001690{
1691 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d, GLintptr offset = %d, GLsizeiptr size = %d)",
1692 target, index, buffer, offset, size);
1693
1694 if(buffer != 0 && size <= 0)
1695 {
1696 return error(GL_INVALID_VALUE);
1697 }
1698
Chris Forbes108f3e12018-08-30 19:41:59 -07001699 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001700
1701 if(context)
1702 {
1703 switch(target)
1704 {
1705 case GL_TRANSFORM_FEEDBACK_BUFFER:
1706 if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1707 {
1708 return error(GL_INVALID_VALUE);
1709 }
1710 if(size & 0x3 || offset & 0x3) // size and offset must be multiples of 4
1711 {
1712 return error(GL_INVALID_VALUE);
1713 }
1714 context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size);
1715 context->bindGenericTransformFeedbackBuffer(buffer);
1716 break;
1717 case GL_UNIFORM_BUFFER:
1718 if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
1719 {
1720 return error(GL_INVALID_VALUE);
1721 }
1722 if(offset % UNIFORM_BUFFER_OFFSET_ALIGNMENT != 0)
1723 {
1724 return error(GL_INVALID_VALUE);
1725 }
1726 context->bindIndexedUniformBuffer(buffer, index, offset, size);
1727 context->bindGenericUniformBuffer(buffer);
1728 break;
1729 default:
1730 return error(GL_INVALID_ENUM);
1731 }
1732 }
1733}
1734
Nicolas Capens805d7612018-08-02 13:56:32 -04001735void BindBufferBase(GLenum target, GLuint index, GLuint buffer)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001736{
1737 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d)",
1738 target, index, buffer);
1739
Chris Forbes108f3e12018-08-30 19:41:59 -07001740 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001741
1742 if(context)
1743 {
1744 switch(target)
1745 {
1746 case GL_TRANSFORM_FEEDBACK_BUFFER:
1747 if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1748 {
1749 return error(GL_INVALID_VALUE);
1750 }
1751 context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0);
1752 context->bindGenericTransformFeedbackBuffer(buffer);
1753 break;
1754 case GL_UNIFORM_BUFFER:
1755 if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
1756 {
1757 return error(GL_INVALID_VALUE);
1758 }
1759 context->bindIndexedUniformBuffer(buffer, index, 0, 0);
1760 context->bindGenericUniformBuffer(buffer);
1761 break;
1762 default:
1763 return error(GL_INVALID_ENUM);
1764 }
1765 }
1766}
1767
Nicolas Capens805d7612018-08-02 13:56:32 -04001768void TransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001769{
1770 TRACE("(GLuint program = %d, GLsizei count = %d, const GLchar *const*varyings = %p, GLenum bufferMode = 0x%X)",
1771 program, count, varyings, bufferMode);
1772
1773 switch(bufferMode)
1774 {
1775 case GL_SEPARATE_ATTRIBS:
1776 if(count > MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1777 {
1778 return error(GL_INVALID_VALUE);
1779 }
1780 case GL_INTERLEAVED_ATTRIBS:
1781 break;
1782 default:
1783 return error(GL_INVALID_ENUM);
1784 }
1785
Chris Forbes108f3e12018-08-30 19:41:59 -07001786 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001787
1788 if(context)
1789 {
1790 es2::Program *programObject = context->getProgram(program);
1791
1792 if(!programObject)
1793 {
1794 return error(GL_INVALID_VALUE);
1795 }
1796
1797 programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);
1798 }
1799}
1800
Nicolas Capens805d7612018-08-02 13:56:32 -04001801void GetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001802{
1803 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
1804 program, index, bufSize, length, size, type, name);
1805
1806 if(bufSize < 0)
1807 {
1808 return error(GL_INVALID_VALUE);
1809 }
1810
Chris Forbes108f3e12018-08-30 19:41:59 -07001811 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001812
1813 if(context)
1814 {
1815 es2::Program *programObject = context->getProgram(program);
1816
1817 if(!programObject)
1818 {
1819 return error(GL_INVALID_VALUE);
1820 }
1821
1822 if(index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount()))
1823 {
1824 return error(GL_INVALID_VALUE);
1825 }
1826
1827 programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name);
1828 }
1829}
1830
Nicolas Capens805d7612018-08-02 13:56:32 -04001831void VertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001832{
1833 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
1834 index, size, type, stride, pointer);
1835
1836 if(index >= es2::MAX_VERTEX_ATTRIBS)
1837 {
1838 return error(GL_INVALID_VALUE);
1839 }
1840
1841 if(size < 1 || size > 4 || stride < 0)
1842 {
1843 return error(GL_INVALID_VALUE);
1844 }
1845
1846 switch(type)
1847 {
1848 case GL_BYTE:
1849 case GL_UNSIGNED_BYTE:
1850 case GL_SHORT:
1851 case GL_UNSIGNED_SHORT:
1852 case GL_INT:
1853 case GL_UNSIGNED_INT:
1854 break;
1855 default:
1856 return error(GL_INVALID_ENUM);
1857 }
1858
Chris Forbes108f3e12018-08-30 19:41:59 -07001859 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001860
1861 if(context)
1862 {
Alexis Hetuc1ef1ad2017-11-15 10:50:10 -05001863 es2::VertexArray* vertexArray = context->getCurrentVertexArray();
1864 if((context->getArrayBufferName() == 0) && vertexArray && (vertexArray->name != 0) && pointer)
1865 {
1866 // GL_INVALID_OPERATION is generated if a non-zero vertex array object is bound, zero is bound
1867 // to the GL_ARRAY_BUFFER buffer object binding point and the pointer argument is not NULL.
1868 return error(GL_INVALID_OPERATION);
1869 }
1870
Alexis Hetu6f284032017-12-11 15:19:36 -05001871 context->setVertexAttribState(index, context->getArrayBuffer(), size, type, false, true, stride, pointer);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001872 }
1873}
1874
Nicolas Capens805d7612018-08-02 13:56:32 -04001875void GetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001876{
1877 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint *params = %p)",
1878 index, pname, params);
1879
Chris Forbes108f3e12018-08-30 19:41:59 -07001880 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001881
1882 if(context)
1883 {
1884 if(index >= es2::MAX_VERTEX_ATTRIBS)
1885 {
1886 return error(GL_INVALID_VALUE);
1887 }
1888
1889 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
1890
1891 switch(pname)
1892 {
1893 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1894 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
1895 break;
1896 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1897 *params = attribState.mSize;
1898 break;
1899 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1900 *params = attribState.mStride;
1901 break;
1902 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1903 *params = attribState.mType;
1904 break;
1905 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1906 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
1907 break;
1908 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1909 *params = attribState.mBoundBuffer.name();
1910 break;
1911 case GL_CURRENT_VERTEX_ATTRIB:
1912 {
1913 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
1914 for(int i = 0; i < 4; ++i)
1915 {
1916 params[i] = attrib.getCurrentValueI(i);
1917 }
1918 }
1919 break;
1920 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Alexis Hetu6f284032017-12-11 15:19:36 -05001921 *params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001922 break;
1923 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1924 *params = attribState.mDivisor;
1925 break;
1926 default: return error(GL_INVALID_ENUM);
1927 }
1928 }
1929}
1930
Nicolas Capens805d7612018-08-02 13:56:32 -04001931void GetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001932{
1933 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLuint *params = %p)",
1934 index, pname, params);
1935
Chris Forbes108f3e12018-08-30 19:41:59 -07001936 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001937
1938 if(context)
1939 {
1940 if(index >= es2::MAX_VERTEX_ATTRIBS)
1941 {
1942 return error(GL_INVALID_VALUE);
1943 }
1944
1945 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
1946
1947 switch(pname)
1948 {
1949 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
1950 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
1951 break;
1952 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
1953 *params = attribState.mSize;
1954 break;
1955 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
1956 *params = attribState.mStride;
1957 break;
1958 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
1959 *params = attribState.mType;
1960 break;
1961 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
1962 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
1963 break;
1964 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
1965 *params = attribState.mBoundBuffer.name();
1966 break;
1967 case GL_CURRENT_VERTEX_ATTRIB:
1968 {
1969 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
1970 for(int i = 0; i < 4; ++i)
1971 {
1972 params[i] = attrib.getCurrentValueUI(i);
1973 }
1974 }
1975 break;
1976 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
Alexis Hetu6f284032017-12-11 15:19:36 -05001977 *params = (attribState.mPureInteger ? GL_TRUE : GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001978 break;
1979 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
1980 *params = attribState.mDivisor;
1981 break;
1982 default: return error(GL_INVALID_ENUM);
1983 }
1984 }
1985}
1986
Nicolas Capens805d7612018-08-02 13:56:32 -04001987void VertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001988{
1989 TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
1990 index, x, y, z, w);
1991
1992 if(index >= es2::MAX_VERTEX_ATTRIBS)
1993 {
1994 return error(GL_INVALID_VALUE);
1995 }
1996
Chris Forbes108f3e12018-08-30 19:41:59 -07001997 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04001998
1999 if(context)
2000 {
2001 GLint vals[4] = { x, y, z, w };
2002 context->setVertexAttrib(index, vals);
2003 }
2004}
2005
Nicolas Capens805d7612018-08-02 13:56:32 -04002006void VertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002007{
2008 TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
2009 index, x, y, z, w);
2010
2011 if(index >= es2::MAX_VERTEX_ATTRIBS)
2012 {
2013 return error(GL_INVALID_VALUE);
2014 }
2015
Chris Forbes108f3e12018-08-30 19:41:59 -07002016 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002017
2018 if(context)
2019 {
2020 GLuint vals[4] = { x, y, z, w };
2021 context->setVertexAttrib(index, vals);
2022 }
2023}
2024
Nicolas Capens805d7612018-08-02 13:56:32 -04002025void VertexAttribI4iv(GLuint index, const GLint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002026{
2027 TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2028
2029 if(index >= es2::MAX_VERTEX_ATTRIBS)
2030 {
2031 return error(GL_INVALID_VALUE);
2032 }
2033
Chris Forbes108f3e12018-08-30 19:41:59 -07002034 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002035
2036 if(context)
2037 {
2038 context->setVertexAttrib(index, v);
2039 }
2040}
2041
Nicolas Capens805d7612018-08-02 13:56:32 -04002042void VertexAttribI4uiv(GLuint index, const GLuint *v)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002043{
2044 TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2045
2046 if(index >= es2::MAX_VERTEX_ATTRIBS)
2047 {
2048 return error(GL_INVALID_VALUE);
2049 }
2050
Chris Forbes108f3e12018-08-30 19:41:59 -07002051 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002052
2053 if(context)
2054 {
2055 context->setVertexAttrib(index, v);
2056 }
2057}
2058
Nicolas Capens805d7612018-08-02 13:56:32 -04002059void GetUniformuiv(GLuint program, GLint location, GLuint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002060{
2061 TRACE("(GLuint program = %d, GLint location = %d, GLuint *params = %p)",
2062 program, location, params);
2063
Chris Forbes108f3e12018-08-30 19:41:59 -07002064 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002065
2066 if(context)
2067 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04002068 es2::Program *programObject = context->getProgram(program);
2069
Alexis Hetu48280a42017-11-30 15:04:39 -05002070 if(!programObject)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002071 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002072 if(context->getShader(program))
2073 {
2074 return error(GL_INVALID_OPERATION);
2075 }
2076 else
2077 {
2078 return error(GL_INVALID_VALUE);
2079 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002080 }
2081
Alexis Hetu48280a42017-11-30 15:04:39 -05002082 if(!programObject->isLinked())
Nicolas Capens0bac2852016-05-07 06:09:58 -04002083 {
2084 return error(GL_INVALID_OPERATION);
2085 }
2086
2087 if(!programObject->getUniformuiv(location, nullptr, params))
2088 {
2089 return error(GL_INVALID_OPERATION);
2090 }
2091 }
2092}
2093
Nicolas Capens805d7612018-08-02 13:56:32 -04002094GLint GetFragDataLocation(GLuint program, const GLchar *name)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002095{
2096 TRACE("(GLuint program = %d, const GLchar *name = %p)", program, name);
2097
Chris Forbes108f3e12018-08-30 19:41:59 -07002098 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002099
Nicolas Capens0bac2852016-05-07 06:09:58 -04002100 if(context)
2101 {
2102 es2::Program *programObject = context->getProgram(program);
2103
2104 if(!programObject)
2105 {
2106 if(context->getShader(program))
2107 {
2108 return error(GL_INVALID_OPERATION, -1);
2109 }
2110 else
2111 {
2112 return error(GL_INVALID_VALUE, -1);
2113 }
2114 }
2115
2116 if(!programObject->isLinked())
2117 {
2118 return error(GL_INVALID_OPERATION, -1);
2119 }
Alexis Hetub3f5ed72017-08-16 16:37:19 -04002120
2121 return programObject->getFragDataLocation(name);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002122 }
2123
Nicolas Capens0bac2852016-05-07 06:09:58 -04002124 return -1;
2125}
2126
Nicolas Capens805d7612018-08-02 13:56:32 -04002127void Uniform1uiv(GLint location, GLsizei count, const GLuint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002128{
2129 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2130 location, count, value);
2131
2132 if(count < 0)
2133 {
2134 return error(GL_INVALID_VALUE);
2135 }
2136
Chris Forbes108f3e12018-08-30 19:41:59 -07002137 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002138
2139 if(context)
2140 {
2141 es2::Program *program = context->getCurrentProgram();
2142
2143 if(!program)
2144 {
2145 return error(GL_INVALID_OPERATION);
2146 }
2147
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002148 if(location == -1)
2149 {
2150 return;
2151 }
2152
Nicolas Capens0bac2852016-05-07 06:09:58 -04002153 if(!program->setUniform1uiv(location, count, value))
2154 {
2155 return error(GL_INVALID_OPERATION);
2156 }
2157 }
2158}
2159
Nicolas Capens805d7612018-08-02 13:56:32 -04002160void Uniform2uiv(GLint location, GLsizei count, const GLuint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002161{
2162 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2163 location, count, value);
2164
2165 if(count < 0)
2166 {
2167 return error(GL_INVALID_VALUE);
2168 }
2169
Chris Forbes108f3e12018-08-30 19:41:59 -07002170 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002171
2172 if(context)
2173 {
2174 es2::Program *program = context->getCurrentProgram();
2175
2176 if(!program)
2177 {
2178 return error(GL_INVALID_OPERATION);
2179 }
2180
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002181 if(location == -1)
2182 {
2183 return;
2184 }
2185
Nicolas Capens0bac2852016-05-07 06:09:58 -04002186 if(!program->setUniform2uiv(location, count, value))
2187 {
2188 return error(GL_INVALID_OPERATION);
2189 }
2190 }
2191}
2192
Nicolas Capens805d7612018-08-02 13:56:32 -04002193void Uniform3uiv(GLint location, GLsizei count, const GLuint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002194{
2195 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2196 location, count, value);
2197
2198 if(count < 0)
2199 {
2200 return error(GL_INVALID_VALUE);
2201 }
2202
Chris Forbes108f3e12018-08-30 19:41:59 -07002203 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002204
2205 if(context)
2206 {
2207 es2::Program *program = context->getCurrentProgram();
2208
2209 if(!program)
2210 {
2211 return error(GL_INVALID_OPERATION);
2212 }
2213
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002214 if(location == -1)
2215 {
2216 return;
2217 }
2218
Nicolas Capens0bac2852016-05-07 06:09:58 -04002219 if(!program->setUniform3uiv(location, count, value))
2220 {
2221 return error(GL_INVALID_OPERATION);
2222 }
2223 }
2224}
2225
Nicolas Capens805d7612018-08-02 13:56:32 -04002226void Uniform4uiv(GLint location, GLsizei count, const GLuint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002227{
2228 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2229 location, count, value);
2230
2231 if(count < 0)
2232 {
2233 return error(GL_INVALID_VALUE);
2234 }
2235
Chris Forbes108f3e12018-08-30 19:41:59 -07002236 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002237
2238 if(context)
2239 {
2240 es2::Program *program = context->getCurrentProgram();
2241
2242 if(!program)
2243 {
2244 return error(GL_INVALID_OPERATION);
2245 }
2246
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002247 if(location == -1)
2248 {
2249 return;
2250 }
2251
Nicolas Capens0bac2852016-05-07 06:09:58 -04002252 if(!program->setUniform4uiv(location, count, value))
2253 {
2254 return error(GL_INVALID_OPERATION);
2255 }
2256 }
2257}
2258
Nicolas Capens805d7612018-08-02 13:56:32 -04002259void Uniform1ui(GLint location, GLuint v0)
2260{
2261 Uniform1uiv(location, 1, &v0);
2262}
2263
2264void Uniform2ui(GLint location, GLuint v0, GLuint v1)
2265{
2266 GLuint xy[2] = { v0, v1 };
2267
2268 Uniform2uiv(location, 1, (GLuint*)&xy);
2269}
2270
2271void Uniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
2272{
2273 GLuint xyz[3] = { v0, v1, v2 };
2274
2275 Uniform3uiv(location, 1, (GLuint*)&xyz);
2276}
2277
2278void Uniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
2279{
2280 GLuint xyzw[4] = { v0, v1, v2, v3 };
2281
2282 Uniform4uiv(location, 1, (GLuint*)&xyzw);
2283}
2284
2285void ClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002286{
2287 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint *value = %p)",
2288 buffer, drawbuffer, value);
2289
Chris Forbes108f3e12018-08-30 19:41:59 -07002290 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002291
2292 if(context)
2293 {
2294 switch(buffer)
2295 {
2296 case GL_COLOR:
2297 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2298 {
2299 return error(GL_INVALID_VALUE);
2300 }
2301 else
2302 {
2303 context->clearColorBuffer(drawbuffer, value);
2304 }
2305 break;
2306 case GL_STENCIL:
2307 if(drawbuffer != 0)
2308 {
2309 return error(GL_INVALID_VALUE);
2310 }
2311 else
2312 {
2313 context->clearStencilBuffer(value[0]);
2314 }
2315 break;
2316 default:
2317 return error(GL_INVALID_ENUM);
2318 }
2319 }
2320}
2321
Nicolas Capens805d7612018-08-02 13:56:32 -04002322void ClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002323{
2324 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint *value = %p)",
2325 buffer, drawbuffer, value);
2326
Chris Forbes108f3e12018-08-30 19:41:59 -07002327 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002328
2329 if(context)
2330 {
2331 switch(buffer)
2332 {
2333 case GL_COLOR:
2334 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2335 {
2336 return error(GL_INVALID_VALUE);
2337 }
2338 else
2339 {
2340 context->clearColorBuffer(drawbuffer, value);
2341 }
2342 break;
2343 default:
2344 return error(GL_INVALID_ENUM);
2345 }
2346 }
2347}
2348
Nicolas Capens805d7612018-08-02 13:56:32 -04002349void ClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002350{
2351 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat *value = %p)",
2352 buffer, drawbuffer, value);
2353
Chris Forbes108f3e12018-08-30 19:41:59 -07002354 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002355
2356 if(context)
2357 {
2358 switch(buffer)
2359 {
2360 case GL_COLOR:
2361 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2362 {
2363 return error(GL_INVALID_VALUE);
2364 }
2365 else
2366 {
2367 context->clearColorBuffer(drawbuffer, value);
2368 }
2369 break;
2370 case GL_DEPTH:
2371 if(drawbuffer != 0)
2372 {
2373 return error(GL_INVALID_VALUE);
2374 }
2375 else
2376 {
2377 context->clearDepthBuffer(value[0]);
2378 }
2379 break;
2380 default:
2381 return error(GL_INVALID_ENUM);
2382 }
2383 }
2384}
2385
Nicolas Capens805d7612018-08-02 13:56:32 -04002386void ClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002387{
2388 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth = %f, GLint stencil = %d)",
2389 buffer, drawbuffer, depth, stencil);
2390
Chris Forbes108f3e12018-08-30 19:41:59 -07002391 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002392
2393 if(context)
2394 {
2395 switch(buffer)
2396 {
2397 case GL_DEPTH_STENCIL:
2398 if(drawbuffer != 0)
2399 {
2400 return error(GL_INVALID_VALUE);
2401 }
2402 else
2403 {
2404 context->clearDepthBuffer(depth);
2405 context->clearStencilBuffer(stencil);
2406 }
2407 break;
2408 default:
2409 return error(GL_INVALID_ENUM);
2410 }
2411 }
2412}
2413
Nicolas Capens805d7612018-08-02 13:56:32 -04002414const GLubyte *GetStringi(GLenum name, GLuint index)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002415{
2416 TRACE("(GLenum name = 0x%X, GLuint index = %d)", name, index);
2417
Chris Forbes108f3e12018-08-30 19:41:59 -07002418 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002419 if(context)
2420 {
2421 GLuint numExtensions;
2422 context->getExtensions(0, &numExtensions);
2423
2424 if(index >= numExtensions)
2425 {
2426 return error(GL_INVALID_VALUE, (GLubyte*)nullptr);
2427 }
2428
2429 switch(name)
2430 {
2431 case GL_EXTENSIONS:
2432 return context->getExtensions(index);
2433 default:
2434 return error(GL_INVALID_ENUM, (GLubyte*)nullptr);
2435 }
2436 }
2437
2438 return (GLubyte*)nullptr;
2439}
2440
Nicolas Capens805d7612018-08-02 13:56:32 -04002441void CopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002442{
2443 TRACE("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)",
2444 readTarget, writeTarget, readOffset, writeOffset, size);
2445
2446 if(readOffset < 0 || writeOffset < 0 || size < 0)
2447 {
2448 return error(GL_INVALID_VALUE);
2449 }
2450
Chris Forbes108f3e12018-08-30 19:41:59 -07002451 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002452
2453 if(context)
2454 {
2455 es2::Buffer *readBuffer = nullptr, *writeBuffer = nullptr;
2456 if(!context->getBuffer(readTarget, &readBuffer) || !context->getBuffer(writeTarget, &writeBuffer))
2457 {
2458 return error(GL_INVALID_ENUM);
2459 }
2460 if(!readBuffer || readBuffer->isMapped() || !writeBuffer || writeBuffer->isMapped())
2461 {
2462 return error(GL_INVALID_OPERATION);
2463 }
2464 if(readBuffer == writeBuffer)
2465 {
2466 // If same buffer, check for overlap
2467 if(((readOffset >= writeOffset) && (readOffset < (writeOffset + size))) ||
2468 ((writeOffset >= readOffset) && (writeOffset < (readOffset + size))))
2469 {
2470 return error(GL_INVALID_VALUE);
2471 }
2472 }
2473
2474 if((static_cast<size_t>(readOffset + size) > readBuffer->size()) ||
2475 (static_cast<size_t>(writeOffset + size) > writeBuffer->size()))
2476 {
2477 return error(GL_INVALID_VALUE);
2478 }
2479
2480 writeBuffer->bufferSubData(((char*)readBuffer->data()) + readOffset, size, writeOffset);
2481 }
2482}
2483
Nicolas Capens805d7612018-08-02 13:56:32 -04002484void GetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002485{
2486 TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLuint *uniformIndices = %p)",
2487 program, uniformCount, uniformNames, uniformIndices);
2488
2489 if(uniformCount < 0)
2490 {
2491 return error(GL_INVALID_VALUE);
2492 }
2493
Chris Forbes108f3e12018-08-30 19:41:59 -07002494 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002495
2496 if(context)
2497 {
2498 es2::Program *programObject = context->getProgram(program);
2499
2500 if(!programObject)
2501 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002502 if(context->getShader(program))
2503 {
2504 return error(GL_INVALID_OPERATION);
2505 }
2506 else
2507 {
2508 return error(GL_INVALID_VALUE);
2509 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002510 }
2511
2512 if(!programObject->isLinked())
2513 {
2514 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2515 {
2516 uniformIndices[uniformId] = GL_INVALID_INDEX;
2517 }
2518 }
2519 else
2520 {
2521 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2522 {
2523 uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]);
2524 }
2525 }
2526 }
2527}
2528
Nicolas Capens805d7612018-08-02 13:56:32 -04002529void GetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002530{
2531 TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLenum pname = 0x%X, GLuint *uniformIndices = %p)",
2532 program, uniformCount, uniformIndices, pname, uniformIndices);
2533
2534 switch(pname)
2535 {
2536 case GL_UNIFORM_TYPE:
2537 case GL_UNIFORM_SIZE:
2538 case GL_UNIFORM_NAME_LENGTH:
2539 case GL_UNIFORM_BLOCK_INDEX:
2540 case GL_UNIFORM_OFFSET:
2541 case GL_UNIFORM_ARRAY_STRIDE:
2542 case GL_UNIFORM_MATRIX_STRIDE:
2543 case GL_UNIFORM_IS_ROW_MAJOR:
2544 break;
2545 default:
2546 return error(GL_INVALID_ENUM);
2547 }
2548
2549 if(uniformCount < 0)
2550 {
2551 return error(GL_INVALID_VALUE);
2552 }
2553
Chris Forbes108f3e12018-08-30 19:41:59 -07002554 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002555
2556 if(context)
2557 {
2558 es2::Program *programObject = context->getProgram(program);
2559
2560 if(!programObject)
2561 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002562 if(context->getShader(program))
2563 {
2564 return error(GL_INVALID_OPERATION);
2565 }
2566 else
2567 {
2568 return error(GL_INVALID_VALUE);
2569 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002570 }
2571
2572 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2573 {
2574 const GLuint index = uniformIndices[uniformId];
2575
2576 if(index >= programObject->getActiveUniformCount())
2577 {
2578 return error(GL_INVALID_VALUE);
2579 }
2580 }
2581
2582 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2583 {
2584 const GLuint index = uniformIndices[uniformId];
2585 params[uniformId] = programObject->getActiveUniformi(index, pname);
2586 }
2587 }
2588}
2589
Nicolas Capens805d7612018-08-02 13:56:32 -04002590GLuint GetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002591{
2592 TRACE("(GLuint program = %d, const GLchar *uniformBlockName = %p)",
2593 program, uniformBlockName);
2594
Chris Forbes108f3e12018-08-30 19:41:59 -07002595 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002596
2597 if(context)
2598 {
2599 es2::Program *programObject = context->getProgram(program);
2600
2601 if(!programObject)
2602 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002603 if(context->getShader(program))
2604 {
2605 return error(GL_INVALID_OPERATION, GL_INVALID_INDEX);
2606 }
2607 else
2608 {
2609 return error(GL_INVALID_VALUE, GL_INVALID_INDEX);
2610 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002611 }
2612
2613 return programObject->getUniformBlockIndex(uniformBlockName);
2614 }
2615
2616 return GL_INVALID_INDEX;
2617}
2618
Nicolas Capens805d7612018-08-02 13:56:32 -04002619void GetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002620{
2621 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLenum pname = 0x%X, GLint *params = %p)",
2622 program, uniformBlockIndex, pname, params);
2623
Chris Forbes108f3e12018-08-30 19:41:59 -07002624 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002625
2626 if(context)
2627 {
2628 es2::Program *programObject = context->getProgram(program);
2629
2630 if(!programObject)
2631 {
2632 return error(GL_INVALID_OPERATION);
2633 }
2634
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04002635 if(uniformBlockIndex >= programObject->getActiveUniformBlockCount())
2636 {
2637 return error(GL_INVALID_VALUE);
2638 }
2639
Nicolas Capens0bac2852016-05-07 06:09:58 -04002640 switch(pname)
2641 {
2642 case GL_UNIFORM_BLOCK_BINDING:
2643 *params = static_cast<GLint>(programObject->getUniformBlockBinding(uniformBlockIndex));
2644 break;
2645 case GL_UNIFORM_BLOCK_DATA_SIZE:
2646 case GL_UNIFORM_BLOCK_NAME_LENGTH:
2647 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2648 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2649 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2650 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2651 programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
2652 break;
2653 default:
2654 return error(GL_INVALID_ENUM);
2655 }
2656 }
2657}
2658
Nicolas Capens805d7612018-08-02 13:56:32 -04002659void GetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002660{
2661 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLchar *uniformBlockName = %p)",
2662 program, uniformBlockIndex, bufSize, length, uniformBlockName);
2663
2664 if(bufSize < 0)
2665 {
2666 return error(GL_INVALID_VALUE);
2667 }
2668
Chris Forbes108f3e12018-08-30 19:41:59 -07002669 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002670
2671 if(context)
2672 {
2673 es2::Program *programObject = context->getProgram(program);
2674
2675 if(!programObject)
2676 {
2677 return error(GL_INVALID_OPERATION);
2678 }
2679
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04002680 if(uniformBlockIndex >= programObject->getActiveUniformBlockCount())
2681 {
2682 return error(GL_INVALID_VALUE);
2683 }
2684
Nicolas Capens0bac2852016-05-07 06:09:58 -04002685 programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
2686 }
2687}
2688
Nicolas Capens805d7612018-08-02 13:56:32 -04002689void UniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002690{
2691 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLuint uniformBlockBinding = %d)",
2692 program, uniformBlockIndex, uniformBlockBinding);
2693
2694 if(uniformBlockBinding >= MAX_UNIFORM_BUFFER_BINDINGS)
2695 {
2696 return error(GL_INVALID_VALUE);
2697 }
2698
Chris Forbes108f3e12018-08-30 19:41:59 -07002699 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002700
2701 if(context)
2702 {
2703 es2::Program *programObject = context->getProgram(program);
2704
2705 if(!programObject)
2706 {
2707 return error(GL_INVALID_VALUE);
2708 }
2709
Nicolas Capens7f1c3d02018-07-30 16:42:49 -04002710 if(uniformBlockIndex >= programObject->getActiveUniformBlockCount())
2711 {
2712 return error(GL_INVALID_VALUE);
2713 }
2714
Nicolas Capens65dcbbd2016-08-12 16:59:04 -04002715 programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002716 }
2717}
2718
Nicolas Capens805d7612018-08-02 13:56:32 -04002719void DrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002720{
2721 TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
2722 mode, first, count, instanceCount);
2723
2724 switch(mode)
2725 {
2726 case GL_POINTS:
2727 case GL_LINES:
2728 case GL_LINE_LOOP:
2729 case GL_LINE_STRIP:
2730 case GL_TRIANGLES:
2731 case GL_TRIANGLE_FAN:
2732 case GL_TRIANGLE_STRIP:
2733 break;
2734 default:
2735 return error(GL_INVALID_ENUM);
2736 }
2737
2738 if(count < 0 || instanceCount < 0)
2739 {
2740 return error(GL_INVALID_VALUE);
2741 }
2742
Chris Forbes108f3e12018-08-30 19:41:59 -07002743 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002744
2745 if(context)
2746 {
2747 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
2748 if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
2749 {
2750 return error(GL_INVALID_OPERATION);
2751 }
2752
2753 context->drawArrays(mode, first, count, instanceCount);
2754 }
2755}
2756
Nicolas Capens805d7612018-08-02 13:56:32 -04002757void DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002758{
2759 TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = %p, GLsizei instanceCount = %d)",
2760 mode, count, type, indices, instanceCount);
2761
2762 switch(mode)
2763 {
2764 case GL_POINTS:
2765 case GL_LINES:
2766 case GL_LINE_LOOP:
2767 case GL_LINE_STRIP:
2768 case GL_TRIANGLES:
2769 case GL_TRIANGLE_FAN:
2770 case GL_TRIANGLE_STRIP:
2771 break;
2772 default:
2773 return error(GL_INVALID_ENUM);
2774 }
2775
2776 switch(type)
2777 {
2778 case GL_UNSIGNED_BYTE:
2779 case GL_UNSIGNED_SHORT:
2780 case GL_UNSIGNED_INT:
2781 break;
2782 default:
2783 return error(GL_INVALID_ENUM);
2784 }
2785
2786 if(count < 0 || instanceCount < 0)
2787 {
2788 return error(GL_INVALID_VALUE);
2789 }
2790
Chris Forbes108f3e12018-08-30 19:41:59 -07002791 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002792
2793 if(context)
2794 {
2795 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
2796 if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
2797 {
2798 return error(GL_INVALID_OPERATION);
2799 }
2800
2801 context->drawElements(mode, 0, MAX_ELEMENT_INDEX, count, type, indices, instanceCount);
2802 }
2803}
2804
Nicolas Capens805d7612018-08-02 13:56:32 -04002805GLsync FenceSync(GLenum condition, GLbitfield flags)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002806{
2807 TRACE("(GLenum condition = 0x%X, GLbitfield flags = %X)", condition, flags);
2808
2809 switch(condition)
2810 {
2811 case GL_SYNC_GPU_COMMANDS_COMPLETE:
2812 break;
2813 default:
2814 return error(GL_INVALID_ENUM, nullptr);
2815 }
2816
2817 if(flags != 0)
2818 {
2819 return error(GL_INVALID_VALUE, nullptr);
2820 }
2821
Chris Forbes108f3e12018-08-30 19:41:59 -07002822 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002823
2824 if(context)
2825 {
2826 return context->createFenceSync(condition, flags);
2827 }
2828
2829 return nullptr;
2830}
2831
Nicolas Capens805d7612018-08-02 13:56:32 -04002832GLboolean IsSync(GLsync sync)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002833{
2834 TRACE("(GLsync sync = %p)", sync);
2835
Chris Forbes108f3e12018-08-30 19:41:59 -07002836 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002837
2838 if(context)
2839 {
2840 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2841
2842 if(fenceSyncObject)
2843 {
2844 return GL_TRUE;
2845 }
2846 }
2847
2848 return GL_FALSE;
2849}
2850
Nicolas Capens805d7612018-08-02 13:56:32 -04002851void DeleteSync(GLsync sync)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002852{
2853 TRACE("(GLsync sync = %p)", sync);
2854
Alexis Hetuadd96ad2017-11-14 17:22:46 -05002855 if(!sync)
2856 {
2857 return;
2858 }
2859
Chris Forbes108f3e12018-08-30 19:41:59 -07002860 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002861
2862 if(context)
2863 {
Alexis Hetuadd96ad2017-11-14 17:22:46 -05002864 if(!context->getFenceSync(sync))
2865 {
2866 return error(GL_INVALID_VALUE);
2867 }
2868
Nicolas Capens0bac2852016-05-07 06:09:58 -04002869 context->deleteFenceSync(sync);
2870 }
2871}
2872
Nicolas Capens805d7612018-08-02 13:56:32 -04002873GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002874{
2875 TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
2876
2877 if((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0)
2878 {
Alexis Hetu6e864492017-11-14 15:27:00 -05002879 return error(GL_INVALID_VALUE, GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002880 }
2881
Chris Forbes108f3e12018-08-30 19:41:59 -07002882 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002883
2884 if(context)
2885 {
2886 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2887
2888 if(fenceSyncObject)
2889 {
2890 return fenceSyncObject->clientWait(flags, timeout);
2891 }
2892 else
2893 {
2894 return error(GL_INVALID_VALUE, GL_FALSE);
2895 }
2896 }
2897
2898 return GL_FALSE;
2899}
2900
Nicolas Capens805d7612018-08-02 13:56:32 -04002901void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002902{
2903 TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
2904
2905 if(flags != 0)
2906 {
2907 return error(GL_INVALID_VALUE);
2908 }
2909
2910 if(timeout != GL_TIMEOUT_IGNORED)
2911 {
2912 return error(GL_INVALID_VALUE);
2913 }
2914
Chris Forbes108f3e12018-08-30 19:41:59 -07002915 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002916
2917 if(context)
2918 {
2919 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
2920
2921 if(fenceSyncObject)
2922 {
2923 fenceSyncObject->serverWait(flags, timeout);
2924 }
2925 else
2926 {
2927 return error(GL_INVALID_VALUE);
2928 }
2929 }
2930}
2931
Nicolas Capens805d7612018-08-02 13:56:32 -04002932void GetInteger64v(GLenum pname, GLint64 *data)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002933{
2934 TRACE("(GLenum pname = 0x%X, GLint64 *data = %p)", pname, data);
2935
Chris Forbes108f3e12018-08-30 19:41:59 -07002936 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04002937
2938 if(context)
2939 {
2940 if(!(context->getIntegerv(pname, data)))
2941 {
2942 GLenum nativeType;
2943 unsigned int numParams = 0;
2944 if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))
2945 return error(GL_INVALID_ENUM);
2946
2947 if(numParams == 0)
2948 return; // it is known that pname is valid, but there are no parameters to return
2949
2950 if(nativeType == GL_BOOL)
2951 {
2952 GLboolean *boolParams = nullptr;
2953 boolParams = new GLboolean[numParams];
2954
2955 context->getBooleanv(pname, boolParams);
2956
2957 for(unsigned int i = 0; i < numParams; ++i)
2958 {
2959 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
2960 }
2961
2962 delete[] boolParams;
2963 }
2964 else if(nativeType == GL_FLOAT)
2965 {
2966 GLfloat *floatParams = nullptr;
2967 floatParams = new GLfloat[numParams];
2968
2969 context->getFloatv(pname, floatParams);
2970
2971 for(unsigned int i = 0; i < numParams; ++i)
2972 {
2973 if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
2974 {
Alexis Hetu60e20282017-12-13 07:42:22 -05002975 data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
Nicolas Capens0bac2852016-05-07 06:09:58 -04002976 }
2977 else
2978 {
2979 data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
2980 }
2981 }
2982
2983 delete[] floatParams;
2984 }
2985 }
2986 }
2987}
2988
Nicolas Capens805d7612018-08-02 13:56:32 -04002989void GetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002990{
2991 TRACE("(GLsync sync = %p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei *length = %p, GLint *values = %p)",
2992 sync, pname, bufSize, length, values);
2993
2994 if(bufSize < 0)
2995 {
2996 return error(GL_INVALID_VALUE);
2997 }
2998
Chris Forbes108f3e12018-08-30 19:41:59 -07002999 auto context = es2::getContext();
Alexis Hetu0f7c7b82017-02-17 17:07:50 -05003000
3001 if(context)
3002 {
3003 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
3004 if(!fenceSyncObject)
3005 {
3006 return error(GL_INVALID_VALUE);
3007 }
3008
3009 fenceSyncObject->getSynciv(pname, length, values);
3010 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003011}
3012
Nicolas Capens805d7612018-08-02 13:56:32 -04003013void GetInteger64i_v(GLenum target, GLuint index, GLint64 *data)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003014{
3015 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint64 *data = %p)", target, index, data);
3016
Chris Forbes108f3e12018-08-30 19:41:59 -07003017 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003018
3019 if(context)
3020 {
3021 if(!context->getTransformFeedbackiv(index, target, data) &&
3022 !context->getUniformBufferiv(index, target, data) &&
3023 !context->getIntegerv(target, data))
3024 {
3025 GLenum nativeType;
3026 unsigned int numParams = 0;
3027 if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
3028 return error(GL_INVALID_ENUM);
3029
3030 if(numParams == 0)
3031 return; // it is known that target is valid, but there are no parameters to return
3032
3033 if(nativeType == GL_BOOL)
3034 {
3035 GLboolean *boolParams = nullptr;
3036 boolParams = new GLboolean[numParams];
3037
3038 context->getBooleanv(target, boolParams);
3039
3040 for(unsigned int i = 0; i < numParams; ++i)
3041 {
3042 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
3043 }
3044
3045 delete[] boolParams;
3046 }
3047 else if(nativeType == GL_FLOAT)
3048 {
3049 GLfloat *floatParams = nullptr;
3050 floatParams = new GLfloat[numParams];
3051
3052 context->getFloatv(target, floatParams);
3053
3054 for(unsigned int i = 0; i < numParams; ++i)
3055 {
3056 if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
3057 {
Alexis Hetu60e20282017-12-13 07:42:22 -05003058 data[i] = (GLint64)(convert_float_fixed(floatParams[i]));
Nicolas Capens0bac2852016-05-07 06:09:58 -04003059 }
3060 else
3061 {
3062 data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
3063 }
3064 }
3065
3066 delete[] floatParams;
3067 }
3068 }
3069 }
3070}
3071
Nicolas Capens805d7612018-08-02 13:56:32 -04003072void GetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003073{
3074 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64 *params = %p)", target, pname, params);
3075
Chris Forbes108f3e12018-08-30 19:41:59 -07003076 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003077
3078 if(context)
3079 {
3080 es2::Buffer *buffer = nullptr;
3081
3082 if(!context->getBuffer(target, &buffer))
3083 {
3084 return error(GL_INVALID_ENUM);
3085 }
3086
3087 if(!buffer)
3088 {
3089 // A null buffer means that "0" is bound to the requested buffer target
3090 return error(GL_INVALID_OPERATION);
3091 }
3092
3093 switch(pname)
3094 {
3095 case GL_BUFFER_USAGE:
3096 *params = buffer->usage();
3097 break;
3098 case GL_BUFFER_SIZE:
3099 *params = buffer->size();
3100 break;
3101 case GL_BUFFER_ACCESS_FLAGS:
3102 *params = buffer->access();
3103 break;
3104 case GL_BUFFER_MAPPED:
3105 *params = buffer->isMapped();
3106 break;
3107 case GL_BUFFER_MAP_LENGTH:
3108 *params = buffer->length();
3109 break;
3110 case GL_BUFFER_MAP_OFFSET:
3111 *params = buffer->offset();
3112 break;
3113 default:
3114 return error(GL_INVALID_ENUM);
3115 }
3116 }
3117}
3118
Nicolas Capens805d7612018-08-02 13:56:32 -04003119void GenSamplers(GLsizei count, GLuint *samplers)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003120{
3121 TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3122
3123 if(count < 0)
3124 {
3125 return error(GL_INVALID_VALUE);
3126 }
3127
Chris Forbes108f3e12018-08-30 19:41:59 -07003128 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003129
3130 if(context)
3131 {
3132 for(int i = 0; i < count; i++)
3133 {
3134 samplers[i] = context->createSampler();
3135 }
3136 }
3137}
3138
Nicolas Capens805d7612018-08-02 13:56:32 -04003139void DeleteSamplers(GLsizei count, const GLuint *samplers)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003140{
3141 TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3142
3143 if(count < 0)
3144 {
3145 return error(GL_INVALID_VALUE);
3146 }
3147
Chris Forbes108f3e12018-08-30 19:41:59 -07003148 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003149
3150 if(context)
3151 {
3152 for(int i = 0; i < count; i++)
3153 {
3154 context->deleteSampler(samplers[i]);
3155 }
3156 }
3157}
3158
Nicolas Capens805d7612018-08-02 13:56:32 -04003159GLboolean IsSampler(GLuint sampler)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003160{
3161 TRACE("(GLuint sampler = %d)", sampler);
3162
3163 if(sampler == 0)
3164 {
3165 return GL_FALSE;
3166 }
3167
Chris Forbes108f3e12018-08-30 19:41:59 -07003168 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003169
3170 if(context)
3171 {
3172 if(context->isSampler(sampler))
3173 {
3174 return GL_TRUE;
3175 }
3176 }
3177
3178 return GL_FALSE;
3179}
3180
Nicolas Capens805d7612018-08-02 13:56:32 -04003181void BindSampler(GLuint unit, GLuint sampler)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003182{
3183 TRACE("(GLuint unit = %d, GLuint sampler = %d)", unit, sampler);
3184
3185 if(unit >= es2::MAX_COMBINED_TEXTURE_IMAGE_UNITS)
3186 {
3187 return error(GL_INVALID_VALUE);
3188 }
3189
Chris Forbes108f3e12018-08-30 19:41:59 -07003190 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003191
3192 if(context)
3193 {
3194 if(sampler != 0 && !context->isSampler(sampler))
3195 {
3196 return error(GL_INVALID_OPERATION);
3197 }
3198
3199 context->bindSampler(unit, sampler);
3200 }
3201}
3202
Nicolas Capens805d7612018-08-02 13:56:32 -04003203void SamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003204{
3205 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLint *param = %p)",
3206 sampler, pname, param);
3207
3208 if(!ValidateSamplerObjectParameter(pname))
3209 {
3210 return error(GL_INVALID_ENUM);
3211 }
3212
3213 if(!ValidateTexParamParameters(pname, *param))
3214 {
3215 return;
3216 }
3217
Chris Forbes108f3e12018-08-30 19:41:59 -07003218 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003219
3220 if(context)
3221 {
3222 if(!context->isSampler(sampler))
3223 {
3224 return error(GL_INVALID_OPERATION);
3225 }
3226
3227 context->samplerParameteri(sampler, pname, *param);
3228 }
3229}
3230
Nicolas Capens805d7612018-08-02 13:56:32 -04003231void SamplerParameteri(GLuint sampler, GLenum pname, GLint param)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003232{
Nicolas Capens805d7612018-08-02 13:56:32 -04003233 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint param = %d)",
Nicolas Capens0bac2852016-05-07 06:09:58 -04003234 sampler, pname, param);
3235
Nicolas Capens805d7612018-08-02 13:56:32 -04003236 SamplerParameteriv(sampler, pname, &param);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003237}
3238
Nicolas Capens805d7612018-08-02 13:56:32 -04003239void SamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003240{
3241 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLfloat *param = %p)",
3242 sampler, pname, param);
3243
3244 if(!ValidateSamplerObjectParameter(pname))
3245 {
3246 return error(GL_INVALID_ENUM);
3247 }
3248
Chris Forbes108f3e12018-08-30 19:41:59 -07003249 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003250
3251 if(context)
3252 {
3253 if(!context->isSampler(sampler))
3254 {
3255 return error(GL_INVALID_OPERATION);
3256 }
3257
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003258 if(ValidateTexParamParameters(pname, static_cast<GLint>(roundf(*param))))
3259 {
3260 context->samplerParameterf(sampler, pname, *param);
3261 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003262 }
3263}
3264
Nicolas Capens805d7612018-08-02 13:56:32 -04003265void SamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
3266{
3267 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat param = %f)",
3268 sampler, pname, param);
3269
3270 SamplerParameterfv(sampler, pname, &param);
3271}
3272
3273void GetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003274{
3275 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint *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->getSamplerParameteri(sampler, pname);
3293 }
3294}
3295
Nicolas Capens805d7612018-08-02 13:56:32 -04003296void GetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003297{
3298 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat *params = %p)",
3299 sampler, pname, params);
3300
3301 if(!ValidateSamplerObjectParameter(pname))
3302 {
3303 return error(GL_INVALID_ENUM);
3304 }
3305
Chris Forbes108f3e12018-08-30 19:41:59 -07003306 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003307
3308 if(context)
3309 {
3310 if(!context->isSampler(sampler))
3311 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003312 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003313 }
3314
3315 *params = context->getSamplerParameterf(sampler, pname);
3316 }
3317}
3318
Nicolas Capens805d7612018-08-02 13:56:32 -04003319void VertexAttribDivisor(GLuint index, GLuint divisor)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003320{
3321 TRACE("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
3322
Chris Forbes108f3e12018-08-30 19:41:59 -07003323 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003324
3325 if(context)
3326 {
3327 if(index >= es2::MAX_VERTEX_ATTRIBS)
3328 {
3329 return error(GL_INVALID_VALUE);
3330 }
3331
3332 context->setVertexAttribDivisor(index, divisor);
3333 }
3334}
3335
Nicolas Capens805d7612018-08-02 13:56:32 -04003336void BindTransformFeedback(GLenum target, GLuint id)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003337{
3338 TRACE("(GLenum target = 0x%X, GLuint id = %d)", target, id);
3339
3340 if(target != GL_TRANSFORM_FEEDBACK)
3341 {
3342 return error(GL_INVALID_ENUM);
3343 }
3344
Chris Forbes108f3e12018-08-30 19:41:59 -07003345 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003346
3347 if(context)
3348 {
3349 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3350
3351 if(transformFeedbackObject && transformFeedbackObject->isActive() && !transformFeedbackObject->isPaused())
3352 {
3353 return error(GL_INVALID_OPERATION);
3354 }
3355
Alexis Hetu5bf97082017-11-14 11:06:03 -05003356 if(!context->isTransformFeedback(id))
3357 {
3358 return error(GL_INVALID_OPERATION);
3359 }
3360
Nicolas Capens0bac2852016-05-07 06:09:58 -04003361 context->bindTransformFeedback(id);
3362 }
3363}
3364
Nicolas Capens805d7612018-08-02 13:56:32 -04003365void DeleteTransformFeedbacks(GLsizei n, const GLuint *ids)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003366{
3367 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3368
3369 if(n < 0)
3370 {
3371 return error(GL_INVALID_VALUE);
3372 }
3373
Chris Forbes108f3e12018-08-30 19:41:59 -07003374 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003375
3376 if(context)
3377 {
3378 for(int i = 0; i < n; i++)
3379 {
Nicolas Capens56eacf02018-09-27 13:54:27 -04003380 if(ids[i] != 0) // Attempts to delete default transform feedback silently ignored.
Nicolas Capens0bac2852016-05-07 06:09:58 -04003381 {
Alexis Hetu5bf97082017-11-14 11:06:03 -05003382 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(ids[i]);
3383
3384 if(transformFeedbackObject && transformFeedbackObject->isActive())
3385 {
3386 return error(GL_INVALID_OPERATION);
3387 }
3388
Nicolas Capens0bac2852016-05-07 06:09:58 -04003389 context->deleteTransformFeedback(ids[i]);
3390 }
3391 }
3392 }
3393}
3394
Nicolas Capens805d7612018-08-02 13:56:32 -04003395void GenTransformFeedbacks(GLsizei n, GLuint *ids)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003396{
3397 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3398
3399 if(n < 0)
3400 {
3401 return error(GL_INVALID_VALUE);
3402 }
3403
Chris Forbes108f3e12018-08-30 19:41:59 -07003404 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003405
3406 if(context)
3407 {
3408 for(int i = 0; i < n; i++)
3409 {
3410 ids[i] = context->createTransformFeedback();
3411 }
3412 }
3413}
3414
Nicolas Capens805d7612018-08-02 13:56:32 -04003415GLboolean IsTransformFeedback(GLuint id)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003416{
3417 TRACE("(GLuint id = %d)", id);
3418
3419 if(id == 0)
3420 {
3421 return GL_FALSE;
3422 }
3423
Chris Forbes108f3e12018-08-30 19:41:59 -07003424 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003425
3426 if(context)
3427 {
3428 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(id);
3429
3430 if(transformFeedbackObject)
3431 {
3432 return GL_TRUE;
3433 }
3434 }
3435
3436 return GL_FALSE;
3437}
3438
Nicolas Capens805d7612018-08-02 13:56:32 -04003439void PauseTransformFeedback(void)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003440{
3441 TRACE("()");
3442
Chris Forbes108f3e12018-08-30 19:41:59 -07003443 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003444
3445 if(context)
3446 {
3447 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3448
3449 if(transformFeedbackObject)
3450 {
3451 if(!transformFeedbackObject->isActive() || transformFeedbackObject->isPaused())
3452 {
3453 return error(GL_INVALID_OPERATION);
3454 }
3455 transformFeedbackObject->setPaused(true);
3456 }
3457 }
3458}
3459
Nicolas Capens805d7612018-08-02 13:56:32 -04003460void ResumeTransformFeedback(void)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003461{
3462 TRACE("()");
3463
Chris Forbes108f3e12018-08-30 19:41:59 -07003464 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003465
3466 if(context)
3467 {
3468 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3469
3470 if(transformFeedbackObject)
3471 {
3472 if(!transformFeedbackObject->isActive() || !transformFeedbackObject->isPaused())
3473 {
3474 return error(GL_INVALID_OPERATION);
3475 }
3476 transformFeedbackObject->setPaused(false);
3477 }
3478 }
3479}
3480
Nicolas Capens805d7612018-08-02 13:56:32 -04003481void GetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003482{
3483 TRACE("(GLuint program = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLenum *binaryFormat = %p, void *binary = %p)",
3484 program, bufSize, length, binaryFormat, binary);
3485
3486 if(bufSize < 0)
3487 {
3488 return error(GL_INVALID_VALUE);
3489 }
3490
Chris Forbes108f3e12018-08-30 19:41:59 -07003491 auto context = es2::getContext();
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003492
3493 if(context)
3494 {
3495 es2::Program *programObject = context->getProgram(program);
3496
3497 if(!programObject || !programObject->isLinked())
3498 {
3499 return error(GL_INVALID_OPERATION);
3500 }
3501 }
3502
Alexis Hetu0e92cca2017-12-19 10:53:31 -05003503 // SwiftShader doesn't return a program binary and sets the program binay size to 0, so any attempt at getting one is invalid.
3504 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003505}
3506
Nicolas Capens805d7612018-08-02 13:56:32 -04003507void ProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003508{
3509 TRACE("(GLuint program = %d, GLenum binaryFormat = 0x%X, const void *binary = %p, GLsizei length = %d)",
3510 program, binaryFormat, binaryFormat, length);
3511
3512 if(length < 0)
3513 {
3514 return error(GL_INVALID_VALUE);
3515 }
3516
Chris Forbes108f3e12018-08-30 19:41:59 -07003517 auto context = es2::getContext();
Alexis Hetu0e92cca2017-12-19 10:53:31 -05003518
3519 if(context)
3520 {
3521 es2::Program *programObject = context->getProgram(program);
3522
3523 if(!programObject)
3524 {
3525 return error(GL_INVALID_OPERATION);
3526 }
3527 }
3528
3529 // Regardless of what the binaryFormat is, it is unrecognized by SwiftShader, since it supports no format.
3530 return error(GL_INVALID_ENUM);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003531}
3532
Nicolas Capens805d7612018-08-02 13:56:32 -04003533void ProgramParameteri(GLuint program, GLenum pname, GLint value)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003534{
3535 TRACE("(GLuint program = %d, GLenum pname = 0x%X, GLint value = %d)",
3536 program, pname, value);
3537
Chris Forbes108f3e12018-08-30 19:41:59 -07003538 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003539
3540 if(context)
3541 {
3542 es2::Program *programObject = context->getProgram(program);
3543
3544 if(!programObject)
3545 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003546 return error(GL_INVALID_VALUE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003547 }
3548
3549 switch(pname)
3550 {
3551 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003552 if((value != GL_TRUE) && (value != GL_FALSE))
3553 {
3554 return error(GL_INVALID_VALUE);
3555 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003556 programObject->setBinaryRetrievable(value != GL_FALSE);
3557 break;
3558 default:
3559 return error(GL_INVALID_ENUM);
3560 }
3561 }
3562}
3563
Nicolas Capens805d7612018-08-02 13:56:32 -04003564void InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003565{
3566 TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
3567 target, numAttachments, attachments, x, y, width, height);
3568
Chris Forbes108f3e12018-08-30 19:41:59 -07003569 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003570
3571 if(context)
3572 {
3573 if(numAttachments < 0 || width < 0 || height < 0)
3574 {
3575 return error(GL_INVALID_VALUE);
3576 }
3577
3578 es2::Framebuffer *framebuffer = nullptr;
3579 switch(target)
3580 {
3581 case GL_DRAW_FRAMEBUFFER:
3582 case GL_FRAMEBUFFER:
3583 framebuffer = context->getDrawFramebuffer();
Nicolas Capens6c4564a2018-01-26 01:14:34 +00003584 break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04003585 case GL_READ_FRAMEBUFFER:
3586 framebuffer = context->getReadFramebuffer();
3587 break;
3588 default:
3589 return error(GL_INVALID_ENUM);
3590 }
3591
3592 if(framebuffer)
3593 {
3594 for(int i = 0; i < numAttachments; i++)
3595 {
3596 switch(attachments[i])
3597 {
3598 case GL_COLOR:
3599 case GL_DEPTH:
3600 case GL_STENCIL:
3601 if(!framebuffer->isDefaultFramebuffer())
3602 {
3603 return error(GL_INVALID_ENUM);
3604 }
3605 break;
3606 case GL_DEPTH_ATTACHMENT:
3607 case GL_STENCIL_ATTACHMENT:
3608 case GL_DEPTH_STENCIL_ATTACHMENT:
3609 break;
3610 default:
3611 if(attachments[i] >= GL_COLOR_ATTACHMENT0 &&
3612 attachments[i] <= GL_COLOR_ATTACHMENT31)
3613 {
3614 if(attachments[i] - GL_COLOR_ATTACHMENT0 >= MAX_DRAW_BUFFERS)
3615 {
3616 return error(GL_INVALID_OPERATION);
3617 }
3618 }
3619 else
3620 {
3621 return error(GL_INVALID_ENUM);
3622 }
3623 break;
3624 }
3625 }
3626 }
3627
3628 // UNIMPLEMENTED(); // It is valid for this function to be treated as a no-op
3629 }
3630}
3631
Nicolas Capens805d7612018-08-02 13:56:32 -04003632void InvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
3633{
3634 TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p)",
3635 target, numAttachments, attachments);
3636
3637 InvalidateSubFramebuffer(target, numAttachments, attachments, 0, 0, std::numeric_limits<GLsizei>::max(), std::numeric_limits<GLsizei>::max());
3638}
3639
3640void TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003641{
3642 TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
3643 target, levels, internalformat, width, height);
3644
Alexis Hetu0988fb82018-02-02 17:23:48 -05003645 if(width < 1 || height < 1 || levels < 1 || ((target == GL_TEXTURE_RECTANGLE_ARB) && (levels != 1)))
Nicolas Capens0bac2852016-05-07 06:09:58 -04003646 {
3647 return error(GL_INVALID_VALUE);
3648 }
3649
3650 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
3651 {
3652 return error(GL_INVALID_OPERATION);
3653 }
3654
Nicolas Capens83463112018-06-12 23:55:16 -04003655 bool isCompressed = IsCompressed(internalformat);
Alexis Hetu0988fb82018-02-02 17:23:48 -05003656 if(!IsSizedInternalFormat(internalformat) && !isCompressed)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003657 {
3658 return error(GL_INVALID_ENUM);
3659 }
3660
Chris Forbes108f3e12018-08-30 19:41:59 -07003661 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003662
3663 if(context)
3664 {
3665 switch(target)
3666 {
Alexis Hetu46768622018-01-16 22:09:28 -05003667 case GL_TEXTURE_RECTANGLE_ARB:
Alexis Hetu0988fb82018-02-02 17:23:48 -05003668 if(isCompressed) // Rectangle textures cannot be compressed
Nicolas Capens0bac2852016-05-07 06:09:58 -04003669 {
Alexis Hetu0988fb82018-02-02 17:23:48 -05003670 return error(GL_INVALID_ENUM);
3671 }
Nicolas Capens894858a2018-03-22 00:55:23 -04003672 // Fall through to GL_TEXTURE_2D case.
Alexis Hetu0988fb82018-02-02 17:23:48 -05003673 case GL_TEXTURE_2D:
3674 {
3675 if((width > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE) ||
3676 (height > es2::IMPLEMENTATION_MAX_TEXTURE_SIZE))
3677 {
3678 return error(GL_INVALID_VALUE);
3679 }
3680
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003681 es2::Texture2D *texture = context->getTexture2D(target);
Nicolas Capens51814272018-10-15 13:01:22 -04003682 if(!texture || texture->name == 0 || texture->getImmutableFormat() != GL_FALSE)
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003683 {
3684 return error(GL_INVALID_OPERATION);
3685 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003686
Nicolas Capens648b5822018-01-18 00:04:26 -05003687 for(int level = 0; level < levels; level++)
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003688 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003689 texture->setImage(level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003690 width = std::max(1, (width / 2));
3691 height = std::max(1, (height / 2));
3692 }
3693 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003694 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003695 break;
3696 case GL_TEXTURE_CUBE_MAP:
Nicolas Capens0bac2852016-05-07 06:09:58 -04003697 {
Alexis Hetu0988fb82018-02-02 17:23:48 -05003698 if((width > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE) ||
3699 (height > es2::IMPLEMENTATION_MAX_CUBE_MAP_TEXTURE_SIZE))
3700 {
3701 return error(GL_INVALID_VALUE);
3702 }
3703
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003704 es2::TextureCubeMap *texture = context->getTextureCubeMap();
3705 if(!texture || texture->name == 0 || texture->getImmutableFormat())
Alexis Hetu46768622018-01-16 22:09:28 -05003706 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003707 return error(GL_INVALID_OPERATION);
Nicolas Capens648b5822018-01-18 00:04:26 -05003708 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003709
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003710 for(int level = 0; level < levels; level++)
3711 {
3712 for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; face++)
3713 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003714 texture->setImage(face, level, width, height, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003715 }
3716 width = std::max(1, (width / 2));
3717 height = std::max(1, (height / 2));
3718 }
3719 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003720 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003721 break;
3722 default:
3723 return error(GL_INVALID_ENUM);
3724 }
3725 }
3726}
3727
Nicolas Capens805d7612018-08-02 13:56:32 -04003728void TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003729{
3730 TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d)",
3731 target, levels, internalformat, width, height, depth);
3732
3733 if(width < 1 || height < 1 || depth < 1 || levels < 1)
3734 {
3735 return error(GL_INVALID_VALUE);
3736 }
3737
Nicolas Capens83463112018-06-12 23:55:16 -04003738 if(!IsSizedInternalFormat(internalformat) && !IsCompressed(internalformat))
Nicolas Capens0bac2852016-05-07 06:09:58 -04003739 {
3740 return error(GL_INVALID_ENUM);
3741 }
3742
Chris Forbes108f3e12018-08-30 19:41:59 -07003743 auto context = es2::getContext();
Nicolas Capens0bac2852016-05-07 06:09:58 -04003744
3745 if(context)
3746 {
3747 switch(target)
3748 {
3749 case GL_TEXTURE_3D:
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(std::max(width, height), depth)) + 1))
3752 {
3753 return error(GL_INVALID_OPERATION);
3754 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003755
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003756 es2::Texture3D *texture = context->getTexture3D();
Nicolas Capens51814272018-10-15 13:01:22 -04003757 if(!texture || texture->name == 0 || texture->getImmutableFormat() != GL_FALSE)
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003758 {
3759 return error(GL_INVALID_OPERATION);
3760 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003761
Nicolas Capens648b5822018-01-18 00:04:26 -05003762 for(int level = 0; level < levels; level++)
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003763 {
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003764 texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003765 width = std::max(1, (width / 2));
3766 height = std::max(1, (height / 2));
3767 depth = std::max(1, (depth / 2));
3768 }
3769 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003770 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003771 break;
3772 case GL_TEXTURE_2D_ARRAY:
Nicolas Capens0bac2852016-05-07 06:09:58 -04003773 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003774 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
Alexis Hetu46768622018-01-16 22:09:28 -05003775 {
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003776 return error(GL_INVALID_OPERATION);
Nicolas Capens648b5822018-01-18 00:04:26 -05003777 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003778
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003779 es2::Texture3D *texture = context->getTexture2DArray();
3780 if(!texture || texture->name == 0 || texture->getImmutableFormat())
3781 {
3782 return error(GL_INVALID_OPERATION);
3783 }
Nicolas Capens3b4a25c2018-02-22 20:14:07 -05003784
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003785 for(int level = 0; level < levels; level++)
3786 {
Nicolas Capens894858a2018-03-22 00:55:23 -04003787 texture->setImage(level, width, height, depth, internalformat, GL_NONE, GL_NONE, context->getUnpackParameters(), nullptr);
3788
Nicolas Capens7ada9ec2018-02-07 16:29:06 -05003789 width = std::max(1, (width / 2));
3790 height = std::max(1, (height / 2));
3791 }
3792 texture->makeImmutable(levels);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003793 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003794 break;
3795 default:
3796 return error(GL_INVALID_ENUM);
3797 }
3798 }
3799}
3800
Nicolas Capens805d7612018-08-02 13:56:32 -04003801void GetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003802{
3803 TRACE("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, GLint *params = %p)",
3804 target, internalformat, pname, bufSize, params);
3805
3806 if(bufSize < 0)
3807 {
3808 return error(GL_INVALID_VALUE);
3809 }
3810
3811 if(bufSize == 0)
3812 {
3813 return;
3814 }
3815
Nicolas Capens2acbd262018-01-17 13:39:58 -05003816 // OpenGL ES 3.0, section 4.4.4: "An internal format is color-renderable if it is one of the formats
3817 // from table 3.13 noted as color-renderable or if it is unsized format RGBA or RGB."
3818 // Since we only use sized formats internally, replace them here (assuming type = GL_UNSIGNED_BYTE).
3819 if(internalformat == GL_RGB) internalformat = GL_RGB8;
3820 if(internalformat == GL_RGBA) internalformat = GL_RGBA8;
3821
Nicolas Capens83463112018-06-12 23:55:16 -04003822 if(!IsColorRenderable(internalformat) &&
3823 !IsDepthRenderable(internalformat) &&
3824 !IsStencilRenderable(internalformat))
Nicolas Capens0bac2852016-05-07 06:09:58 -04003825 {
3826 return error(GL_INVALID_ENUM);
3827 }
3828
3829 switch(target)
3830 {
3831 case GL_RENDERBUFFER:
3832 break;
3833 default:
3834 return error(GL_INVALID_ENUM);
3835 }
3836
Nicolas Capens0bac2852016-05-07 06:09:58 -04003837 GLint numMultisampleCounts = NUM_MULTISAMPLE_COUNTS;
Nicolas Capens135e2402018-01-17 14:02:55 -05003838
3839 // Integer types have no multisampling
3840 GLenum type = GetColorComponentType(internalformat);
3841 if(type != GL_UNSIGNED_NORMALIZED && type != GL_FLOAT)
Nicolas Capens0bac2852016-05-07 06:09:58 -04003842 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04003843 numMultisampleCounts = 0;
Nicolas Capens0bac2852016-05-07 06:09:58 -04003844 }
3845
3846 switch(pname)
3847 {
3848 case GL_NUM_SAMPLE_COUNTS:
3849 *params = numMultisampleCounts;
3850 break;
3851 case GL_SAMPLES:
3852 for(int i = 0; i < numMultisampleCounts && i < bufSize; i++)
3853 {
3854 params[i] = multisampleCount[i];
3855 }
3856 break;
3857 default:
3858 return error(GL_INVALID_ENUM);
3859 }
3860}
3861
3862}