Bug 922810 - Part 1: track image initialization with a WebGLImageDataStatus enum - r=jgilbert

This commit is contained in:
Benoit Jacob 2013-10-11 09:16:43 -04:00
Родитель ae7e07a8a9
Коммит 8e13af6dbf
10 изменённых файлов: 130 добавлений и 61 удалений

Просмотреть файл

@ -30,7 +30,7 @@ WebGLContext::Clear(GLbitfield mask)
}
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
return ErrorInvalidFramebufferOperation("clear: incomplete framebuffer");
gl->fClear(mask);

Просмотреть файл

@ -508,7 +508,7 @@ WebGLContext::CopyTexImage2D(GLenum target,
return ErrorInvalidOperation("copyTexImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
if (mBoundFramebuffer)
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
return ErrorInvalidFramebufferOperation("copyTexImage2D: incomplete framebuffer");
WebGLTexture *tex = activeBoundTextureForTarget(target);
@ -537,12 +537,13 @@ WebGLContext::CopyTexImage2D(GLenum target,
if (error) {
GenerateWarning("copyTexImage2D generated error %s", ErrorName(error));
return;
}
}
} else {
CopyTexSubImage2D_base(target, level, internalformat, 0, 0, x, y, width, height, false);
}
tex->SetImageInfo(target, level, width, height, internalformat, type);
tex->SetImageInfo(target, level, width, height, internalformat, type,
WebGLImageDataStatus::InitializedImageData);
}
void
@ -617,7 +618,7 @@ WebGLContext::CopyTexSubImage2D(GLenum target,
return ErrorInvalidOperation("copyTexSubImage2D: a base internal format of DEPTH_COMPONENT or DEPTH_STENCIL isn't supported");
if (mBoundFramebuffer)
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
return ErrorInvalidFramebufferOperation("copyTexSubImage2D: incomplete framebuffer");
return CopyTexSubImage2D_base(target, level, format, xoffset, yoffset, x, y, width, height, true);
@ -2254,7 +2255,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
if (mBoundFramebuffer) {
// prevent readback of arbitrary video memory through uninitialized renderbuffers!
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers())
if (!mBoundFramebuffer->CheckAndInitializeAttachments())
return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
}
// Now that the errors are out of the way, on to actually reading
@ -2440,7 +2441,7 @@ WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei
mBoundRenderbuffer->SetInternalFormat(internalformat);
mBoundRenderbuffer->SetInternalFormatForGL(internalformatForGL);
mBoundRenderbuffer->setDimensions(width, height);
mBoundRenderbuffer->SetInitialized(false);
mBoundRenderbuffer->SetImageDataStatus(WebGLImageDataStatus::UninitializedImageData);
}
void
@ -3303,7 +3304,8 @@ WebGLContext::CompressedTexImage2D(GLenum target, GLint level, GLenum internalfo
}
gl->fCompressedTexImage2D(target, level, internalformat, width, height, border, byteLength, view.Data());
tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE);
tex->SetImageInfo(target, level, width, height, internalformat, LOCAL_GL_UNSIGNED_BYTE,
WebGLImageDataStatus::InitializedImageData);
ReattachTextureToAnyFramebufferToWorkAroundBugs(tex, level);
}
@ -3710,6 +3712,8 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
GLenum error = LOCAL_GL_NO_ERROR;
WebGLImageDataStatus imageInfoStatusIfSuccess = WebGLImageDataStatus::NoImageData;
if (byteLength) {
size_t srcStride = srcStrideOrZero ? srcStrideOrZero : checked_alignedRowSize.value();
@ -3737,6 +3741,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
error = CheckedTexImage2D(target, level, internalformat,
width, height, border, format, type, convertedData);
}
imageInfoStatusIfSuccess = WebGLImageDataStatus::InitializedImageData;
} else {
if (isDepthTexture && !gl->IsSupported(GLFeature::depth_texture)) {
// There's only one way that we can we supporting depth textures without
@ -3794,6 +3799,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
if (!success) {
return ErrorOutOfMemory("texImage2D: sorry, ran out of ways to initialize a depth texture.");
}
imageInfoStatusIfSuccess = WebGLImageDataStatus::InitializedImageData;
} else {
// We need some zero pages, because GL doesn't guarantee the
// contents of a texture allocated with nullptr data.
@ -3806,6 +3812,7 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
width, height, border, format, type, tempZeroData);
free(tempZeroData);
imageInfoStatusIfSuccess = WebGLImageDataStatus::InitializedImageData;
}
}
@ -3814,7 +3821,12 @@ WebGLContext::TexImage2D_base(GLenum target, GLint level, GLenum internalformat,
return;
}
tex->SetImageInfo(target, level, width, height, format, type);
// in all of the code paths above, we should have either initialized data,
// or allocated data and left it uninitialized, but in any case we shouldn't
// have NoImageData at this point.
MOZ_ASSERT(imageInfoStatusIfSuccess != WebGLImageDataStatus::NoImageData);
tex->SetImageInfo(target, level, width, height, format, type, imageInfoStatusIfSuccess);
ReattachTextureToAnyFramebufferToWorkAroundBugs(tex, level);
}

