1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "WebGLTexture.h"
9 #include "mozilla/dom/WebGLRenderingContextBinding.h"
10 #include "mozilla/Scoped.h"
11 #include "ScopedGLHelpers.h"
12 #include "WebGLContext.h"
13 #include "WebGLContextUtils.h"
14 #include "WebGLTexelConversions.h"
18 using namespace mozilla
;
21 WebGLTexture::WrapObject(JSContext
*cx
) {
22 return dom::WebGLTextureBinding::Wrap(cx
, this);
25 WebGLTexture::WebGLTexture(WebGLContext
*context
)
27 , WebGLContextBoundObject(context
)
28 , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR
)
29 , mMagFilter(LOCAL_GL_LINEAR
)
30 , mWrapS(LOCAL_GL_REPEAT
)
31 , mWrapT(LOCAL_GL_REPEAT
)
33 , mMaxLevelWithCustomImages(0)
34 , mHaveGeneratedMipmap(false)
35 , mFakeBlackStatus(WebGLTextureFakeBlackStatus::IncompleteTexture
)
38 mContext
->MakeContextCurrent();
39 mContext
->gl
->fGenTextures(1, &mGLName
);
40 mContext
->mTextures
.insertBack(this);
44 WebGLTexture::Delete() {
46 mContext
->MakeContextCurrent();
47 mContext
->gl
->fDeleteTextures(1, &mGLName
);
48 LinkedListElement
<WebGLTexture
>::removeFrom(mContext
->mTextures
);
52 WebGLTexture::ImageInfo::MemoryUsage() const {
53 if (mImageDataStatus
== WebGLImageDataStatus::NoImageData
)
55 int64_t bitsPerTexel
= WebGLContext::GetBitsPerTexel(mWebGLFormat
, mWebGLType
);
56 return int64_t(mWidth
) * int64_t(mHeight
) * bitsPerTexel
/8;
60 WebGLTexture::MemoryUsage() const {
64 for(size_t face
= 0; face
< mFacesCount
; face
++) {
65 if (mHaveGeneratedMipmap
) {
66 // Each mipmap level is 1/4 the size of the previous level
67 // 1 + x + x^2 + ... = 1/(1-x)
68 // for x = 1/4, we get 1/(1-1/4) = 4/3
69 result
+= ImageInfoAtFace(face
, 0).MemoryUsage() * 4 / 3;
71 for(size_t level
= 0; level
<= mMaxLevelWithCustomImages
; level
++)
72 result
+= ImageInfoAtFace(face
, level
).MemoryUsage();
79 WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImageTarget
) const {
80 if (mHaveGeneratedMipmap
)
83 // We want a copy here so we can modify it temporarily.
84 ImageInfo expected
= ImageInfoAt(texImageTarget
, 0);
86 // checks if custom level>0 images are all defined up to the highest level defined
87 // and have the expected dimensions
88 for (size_t level
= 0; level
<= mMaxLevelWithCustomImages
; ++level
) {
89 const ImageInfo
& actual
= ImageInfoAt(texImageTarget
, level
);
90 if (actual
!= expected
)
92 expected
.mWidth
= std::max(1, expected
.mWidth
>> 1);
93 expected
.mHeight
= std::max(1, expected
.mHeight
>> 1);
95 // if the current level has size 1x1, we can stop here: the spec doesn't seem to forbid the existence
96 // of extra useless levels.
97 if (actual
.mWidth
== 1 && actual
.mHeight
== 1)
101 // if we're here, we've exhausted all levels without finding a 1x1 image
106 WebGLTexture::Bind(GLenum aTarget
) {
107 // this function should only be called by bindTexture().
108 // it assumes that the GL context is already current.
110 bool firstTimeThisTextureIsBound
= !HasEverBeenBound();
112 if (firstTimeThisTextureIsBound
) {
114 } else if (aTarget
!= Target()) {
115 mContext
->ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
116 // very important to return here before modifying texture state! This was the place when I lost a whole day figuring
117 // very strange 'invalid write' crashes.
121 GLuint name
= GLName();
122 GLenum target
= Target();
124 mContext
->gl
->fBindTexture(target
, name
);
126 if (firstTimeThisTextureIsBound
) {
127 mFacesCount
= (mTarget
== LOCAL_GL_TEXTURE_2D
) ? 1 : 6;
128 EnsureMaxLevelWithCustomImagesAtLeast(0);
129 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown
);
131 // thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
132 // present in GLES 2, but is present in GL and it seems as if for cube maps
133 // we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior.
134 if (mTarget
== LOCAL_GL_TEXTURE_CUBE_MAP
&& !mContext
->gl
->IsGLES())
135 mContext
->gl
->fTexParameteri(mTarget
, LOCAL_GL_TEXTURE_WRAP_R
, LOCAL_GL_CLAMP_TO_EDGE
);
140 WebGLTexture::SetImageInfo(GLenum aTarget
, GLint aLevel
,
141 GLsizei aWidth
, GLsizei aHeight
,
142 GLenum aFormat
, GLenum aType
, WebGLImageDataStatus aStatus
)
144 // TODO(djg): I suspected the following ASSERT and check are
145 // trying to express more than they're saying, probably
146 // to do with cubemap targets. We should do this
147 // properly. https://bugzilla.mozilla.org/show_bug.cgi?id=1006908
148 MOZ_ASSERT((aTarget
== LOCAL_GL_TEXTURE_2D
) == (mTarget
== LOCAL_GL_TEXTURE_2D
));
149 if ((aTarget
== LOCAL_GL_TEXTURE_2D
) != (mTarget
== LOCAL_GL_TEXTURE_2D
)) {
153 EnsureMaxLevelWithCustomImagesAtLeast(aLevel
);
155 ImageInfoAt(aTarget
, aLevel
) = ImageInfo(aWidth
, aHeight
, aFormat
, aType
, aStatus
);
160 // Invalidate framebuffer status cache
161 NotifyFBsStatusChanged();
163 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown
);
167 WebGLTexture::SetGeneratedMipmap() {
168 if (!mHaveGeneratedMipmap
) {
169 mHaveGeneratedMipmap
= true;
170 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown
);
175 WebGLTexture::SetCustomMipmap() {
176 if (mHaveGeneratedMipmap
) {
177 // if we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
178 // we need to compute now all the mipmap image info.
180 // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info,
181 // and are power-of-two.
182 ImageInfo imageInfo
= ImageInfoAtFace(0, 0);
183 NS_ASSERTION(imageInfo
.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
185 GLsizei size
= std::max(imageInfo
.mWidth
, imageInfo
.mHeight
);
187 // so, the size is a power of two, let's find its log in base 2.
189 for (GLsizei n
= size
; n
> 1; n
>>= 1)
192 EnsureMaxLevelWithCustomImagesAtLeast(maxLevel
);
194 for (size_t level
= 1; level
<= maxLevel
; ++level
) {
195 // again, since the sizes are powers of two, no need for any max(1,x) computation
196 imageInfo
.mWidth
>>= 1;
197 imageInfo
.mHeight
>>= 1;
198 for(size_t face
= 0; face
< mFacesCount
; ++face
)
199 ImageInfoAtFace(face
, level
) = imageInfo
;
202 mHaveGeneratedMipmap
= false;
206 WebGLTexture::AreAllLevel0ImageInfosEqual() const {
207 for (size_t face
= 1; face
< mFacesCount
; ++face
) {
208 if (ImageInfoAtFace(face
, 0) != ImageInfoAtFace(0, 0))
215 WebGLTexture::IsMipmapTexture2DComplete() const {
216 if (mTarget
!= LOCAL_GL_TEXTURE_2D
)
218 if (!ImageInfoAt(LOCAL_GL_TEXTURE_2D
, 0).IsPositive())
220 if (mHaveGeneratedMipmap
)
222 return DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D
);
226 WebGLTexture::IsCubeComplete() const {
227 if (mTarget
!= LOCAL_GL_TEXTURE_CUBE_MAP
)
229 const ImageInfo
&first
= ImageInfoAt(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
, 0);
230 if (!first
.IsPositive() || !first
.IsSquare())
232 return AreAllLevel0ImageInfosEqual();
236 GLCubeMapFaceById(int id
)
238 GLenum result
= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ id
;
239 MOZ_ASSERT(result
>= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
&&
240 result
<= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
);
245 WebGLTexture::IsMipmapCubeComplete() const {
246 if (!IsCubeComplete()) // in particular, this checks that this is a cube map
248 for (int i
= 0; i
< 6; i
++) {
249 GLenum face
= GLCubeMapFaceById(i
);
250 if (!DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(face
))
256 WebGLTextureFakeBlackStatus
257 WebGLTexture::ResolvedFakeBlackStatus() {
258 if (MOZ_LIKELY(mFakeBlackStatus
!= WebGLTextureFakeBlackStatus::Unknown
)) {
259 return mFakeBlackStatus
;
262 // Determine if the texture needs to be faked as a black texture.
263 // See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec.
265 for (size_t face
= 0; face
< mFacesCount
; ++face
) {
266 if (ImageInfoAtFace(face
, 0).mImageDataStatus
== WebGLImageDataStatus::NoImageData
) {
267 // In case of undefined texture image, we don't print any message because this is a very common
268 // and often legitimate case (asynchronous texture loading).
269 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
270 return mFakeBlackStatus
;
274 const char *msg_rendering_as_black
275 = "A texture is going to be rendered as if it were black, as per the OpenGL ES 2.0.24 spec section 3.8.2, "
278 if (mTarget
== LOCAL_GL_TEXTURE_2D
)
280 if (DoesMinFilterRequireMipmap())
282 if (!IsMipmapTexture2DComplete()) {
283 mContext
->GenerateWarning
284 ("%s is a 2D texture, with a minification filter requiring a mipmap, "
285 "and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black
);
286 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
287 } else if (!ImageInfoAt(mTarget
, 0).IsPowerOfTwo()) {
288 mContext
->GenerateWarning
289 ("%s is a 2D texture, with a minification filter requiring a mipmap, "
290 "and either its width or height is not a power of two.", msg_rendering_as_black
);
291 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
294 else // no mipmap required
296 if (!ImageInfoAt(mTarget
, 0).IsPositive()) {
297 mContext
->GenerateWarning
298 ("%s is a 2D texture and its width or height is equal to zero.",
299 msg_rendering_as_black
);
300 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
301 } else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(mTarget
, 0).IsPowerOfTwo()) {
302 mContext
->GenerateWarning
303 ("%s is a 2D texture, with a minification filter not requiring a mipmap, "
304 "with its width or height not a power of two, and with a wrap mode "
305 "different from CLAMP_TO_EDGE.", msg_rendering_as_black
);
306 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
312 bool areAllLevel0ImagesPOT
= true;
313 for (size_t face
= 0; face
< mFacesCount
; ++face
)
314 areAllLevel0ImagesPOT
&= ImageInfoAtFace(face
, 0).IsPowerOfTwo();
316 if (DoesMinFilterRequireMipmap())
318 if (!IsMipmapCubeComplete()) {
319 mContext
->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
320 "and is not mipmap cube complete (as defined in section 3.7.10).",
321 msg_rendering_as_black
);
322 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
323 } else if (!areAllLevel0ImagesPOT
) {
324 mContext
->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
325 "and either the width or the height of some level 0 image is not a power of two.",
326 msg_rendering_as_black
);
327 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
330 else // no mipmap required
332 if (!IsCubeComplete()) {
333 mContext
->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
334 "and is not cube complete (as defined in section 3.7.10).",
335 msg_rendering_as_black
);
336 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
337 } else if (!AreBothWrapModesClampToEdge() && !areAllLevel0ImagesPOT
) {
338 mContext
->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
339 "with some level 0 image having width or height not a power of two, and with a wrap mode "
340 "different from CLAMP_TO_EDGE.", msg_rendering_as_black
);
341 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
346 if (ImageInfoBase().mWebGLType
== LOCAL_GL_FLOAT
&&
347 !Context()->IsExtensionEnabled(WebGLExtensionID::OES_texture_float_linear
))
349 if (mMinFilter
== LOCAL_GL_LINEAR
||
350 mMinFilter
== LOCAL_GL_LINEAR_MIPMAP_LINEAR
||
351 mMinFilter
== LOCAL_GL_LINEAR_MIPMAP_NEAREST
||
352 mMinFilter
== LOCAL_GL_NEAREST_MIPMAP_LINEAR
)
354 mContext
->GenerateWarning("%s is a texture with a linear minification filter, "
355 "which is not compatible with gl.FLOAT by default. "
356 "Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black
);
357 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
359 else if (mMagFilter
== LOCAL_GL_LINEAR
)
361 mContext
->GenerateWarning("%s is a texture with a linear magnification filter, "
362 "which is not compatible with gl.FLOAT by default. "
363 "Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black
);
364 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
366 } else if (ImageInfoBase().mWebGLType
== LOCAL_GL_HALF_FLOAT_OES
&&
367 !Context()->IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float_linear
))
369 if (mMinFilter
== LOCAL_GL_LINEAR
||
370 mMinFilter
== LOCAL_GL_LINEAR_MIPMAP_LINEAR
||
371 mMinFilter
== LOCAL_GL_LINEAR_MIPMAP_NEAREST
||
372 mMinFilter
== LOCAL_GL_NEAREST_MIPMAP_LINEAR
)
374 mContext
->GenerateWarning("%s is a texture with a linear minification filter, "
375 "which is not compatible with gl.HALF_FLOAT by default. "
376 "Try enabling the OES_texture_half_float_linear extension if supported.", msg_rendering_as_black
);
377 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
379 else if (mMagFilter
== LOCAL_GL_LINEAR
)
381 mContext
->GenerateWarning("%s is a texture with a linear magnification filter, "
382 "which is not compatible with gl.HALF_FLOAT by default. "
383 "Try enabling the OES_texture_half_float_linear extension if supported.", msg_rendering_as_black
);
384 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::IncompleteTexture
;
388 // We have exhausted all cases of incomplete textures, where we would need opaque black.
389 // We may still need transparent black in case of uninitialized image data.
390 bool hasUninitializedImageData
= false;
391 for (size_t level
= 0; level
<= mMaxLevelWithCustomImages
; ++level
) {
392 for (size_t face
= 0; face
< mFacesCount
; ++face
) {
393 hasUninitializedImageData
|= (ImageInfoAtFace(face
, level
).mImageDataStatus
== WebGLImageDataStatus::UninitializedImageData
);
397 if (hasUninitializedImageData
) {
398 bool hasAnyInitializedImageData
= false;
399 for (size_t level
= 0; level
<= mMaxLevelWithCustomImages
; ++level
) {
400 for (size_t face
= 0; face
< mFacesCount
; ++face
) {
401 if (ImageInfoAtFace(face
, level
).mImageDataStatus
== WebGLImageDataStatus::InitializedImageData
) {
402 hasAnyInitializedImageData
= true;
406 if (hasAnyInitializedImageData
) {
411 if (hasAnyInitializedImageData
) {
412 // The texture contains some initialized image data, and some uninitialized image data.
413 // In this case, we have no choice but to initialize all image data now. Fortunately,
414 // in this case we know that we can't be dealing with a depth texture per WEBGL_depth_texture
415 // and ANGLE_depth_texture (which allow only one image per texture) so we can assume that
416 // glTexImage2D is able to upload data to images.
417 for (size_t level
= 0; level
<= mMaxLevelWithCustomImages
; ++level
) {
418 for (size_t face
= 0; face
< mFacesCount
; ++face
) {
419 GLenum imageTarget
= mTarget
== LOCAL_GL_TEXTURE_2D
420 ? LOCAL_GL_TEXTURE_2D
421 : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X
+ face
;
422 const ImageInfo
& imageInfo
= ImageInfoAt(imageTarget
, level
);
423 if (imageInfo
.mImageDataStatus
== WebGLImageDataStatus::UninitializedImageData
) {
424 DoDeferredImageInitialization(imageTarget
, level
);
428 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::NotNeeded
;
430 // The texture only contains uninitialized image data. In this case,
431 // we can use a black texture for it.
432 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::UninitializedImageData
;
436 // we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
437 // that means that we do NOT need it.
438 if (mFakeBlackStatus
== WebGLTextureFakeBlackStatus::Unknown
) {
439 mFakeBlackStatus
= WebGLTextureFakeBlackStatus::NotNeeded
;
442 MOZ_ASSERT(mFakeBlackStatus
!= WebGLTextureFakeBlackStatus::Unknown
);
443 return mFakeBlackStatus
;
448 ClearByMask(WebGLContext
* context
, GLbitfield mask
)
450 gl::GLContext
* gl
= context
->GL();
451 MOZ_ASSERT(gl
->IsCurrent());
453 GLenum status
= gl
->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER
);
454 if (status
!= LOCAL_GL_FRAMEBUFFER_COMPLETE
)
457 bool colorAttachmentsMask
[WebGLContext::kMaxColorAttachments
] = {false};
458 if (mask
& LOCAL_GL_COLOR_BUFFER_BIT
) {
459 colorAttachmentsMask
[0] = true;
462 context
->ForceClearFramebufferWithDefaultValues(mask
, colorAttachmentsMask
);
466 // `mask` from glClear.
468 ClearWithTempFB(WebGLContext
* context
, GLuint tex
,
469 GLenum texImageTarget
, GLint level
,
470 GLenum baseInternalFormat
,
471 GLsizei width
, GLsizei height
)
473 if (texImageTarget
!= LOCAL_GL_TEXTURE_2D
)
476 gl::GLContext
* gl
= context
->GL();
477 MOZ_ASSERT(gl
->IsCurrent());
479 gl::ScopedFramebuffer
fb(gl
);
480 gl::ScopedBindFramebuffer
autoFB(gl
, fb
.FB());
483 switch (baseInternalFormat
) {
484 case LOCAL_GL_LUMINANCE
:
485 case LOCAL_GL_LUMINANCE_ALPHA
:
491 mask
= LOCAL_GL_COLOR_BUFFER_BIT
;
492 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_COLOR_ATTACHMENT0
,
493 texImageTarget
, tex
, level
);
496 case LOCAL_GL_DEPTH_COMPONENT
:
497 mask
= LOCAL_GL_DEPTH_BUFFER_BIT
;
498 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_ATTACHMENT
,
499 texImageTarget
, tex
, level
);
502 case LOCAL_GL_DEPTH_STENCIL
:
503 mask
= LOCAL_GL_DEPTH_BUFFER_BIT
|
504 LOCAL_GL_STENCIL_BUFFER_BIT
;
505 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_DEPTH_ATTACHMENT
,
506 texImageTarget
, tex
, level
);
507 gl
->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_STENCIL_ATTACHMENT
,
508 texImageTarget
, tex
, level
);
516 if (ClearByMask(context
, mask
))
519 // Failed to simply build an FB from the tex, but maybe it needs a
520 // color buffer to be complete.
522 if (mask
& LOCAL_GL_COLOR_BUFFER_BIT
) {
523 // Nope, it already had one.
527 gl::ScopedRenderbuffer
rb(gl
);
529 gl::ScopedBindRenderbuffer(gl
, rb
.RB());
530 gl
->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER
,
535 gl
->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER
, LOCAL_GL_COLOR_ATTACHMENT0
,
536 LOCAL_GL_RENDERBUFFER
, rb
.RB());
537 mask
|= LOCAL_GL_COLOR_BUFFER_BIT
;
540 return ClearByMask(context
, mask
);
545 WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget
, GLint level
)
547 const ImageInfo
& imageInfo
= ImageInfoAt(imageTarget
, level
);
548 MOZ_ASSERT(imageInfo
.mImageDataStatus
== WebGLImageDataStatus::UninitializedImageData
);
550 mContext
->MakeContextCurrent();
552 // Try to clear with glCLear.
553 GLenum format
= imageInfo
.mWebGLFormat
;
554 GLenum type
= imageInfo
.mWebGLType
;
555 WebGLTexelFormat texelformat
= GetWebGLTexelFormat(format
, type
);
557 bool cleared
= ClearWithTempFB(mContext
, GLName(),
559 format
, imageInfo
.mHeight
, imageInfo
.mWidth
);
561 SetImageDataStatus(imageTarget
, level
, WebGLImageDataStatus::InitializedImageData
);
565 // That didn't work. Try uploading zeros then.
566 gl::ScopedBindTexture
autoBindTex(mContext
->gl
, GLName(), mTarget
);
568 uint32_t texelsize
= WebGLTexelConversions::TexelBytesForFormat(texelformat
);
569 CheckedUint32 checked_byteLength
570 = WebGLContext::GetImageSize(
574 mContext
->mPixelStoreUnpackAlignment
);
575 MOZ_ASSERT(checked_byteLength
.isValid()); // should have been checked earlier
577 UniquePtr
<uint8_t> zeros((uint8_t*)moz_xcalloc(1, checked_byteLength
.value())); // Infallible for now.
579 gl::GLContext
* gl
= mContext
->gl
;
580 GLenum driverType
= DriverTypeFromType(gl
, type
);
581 GLenum driverInternalFormat
= LOCAL_GL_NONE
;
582 GLenum driverFormat
= LOCAL_GL_NONE
;
583 DriverFormatsFromFormatAndType(gl
, format
, type
, &driverInternalFormat
, &driverFormat
);
585 mContext
->GetAndFlushUnderlyingGLErrors();
586 gl
->fTexImage2D(imageTarget
, level
, driverInternalFormat
,
587 imageInfo
.mWidth
, imageInfo
.mHeight
,
588 0, driverFormat
, driverType
,
590 GLenum error
= mContext
->GetAndFlushUnderlyingGLErrors();
592 // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here.
593 printf_stderr("Error: 0x%4x\n", error
);
594 MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past.
597 SetImageDataStatus(imageTarget
, level
, WebGLImageDataStatus::InitializedImageData
);
601 WebGLTexture::SetFakeBlackStatus(WebGLTextureFakeBlackStatus x
)
603 mFakeBlackStatus
= x
;
604 mContext
->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown
);
607 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture
)
609 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTexture
, AddRef
)
610 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTexture
, Release
)