1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #include "WebGLContextUtils.h"
7 #include "WebGLContext.h"
8
9 #include "GLContext.h"
10 #include "jsapi.h"
11 #include "mozilla/dom/ScriptSettings.h"
12 #include "mozilla/Preferences.h"
13 #include "nsIDOMDataContainerEvent.h"
14 #include "nsIDOMEvent.h"
15 #include "nsIScriptSecurityManager.h"
16 #include "nsIVariant.h"
17 #include "nsPrintfCString.h"
18 #include "nsServiceManagerUtils.h"
19 #include "prprf.h"
20 #include <stdarg.h>
21 #include "WebGLBuffer.h"
22 #include "WebGLExtensions.h"
23 #include "WebGLFramebuffer.h"
24 #include "WebGLProgram.h"
25 #include "WebGLTexture.h"
26 #include "WebGLVertexArray.h"
27
28 namespace mozilla {
29
30 TexTarget
TexImageTargetToTexTarget(TexImageTarget texImageTarget)31 TexImageTargetToTexTarget(TexImageTarget texImageTarget)
32 {
33 switch (texImageTarget.get()) {
34 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
35 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
36 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
37 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
38 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
39 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
40 return LOCAL_GL_TEXTURE_CUBE_MAP;
41
42 default:
43 return texImageTarget.get();
44 }
45 }
46
47 JS::Value
StringValue(JSContext * cx,const char * chars,ErrorResult & rv)48 StringValue(JSContext* cx, const char* chars, ErrorResult& rv)
49 {
50 JSString* str = JS_NewStringCopyZ(cx, chars);
51 if (!str) {
52 rv.Throw(NS_ERROR_OUT_OF_MEMORY);
53 return JS::NullValue();
54 }
55
56 return JS::StringValue(str);
57 }
58
59 void
GenerateWarning(const char * fmt,...)60 WebGLContext::GenerateWarning(const char* fmt, ...)
61 {
62 va_list ap;
63 va_start(ap, fmt);
64
65 GenerateWarning(fmt, ap);
66
67 va_end(ap);
68 }
69
70 void
GenerateWarning(const char * fmt,va_list ap)71 WebGLContext::GenerateWarning(const char* fmt, va_list ap)
72 {
73 if (!ShouldGenerateWarnings())
74 return;
75
76 mAlreadyGeneratedWarnings++;
77
78 char buf[1024];
79 PR_vsnprintf(buf, 1024, fmt, ap);
80
81 // no need to print to stderr, as JS_ReportWarning takes care of this for us.
82
83 if (!mCanvasElement) {
84 return;
85 }
86
87 dom::AutoJSAPI api;
88 if (!api.Init(mCanvasElement->OwnerDoc()->GetScopeObject())) {
89 return;
90 }
91
92 JSContext* cx = api.cx();
93 JS_ReportWarningASCII(cx, "WebGL: %s", buf);
94 if (!ShouldGenerateWarnings()) {
95 JS_ReportWarningASCII(cx,
96 "WebGL: No further warnings will be reported for"
97 " this WebGL context."
98 " (already reported %d warnings)",
99 mAlreadyGeneratedWarnings);
100 }
101 }
102
103 bool
ShouldGenerateWarnings() const104 WebGLContext::ShouldGenerateWarnings() const
105 {
106 if (mMaxWarnings == -1)
107 return true;
108
109 return mAlreadyGeneratedWarnings < mMaxWarnings;
110 }
111
112 void
SynthesizeGLError(GLenum err)113 WebGLContext::SynthesizeGLError(GLenum err)
114 {
115 /* ES2 section 2.5 "GL Errors" states that implementations can have
116 * multiple 'flags', as errors might be caught in different parts of
117 * a distributed implementation.
118 * We're signing up as a distributed implementation here, with
119 * separate flags for WebGL and the underlying GLContext.
120 */
121 if (!mWebGLError)
122 mWebGLError = err;
123 }
124
125 void
SynthesizeGLError(GLenum err,const char * fmt,...)126 WebGLContext::SynthesizeGLError(GLenum err, const char* fmt, ...)
127 {
128 va_list va;
129 va_start(va, fmt);
130 GenerateWarning(fmt, va);
131 va_end(va);
132
133 return SynthesizeGLError(err);
134 }
135
136 void
ErrorInvalidEnum(const char * fmt,...)137 WebGLContext::ErrorInvalidEnum(const char* fmt, ...)
138 {
139 va_list va;
140 va_start(va, fmt);
141 GenerateWarning(fmt, va);
142 va_end(va);
143
144 return SynthesizeGLError(LOCAL_GL_INVALID_ENUM);
145 }
146
147 void
ErrorInvalidEnumInfo(const char * info,GLenum enumValue)148 WebGLContext::ErrorInvalidEnumInfo(const char* info, GLenum enumValue)
149 {
150 nsCString name;
151 EnumName(enumValue, &name);
152
153 return ErrorInvalidEnum("%s: invalid enum value %s", info, name.BeginReading());
154 }
155
156 void
ErrorInvalidEnumInfo(const char * info,const char * funcName,GLenum enumValue)157 WebGLContext::ErrorInvalidEnumInfo(const char* info, const char* funcName,
158 GLenum enumValue)
159 {
160 nsCString name;
161 EnumName(enumValue, &name);
162
163 ErrorInvalidEnum("%s: %s: Invalid enum: 0x%04x (%s).", funcName, info,
164 enumValue, name.BeginReading());
165 }
166
167 void
ErrorInvalidOperation(const char * fmt,...)168 WebGLContext::ErrorInvalidOperation(const char* fmt, ...)
169 {
170 va_list va;
171 va_start(va, fmt);
172 GenerateWarning(fmt, va);
173 va_end(va);
174
175 return SynthesizeGLError(LOCAL_GL_INVALID_OPERATION);
176 }
177
178 void
ErrorInvalidValue(const char * fmt,...)179 WebGLContext::ErrorInvalidValue(const char* fmt, ...)
180 {
181 va_list va;
182 va_start(va, fmt);
183 GenerateWarning(fmt, va);
184 va_end(va);
185
186 return SynthesizeGLError(LOCAL_GL_INVALID_VALUE);
187 }
188
189 void
ErrorInvalidFramebufferOperation(const char * fmt,...)190 WebGLContext::ErrorInvalidFramebufferOperation(const char* fmt, ...)
191 {
192 va_list va;
193 va_start(va, fmt);
194 GenerateWarning(fmt, va);
195 va_end(va);
196
197 return SynthesizeGLError(LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION);
198 }
199
200 void
ErrorOutOfMemory(const char * fmt,...)201 WebGLContext::ErrorOutOfMemory(const char* fmt, ...)
202 {
203 va_list va;
204 va_start(va, fmt);
205 GenerateWarning(fmt, va);
206 va_end(va);
207
208 return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
209 }
210
211 void
ErrorImplementationBug(const char * fmt,...)212 WebGLContext::ErrorImplementationBug(const char* fmt, ...)
213 {
214 const nsPrintfCString warning("Implementation bug, please file at %s! %s",
215 "https://bugzilla.mozilla.org/", fmt);
216
217 va_list va;
218 va_start(va, fmt);
219 GenerateWarning(warning.BeginReading(), va);
220 va_end(va);
221
222 MOZ_ASSERT(false, "WebGLContext::ErrorImplementationBug");
223 NS_ERROR("WebGLContext::ErrorImplementationBug");
224 return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
225 }
226
227 const char*
ErrorName(GLenum error)228 WebGLContext::ErrorName(GLenum error)
229 {
230 switch(error) {
231 case LOCAL_GL_INVALID_ENUM:
232 return "INVALID_ENUM";
233 case LOCAL_GL_INVALID_OPERATION:
234 return "INVALID_OPERATION";
235 case LOCAL_GL_INVALID_VALUE:
236 return "INVALID_VALUE";
237 case LOCAL_GL_OUT_OF_MEMORY:
238 return "OUT_OF_MEMORY";
239 case LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION:
240 return "INVALID_FRAMEBUFFER_OPERATION";
241 case LOCAL_GL_NO_ERROR:
242 return "NO_ERROR";
243 default:
244 MOZ_ASSERT(false);
245 return "[unknown WebGL error]";
246 }
247 }
248
249 // This version is fallible and will return nullptr if unrecognized.
250 static const char*
GetEnumName(GLenum val)251 GetEnumName(GLenum val)
252 {
253 switch (val) {
254 #define XX(x) case LOCAL_GL_##x: return #x
255 XX(NONE);
256 XX(ALPHA);
257 XX(ATC_RGB);
258 XX(ATC_RGBA_EXPLICIT_ALPHA);
259 XX(ATC_RGBA_INTERPOLATED_ALPHA);
260 XX(COMPRESSED_RGBA_PVRTC_2BPPV1);
261 XX(COMPRESSED_RGBA_PVRTC_4BPPV1);
262 XX(COMPRESSED_RGBA_S3TC_DXT1_EXT);
263 XX(COMPRESSED_RGBA_S3TC_DXT3_EXT);
264 XX(COMPRESSED_RGBA_S3TC_DXT5_EXT);
265 XX(COMPRESSED_RGB_PVRTC_2BPPV1);
266 XX(COMPRESSED_RGB_PVRTC_4BPPV1);
267 XX(COMPRESSED_RGB_S3TC_DXT1_EXT);
268 XX(DEPTH_ATTACHMENT);
269 XX(DEPTH_COMPONENT);
270 XX(DEPTH_COMPONENT16);
271 XX(DEPTH_COMPONENT32);
272 XX(DEPTH_STENCIL);
273 XX(DEPTH24_STENCIL8);
274 XX(DRAW_FRAMEBUFFER);
275 XX(ETC1_RGB8_OES);
276 XX(FLOAT);
277 XX(INT);
278 XX(FRAMEBUFFER);
279 XX(HALF_FLOAT);
280 XX(LUMINANCE);
281 XX(LUMINANCE_ALPHA);
282 XX(READ_FRAMEBUFFER);
283 XX(RGB);
284 XX(RGB16F);
285 XX(RGB32F);
286 XX(RGBA);
287 XX(RGBA16F);
288 XX(RGBA32F);
289 XX(SRGB);
290 XX(SRGB_ALPHA);
291 XX(TEXTURE_2D);
292 XX(TEXTURE_3D);
293 XX(TEXTURE_CUBE_MAP);
294 XX(TEXTURE_CUBE_MAP_NEGATIVE_X);
295 XX(TEXTURE_CUBE_MAP_NEGATIVE_Y);
296 XX(TEXTURE_CUBE_MAP_NEGATIVE_Z);
297 XX(TEXTURE_CUBE_MAP_POSITIVE_X);
298 XX(TEXTURE_CUBE_MAP_POSITIVE_Y);
299 XX(TEXTURE_CUBE_MAP_POSITIVE_Z);
300 XX(UNSIGNED_BYTE);
301 XX(UNSIGNED_INT);
302 XX(UNSIGNED_INT_24_8);
303 XX(UNSIGNED_SHORT);
304 XX(UNSIGNED_SHORT_4_4_4_4);
305 XX(UNSIGNED_SHORT_5_5_5_1);
306 XX(UNSIGNED_SHORT_5_6_5);
307 XX(READ_BUFFER);
308 XX(UNPACK_ROW_LENGTH);
309 XX(UNPACK_SKIP_ROWS);
310 XX(UNPACK_SKIP_PIXELS);
311 XX(PACK_ROW_LENGTH);
312 XX(PACK_SKIP_ROWS);
313 XX(PACK_SKIP_PIXELS);
314 XX(COLOR);
315 XX(DEPTH);
316 XX(STENCIL);
317 XX(RED);
318 XX(RGB8);
319 XX(RGBA8);
320 XX(RGB10_A2);
321 XX(TEXTURE_BINDING_3D);
322 XX(UNPACK_SKIP_IMAGES);
323 XX(UNPACK_IMAGE_HEIGHT);
324 XX(TEXTURE_WRAP_R);
325 XX(MAX_3D_TEXTURE_SIZE);
326 XX(UNSIGNED_INT_2_10_10_10_REV);
327 XX(MAX_ELEMENTS_VERTICES);
328 XX(MAX_ELEMENTS_INDICES);
329 XX(TEXTURE_MIN_LOD);
330 XX(TEXTURE_MAX_LOD);
331 XX(TEXTURE_BASE_LEVEL);
332 XX(TEXTURE_MAX_LEVEL);
333 XX(MIN);
334 XX(MAX);
335 XX(DEPTH_COMPONENT24);
336 XX(MAX_TEXTURE_LOD_BIAS);
337 XX(TEXTURE_COMPARE_MODE);
338 XX(TEXTURE_COMPARE_FUNC);
339 XX(CURRENT_QUERY);
340 XX(QUERY_RESULT);
341 XX(QUERY_RESULT_AVAILABLE);
342 XX(STREAM_READ);
343 XX(STREAM_COPY);
344 XX(STATIC_READ);
345 XX(STATIC_COPY);
346 XX(DYNAMIC_READ);
347 XX(DYNAMIC_COPY);
348 XX(MAX_DRAW_BUFFERS);
349 XX(DRAW_BUFFER0);
350 XX(DRAW_BUFFER1);
351 XX(DRAW_BUFFER2);
352 XX(DRAW_BUFFER3);
353 XX(DRAW_BUFFER4);
354 XX(DRAW_BUFFER5);
355 XX(DRAW_BUFFER6);
356 XX(DRAW_BUFFER7);
357 XX(DRAW_BUFFER8);
358 XX(DRAW_BUFFER9);
359 XX(DRAW_BUFFER10);
360 XX(DRAW_BUFFER11);
361 XX(DRAW_BUFFER12);
362 XX(DRAW_BUFFER13);
363 XX(DRAW_BUFFER14);
364 XX(DRAW_BUFFER15);
365 XX(MAX_FRAGMENT_UNIFORM_COMPONENTS);
366 XX(MAX_VERTEX_UNIFORM_COMPONENTS);
367 XX(SAMPLER_3D);
368 XX(SAMPLER_2D_SHADOW);
369 XX(FRAGMENT_SHADER_DERIVATIVE_HINT);
370 XX(PIXEL_PACK_BUFFER);
371 XX(PIXEL_UNPACK_BUFFER);
372 XX(PIXEL_PACK_BUFFER_BINDING);
373 XX(PIXEL_UNPACK_BUFFER_BINDING);
374 XX(FLOAT_MAT2x3);
375 XX(FLOAT_MAT2x4);
376 XX(FLOAT_MAT3x2);
377 XX(FLOAT_MAT3x4);
378 XX(FLOAT_MAT4x2);
379 XX(FLOAT_MAT4x3);
380 XX(SRGB8);
381 XX(SRGB8_ALPHA8);
382 XX(COMPARE_REF_TO_TEXTURE);
383 XX(VERTEX_ATTRIB_ARRAY_INTEGER);
384 XX(MAX_ARRAY_TEXTURE_LAYERS);
385 XX(MIN_PROGRAM_TEXEL_OFFSET);
386 XX(MAX_PROGRAM_TEXEL_OFFSET);
387 XX(MAX_VARYING_COMPONENTS);
388 XX(TEXTURE_2D_ARRAY);
389 XX(TEXTURE_BINDING_2D_ARRAY);
390 XX(R11F_G11F_B10F);
391 XX(UNSIGNED_INT_10F_11F_11F_REV);
392 XX(RGB9_E5);
393 XX(UNSIGNED_INT_5_9_9_9_REV);
394 XX(TRANSFORM_FEEDBACK_BUFFER_MODE);
395 XX(MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS);
396 XX(TRANSFORM_FEEDBACK_VARYINGS);
397 XX(TRANSFORM_FEEDBACK_BUFFER_START);
398 XX(TRANSFORM_FEEDBACK_BUFFER_SIZE);
399 XX(TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
400 XX(RASTERIZER_DISCARD);
401 XX(MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS);
402 XX(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS);
403 XX(INTERLEAVED_ATTRIBS);
404 XX(SEPARATE_ATTRIBS);
405 XX(TRANSFORM_FEEDBACK_BUFFER);
406 XX(TRANSFORM_FEEDBACK_BUFFER_BINDING);
407 XX(RGBA32UI);
408 XX(RGB32UI);
409 XX(RGBA16UI);
410 XX(RGB16UI);
411 XX(RGBA8UI);
412 XX(RGB8UI);
413 XX(RGBA32I);
414 XX(RGB32I);
415 XX(RGBA16I);
416 XX(RGB16I);
417 XX(RGBA8I);
418 XX(RGB8I);
419 XX(RED_INTEGER);
420 XX(RGB_INTEGER);
421 XX(RGBA_INTEGER);
422 XX(SAMPLER_2D_ARRAY);
423 XX(SAMPLER_2D_ARRAY_SHADOW);
424 XX(SAMPLER_CUBE_SHADOW);
425 XX(UNSIGNED_INT_VEC2);
426 XX(UNSIGNED_INT_VEC3);
427 XX(UNSIGNED_INT_VEC4);
428 XX(INT_SAMPLER_2D);
429 XX(INT_SAMPLER_3D);
430 XX(INT_SAMPLER_CUBE);
431 XX(INT_SAMPLER_2D_ARRAY);
432 XX(UNSIGNED_INT_SAMPLER_2D);
433 XX(UNSIGNED_INT_SAMPLER_3D);
434 XX(UNSIGNED_INT_SAMPLER_CUBE);
435 XX(UNSIGNED_INT_SAMPLER_2D_ARRAY);
436 XX(DEPTH_COMPONENT32F);
437 XX(DEPTH32F_STENCIL8);
438 XX(FLOAT_32_UNSIGNED_INT_24_8_REV);
439 XX(FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING);
440 XX(FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE);
441 XX(FRAMEBUFFER_ATTACHMENT_RED_SIZE);
442 XX(FRAMEBUFFER_ATTACHMENT_GREEN_SIZE);
443 XX(FRAMEBUFFER_ATTACHMENT_BLUE_SIZE);
444 XX(FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE);
445 XX(FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE);
446 XX(FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE);
447 XX(FRAMEBUFFER_DEFAULT);
448 XX(DEPTH_STENCIL_ATTACHMENT);
449 XX(UNSIGNED_NORMALIZED);
450 XX(DRAW_FRAMEBUFFER_BINDING);
451 XX(READ_FRAMEBUFFER_BINDING);
452 XX(RENDERBUFFER_SAMPLES);
453 XX(FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER);
454 XX(MAX_COLOR_ATTACHMENTS);
455 XX(COLOR_ATTACHMENT0);
456 XX(COLOR_ATTACHMENT1);
457 XX(COLOR_ATTACHMENT2);
458 XX(COLOR_ATTACHMENT3);
459 XX(COLOR_ATTACHMENT4);
460 XX(COLOR_ATTACHMENT5);
461 XX(COLOR_ATTACHMENT6);
462 XX(COLOR_ATTACHMENT7);
463 XX(COLOR_ATTACHMENT8);
464 XX(COLOR_ATTACHMENT9);
465 XX(COLOR_ATTACHMENT10);
466 XX(COLOR_ATTACHMENT11);
467 XX(COLOR_ATTACHMENT12);
468 XX(COLOR_ATTACHMENT13);
469 XX(COLOR_ATTACHMENT14);
470 XX(COLOR_ATTACHMENT15);
471 XX(FRAMEBUFFER_INCOMPLETE_MULTISAMPLE);
472 XX(MAX_SAMPLES);
473 XX(RG);
474 XX(RG_INTEGER);
475 XX(R8);
476 XX(RG8);
477 XX(R16F);
478 XX(R32F);
479 XX(RG16F);
480 XX(RG32F);
481 XX(R8I);
482 XX(R8UI);
483 XX(R16I);
484 XX(R16UI);
485 XX(R32I);
486 XX(R32UI);
487 XX(RG8I);
488 XX(RG8UI);
489 XX(RG16I);
490 XX(RG16UI);
491 XX(RG32I);
492 XX(RG32UI);
493 XX(VERTEX_ARRAY_BINDING);
494 XX(R8_SNORM);
495 XX(RG8_SNORM);
496 XX(RGB8_SNORM);
497 XX(RGBA8_SNORM);
498 XX(SIGNED_NORMALIZED);
499 XX(PRIMITIVE_RESTART_FIXED_INDEX);
500 XX(COPY_READ_BUFFER);
501 XX(COPY_WRITE_BUFFER);
502 XX(UNIFORM_BUFFER);
503 XX(UNIFORM_BUFFER_BINDING);
504 XX(UNIFORM_BUFFER_START);
505 XX(UNIFORM_BUFFER_SIZE);
506 XX(MAX_VERTEX_UNIFORM_BLOCKS);
507 XX(MAX_FRAGMENT_UNIFORM_BLOCKS);
508 XX(MAX_COMBINED_UNIFORM_BLOCKS);
509 XX(MAX_UNIFORM_BUFFER_BINDINGS);
510 XX(MAX_UNIFORM_BLOCK_SIZE);
511 XX(MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS);
512 XX(MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS);
513 XX(UNIFORM_BUFFER_OFFSET_ALIGNMENT);
514 XX(ACTIVE_UNIFORM_BLOCKS);
515 XX(UNIFORM_TYPE);
516 XX(UNIFORM_SIZE);
517 XX(UNIFORM_BLOCK_INDEX);
518 XX(UNIFORM_OFFSET);
519 XX(UNIFORM_ARRAY_STRIDE);
520 XX(UNIFORM_MATRIX_STRIDE);
521 XX(UNIFORM_IS_ROW_MAJOR);
522 XX(UNIFORM_BLOCK_BINDING);
523 XX(UNIFORM_BLOCK_DATA_SIZE);
524 XX(UNIFORM_BLOCK_ACTIVE_UNIFORMS);
525 XX(UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES);
526 XX(UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER);
527 XX(UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER);
528 XX(MAX_VERTEX_OUTPUT_COMPONENTS);
529 XX(MAX_FRAGMENT_INPUT_COMPONENTS);
530 XX(MAX_SERVER_WAIT_TIMEOUT);
531 XX(OBJECT_TYPE);
532 XX(SYNC_CONDITION);
533 XX(SYNC_STATUS);
534 XX(SYNC_FLAGS);
535 XX(SYNC_FENCE);
536 XX(SYNC_GPU_COMMANDS_COMPLETE);
537 XX(UNSIGNALED);
538 XX(SIGNALED);
539 XX(ALREADY_SIGNALED);
540 XX(TIMEOUT_EXPIRED);
541 XX(CONDITION_SATISFIED);
542 XX(WAIT_FAILED);
543 XX(VERTEX_ATTRIB_ARRAY_DIVISOR);
544 XX(ANY_SAMPLES_PASSED);
545 XX(ANY_SAMPLES_PASSED_CONSERVATIVE);
546 XX(SAMPLER_BINDING);
547 XX(RGB10_A2UI);
548 XX(TEXTURE_SWIZZLE_R);
549 XX(TEXTURE_SWIZZLE_G);
550 XX(TEXTURE_SWIZZLE_B);
551 XX(TEXTURE_SWIZZLE_A);
552 XX(GREEN);
553 XX(BLUE);
554 XX(INT_2_10_10_10_REV);
555 XX(TRANSFORM_FEEDBACK);
556 XX(TRANSFORM_FEEDBACK_PAUSED);
557 XX(TRANSFORM_FEEDBACK_ACTIVE);
558 XX(TRANSFORM_FEEDBACK_BINDING);
559 XX(COMPRESSED_R11_EAC);
560 XX(COMPRESSED_SIGNED_R11_EAC);
561 XX(COMPRESSED_RG11_EAC);
562 XX(COMPRESSED_SIGNED_RG11_EAC);
563 XX(COMPRESSED_RGB8_ETC2);
564 XX(COMPRESSED_SRGB8_ETC2);
565 XX(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2);
566 XX(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2);
567 XX(COMPRESSED_RGBA8_ETC2_EAC);
568 XX(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC);
569 XX(TEXTURE_IMMUTABLE_FORMAT);
570 XX(MAX_ELEMENT_INDEX);
571 XX(NUM_SAMPLE_COUNTS);
572 XX(TEXTURE_IMMUTABLE_LEVELS);
573 #undef XX
574 }
575
576 return nullptr;
577 }
578
579 /*static*/ void
EnumName(GLenum val,nsCString * out_name)580 WebGLContext::EnumName(GLenum val, nsCString* out_name)
581 {
582 const char* name = GetEnumName(val);
583 if (name) {
584 *out_name = name;
585 return;
586 }
587
588 *out_name = nsPrintfCString("<enum 0x%04x>", val);
589 }
590
591 void
ErrorInvalidEnumArg(const char * funcName,const char * argName,GLenum val)592 WebGLContext::ErrorInvalidEnumArg(const char* funcName, const char* argName, GLenum val)
593 {
594 nsCString enumName;
595 EnumName(val, &enumName);
596 ErrorInvalidEnum("%s: Bad `%s`: %s", funcName, argName, enumName.BeginReading());
597 }
598
599 bool
IsCompressedTextureFormat(GLenum format)600 IsCompressedTextureFormat(GLenum format)
601 {
602 switch (format) {
603 case LOCAL_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
604 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
605 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
606 case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
607 case LOCAL_GL_ATC_RGB:
608 case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
609 case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
610 case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
611 case LOCAL_GL_COMPRESSED_RGB_PVRTC_2BPPV1:
612 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
613 case LOCAL_GL_COMPRESSED_RGBA_PVRTC_2BPPV1:
614 case LOCAL_GL_ETC1_RGB8_OES:
615 case LOCAL_GL_COMPRESSED_R11_EAC:
616 case LOCAL_GL_COMPRESSED_SIGNED_R11_EAC:
617 case LOCAL_GL_COMPRESSED_RG11_EAC:
618 case LOCAL_GL_COMPRESSED_SIGNED_RG11_EAC:
619 case LOCAL_GL_COMPRESSED_RGB8_ETC2:
620 case LOCAL_GL_COMPRESSED_SRGB8_ETC2:
621 case LOCAL_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
622 case LOCAL_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
623 case LOCAL_GL_COMPRESSED_RGBA8_ETC2_EAC:
624 case LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
625 return true;
626 default:
627 return false;
628 }
629 }
630
631
632 bool
IsTextureFormatCompressed(TexInternalFormat format)633 IsTextureFormatCompressed(TexInternalFormat format)
634 {
635 return IsCompressedTextureFormat(format.get());
636 }
637
638 GLenum
GetAndFlushUnderlyingGLErrors()639 WebGLContext::GetAndFlushUnderlyingGLErrors()
640 {
641 // Get and clear GL error in ALL cases.
642 GLenum error = gl->fGetError();
643
644 // Only store in mUnderlyingGLError if is hasn't already recorded an
645 // error.
646 if (!mUnderlyingGLError)
647 mUnderlyingGLError = error;
648
649 return error;
650 }
651
652 #ifdef DEBUG
653 // For NaNs, etc.
654 static bool
IsCacheCorrect(float cached,float actual)655 IsCacheCorrect(float cached, float actual)
656 {
657 if (IsNaN(cached)) {
658 // GL is allowed to do anything it wants for NaNs, so if we're shadowing
659 // a NaN, then whatever `actual` is might be correct.
660 return true;
661 }
662
663 return cached == actual;
664 }
665
666 void
AssertUintParamCorrect(gl::GLContext * gl,GLenum pname,GLuint shadow)667 AssertUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint shadow)
668 {
669 GLuint val = 0;
670 gl->GetUIntegerv(pname, &val);
671 if (val != shadow) {
672 printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n",
673 pname, shadow, shadow, val, val);
674 MOZ_ASSERT(false, "Bad cached value.");
675 }
676 }
677
678 void
AssertMaskedUintParamCorrect(gl::GLContext * gl,GLenum pname,GLuint mask,GLuint shadow)679 AssertMaskedUintParamCorrect(gl::GLContext* gl, GLenum pname, GLuint mask,
680 GLuint shadow)
681 {
682 GLuint val = 0;
683 gl->GetUIntegerv(pname, &val);
684
685 const GLuint valMasked = val & mask;
686 const GLuint shadowMasked = shadow & mask;
687
688 if (valMasked != shadowMasked) {
689 printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n",
690 pname, shadowMasked, shadowMasked, valMasked, valMasked);
691 MOZ_ASSERT(false, "Bad cached value.");
692 }
693 }
694 #else
695 void
AssertUintParamCorrect(gl::GLContext *,GLenum,GLuint)696 AssertUintParamCorrect(gl::GLContext*, GLenum, GLuint)
697 {
698 }
699 #endif
700
701 void
AssertCachedBindings()702 WebGLContext::AssertCachedBindings()
703 {
704 #ifdef DEBUG
705 MakeContextCurrent();
706
707 GetAndFlushUnderlyingGLErrors();
708
709 if (IsWebGL2() || IsExtensionEnabled(WebGLExtensionID::OES_vertex_array_object)) {
710 GLuint bound = mBoundVertexArray ? mBoundVertexArray->GLName() : 0;
711 AssertUintParamCorrect(gl, LOCAL_GL_VERTEX_ARRAY_BINDING, bound);
712 }
713
714 // Framebuffers
715 if (IsWebGL2()) {
716 GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
717 : 0;
718 AssertUintParamCorrect(gl, LOCAL_GL_DRAW_FRAMEBUFFER_BINDING, bound);
719
720 bound = mBoundReadFramebuffer ? mBoundReadFramebuffer->mGLName : 0;
721 AssertUintParamCorrect(gl, LOCAL_GL_READ_FRAMEBUFFER_BINDING, bound);
722 } else {
723 MOZ_ASSERT(mBoundDrawFramebuffer == mBoundReadFramebuffer);
724 GLuint bound = mBoundDrawFramebuffer ? mBoundDrawFramebuffer->mGLName
725 : 0;
726 AssertUintParamCorrect(gl, LOCAL_GL_FRAMEBUFFER_BINDING, bound);
727 }
728
729 GLint stencilBits = 0;
730 if (GetStencilBits(&stencilBits)) { // Depends on current draw framebuffer.
731 const GLuint stencilRefMask = (1 << stencilBits) - 1;
732
733 AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_REF, stencilRefMask, mStencilRefFront);
734 AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_REF, stencilRefMask, mStencilRefBack);
735 }
736
737 // Program
738 GLuint bound = mCurrentProgram ? mCurrentProgram->mGLName : 0;
739 AssertUintParamCorrect(gl, LOCAL_GL_CURRENT_PROGRAM, bound);
740
741 // Textures
742 GLenum activeTexture = mActiveTexture + LOCAL_GL_TEXTURE0;
743 AssertUintParamCorrect(gl, LOCAL_GL_ACTIVE_TEXTURE, activeTexture);
744
745 WebGLTexture* curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_2D);
746 bound = curTex ? curTex->mGLName : 0;
747 AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_2D, bound);
748
749 curTex = ActiveBoundTextureForTarget(LOCAL_GL_TEXTURE_CUBE_MAP);
750 bound = curTex ? curTex->mGLName : 0;
751 AssertUintParamCorrect(gl, LOCAL_GL_TEXTURE_BINDING_CUBE_MAP, bound);
752
753 // Buffers
754 bound = mBoundArrayBuffer ? mBoundArrayBuffer->mGLName : 0;
755 AssertUintParamCorrect(gl, LOCAL_GL_ARRAY_BUFFER_BINDING, bound);
756
757 MOZ_ASSERT(mBoundVertexArray);
758 WebGLBuffer* curBuff = mBoundVertexArray->mElementArrayBuffer;
759 bound = curBuff ? curBuff->mGLName : 0;
760 AssertUintParamCorrect(gl, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING, bound);
761
762 MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
763 #endif
764
765 // We do not check the renderbuffer binding, because we never rely on it matching.
766 }
767
768 void
AssertCachedGlobalState()769 WebGLContext::AssertCachedGlobalState()
770 {
771 #ifdef DEBUG
772 MakeContextCurrent();
773
774 GetAndFlushUnderlyingGLErrors();
775
776 ////////////////
777
778 // Draw state
779 MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DEPTH_TEST) == mDepthTestEnabled);
780 MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_DITHER) == mDitherEnabled);
781 MOZ_ASSERT_IF(IsWebGL2(),
782 gl->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD) == mRasterizerDiscardEnabled);
783 MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_SCISSOR_TEST) == mScissorTestEnabled);
784 MOZ_ASSERT(gl->fIsEnabled(LOCAL_GL_STENCIL_TEST) == mStencilTestEnabled);
785
786 realGLboolean colorWriteMask[4] = {0, 0, 0, 0};
787 gl->fGetBooleanv(LOCAL_GL_COLOR_WRITEMASK, colorWriteMask);
788 MOZ_ASSERT(colorWriteMask[0] == mColorWriteMask[0] &&
789 colorWriteMask[1] == mColorWriteMask[1] &&
790 colorWriteMask[2] == mColorWriteMask[2] &&
791 colorWriteMask[3] == mColorWriteMask[3]);
792
793 GLfloat colorClearValue[4] = {0.0f, 0.0f, 0.0f, 0.0f};
794 gl->fGetFloatv(LOCAL_GL_COLOR_CLEAR_VALUE, colorClearValue);
795 MOZ_ASSERT(IsCacheCorrect(mColorClearValue[0], colorClearValue[0]) &&
796 IsCacheCorrect(mColorClearValue[1], colorClearValue[1]) &&
797 IsCacheCorrect(mColorClearValue[2], colorClearValue[2]) &&
798 IsCacheCorrect(mColorClearValue[3], colorClearValue[3]));
799
800 realGLboolean depthWriteMask = 0;
801 gl->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK, &depthWriteMask);
802 MOZ_ASSERT(depthWriteMask == mDepthWriteMask);
803
804 GLfloat depthClearValue = 0.0f;
805 gl->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE, &depthClearValue);
806 MOZ_ASSERT(IsCacheCorrect(mDepthClearValue, depthClearValue));
807
808 AssertUintParamCorrect(gl, LOCAL_GL_STENCIL_CLEAR_VALUE, mStencilClearValue);
809
810 // GLES 3.0.4, $4.1.4, p177:
811 // [...] the front and back stencil mask are both set to the value `2^s - 1`, where
812 // `s` is greater than or equal to the number of bits in the deepest stencil buffer
813 // supported by the GL implementation.
814 const int maxStencilBits = 8;
815 const GLuint maxStencilBitsMask = (1 << maxStencilBits) - 1;
816 AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_VALUE_MASK, maxStencilBitsMask, mStencilValueMaskFront);
817 AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_VALUE_MASK, maxStencilBitsMask, mStencilValueMaskBack);
818
819 AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_WRITEMASK, maxStencilBitsMask, mStencilWriteMaskFront);
820 AssertMaskedUintParamCorrect(gl, LOCAL_GL_STENCIL_BACK_WRITEMASK, maxStencilBitsMask, mStencilWriteMaskBack);
821
822 // Viewport
823 GLint int4[4] = {0, 0, 0, 0};
824 gl->fGetIntegerv(LOCAL_GL_VIEWPORT, int4);
825 MOZ_ASSERT(int4[0] == mViewportX &&
826 int4[1] == mViewportY &&
827 int4[2] == mViewportWidth &&
828 int4[3] == mViewportHeight);
829
830 AssertUintParamCorrect(gl, LOCAL_GL_PACK_ALIGNMENT, mPixelStore_PackAlignment);
831 AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ALIGNMENT, mPixelStore_UnpackAlignment);
832
833 if (IsWebGL2()) {
834 AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_IMAGE_HEIGHT, mPixelStore_UnpackImageHeight);
835 AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_IMAGES , mPixelStore_UnpackSkipImages);
836 AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_ROW_LENGTH , mPixelStore_UnpackRowLength);
837 AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_ROWS , mPixelStore_UnpackSkipRows);
838 AssertUintParamCorrect(gl, LOCAL_GL_UNPACK_SKIP_PIXELS , mPixelStore_UnpackSkipPixels);
839 AssertUintParamCorrect(gl, LOCAL_GL_PACK_ROW_LENGTH , mPixelStore_PackRowLength);
840 AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_ROWS , mPixelStore_PackSkipRows);
841 AssertUintParamCorrect(gl, LOCAL_GL_PACK_SKIP_PIXELS , mPixelStore_PackSkipPixels);
842 }
843
844 MOZ_ASSERT(!GetAndFlushUnderlyingGLErrors());
845 #endif
846 }
847
848 const char*
InfoFrom(WebGLTexImageFunc func,WebGLTexDimensions dims)849 InfoFrom(WebGLTexImageFunc func, WebGLTexDimensions dims)
850 {
851 switch (dims) {
852 case WebGLTexDimensions::Tex2D:
853 switch (func) {
854 case WebGLTexImageFunc::TexImage: return "texImage2D";
855 case WebGLTexImageFunc::TexSubImage: return "texSubImage2D";
856 case WebGLTexImageFunc::CopyTexImage: return "copyTexImage2D";
857 case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage2D";
858 case WebGLTexImageFunc::CompTexImage: return "compressedTexImage2D";
859 case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage2D";
860 default:
861 MOZ_CRASH("GFX: invalid 2D TexDimensions");
862 }
863 case WebGLTexDimensions::Tex3D:
864 switch (func) {
865 case WebGLTexImageFunc::TexImage: return "texImage3D";
866 case WebGLTexImageFunc::TexSubImage: return "texSubImage3D";
867 case WebGLTexImageFunc::CopyTexSubImage: return "copyTexSubImage3D";
868 case WebGLTexImageFunc::CompTexSubImage: return "compressedTexSubImage3D";
869 default:
870 MOZ_CRASH("GFX: invalid 3D TexDimensions");
871 }
872 default:
873 MOZ_CRASH("GFX: invalid TexDimensions");
874 }
875 }
876
877 } // namespace mozilla
878