Просмотреть файл

@ -498,7 +498,7 @@ bool WebGLContext::DrawArrays_check(GLint first, GLsizei count, GLsizei primcoun
MakeContextCurrent();
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers()) {
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
return false;
}
@ -655,7 +655,7 @@ WebGLContext::DrawElements_check(GLsizei count, GLenum type, WebGLintptr byteOff
MakeContextCurrent();
if (mBoundFramebuffer) {
if (!mBoundFramebuffer->CheckAndInitializeRenderbuffers()) {
if (!mBoundFramebuffer->CheckAndInitializeAttachments()) {
ErrorInvalidFramebufferOperation("%s: incomplete framebuffer", info);
return false;
}

Просмотреть файл

@ -67,8 +67,27 @@ WebGLFramebuffer::Attachment::SetTexImage(WebGLTexture *tex, GLenum target, GLin
}
bool
WebGLFramebuffer::Attachment::HasUninitializedRenderbuffer() const {
return mRenderbufferPtr && !mRenderbufferPtr->Initialized();
WebGLFramebuffer::Attachment::HasUninitializedImageData() const {
if (mRenderbufferPtr) {
return mRenderbufferPtr->HasUninitializedImageData();
} else if (mTexturePtr) {
if (!mTexturePtr->HasImageInfoAt(mTexImageTarget, mTexImageLevel))
return false;
return mTexturePtr->ImageInfoAt(mTexImageTarget, mTexImageLevel).HasUninitializedImageData();
} else {
return false;
}
}
void
WebGLFramebuffer::Attachment::SetImageDataStatus(WebGLImageDataStatus newStatus) {
if (mRenderbufferPtr) {
mRenderbufferPtr->SetImageDataStatus(newStatus);
} else if (mTexturePtr) {
mTexturePtr->SetImageDataStatus(mTexImageTarget, mTexImageLevel, newStatus);
} else {
MOZ_ASSERT(false); // should not get here, worth crashing a debug build.
}
}
const WebGLRectangleObject*
@ -368,7 +387,7 @@ WebGLFramebuffer::DetachRenderbuffer(const WebGLRenderbuffer *rb) {
}
bool
WebGLFramebuffer::CheckAndInitializeRenderbuffers()
WebGLFramebuffer::CheckAndInitializeAttachments()
{
MOZ_ASSERT(mContext->mBoundFramebuffer == this);
// enforce WebGL section 6.5 which is WebGL-specific, hence OpenGL itself would not
@ -387,16 +406,16 @@ WebGLFramebuffer::CheckAndInitializeRenderbuffers()
size_t colorAttachmentCount = size_t(mColorAttachments.Length());
{
bool hasUnitializedRenderbuffers = false;
bool hasUnitializedAttachments = false;
for (size_t i = 0; i < colorAttachmentCount; i++) {
hasUnitializedRenderbuffers |= mColorAttachments[i].HasUninitializedRenderbuffer();
hasUnitializedAttachments |= mColorAttachments[i].HasUninitializedImageData();
}
if (!hasUnitializedRenderbuffers &&
!mDepthAttachment.HasUninitializedRenderbuffer() &&
!mStencilAttachment.HasUninitializedRenderbuffer() &&
!mDepthStencilAttachment.HasUninitializedRenderbuffer())
if (!hasUnitializedAttachments &&
!mDepthAttachment.HasUninitializedImageData() &&
!mStencilAttachment.HasUninitializedImageData() &&
!mDepthStencilAttachment.HasUninitializedImageData())
{
return true;
}
@ -420,21 +439,21 @@ WebGLFramebuffer::CheckAndInitializeRenderbuffers()
for (size_t i = 0; i < colorAttachmentCount; i++)
{
colorAttachmentsMask[i] = mColorAttachments[i].HasUninitializedRenderbuffer();
colorAttachmentsMask[i] = mColorAttachments[i].HasUninitializedImageData();
if (colorAttachmentsMask[i]) {
mask |= LOCAL_GL_COLOR_BUFFER_BIT;
}
}
if (mDepthAttachment.HasUninitializedRenderbuffer() ||
mDepthStencilAttachment.HasUninitializedRenderbuffer())
if (mDepthAttachment.HasUninitializedImageData() ||
mDepthStencilAttachment.HasUninitializedImageData())
{
mask |= LOCAL_GL_DEPTH_BUFFER_BIT;
}
if (mStencilAttachment.HasUninitializedRenderbuffer() ||
mDepthStencilAttachment.HasUninitializedRenderbuffer())
if (mStencilAttachment.HasUninitializedImageData() ||
mDepthStencilAttachment.HasUninitializedImageData())
{
mask |= LOCAL_GL_STENCIL_BUFFER_BIT;
}
@ -443,19 +462,16 @@ WebGLFramebuffer::CheckAndInitializeRenderbuffers()
for (size_t i = 0; i < colorAttachmentCount; i++)
{
if (colorAttachmentsMask[i]) {
mColorAttachments[i].Renderbuffer()->SetInitialized(true);
}
if (mColorAttachments[i].HasUninitializedImageData())
mColorAttachments[i].SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
}
if (mDepthAttachment.HasUninitializedRenderbuffer())
mDepthAttachment.Renderbuffer()->SetInitialized(true);
if (mStencilAttachment.HasUninitializedRenderbuffer())
mStencilAttachment.Renderbuffer()->SetInitialized(true);
if (mDepthStencilAttachment.HasUninitializedRenderbuffer())
mDepthStencilAttachment.Renderbuffer()->SetInitialized(true);
if (mDepthAttachment.HasUninitializedImageData())
mDepthAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
if (mStencilAttachment.HasUninitializedImageData())
mStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
if (mDepthStencilAttachment.HasUninitializedImageData())
mDepthStencilAttachment.SetImageDataStatus(WebGLImageDataStatus::InitializedImageData);
return true;
}

Просмотреть файл

@ -78,7 +78,8 @@ public:
return mTexImageLevel;
}
bool HasUninitializedRenderbuffer() const;
bool HasUninitializedImageData() const;
void SetImageDataStatus(WebGLImageDataStatus x);
void Reset() {
mTexturePtr = nullptr;
@ -161,7 +162,7 @@ public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(WebGLFramebuffer)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(WebGLFramebuffer)
bool CheckAndInitializeRenderbuffers();
bool CheckAndInitializeAttachments();
bool CheckColorAttachementNumber(GLenum attachment, const char * functionName) const;

Просмотреть файл

@ -48,7 +48,7 @@ WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext *context)
, mInternalFormat(0)
, mInternalFormatForGL(0)
, mHasEverBeenBound(false)
, mInitialized(false)
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
{
SetIsDOMBinding();
mContext->MakeContextCurrent();

Просмотреть файл

@ -33,8 +33,13 @@ public:
bool HasEverBeenBound() { return mHasEverBeenBound; }
void SetHasEverBeenBound(bool x) { mHasEverBeenBound = x; }
bool Initialized() const { return mInitialized; }
void SetInitialized(bool aInitialized) { mInitialized = aInitialized; }
bool HasUninitializedImageData() const { return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData; }
void SetImageDataStatus(WebGLImageDataStatus x) {
// there is no way to go from having image data to not having any
MOZ_ASSERT(x != WebGLImageDataStatus::NoImageData ||
mImageDataStatus == WebGLImageDataStatus::NoImageData);
mImageDataStatus = x;
}
GLenum InternalFormat() const { return mInternalFormat; }
void SetInternalFormat(GLenum aInternalFormat) { mInternalFormat = aInternalFormat; }
@ -66,7 +71,7 @@ protected:
GLenum mInternalFormat;
GLenum mInternalFormatForGL;
bool mHasEverBeenBound;
bool mInitialized;
WebGLImageDataStatus mImageDataStatus;
friend class WebGLFramebuffer;
};

Просмотреть файл

@ -45,7 +45,7 @@ WebGLTexture::Delete() {
int64_t
WebGLTexture::ImageInfo::MemoryUsage() const {
if (!mIsDefined)
if (mImageDataStatus == WebGLImageDataStatus::NoImageData)
return 0;
int64_t texelSizeInBits = WebGLContext::GetBitsPerTexel(mFormat, mType);
return int64_t(mWidth) * int64_t(mHeight) * texelSizeInBits / 8;
@ -139,14 +139,14 @@ WebGLTexture::Bind(GLenum aTarget) {
void
WebGLTexture::SetImageInfo(GLenum aTarget, GLint aLevel,
GLsizei aWidth, GLsizei aHeight,
GLenum aFormat, GLenum aType)
GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus)
{
if ( (aTarget == LOCAL_GL_TEXTURE_2D) != (mTarget == LOCAL_GL_TEXTURE_2D) )
return;
EnsureMaxLevelWithCustomImagesAtLeast(aLevel);
ImageInfoAt(aTarget, aLevel) = ImageInfo(aWidth, aHeight, aFormat, aType);
ImageInfoAt(aTarget, aLevel) = ImageInfo(aWidth, aHeight, aFormat, aType, aStatus);
if (aLevel > 0)
SetCustomMipmap();
@ -255,7 +255,7 @@ WebGLTexture::NeedFakeBlack() {
// See 3.8.2 Shader Execution in the OpenGL ES 2.0.24 spec.
for (size_t face = 0; face < mFacesCount; ++face) {
if (!ImageInfoAtFace(face, 0).mIsDefined) {
if (ImageInfoAtFace(face, 0).mImageDataStatus != WebGLImageDataStatus::InitializedImageData) {
// In case of undefined texture image, we don't print any message because this is a very common
// and often legitimate case, for example when doing asynchronous texture loading.
// An extreme case of this is the photowall google demo.

Просмотреть файл

@ -66,28 +66,33 @@ protected:
public:
class ImageInfo : public WebGLRectangleObject {
class ImageInfo
: public WebGLRectangleObject
{
public:
ImageInfo()
: mFormat(0)
, mType(0)
, mIsDefined(false)
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
{}
ImageInfo(GLsizei width, GLsizei height,
GLenum format, GLenum type)
GLenum format, GLenum type, WebGLImageDataStatus status)
: WebGLRectangleObject(width, height)
, mFormat(format)
, mType(type)
, mIsDefined(true)
{}
, mImageDataStatus(status)
{
// shouldn't use this constructor to construct a null ImageInfo
MOZ_ASSERT(status != WebGLImageDataStatus::NoImageData);
}
bool operator==(const ImageInfo& a) const {
return mIsDefined == a.mIsDefined &&
mWidth == a.mWidth &&
mHeight == a.mHeight &&
mFormat == a.mFormat &&
mType == a.mType;
return mImageDataStatus == a.mImageDataStatus &&
mWidth == a.mWidth &&
mHeight == a.mHeight &&
mFormat == a.mFormat &&
mType == a.mType;
}
bool operator!=(const ImageInfo& a) const {
return !(*this == a);
@ -102,12 +107,15 @@ public:
return is_pot_assuming_nonnegative(mWidth) &&
is_pot_assuming_nonnegative(mHeight); // negative sizes should never happen (caught in texImage2D...)
}
bool HasUninitializedImageData() const {
return mImageDataStatus == WebGLImageDataStatus::UninitializedImageData;
}
int64_t MemoryUsage() const;
GLenum Format() const { return mFormat; }
GLenum Type() const { return mType; }
protected:
GLenum mFormat, mType;
bool mIsDefined;
WebGLImageDataStatus mImageDataStatus;
friend class WebGLTexture;
};
@ -149,12 +157,12 @@ public:
bool HasImageInfoAt(GLenum imageTarget, GLint level) const {
MOZ_ASSERT(imageTarget);
size_t face = FaceForTarget(imageTarget);
CheckedUint32 checked_index = CheckedUint32(level) * mFacesCount + face;
return checked_index.isValid() &&
checked_index.value() < mImageInfos.Length() &&
ImageInfoAt(imageTarget, level).mIsDefined;
ImageInfoAt(imageTarget, level).mImageDataStatus != WebGLImageDataStatus::NoImageData;
}
ImageInfo& ImageInfoBase() {
@ -167,6 +175,15 @@ public:
int64_t MemoryUsage() const;
void SetImageDataStatus(GLenum imageTarget, GLint level, WebGLImageDataStatus newStatus) {
MOZ_ASSERT(HasImageInfoAt(imageTarget, level));
ImageInfo& imageInfo = ImageInfoAt(imageTarget, level);
// there is no way to go from having image data to not having any
MOZ_ASSERT(newStatus != WebGLImageDataStatus::NoImageData ||
imageInfo.mImageDataStatus == WebGLImageDataStatus::NoImageData);
imageInfo.mImageDataStatus = newStatus;
}
protected:
GLenum mTarget;
@ -203,7 +220,7 @@ public:
void SetImageInfo(GLenum aTarget, GLint aLevel,
GLsizei aWidth, GLsizei aHeight,
GLenum aFormat, GLenum aType);
GLenum aFormat, GLenum aType, WebGLImageDataStatus aStatus);
void SetMinFilter(GLenum aMinFilter) {
mMinFilter = aMinFilter;

Просмотреть файл

@ -6,6 +6,8 @@
#ifndef WEBGLTYPES_H_
#define WEBGLTYPES_H_
#include "mozilla/TypedEnum.h"
// Most WebIDL typedefs are identical to their OpenGL counterparts.
#include "GLTypes.h"
@ -23,6 +25,22 @@ struct VertexAttrib0Status {
enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
};
/*
* Enum to track the status of image data (renderbuffer or texture image) presence
* and initialization.
*
* - NoImageData is the initial state before any image data is allocated.
* - InitializedImageData is the state after image data is allocated and initialized.
* - UninitializedImageData is an intermediate state where data is allocated but not
* initialized. It is the state that renderbuffers are in after a renderbufferStorage call,
* and it is the state that texture images are in after a texImage2D call with null data.
*/
MOZ_BEGIN_ENUM_CLASS(WebGLImageDataStatus, int)
NoImageData,
UninitializedImageData,
InitializedImageData
MOZ_END_ENUM_CLASS(WebGLImageDataStatus)
namespace WebGLTexelConversions {
/*