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