blob: 2d646ec16a56fd8f3d82d313affbba35915897a8 [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
732 GLenum validationError = ValidateSubImageParams(false, width, height, depth, xoffset, yoffset, zoffset, target, level, sizedInternalFormat, texture);
733 if(validationError == GL_NONE)
734 {
Alexis Hetu848aa7f2017-11-17 13:15:32 -0500735 GLenum validationError = context->getPixels(&data, type, context->getRequiredBufferSize(width, height, depth, sizedInternalFormat, type));
Alexis Hetuf97f6e02017-11-15 13:01:28 -0500736 if(validationError != GL_NONE)
737 {
738 return error(validationError);
739 }
740
741 texture->subImage(context, level, xoffset, yoffset, zoffset, width, height, depth, sizedInternalFormat, type, context->getUnpackInfo(), data);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400742 }
743 else
744 {
745 return error(validationError);
746 }
747 }
748}
749
750GL_APICALL void GL_APIENTRY glCopyTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height)
751{
752 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
753 "GLint zoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
754 target, level, xoffset, yoffset, zoffset, x, y, width, height);
755
756 switch(target)
757 {
758 case GL_TEXTURE_3D:
759 case GL_TEXTURE_2D_ARRAY:
760 break;
761 default:
762 return error(GL_INVALID_ENUM);
763 }
764
765 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
766 {
767 return error(GL_INVALID_VALUE);
768 }
769
770 if((width < 0) || (height < 0) || (xoffset < 0) || (yoffset < 0) || (zoffset < 0))
771 {
772 return error(GL_INVALID_VALUE);
773 }
774
775 es2::Context *context = es2::getContext();
776
777 if(context)
778 {
779 es2::Framebuffer *framebuffer = context->getReadFramebuffer();
780
781 if(framebuffer->completeness() != GL_FRAMEBUFFER_COMPLETE)
782 {
783 return error(GL_INVALID_FRAMEBUFFER_OPERATION);
784 }
785
786 es2::Renderbuffer *source = framebuffer->getReadColorbuffer();
787
788 if(context->getReadFramebufferName() != 0 && (!source || source->getSamples() > 1))
789 {
790 return error(GL_INVALID_OPERATION);
791 }
792
793 GLenum colorbufferFormat = source->getFormat();
794 es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
795
796 GLenum validationError = ValidateSubImageParams(false, width, height, 1, xoffset, yoffset, zoffset, target, level, GL_NONE, texture);
797 if(validationError != GL_NONE)
798 {
799 return error(validationError);
800 }
801
802 GLenum textureFormat = texture->getFormat(target, level);
803
804 if(!validateColorBufferFormat(textureFormat, colorbufferFormat))
805 {
806 return;
807 }
808
809 texture->copySubImage(target, level, xoffset, yoffset, zoffset, x, y, width, height, framebuffer);
810 }
811}
812
813GL_APICALL void GL_APIENTRY glCompressedTexImage3D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void *data)
814{
815 TRACE("(GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, "
816 "GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLsizei imageSize = %d, const GLvoid* data = %p)",
817 target, level, internalformat, width, height, depth, border, imageSize, data);
818
819 switch(target)
820 {
821 case GL_TEXTURE_3D:
822 case GL_TEXTURE_2D_ARRAY:
823 break;
824 default:
825 return error(GL_INVALID_ENUM);
826 }
827
828 if((level < 0) || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
829 {
830 return error(GL_INVALID_VALUE);
831 }
832
833 const GLsizei maxSize3D = es2::IMPLEMENTATION_MAX_TEXTURE_SIZE >> level;
834 if((width < 0) || (height < 0) || (depth < 0) || (width > maxSize3D) || (height > maxSize3D) || (depth > maxSize3D) || (border != 0) || (imageSize < 0))
835 {
836 return error(GL_INVALID_VALUE);
837 }
838
839 switch(internalformat)
840 {
841 case GL_DEPTH_COMPONENT:
842 case GL_DEPTH_COMPONENT16:
843 case GL_DEPTH_COMPONENT32_OES:
844 case GL_DEPTH_STENCIL:
845 case GL_DEPTH24_STENCIL8:
846 return error(GL_INVALID_OPERATION);
847 default:
848 {
849 GLenum validationError = ValidateCompressedFormat(internalformat, egl::getClientVersion(), true);
850 if(validationError != GL_NONE)
851 {
852 return error(validationError);
853 }
854 }
855 }
856
857 if(imageSize != egl::ComputeCompressedSize(width, height, internalformat) * depth)
858 {
859 return error(GL_INVALID_VALUE);
860 }
861
862 es2::Context *context = es2::getContext();
863
864 if(context)
865 {
866 es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
867
868 if(!texture)
869 {
870 return error(GL_INVALID_OPERATION);
871 }
872
Alexis Hetu848aa7f2017-11-17 13:15:32 -0500873 GLenum validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
Alexis Hetuf97f6e02017-11-15 13:01:28 -0500874 if(validationError != GL_NONE)
875 {
876 return error(validationError);
877 }
878
Nicolas Capens0bac2852016-05-07 06:09:58 -0400879 texture->setCompressedImage(level, internalformat, width, height, depth, imageSize, data);
880 }
881}
882
883GL_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)
884{
885 TRACE("(GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, "
886 "GLint zoffset = %d, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, "
887 "GLenum format = 0x%X, GLsizei imageSize = %d, const void *data = %p)",
888 target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
889
890 switch(target)
891 {
892 case GL_TEXTURE_3D:
893 case GL_TEXTURE_2D_ARRAY:
894 break;
895 default:
896 return error(GL_INVALID_ENUM);
897 }
898
899 if(level < 0 || level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS)
900 {
901 return error(GL_INVALID_VALUE);
902 }
903
904 if(xoffset < 0 || yoffset < 0 || zoffset < 0 || !validImageSize(level, width, height) || depth < 0 || imageSize < 0)
905 {
906 return error(GL_INVALID_VALUE);
907 }
908
909 GLenum validationError = ValidateCompressedFormat(format, egl::getClientVersion(), true);
910 if(validationError != GL_NONE)
911 {
912 return error(validationError);
913 }
914
Alexis Hetubbb8fc12017-11-21 12:39:41 -0500915 if(imageSize != egl::ComputeCompressedSize(width, height, format) * depth)
Nicolas Capens0bac2852016-05-07 06:09:58 -0400916 {
Alexis Hetubbb8fc12017-11-21 12:39:41 -0500917 return error(GL_INVALID_VALUE);
918 }
919
920 bool is_ETC2_EAC = false;
921 switch(format)
922 {
923 case GL_COMPRESSED_R11_EAC:
924 case GL_COMPRESSED_SIGNED_R11_EAC:
925 case GL_COMPRESSED_RG11_EAC:
926 case GL_COMPRESSED_SIGNED_RG11_EAC:
927 case GL_COMPRESSED_RGB8_ETC2:
928 case GL_COMPRESSED_SRGB8_ETC2:
929 case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
930 case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
931 case GL_COMPRESSED_RGBA8_ETC2_EAC:
932 case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
933 if(target != GL_TEXTURE_2D_ARRAY)
934 {
935 return error(GL_INVALID_OPERATION);
936 }
937
938 if(((width % 4) != 0) || ((height % 4) != 0) ||
939 ((xoffset % 4) != 0) || ((yoffset % 4) != 0))
940 {
941 return error(GL_INVALID_OPERATION);
942 }
943
944 is_ETC2_EAC = true;
945 break;
946 default:
947 break;
Nicolas Capens0bac2852016-05-07 06:09:58 -0400948 }
949
950 es2::Context *context = es2::getContext();
951
952 if(context)
953 {
954 es2::Texture3D *texture = (target == GL_TEXTURE_3D) ? context->getTexture3D() : context->getTexture2DArray();
955
956 if(!texture)
957 {
958 return error(GL_INVALID_OPERATION);
959 }
960
Alexis Hetu848aa7f2017-11-17 13:15:32 -0500961 GLenum validationError = context->getPixels(&data, texture->getType(target, level), imageSize);
Alexis Hetuf97f6e02017-11-15 13:01:28 -0500962 if(validationError != GL_NONE)
963 {
964 return error(validationError);
965 }
966
Alexis Hetubbb8fc12017-11-21 12:39:41 -0500967 if(is_ETC2_EAC)
968 {
969 if(((width + xoffset) != texture->getWidth(target, level)) ||
970 ((height + yoffset) != texture->getHeight(target, level)))
971 {
972 return error(GL_INVALID_OPERATION);
973 }
974 }
975
Alexis Hetuf97f6e02017-11-15 13:01:28 -0500976 texture->subImageCompressed(level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data);
Nicolas Capens0bac2852016-05-07 06:09:58 -0400977 }
978}
979
980GL_APICALL void GL_APIENTRY glGenQueries(GLsizei n, GLuint *ids)
981{
982 TRACE("(GLsizei n = %d, GLuint* ids = %p)", n, ids);
983
984 if(n < 0)
985 {
986 return error(GL_INVALID_VALUE);
987 }
988
989 es2::Context *context = es2::getContext();
990
991 if(context)
992 {
993 for(int i = 0; i < n; i++)
994 {
995 ids[i] = context->createQuery();
996 }
997 }
998}
999
1000GL_APICALL void GL_APIENTRY glDeleteQueries(GLsizei n, const GLuint *ids)
1001{
1002 TRACE("(GLsizei n = %d, GLuint* ids = %p)", n, ids);
1003
1004 if(n < 0)
1005 {
1006 return error(GL_INVALID_VALUE);
1007 }
1008
1009 es2::Context *context = es2::getContext();
1010
1011 if(context)
1012 {
1013 for(int i = 0; i < n; i++)
1014 {
1015 context->deleteQuery(ids[i]);
1016 }
1017 }
1018}
1019
1020GL_APICALL GLboolean GL_APIENTRY glIsQuery(GLuint id)
1021{
1022 TRACE("(GLuint id = %d)", id);
1023
1024 if(id == 0)
1025 {
1026 return GL_FALSE;
1027 }
1028
1029 es2::Context *context = es2::getContext();
1030
1031 if(context)
1032 {
1033 es2::Query *queryObject = context->getQuery(id);
1034
1035 if(queryObject)
1036 {
1037 return GL_TRUE;
1038 }
1039 }
1040
1041 return GL_FALSE;
1042}
1043
1044GL_APICALL void GL_APIENTRY glBeginQuery(GLenum target, GLuint id)
1045{
1046 TRACE("(GLenum target = 0x%X, GLuint id = %d)", target, id);
1047
1048 if(!ValidateQueryTarget(target))
1049 {
1050 return error(GL_INVALID_ENUM);
1051 }
1052
1053 if(id == 0)
1054 {
1055 return error(GL_INVALID_OPERATION);
1056 }
1057
1058 es2::Context *context = es2::getContext();
1059
1060 if(context)
1061 {
1062 context->beginQuery(target, id);
1063 }
1064}
1065
1066GL_APICALL void GL_APIENTRY glEndQuery(GLenum target)
1067{
1068 TRACE("(GLenum target = 0x%X)", target);
1069
1070 if(!ValidateQueryTarget(target))
1071 {
1072 return error(GL_INVALID_ENUM);
1073 }
1074
1075 es2::Context *context = es2::getContext();
1076
1077 if(context)
1078 {
1079 context->endQuery(target);
1080 }
1081}
1082
1083GL_APICALL void GL_APIENTRY glGetQueryiv(GLenum target, GLenum pname, GLint *params)
1084{
1085 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = %p)",
1086 target, pname, params);
1087
1088 if(!ValidateQueryTarget(target) || (pname != GL_CURRENT_QUERY))
1089 {
1090 return error(GL_INVALID_ENUM);
1091 }
1092
1093 es2::Context *context = es2::getContext();
1094
1095 if(context)
1096 {
1097 params[0] = context->getActiveQuery(target);
1098 }
1099}
1100
1101GL_APICALL void GL_APIENTRY glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params)
1102{
1103 TRACE("(GLuint id = %d, GLenum pname = 0x%X, GLint *params = %p)",
1104 id, pname, params);
1105
1106 switch(pname)
1107 {
1108 case GL_QUERY_RESULT:
1109 case GL_QUERY_RESULT_AVAILABLE:
1110 break;
1111 default:
1112 return error(GL_INVALID_ENUM);
1113 }
1114
1115 es2::Context *context = es2::getContext();
1116
1117 if(context)
1118 {
1119 es2::Query *queryObject = context->getQuery(id);
1120
1121 if(!queryObject)
1122 {
1123 return error(GL_INVALID_OPERATION);
1124 }
1125
1126 if(context->getActiveQuery(queryObject->getType()) == id)
1127 {
1128 return error(GL_INVALID_OPERATION);
1129 }
1130
1131 switch(pname)
1132 {
1133 case GL_QUERY_RESULT:
1134 params[0] = queryObject->getResult();
1135 break;
1136 case GL_QUERY_RESULT_AVAILABLE:
1137 params[0] = queryObject->isResultAvailable();
1138 break;
1139 default:
1140 ASSERT(false);
1141 }
1142 }
1143}
1144
1145GL_APICALL GLboolean GL_APIENTRY glUnmapBuffer(GLenum target)
1146{
1147 TRACE("(GLenum target = 0x%X)", target);
1148
1149 es2::Context *context = es2::getContext();
1150
1151 if(context)
1152 {
1153 es2::Buffer *buffer = nullptr;
1154 if(!context->getBuffer(target, &buffer))
1155 {
1156 return error(GL_INVALID_ENUM, GL_TRUE);
1157 }
1158
1159 if(!buffer)
1160 {
1161 // A null buffer means that "0" is bound to the requested buffer target
1162 return error(GL_INVALID_OPERATION, GL_TRUE);
1163 }
1164
Alexis Hetu6e864492017-11-14 15:27:00 -05001165 if(!buffer->isMapped())
1166 {
1167 // Already unmapped
1168 return error(GL_INVALID_OPERATION, GL_TRUE);
1169 }
1170
Nicolas Capens0bac2852016-05-07 06:09:58 -04001171 return buffer->unmap() ? GL_TRUE : GL_FALSE;
1172 }
1173
1174 return GL_TRUE;
1175}
1176
1177GL_APICALL void GL_APIENTRY glGetBufferPointerv(GLenum target, GLenum pname, void **params)
1178{
1179 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint *params = %p)",
1180 target, pname, params);
1181
1182 if(pname != GL_BUFFER_MAP_POINTER)
1183 {
1184 return error(GL_INVALID_ENUM);
1185 }
1186
1187 es2::Context *context = es2::getContext();
1188
1189 if(context)
1190 {
1191 es2::Buffer *buffer = nullptr;
1192 if(!context->getBuffer(target, &buffer))
1193 {
1194 return error(GL_INVALID_ENUM);
1195 }
1196
1197 if(!buffer)
1198 {
1199 // A null buffer means that "0" is bound to the requested buffer target
1200 return error(GL_INVALID_OPERATION);
1201 }
1202
1203 *params = buffer->isMapped() ? (void*)(((const char*)buffer->data()) + buffer->offset()) : nullptr;
1204 }
1205}
1206
1207GL_APICALL void GL_APIENTRY glDrawBuffers(GLsizei n, const GLenum *bufs)
1208{
1209 TRACE("(GLsizei n = %d, const GLenum *bufs = %p)", n, bufs);
1210
1211 if(n < 0 || n > MAX_DRAW_BUFFERS)
1212 {
1213 return error(GL_INVALID_VALUE);
1214 }
1215
1216 es2::Context *context = es2::getContext();
1217
1218 if(context)
1219 {
1220 GLuint drawFramebufferName = context->getDrawFramebufferName();
1221
1222 if((drawFramebufferName == 0) && (n != 1))
1223 {
1224 return error(GL_INVALID_OPERATION);
1225 }
1226
1227 for(unsigned int i = 0; i < (unsigned)n; i++)
1228 {
1229 switch(bufs[i])
1230 {
1231 case GL_BACK:
1232 if(drawFramebufferName != 0)
1233 {
1234 return error(GL_INVALID_OPERATION);
1235 }
1236 break;
1237 case GL_NONE:
1238 break;
1239 case GL_COLOR_ATTACHMENT0:
1240 case GL_COLOR_ATTACHMENT1:
1241 case GL_COLOR_ATTACHMENT2:
1242 case GL_COLOR_ATTACHMENT3:
1243 case GL_COLOR_ATTACHMENT4:
1244 case GL_COLOR_ATTACHMENT5:
1245 case GL_COLOR_ATTACHMENT6:
1246 case GL_COLOR_ATTACHMENT7:
1247 case GL_COLOR_ATTACHMENT8:
1248 case GL_COLOR_ATTACHMENT9:
1249 case GL_COLOR_ATTACHMENT10:
1250 case GL_COLOR_ATTACHMENT11:
1251 case GL_COLOR_ATTACHMENT12:
1252 case GL_COLOR_ATTACHMENT13:
1253 case GL_COLOR_ATTACHMENT14:
1254 case GL_COLOR_ATTACHMENT15:
1255 case GL_COLOR_ATTACHMENT16:
1256 case GL_COLOR_ATTACHMENT17:
1257 case GL_COLOR_ATTACHMENT18:
1258 case GL_COLOR_ATTACHMENT19:
1259 case GL_COLOR_ATTACHMENT20:
1260 case GL_COLOR_ATTACHMENT21:
1261 case GL_COLOR_ATTACHMENT22:
1262 case GL_COLOR_ATTACHMENT23:
1263 case GL_COLOR_ATTACHMENT24:
1264 case GL_COLOR_ATTACHMENT25:
1265 case GL_COLOR_ATTACHMENT26:
1266 case GL_COLOR_ATTACHMENT27:
1267 case GL_COLOR_ATTACHMENT28:
1268 case GL_COLOR_ATTACHMENT29:
1269 case GL_COLOR_ATTACHMENT30:
1270 case GL_COLOR_ATTACHMENT31:
1271 {
1272 GLuint index = (bufs[i] - GL_COLOR_ATTACHMENT0);
1273
1274 if(index >= MAX_COLOR_ATTACHMENTS)
1275 {
1276 return error(GL_INVALID_OPERATION);
1277 }
1278
1279 if(index != i)
1280 {
1281 return error(GL_INVALID_OPERATION);
1282 }
1283
1284 if(drawFramebufferName == 0)
1285 {
1286 return error(GL_INVALID_OPERATION);
1287 }
1288 }
1289 break;
1290 default:
1291 return error(GL_INVALID_ENUM);
1292 }
1293 }
1294
1295 context->setFramebufferDrawBuffers(n, bufs);
1296 }
1297}
1298
1299GL_APICALL void GL_APIENTRY glUniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1300{
1301 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1302
1303 if(count < 0)
1304 {
1305 return error(GL_INVALID_VALUE);
1306 }
1307
Nicolas Capens0bac2852016-05-07 06:09:58 -04001308 es2::Context *context = es2::getContext();
1309
1310 if(context)
1311 {
1312 es2::Program *program = context->getCurrentProgram();
1313
1314 if(!program)
1315 {
1316 return error(GL_INVALID_OPERATION);
1317 }
1318
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001319 if(location == -1)
1320 {
1321 return;
1322 }
1323
Nicolas Capens0bac2852016-05-07 06:09:58 -04001324 if(!program->setUniformMatrix2x3fv(location, count, transpose, value))
1325 {
1326 return error(GL_INVALID_OPERATION);
1327 }
1328 }
1329}
1330
1331GL_APICALL void GL_APIENTRY glUniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1332{
1333 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1334
1335 if(count < 0)
1336 {
1337 return error(GL_INVALID_VALUE);
1338 }
1339
Nicolas Capens0bac2852016-05-07 06:09:58 -04001340 es2::Context *context = es2::getContext();
1341
1342 if(context)
1343 {
1344 es2::Program *program = context->getCurrentProgram();
1345
1346 if(!program)
1347 {
1348 return error(GL_INVALID_OPERATION);
1349 }
1350
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001351 if(location == -1)
1352 {
1353 return;
1354 }
1355
Nicolas Capens0bac2852016-05-07 06:09:58 -04001356 if(!program->setUniformMatrix3x2fv(location, count, transpose, value))
1357 {
1358 return error(GL_INVALID_OPERATION);
1359 }
1360 }
1361}
1362
1363GL_APICALL void GL_APIENTRY glUniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1364{
1365 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1366
1367 if(count < 0)
1368 {
1369 return error(GL_INVALID_VALUE);
1370 }
1371
Nicolas Capens0bac2852016-05-07 06:09:58 -04001372 es2::Context *context = es2::getContext();
1373
1374 if(context)
1375 {
1376 es2::Program *program = context->getCurrentProgram();
1377
1378 if(!program)
1379 {
1380 return error(GL_INVALID_OPERATION);
1381 }
1382
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001383 if(location == -1)
1384 {
1385 return;
1386 }
1387
Nicolas Capens0bac2852016-05-07 06:09:58 -04001388 if(!program->setUniformMatrix2x4fv(location, count, transpose, value))
1389 {
1390 return error(GL_INVALID_OPERATION);
1391 }
1392 }
1393}
1394
1395GL_APICALL void GL_APIENTRY glUniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1396{
1397 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1398
1399 if(count < 0)
1400 {
1401 return error(GL_INVALID_VALUE);
1402 }
1403
Nicolas Capens0bac2852016-05-07 06:09:58 -04001404 es2::Context *context = es2::getContext();
1405
1406 if(context)
1407 {
1408 es2::Program *program = context->getCurrentProgram();
1409
1410 if(!program)
1411 {
1412 return error(GL_INVALID_OPERATION);
1413 }
1414
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001415 if(location == -1)
1416 {
1417 return;
1418 }
1419
Nicolas Capens0bac2852016-05-07 06:09:58 -04001420 if(!program->setUniformMatrix4x2fv(location, count, transpose, value))
1421 {
1422 return error(GL_INVALID_OPERATION);
1423 }
1424 }
1425}
1426
1427GL_APICALL void GL_APIENTRY glUniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1428{
1429 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1430
1431 if(count < 0)
1432 {
1433 return error(GL_INVALID_VALUE);
1434 }
1435
Nicolas Capens0bac2852016-05-07 06:09:58 -04001436 es2::Context *context = es2::getContext();
1437
1438 if(context)
1439 {
1440 es2::Program *program = context->getCurrentProgram();
1441
1442 if(!program)
1443 {
1444 return error(GL_INVALID_OPERATION);
1445 }
1446
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001447 if(location == -1)
1448 {
1449 return;
1450 }
1451
Nicolas Capens0bac2852016-05-07 06:09:58 -04001452 if(!program->setUniformMatrix3x4fv(location, count, transpose, value))
1453 {
1454 return error(GL_INVALID_OPERATION);
1455 }
1456 }
1457}
1458
1459GL_APICALL void GL_APIENTRY glUniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
1460{
1461 TRACE("(GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat *value = %p)", location, count, transpose, value);
1462
1463 if(count < 0)
1464 {
1465 return error(GL_INVALID_VALUE);
1466 }
1467
Nicolas Capens0bac2852016-05-07 06:09:58 -04001468 es2::Context *context = es2::getContext();
1469
1470 if(context)
1471 {
1472 es2::Program *program = context->getCurrentProgram();
1473
1474 if(!program)
1475 {
1476 return error(GL_INVALID_OPERATION);
1477 }
1478
Alexis Hetu3eb573f2017-11-22 13:27:03 -05001479 if(location == -1)
1480 {
1481 return;
1482 }
1483
Nicolas Capens0bac2852016-05-07 06:09:58 -04001484 if(!program->setUniformMatrix4x3fv(location, count, transpose, value))
1485 {
1486 return error(GL_INVALID_OPERATION);
1487 }
1488 }
1489}
1490
1491GL_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)
1492{
1493 TRACE("(GLint srcX0 = %d, GLint srcY0 = %d, GLint srcX1 = %d, GLint srcY1 = %d, "
1494 "GLint dstX0 = %d, GLint dstY0 = %d, GLint dstX1 = %d, GLint dstY1 = %d, "
1495 "GLbitfield mask = 0x%X, GLenum filter = 0x%X)",
1496 srcX0, srcY0, srcX1, srcX1, dstX0, dstY0, dstX1, dstY1, mask, filter);
1497
1498 switch(filter)
1499 {
1500 case GL_NEAREST:
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001501 break;
Nicolas Capens0bac2852016-05-07 06:09:58 -04001502 case GL_LINEAR:
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001503 if((mask & GL_DEPTH_BUFFER_BIT) || (mask & GL_STENCIL_BUFFER_BIT))
1504 {
1505 return error(GL_INVALID_OPERATION);
1506 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001507 break;
1508 default:
1509 return error(GL_INVALID_ENUM);
1510 }
1511
1512 if((mask & ~(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)) != 0)
1513 {
1514 return error(GL_INVALID_VALUE);
1515 }
1516
1517 es2::Context *context = es2::getContext();
1518
1519 if(context)
1520 {
1521 if(context->getReadFramebufferName() == context->getDrawFramebufferName())
1522 {
1523 ERR("Blits with the same source and destination framebuffer are not supported by this implementation.");
1524 return error(GL_INVALID_OPERATION);
1525 }
1526
Alexis Hetub9dda642016-10-06 11:25:32 -04001527 context->blitFramebuffer(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter == GL_LINEAR, true);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001528 }
1529}
1530
Nicolas Capens0bac2852016-05-07 06:09:58 -04001531GL_APICALL void GL_APIENTRY glFramebufferTextureLayer(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer)
1532{
1533 TRACE("(GLenum target = 0x%X, GLenum attachment = 0x%X, GLuint texture = %d, GLint level = %d, GLint layer = %d)",
1534 target, attachment, texture, level, layer);
1535
1536 // GLES 3.0.4 spec, p.209, section 4.4.2
1537 // If texture is zero, any image or array of images attached to the attachment point
1538 // named by attachment is detached. Any additional parameters(level, textarget,
1539 // and / or layer) are ignored when texture is zero.
1540 if(texture != 0 && (layer < 0 || level < 0))
1541 {
1542 return error(GL_INVALID_VALUE);
1543 }
1544
1545 es2::Context *context = es2::getContext();
1546
1547 if(context)
1548 {
1549 Texture* textureObject = context->getTexture(texture);
1550 GLenum textarget = GL_NONE;
1551 if(texture != 0)
1552 {
1553 if(!textureObject)
1554 {
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001555 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001556 }
1557
1558 textarget = textureObject->getTarget();
1559 switch(textarget)
1560 {
1561 case GL_TEXTURE_3D:
1562 case GL_TEXTURE_2D_ARRAY:
1563 if(layer >= es2::IMPLEMENTATION_MAX_TEXTURE_SIZE || (level >= es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS))
1564 {
1565 return error(GL_INVALID_VALUE);
1566 }
1567 break;
1568 default:
1569 return error(GL_INVALID_OPERATION);
1570 }
1571
1572 if(textureObject->isCompressed(textarget, level))
1573 {
1574 return error(GL_INVALID_OPERATION);
1575 }
1576 }
1577
1578 es2::Framebuffer *framebuffer = nullptr;
1579 switch(target)
1580 {
1581 case GL_DRAW_FRAMEBUFFER:
1582 case GL_FRAMEBUFFER:
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001583 if(context->getDrawFramebufferName() == 0)
1584 {
1585 return error(GL_INVALID_OPERATION);
1586 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001587 framebuffer = context->getDrawFramebuffer();
1588 break;
1589 case GL_READ_FRAMEBUFFER:
Alexis Hetu1c93b6c2017-11-20 14:52:03 -05001590 if(context->getReadFramebufferName() == 0)
1591 {
1592 return error(GL_INVALID_OPERATION);
1593 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04001594 framebuffer = context->getReadFramebuffer();
1595 break;
1596 default:
1597 return error(GL_INVALID_ENUM);
1598 }
1599
1600 if(!framebuffer)
1601 {
1602 return error(GL_INVALID_OPERATION);
1603 }
1604
1605 switch(attachment)
1606 {
1607 case GL_COLOR_ATTACHMENT0:
1608 case GL_COLOR_ATTACHMENT1:
1609 case GL_COLOR_ATTACHMENT2:
1610 case GL_COLOR_ATTACHMENT3:
1611 case GL_COLOR_ATTACHMENT4:
1612 case GL_COLOR_ATTACHMENT5:
1613 case GL_COLOR_ATTACHMENT6:
1614 case GL_COLOR_ATTACHMENT7:
1615 case GL_COLOR_ATTACHMENT8:
1616 case GL_COLOR_ATTACHMENT9:
1617 case GL_COLOR_ATTACHMENT10:
1618 case GL_COLOR_ATTACHMENT11:
1619 case GL_COLOR_ATTACHMENT12:
1620 case GL_COLOR_ATTACHMENT13:
1621 case GL_COLOR_ATTACHMENT14:
1622 case GL_COLOR_ATTACHMENT15:
1623 case GL_COLOR_ATTACHMENT16:
1624 case GL_COLOR_ATTACHMENT17:
1625 case GL_COLOR_ATTACHMENT18:
1626 case GL_COLOR_ATTACHMENT19:
1627 case GL_COLOR_ATTACHMENT20:
1628 case GL_COLOR_ATTACHMENT21:
1629 case GL_COLOR_ATTACHMENT22:
1630 case GL_COLOR_ATTACHMENT23:
1631 case GL_COLOR_ATTACHMENT24:
1632 case GL_COLOR_ATTACHMENT25:
1633 case GL_COLOR_ATTACHMENT26:
1634 case GL_COLOR_ATTACHMENT27:
1635 case GL_COLOR_ATTACHMENT28:
1636 case GL_COLOR_ATTACHMENT29:
1637 case GL_COLOR_ATTACHMENT30:
1638 case GL_COLOR_ATTACHMENT31:
1639 framebuffer->setColorbuffer(textarget, texture, attachment - GL_COLOR_ATTACHMENT0, level, layer);
1640 break;
1641 case GL_DEPTH_ATTACHMENT:
1642 framebuffer->setDepthbuffer(textarget, texture, level, layer);
1643 break;
1644 case GL_STENCIL_ATTACHMENT:
1645 framebuffer->setStencilbuffer(textarget, texture, level, layer);
1646 break;
1647 case GL_DEPTH_STENCIL_ATTACHMENT:
1648 framebuffer->setDepthbuffer(textarget, texture, level, layer);
1649 framebuffer->setStencilbuffer(textarget, texture, level, layer);
1650 break;
1651 default:
1652 return error(GL_INVALID_ENUM);
1653 }
1654 }
1655}
1656
1657GL_APICALL void *GL_APIENTRY glMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access)
1658{
1659 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d, GLbitfield access = %X)",
1660 target, offset, length, access);
1661
Alexis Hetu6e864492017-11-14 15:27:00 -05001662 if((offset < 0) || (length < 0))
1663 {
1664 return error(GL_INVALID_VALUE, nullptr);
1665 }
1666
1667 if(!(access & (GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)))
1668 {
1669 // Must be able to read or write the buffer
1670 return error(GL_INVALID_OPERATION, nullptr);
1671 }
1672 else if((access & GL_MAP_READ_BIT) && (access & (GL_MAP_INVALIDATE_RANGE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT | GL_MAP_UNSYNCHRONIZED_BIT)))
1673 {
1674 // GL_MAP_INVALIDATE_RANGE_BIT, GL_MAP_INVALIDATE_BUFFER_BIT and GL_MAP_UNSYNCHRONIZED_BIT can't be used with GL_MAP_READ_BIT
1675 return error(GL_INVALID_OPERATION, nullptr);
1676 }
1677 else if((!(access & GL_MAP_WRITE_BIT)) && (access & GL_MAP_FLUSH_EXPLICIT_BIT))
1678 {
1679 // GL_MAP_FLUSH_EXPLICIT_BIT can't be used without GL_MAP_WRITE_BIT
1680 return error(GL_INVALID_OPERATION, nullptr);
1681 }
1682
Nicolas Capens0bac2852016-05-07 06:09:58 -04001683 es2::Context *context = es2::getContext();
1684
1685 if(context)
1686 {
1687 es2::Buffer *buffer = nullptr;
1688 if(!context->getBuffer(target, &buffer))
1689 {
1690 return error(GL_INVALID_ENUM, nullptr);
1691 }
1692
1693 if(!buffer)
1694 {
1695 // A null buffer means that "0" is bound to the requested buffer target
1696 return error(GL_INVALID_OPERATION, nullptr);
1697 }
1698
Alexis Hetu1b4eb7f2017-11-14 13:24:37 -05001699 if(buffer->isMapped())
1700 {
1701 // It is an invalid operation to map an already mapped buffer
1702 return error(GL_INVALID_OPERATION, nullptr);
1703 }
1704
Nicolas Capens0bac2852016-05-07 06:09:58 -04001705 GLsizeiptr bufferSize = buffer->size();
Alexis Hetu6e864492017-11-14 15:27:00 -05001706 if((offset + length) > bufferSize)
Nicolas Capens0bac2852016-05-07 06:09:58 -04001707 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001708 return error(GL_INVALID_VALUE, nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001709 }
1710
1711 if((access & ~(GL_MAP_READ_BIT |
1712 GL_MAP_WRITE_BIT |
1713 GL_MAP_INVALIDATE_RANGE_BIT |
1714 GL_MAP_INVALIDATE_BUFFER_BIT |
1715 GL_MAP_FLUSH_EXPLICIT_BIT |
1716 GL_MAP_UNSYNCHRONIZED_BIT)) != 0)
1717 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001718 return error(GL_INVALID_VALUE, nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001719 }
1720
1721 return buffer->mapRange(offset, length, access);
1722 }
1723
1724 return nullptr;
1725}
1726
1727GL_APICALL void GL_APIENTRY glFlushMappedBufferRange(GLenum target, GLintptr offset, GLsizeiptr length)
1728{
1729 TRACE("(GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr length = %d)",
1730 target, offset, length);
1731
Alexis Hetu6e864492017-11-14 15:27:00 -05001732 if((offset < 0) || (length < 0))
1733 {
1734 return error(GL_INVALID_VALUE);
1735 }
1736
Nicolas Capens0bac2852016-05-07 06:09:58 -04001737 es2::Context *context = es2::getContext();
1738
1739 if(context)
1740 {
1741 es2::Buffer *buffer = nullptr;
1742 if(!context->getBuffer(target, &buffer))
1743 {
1744 return error(GL_INVALID_ENUM);
1745 }
1746
1747 if(!buffer)
1748 {
1749 // A null buffer means that "0" is bound to the requested buffer target
1750 return error(GL_INVALID_OPERATION);
1751 }
1752
Alexis Hetu6e864492017-11-14 15:27:00 -05001753 if(!buffer->isMapped())
Nicolas Capens0bac2852016-05-07 06:09:58 -04001754 {
Alexis Hetu6e864492017-11-14 15:27:00 -05001755 // Buffer must be mapped
1756 return error(GL_INVALID_OPERATION);
1757 }
1758
1759 GLsizeiptr bufferSize = buffer->length();
1760 if((offset + length) > bufferSize)
1761 {
1762 return error(GL_INVALID_VALUE);
1763 }
1764
Alexis Hetua752b892017-11-22 14:00:37 -05001765 if(!(buffer->access() & GL_MAP_FLUSH_EXPLICIT_BIT))
Alexis Hetu6e864492017-11-14 15:27:00 -05001766 {
1767 // Flush must be explicitly allowed
1768 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001769 }
1770
1771 buffer->flushMappedRange(offset, length);
1772 }
1773}
1774
1775GL_APICALL void GL_APIENTRY glBindVertexArray(GLuint array)
1776{
1777 TRACE("(GLuint array = %d)", array);
1778
Nicolas Capens0bac2852016-05-07 06:09:58 -04001779 es2::Context *context = es2::getContext();
1780
1781 if(context)
1782 {
1783 if(!context->isVertexArray(array))
1784 {
1785 return error(GL_INVALID_OPERATION);
1786 }
1787
1788 context->bindVertexArray(array);
1789 }
1790}
1791
1792GL_APICALL void GL_APIENTRY glDeleteVertexArrays(GLsizei n, const GLuint *arrays)
1793{
1794 TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1795
1796 if(n < 0)
1797 {
1798 return error(GL_INVALID_VALUE);
1799 }
1800
1801 es2::Context *context = es2::getContext();
1802
1803 if(context)
1804 {
1805 for(int i = 0; i < n; i++)
1806 {
1807 context->deleteVertexArray(arrays[i]);
1808 }
1809 }
1810}
1811
1812GL_APICALL void GL_APIENTRY glGenVertexArrays(GLsizei n, GLuint *arrays)
1813{
1814 TRACE("(GLsizei n = %d, const GLuint *arrays = %p)", n, arrays);
1815
1816 if(n < 0)
1817 {
1818 return error(GL_INVALID_VALUE);
1819 }
1820
1821 es2::Context *context = es2::getContext();
1822
1823 if(context)
1824 {
1825 for(int i = 0; i < n; i++)
1826 {
1827 arrays[i] = context->createVertexArray();
1828 }
1829 }
1830}
1831
1832GL_APICALL GLboolean GL_APIENTRY glIsVertexArray(GLuint array)
1833{
1834 TRACE("(GLuint array = %d)", array);
1835
1836 if(array == 0)
1837 {
1838 return GL_FALSE;
1839 }
1840
1841 es2::Context *context = es2::getContext();
1842
1843 if(context)
1844 {
1845 es2::VertexArray *arrayObject = context->getVertexArray(array);
1846
1847 if(arrayObject)
1848 {
1849 return GL_TRUE;
1850 }
1851 }
1852
1853 return GL_FALSE;
1854}
1855
1856GL_APICALL void GL_APIENTRY glGetIntegeri_v(GLenum target, GLuint index, GLint *data)
1857{
1858 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint* data = %p)",
1859 target, index, data);
1860
1861 es2::Context *context = es2::getContext();
1862
1863 if(context)
1864 {
1865 if(!context->getTransformFeedbackiv(index, target, data) &&
1866 !context->getUniformBufferiv(index, target, data) &&
1867 !context->getIntegerv(target, data))
1868 {
1869 GLenum nativeType;
1870 unsigned int numParams = 0;
1871 if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
1872 return error(GL_INVALID_ENUM);
1873
1874 if(numParams == 0)
1875 return; // it is known that target is valid, but there are no parameters to return
1876
1877 if(nativeType == GL_BOOL)
1878 {
1879 GLboolean *boolParams = nullptr;
1880 boolParams = new GLboolean[numParams];
1881
1882 context->getBooleanv(target, boolParams);
1883
1884 for(unsigned int i = 0; i < numParams; ++i)
1885 {
1886 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
1887 }
1888
1889 delete[] boolParams;
1890 }
1891 else if(nativeType == GL_FLOAT)
1892 {
1893 GLfloat *floatParams = nullptr;
1894 floatParams = new GLfloat[numParams];
1895
1896 context->getFloatv(target, floatParams);
1897
1898 for(unsigned int i = 0; i < numParams; ++i)
1899 {
1900 if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
1901 {
Nicolas Capens53318fa2016-04-11 17:41:39 -04001902 data[i] = convert_float_int(floatParams[i]);
Nicolas Capens0bac2852016-05-07 06:09:58 -04001903 }
1904 else
1905 {
1906 data[i] = (GLint)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
1907 }
1908 }
1909
1910 delete[] floatParams;
1911 }
1912 }
1913 }
1914}
1915
1916GL_APICALL void GL_APIENTRY glBeginTransformFeedback(GLenum primitiveMode)
1917{
1918 TRACE("(GLenum primitiveMode = 0x%X)", primitiveMode);
1919
1920 switch(primitiveMode)
1921 {
1922 case GL_POINTS:
1923 case GL_LINES:
1924 case GL_TRIANGLES:
1925 break;
1926 default:
1927 return error(GL_INVALID_ENUM);
1928 }
1929
1930 es2::Context *context = es2::getContext();
1931
1932 if(context)
1933 {
1934 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1935
1936 if(transformFeedbackObject)
1937 {
1938 if(transformFeedbackObject->isActive())
1939 {
1940 return error(GL_INVALID_OPERATION);
1941 }
1942 transformFeedbackObject->begin(primitiveMode);
1943 }
1944 else
1945 {
1946 return error(GL_INVALID_OPERATION);
1947 }
1948 }
1949}
1950
1951GL_APICALL void GL_APIENTRY glEndTransformFeedback(void)
1952{
1953 TRACE("()");
1954
1955 es2::Context *context = es2::getContext();
1956
1957 if(context)
1958 {
1959 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
1960
1961 if(transformFeedbackObject)
1962 {
1963 if(!transformFeedbackObject->isActive())
1964 {
1965 return error(GL_INVALID_OPERATION);
1966 }
1967 transformFeedbackObject->end();
1968 }
1969 else
1970 {
1971 return error(GL_INVALID_OPERATION);
1972 }
1973 }
1974}
1975
1976GL_APICALL void GL_APIENTRY glBindBufferRange(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size)
1977{
1978 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d, GLintptr offset = %d, GLsizeiptr size = %d)",
1979 target, index, buffer, offset, size);
1980
1981 if(buffer != 0 && size <= 0)
1982 {
1983 return error(GL_INVALID_VALUE);
1984 }
1985
1986 es2::Context *context = es2::getContext();
1987
1988 if(context)
1989 {
1990 switch(target)
1991 {
1992 case GL_TRANSFORM_FEEDBACK_BUFFER:
1993 if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
1994 {
1995 return error(GL_INVALID_VALUE);
1996 }
1997 if(size & 0x3 || offset & 0x3) // size and offset must be multiples of 4
1998 {
1999 return error(GL_INVALID_VALUE);
2000 }
2001 context->bindIndexedTransformFeedbackBuffer(buffer, index, offset, size);
2002 context->bindGenericTransformFeedbackBuffer(buffer);
2003 break;
2004 case GL_UNIFORM_BUFFER:
2005 if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
2006 {
2007 return error(GL_INVALID_VALUE);
2008 }
2009 if(offset % UNIFORM_BUFFER_OFFSET_ALIGNMENT != 0)
2010 {
2011 return error(GL_INVALID_VALUE);
2012 }
2013 context->bindIndexedUniformBuffer(buffer, index, offset, size);
2014 context->bindGenericUniformBuffer(buffer);
2015 break;
2016 default:
2017 return error(GL_INVALID_ENUM);
2018 }
2019 }
2020}
2021
2022GL_APICALL void GL_APIENTRY glBindBufferBase(GLenum target, GLuint index, GLuint buffer)
2023{
2024 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLuint buffer = %d)",
2025 target, index, buffer);
2026
2027 es2::Context *context = es2::getContext();
2028
2029 if(context)
2030 {
2031 switch(target)
2032 {
2033 case GL_TRANSFORM_FEEDBACK_BUFFER:
2034 if(index >= MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
2035 {
2036 return error(GL_INVALID_VALUE);
2037 }
2038 context->bindIndexedTransformFeedbackBuffer(buffer, index, 0, 0);
2039 context->bindGenericTransformFeedbackBuffer(buffer);
2040 break;
2041 case GL_UNIFORM_BUFFER:
2042 if(index >= MAX_UNIFORM_BUFFER_BINDINGS)
2043 {
2044 return error(GL_INVALID_VALUE);
2045 }
2046 context->bindIndexedUniformBuffer(buffer, index, 0, 0);
2047 context->bindGenericUniformBuffer(buffer);
2048 break;
2049 default:
2050 return error(GL_INVALID_ENUM);
2051 }
2052 }
2053}
2054
2055GL_APICALL void GL_APIENTRY glTransformFeedbackVaryings(GLuint program, GLsizei count, const GLchar *const*varyings, GLenum bufferMode)
2056{
2057 TRACE("(GLuint program = %d, GLsizei count = %d, const GLchar *const*varyings = %p, GLenum bufferMode = 0x%X)",
2058 program, count, varyings, bufferMode);
2059
2060 switch(bufferMode)
2061 {
2062 case GL_SEPARATE_ATTRIBS:
2063 if(count > MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS)
2064 {
2065 return error(GL_INVALID_VALUE);
2066 }
2067 case GL_INTERLEAVED_ATTRIBS:
2068 break;
2069 default:
2070 return error(GL_INVALID_ENUM);
2071 }
2072
2073 es2::Context *context = es2::getContext();
2074
2075 if(context)
2076 {
2077 es2::Program *programObject = context->getProgram(program);
2078
2079 if(!programObject)
2080 {
2081 return error(GL_INVALID_VALUE);
2082 }
2083
2084 programObject->setTransformFeedbackVaryings(count, varyings, bufferMode);
2085 }
2086}
2087
2088GL_APICALL void GL_APIENTRY glGetTransformFeedbackVarying(GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLsizei *size, GLenum *type, GLchar *name)
2089{
2090 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
2091 program, index, bufSize, length, size, type, name);
2092
2093 if(bufSize < 0)
2094 {
2095 return error(GL_INVALID_VALUE);
2096 }
2097
2098 es2::Context *context = es2::getContext();
2099
2100 if(context)
2101 {
2102 es2::Program *programObject = context->getProgram(program);
2103
2104 if(!programObject)
2105 {
2106 return error(GL_INVALID_VALUE);
2107 }
2108
2109 if(index >= static_cast<GLuint>(programObject->getTransformFeedbackVaryingCount()))
2110 {
2111 return error(GL_INVALID_VALUE);
2112 }
2113
2114 programObject->getTransformFeedbackVarying(index, bufSize, length, size, type, name);
2115 }
2116}
2117
2118GL_APICALL void GL_APIENTRY glVertexAttribIPointer(GLuint index, GLint size, GLenum type, GLsizei stride, const void *pointer)
2119{
2120 TRACE("(GLuint program = %d, GLuint index = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLsizei *size = %p, GLenum *type = %p, GLchar *name = %p)",
2121 index, size, type, stride, pointer);
2122
2123 if(index >= es2::MAX_VERTEX_ATTRIBS)
2124 {
2125 return error(GL_INVALID_VALUE);
2126 }
2127
2128 if(size < 1 || size > 4 || stride < 0)
2129 {
2130 return error(GL_INVALID_VALUE);
2131 }
2132
2133 switch(type)
2134 {
2135 case GL_BYTE:
2136 case GL_UNSIGNED_BYTE:
2137 case GL_SHORT:
2138 case GL_UNSIGNED_SHORT:
2139 case GL_INT:
2140 case GL_UNSIGNED_INT:
2141 break;
2142 default:
2143 return error(GL_INVALID_ENUM);
2144 }
2145
2146 es2::Context *context = es2::getContext();
2147
2148 if(context)
2149 {
Alexis Hetuc1ef1ad2017-11-15 10:50:10 -05002150 es2::VertexArray* vertexArray = context->getCurrentVertexArray();
2151 if((context->getArrayBufferName() == 0) && vertexArray && (vertexArray->name != 0) && pointer)
2152 {
2153 // GL_INVALID_OPERATION is generated if a non-zero vertex array object is bound, zero is bound
2154 // to the GL_ARRAY_BUFFER buffer object binding point and the pointer argument is not NULL.
2155 return error(GL_INVALID_OPERATION);
2156 }
2157
Nicolas Capens0bac2852016-05-07 06:09:58 -04002158 context->setVertexAttribState(index, context->getArrayBuffer(), size, type, false, stride, pointer);
2159 }
2160}
2161
2162GL_APICALL void GL_APIENTRY glGetVertexAttribIiv(GLuint index, GLenum pname, GLint *params)
2163{
2164 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLint *params = %p)",
2165 index, pname, params);
2166
2167 es2::Context *context = es2::getContext();
2168
2169 if(context)
2170 {
2171 if(index >= es2::MAX_VERTEX_ATTRIBS)
2172 {
2173 return error(GL_INVALID_VALUE);
2174 }
2175
2176 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
2177
2178 switch(pname)
2179 {
2180 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
2181 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
2182 break;
2183 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
2184 *params = attribState.mSize;
2185 break;
2186 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
2187 *params = attribState.mStride;
2188 break;
2189 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
2190 *params = attribState.mType;
2191 break;
2192 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
2193 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
2194 break;
2195 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2196 *params = attribState.mBoundBuffer.name();
2197 break;
2198 case GL_CURRENT_VERTEX_ATTRIB:
2199 {
2200 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
2201 for(int i = 0; i < 4; ++i)
2202 {
2203 params[i] = attrib.getCurrentValueI(i);
2204 }
2205 }
2206 break;
2207 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
2208 switch(attribState.mType)
2209 {
2210 case GL_BYTE:
2211 case GL_UNSIGNED_BYTE:
2212 case GL_SHORT:
2213 case GL_UNSIGNED_SHORT:
2214 case GL_INT:
2215 case GL_INT_2_10_10_10_REV:
2216 case GL_UNSIGNED_INT:
2217 case GL_FIXED:
2218 *params = GL_TRUE;
2219 break;
2220 default:
2221 *params = GL_FALSE;
2222 break;
2223 }
2224 break;
2225 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
2226 *params = attribState.mDivisor;
2227 break;
2228 default: return error(GL_INVALID_ENUM);
2229 }
2230 }
2231}
2232
2233GL_APICALL void GL_APIENTRY glGetVertexAttribIuiv(GLuint index, GLenum pname, GLuint *params)
2234{
2235 TRACE("(GLuint index = %d, GLenum pname = 0x%X, GLuint *params = %p)",
2236 index, pname, params);
2237
2238 es2::Context *context = es2::getContext();
2239
2240 if(context)
2241 {
2242 if(index >= es2::MAX_VERTEX_ATTRIBS)
2243 {
2244 return error(GL_INVALID_VALUE);
2245 }
2246
2247 const es2::VertexAttribute &attribState = context->getVertexAttribState(index);
2248
2249 switch(pname)
2250 {
2251 case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
2252 *params = (attribState.mArrayEnabled ? GL_TRUE : GL_FALSE);
2253 break;
2254 case GL_VERTEX_ATTRIB_ARRAY_SIZE:
2255 *params = attribState.mSize;
2256 break;
2257 case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
2258 *params = attribState.mStride;
2259 break;
2260 case GL_VERTEX_ATTRIB_ARRAY_TYPE:
2261 *params = attribState.mType;
2262 break;
2263 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
2264 *params = (attribState.mNormalized ? GL_TRUE : GL_FALSE);
2265 break;
2266 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
2267 *params = attribState.mBoundBuffer.name();
2268 break;
2269 case GL_CURRENT_VERTEX_ATTRIB:
2270 {
2271 const VertexAttribute& attrib = context->getCurrentVertexAttributes()[index];
2272 for(int i = 0; i < 4; ++i)
2273 {
2274 params[i] = attrib.getCurrentValueUI(i);
2275 }
2276 }
2277 break;
2278 case GL_VERTEX_ATTRIB_ARRAY_INTEGER:
2279 switch(attribState.mType)
2280 {
2281 case GL_BYTE:
2282 case GL_UNSIGNED_BYTE:
2283 case GL_SHORT:
2284 case GL_UNSIGNED_SHORT:
2285 case GL_INT:
2286 case GL_INT_2_10_10_10_REV:
2287 case GL_UNSIGNED_INT:
2288 case GL_FIXED:
2289 *params = GL_TRUE;
2290 break;
2291 default:
2292 *params = GL_FALSE;
2293 break;
2294 }
2295 break;
2296 case GL_VERTEX_ATTRIB_ARRAY_DIVISOR:
2297 *params = attribState.mDivisor;
2298 break;
2299 default: return error(GL_INVALID_ENUM);
2300 }
2301 }
2302}
2303
2304GL_APICALL void GL_APIENTRY glVertexAttribI4i(GLuint index, GLint x, GLint y, GLint z, GLint w)
2305{
2306 TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
2307 index, x, y, z, w);
2308
2309 if(index >= es2::MAX_VERTEX_ATTRIBS)
2310 {
2311 return error(GL_INVALID_VALUE);
2312 }
2313
2314 es2::Context *context = es2::getContext();
2315
2316 if(context)
2317 {
2318 GLint vals[4] = { x, y, z, w };
2319 context->setVertexAttrib(index, vals);
2320 }
2321}
2322
2323GL_APICALL void GL_APIENTRY glVertexAttribI4ui(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w)
2324{
2325 TRACE("(GLuint index = %d, GLint x = %d, GLint y = %d, GLint z = %d, GLint w = %d)",
2326 index, x, y, z, w);
2327
2328 if(index >= es2::MAX_VERTEX_ATTRIBS)
2329 {
2330 return error(GL_INVALID_VALUE);
2331 }
2332
2333 es2::Context *context = es2::getContext();
2334
2335 if(context)
2336 {
2337 GLuint vals[4] = { x, y, z, w };
2338 context->setVertexAttrib(index, vals);
2339 }
2340}
2341
2342GL_APICALL void GL_APIENTRY glVertexAttribI4iv(GLuint index, const GLint *v)
2343{
2344 TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2345
2346 if(index >= es2::MAX_VERTEX_ATTRIBS)
2347 {
2348 return error(GL_INVALID_VALUE);
2349 }
2350
2351 es2::Context *context = es2::getContext();
2352
2353 if(context)
2354 {
2355 context->setVertexAttrib(index, v);
2356 }
2357}
2358
2359GL_APICALL void GL_APIENTRY glVertexAttribI4uiv(GLuint index, const GLuint *v)
2360{
2361 TRACE("(GLuint index = %d, GLint *v = %p)", index, v);
2362
2363 if(index >= es2::MAX_VERTEX_ATTRIBS)
2364 {
2365 return error(GL_INVALID_VALUE);
2366 }
2367
2368 es2::Context *context = es2::getContext();
2369
2370 if(context)
2371 {
2372 context->setVertexAttrib(index, v);
2373 }
2374}
2375
2376GL_APICALL void GL_APIENTRY glGetUniformuiv(GLuint program, GLint location, GLuint *params)
2377{
2378 TRACE("(GLuint program = %d, GLint location = %d, GLuint *params = %p)",
2379 program, location, params);
2380
2381 es2::Context *context = es2::getContext();
2382
2383 if(context)
2384 {
Nicolas Capens0bac2852016-05-07 06:09:58 -04002385 es2::Program *programObject = context->getProgram(program);
2386
Alexis Hetu48280a42017-11-30 15:04:39 -05002387 if(!programObject)
Nicolas Capens0bac2852016-05-07 06:09:58 -04002388 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002389 if(context->getShader(program))
2390 {
2391 return error(GL_INVALID_OPERATION);
2392 }
2393 else
2394 {
2395 return error(GL_INVALID_VALUE);
2396 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002397 }
2398
Alexis Hetu48280a42017-11-30 15:04:39 -05002399 if(!programObject->isLinked())
Nicolas Capens0bac2852016-05-07 06:09:58 -04002400 {
2401 return error(GL_INVALID_OPERATION);
2402 }
2403
2404 if(!programObject->getUniformuiv(location, nullptr, params))
2405 {
2406 return error(GL_INVALID_OPERATION);
2407 }
2408 }
2409}
2410
2411GL_APICALL GLint GL_APIENTRY glGetFragDataLocation(GLuint program, const GLchar *name)
2412{
2413 TRACE("(GLuint program = %d, const GLchar *name = %p)", program, name);
2414
2415 es2::Context *context = es2::getContext();
2416
Nicolas Capens0bac2852016-05-07 06:09:58 -04002417 if(context)
2418 {
2419 es2::Program *programObject = context->getProgram(program);
2420
2421 if(!programObject)
2422 {
2423 if(context->getShader(program))
2424 {
2425 return error(GL_INVALID_OPERATION, -1);
2426 }
2427 else
2428 {
2429 return error(GL_INVALID_VALUE, -1);
2430 }
2431 }
2432
2433 if(!programObject->isLinked())
2434 {
2435 return error(GL_INVALID_OPERATION, -1);
2436 }
Alexis Hetub3f5ed72017-08-16 16:37:19 -04002437
2438 return programObject->getFragDataLocation(name);
Nicolas Capens0bac2852016-05-07 06:09:58 -04002439 }
2440
Nicolas Capens0bac2852016-05-07 06:09:58 -04002441 return -1;
2442}
2443
2444GL_APICALL void GL_APIENTRY glUniform1ui(GLint location, GLuint v0)
2445{
2446 glUniform1uiv(location, 1, &v0);
2447}
2448
2449GL_APICALL void GL_APIENTRY glUniform2ui(GLint location, GLuint v0, GLuint v1)
2450{
2451 GLuint xy[2] = { v0, v1 };
2452
2453 glUniform2uiv(location, 1, (GLuint*)&xy);
2454}
2455
2456GL_APICALL void GL_APIENTRY glUniform3ui(GLint location, GLuint v0, GLuint v1, GLuint v2)
2457{
2458 GLuint xyz[3] = { v0, v1, v2 };
2459
2460 glUniform3uiv(location, 1, (GLuint*)&xyz);
2461}
2462
2463GL_APICALL void GL_APIENTRY glUniform4ui(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
2464{
2465 GLuint xyzw[4] = { v0, v1, v2, v3 };
2466
2467 glUniform4uiv(location, 1, (GLuint*)&xyzw);
2468}
2469
2470GL_APICALL void GL_APIENTRY glUniform1uiv(GLint location, GLsizei count, const GLuint *value)
2471{
2472 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2473 location, count, value);
2474
2475 if(count < 0)
2476 {
2477 return error(GL_INVALID_VALUE);
2478 }
2479
Nicolas Capens0bac2852016-05-07 06:09:58 -04002480 es2::Context *context = es2::getContext();
2481
2482 if(context)
2483 {
2484 es2::Program *program = context->getCurrentProgram();
2485
2486 if(!program)
2487 {
2488 return error(GL_INVALID_OPERATION);
2489 }
2490
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002491 if(location == -1)
2492 {
2493 return;
2494 }
2495
Nicolas Capens0bac2852016-05-07 06:09:58 -04002496 if(!program->setUniform1uiv(location, count, value))
2497 {
2498 return error(GL_INVALID_OPERATION);
2499 }
2500 }
2501}
2502
2503GL_APICALL void GL_APIENTRY glUniform2uiv(GLint location, GLsizei count, const GLuint *value)
2504{
2505 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2506 location, count, value);
2507
2508 if(count < 0)
2509 {
2510 return error(GL_INVALID_VALUE);
2511 }
2512
Nicolas Capens0bac2852016-05-07 06:09:58 -04002513 es2::Context *context = es2::getContext();
2514
2515 if(context)
2516 {
2517 es2::Program *program = context->getCurrentProgram();
2518
2519 if(!program)
2520 {
2521 return error(GL_INVALID_OPERATION);
2522 }
2523
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002524 if(location == -1)
2525 {
2526 return;
2527 }
2528
Nicolas Capens0bac2852016-05-07 06:09:58 -04002529 if(!program->setUniform2uiv(location, count, value))
2530 {
2531 return error(GL_INVALID_OPERATION);
2532 }
2533 }
2534}
2535
2536GL_APICALL void GL_APIENTRY glUniform3uiv(GLint location, GLsizei count, const GLuint *value)
2537{
2538 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2539 location, count, value);
2540
2541 if(count < 0)
2542 {
2543 return error(GL_INVALID_VALUE);
2544 }
2545
Nicolas Capens0bac2852016-05-07 06:09:58 -04002546 es2::Context *context = es2::getContext();
2547
2548 if(context)
2549 {
2550 es2::Program *program = context->getCurrentProgram();
2551
2552 if(!program)
2553 {
2554 return error(GL_INVALID_OPERATION);
2555 }
2556
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002557 if(location == -1)
2558 {
2559 return;
2560 }
2561
Nicolas Capens0bac2852016-05-07 06:09:58 -04002562 if(!program->setUniform3uiv(location, count, value))
2563 {
2564 return error(GL_INVALID_OPERATION);
2565 }
2566 }
2567}
2568
2569GL_APICALL void GL_APIENTRY glUniform4uiv(GLint location, GLsizei count, const GLuint *value)
2570{
2571 TRACE("(GLint location = %d, GLsizei count = %d, const GLuint *value = %p)",
2572 location, count, value);
2573
2574 if(count < 0)
2575 {
2576 return error(GL_INVALID_VALUE);
2577 }
2578
Nicolas Capens0bac2852016-05-07 06:09:58 -04002579 es2::Context *context = es2::getContext();
2580
2581 if(context)
2582 {
2583 es2::Program *program = context->getCurrentProgram();
2584
2585 if(!program)
2586 {
2587 return error(GL_INVALID_OPERATION);
2588 }
2589
Alexis Hetu3eb573f2017-11-22 13:27:03 -05002590 if(location == -1)
2591 {
2592 return;
2593 }
2594
Nicolas Capens0bac2852016-05-07 06:09:58 -04002595 if(!program->setUniform4uiv(location, count, value))
2596 {
2597 return error(GL_INVALID_OPERATION);
2598 }
2599 }
2600}
2601
2602GL_APICALL void GL_APIENTRY glClearBufferiv(GLenum buffer, GLint drawbuffer, const GLint *value)
2603{
2604 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLint *value = %p)",
2605 buffer, drawbuffer, value);
2606
2607 es2::Context *context = es2::getContext();
2608
2609 if(context)
2610 {
2611 switch(buffer)
2612 {
2613 case GL_COLOR:
2614 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2615 {
2616 return error(GL_INVALID_VALUE);
2617 }
2618 else
2619 {
2620 context->clearColorBuffer(drawbuffer, value);
2621 }
2622 break;
2623 case GL_STENCIL:
2624 if(drawbuffer != 0)
2625 {
2626 return error(GL_INVALID_VALUE);
2627 }
2628 else
2629 {
2630 context->clearStencilBuffer(value[0]);
2631 }
2632 break;
2633 default:
2634 return error(GL_INVALID_ENUM);
2635 }
2636 }
2637}
2638
2639GL_APICALL void GL_APIENTRY glClearBufferuiv(GLenum buffer, GLint drawbuffer, const GLuint *value)
2640{
2641 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLuint *value = %p)",
2642 buffer, drawbuffer, value);
2643
2644 es2::Context *context = es2::getContext();
2645
2646 if(context)
2647 {
2648 switch(buffer)
2649 {
2650 case GL_COLOR:
2651 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2652 {
2653 return error(GL_INVALID_VALUE);
2654 }
2655 else
2656 {
2657 context->clearColorBuffer(drawbuffer, value);
2658 }
2659 break;
2660 default:
2661 return error(GL_INVALID_ENUM);
2662 }
2663 }
2664}
2665
2666GL_APICALL void GL_APIENTRY glClearBufferfv(GLenum buffer, GLint drawbuffer, const GLfloat *value)
2667{
2668 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, const GLfloat *value = %p)",
2669 buffer, drawbuffer, value);
2670
2671 es2::Context *context = es2::getContext();
2672
2673 if(context)
2674 {
2675 switch(buffer)
2676 {
2677 case GL_COLOR:
2678 if(drawbuffer < 0 || drawbuffer >= MAX_DRAW_BUFFERS)
2679 {
2680 return error(GL_INVALID_VALUE);
2681 }
2682 else
2683 {
2684 context->clearColorBuffer(drawbuffer, value);
2685 }
2686 break;
2687 case GL_DEPTH:
2688 if(drawbuffer != 0)
2689 {
2690 return error(GL_INVALID_VALUE);
2691 }
2692 else
2693 {
2694 context->clearDepthBuffer(value[0]);
2695 }
2696 break;
2697 default:
2698 return error(GL_INVALID_ENUM);
2699 }
2700 }
2701}
2702
2703GL_APICALL void GL_APIENTRY glClearBufferfi(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil)
2704{
2705 TRACE("(GLenum buffer = 0x%X, GLint drawbuffer = %d, GLfloat depth = %f, GLint stencil = %d)",
2706 buffer, drawbuffer, depth, stencil);
2707
2708 es2::Context *context = es2::getContext();
2709
2710 if(context)
2711 {
2712 switch(buffer)
2713 {
2714 case GL_DEPTH_STENCIL:
2715 if(drawbuffer != 0)
2716 {
2717 return error(GL_INVALID_VALUE);
2718 }
2719 else
2720 {
2721 context->clearDepthBuffer(depth);
2722 context->clearStencilBuffer(stencil);
2723 }
2724 break;
2725 default:
2726 return error(GL_INVALID_ENUM);
2727 }
2728 }
2729}
2730
2731GL_APICALL const GLubyte *GL_APIENTRY glGetStringi(GLenum name, GLuint index)
2732{
2733 TRACE("(GLenum name = 0x%X, GLuint index = %d)", name, index);
2734
2735 es2::Context *context = es2::getContext();
2736 if(context)
2737 {
2738 GLuint numExtensions;
2739 context->getExtensions(0, &numExtensions);
2740
2741 if(index >= numExtensions)
2742 {
2743 return error(GL_INVALID_VALUE, (GLubyte*)nullptr);
2744 }
2745
2746 switch(name)
2747 {
2748 case GL_EXTENSIONS:
2749 return context->getExtensions(index);
2750 default:
2751 return error(GL_INVALID_ENUM, (GLubyte*)nullptr);
2752 }
2753 }
2754
2755 return (GLubyte*)nullptr;
2756}
2757
2758GL_APICALL void GL_APIENTRY glCopyBufferSubData(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizeiptr size)
2759{
2760 TRACE("(GLenum readTarget = 0x%X, GLenum writeTarget = 0x%X, GLintptr readOffset = %d, GLintptr writeOffset = %d, GLsizeiptr size = %d)",
2761 readTarget, writeTarget, readOffset, writeOffset, size);
2762
2763 if(readOffset < 0 || writeOffset < 0 || size < 0)
2764 {
2765 return error(GL_INVALID_VALUE);
2766 }
2767
2768 es2::Context *context = es2::getContext();
2769
2770 if(context)
2771 {
2772 es2::Buffer *readBuffer = nullptr, *writeBuffer = nullptr;
2773 if(!context->getBuffer(readTarget, &readBuffer) || !context->getBuffer(writeTarget, &writeBuffer))
2774 {
2775 return error(GL_INVALID_ENUM);
2776 }
2777 if(!readBuffer || readBuffer->isMapped() || !writeBuffer || writeBuffer->isMapped())
2778 {
2779 return error(GL_INVALID_OPERATION);
2780 }
2781 if(readBuffer == writeBuffer)
2782 {
2783 // If same buffer, check for overlap
2784 if(((readOffset >= writeOffset) && (readOffset < (writeOffset + size))) ||
2785 ((writeOffset >= readOffset) && (writeOffset < (readOffset + size))))
2786 {
2787 return error(GL_INVALID_VALUE);
2788 }
2789 }
2790
2791 if((static_cast<size_t>(readOffset + size) > readBuffer->size()) ||
2792 (static_cast<size_t>(writeOffset + size) > writeBuffer->size()))
2793 {
2794 return error(GL_INVALID_VALUE);
2795 }
2796
2797 writeBuffer->bufferSubData(((char*)readBuffer->data()) + readOffset, size, writeOffset);
2798 }
2799}
2800
2801GL_APICALL void GL_APIENTRY glGetUniformIndices(GLuint program, GLsizei uniformCount, const GLchar *const*uniformNames, GLuint *uniformIndices)
2802{
2803 TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLuint *uniformIndices = %p)",
2804 program, uniformCount, uniformNames, uniformIndices);
2805
2806 if(uniformCount < 0)
2807 {
2808 return error(GL_INVALID_VALUE);
2809 }
2810
2811 es2::Context *context = es2::getContext();
2812
2813 if(context)
2814 {
2815 es2::Program *programObject = context->getProgram(program);
2816
2817 if(!programObject)
2818 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002819 if(context->getShader(program))
2820 {
2821 return error(GL_INVALID_OPERATION);
2822 }
2823 else
2824 {
2825 return error(GL_INVALID_VALUE);
2826 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002827 }
2828
2829 if(!programObject->isLinked())
2830 {
2831 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2832 {
2833 uniformIndices[uniformId] = GL_INVALID_INDEX;
2834 }
2835 }
2836 else
2837 {
2838 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2839 {
2840 uniformIndices[uniformId] = programObject->getUniformIndex(uniformNames[uniformId]);
2841 }
2842 }
2843 }
2844}
2845
2846GL_APICALL void GL_APIENTRY glGetActiveUniformsiv(GLuint program, GLsizei uniformCount, const GLuint *uniformIndices, GLenum pname, GLint *params)
2847{
2848 TRACE("(GLuint program = %d, GLsizei uniformCount = %d, const GLchar *const*uniformNames = %p, GLenum pname = 0x%X, GLuint *uniformIndices = %p)",
2849 program, uniformCount, uniformIndices, pname, uniformIndices);
2850
2851 switch(pname)
2852 {
2853 case GL_UNIFORM_TYPE:
2854 case GL_UNIFORM_SIZE:
2855 case GL_UNIFORM_NAME_LENGTH:
2856 case GL_UNIFORM_BLOCK_INDEX:
2857 case GL_UNIFORM_OFFSET:
2858 case GL_UNIFORM_ARRAY_STRIDE:
2859 case GL_UNIFORM_MATRIX_STRIDE:
2860 case GL_UNIFORM_IS_ROW_MAJOR:
2861 break;
2862 default:
2863 return error(GL_INVALID_ENUM);
2864 }
2865
2866 if(uniformCount < 0)
2867 {
2868 return error(GL_INVALID_VALUE);
2869 }
2870
2871 es2::Context *context = es2::getContext();
2872
2873 if(context)
2874 {
2875 es2::Program *programObject = context->getProgram(program);
2876
2877 if(!programObject)
2878 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002879 if(context->getShader(program))
2880 {
2881 return error(GL_INVALID_OPERATION);
2882 }
2883 else
2884 {
2885 return error(GL_INVALID_VALUE);
2886 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002887 }
2888
2889 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2890 {
2891 const GLuint index = uniformIndices[uniformId];
2892
2893 if(index >= programObject->getActiveUniformCount())
2894 {
2895 return error(GL_INVALID_VALUE);
2896 }
2897 }
2898
2899 for(int uniformId = 0; uniformId < uniformCount; uniformId++)
2900 {
2901 const GLuint index = uniformIndices[uniformId];
2902 params[uniformId] = programObject->getActiveUniformi(index, pname);
2903 }
2904 }
2905}
2906
2907GL_APICALL GLuint GL_APIENTRY glGetUniformBlockIndex(GLuint program, const GLchar *uniformBlockName)
2908{
2909 TRACE("(GLuint program = %d, const GLchar *uniformBlockName = %p)",
2910 program, uniformBlockName);
2911
2912 es2::Context *context = es2::getContext();
2913
2914 if(context)
2915 {
2916 es2::Program *programObject = context->getProgram(program);
2917
2918 if(!programObject)
2919 {
Alexis Hetu48280a42017-11-30 15:04:39 -05002920 if(context->getShader(program))
2921 {
2922 return error(GL_INVALID_OPERATION, GL_INVALID_INDEX);
2923 }
2924 else
2925 {
2926 return error(GL_INVALID_VALUE, GL_INVALID_INDEX);
2927 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04002928 }
2929
2930 return programObject->getUniformBlockIndex(uniformBlockName);
2931 }
2932
2933 return GL_INVALID_INDEX;
2934}
2935
2936GL_APICALL void GL_APIENTRY glGetActiveUniformBlockiv(GLuint program, GLuint uniformBlockIndex, GLenum pname, GLint *params)
2937{
2938 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLenum pname = 0x%X, GLint *params = %p)",
2939 program, uniformBlockIndex, pname, params);
2940
2941 es2::Context *context = es2::getContext();
2942
2943 if(context)
2944 {
2945 es2::Program *programObject = context->getProgram(program);
2946
2947 if(!programObject)
2948 {
2949 return error(GL_INVALID_OPERATION);
2950 }
2951
2952 switch(pname)
2953 {
2954 case GL_UNIFORM_BLOCK_BINDING:
2955 *params = static_cast<GLint>(programObject->getUniformBlockBinding(uniformBlockIndex));
2956 break;
2957 case GL_UNIFORM_BLOCK_DATA_SIZE:
2958 case GL_UNIFORM_BLOCK_NAME_LENGTH:
2959 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS:
2960 case GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES:
2961 case GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER:
2962 case GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER:
2963 programObject->getActiveUniformBlockiv(uniformBlockIndex, pname, params);
2964 break;
2965 default:
2966 return error(GL_INVALID_ENUM);
2967 }
2968 }
2969}
2970
2971GL_APICALL void GL_APIENTRY glGetActiveUniformBlockName(GLuint program, GLuint uniformBlockIndex, GLsizei bufSize, GLsizei *length, GLchar *uniformBlockName)
2972{
2973 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLchar *uniformBlockName = %p)",
2974 program, uniformBlockIndex, bufSize, length, uniformBlockName);
2975
2976 if(bufSize < 0)
2977 {
2978 return error(GL_INVALID_VALUE);
2979 }
2980
2981 es2::Context *context = es2::getContext();
2982
2983 if(context)
2984 {
2985 es2::Program *programObject = context->getProgram(program);
2986
2987 if(!programObject)
2988 {
2989 return error(GL_INVALID_OPERATION);
2990 }
2991
2992 programObject->getActiveUniformBlockName(uniformBlockIndex, bufSize, length, uniformBlockName);
2993 }
2994}
2995
2996GL_APICALL void GL_APIENTRY glUniformBlockBinding(GLuint program, GLuint uniformBlockIndex, GLuint uniformBlockBinding)
2997{
2998 TRACE("(GLuint program = %d, GLuint uniformBlockIndex = %d, GLuint uniformBlockBinding = %d)",
2999 program, uniformBlockIndex, uniformBlockBinding);
3000
3001 if(uniformBlockBinding >= MAX_UNIFORM_BUFFER_BINDINGS)
3002 {
3003 return error(GL_INVALID_VALUE);
3004 }
3005
3006 es2::Context *context = es2::getContext();
3007
3008 if(context)
3009 {
3010 es2::Program *programObject = context->getProgram(program);
3011
3012 if(!programObject)
3013 {
3014 return error(GL_INVALID_VALUE);
3015 }
3016
Nicolas Capens65dcbbd2016-08-12 16:59:04 -04003017 programObject->bindUniformBlock(uniformBlockIndex, uniformBlockBinding);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003018 }
3019}
3020
3021GL_APICALL void GL_APIENTRY glDrawArraysInstanced(GLenum mode, GLint first, GLsizei count, GLsizei instanceCount)
3022{
3023 TRACE("(GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d, GLsizei instanceCount = %d)",
3024 mode, first, count, instanceCount);
3025
3026 switch(mode)
3027 {
3028 case GL_POINTS:
3029 case GL_LINES:
3030 case GL_LINE_LOOP:
3031 case GL_LINE_STRIP:
3032 case GL_TRIANGLES:
3033 case GL_TRIANGLE_FAN:
3034 case GL_TRIANGLE_STRIP:
3035 break;
3036 default:
3037 return error(GL_INVALID_ENUM);
3038 }
3039
3040 if(count < 0 || instanceCount < 0)
3041 {
3042 return error(GL_INVALID_VALUE);
3043 }
3044
3045 es2::Context *context = es2::getContext();
3046
3047 if(context)
3048 {
3049 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
3050 if(transformFeedback && transformFeedback->isActive() && (mode != transformFeedback->primitiveMode()))
3051 {
3052 return error(GL_INVALID_OPERATION);
3053 }
3054
3055 context->drawArrays(mode, first, count, instanceCount);
3056 }
3057}
3058
3059GL_APICALL void GL_APIENTRY glDrawElementsInstanced(GLenum mode, GLsizei count, GLenum type, const void *indices, GLsizei instanceCount)
3060{
3061 TRACE("(GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void *indices = %p, GLsizei instanceCount = %d)",
3062 mode, count, type, indices, instanceCount);
3063
3064 switch(mode)
3065 {
3066 case GL_POINTS:
3067 case GL_LINES:
3068 case GL_LINE_LOOP:
3069 case GL_LINE_STRIP:
3070 case GL_TRIANGLES:
3071 case GL_TRIANGLE_FAN:
3072 case GL_TRIANGLE_STRIP:
3073 break;
3074 default:
3075 return error(GL_INVALID_ENUM);
3076 }
3077
3078 switch(type)
3079 {
3080 case GL_UNSIGNED_BYTE:
3081 case GL_UNSIGNED_SHORT:
3082 case GL_UNSIGNED_INT:
3083 break;
3084 default:
3085 return error(GL_INVALID_ENUM);
3086 }
3087
3088 if(count < 0 || instanceCount < 0)
3089 {
3090 return error(GL_INVALID_VALUE);
3091 }
3092
3093 es2::Context *context = es2::getContext();
3094
3095 if(context)
3096 {
3097 es2::TransformFeedback* transformFeedback = context->getTransformFeedback();
3098 if(transformFeedback && transformFeedback->isActive() && !transformFeedback->isPaused())
3099 {
3100 return error(GL_INVALID_OPERATION);
3101 }
3102
3103 context->drawElements(mode, 0, MAX_ELEMENT_INDEX, count, type, indices, instanceCount);
3104 }
3105}
3106
3107GL_APICALL GLsync GL_APIENTRY glFenceSync(GLenum condition, GLbitfield flags)
3108{
3109 TRACE("(GLenum condition = 0x%X, GLbitfield flags = %X)", condition, flags);
3110
3111 switch(condition)
3112 {
3113 case GL_SYNC_GPU_COMMANDS_COMPLETE:
3114 break;
3115 default:
3116 return error(GL_INVALID_ENUM, nullptr);
3117 }
3118
3119 if(flags != 0)
3120 {
3121 return error(GL_INVALID_VALUE, nullptr);
3122 }
3123
3124 es2::Context *context = es2::getContext();
3125
3126 if(context)
3127 {
3128 return context->createFenceSync(condition, flags);
3129 }
3130
3131 return nullptr;
3132}
3133
3134GL_APICALL GLboolean GL_APIENTRY glIsSync(GLsync sync)
3135{
3136 TRACE("(GLsync sync = %p)", sync);
3137
3138 es2::Context *context = es2::getContext();
3139
3140 if(context)
3141 {
3142 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
3143
3144 if(fenceSyncObject)
3145 {
3146 return GL_TRUE;
3147 }
3148 }
3149
3150 return GL_FALSE;
3151}
3152
3153GL_APICALL void GL_APIENTRY glDeleteSync(GLsync sync)
3154{
3155 TRACE("(GLsync sync = %p)", sync);
3156
Alexis Hetuadd96ad2017-11-14 17:22:46 -05003157 if(!sync)
3158 {
3159 return;
3160 }
3161
Nicolas Capens0bac2852016-05-07 06:09:58 -04003162 es2::Context *context = es2::getContext();
3163
3164 if(context)
3165 {
Alexis Hetuadd96ad2017-11-14 17:22:46 -05003166 if(!context->getFenceSync(sync))
3167 {
3168 return error(GL_INVALID_VALUE);
3169 }
3170
Nicolas Capens0bac2852016-05-07 06:09:58 -04003171 context->deleteFenceSync(sync);
3172 }
3173}
3174
3175GL_APICALL GLenum GL_APIENTRY glClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
3176{
3177 TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
3178
3179 if((flags & ~(GL_SYNC_FLUSH_COMMANDS_BIT)) != 0)
3180 {
Alexis Hetu6e864492017-11-14 15:27:00 -05003181 return error(GL_INVALID_VALUE, GL_FALSE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003182 }
3183
3184 es2::Context *context = es2::getContext();
3185
3186 if(context)
3187 {
3188 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
3189
3190 if(fenceSyncObject)
3191 {
3192 return fenceSyncObject->clientWait(flags, timeout);
3193 }
3194 else
3195 {
3196 return error(GL_INVALID_VALUE, GL_FALSE);
3197 }
3198 }
3199
3200 return GL_FALSE;
3201}
3202
3203GL_APICALL void GL_APIENTRY glWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout)
3204{
3205 TRACE("(GLsync sync = %p, GLbitfield flags = %X, GLuint64 timeout = %llu)", sync, flags, timeout);
3206
3207 if(flags != 0)
3208 {
3209 return error(GL_INVALID_VALUE);
3210 }
3211
3212 if(timeout != GL_TIMEOUT_IGNORED)
3213 {
3214 return error(GL_INVALID_VALUE);
3215 }
3216
3217 es2::Context *context = es2::getContext();
3218
3219 if(context)
3220 {
3221 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
3222
3223 if(fenceSyncObject)
3224 {
3225 fenceSyncObject->serverWait(flags, timeout);
3226 }
3227 else
3228 {
3229 return error(GL_INVALID_VALUE);
3230 }
3231 }
3232}
3233
3234GL_APICALL void GL_APIENTRY glGetInteger64v(GLenum pname, GLint64 *data)
3235{
3236 TRACE("(GLenum pname = 0x%X, GLint64 *data = %p)", pname, data);
3237
3238 es2::Context *context = es2::getContext();
3239
3240 if(context)
3241 {
3242 if(!(context->getIntegerv(pname, data)))
3243 {
3244 GLenum nativeType;
3245 unsigned int numParams = 0;
3246 if(!context->getQueryParameterInfo(pname, &nativeType, &numParams))
3247 return error(GL_INVALID_ENUM);
3248
3249 if(numParams == 0)
3250 return; // it is known that pname is valid, but there are no parameters to return
3251
3252 if(nativeType == GL_BOOL)
3253 {
3254 GLboolean *boolParams = nullptr;
3255 boolParams = new GLboolean[numParams];
3256
3257 context->getBooleanv(pname, boolParams);
3258
3259 for(unsigned int i = 0; i < numParams; ++i)
3260 {
3261 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
3262 }
3263
3264 delete[] boolParams;
3265 }
3266 else if(nativeType == GL_FLOAT)
3267 {
3268 GLfloat *floatParams = nullptr;
3269 floatParams = new GLfloat[numParams];
3270
3271 context->getFloatv(pname, floatParams);
3272
3273 for(unsigned int i = 0; i < numParams; ++i)
3274 {
3275 if(pname == GL_DEPTH_RANGE || pname == GL_COLOR_CLEAR_VALUE || pname == GL_DEPTH_CLEAR_VALUE || pname == GL_BLEND_COLOR)
3276 {
Nicolas Capens53318fa2016-04-11 17:41:39 -04003277 data[i] = (GLint64)(convert_float_int(floatParams[i]));
Nicolas Capens0bac2852016-05-07 06:09:58 -04003278 }
3279 else
3280 {
3281 data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
3282 }
3283 }
3284
3285 delete[] floatParams;
3286 }
3287 }
3288 }
3289}
3290
3291GL_APICALL void GL_APIENTRY glGetSynciv(GLsync sync, GLenum pname, GLsizei bufSize, GLsizei *length, GLint *values)
3292{
3293 TRACE("(GLsync sync = %p, GLenum pname = 0x%X, GLsizei bufSize = %d, GLsizei *length = %p, GLint *values = %p)",
3294 sync, pname, bufSize, length, values);
3295
3296 if(bufSize < 0)
3297 {
3298 return error(GL_INVALID_VALUE);
3299 }
3300
Alexis Hetu0f7c7b82017-02-17 17:07:50 -05003301 es2::Context *context = es2::getContext();
3302
3303 if(context)
3304 {
3305 es2::FenceSync *fenceSyncObject = context->getFenceSync(sync);
3306 if(!fenceSyncObject)
3307 {
3308 return error(GL_INVALID_VALUE);
3309 }
3310
3311 fenceSyncObject->getSynciv(pname, length, values);
3312 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003313}
3314
3315GL_APICALL void GL_APIENTRY glGetInteger64i_v(GLenum target, GLuint index, GLint64 *data)
3316{
3317 TRACE("(GLenum target = 0x%X, GLuint index = %d, GLint64 *data = %p)", target, index, data);
3318
3319 es2::Context *context = es2::getContext();
3320
3321 if(context)
3322 {
3323 if(!context->getTransformFeedbackiv(index, target, data) &&
3324 !context->getUniformBufferiv(index, target, data) &&
3325 !context->getIntegerv(target, data))
3326 {
3327 GLenum nativeType;
3328 unsigned int numParams = 0;
3329 if(!context->getQueryParameterInfo(target, &nativeType, &numParams))
3330 return error(GL_INVALID_ENUM);
3331
3332 if(numParams == 0)
3333 return; // it is known that target is valid, but there are no parameters to return
3334
3335 if(nativeType == GL_BOOL)
3336 {
3337 GLboolean *boolParams = nullptr;
3338 boolParams = new GLboolean[numParams];
3339
3340 context->getBooleanv(target, boolParams);
3341
3342 for(unsigned int i = 0; i < numParams; ++i)
3343 {
3344 data[i] = (boolParams[i] == GL_FALSE) ? 0 : 1;
3345 }
3346
3347 delete[] boolParams;
3348 }
3349 else if(nativeType == GL_FLOAT)
3350 {
3351 GLfloat *floatParams = nullptr;
3352 floatParams = new GLfloat[numParams];
3353
3354 context->getFloatv(target, floatParams);
3355
3356 for(unsigned int i = 0; i < numParams; ++i)
3357 {
3358 if(target == GL_DEPTH_RANGE || target == GL_COLOR_CLEAR_VALUE || target == GL_DEPTH_CLEAR_VALUE || target == GL_BLEND_COLOR)
3359 {
Nicolas Capens53318fa2016-04-11 17:41:39 -04003360 data[i] = (GLint64)(convert_float_int(floatParams[i]));
Nicolas Capens0bac2852016-05-07 06:09:58 -04003361 }
3362 else
3363 {
3364 data[i] = (GLint64)(floatParams[i] > 0.0f ? floor(floatParams[i] + 0.5) : ceil(floatParams[i] - 0.5));
3365 }
3366 }
3367
3368 delete[] floatParams;
3369 }
3370 }
3371 }
3372}
3373
3374GL_APICALL void GL_APIENTRY glGetBufferParameteri64v(GLenum target, GLenum pname, GLint64 *params)
3375{
3376 TRACE("(GLenum target = 0x%X, GLenum pname = 0x%X, GLint64 *params = %p)", target, pname, params);
3377
3378 es2::Context *context = es2::getContext();
3379
3380 if(context)
3381 {
3382 es2::Buffer *buffer = nullptr;
3383
3384 if(!context->getBuffer(target, &buffer))
3385 {
3386 return error(GL_INVALID_ENUM);
3387 }
3388
3389 if(!buffer)
3390 {
3391 // A null buffer means that "0" is bound to the requested buffer target
3392 return error(GL_INVALID_OPERATION);
3393 }
3394
3395 switch(pname)
3396 {
3397 case GL_BUFFER_USAGE:
3398 *params = buffer->usage();
3399 break;
3400 case GL_BUFFER_SIZE:
3401 *params = buffer->size();
3402 break;
3403 case GL_BUFFER_ACCESS_FLAGS:
3404 *params = buffer->access();
3405 break;
3406 case GL_BUFFER_MAPPED:
3407 *params = buffer->isMapped();
3408 break;
3409 case GL_BUFFER_MAP_LENGTH:
3410 *params = buffer->length();
3411 break;
3412 case GL_BUFFER_MAP_OFFSET:
3413 *params = buffer->offset();
3414 break;
3415 default:
3416 return error(GL_INVALID_ENUM);
3417 }
3418 }
3419}
3420
3421GL_APICALL void GL_APIENTRY glGenSamplers(GLsizei count, GLuint *samplers)
3422{
3423 TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3424
3425 if(count < 0)
3426 {
3427 return error(GL_INVALID_VALUE);
3428 }
3429
3430 es2::Context *context = es2::getContext();
3431
3432 if(context)
3433 {
3434 for(int i = 0; i < count; i++)
3435 {
3436 samplers[i] = context->createSampler();
3437 }
3438 }
3439}
3440
3441GL_APICALL void GL_APIENTRY glDeleteSamplers(GLsizei count, const GLuint *samplers)
3442{
3443 TRACE("(GLsizei count = %d, GLuint *samplers = %p)", count, samplers);
3444
3445 if(count < 0)
3446 {
3447 return error(GL_INVALID_VALUE);
3448 }
3449
3450 es2::Context *context = es2::getContext();
3451
3452 if(context)
3453 {
3454 for(int i = 0; i < count; i++)
3455 {
3456 context->deleteSampler(samplers[i]);
3457 }
3458 }
3459}
3460
3461GL_APICALL GLboolean GL_APIENTRY glIsSampler(GLuint sampler)
3462{
3463 TRACE("(GLuint sampler = %d)", sampler);
3464
3465 if(sampler == 0)
3466 {
3467 return GL_FALSE;
3468 }
3469
3470 es2::Context *context = es2::getContext();
3471
3472 if(context)
3473 {
3474 if(context->isSampler(sampler))
3475 {
3476 return GL_TRUE;
3477 }
3478 }
3479
3480 return GL_FALSE;
3481}
3482
3483GL_APICALL void GL_APIENTRY glBindSampler(GLuint unit, GLuint sampler)
3484{
3485 TRACE("(GLuint unit = %d, GLuint sampler = %d)", unit, sampler);
3486
3487 if(unit >= es2::MAX_COMBINED_TEXTURE_IMAGE_UNITS)
3488 {
3489 return error(GL_INVALID_VALUE);
3490 }
3491
3492 es2::Context *context = es2::getContext();
3493
3494 if(context)
3495 {
3496 if(sampler != 0 && !context->isSampler(sampler))
3497 {
3498 return error(GL_INVALID_OPERATION);
3499 }
3500
3501 context->bindSampler(unit, sampler);
3502 }
3503}
3504
3505GL_APICALL void GL_APIENTRY glSamplerParameteri(GLuint sampler, GLenum pname, GLint param)
3506{
3507 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint param = %d)",
3508 sampler, pname, param);
3509
3510 glSamplerParameteriv(sampler, pname, &param);
3511}
3512
3513GL_APICALL void GL_APIENTRY glSamplerParameteriv(GLuint sampler, GLenum pname, const GLint *param)
3514{
3515 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLint *param = %p)",
3516 sampler, pname, param);
3517
3518 if(!ValidateSamplerObjectParameter(pname))
3519 {
3520 return error(GL_INVALID_ENUM);
3521 }
3522
3523 if(!ValidateTexParamParameters(pname, *param))
3524 {
3525 return;
3526 }
3527
3528 es2::Context *context = es2::getContext();
3529
3530 if(context)
3531 {
3532 if(!context->isSampler(sampler))
3533 {
3534 return error(GL_INVALID_OPERATION);
3535 }
3536
3537 context->samplerParameteri(sampler, pname, *param);
3538 }
3539}
3540
3541GL_APICALL void GL_APIENTRY glSamplerParameterf(GLuint sampler, GLenum pname, GLfloat param)
3542{
3543 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat param = %f)",
3544 sampler, pname, param);
3545
3546 glSamplerParameterfv(sampler, pname, &param);
3547}
3548
3549GL_APICALL void GL_APIENTRY glSamplerParameterfv(GLuint sampler, GLenum pname, const GLfloat *param)
3550{
3551 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, const GLfloat *param = %p)",
3552 sampler, pname, param);
3553
3554 if(!ValidateSamplerObjectParameter(pname))
3555 {
3556 return error(GL_INVALID_ENUM);
3557 }
3558
Nicolas Capens0bac2852016-05-07 06:09:58 -04003559 es2::Context *context = es2::getContext();
3560
3561 if(context)
3562 {
3563 if(!context->isSampler(sampler))
3564 {
3565 return error(GL_INVALID_OPERATION);
3566 }
3567
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003568 if(ValidateTexParamParameters(pname, static_cast<GLint>(roundf(*param))))
3569 {
3570 context->samplerParameterf(sampler, pname, *param);
3571 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003572 }
3573}
3574
3575GL_APICALL void GL_APIENTRY glGetSamplerParameteriv(GLuint sampler, GLenum pname, GLint *params)
3576{
3577 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLint *params = %p)",
3578 sampler, pname, params);
3579
3580 if(!ValidateSamplerObjectParameter(pname))
3581 {
3582 return error(GL_INVALID_ENUM);
3583 }
3584
3585 es2::Context *context = es2::getContext();
3586
3587 if(context)
3588 {
3589 if(!context->isSampler(sampler))
3590 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003591 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003592 }
3593
3594 *params = context->getSamplerParameteri(sampler, pname);
3595 }
3596}
3597
3598GL_APICALL void GL_APIENTRY glGetSamplerParameterfv(GLuint sampler, GLenum pname, GLfloat *params)
3599{
3600 TRACE("(GLuint sampler = %d, GLenum pname = 0x%X, GLfloat *params = %p)",
3601 sampler, pname, params);
3602
3603 if(!ValidateSamplerObjectParameter(pname))
3604 {
3605 return error(GL_INVALID_ENUM);
3606 }
3607
3608 es2::Context *context = es2::getContext();
3609
3610 if(context)
3611 {
3612 if(!context->isSampler(sampler))
3613 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003614 return error(GL_INVALID_OPERATION);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003615 }
3616
3617 *params = context->getSamplerParameterf(sampler, pname);
3618 }
3619}
3620
3621GL_APICALL void GL_APIENTRY glVertexAttribDivisor(GLuint index, GLuint divisor)
3622{
3623 TRACE("(GLuint index = %d, GLuint divisor = %d)", index, divisor);
3624
3625 es2::Context *context = es2::getContext();
3626
3627 if(context)
3628 {
3629 if(index >= es2::MAX_VERTEX_ATTRIBS)
3630 {
3631 return error(GL_INVALID_VALUE);
3632 }
3633
3634 context->setVertexAttribDivisor(index, divisor);
3635 }
3636}
3637
3638GL_APICALL void GL_APIENTRY glBindTransformFeedback(GLenum target, GLuint id)
3639{
3640 TRACE("(GLenum target = 0x%X, GLuint id = %d)", target, id);
3641
3642 if(target != GL_TRANSFORM_FEEDBACK)
3643 {
3644 return error(GL_INVALID_ENUM);
3645 }
3646
3647 es2::Context *context = es2::getContext();
3648
3649 if(context)
3650 {
3651 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3652
3653 if(transformFeedbackObject && transformFeedbackObject->isActive() && !transformFeedbackObject->isPaused())
3654 {
3655 return error(GL_INVALID_OPERATION);
3656 }
3657
Alexis Hetu5bf97082017-11-14 11:06:03 -05003658 if(!context->isTransformFeedback(id))
3659 {
3660 return error(GL_INVALID_OPERATION);
3661 }
3662
Nicolas Capens0bac2852016-05-07 06:09:58 -04003663 context->bindTransformFeedback(id);
3664 }
3665}
3666
3667GL_APICALL void GL_APIENTRY glDeleteTransformFeedbacks(GLsizei n, const GLuint *ids)
3668{
3669 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3670
3671 if(n < 0)
3672 {
3673 return error(GL_INVALID_VALUE);
3674 }
3675
3676 es2::Context *context = es2::getContext();
3677
3678 if(context)
3679 {
3680 for(int i = 0; i < n; i++)
3681 {
3682 if(ids[i] != 0)
3683 {
Alexis Hetu5bf97082017-11-14 11:06:03 -05003684 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(ids[i]);
3685
3686 if(transformFeedbackObject && transformFeedbackObject->isActive())
3687 {
3688 return error(GL_INVALID_OPERATION);
3689 }
3690
Nicolas Capens0bac2852016-05-07 06:09:58 -04003691 context->deleteTransformFeedback(ids[i]);
3692 }
3693 }
3694 }
3695}
3696
3697GL_APICALL void GL_APIENTRY glGenTransformFeedbacks(GLsizei n, GLuint *ids)
3698{
3699 TRACE("(GLsizei n = %d, const GLuint *ids = %p)", n, ids);
3700
3701 if(n < 0)
3702 {
3703 return error(GL_INVALID_VALUE);
3704 }
3705
3706 es2::Context *context = es2::getContext();
3707
3708 if(context)
3709 {
3710 for(int i = 0; i < n; i++)
3711 {
3712 ids[i] = context->createTransformFeedback();
3713 }
3714 }
3715}
3716
3717GL_APICALL GLboolean GL_APIENTRY glIsTransformFeedback(GLuint id)
3718{
3719 TRACE("(GLuint id = %d)", id);
3720
3721 if(id == 0)
3722 {
3723 return GL_FALSE;
3724 }
3725
3726 es2::Context *context = es2::getContext();
3727
3728 if(context)
3729 {
3730 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback(id);
3731
3732 if(transformFeedbackObject)
3733 {
3734 return GL_TRUE;
3735 }
3736 }
3737
3738 return GL_FALSE;
3739}
3740
3741GL_APICALL void GL_APIENTRY glPauseTransformFeedback(void)
3742{
3743 TRACE("()");
3744
3745 es2::Context *context = es2::getContext();
3746
3747 if(context)
3748 {
3749 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3750
3751 if(transformFeedbackObject)
3752 {
3753 if(!transformFeedbackObject->isActive() || transformFeedbackObject->isPaused())
3754 {
3755 return error(GL_INVALID_OPERATION);
3756 }
3757 transformFeedbackObject->setPaused(true);
3758 }
3759 }
3760}
3761
3762GL_APICALL void GL_APIENTRY glResumeTransformFeedback(void)
3763{
3764 TRACE("()");
3765
3766 es2::Context *context = es2::getContext();
3767
3768 if(context)
3769 {
3770 es2::TransformFeedback *transformFeedbackObject = context->getTransformFeedback();
3771
3772 if(transformFeedbackObject)
3773 {
3774 if(!transformFeedbackObject->isActive() || !transformFeedbackObject->isPaused())
3775 {
3776 return error(GL_INVALID_OPERATION);
3777 }
3778 transformFeedbackObject->setPaused(false);
3779 }
3780 }
3781}
3782
3783GL_APICALL void GL_APIENTRY glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary)
3784{
3785 TRACE("(GLuint program = %d, GLsizei bufSize = %d, GLsizei *length = %p, GLenum *binaryFormat = %p, void *binary = %p)",
3786 program, bufSize, length, binaryFormat, binary);
3787
3788 if(bufSize < 0)
3789 {
3790 return error(GL_INVALID_VALUE);
3791 }
3792
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003793 es2::Context *context = es2::getContext();
3794
3795 if(context)
3796 {
3797 es2::Program *programObject = context->getProgram(program);
3798
3799 if(!programObject || !programObject->isLinked())
3800 {
3801 return error(GL_INVALID_OPERATION);
3802 }
3803 }
3804
Nicolas Capens0bac2852016-05-07 06:09:58 -04003805 UNIMPLEMENTED();
3806}
3807
3808GL_APICALL void GL_APIENTRY glProgramBinary(GLuint program, GLenum binaryFormat, const void *binary, GLsizei length)
3809{
3810 TRACE("(GLuint program = %d, GLenum binaryFormat = 0x%X, const void *binary = %p, GLsizei length = %d)",
3811 program, binaryFormat, binaryFormat, length);
3812
3813 if(length < 0)
3814 {
3815 return error(GL_INVALID_VALUE);
3816 }
3817
3818 UNIMPLEMENTED();
3819}
3820
3821GL_APICALL void GL_APIENTRY glProgramParameteri(GLuint program, GLenum pname, GLint value)
3822{
3823 TRACE("(GLuint program = %d, GLenum pname = 0x%X, GLint value = %d)",
3824 program, pname, value);
3825
3826 es2::Context *context = es2::getContext();
3827
3828 if(context)
3829 {
3830 es2::Program *programObject = context->getProgram(program);
3831
3832 if(!programObject)
3833 {
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003834 return error(GL_INVALID_VALUE);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003835 }
3836
3837 switch(pname)
3838 {
3839 case GL_PROGRAM_BINARY_RETRIEVABLE_HINT:
Alexis Hetu3eb573f2017-11-22 13:27:03 -05003840 if((value != GL_TRUE) && (value != GL_FALSE))
3841 {
3842 return error(GL_INVALID_VALUE);
3843 }
Nicolas Capens0bac2852016-05-07 06:09:58 -04003844 programObject->setBinaryRetrievable(value != GL_FALSE);
3845 break;
3846 default:
3847 return error(GL_INVALID_ENUM);
3848 }
3849 }
3850}
3851
3852GL_APICALL void GL_APIENTRY glInvalidateFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments)
3853{
3854 TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p)",
3855 target, numAttachments, attachments);
3856
3857 glInvalidateSubFramebuffer(target, numAttachments, attachments, 0, 0, std::numeric_limits<GLsizei>::max(), std::numeric_limits<GLsizei>::max());
3858}
3859
3860GL_APICALL void GL_APIENTRY glInvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, const GLenum *attachments, GLint x, GLint y, GLsizei width, GLsizei height)
3861{
3862 TRACE("(GLenum target = 0x%X, GLsizei numAttachments = %d, const GLenum *attachments = %p, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d)",
3863 target, numAttachments, attachments, x, y, width, height);
3864
3865 es2::Context *context = es2::getContext();
3866
3867 if(context)
3868 {
3869 if(numAttachments < 0 || width < 0 || height < 0)
3870 {
3871 return error(GL_INVALID_VALUE);
3872 }
3873
3874 es2::Framebuffer *framebuffer = nullptr;
3875 switch(target)
3876 {
3877 case GL_DRAW_FRAMEBUFFER:
3878 case GL_FRAMEBUFFER:
3879 framebuffer = context->getDrawFramebuffer();
3880 case GL_READ_FRAMEBUFFER:
3881 framebuffer = context->getReadFramebuffer();
3882 break;
3883 default:
3884 return error(GL_INVALID_ENUM);
3885 }
3886
3887 if(framebuffer)
3888 {
3889 for(int i = 0; i < numAttachments; i++)
3890 {
3891 switch(attachments[i])
3892 {
3893 case GL_COLOR:
3894 case GL_DEPTH:
3895 case GL_STENCIL:
3896 if(!framebuffer->isDefaultFramebuffer())
3897 {
3898 return error(GL_INVALID_ENUM);
3899 }
3900 break;
3901 case GL_DEPTH_ATTACHMENT:
3902 case GL_STENCIL_ATTACHMENT:
3903 case GL_DEPTH_STENCIL_ATTACHMENT:
3904 break;
3905 default:
3906 if(attachments[i] >= GL_COLOR_ATTACHMENT0 &&
3907 attachments[i] <= GL_COLOR_ATTACHMENT31)
3908 {
3909 if(attachments[i] - GL_COLOR_ATTACHMENT0 >= MAX_DRAW_BUFFERS)
3910 {
3911 return error(GL_INVALID_OPERATION);
3912 }
3913 }
3914 else
3915 {
3916 return error(GL_INVALID_ENUM);
3917 }
3918 break;
3919 }
3920 }
3921 }
3922
3923 // UNIMPLEMENTED(); // It is valid for this function to be treated as a no-op
3924 }
3925}
3926
3927GL_APICALL void GL_APIENTRY glTexStorage2D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height)
3928{
3929 TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d)",
3930 target, levels, internalformat, width, height);
3931
3932 if(width < 1 || height < 1 || levels < 1)
3933 {
3934 return error(GL_INVALID_VALUE);
3935 }
3936
3937 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
3938 {
3939 return error(GL_INVALID_OPERATION);
3940 }
3941
3942 GLenum type;
3943 if(!GetStorageType(internalformat, type))
3944 {
3945 return error(GL_INVALID_ENUM);
3946 }
3947
3948 es2::Context *context = es2::getContext();
3949
3950 if(context)
3951 {
3952 switch(target)
3953 {
3954 case GL_TEXTURE_2D:
3955 {
3956 es2::Texture2D *texture = context->getTexture2D();
3957 if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
3958 {
3959 return error(GL_INVALID_OPERATION);
3960 }
3961
3962 for(int level = 0; level < levels; ++level)
3963 {
Nicolas Capens81aa97b2017-06-27 17:08:08 -04003964 texture->setImage(context, level, width, height, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003965 width = std::max(1, (width / 2));
3966 height = std::max(1, (height / 2));
3967 }
3968 texture->makeImmutable(levels);
3969 }
3970 break;
3971 case GL_TEXTURE_CUBE_MAP:
3972 {
3973 es2::TextureCubeMap *texture = context->getTextureCubeMap();
3974 if(!texture || texture->name == 0 || texture->getImmutableFormat())
3975 {
3976 return error(GL_INVALID_OPERATION);
3977 }
3978
3979 for(int level = 0; level < levels; ++level)
3980 {
3981 for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; ++face)
3982 {
Nicolas Capens81aa97b2017-06-27 17:08:08 -04003983 texture->setImage(context, face, level, width, height, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04003984 }
3985 width = std::max(1, (width / 2));
3986 height = std::max(1, (height / 2));
3987 }
3988 texture->makeImmutable(levels);
3989 }
3990 break;
3991 default:
3992 return error(GL_INVALID_ENUM);
3993 }
3994 }
3995}
3996
3997GL_APICALL void GL_APIENTRY glTexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth)
3998{
3999 TRACE("(GLenum target = 0x%X, GLsizei levels = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d)",
4000 target, levels, internalformat, width, height, depth);
4001
4002 if(width < 1 || height < 1 || depth < 1 || levels < 1)
4003 {
4004 return error(GL_INVALID_VALUE);
4005 }
4006
4007 GLenum type;
4008 if(!GetStorageType(internalformat, type))
4009 {
4010 return error(GL_INVALID_ENUM);
4011 }
4012
4013 es2::Context *context = es2::getContext();
4014
4015 if(context)
4016 {
4017 switch(target)
4018 {
4019 case GL_TEXTURE_3D:
4020 {
4021 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(std::max(width, height), depth)) + 1))
4022 {
4023 return error(GL_INVALID_OPERATION);
4024 }
4025
4026 es2::Texture3D *texture = context->getTexture3D();
4027 if(!texture || texture->name == 0 || texture->getImmutableFormat() == GL_TRUE)
4028 {
4029 return error(GL_INVALID_OPERATION);
4030 }
4031
4032 for(int level = 0; level < levels; ++level)
4033 {
Nicolas Capens81aa97b2017-06-27 17:08:08 -04004034 texture->setImage(context, level, width, height, depth, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04004035 width = std::max(1, (width / 2));
4036 height = std::max(1, (height / 2));
4037 depth = std::max(1, (depth / 2));
4038 }
4039 texture->makeImmutable(levels);
4040 }
4041 break;
4042 case GL_TEXTURE_2D_ARRAY:
4043 {
4044 if(levels > es2::IMPLEMENTATION_MAX_TEXTURE_LEVELS || levels > (log2(std::max(width, height)) + 1))
4045 {
4046 return error(GL_INVALID_OPERATION);
4047 }
4048
4049 es2::Texture3D *texture = context->getTexture2DArray();
4050 if(!texture || texture->name == 0 || texture->getImmutableFormat())
4051 {
4052 return error(GL_INVALID_OPERATION);
4053 }
4054
4055 for(int level = 0; level < levels; ++level)
4056 {
4057 for(int face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; ++face)
4058 {
Nicolas Capens81aa97b2017-06-27 17:08:08 -04004059 texture->setImage(context, level, width, height, depth, GetSizedInternalFormat(internalformat, type), type, context->getUnpackInfo(), nullptr);
Nicolas Capens0bac2852016-05-07 06:09:58 -04004060 }
4061 width = std::max(1, (width / 2));
4062 height = std::max(1, (height / 2));
4063 }
4064 texture->makeImmutable(levels);
4065 }
4066 break;
4067 default:
4068 return error(GL_INVALID_ENUM);
4069 }
4070 }
4071}
4072
4073GL_APICALL void GL_APIENTRY glGetInternalformativ(GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params)
4074{
4075 TRACE("(GLenum target = 0x%X, GLenum internalformat = 0x%X, GLenum pname = 0x%X, GLsizei bufSize = %d, GLint *params = %p)",
4076 target, internalformat, pname, bufSize, params);
4077
4078 if(bufSize < 0)
4079 {
4080 return error(GL_INVALID_VALUE);
4081 }
4082
4083 if(bufSize == 0)
4084 {
4085 return;
4086 }
4087
Nicolas Capens400667e2017-03-29 14:40:14 -04004088 if(!IsColorRenderable(internalformat, egl::getClientVersion(), false) &&
4089 !IsDepthRenderable(internalformat, egl::getClientVersion()) &&
4090 !IsStencilRenderable(internalformat, egl::getClientVersion()))
Nicolas Capens0bac2852016-05-07 06:09:58 -04004091 {
4092 return error(GL_INVALID_ENUM);
4093 }
4094
4095 switch(target)
4096 {
4097 case GL_RENDERBUFFER:
4098 break;
4099 default:
4100 return error(GL_INVALID_ENUM);
4101 }
4102
4103 // Integer types have no multisampling
4104 GLint numMultisampleCounts = NUM_MULTISAMPLE_COUNTS;
4105 switch(internalformat)
4106 {
4107 case GL_R8UI:
4108 case GL_R8I:
4109 case GL_R16UI:
4110 case GL_R16I:
4111 case GL_R32UI:
4112 case GL_R32I:
4113 case GL_RG8UI:
4114 case GL_RG8I:
4115 case GL_RG16UI:
4116 case GL_RG16I:
4117 case GL_RG32UI:
4118 case GL_RG32I:
4119 case GL_RGB8UI:
4120 case GL_RGB8I:
4121 case GL_RGB16UI:
4122 case GL_RGB16I:
4123 case GL_RGB32UI:
4124 case GL_RGB32I:
4125 case GL_RGBA8UI:
4126 case GL_RGBA8I:
4127 case GL_RGB10_A2UI:
4128 case GL_RGBA16UI:
4129 case GL_RGBA16I:
4130 case GL_RGBA32UI:
4131 case GL_RGBA32I:
4132 numMultisampleCounts = 0;
4133 break;
4134 default:
4135 break;
4136 }
4137
4138 switch(pname)
4139 {
4140 case GL_NUM_SAMPLE_COUNTS:
4141 *params = numMultisampleCounts;
4142 break;
4143 case GL_SAMPLES:
4144 for(int i = 0; i < numMultisampleCounts && i < bufSize; i++)
4145 {
4146 params[i] = multisampleCount[i];
4147 }
4148 break;
4149 default:
4150 return error(GL_INVALID_ENUM);
4151 }
4152}
4153
4154}