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
) {
73 XX(COMPRESSED_RGBA_PVRTC_2BPPV1
)
74 XX(COMPRESSED_RGBA_PVRTC_4BPPV1
)
75 XX(COMPRESSED_RGBA_S3TC_DXT1_EXT
)
76 XX(COMPRESSED_RGBA_S3TC_DXT3_EXT
)
77 XX(COMPRESSED_RGBA_S3TC_DXT5_EXT
)
78 XX(COMPRESSED_RGB_PVRTC_2BPPV1
)
79 XX(COMPRESSED_RGB_PVRTC_4BPPV1
)
80 XX(COMPRESSED_RGB_S3TC_DXT1_EXT
)
107 XX(TEXTURE_CUBE_MAP_NEGATIVE_X
)
108 XX(TEXTURE_CUBE_MAP_NEGATIVE_Y
)
109 XX(TEXTURE_CUBE_MAP_NEGATIVE_Z
)
110 XX(TEXTURE_CUBE_MAP_POSITIVE_X
)
111 XX(TEXTURE_CUBE_MAP_POSITIVE_Y
)
112 XX(TEXTURE_CUBE_MAP_POSITIVE_Z
)
115 XX(UNSIGNED_INT_24_8
)
117 XX(UNSIGNED_SHORT_4_4_4_4
)
118 XX(UNSIGNED_SHORT_5_5_5_1
)
119 XX(UNSIGNED_SHORT_5_6_5
)
121 XX(UNPACK_ROW_LENGTH
)
123 XX(UNPACK_SKIP_PIXELS
)
134 XX(TEXTURE_BINDING_3D
)
135 XX(UNPACK_SKIP_IMAGES
)
136 XX(UNPACK_IMAGE_HEIGHT
)
138 XX(MAX_3D_TEXTURE_SIZE
)
139 XX(UNSIGNED_INT_2_10_10_10_REV
)
140 XX(MAX_ELEMENTS_VERTICES
)
141 XX(MAX_ELEMENTS_INDICES
)
144 XX(TEXTURE_BASE_LEVEL
)
145 XX(TEXTURE_MAX_LEVEL
)
148 XX(DEPTH_COMPONENT24
)
149 XX(MAX_TEXTURE_LOD_BIAS
)
150 XX(TEXTURE_COMPARE_MODE
)
151 XX(TEXTURE_COMPARE_FUNC
)
154 XX(QUERY_RESULT_AVAILABLE
)
178 XX(MAX_FRAGMENT_UNIFORM_COMPONENTS
)
179 XX(MAX_VERTEX_UNIFORM_COMPONENTS
)
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
)
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
)
216 XX(TRANSFORM_FEEDBACK_BUFFER
)
217 XX(TRANSFORM_FEEDBACK_BUFFER_BINDING
)
234 XX(SAMPLER_2D_SHADOW
)
236 XX(SAMPLER_CUBE_SHADOW
)
239 XX(SAMPLER_2D_ARRAY_SHADOW
)
240 XX(UNSIGNED_INT_VEC2
)
241 XX(UNSIGNED_INT_VEC3
)
242 XX(UNSIGNED_INT_VEC4
)
246 XX(INT_SAMPLER_2D_ARRAY
)
247 XX(UNSIGNED_INT_SAMPLER_2D
)
248 XX(UNSIGNED_INT_SAMPLER_3D
)
249 XX(UNSIGNED_INT_SAMPLER_CUBE
)
250 XX(UNSIGNED_INT_SAMPLER_2D_ARRAY
)
251 XX(DEPTH_COMPONENT32F
)
252 XX(DEPTH32F_STENCIL8
)
253 XX(FLOAT_32_UNSIGNED_INT_24_8_REV
)
254 XX(FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING
)
255 XX(FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE
)
256 XX(FRAMEBUFFER_ATTACHMENT_RED_SIZE
)
257 XX(FRAMEBUFFER_ATTACHMENT_GREEN_SIZE
)
258 XX(FRAMEBUFFER_ATTACHMENT_BLUE_SIZE
)
259 XX(FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE
)
260 XX(FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE
)
261 XX(FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE
)
262 XX(FRAMEBUFFER_DEFAULT
)
263 XX(DEPTH_STENCIL_ATTACHMENT
)
264 XX(UNSIGNED_NORMALIZED
)
265 XX(DRAW_FRAMEBUFFER_BINDING
)
266 XX(READ_FRAMEBUFFER_BINDING
)
267 XX(RENDERBUFFER_SAMPLES
)
268 XX(FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER
)
269 XX(MAX_COLOR_ATTACHMENTS
)
270 XX(COLOR_ATTACHMENT0
)
271 XX(COLOR_ATTACHMENT1
)
272 XX(COLOR_ATTACHMENT2
)
273 XX(COLOR_ATTACHMENT3
)
274 XX(COLOR_ATTACHMENT4
)
275 XX(COLOR_ATTACHMENT5
)
276 XX(COLOR_ATTACHMENT6
)
277 XX(COLOR_ATTACHMENT7
)
278 XX(COLOR_ATTACHMENT8
)
279 XX(COLOR_ATTACHMENT9
)
280 XX(COLOR_ATTACHMENT10
)
281 XX(COLOR_ATTACHMENT11
)
282 XX(COLOR_ATTACHMENT12
)
283 XX(COLOR_ATTACHMENT13
)
284 XX(COLOR_ATTACHMENT14
)
285 XX(COLOR_ATTACHMENT15
)
286 XX(FRAMEBUFFER_INCOMPLETE_MULTISAMPLE
)
308 XX(VERTEX_ARRAY_BINDING
)
313 XX(SIGNED_NORMALIZED
)
314 XX(PRIMITIVE_RESTART_FIXED_INDEX
)
316 XX(COPY_WRITE_BUFFER
)
318 XX(UNIFORM_BUFFER_BINDING
)
319 XX(UNIFORM_BUFFER_START
)
320 XX(UNIFORM_BUFFER_SIZE
)
321 XX(MAX_VERTEX_UNIFORM_BLOCKS
)
322 XX(MAX_FRAGMENT_UNIFORM_BLOCKS
)
323 XX(MAX_COMBINED_UNIFORM_BLOCKS
)
324 XX(MAX_UNIFORM_BUFFER_BINDINGS
)
325 XX(MAX_UNIFORM_BLOCK_SIZE
)
326 XX(MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS
)
327 XX(MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS
)
328 XX(UNIFORM_BUFFER_OFFSET_ALIGNMENT
)
329 XX(ACTIVE_UNIFORM_BLOCKS
)
332 XX(UNIFORM_BLOCK_INDEX
)
334 XX(UNIFORM_ARRAY_STRIDE
)
335 XX(UNIFORM_MATRIX_STRIDE
)
336 XX(UNIFORM_IS_ROW_MAJOR
)
337 XX(UNIFORM_BLOCK_BINDING
)
338 XX(UNIFORM_BLOCK_DATA_SIZE
)
339 XX(UNIFORM_BLOCK_ACTIVE_UNIFORMS
)
340 XX(UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES
)
341 XX(UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER
)
342 XX(UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER
)
343 XX(MAX_VERTEX_OUTPUT_COMPONENTS
)
344 XX(MAX_FRAGMENT_INPUT_COMPONENTS
)
345 XX(MAX_SERVER_WAIT_TIMEOUT
)
351 XX(SYNC_GPU_COMMANDS_COMPLETE
)
356 XX(CONDITION_SATISFIED
)
358 XX(VERTEX_ATTRIB_ARRAY_DIVISOR
)
359 XX(ANY_SAMPLES_PASSED
)
360 XX(ANY_SAMPLES_PASSED_CONSERVATIVE
)
363 XX(TEXTURE_SWIZZLE_R
)
364 XX(TEXTURE_SWIZZLE_G
)
365 XX(TEXTURE_SWIZZLE_B
)
366 XX(TEXTURE_SWIZZLE_A
)
369 XX(INT_2_10_10_10_REV
)
370 XX(TRANSFORM_FEEDBACK
)
371 XX(TRANSFORM_FEEDBACK_PAUSED
)
372 XX(TRANSFORM_FEEDBACK_ACTIVE
)
373 XX(TRANSFORM_FEEDBACK_BINDING
)
374 XX(COMPRESSED_R11_EAC
)
375 XX(COMPRESSED_SIGNED_R11_EAC
)
376 XX(COMPRESSED_RG11_EAC
)
377 XX(COMPRESSED_SIGNED_RG11_EAC
)
378 XX(COMPRESSED_RGB8_ETC2
)
379 XX(COMPRESSED_SRGB8_ETC2
)
380 XX(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
)
381 XX(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
)
382 XX(COMPRESSED_RGBA8_ETC2_EAC
)
383 XX(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
)
384 XX(TEXTURE_IMMUTABLE_FORMAT
)
385 XX(MAX_ELEMENT_INDEX
)
386 XX(NUM_SAMPLE_COUNTS
)
387 XX(TEXTURE_IMMUTABLE_LEVELS
)
395 void WebGLContext::EnumName(GLenum val
, nsCString
* out_name
) {
396 const char* name
= GetEnumName(val
, nullptr);
402 *out_name
= nsPrintfCString("<enum 0x%04x>", val
);
405 std::string
EnumString(const GLenum val
) {
406 const char* name
= GetEnumName(val
, nullptr);
411 const nsPrintfCString
hex("<enum 0x%04x>", val
);
412 return hex
.BeginReading();
415 void WebGLContext::ErrorInvalidEnumArg(const char* const argName
,
416 const GLenum val
) const {
417 const auto info
= nsPrintfCString("Bad `%s`", argName
);
418 ErrorInvalidEnumInfo(info
.BeginReading(), val
);
421 void WebGLContext::ErrorInvalidEnumInfo(const char* const info
,
422 const GLenum enumValue
) const {
424 EnumName(enumValue
, &name
);
426 const char* hint
= "";
428 hint
= " (Did you typo `gl.SOMETHINGG` and pass `undefined`?)";
431 ErrorInvalidEnum("%s: Invalid enum value %s%s", info
, name
.BeginReading(),
437 static bool IsCacheCorrect(float cached
, float actual
) {
438 if (std::isnan(cached
)) {
439 // GL is allowed to do anything it wants for NaNs, so if we're shadowing
440 // a NaN, then whatever `actual` is might be correct.
444 return cached
== actual
;
447 void AssertUintParamCorrect(gl::GLContext
* gl
, GLenum pname
, GLuint shadow
) {
449 gl
->GetUIntegerv(pname
, &val
);
451 printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n",
452 pname
, shadow
, shadow
, val
, val
);
453 MOZ_ASSERT(false, "Bad cached value.");
457 void AssertMaskedUintParamCorrect(gl::GLContext
* gl
, GLenum pname
, GLuint mask
,
460 gl
->GetUIntegerv(pname
, &val
);
462 const GLuint valMasked
= val
& mask
;
463 const GLuint shadowMasked
= shadow
& mask
;
465 if (valMasked
!= shadowMasked
) {
466 printf_stderr("Failed 0x%04x shadow: Cached 0x%x/%u, should be 0x%x/%u.\n",
467 pname
, shadowMasked
, shadowMasked
, valMasked
, valMasked
);
468 MOZ_ASSERT(false, "Bad cached value.");
472 void AssertUintParamCorrect(gl::GLContext
*, GLenum
, GLuint
) {}
475 void WebGLContext::AssertCachedBindings() const {
477 gl::GLContext::LocalErrorScope
errorScope(*gl
);
479 GLint stencilBits
= 0;
480 if (GetStencilBits(&stencilBits
)) { // Depends on current draw framebuffer.
481 const GLuint stencilRefMask
= (1 << stencilBits
) - 1;
483 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_REF
, stencilRefMask
,
485 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_BACK_REF
, stencilRefMask
,
490 GLuint bound
= mCurrentProgram
? mCurrentProgram
->mGLName
: 0;
491 AssertUintParamCorrect(gl
, LOCAL_GL_CURRENT_PROGRAM
, bound
);
494 bound
= mBoundArrayBuffer
? mBoundArrayBuffer
->mGLName
: 0;
495 AssertUintParamCorrect(gl
, LOCAL_GL_ARRAY_BUFFER_BINDING
, bound
);
497 MOZ_ASSERT(mBoundVertexArray
);
498 WebGLBuffer
* curBuff
= mBoundVertexArray
->mElementArrayBuffer
;
499 bound
= curBuff
? curBuff
->mGLName
: 0;
500 AssertUintParamCorrect(gl
, LOCAL_GL_ELEMENT_ARRAY_BUFFER_BINDING
, bound
);
502 MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope
.GetError()));
505 // We do not check the renderbuffer binding, because we never rely on it
509 void WebGLContext::AssertCachedGlobalState() const {
511 gl::GLContext::LocalErrorScope
errorScope(*gl
);
516 MOZ_ASSERT(gl
->fIsEnabled(LOCAL_GL_DITHER
) == mDitherEnabled
);
517 MOZ_ASSERT_IF(IsWebGL2(), gl
->fIsEnabled(LOCAL_GL_RASTERIZER_DISCARD
) ==
518 mRasterizerDiscardEnabled
);
519 MOZ_ASSERT(gl
->fIsEnabled(LOCAL_GL_SCISSOR_TEST
) == mScissorTestEnabled
);
521 // Cannot trivially check COLOR_CLEAR_VALUE, since in old GL versions glGet
522 // may clamp based on whether the current framebuffer is floating-point or
523 // not. This also means COLOR_CLEAR_VALUE save+restore is dangerous!
525 realGLboolean depthWriteMask
= 0;
526 gl
->fGetBooleanv(LOCAL_GL_DEPTH_WRITEMASK
, &depthWriteMask
);
527 MOZ_ASSERT(depthWriteMask
== mDepthWriteMask
);
529 GLfloat depthClearValue
= 0.0f
;
530 gl
->fGetFloatv(LOCAL_GL_DEPTH_CLEAR_VALUE
, &depthClearValue
);
531 MOZ_ASSERT(IsCacheCorrect(mDepthClearValue
, depthClearValue
));
533 const int maxStencilBits
= 8;
534 const GLuint maxStencilBitsMask
= (1 << maxStencilBits
) - 1;
535 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_CLEAR_VALUE
,
536 maxStencilBitsMask
, mStencilClearValue
);
538 // GLES 3.0.4, $4.1.4, p177:
539 // [...] the front and back stencil mask are both set to the value `2^s -
540 // 1`, where `s` is greater than or equal to the number of bits in the
541 // deepest stencil buffer supported by the GL implementation.
542 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_VALUE_MASK
,
543 maxStencilBitsMask
, mStencilValueMaskFront
);
544 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_BACK_VALUE_MASK
,
545 maxStencilBitsMask
, mStencilValueMaskBack
);
547 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_WRITEMASK
,
548 maxStencilBitsMask
, mStencilWriteMaskFront
);
549 AssertMaskedUintParamCorrect(gl
, LOCAL_GL_STENCIL_BACK_WRITEMASK
,
550 maxStencilBitsMask
, mStencilWriteMaskBack
);
553 GLint int4
[4] = {0, 0, 0, 0};
554 gl
->fGetIntegerv(LOCAL_GL_VIEWPORT
, int4
);
555 MOZ_ASSERT(int4
[0] == mViewportX
&& int4
[1] == mViewportY
&&
556 int4
[2] == mViewportWidth
&& int4
[3] == mViewportHeight
);
558 MOZ_ASSERT(!gl::GLContext::IsBadCallError(errorScope
.GetError()));
562 const char* InfoFrom(WebGLTexImageFunc func
, WebGLTexDimensions dims
) {
564 case WebGLTexDimensions::Tex2D
:
566 case WebGLTexImageFunc::TexImage
:
568 case WebGLTexImageFunc::TexSubImage
:
569 return "texSubImage2D";
570 case WebGLTexImageFunc::CopyTexImage
:
571 return "copyTexImage2D";
572 case WebGLTexImageFunc::CopyTexSubImage
:
573 return "copyTexSubImage2D";
574 case WebGLTexImageFunc::CompTexImage
:
575 return "compressedTexImage2D";
576 case WebGLTexImageFunc::CompTexSubImage
:
577 return "compressedTexSubImage2D";
579 MOZ_CRASH("GFX: invalid 2D TexDimensions");
581 case WebGLTexDimensions::Tex3D
:
583 case WebGLTexImageFunc::TexImage
:
585 case WebGLTexImageFunc::TexSubImage
:
586 return "texSubImage3D";
587 case WebGLTexImageFunc::CopyTexSubImage
:
588 return "copyTexSubImage3D";
589 case WebGLTexImageFunc::CompTexSubImage
:
590 return "compressedTexSubImage3D";
592 MOZ_CRASH("GFX: invalid 3D TexDimensions");
595 MOZ_CRASH("GFX: invalid TexDimensions");
601 } // namespace mozilla