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