Bug 922810 - Part 2: reorganize the tracking of fake back statuses - r=jgilbert

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

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

@ -122,7 +122,7 @@ WebGLContext::WebGLContext()
mShaderValidation = true;
mBlackTexturesAreInitialized = false;
mFakeBlackStatus = DoNotNeedFakeBlack;
mFakeBlackStatus = WebGLContextFakeBlackStatus::Unknown;
mVertexAttrib0Vector[0] = 0;
mVertexAttrib0Vector[1] = 0;

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

@ -798,11 +798,13 @@ private:
// -----------------------------------------------------------------------------
// PROTECTED
protected:
void SetDontKnowIfNeedFakeBlack() {
mFakeBlackStatus = DontKnowIfNeedFakeBlack;
void SetFakeBlackStatus(WebGLContextFakeBlackStatus x) {
mFakeBlackStatus = x;
}
// Returns the current fake-black-status, except if it was Unknown,
// in which case this function resolves it first, so it never returns Unknown.
WebGLContextFakeBlackStatus ResolvedFakeBlackStatus();
bool NeedFakeBlack();
void BindFakeBlackTextures();
void UnbindFakeBlackTextures();
@ -1090,7 +1092,7 @@ protected:
uint32_t mPixelStorePackAlignment, mPixelStoreUnpackAlignment, mPixelStoreColorspaceConversion;
bool mPixelStoreFlipY, mPixelStorePremultiplyAlpha;
FakeBlackStatus mFakeBlackStatus;
WebGLContextFakeBlackStatus mFakeBlackStatus;
GLuint mBlackTexture2D, mBlackTextureCubeMap;
bool mBlackTexturesAreInitialized;

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

@ -211,7 +211,7 @@ WebGLContext::BindTexture(GLenum target, WebGLTexture *tex)
return ErrorInvalidEnumInfo("bindTexture: target", target);
}
SetDontKnowIfNeedFakeBlack();
mFakeBlackStatus = WebGLContextFakeBlackStatus::Unknown;
MakeContextCurrent();
if (tex)
@ -932,36 +932,36 @@ WebGLContext::UndoFakeVertexAttrib0()
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
}
bool
WebGLContext::NeedFakeBlack()
WebGLContextFakeBlackStatus
WebGLContext::ResolvedFakeBlackStatus()
{
// handle this case first, it's the generic case
if (mFakeBlackStatus == DoNotNeedFakeBlack)
return false;
if (MOZ_LIKELY(mFakeBlackStatus == WebGLContextFakeBlackStatus::NotNeeded))
return mFakeBlackStatus;
if (mFakeBlackStatus == DoNeedFakeBlack)
return true;
if (mFakeBlackStatus == WebGLContextFakeBlackStatus::Needed)
return mFakeBlackStatus;
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if ((mBound2DTextures[i] && mBound2DTextures[i]->NeedFakeBlack()) ||
(mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->NeedFakeBlack()))
if ((mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) ||
(mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded))
{
mFakeBlackStatus = DoNeedFakeBlack;
return true;
mFakeBlackStatus = WebGLContextFakeBlackStatus::Needed;
return mFakeBlackStatus;
}
}
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
// that means that we do NOT need it.
mFakeBlackStatus = DoNotNeedFakeBlack;
return false;
mFakeBlackStatus = WebGLContextFakeBlackStatus::NotNeeded;
return mFakeBlackStatus;
}
void
WebGLContext::BindFakeBlackTextures()
{
// this is the generic case: try to return early
if (!NeedFakeBlack())
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
return;
if (!mBlackTexturesAreInitialized) {
@ -992,11 +992,18 @@ WebGLContext::BindFakeBlackTextures()
}
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if (mBound2DTextures[i] && mBound2DTextures[i]->NeedFakeBlack()) {
WebGLTextureFakeBlackStatus s;
s = mBound2DTextures[i]
? mBound2DTextures[i]->ResolvedFakeBlackStatus()
: WebGLTextureFakeBlackStatus::NotNeeded;
if (s != WebGLTextureFakeBlackStatus::NotNeeded) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBlackTexture2D);
}
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->NeedFakeBlack()) {
s = mBoundCubeMapTextures[i]
? mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus()
: WebGLTextureFakeBlackStatus::NotNeeded;
if (s != WebGLTextureFakeBlackStatus::NotNeeded) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBlackTextureCubeMap);
}
@ -1007,15 +1014,15 @@ void
WebGLContext::UnbindFakeBlackTextures()
{
// this is the generic case: try to return early
if (!NeedFakeBlack())
if (MOZ_LIKELY(ResolvedFakeBlackStatus() == WebGLContextFakeBlackStatus::NotNeeded))
return;
for (int32_t i = 0; i < mGLMaxTextureUnits; ++i) {
if (mBound2DTextures[i] && mBound2DTextures[i]->NeedFakeBlack()) {
if (mBound2DTextures[i] && mBound2DTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mBound2DTextures[i]->GLName());
}
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->NeedFakeBlack()) {
if (mBoundCubeMapTextures[i] && mBoundCubeMapTextures[i]->ResolvedFakeBlackStatus() != WebGLTextureFakeBlackStatus::NotNeeded) {
gl->fActiveTexture(LOCAL_GL_TEXTURE0 + i);
gl->fBindTexture(LOCAL_GL_TEXTURE_CUBE_MAP, mBoundCubeMapTextures[i]->GLName());
}

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

@ -51,11 +51,7 @@ WebGLFramebuffer::Attachment::HasAlpha() const {
format = Texture()->ImageInfoAt(mTexImageTarget, mTexImageLevel).Format();
else if (Renderbuffer())
format = Renderbuffer()->InternalFormat();
return format == LOCAL_GL_RGBA ||
format == LOCAL_GL_LUMINANCE_ALPHA ||
format == LOCAL_GL_ALPHA ||
format == LOCAL_GL_RGBA4 ||
format == LOCAL_GL_RGB5_A1;
return FormatHasAlpha(format);
}
void

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

@ -27,7 +27,7 @@ WebGLTexture::WebGLTexture(WebGLContext *context)
, mFacesCount(0)
, mMaxLevelWithCustomImages(0)
, mHaveGeneratedMipmap(false)
, mFakeBlackStatus(DoNotNeedFakeBlack)
, mFakeBlackStatus(WebGLTextureFakeBlackStatus::IncompleteTexture)
{
SetIsDOMBinding();
mContext->MakeContextCurrent();
@ -97,12 +97,6 @@ WebGLTexture::DoesTexture2DMipmapHaveAllLevelsConsistentlyDefined(GLenum texImag
return false;
}
void
WebGLTexture::SetDontKnowIfNeedFakeBlack() {
mFakeBlackStatus = DontKnowIfNeedFakeBlack;
mContext->SetDontKnowIfNeedFakeBlack();
}
void
WebGLTexture::Bind(GLenum aTarget) {
// this function should only be called by bindTexture().
@ -124,7 +118,7 @@ WebGLTexture::Bind(GLenum aTarget) {
if (firstTimeThisTextureIsBound) {
mFacesCount = (mTarget == LOCAL_GL_TEXTURE_2D) ? 1 : 6;
EnsureMaxLevelWithCustomImagesAtLeast(0);
SetDontKnowIfNeedFakeBlack();
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
// thanks to the WebKit people for finding this out: GL_TEXTURE_WRAP_R is not
// present in GLES 2, but is present in GL and it seems as if for cube maps
@ -151,14 +145,14 @@ WebGLTexture::SetImageInfo(GLenum aTarget, GLint aLevel,
if (aLevel > 0)
SetCustomMipmap();
SetDontKnowIfNeedFakeBlack();
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
void
WebGLTexture::SetGeneratedMipmap() {
if (!mHaveGeneratedMipmap) {
mHaveGeneratedMipmap = true;
SetDontKnowIfNeedFakeBlack();
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
}
@ -244,128 +238,139 @@ WebGLTexture::IsMipmapCubeComplete() const {
return true;
}
bool
WebGLTexture::NeedFakeBlack() {
// handle this case first, it's the generic case
if (mFakeBlackStatus == DoNotNeedFakeBlack)
return false;
if (mFakeBlackStatus == DontKnowIfNeedFakeBlack) {
// Determine if the texture needs to be faked as a black texture.
// 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).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.
// Exiting early here allows us to avoid making noise on valid webgl code.
mFakeBlackStatus = DoNeedFakeBlack;
return true;
}
}
const char *msg_rendering_as_black
= "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 (DoesMinFilterRequireMipmap())
{
if (!IsMipmapTexture2DComplete()) {
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);
mFakeBlackStatus = DoNeedFakeBlack;
} else if (!ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
mContext->GenerateWarning
("%s is a 2D 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 = DoNeedFakeBlack;
}
}
else // no mipmap required
{
if (!ImageInfoAt(mTarget, 0).IsPositive()) {
mContext->GenerateWarning
("%s is a 2D texture and its width or height is equal to zero.",
msg_rendering_as_black);
mFakeBlackStatus = DoNeedFakeBlack;
} else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
mContext->GenerateWarning
("%s is a 2D 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);
mFakeBlackStatus = DoNeedFakeBlack;
}
}
}
else // cube map
{
bool areAllLevel0ImagesPOT = true;
for (size_t face = 0; face < mFacesCount; ++face)
areAllLevel0ImagesPOT &= ImageInfoAtFace(face, 0).IsPowerOfTwo();
if (DoesMinFilterRequireMipmap())
{
if (!IsMipmapCubeComplete()) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
"and is not mipmap cube complete (as defined in section 3.7.10).",
msg_rendering_as_black);
mFakeBlackStatus = DoNeedFakeBlack;
} else if (!areAllLevel0ImagesPOT) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
"and either the width or the height of some level 0 image is not a power of two.",
msg_rendering_as_black);
mFakeBlackStatus = DoNeedFakeBlack;
}
}
else // no mipmap required
{
if (!IsCubeComplete()) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
"and is not cube complete (as defined in section 3.7.10).",
msg_rendering_as_black);
mFakeBlackStatus = DoNeedFakeBlack;
} else if (!AreBothWrapModesClampToEdge() && !areAllLevel0ImagesPOT) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
"with some level 0 image having width or height not a power of two, and with a wrap mode "
"different from CLAMP_TO_EDGE.", msg_rendering_as_black);
mFakeBlackStatus = DoNeedFakeBlack;
}
}
}
if (ImageInfoBase().mType == LOCAL_GL_FLOAT &&
!Context()->IsExtensionEnabled(WebGLContext::OES_texture_float_linear))
{
if (mMinFilter == LOCAL_GL_LINEAR ||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR ||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST ||
mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR)
{
mContext->GenerateWarning("%s is a texture with a linear minification filter, "
"which is not compatible with gl.FLOAT by default. "
"Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
mFakeBlackStatus = DoNeedFakeBlack;
}
else if (mMagFilter == LOCAL_GL_LINEAR)
{
mContext->GenerateWarning("%s is a texture with a linear magnification filter, "
"which is not compatible with gl.FLOAT by default. "
"Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
mFakeBlackStatus = DoNeedFakeBlack;
}
}
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
// that means that we do NOT need it.
if (mFakeBlackStatus == DontKnowIfNeedFakeBlack)
mFakeBlackStatus = DoNotNeedFakeBlack;
WebGLTextureFakeBlackStatus
WebGLTexture::ResolvedFakeBlackStatus() {
if (MOZ_LIKELY(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown)) {
return mFakeBlackStatus;
}
return mFakeBlackStatus == DoNeedFakeBlack;
// Determine if the texture needs to be faked as a black texture.
// 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).mImageDataStatus == WebGLImageDataStatus::NoImageData) {
// In case of undefined texture image, we don't print any message because this is a very common
// and often legitimate case (asynchronous texture loading).
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
return mFakeBlackStatus;
}
}
const char *msg_rendering_as_black
= "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 (DoesMinFilterRequireMipmap())
{
if (!IsMipmapTexture2DComplete()) {
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);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
} else if (!ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
mContext->GenerateWarning
("%s is a 2D 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;
}
}
else // no mipmap required
{
if (!ImageInfoAt(mTarget, 0).IsPositive()) {
mContext->GenerateWarning
("%s is a 2D texture and its width or height is equal to zero.",
msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
} else if (!AreBothWrapModesClampToEdge() && !ImageInfoAt(mTarget, 0).IsPowerOfTwo()) {
mContext->GenerateWarning
("%s is a 2D 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);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
}
}
else // cube map
{
bool areAllLevel0ImagesPOT = true;
for (size_t face = 0; face < mFacesCount; ++face)
areAllLevel0ImagesPOT &= ImageInfoAtFace(face, 0).IsPowerOfTwo();
if (DoesMinFilterRequireMipmap())
{
if (!IsMipmapCubeComplete()) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
"and is not mipmap cube complete (as defined in section 3.7.10).",
msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
} else if (!areAllLevel0ImagesPOT) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter requiring a mipmap, "
"and either the width or the height of some level 0 image is not a power of two.",
msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
}
else // no mipmap required
{
if (!IsCubeComplete()) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
"and is not cube complete (as defined in section 3.7.10).",
msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
} else if (!AreBothWrapModesClampToEdge() && !areAllLevel0ImagesPOT) {
mContext->GenerateWarning("%s is a cube map texture, with a minification filter not requiring a mipmap, "
"with some level 0 image having width or height not a power of two, and with a wrap mode "
"different from CLAMP_TO_EDGE.", msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
}
}
if (ImageInfoBase().mType == LOCAL_GL_FLOAT &&
!Context()->IsExtensionEnabled(WebGLContext::OES_texture_float_linear))
{
if (mMinFilter == LOCAL_GL_LINEAR ||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_LINEAR ||
mMinFilter == LOCAL_GL_LINEAR_MIPMAP_NEAREST ||
mMinFilter == LOCAL_GL_NEAREST_MIPMAP_LINEAR)
{
mContext->GenerateWarning("%s is a texture with a linear minification filter, "
"which is not compatible with gl.FLOAT by default. "
"Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
else if (mMagFilter == LOCAL_GL_LINEAR)
{
mContext->GenerateWarning("%s is a texture with a linear magnification filter, "
"which is not compatible with gl.FLOAT by default. "
"Try enabling the OES_texture_float_linear extension if supported.", msg_rendering_as_black);
mFakeBlackStatus = WebGLTextureFakeBlackStatus::IncompleteTexture;
}
}
// We have exhausted all cases of incomplete textures, where we would need opaque black.
// We may still need transparent black in case of uninitialized image data.
bool hasUninitializedImageData = false;
for (size_t level = 0; level <= mMaxLevelWithCustomImages; ++level) {
for (size_t face = 0; face < mFacesCount; ++face) {
hasUninitializedImageData |= (ImageInfoAtFace(face, level).mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
}
}
if (hasUninitializedImageData) {
mFakeBlackStatus = WebGLTextureFakeBlackStatus::UninitializedImageData;
return mFakeBlackStatus;
}
// we have exhausted all cases where we do need fakeblack, so if the status is still unknown,
// that means that we do NOT need it.
if (mFakeBlackStatus == WebGLTextureFakeBlackStatus::Unknown) {
mFakeBlackStatus = WebGLTextureFakeBlackStatus::NotNeeded;
}
MOZ_ASSERT(mFakeBlackStatus != WebGLTextureFakeBlackStatus::Unknown);
return mFakeBlackStatus;
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)

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

@ -21,6 +21,15 @@ inline bool is_pot_assuming_nonnegative(GLsizei x)
return x && (x & (x-1)) == 0;
}
inline bool FormatHasAlpha(GLenum format)
{
return format == LOCAL_GL_RGBA ||
format == LOCAL_GL_LUMINANCE_ALPHA ||
format == LOCAL_GL_ALPHA ||
format == LOCAL_GL_RGBA4 ||
format == LOCAL_GL_RGB5_A1;
}
// NOTE: When this class is switched to new DOM bindings, update the (then-slow)
// WrapObject calls in GetParameter and GetFramebufferAttachmentParameter.
class WebGLTexture MOZ_FINAL
@ -181,6 +190,9 @@ public:
// there is no way to go from having image data to not having any
MOZ_ASSERT(newStatus != WebGLImageDataStatus::NoImageData ||
imageInfo.mImageDataStatus == WebGLImageDataStatus::NoImageData);
if (imageInfo.mImageDataStatus != newStatus) {
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
imageInfo.mImageDataStatus = newStatus;
}
@ -193,7 +205,7 @@ protected:
nsTArray<ImageInfo> mImageInfos;
bool mHaveGeneratedMipmap;
FakeBlackStatus mFakeBlackStatus;
WebGLTextureFakeBlackStatus mFakeBlackStatus;
void EnsureMaxLevelWithCustomImagesAtLeast(size_t aMaxLevelWithCustomImages) {
mMaxLevelWithCustomImages = std::max(mMaxLevelWithCustomImages, aMaxLevelWithCustomImages);
@ -214,8 +226,6 @@ protected:
public:
void SetDontKnowIfNeedFakeBlack();
void Bind(GLenum aTarget);
void SetImageInfo(GLenum aTarget, GLint aLevel,
@ -224,19 +234,19 @@ public:
void SetMinFilter(GLenum aMinFilter) {
mMinFilter = aMinFilter;
SetDontKnowIfNeedFakeBlack();
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
void SetMagFilter(GLenum aMagFilter) {
mMagFilter = aMagFilter;
SetDontKnowIfNeedFakeBlack();
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
void SetWrapS(GLenum aWrapS) {
mWrapS = aWrapS;
SetDontKnowIfNeedFakeBlack();
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
void SetWrapT(GLenum aWrapT) {
mWrapT = aWrapT;
SetDontKnowIfNeedFakeBlack();
SetFakeBlackStatus(WebGLTextureFakeBlackStatus::Unknown);
}
GLenum MinFilter() const { return mMinFilter; }
@ -260,7 +270,13 @@ public:
bool IsMipmapCubeComplete() const;
bool NeedFakeBlack();
void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x) {
mFakeBlackStatus = x;
mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
}
// Returns the current fake-black-status, except if it was Unknown,
// in which case this function resolves it first, so it never returns Unknown.
WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus();
};
} // namespace mozilla

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

@ -19,7 +19,45 @@ typedef bool WebGLboolean;
namespace mozilla {
enum FakeBlackStatus { DoNotNeedFakeBlack, DoNeedFakeBlack, DontKnowIfNeedFakeBlack };
/*
* WebGLContextFakeBlackStatus and WebGLTextureFakeBlackStatus are enums to
* track what needs to use a dummy 1x1 black texture, which we refer to as a
* 'fake black' texture.
*
* There are generally two things that can cause us to use such 'fake black'
* textures:
*
* (1) OpenGL ES rules on sampling incomplete textures specify that they
* must be sampled as RGBA(0, 0, 0, 1) (opaque black). We have to implement these rules
* ourselves, if only because we do not always run on OpenGL ES, and also
* because this is dangerously close to the kind of case where we don't
* want to trust the driver with corner cases of texture memory accesses.
*
* (2) OpenGL has cases where a renderbuffer, or a texture image, can contain
* uninitialized image data. See below the comment about WebGLImageDataStatus.
* WebGL must never have access to uninitialized image data. The WebGL 1 spec,
* section 4.1 'Resource Restrictions', specifies that in any such case, the
* uninitialized image data must be exposed to WebGL as if it were filled
* with zero bytes, which means it's either opaque or transparent black
* depending on whether the image format has alpha.
*
* Why are there _two_ separate enums there, WebGLContextFakeBlackStatus
* and WebGLTextureFakeBlackStatus? That's because each texture must know the precise
* reason why it needs to be faked (incomplete texture vs. uninitialized image data),
* whereas the WebGL context can only know whether _any_ faking is currently needed at all.
*/
MOZ_BEGIN_ENUM_CLASS(WebGLContextFakeBlackStatus, int)
Unknown,
NotNeeded,
Needed
MOZ_END_ENUM_CLASS(WebGLContextFakeBlackStatus)
MOZ_BEGIN_ENUM_CLASS(WebGLTextureFakeBlackStatus, int)
Unknown,
NotNeeded,
IncompleteTexture,
UninitializedImageData
MOZ_END_ENUM_CLASS(WebGLTextureFakeBlackStatus)
struct VertexAttrib0Status {
enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };