1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/content/canvas/src/WebGLTexture.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,485 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "WebGLContext.h" 1.10 +#include "WebGLContextUtils.h" 1.11 +#include "WebGLTexture.h" 1.12 +#include "GLContext.h" 1.13 +#include "ScopedGLHelpers.h" 1.14 +#include "WebGLTexelConversions.h" 1.15 +#include "mozilla/dom/WebGLRenderingContextBinding.h" 1.16 +#include <algorithm> 1.17 + 1.18 +using namespace mozilla; 1.19 + 1.20 +JSObject* 1.21 +WebGLTexture::WrapObject(JSContext *cx) { 1.22 + return dom::WebGLTextureBinding::Wrap(cx, this); 1.23 +} 1.24 + 1.25 +WebGLTexture::WebGLTexture(WebGLContext *context) 1.26 + : WebGLContextBoundObject(context) 1.27 + , mHasEverBeenBound(false) 1.28 + , mTarget(0) 1.29 + , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR) 1.30 + , mMagFilter(LOCAL_GL_LINEAR) 1.31 + , mWrapS(LOCAL_GL_REPEAT) 1.32 + , mWrapT(LOCAL_GL_REPEAT) 1.33 + , mFacesCount(0) 1.34 + , mMaxLevelWithCustomImages(0) 1.35 + , mHaveGeneratedMipmap(false) 1.36 + , mFakeBlackStatus(WebGLTextureFakeBlackStatus::IncompleteTexture) 1.37 +{ 1.38 + SetIsDOMBinding(); 1.39 + mContext->MakeContextCurrent(); 1.40 + mContext->gl->fGenTextures(1, &mGLName); 1.41 + mContext->mTextures.insertBack(this); 1.42 +} 1.43 + 1.44 +void 1.45 +WebGLTexture::Delete() { 1.46 + mImageInfos.Clear(); 1.47 + mContext->MakeContextCurrent(); 1.48 + mContext->gl->fDeleteTextures(1, &mGLName); 1.49 + LinkedListElement<WebGLTexture>::removeFrom(mContext->mTextures); 1.50 +} 1.51 + 1.52 +int64_t 1.53 +WebGLTexture::ImageInfo::MemoryUsage() const { 1.54 + if (mImageDataStatus == WebGLImageDataStatus::NoImageData) 1.55 + return 0; 1.56 + int64_t bitsPerTexel = WebGLContext::GetBitsPerTexel(mWebGLFormat, mWebGLType); 1.57 + return int64_t(mWidth) * int64_t(mHeight) * bitsPerTexel/8; 1.58 +} 1.59 + 1.60 +int64_t 1.61 +WebGLTexture::MemoryUsage() const { 1.62 + if (IsDeleted()) 1.63 + return 0; 1.64 + int64_t result = 0; 1.65 + for(size_t face = 0; face < mFacesCount; face++) { 1.66 + if (mHaveGeneratedMipmap) { 1.67 + // Each mipmap level is 1/4 the size of the previous level 1.68 + // 1 + x + x^2 + ... = 1/(1-x) 1.69 + // for x = 1/4, we get 1/(1-1/4) = 4/3 1.70 + result += ImageInfoAtFace(face, 0).MemoryUsage() * 4 / 3; 1.71 + } else { 1.72 + for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++) 1.73 + result += ImageInfoAtFace(face, level).MemoryUsage(); 1.74 + } 1.75 + } 1.76 + return result; 1.77 +} 1.78 + 1.79 +bool 1.80 +WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImageTarget) const { 1.81 + if (mHaveGeneratedMipmap) 1.82 + return true; 1.83 + 1.84 + // We want a copy here so we can modify it temporarily. 1.85 + ImageInfo expected = ImageInfoAt(texImageTarget, 0); 1.86 + 1.87 + // checks if custom level>0 images are all defined up to the highest level defined 1.88 + // and have the expected dimensions 1.89 + for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) { 1.90 + const ImageInfo& actual = ImageInfoAt(texImageTarget, level); 1.91 + if (actual != expected) 1.92 + return false; 1.93 + expected.mWidth = std::max(1, expected.mWidth >> 1); 1.94 + expected.mHeight = std::max(1, expected.mHeight >> 1); 1.95 + 1.96 + // if the current level has size 1x1, we can stop here: the spec doesn't seem to forbid the existence 1.97 + // of extra useless levels. 1.98 + if (actual.mWidth == 1 && actual.mHeight == 1) 1.99 + return true; 1.100 + } 1.101 + 1.102 + // if we're here, we've exhausted all levels without finding a 1x1 image 1.103 + return false; 1.104 +} 1.105 + 1.106 +void 1.107 +WebGLTexture::Bind(GLenum aTarget) { 1.108 + // this function should only be called by bindTexture(). 1.109 + // it assumes that the GL context is already current. 1.110 + 1.111 + bool firstTimeThisTextureIsBound = !mHasEverBeenBound; 1.112 + 1.113 + if (!firstTimeThisTextureIsBound && aTarget != mTarget) { 1.114 + mContext->ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target"); 1.115 + // very important to return here before modifying texture state! This was the place when I lost a whole day figuring 1.116 + // very strange 'invalid write' crashes. 1.117 + return; 1.118 + } 1.119 + 1.120 + mTarget = aTarget; 1.121 + 1.122 + mContext->gl->fBindTexture(mTarget, mGLName); 1.123 + 1.124 + if (firstTimeThisTextureIsBound) { 1.125 + mFacesCount = (mTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6; 1.126 + EnsureMaxLevelWithCustomImagesAtLeast(0); 1.127 + SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); 1.128 + 1.129 + // thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not 1.130 + // present in GLES 2, but is present in GL and it seems as if for cube maps 1.131 + // we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior. 1.132 + if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES()) 1.133 + mContext->gl->fTexParameteri(mTarget, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE); 1.134 + } 1.135 + 1.136 + mHasEverBeenBound = true; 1.137 +} 1.138 + 1.139 +void 1.140 +WebGLTexture::SetImageInfo(GLenum aTarget, GLint aLevel, 1.141 + GLsizei aWidth, GLsizei aHeight, 1.142 + GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus) 1.143 +{ 1.144 + if ( (aTarget == LOCAL_GL_TEXTURE_2D) != (mTarget == LOCAL_GL_TEXTURE_2D) ) 1.145 + return; 1.146 + 1.147 + EnsureMaxLevelWithCustomImagesAtLeast(aLevel); 1.148 + 1.149 + ImageInfoAt(aTarget, aLevel) = ImageInfo(aWidth, aHeight, aFormat, aType, aStatus); 1.150 + 1.151 + if (aLevel > 0) 1.152 + SetCustomMipmap(); 1.153 + 1.154 + // Invalidate framebuffer status cache 1.155 + NotifyFBsStatusChanged(); 1.156 + 1.157 + SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); 1.158 +} 1.159 + 1.160 +void 1.161 +WebGLTexture::SetGeneratedMipmap() { 1.162 + if (!mHaveGeneratedMipmap) { 1.163 + mHaveGeneratedMipmap = true; 1.164 + SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown); 1.165 + } 1.166 +} 1.167 + 1.168 +void 1.169 +WebGLTexture::SetCustomMipmap() { 1.170 + if (mHaveGeneratedMipmap) { 1.171 + // if we were in GeneratedMipmap mode and are now switching to CustomMipmap mode, 1.172 + // we need to compute now all the mipmap image info. 1.173 + 1.174 + // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info, 1.175 + // and are power-of-two. 1.176 + ImageInfo imageInfo = ImageInfoAtFace(0, 0); 1.177 + NS_ASSERTION(imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?"); 1.178 + 1.179 + GLsizei size = std::max(imageInfo.mWidth, imageInfo.mHeight); 1.180 + 1.181 + // so, the size is a power of two, let's find its log in base 2. 1.182 + size_t maxLevel = 0; 1.183 + for (GLsizei n = size; n > 1; n >>= 1) 1.184 + ++maxLevel; 1.185 + 1.186 + EnsureMaxLevelWithCustomImagesAtLeast(maxLevel); 1.187 + 1.188 + for (size_t level = 1; level <= maxLevel; ++level) { 1.189 + // again, since the sizes are powers of two, no need for any max(1,x) computation 1.190 + imageInfo.mWidth >>= 1; 1.191 + imageInfo.mHeight >>= 1; 1.192 + for(size_t face = 0; face < mFacesCount; ++face) 1.193 + ImageInfoAtFace(face, level) = imageInfo; 1.194 + } 1.195 + } 1.196 + mHaveGeneratedMipmap = false; 1.197 +} 1.198 + 1.199 +bool 1.200 +WebGLTexture::AreAllLevel0ImageInfosEqual() const { 1.201 + for (size_t face = 1; face < mFacesCount; ++face) { 1.202 + if (ImageInfoAtFace(face, 0) != ImageInfoAtFace(0, 0)) 1.203 + return false; 1.204 + } 1.205 + return true; 1.206 +} 1.207 + 1.208 +bool 1.209 +WebGLTexture::IsMipmapTexture2DComplete() const { 1.210 + if (mTarget != LOCAL_GL_TEXTURE_2D) 1.211 + return false; 1.212 + if (!ImageInfoAt(LOCAL_GL_TEXTURE_2D, 0).IsPositive()) 1.213 + return false; 1.214 + if (mHaveGeneratedMipmap) 1.215 + return true; 1.216 + return DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D); 1.217 +} 1.218 + 1.219 +bool 1.220 +WebGLTexture::IsCubeComplete() const { 1.221 + if (mTarget != LOCAL_GL_TEXTURE_CUBE_MAP) 1.222 + return false; 1.223 + const ImageInfo &first = ImageInfoAt(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0); 1.224 + if (!first.IsPositive() || !first.IsSquare()) 1.225 + return false; 1.226 + return AreAllLevel0ImageInfosEqual(); 1.227 +} 1.228 + 1.229 +static GLenum 1.230 +GLCubeMapFaceById(int id) 1.231 +{ 1.232 + GLenum result = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + id; 1.233 + MOZ_ASSERT(result >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X && 1.234 + result <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z); 1.235 + return result; 1.236 +} 1.237 + 1.238 +bool 1.239 +WebGLTexture::IsMipmapCubeComplete() const { 1.240 + if (!IsCubeComplete()) // in particular, this checks that this is a cube map 1.241 + return false; 1.242 + for (int i = 0; i < 6; i++) { 1.243 + GLenum face = GLCubeMapFaceById(i); 1.244 + if (!DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(face)) 1.245 + return false; 1.246 + } 1.247 + return true; 1.248 +} 1.249 + 1.250 +WebGLTextureFakeBlackStatus 1.251 +WebGLTexture::ResolvedFakeBlackStatus() { 1.252 + if (MOZ_LIKELY(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown)) { 1.253 + return mFakeBlackStatus; 1.254 + } 1.255 + 1.256 + // Determine if the texture needs to be faked as a black texture. 1.257 + // See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec. 1.258 + 1.259 + for (size_t face = 0; face < mFacesCount; ++face) { 1.260 + if (ImageInfoAtFace(face, 0).mImageDataStatus == WebGLImageDataStatus::NoImageData) { 1.261 + // In case of undefined texture image, we don't print any message because this is a very common 1.262 + // and often legitimate case (asynchronous texture loading). 1.263 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.264 + return mFakeBlackStatus; 1.265 + } 1.266 + } 1.267 + 1.268 + const char *msg_rendering_as_black 1.269 + = "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, " 1.270 + "because it"; 1.271 + 1.272 + if (mTarget == LOCAL_GL_TEXTURE_2D) 1.273 + { 1.274 + if (DoesMinFilterRequireMipmap()) 1.275 + { 1.276 + if (!IsMipmapTexture2DComplete()) { 1.277 + mContext->GenerateWarning 1.278 + ("%s is a 2D texture, with a minification filter requiring a mipmap, " 1.279 + "and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black); 1.280 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.281 + } else if (!ImageInfoAt(mTarget, 0).IsPowerOfTwo()) { 1.282 + mContext->GenerateWarning 1.283 + ("%s is a 2D texture, with a minification filter requiring a mipmap, " 1.284 + "and either its width or height is not a power of two.", msg_rendering_as_black); 1.285 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.286 + } 1.287 + } 1.288 + else // no mipmap required 1.289 + { 1.290 + if (!ImageInfoAt(mTarget, 0).IsPositive()) { 1.291 + mContext->GenerateWarning 1.292 + ("%s is a 2D texture and its width or height is equal to zero.", 1.293 + msg_rendering_as_black); 1.294 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.295 + } else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(mTarget, 0).IsPowerOfTwo()) { 1.296 + mContext->GenerateWarning 1.297 + ("%s is a 2D texture, with a minification filter not requiring a mipmap, " 1.298 + "with its width or height not a power of two, and with a wrap mode " 1.299 + "different from CLAMP_TO_EDGE.", msg_rendering_as_black); 1.300 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.301 + } 1.302 + } 1.303 + } 1.304 + else // cube map 1.305 + { 1.306 + bool areAllLevel0ImagesPOT = true; 1.307 + for (size_t face = 0; face < mFacesCount; ++face) 1.308 + areAllLevel0ImagesPOT &= ImageInfoAtFace(face, 0).IsPowerOfTwo(); 1.309 + 1.310 + if (DoesMinFilterRequireMipmap()) 1.311 + { 1.312 + if (!IsMipmapCubeComplete()) { 1.313 + mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, " 1.314 + "and is not mipmap cube complete (as defined in section 3.7.10).", 1.315 + msg_rendering_as_black); 1.316 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.317 + } else if (!areAllLevel0ImagesPOT) { 1.318 + mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, " 1.319 + "and either the width or the height of some level 0 image is not a power of two.", 1.320 + msg_rendering_as_black); 1.321 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.322 + } 1.323 + } 1.324 + else // no mipmap required 1.325 + { 1.326 + if (!IsCubeComplete()) { 1.327 + mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, " 1.328 + "and is not cube complete (as defined in section 3.7.10).", 1.329 + msg_rendering_as_black); 1.330 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.331 + } else if (!AreBothWrapModesClampToEdge() && !areAllLevel0ImagesPOT) { 1.332 + mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, " 1.333 + "with some level 0 image having width or height not a power of two, and with a wrap mode " 1.334 + "different from CLAMP_TO_EDGE.", msg_rendering_as_black); 1.335 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.336 + } 1.337 + } 1.338 + } 1.339 + 1.340 + if (ImageInfoBase().mWebGLType == LOCAL_GL_FLOAT && 1.341 + !Context()->IsExtensionEnabled(WebGLExtensionID::OES_texture_float_linear)) 1.342 + { 1.343 + if (mMinFilter == LOCAL_GL_LINEAR || 1.344 + mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR || 1.345 + mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST || 1.346 + mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR) 1.347 + { 1.348 + mContext->GenerateWarning("%s is a texture with a linear minification filter, " 1.349 + "which is not compatible with gl.FLOAT by default. " 1.350 + "Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black); 1.351 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.352 + } 1.353 + else if (mMagFilter == LOCAL_GL_LINEAR) 1.354 + { 1.355 + mContext->GenerateWarning("%s is a texture with a linear magnification filter, " 1.356 + "which is not compatible with gl.FLOAT by default. " 1.357 + "Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black); 1.358 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.359 + } 1.360 + } else if (ImageInfoBase().mWebGLType == LOCAL_GL_HALF_FLOAT_OES && 1.361 + !Context()->IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float_linear)) 1.362 + { 1.363 + if (mMinFilter == LOCAL_GL_LINEAR || 1.364 + mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR || 1.365 + mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST || 1.366 + mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR) 1.367 + { 1.368 + mContext->GenerateWarning("%s is a texture with a linear minification filter, " 1.369 + "which is not compatible with gl.HALF_FLOAT by default. " 1.370 + "Try enabling the OES_texture_half_float_linear extension if supported.", msg_rendering_as_black); 1.371 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.372 + } 1.373 + else if (mMagFilter == LOCAL_GL_LINEAR) 1.374 + { 1.375 + mContext->GenerateWarning("%s is a texture with a linear magnification filter, " 1.376 + "which is not compatible with gl.HALF_FLOAT by default. " 1.377 + "Try enabling the OES_texture_half_float_linear extension if supported.", msg_rendering_as_black); 1.378 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture; 1.379 + } 1.380 + } 1.381 + 1.382 + // We have exhausted all cases of incomplete textures, where we would need opaque black. 1.383 + // We may still need transparent black in case of uninitialized image data. 1.384 + bool hasUninitializedImageData = false; 1.385 + for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) { 1.386 + for (size_t face = 0; face < mFacesCount; ++face) { 1.387 + hasUninitializedImageData |= (ImageInfoAtFace(face, level).mImageDataStatus == WebGLImageDataStatus::UninitializedImageData); 1.388 + } 1.389 + } 1.390 + 1.391 + if (hasUninitializedImageData) { 1.392 + bool hasAnyInitializedImageData = false; 1.393 + for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) { 1.394 + for (size_t face = 0; face < mFacesCount; ++face) { 1.395 + if (ImageInfoAtFace(face, level).mImageDataStatus == WebGLImageDataStatus::InitializedImageData) { 1.396 + hasAnyInitializedImageData = true; 1.397 + break; 1.398 + } 1.399 + } 1.400 + if (hasAnyInitializedImageData) { 1.401 + break; 1.402 + } 1.403 + } 1.404 + 1.405 + if (hasAnyInitializedImageData) { 1.406 + // The texture contains some initialized image data, and some uninitialized image data. 1.407 + // In this case, we have no choice but to initialize all image data now. Fortunately, 1.408 + // in this case we know that we can't be dealing with a depth texture per WEBGL_depth_texture 1.409 + // and ANGLE_depth_texture (which allow only one image per texture) so we can assume that 1.410 + // glTexImage2D is able to upload data to images. 1.411 + for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) { 1.412 + for (size_t face = 0; face < mFacesCount; ++face) { 1.413 + GLenum imageTarget = mTarget == LOCAL_GL_TEXTURE_2D 1.414 + ? LOCAL_GL_TEXTURE_2D 1.415 + : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; 1.416 + const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level); 1.417 + if (imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData) { 1.418 + DoDeferredImageInitialization(imageTarget, level); 1.419 + } 1.420 + } 1.421 + } 1.422 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded; 1.423 + } else { 1.424 + // The texture only contains uninitialized image data. In this case, 1.425 + // we can use a black texture for it. 1.426 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::UninitializedImageData; 1.427 + } 1.428 + } 1.429 + 1.430 + // we have exhausted all cases where we do need fakeblack, so if the status is still unknown, 1.431 + // that means that we do NOT need it. 1.432 + if (mFakeBlackStatus == WebGLTextureFakeBlackStatus::Unknown) { 1.433 + mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded; 1.434 + } 1.435 + 1.436 + MOZ_ASSERT(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown); 1.437 + return mFakeBlackStatus; 1.438 +} 1.439 + 1.440 +void 1.441 +WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level) 1.442 +{ 1.443 + const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level); 1.444 + MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData); 1.445 + 1.446 + mContext->MakeContextCurrent(); 1.447 + gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget); 1.448 + 1.449 + GLenum format = imageInfo.mWebGLFormat; 1.450 + GLenum type = imageInfo.mWebGLType; 1.451 + WebGLTexelFormat texelformat = GetWebGLTexelFormat(format, type); 1.452 + uint32_t texelsize = WebGLTexelConversions::TexelBytesForFormat(texelformat); 1.453 + CheckedUint32 checked_byteLength 1.454 + = WebGLContext::GetImageSize( 1.455 + imageInfo.mHeight, 1.456 + imageInfo.mWidth, 1.457 + texelsize, 1.458 + mContext->mPixelStoreUnpackAlignment); 1.459 + MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier 1.460 + void *zeros = calloc(1, checked_byteLength.value()); 1.461 + 1.462 + gl::GLContext* gl = mContext->gl; 1.463 + GLenum driverType = DriverTypeFromType(gl, type); 1.464 + GLenum driverInternalFormat = LOCAL_GL_NONE; 1.465 + GLenum driverFormat = LOCAL_GL_NONE; 1.466 + DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat); 1.467 + 1.468 + mContext->GetAndFlushUnderlyingGLErrors(); 1.469 + gl->fTexImage2D(imageTarget, level, driverInternalFormat, 1.470 + imageInfo.mWidth, imageInfo.mHeight, 1.471 + 0, driverFormat, driverType, 1.472 + zeros); 1.473 + GLenum error = mContext->GetAndFlushUnderlyingGLErrors(); 1.474 + 1.475 + free(zeros); 1.476 + SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData); 1.477 + 1.478 + if (error) { 1.479 + // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here. 1.480 + MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past. 1.481 + return; 1.482 + } 1.483 +} 1.484 + 1.485 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture) 1.486 + 1.487 +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTexture, AddRef) 1.488 +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTexture, Release)