Bug 1081125 - WebGL2 3D textures - Part 2: update our texture state tracking to handle 3D textures - r=jgilbert

This commit is contained in:
Benoit Jacob 2014-10-13 19:42:20 -04:00
parent 91d773f494
commit 1d66ded08a
9 changed files with 161 additions and 86 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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) {

View File

@ -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

View File

@ -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