1 /* -*- Mode: C++; tab-width: 4; 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/. */
6 #include "WebGLContext.h"
7 #include "WebGLContextUtils.h"
8 #include "WebGLBuffer.h"
9 #include "WebGLVertexAttribData.h"
10 #include "WebGLShader.h"
11 #include "WebGLProgram.h"
12 #include "WebGLUniformLocation.h"
13 #include "WebGLFramebuffer.h"
14 #include "WebGLRenderbuffer.h"
15 #include "WebGLShaderPrecisionFormat.h"
16 #include "WebGLTexture.h"
17 #include "WebGLExtensions.h"
18 #include "WebGLVertexArray.h"
22 #include "nsReadableUtils.h"
24 #include "gfxContext.h"
25 #include "gfxPlatform.h"
26 #include "GLContext.h"
28 #include "nsContentUtils.h"
30 #include "nsLayoutUtils.h"
32 #include "CanvasUtils.h"
35 #include "jsfriendapi.h"
37 #include "WebGLTexelConversions.h"
38 #include "WebGLValidateStrings.h"
41 // needed to check if current OS is lower than 10.7
42 #if defined(MOZ_WIDGET_COCOA)
43 #include "nsCocoaFeatures.h"
46 #include "mozilla/DebugOnly.h"
47 #include "mozilla/dom/BindingUtils.h"
48 #include "mozilla/dom/ImageData.h"
49 #include "mozilla/dom/ToJSValue.h"
50 #include "mozilla/Endian.h"
51 #include "mozilla/fallible.h"
53 using namespace mozilla
;
54 using namespace mozilla::dom
;
55 using namespace mozilla::gl
;
56 using namespace mozilla::gfx
;
58 static bool BaseTypeAndSizeFromUniformType(GLenum uType
, GLenum
*baseType
, GLint
*unitSize
);
60 const WebGLRectangleObject
*
61 WebGLContext::CurValidFBRectObject() const
63 const WebGLRectangleObject
* rect
= nullptr;
65 if (mBoundFramebuffer
) {
66 // We don't really need to ask the driver.
67 // Use 'precheck' to just check that our internal state looks good.
68 GLenum precheckStatus
= mBoundFramebuffer
->PrecheckFramebufferStatus();
69 if (precheckStatus
== LOCAL_GL_FRAMEBUFFER_COMPLETE
)
70 rect
= &mBoundFramebuffer
->RectangleObject();
72 rect
= static_cast<const WebGLRectangleObject
*>(this);
83 WebGLContext::ActiveTexture(GLenum texture
)
88 if (texture
< LOCAL_GL_TEXTURE0
||
89 texture
>= LOCAL_GL_TEXTURE0
+ uint32_t(mGLMaxTextureUnits
))
91 return ErrorInvalidEnum(
92 "ActiveTexture: texture unit %d out of range. "
93 "Accepted values range from TEXTURE0 to TEXTURE0 + %d. "
94 "Notice that TEXTURE0 != 0.",
95 texture
, mGLMaxTextureUnits
);
99 mActiveTexture
= texture
- LOCAL_GL_TEXTURE0
;
100 gl
->fActiveTexture(texture
);
104 WebGLContext::AttachShader(WebGLProgram
*program
, WebGLShader
*shader
)
109 if (!ValidateObject("attachShader: program", program
) ||
110 !ValidateObject("attachShader: shader", shader
))
113 // Per GLSL ES 2.0, we can only have one of each type of shader
114 // attached. This renders the next test somewhat moot, but we'll
115 // leave it for when we support more than one shader of each type.
116 if (program
->HasAttachedShaderOfType(shader
->ShaderType()))
117 return ErrorInvalidOperation("attachShader: only one of each type of shader may be attached to a program");
119 if (!program
->AttachShader(shader
))
120 return ErrorInvalidOperation("attachShader: shader is already attached");
125 WebGLContext::BindAttribLocation(WebGLProgram
*prog
, GLuint location
,
126 const nsAString
& name
)
131 if (!ValidateObject("bindAttribLocation: program", prog
))
134 GLuint progname
= prog
->GLName();
136 if (!ValidateGLSLVariableName(name
, "bindAttribLocation"))
139 if (!ValidateAttribIndex(location
, "bindAttribLocation"))
142 if (StringBeginsWith(name
, NS_LITERAL_STRING("gl_")))
143 return ErrorInvalidOperation("bindAttribLocation: can't set the location of a name that starts with 'gl_'");
145 NS_LossyConvertUTF16toASCII
cname(name
);
146 nsCString mappedName
;
147 if (mShaderValidation
) {
148 WebGLProgram::HashMapIdentifier(cname
, &mappedName
);
150 mappedName
.Assign(cname
);
153 MakeContextCurrent();
154 gl
->fBindAttribLocation(progname
, location
, mappedName
.get());
158 WebGLContext::BindFramebuffer(GLenum target
, WebGLFramebuffer
*wfb
)
163 if (target
!= LOCAL_GL_FRAMEBUFFER
)
164 return ErrorInvalidEnum("bindFramebuffer: target must be GL_FRAMEBUFFER");
166 if (!ValidateObjectAllowDeletedOrNull("bindFramebuffer", wfb
))
169 // silently ignore a deleted frame buffer
170 if (wfb
&& wfb
->IsDeleted())
173 MakeContextCurrent();
176 gl
->fBindFramebuffer(target
, 0);
179 GLuint framebuffername
= wfb
->GLName();
180 gl
->fBindFramebuffer(target
, framebuffername
);
183 mBoundFramebuffer
= wfb
;
187 WebGLContext::BindRenderbuffer(GLenum target
, WebGLRenderbuffer
*wrb
)
192 if (target
!= LOCAL_GL_RENDERBUFFER
)
193 return ErrorInvalidEnumInfo("bindRenderbuffer: target", target
);
195 if (!ValidateObjectAllowDeletedOrNull("bindRenderbuffer", wrb
))
198 // silently ignore a deleted buffer
199 if (wrb
&& wrb
->IsDeleted())
205 MakeContextCurrent();
207 // Sometimes we emulate renderbuffers (depth-stencil emu), so there's not
208 // always a 1-1 mapping from `wrb` to GL name. Just have `wrb` handle it.
210 wrb
->BindRenderbuffer();
212 gl
->fBindRenderbuffer(target
, 0);
215 mBoundRenderbuffer
= wrb
;
219 WebGLContext::BindTexture(GLenum target
, WebGLTexture
*newTex
)
224 if (!ValidateObjectAllowDeletedOrNull("bindTexture", newTex
))
227 // silently ignore a deleted texture
228 if (newTex
&& newTex
->IsDeleted())
231 WebGLRefPtr
<WebGLTexture
>* currentTexPtr
= nullptr;
233 if (target
== LOCAL_GL_TEXTURE_2D
) {
234 currentTexPtr
= &mBound2DTextures
[mActiveTexture
];
235 } else if (target
== LOCAL_GL_TEXTURE_CUBE_MAP
) {
236 currentTexPtr
= &mBoundCubeMapTextures
[mActiveTexture
];
238 return ErrorInvalidEnumInfo("bindTexture: target", target
);
241 WebGLTextureFakeBlackStatus currentTexFakeBlackStatus
= WebGLTextureFakeBlackStatus::NotNeeded
;
242 if (*currentTexPtr
) {
243 currentTexFakeBlackStatus
= (*currentTexPtr
)->ResolvedFakeBlackStatus();
245 WebGLTextureFakeBlackStatus newTexFakeBlackStatus
= WebGLTextureFakeBlackStatus::NotNeeded
;
247 newTexFakeBlackStatus
= newTex
->ResolvedFakeBlackStatus();
250 *currentTexPtr
= newTex
;
252 if (currentTexFakeBlackStatus
!= newTexFakeBlackStatus
) {
253 SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown
);
256 MakeContextCurrent();
259 newTex
->Bind(target
);
261 gl
->fBindTexture(target
, 0 /* == texturename */);
264 void WebGLContext::BlendEquation(GLenum mode
)
269 if (!ValidateBlendEquationEnum(mode
, "blendEquation: mode"))
272 MakeContextCurrent();
273 gl
->fBlendEquation(mode
);
276 void WebGLContext::BlendEquationSeparate(GLenum modeRGB
, GLenum modeAlpha
)
281 if (!ValidateBlendEquationEnum(modeRGB
, "blendEquationSeparate: modeRGB") ||
282 !ValidateBlendEquationEnum(modeAlpha
, "blendEquationSeparate: modeAlpha"))
285 MakeContextCurrent();
286 gl
->fBlendEquationSeparate(modeRGB
, modeAlpha
);
289 void WebGLContext::BlendFunc(GLenum sfactor
, GLenum dfactor
)
294 if (!ValidateBlendFuncSrcEnum(sfactor
, "blendFunc: sfactor") ||
295 !ValidateBlendFuncDstEnum(dfactor
, "blendFunc: dfactor"))
298 if (!ValidateBlendFuncEnumsCompatibility(sfactor
, dfactor
, "blendFuncSeparate: srcRGB and dstRGB"))
301 MakeContextCurrent();
302 gl
->fBlendFunc(sfactor
, dfactor
);
306 WebGLContext::BlendFuncSeparate(GLenum srcRGB
, GLenum dstRGB
,
307 GLenum srcAlpha
, GLenum dstAlpha
)
312 if (!ValidateBlendFuncSrcEnum(srcRGB
, "blendFuncSeparate: srcRGB") ||
313 !ValidateBlendFuncSrcEnum(srcAlpha
, "blendFuncSeparate: srcAlpha") ||
314 !ValidateBlendFuncDstEnum(dstRGB
, "blendFuncSeparate: dstRGB") ||
315 !ValidateBlendFuncDstEnum(dstAlpha
, "blendFuncSeparate: dstAlpha"))
318 // note that we only check compatibity for the RGB enums, no need to for the Alpha enums, see
319 // "Section 6.8 forgetting to mention alpha factors?" thread on the public_webgl mailing list
320 if (!ValidateBlendFuncEnumsCompatibility(srcRGB
, dstRGB
, "blendFuncSeparate: srcRGB and dstRGB"))
323 MakeContextCurrent();
324 gl
->fBlendFuncSeparate(srcRGB
, dstRGB
, srcAlpha
, dstAlpha
);
328 WebGLContext::CheckFramebufferStatus(GLenum target
)
331 return LOCAL_GL_FRAMEBUFFER_UNSUPPORTED
;
333 if (target
!= LOCAL_GL_FRAMEBUFFER
) {
334 ErrorInvalidEnum("checkFramebufferStatus: target must be FRAMEBUFFER");
338 if (!mBoundFramebuffer
)
339 return LOCAL_GL_FRAMEBUFFER_COMPLETE
;
341 return mBoundFramebuffer
->CheckFramebufferStatus();
345 WebGLContext::CopyTexSubImage2D_base(GLenum target
,
347 GLenum internalformat
,
356 const WebGLRectangleObject
* framebufferRect
= CurValidFBRectObject();
357 GLsizei framebufferWidth
= framebufferRect
? framebufferRect
->Width() : 0;
358 GLsizei framebufferHeight
= framebufferRect
? framebufferRect
->Height() : 0;
360 const char* info
= sub
? "copyTexSubImage2D" : "copyTexImage2D";
361 WebGLTexImageFunc func
= sub
? WebGLTexImageFunc::CopyTexSubImage
: WebGLTexImageFunc::CopyTexImage
;
363 // TODO: This changes with color_buffer_float. Reassess when the
365 if (!ValidateTexImage(2, target
, level
, internalformat
,
368 0, internalformat
, LOCAL_GL_UNSIGNED_BYTE
,
374 if (!ValidateCopyTexImage(internalformat
, func
))
377 if (!mBoundFramebuffer
)
378 ClearBackbufferIfNeeded();
380 MakeContextCurrent();
382 WebGLTexture
*tex
= activeBoundTextureForTarget(target
);
385 return ErrorInvalidOperation("%s: no texture is bound to this target");
387 if (CanvasUtils::CheckSaneSubrectSize(x
, y
, width
, height
, framebufferWidth
, framebufferHeight
)) {
389 gl
->fCopyTexSubImage2D(target
, level
, xoffset
, yoffset
, x
, y
, width
, height
);
391 gl
->fCopyTexImage2D(target
, level
, internalformat
, x
, y
, width
, height
, 0);
394 // the rect doesn't fit in the framebuffer
396 /*** first, we initialize the texture as black ***/
398 // first, compute the size of the buffer we should allocate to initialize the texture as black
400 if (!ValidateTexInputData(LOCAL_GL_UNSIGNED_BYTE
, -1, func
))
403 uint32_t texelSize
= GetBitsPerTexel(internalformat
, LOCAL_GL_UNSIGNED_BYTE
) / 8;
405 CheckedUint32 checked_neededByteLength
=
406 GetImageSize(height
, width
, texelSize
, mPixelStoreUnpackAlignment
);
408 if (!checked_neededByteLength
.isValid())
409 return ErrorInvalidOperation("%s: integer overflow computing the needed buffer size", info
);
411 uint32_t bytesNeeded
= checked_neededByteLength
.value();
413 // now that the size is known, create the buffer
415 // We need some zero pages, because GL doesn't guarantee the
416 // contents of a texture allocated with nullptr data.
417 // Hopefully calloc will just mmap zero pages here.
418 void* tempZeroData
= calloc(1, bytesNeeded
);
420 return ErrorOutOfMemory("%s: could not allocate %d bytes (for zero fill)", info
, bytesNeeded
);
422 // now initialize the texture as black
425 gl
->fTexSubImage2D(target
, level
, 0, 0, width
, height
,
426 internalformat
, LOCAL_GL_UNSIGNED_BYTE
, tempZeroData
);
428 gl
->fTexImage2D(target
, level
, internalformat
, width
, height
,
429 0, internalformat
, LOCAL_GL_UNSIGNED_BYTE
, tempZeroData
);
432 // if we are completely outside of the framebuffer, we can exit now with our black texture
433 if ( x
>= framebufferWidth
435 || y
>= framebufferHeight
438 // we are completely outside of range, can exit now with buffer filled with zeros
439 return DummyFramebufferOperation(info
);
442 GLint actual_x
= clamped(x
, 0, framebufferWidth
);
443 GLint actual_x_plus_width
= clamped(x
+ width
, 0, framebufferWidth
);
444 GLsizei actual_width
= actual_x_plus_width
- actual_x
;
445 GLint actual_xoffset
= xoffset
+ actual_x
- x
;
447 GLint actual_y
= clamped(y
, 0, framebufferHeight
);
448 GLint actual_y_plus_height
= clamped(y
+ height
, 0, framebufferHeight
);
449 GLsizei actual_height
= actual_y_plus_height
- actual_y
;
450 GLint actual_yoffset
= yoffset
+ actual_y
- y
;
452 gl
->fCopyTexSubImage2D(target
, level
, actual_xoffset
, actual_yoffset
, actual_x
, actual_y
, actual_width
, actual_height
);
457 WebGLContext::CopyTexImage2D(GLenum target
,
459 GLenum internalformat
,
469 // copyTexImage2D only generates textures with type = UNSIGNED_BYTE
470 const WebGLTexImageFunc func
= WebGLTexImageFunc::CopyTexImage
;
471 const GLenum format
= internalformat
; // WebGL/ES Format
472 const GLenum type
= LOCAL_GL_UNSIGNED_BYTE
; // WebGL/ES Format
474 if (!ValidateTexImage(2, target
, level
, format
,
477 border
, format
, type
,
483 if (!ValidateCopyTexImage(format
, func
))
486 if (!mBoundFramebuffer
)
487 ClearBackbufferIfNeeded();
489 // check if the memory size of this texture may change with this call
490 bool sizeMayChange
= true;
491 WebGLTexture
* tex
= activeBoundTextureForTarget(target
);
492 if (tex
->HasImageInfoAt(target
, level
)) {
493 const WebGLTexture::ImageInfo
& imageInfo
= tex
->ImageInfoAt(target
, level
);
495 sizeMayChange
= width
!= imageInfo
.Width() ||
496 height
!= imageInfo
.Height() ||
497 format
!= imageInfo
.WebGLFormat() ||
498 type
!= imageInfo
.WebGLType();
502 GetAndFlushUnderlyingGLErrors();
504 CopyTexSubImage2D_base(target
, level
, format
, 0, 0, x
, y
, width
, height
, false);
507 GLenum error
= GetAndFlushUnderlyingGLErrors();
509 GenerateWarning("copyTexImage2D generated error %s", ErrorName(error
));
514 tex
->SetImageInfo(target
, level
, width
, height
, format
, type
,
515 WebGLImageDataStatus::InitializedImageData
);
519 WebGLContext::CopyTexSubImage2D(GLenum target
,
532 case LOCAL_GL_TEXTURE_2D
:
533 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
:
534 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X
:
535 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y
:
536 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y
:
537 case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z
:
538 case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
:
541 return ErrorInvalidEnumInfo("copyTexSubImage2D: target", target
);
545 return ErrorInvalidValue("copyTexSubImage2D: level may not be negative");
547 GLsizei maxTextureSize
= MaxTextureSizeForTarget(target
);
548 if (!(maxTextureSize
>> level
))
549 return ErrorInvalidValue("copyTexSubImage2D: 2^level exceeds maximum texture size");
551 if (width
< 0 || height
< 0)
552 return ErrorInvalidValue("copyTexSubImage2D: width and height may not be negative");
554 if (xoffset
< 0 || yoffset
< 0)
555 return ErrorInvalidValue("copyTexSubImage2D: xoffset and yoffset may not be negative");
557 WebGLTexture
*tex
= activeBoundTextureForTarget(target
);
559 return ErrorInvalidOperation("copyTexSubImage2D: no texture bound to this target");
561 if (!tex
->HasImageInfoAt(target
, level
))
562 return ErrorInvalidOperation("copyTexSubImage2D: no texture image previously defined for this level and face");
564 const WebGLTexture::ImageInfo
&imageInfo
= tex
->ImageInfoAt(target
, level
);
565 GLsizei texWidth
= imageInfo
.Width();
566 GLsizei texHeight
= imageInfo
.Height();
568 if (xoffset
+ width
> texWidth
|| xoffset
+ width
< 0)
569 return ErrorInvalidValue("copyTexSubImage2D: xoffset+width is too large");
571 if (yoffset
+ height
> texHeight
|| yoffset
+ height
< 0)
572 return ErrorInvalidValue("copyTexSubImage2D: yoffset+height is too large");
574 if (!mBoundFramebuffer
)
575 ClearBackbufferIfNeeded();
577 if (imageInfo
.HasUninitializedImageData()) {
578 tex
->DoDeferredImageInitialization(target
, level
);
581 return CopyTexSubImage2D_base(target
, level
, imageInfo
.WebGLFormat(), xoffset
, yoffset
, x
, y
, width
, height
, true);
585 already_AddRefed
<WebGLProgram
>
586 WebGLContext::CreateProgram()
590 nsRefPtr
<WebGLProgram
> globj
= new WebGLProgram(this);
591 return globj
.forget();
594 already_AddRefed
<WebGLShader
>
595 WebGLContext::CreateShader(GLenum type
)
600 if (type
!= LOCAL_GL_VERTEX_SHADER
&&
601 type
!= LOCAL_GL_FRAGMENT_SHADER
)
603 ErrorInvalidEnumInfo("createShader: type", type
);
607 nsRefPtr
<WebGLShader
> shader
= new WebGLShader(this, type
);
608 return shader
.forget();
612 WebGLContext::CullFace(GLenum face
)
617 if (!ValidateFaceEnum(face
, "cullFace"))
620 MakeContextCurrent();
625 WebGLContext::DeleteFramebuffer(WebGLFramebuffer
* fbuf
)
630 if (!ValidateObjectAllowDeletedOrNull("deleteFramebuffer", fbuf
))
633 if (!fbuf
|| fbuf
->IsDeleted())
636 fbuf
->RequestDelete();
638 if (mBoundFramebuffer
== fbuf
)
639 BindFramebuffer(LOCAL_GL_FRAMEBUFFER
,
640 static_cast<WebGLFramebuffer
*>(nullptr));
644 WebGLContext::DeleteRenderbuffer(WebGLRenderbuffer
*rbuf
)
649 if (!ValidateObjectAllowDeletedOrNull("deleteRenderbuffer", rbuf
))
652 if (!rbuf
|| rbuf
->IsDeleted())
655 if (mBoundFramebuffer
)
656 mBoundFramebuffer
->DetachRenderbuffer(rbuf
);
658 // Invalidate framebuffer status cache
659 rbuf
->NotifyFBsStatusChanged();
661 if (mBoundRenderbuffer
== rbuf
)
662 BindRenderbuffer(LOCAL_GL_RENDERBUFFER
,
663 static_cast<WebGLRenderbuffer
*>(nullptr));
665 rbuf
->RequestDelete();
669 WebGLContext::DeleteTexture(WebGLTexture
*tex
)
674 if (!ValidateObjectAllowDeletedOrNull("deleteTexture", tex
))
677 if (!tex
|| tex
->IsDeleted())
680 if (mBoundFramebuffer
)
681 mBoundFramebuffer
->DetachTexture(tex
);
683 // Invalidate framebuffer status cache
684 tex
->NotifyFBsStatusChanged();
686 GLuint activeTexture
= mActiveTexture
;
687 for (int32_t i
= 0; i
< mGLMaxTextureUnits
; i
++) {
688 if ((tex
->Target() == LOCAL_GL_TEXTURE_2D
&& mBound2DTextures
[i
] == tex
) ||
689 (tex
->Target() == LOCAL_GL_TEXTURE_CUBE_MAP
&& mBoundCubeMapTextures
[i
] == tex
))
691 ActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
692 BindTexture(tex
->Target(), static_cast<WebGLTexture
*>(nullptr));
695 ActiveTexture(LOCAL_GL_TEXTURE0
+ activeTexture
);
697 tex
->RequestDelete();
701 WebGLContext::DeleteProgram(WebGLProgram
*prog
)
706 if (!ValidateObjectAllowDeletedOrNull("deleteProgram", prog
))
709 if (!prog
|| prog
->IsDeleted())
712 prog
->RequestDelete();
716 WebGLContext::DeleteShader(WebGLShader
*shader
)
721 if (!ValidateObjectAllowDeletedOrNull("deleteShader", shader
))
724 if (!shader
|| shader
->IsDeleted())
727 shader
->RequestDelete();
731 WebGLContext::DetachShader(WebGLProgram
*program
, WebGLShader
*shader
)
736 if (!ValidateObject("detachShader: program", program
) ||
737 // it's valid to attempt to detach a deleted shader, since it's
739 !ValidateObjectAllowDeleted("detashShader: shader", shader
))
742 if (!program
->DetachShader(shader
))
743 return ErrorInvalidOperation("detachShader: shader is not attached");
747 WebGLContext::DepthFunc(GLenum func
)
752 if (!ValidateComparisonEnum(func
, "depthFunc"))
755 MakeContextCurrent();
756 gl
->fDepthFunc(func
);
760 WebGLContext::DepthRange(GLfloat zNear
, GLfloat zFar
)
766 return ErrorInvalidOperation("depthRange: the near value is greater than the far value!");
768 MakeContextCurrent();
769 gl
->fDepthRange(zNear
, zFar
);
773 WebGLContext::FramebufferRenderbuffer(GLenum target
, GLenum attachment
, GLenum rbtarget
, WebGLRenderbuffer
*wrb
)
778 if (!mBoundFramebuffer
)
779 return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
781 return mBoundFramebuffer
->FramebufferRenderbuffer(target
, attachment
, rbtarget
, wrb
);
785 WebGLContext::FramebufferTexture2D(GLenum target
,
794 if (!mBoundFramebuffer
)
795 return ErrorInvalidOperation("framebufferRenderbuffer: cannot modify framebuffer 0");
797 return mBoundFramebuffer
->FramebufferTexture2D(target
, attachment
, textarget
, tobj
, level
);
801 WebGLContext::FrontFace(GLenum mode
)
811 return ErrorInvalidEnumInfo("frontFace: mode", mode
);
814 MakeContextCurrent();
815 gl
->fFrontFace(mode
);
818 already_AddRefed
<WebGLActiveInfo
>
819 WebGLContext::GetActiveAttrib(WebGLProgram
*prog
, uint32_t index
)
824 if (!ValidateObject("getActiveAttrib: program", prog
))
827 MakeContextCurrent();
830 GLuint progname
= prog
->GLName();;
831 gl
->fGetProgramiv(progname
, LOCAL_GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
, &len
);
835 nsAutoArrayPtr
<char> name(new char[len
]);
839 gl
->fGetActiveAttrib(progname
, index
, len
, &len
, &attrsize
, &attrtype
, name
);
840 if (attrsize
== 0 || attrtype
== 0) {
844 nsCString reverseMappedName
;
845 prog
->ReverseMapIdentifier(nsDependentCString(name
), &reverseMappedName
);
847 nsRefPtr
<WebGLActiveInfo
> retActiveInfo
=
848 new WebGLActiveInfo(attrsize
, attrtype
, reverseMappedName
);
849 return retActiveInfo
.forget();
853 WebGLContext::GenerateMipmap(GLenum target
)
858 if (!ValidateTextureTargetEnum(target
, "generateMipmap"))
861 WebGLTexture
*tex
= activeBoundTextureForTarget(target
);
864 return ErrorInvalidOperation("generateMipmap: No texture is bound to this target.");
866 GLenum imageTarget
= (target
== LOCAL_GL_TEXTURE_2D
) ? LOCAL_GL_TEXTURE_2D
867 : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
;
868 if (!tex
->HasImageInfoAt(imageTarget
, 0))
870 return ErrorInvalidOperation("generateMipmap: Level zero of texture is not defined.");
873 if (!tex
->IsFirstImagePowerOfTwo())
874 return ErrorInvalidOperation("generateMipmap: Level zero of texture does not have power-of-two width and height.");
876 GLenum webGLFormat
= tex
->ImageInfoAt(imageTarget
, 0).WebGLFormat();
877 if (IsTextureFormatCompressed(webGLFormat
))
878 return ErrorInvalidOperation("generateMipmap: Texture data at level zero is compressed.");
880 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_depth_texture
) &&
881 (IsGLDepthFormat(webGLFormat
) || IsGLDepthStencilFormat(webGLFormat
)))
883 return ErrorInvalidOperation("generateMipmap: "
884 "A texture that has a base internal format of "
885 "DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
888 if (!tex
->AreAllLevel0ImageInfosEqual())
889 return ErrorInvalidOperation("generateMipmap: The six faces of this cube map have different dimensions, format, or type.");
891 tex
->SetGeneratedMipmap();
893 MakeContextCurrent();
895 if (gl
->WorkAroundDriverBugs()) {
896 // bug 696495 - to work around failures in the texture-mips.html test on various drivers, we
897 // set the minification filter before calling glGenerateMipmap. This should not carry a significant performance
898 // overhead so we do it unconditionally.
900 // note that the choice of GL_NEAREST_MIPMAP_NEAREST really matters. See Chromium bug 101105.
901 gl
->fTexParameteri(target
, LOCAL_GL_TEXTURE_MIN_FILTER
, LOCAL_GL_NEAREST_MIPMAP_NEAREST
);
902 gl
->fGenerateMipmap(target
);
903 gl
->fTexParameteri(target
, LOCAL_GL_TEXTURE_MIN_FILTER
, tex
->MinFilter());
905 gl
->fGenerateMipmap(target
);
909 already_AddRefed
<WebGLActiveInfo
>
910 WebGLContext::GetActiveUniform(WebGLProgram
*prog
, uint32_t index
)
915 if (!ValidateObject("getActiveUniform: program", prog
))
918 MakeContextCurrent();
921 GLuint progname
= prog
->GLName();
922 gl
->fGetProgramiv(progname
, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH
, &len
);
926 nsAutoArrayPtr
<char> name(new char[len
]);
931 gl
->fGetActiveUniform(progname
, index
, len
, &len
, &usize
, &utype
, name
);
932 if (len
== 0 || usize
== 0 || utype
== 0) {
936 nsCString reverseMappedName
;
937 prog
->ReverseMapIdentifier(nsDependentCString(name
), &reverseMappedName
);
939 // OpenGL ES 2.0 specifies that if foo is a uniform array, GetActiveUniform returns its name as "foo[0]".
940 // See section 2.10 page 35 in the OpenGL ES 2.0.24 specification:
942 // > If the active uniform is an array, the uniform name returned in name will always
943 // > be the name of the uniform array appended with "[0]".
945 // There is no such requirement in the OpenGL (non-ES) spec and indeed we have OpenGL implementations returning
946 // "foo" instead of "foo[0]". So, when implementing WebGL on top of desktop OpenGL, we must check if the
947 // returned name ends in [0], and if it doesn't, append that.
949 // In principle we don't need to do that on OpenGL ES, but this is such a tricky difference between the ES and non-ES
950 // specs that it seems probable that some ES implementers will overlook it. Since the work-around is quite cheap,
951 // we do it unconditionally.
952 if (usize
> 1 && reverseMappedName
.CharAt(reverseMappedName
.Length()-1) != ']')
953 reverseMappedName
.AppendLiteral("[0]");
955 nsRefPtr
<WebGLActiveInfo
> retActiveInfo
=
956 new WebGLActiveInfo(usize
, utype
, reverseMappedName
);
957 return retActiveInfo
.forget();
961 WebGLContext::GetAttachedShaders(WebGLProgram
*prog
,
962 Nullable
< nsTArray
<WebGLShader
*> > &retval
)
968 if (!ValidateObjectAllowNull("getAttachedShaders", prog
))
971 MakeContextCurrent();
975 ErrorInvalidValue("getAttachedShaders: invalid program");
976 } else if (prog
->AttachedShaders().Length() == 0) {
977 retval
.SetValue().TruncateLength(0);
979 retval
.SetValue().AppendElements(prog
->AttachedShaders());
984 WebGLContext::GetAttribLocation(WebGLProgram
*prog
, const nsAString
& name
)
989 if (!ValidateObject("getAttribLocation: program", prog
))
992 if (!ValidateGLSLVariableName(name
, "getAttribLocation"))
995 NS_LossyConvertUTF16toASCII
cname(name
);
996 nsCString mappedName
;
997 prog
->MapIdentifier(cname
, &mappedName
);
999 GLuint progname
= prog
->GLName();
1001 MakeContextCurrent();
1002 return gl
->fGetAttribLocation(progname
, mappedName
.get());
1006 WebGLContext::GetBufferParameter(GLenum target
, GLenum pname
)
1008 if (IsContextLost())
1009 return JS::NullValue();
1011 if (target
!= LOCAL_GL_ARRAY_BUFFER
&& target
!= LOCAL_GL_ELEMENT_ARRAY_BUFFER
) {
1012 ErrorInvalidEnumInfo("getBufferParameter: target", target
);
1013 return JS::NullValue();
1016 MakeContextCurrent();
1019 case LOCAL_GL_BUFFER_SIZE
:
1020 case LOCAL_GL_BUFFER_USAGE
:
1023 gl
->fGetBufferParameteriv(target
, pname
, &i
);
1024 if (pname
== LOCAL_GL_BUFFER_SIZE
) {
1025 return JS::Int32Value(i
);
1028 MOZ_ASSERT(pname
== LOCAL_GL_BUFFER_USAGE
);
1029 return JS::NumberValue(uint32_t(i
));
1034 ErrorInvalidEnumInfo("getBufferParameter: parameter", pname
);
1037 return JS::NullValue();
1041 WebGLContext::GetFramebufferAttachmentParameter(JSContext
* cx
,
1047 if (IsContextLost())
1048 return JS::NullValue();
1050 if (target
!= LOCAL_GL_FRAMEBUFFER
) {
1051 ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: target", target
);
1052 return JS::NullValue();
1055 if (!mBoundFramebuffer
) {
1056 ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot query framebuffer 0");
1057 return JS::NullValue();
1060 if (attachment
!= LOCAL_GL_DEPTH_ATTACHMENT
&&
1061 attachment
!= LOCAL_GL_STENCIL_ATTACHMENT
&&
1062 attachment
!= LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
)
1064 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers
))
1066 if (attachment
< LOCAL_GL_COLOR_ATTACHMENT0
||
1067 attachment
>= GLenum(LOCAL_GL_COLOR_ATTACHMENT0
+ mGLMaxColorAttachments
))
1069 ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: attachment", attachment
);
1070 return JS::NullValue();
1073 mBoundFramebuffer
->EnsureColorAttachments(attachment
- LOCAL_GL_COLOR_ATTACHMENT0
);
1075 else if (attachment
!= LOCAL_GL_COLOR_ATTACHMENT0
)
1077 ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: attachment", attachment
);
1078 return JS::NullValue();
1082 MakeContextCurrent();
1084 const WebGLFramebuffer::Attachment
& fba
= mBoundFramebuffer
->GetAttachment(attachment
);
1086 if (fba
.Renderbuffer()) {
1088 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT
:
1089 if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB
)) {
1090 const GLenum internalFormat
= fba
.Renderbuffer()->InternalFormat();
1091 return (internalFormat
== LOCAL_GL_SRGB_EXT
||
1092 internalFormat
== LOCAL_GL_SRGB_ALPHA_EXT
||
1093 internalFormat
== LOCAL_GL_SRGB8_ALPHA8_EXT
) ?
1094 JS::NumberValue(uint32_t(LOCAL_GL_SRGB_EXT
)) :
1095 JS::NumberValue(uint32_t(LOCAL_GL_LINEAR
));
1099 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
:
1100 return JS::NumberValue(uint32_t(LOCAL_GL_RENDERBUFFER
));
1102 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME
:
1103 return WebGLObjectAsJSValue(cx
, fba
.Renderbuffer(), rv
);
1105 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE
: {
1106 if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float
) &&
1107 !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float
))
1112 if (attachment
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
) {
1113 ErrorInvalidOperation("getFramebufferAttachmentParameter: Cannot get component"
1114 " type of a depth-stencil attachment.");
1115 return JS::NullValue();
1118 if (!fba
.IsComplete())
1119 return JS::NumberValue(uint32_t(LOCAL_GL_NONE
));
1121 uint32_t ret
= LOCAL_GL_NONE
;
1122 switch (fba
.Renderbuffer()->InternalFormat()) {
1123 case LOCAL_GL_RGBA4
:
1124 case LOCAL_GL_RGB5_A1
:
1125 case LOCAL_GL_RGB565
:
1126 case LOCAL_GL_SRGB8_ALPHA8
:
1127 ret
= LOCAL_GL_UNSIGNED_NORMALIZED
;
1129 case LOCAL_GL_RGB16F
:
1130 case LOCAL_GL_RGBA16F
:
1131 case LOCAL_GL_RGB32F
:
1132 case LOCAL_GL_RGBA32F
:
1133 ret
= LOCAL_GL_FLOAT
;
1135 case LOCAL_GL_DEPTH_COMPONENT16
:
1136 case LOCAL_GL_STENCIL_INDEX8
:
1137 ret
= LOCAL_GL_UNSIGNED_INT
;
1140 MOZ_ASSERT(false, "Unhandled RB component type.");
1143 return JS::NumberValue(uint32_t(ret
));
1147 ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname
);
1148 return JS::NullValue();
1149 } else if (fba
.Texture()) {
1151 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT
:
1152 if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB
)) {
1153 const GLenum webGLFormat
=
1154 fba
.Texture()->ImageInfoBase().WebGLFormat();
1155 return (webGLFormat
== LOCAL_GL_SRGB
||
1156 webGLFormat
== LOCAL_GL_SRGB_ALPHA
) ?
1157 JS::NumberValue(uint32_t(LOCAL_GL_SRGB
)) :
1158 JS::NumberValue(uint32_t(LOCAL_GL_LINEAR
));
1162 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
:
1163 return JS::NumberValue(uint32_t(LOCAL_GL_TEXTURE
));
1165 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME
:
1166 return WebGLObjectAsJSValue(cx
, fba
.Texture(), rv
);
1168 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL
:
1169 return JS::Int32Value(fba
.TexImageLevel());
1171 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE
: {
1172 GLenum face
= fba
.TexImageTarget();
1173 if (face
== LOCAL_GL_TEXTURE_2D
)
1175 return JS::Int32Value(face
);
1178 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE
: {
1179 if (!IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float
) &&
1180 !IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float
))
1185 if (attachment
== LOCAL_GL_DEPTH_STENCIL_ATTACHMENT
) {
1186 ErrorInvalidOperation("getFramebufferAttachmentParameter: cannot component"
1187 " type of depth-stencil attachments.");
1188 return JS::NullValue();
1191 if (!fba
.IsComplete())
1192 return JS::NumberValue(uint32_t(LOCAL_GL_NONE
));
1194 uint32_t ret
= LOCAL_GL_NONE
;
1195 GLenum type
= fba
.Texture()->ImageInfoAt(fba
.TexImageTarget(),
1196 fba
.TexImageLevel()).WebGLType();
1198 case LOCAL_GL_UNSIGNED_BYTE
:
1199 case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4
:
1200 case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1
:
1201 case LOCAL_GL_UNSIGNED_SHORT_5_6_5
:
1202 ret
= LOCAL_GL_UNSIGNED_NORMALIZED
;
1204 case LOCAL_GL_FLOAT
:
1205 case LOCAL_GL_HALF_FLOAT_OES
:
1206 ret
= LOCAL_GL_FLOAT
;
1208 case LOCAL_GL_UNSIGNED_SHORT
:
1209 case LOCAL_GL_UNSIGNED_INT
:
1210 ret
= LOCAL_GL_UNSIGNED_INT
;
1213 MOZ_ASSERT(false, "Unhandled RB component type.");
1216 return JS::NumberValue(uint32_t(ret
));
1220 ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname
);
1221 return JS::NullValue();
1224 case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE
:
1225 return JS::NumberValue(uint32_t(LOCAL_GL_NONE
));
1228 ErrorInvalidEnumInfo("getFramebufferAttachmentParameter: pname", pname
);
1229 return JS::NullValue();
1233 return JS::NullValue();
1237 WebGLContext::GetRenderbufferParameter(GLenum target
, GLenum pname
)
1239 if (IsContextLost())
1240 return JS::NullValue();
1242 if (target
!= LOCAL_GL_RENDERBUFFER
) {
1243 ErrorInvalidEnumInfo("getRenderbufferParameter: target", target
);
1244 return JS::NullValue();
1247 if (!mBoundRenderbuffer
) {
1248 ErrorInvalidOperation("getRenderbufferParameter: no render buffer is bound");
1249 return JS::NullValue();
1252 MakeContextCurrent();
1255 case LOCAL_GL_RENDERBUFFER_WIDTH
:
1256 case LOCAL_GL_RENDERBUFFER_HEIGHT
:
1257 case LOCAL_GL_RENDERBUFFER_RED_SIZE
:
1258 case LOCAL_GL_RENDERBUFFER_GREEN_SIZE
:
1259 case LOCAL_GL_RENDERBUFFER_BLUE_SIZE
:
1260 case LOCAL_GL_RENDERBUFFER_ALPHA_SIZE
:
1261 case LOCAL_GL_RENDERBUFFER_DEPTH_SIZE
:
1262 case LOCAL_GL_RENDERBUFFER_STENCIL_SIZE
:
1264 // RB emulation means we have to ask the RB itself.
1265 GLint i
= mBoundRenderbuffer
->GetRenderbufferParameter(target
, pname
);
1266 return JS::Int32Value(i
);
1268 case LOCAL_GL_RENDERBUFFER_INTERNAL_FORMAT
:
1270 return JS::NumberValue(mBoundRenderbuffer
->InternalFormat());
1273 ErrorInvalidEnumInfo("getRenderbufferParameter: parameter", pname
);
1276 return JS::NullValue();
1279 already_AddRefed
<WebGLTexture
>
1280 WebGLContext::CreateTexture()
1282 if (IsContextLost())
1284 nsRefPtr
<WebGLTexture
> globj
= new WebGLTexture(this);
1285 return globj
.forget();
1289 GetAndClearError(GLenum
* errorVar
)
1291 MOZ_ASSERT(errorVar
);
1292 GLenum ret
= *errorVar
;
1293 *errorVar
= LOCAL_GL_NO_ERROR
;
1298 WebGLContext::GetError()
1300 /* WebGL 1.0: Section 5.14.3: Setting and getting state:
1301 * If the context's webgl context lost flag is set, returns
1302 * CONTEXT_LOST_WEBGL the first time this method is called.
1303 * Afterward, returns NO_ERROR until the context has been
1306 * WEBGL_lose_context:
1307 * [When this extension is enabled: ] loseContext and
1308 * restoreContext are allowed to generate INVALID_OPERATION errors
1309 * even when the context is lost.
1312 if (IsContextLost()) {
1313 if (mEmitContextLostErrorOnce
) {
1314 mEmitContextLostErrorOnce
= false;
1315 return LOCAL_GL_CONTEXT_LOST
;
1317 // Don't return yet, since WEBGL_lose_contexts contradicts the
1318 // original spec, and allows error generation while lost.
1321 GLenum err
= GetAndClearError(&mWebGLError
);
1322 if (err
!= LOCAL_GL_NO_ERROR
)
1325 if (IsContextLost())
1326 return LOCAL_GL_NO_ERROR
;
1328 // Either no WebGL-side error, or it's already been cleared.
1329 // UnderlyingGL-side errors, now.
1331 MakeContextCurrent();
1332 GetAndFlushUnderlyingGLErrors();
1334 err
= GetAndClearError(&mUnderlyingGLError
);
1339 WebGLContext::GetProgramParameter(WebGLProgram
*prog
, GLenum pname
)
1341 if (IsContextLost())
1342 return JS::NullValue();
1344 if (!ValidateObjectAllowDeleted("getProgramParameter: program", prog
))
1345 return JS::NullValue();
1347 GLuint progname
= prog
->GLName();
1349 MakeContextCurrent();
1352 case LOCAL_GL_ATTACHED_SHADERS
:
1353 case LOCAL_GL_ACTIVE_UNIFORMS
:
1354 case LOCAL_GL_ACTIVE_ATTRIBUTES
:
1357 gl
->fGetProgramiv(progname
, pname
, &i
);
1358 return JS::Int32Value(i
);
1360 case LOCAL_GL_DELETE_STATUS
:
1361 return JS::BooleanValue(prog
->IsDeleteRequested());
1362 case LOCAL_GL_LINK_STATUS
:
1364 return JS::BooleanValue(prog
->LinkStatus());
1366 case LOCAL_GL_VALIDATE_STATUS
:
1370 // See comment in ValidateProgram below.
1371 if (gl
->WorkAroundDriverBugs())
1374 gl
->fGetProgramiv(progname
, pname
, &i
);
1376 gl
->fGetProgramiv(progname
, pname
, &i
);
1378 return JS::BooleanValue(bool(i
));
1383 ErrorInvalidEnumInfo("getProgramParameter: parameter", pname
);
1386 return JS::NullValue();
1390 WebGLContext::GetProgramInfoLog(WebGLProgram
*prog
, nsAString
& retval
)
1393 GetProgramInfoLog(prog
, s
);
1395 retval
.SetIsVoid(true);
1397 CopyASCIItoUTF16(s
, retval
);
1401 WebGLContext::GetProgramInfoLog(WebGLProgram
*prog
, nsACString
& retval
)
1403 if (IsContextLost())
1405 retval
.SetIsVoid(true);
1409 if (!ValidateObject("getProgramInfoLog: program", prog
)) {
1414 GLuint progname
= prog
->GLName();
1416 MakeContextCurrent();
1419 gl
->fGetProgramiv(progname
, LOCAL_GL_INFO_LOG_LENGTH
, &k
);
1421 // If GetProgramiv doesn't modify |k|,
1422 // it's because there was a GL error.
1423 // GetProgramInfoLog should return null on error. (Bug 746740)
1424 retval
.SetIsVoid(true);
1433 retval
.SetCapacity(k
);
1434 gl
->fGetProgramInfoLog(progname
, k
, &k
, (char*) retval
.BeginWriting());
1435 retval
.SetLength(k
);
1438 // here we have to support all pnames with both int and float params.
1439 // See this discussion:
1440 // https://www.khronos.org/webgl/public-mailing-list/archives/1008/msg00014.html
1441 void WebGLContext::TexParameter_base(GLenum target
, GLenum pname
,
1443 GLfloat
*floatParamPtr
)
1445 MOZ_ASSERT(intParamPtr
|| floatParamPtr
);
1447 if (IsContextLost())
1450 GLint intParam
= intParamPtr
? *intParamPtr
: GLint(*floatParamPtr
);
1451 GLfloat floatParam
= floatParamPtr
? *floatParamPtr
: GLfloat(*intParamPtr
);
1453 if (!ValidateTextureTargetEnum(target
, "texParameter: target"))
1456 WebGLTexture
*tex
= activeBoundTextureForTarget(target
);
1458 return ErrorInvalidOperation("texParameter: no texture is bound to this target");
1460 bool pnameAndParamAreIncompatible
= false;
1461 bool paramValueInvalid
= false;
1464 case LOCAL_GL_TEXTURE_MIN_FILTER
:
1466 case LOCAL_GL_NEAREST
:
1467 case LOCAL_GL_LINEAR
:
1468 case LOCAL_GL_NEAREST_MIPMAP_NEAREST
:
1469 case LOCAL_GL_LINEAR_MIPMAP_NEAREST
:
1470 case LOCAL_GL_NEAREST_MIPMAP_LINEAR
:
1471 case LOCAL_GL_LINEAR_MIPMAP_LINEAR
:
1472 tex
->SetMinFilter(intParam
);
1475 pnameAndParamAreIncompatible
= true;
1478 case LOCAL_GL_TEXTURE_MAG_FILTER
:
1480 case LOCAL_GL_NEAREST
:
1481 case LOCAL_GL_LINEAR
:
1482 tex
->SetMagFilter(intParam
);
1485 pnameAndParamAreIncompatible
= true;
1488 case LOCAL_GL_TEXTURE_WRAP_S
:
1490 case LOCAL_GL_CLAMP_TO_EDGE
:
1491 case LOCAL_GL_MIRRORED_REPEAT
:
1492 case LOCAL_GL_REPEAT
:
1493 tex
->SetWrapS(intParam
);
1496 pnameAndParamAreIncompatible
= true;
1499 case LOCAL_GL_TEXTURE_WRAP_T
:
1501 case LOCAL_GL_CLAMP_TO_EDGE
:
1502 case LOCAL_GL_MIRRORED_REPEAT
:
1503 case LOCAL_GL_REPEAT
:
1504 tex
->SetWrapT(intParam
);
1507 pnameAndParamAreIncompatible
= true;
1510 case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT
:
1511 if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic
)) {
1512 if (floatParamPtr
&& floatParam
< 1.f
)
1513 paramValueInvalid
= true;
1514 else if (intParamPtr
&& intParam
< 1)
1515 paramValueInvalid
= true;
1518 pnameAndParamAreIncompatible
= true;
1521 return ErrorInvalidEnumInfo("texParameter: pname", pname
);
1524 if (pnameAndParamAreIncompatible
) {
1526 return ErrorInvalidEnum("texParameteri: pname %x and param %x (decimal %d) are mutually incompatible",
1527 pname
, intParam
, intParam
);
1529 return ErrorInvalidEnum("texParameterf: pname %x and param %g are mutually incompatible",
1531 } else if (paramValueInvalid
) {
1533 return ErrorInvalidValue("texParameteri: pname %x and param %x (decimal %d) is invalid",
1534 pname
, intParam
, intParam
);
1536 return ErrorInvalidValue("texParameterf: pname %x and param %g is invalid",
1540 MakeContextCurrent();
1542 gl
->fTexParameteri(target
, pname
, intParam
);
1544 gl
->fTexParameterf(target
, pname
, floatParam
);
1548 WebGLContext::GetTexParameter(GLenum target
, GLenum pname
)
1550 if (IsContextLost())
1551 return JS::NullValue();
1553 MakeContextCurrent();
1555 if (!ValidateTextureTargetEnum(target
, "getTexParameter: target"))
1556 return JS::NullValue();
1558 if (!activeBoundTextureForTarget(target
)) {
1559 ErrorInvalidOperation("getTexParameter: no texture bound");
1560 return JS::NullValue();
1564 case LOCAL_GL_TEXTURE_MIN_FILTER
:
1565 case LOCAL_GL_TEXTURE_MAG_FILTER
:
1566 case LOCAL_GL_TEXTURE_WRAP_S
:
1567 case LOCAL_GL_TEXTURE_WRAP_T
:
1570 gl
->fGetTexParameteriv(target
, pname
, &i
);
1571 return JS::NumberValue(uint32_t(i
));
1573 case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT
:
1574 if (IsExtensionEnabled(WebGLExtensionID::EXT_texture_filter_anisotropic
)) {
1576 gl
->fGetTexParameterfv(target
, pname
, &f
);
1577 return JS::DoubleValue(f
);
1580 ErrorInvalidEnumInfo("getTexParameter: parameter", pname
);
1584 ErrorInvalidEnumInfo("getTexParameter: parameter", pname
);
1587 return JS::NullValue();
1591 WebGLContext::GetUniform(JSContext
* cx
, WebGLProgram
*prog
,
1592 WebGLUniformLocation
*location
)
1594 if (IsContextLost())
1595 return JS::NullValue();
1597 if (!ValidateObject("getUniform: program", prog
))
1598 return JS::NullValue();
1600 if (!ValidateObject("getUniform: location", location
))
1601 return JS::NullValue();
1603 if (location
->Program() != prog
) {
1604 ErrorInvalidValue("getUniform: this uniform location corresponds to another program");
1605 return JS::NullValue();
1608 if (location
->ProgramGeneration() != prog
->Generation()) {
1609 ErrorInvalidOperation("getUniform: this uniform location is obsolete since the program has been relinked");
1610 return JS::NullValue();
1613 GLuint progname
= prog
->GLName();
1615 MakeContextCurrent();
1618 GLint uniformNameMaxLength
= 0;
1619 gl
->fGetProgramiv(progname
, LOCAL_GL_ACTIVE_UNIFORMS
, &uniforms
);
1620 gl
->fGetProgramiv(progname
, LOCAL_GL_ACTIVE_UNIFORM_MAX_LENGTH
, &uniformNameMaxLength
);
1622 // we now need the type info to switch between fGetUniformfv and fGetUniformiv
1623 // the only way to get that is to iterate through all active uniforms by index until
1624 // one matches the given uniform location.
1625 GLenum uniformType
= 0;
1626 nsAutoArrayPtr
<GLchar
> uniformName(new GLchar
[uniformNameMaxLength
]);
1627 // this buffer has 16 more bytes to be able to store [index] at the end.
1628 nsAutoArrayPtr
<GLchar
> uniformNameBracketIndex(new GLchar
[uniformNameMaxLength
+ 16]);
1631 for (index
= 0; index
< uniforms
; ++index
) {
1634 gl
->fGetActiveUniform(progname
, index
, uniformNameMaxLength
, &length
,
1635 &size
, &uniformType
, uniformName
);
1636 if (gl
->fGetUniformLocation(progname
, uniformName
) == location
->Location())
1639 // now we handle the case of array uniforms. In that case, fGetActiveUniform returned as 'size'
1640 // the biggest index used plus one, so we need to loop over that. The 0 index has already been handled above,
1641 // so we can start at one. For each index, we construct the string uniformName + "[" + index + "]".
1643 bool found_it
= false;
1644 if (uniformName
[length
- 1] == ']') { // if uniformName ends in [0]
1645 // remove the [0] at the end
1647 uniformName
[length
] = 0;
1649 for (GLint arrayIndex
= 1; arrayIndex
< size
; arrayIndex
++) {
1650 sprintf(uniformNameBracketIndex
.get(), "%s[%d]", uniformName
.get(), arrayIndex
);
1651 if (gl
->fGetUniformLocation(progname
, uniformNameBracketIndex
) == location
->Location()) {
1656 if (found_it
) break;
1660 if (index
== uniforms
) {
1661 GenerateWarning("getUniform: internal error: hit an OpenGL driver bug");
1662 return JS::NullValue();
1667 if (!BaseTypeAndSizeFromUniformType(uniformType
, &baseType
, &unitSize
)) {
1668 GenerateWarning("getUniform: internal error: unknown uniform type 0x%x", uniformType
);
1669 return JS::NullValue();
1672 // this should never happen
1673 if (unitSize
> 16) {
1674 GenerateWarning("getUniform: internal error: unexpected uniform unit size %d", unitSize
);
1675 return JS::NullValue();
1678 if (baseType
== LOCAL_GL_FLOAT
) {
1679 GLfloat fv
[16] = { GLfloat(0) };
1680 gl
->fGetUniformfv(progname
, location
->Location(), fv
);
1681 if (unitSize
== 1) {
1682 return JS::DoubleValue(fv
[0]);
1684 JSObject
* obj
= Float32Array::Create(cx
, this, unitSize
, fv
);
1686 ErrorOutOfMemory("getUniform: out of memory");
1687 return JS::NullValue();
1689 return JS::ObjectOrNullValue(obj
);
1691 } else if (baseType
== LOCAL_GL_INT
) {
1692 GLint iv
[16] = { 0 };
1693 gl
->fGetUniformiv(progname
, location
->Location(), iv
);
1694 if (unitSize
== 1) {
1695 return JS::Int32Value(iv
[0]);
1697 JSObject
* obj
= Int32Array::Create(cx
, this, unitSize
, iv
);
1699 ErrorOutOfMemory("getUniform: out of memory");
1700 return JS::NullValue();
1702 return JS::ObjectOrNullValue(obj
);
1704 } else if (baseType
== LOCAL_GL_BOOL
) {
1705 GLint iv
[16] = { 0 };
1706 gl
->fGetUniformiv(progname
, location
->Location(), iv
);
1707 if (unitSize
== 1) {
1708 return JS::BooleanValue(iv
[0] ? true : false);
1711 for (int k
= 0; k
< unitSize
; k
++)
1713 JS::Rooted
<JS::Value
> val(cx
);
1714 // Be careful: we don't want to convert all of |uv|!
1715 if (!ToJSValue(cx
, uv
, unitSize
, &val
)) {
1716 ErrorOutOfMemory("getUniform: out of memory");
1717 return JS::NullValue();
1723 // Else preserving behavior, but I'm not sure this is correct per spec
1724 return JS::UndefinedValue();
1727 already_AddRefed
<WebGLUniformLocation
>
1728 WebGLContext::GetUniformLocation(WebGLProgram
*prog
, const nsAString
& name
)
1730 if (IsContextLost())
1733 if (!ValidateObject("getUniformLocation: program", prog
))
1736 if (!ValidateGLSLVariableName(name
, "getUniformLocation"))
1739 NS_LossyConvertUTF16toASCII
cname(name
);
1740 nsCString mappedName
;
1741 prog
->MapIdentifier(cname
, &mappedName
);
1743 GLuint progname
= prog
->GLName();
1744 MakeContextCurrent();
1745 GLint intlocation
= gl
->fGetUniformLocation(progname
, mappedName
.get());
1747 nsRefPtr
<WebGLUniformLocation
> loc
;
1748 if (intlocation
>= 0) {
1749 WebGLUniformInfo info
= prog
->GetUniformInfoForMappedIdentifier(mappedName
);
1750 loc
= new WebGLUniformLocation(this,
1755 return loc
.forget();
1759 WebGLContext::Hint(GLenum target
, GLenum mode
)
1761 if (IsContextLost())
1764 bool isValid
= false;
1767 case LOCAL_GL_GENERATE_MIPMAP_HINT
:
1770 case LOCAL_GL_FRAGMENT_SHADER_DERIVATIVE_HINT
:
1771 if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives
))
1777 return ErrorInvalidEnum("hint: invalid hint");
1779 MakeContextCurrent();
1780 gl
->fHint(target
, mode
);
1784 WebGLContext::IsFramebuffer(WebGLFramebuffer
*fb
)
1786 if (IsContextLost())
1789 return ValidateObjectAllowDeleted("isFramebuffer", fb
) &&
1791 fb
->HasEverBeenBound();
1795 WebGLContext::IsProgram(WebGLProgram
*prog
)
1797 if (IsContextLost())
1800 return ValidateObjectAllowDeleted("isProgram", prog
) && !prog
->IsDeleted();
1804 WebGLContext::IsRenderbuffer(WebGLRenderbuffer
*rb
)
1806 if (IsContextLost())
1809 return ValidateObjectAllowDeleted("isRenderBuffer", rb
) &&
1811 rb
->HasEverBeenBound();
1815 WebGLContext::IsShader(WebGLShader
*shader
)
1817 if (IsContextLost())
1820 return ValidateObjectAllowDeleted("isShader", shader
) &&
1821 !shader
->IsDeleted();
1825 WebGLContext::IsTexture(WebGLTexture
*tex
)
1827 if (IsContextLost())
1830 return ValidateObjectAllowDeleted("isTexture", tex
) &&
1831 !tex
->IsDeleted() &&
1832 tex
->HasEverBeenBound();
1835 // Try to bind an attribute that is an array to location 0:
1836 bool WebGLContext::BindArrayAttribToLocation0(WebGLProgram
*program
)
1838 if (mBoundVertexArray
->IsAttribArrayEnabled(0)) {
1842 GLint leastArrayLocation
= -1;
1844 std::map
<GLint
, nsCString
>::iterator itr
;
1845 for (itr
= program
->mActiveAttribMap
.begin();
1846 itr
!= program
->mActiveAttribMap
.end();
1848 int32_t index
= itr
->first
;
1849 if (mBoundVertexArray
->IsAttribArrayEnabled(index
) &&
1850 index
< leastArrayLocation
)
1852 leastArrayLocation
= index
;
1856 if (leastArrayLocation
> 0) {
1857 nsCString
& attrName
= program
->mActiveAttribMap
.find(leastArrayLocation
)->second
;
1858 const char* attrNameCStr
= attrName
.get();
1859 gl
->fBindAttribLocation(program
->GLName(), 0, attrNameCStr
);
1866 WebGLContext::LinkProgram(WebGLProgram
*program
)
1868 if (IsContextLost())
1871 if (!ValidateObject("linkProgram", program
))
1874 InvalidateBufferFetching(); // we do it early in this function
1875 // as some of the validation below changes program state
1877 GLuint progname
= program
->GLName();
1879 if (!program
->NextGeneration()) {
1884 if (!program
->HasBothShaderTypesAttached()) {
1885 GenerateWarning("linkProgram: this program doesn't have both a vertex shader"
1886 " and a fragment shader");
1887 program
->SetLinkStatus(false);
1892 // Mesa can't handle more than 16 samplers per program, counting each array entry.
1893 if (gl
->WorkAroundDriverBugs() &&
1895 program
->UpperBoundNumSamplerUniforms() > 16)
1897 GenerateWarning("Programs with more than 16 samplers are disallowed on Mesa drivers " "to avoid a Mesa crasher.");
1898 program
->SetLinkStatus(false);
1902 bool updateInfoSucceeded
= false;
1904 if (gl
->WorkAroundDriverBugs() &&
1905 program
->HasBadShaderAttached())
1907 // it's a common driver bug, caught by program-test.html, that linkProgram doesn't
1908 // correctly preserve the state of an in-use program that has been attached a bad shader
1912 MakeContextCurrent();
1913 gl
->fLinkProgram(progname
);
1914 gl
->fGetProgramiv(progname
, LOCAL_GL_LINK_STATUS
, &ok
);
1917 updateInfoSucceeded
= program
->UpdateInfo();
1918 program
->SetLinkStatus(updateInfoSucceeded
);
1920 if (BindArrayAttribToLocation0(program
)) {
1921 GenerateWarning("linkProgram: relinking program to make attrib0 an "
1923 gl
->fLinkProgram(progname
);
1924 gl
->fGetProgramiv(progname
, LOCAL_GL_LINK_STATUS
, &ok
);
1926 updateInfoSucceeded
= program
->UpdateInfo();
1927 program
->SetLinkStatus(updateInfoSucceeded
);
1935 if (gl
->WorkAroundDriverBugs() &&
1936 updateInfoSucceeded
&&
1937 gl
->Vendor() == gl::GLVendor::NVIDIA
)
1939 if (program
== mCurrentProgram
)
1940 gl
->fUseProgram(progname
);
1943 program
->SetLinkStatus(false);
1945 if (ShouldGenerateWarnings()) {
1947 // report shader/program infoLogs as warnings.
1948 // note that shader compilation errors can be deferred to linkProgram,
1949 // which is why we can't do anything in compileShader. In practice we could
1950 // report in compileShader the translation errors generated by ANGLE,
1951 // but it seems saner to keep a single way of obtaining shader infologs.
1955 bool alreadyReportedShaderInfoLog
= false;
1957 for (size_t i
= 0; i
< program
->AttachedShaders().Length(); i
++) {
1959 WebGLShader
* shader
= program
->AttachedShaders()[i
];
1961 if (shader
->CompileStatus())
1964 const char *shaderTypeName
= nullptr;
1965 if (shader
->ShaderType() == LOCAL_GL_VERTEX_SHADER
) {
1966 shaderTypeName
= "vertex";
1967 } else if (shader
->ShaderType() == LOCAL_GL_FRAGMENT_SHADER
) {
1968 shaderTypeName
= "fragment";
1970 // should have been validated earlier
1972 shaderTypeName
= "<unknown>";
1975 GetShaderInfoLog(shader
, log
);
1977 GenerateWarning("linkProgram: a %s shader used in this program failed to "
1978 "compile, with this log:\n%s\n",
1981 alreadyReportedShaderInfoLog
= true;
1984 if (!alreadyReportedShaderInfoLog
) {
1985 GetProgramInfoLog(program
, log
);
1986 if (!log
.IsEmpty()) {
1987 GenerateWarning("linkProgram failed, with this log:\n%s\n",
1996 WebGLContext::PixelStorei(GLenum pname
, GLint param
)
1998 if (IsContextLost())
2002 case UNPACK_FLIP_Y_WEBGL
:
2003 mPixelStoreFlipY
= (param
!= 0);
2005 case UNPACK_PREMULTIPLY_ALPHA_WEBGL
:
2006 mPixelStorePremultiplyAlpha
= (param
!= 0);
2008 case UNPACK_COLORSPACE_CONVERSION_WEBGL
:
2009 if (param
== LOCAL_GL_NONE
|| param
== BROWSER_DEFAULT_WEBGL
)
2010 mPixelStoreColorspaceConversion
= param
;
2012 return ErrorInvalidEnumInfo("pixelStorei: colorspace conversion parameter", param
);
2014 case LOCAL_GL_PACK_ALIGNMENT
:
2015 case LOCAL_GL_UNPACK_ALIGNMENT
:
2020 return ErrorInvalidValue("pixelStorei: invalid pack/unpack alignment value");
2021 if (pname
== LOCAL_GL_PACK_ALIGNMENT
)
2022 mPixelStorePackAlignment
= param
;
2023 else if (pname
== LOCAL_GL_UNPACK_ALIGNMENT
)
2024 mPixelStoreUnpackAlignment
= param
;
2025 MakeContextCurrent();
2026 gl
->fPixelStorei(pname
, param
);
2029 return ErrorInvalidEnumInfo("pixelStorei: parameter", pname
);
2034 WebGLContext::ReadPixels(GLint x
, GLint y
, GLsizei width
,
2035 GLsizei height
, GLenum format
,
2036 GLenum type
, const Nullable
<ArrayBufferView
> &pixels
,
2039 if (IsContextLost())
2042 if (mCanvasElement
->IsWriteOnly() && !nsContentUtils::IsCallerChrome()) {
2043 GenerateWarning("readPixels: Not allowed");
2044 return rv
.Throw(NS_ERROR_DOM_SECURITY_ERR
);
2047 if (width
< 0 || height
< 0)
2048 return ErrorInvalidValue("readPixels: negative size passed");
2050 if (pixels
.IsNull())
2051 return ErrorInvalidValue("readPixels: null destination buffer");
2053 const WebGLRectangleObject
* framebufferRect
= CurValidFBRectObject();
2054 GLsizei framebufferWidth
= framebufferRect
? framebufferRect
->Width() : 0;
2055 GLsizei framebufferHeight
= framebufferRect
? framebufferRect
->Height() : 0;
2057 uint32_t channels
= 0;
2059 // Check the format param
2061 case LOCAL_GL_ALPHA
:
2071 return ErrorInvalidEnum("readPixels: Bad format");
2074 uint32_t bytesPerPixel
= 0;
2075 int requiredDataType
= 0;
2077 // Check the type param
2078 bool isReadTypeValid
= false;
2079 bool isReadTypeFloat
= false;
2081 case LOCAL_GL_UNSIGNED_BYTE
:
2082 isReadTypeValid
= true;
2083 bytesPerPixel
= 1*channels
;
2084 requiredDataType
= js::Scalar::Uint8
;
2086 case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4
:
2087 case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1
:
2088 case LOCAL_GL_UNSIGNED_SHORT_5_6_5
:
2089 isReadTypeValid
= true;
2091 requiredDataType
= js::Scalar::Uint16
;
2093 case LOCAL_GL_FLOAT
:
2094 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float
) ||
2095 IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float
))
2097 isReadTypeValid
= true;
2098 isReadTypeFloat
= true;
2099 bytesPerPixel
= 4*channels
;
2100 requiredDataType
= js::Scalar::Float32
;
2104 if (!isReadTypeValid
)
2105 return ErrorInvalidEnum("readPixels: Bad type", type
);
2107 const ArrayBufferView
& pixbuf
= pixels
.Value();
2108 int dataType
= JS_GetArrayBufferViewType(pixbuf
.Obj());
2110 // Check the pixels param type
2111 if (dataType
!= requiredDataType
)
2112 return ErrorInvalidOperation("readPixels: Mismatched type/pixels types");
2114 // Check the pixels param size
2115 CheckedUint32 checked_neededByteLength
=
2116 GetImageSize(height
, width
, bytesPerPixel
, mPixelStorePackAlignment
);
2118 CheckedUint32 checked_plainRowSize
= CheckedUint32(width
) * bytesPerPixel
;
2120 CheckedUint32 checked_alignedRowSize
=
2121 RoundedToNextMultipleOf(checked_plainRowSize
, mPixelStorePackAlignment
);
2123 if (!checked_neededByteLength
.isValid())
2124 return ErrorInvalidOperation("readPixels: integer overflow computing the needed buffer size");
2126 // Compute length and data. Don't reenter after this point, lest the
2127 // precomputed go out of sync with the instant length/data.
2128 pixbuf
.ComputeLengthAndData();
2130 uint32_t dataByteLen
= pixbuf
.Length();
2131 if (checked_neededByteLength
.value() > dataByteLen
)
2132 return ErrorInvalidOperation("readPixels: buffer too small");
2134 void* data
= pixbuf
.Data();
2136 ErrorOutOfMemory("readPixels: buffer storage is null. Did we run out of memory?");
2137 return rv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
2140 bool isSourceTypeFloat
= false;
2141 if (mBoundFramebuffer
&&
2142 mBoundFramebuffer
->ColorAttachmentCount() &&
2143 mBoundFramebuffer
->ColorAttachment(0).IsDefined())
2145 isSourceTypeFloat
= mBoundFramebuffer
->ColorAttachment(0).IsReadableFloat();
2148 if (isReadTypeFloat
!= isSourceTypeFloat
)
2149 return ErrorInvalidOperation("readPixels: Invalid type floatness");
2151 // Check the format and type params to assure they are an acceptable pair (as per spec)
2152 MakeContextCurrent();
2154 if (mBoundFramebuffer
) {
2155 // prevent readback of arbitrary video memory through uninitialized renderbuffers!
2156 if (!mBoundFramebuffer
->CheckAndInitializeAttachments())
2157 return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
2159 GLenum readPlaneBits
= LOCAL_GL_COLOR_BUFFER_BIT
;
2160 if (!mBoundFramebuffer
->HasCompletePlanes(readPlaneBits
)) {
2161 return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
2162 " correct color/depth/stencil type.");
2165 ClearBackbufferIfNeeded();
2168 bool isFormatAndTypeValid
= false;
2170 // OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid
2171 // combination for glReadPixels().
2172 if (gl
->IsSupported(gl::GLFeature::ES2_compatibility
)) {
2173 GLenum implType
= 0;
2174 GLenum implFormat
= 0;
2176 gl
->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE
,
2177 reinterpret_cast<GLint
*>(&implType
));
2178 gl
->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT
,
2179 reinterpret_cast<GLint
*>(&implFormat
));
2181 if (type
== implType
&& format
== implFormat
) {
2182 isFormatAndTypeValid
= true;
2187 case LOCAL_GL_RGBA
: {
2189 case LOCAL_GL_UNSIGNED_BYTE
:
2190 case LOCAL_GL_FLOAT
:
2191 isFormatAndTypeValid
= true;
2198 if (!isFormatAndTypeValid
) {
2199 return ErrorInvalidOperation("readPixels: Invalid format/type pair");
2202 // Now that the errors are out of the way, on to actually reading
2204 // If we won't be reading any pixels anyways, just skip the actual reading
2205 if (width
== 0 || height
== 0)
2206 return DummyFramebufferOperation("readPixels");
2208 if (CanvasUtils::CheckSaneSubrectSize(x
, y
, width
, height
, framebufferWidth
, framebufferHeight
)) {
2209 // the easy case: we're not reading out-of-range pixels
2210 gl
->fReadPixels(x
, y
, width
, height
, format
, type
, data
);
2212 // the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
2213 // of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
2214 // to do that for us, because passing out of range parameters to a buggy OpenGL implementation
2215 // could conceivably allow to read memory we shouldn't be allowed to read. So we manually initialize
2216 // the buffer to zero and compute the parameters to pass to OpenGL. We have to use an intermediate buffer
2217 // to accomodate the potentially different strides (widths).
2219 // Zero the whole pixel dest area in the destination buffer.
2220 memset(data
, 0, checked_neededByteLength
.value());
2222 if ( x
>= framebufferWidth
2224 || y
>= framebufferHeight
2227 // we are completely outside of range, can exit now with buffer filled with zeros
2228 return DummyFramebufferOperation("readPixels");
2231 // compute the parameters of the subrect we're actually going to call glReadPixels on
2232 GLint subrect_x
= std::max(x
, 0);
2233 GLint subrect_end_x
= std::min(x
+width
, framebufferWidth
);
2234 GLsizei subrect_width
= subrect_end_x
- subrect_x
;
2236 GLint subrect_y
= std::max(y
, 0);
2237 GLint subrect_end_y
= std::min(y
+height
, framebufferHeight
);
2238 GLsizei subrect_height
= subrect_end_y
- subrect_y
;
2240 if (subrect_width
< 0 || subrect_height
< 0 ||
2241 subrect_width
> width
|| subrect_height
> height
)
2242 return ErrorInvalidOperation("readPixels: integer overflow computing clipped rect size");
2244 // now we know that subrect_width is in the [0..width] interval, and same for heights.
2246 // now, same computation as above to find the size of the intermediate buffer to allocate for the subrect
2247 // no need to check again for integer overflow here, since we already know the sizes aren't greater than before
2248 uint32_t subrect_plainRowSize
= subrect_width
* bytesPerPixel
;
2249 // There are checks above to ensure that this doesn't overflow.
2250 uint32_t subrect_alignedRowSize
=
2251 RoundedToNextMultipleOf(subrect_plainRowSize
, mPixelStorePackAlignment
).value();
2252 uint32_t subrect_byteLength
= (subrect_height
-1)*subrect_alignedRowSize
+ subrect_plainRowSize
;
2254 // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer
2255 UniquePtr
<GLubyte
> subrect_data(new ((fallible_t())) GLubyte
[subrect_byteLength
]);
2257 return ErrorOutOfMemory("readPixels: subrect_data");
2259 gl
->fReadPixels(subrect_x
, subrect_y
, subrect_width
, subrect_height
,
2260 format
, type
, subrect_data
.get());
2262 // notice that this for loop terminates because we already checked that subrect_height is at most height
2263 for (GLint y_inside_subrect
= 0; y_inside_subrect
< subrect_height
; ++y_inside_subrect
) {
2264 GLint subrect_x_in_dest_buffer
= subrect_x
- x
;
2265 GLint subrect_y_in_dest_buffer
= subrect_y
- y
;
2266 memcpy(static_cast<GLubyte
*>(data
)
2267 + checked_alignedRowSize
.value() * (subrect_y_in_dest_buffer
+ y_inside_subrect
)
2268 + bytesPerPixel
* subrect_x_in_dest_buffer
, // destination
2269 subrect_data
.get() + subrect_alignedRowSize
* y_inside_subrect
, // source
2270 subrect_plainRowSize
); // size
2274 // if we're reading alpha, we may need to do fixup. Note that we don't allow
2275 // GL_ALPHA to readpixels currently, but we had the code written for it already.
2276 if (format
== LOCAL_GL_ALPHA
||
2277 format
== LOCAL_GL_RGBA
)
2279 bool needAlphaFixup
;
2280 if (mBoundFramebuffer
) {
2281 needAlphaFixup
= !mBoundFramebuffer
->ColorAttachment(0).HasAlpha();
2283 needAlphaFixup
= gl
->GetPixelFormat().alpha
== 0;
2286 if (needAlphaFixup
) {
2287 if (format
== LOCAL_GL_ALPHA
&& type
== LOCAL_GL_UNSIGNED_BYTE
) {
2288 // this is easy; it's an 0xff memset per row
2289 uint8_t *row
= static_cast<uint8_t*>(data
);
2290 for (GLint j
= 0; j
< height
; ++j
) {
2291 memset(row
, 0xff, checked_plainRowSize
.value());
2292 row
+= checked_alignedRowSize
.value();
2294 } else if (format
== LOCAL_GL_RGBA
&& type
== LOCAL_GL_UNSIGNED_BYTE
) {
2295 // this is harder, we need to just set the alpha byte here
2296 uint8_t *row
= static_cast<uint8_t*>(data
);
2297 for (GLint j
= 0; j
< height
; ++j
) {
2298 uint8_t *rowp
= row
;
2299 #if MOZ_LITTLE_ENDIAN
2300 // offset to get the alpha byte; we're always going to
2304 uint8_t *endrowp
= rowp
+ 4 * width
;
2305 while (rowp
!= endrowp
) {
2310 row
+= checked_alignedRowSize
.value();
2312 } else if (format
== LOCAL_GL_RGBA
&& type
== LOCAL_GL_FLOAT
) {
2313 float* row
= static_cast<float*>(data
);
2315 for (GLint j
= 0; j
< height
; ++j
) {
2316 float* pAlpha
= row
+ 3;
2317 float* pAlphaEnd
= pAlpha
+ 4*width
;
2319 while (pAlpha
!= pAlphaEnd
) {
2324 row
+= checked_alignedRowSize
.value();
2327 NS_WARNING("Unhandled case, how'd we get here?");
2328 return rv
.Throw(NS_ERROR_FAILURE
);
2335 WebGLContext::RenderbufferStorage(GLenum target
, GLenum internalformat
, GLsizei width
, GLsizei height
)
2337 if (IsContextLost())
2340 if (!mBoundRenderbuffer
)
2341 return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
2343 if (target
!= LOCAL_GL_RENDERBUFFER
)
2344 return ErrorInvalidEnumInfo("renderbufferStorage: target", target
);
2346 if (width
< 0 || height
< 0)
2347 return ErrorInvalidValue("renderbufferStorage: width and height must be >= 0");
2349 if (width
> mGLMaxRenderbufferSize
|| height
> mGLMaxRenderbufferSize
)
2350 return ErrorInvalidValue("renderbufferStorage: width or height exceeds maximum renderbuffer size");
2352 // certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
2353 GLenum internalformatForGL
= internalformat
;
2355 switch (internalformat
) {
2356 case LOCAL_GL_RGBA4
:
2357 case LOCAL_GL_RGB5_A1
:
2358 // 16-bit RGBA formats are not supported on desktop GL
2359 if (!gl
->IsGLES()) internalformatForGL
= LOCAL_GL_RGBA8
;
2361 case LOCAL_GL_RGB565
:
2362 // the RGB565 format is not supported on desktop GL
2363 if (!gl
->IsGLES()) internalformatForGL
= LOCAL_GL_RGB8
;
2365 case LOCAL_GL_DEPTH_COMPONENT16
:
2366 if (!gl
->IsGLES() || gl
->IsExtensionSupported(gl::GLContext::OES_depth24
))
2367 internalformatForGL
= LOCAL_GL_DEPTH_COMPONENT24
;
2368 else if (gl
->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil
))
2369 internalformatForGL
= LOCAL_GL_DEPTH24_STENCIL8
;
2371 case LOCAL_GL_STENCIL_INDEX8
:
2373 case LOCAL_GL_DEPTH_STENCIL
:
2374 // We emulate this in WebGLRenderbuffer if we don't have the requisite extension.
2375 internalformatForGL
= LOCAL_GL_DEPTH24_STENCIL8
;
2377 case LOCAL_GL_SRGB8_ALPHA8_EXT
:
2379 case LOCAL_GL_RGB16F
:
2380 case LOCAL_GL_RGBA16F
: {
2381 bool hasExtensions
= IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float
) &&
2382 IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float
);
2384 return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", target
);
2387 case LOCAL_GL_RGB32F
:
2388 case LOCAL_GL_RGBA32F
: {
2389 bool hasExtensions
= IsExtensionEnabled(WebGLExtensionID::OES_texture_float
) &&
2390 IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float
);
2392 return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", target
);
2396 return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat
);
2399 MakeContextCurrent();
2401 bool sizeChanges
= width
!= mBoundRenderbuffer
->Width() ||
2402 height
!= mBoundRenderbuffer
->Height() ||
2403 internalformat
!= mBoundRenderbuffer
->InternalFormat();
2405 // Invalidate framebuffer status cache
2406 mBoundRenderbuffer
->NotifyFBsStatusChanged();
2407 GetAndFlushUnderlyingGLErrors();
2408 mBoundRenderbuffer
->RenderbufferStorage(internalformatForGL
, width
, height
);
2409 GLenum error
= GetAndFlushUnderlyingGLErrors();
2411 GenerateWarning("renderbufferStorage generated error %s", ErrorName(error
));
2415 mBoundRenderbuffer
->RenderbufferStorage(internalformatForGL
, width
, height
);
2418 mBoundRenderbuffer
->SetInternalFormat(internalformat
);
2419 mBoundRenderbuffer
->SetInternalFormatForGL(internalformatForGL
);
2420 mBoundRenderbuffer
->setDimensions(width
, height
);
2421 mBoundRenderbuffer
->SetImageDataStatus(WebGLImageDataStatus::UninitializedImageData
);
2425 WebGLContext::Scissor(GLint x
, GLint y
, GLsizei width
, GLsizei height
)
2427 if (IsContextLost())
2430 if (width
< 0 || height
< 0)
2431 return ErrorInvalidValue("scissor: negative size");
2433 MakeContextCurrent();
2434 gl
->fScissor(x
, y
, width
, height
);
2438 WebGLContext::StencilFunc(GLenum func
, GLint ref
, GLuint mask
)
2440 if (IsContextLost())
2443 if (!ValidateComparisonEnum(func
, "stencilFunc: func"))
2446 mStencilRefFront
= ref
;
2447 mStencilRefBack
= ref
;
2448 mStencilValueMaskFront
= mask
;
2449 mStencilValueMaskBack
= mask
;
2451 MakeContextCurrent();
2452 gl
->fStencilFunc(func
, ref
, mask
);
2456 WebGLContext::StencilFuncSeparate(GLenum face
, GLenum func
, GLint ref
, GLuint mask
)
2458 if (IsContextLost())
2461 if (!ValidateFaceEnum(face
, "stencilFuncSeparate: face") ||
2462 !ValidateComparisonEnum(func
, "stencilFuncSeparate: func"))
2466 case LOCAL_GL_FRONT_AND_BACK
:
2467 mStencilRefFront
= ref
;
2468 mStencilRefBack
= ref
;
2469 mStencilValueMaskFront
= mask
;
2470 mStencilValueMaskBack
= mask
;
2472 case LOCAL_GL_FRONT
:
2473 mStencilRefFront
= ref
;
2474 mStencilValueMaskFront
= mask
;
2477 mStencilRefBack
= ref
;
2478 mStencilValueMaskBack
= mask
;
2482 MakeContextCurrent();
2483 gl
->fStencilFuncSeparate(face
, func
, ref
, mask
);
2487 WebGLContext::StencilOp(GLenum sfail
, GLenum dpfail
, GLenum dppass
)
2489 if (IsContextLost())
2492 if (!ValidateStencilOpEnum(sfail
, "stencilOp: sfail") ||
2493 !ValidateStencilOpEnum(dpfail
, "stencilOp: dpfail") ||
2494 !ValidateStencilOpEnum(dppass
, "stencilOp: dppass"))
2497 MakeContextCurrent();
2498 gl
->fStencilOp(sfail
, dpfail
, dppass
);
2502 WebGLContext::StencilOpSeparate(GLenum face
, GLenum sfail
, GLenum dpfail
, GLenum dppass
)
2504 if (IsContextLost())
2507 if (!ValidateFaceEnum(face
, "stencilOpSeparate: face") ||
2508 !ValidateStencilOpEnum(sfail
, "stencilOpSeparate: sfail") ||
2509 !ValidateStencilOpEnum(dpfail
, "stencilOpSeparate: dpfail") ||
2510 !ValidateStencilOpEnum(dppass
, "stencilOpSeparate: dppass"))
2513 MakeContextCurrent();
2514 gl
->fStencilOpSeparate(face
, sfail
, dpfail
, dppass
);
2518 WebGLContext::SurfaceFromElementResultToImageSurface(nsLayoutUtils::SurfaceFromElementResult
& res
,
2519 RefPtr
<DataSourceSurface
>& imageOut
, WebGLTexelFormat
*format
)
2521 *format
= WebGLTexelFormat::None
;
2523 if (!res
.mSourceSurface
)
2525 RefPtr
<DataSourceSurface
> data
= res
.mSourceSurface
->GetDataSurface();
2527 // SurfaceFromElement lied!
2531 if (!mPixelStorePremultiplyAlpha
&& res
.mIsPremultiplied
) {
2532 switch (data
->GetFormat()) {
2533 case SurfaceFormat::B8G8R8X8
:
2534 // No alpha, so de-facto premult'd.
2536 case SurfaceFormat::B8G8R8A8
:
2537 data
= gfxUtils::CreateUnpremultipliedDataSurface(data
);
2540 MOZ_ASSERT(false, "Format unsupported.");
2545 // We disallow loading cross-domain images and videos that have not been validated
2546 // with CORS as WebGL textures. The reason for doing that is that timing
2547 // attacks on WebGL shaders are able to retrieve approximations of the
2548 // pixel values in WebGL textures; see bug 655987.
2550 // To prevent a loophole where a Canvas2D would be used as a proxy to load
2551 // cross-domain textures, we also disallow loading textures from write-only
2554 // part 1: check that the DOM element is same-origin, or has otherwise been
2555 // validated for cross-domain use.
2556 if (!res
.mCORSUsed
) {
2558 nsresult rv
= mCanvasElement
->NodePrincipal()->Subsumes(res
.mPrincipal
, &subsumes
);
2559 if (NS_FAILED(rv
) || !subsumes
) {
2560 GenerateWarning("It is forbidden to load a WebGL texture from a cross-domain element that has not been validated with CORS. "
2561 "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
2562 return NS_ERROR_DOM_SECURITY_ERR
;
2566 // part 2: if the DOM element is write-only, it might contain
2567 // cross-domain image data.
2568 if (res
.mIsWriteOnly
) {
2569 GenerateWarning("The canvas used as source for texImage2D here is tainted (write-only). It is forbidden "
2570 "to load a WebGL texture from a tainted canvas. A Canvas becomes tainted for example "
2571 "when a cross-domain image is drawn on it. "
2572 "See https://developer.mozilla.org/en/WebGL/Cross-Domain_Textures");
2573 return NS_ERROR_DOM_SECURITY_ERR
;
2576 // End of security checks, now we should be safe regarding cross-domain images
2577 // Notice that there is never a need to mark the WebGL canvas as write-only, since we reject write-only/cross-domain
2578 // texture sources in the first place.
2580 switch (data
->GetFormat()) {
2581 case SurfaceFormat::B8G8R8A8
:
2582 *format
= WebGLTexelFormat::BGRA8
; // careful, our ARGB means BGRA
2584 case SurfaceFormat::B8G8R8X8
:
2585 *format
= WebGLTexelFormat::BGRX8
; // careful, our RGB24 is not tightly packed. Whence BGRX8.
2587 case SurfaceFormat::A8
:
2588 *format
= WebGLTexelFormat::A8
;
2590 case SurfaceFormat::R5G6B5
:
2591 *format
= WebGLTexelFormat::RGB565
;
2594 NS_ASSERTION(false, "Unsupported image format. Unimplemented.");
2595 return NS_ERROR_NOT_IMPLEMENTED
;
2606 WebGLContext::Uniform1i(WebGLUniformLocation
*location_object
, GLint a1
)
2609 if (!ValidateUniformSetter("Uniform1i", location_object
, location
))
2612 // Only uniform1i can take sampler settings.
2613 if (!ValidateSamplerUniformSetter("Uniform1i", location_object
, a1
))
2616 MakeContextCurrent();
2617 gl
->fUniform1i(location
, a1
);
2621 WebGLContext::Uniform2i(WebGLUniformLocation
*location_object
, GLint a1
,
2625 if (!ValidateUniformSetter("Uniform2i", location_object
, location
))
2628 MakeContextCurrent();
2629 gl
->fUniform2i(location
, a1
, a2
);
2633 WebGLContext::Uniform3i(WebGLUniformLocation
*location_object
, GLint a1
,
2637 if (!ValidateUniformSetter("Uniform3i", location_object
, location
))
2640 MakeContextCurrent();
2641 gl
->fUniform3i(location
, a1
, a2
, a3
);
2645 WebGLContext::Uniform4i(WebGLUniformLocation
*location_object
, GLint a1
,
2646 GLint a2
, GLint a3
, GLint a4
)
2649 if (!ValidateUniformSetter("Uniform4i", location_object
, location
))
2652 MakeContextCurrent();
2653 gl
->fUniform4i(location
, a1
, a2
, a3
, a4
);
2657 WebGLContext::Uniform1f(WebGLUniformLocation
*location_object
, GLfloat a1
)
2660 if (!ValidateUniformSetter("Uniform1f", location_object
, location
))
2662 MakeContextCurrent();
2663 gl
->fUniform1f(location
, a1
);
2667 WebGLContext::Uniform2f(WebGLUniformLocation
*location_object
, GLfloat a1
,
2671 if (!ValidateUniformSetter("Uniform2f", location_object
, location
))
2673 MakeContextCurrent();
2674 gl
->fUniform2f(location
, a1
, a2
);
2678 WebGLContext::Uniform3f(WebGLUniformLocation
*location_object
, GLfloat a1
,
2679 GLfloat a2
, GLfloat a3
)
2682 if (!ValidateUniformSetter("Uniform3f", location_object
, location
))
2684 MakeContextCurrent();
2685 gl
->fUniform3f(location
, a1
, a2
, a3
);
2689 WebGLContext::Uniform4f(WebGLUniformLocation
*location_object
, GLfloat a1
,
2690 GLfloat a2
, GLfloat a3
, GLfloat a4
)
2693 if (!ValidateUniformSetter("Uniform4f", location_object
, location
))
2695 MakeContextCurrent();
2696 gl
->fUniform4f(location
, a1
, a2
, a3
, a4
);
2700 WebGLContext::Uniform1iv_base(WebGLUniformLocation
*location_object
,
2701 uint32_t arrayLength
, const GLint
* data
)
2703 uint32_t numElementsToUpload
;
2705 if (!ValidateUniformArraySetter("Uniform1iv", 1, location_object
, location
,
2706 numElementsToUpload
, arrayLength
)) {
2710 if (!ValidateSamplerUniformSetter("Uniform1iv", location_object
, data
[0]))
2713 MakeContextCurrent();
2714 gl
->fUniform1iv(location
, numElementsToUpload
, data
);
2718 WebGLContext::Uniform2iv_base(WebGLUniformLocation
*location_object
,
2719 uint32_t arrayLength
, const GLint
* data
)
2721 uint32_t numElementsToUpload
;
2723 if (!ValidateUniformArraySetter("Uniform2iv", 2, location_object
, location
,
2724 numElementsToUpload
, arrayLength
)) {
2728 if (!ValidateSamplerUniformSetter("Uniform2iv", location_object
, data
[0]) ||
2729 !ValidateSamplerUniformSetter("Uniform2iv", location_object
, data
[1]))
2734 MakeContextCurrent();
2735 gl
->fUniform2iv(location
, numElementsToUpload
, data
);
2739 WebGLContext::Uniform3iv_base(WebGLUniformLocation
*location_object
,
2740 uint32_t arrayLength
, const GLint
* data
)
2742 uint32_t numElementsToUpload
;
2744 if (!ValidateUniformArraySetter("Uniform3iv", 3, location_object
, location
,
2745 numElementsToUpload
, arrayLength
)) {
2749 if (!ValidateSamplerUniformSetter("Uniform3iv", location_object
, data
[0]) ||
2750 !ValidateSamplerUniformSetter("Uniform3iv", location_object
, data
[1]) ||
2751 !ValidateSamplerUniformSetter("Uniform3iv", location_object
, data
[2]))
2756 MakeContextCurrent();
2757 gl
->fUniform3iv(location
, numElementsToUpload
, data
);
2761 WebGLContext::Uniform4iv_base(WebGLUniformLocation
*location_object
,
2762 uint32_t arrayLength
, const GLint
* data
)
2764 uint32_t numElementsToUpload
;
2766 if (!ValidateUniformArraySetter("Uniform4iv", 4, location_object
, location
,
2767 numElementsToUpload
, arrayLength
)) {
2771 if (!ValidateSamplerUniformSetter("Uniform4iv", location_object
, data
[0]) ||
2772 !ValidateSamplerUniformSetter("Uniform4iv", location_object
, data
[1]) ||
2773 !ValidateSamplerUniformSetter("Uniform4iv", location_object
, data
[2]) ||
2774 !ValidateSamplerUniformSetter("Uniform4iv", location_object
, data
[3]))
2779 MakeContextCurrent();
2780 gl
->fUniform4iv(location
, numElementsToUpload
, data
);
2784 WebGLContext::Uniform1fv_base(WebGLUniformLocation
*location_object
,
2785 uint32_t arrayLength
, const GLfloat
* data
)
2787 uint32_t numElementsToUpload
;
2789 if (!ValidateUniformArraySetter("Uniform1fv", 1, location_object
, location
,
2790 numElementsToUpload
, arrayLength
)) {
2793 MakeContextCurrent();
2794 gl
->fUniform1fv(location
, numElementsToUpload
, data
);
2798 WebGLContext::Uniform2fv_base(WebGLUniformLocation
*location_object
,
2799 uint32_t arrayLength
, const GLfloat
* data
)
2801 uint32_t numElementsToUpload
;
2803 if (!ValidateUniformArraySetter("Uniform2fv", 2, location_object
, location
,
2804 numElementsToUpload
, arrayLength
)) {
2807 MakeContextCurrent();
2808 gl
->fUniform2fv(location
, numElementsToUpload
, data
);
2812 WebGLContext::Uniform3fv_base(WebGLUniformLocation
*location_object
,
2813 uint32_t arrayLength
, const GLfloat
* data
)
2815 uint32_t numElementsToUpload
;
2817 if (!ValidateUniformArraySetter("Uniform3fv", 3, location_object
, location
,
2818 numElementsToUpload
, arrayLength
)) {
2821 MakeContextCurrent();
2822 gl
->fUniform3fv(location
, numElementsToUpload
, data
);
2826 WebGLContext::Uniform4fv_base(WebGLUniformLocation
*location_object
,
2827 uint32_t arrayLength
, const GLfloat
* data
)
2829 uint32_t numElementsToUpload
;
2831 if (!ValidateUniformArraySetter("Uniform4fv", 4, location_object
, location
,
2832 numElementsToUpload
, arrayLength
)) {
2835 MakeContextCurrent();
2836 gl
->fUniform4fv(location
, numElementsToUpload
, data
);
2840 WebGLContext::UniformMatrix2fv_base(WebGLUniformLocation
* location_object
,
2841 WebGLboolean aTranspose
, uint32_t arrayLength
,
2844 uint32_t numElementsToUpload
;
2846 if (!ValidateUniformMatrixArraySetter("UniformMatrix2fv", 2, location_object
, location
,
2847 numElementsToUpload
, arrayLength
, aTranspose
)) {
2850 MakeContextCurrent();
2851 gl
->fUniformMatrix2fv(location
, numElementsToUpload
, false, data
);
2855 WebGLContext::UniformMatrix3fv_base(WebGLUniformLocation
* location_object
,
2856 WebGLboolean aTranspose
, uint32_t arrayLength
,
2859 uint32_t numElementsToUpload
;
2861 if (!ValidateUniformMatrixArraySetter("UniformMatrix3fv", 3, location_object
, location
,
2862 numElementsToUpload
, arrayLength
, aTranspose
)) {
2865 MakeContextCurrent();
2866 gl
->fUniformMatrix3fv(location
, numElementsToUpload
, false, data
);
2870 WebGLContext::UniformMatrix4fv_base(WebGLUniformLocation
* location_object
,
2871 WebGLboolean aTranspose
, uint32_t arrayLength
,
2874 uint32_t numElementsToUpload
;
2876 if (!ValidateUniformMatrixArraySetter("UniformMatrix4fv", 4, location_object
, location
,
2877 numElementsToUpload
, arrayLength
, aTranspose
)) {
2880 MakeContextCurrent();
2881 gl
->fUniformMatrix4fv(location
, numElementsToUpload
, false, data
);
2885 WebGLContext::UseProgram(WebGLProgram
*prog
)
2887 if (IsContextLost())
2890 if (!ValidateObjectAllowNull("useProgram", prog
))
2893 MakeContextCurrent();
2895 InvalidateBufferFetching();
2897 GLuint progname
= prog
? prog
->GLName() : 0;
2899 if (prog
&& !prog
->LinkStatus())
2900 return ErrorInvalidOperation("useProgram: program was not linked successfully");
2902 gl
->fUseProgram(progname
);
2904 mCurrentProgram
= prog
;
2908 WebGLContext::ValidateProgram(WebGLProgram
*prog
)
2910 if (IsContextLost())
2913 if (!ValidateObject("validateProgram", prog
))
2916 MakeContextCurrent();
2919 // see bug 593867 for NVIDIA and bug 657201 for ATI. The latter is confirmed with Mac OS 10.6.7
2920 if (gl
->WorkAroundDriverBugs()) {
2921 GenerateWarning("validateProgram: implemented as a no-operation on Mac to work around crashes");
2926 GLuint progname
= prog
->GLName();
2927 gl
->fValidateProgram(progname
);
2930 already_AddRefed
<WebGLFramebuffer
>
2931 WebGLContext::CreateFramebuffer()
2933 if (IsContextLost())
2935 nsRefPtr
<WebGLFramebuffer
> globj
= new WebGLFramebuffer(this);
2936 return globj
.forget();
2939 already_AddRefed
<WebGLRenderbuffer
>
2940 WebGLContext::CreateRenderbuffer()
2942 if (IsContextLost())
2944 nsRefPtr
<WebGLRenderbuffer
> globj
= new WebGLRenderbuffer(this);
2945 return globj
.forget();
2949 WebGLContext::Viewport(GLint x
, GLint y
, GLsizei width
, GLsizei height
)
2951 if (IsContextLost())
2954 if (width
< 0 || height
< 0)
2955 return ErrorInvalidValue("viewport: negative size");
2957 MakeContextCurrent();
2958 gl
->fViewport(x
, y
, width
, height
);
2962 mViewportWidth
= width
;
2963 mViewportHeight
= height
;
2967 WebGLContext::CompileShader(WebGLShader
*shader
)
2969 if (IsContextLost())
2972 if (!ValidateObject("compileShader", shader
))
2975 GLuint shadername
= shader
->GLName();
2977 shader
->SetCompileStatus(false);
2979 // nothing to do if the validator is disabled
2980 if (!mShaderValidation
)
2983 // nothing to do if translation was already done
2984 if (!shader
->NeedsTranslation())
2987 MakeContextCurrent();
2989 ShShaderOutput targetShaderSourceLanguage
= gl
->IsGLES() ? SH_ESSL_OUTPUT
: SH_GLSL_OUTPUT
;
2991 ShHandle compiler
= 0;
2992 ShBuiltInResources resources
;
2994 memset(&resources
, 0, sizeof(ShBuiltInResources
));
2996 ShInitBuiltInResources(&resources
);
2998 resources
.MaxVertexAttribs
= mGLMaxVertexAttribs
;
2999 resources
.MaxVertexUniformVectors
= mGLMaxVertexUniformVectors
;
3000 resources
.MaxVaryingVectors
= mGLMaxVaryingVectors
;
3001 resources
.MaxVertexTextureImageUnits
= mGLMaxVertexTextureImageUnits
;
3002 resources
.MaxCombinedTextureImageUnits
= mGLMaxTextureUnits
;
3003 resources
.MaxTextureImageUnits
= mGLMaxTextureImageUnits
;
3004 resources
.MaxFragmentUniformVectors
= mGLMaxFragmentUniformVectors
;
3005 resources
.MaxDrawBuffers
= mGLMaxDrawBuffers
;
3007 if (IsExtensionEnabled(WebGLExtensionID::EXT_frag_depth
))
3008 resources
.EXT_frag_depth
= 1;
3010 if (IsExtensionEnabled(WebGLExtensionID::OES_standard_derivatives
))
3011 resources
.OES_standard_derivatives
= 1;
3013 if (IsExtensionEnabled(WebGLExtensionID::WEBGL_draw_buffers
))
3014 resources
.EXT_draw_buffers
= 1;
3016 if (IsExtensionEnabled(WebGLExtensionID::EXT_shader_texture_lod
))
3017 resources
.EXT_shader_texture_lod
= 1;
3019 // Tell ANGLE to allow highp in frag shaders. (unless disabled)
3020 // If underlying GLES doesn't have highp in frag shaders, it should complain anyways.
3021 resources
.FragmentPrecisionHigh
= mDisableFragHighP
? 0 : 1;
3023 resources
.HashFunction
= WebGLProgram::IdentifierHashFunction
;
3025 if (gl
->WorkAroundDriverBugs()) {
3027 if (gl
->Vendor() == gl::GLVendor::NVIDIA
) {
3028 // Work around bug 890432
3029 resources
.MaxExpressionComplexity
= 1000;
3034 // We're storing an actual instance of StripComments because, if we don't, the
3035 // cleanSource nsAString instance will be destroyed before the reference is
3037 StripComments
stripComments(shader
->Source());
3038 const nsAString
& cleanSource
= Substring(stripComments
.result().Elements(), stripComments
.length());
3039 if (!ValidateGLSLString(cleanSource
, "compileShader"))
3042 // shaderSource() already checks that the source stripped of comments is in the
3043 // 7-bit ASCII range, so we can skip the NS_IsAscii() check.
3044 NS_LossyConvertUTF16toASCII
sourceCString(cleanSource
);
3046 if (gl
->WorkAroundDriverBugs()) {
3047 const uint32_t maxSourceLength
= 0x3ffff;
3048 if (sourceCString
.Length() > maxSourceLength
)
3049 return ErrorInvalidValue("compileShader: source has more than %d characters",
3053 const char *s
= sourceCString
.get();
3055 #define WEBGL2_BYPASS_ANGLE
3056 #ifdef WEBGL2_BYPASS_ANGLE
3058 * The bypass don't bring a full support for GLSL ES 3.0, but the main purpose
3059 * is to natively bring gl_InstanceID (to do instanced rendering) and gl_FragData
3061 * To remove the bypass code, just comment #define WEBGL2_BYPASS_ANGLE above
3063 * To bypass angle, the context must be a WebGL 2 and the shader must have the
3064 * following line at the very top :
3065 * #version proto-200
3067 * In this case, byPassANGLE == true and here is what we do :
3068 * We create two shader source code:
3069 * - one for the driver, that enable GL_EXT_gpu_shader4
3070 * - one for the angle compilor, to get informations about vertex attributes
3073 static const char *bypassPrefixSearch
= "#version proto-200";
3074 static const char *bypassANGLEPrefix
[2] = {"precision mediump float;\n"
3075 "#define gl_VertexID 0\n"
3076 "#define gl_InstanceID 0\n",
3078 "precision mediump float;\n"
3079 "#extension GL_EXT_draw_buffers : enable\n"
3080 "#define gl_PrimitiveID 0\n"};
3082 const bool bypassANGLE
= IsWebGL2() && (strstr(s
, bypassPrefixSearch
) != 0);
3084 const char *angleShaderCode
= s
;
3085 nsTArray
<char> bypassANGLEShaderCode
;
3086 nsTArray
<char> bypassDriverShaderCode
;
3089 const int bypassStage
= (shader
->ShaderType() == LOCAL_GL_FRAGMENT_SHADER
) ? 1 : 0;
3090 const char *originalShader
= strstr(s
, bypassPrefixSearch
) + strlen(bypassPrefixSearch
);
3091 int originalShaderSize
= strlen(s
) - (originalShader
- s
);
3092 int bypassShaderCodeSize
= originalShaderSize
+ 4096 + 1;
3094 bypassANGLEShaderCode
.SetLength(bypassShaderCodeSize
);
3095 strcpy(bypassANGLEShaderCode
.Elements(), bypassANGLEPrefix
[bypassStage
]);
3096 strcat(bypassANGLEShaderCode
.Elements(), originalShader
);
3098 bypassDriverShaderCode
.SetLength(bypassShaderCodeSize
);
3099 strcpy(bypassDriverShaderCode
.Elements(), "#extension GL_EXT_gpu_shader4 : enable\n");
3100 strcat(bypassDriverShaderCode
.Elements(), originalShader
);
3102 angleShaderCode
= bypassANGLEShaderCode
.Elements();
3106 compiler
= ShConstructCompiler((ShShaderType
) shader
->ShaderType(),
3108 targetShaderSourceLanguage
,
3111 int compileOptions
= SH_VARIABLES
|
3112 SH_ENFORCE_PACKING_RESTRICTIONS
|
3113 SH_INIT_VARYINGS_WITHOUT_STATIC_USE
|
3116 if (resources
.MaxExpressionComplexity
> 0) {
3117 compileOptions
|= SH_LIMIT_EXPRESSION_COMPLEXITY
;
3121 // We want to do this everywhere, but to do this on Mac, we need
3122 // to do it only on Mac OSX > 10.6 as this causes the shader
3123 // compiler in 10.6 to crash
3124 compileOptions
|= SH_CLAMP_INDIRECT_ARRAY_BOUNDS
;
3128 if (gl
->WorkAroundDriverBugs()) {
3129 // Work around bug 665578 and bug 769810
3130 if (gl
->Vendor() == gl::GLVendor::ATI
) {
3131 compileOptions
|= SH_EMULATE_BUILT_IN_FUNCTIONS
;
3134 // Work around bug 735560
3135 if (gl
->Vendor() == gl::GLVendor::Intel
) {
3136 compileOptions
|= SH_EMULATE_BUILT_IN_FUNCTIONS
;
3139 // Work around bug 636926
3140 if (gl
->Vendor() == gl::GLVendor::NVIDIA
) {
3141 compileOptions
|= SH_UNROLL_FOR_LOOP_WITH_SAMPLER_ARRAY_INDEX
;
3144 // Work around https://bugs.webkit.org/show_bug.cgi?id=124684,
3145 // https://chromium.googlesource.com/angle/angle/+/5e70cf9d0b1bb
3146 compileOptions
|= SH_UNFOLD_SHORT_CIRCUIT
;
3150 #ifdef WEBGL2_BYPASS_ANGLE
3151 if (!ShCompile(compiler
, &angleShaderCode
, 1, compileOptions
)) {
3153 if (!ShCompile(compiler
, &s
, 1, compileOptions
)) {
3155 size_t lenWithNull
= 0;
3156 ShGetInfo(compiler
, SH_INFO_LOG_LENGTH
, &lenWithNull
);
3159 // Error in ShGetInfo.
3160 shader
->SetTranslationFailure(NS_LITERAL_CSTRING("Internal error: failed to get shader info log"));
3162 size_t len
= lenWithNull
- 1;
3166 // Don't allocate or try to write to zero length string
3167 info
.SetLength(len
); // Allocates len+1, for the null-term.
3168 ShGetInfoLog(compiler
, info
.BeginWriting());
3170 shader
->SetTranslationFailure(info
);
3172 ShDestruct(compiler
);
3173 shader
->SetCompileStatus(false);
3177 size_t num_attributes
= 0;
3178 ShGetInfo(compiler
, SH_ACTIVE_ATTRIBUTES
, &num_attributes
);
3179 size_t num_uniforms
= 0;
3180 ShGetInfo(compiler
, SH_ACTIVE_UNIFORMS
, &num_uniforms
);
3181 size_t attrib_max_length
= 0;
3182 ShGetInfo(compiler
, SH_ACTIVE_ATTRIBUTE_MAX_LENGTH
, &attrib_max_length
);
3183 size_t uniform_max_length
= 0;
3184 ShGetInfo(compiler
, SH_ACTIVE_UNIFORM_MAX_LENGTH
, &uniform_max_length
);
3185 size_t mapped_max_length
= 0;
3186 ShGetInfo(compiler
, SH_MAPPED_NAME_MAX_LENGTH
, &mapped_max_length
);
3188 shader
->mAttribMaxNameLength
= attrib_max_length
;
3190 shader
->mAttributes
.Clear();
3191 shader
->mUniforms
.Clear();
3192 shader
->mUniformInfos
.Clear();
3194 nsAutoArrayPtr
<char> attribute_name(new char[attrib_max_length
+1]);
3195 nsAutoArrayPtr
<char> uniform_name(new char[uniform_max_length
+1]);
3196 nsAutoArrayPtr
<char> mapped_name(new char[mapped_max_length
+1]);
3198 for (size_t i
= 0; i
< num_uniforms
; i
++) {
3202 ShPrecisionType precision
;
3204 ShGetVariableInfo(compiler
, SH_ACTIVE_UNIFORMS
, (int)i
,
3205 &length
, &size
, &type
,
3206 &precision
, &staticUse
,
3210 shader
->mUniforms
.AppendElement(WebGLMappedIdentifier(
3211 nsDependentCString(uniform_name
),
3212 nsDependentCString(mapped_name
)));
3214 // we need uniform info to validate uniform setter calls
3215 char mappedNameLength
= strlen(mapped_name
);
3216 char mappedNameLastChar
= mappedNameLength
> 1
3217 ? mapped_name
[mappedNameLength
- 1]
3219 shader
->mUniformInfos
.AppendElement(WebGLUniformInfo(
3221 mappedNameLastChar
== ']',
3225 for (size_t i
= 0; i
< num_attributes
; i
++) {
3229 ShPrecisionType precision
;
3231 ShGetVariableInfo(compiler
, SH_ACTIVE_ATTRIBUTES
, (int)i
,
3232 &length
, &size
, &type
,
3233 &precision
, &staticUse
,
3236 shader
->mAttributes
.AppendElement(WebGLMappedIdentifier(
3237 nsDependentCString(attribute_name
),
3238 nsDependentCString(mapped_name
)));
3241 size_t lenWithNull
= 0;
3242 ShGetInfo(compiler
, SH_OBJECT_CODE_LENGTH
, &lenWithNull
);
3243 MOZ_ASSERT(lenWithNull
>= 1);
3244 size_t len
= lenWithNull
- 1;
3246 nsAutoCString translatedSrc
;
3247 translatedSrc
.SetLength(len
); // Allocates len+1, for the null-term.
3248 ShGetObjectCode(compiler
, translatedSrc
.BeginWriting());
3250 CopyASCIItoUTF16(translatedSrc
, shader
->mTranslatedSource
);
3252 const char *ts
= translatedSrc
.get();
3254 #ifdef WEBGL2_BYPASS_ANGLE
3256 const char* driverShaderCode
= bypassDriverShaderCode
.Elements();
3257 gl
->fShaderSource(shadername
, 1, (const GLchar
**) &driverShaderCode
, nullptr);
3259 gl
->fShaderSource(shadername
, 1, &ts
, nullptr);
3262 gl
->fShaderSource(shadername
, 1, &ts
, nullptr);
3265 shader
->SetTranslationSuccess();
3267 ShDestruct(compiler
);
3269 gl
->fCompileShader(shadername
);
3271 gl
->fGetShaderiv(shadername
, LOCAL_GL_COMPILE_STATUS
, &ok
);
3272 shader
->SetCompileStatus(ok
);
3276 WebGLContext::CompressedTexImage2D(GLenum target
, GLint level
, GLenum internalformat
,
3277 GLsizei width
, GLsizei height
, GLint border
,
3278 const ArrayBufferView
& view
)
3280 if (IsContextLost())
3283 const WebGLTexImageFunc func
= WebGLTexImageFunc::CompTexImage
;
3285 if (!ValidateTexImage(2, target
, level
, internalformat
,
3286 0, 0, 0, width
, height
, 0,
3287 border
, internalformat
, LOCAL_GL_UNSIGNED_BYTE
,
3293 view
.ComputeLengthAndData();
3295 uint32_t byteLength
= view
.Length();
3296 if (!ValidateCompTexImageDataSize(target
, internalformat
, width
, height
, byteLength
, func
)) {
3300 if (!ValidateCompTexImageSize(target
, level
, internalformat
, 0, 0,
3301 width
, height
, width
, height
, func
))
3306 MakeContextCurrent();
3307 gl
->fCompressedTexImage2D(target
, level
, internalformat
, width
, height
, border
, byteLength
, view
.Data());
3308 WebGLTexture
* tex
= activeBoundTextureForTarget(target
);
3310 tex
->SetImageInfo(target
, level
, width
, height
, internalformat
, LOCAL_GL_UNSIGNED_BYTE
,
3311 WebGLImageDataStatus::InitializedImageData
);
3315 WebGLContext::CompressedTexSubImage2D(GLenum target
, GLint level
, GLint xoffset
,
3316 GLint yoffset
, GLsizei width
, GLsizei height
,
3317 GLenum format
, const ArrayBufferView
& view
)
3319 if (IsContextLost())
3322 const WebGLTexImageFunc func
= WebGLTexImageFunc::CompTexSubImage
;
3324 if (!ValidateTexImage(2, target
,
3326 xoffset
, yoffset
, 0,
3328 0, format
, LOCAL_GL_UNSIGNED_BYTE
,
3334 WebGLTexture
*tex
= activeBoundTextureForTarget(target
);
3336 WebGLTexture::ImageInfo
& levelInfo
= tex
->ImageInfoAt(target
, level
);
3338 view
.ComputeLengthAndData();
3340 uint32_t byteLength
= view
.Length();
3341 if (!ValidateCompTexImageDataSize(target
, format
, width
, height
, byteLength
, func
))
3344 if (!ValidateCompTexImageSize(target
, level
, format
,
3347 levelInfo
.Width(), levelInfo
.Height(),
3353 if (levelInfo
.HasUninitializedImageData())
3354 tex
->DoDeferredImageInitialization(target
, level
);
3356 MakeContextCurrent();
3357 gl
->fCompressedTexSubImage2D(target
, level
, xoffset
, yoffset
, width
, height
, format
, byteLength
, view
.Data());
3361 WebGLContext::GetShaderParameter(WebGLShader
*shader
, GLenum pname
)
3363 if (IsContextLost())
3364 return JS::NullValue();
3366 if (!ValidateObject("getShaderParameter: shader", shader
))
3367 return JS::NullValue();
3369 GLuint shadername
= shader
->GLName();
3371 MakeContextCurrent();
3374 case LOCAL_GL_SHADER_TYPE
:
3377 gl
->fGetShaderiv(shadername
, pname
, &i
);
3378 return JS::NumberValue(uint32_t(i
));
3381 case LOCAL_GL_DELETE_STATUS
:
3382 return JS::BooleanValue(shader
->IsDeleteRequested());
3384 case LOCAL_GL_COMPILE_STATUS
:
3387 gl
->fGetShaderiv(shadername
, pname
, &i
);
3388 return JS::BooleanValue(bool(i
));
3392 ErrorInvalidEnumInfo("getShaderParameter: parameter", pname
);
3395 return JS::NullValue();
3399 WebGLContext::GetShaderInfoLog(WebGLShader
*shader
, nsAString
& retval
)
3402 GetShaderInfoLog(shader
, s
);
3404 retval
.SetIsVoid(true);
3406 CopyASCIItoUTF16(s
, retval
);
3410 WebGLContext::GetShaderInfoLog(WebGLShader
*shader
, nsACString
& retval
)
3412 if (IsContextLost())
3414 retval
.SetIsVoid(true);
3418 if (!ValidateObject("getShaderInfoLog: shader", shader
))
3421 retval
= shader
->TranslationLog();
3422 if (!retval
.IsVoid()) {
3426 MakeContextCurrent();
3428 GLuint shadername
= shader
->GLName();
3430 gl
->fGetShaderiv(shadername
, LOCAL_GL_INFO_LOG_LENGTH
, &k
);
3432 // XXX GL Error? should never happen.
3441 retval
.SetCapacity(k
);
3442 gl
->fGetShaderInfoLog(shadername
, k
, &k
, (char*) retval
.BeginWriting());
3443 retval
.SetLength(k
);
3446 already_AddRefed
<WebGLShaderPrecisionFormat
>
3447 WebGLContext::GetShaderPrecisionFormat(GLenum shadertype
, GLenum precisiontype
)
3449 if (IsContextLost())
3452 switch (shadertype
) {
3453 case LOCAL_GL_FRAGMENT_SHADER
:
3454 case LOCAL_GL_VERTEX_SHADER
:
3457 ErrorInvalidEnumInfo("getShaderPrecisionFormat: shadertype", shadertype
);
3461 switch (precisiontype
) {
3462 case LOCAL_GL_LOW_FLOAT
:
3463 case LOCAL_GL_MEDIUM_FLOAT
:
3464 case LOCAL_GL_HIGH_FLOAT
:
3465 case LOCAL_GL_LOW_INT
:
3466 case LOCAL_GL_MEDIUM_INT
:
3467 case LOCAL_GL_HIGH_INT
:
3470 ErrorInvalidEnumInfo("getShaderPrecisionFormat: precisiontype", precisiontype
);
3474 MakeContextCurrent();
3475 GLint range
[2], precision
;
3477 if (mDisableFragHighP
&&
3478 shadertype
== LOCAL_GL_FRAGMENT_SHADER
&&
3479 (precisiontype
== LOCAL_GL_HIGH_FLOAT
||
3480 precisiontype
== LOCAL_GL_HIGH_INT
))
3486 gl
->fGetShaderPrecisionFormat(shadertype
, precisiontype
, range
, &precision
);
3489 nsRefPtr
<WebGLShaderPrecisionFormat
> retShaderPrecisionFormat
3490 = new WebGLShaderPrecisionFormat(this, range
[0], range
[1], precision
);
3491 return retShaderPrecisionFormat
.forget();
3495 WebGLContext::GetShaderSource(WebGLShader
*shader
, nsAString
& retval
)
3497 if (IsContextLost()) {
3498 retval
.SetIsVoid(true);
3502 if (!ValidateObject("getShaderSource: shader", shader
))
3505 retval
.Assign(shader
->Source());
3509 WebGLContext::ShaderSource(WebGLShader
*shader
, const nsAString
& source
)
3511 if (IsContextLost())
3514 if (!ValidateObject("shaderSource: shader", shader
))
3517 // We're storing an actual instance of StripComments because, if we don't, the
3518 // cleanSource nsAString instance will be destroyed before the reference is
3520 StripComments
stripComments(source
);
3521 const nsAString
& cleanSource
= Substring(stripComments
.result().Elements(), stripComments
.length());
3522 if (!ValidateGLSLString(cleanSource
, "compileShader"))
3525 shader
->SetSource(source
);
3527 shader
->SetNeedsTranslation();
3531 WebGLContext::GetShaderTranslatedSource(WebGLShader
*shader
, nsAString
& retval
)
3533 if (IsContextLost()) {
3534 retval
.SetIsVoid(true);
3538 if (!ValidateObject("getShaderTranslatedSource: shader", shader
))
3541 retval
.Assign(shader
->TranslatedSource());
3544 GLenum
WebGLContext::CheckedTexImage2D(GLenum target
,
3546 GLenum internalFormat
,
3554 MOZ_ASSERT(internalFormat
== format
);
3555 WebGLTexture
*tex
= activeBoundTextureForTarget(target
);
3556 MOZ_ASSERT(tex
!= nullptr, "no texture bound");
3558 bool sizeMayChange
= true;
3560 if (tex
->HasImageInfoAt(target
, level
)) {
3561 const WebGLTexture::ImageInfo
& imageInfo
= tex
->ImageInfoAt(target
, level
);
3562 sizeMayChange
= width
!= imageInfo
.Width() ||
3563 height
!= imageInfo
.Height() ||
3564 format
!= imageInfo
.WebGLFormat() ||
3565 type
!= imageInfo
.WebGLType();
3568 // Convert to format and type required by OpenGL 'driver'.
3569 GLenum driverType
= DriverTypeFromType(gl
, type
);
3570 GLenum driverInternalFormat
= LOCAL_GL_NONE
;
3571 GLenum driverFormat
= LOCAL_GL_NONE
;
3572 DriverFormatsFromFormatAndType(gl
, format
, type
, &driverInternalFormat
, &driverFormat
);
3574 if (sizeMayChange
) {
3575 GetAndFlushUnderlyingGLErrors();
3578 gl
->fTexImage2D(target
, level
, driverInternalFormat
, width
, height
, border
, driverFormat
, driverType
, data
);
3580 GLenum error
= LOCAL_GL_NO_ERROR
;
3581 if (sizeMayChange
) {
3582 error
= GetAndFlushUnderlyingGLErrors();
3589 WebGLContext::TexImage2D_base(GLenum target
, GLint level
, GLenum internalformat
,
3590 GLsizei width
, GLsizei height
, GLsizei srcStrideOrZero
,
3592 GLenum format
, GLenum type
,
3593 void* data
, uint32_t byteLength
,
3594 int jsArrayType
, // a TypedArray format enum, or -1 if not relevant
3595 WebGLTexelFormat srcFormat
, bool srcPremultiplied
)
3597 const WebGLTexImageFunc func
= WebGLTexImageFunc::TexImage
;
3599 if (!ValidateTexImage(2, target
, level
, internalformat
,
3602 border
, format
, type
, func
))
3607 const bool isDepthTexture
= format
== LOCAL_GL_DEPTH_COMPONENT
||
3608 format
== LOCAL_GL_DEPTH_STENCIL
;
3610 if (isDepthTexture
) {
3611 if (data
!= nullptr || level
!= 0)
3612 return ErrorInvalidOperation("texImage2D: "
3613 "with format of DEPTH_COMPONENT or DEPTH_STENCIL, "
3614 "data must be nullptr, "
3615 "level must be zero");
3618 if (!ValidateTexInputData(type
, jsArrayType
, func
))
3621 WebGLTexelFormat dstFormat
= GetWebGLTexelFormat(format
, type
);
3622 WebGLTexelFormat actualSrcFormat
= srcFormat
== WebGLTexelFormat::Auto
? dstFormat
: srcFormat
;
3624 uint32_t srcTexelSize
= WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat
);
3626 CheckedUint32 checked_neededByteLength
=
3627 GetImageSize(height
, width
, srcTexelSize
, mPixelStoreUnpackAlignment
);
3629 CheckedUint32 checked_plainRowSize
= CheckedUint32(width
) * srcTexelSize
;
3630 CheckedUint32 checked_alignedRowSize
=
3631 RoundedToNextMultipleOf(checked_plainRowSize
.value(), mPixelStoreUnpackAlignment
);
3633 if (!checked_neededByteLength
.isValid())
3634 return ErrorInvalidOperation("texImage2D: integer overflow computing the needed buffer size");
3636 uint32_t bytesNeeded
= checked_neededByteLength
.value();
3638 if (byteLength
&& byteLength
< bytesNeeded
)
3639 return ErrorInvalidOperation("texImage2D: not enough data for operation (need %d, have %d)",
3640 bytesNeeded
, byteLength
);
3642 WebGLTexture
*tex
= activeBoundTextureForTarget(target
);
3645 return ErrorInvalidOperation("texImage2D: no texture is bound to this target");
3647 MakeContextCurrent();
3649 nsAutoArrayPtr
<uint8_t> convertedData
;
3650 void* pixels
= nullptr;
3651 WebGLImageDataStatus imageInfoStatusIfSuccess
= WebGLImageDataStatus::UninitializedImageData
;
3654 size_t srcStride
= srcStrideOrZero
? srcStrideOrZero
: checked_alignedRowSize
.value();
3655 uint32_t dstTexelSize
= GetBitsPerTexel(format
, type
) / 8;
3656 size_t dstPlainRowSize
= dstTexelSize
* width
;
3657 size_t unpackAlignment
= mPixelStoreUnpackAlignment
;
3658 size_t dstStride
= ((dstPlainRowSize
+ unpackAlignment
-1) / unpackAlignment
) * unpackAlignment
;
3660 if (actualSrcFormat
== dstFormat
&&
3661 srcPremultiplied
== mPixelStorePremultiplyAlpha
&&
3662 srcStride
== dstStride
&&
3665 // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
3670 size_t convertedDataSize
= height
* dstStride
;
3671 convertedData
= new ((fallible_t())) uint8_t[convertedDataSize
];
3672 if (!convertedData
) {
3673 ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
3674 " a buffer for doing format conversion.");
3677 ConvertImage(width
, height
, srcStride
, dstStride
,
3678 static_cast<uint8_t*>(data
), convertedData
,
3679 actualSrcFormat
, srcPremultiplied
,
3680 dstFormat
, mPixelStorePremultiplyAlpha
, dstTexelSize
);
3681 pixels
= reinterpret_cast<void*>(convertedData
.get());
3683 imageInfoStatusIfSuccess
= WebGLImageDataStatus::InitializedImageData
;
3686 GLenum error
= CheckedTexImage2D(target
, level
, internalformat
, width
,
3687 height
, border
, format
, type
, pixels
);
3690 GenerateWarning("texImage2D generated error %s", ErrorName(error
));
3694 // in all of the code paths above, we should have either initialized data,
3695 // or allocated data and left it uninitialized, but in any case we shouldn't
3696 // have NoImageData at this point.
3697 MOZ_ASSERT(imageInfoStatusIfSuccess
!= WebGLImageDataStatus::NoImageData
);
3699 tex
->SetImageInfo(target
, level
, width
, height
, format
, type
, imageInfoStatusIfSuccess
);
3703 WebGLContext::TexImage2D(GLenum target
, GLint level
,
3704 GLenum internalformat
, GLsizei width
,
3705 GLsizei height
, GLint border
, GLenum format
,
3706 GLenum type
, const Nullable
<ArrayBufferView
> &pixels
, ErrorResult
& rv
)
3708 if (IsContextLost())
3714 if (pixels
.IsNull()) {
3719 const ArrayBufferView
& view
= pixels
.Value();
3720 view
.ComputeLengthAndData();
3723 length
= view
.Length();
3724 jsArrayType
= int(JS_GetArrayBufferViewType(view
.Obj()));
3727 return TexImage2D_base(target
, level
, internalformat
, width
, height
, 0, border
, format
, type
,
3728 data
, length
, jsArrayType
,
3729 WebGLTexelFormat::Auto
, false);
3733 WebGLContext::TexImage2D(GLenum target
, GLint level
,
3734 GLenum internalformat
, GLenum format
,
3735 GLenum type
, ImageData
* pixels
, ErrorResult
& rv
)
3737 if (IsContextLost())
3741 // Spec says to generate an INVALID_VALUE error
3742 return ErrorInvalidValue("texImage2D: null ImageData");
3745 Uint8ClampedArray arr
;
3746 DebugOnly
<bool> inited
= arr
.Init(pixels
->GetDataObject());
3748 arr
.ComputeLengthAndData();
3750 return TexImage2D_base(target
, level
, internalformat
, pixels
->Width(),
3751 pixels
->Height(), 4*pixels
->Width(), 0,
3752 format
, type
, arr
.Data(), arr
.Length(), -1,
3753 WebGLTexelFormat::RGBA8
, false);
3758 WebGLContext::TexSubImage2D_base(GLenum target
, GLint level
,
3759 GLint xoffset
, GLint yoffset
,
3760 GLsizei width
, GLsizei height
, GLsizei srcStrideOrZero
,
3761 GLenum format
, GLenum type
,
3762 void* data
, uint32_t byteLength
,
3764 WebGLTexelFormat srcFormat
, bool srcPremultiplied
)
3766 const WebGLTexImageFunc func
= WebGLTexImageFunc::TexSubImage
;
3768 if (!ValidateTexImage(2, target
, level
, format
,
3769 xoffset
, yoffset
, 0,
3771 0, format
, type
, func
))
3776 if (!ValidateTexInputData(type
, jsArrayType
, func
))
3779 WebGLTexelFormat dstFormat
= GetWebGLTexelFormat(format
, type
);
3780 WebGLTexelFormat actualSrcFormat
= srcFormat
== WebGLTexelFormat::Auto
? dstFormat
: srcFormat
;
3782 uint32_t srcTexelSize
= WebGLTexelConversions::TexelBytesForFormat(actualSrcFormat
);
3784 if (width
== 0 || height
== 0)
3785 return; // ES 2.0 says it has no effect, we better return right now
3787 CheckedUint32 checked_neededByteLength
=
3788 GetImageSize(height
, width
, srcTexelSize
, mPixelStoreUnpackAlignment
);
3790 CheckedUint32 checked_plainRowSize
= CheckedUint32(width
) * srcTexelSize
;
3792 CheckedUint32 checked_alignedRowSize
=
3793 RoundedToNextMultipleOf(checked_plainRowSize
.value(), mPixelStoreUnpackAlignment
);
3795 if (!checked_neededByteLength
.isValid())
3796 return ErrorInvalidOperation("texSubImage2D: integer overflow computing the needed buffer size");
3798 uint32_t bytesNeeded
= checked_neededByteLength
.value();
3800 if (byteLength
< bytesNeeded
)
3801 return ErrorInvalidOperation("texSubImage2D: not enough data for operation (need %d, have %d)", bytesNeeded
, byteLength
);
3803 WebGLTexture
*tex
= activeBoundTextureForTarget(target
);
3804 const WebGLTexture::ImageInfo
&imageInfo
= tex
->ImageInfoAt(target
, level
);
3806 if (imageInfo
.HasUninitializedImageData())
3807 tex
->DoDeferredImageInitialization(target
, level
);
3809 MakeContextCurrent();
3811 size_t srcStride
= srcStrideOrZero
? srcStrideOrZero
: checked_alignedRowSize
.value();
3812 uint32_t dstTexelSize
= GetBitsPerTexel(format
, type
) / 8;
3813 size_t dstPlainRowSize
= dstTexelSize
* width
;
3814 // There are checks above to ensure that this won't overflow.
3815 size_t dstStride
= RoundedToNextMultipleOf(dstPlainRowSize
, mPixelStoreUnpackAlignment
).value();
3817 void* pixels
= data
;
3818 nsAutoArrayPtr
<uint8_t> convertedData
;
3820 // no conversion, no flipping, so we avoid copying anything and just pass the source pointer
3821 bool noConversion
= (actualSrcFormat
== dstFormat
&&
3822 srcPremultiplied
== mPixelStorePremultiplyAlpha
&&
3823 srcStride
== dstStride
&&
3826 if (!noConversion
) {
3827 size_t convertedDataSize
= height
* dstStride
;
3828 convertedData
= new ((fallible_t())) uint8_t[convertedDataSize
];
3829 if (!convertedData
) {
3830 ErrorOutOfMemory("texImage2D: Ran out of memory when allocating"
3831 " a buffer for doing format conversion.");
3834 ConvertImage(width
, height
, srcStride
, dstStride
,
3835 static_cast<const uint8_t*>(data
), convertedData
,
3836 actualSrcFormat
, srcPremultiplied
,
3837 dstFormat
, mPixelStorePremultiplyAlpha
, dstTexelSize
);
3838 pixels
= reinterpret_cast<void*>(convertedData
.get());
3841 GLenum driverType
= DriverTypeFromType(gl
, type
);
3842 GLenum driverInternalFormat
= LOCAL_GL_NONE
;
3843 GLenum driverFormat
= LOCAL_GL_NONE
;
3844 DriverFormatsFromFormatAndType(gl
, format
, type
, &driverInternalFormat
, &driverFormat
);
3846 gl
->fTexSubImage2D(target
, level
, xoffset
, yoffset
, width
, height
, driverFormat
, driverType
, pixels
);
3850 WebGLContext::TexSubImage2D(GLenum target
, GLint level
,
3851 GLint xoffset
, GLint yoffset
,
3852 GLsizei width
, GLsizei height
,
3853 GLenum format
, GLenum type
,
3854 const Nullable
<ArrayBufferView
> &pixels
,
3857 if (IsContextLost())
3860 if (pixels
.IsNull())
3861 return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
3863 const ArrayBufferView
& view
= pixels
.Value();
3864 view
.ComputeLengthAndData();
3866 return TexSubImage2D_base(target
, level
, xoffset
, yoffset
,
3867 width
, height
, 0, format
, type
,
3868 view
.Data(), view
.Length(),
3869 JS_GetArrayBufferViewType(view
.Obj()),
3870 WebGLTexelFormat::Auto
, false);
3874 WebGLContext::TexSubImage2D(GLenum target
, GLint level
,
3875 GLint xoffset
, GLint yoffset
,
3876 GLenum format
, GLenum type
, ImageData
* pixels
,
3879 if (IsContextLost())
3883 return ErrorInvalidValue("texSubImage2D: pixels must not be null!");
3885 Uint8ClampedArray arr
;
3886 DebugOnly
<bool> inited
= arr
.Init(pixels
->GetDataObject());
3888 arr
.ComputeLengthAndData();
3890 return TexSubImage2D_base(target
, level
, xoffset
, yoffset
,
3891 pixels
->Width(), pixels
->Height(),
3892 4*pixels
->Width(), format
, type
,
3893 arr
.Data(), arr
.Length(),
3895 WebGLTexelFormat::RGBA8
, false);
3899 WebGLContext::LoseContext()
3901 if (IsContextLost())
3902 return ErrorInvalidOperation("loseContext: Context is already lost.");
3904 ForceLoseContext(true);
3908 WebGLContext::RestoreContext()
3910 if (!IsContextLost())
3911 return ErrorInvalidOperation("restoreContext: Context is not lost.");
3913 if (!mLastLossWasSimulated
) {
3914 return ErrorInvalidOperation("restoreContext: Context loss was not simulated."
3915 " Cannot simulate restore.");
3917 // If we're currently lost, and the last loss was simulated, then
3918 // we're currently only simulated-lost, allowing us to call
3919 // restoreContext().
3921 if (!mAllowContextRestore
)
3922 return ErrorInvalidOperation("restoreContext: Context cannot be restored.");
3924 ForceRestoreContext();
3928 BaseTypeAndSizeFromUniformType(GLenum uType
, GLenum
*baseType
, GLint
*unitSize
)
3932 case LOCAL_GL_INT_VEC2
:
3933 case LOCAL_GL_INT_VEC3
:
3934 case LOCAL_GL_INT_VEC4
:
3935 case LOCAL_GL_SAMPLER_2D
:
3936 case LOCAL_GL_SAMPLER_CUBE
:
3937 *baseType
= LOCAL_GL_INT
;
3939 case LOCAL_GL_FLOAT
:
3940 case LOCAL_GL_FLOAT_VEC2
:
3941 case LOCAL_GL_FLOAT_VEC3
:
3942 case LOCAL_GL_FLOAT_VEC4
:
3943 case LOCAL_GL_FLOAT_MAT2
:
3944 case LOCAL_GL_FLOAT_MAT3
:
3945 case LOCAL_GL_FLOAT_MAT4
:
3946 *baseType
= LOCAL_GL_FLOAT
;
3949 case LOCAL_GL_BOOL_VEC2
:
3950 case LOCAL_GL_BOOL_VEC3
:
3951 case LOCAL_GL_BOOL_VEC4
:
3952 *baseType
= LOCAL_GL_BOOL
; // pretend these are int
3960 case LOCAL_GL_FLOAT
:
3962 case LOCAL_GL_SAMPLER_2D
:
3963 case LOCAL_GL_SAMPLER_CUBE
:
3966 case LOCAL_GL_INT_VEC2
:
3967 case LOCAL_GL_FLOAT_VEC2
:
3968 case LOCAL_GL_BOOL_VEC2
:
3971 case LOCAL_GL_INT_VEC3
:
3972 case LOCAL_GL_FLOAT_VEC3
:
3973 case LOCAL_GL_BOOL_VEC3
:
3976 case LOCAL_GL_INT_VEC4
:
3977 case LOCAL_GL_FLOAT_VEC4
:
3978 case LOCAL_GL_BOOL_VEC4
:
3981 case LOCAL_GL_FLOAT_MAT2
:
3984 case LOCAL_GL_FLOAT_MAT3
:
3987 case LOCAL_GL_FLOAT_MAT4
:
3998 WebGLTexelFormat
mozilla::GetWebGLTexelFormat(GLenum internalformat
, GLenum type
)
4001 // WEBGL_depth_texture
4002 if (internalformat
== LOCAL_GL_DEPTH_COMPONENT
) {
4004 case LOCAL_GL_UNSIGNED_SHORT
:
4005 return WebGLTexelFormat::D16
;
4006 case LOCAL_GL_UNSIGNED_INT
:
4007 return WebGLTexelFormat::D32
;
4010 MOZ_CRASH("Invalid WebGL texture format/type?");
4013 if (internalformat
== LOCAL_GL_DEPTH_STENCIL
) {
4015 case LOCAL_GL_UNSIGNED_INT_24_8_EXT
:
4016 return WebGLTexelFormat::D24S8
;
4019 MOZ_CRASH("Invalid WebGL texture format/type?");
4022 if (internalformat
== LOCAL_GL_DEPTH_COMPONENT16
) {
4023 return WebGLTexelFormat::D16
;
4026 if (internalformat
== LOCAL_GL_DEPTH_COMPONENT32
) {
4027 return WebGLTexelFormat::D32
;
4030 if (internalformat
== LOCAL_GL_DEPTH24_STENCIL8
) {
4031 return WebGLTexelFormat::D24S8
;
4034 if (type
== LOCAL_GL_UNSIGNED_BYTE
) {
4035 switch (internalformat
) {
4037 case LOCAL_GL_SRGB_ALPHA_EXT
:
4038 return WebGLTexelFormat::RGBA8
;
4040 case LOCAL_GL_SRGB_EXT
:
4041 return WebGLTexelFormat::RGB8
;
4042 case LOCAL_GL_ALPHA
:
4043 return WebGLTexelFormat::A8
;
4044 case LOCAL_GL_LUMINANCE
:
4045 return WebGLTexelFormat::R8
;
4046 case LOCAL_GL_LUMINANCE_ALPHA
:
4047 return WebGLTexelFormat::RA8
;
4050 MOZ_CRASH("Invalid WebGL texture format/type?");
4053 if (type
== LOCAL_GL_FLOAT
) {
4054 // OES_texture_float
4055 switch (internalformat
) {
4057 case LOCAL_GL_RGBA32F
:
4058 return WebGLTexelFormat::RGBA32F
;
4060 case LOCAL_GL_RGB32F
:
4061 return WebGLTexelFormat::RGB32F
;
4062 case LOCAL_GL_ALPHA
:
4063 case LOCAL_GL_ALPHA32F_ARB
:
4064 return WebGLTexelFormat::A32F
;
4065 case LOCAL_GL_LUMINANCE
:
4066 case LOCAL_GL_LUMINANCE32F_ARB
:
4067 return WebGLTexelFormat::R32F
;
4068 case LOCAL_GL_LUMINANCE_ALPHA
:
4069 case LOCAL_GL_LUMINANCE_ALPHA32F_ARB
:
4070 return WebGLTexelFormat::RA32F
;
4073 MOZ_CRASH("Invalid WebGL texture format/type?");
4074 } else if (type
== LOCAL_GL_HALF_FLOAT_OES
) {
4075 // OES_texture_half_float
4076 switch (internalformat
) {
4078 case LOCAL_GL_RGBA16F
:
4079 return WebGLTexelFormat::RGBA16F
;
4081 case LOCAL_GL_RGB16F
:
4082 return WebGLTexelFormat::RGB16F
;
4083 case LOCAL_GL_ALPHA
:
4084 case LOCAL_GL_ALPHA16F_ARB
:
4085 return WebGLTexelFormat::A16F
;
4086 case LOCAL_GL_LUMINANCE
:
4087 case LOCAL_GL_LUMINANCE16F_ARB
:
4088 return WebGLTexelFormat::R16F
;
4089 case LOCAL_GL_LUMINANCE_ALPHA
:
4090 case LOCAL_GL_LUMINANCE_ALPHA16F_ARB
:
4091 return WebGLTexelFormat::RA16F
;
4093 MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
4094 return WebGLTexelFormat::BadFormat
;
4099 case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4
:
4100 return WebGLTexelFormat::RGBA4444
;
4101 case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1
:
4102 return WebGLTexelFormat::RGBA5551
;
4103 case LOCAL_GL_UNSIGNED_SHORT_5_6_5
:
4104 return WebGLTexelFormat::RGB565
;
4106 MOZ_ASSERT(false, "Coding mistake?! Should never reach this point.");
4107 return WebGLTexelFormat::BadFormat
;
4110 MOZ_CRASH("Invalid WebGL texture format/type?");
4114 WebGLContext::BlendColor(GLclampf r
, GLclampf g
, GLclampf b
, GLclampf a
) {
4115 if (IsContextLost())
4117 MakeContextCurrent();
4118 gl
->fBlendColor(r
, g
, b
, a
);
4122 WebGLContext::Flush() {
4123 if (IsContextLost())
4125 MakeContextCurrent();
4130 WebGLContext::Finish() {
4131 if (IsContextLost())
4133 MakeContextCurrent();
4138 WebGLContext::LineWidth(GLfloat width
) {
4139 if (IsContextLost())
4141 MakeContextCurrent();
4142 gl
->fLineWidth(width
);
4146 WebGLContext::PolygonOffset(GLfloat factor
, GLfloat units
) {
4147 if (IsContextLost())
4149 MakeContextCurrent();
4150 gl
->fPolygonOffset(factor
, units
);
4154 WebGLContext::SampleCoverage(GLclampf value
, WebGLboolean invert
) {
4155 if (IsContextLost())
4157 MakeContextCurrent();
4158 gl
->fSampleCoverage(value
, invert
);