mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1081125 - WebGL2 3D textures - Part 2: update our texture state tracking to handle 3D textures - r=jgilbert
This commit is contained in:
parent
91d773f494
commit
1d66ded08a
@ -154,12 +154,12 @@ WebGL2Context::TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat
|
||||
for (size_t l = 0; l < size_t(levels); l++) {
|
||||
for (size_t f = 0; f < facesCount; f++) {
|
||||
tex->SetImageInfo(TexImageTargetForTargetAndFace(target, f),
|
||||
l, w, h,
|
||||
l, w, h, 1,
|
||||
internalformat,
|
||||
WebGLImageDataStatus::UninitializedImageData);
|
||||
}
|
||||
w = std::max(1, w/2);
|
||||
h = std::max(1, h/2);
|
||||
w = std::max(1, w / 2);
|
||||
h = std::max(1, h / 2);
|
||||
}
|
||||
|
||||
gl->fTexStorage2D(target, levels, internalformat, width, height);
|
||||
|
@ -345,6 +345,7 @@ WebGLContext::DestroyResourcesAndContext()
|
||||
|
||||
mBound2DTextures.Clear();
|
||||
mBoundCubeMapTextures.Clear();
|
||||
mBound3DTextures.Clear();
|
||||
mBoundArrayBuffer = nullptr;
|
||||
mBoundTransformFeedbackBuffer = nullptr;
|
||||
mCurrentProgram = nullptr;
|
||||
@ -1828,7 +1829,7 @@ bool WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
|
||||
TexInternalFormat effectiveinternalformat =
|
||||
EffectiveInternalFormatFromInternalFormatAndType(internalformat, type);
|
||||
MOZ_ASSERT(effectiveinternalformat != LOCAL_GL_NONE);
|
||||
tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height,
|
||||
tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, 1,
|
||||
effectiveinternalformat, WebGLImageDataStatus::InitializedImageData);
|
||||
tex->Bind(TexImageTargetToTexTarget(texImageTarget));
|
||||
}
|
||||
@ -1872,6 +1873,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(WebGLContext,
|
||||
mExtensions,
|
||||
mBound2DTextures,
|
||||
mBoundCubeMapTextures,
|
||||
mBound3DTextures,
|
||||
mBoundArrayBuffer,
|
||||
mBoundTransformFeedbackBuffer,
|
||||
mCurrentProgram,
|
||||
|
@ -228,8 +228,16 @@ public:
|
||||
void DummyFramebufferOperation(const char *info);
|
||||
|
||||
WebGLTexture* activeBoundTextureForTarget(const TexTarget texTarget) const {
|
||||
return texTarget == LOCAL_GL_TEXTURE_2D ? mBound2DTextures[mActiveTexture]
|
||||
: mBoundCubeMapTextures[mActiveTexture];
|
||||
switch (texTarget.get()) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
return mBound2DTextures[mActiveTexture];
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
||||
return mBoundCubeMapTextures[mActiveTexture];
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
return mBound3DTextures[mActiveTexture];
|
||||
default:
|
||||
MOZ_CRASH("bad target");
|
||||
}
|
||||
}
|
||||
|
||||
/* Use this function when you have the texture image target, for example:
|
||||
@ -978,6 +986,7 @@ protected:
|
||||
|
||||
static CheckedUint32 GetImageSize(GLsizei height,
|
||||
GLsizei width,
|
||||
GLsizei depth,
|
||||
uint32_t pixelSize,
|
||||
uint32_t alignment);
|
||||
|
||||
@ -1282,6 +1291,7 @@ protected:
|
||||
|
||||
nsTArray<WebGLRefPtr<WebGLTexture> > mBound2DTextures;
|
||||
nsTArray<WebGLRefPtr<WebGLTexture> > mBoundCubeMapTextures;
|
||||
nsTArray<WebGLRefPtr<WebGLTexture> > mBound3DTextures;
|
||||
|
||||
WebGLRefPtr<WebGLProgram> mCurrentProgram;
|
||||
|
||||
|
@ -234,6 +234,12 @@ WebGLContext::BindTexture(GLenum rawTarget, WebGLTexture *newTex)
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
||||
currentTexPtr = &mBoundCubeMapTextures[mActiveTexture];
|
||||
break;
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
if (!IsWebGL2()) {
|
||||
return ErrorInvalidEnum("bindTexture: target TEXTURE_3D is only available in WebGL version 2.0 or newer");
|
||||
}
|
||||
currentTexPtr = &mBound3DTextures[mActiveTexture];
|
||||
break;
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("bindTexture: target", rawTarget);
|
||||
}
|
||||
@ -444,7 +450,7 @@ WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
||||
|
||||
// first, we initialize the texture as black
|
||||
if (!sub) {
|
||||
tex->SetImageInfo(texImageTarget, level, width, height,
|
||||
tex->SetImageInfo(texImageTarget, level, width, height, 1,
|
||||
effectiveInternalFormat,
|
||||
WebGLImageDataStatus::UninitializedImageData);
|
||||
tex->DoDeferredImageInitialization(texImageTarget, level);
|
||||
@ -482,7 +488,7 @@ WebGLContext::CopyTexSubImage2D_base(TexImageTarget texImageTarget,
|
||||
}
|
||||
|
||||
if (!sub) {
|
||||
tex->SetImageInfo(texImageTarget, level, width, height,
|
||||
tex->SetImageInfo(texImageTarget, level, width, height, 1,
|
||||
effectiveInternalFormat,
|
||||
WebGLImageDataStatus::InitializedImageData);
|
||||
}
|
||||
@ -703,7 +709,8 @@ WebGLContext::DeleteTexture(WebGLTexture *tex)
|
||||
GLuint activeTexture = mActiveTexture;
|
||||
for (int32_t i = 0; i < mGLMaxTextureUnits; i++) {
|
||||
if ((mBound2DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_2D) ||
|
||||
(mBoundCubeMapTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP))
|
||||
(mBoundCubeMapTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_CUBE_MAP) ||
|
||||
(mBound3DTextures[i] == tex && tex->Target() == LOCAL_GL_TEXTURE_3D))
|
||||
{
|
||||
ActiveTexture(LOCAL_GL_TEXTURE0 + i);
|
||||
BindTexture(tex->Target().get(), static_cast<WebGLTexture*>(nullptr));
|
||||
@ -2149,7 +2156,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
|
||||
// Check the pixels param size
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, bytesPerPixel, mPixelStorePackAlignment);
|
||||
GetImageSize(height, width, 1, bytesPerPixel, mPixelStorePackAlignment);
|
||||
|
||||
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * bytesPerPixel;
|
||||
|
||||
@ -3353,7 +3360,7 @@ WebGLContext::CompressedTexImage2D(GLenum rawTexImgTarget,
|
||||
MakeContextCurrent();
|
||||
gl->fCompressedTexImage2D(texImageTarget.get(), level, internalformat, width, height, border, byteLength, view.Data());
|
||||
|
||||
tex->SetImageInfo(texImageTarget, level, width, height, internalformat,
|
||||
tex->SetImageInfo(texImageTarget, level, width, height, 1, internalformat,
|
||||
WebGLImageDataStatus::InitializedImageData);
|
||||
}
|
||||
|
||||
@ -3709,7 +3716,7 @@ WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
|
||||
}
|
||||
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
GetImageSize(height, width, 1, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
|
||||
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
|
||||
CheckedUint32 checked_alignedRowSize =
|
||||
@ -3794,7 +3801,7 @@ WebGLContext::TexImage2D_base(TexImageTarget texImageTarget, GLint level,
|
||||
// have NoImageData at this point.
|
||||
MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData);
|
||||
|
||||
tex->SetImageInfo(texImageTarget, level, width, height,
|
||||
tex->SetImageInfo(texImageTarget, level, width, height, 1,
|
||||
effectiveInternalFormat, imageInfoStatusIfSuccess);
|
||||
}
|
||||
|
||||
@ -3919,7 +3926,7 @@ WebGLContext::TexSubImage2D_base(TexImageTarget texImageTarget, GLint level,
|
||||
return; // ES 2.0 says it has no effect, we better return right now
|
||||
|
||||
CheckedUint32 checked_neededByteLength =
|
||||
GetImageSize(height, width, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
GetImageSize(height, width, 1, srcTexelSize, mPixelStoreUnpackAlignment);
|
||||
|
||||
CheckedUint32 checked_plainRowSize = CheckedUint32(width) * srcTexelSize;
|
||||
|
||||
|
@ -60,7 +60,8 @@ TexImageTargetToTexTarget(TexImageTarget texImageTarget)
|
||||
{
|
||||
switch (texImageTarget.get()) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
return LOCAL_GL_TEXTURE_2D;
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
return texImageTarget.get();
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
|
||||
@ -69,7 +70,7 @@ TexImageTargetToTexTarget(TexImageTarget texImageTarget)
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
|
||||
return LOCAL_GL_TEXTURE_CUBE_MAP;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Bad texture conversion");
|
||||
MOZ_ASSERT(false, "Bad texture target");
|
||||
// Should be caught by the constructor for TexTarget
|
||||
return LOCAL_GL_NONE;
|
||||
}
|
||||
@ -448,6 +449,7 @@ WebGLContext::ShouldGenerateWarnings() const
|
||||
CheckedUint32
|
||||
WebGLContext::GetImageSize(GLsizei height,
|
||||
GLsizei width,
|
||||
GLsizei depth,
|
||||
uint32_t pixelSize,
|
||||
uint32_t packOrUnpackAlignment)
|
||||
{
|
||||
@ -457,10 +459,12 @@ WebGLContext::GetImageSize(GLsizei height,
|
||||
CheckedUint32 checked_alignedRowSize = RoundedToNextMultipleOf(checked_plainRowSize, packOrUnpackAlignment);
|
||||
|
||||
// if height is 0, we don't need any memory to store this; without this check, we'll get an overflow
|
||||
CheckedUint32 checked_neededByteLength
|
||||
CheckedUint32 checked_2dImageSize
|
||||
= height <= 0 ? 0 : (height-1) * checked_alignedRowSize + checked_plainRowSize;
|
||||
|
||||
return checked_neededByteLength;
|
||||
// FIXME - we should honor UNPACK_IMAGE_HEIGHT
|
||||
CheckedUint32 checked_imageSize = checked_2dImageSize * depth;
|
||||
return checked_imageSize;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -827,7 +827,7 @@ WebGLContext::ValidateTexImageSize(TexImageTarget texImageTarget, GLint level,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!is_pot_assuming_nonnegative(depth)) {
|
||||
if (depth > 0 && !is_pot_assuming_nonnegative(depth)) {
|
||||
ErrorInvalidValue("%s: level >= 0, depth of %d must be a power of two.",
|
||||
InfoFrom(func, dims), depth);
|
||||
return false;
|
||||
@ -1508,6 +1508,7 @@ WebGLContext::InitAndValidateGL()
|
||||
|
||||
mBound2DTextures.Clear();
|
||||
mBoundCubeMapTextures.Clear();
|
||||
mBound3DTextures.Clear();
|
||||
|
||||
mBoundArrayBuffer = nullptr;
|
||||
mBoundTransformFeedbackBuffer = nullptr;
|
||||
@ -1548,6 +1549,7 @@ WebGLContext::InitAndValidateGL()
|
||||
|
||||
mBound2DTextures.SetLength(mGLMaxTextureUnits);
|
||||
mBoundCubeMapTextures.SetLength(mGLMaxTextureUnits);
|
||||
mBound3DTextures.SetLength(mGLMaxTextureUnits);
|
||||
|
||||
if (MinCapabilityMode()) {
|
||||
mGLMaxTextureSize = MINVALUE_GL_MAX_TEXTURE_SIZE;
|
||||
|
@ -48,25 +48,32 @@ WebGLTexture::Delete() {
|
||||
LinkedListElement<WebGLTexture>::removeFrom(mContext->mTextures);
|
||||
}
|
||||
|
||||
int64_t
|
||||
size_t
|
||||
WebGLTexture::ImageInfo::MemoryUsage() const {
|
||||
if (mImageDataStatus == WebGLImageDataStatus::NoImageData)
|
||||
return 0;
|
||||
int64_t bitsPerTexel = GetBitsPerTexel(mEffectiveInternalFormat);
|
||||
return int64_t(mWidth) * int64_t(mHeight) * bitsPerTexel/8;
|
||||
size_t bitsPerTexel = GetBitsPerTexel(mEffectiveInternalFormat);
|
||||
return size_t(mWidth) * size_t(mHeight) * size_t(mDepth) * bitsPerTexel / 8;
|
||||
}
|
||||
|
||||
int64_t
|
||||
size_t
|
||||
WebGLTexture::MemoryUsage() const {
|
||||
if (IsDeleted())
|
||||
return 0;
|
||||
int64_t result = 0;
|
||||
size_t result = 0;
|
||||
for(size_t face = 0; face < mFacesCount; face++) {
|
||||
if (mHaveGeneratedMipmap) {
|
||||
// Each mipmap level is 1/4 the size of the previous level
|
||||
size_t level0MemoryUsage = ImageInfoAtFace(face, 0).MemoryUsage();
|
||||
// Each mipmap level is 1/(2^d) the size of the previous level,
|
||||
// where d is 2 or 3 depending on whether the images are 2D or 3D
|
||||
// 1 + x + x^2 + ... = 1/(1-x)
|
||||
// for x = 1/4, we get 1/(1-1/4) = 4/3
|
||||
result += ImageInfoAtFace(face, 0).MemoryUsage() * 4 / 3;
|
||||
// for x = 1/(2^2), we get 1/(1-1/4) = 4/3
|
||||
// for x = 1/(2^3), we get 1/(1-1/8) = 8/7
|
||||
size_t allLevelsMemoryUsage =
|
||||
mTarget == LOCAL_GL_TEXTURE_3D
|
||||
? level0MemoryUsage * 8 / 7
|
||||
: level0MemoryUsage * 4 / 3;
|
||||
result += allLevelsMemoryUsage;
|
||||
} else {
|
||||
for(size_t level = 0; level <= mMaxLevelWithCustomImages; level++)
|
||||
result += ImageInfoAtFace(face, level).MemoryUsage();
|
||||
@ -76,7 +83,8 @@ WebGLTexture::MemoryUsage() const {
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const {
|
||||
WebGLTexture::DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const
|
||||
{
|
||||
if (mHaveGeneratedMipmap)
|
||||
return true;
|
||||
|
||||
@ -89,13 +97,18 @@ WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget
|
||||
const ImageInfo& actual = ImageInfoAt(texImageTarget, level);
|
||||
if (actual != expected)
|
||||
return false;
|
||||
expected.mWidth = std::max(1, expected.mWidth >> 1);
|
||||
expected.mHeight = std::max(1, expected.mHeight >> 1);
|
||||
expected.mWidth = std::max(1, expected.mWidth / 2);
|
||||
expected.mHeight = std::max(1, expected.mHeight / 2);
|
||||
expected.mDepth = std::max(1, expected.mDepth / 2);
|
||||
|
||||
// if the current level has size 1x1, we can stop here: the spec doesn't seem to forbid the existence
|
||||
// of extra useless levels.
|
||||
if (actual.mWidth == 1 && actual.mHeight == 1)
|
||||
if (actual.mWidth == 1 &&
|
||||
actual.mHeight == 1 &&
|
||||
actual.mDepth == 1)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// if we're here, we've exhausted all levels without finding a 1x1 image
|
||||
@ -123,7 +136,7 @@ WebGLTexture::Bind(TexTarget aTexTarget) {
|
||||
mContext->gl->fBindTexture(aTexTarget.get(), name);
|
||||
|
||||
if (firstTimeThisTextureIsBound) {
|
||||
mFacesCount = (aTexTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
|
||||
mFacesCount = (aTexTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? 6 : 1;
|
||||
EnsureMaxLevelWithCustomImagesAtLeast(0);
|
||||
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
|
||||
|
||||
@ -137,16 +150,15 @@ WebGLTexture::Bind(TexTarget aTexTarget) {
|
||||
|
||||
void
|
||||
WebGLTexture::SetImageInfo(TexImageTarget aTexImageTarget, GLint aLevel,
|
||||
GLsizei aWidth, GLsizei aHeight,
|
||||
GLsizei aWidth, GLsizei aHeight, GLsizei aDepth,
|
||||
TexInternalFormat aEffectiveInternalFormat, WebGLImageDataStatus aStatus)
|
||||
{
|
||||
MOZ_ASSERT(aDepth == 1 || aTexImageTarget == LOCAL_GL_TEXTURE_3D);
|
||||
MOZ_ASSERT(TexImageTargetToTexTarget(aTexImageTarget) == mTarget);
|
||||
if (TexImageTargetToTexTarget(aTexImageTarget) != mTarget)
|
||||
return;
|
||||
|
||||
EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
|
||||
|
||||
ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aEffectiveInternalFormat, aStatus);
|
||||
ImageInfoAt(aTexImageTarget, aLevel) = ImageInfo(aWidth, aHeight, aDepth, aEffectiveInternalFormat, aStatus);
|
||||
|
||||
if (aLevel > 0)
|
||||
SetCustomMipmap();
|
||||
@ -176,7 +188,7 @@ WebGLTexture::SetCustomMipmap() {
|
||||
ImageInfo imageInfo = ImageInfoAtFace(0, 0);
|
||||
NS_ASSERTION(imageInfo.IsPowerOfTwo(), "this texture is NPOT, so how could GenerateMipmap() ever accept it?");
|
||||
|
||||
GLsizei size = std::max(imageInfo.mWidth, imageInfo.mHeight);
|
||||
GLsizei size = std::max(std::max(imageInfo.mWidth, imageInfo.mHeight), imageInfo.mDepth);
|
||||
|
||||
// so, the size is a power of two, let's find its log in base 2.
|
||||
size_t maxLevel = 0;
|
||||
@ -187,8 +199,9 @@ WebGLTexture::SetCustomMipmap() {
|
||||
|
||||
for (size_t level = 1; level <= maxLevel; ++level) {
|
||||
// again, since the sizes are powers of two, no need for any max(1,x) computation
|
||||
imageInfo.mWidth >>= 1;
|
||||
imageInfo.mHeight >>= 1;
|
||||
imageInfo.mWidth = std::max(imageInfo.mWidth / 2, 1);
|
||||
imageInfo.mHeight = std::max(imageInfo.mHeight / 2, 1);
|
||||
imageInfo.mDepth = std::max(imageInfo.mDepth / 2, 1);
|
||||
for(size_t face = 0; face < mFacesCount; ++face)
|
||||
ImageInfoAtFace(face, level) = imageInfo;
|
||||
}
|
||||
@ -206,20 +219,21 @@ WebGLTexture::AreAllLevel0ImageInfosEqual() const {
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLTexture::IsMipmapTexture2DComplete() const {
|
||||
if (mTarget != LOCAL_GL_TEXTURE_2D)
|
||||
return false;
|
||||
if (!ImageInfoAt(LOCAL_GL_TEXTURE_2D, 0).IsPositive())
|
||||
WebGLTexture::IsMipmapComplete() const {
|
||||
MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_2D ||
|
||||
mTarget == LOCAL_GL_TEXTURE_3D);
|
||||
|
||||
if (!ImageInfoAtFace(0, 0).IsPositive())
|
||||
return false;
|
||||
if (mHaveGeneratedMipmap)
|
||||
return true;
|
||||
return DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D);
|
||||
return DoesMipmapHaveAllLevelsConsistentlyDefined(LOCAL_GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLTexture::IsCubeComplete() const {
|
||||
if (mTarget != LOCAL_GL_TEXTURE_CUBE_MAP)
|
||||
return false;
|
||||
MOZ_ASSERT(mTarget == LOCAL_GL_TEXTURE_CUBE_MAP);
|
||||
|
||||
const ImageInfo &first = ImageInfoAt(LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0);
|
||||
if (!first.IsPositive() || !first.IsSquare())
|
||||
return false;
|
||||
@ -232,7 +246,7 @@ WebGLTexture::IsMipmapCubeComplete() const {
|
||||
return false;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
const TexImageTarget face = TexImageTargetForTargetAndFace(LOCAL_GL_TEXTURE_CUBE_MAP, i);
|
||||
if (!DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(face))
|
||||
if (!DoesMipmapHaveAllLevelsConsistentlyDefined(face))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@ -260,18 +274,20 @@ WebGLTexture::ResolvedFakeBlackStatus() {
|
||||
= "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, "
|
||||
"because it";
|
||||
|
||||
if (mTarget == LOCAL_GL_TEXTURE_2D)
|
||||
if (mTarget == LOCAL_GL_TEXTURE_2D ||
|
||||
mTarget == LOCAL_GL_TEXTURE_3D)
|
||||
{
|
||||
int dim = mTarget == LOCAL_GL_TEXTURE_2D ? 2 : 3;
|
||||
if (DoesMinFilterRequireMipmap())
|
||||
{
|
||||
if (!IsMipmapTexture2DComplete()) {
|
||||
if (!IsMipmapComplete()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D texture, with a minification filter requiring a mipmap, "
|
||||
"and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black);
|
||||
("%s is a %dD texture, with a minification filter requiring a mipmap, "
|
||||
"and is not mipmap complete (as defined in section 3.7.10).", msg_rendering_as_black, dim);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
} else if (!ImageInfoBase().IsPowerOfTwo()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D texture, with a minification filter requiring a mipmap, "
|
||||
("%s is a %dD texture, with a minification filter requiring a mipmap, "
|
||||
"and either its width or height is not a power of two.", msg_rendering_as_black);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
}
|
||||
@ -280,14 +296,14 @@ WebGLTexture::ResolvedFakeBlackStatus() {
|
||||
{
|
||||
if (!ImageInfoBase().IsPositive()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D texture and its width or height is equal to zero.",
|
||||
msg_rendering_as_black);
|
||||
("%s is a %dD texture and its width or height is equal to zero.",
|
||||
msg_rendering_as_black, dim);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
} else if (!AreBothWrapModesClampToEdge() && !ImageInfoBase().IsPowerOfTwo()) {
|
||||
mContext->GenerateWarning
|
||||
("%s is a 2D texture, with a minification filter not requiring a mipmap, "
|
||||
("%s is a %dD texture, with a minification filter not requiring a mipmap, "
|
||||
"with its width or height not a power of two, and with a wrap mode "
|
||||
"different from CLAMP_TO_EDGE.", msg_rendering_as_black);
|
||||
"different from CLAMP_TO_EDGE.", msg_rendering_as_black, dim);
|
||||
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
|
||||
}
|
||||
}
|
||||
@ -455,8 +471,7 @@ ClearWithTempFB(WebGLContext* context, GLuint tex,
|
||||
TexInternalFormat baseInternalFormat,
|
||||
GLsizei width, GLsizei height)
|
||||
{
|
||||
if (texImageTarget != LOCAL_GL_TEXTURE_2D)
|
||||
return false;
|
||||
MOZ_ASSERT(texImageTarget == LOCAL_GL_TEXTURE_2D);
|
||||
|
||||
gl::GLContext* gl = context->GL();
|
||||
MOZ_ASSERT(gl->IsCurrent());
|
||||
@ -536,13 +551,15 @@ WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint le
|
||||
|
||||
// Try to clear with glCLear.
|
||||
|
||||
bool cleared = ClearWithTempFB(mContext, GLName(),
|
||||
imageTarget, level,
|
||||
imageInfo.mEffectiveInternalFormat,
|
||||
imageInfo.mHeight, imageInfo.mWidth);
|
||||
if (cleared) {
|
||||
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
return;
|
||||
if (imageTarget == LOCAL_GL_TEXTURE_2D) {
|
||||
bool cleared = ClearWithTempFB(mContext, GLName(),
|
||||
imageTarget, level,
|
||||
imageInfo.mEffectiveInternalFormat,
|
||||
imageInfo.mHeight, imageInfo.mWidth);
|
||||
if (cleared) {
|
||||
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// That didn't work. Try uploading zeros then.
|
||||
@ -556,6 +573,7 @@ WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint le
|
||||
= WebGLContext::GetImageSize(
|
||||
imageInfo.mHeight,
|
||||
imageInfo.mWidth,
|
||||
imageInfo.mDepth,
|
||||
bytespertexel,
|
||||
mContext->mPixelStoreUnpackAlignment);
|
||||
MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
|
||||
@ -570,16 +588,24 @@ WebGLTexture::DoDeferredImageInitialization(TexImageTarget imageTarget, GLint le
|
||||
&driverInternalFormat, &driverFormat, &driverType);
|
||||
|
||||
mContext->GetAndFlushUnderlyingGLErrors();
|
||||
if (mImmutable) {
|
||||
gl->fTexSubImage2D(imageTarget.get(), level, 0, 0,
|
||||
imageInfo.mWidth, imageInfo.mHeight,
|
||||
driverFormat, driverType,
|
||||
zeros);
|
||||
} else {
|
||||
gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat,
|
||||
imageInfo.mWidth, imageInfo.mHeight,
|
||||
0, driverFormat, driverType,
|
||||
if (imageTarget == LOCAL_GL_TEXTURE_3D) {
|
||||
MOZ_ASSERT(mImmutable, "Shouldn't be possible to have non-immutable-format 3D textures in WebGL");
|
||||
gl->fTexSubImage3D(imageTarget.get(), level, 0, 0, 0,
|
||||
imageInfo.mWidth, imageInfo.mHeight, imageInfo.mDepth,
|
||||
driverFormat, driverType,
|
||||
zeros);
|
||||
} else {
|
||||
if (mImmutable) {
|
||||
gl->fTexSubImage2D(imageTarget.get(), level, 0, 0,
|
||||
imageInfo.mWidth, imageInfo.mHeight,
|
||||
driverFormat, driverType,
|
||||
zeros);
|
||||
} else {
|
||||
gl->fTexImage2D(imageTarget.get(), level, driverInternalFormat,
|
||||
imageInfo.mWidth, imageInfo.mHeight,
|
||||
0, driverFormat, driverType,
|
||||
zeros);
|
||||
}
|
||||
}
|
||||
GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "mozilla/CheckedInt.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
@ -68,15 +69,18 @@ public:
|
||||
public:
|
||||
ImageInfo()
|
||||
: mEffectiveInternalFormat(LOCAL_GL_NONE)
|
||||
, mDepth(0)
|
||||
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
|
||||
{}
|
||||
|
||||
ImageInfo(GLsizei width,
|
||||
GLsizei height,
|
||||
GLsizei depth,
|
||||
TexInternalFormat effectiveInternalFormat,
|
||||
WebGLImageDataStatus status)
|
||||
: WebGLRectangleObject(width, height)
|
||||
, mEffectiveInternalFormat(effectiveInternalFormat)
|
||||
, mDepth(depth)
|
||||
, mImageDataStatus(status)
|
||||
{
|
||||
// shouldn't use this constructor to construct a null ImageInfo
|
||||
@ -87,6 +91,7 @@ public:
|
||||
return mImageDataStatus == a.mImageDataStatus &&
|
||||
mWidth == a.mWidth &&
|
||||
mHeight == a.mHeight &&
|
||||
mDepth == a.mDepth &&
|
||||
mEffectiveInternalFormat == a.mEffectiveInternalFormat;
|
||||
}
|
||||
bool operator!=(const ImageInfo& a) const {
|
||||
@ -96,7 +101,7 @@ public:
|
||||
return mWidth == mHeight;
|
||||
}
|
||||
bool IsPositive() const {
|
||||
return mWidth > 0 && mHeight > 0;
|
||||
return mWidth > 0 && mHeight > 0 && mDepth > 0;
|
||||
}
|
||||
bool IsPowerOfTwo() const {
|
||||
return is_pot_assuming_nonnegative(mWidth) &&
|
||||
@ -105,7 +110,7 @@ public:
|
||||
bool HasUninitializedImageData() const {
|
||||
return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData;
|
||||
}
|
||||
int64_t MemoryUsage() const;
|
||||
size_t MemoryUsage() const;
|
||||
|
||||
TexInternalFormat EffectiveInternalFormat() const { return mEffectiveInternalFormat; }
|
||||
|
||||
@ -117,6 +122,14 @@ public:
|
||||
*/
|
||||
TexInternalFormat mEffectiveInternalFormat;
|
||||
|
||||
/*
|
||||
* Used only for 3D textures.
|
||||
* Note that mWidth and mHeight are inherited from WebGLRectangleObject.
|
||||
* It's a pity to store a useless mDepth on non-3D texture images, but
|
||||
* the size of GLsizei is negligible compared to the typical size of a texture image.
|
||||
*/
|
||||
GLsizei mDepth;
|
||||
|
||||
WebGLImageDataStatus mImageDataStatus;
|
||||
|
||||
friend class WebGLTexture;
|
||||
@ -124,14 +137,16 @@ public:
|
||||
|
||||
private:
|
||||
static size_t FaceForTarget(TexImageTarget texImageTarget) {
|
||||
if (texImageTarget == LOCAL_GL_TEXTURE_2D)
|
||||
if (texImageTarget == LOCAL_GL_TEXTURE_2D ||
|
||||
texImageTarget == LOCAL_GL_TEXTURE_3D)
|
||||
{
|
||||
return 0;
|
||||
|
||||
}
|
||||
return texImageTarget.get() - LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X;
|
||||
}
|
||||
|
||||
ImageInfo& ImageInfoAtFace(size_t face, GLint level) {
|
||||
MOZ_ASSERT(face < mFacesCount, "wrong face index, must be 0 for TEXTURE_2D and at most 5 for cube maps");
|
||||
MOZ_ASSERT(face < mFacesCount, "wrong face index, must be 0 for TEXTURE_2D or TEXTURE_3D, and at most 5 for cube maps");
|
||||
|
||||
// no need to check level as a wrong value would be caught by ElementAt().
|
||||
return mImageInfos.ElementAt(level * mFacesCount + face);
|
||||
@ -169,7 +184,7 @@ public:
|
||||
return ImageInfoAtFace(0, 0);
|
||||
}
|
||||
|
||||
int64_t MemoryUsage() const;
|
||||
size_t MemoryUsage() const;
|
||||
|
||||
void SetImageDataStatus(TexImageTarget imageTarget, GLint level, WebGLImageDataStatus newStatus) {
|
||||
MOZ_ASSERT(HasImageInfoAt(imageTarget, level));
|
||||
@ -214,14 +229,14 @@ protected:
|
||||
return mWrapS == LOCAL_GL_CLAMP_TO_EDGE && mWrapT == LOCAL_GL_CLAMP_TO_EDGE;
|
||||
}
|
||||
|
||||
bool DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const;
|
||||
bool DoesMipmapHaveAllLevelsConsistentlyDefined(TexImageTarget texImageTarget) const;
|
||||
|
||||
public:
|
||||
|
||||
void Bind(TexTarget aTexTarget);
|
||||
|
||||
void SetImageInfo(TexImageTarget aTarget, GLint aLevel,
|
||||
GLsizei aWidth, GLsizei aHeight,
|
||||
GLsizei aWidth, GLsizei aHeight, GLsizei aDepth,
|
||||
TexInternalFormat aFormat, WebGLImageDataStatus aStatus);
|
||||
|
||||
void SetMinFilter(TexMinFilter aMinFilter) {
|
||||
@ -256,7 +271,7 @@ public:
|
||||
|
||||
bool AreAllLevel0ImageInfosEqual() const;
|
||||
|
||||
bool IsMipmapTexture2DComplete() const;
|
||||
bool IsMipmapComplete() const;
|
||||
|
||||
bool IsCubeComplete() const;
|
||||
|
||||
@ -277,9 +292,17 @@ public:
|
||||
inline TexImageTarget
|
||||
TexImageTargetForTargetAndFace(TexTarget target, size_t face)
|
||||
{
|
||||
return target == LOCAL_GL_TEXTURE_2D
|
||||
? LOCAL_GL_TEXTURE_2D
|
||||
: LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
||||
switch (target.get()) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
case LOCAL_GL_TEXTURE_3D:
|
||||
MOZ_ASSERT(face == 0);
|
||||
return target.get();
|
||||
case LOCAL_GL_TEXTURE_CUBE_MAP:
|
||||
MOZ_ASSERT(face < 6);
|
||||
return LOCAL_GL_TEXTURE_CUBE_MAP_POSITIVE_X + face;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -180,6 +180,7 @@ ScopedBindTexture::Init(GLenum aTarget)
|
||||
mTarget = aTarget;
|
||||
mOldTex = 0;
|
||||
GLenum bindingTarget = (aTarget == LOCAL_GL_TEXTURE_2D) ? LOCAL_GL_TEXTURE_BINDING_2D
|
||||
: (aTarget == LOCAL_GL_TEXTURE_3D) ? LOCAL_GL_TEXTURE_BINDING_3D
|
||||
: (aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB) ? LOCAL_GL_TEXTURE_BINDING_RECTANGLE_ARB
|
||||
: (aTarget == LOCAL_GL_TEXTURE_CUBE_MAP) ? LOCAL_GL_TEXTURE_BINDING_CUBE_MAP
|
||||
: (aTarget == LOCAL_GL_TEXTURE_EXTERNAL) ? LOCAL_GL_TEXTURE_BINDING_EXTERNAL
|
||||
|
Loading…
Reference in New Issue
Block a user