content/canvas/src/WebGLTexture.cpp

Thu, 15 Jan 2015 21:03:48 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 21:03:48 +0100
branch
TOR_BUG_9701
changeset 11
deefc01c0e14
permissions
-rw-r--r--

Integrate friendly tips from Tor colleagues to make (or not) 4.5 alpha 3;
This includes removal of overloaded (but unused) methods, and addition of
a overlooked call to DataStruct::SetData(nsISupports, uint32_t, bool.)

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "WebGLContext.h"
michael@0 7 #include "WebGLContextUtils.h"
michael@0 8 #include "WebGLTexture.h"
michael@0 9 #include "GLContext.h"
michael@0 10 #include "ScopedGLHelpers.h"
michael@0 11 #include "WebGLTexelConversions.h"
michael@0 12 #include "mozilla/dom/WebGLRenderingContextBinding.h"
michael@0 13 #include <algorithm>
michael@0 14
michael@0 15 using namespace mozilla;
michael@0 16
michael@0 17 JSObject*
michael@0 18 WebGLTexture::WrapObject(JSContext *cx) {
michael@0 19 return dom::WebGLTextureBinding::Wrap(cx, this);
michael@0 20 }
michael@0 21
michael@0 22 WebGLTexture::WebGLTexture(WebGLContext *context)
michael@0 23 : WebGLContextBoundObject(context)
michael@0 24 , mHasEverBeenBound(false)
michael@0 25 , mTarget(0)
michael@0 26 , mMinFilter(LOCAL_GL_NEAREST_MIPMAP_LINEAR)
michael@0 27 , mMagFilter(LOCAL_GL_LINEAR)
michael@0 28 , mWrapS(LOCAL_GL_REPEAT)
michael@0 29 , mWrapT(LOCAL_GL_REPEAT)
michael@0 30 , mFacesCount(0)
michael@0 31 , mMaxLevelWithCustomImages(0)
michael@0 32 , mHaveGeneratedMipmap(false)
michael@0 33 , mFakeBlackStatus(WebGLTextureFakeBlackStatus::IncompleteTexture)
michael@0 34 {
michael@0 35 SetIsDOMBinding();
michael@0 36 mContext->MakeContextCurrent();
michael@0 37 mContext->gl->fGenTextures(1, &mGLName);
michael@0 38 mContext->mTextures.insertBack(this);
michael@0 39 }
michael@0 40
michael@0 41 void
michael@0 42 WebGLTexture::Delete() {
michael@0 43 mImageInfos.Clear();
michael@0 44 mContext->MakeContextCurrent();
michael@0 45 mContext->gl->fDeleteTextures(1, &mGLName);
michael@0 46 LinkedListElement<WebGLTexture>::removeFrom(mContext->mTextures);
michael@0 47 }
michael@0 48
michael@0 49 int64_t
michael@0 50 WebGLTexture::ImageInfo::MemoryUsage() const {
michael@0 51 if (mImageDataStatus == WebGLImageDataStatus::NoImageData)
michael@0 52 return 0;
michael@0 53 int64_t bitsPerTexel = WebGLContext::GetBitsPerTexel(mWebGLFormat, mWebGLType);
michael@0 54 return int64_t(mWidth) * int64_t(mHeight) * bitsPerTexel/8;
michael@0 55 }
michael@0 56
michael@0 57 int64_t
michael@0 58 WebGLTexture::MemoryUsage() const {
michael@0 59 if (IsDeleted())
michael@0 60 return 0;
michael@0 61 int64_t result = 0;
michael@0 62 for(size_t face = 0; face < mFacesCount; face++) {
michael@0 63 if (mHaveGeneratedMipmap) {
michael@0 64 // Each mipmap level is 1/4 the size of the previous level
michael@0 65 // 1 + x + x^2 + ... = 1/(1-x)
michael@0 66 // for x = 1/4, we get 1/(1-1/4) = 4/3
michael@0 67 result += ImageInfoAtFace(face, 0).MemoryUsage() * 4 / 3;
michael@0 68 } else {
michael@0 69 for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
michael@0 70 result += ImageInfoAtFace(face, level).MemoryUsage();
michael@0 71 }
michael@0 72 }
michael@0 73 return result;
michael@0 74 }
michael@0 75
michael@0 76 bool
michael@0 77 WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImageTarget) const {
michael@0 78 if (mHaveGeneratedMipmap)
michael@0 79 return true;
michael@0 80
michael@0 81 // We want a copy here so we can modify it temporarily.
michael@0 82 ImageInfo expected = ImageInfoAt(texImageTarget, 0);
michael@0 83
michael@0 84 // checks if custom level>0 images are all defined up to the highest level defined
michael@0 85 // and have the expected dimensions
michael@0 86 for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
michael@0 87 const ImageInfo& actual = ImageInfoAt(texImageTarget, level);
michael@0 88 if (actual != expected)
michael@0 89 return false;
michael@0 90 expected.mWidth = std::max(1, expected.mWidth >> 1);
michael@0 91 expected.mHeight = std::max(1, expected.mHeight >> 1);
michael@0 92
michael@0 93 // if the current level has size 1x1, we can stop here: the spec doesn't seem to forbid the existence
michael@0 94 // of extra useless levels.
michael@0 95 if (actual.mWidth == 1 && actual.mHeight == 1)
michael@0 96 return true;
michael@0 97 }
michael@0 98
michael@0 99 // if we're here, we've exhausted all levels without finding a 1x1 image
michael@0 100 return false;
michael@0 101 }
michael@0 102
michael@0 103 void
michael@0 104 WebGLTexture::Bind(GLenum aTarget) {
michael@0 105 // this function should only be called by bindTexture().
michael@0 106 // it assumes that the GL context is already current.
michael@0 107
michael@0 108 bool firstTimeThisTextureIsBound = !mHasEverBeenBound;
michael@0 109
michael@0 110 if (!firstTimeThisTextureIsBound && aTarget != mTarget) {
michael@0 111 mContext->ErrorInvalidOperation("bindTexture: this texture has already been bound to a different target");
michael@0 112 // very important to return here before modifying texture state! This was the place when I lost a whole day figuring
michael@0 113 // very strange 'invalid write' crashes.
michael@0 114 return;
michael@0 115 }
michael@0 116
michael@0 117 mTarget = aTarget;
michael@0 118
michael@0 119 mContext->gl->fBindTexture(mTarget, mGLName);
michael@0 120
michael@0 121 if (firstTimeThisTextureIsBound) {
michael@0 122 mFacesCount = (mTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
michael@0 123 EnsureMaxLevelWithCustomImagesAtLeast(0);
michael@0 124 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
michael@0 125
michael@0 126 // thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
michael@0 127 // present in GLES 2, but is present in GL and it seems as if for cube maps
michael@0 128 // we need to set it to GL_CLAMP_TO_EDGE to get the expected GLES behavior.
michael@0 129 if (mTarget == LOCAL_GL_TEXTURE_CUBE_MAP && !mContext->gl->IsGLES())
michael@0 130 mContext->gl->fTexParameteri(mTarget, LOCAL_GL_TEXTURE_WRAP_R, LOCAL_GL_CLAMP_TO_EDGE);
michael@0 131 }
michael@0 132
michael@0 133 mHasEverBeenBound = true;
michael@0 134 }
michael@0 135
michael@0 136 void
michael@0 137 WebGLTexture::SetImageInfo(GLenum aTarget, GLint aLevel,
michael@0 138 GLsizei aWidth, GLsizei aHeight,
michael@0 139 GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus)
michael@0 140 {
michael@0 141 if ( (aTarget == LOCAL_GL_TEXTURE_2D) != (mTarget == LOCAL_GL_TEXTURE_2D) )
michael@0 142 return;
michael@0 143
michael@0 144 EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
michael@0 145
michael@0 146 ImageInfoAt(aTarget, aLevel) = ImageInfo(aWidth, aHeight, aFormat, aType, aStatus);
michael@0 147
michael@0 148 if (aLevel > 0)
michael@0 149 SetCustomMipmap();
michael@0 150
michael@0 151 // Invalidate framebuffer status cache
michael@0 152 NotifyFBsStatusChanged();
michael@0 153
michael@0 154 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
michael@0 155 }
michael@0 156
michael@0 157 void
michael@0 158 WebGLTexture::SetGeneratedMipmap() {
michael@0 159 if (!mHaveGeneratedMipmap) {
michael@0 160 mHaveGeneratedMipmap = true;
michael@0 161 SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
michael@0 162 }
michael@0 163 }
michael@0 164
michael@0 165 void
michael@0 166 WebGLTexture::SetCustomMipmap() {
michael@0 167 if (mHaveGeneratedMipmap) {
michael@0 168 // if we were in GeneratedMipmap mode and are now switching to CustomMipmap mode,
michael@0 169 // we need to compute now all the mipmap image info.
michael@0 170
michael@0 171 // since we were in GeneratedMipmap mode, we know that the level 0 images all have the same info,
michael@0 172 // and are power-of-two.
michael@0 173 ImageInfo imageInfo = ImageInfoAtFace(0, 0);
michael@0 174 NS_ASSERTION(imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
michael@0 175
michael@0 176 GLsizei size = std::max(imageInfo.mWidth, imageInfo.mHeight);
michael@0 177
michael@0 178 // so, the size is a power of two, let's find its log in base 2.
michael@0 179 size_t maxLevel = 0;
michael@0 180 for (GLsizei n = size; n > 1; n >>= 1)
michael@0 181 ++maxLevel;
michael@0 182
michael@0 183 EnsureMaxLevelWithCustomImagesAtLeast(maxLevel);
michael@0 184
michael@0 185 for (size_t level = 1; level <= maxLevel; ++level) {
michael@0 186 // again, since the sizes are powers of two, no need for any max(1,x) computation
michael@0 187 imageInfo.mWidth >>= 1;
michael@0 188 imageInfo.mHeight >>= 1;
michael@0 189 for(size_t face = 0; face < mFacesCount; ++face)
michael@0 190 ImageInfoAtFace(face, level) = imageInfo;
michael@0 191 }
michael@0 192 }
michael@0 193 mHaveGeneratedMipmap = false;
michael@0 194 }
michael@0 195
michael@0 196 bool
michael@0 197 WebGLTexture::AreAllLevel0ImageInfosEqual() const {
michael@0 198 for (size_t face = 1; face < mFacesCount; ++face) {
michael@0 199 if (ImageInfoAtFace(face, 0) != ImageInfoAtFace(0, 0))
michael@0 200 return false;
michael@0 201 }
michael@0 202 return true;
michael@0 203 }
michael@0 204
michael@0 205 bool
michael@0 206 WebGLTexture::IsMipmapTexture2DComplete() const {
michael@0 207 if (mTarget != LOCAL_GL_TEXTURE_2D)
michael@0 208 return false;
michael@0 209 if (!ImageInfoAt(LOCAL_GL_TEXTURE_2D, 0).IsPositive())
michael@0 210 return false;
michael@0 211 if (mHaveGeneratedMipmap)
michael@0 212 return true;
michael@0 213 return DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D);
michael@0 214 }
michael@0 215
michael@0 216 bool
michael@0 217 WebGLTexture::IsCubeComplete() const {
michael@0 218 if (mTarget != LOCAL_GL_TEXTURE_CUBE_MAP)
michael@0 219 return false;
michael@0 220 const ImageInfo &first = ImageInfoAt(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
michael@0 221 if (!first.IsPositive() || !first.IsSquare())
michael@0 222 return false;
michael@0 223 return AreAllLevel0ImageInfosEqual();
michael@0 224 }
michael@0 225
michael@0 226 static GLenum
michael@0 227 GLCubeMapFaceById(int id)
michael@0 228 {
michael@0 229 GLenum result = LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + id;
michael@0 230 MOZ_ASSERT(result >= LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X &&
michael@0 231 result <= LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z);
michael@0 232 return result;
michael@0 233 }
michael@0 234
michael@0 235 bool
michael@0 236 WebGLTexture::IsMipmapCubeComplete() const {
michael@0 237 if (!IsCubeComplete()) // in particular, this checks that this is a cube map
michael@0 238 return false;
michael@0 239 for (int i = 0; i < 6; i++) {
michael@0 240 GLenum face = GLCubeMapFaceById(i);
michael@0 241 if (!DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(face))
michael@0 242 return false;
michael@0 243 }
michael@0 244 return true;
michael@0 245 }
michael@0 246
michael@0 247 WebGLTextureFakeBlackStatus
michael@0 248 WebGLTexture::ResolvedFakeBlackStatus() {
michael@0 249 if (MOZ_LIKELY(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown)) {
michael@0 250 return mFakeBlackStatus;
michael@0 251 }
michael@0 252
michael@0 253 // Determine if the texture needs to be faked as a black texture.
michael@0 254 // See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec.
michael@0 255
michael@0 256 for (size_t face = 0; face < mFacesCount; ++face) {
michael@0 257 if (ImageInfoAtFace(face, 0).mImageDataStatus == WebGLImageDataStatus::NoImageData) {
michael@0 258 // In case of undefined texture image, we don't print any message because this is a very common
michael@0 259 // and often legitimate case (asynchronous texture loading).
michael@0 260 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 261 return mFakeBlackStatus;
michael@0 262 }
michael@0 263 }
michael@0 264
michael@0 265 const char *msg_rendering_as_black
michael@0 266 = "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, "
michael@0 267 "because it";
michael@0 268
michael@0 269 if (mTarget == LOCAL_GL_TEXTURE_2D)
michael@0 270 {
michael@0 271 if (DoesMinFilterRequireMipmap())
michael@0 272 {
michael@0 273 if (!IsMipmapTexture2DComplete()) {
michael@0 274 mContext->GenerateWarning
michael@0 275 ("%s is a 2D texture, with a minification filter requiring a mipmap, "
michael@0 276 "and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black);
michael@0 277 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 278 } else if (!ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
michael@0 279 mContext->GenerateWarning
michael@0 280 ("%s is a 2D texture, with a minification filter requiring a mipmap, "
michael@0 281 "and either its width or height is not a power of two.", msg_rendering_as_black);
michael@0 282 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 283 }
michael@0 284 }
michael@0 285 else // no mipmap required
michael@0 286 {
michael@0 287 if (!ImageInfoAt(mTarget, 0).IsPositive()) {
michael@0 288 mContext->GenerateWarning
michael@0 289 ("%s is a 2D texture and its width or height is equal to zero.",
michael@0 290 msg_rendering_as_black);
michael@0 291 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 292 } else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
michael@0 293 mContext->GenerateWarning
michael@0 294 ("%s is a 2D texture, with a minification filter not requiring a mipmap, "
michael@0 295 "with its width or height not a power of two, and with a wrap mode "
michael@0 296 "different from CLAMP_TO_EDGE.", msg_rendering_as_black);
michael@0 297 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 298 }
michael@0 299 }
michael@0 300 }
michael@0 301 else // cube map
michael@0 302 {
michael@0 303 bool areAllLevel0ImagesPOT = true;
michael@0 304 for (size_t face = 0; face < mFacesCount; ++face)
michael@0 305 areAllLevel0ImagesPOT &= ImageInfoAtFace(face, 0).IsPowerOfTwo();
michael@0 306
michael@0 307 if (DoesMinFilterRequireMipmap())
michael@0 308 {
michael@0 309 if (!IsMipmapCubeComplete()) {
michael@0 310 mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
michael@0 311 "and is not mipmap cube complete (as defined in section 3.7.10).",
michael@0 312 msg_rendering_as_black);
michael@0 313 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 314 } else if (!areAllLevel0ImagesPOT) {
michael@0 315 mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
michael@0 316 "and either the width or the height of some level 0 image is not a power of two.",
michael@0 317 msg_rendering_as_black);
michael@0 318 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 319 }
michael@0 320 }
michael@0 321 else // no mipmap required
michael@0 322 {
michael@0 323 if (!IsCubeComplete()) {
michael@0 324 mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
michael@0 325 "and is not cube complete (as defined in section 3.7.10).",
michael@0 326 msg_rendering_as_black);
michael@0 327 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 328 } else if (!AreBothWrapModesClampToEdge() && !areAllLevel0ImagesPOT) {
michael@0 329 mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
michael@0 330 "with some level 0 image having width or height not a power of two, and with a wrap mode "
michael@0 331 "different from CLAMP_TO_EDGE.", msg_rendering_as_black);
michael@0 332 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 333 }
michael@0 334 }
michael@0 335 }
michael@0 336
michael@0 337 if (ImageInfoBase().mWebGLType == LOCAL_GL_FLOAT &&
michael@0 338 !Context()->IsExtensionEnabled(WebGLExtensionID::OES_texture_float_linear))
michael@0 339 {
michael@0 340 if (mMinFilter == LOCAL_GL_LINEAR ||
michael@0 341 mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR ||
michael@0 342 mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST ||
michael@0 343 mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR)
michael@0 344 {
michael@0 345 mContext->GenerateWarning("%s is a texture with a linear minification filter, "
michael@0 346 "which is not compatible with gl.FLOAT by default. "
michael@0 347 "Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
michael@0 348 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 349 }
michael@0 350 else if (mMagFilter == LOCAL_GL_LINEAR)
michael@0 351 {
michael@0 352 mContext->GenerateWarning("%s is a texture with a linear magnification filter, "
michael@0 353 "which is not compatible with gl.FLOAT by default. "
michael@0 354 "Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
michael@0 355 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 356 }
michael@0 357 } else if (ImageInfoBase().mWebGLType == LOCAL_GL_HALF_FLOAT_OES &&
michael@0 358 !Context()->IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float_linear))
michael@0 359 {
michael@0 360 if (mMinFilter == LOCAL_GL_LINEAR ||
michael@0 361 mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR ||
michael@0 362 mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST ||
michael@0 363 mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR)
michael@0 364 {
michael@0 365 mContext->GenerateWarning("%s is a texture with a linear minification filter, "
michael@0 366 "which is not compatible with gl.HALF_FLOAT by default. "
michael@0 367 "Try enabling the OES_texture_half_float_linear extension if supported.", msg_rendering_as_black);
michael@0 368 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 369 }
michael@0 370 else if (mMagFilter == LOCAL_GL_LINEAR)
michael@0 371 {
michael@0 372 mContext->GenerateWarning("%s is a texture with a linear magnification filter, "
michael@0 373 "which is not compatible with gl.HALF_FLOAT by default. "
michael@0 374 "Try enabling the OES_texture_half_float_linear extension if supported.", msg_rendering_as_black);
michael@0 375 mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
michael@0 376 }
michael@0 377 }
michael@0 378
michael@0 379 // We have exhausted all cases of incomplete textures, where we would need opaque black.
michael@0 380 // We may still need transparent black in case of uninitialized image data.
michael@0 381 bool hasUninitializedImageData = false;
michael@0 382 for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
michael@0 383 for (size_t face = 0; face < mFacesCount; ++face) {
michael@0 384 hasUninitializedImageData |= (ImageInfoAtFace(face, level).mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
michael@0 385 }
michael@0 386 }
michael@0 387
michael@0 388 if (hasUninitializedImageData) {
michael@0 389 bool hasAnyInitializedImageData = false;
michael@0 390 for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
michael@0 391 for (size_t face = 0; face < mFacesCount; ++face) {
michael@0 392 if (ImageInfoAtFace(face, level).mImageDataStatus == WebGLImageDataStatus::InitializedImageData) {
michael@0 393 hasAnyInitializedImageData = true;
michael@0 394 break;
michael@0 395 }
michael@0 396 }
michael@0 397 if (hasAnyInitializedImageData) {
michael@0 398 break;
michael@0 399 }
michael@0 400 }
michael@0 401
michael@0 402 if (hasAnyInitializedImageData) {
michael@0 403 // The texture contains some initialized image data, and some uninitialized image data.
michael@0 404 // In this case, we have no choice but to initialize all image data now. Fortunately,
michael@0 405 // in this case we know that we can't be dealing with a depth texture per WEBGL_depth_texture
michael@0 406 // and ANGLE_depth_texture (which allow only one image per texture) so we can assume that
michael@0 407 // glTexImage2D is able to upload data to images.
michael@0 408 for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
michael@0 409 for (size_t face = 0; face < mFacesCount; ++face) {
michael@0 410 GLenum imageTarget = mTarget == LOCAL_GL_TEXTURE_2D
michael@0 411 ? LOCAL_GL_TEXTURE_2D
michael@0 412 : LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
michael@0 413 const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
michael@0 414 if (imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData) {
michael@0 415 DoDeferredImageInitialization(imageTarget, level);
michael@0 416 }
michael@0 417 }
michael@0 418 }
michael@0 419 mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
michael@0 420 } else {
michael@0 421 // The texture only contains uninitialized image data. In this case,
michael@0 422 // we can use a black texture for it.
michael@0 423 mFakeBlackStatus = WebGLTextureFakeBlackStatus::UninitializedImageData;
michael@0 424 }
michael@0 425 }
michael@0 426
michael@0 427 // we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
michael@0 428 // that means that we do NOT need it.
michael@0 429 if (mFakeBlackStatus == WebGLTextureFakeBlackStatus::Unknown) {
michael@0 430 mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
michael@0 431 }
michael@0 432
michael@0 433 MOZ_ASSERT(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown);
michael@0 434 return mFakeBlackStatus;
michael@0 435 }
michael@0 436
michael@0 437 void
michael@0 438 WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level)
michael@0 439 {
michael@0 440 const ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
michael@0 441 MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
michael@0 442
michael@0 443 mContext->MakeContextCurrent();
michael@0 444 gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget);
michael@0 445
michael@0 446 GLenum format = imageInfo.mWebGLFormat;
michael@0 447 GLenum type = imageInfo.mWebGLType;
michael@0 448 WebGLTexelFormat texelformat = GetWebGLTexelFormat(format, type);
michael@0 449 uint32_t texelsize = WebGLTexelConversions::TexelBytesForFormat(texelformat);
michael@0 450 CheckedUint32 checked_byteLength
michael@0 451 = WebGLContext::GetImageSize(
michael@0 452 imageInfo.mHeight,
michael@0 453 imageInfo.mWidth,
michael@0 454 texelsize,
michael@0 455 mContext->mPixelStoreUnpackAlignment);
michael@0 456 MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
michael@0 457 void *zeros = calloc(1, checked_byteLength.value());
michael@0 458
michael@0 459 gl::GLContext* gl = mContext->gl;
michael@0 460 GLenum driverType = DriverTypeFromType(gl, type);
michael@0 461 GLenum driverInternalFormat = LOCAL_GL_NONE;
michael@0 462 GLenum driverFormat = LOCAL_GL_NONE;
michael@0 463 DriverFormatsFromFormatAndType(gl, format, type, &driverInternalFormat, &driverFormat);
michael@0 464
michael@0 465 mContext->GetAndFlushUnderlyingGLErrors();
michael@0 466 gl->fTexImage2D(imageTarget, level, driverInternalFormat,
michael@0 467 imageInfo.mWidth, imageInfo.mHeight,
michael@0 468 0, driverFormat, driverType,
michael@0 469 zeros);
michael@0 470 GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
michael@0 471
michael@0 472 free(zeros);
michael@0 473 SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
michael@0 474
michael@0 475 if (error) {
michael@0 476 // Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here.
michael@0 477 MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past.
michael@0 478 return;
michael@0 479 }
michael@0 480 }
michael@0 481
michael@0 482 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)
michael@0 483
michael@0 484 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(WebGLTexture, AddRef)
michael@0 485 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(WebGLTexture, Release)

mercurial