1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
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/. */
6 #include "WebGLContextUtils.h"
7 #include "WebGLContext.h"
8 #include "HostWebGLContext.h"
11 #include "js/Warnings.h" // JS::WarnASCII
12 #include "mozilla/dom/ScriptSettings.h"
13 #include "mozilla/gfx/Logging.h"
14 #include "mozilla/Preferences.h"
15 #include "mozilla/Sprintf.h"
16 #include "nsPrintfCString.h"
17 #include "nsServiceManagerUtils.h"
19 #include "WebGLBuffer.h"
20 #include "WebGLExtensions.h"
21 #include "WebGLFramebuffer.h"
22 #include "WebGLProgram.h"
23 #include "WebGLTexture.h"
24 #include "WebGLVertexArray.h"
28 TexTarget
TexImageTargetToTexTarget(TexImageTarget texImageTarget
) {
29 switch (texImageTarget
.get()) {
30 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
31 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
32 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
33 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
34 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
35 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
36 return LOCAL_GL_TEXTURE_CUBE_MAP
;
39 return texImageTarget
.get();
43 /*static*/ const char* WebGLContext::ErrorName(GLenum error
) {
45 case LOCAL_GL_INVALID_ENUM
:
46 return "INVALID_ENUM";
47 case LOCAL_GL_INVALID_OPERATION
:
48 return "INVALID_OPERATION";
49 case LOCAL_GL_INVALID_VALUE
:
50 return "INVALID_VALUE";
51 case LOCAL_GL_OUT_OF_MEMORY
:
52 return "OUT_OF_MEMORY";
53 case LOCAL_GL_INVALID_FRAMEBUFFER_OPERATION
:
54 return "INVALID_FRAMEBUFFER_OPERATION";
55 case LOCAL_GL_NO_ERROR
:
59 return "[unknown WebGL error]";
63 // This version is fallible and will return nullptr if unrecognized.
64 const char* GetEnumName(const GLenum val
, const char* const defaultRet
) {
71 XX(COMPRESSED_RGBA_PVRTC_2BPPV1
);
72 XX(COMPRESSED_RGBA_PVRTC_4BPPV1
);
73 XX(COMPRESSED_RGBA_S3TC_DXT1_EXT
);
74 XX(COMPRESSED_RGBA_S3TC_DXT3_EXT
);
75 XX(COMPRESSED_RGBA_S3TC_DXT5_EXT
);
76 XX(COMPRESSED_RGB_PVRTC_2BPPV1
);
77 XX(COMPRESSED_RGB_PVRTC_4BPPV1
);
78 XX(COMPRESSED_RGB_S3TC_DXT1_EXT
);
81 XX(DEPTH_COMPONENT16
);
82 XX(DEPTH_COMPONENT32
);
104 XX(TEXTURE_CUBE_MAP
);
105 XX(TEXTURE_CUBE_MAP_NEGATIVE_X
);
106 XX(TEXTURE_CUBE_MAP_NEGATIVE_Y
);
107 XX(TEXTURE_CUBE_MAP_NEGATIVE_Z
);
108 XX(TEXTURE_CUBE_MAP_POSITIVE_X
);
109 XX(TEXTURE_CUBE_MAP_POSITIVE_Y
);
110 XX(TEXTURE_CUBE_MAP_POSITIVE_Z
);
113 XX(UNSIGNED_INT_24_8
);
115 XX(UNSIGNED_SHORT_4_4_4_4
);
116 XX(UNSIGNED_SHORT_5_5_5_1
);
117 XX(UNSIGNED_SHORT_5_6_5
);
119 XX(UNPACK_ROW_LENGTH
);
120 XX(UNPACK_SKIP_ROWS
);
121 XX(UNPACK_SKIP_PIXELS
);
124 XX(PACK_SKIP_PIXELS
);
132 XX(TEXTURE_BINDING_3D
);
133 XX(UNPACK_SKIP_IMAGES
);
134 XX(UNPACK_IMAGE_HEIGHT
);
136 XX(MAX_3D_TEXTURE_SIZE
);
137 XX(UNSIGNED_INT_2_10_10_10_REV
);
138 XX(MAX_ELEMENTS_VERTICES
);
139 XX(MAX_ELEMENTS_INDICES
);
142 XX(TEXTURE_BASE_LEVEL
);
143 XX(TEXTURE_MAX_LEVEL
);
146 XX(DEPTH_COMPONENT24
);
147 XX(MAX_TEXTURE_LOD_BIAS
);
148 XX(TEXTURE_COMPARE_MODE
);
149 XX(TEXTURE_COMPARE_FUNC
);
152 XX(QUERY_RESULT_AVAILABLE
);
159 XX(MAX_DRAW_BUFFERS
);
176 XX(MAX_FRAGMENT_UNIFORM_COMPONENTS
);
177 XX(MAX_VERTEX_UNIFORM_COMPONENTS
);
179 XX(SAMPLER_2D_SHADOW
);
180 XX(FRAGMENT_SHADER_DERIVATIVE_HINT
);
181 XX(PIXEL_PACK_BUFFER
);
182 XX(PIXEL_UNPACK_BUFFER
);
183 XX(PIXEL_PACK_BUFFER_BINDING
);
184 XX(PIXEL_UNPACK_BUFFER_BINDING
);
193 XX(COMPARE_REF_TO_TEXTURE
);
194 XX(VERTEX_ATTRIB_ARRAY_INTEGER
);
195 XX(MAX_ARRAY_TEXTURE_LAYERS
);
196 XX(MIN_PROGRAM_TEXEL_OFFSET
);
197 XX(MAX_PROGRAM_TEXEL_OFFSET
);
198 XX(MAX_VARYING_COMPONENTS
);
199 XX(TEXTURE_2D_ARRAY
);
200 XX(TEXTURE_BINDING_2D_ARRAY
);
202 XX(UNSIGNED_INT_10F_11F_11F_REV
);
204 XX(UNSIGNED_INT_5_9_9_9_REV
);
205 XX(TRANSFORM_FEEDBACK_BUFFER_MODE
);
206 XX(MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS
);
207 XX(TRANSFORM_FEEDBACK_VARYINGS
);
208 XX(TRANSFORM_FEEDBACK_BUFFER_START
);
209 XX(TRANSFORM_FEEDBACK_BUFFER_SIZE
);
210 XX(TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
);
211 XX(RASTERIZER_DISCARD
);
212 XX(MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS
);
213 XX(MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS
);
214 XX(INTERLEAVED_ATTRIBS
);
215 XX(SEPARATE_ATTRIBS
);
216 XX(TRANSFORM_FEEDBACK_BUFFER
);
217 XX(TRANSFORM_FEEDBACK_BUFFER_BINDING
);
233 XX(SAMPLER_2D_ARRAY
);
234 XX(SAMPLER_2D_ARRAY_SHADOW
);
235 XX(SAMPLER_CUBE_SHADOW
);
236 XX(UNSIGNED_INT_VEC2
);
237 XX(UNSIGNED_INT_VEC3
);
238 XX(UNSIGNED_INT_VEC4
);
241 XX(INT_SAMPLER_CUBE
);
242 XX(INT_SAMPLER_2D_ARRAY
);
243 XX(UNSIGNED_INT_SAMPLER_2D
);
244 XX(UNSIGNED_INT_SAMPLER_3D
);
245 XX(UNSIGNED_INT_SAMPLER_CUBE
);
246 XX(UNSIGNED_INT_SAMPLER_2D_ARRAY
);
247 XX(DEPTH_COMPONENT32F
);
248 XX(DEPTH32F_STENCIL8
);
249 XX(FLOAT_32_UNSIGNED_INT_24_8_REV
);
250 XX(FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
);
251 XX(FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE
);
252 XX(FRAMEBUFFER_ATTACHMENT_RED_SIZE
);
253 XX(FRAMEBUFFER_ATTACHMENT_GREEN_SIZE
);
254 XX(FRAMEBUFFER_ATTACHMENT_BLUE_SIZE
);
255 XX(FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE
);
256 XX(FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE
);
257 XX(FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE
);
258 XX(FRAMEBUFFER_DEFAULT
);
259 XX(DEPTH_STENCIL_ATTACHMENT
);
260 XX(UNSIGNED_NORMALIZED
);
261 XX(DRAW_FRAMEBUFFER_BINDING
);
262 XX(READ_FRAMEBUFFER_BINDING
);
263 XX(RENDERBUFFER_SAMPLES
);
264 XX(FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER
);
265 XX(MAX_COLOR_ATTACHMENTS
);
266 XX(COLOR_ATTACHMENT0
);
267 XX(COLOR_ATTACHMENT1
);
268 XX(COLOR_ATTACHMENT2
);
269 XX(COLOR_ATTACHMENT3
);
270 XX(COLOR_ATTACHMENT4
);
271 XX(COLOR_ATTACHMENT5
);
272 XX(COLOR_ATTACHMENT6
);
273 XX(COLOR_ATTACHMENT7
);
274 XX(COLOR_ATTACHMENT8
);
275 XX(COLOR_ATTACHMENT9
);
276 XX(COLOR_ATTACHMENT10
);
277 XX(COLOR_ATTACHMENT11
);
278 XX(COLOR_ATTACHMENT12
);
279 XX(COLOR_ATTACHMENT13
);
280 XX(COLOR_ATTACHMENT14
);
281 XX(COLOR_ATTACHMENT15
);
282 XX(FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
);
304 XX(VERTEX_ARRAY_BINDING
);
309 XX(SIGNED_NORMALIZED
);
310 XX(PRIMITIVE_RESTART_FIXED_INDEX
);
311 XX(COPY_READ_BUFFER
);
312 XX(COPY_WRITE_BUFFER
);
314 XX(UNIFORM_BUFFER_BINDING
);
315 XX(UNIFORM_BUFFER_START
);
316 XX(UNIFORM_BUFFER_SIZE
);
317 XX(MAX_VERTEX_UNIFORM_BLOCKS
);
318 XX(MAX_FRAGMENT_UNIFORM_BLOCKS
);
319 XX(MAX_COMBINED_UNIFORM_BLOCKS
);
320 XX(MAX_UNIFORM_BUFFER_BINDINGS
);
321 XX(MAX_UNIFORM_BLOCK_SIZE
);
322 XX(MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS
);
323 XX(MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS
);
324 XX(UNIFORM_BUFFER_OFFSET_ALIGNMENT
);
325 XX(ACTIVE_UNIFORM_BLOCKS
);
328 XX(UNIFORM_BLOCK_INDEX
);
330 XX(UNIFORM_ARRAY_STRIDE
);
331 XX(UNIFORM_MATRIX_STRIDE
);
332 XX(UNIFORM_IS_ROW_MAJOR
);
333 XX(UNIFORM_BLOCK_BINDING
);
334 XX(UNIFORM_BLOCK_DATA_SIZE
);
335 XX(UNIFORM_BLOCK_ACTIVE_UNIFORMS
);
336 XX(UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES
);
337 XX(UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER
);
338 XX(UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER
);
339 XX(MAX_VERTEX_OUTPUT_COMPONENTS
);
340 XX(MAX_FRAGMENT_INPUT_COMPONENTS
);
341 XX(MAX_SERVER_WAIT_TIMEOUT
);
347 XX(SYNC_GPU_COMMANDS_COMPLETE
);
350 XX(ALREADY_SIGNALED
);
352 XX(CONDITION_SATISFIED
);
354 XX(VERTEX_ATTRIB_ARRAY_DIVISOR
);
355 XX(ANY_SAMPLES_PASSED
);
356 XX(ANY_SAMPLES_PASSED_CONSERVATIVE
);
359 XX(TEXTURE_SWIZZLE_R
);
360 XX(TEXTURE_SWIZZLE_G
);
361 XX(TEXTURE_SWIZZLE_B
);
362 XX(TEXTURE_SWIZZLE_A
);
365 XX(INT_2_10_10_10_REV
);
366 XX(TRANSFORM_FEEDBACK
);
367 XX(TRANSFORM_FEEDBACK_PAUSED
);
368 XX(TRANSFORM_FEEDBACK_ACTIVE
);
369 XX(TRANSFORM_FEEDBACK_BINDING
);
370 XX(COMPRESSED_R11_EAC
);
371 XX(COMPRESSED_SIGNED_R11_EAC
);
372 XX(COMPRESSED_RG11_EAC
);
373 XX(COMPRESSED_SIGNED_RG11_EAC
);
374 XX(COMPRESSED_RGB8_ETC2
);
375 XX(COMPRESSED_SRGB8_ETC2
);
376 XX(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
);
377 XX(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
);
378 XX(COMPRESSED_RGBA8_ETC2_EAC
);
379 XX(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
);
380 XX(TEXTURE_IMMUTABLE_FORMAT
);
381 XX(MAX_ELEMENT_INDEX
);
382 XX(NUM_SAMPLE_COUNTS
);
383 XX(TEXTURE_IMMUTABLE_LEVELS
);
391 void WebGLContext::EnumName(GLenum val
, nsCString
* out_name
) {
392 const char* name
= GetEnumName(val
, nullptr);
398 *out_name
= nsPrintfCString("<enum 0x%04x>", val
);
401 std::string
EnumString(const GLenum val
) {
402 const char* name
= GetEnumName(val
, nullptr);
407 const nsPrintfCString
hex("<enum 0x%04x>", val
);
408 return hex
.BeginReading();
411 void WebGLContext::ErrorInvalidEnumArg(const char* const argName
,
412 const GLenum val
) const {
414 EnumName(val
, &enumName
);
415 ErrorInvalidEnum("Bad `%s`: %s", argName
, enumName
.BeginReading());
418 void WebGLContext::ErrorInvalidEnumInfo(const char* const info
,
419 const GLenum enumValue
) const {
421 EnumName(enumValue
, &name
);
422 return ErrorInvalidEnum("%s: Invalid enum value %s", info
,
423 name
.BeginReading());
428 static bool IsCacheCorrect(float cached
, float actual
) {
430 // GL is allowed to do anything it wants for NaNs, so if we're shadowing
431 // a NaN, then whatever `actual` is might be correct.
435 return cached
== actual
;
438 void AssertUintParamCorrect(gl::GLContext
* gl
, GLenum pname
, GLuint shadow
) {
440 gl
->GetUIntegerv(pname
, &val
);
442 printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n",
443 pname
, shadow
, shadow
, val
, val
);
444 MOZ_ASSERT(false, "Bad cached value.");
448 void AssertMaskedUintParamCorrect(gl::GLContext
* gl
, GLenum pname
, GLuint mask
,
451 gl
->GetUIntegerv(pname
, &val
);
453 const GLuint valMasked
= val
& mask
;
454 const GLuint shadowMasked
= shadow
& mask
;
456 if (valMasked
!= shadowMasked
) {
457 printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n",
458 pname
, shadowMasked
, shadowMasked
, valMasked
, valMasked
);
459 MOZ_ASSERT(false, "Bad cached value.");
463 void AssertUintParamCorrect(gl::GLContext
*, GLenum
, GLuint
) {}
466 void WebGLContext::AssertCachedBindings() const {
468 gl::GLContext::LocalErrorScope
errorScope(*gl
);
470 GLint stencilBits
= 0;
471 if (GetStencilBits(&stencilBits
)) { // Depends on current draw framebuffer.
472 const GLuint stencilRefMask
= (1 << stencilBits
) - 1;
474 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_REF
, stencilRefMask
,
476 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_BACK_REF
, stencilRefMask
,
481 GLuint bound
= mCurrentProgram
? mCurrentProgram
->mGLName
: 0;
482 AssertUintParamCorrect(gl
, LOCAL_GL_CURRENT_PROGRAM
, bound
);
485 bound
= mBoundArrayBuffer
? mBoundArrayBuffer
->mGLName
: 0;
486 AssertUintParamCorrect(gl
, LOCAL_GL_ARRAY_BUFFER_BINDING
, bound
);
488 MOZ_ASSERT(mBoundVertexArray
);
489 WebGLBuffer
* curBuff
= mBoundVertexArray
->mElementArrayBuffer
;
490 bound
= curBuff
? curBuff
->mGLName
: 0;
491 AssertUintParamCorrect(gl
, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING
, bound
);
493 MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope
.GetError()));
496 // We do not check the renderbuffer binding, because we never rely on it
500 void WebGLContext::AssertCachedGlobalState() const {
502 gl::GLContext::LocalErrorScope
errorScope(*gl
);
507 MOZ_ASSERT(gl
->fIsEnabled(LOCAL_GL_DITHER
) == mDitherEnabled
);
508 MOZ_ASSERT_IF(IsWebGL2(), gl
->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD
) ==
509 mRasterizerDiscardEnabled
);
510 MOZ_ASSERT(gl
->fIsEnabled(LOCAL_GL_SCISSOR_TEST
) == mScissorTestEnabled
);
512 // Cannot trivially check COLOR_CLEAR_VALUE, since in old GL versions glGet
513 // may clamp based on whether the current framebuffer is floating-point or
514 // not. This also means COLOR_CLEAR_VALUE save+restore is dangerous!
516 realGLboolean depthWriteMask
= 0;
517 gl
->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK
, &depthWriteMask
);
518 MOZ_ASSERT(depthWriteMask
== mDepthWriteMask
);
520 GLfloat depthClearValue
= 0.0f
;
521 gl
->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE
, &depthClearValue
);
522 MOZ_ASSERT(IsCacheCorrect(mDepthClearValue
, depthClearValue
));
524 const int maxStencilBits
= 8;
525 const GLuint maxStencilBitsMask
= (1 << maxStencilBits
) - 1;
526 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_CLEAR_VALUE
,
527 maxStencilBitsMask
, mStencilClearValue
);
529 // GLES 3.0.4, $4.1.4, p177:
530 // [...] the front and back stencil mask are both set to the value `2^s -
531 // 1`, where `s` is greater than or equal to the number of bits in the
532 // deepest stencil buffer supported by the GL implementation.
533 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_VALUE_MASK
,
534 maxStencilBitsMask
, mStencilValueMaskFront
);
535 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_BACK_VALUE_MASK
,
536 maxStencilBitsMask
, mStencilValueMaskBack
);
538 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_WRITEMASK
,
539 maxStencilBitsMask
, mStencilWriteMaskFront
);
540 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_BACK_WRITEMASK
,
541 maxStencilBitsMask
, mStencilWriteMaskBack
);
544 GLint int4
[4] = {0, 0, 0, 0};
545 gl
->fGetIntegerv(LOCAL_GL_VIEWPORT
, int4
);
546 MOZ_ASSERT(int4
[0] == mViewportX
&& int4
[1] == mViewportY
&&
547 int4
[2] == mViewportWidth
&& int4
[3] == mViewportHeight
);
549 MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope
.GetError()));
553 const char* InfoFrom(WebGLTexImageFunc func
, WebGLTexDimensions dims
) {
555 case WebGLTexDimensions::Tex2D
:
557 case WebGLTexImageFunc::TexImage
:
559 case WebGLTexImageFunc::TexSubImage
:
560 return "texSubImage2D";
561 case WebGLTexImageFunc::CopyTexImage
:
562 return "copyTexImage2D";
563 case WebGLTexImageFunc::CopyTexSubImage
:
564 return "copyTexSubImage2D";
565 case WebGLTexImageFunc::CompTexImage
:
566 return "compressedTexImage2D";
567 case WebGLTexImageFunc::CompTexSubImage
:
568 return "compressedTexSubImage2D";
570 MOZ_CRASH("GFX: invalid 2D TexDimensions");
572 case WebGLTexDimensions::Tex3D
:
574 case WebGLTexImageFunc::TexImage
:
576 case WebGLTexImageFunc::TexSubImage
:
577 return "texSubImage3D";
578 case WebGLTexImageFunc::CopyTexSubImage
:
579 return "copyTexSubImage3D";
580 case WebGLTexImageFunc::CompTexSubImage
:
581 return "compressedTexSubImage3D";
583 MOZ_CRASH("GFX: invalid 3D TexDimensions");
586 MOZ_CRASH("GFX: invalid TexDimensions");
592 } // namespace mozilla