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"
9 #include "mozilla/CheckedInt.h"
10 #include "WebGLBuffer.h"
11 #include "WebGLContextUtils.h"
12 #include "WebGLFramebuffer.h"
13 #include "WebGLProgram.h"
14 #include "WebGLRenderbuffer.h"
15 #include "WebGLShader.h"
16 #include "WebGLTexture.h"
17 #include "WebGLUniformInfo.h"
18 #include "WebGLVertexArray.h"
19 #include "WebGLVertexAttribData.h"
21 using namespace mozilla
;
22 using namespace mozilla::dom
;
23 using namespace mozilla::gl
;
25 // For a Tegra workaround.
26 static const int MAX_DRAW_CALLS_SINCE_FLUSH
= 100;
29 WebGLContext::DrawInstanced_check(const char* info
)
31 // This restriction was removed in GLES3, so WebGL2 shouldn't have it.
33 IsExtensionEnabled(WebGLExtensionID::ANGLE_instanced_arrays
) &&
34 !mBufferFetchingHasPerVertex
)
36 /* http://www.khronos.org/registry/gles/extensions/ANGLE/ANGLE_instanced_arrays.txt
37 * If all of the enabled vertex attribute arrays that are bound to active
38 * generic attributes in the program have a non-zero divisor, the draw
39 * call should return INVALID_OPERATION.
41 * NB: This also appears to apply to NV_instanced_arrays, though the
42 * INVALID_OPERATION emission is not explicitly stated.
43 * ARB_instanced_arrays does not have this restriction.
45 ErrorInvalidOperation("%s: at least one vertex attribute divisor should be 0", info
);
52 bool WebGLContext::DrawArrays_check(GLint first
, GLsizei count
, GLsizei primcount
, const char* info
)
54 if (first
< 0 || count
< 0) {
55 ErrorInvalidValue("%s: negative first or count", info
);
60 ErrorInvalidValue("%s: negative primcount", info
);
64 if (!ValidateStencilParamsForDrawCall()) {
68 // If count is 0, there's nothing to do.
69 if (count
== 0 || primcount
== 0) {
73 // Any checks below this depend on a program being available.
74 if (!mCurrentProgram
) {
75 ErrorInvalidOperation("%s: null CURRENT_PROGRAM", info
);
79 if (!ValidateBufferFetching(info
)) {
83 CheckedInt
<GLsizei
> checked_firstPlusCount
= CheckedInt
<GLsizei
>(first
) + count
;
85 if (!checked_firstPlusCount
.isValid()) {
86 ErrorInvalidOperation("%s: overflow in first+count", info
);
90 if (uint32_t(checked_firstPlusCount
.value()) > mMaxFetchedVertices
) {
91 ErrorInvalidOperation("%s: bound vertex attribute buffers do not have sufficient size for given first and count", info
);
95 if (uint32_t(primcount
) > mMaxFetchedInstances
) {
96 ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info
);
100 MakeContextCurrent();
102 if (mBoundFramebuffer
) {
103 if (!mBoundFramebuffer
->CheckAndInitializeAttachments()) {
104 ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info
);
108 ClearBackbufferIfNeeded();
111 if (!DoFakeVertexAttrib0(checked_firstPlusCount
.value())) {
115 if (!DrawInstanced_check(info
)) {
119 BindFakeBlackTextures();
125 WebGLContext::DrawArrays(GLenum mode
, GLint first
, GLsizei count
)
130 if (!ValidateDrawModeEnum(mode
, "drawArrays: mode"))
133 if (!DrawArrays_check(first
, count
, 1, "drawArrays"))
136 RunContextLossTimer();
137 gl
->fDrawArrays(mode
, first
, count
);
143 WebGLContext::DrawArraysInstanced(GLenum mode
, GLint first
, GLsizei count
, GLsizei primcount
)
148 if (!ValidateDrawModeEnum(mode
, "drawArraysInstanced: mode"))
151 if (!DrawArrays_check(first
, count
, primcount
, "drawArraysInstanced"))
154 RunContextLossTimer();
155 gl
->fDrawArraysInstanced(mode
, first
, count
, primcount
);
161 WebGLContext::DrawElements_check(GLsizei count
, GLenum type
,
162 WebGLintptr byteOffset
, GLsizei primcount
,
163 const char* info
, GLuint
* out_upperBound
)
165 if (count
< 0 || byteOffset
< 0) {
166 ErrorInvalidValue("%s: negative count or offset", info
);
171 ErrorInvalidValue("%s: negative primcount", info
);
175 if (!ValidateStencilParamsForDrawCall()) {
179 // If count is 0, there's nothing to do.
180 if (count
== 0 || primcount
== 0) {
184 CheckedUint32 checked_byteCount
;
188 if (type
== LOCAL_GL_UNSIGNED_SHORT
) {
189 checked_byteCount
= 2 * CheckedUint32(count
);
190 if (byteOffset
% 2 != 0) {
191 ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_SHORT (must be a multiple of 2)", info
);
194 first
= byteOffset
/ 2;
196 else if (type
== LOCAL_GL_UNSIGNED_BYTE
) {
197 checked_byteCount
= count
;
200 else if (type
== LOCAL_GL_UNSIGNED_INT
&& IsExtensionEnabled(WebGLExtensionID::OES_element_index_uint
)) {
201 checked_byteCount
= 4 * CheckedUint32(count
);
202 if (byteOffset
% 4 != 0) {
203 ErrorInvalidOperation("%s: invalid byteOffset for UNSIGNED_INT (must be a multiple of 4)", info
);
206 first
= byteOffset
/ 4;
209 ErrorInvalidEnum("%s: type must be UNSIGNED_SHORT or UNSIGNED_BYTE", info
);
213 if (!checked_byteCount
.isValid()) {
214 ErrorInvalidValue("%s: overflow in byteCount", info
);
218 // Any checks below this depend on a program being available.
219 if (!mCurrentProgram
) {
220 ErrorInvalidOperation("%s: null CURRENT_PROGRAM", info
);
224 if (!mBoundVertexArray
->mElementArrayBuffer
) {
225 ErrorInvalidOperation("%s: must have element array buffer binding", info
);
229 WebGLBuffer
& elemArrayBuffer
= *mBoundVertexArray
->mElementArrayBuffer
;
231 if (!elemArrayBuffer
.ByteLength()) {
232 ErrorInvalidOperation("%s: bound element array buffer doesn't have any data", info
);
236 CheckedInt
<GLsizei
> checked_neededByteCount
= checked_byteCount
.toChecked
<GLsizei
>() + byteOffset
;
238 if (!checked_neededByteCount
.isValid()) {
239 ErrorInvalidOperation("%s: overflow in byteOffset+byteCount", info
);
243 if (uint32_t(checked_neededByteCount
.value()) > elemArrayBuffer
.ByteLength()) {
244 ErrorInvalidOperation("%s: bound element array buffer is too small for given count and offset", info
);
248 if (!ValidateBufferFetching(info
))
251 if (!mMaxFetchedVertices
||
252 !elemArrayBuffer
.Validate(type
, mMaxFetchedVertices
- 1, first
, count
, out_upperBound
))
254 ErrorInvalidOperation(
255 "%s: bound vertex attribute buffers do not have sufficient "
256 "size for given indices from the bound element array", info
);
260 if (uint32_t(primcount
) > mMaxFetchedInstances
) {
261 ErrorInvalidOperation("%s: bound instance attribute buffers do not have sufficient size for given primcount", info
);
265 // Bug 1008310 - Check if buffer has been used with a different previous type
266 if (elemArrayBuffer
.IsElementArrayUsedWithMultipleTypes()) {
267 GenerateWarning("%s: bound element array buffer previously used with a type other than "
268 "%s, this will affect performance.",
270 WebGLContext::EnumName(type
));
273 MakeContextCurrent();
275 if (mBoundFramebuffer
) {
276 if (!mBoundFramebuffer
->CheckAndInitializeAttachments()) {
277 ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info
);
281 ClearBackbufferIfNeeded();
284 if (!DoFakeVertexAttrib0(mMaxFetchedVertices
)) {
288 if (!DrawInstanced_check(info
)) {
292 BindFakeBlackTextures();
298 WebGLContext::DrawElements(GLenum mode
, GLsizei count
, GLenum type
,
299 WebGLintptr byteOffset
)
304 if (!ValidateDrawModeEnum(mode
, "drawElements: mode"))
307 GLuint upperBound
= 0;
308 if (!DrawElements_check(count
, type
, byteOffset
, 1, "drawElements",
314 RunContextLossTimer();
316 if (gl
->IsSupported(gl::GLFeature::draw_range_elements
)) {
317 gl
->fDrawRangeElements(mode
, 0, upperBound
,
318 count
, type
, reinterpret_cast<GLvoid
*>(byteOffset
));
320 gl
->fDrawElements(mode
, count
, type
, reinterpret_cast<GLvoid
*>(byteOffset
));
327 WebGLContext::DrawElementsInstanced(GLenum mode
, GLsizei count
, GLenum type
,
328 WebGLintptr byteOffset
, GLsizei primcount
)
333 if (!ValidateDrawModeEnum(mode
, "drawElementsInstanced: mode"))
336 GLuint upperBound
= 0;
337 if (!DrawElements_check(count
, type
, byteOffset
, primcount
, "drawElementsInstanced",
341 RunContextLossTimer();
342 gl
->fDrawElementsInstanced(mode
, count
, type
, reinterpret_cast<GLvoid
*>(byteOffset
), primcount
);
347 void WebGLContext::Draw_cleanup()
349 UndoFakeVertexAttrib0();
350 UnbindFakeBlackTextures();
352 if (!mBoundFramebuffer
) {
354 mShouldPresent
= true;
355 MOZ_ASSERT(!mBackbufferNeedsClear
);
358 if (gl
->WorkAroundDriverBugs()) {
359 if (gl
->Renderer() == gl::GLRenderer::Tegra
) {
360 mDrawCallsSinceLastFlush
++;
362 if (mDrawCallsSinceLastFlush
>= MAX_DRAW_CALLS_SINCE_FLUSH
) {
364 mDrawCallsSinceLastFlush
= 0;
369 // Let's check the viewport
370 const WebGLRectangleObject
* rect
= CurValidFBRectObject();
372 if (mViewportWidth
> rect
->Width() ||
373 mViewportHeight
> rect
->Height())
375 if (!mAlreadyWarnedAboutViewportLargerThanDest
) {
376 GenerateWarning("Drawing to a destination rect smaller than the viewport rect. "
377 "(This warning will only be given once)");
378 mAlreadyWarnedAboutViewportLargerThanDest
= true;
385 * Verify that state is consistent for drawing, and compute max number of elements (maxAllowedCount)
386 * that will be legal to be read from bound VBOs.
390 WebGLContext::ValidateBufferFetching(const char *info
)
393 GLint currentProgram
= 0;
394 MakeContextCurrent();
395 gl
->fGetIntegerv(LOCAL_GL_CURRENT_PROGRAM
, ¤tProgram
);
396 MOZ_ASSERT(GLuint(currentProgram
) == mCurrentProgram
->GLName(),
397 "WebGL: current program doesn't agree with GL state");
400 if (mBufferFetchingIsVerified
) {
404 bool hasPerVertex
= false;
405 uint32_t maxVertices
= UINT32_MAX
;
406 uint32_t maxInstances
= UINT32_MAX
;
407 uint32_t attribs
= mBoundVertexArray
->mAttribs
.Length();
409 for (uint32_t i
= 0; i
< attribs
; ++i
) {
410 const WebGLVertexAttribData
& vd
= mBoundVertexArray
->mAttribs
[i
];
412 // If the attrib array isn't enabled, there's nothing to check;
413 // it's a static value.
417 if (vd
.buf
== nullptr) {
418 ErrorInvalidOperation("%s: no VBO bound to enabled vertex attrib index %d!", info
, i
);
422 // If the attrib is not in use, then we don't have to validate
423 // it, just need to make sure that the binding is non-null.
424 if (!mCurrentProgram
->IsAttribInUse(i
))
428 CheckedUint32 checked_byteLength
= CheckedUint32(vd
.buf
->ByteLength()) - vd
.byteOffset
;
429 CheckedUint32 checked_sizeOfLastElement
= CheckedUint32(vd
.componentSize()) * vd
.size
;
431 if (!checked_byteLength
.isValid() ||
432 !checked_sizeOfLastElement
.isValid())
434 ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info
, i
);
438 if (checked_byteLength
.value() < checked_sizeOfLastElement
.value()) {
444 CheckedUint32 checked_maxAllowedCount
= ((checked_byteLength
- checked_sizeOfLastElement
) / vd
.actualStride()) + 1;
446 if (!checked_maxAllowedCount
.isValid()) {
447 ErrorInvalidOperation("%s: integer overflow occured while checking vertex attrib %d", info
, i
);
451 if (vd
.divisor
== 0) {
452 maxVertices
= std::min(maxVertices
, checked_maxAllowedCount
.value());
455 CheckedUint32 checked_curMaxInstances
= checked_maxAllowedCount
* vd
.divisor
;
457 uint32_t curMaxInstances
= UINT32_MAX
;
458 // If this isn't valid, it's because we overflowed our
459 // uint32 above. Just leave this as UINT32_MAX, since
460 // sizeof(uint32) becomes our limiting factor.
461 if (checked_curMaxInstances
.isValid()) {
462 curMaxInstances
= checked_curMaxInstances
.value();
465 maxInstances
= std::min(maxInstances
, curMaxInstances
);
469 mBufferFetchingIsVerified
= true;
470 mBufferFetchingHasPerVertex
= hasPerVertex
;
471 mMaxFetchedVertices
= maxVertices
;
472 mMaxFetchedInstances
= maxInstances
;
477 WebGLVertexAttrib0Status
478 WebGLContext::WhatDoesVertexAttrib0Need()
480 MOZ_ASSERT(mCurrentProgram
);
482 // work around Mac OSX crash, see bug 631420
484 if (gl
->WorkAroundDriverBugs() &&
485 mBoundVertexArray
->IsAttribArrayEnabled(0) &&
486 !mCurrentProgram
->IsAttribInUse(0))
488 return WebGLVertexAttrib0Status::EmulatedUninitializedArray
;
492 if (MOZ_LIKELY(gl
->IsGLES() ||
493 mBoundVertexArray
->IsAttribArrayEnabled(0)))
495 return WebGLVertexAttrib0Status::Default
;
498 return mCurrentProgram
->IsAttribInUse(0)
499 ? WebGLVertexAttrib0Status::EmulatedInitializedArray
500 : WebGLVertexAttrib0Status::EmulatedUninitializedArray
;
504 WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount
)
506 WebGLVertexAttrib0Status whatDoesAttrib0Need
= WhatDoesVertexAttrib0Need();
508 if (MOZ_LIKELY(whatDoesAttrib0Need
== WebGLVertexAttrib0Status::Default
))
511 if (!mAlreadyWarnedAboutFakeVertexAttrib0
) {
512 GenerateWarning("Drawing without vertex attrib 0 array enabled forces the browser "
513 "to do expensive emulation work when running on desktop OpenGL "
514 "platforms, for example on Mac. It is preferable to always draw "
515 "with vertex attrib 0 array enabled, by using bindAttribLocation "
516 "to bind some always-used attribute to location 0.");
517 mAlreadyWarnedAboutFakeVertexAttrib0
= true;
520 CheckedUint32 checked_dataSize
= CheckedUint32(vertexCount
) * 4 * sizeof(GLfloat
);
522 if (!checked_dataSize
.isValid()) {
523 ErrorOutOfMemory("Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation "
524 "with %d vertices. Try reducing the number of vertices.", vertexCount
);
528 GLuint dataSize
= checked_dataSize
.value();
530 if (!mFakeVertexAttrib0BufferObject
) {
531 gl
->fGenBuffers(1, &mFakeVertexAttrib0BufferObject
);
534 // if the VBO status is already exactly what we need, or if the only difference is that it's initialized and
535 // we don't need it to be, then consider it OK
536 bool vertexAttrib0BufferStatusOK
=
537 mFakeVertexAttrib0BufferStatus
== whatDoesAttrib0Need
||
538 (mFakeVertexAttrib0BufferStatus
== WebGLVertexAttrib0Status::EmulatedInitializedArray
&&
539 whatDoesAttrib0Need
== WebGLVertexAttrib0Status::EmulatedUninitializedArray
);
541 if (!vertexAttrib0BufferStatusOK
||
542 mFakeVertexAttrib0BufferObjectSize
< dataSize
||
543 mFakeVertexAttrib0BufferObjectVector
[0] != mVertexAttrib0Vector
[0] ||
544 mFakeVertexAttrib0BufferObjectVector
[1] != mVertexAttrib0Vector
[1] ||
545 mFakeVertexAttrib0BufferObjectVector
[2] != mVertexAttrib0Vector
[2] ||
546 mFakeVertexAttrib0BufferObjectVector
[3] != mVertexAttrib0Vector
[3])
548 mFakeVertexAttrib0BufferStatus
= whatDoesAttrib0Need
;
549 mFakeVertexAttrib0BufferObjectSize
= dataSize
;
550 mFakeVertexAttrib0BufferObjectVector
[0] = mVertexAttrib0Vector
[0];
551 mFakeVertexAttrib0BufferObjectVector
[1] = mVertexAttrib0Vector
[1];
552 mFakeVertexAttrib0BufferObjectVector
[2] = mVertexAttrib0Vector
[2];
553 mFakeVertexAttrib0BufferObjectVector
[3] = mVertexAttrib0Vector
[3];
555 gl
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mFakeVertexAttrib0BufferObject
);
557 GetAndFlushUnderlyingGLErrors();
559 if (mFakeVertexAttrib0BufferStatus
== WebGLVertexAttrib0Status::EmulatedInitializedArray
) {
560 UniquePtr
<GLfloat
[]> array(new ((fallible_t())) GLfloat
[4 * vertexCount
]);
562 ErrorOutOfMemory("Fake attrib0 array.");
565 for(size_t i
= 0; i
< vertexCount
; ++i
) {
566 array
[4 * i
+ 0] = mVertexAttrib0Vector
[0];
567 array
[4 * i
+ 1] = mVertexAttrib0Vector
[1];
568 array
[4 * i
+ 2] = mVertexAttrib0Vector
[2];
569 array
[4 * i
+ 3] = mVertexAttrib0Vector
[3];
571 gl
->fBufferData(LOCAL_GL_ARRAY_BUFFER
, dataSize
, array
.get(), LOCAL_GL_DYNAMIC_DRAW
);
573 gl
->fBufferData(LOCAL_GL_ARRAY_BUFFER
, dataSize
, nullptr, LOCAL_GL_DYNAMIC_DRAW
);
575 GLenum error
= GetAndFlushUnderlyingGLErrors();
577 gl
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mBoundArrayBuffer
? mBoundArrayBuffer
->GLName() : 0);
579 // note that we do this error checking and early return AFTER having restored the buffer binding above
581 ErrorOutOfMemory("Ran out of memory trying to construct a fake vertex attrib 0 array for a draw-operation "
582 "with %d vertices. Try reducing the number of vertices.", vertexCount
);
587 gl
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mFakeVertexAttrib0BufferObject
);
588 gl
->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT
, LOCAL_GL_FALSE
, 0, 0);
594 WebGLContext::UndoFakeVertexAttrib0()
596 WebGLVertexAttrib0Status whatDoesAttrib0Need
= WhatDoesVertexAttrib0Need();
598 if (MOZ_LIKELY(whatDoesAttrib0Need
== WebGLVertexAttrib0Status::Default
))
601 if (mBoundVertexArray
->HasAttrib(0) && mBoundVertexArray
->mAttribs
[0].buf
) {
602 const WebGLVertexAttribData
& attrib0
= mBoundVertexArray
->mAttribs
[0];
603 gl
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, attrib0
.buf
->GLName());
604 gl
->fVertexAttribPointer(0,
609 reinterpret_cast<const GLvoid
*>(attrib0
.byteOffset
));
611 gl
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, 0);
614 gl
->fBindBuffer(LOCAL_GL_ARRAY_BUFFER
, mBoundArrayBuffer
? mBoundArrayBuffer
->GLName() : 0);
617 WebGLContextFakeBlackStatus
618 WebGLContext::ResolvedFakeBlackStatus()
620 // handle this case first, it's the generic case
621 if (MOZ_LIKELY(mFakeBlackStatus
== WebGLContextFakeBlackStatus::NotNeeded
))
622 return mFakeBlackStatus
;
624 if (mFakeBlackStatus
== WebGLContextFakeBlackStatus::Needed
)
625 return mFakeBlackStatus
;
627 for (int32_t i
= 0; i
< mGLMaxTextureUnits
; ++i
) {
628 if ((mBound2DTextures
[i
] && mBound2DTextures
[i
]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded
) ||
629 (mBoundCubeMapTextures
[i
] && mBoundCubeMapTextures
[i
]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded
))
631 mFakeBlackStatus
= WebGLContextFakeBlackStatus::Needed
;
632 return mFakeBlackStatus
;
636 // we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
637 // that means that we do NOT need it.
638 mFakeBlackStatus
= WebGLContextFakeBlackStatus::NotNeeded
;
639 return mFakeBlackStatus
;
643 WebGLContext::BindFakeBlackTexturesHelper(
645 const nsTArray
<WebGLRefPtr
<WebGLTexture
> > & boundTexturesArray
,
646 UniquePtr
<FakeBlackTexture
> & opaqueTextureScopedPtr
,
647 UniquePtr
<FakeBlackTexture
> & transparentTextureScopedPtr
)
649 for (int32_t i
= 0; i
< mGLMaxTextureUnits
; ++i
) {
650 if (!boundTexturesArray
[i
]) {
654 WebGLTextureFakeBlackStatus s
= boundTexturesArray
[i
]->ResolvedFakeBlackStatus();
655 MOZ_ASSERT(s
!= WebGLTextureFakeBlackStatus::Unknown
);
657 if (MOZ_LIKELY(s
== WebGLTextureFakeBlackStatus::NotNeeded
)) {
661 bool alpha
= s
== WebGLTextureFakeBlackStatus::UninitializedImageData
&&
662 FormatHasAlpha(boundTexturesArray
[i
]->ImageInfoBase().WebGLFormat());
663 UniquePtr
<FakeBlackTexture
>&
664 blackTexturePtr
= alpha
665 ? transparentTextureScopedPtr
666 : opaqueTextureScopedPtr
;
668 if (!blackTexturePtr
) {
669 GLenum format
= alpha
? LOCAL_GL_RGBA
: LOCAL_GL_RGB
;
670 blackTexturePtr
= MakeUnique
<FakeBlackTexture
>(gl
, target
, format
);
673 gl
->fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
674 gl
->fBindTexture(target
,
675 blackTexturePtr
->GLName());
680 WebGLContext::BindFakeBlackTextures()
682 // this is the generic case: try to return early
683 if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded
))
686 BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_2D
,
688 mBlackOpaqueTexture2D
,
689 mBlackTransparentTexture2D
);
690 BindFakeBlackTexturesHelper(LOCAL_GL_TEXTURE_CUBE_MAP
,
691 mBoundCubeMapTextures
,
692 mBlackOpaqueTextureCubeMap
,
693 mBlackTransparentTextureCubeMap
);
697 WebGLContext::UnbindFakeBlackTextures()
699 // this is the generic case: try to return early
700 if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded
))
703 for (int32_t i
= 0; i
< mGLMaxTextureUnits
; ++i
) {
704 if (mBound2DTextures
[i
] && mBound2DTextures
[i
]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded
) {
705 gl
->fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
706 gl
->fBindTexture(LOCAL_GL_TEXTURE_2D
, mBound2DTextures
[i
]->GLName());
708 if (mBoundCubeMapTextures
[i
] && mBoundCubeMapTextures
[i
]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded
) {
709 gl
->fActiveTexture(LOCAL_GL_TEXTURE0
+ i
);
710 gl
->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP
, mBoundCubeMapTextures
[i
]->GLName());
714 gl
->fActiveTexture(LOCAL_GL_TEXTURE0
+ mActiveTexture
);
717 WebGLContext::FakeBlackTexture::FakeBlackTexture(GLContext
*gl
, GLenum target
, GLenum format
)
721 MOZ_ASSERT(target
== LOCAL_GL_TEXTURE_2D
|| target
== LOCAL_GL_TEXTURE_CUBE_MAP
);
722 MOZ_ASSERT(format
== LOCAL_GL_RGB
|| format
== LOCAL_GL_RGBA
);
725 GLuint formerBinding
= 0;
726 gl
->GetUIntegerv(target
== LOCAL_GL_TEXTURE_2D
727 ? LOCAL_GL_TEXTURE_BINDING_2D
728 : LOCAL_GL_TEXTURE_BINDING_CUBE_MAP
,
730 gl
->fGenTextures(1, &mGLName
);
731 gl
->fBindTexture(target
, mGLName
);
733 // we allocate our zeros on the heap, and we overallocate (16 bytes instead of 4)
734 // to minimize the risk of running into a driver bug in texImage2D, as it is
735 // a bit unusual maybe to create 1x1 textures, and the stack may not have the alignment
736 // that texImage2D expects.
737 UniquePtr
<uint8_t> zeros((uint8_t*)moz_xcalloc(1, 16));
738 if (target
== LOCAL_GL_TEXTURE_2D
) {
739 gl
->fTexImage2D(target
, 0, format
, 1, 1,
740 0, format
, LOCAL_GL_UNSIGNED_BYTE
, zeros
.get());
742 for (GLuint i
= 0; i
< 6; ++i
) {
743 gl
->fTexImage2D(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ i
, 0, format
, 1, 1,
744 0, format
, LOCAL_GL_UNSIGNED_BYTE
, zeros
.get());
748 gl
->fBindTexture(target
, formerBinding
);
751 WebGLContext::FakeBlackTexture::~FakeBlackTexture()
755 mGL
->fDeleteTextures(1, &mGLName
);