blob: 0e006c3ed09b388c9c08c8386291a9705a1d12a8 [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
37typedef std::pair<GLenum, GLenum> InternalFormatTypePair;
38typedef std::map<InternalFormatTypePair, GLenum> FormatMap;
39
40// A helper function to insert data into the format map with fewer characters.
41static void InsertFormatMapping(FormatMap& map, GLenum internalformat, GLenum format, GLenum type)
42{
43 map[InternalFormatTypePair(internalformat, type)] = format;
44}
45
46static bool validImageSize(GLint level, GLsizei width, GLsizei height)
47{
48 if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || width < 0 || height < 0)
49 {
50 return false;
51 }
52
53 return true;
54}
55
Nicolas Capens0bac2852016-05-07 06:09:58 -040056static bool validateColorBufferFormat(GLenum textureFormat, GLenum colorbufferFormat)
57{
58 GLenum validationError = ValidateCompressedFormat(textureFormat, egl::getClientVersion(), false);
59 if(validationError != GL_NONE)
60 {
61 return error(validationError, false);
62 }
63
64 switch(textureFormat)
65 {
66 case GL_ALPHA:
67 if(colorbufferFormat != GL_ALPHA &&
68 colorbufferFormat != GL_RGBA &&
69 colorbufferFormat != GL_RGBA4 &&
70 colorbufferFormat != GL_RGB5_A1 &&
71 colorbufferFormat != GL_RGBA8)
72 {
73 return error(GL_INVALID_OPERATION, false);
74 }
75 break;
76 case GL_LUMINANCE:
77 case GL_RGB:
78 if(colorbufferFormat != GL_RGB &&
79 colorbufferFormat != GL_RGB565 &&
80 colorbufferFormat != GL_RGB8 &&
81 colorbufferFormat != GL_RGBA &&
82 colorbufferFormat != GL_RGBA4 &&
83 colorbufferFormat != GL_RGB5_A1 &&
84 colorbufferFormat != GL_RGBA8)
85 {
86 return error(GL_INVALID_OPERATION, false);
87 }
88 break;
89 case GL_LUMINANCE_ALPHA:
90 case GL_RGBA:
91 if(colorbufferFormat != GL_RGBA &&
92 colorbufferFormat != GL_RGBA4 &&
93 colorbufferFormat != GL_RGB5_A1 &&
94 colorbufferFormat != GL_RGBA8)
95 {
96 return error(GL_INVALID_OPERATION, false);
97 }
98 break;
99 case GL_DEPTH_COMPONENT:
100 case GL_DEPTH_STENCIL:
101 return error(GL_INVALID_OPERATION, false);
102 default:
103 return error(GL_INVALID_ENUM, false);
104 }
105 return true;
106}
107
108static FormatMap BuildFormatMap3D()
109{
110 FormatMap map;
111
112 // Internal format | Format | Type
113 InsertFormatMapping(map, GL_RGB, GL_RGB, GL_UNSIGNED_BYTE);
114 InsertFormatMapping(map, GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
115 InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE);
116 InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4);
117 InsertFormatMapping(map, GL_RGBA, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
118 InsertFormatMapping(map, GL_LUMINANCE_ALPHA, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE);
119 InsertFormatMapping(map, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE);
120 InsertFormatMapping(map, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE);
121 InsertFormatMapping(map, GL_R8, GL_RED, GL_UNSIGNED_BYTE);
122 InsertFormatMapping(map, GL_R8_SNORM, GL_RED, GL_BYTE);
123 InsertFormatMapping(map, GL_R16F, GL_RED, GL_HALF_FLOAT);
124 InsertFormatMapping(map, GL_R16F, GL_RED, GL_FLOAT);
125 InsertFormatMapping(map, GL_R32F, GL_RED, GL_FLOAT);
126 InsertFormatMapping(map, GL_R8UI, GL_RED_INTEGER, GL_UNSIGNED_BYTE);
127 InsertFormatMapping(map, GL_R8I, GL_RED_INTEGER, GL_BYTE);
128 InsertFormatMapping(map, GL_R16UI, GL_RED_INTEGER, GL_UNSIGNED_SHORT);
129 InsertFormatMapping(map, GL_R16I, GL_RED_INTEGER, GL_SHORT);
130 InsertFormatMapping(map, GL_R32UI, GL_RED_INTEGER, GL_UNSIGNED_INT);
131 InsertFormatMapping(map, GL_R32I, GL_RED_INTEGER, GL_INT);
132 InsertFormatMapping(map, GL_RG8, GL_RG, GL_UNSIGNED_BYTE);
133 InsertFormatMapping(map, GL_RG8_SNORM, GL_RG, GL_BYTE);
134 InsertFormatMapping(map, GL_RG16F, GL_RG, GL_HALF_FLOAT);
135 InsertFormatMapping(map, GL_RG16F, GL_RG, GL_FLOAT);
136 InsertFormatMapping(map, GL_RG32F, GL_RG, GL_FLOAT);
137 InsertFormatMapping(map, GL_RG8UI, GL_RG_INTEGER, GL_UNSIGNED_BYTE);
138 InsertFormatMapping(map, GL_RG8I, GL_RG_INTEGER, GL_BYTE);
139 InsertFormatMapping(map, GL_RG16UI, GL_RG_INTEGER, GL_UNSIGNED_SHORT);
140 InsertFormatMapping(map, GL_RG16I, GL_RG_INTEGER, GL_SHORT);
141 InsertFormatMapping(map, GL_RG32UI, GL_RG_INTEGER, GL_UNSIGNED_INT);
142 InsertFormatMapping(map, GL_RG32I, GL_RG_INTEGER, GL_INT);
143 InsertFormatMapping(map, GL_RGB8, GL_RGB, GL_UNSIGNED_BYTE);
144 InsertFormatMapping(map, GL_SRGB8, GL_RGB, GL_UNSIGNED_BYTE);
145 InsertFormatMapping(map, GL_RGB565, GL_RGB, GL_UNSIGNED_BYTE);
146 InsertFormatMapping(map, GL_RGB565, GL_RGB, GL_UNSIGNED_SHORT_5_6_5);
147 InsertFormatMapping(map, GL_RGB8_SNORM, GL_RGB, GL_BYTE);
148 InsertFormatMapping(map, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV);
149 InsertFormatMapping(map, GL_R11F_G11F_B10F, GL_RGB, GL_HALF_FLOAT);
150 InsertFormatMapping(map, GL_R11F_G11F_B10F, GL_RGB, GL_FLOAT);
151 InsertFormatMapping(map, GL_RGB9_E5, GL_RGB, GL_UNSIGNED_INT_5_9_9_9_REV);
152 InsertFormatMapping(map, GL_RGB9_E5, GL_RGB, GL_HALF_FLOAT);
153 InsertFormatMapping(map, GL_RGB9_E5, GL_RGB, GL_FLOAT);
154 InsertFormatMapping(map, GL_RGB16F, GL_RGB, GL_HALF_FLOAT);
155 InsertFormatMapping(map, GL_RGB16F, GL_RGB, GL_FLOAT);
156 InsertFormatMapping(map, GL_RGB32F, GL_RGB, GL_FLOAT);
157 InsertFormatMapping(map, GL_RGB8UI, GL_RGB_INTEGER, GL_UNSIGNED_BYTE);
158 InsertFormatMapping(map, GL_RGB8I, GL_RGB_INTEGER, GL_BYTE);
159 InsertFormatMapping(map, GL_RGB16UI, GL_RGB_INTEGER, GL_UNSIGNED_SHORT);
160 InsertFormatMapping(map, GL_RGB16I, GL_RGB_INTEGER, GL_SHORT);
161 InsertFormatMapping(map, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT);
162 InsertFormatMapping(map, GL_RGB32I, GL_RGB_INTEGER, GL_INT);
163 InsertFormatMapping(map, GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE);
164 InsertFormatMapping(map, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE);
165 InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_BYTE);
166 InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_5_5_5_1);
167 InsertFormatMapping(map, GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV);
168 InsertFormatMapping(map, GL_RGBA8_SNORM, GL_RGBA, GL_BYTE);
169 InsertFormatMapping(map, GL_RGBA4, GL_RGBA, GL_UNSIGNED_BYTE);
170 InsertFormatMapping(map, GL_RGBA4, GL_RGBA, GL_UNSIGNED_SHORT_4_4_4_4);
171 InsertFormatMapping(map, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV);
172 InsertFormatMapping(map, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT);
173 InsertFormatMapping(map, GL_RGBA16F, GL_RGBA, GL_FLOAT);
174 InsertFormatMapping(map, GL_RGBA32F, GL_RGBA, GL_FLOAT);
175 InsertFormatMapping(map, GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE);
176 InsertFormatMapping(map, GL_RGBA8I, GL_RGBA_INTEGER, GL_BYTE);
177 InsertFormatMapping(map, GL_RGB10_A2UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT_2_10_10_10_REV);
178 InsertFormatMapping(map, GL_RGBA16UI, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT);
179 InsertFormatMapping(map, GL_RGBA16I, GL_RGBA_INTEGER, GL_SHORT);
180 InsertFormatMapping(map, GL_RGBA32UI, GL_RGBA_INTEGER, GL_UNSIGNED_INT);
181 InsertFormatMapping(map, GL_RGBA32I, GL_RGBA_INTEGER, GL_INT);
182
183 InsertFormatMapping(map, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT);
184 InsertFormatMapping(map, GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
185 InsertFormatMapping(map, GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
186 InsertFormatMapping(map, GL_DEPTH_COMPONENT32_OES, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT);
187 InsertFormatMapping(map, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT);
188 InsertFormatMapping(map, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8);
189 InsertFormatMapping(map, GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
190
191 return map;
192}
193
194static bool ValidateType3D(GLenum type)
195{
196 switch(type)
197 {
198 case GL_UNSIGNED_BYTE:
199 case GL_BYTE:
200 case GL_UNSIGNED_SHORT:
201 case GL_SHORT:
202 case GL_UNSIGNED_INT:
203 case GL_INT:
204 case GL_HALF_FLOAT:
205 case GL_FLOAT:
206 case GL_UNSIGNED_SHORT_5_6_5:
207 case GL_UNSIGNED_SHORT_4_4_4_4:
208 case GL_UNSIGNED_SHORT_5_5_5_1:
209 case GL_UNSIGNED_INT_2_10_10_10_REV:
210 case GL_UNSIGNED_INT_10F_11F_11F_REV:
211 case GL_UNSIGNED_INT_5_9_9_9_REV:
212 case GL_UNSIGNED_INT_24_8:
213 case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
214 return true;
215 default:
216 break;
217 }
218 return false;
219}
220
221static bool ValidateFormat3D(GLenum format)
222{
223 switch(format)
224 {
225 case GL_RED:
226 case GL_RG:
227 case GL_RGB:
228 case GL_RGBA:
229 case GL_DEPTH_COMPONENT:
230 case GL_DEPTH_STENCIL:
231 case GL_LUMINANCE_ALPHA:
232 case GL_LUMINANCE:
233 case GL_ALPHA:
234 case GL_RED_INTEGER:
235 case GL_RG_INTEGER:
236 case GL_RGB_INTEGER:
237 case GL_RGBA_INTEGER:
238 return true;
239 default:
240 break;
241 }
242 return false;
243}
244
245static bool ValidateInternalFormat3D(GLenum internalformat, GLenum format, GLenum type)
246{
247 static const FormatMap formatMap = BuildFormatMap3D();
248 FormatMap::const_iterator iter = formatMap.find(InternalFormatTypePair(internalformat, type));
249 if(iter != formatMap.end())
250 {
251 return iter->second == format;
252 }
253 return false;
254}
255
256typedef std::map<GLenum, GLenum> FormatMapStorage;
257
258// A helper function to insert data into the format map with fewer characters.
259static void InsertFormatStorageMapping(FormatMapStorage& map, GLenum internalformat, GLenum type)
260{
261 map[internalformat] = type;
262}
263
264static FormatMapStorage BuildFormatMapStorage2D()
265{
266 FormatMapStorage map;
267
268 // Internal format | Type
269 InsertFormatStorageMapping(map, GL_R8, GL_UNSIGNED_BYTE);
270 InsertFormatStorageMapping(map, GL_R8_SNORM, GL_UNSIGNED_BYTE);
271 InsertFormatStorageMapping(map, GL_R16F, GL_HALF_FLOAT);
272 InsertFormatStorageMapping(map, GL_R32F, GL_FLOAT);
273 InsertFormatStorageMapping(map, GL_R8UI, GL_UNSIGNED_BYTE);
274 InsertFormatStorageMapping(map, GL_R8I, GL_BYTE);
275 InsertFormatStorageMapping(map, GL_R16UI, GL_UNSIGNED_SHORT);
276 InsertFormatStorageMapping(map, GL_R16I, GL_SHORT);
277 InsertFormatStorageMapping(map, GL_R32UI, GL_UNSIGNED_INT);
278 InsertFormatStorageMapping(map, GL_R32I, GL_INT);
279 InsertFormatStorageMapping(map, GL_RG8, GL_UNSIGNED_BYTE);
280 InsertFormatStorageMapping(map, GL_RG8_SNORM, GL_BYTE);
281 InsertFormatStorageMapping(map, GL_RG16F, GL_HALF_FLOAT);
282 InsertFormatStorageMapping(map, GL_RG32F, GL_FLOAT);
283 InsertFormatStorageMapping(map, GL_RG8UI, GL_UNSIGNED_BYTE);
284 InsertFormatStorageMapping(map, GL_RG8I, GL_BYTE);
285 InsertFormatStorageMapping(map, GL_RG16UI, GL_UNSIGNED_SHORT);
286 InsertFormatStorageMapping(map, GL_RG16I, GL_SHORT);
287 InsertFormatStorageMapping(map, GL_RG32UI, GL_UNSIGNED_INT);
288 InsertFormatStorageMapping(map, GL_RG32I, GL_INT);
289 InsertFormatStorageMapping(map, GL_RGB8, GL_UNSIGNED_BYTE);
290 InsertFormatStorageMapping(map, GL_SRGB8, GL_UNSIGNED_BYTE);
291 InsertFormatStorageMapping(map, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5);
292 InsertFormatStorageMapping(map, GL_RGB8_SNORM, GL_BYTE);
293 InsertFormatStorageMapping(map, GL_R11F_G11F_B10F, GL_UNSIGNED_INT_10F_11F_11F_REV);
294 InsertFormatStorageMapping(map, GL_RGB9_E5, GL_UNSIGNED_INT_5_9_9_9_REV);
295 InsertFormatStorageMapping(map, GL_RGB16F, GL_HALF_FLOAT);
296 InsertFormatStorageMapping(map, GL_RGB32F, GL_FLOAT);
297 InsertFormatStorageMapping(map, GL_RGB8UI, GL_UNSIGNED_BYTE);
298 InsertFormatStorageMapping(map, GL_RGB8I, GL_BYTE);
299 InsertFormatStorageMapping(map, GL_RGB16UI, GL_UNSIGNED_SHORT);
300 InsertFormatStorageMapping(map, GL_RGB16I, GL_SHORT);
301 InsertFormatStorageMapping(map, GL_RGB32UI, GL_UNSIGNED_INT);
302 InsertFormatStorageMapping(map, GL_RGB32I, GL_INT);
303 InsertFormatStorageMapping(map, GL_RGBA8, GL_UNSIGNED_BYTE);
304 InsertFormatStorageMapping(map, GL_SRGB8_ALPHA8, GL_UNSIGNED_BYTE);
305 InsertFormatStorageMapping(map, GL_RGBA8_SNORM, GL_BYTE);
306 InsertFormatStorageMapping(map, GL_RGB5_A1, GL_UNSIGNED_SHORT_5_5_5_1);
307 InsertFormatStorageMapping(map, GL_RGBA4, GL_UNSIGNED_SHORT_4_4_4_4);
308 InsertFormatStorageMapping(map, GL_RGB10_A2, GL_UNSIGNED_INT_2_10_10_10_REV);
309 InsertFormatStorageMapping(map, GL_RGBA16F, GL_HALF_FLOAT);
310 InsertFormatStorageMapping(map, GL_RGBA32F, GL_FLOAT);
311 InsertFormatStorageMapping(map, GL_RGBA8UI, GL_UNSIGNED_BYTE);
312 InsertFormatStorageMapping(map, GL_RGBA8I, GL_BYTE);
313 InsertFormatStorageMapping(map, GL_RGB10_A2UI, GL_UNSIGNED_INT_2_10_10_10_REV);
314 InsertFormatStorageMapping(map, GL_RGBA16UI, GL_UNSIGNED_SHORT);
315 InsertFormatStorageMapping(map, GL_RGBA16I, GL_SHORT);
316 InsertFormatStorageMapping(map, GL_RGBA32UI, GL_UNSIGNED_INT);
317 InsertFormatStorageMapping(map, GL_RGBA32I, GL_INT);
318
319 InsertFormatStorageMapping(map, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT);
320 InsertFormatStorageMapping(map, GL_DEPTH_COMPONENT24, GL_UNSIGNED_INT);
321 InsertFormatStorageMapping(map, GL_DEPTH_COMPONENT32F, GL_FLOAT);
322 InsertFormatStorageMapping(map, GL_DEPTH24_STENCIL8, GL_UNSIGNED_INT_24_8);
323 InsertFormatStorageMapping(map, GL_DEPTH32F_STENCIL8, GL_FLOAT_32_UNSIGNED_INT_24_8_REV);
324
325 return map;
326}
327
328static bool GetStorageType(GLenum internalformat, GLenum& type)
329{
330 static const FormatMapStorage formatMap = BuildFormatMapStorage2D();
331 FormatMapStorage::const_iterator iter = formatMap.find(internalformat);
332 if(iter != formatMap.end())
333 {
334 type = iter->second;
335 return true;
336 }
337 return false;
338}
339
340static bool ValidateQueryTarget(GLenum target)
341{
342 switch(target)
343 {
344 case GL_ANY_SAMPLES_PASSED:
345 case GL_ANY_SAMPLES_PASSED_CONSERVATIVE:
346 case GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN:
347 break;
348 default:
349 return false;
350 }
351
352 return true;
353}
354
355bool ValidateTexParamParameters(GLenum pname, GLint param)
356{
357 switch(pname)
358 {
359 case GL_TEXTURE_WRAP_S:
360 case GL_TEXTURE_WRAP_T:
361 case GL_TEXTURE_WRAP_R:
362 switch(param)
363 {
364 case GL_REPEAT:
365 case GL_CLAMP_TO_EDGE:
366 case GL_MIRRORED_REPEAT:
367 return true;
368 default:
369 return error(GL_INVALID_ENUM, false);
370 }
371
372 case GL_TEXTURE_MIN_FILTER:
373 switch(param)
374 {
375 case GL_NEAREST:
376 case GL_LINEAR:
377 case GL_NEAREST_MIPMAP_NEAREST:
378 case GL_LINEAR_MIPMAP_NEAREST:
379 case GL_NEAREST_MIPMAP_LINEAR:
380 case GL_LINEAR_MIPMAP_LINEAR:
381 return true;
382 default:
383 return error(GL_INVALID_ENUM, false);
384 }
385 break;
386
387 case GL_TEXTURE_MAG_FILTER:
388 switch(param)
389 {
390 case GL_NEAREST:
391 case GL_LINEAR:
392 return true;
393 default:
394 return error(GL_INVALID_ENUM, false);
395 }
396 break;
397
398 case GL_TEXTURE_USAGE_ANGLE:
399 switch(param)
400 {
401 case GL_NONE:
402 case GL_FRAMEBUFFER_ATTACHMENT_ANGLE:
403 return true;
404 default:
405 return error(GL_INVALID_ENUM, false);
406 }
407 break;
408
409 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
410 // we assume the parameter passed to this validation method is truncated, not rounded
411 if(param < 1)
412 {
413 return error(GL_INVALID_VALUE, false);
414 }
415 return true;
416
417 case GL_TEXTURE_MIN_LOD:
418 case GL_TEXTURE_MAX_LOD:
419 // any value is permissible
420 return true;
421
422 case GL_TEXTURE_COMPARE_MODE:
423 // Acceptable mode parameters from GLES 3.0.2 spec, table 3.17
424 switch(param)
425 {
426 case GL_NONE:
427 case GL_COMPARE_REF_TO_TEXTURE:
428 return true;
429 default:
430 return error(GL_INVALID_ENUM, false);
431 }
432 break;
433
434 case GL_TEXTURE_COMPARE_FUNC:
435 // Acceptable function parameters from GLES 3.0.2 spec, table 3.17
436 switch(param)
437 {
438 case GL_LEQUAL:
439 case GL_GEQUAL:
440 case GL_LESS:
441 case GL_GREATER:
442 case GL_EQUAL:
443 case GL_NOTEQUAL:
444 case GL_ALWAYS:
445 case GL_NEVER:
446 return true;
447 default:
448 return error(GL_INVALID_ENUM, false);
449 }
450 break;
451
452 case GL_TEXTURE_SWIZZLE_R:
453 case GL_TEXTURE_SWIZZLE_G:
454 case GL_TEXTURE_SWIZZLE_B:
455 case GL_TEXTURE_SWIZZLE_A:
456 switch(param)
457 {
458 case GL_RED:
459 case GL_GREEN:
460 case GL_BLUE:
461 case GL_ALPHA:
462 case GL_ZERO:
463 case GL_ONE:
464 return true;
465 default:
466 return error(GL_INVALID_ENUM, false);
467 }
468 break;
469
470 case GL_TEXTURE_BASE_LEVEL:
471 case GL_TEXTURE_MAX_LEVEL:
472 if(param < 0)
473 {
474 return error(GL_INVALID_VALUE, false);
475 }
476 return true;
477
478 default:
479 return error(GL_INVALID_ENUM, false);
480 }
481}
482
483static bool ValidateSamplerObjectParameter(GLenum pname)
484{
485 switch(pname)
486 {
487 case GL_TEXTURE_MIN_FILTER:
488 case GL_TEXTURE_MAG_FILTER:
489 case GL_TEXTURE_WRAP_S:
490 case GL_TEXTURE_WRAP_T:
491 case GL_TEXTURE_WRAP_R:
492 case GL_TEXTURE_MIN_LOD:
493 case GL_TEXTURE_MAX_LOD:
494 case GL_TEXTURE_COMPARE_MODE:
495 case GL_TEXTURE_COMPARE_FUNC:
Lingfeng Yang73981b82017-05-12 17:28:04 -0700496 case GL_TEXTURE_MAX_ANISOTROPY_EXT:
Nicolas Capens0bac2852016-05-07 06:09:58 -0400497 return true;
498 default:
499 return false;
500 }
501}
502
503extern "C"
504{
505
506GL_APICALL void GL_APIENTRY glReadBuffer(GLenum src)
507{
508 TRACE("(GLenum src = 0x%X)", src);
509
510 es2::Context *context = es2::getContext();
511
512 if(context)
513 {
514 GLuint readFramebufferName = context->getReadFramebufferName();
515
516 switch(src)
517 {
518 case GL_BACK:
519 if(readFramebufferName != 0)
520 {
521 return error(GL_INVALID_OPERATION);
522 }
523 context->setFramebufferReadBuffer(src);
524 break;
525 case GL_NONE:
526 context->setFramebufferReadBuffer(src);
527 break;
528 case GL_COLOR_ATTACHMENT0:
529 case GL_COLOR_ATTACHMENT1:
530 case GL_COLOR_ATTACHMENT2:
531 case GL_COLOR_ATTACHMENT3:
532 case GL_COLOR_ATTACHMENT4:
533 case GL_COLOR_ATTACHMENT5:
534 case GL_COLOR_ATTACHMENT6:
535 case GL_COLOR_ATTACHMENT7:
536 case GL_COLOR_ATTACHMENT8:
537 case GL_COLOR_ATTACHMENT9:
538 case GL_COLOR_ATTACHMENT10:
539 case GL_COLOR_ATTACHMENT11:
540 case GL_COLOR_ATTACHMENT12:
541 case GL_COLOR_ATTACHMENT13:
542 case GL_COLOR_ATTACHMENT14:
543 case GL_COLOR_ATTACHMENT15:
544 case GL_COLOR_ATTACHMENT16:
545 case GL_COLOR_ATTACHMENT17:
546 case GL_COLOR_ATTACHMENT18:
547 case GL_COLOR_ATTACHMENT19:
548 case GL_COLOR_ATTACHMENT20:
549 case GL_COLOR_ATTACHMENT21:
550 case GL_COLOR_ATTACHMENT22:
551 case GL_COLOR_ATTACHMENT23:
552 case GL_COLOR_ATTACHMENT24:
553 case GL_COLOR_ATTACHMENT25:
554 case GL_COLOR_ATTACHMENT26:
555 case GL_COLOR_ATTACHMENT27:
556 case GL_COLOR_ATTACHMENT28:
557 case GL_COLOR_ATTACHMENT29:
558 case GL_COLOR_ATTACHMENT30:
559 case GL_COLOR_ATTACHMENT31:
560 {
561 GLuint index = (src - GL_COLOR_ATTACHMENT0);
562 if(index >= MAX_COLOR_ATTACHMENTS)
563 {
Alexis Hetu6e864492017-11-14 15:27:00 -0500564 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400565 }
566 if(readFramebufferName == 0)
567 {
568 return error(GL_INVALID_OPERATION);
569 }
570 context->setFramebufferReadBuffer(src);
571 }
572 break;
573 default:
Alexis Hetu6e864492017-11-14 15:27:00 -0500574 return error(GL_INVALID_ENUM);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400575 }
576 }
577}
578
579GL_APICALL void GL_APIENTRY glDrawRangeElements(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void *indices)
580{
581 TRACE("(GLenum mode = 0x%X, GLuint start = %d, GLuint end = %d, "
582 "GLsizei count = %d, GLenum type = 0x%x, const void* indices = %p)",
583 mode, start, end, count, type, indices);
584
585 switch(mode)
586 {
587 case GL_POINTS:
588 case GL_LINES:
589 case GL_LINE_LOOP:
590 case GL_LINE_STRIP:
591 case GL_TRIANGLES:
592 case GL_TRIANGLE_FAN:
593 case GL_TRIANGLE_STRIP:
594 break;
595 default:
596 return error(GL_INVALID_ENUM);
597 }
598
599 switch(type)
600 {
601 case GL_UNSIGNED_BYTE:
602 case GL_UNSIGNED_SHORT:
603 case GL_UNSIGNED_INT:
604 break;
605 default:
606 return error(GL_INVALID_ENUM);
607 }
608
609 if((count < 0) || (end < start))
610 {
611 return error(GL_INVALID_VALUE);
612 }
613
614 es2::Context *context = es2::getContext();
615
616 if(context)
617 {
618 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
619 if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
620 {
621 return error(GL_INVALID_OPERATION);
622 }
623
624 context->drawElements(mode, start, end, count, type, indices);
625 }
626}
627
Alexis Hetu53f48092016-06-17 14:08:06 -0400628GL_APICALL void GL_APIENTRY glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void *data)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400629{
630 TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, "
631 "GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, "
Alexis Hetu53f48092016-06-17 14:08:06 -0400632 "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* data = %p)",
633 target, level, internalformat, width, height, depth, border, format, type, data);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400634
635 switch(target)
636 {
637 case GL_TEXTURE_3D:
638 case GL_TEXTURE_2D_ARRAY:
639 break;
640 default:
641 return error(GL_INVALID_ENUM);
642 }
643
644 if(!ValidateType3D(type) || !ValidateFormat3D(format))
645 {
646 return error(GL_INVALID_ENUM);
647 }
648
649 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
650 {
651 return error(GL_INVALID_VALUE);
652 }
653
654 const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level;
655 if((width < 0) || (height < 0) || (depth < 0) || (width > maxSize3D) || (height > maxSize3D) || (depth > maxSize3D))
656 {
657 return error(GL_INVALID_VALUE);
658 }
659
660 if(border != 0)
661 {
662 return error(GL_INVALID_VALUE);
663 }
664
665 if(!ValidateInternalFormat3D(internalformat, format, type))
666 {
667 return error(GL_INVALID_OPERATION);
668 }
669
670 es2::Context *context = es2::getContext();
671
672 if(context)
673 {
674 es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
675
676 if(!texture)
677 {
678 return error(GL_INVALID_OPERATION);
679 }
680
Alexis Hetuf97f6e02017-11-15 13:01:28 -0500681 GLenum sizedInternalFormat = GetSizedInternalFormat(internalformat, type);
682
Alexis Hetu848aa7f2017-11-17 13:15:32 -0500683 GLenum validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, sizedInternalFormat, type));
Alexis Hetuf97f6e02017-11-15 13:01:28 -0500684 if(validationError != GL_NONE)
685 {
686 return error(validationError);
687 }
688
689 texture->setImage(context, level, width, height, depth, sizedInternalFormat, type, context->getUnpackInfo(), data);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400690 }
691}
692
Alexis Hetu53f48092016-06-17 14:08:06 -0400693GL_APICALL void GL_APIENTRY glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void *data)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400694{
695 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
696 "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
Alexis Hetu53f48092016-06-17 14:08:06 -0400697 "GLenum format = 0x%X, GLenum type = 0x%x, const GLvoid* data = %p)",
698 target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, data);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400699
700 switch(target)
701 {
702 case GL_TEXTURE_3D:
703 case GL_TEXTURE_2D_ARRAY:
704 break;
705 default:
706 return error(GL_INVALID_ENUM);
707 }
708
709 if(!ValidateType3D(type) || !ValidateFormat3D(format))
710 {
711 return error(GL_INVALID_ENUM);
712 }
713
714 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
715 {
716 return error(GL_INVALID_VALUE);
717 }
718
719 if((width < 0) || (height < 0) || (depth < 0) || (xoffset < 0) || (yoffset < 0) || (zoffset < 0))
720 {
721 return error(GL_INVALID_VALUE);
722 }
723
724 es2::Context *context = es2::getContext();
725
726 if(context)
727 {
728 es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
729
730 GLenum sizedInternalFormat = GetSizedInternalFormat(format, type);
731
Nicolas Capensd2faaa92017-12-04 11:15:51 -0500732 GLenum validationError = ValidateSubImageParams(false, false, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, texture, context->getClientVersion());
733 if(validationError != GL_NONE)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400734 {
735 return error(validationError);
736 }
Nicolas Capensd2faaa92017-12-04 11:15:51 -0500737
738 validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, sizedInternalFormat, type));
739 if(validationError != GL_NONE)
740 {
741 return error(validationError);
742 }
743
744 texture->subImage(context, level, xoffset, yoffset, zoffset, width, height, depth, sizedInternalFormat, type, context->getUnpackInfo(), data);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400745 }
746}
747
748GL_APICALL void GL_APIENTRY glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
749{
750 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
751 "GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
752 target, level, xoffset, yoffset, zoffset, x, y, width, height);
753
754 switch(target)
755 {
756 case GL_TEXTURE_3D:
757 case GL_TEXTURE_2D_ARRAY:
758 break;
759 default:
760 return error(GL_INVALID_ENUM);
761 }
762
763 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
764 {
765 return error(GL_INVALID_VALUE);
766 }
767
768 if((width < 0) || (height < 0) || (xoffset < 0) || (yoffset < 0) || (zoffset < 0))
769 {
770 return error(GL_INVALID_VALUE);
771 }
772
773 es2::Context *context = es2::getContext();
774
775 if(context)
776 {
777 es2::Framebuffer *framebuffer = context->getReadFramebuffer();
778
779 if(framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
780 {
781 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
782 }
783
784 es2::Renderbuffer *source = framebuffer->getReadColorbuffer();
785
786 if(context->getReadFramebufferName() != 0 && (!source || source->getSamples() > 1))
787 {
788 return error(GL_INVALID_OPERATION);
789 }
790
791 GLenum colorbufferFormat = source->getFormat();
792 es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
793
Nicolas Capensd2faaa92017-12-04 11:15:51 -0500794 GLenum validationError = ValidateSubImageParams(false, true, target, level, xoffset, yoffset, zoffset, width, height, 1, GL_NONE, GL_NONE, texture, context->getClientVersion());
Nicolas Capens0bac2852016-05-07 06:09:58 -0400795 if(validationError != GL_NONE)
796 {
797 return error(validationError);
798 }
799
800 GLenum textureFormat = texture->getFormat(target, level);
801
802 if(!validateColorBufferFormat(textureFormat, colorbufferFormat))
803 {
804 return;
805 }
806
807 texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, framebuffer);
808 }
809}
810
811GL_APICALL void GL_APIENTRY glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data)
812{
813 TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
814 "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = %p)",
815 target, level, internalformat, width, height, depth, border, imageSize, data);
816
817 switch(target)
818 {
819 case GL_TEXTURE_3D:
820 case GL_TEXTURE_2D_ARRAY:
821 break;
822 default:
823 return error(GL_INVALID_ENUM);
824 }
825
826 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
827 {
828 return error(GL_INVALID_VALUE);
829 }
830
831 const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level;
832 if((width < 0) || (height < 0) || (depth < 0) || (width > maxSize3D) || (height > maxSize3D) || (depth > maxSize3D) || (border != 0) || (imageSize < 0))
833 {
834 return error(GL_INVALID_VALUE);
835 }
836
837 switch(internalformat)
838 {
839 case GL_DEPTH_COMPONENT:
840 case GL_DEPTH_COMPONENT16:
841 case GL_DEPTH_COMPONENT32_OES:
842 case GL_DEPTH_STENCIL:
843 case GL_DEPTH24_STENCIL8:
844 return error(GL_INVALID_OPERATION);
845 default:
846 {
847 GLenum validationError = ValidateCompressedFormat(internalformat, egl::getClientVersion(), true);
848 if(validationError != GL_NONE)
849 {
850 return error(validationError);
851 }
852 }
853 }
854
855 if(imageSize != egl::ComputeCompressedSize(width, height, internalformat) * depth)
856 {
857 return error(GL_INVALID_VALUE);
858 }
859
860 es2::Context *context = es2::getContext();
861
862 if(context)
863 {
864 es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
865
866 if(!texture)
867 {
868 return error(GL_INVALID_OPERATION);
869 }
870
Alexis Hetu848aa7f2017-11-17 13:15:32 -0500871 GLenum validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
Alexis Hetuf97f6e02017-11-15 13:01:28 -0500872 if(validationError != GL_NONE)
873 {
874 return error(validationError);
875 }
876
Nicolas Capens0bac2852016-05-07 06:09:58 -0400877 texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data);
878 }
879}
880
881GL_APICALL void GL_APIENTRY glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void *data)
882{
883 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
884 "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
885 "GLenum format = 0x%X, GLsizei imageSize = %d, const void *data = %p)",
886 target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
887
888 switch(target)
889 {
890 case GL_TEXTURE_3D:
891 case GL_TEXTURE_2D_ARRAY:
892 break;
893 default:
894 return error(GL_INVALID_ENUM);
895 }
896
897 if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
898 {
899 return error(GL_INVALID_VALUE);
900 }
901
902 if(xoffset < 0 || yoffset < 0 || zoffset < 0 || !validImageSize(level, width, height) || depth < 0 || imageSize < 0)
903 {
904 return error(GL_INVALID_VALUE);
905 }
906
907 GLenum validationError = ValidateCompressedFormat(format, egl::getClientVersion(), true);
908 if(validationError != GL_NONE)
909 {
910 return error(validationError);
911 }
912
Alexis Hetubbb8fc12017-11-21 12:39:41 -0500913 if(imageSize != egl::ComputeCompressedSize(width, height, format) * depth)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400914 {
Alexis Hetubbb8fc12017-11-21 12:39:41 -0500915 return error(GL_INVALID_VALUE);
916 }
917
918 bool is_ETC2_EAC = false;
919 switch(format)
920 {
921 case GL_COMPRESSED_R11_EAC:
922 case GL_COMPRESSED_SIGNED_R11_EAC:
923 case GL_COMPRESSED_RG11_EAC:
924 case GL_COMPRESSED_SIGNED_RG11_EAC:
925 case GL_COMPRESSED_RGB8_ETC2:
926 case GL_COMPRESSED_SRGB8_ETC2:
927 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
928 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
929 case GL_COMPRESSED_RGBA8_ETC2_EAC:
930 case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
931 if(target != GL_TEXTURE_2D_ARRAY)
932 {
933 return error(GL_INVALID_OPERATION);
934 }
935
Nicolas Capensd2faaa92017-12-04 11:15:51 -0500936 if(((width % 4) != 0) || ((height % 4) != 0) ||
Alexis Hetubbb8fc12017-11-21 12:39:41 -0500937 ((xoffset % 4) != 0) || ((yoffset % 4) != 0))
938 {
939 return error(GL_INVALID_OPERATION);
940 }
941
942 is_ETC2_EAC = true;
943 break;
944 default:
945 break;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400946 }
947
948 es2::Context *context = es2::getContext();
949
950 if(context)
951 {
952 es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
953
954 if(!texture)
955 {
956 return error(GL_INVALID_OPERATION);
957 }
958
Alexis Hetu848aa7f2017-11-17 13:15:32 -0500959 GLenum validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
Alexis Hetuf97f6e02017-11-15 13:01:28 -0500960 if(validationError != GL_NONE)
961 {
962 return error(validationError);
963 }
964
Alexis Hetubbb8fc12017-11-21 12:39:41 -0500965 if(is_ETC2_EAC)
966 {
967 if(((width + xoffset) != texture->getWidth(target, level)) ||
Nicolas Capensd2faaa92017-12-04 11:15:51 -0500968 ((height + yoffset) != texture->getHeight(target, level)) ||
969 ((depth + zoffset) != texture->getDepth(target, level)))
Alexis Hetubbb8fc12017-11-21 12:39:41 -0500970 {
971 return error(GL_INVALID_OPERATION);
972 }
973 }
974
Alexis Hetuf97f6e02017-11-15 13:01:28 -0500975 texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400976 }
977}
978
979GL_APICALL void GL_APIENTRY glGenQueries(GLsizei n, GLuint *ids)
980{
981 TRACE("(GLsizei n = %d, GLuint* ids = %p)", n, ids);
982
983 if(n < 0)
984 {
985 return error(GL_INVALID_VALUE);
986 }
987
988 es2::Context *context = es2::getContext();
989
990 if(context)
991 {
992 for(int i = 0; i < n; i++)
993 {
994 ids[i] = context->createQuery();
995 }
996 }
997}
998
999GL_APICALL void GL_APIENTRY glDeleteQueries(GLsizei n, const GLuint *ids)
1000{
1001 TRACE("(GLsizei n = %d, GLuint* ids = %p)", n, ids);
1002
1003 if(n < 0)
1004 {
1005 return error(GL_INVALID_VALUE);
1006 }
1007
1008 es2::Context *context = es2::getContext();
1009
1010 if(context)
1011 {
1012 for(int i = 0; i < n; i++)
1013 {
1014 context->deleteQuery(ids[i]);
1015 }
1016 }
1017}
1018
1019GL_APICALL GLboolean GL_APIENTRY glIsQuery(GLuint id)
1020{
1021 TRACE("(GLuint id = %d)", id);
1022
1023 if(id == 0)
1024 {
1025 return GL_FALSE;
1026 }
1027
1028 es2::Context *context = es2::getContext();
1029
1030 if(context)
1031 {
1032 es2::Query *queryObject = context->getQuery(id);
1033
1034 if(queryObject)
1035 {
1036 return GL_TRUE;
1037 }
1038 }
1039
1040 return GL_FALSE;
1041}
1042
1043GL_APICALL void GL_APIENTRY glBeginQuery(GLenum target, GLuint id)
1044{
1045 TRACE("(GLenum target = 0x%X, GLuint id = %d)", target, id);
1046
1047 if(!ValidateQueryTarget(target))
1048 {
1049 return error(GL_INVALID_ENUM);
1050 }
1051
1052 if(id == 0)
1053 {
1054 return error(GL_INVALID_OPERATION);
1055 }
1056
1057 es2::Context *context = es2::getContext();
1058
1059 if(context)
1060 {
1061 context->beginQuery(target, id);
1062 }
1063}
1064
1065GL_APICALL void GL_APIENTRY glEndQuery(GLenum target)
1066{
1067 TRACE("(GLenum target = 0x%X)", target);
1068
1069 if(!ValidateQueryTarget(target))
1070 {
1071 return error(GL_INVALID_ENUM);
1072 }
1073
1074 es2::Context *context = es2::getContext();
1075
1076 if(context)
1077 {
1078 context->endQuery(target);
1079 }
1080}
1081
1082GL_APICALL void GL_APIENTRY glGetQueryiv(GLenum target, GLenum pname, GLint *params)
1083{
1084 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = %p)",
1085 target, pname, params);
1086
1087 if(!ValidateQueryTarget(target) || (pname != GL_CURRENT_QUERY))
1088 {
1089 return error(GL_INVALID_ENUM);
1090 }
1091
1092 es2::Context *context = es2::getContext();
1093
1094 if(context)
1095 {
1096 params[0] = context->getActiveQuery(target);
1097 }
1098}
1099
1100GL_APICALL void GL_APIENTRY glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
1101{
1102 TRACE("(GLuint id = %d, GLenum pname = 0x%X, GLint *params = %p)",
1103 id, pname, params);
1104
1105 switch(pname)
1106 {
1107 case GL_QUERY_RESULT:
1108 case GL_QUERY_RESULT_AVAILABLE:
1109 break;
1110 default:
1111 return error(GL_INVALID_ENUM);
1112 }
1113
1114 es2::Context *context = es2::getContext();
1115
1116 if(context)
1117 {
1118 es2::Query *queryObject = context->getQuery(id);
1119
1120 if(!queryObject)
1121 {
1122 return error(GL_INVALID_OPERATION);
1123 }
1124
1125 if(context->getActiveQuery(queryObject->getType()) == id)
1126 {
1127 return error(GL_INVALID_OPERATION);
1128 }
1129
1130 switch(pname)
1131 {
1132 case GL_QUERY_RESULT:
1133 params[0] = queryObject->getResult();
1134 break;
1135 case GL_QUERY_RESULT_AVAILABLE:
1136 params[0] = queryObject->isResultAvailable();
1137 break;
1138 default:
1139 ASSERT(false);
1140 }
1141 }
1142}
1143
1144GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer(GLenum target)
1145{
1146 TRACE("(GLenum target = 0x%X)", target);
1147
1148 es2::Context *context = es2::getContext();
1149
1150 if(context)
1151 {
1152 es2::Buffer *buffer = nullptr;
1153 if(!context->getBuffer(target, &buffer))
1154 {
1155 return error(GL_INVALID_ENUM, GL_TRUE);
1156 }
1157
1158 if(!buffer)
1159 {
1160 // A null buffer means that "0" is bound to the requested buffer target
1161 return error(GL_INVALID_OPERATION, GL_TRUE);
1162 }
1163
Alexis Hetu6e864492017-11-14 15:27:00 -05001164 if(!buffer->isMapped())
1165 {
1166 // Already unmapped
1167 return error(GL_INVALID_OPERATION, GL_TRUE);
1168 }
1169
Nicolas Capens0bac2852016-05-07 06:09:58 -04001170 return buffer->unmap() ? GL_TRUE : GL_FALSE;
1171 }
1172
1173 return GL_TRUE;
1174}
1175
1176GL_APICALL void GL_APIENTRY glGetBufferPointerv(GLenum target, GLenum pname, void **params)
1177{
1178 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = %p)",
1179 target, pname, params);
1180
1181 if(pname != GL_BUFFER_MAP_POINTER)
1182 {
1183 return error(GL_INVALID_ENUM);
1184 }
1185
1186 es2::Context *context = es2::getContext();
1187
1188 if(context)
1189 {
1190 es2::Buffer *buffer = nullptr;
1191 if(!context->getBuffer(target, &buffer))
1192 {
1193 return error(GL_INVALID_ENUM);
1194 }
1195
1196 if(!buffer)
1197 {
1198 // A null buffer means that "0" is bound to the requested buffer target
1199 return error(GL_INVALID_OPERATION);
1200 }
1201
1202 *params = buffer->isMapped() ? (void*)(((const char*)buffer->data()) + buffer->offset()) : nullptr;
1203 }
1204}
1205
1206GL_APICALL void GL_APIENTRY glDrawBuffers(GLsizei n, const GLenum *bufs)
1207{
1208 TRACE("(GLsizei n = %d, const GLenum *bufs = %p)", n, bufs);
1209
1210 if(n < 0 || n > MAX_DRAW_BUFFERS)
1211 {
1212 return error(GL_INVALID_VALUE);
1213 }
1214
1215 es2::Context *context = es2::getContext();
1216
1217 if(context)
1218 {
1219 GLuint drawFramebufferName = context->getDrawFramebufferName();
1220
1221 if((drawFramebufferName == 0) && (n != 1))
1222 {
1223 return error(GL_INVALID_OPERATION);
1224 }
1225
1226 for(unsigned int i = 0; i < (unsigned)n; i++)
1227 {
1228 switch(bufs[i])
1229 {
1230 case GL_BACK:
1231 if(drawFramebufferName != 0)
1232 {
1233 return error(GL_INVALID_OPERATION);
1234 }
1235 break;
1236 case GL_NONE:
1237 break;
1238 case GL_COLOR_ATTACHMENT0:
1239 case GL_COLOR_ATTACHMENT1:
1240 case GL_COLOR_ATTACHMENT2:
1241 case GL_COLOR_ATTACHMENT3:
1242 case GL_COLOR_ATTACHMENT4:
1243 case GL_COLOR_ATTACHMENT5:
1244 case GL_COLOR_ATTACHMENT6:
1245 case GL_COLOR_ATTACHMENT7:
1246 case GL_COLOR_ATTACHMENT8:
1247 case GL_COLOR_ATTACHMENT9:
1248 case GL_COLOR_ATTACHMENT10:
1249 case GL_COLOR_ATTACHMENT11:
1250 case GL_COLOR_ATTACHMENT12:
1251 case GL_COLOR_ATTACHMENT13:
1252 case GL_COLOR_ATTACHMENT14:
1253 case GL_COLOR_ATTACHMENT15:
1254 case GL_COLOR_ATTACHMENT16:
1255 case GL_COLOR_ATTACHMENT17:
1256 case GL_COLOR_ATTACHMENT18:
1257 case GL_COLOR_ATTACHMENT19:
1258 case GL_COLOR_ATTACHMENT20:
1259 case GL_COLOR_ATTACHMENT21:
1260 case GL_COLOR_ATTACHMENT22:
1261 case GL_COLOR_ATTACHMENT23:
1262 case GL_COLOR_ATTACHMENT24:
1263 case GL_COLOR_ATTACHMENT25:
1264 case GL_COLOR_ATTACHMENT26:
1265 case GL_COLOR_ATTACHMENT27:
1266 case GL_COLOR_ATTACHMENT28:
1267 case GL_COLOR_ATTACHMENT29:
1268 case GL_COLOR_ATTACHMENT30:
1269 case GL_COLOR_ATTACHMENT31:
1270 {
1271 GLuint index = (bufs[i] - GL_COLOR_ATTACHMENT0);
1272
1273 if(index >= MAX_COLOR_ATTACHMENTS)
1274 {
1275 return error(GL_INVALID_OPERATION);
1276 }
1277
1278 if(index != i)
1279 {
1280 return error(GL_INVALID_OPERATION);
1281 }
1282
1283 if(drawFramebufferName == 0)
1284 {
1285 return error(GL_INVALID_OPERATION);
1286 }
1287 }
1288 break;
1289 default:
1290 return error(GL_INVALID_ENUM);
1291 }
1292 }
1293
1294 context->setFramebufferDrawBuffers(n, bufs);
1295 }
1296}
1297
1298GL_APICALL void GL_APIENTRY glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1299{
1300 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1301
1302 if(count < 0)
1303 {
1304 return error(GL_INVALID_VALUE);
1305 }
1306
Nicolas Capens0bac2852016-05-07 06:09:58 -04001307 es2::Context *context = es2::getContext();
1308
1309 if(context)
1310 {
1311 es2::Program *program = context->getCurrentProgram();
1312
1313 if(!program)
1314 {
1315 return error(GL_INVALID_OPERATION);
1316 }
1317
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001318 if(location == -1)
1319 {
1320 return;
1321 }
1322
Nicolas Capens0bac2852016-05-07 06:09:58 -04001323 if(!program->setUniformMatrix2x3fv(location, count, transpose, value))
1324 {
1325 return error(GL_INVALID_OPERATION);
1326 }
1327 }
1328}
1329
1330GL_APICALL void GL_APIENTRY glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1331{
1332 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1333
1334 if(count < 0)
1335 {
1336 return error(GL_INVALID_VALUE);
1337 }
1338
Nicolas Capens0bac2852016-05-07 06:09:58 -04001339 es2::Context *context = es2::getContext();
1340
1341 if(context)
1342 {
1343 es2::Program *program = context->getCurrentProgram();
1344
1345 if(!program)
1346 {
1347 return error(GL_INVALID_OPERATION);
1348 }
1349
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001350 if(location == -1)
1351 {
1352 return;
1353 }
1354
Nicolas Capens0bac2852016-05-07 06:09:58 -04001355 if(!program->setUniformMatrix3x2fv(location, count, transpose, value))
1356 {
1357 return error(GL_INVALID_OPERATION);
1358 }
1359 }
1360}
1361
1362GL_APICALL void GL_APIENTRY glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1363{
1364 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1365
1366 if(count < 0)
1367 {
1368 return error(GL_INVALID_VALUE);
1369 }
1370
Nicolas Capens0bac2852016-05-07 06:09:58 -04001371 es2::Context *context = es2::getContext();
1372
1373 if(context)
1374 {
1375 es2::Program *program = context->getCurrentProgram();
1376
1377 if(!program)
1378 {
1379 return error(GL_INVALID_OPERATION);
1380 }
1381
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001382 if(location == -1)
1383 {
1384 return;
1385 }
1386
Nicolas Capens0bac2852016-05-07 06:09:58 -04001387 if(!program->setUniformMatrix2x4fv(location, count, transpose, value))
1388 {
1389 return error(GL_INVALID_OPERATION);
1390 }
1391 }
1392}
1393
1394GL_APICALL void GL_APIENTRY glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1395{
1396 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1397
1398 if(count < 0)
1399 {
1400 return error(GL_INVALID_VALUE);
1401 }
1402
Nicolas Capens0bac2852016-05-07 06:09:58 -04001403 es2::Context *context = es2::getContext();
1404
1405 if(context)
1406 {
1407 es2::Program *program = context->getCurrentProgram();
1408
1409 if(!program)
1410 {
1411 return error(GL_INVALID_OPERATION);
1412 }
1413
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001414 if(location == -1)
1415 {
1416 return;
1417 }
1418
Nicolas Capens0bac2852016-05-07 06:09:58 -04001419 if(!program->setUniformMatrix4x2fv(location, count, transpose, value))
1420 {
1421 return error(GL_INVALID_OPERATION);
1422 }
1423 }
1424}
1425
1426GL_APICALL void GL_APIENTRY glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1427{
1428 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1429
1430 if(count < 0)
1431 {
1432 return error(GL_INVALID_VALUE);
1433 }
1434
Nicolas Capens0bac2852016-05-07 06:09:58 -04001435 es2::Context *context = es2::getContext();
1436
1437 if(context)
1438 {
1439 es2::Program *program = context->getCurrentProgram();
1440
1441 if(!program)
1442 {
1443 return error(GL_INVALID_OPERATION);
1444 }
1445
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001446 if(location == -1)
1447 {
1448 return;
1449 }
1450
Nicolas Capens0bac2852016-05-07 06:09:58 -04001451 if(!program->setUniformMatrix3x4fv(location, count, transpose, value))
1452 {
1453 return error(GL_INVALID_OPERATION);
1454 }
1455 }
1456}
1457
1458GL_APICALL void GL_APIENTRY glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1459{
1460 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1461
1462 if(count < 0)
1463 {
1464 return error(GL_INVALID_VALUE);
1465 }
1466
Nicolas Capens0bac2852016-05-07 06:09:58 -04001467 es2::Context *context = es2::getContext();
1468
1469 if(context)
1470 {
1471 es2::Program *program = context->getCurrentProgram();
1472
1473 if(!program)
1474 {
1475 return error(GL_INVALID_OPERATION);
1476 }
1477
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001478 if(location == -1)
1479 {
1480 return;
1481 }
1482
Nicolas Capens0bac2852016-05-07 06:09:58 -04001483 if(!program->setUniformMatrix4x3fv(location, count, transpose, value))
1484 {
1485 return error(GL_INVALID_OPERATION);
1486 }
1487 }
1488}
1489
1490GL_APICALL void GL_APIENTRY glBlitFramebuffer(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter)
1491{
1492 TRACE("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
1493 "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "
1494 "GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
1495 srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);
1496
1497 switch(filter)
1498 {
1499 case GL_NEAREST:
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001500 break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001501 case GL_LINEAR:
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001502 if((mask & GL_DEPTH_BUFFER_BIT) || (mask & GL_STENCIL_BUFFER_BIT))
1503 {
1504 return error(GL_INVALID_OPERATION);
1505 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001506 break;
1507 default:
1508 return error(GL_INVALID_ENUM);
1509 }
1510
1511 if((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
1512 {
1513 return error(GL_INVALID_VALUE);
1514 }
1515
1516 es2::Context *context = es2::getContext();
1517
1518 if(context)
1519 {
1520 if(context->getReadFramebufferName() == context->getDrawFramebufferName())
1521 {
1522 ERR("Blits with the same source and destination framebuffer are not supported by this implementation.");
1523 return error(GL_INVALID_OPERATION);
1524 }
1525
Alexis Hetub9dda642016-10-06 11:25:32 -04001526 context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter == GL_LINEAR, true);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001527 }
1528}
1529
Nicolas Capens0bac2852016-05-07 06:09:58 -04001530GL_APICALL void GL_APIENTRY glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
1531{
1532 TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %d, GLint level = %d, GLint layer = %d)",
1533 target, attachment, texture, level, layer);
1534
1535 // GLES 3.0.4 spec, p.209, section 4.4.2
1536 // If texture is zero, any image or array of images attached to the attachment point
1537 // named by attachment is detached. Any additional parameters(level, textarget,
1538 // and / or layer) are ignored when texture is zero.
1539 if(texture != 0 && (layer < 0 || level < 0))
1540 {
1541 return error(GL_INVALID_VALUE);
1542 }
1543
1544 es2::Context *context = es2::getContext();
1545
1546 if(context)
1547 {
1548 Texture* textureObject = context->getTexture(texture);
1549 GLenum textarget = GL_NONE;
1550 if(texture != 0)
1551 {
1552 if(!textureObject)
1553 {
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001554 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001555 }
1556
1557 textarget = textureObject->getTarget();
1558 switch(textarget)
1559 {
1560 case GL_TEXTURE_3D:
1561 case GL_TEXTURE_2D_ARRAY:
1562 if(layer >= es2::IMPLEMENTATION_MAX_TEXTURE_SIZE || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
1563 {
1564 return error(GL_INVALID_VALUE);
1565 }
1566 break;
1567 default:
1568 return error(GL_INVALID_OPERATION);
1569 }
1570
1571 if(textureObject->isCompressed(textarget, level))
1572 {
1573 return error(GL_INVALID_OPERATION);
1574 }
1575 }
1576
1577 es2::Framebuffer *framebuffer = nullptr;
1578 switch(target)
1579 {
1580 case GL_DRAW_FRAMEBUFFER:
1581 case GL_FRAMEBUFFER:
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001582 if(context->getDrawFramebufferName() == 0)
1583 {
1584 return error(GL_INVALID_OPERATION);
1585 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001586 framebuffer = context->getDrawFramebuffer();
1587 break;
1588 case GL_READ_FRAMEBUFFER:
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001589 if(context->getReadFramebufferName() == 0)
1590 {
1591 return error(GL_INVALID_OPERATION);
1592 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001593 framebuffer = context->getReadFramebuffer();
1594 break;
1595 default:
1596 return error(GL_INVALID_ENUM);
1597 }
1598
1599 if(!framebuffer)
1600 {
1601 return error(GL_INVALID_OPERATION);
1602 }
1603
1604 switch(attachment)
1605 {
1606 case GL_COLOR_ATTACHMENT0:
1607 case GL_COLOR_ATTACHMENT1:
1608 case GL_COLOR_ATTACHMENT2:
1609 case GL_COLOR_ATTACHMENT3:
1610 case GL_COLOR_ATTACHMENT4:
1611 case GL_COLOR_ATTACHMENT5:
1612 case GL_COLOR_ATTACHMENT6:
1613 case GL_COLOR_ATTACHMENT7:
1614 case GL_COLOR_ATTACHMENT8:
1615 case GL_COLOR_ATTACHMENT9:
1616 case GL_COLOR_ATTACHMENT10:
1617 case GL_COLOR_ATTACHMENT11:
1618 case GL_COLOR_ATTACHMENT12:
1619 case GL_COLOR_ATTACHMENT13:
1620 case GL_COLOR_ATTACHMENT14:
1621 case GL_COLOR_ATTACHMENT15:
1622 case GL_COLOR_ATTACHMENT16:
1623 case GL_COLOR_ATTACHMENT17:
1624 case GL_COLOR_ATTACHMENT18:
1625 case GL_COLOR_ATTACHMENT19:
1626 case GL_COLOR_ATTACHMENT20:
1627 case GL_COLOR_ATTACHMENT21:
1628 case GL_COLOR_ATTACHMENT22:
1629 case GL_COLOR_ATTACHMENT23:
1630 case GL_COLOR_ATTACHMENT24:
1631 case GL_COLOR_ATTACHMENT25:
1632 case GL_COLOR_ATTACHMENT26:
1633 case GL_COLOR_ATTACHMENT27:
1634 case GL_COLOR_ATTACHMENT28:
1635 case GL_COLOR_ATTACHMENT29:
1636 case GL_COLOR_ATTACHMENT30:
1637 case GL_COLOR_ATTACHMENT31:
1638 framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0, level, layer);
1639 break;
1640 case GL_DEPTH_ATTACHMENT:
1641 framebuffer->setDepthbuffer(textarget, texture, level, layer);
1642 break;
1643 case GL_STENCIL_ATTACHMENT:
1644 framebuffer->setStencilbuffer(textarget, texture, level, layer);
1645 break;
1646 case GL_DEPTH_STENCIL_ATTACHMENT:
1647 framebuffer->setDepthbuffer(textarget, texture, level, layer);
1648 framebuffer->setStencilbuffer(textarget, texture, level, layer);
1649 break;
1650 default:
1651 return error(GL_INVALID_ENUM);
1652 }
1653 }
1654}
1655
1656GL_APICALL void *GL_APIENTRY glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
1657{
1658 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = %X)",
1659 target, offset, length, access);
1660
Alexis Hetu6e864492017-11-14 15:27:00 -05001661 if((offset < 0) || (length < 0))
1662 {
1663 return error(GL_INVALID_VALUE, nullptr);
1664 }
1665
1666 if(!(access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)))
1667 {
1668 // Must be able to read or write the buffer
1669 return error(GL_INVALID_OPERATION, nullptr);
1670 }
1671 else if((access & GL_MAP_READ_BIT) && (access & (GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT)))
1672 {
1673 // GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT and GL_MAP_UNSYNCHRONIZED_BIT can't be used with GL_MAP_READ_BIT
1674 return error(GL_INVALID_OPERATION, nullptr);
1675 }
1676 else if((!(access & GL_MAP_WRITE_BIT)) && (access & GL_MAP_FLUSH_EXPLICIT_BIT))
1677 {
1678 // GL_MAP_FLUSH_EXPLICIT_BIT can't be used without GL_MAP_WRITE_BIT
1679 return error(GL_INVALID_OPERATION, nullptr);
1680 }
1681
Nicolas Capens0bac2852016-05-07 06:09:58 -04001682 es2::Context *context = es2::getContext();
1683
1684 if(context)
1685 {
1686 es2::Buffer *buffer = nullptr;
1687 if(!context->getBuffer(target, &buffer))
1688 {
1689 return error(GL_INVALID_ENUM, nullptr);
1690 }
1691
1692 if(!buffer)
1693 {
1694 // A null buffer means that "0" is bound to the requested buffer target
1695 return error(GL_INVALID_OPERATION, nullptr);
1696 }
1697
Alexis Hetu1b4eb7f2017-11-14 13:24:37 -05001698 if(buffer->isMapped())
1699 {
1700 // It is an invalid operation to map an already mapped buffer
1701 return error(GL_INVALID_OPERATION, nullptr);
1702 }
1703
Nicolas Capens0bac2852016-05-07 06:09:58 -04001704 GLsizeiptr bufferSize = buffer->size();
Alexis Hetu6e864492017-11-14 15:27:00 -05001705 if((offset + length) > bufferSize)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001706 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001707 return error(GL_INVALID_VALUE, nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001708 }
1709
1710 if((access & ~(GL_MAP_READ_BIT |
1711 GL_MAP_WRITE_BIT |
1712 GL_MAP_INVALIDATE_RANGE_BIT |
1713 GL_MAP_INVALIDATE_BUFFER_BIT |
1714 GL_MAP_FLUSH_EXPLICIT_BIT |
1715 GL_MAP_UNSYNCHRONIZED_BIT)) != 0)
1716 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001717 return error(GL_INVALID_VALUE, nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001718 }
1719
1720 return buffer->mapRange(offset, length, access);
1721 }
1722
1723 return nullptr;
1724}
1725
1726GL_APICALL void GL_APIENTRY glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
1727{
1728 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)",
1729 target, offset, length);
1730
Alexis Hetu6e864492017-11-14 15:27:00 -05001731 if((offset < 0) || (length < 0))
1732 {
1733 return error(GL_INVALID_VALUE);
1734 }
1735
Nicolas Capens0bac2852016-05-07 06:09:58 -04001736 es2::Context *context = es2::getContext();
1737
1738 if(context)
1739 {
1740 es2::Buffer *buffer = nullptr;
1741 if(!context->getBuffer(target, &buffer))
1742 {
1743 return error(GL_INVALID_ENUM);
1744 }
1745
1746 if(!buffer)
1747 {
1748 // A null buffer means that "0" is bound to the requested buffer target
1749 return error(GL_INVALID_OPERATION);
1750 }
1751
Alexis Hetu6e864492017-11-14 15:27:00 -05001752 if(!buffer->isMapped())
Nicolas Capens0bac2852016-05-07 06:09:58 -04001753 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001754 // Buffer must be mapped
1755 return error(GL_INVALID_OPERATION);
1756 }
1757
1758 GLsizeiptr bufferSize = buffer->length();
1759 if((offset + length) > bufferSize)
1760 {
1761 return error(GL_INVALID_VALUE);
1762 }
1763
Alexis Hetua752b892017-11-22 14:00:37 -05001764 if(!(buffer->access() & GL_MAP_FLUSH_EXPLICIT_BIT))
Alexis Hetu6e864492017-11-14 15:27:00 -05001765 {
1766 // Flush must be explicitly allowed
1767 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001768 }
1769
1770 buffer->flushMappedRange(offset, length);
1771 }
1772}
1773
1774GL_APICALL void GL_APIENTRY glBindVertexArray(GLuint array)
1775{
1776 TRACE("(GLuint array = %d)", array);
1777
Nicolas Capens0bac2852016-05-07 06:09:58 -04001778 es2::Context *context = es2::getContext();
1779
1780 if(context)
1781 {
1782 if(!context->isVertexArray(array))
1783 {
1784 return error(GL_INVALID_OPERATION);
1785 }
1786
1787 context->bindVertexArray(array);
1788 }
1789}
1790
1791GL_APICALL void GL_APIENTRY glDeleteVertexArrays(GLsizei n, const GLuint *arrays)
1792{
1793 TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1794
1795 if(n < 0)
1796 {
1797 return error(GL_INVALID_VALUE);
1798 }
1799
1800 es2::Context *context = es2::getContext();
1801
1802 if(context)
1803 {
1804 for(int i = 0; i < n; i++)
1805 {
1806 context->deleteVertexArray(arrays[i]);
1807 }
1808 }
1809}
1810
1811GL_APICALL void GL_APIENTRY glGenVertexArrays(GLsizei n, GLuint *arrays)
1812{
1813 TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1814
1815 if(n < 0)
1816 {
1817 return error(GL_INVALID_VALUE);
1818 }
1819
1820 es2::Context *context = es2::getContext();
1821
1822 if(context)
1823 {
1824 for(int i = 0; i < n; i++)
1825 {
1826 arrays[i] = context->createVertexArray();
1827 }
1828 }
1829}
1830
1831GL_APICALL GLboolean GL_APIENTRY glIsVertexArray(GLuint array)
1832{
1833 TRACE("(GLuint array = %d)", array);
1834
1835 if(array == 0)
1836 {
1837 return GL_FALSE;
1838 }
1839
1840 es2::Context *context = es2::getContext();
1841
1842 if(context)
1843 {
1844 es2::VertexArray *arrayObject = context->getVertexArray(array);
1845
1846 if(arrayObject)
1847 {
1848 return GL_TRUE;
1849 }
1850 }
1851
1852 return GL_FALSE;
1853}
1854
1855GL_APICALL void GL_APIENTRY glGetIntegeri_v(GLenum target, GLuint index, GLint *data)
1856{
1857 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint* data = %p)",
1858 target, index, data);
1859
1860 es2::Context *context = es2::getContext();
1861
1862 if(context)
1863 {
1864 if(!context->getTransformFeedbackiv(index, target, data) &&
1865 !context->getUniformBufferiv(index, target, data) &&
1866 !context->getIntegerv(target, data))
1867 {
1868 GLenum nativeType;
1869 unsigned int numParams = 0;
1870 if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
1871 return error(GL_INVALID_ENUM);
1872
1873 if(numParams == 0)
1874 return; // it is known that target is valid, but there are no parameters to return
1875
1876 if(nativeType == GL_BOOL)
1877 {
1878 GLboolean *boolParams = nullptr;
1879 boolParams = new GLboolean[numParams];
1880
1881 context->getBooleanv(target, boolParams);
1882
1883 for(unsigned int i = 0; i < numParams; ++i)
1884 {
1885 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
1886 }
1887
1888 delete[] boolParams;
1889 }
1890 else if(nativeType == GL_FLOAT)
1891 {
1892 GLfloat *floatParams = nullptr;
1893 floatParams = new GLfloat[numParams];
1894
1895 context->getFloatv(target, floatParams);
1896
1897 for(unsigned int i = 0; i < numParams; ++i)
1898 {
1899 if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
1900 {
Nicolas Capens53318fa2016-04-11 17:41:39 -04001901 data[i] = convert_float_int(floatParams[i]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001902 }
1903 else
1904 {
1905 data[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
1906 }
1907 }
1908
1909 delete[] floatParams;
1910 }
1911 }
1912 }
1913}
1914
1915GL_APICALL void GL_APIENTRY glBeginTransformFeedback(GLenum primitiveMode)
1916{
1917 TRACE("(GLenum primitiveMode = 0x%X)", primitiveMode);
1918
1919 switch(primitiveMode)
1920 {
1921 case GL_POINTS:
1922 case GL_LINES:
1923 case GL_TRIANGLES:
1924 break;
1925 default:
1926 return error(GL_INVALID_ENUM);
1927 }
1928
1929 es2::Context *context = es2::getContext();
1930
1931 if(context)
1932 {
1933 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1934
1935 if(transformFeedbackObject)
1936 {
1937 if(transformFeedbackObject->isActive())
1938 {
1939 return error(GL_INVALID_OPERATION);
1940 }
1941 transformFeedbackObject->begin(primitiveMode);
1942 }
1943 else
1944 {
1945 return error(GL_INVALID_OPERATION);
1946 }
1947 }
1948}
1949
1950GL_APICALL void GL_APIENTRY glEndTransformFeedback(void)
1951{
1952 TRACE("()");
1953
1954 es2::Context *context = es2::getContext();
1955
1956 if(context)
1957 {
1958 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1959
1960 if(transformFeedbackObject)
1961 {
1962 if(!transformFeedbackObject->isActive())
1963 {
1964 return error(GL_INVALID_OPERATION);
1965 }
1966 transformFeedbackObject->end();
1967 }
1968 else
1969 {
1970 return error(GL_INVALID_OPERATION);
1971 }
1972 }
1973}
1974
1975GL_APICALL void GL_APIENTRY glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
1976{
1977 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d, GLintptr offset = %d, GLsizeiptr size = %d)",
1978 target, index, buffer, offset, size);
1979
1980 if(buffer != 0 && size <= 0)
1981 {
1982 return error(GL_INVALID_VALUE);
1983 }
1984
1985 es2::Context *context = es2::getContext();
1986
1987 if(context)
1988 {
1989 switch(target)
1990 {
1991 case GL_TRANSFORM_FEEDBACK_BUFFER:
1992 if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1993 {
1994 return error(GL_INVALID_VALUE);
1995 }
1996 if(size & 0x3 || offset & 0x3) // size and offset must be multiples of 4
1997 {
1998 return error(GL_INVALID_VALUE);
1999 }
2000 context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size);
2001 context->bindGenericTransformFeedbackBuffer(buffer);
2002 break;
2003 case GL_UNIFORM_BUFFER:
2004 if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
2005 {
2006 return error(GL_INVALID_VALUE);
2007 }
2008 if(offset % UNIFORM_BUFFER_OFFSET_ALIGNMENT != 0)
2009 {
2010 return error(GL_INVALID_VALUE);
2011 }
2012 context->bindIndexedUniformBuffer(buffer, index, offset, size);
2013 context->bindGenericUniformBuffer(buffer);
2014 break;
2015 default:
2016 return error(GL_INVALID_ENUM);
2017 }
2018 }
2019}
2020
2021GL_APICALL void GL_APIENTRY glBindBufferBase(GLenum target, GLuint index, GLuint buffer)
2022{
2023 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d)",
2024 target, index, buffer);
2025
2026 es2::Context *context = es2::getContext();
2027
2028 if(context)
2029 {
2030 switch(target)
2031 {
2032 case GL_TRANSFORM_FEEDBACK_BUFFER:
2033 if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
2034 {
2035 return error(GL_INVALID_VALUE);
2036 }
2037 context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0);
2038 context->bindGenericTransformFeedbackBuffer(buffer);
2039 break;
2040 case GL_UNIFORM_BUFFER:
2041 if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
2042 {
2043 return error(GL_INVALID_VALUE);
2044 }
2045 context->bindIndexedUniformBuffer(buffer, index, 0, 0);
2046 context->bindGenericUniformBuffer(buffer);
2047 break;
2048 default:
2049 return error(GL_INVALID_ENUM);
2050 }
2051 }
2052}
2053
2054GL_APICALL void GL_APIENTRY glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode)
2055{
2056 TRACE("(GLuint program = %d, GLsizei count = %d, const GLchar *const*varyings = %p, GLenum bufferMode = 0x%X)",
2057 program, count, varyings, bufferMode);
2058
2059 switch(bufferMode)
2060 {
2061 case GL_SEPARATE_ATTRIBS:
2062 if(count > MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
2063 {
2064 return error(GL_INVALID_VALUE);
2065 }
2066 case GL_INTERLEAVED_ATTRIBS:
2067 break;
2068 default:
2069 return error(GL_INVALID_ENUM);
2070 }
2071
2072 es2::Context *context = es2::getContext();
2073
2074 if(context)
2075 {
2076 es2::Program *programObject = context->getProgram(program);
2077
2078 if(!programObject)
2079 {
2080 return error(GL_INVALID_VALUE);
2081 }
2082
2083 programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);
2084 }
2085}
2086
2087GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name)
2088{
2089 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
2090 program, index, bufSize, length, size, type, name);
2091
2092 if(bufSize < 0)
2093 {
2094 return error(GL_INVALID_VALUE);
2095 }
2096
2097 es2::Context *context = es2::getContext();
2098
2099 if(context)
2100 {
2101 es2::Program *programObject = context->getProgram(program);
2102
2103 if(!programObject)
2104 {
2105 return error(GL_INVALID_VALUE);
2106 }
2107
2108 if(index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount()))
2109 {
2110 return error(GL_INVALID_VALUE);
2111 }
2112
2113 programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name);
2114 }
2115}
2116
2117GL_APICALL void GL_APIENTRY glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)
2118{
2119 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
2120 index, size, type, stride, pointer);
2121
2122 if(index >= es2::MAX_VERTEX_ATTRIBS)
2123 {
2124 return error(GL_INVALID_VALUE);
2125 }
2126
2127 if(size < 1 || size > 4 || stride < 0)
2128 {
2129 return error(GL_INVALID_VALUE);
2130 }
2131
2132 switch(type)
2133 {
2134 case GL_BYTE:
2135 case GL_UNSIGNED_BYTE:
2136 case GL_SHORT:
2137 case GL_UNSIGNED_SHORT:
2138 case GL_INT:
2139 case GL_UNSIGNED_INT:
2140 break;
2141 default:
2142 return error(GL_INVALID_ENUM);
2143 }
2144
2145 es2::Context *context = es2::getContext();
2146
2147 if(context)
2148 {
Alexis Hetuc1ef1ad2017-11-15 10:50:10 -05002149 es2::VertexArray* vertexArray = context->getCurrentVertexArray();
2150 if((context->getArrayBufferName() == 0) && vertexArray && (vertexArray->name != 0) && pointer)
2151 {
2152 // GL_INVALID_OPERATION is generated if a non-zero vertex array object is bound, zero is bound
2153 // to the GL_ARRAY_BUFFER buffer object binding point and the pointer argument is not NULL.
2154 return error(GL_INVALID_OPERATION);
2155 }
2156
Nicolas Capens0bac2852016-05-07 06:09:58 -04002157 context->setVertexAttribState(index, context->getArrayBuffer(), size, type, false, stride, pointer);
2158 }
2159}
2160
2161GL_APICALL void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
2162{
2163 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint *params = %p)",
2164 index, pname, params);
2165
2166 es2::Context *context = es2::getContext();
2167
2168 if(context)
2169 {
2170 if(index >= es2::MAX_VERTEX_ATTRIBS)
2171 {
2172 return error(GL_INVALID_VALUE);
2173 }
2174
2175 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
2176
2177 switch(pname)
2178 {
2179 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
2180 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
2181 break;
2182 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
2183 *params = attribState.mSize;
2184 break;
2185 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
2186 *params = attribState.mStride;
2187 break;
2188 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
2189 *params = attribState.mType;
2190 break;
2191 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
2192 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
2193 break;
2194 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2195 *params = attribState.mBoundBuffer.name();
2196 break;
2197 case GL_CURRENT_VERTEX_ATTRIB:
2198 {
2199 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
2200 for(int i = 0; i < 4; ++i)
2201 {
2202 params[i] = attrib.getCurrentValueI(i);
2203 }
2204 }
2205 break;
2206 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
2207 switch(attribState.mType)
2208 {
2209 case GL_BYTE:
2210 case GL_UNSIGNED_BYTE:
2211 case GL_SHORT:
2212 case GL_UNSIGNED_SHORT:
2213 case GL_INT:
2214 case GL_INT_2_10_10_10_REV:
2215 case GL_UNSIGNED_INT:
2216 case GL_FIXED:
2217 *params = GL_TRUE;
2218 break;
2219 default:
2220 *params = GL_FALSE;
2221 break;
2222 }
2223 break;
2224 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
2225 *params = attribState.mDivisor;
2226 break;
2227 default: return error(GL_INVALID_ENUM);
2228 }
2229 }
2230}
2231
2232GL_APICALL void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params)
2233{
2234 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLuint *params = %p)",
2235 index, pname, params);
2236
2237 es2::Context *context = es2::getContext();
2238
2239 if(context)
2240 {
2241 if(index >= es2::MAX_VERTEX_ATTRIBS)
2242 {
2243 return error(GL_INVALID_VALUE);
2244 }
2245
2246 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
2247
2248 switch(pname)
2249 {
2250 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
2251 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
2252 break;
2253 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
2254 *params = attribState.mSize;
2255 break;
2256 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
2257 *params = attribState.mStride;
2258 break;
2259 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
2260 *params = attribState.mType;
2261 break;
2262 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
2263 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
2264 break;
2265 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2266 *params = attribState.mBoundBuffer.name();
2267 break;
2268 case GL_CURRENT_VERTEX_ATTRIB:
2269 {
2270 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
2271 for(int i = 0; i < 4; ++i)
2272 {
2273 params[i] = attrib.getCurrentValueUI(i);
2274 }
2275 }
2276 break;
2277 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
2278 switch(attribState.mType)
2279 {
2280 case GL_BYTE:
2281 case GL_UNSIGNED_BYTE:
2282 case GL_SHORT:
2283 case GL_UNSIGNED_SHORT:
2284 case GL_INT:
2285 case GL_INT_2_10_10_10_REV:
2286 case GL_UNSIGNED_INT:
2287 case GL_FIXED:
2288 *params = GL_TRUE;
2289 break;
2290 default:
2291 *params = GL_FALSE;
2292 break;
2293 }
2294 break;
2295 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
2296 *params = attribState.mDivisor;
2297 break;
2298 default: return error(GL_INVALID_ENUM);
2299 }
2300 }
2301}
2302
2303GL_APICALL void GL_APIENTRY glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
2304{
2305 TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
2306 index, x, y, z, w);
2307
2308 if(index >= es2::MAX_VERTEX_ATTRIBS)
2309 {
2310 return error(GL_INVALID_VALUE);
2311 }
2312
2313 es2::Context *context = es2::getContext();
2314
2315 if(context)
2316 {
2317 GLint vals[4] = { x, y, z, w };
2318 context->setVertexAttrib(index, vals);
2319 }
2320}
2321
2322GL_APICALL void GL_APIENTRY glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
2323{
2324 TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
2325 index, x, y, z, w);
2326
2327 if(index >= es2::MAX_VERTEX_ATTRIBS)
2328 {
2329 return error(GL_INVALID_VALUE);
2330 }
2331
2332 es2::Context *context = es2::getContext();
2333
2334 if(context)
2335 {
2336 GLuint vals[4] = { x, y, z, w };
2337 context->setVertexAttrib(index, vals);
2338 }
2339}
2340
2341GL_APICALL void GL_APIENTRY glVertexAttribI4iv(GLuint index, const GLint *v)
2342{
2343 TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2344
2345 if(index >= es2::MAX_VERTEX_ATTRIBS)
2346 {
2347 return error(GL_INVALID_VALUE);
2348 }
2349
2350 es2::Context *context = es2::getContext();
2351
2352 if(context)
2353 {
2354 context->setVertexAttrib(index, v);
2355 }
2356}
2357
2358GL_APICALL void GL_APIENTRY glVertexAttribI4uiv(GLuint index, const GLuint *v)
2359{
2360 TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2361
2362 if(index >= es2::MAX_VERTEX_ATTRIBS)
2363 {
2364 return error(GL_INVALID_VALUE);
2365 }
2366
2367 es2::Context *context = es2::getContext();
2368
2369 if(context)
2370 {
2371 context->setVertexAttrib(index, v);
2372 }
2373}
2374
2375GL_APICALL void GL_APIENTRY glGetUniformuiv(GLuint program, GLint location, GLuint *params)
2376{
2377 TRACE("(GLuint program = %d, GLint location = %d, GLuint *params = %p)",
2378 program, location, params);
2379
2380 es2::Context *context = es2::getContext();
2381
2382 if(context)
2383 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04002384 es2::Program *programObject = context->getProgram(program);
2385
Alexis Hetu48280a42017-11-30 15:04:39 -05002386 if(!programObject)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002387 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002388 if(context->getShader(program))
2389 {
2390 return error(GL_INVALID_OPERATION);
2391 }
2392 else
2393 {
2394 return error(GL_INVALID_VALUE);
2395 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002396 }
2397
Alexis Hetu48280a42017-11-30 15:04:39 -05002398 if(!programObject->isLinked())
Nicolas Capens0bac2852016-05-07 06:09:58 -04002399 {
2400 return error(GL_INVALID_OPERATION);
2401 }
2402
2403 if(!programObject->getUniformuiv(location, nullptr, params))
2404 {
2405 return error(GL_INVALID_OPERATION);
2406 }
2407 }
2408}
2409
2410GL_APICALL GLint GL_APIENTRY glGetFragDataLocation(GLuint program, const GLchar *name)
2411{
2412 TRACE("(GLuint program = %d, const GLchar *name = %p)", program, name);
2413
2414 es2::Context *context = es2::getContext();
2415
Nicolas Capens0bac2852016-05-07 06:09:58 -04002416 if(context)
2417 {
2418 es2::Program *programObject = context->getProgram(program);
2419
2420 if(!programObject)
2421 {
2422 if(context->getShader(program))
2423 {
2424 return error(GL_INVALID_OPERATION, -1);
2425 }
2426 else
2427 {
2428 return error(GL_INVALID_VALUE, -1);
2429 }
2430 }
2431
2432 if(!programObject->isLinked())
2433 {
2434 return error(GL_INVALID_OPERATION, -1);
2435 }
Alexis Hetub3f5ed72017-08-16 16:37:19 -04002436
2437 return programObject->getFragDataLocation(name);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002438 }
2439
Nicolas Capens0bac2852016-05-07 06:09:58 -04002440 return -1;
2441}
2442
2443GL_APICALL void GL_APIENTRY glUniform1ui(GLint location, GLuint v0)
2444{
2445 glUniform1uiv(location, 1, &v0);
2446}
2447
2448GL_APICALL void GL_APIENTRY glUniform2ui(GLint location, GLuint v0, GLuint v1)
2449{
2450 GLuint xy[2] = { v0, v1 };
2451
2452 glUniform2uiv(location, 1, (GLuint*)&xy);
2453}
2454
2455GL_APICALL void GL_APIENTRY glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
2456{
2457 GLuint xyz[3] = { v0, v1, v2 };
2458
2459 glUniform3uiv(location, 1, (GLuint*)&xyz);
2460}
2461
2462GL_APICALL void GL_APIENTRY glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
2463{
2464 GLuint xyzw[4] = { v0, v1, v2, v3 };
2465
2466 glUniform4uiv(location, 1, (GLuint*)&xyzw);
2467}
2468
2469GL_APICALL void GL_APIENTRY glUniform1uiv(GLint location, GLsizei count, const GLuint *value)
2470{
2471 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2472 location, count, value);
2473
2474 if(count < 0)
2475 {
2476 return error(GL_INVALID_VALUE);
2477 }
2478
Nicolas Capens0bac2852016-05-07 06:09:58 -04002479 es2::Context *context = es2::getContext();
2480
2481 if(context)
2482 {
2483 es2::Program *program = context->getCurrentProgram();
2484
2485 if(!program)
2486 {
2487 return error(GL_INVALID_OPERATION);
2488 }
2489
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002490 if(location == -1)
2491 {
2492 return;
2493 }
2494
Nicolas Capens0bac2852016-05-07 06:09:58 -04002495 if(!program->setUniform1uiv(location, count, value))
2496 {
2497 return error(GL_INVALID_OPERATION);
2498 }
2499 }
2500}
2501
2502GL_APICALL void GL_APIENTRY glUniform2uiv(GLint location, GLsizei count, const GLuint *value)
2503{
2504 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2505 location, count, value);
2506
2507 if(count < 0)
2508 {
2509 return error(GL_INVALID_VALUE);
2510 }
2511
Nicolas Capens0bac2852016-05-07 06:09:58 -04002512 es2::Context *context = es2::getContext();
2513
2514 if(context)
2515 {
2516 es2::Program *program = context->getCurrentProgram();
2517
2518 if(!program)
2519 {
2520 return error(GL_INVALID_OPERATION);
2521 }
2522
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002523 if(location == -1)
2524 {
2525 return;
2526 }
2527
Nicolas Capens0bac2852016-05-07 06:09:58 -04002528 if(!program->setUniform2uiv(location, count, value))
2529 {
2530 return error(GL_INVALID_OPERATION);
2531 }
2532 }
2533}
2534
2535GL_APICALL void GL_APIENTRY glUniform3uiv(GLint location, GLsizei count, const GLuint *value)
2536{
2537 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2538 location, count, value);
2539
2540 if(count < 0)
2541 {
2542 return error(GL_INVALID_VALUE);
2543 }
2544
Nicolas Capens0bac2852016-05-07 06:09:58 -04002545 es2::Context *context = es2::getContext();
2546
2547 if(context)
2548 {
2549 es2::Program *program = context->getCurrentProgram();
2550
2551 if(!program)
2552 {
2553 return error(GL_INVALID_OPERATION);
2554 }
2555
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002556 if(location == -1)
2557 {
2558 return;
2559 }
2560
Nicolas Capens0bac2852016-05-07 06:09:58 -04002561 if(!program->setUniform3uiv(location, count, value))
2562 {
2563 return error(GL_INVALID_OPERATION);
2564 }
2565 }
2566}
2567
2568GL_APICALL void GL_APIENTRY glUniform4uiv(GLint location, GLsizei count, const GLuint *value)
2569{
2570 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2571 location, count, value);
2572
2573 if(count < 0)
2574 {
2575 return error(GL_INVALID_VALUE);
2576 }
2577
Nicolas Capens0bac2852016-05-07 06:09:58 -04002578 es2::Context *context = es2::getContext();
2579
2580 if(context)
2581 {
2582 es2::Program *program = context->getCurrentProgram();
2583
2584 if(!program)
2585 {
2586 return error(GL_INVALID_OPERATION);
2587 }
2588
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002589 if(location == -1)
2590 {
2591 return;
2592 }
2593
Nicolas Capens0bac2852016-05-07 06:09:58 -04002594 if(!program->setUniform4uiv(location, count, value))
2595 {
2596 return error(GL_INVALID_OPERATION);
2597 }
2598 }
2599}
2600
2601GL_APICALL void GL_APIENTRY glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
2602{
2603 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint *value = %p)",
2604 buffer, drawbuffer, value);
2605
2606 es2::Context *context = es2::getContext();
2607
2608 if(context)
2609 {
2610 switch(buffer)
2611 {
2612 case GL_COLOR:
2613 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2614 {
2615 return error(GL_INVALID_VALUE);
2616 }
2617 else
2618 {
2619 context->clearColorBuffer(drawbuffer, value);
2620 }
2621 break;
2622 case GL_STENCIL:
2623 if(drawbuffer != 0)
2624 {
2625 return error(GL_INVALID_VALUE);
2626 }
2627 else
2628 {
2629 context->clearStencilBuffer(value[0]);
2630 }
2631 break;
2632 default:
2633 return error(GL_INVALID_ENUM);
2634 }
2635 }
2636}
2637
2638GL_APICALL void GL_APIENTRY glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
2639{
2640 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint *value = %p)",
2641 buffer, drawbuffer, value);
2642
2643 es2::Context *context = es2::getContext();
2644
2645 if(context)
2646 {
2647 switch(buffer)
2648 {
2649 case GL_COLOR:
2650 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2651 {
2652 return error(GL_INVALID_VALUE);
2653 }
2654 else
2655 {
2656 context->clearColorBuffer(drawbuffer, value);
2657 }
2658 break;
2659 default:
2660 return error(GL_INVALID_ENUM);
2661 }
2662 }
2663}
2664
2665GL_APICALL void GL_APIENTRY glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
2666{
2667 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat *value = %p)",
2668 buffer, drawbuffer, value);
2669
2670 es2::Context *context = es2::getContext();
2671
2672 if(context)
2673 {
2674 switch(buffer)
2675 {
2676 case GL_COLOR:
2677 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2678 {
2679 return error(GL_INVALID_VALUE);
2680 }
2681 else
2682 {
2683 context->clearColorBuffer(drawbuffer, value);
2684 }
2685 break;
2686 case GL_DEPTH:
2687 if(drawbuffer != 0)
2688 {
2689 return error(GL_INVALID_VALUE);
2690 }
2691 else
2692 {
2693 context->clearDepthBuffer(value[0]);
2694 }
2695 break;
2696 default:
2697 return error(GL_INVALID_ENUM);
2698 }
2699 }
2700}
2701
2702GL_APICALL void GL_APIENTRY glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
2703{
2704 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth = %f, GLint stencil = %d)",
2705 buffer, drawbuffer, depth, stencil);
2706
2707 es2::Context *context = es2::getContext();
2708
2709 if(context)
2710 {
2711 switch(buffer)
2712 {
2713 case GL_DEPTH_STENCIL:
2714 if(drawbuffer != 0)
2715 {
2716 return error(GL_INVALID_VALUE);
2717 }
2718 else
2719 {
2720 context->clearDepthBuffer(depth);
2721 context->clearStencilBuffer(stencil);
2722 }
2723 break;
2724 default:
2725 return error(GL_INVALID_ENUM);
2726 }
2727 }
2728}
2729
2730GL_APICALL const GLubyte *GL_APIENTRY glGetStringi(GLenum name, GLuint index)
2731{
2732 TRACE("(GLenum name = 0x%X, GLuint index = %d)", name, index);
2733
2734 es2::Context *context = es2::getContext();
2735 if(context)
2736 {
2737 GLuint numExtensions;
2738 context->getExtensions(0, &numExtensions);
2739
2740 if(index >= numExtensions)
2741 {
2742 return error(GL_INVALID_VALUE, (GLubyte*)nullptr);
2743 }
2744
2745 switch(name)
2746 {
2747 case GL_EXTENSIONS:
2748 return context->getExtensions(index);
2749 default:
2750 return error(GL_INVALID_ENUM, (GLubyte*)nullptr);
2751 }
2752 }
2753
2754 return (GLubyte*)nullptr;
2755}
2756
2757GL_APICALL void GL_APIENTRY glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
2758{
2759 TRACE("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)",
2760 readTarget, writeTarget, readOffset, writeOffset, size);
2761
2762 if(readOffset < 0 || writeOffset < 0 || size < 0)
2763 {
2764 return error(GL_INVALID_VALUE);
2765 }
2766
2767 es2::Context *context = es2::getContext();
2768
2769 if(context)
2770 {
2771 es2::Buffer *readBuffer = nullptr, *writeBuffer = nullptr;
2772 if(!context->getBuffer(readTarget, &readBuffer) || !context->getBuffer(writeTarget, &writeBuffer))
2773 {
2774 return error(GL_INVALID_ENUM);
2775 }
2776 if(!readBuffer || readBuffer->isMapped() || !writeBuffer || writeBuffer->isMapped())
2777 {
2778 return error(GL_INVALID_OPERATION);
2779 }
2780 if(readBuffer == writeBuffer)
2781 {
2782 // If same buffer, check for overlap
2783 if(((readOffset >= writeOffset) && (readOffset < (writeOffset + size))) ||
2784 ((writeOffset >= readOffset) && (writeOffset < (readOffset + size))))
2785 {
2786 return error(GL_INVALID_VALUE);
2787 }
2788 }
2789
2790 if((static_cast<size_t>(readOffset + size) > readBuffer->size()) ||
2791 (static_cast<size_t>(writeOffset + size) > writeBuffer->size()))
2792 {
2793 return error(GL_INVALID_VALUE);
2794 }
2795
2796 writeBuffer->bufferSubData(((char*)readBuffer->data()) + readOffset, size, writeOffset);
2797 }
2798}
2799
2800GL_APICALL void GL_APIENTRY glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices)
2801{
2802 TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLuint *uniformIndices = %p)",
2803 program, uniformCount, uniformNames, uniformIndices);
2804
2805 if(uniformCount < 0)
2806 {
2807 return error(GL_INVALID_VALUE);
2808 }
2809
2810 es2::Context *context = es2::getContext();
2811
2812 if(context)
2813 {
2814 es2::Program *programObject = context->getProgram(program);
2815
2816 if(!programObject)
2817 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002818 if(context->getShader(program))
2819 {
2820 return error(GL_INVALID_OPERATION);
2821 }
2822 else
2823 {
2824 return error(GL_INVALID_VALUE);
2825 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002826 }
2827
2828 if(!programObject->isLinked())
2829 {
2830 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2831 {
2832 uniformIndices[uniformId] = GL_INVALID_INDEX;
2833 }
2834 }
2835 else
2836 {
2837 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2838 {
2839 uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]);
2840 }
2841 }
2842 }
2843}
2844
2845GL_APICALL void GL_APIENTRY glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params)
2846{
2847 TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLenum pname = 0x%X, GLuint *uniformIndices = %p)",
2848 program, uniformCount, uniformIndices, pname, uniformIndices);
2849
2850 switch(pname)
2851 {
2852 case GL_UNIFORM_TYPE:
2853 case GL_UNIFORM_SIZE:
2854 case GL_UNIFORM_NAME_LENGTH:
2855 case GL_UNIFORM_BLOCK_INDEX:
2856 case GL_UNIFORM_OFFSET:
2857 case GL_UNIFORM_ARRAY_STRIDE:
2858 case GL_UNIFORM_MATRIX_STRIDE:
2859 case GL_UNIFORM_IS_ROW_MAJOR:
2860 break;
2861 default:
2862 return error(GL_INVALID_ENUM);
2863 }
2864
2865 if(uniformCount < 0)
2866 {
2867 return error(GL_INVALID_VALUE);
2868 }
2869
2870 es2::Context *context = es2::getContext();
2871
2872 if(context)
2873 {
2874 es2::Program *programObject = context->getProgram(program);
2875
2876 if(!programObject)
2877 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002878 if(context->getShader(program))
2879 {
2880 return error(GL_INVALID_OPERATION);
2881 }
2882 else
2883 {
2884 return error(GL_INVALID_VALUE);
2885 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002886 }
2887
2888 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2889 {
2890 const GLuint index = uniformIndices[uniformId];
2891
2892 if(index >= programObject->getActiveUniformCount())
2893 {
2894 return error(GL_INVALID_VALUE);
2895 }
2896 }
2897
2898 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2899 {
2900 const GLuint index = uniformIndices[uniformId];
2901 params[uniformId] = programObject->getActiveUniformi(index, pname);
2902 }
2903 }
2904}
2905
2906GL_APICALL GLuint GL_APIENTRY glGetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName)
2907{
2908 TRACE("(GLuint program = %d, const GLchar *uniformBlockName = %p)",
2909 program, uniformBlockName);
2910
2911 es2::Context *context = es2::getContext();
2912
2913 if(context)
2914 {
2915 es2::Program *programObject = context->getProgram(program);
2916
2917 if(!programObject)
2918 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002919 if(context->getShader(program))
2920 {
2921 return error(GL_INVALID_OPERATION, GL_INVALID_INDEX);
2922 }
2923 else
2924 {
2925 return error(GL_INVALID_VALUE, GL_INVALID_INDEX);
2926 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002927 }
2928
2929 return programObject->getUniformBlockIndex(uniformBlockName);
2930 }
2931
2932 return GL_INVALID_INDEX;
2933}
2934
2935GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params)
2936{
2937 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLenum pname = 0x%X, GLint *params = %p)",
2938 program, uniformBlockIndex, pname, params);
2939
2940 es2::Context *context = es2::getContext();
2941
2942 if(context)
2943 {
2944 es2::Program *programObject = context->getProgram(program);
2945
2946 if(!programObject)
2947 {
2948 return error(GL_INVALID_OPERATION);
2949 }
2950
2951 switch(pname)
2952 {
2953 case GL_UNIFORM_BLOCK_BINDING:
2954 *params = static_cast<GLint>(programObject->getUniformBlockBinding(uniformBlockIndex));
2955 break;
2956 case GL_UNIFORM_BLOCK_DATA_SIZE:
2957 case GL_UNIFORM_BLOCK_NAME_LENGTH:
2958 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2959 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2960 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2961 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2962 programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
2963 break;
2964 default:
2965 return error(GL_INVALID_ENUM);
2966 }
2967 }
2968}
2969
2970GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName)
2971{
2972 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLchar *uniformBlockName = %p)",
2973 program, uniformBlockIndex, bufSize, length, uniformBlockName);
2974
2975 if(bufSize < 0)
2976 {
2977 return error(GL_INVALID_VALUE);
2978 }
2979
2980 es2::Context *context = es2::getContext();
2981
2982 if(context)
2983 {
2984 es2::Program *programObject = context->getProgram(program);
2985
2986 if(!programObject)
2987 {
2988 return error(GL_INVALID_OPERATION);
2989 }
2990
2991 programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
2992 }
2993}
2994
2995GL_APICALL void GL_APIENTRY glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
2996{
2997 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLuint uniformBlockBinding = %d)",
2998 program, uniformBlockIndex, uniformBlockBinding);
2999
3000 if(uniformBlockBinding >= MAX_UNIFORM_BUFFER_BINDINGS)
3001 {
3002 return error(GL_INVALID_VALUE);
3003 }
3004
3005 es2::Context *context = es2::getContext();
3006
3007 if(context)
3008 {
3009 es2::Program *programObject = context->getProgram(program);
3010
3011 if(!programObject)
3012 {
3013 return error(GL_INVALID_VALUE);
3014 }
3015
Nicolas Capens65dcbbd2016-08-12 16:59:04 -04003016 programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003017 }
3018}
3019
3020GL_APICALL void GL_APIENTRY glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
3021{
3022 TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
3023 mode, first, count, instanceCount);
3024
3025 switch(mode)
3026 {
3027 case GL_POINTS:
3028 case GL_LINES:
3029 case GL_LINE_LOOP:
3030 case GL_LINE_STRIP:
3031 case GL_TRIANGLES:
3032 case GL_TRIANGLE_FAN:
3033 case GL_TRIANGLE_STRIP:
3034 break;
3035 default:
3036 return error(GL_INVALID_ENUM);
3037 }
3038
3039 if(count < 0 || instanceCount < 0)
3040 {
3041 return error(GL_INVALID_VALUE);
3042 }
3043
3044 es2::Context *context = es2::getContext();
3045
3046 if(context)
3047 {
3048 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
3049 if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
3050 {
3051 return error(GL_INVALID_OPERATION);
3052 }
3053
3054 context->drawArrays(mode, first, count, instanceCount);
3055 }
3056}
3057
3058GL_APICALL void GL_APIENTRY glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
3059{
3060 TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = %p, GLsizei instanceCount = %d)",
3061 mode, count, type, indices, instanceCount);
3062
3063 switch(mode)
3064 {
3065 case GL_POINTS:
3066 case GL_LINES:
3067 case GL_LINE_LOOP:
3068 case GL_LINE_STRIP:
3069 case GL_TRIANGLES:
3070 case GL_TRIANGLE_FAN:
3071 case GL_TRIANGLE_STRIP:
3072 break;
3073 default:
3074 return error(GL_INVALID_ENUM);
3075 }
3076
3077 switch(type)
3078 {
3079 case GL_UNSIGNED_BYTE:
3080 case GL_UNSIGNED_SHORT:
3081 case GL_UNSIGNED_INT:
3082 break;
3083 default:
3084 return error(GL_INVALID_ENUM);
3085 }
3086
3087 if(count < 0 || instanceCount < 0)
3088 {
3089 return error(GL_INVALID_VALUE);
3090 }
3091
3092 es2::Context *context = es2::getContext();
3093
3094 if(context)
3095 {
3096 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
3097 if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
3098 {
3099 return error(GL_INVALID_OPERATION);
3100 }
3101
3102 context->drawElements(mode, 0, MAX_ELEMENT_INDEX, count, type, indices, instanceCount);
3103 }
3104}
3105
3106GL_APICALL GLsync GL_APIENTRY glFenceSync(GLenum condition, GLbitfield flags)
3107{
3108 TRACE("(GLenum condition = 0x%X, GLbitfield flags = %X)", condition, flags);
3109
3110 switch(condition)
3111 {
3112 case GL_SYNC_GPU_COMMANDS_COMPLETE:
3113 break;
3114 default:
3115 return error(GL_INVALID_ENUM, nullptr);
3116 }
3117
3118 if(flags != 0)
3119 {
3120 return error(GL_INVALID_VALUE, nullptr);
3121 }
3122
3123 es2::Context *context = es2::getContext();
3124
3125 if(context)
3126 {
3127 return context->createFenceSync(condition, flags);
3128 }
3129
3130 return nullptr;
3131}
3132
3133GL_APICALL GLboolean GL_APIENTRY glIsSync(GLsync sync)
3134{
3135 TRACE("(GLsync sync = %p)", sync);
3136
3137 es2::Context *context = es2::getContext();
3138
3139 if(context)
3140 {
3141 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
3142
3143 if(fenceSyncObject)
3144 {
3145 return GL_TRUE;
3146 }
3147 }
3148
3149 return GL_FALSE;
3150}
3151
3152GL_APICALL void GL_APIENTRY glDeleteSync(GLsync sync)
3153{
3154 TRACE("(GLsync sync = %p)", sync);
3155
Alexis Hetuadd96ad2017-11-14 17:22:46 -05003156 if(!sync)
3157 {
3158 return;
3159 }
3160
Nicolas Capens0bac2852016-05-07 06:09:58 -04003161 es2::Context *context = es2::getContext();
3162
3163 if(context)
3164 {
Alexis Hetuadd96ad2017-11-14 17:22:46 -05003165 if(!context->getFenceSync(sync))
3166 {
3167 return error(GL_INVALID_VALUE);
3168 }
3169
Nicolas Capens0bac2852016-05-07 06:09:58 -04003170 context->deleteFenceSync(sync);
3171 }
3172}
3173
3174GL_APICALL GLenum GL_APIENTRY glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
3175{
3176 TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
3177
3178 if((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0)
3179 {
Alexis Hetu6e864492017-11-14 15:27:00 -05003180 return error(GL_INVALID_VALUE, GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003181 }
3182
3183 es2::Context *context = es2::getContext();
3184
3185 if(context)
3186 {
3187 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
3188
3189 if(fenceSyncObject)
3190 {
3191 return fenceSyncObject->clientWait(flags, timeout);
3192 }
3193 else
3194 {
3195 return error(GL_INVALID_VALUE, GL_FALSE);
3196 }
3197 }
3198
3199 return GL_FALSE;
3200}
3201
3202GL_APICALL void GL_APIENTRY glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
3203{
3204 TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
3205
3206 if(flags != 0)
3207 {
3208 return error(GL_INVALID_VALUE);
3209 }
3210
3211 if(timeout != GL_TIMEOUT_IGNORED)
3212 {
3213 return error(GL_INVALID_VALUE);
3214 }
3215
3216 es2::Context *context = es2::getContext();
3217
3218 if(context)
3219 {
3220 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
3221
3222 if(fenceSyncObject)
3223 {
3224 fenceSyncObject->serverWait(flags, timeout);
3225 }
3226 else
3227 {
3228 return error(GL_INVALID_VALUE);
3229 }
3230 }
3231}
3232
3233GL_APICALL void GL_APIENTRY glGetInteger64v(GLenum pname, GLint64 *data)
3234{
3235 TRACE("(GLenum pname = 0x%X, GLint64 *data = %p)", pname, data);
3236
3237 es2::Context *context = es2::getContext();
3238
3239 if(context)
3240 {
3241 if(!(context->getIntegerv(pname, data)))
3242 {
3243 GLenum nativeType;
3244 unsigned int numParams = 0;
3245 if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))
3246 return error(GL_INVALID_ENUM);
3247
3248 if(numParams == 0)
3249 return; // it is known that pname is valid, but there are no parameters to return
3250
3251 if(nativeType == GL_BOOL)
3252 {
3253 GLboolean *boolParams = nullptr;
3254 boolParams = new GLboolean[numParams];
3255
3256 context->getBooleanv(pname, boolParams);
3257
3258 for(unsigned int i = 0; i < numParams; ++i)
3259 {
3260 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
3261 }
3262
3263 delete[] boolParams;
3264 }
3265 else if(nativeType == GL_FLOAT)
3266 {
3267 GLfloat *floatParams = nullptr;
3268 floatParams = new GLfloat[numParams];
3269
3270 context->getFloatv(pname, floatParams);
3271
3272 for(unsigned int i = 0; i < numParams; ++i)
3273 {
3274 if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
3275 {
Nicolas Capens53318fa2016-04-11 17:41:39 -04003276 data[i] = (GLint64)(convert_float_int(floatParams[i]));
Nicolas Capens0bac2852016-05-07 06:09:58 -04003277 }
3278 else
3279 {
3280 data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
3281 }
3282 }
3283
3284 delete[] floatParams;
3285 }
3286 }
3287 }
3288}
3289
3290GL_APICALL void GL_APIENTRY glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
3291{
3292 TRACE("(GLsync sync = %p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei *length = %p, GLint *values = %p)",
3293 sync, pname, bufSize, length, values);
3294
3295 if(bufSize < 0)
3296 {
3297 return error(GL_INVALID_VALUE);
3298 }
3299
Alexis Hetu0f7c7b82017-02-17 17:07:50 -05003300 es2::Context *context = es2::getContext();
3301
3302 if(context)
3303 {
3304 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
3305 if(!fenceSyncObject)
3306 {
3307 return error(GL_INVALID_VALUE);
3308 }
3309
3310 fenceSyncObject->getSynciv(pname, length, values);
3311 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003312}
3313
3314GL_APICALL void GL_APIENTRY glGetInteger64i_v(GLenum target, GLuint index, GLint64 *data)
3315{
3316 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint64 *data = %p)", target, index, data);
3317
3318 es2::Context *context = es2::getContext();
3319
3320 if(context)
3321 {
3322 if(!context->getTransformFeedbackiv(index, target, data) &&
3323 !context->getUniformBufferiv(index, target, data) &&
3324 !context->getIntegerv(target, data))
3325 {
3326 GLenum nativeType;
3327 unsigned int numParams = 0;
3328 if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
3329 return error(GL_INVALID_ENUM);
3330
3331 if(numParams == 0)
3332 return; // it is known that target is valid, but there are no parameters to return
3333
3334 if(nativeType == GL_BOOL)
3335 {
3336 GLboolean *boolParams = nullptr;
3337 boolParams = new GLboolean[numParams];
3338
3339 context->getBooleanv(target, boolParams);
3340
3341 for(unsigned int i = 0; i < numParams; ++i)
3342 {
3343 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
3344 }
3345
3346 delete[] boolParams;
3347 }
3348 else if(nativeType == GL_FLOAT)
3349 {
3350 GLfloat *floatParams = nullptr;
3351 floatParams = new GLfloat[numParams];
3352
3353 context->getFloatv(target, floatParams);
3354
3355 for(unsigned int i = 0; i < numParams; ++i)
3356 {
3357 if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
3358 {
Nicolas Capens53318fa2016-04-11 17:41:39 -04003359 data[i] = (GLint64)(convert_float_int(floatParams[i]));
Nicolas Capens0bac2852016-05-07 06:09:58 -04003360 }
3361 else
3362 {
3363 data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
3364 }
3365 }
3366
3367 delete[] floatParams;
3368 }
3369 }
3370 }
3371}
3372
3373GL_APICALL void GL_APIENTRY glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
3374{
3375 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64 *params = %p)", target, pname, params);
3376
3377 es2::Context *context = es2::getContext();
3378
3379 if(context)
3380 {
3381 es2::Buffer *buffer = nullptr;
3382
3383 if(!context->getBuffer(target, &buffer))
3384 {
3385 return error(GL_INVALID_ENUM);
3386 }
3387
3388 if(!buffer)
3389 {
3390 // A null buffer means that "0" is bound to the requested buffer target
3391 return error(GL_INVALID_OPERATION);
3392 }
3393
3394 switch(pname)
3395 {
3396 case GL_BUFFER_USAGE:
3397 *params = buffer->usage();
3398 break;
3399 case GL_BUFFER_SIZE:
3400 *params = buffer->size();
3401 break;
3402 case GL_BUFFER_ACCESS_FLAGS:
3403 *params = buffer->access();
3404 break;
3405 case GL_BUFFER_MAPPED:
3406 *params = buffer->isMapped();
3407 break;
3408 case GL_BUFFER_MAP_LENGTH:
3409 *params = buffer->length();
3410 break;
3411 case GL_BUFFER_MAP_OFFSET:
3412 *params = buffer->offset();
3413 break;
3414 default:
3415 return error(GL_INVALID_ENUM);
3416 }
3417 }
3418}
3419
3420GL_APICALL void GL_APIENTRY glGenSamplers(GLsizei count, GLuint *samplers)
3421{
3422 TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3423
3424 if(count < 0)
3425 {
3426 return error(GL_INVALID_VALUE);
3427 }
3428
3429 es2::Context *context = es2::getContext();
3430
3431 if(context)
3432 {
3433 for(int i = 0; i < count; i++)
3434 {
3435 samplers[i] = context->createSampler();
3436 }
3437 }
3438}
3439
3440GL_APICALL void GL_APIENTRY glDeleteSamplers(GLsizei count, const GLuint *samplers)
3441{
3442 TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3443
3444 if(count < 0)
3445 {
3446 return error(GL_INVALID_VALUE);
3447 }
3448
3449 es2::Context *context = es2::getContext();
3450
3451 if(context)
3452 {
3453 for(int i = 0; i < count; i++)
3454 {
3455 context->deleteSampler(samplers[i]);
3456 }
3457 }
3458}
3459
3460GL_APICALL GLboolean GL_APIENTRY glIsSampler(GLuint sampler)
3461{
3462 TRACE("(GLuint sampler = %d)", sampler);
3463
3464 if(sampler == 0)
3465 {
3466 return GL_FALSE;
3467 }
3468
3469 es2::Context *context = es2::getContext();
3470
3471 if(context)
3472 {
3473 if(context->isSampler(sampler))
3474 {
3475 return GL_TRUE;
3476 }
3477 }
3478
3479 return GL_FALSE;
3480}
3481
3482GL_APICALL void GL_APIENTRY glBindSampler(GLuint unit, GLuint sampler)
3483{
3484 TRACE("(GLuint unit = %d, GLuint sampler = %d)", unit, sampler);
3485
3486 if(unit >= es2::MAX_COMBINED_TEXTURE_IMAGE_UNITS)
3487 {
3488 return error(GL_INVALID_VALUE);
3489 }
3490
3491 es2::Context *context = es2::getContext();
3492
3493 if(context)
3494 {
3495 if(sampler != 0 && !context->isSampler(sampler))
3496 {
3497 return error(GL_INVALID_OPERATION);
3498 }
3499
3500 context->bindSampler(unit, sampler);
3501 }
3502}
3503
3504GL_APICALL void GL_APIENTRY glSamplerParameteri(GLuint sampler, GLenum pname, GLint param)
3505{
3506 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint param = %d)",
3507 sampler, pname, param);
3508
3509 glSamplerParameteriv(sampler, pname, &param);
3510}
3511
3512GL_APICALL void GL_APIENTRY glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param)
3513{
3514 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLint *param = %p)",
3515 sampler, pname, param);
3516
3517 if(!ValidateSamplerObjectParameter(pname))
3518 {
3519 return error(GL_INVALID_ENUM);
3520 }
3521
3522 if(!ValidateTexParamParameters(pname, *param))
3523 {
3524 return;
3525 }
3526
3527 es2::Context *context = es2::getContext();
3528
3529 if(context)
3530 {
3531 if(!context->isSampler(sampler))
3532 {
3533 return error(GL_INVALID_OPERATION);
3534 }
3535
3536 context->samplerParameteri(sampler, pname, *param);
3537 }
3538}
3539
3540GL_APICALL void GL_APIENTRY glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
3541{
3542 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat param = %f)",
3543 sampler, pname, param);
3544
3545 glSamplerParameterfv(sampler, pname, &param);
3546}
3547
3548GL_APICALL void GL_APIENTRY glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param)
3549{
3550 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLfloat *param = %p)",
3551 sampler, pname, param);
3552
3553 if(!ValidateSamplerObjectParameter(pname))
3554 {
3555 return error(GL_INVALID_ENUM);
3556 }
3557
Nicolas Capens0bac2852016-05-07 06:09:58 -04003558 es2::Context *context = es2::getContext();
3559
3560 if(context)
3561 {
3562 if(!context->isSampler(sampler))
3563 {
3564 return error(GL_INVALID_OPERATION);
3565 }
3566
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003567 if(ValidateTexParamParameters(pname, static_cast<GLint>(roundf(*param))))
3568 {
3569 context->samplerParameterf(sampler, pname, *param);
3570 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003571 }
3572}
3573
3574GL_APICALL void GL_APIENTRY glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
3575{
3576 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint *params = %p)",
3577 sampler, pname, params);
3578
3579 if(!ValidateSamplerObjectParameter(pname))
3580 {
3581 return error(GL_INVALID_ENUM);
3582 }
3583
3584 es2::Context *context = es2::getContext();
3585
3586 if(context)
3587 {
3588 if(!context->isSampler(sampler))
3589 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003590 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003591 }
3592
3593 *params = context->getSamplerParameteri(sampler, pname);
3594 }
3595}
3596
3597GL_APICALL void GL_APIENTRY glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
3598{
3599 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat *params = %p)",
3600 sampler, pname, params);
3601
3602 if(!ValidateSamplerObjectParameter(pname))
3603 {
3604 return error(GL_INVALID_ENUM);
3605 }
3606
3607 es2::Context *context = es2::getContext();
3608
3609 if(context)
3610 {
3611 if(!context->isSampler(sampler))
3612 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003613 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003614 }
3615
3616 *params = context->getSamplerParameterf(sampler, pname);
3617 }
3618}
3619
3620GL_APICALL void GL_APIENTRY glVertexAttribDivisor(GLuint index, GLuint divisor)
3621{
3622 TRACE("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
3623
3624 es2::Context *context = es2::getContext();
3625
3626 if(context)
3627 {
3628 if(index >= es2::MAX_VERTEX_ATTRIBS)
3629 {
3630 return error(GL_INVALID_VALUE);
3631 }
3632
3633 context->setVertexAttribDivisor(index, divisor);
3634 }
3635}
3636
3637GL_APICALL void GL_APIENTRY glBindTransformFeedback(GLenum target, GLuint id)
3638{
3639 TRACE("(GLenum target = 0x%X, GLuint id = %d)", target, id);
3640
3641 if(target != GL_TRANSFORM_FEEDBACK)
3642 {
3643 return error(GL_INVALID_ENUM);
3644 }
3645
3646 es2::Context *context = es2::getContext();
3647
3648 if(context)
3649 {
3650 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3651
3652 if(transformFeedbackObject && transformFeedbackObject->isActive() && !transformFeedbackObject->isPaused())
3653 {
3654 return error(GL_INVALID_OPERATION);
3655 }
3656
Alexis Hetu5bf97082017-11-14 11:06:03 -05003657 if(!context->isTransformFeedback(id))
3658 {
3659 return error(GL_INVALID_OPERATION);
3660 }
3661
Nicolas Capens0bac2852016-05-07 06:09:58 -04003662 context->bindTransformFeedback(id);
3663 }
3664}
3665
3666GL_APICALL void GL_APIENTRY glDeleteTransformFeedbacks(GLsizei n, const GLuint *ids)
3667{
3668 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3669
3670 if(n < 0)
3671 {
3672 return error(GL_INVALID_VALUE);
3673 }
3674
3675 es2::Context *context = es2::getContext();
3676
3677 if(context)
3678 {
3679 for(int i = 0; i < n; i++)
3680 {
3681 if(ids[i] != 0)
3682 {
Alexis Hetu5bf97082017-11-14 11:06:03 -05003683 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(ids[i]);
3684
3685 if(transformFeedbackObject && transformFeedbackObject->isActive())
3686 {
3687 return error(GL_INVALID_OPERATION);
3688 }
3689
Nicolas Capens0bac2852016-05-07 06:09:58 -04003690 context->deleteTransformFeedback(ids[i]);
3691 }
3692 }
3693 }
3694}
3695
3696GL_APICALL void GL_APIENTRY glGenTransformFeedbacks(GLsizei n, GLuint *ids)
3697{
3698 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3699
3700 if(n < 0)
3701 {
3702 return error(GL_INVALID_VALUE);
3703 }
3704
3705 es2::Context *context = es2::getContext();
3706
3707 if(context)
3708 {
3709 for(int i = 0; i < n; i++)
3710 {
3711 ids[i] = context->createTransformFeedback();
3712 }
3713 }
3714}
3715
3716GL_APICALL GLboolean GL_APIENTRY glIsTransformFeedback(GLuint id)
3717{
3718 TRACE("(GLuint id = %d)", id);
3719
3720 if(id == 0)
3721 {
3722 return GL_FALSE;
3723 }
3724
3725 es2::Context *context = es2::getContext();
3726
3727 if(context)
3728 {
3729 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(id);
3730
3731 if(transformFeedbackObject)
3732 {
3733 return GL_TRUE;
3734 }
3735 }
3736
3737 return GL_FALSE;
3738}
3739
3740GL_APICALL void GL_APIENTRY glPauseTransformFeedback(void)
3741{
3742 TRACE("()");
3743
3744 es2::Context *context = es2::getContext();
3745
3746 if(context)
3747 {
3748 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3749
3750 if(transformFeedbackObject)
3751 {
3752 if(!transformFeedbackObject->isActive() || transformFeedbackObject->isPaused())
3753 {
3754 return error(GL_INVALID_OPERATION);
3755 }
3756 transformFeedbackObject->setPaused(true);
3757 }
3758 }
3759}
3760
3761GL_APICALL void GL_APIENTRY glResumeTransformFeedback(void)
3762{
3763 TRACE("()");
3764
3765 es2::Context *context = es2::getContext();
3766
3767 if(context)
3768 {
3769 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3770
3771 if(transformFeedbackObject)
3772 {
3773 if(!transformFeedbackObject->isActive() || !transformFeedbackObject->isPaused())
3774 {
3775 return error(GL_INVALID_OPERATION);
3776 }
3777 transformFeedbackObject->setPaused(false);
3778 }
3779 }
3780}
3781
3782GL_APICALL void GL_APIENTRY glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
3783{
3784 TRACE("(GLuint program = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLenum *binaryFormat = %p, void *binary = %p)",
3785 program, bufSize, length, binaryFormat, binary);
3786
3787 if(bufSize < 0)
3788 {
3789 return error(GL_INVALID_VALUE);
3790 }
3791
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003792 es2::Context *context = es2::getContext();
3793
3794 if(context)
3795 {
3796 es2::Program *programObject = context->getProgram(program);
3797
3798 if(!programObject || !programObject->isLinked())
3799 {
3800 return error(GL_INVALID_OPERATION);
3801 }
3802 }
3803
Nicolas Capens0bac2852016-05-07 06:09:58 -04003804 UNIMPLEMENTED();
3805}
3806
3807GL_APICALL void GL_APIENTRY glProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length)
3808{
3809 TRACE("(GLuint program = %d, GLenum binaryFormat = 0x%X, const void *binary = %p, GLsizei length = %d)",
3810 program, binaryFormat, binaryFormat, length);
3811
3812 if(length < 0)
3813 {
3814 return error(GL_INVALID_VALUE);
3815 }
3816
3817 UNIMPLEMENTED();
3818}
3819
3820GL_APICALL void GL_APIENTRY glProgramParameteri(GLuint program, GLenum pname, GLint value)
3821{
3822 TRACE("(GLuint program = %d, GLenum pname = 0x%X, GLint value = %d)",
3823 program, pname, value);
3824
3825 es2::Context *context = es2::getContext();
3826
3827 if(context)
3828 {
3829 es2::Program *programObject = context->getProgram(program);
3830
3831 if(!programObject)
3832 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003833 return error(GL_INVALID_VALUE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003834 }
3835
3836 switch(pname)
3837 {
3838 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003839 if((value != GL_TRUE) && (value != GL_FALSE))
3840 {
3841 return error(GL_INVALID_VALUE);
3842 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003843 programObject->setBinaryRetrievable(value != GL_FALSE);
3844 break;
3845 default:
3846 return error(GL_INVALID_ENUM);
3847 }
3848 }
3849}
3850
3851GL_APICALL void GL_APIENTRY glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
3852{
3853 TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p)",
3854 target, numAttachments, attachments);
3855
3856 glInvalidateSubFramebuffer(target, numAttachments, attachments, 0, 0, std::numeric_limits<GLsizei>::max(), std::numeric_limits<GLsizei>::max());
3857}
3858
3859GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
3860{
3861 TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
3862 target, numAttachments, attachments, x, y, width, height);
3863
3864 es2::Context *context = es2::getContext();
3865
3866 if(context)
3867 {
3868 if(numAttachments < 0 || width < 0 || height < 0)
3869 {
3870 return error(GL_INVALID_VALUE);
3871 }
3872
3873 es2::Framebuffer *framebuffer = nullptr;
3874 switch(target)
3875 {
3876 case GL_DRAW_FRAMEBUFFER:
3877 case GL_FRAMEBUFFER:
3878 framebuffer = context->getDrawFramebuffer();
3879 case GL_READ_FRAMEBUFFER:
3880 framebuffer = context->getReadFramebuffer();
3881 break;
3882 default:
3883 return error(GL_INVALID_ENUM);
3884 }
3885
3886 if(framebuffer)
3887 {
3888 for(int i = 0; i < numAttachments; i++)
3889 {
3890 switch(attachments[i])
3891 {
3892 case GL_COLOR:
3893 case GL_DEPTH:
3894 case GL_STENCIL:
3895 if(!framebuffer->isDefaultFramebuffer())
3896 {
3897 return error(GL_INVALID_ENUM);
3898 }
3899 break;
3900 case GL_DEPTH_ATTACHMENT:
3901 case GL_STENCIL_ATTACHMENT:
3902 case GL_DEPTH_STENCIL_ATTACHMENT:
3903 break;
3904 default:
3905 if(attachments[i] >= GL_COLOR_ATTACHMENT0 &&
3906 attachments[i] <= GL_COLOR_ATTACHMENT31)
3907 {
3908 if(attachments[i] - GL_COLOR_ATTACHMENT0 >= MAX_DRAW_BUFFERS)
3909 {
3910 return error(GL_INVALID_OPERATION);
3911 }
3912 }
3913 else
3914 {
3915 return error(GL_INVALID_ENUM);
3916 }
3917 break;
3918 }
3919 }
3920 }
3921
3922 // UNIMPLEMENTED(); // It is valid for this function to be treated as a no-op
3923 }
3924}
3925
3926GL_APICALL void GL_APIENTRY glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
3927{
3928 TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
3929 target, levels, internalformat, width, height);
3930
3931 if(width < 1 || height < 1 || levels < 1)
3932 {
3933 return error(GL_INVALID_VALUE);
3934 }
3935
3936 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
3937 {
3938 return error(GL_INVALID_OPERATION);
3939 }
3940
3941 GLenum type;
3942 if(!GetStorageType(internalformat, type))
3943 {
3944 return error(GL_INVALID_ENUM);
3945 }
3946
3947 es2::Context *context = es2::getContext();
3948
3949 if(context)
3950 {
3951 switch(target)
3952 {
3953 case GL_TEXTURE_2D:
3954 {
3955 es2::Texture2D *texture = context->getTexture2D();
3956 if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
3957 {
3958 return error(GL_INVALID_OPERATION);
3959 }
3960
3961 for(int level = 0; level < levels; ++level)
3962 {
Nicolas Capens81aa97b2017-06-27 17:08:08 -04003963 texture->setImage(context, level, width, height, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003964 width = std::max(1, (width / 2));
3965 height = std::max(1, (height / 2));
3966 }
3967 texture->makeImmutable(levels);
3968 }
3969 break;
3970 case GL_TEXTURE_CUBE_MAP:
3971 {
3972 es2::TextureCubeMap *texture = context->getTextureCubeMap();
3973 if(!texture || texture->name == 0 || texture->getImmutableFormat())
3974 {
3975 return error(GL_INVALID_OPERATION);
3976 }
3977
3978 for(int level = 0; level < levels; ++level)
3979 {
3980 for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; ++face)
3981 {
Nicolas Capens81aa97b2017-06-27 17:08:08 -04003982 texture->setImage(context, face, level, width, height, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003983 }
3984 width = std::max(1, (width / 2));
3985 height = std::max(1, (height / 2));
3986 }
3987 texture->makeImmutable(levels);
3988 }
3989 break;
3990 default:
3991 return error(GL_INVALID_ENUM);
3992 }
3993 }
3994}
3995
3996GL_APICALL void GL_APIENTRY glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
3997{
3998 TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d)",
3999 target, levels, internalformat, width, height, depth);
4000
4001 if(width < 1 || height < 1 || depth < 1 || levels < 1)
4002 {
4003 return error(GL_INVALID_VALUE);
4004 }
4005
4006 GLenum type;
4007 if(!GetStorageType(internalformat, type))
4008 {
4009 return error(GL_INVALID_ENUM);
4010 }
4011
4012 es2::Context *context = es2::getContext();
4013
4014 if(context)
4015 {
4016 switch(target)
4017 {
4018 case GL_TEXTURE_3D:
4019 {
4020 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(std::max(width, height), depth)) + 1))
4021 {
4022 return error(GL_INVALID_OPERATION);
4023 }
4024
4025 es2::Texture3D *texture = context->getTexture3D();
4026 if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
4027 {
4028 return error(GL_INVALID_OPERATION);
4029 }
4030
4031 for(int level = 0; level < levels; ++level)
4032 {
Nicolas Capens81aa97b2017-06-27 17:08:08 -04004033 texture->setImage(context, level, width, height, depth, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04004034 width = std::max(1, (width / 2));
4035 height = std::max(1, (height / 2));
4036 depth = std::max(1, (depth / 2));
4037 }
4038 texture->makeImmutable(levels);
4039 }
4040 break;
4041 case GL_TEXTURE_2D_ARRAY:
4042 {
4043 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
4044 {
4045 return error(GL_INVALID_OPERATION);
4046 }
4047
4048 es2::Texture3D *texture = context->getTexture2DArray();
4049 if(!texture || texture->name == 0 || texture->getImmutableFormat())
4050 {
4051 return error(GL_INVALID_OPERATION);
4052 }
4053
4054 for(int level = 0; level < levels; ++level)
4055 {
4056 for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; ++face)
4057 {
Nicolas Capens81aa97b2017-06-27 17:08:08 -04004058 texture->setImage(context, level, width, height, depth, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04004059 }
4060 width = std::max(1, (width / 2));
4061 height = std::max(1, (height / 2));
4062 }
4063 texture->makeImmutable(levels);
4064 }
4065 break;
4066 default:
4067 return error(GL_INVALID_ENUM);
4068 }
4069 }
4070}
4071
4072GL_APICALL void GL_APIENTRY glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params)
4073{
4074 TRACE("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, GLint *params = %p)",
4075 target, internalformat, pname, bufSize, params);
4076
4077 if(bufSize < 0)
4078 {
4079 return error(GL_INVALID_VALUE);
4080 }
4081
4082 if(bufSize == 0)
4083 {
4084 return;
4085 }
4086
Nicolas Capensd2faaa92017-12-04 11:15:51 -05004087 if(!IsColorRenderable(internalformat, egl::getClientVersion()) &&
Nicolas Capens400667e2017-03-29 14:40:14 -04004088 !IsDepthRenderable(internalformat, egl::getClientVersion()) &&
4089 !IsStencilRenderable(internalformat, egl::getClientVersion()))
Nicolas Capens0bac2852016-05-07 06:09:58 -04004090 {
4091 return error(GL_INVALID_ENUM);
4092 }
4093
4094 switch(target)
4095 {
4096 case GL_RENDERBUFFER:
4097 break;
4098 default:
4099 return error(GL_INVALID_ENUM);
4100 }
4101
4102 // Integer types have no multisampling
4103 GLint numMultisampleCounts = NUM_MULTISAMPLE_COUNTS;
4104 switch(internalformat)
4105 {
4106 case GL_R8UI:
4107 case GL_R8I:
4108 case GL_R16UI:
4109 case GL_R16I:
4110 case GL_R32UI:
4111 case GL_R32I:
4112 case GL_RG8UI:
4113 case GL_RG8I:
4114 case GL_RG16UI:
4115 case GL_RG16I:
4116 case GL_RG32UI:
4117 case GL_RG32I:
4118 case GL_RGB8UI:
4119 case GL_RGB8I:
4120 case GL_RGB16UI:
4121 case GL_RGB16I:
4122 case GL_RGB32UI:
4123 case GL_RGB32I:
4124 case GL_RGBA8UI:
4125 case GL_RGBA8I:
4126 case GL_RGB10_A2UI:
4127 case GL_RGBA16UI:
4128 case GL_RGBA16I:
4129 case GL_RGBA32UI:
4130 case GL_RGBA32I:
4131 numMultisampleCounts = 0;
4132 break;
4133 default:
4134 break;
4135 }
4136
4137 switch(pname)
4138 {
4139 case GL_NUM_SAMPLE_COUNTS:
4140 *params = numMultisampleCounts;
4141 break;
4142 case GL_SAMPLES:
4143 for(int i = 0; i < numMultisampleCounts && i < bufSize; i++)
4144 {
4145 params[i] = multisampleCount[i];
4146 }
4147 break;
4148 default:
4149 return error(GL_INVALID_ENUM);
4150 }
4151}
4152
4153}