Bug 978407 - Use glClear to clear deferred-init textures. - r=kamidphish

This commit is contained in:
Jeff Gilbert 2014-04-30 14:30:21 -07:00
parent 35e35895f4
commit d3a469b54a
4 changed files with 205 additions and 18 deletions

View File

@ -3,12 +3,15 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGLContext.h"
#include "WebGLTexture.h"
#include "GLContext.h"
#include "ScopedGLHelpers.h"
#include "WebGLTexelConversions.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "mozilla/Scoped.h"
#include "ScopedGLHelpers.h"
#include "WebGLContext.h"
#include "WebGLTexelConversions.h"
#include <algorithm>
using namespace mozilla;
@ -433,6 +436,104 @@ WebGLTexture::ResolvedFakeBlackStatus() {
return mFakeBlackStatus;
}
static bool
ClearByMask(WebGLContext* context, GLbitfield mask)
{
gl::GLContext* gl = context->GL();
MOZ_ASSERT(gl->IsCurrent());
GLenum status = gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE)
return false;
bool colorAttachmentsMask[context->sMaxColorAttachments] = {false};
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
colorAttachmentsMask[0] = true;
}
context->ForceClearFramebufferWithDefaultValues(mask, colorAttachmentsMask);
return true;
}
// `mask` from glClear.
static bool
ClearWithTempFB(WebGLContext* context, GLuint tex,
GLenum texImageTarget, GLint level,
GLenum baseInternalFormat,
GLsizei width, GLsizei height)
{
if (texImageTarget != LOCAL_GL_TEXTURE_2D)
return false;
gl::GLContext* gl = context->GL();
MOZ_ASSERT(gl->IsCurrent());
gl::ScopedFramebuffer fb(gl);
gl::ScopedBindFramebuffer autoFB(gl, fb.FB());
GLbitfield mask = 0;
switch (baseInternalFormat) {
case LOCAL_GL_LUMINANCE:
case LOCAL_GL_LUMINANCE_ALPHA:
case LOCAL_GL_ALPHA:
case LOCAL_GL_RGB:
case LOCAL_GL_RGBA:
case LOCAL_GL_BGR:
case LOCAL_GL_BGRA:
mask = LOCAL_GL_COLOR_BUFFER_BIT;
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
texImageTarget, tex, level);
break;
case LOCAL_GL_DEPTH_COMPONENT:
mask = LOCAL_GL_DEPTH_BUFFER_BIT;
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
texImageTarget, tex, level);
break;
case LOCAL_GL_DEPTH_STENCIL:
mask = LOCAL_GL_DEPTH_BUFFER_BIT |
LOCAL_GL_STENCIL_BUFFER_BIT;
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_DEPTH_ATTACHMENT,
texImageTarget, tex, level);
gl->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_STENCIL_ATTACHMENT,
texImageTarget, tex, level);
break;
default:
return false;
}
MOZ_ASSERT(mask);
if (ClearByMask(context, mask))
return true;
// Failed to simply build an FB from the tex, but maybe it needs a
// color buffer to be complete.
if (mask & LOCAL_GL_COLOR_BUFFER_BIT) {
// Nope, it already had one.
return false;
}
gl::ScopedRenderbuffer rb(gl);
{
gl::ScopedBindRenderbuffer(gl, rb.RB());
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER,
LOCAL_GL_RGBA4,
width, height);
}
gl->fFramebufferRenderbuffer(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0,
LOCAL_GL_RENDERBUFFER, rb.RB());
mask |= LOCAL_GL_COLOR_BUFFER_BIT;
// Last chance!
return ClearByMask(context, mask);
}
void
WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level)
{
@ -440,9 +541,20 @@ WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level)
MOZ_ASSERT(imageInfo.mImageDataStatus == WebGLImageDataStatus::UninitializedImageData);
mContext->MakeContextCurrent();
// Try to clear with glCLear.
WebGLTexelFormat texelformat = GetWebGLTexelFormat(imageInfo.mInternalFormat, imageInfo.mType);
GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat);
bool cleared = ClearWithTempFB(mContext, GLName(),
imageTarget, level,
format, imageInfo.mHeight, imageInfo.mWidth);
if (cleared)
return;
// That didn't work. Try uploading zeros then.
gl::ScopedBindTexture autoBindTex(mContext->gl, GLName(), mTarget);
WebGLTexelFormat texelformat = GetWebGLTexelFormat(imageInfo.mInternalFormat, imageInfo.mType);
uint32_t texelsize = WebGLTexelConversions::TexelBytesForFormat(texelformat);
CheckedUint32 checked_byteLength
= WebGLContext::GetImageSize(
@ -451,24 +563,28 @@ WebGLTexture::DoDeferredImageInitialization(GLenum imageTarget, GLint level)
texelsize,
mContext->mPixelStoreUnpackAlignment);
MOZ_ASSERT(checked_byteLength.isValid()); // should have been checked earlier
void *zeros = calloc(1, checked_byteLength.value());
ScopedFreePtr<void> zeros;
zeros = calloc(1, checked_byteLength.value());
GLenum format = WebGLTexelConversions::GLFormatForTexelFormat(texelformat);
mContext->GetAndFlushUnderlyingGLErrors();
mContext->gl->fTexImage2D(imageTarget, level, imageInfo.mInternalFormat,
imageInfo.mWidth, imageInfo.mHeight,
0, format, imageInfo.mType,
zeros);
GLenum error = mContext->GetAndFlushUnderlyingGLErrors();
free(zeros);
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
if (error) {
// Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here.
MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past.
return;
// Should only be OUT_OF_MEMORY. Anyway, there's no good way to recover from this here.
MOZ_CRASH(); // errors on texture upload have been related to video memory exposure in the past.
}
SetImageDataStatus(imageTarget, level, WebGLImageDataStatus::InitializedImageData);
}
void
WebGLTexture::SetFakeBlackStatus(WebGLTextureFakeBlackStatus x)
{
mFakeBlackStatus = x;
mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
}
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WebGLTexture)

View File

@ -11,6 +11,7 @@
#include "nsWrapperCache.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/LinkedList.h"
#include <algorithm>
@ -273,10 +274,8 @@ public:
bool IsMipmapCubeComplete() const;
void SetFakeBlackStatus(WebGLTextureFakeBlackStatus x) {
mFakeBlackStatus = x;
mContext->SetFakeBlackStatus(WebGLContextFakeBlackStatus::Unknown);
}
void SetFakeBlackStatus(WebGLTextureFakeBlackStatus 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.
WebGLTextureFakeBlackStatus ResolvedFakeBlackStatus();

View File

@ -102,6 +102,7 @@ ScopedBindTextureUnit::UnwrapImpl() {
ScopedTexture::ScopedTexture(GLContext* aGL)
: ScopedGLWrapper<ScopedTexture>(aGL)
{
MOZ_ASSERT(mGL->IsCurrent());
mGL->fGenTextures(1, &mTexture);
}
@ -111,10 +112,47 @@ ScopedTexture::UnwrapImpl()
// Check that we're not falling out of scope after
// the current context changed.
MOZ_ASSERT(mGL->IsCurrent());
mGL->fDeleteTextures(1, &mTexture);
}
/* ScopedFramebuffer **************************************************************/
ScopedFramebuffer::ScopedFramebuffer(GLContext* aGL)
: ScopedGLWrapper<ScopedFramebuffer>(aGL)
{
MOZ_ASSERT(mGL->IsCurrent());
mGL->fGenFramebuffers(1, &mFB);
}
void
ScopedFramebuffer::UnwrapImpl()
{
// Check that we're not falling out of scope after
// the current context changed.
MOZ_ASSERT(mGL->IsCurrent());
mGL->fDeleteFramebuffers(1, &mFB);
}
/* ScopedRenderbuffer **************************************************************/
ScopedRenderbuffer::ScopedRenderbuffer(GLContext* aGL)
: ScopedGLWrapper<ScopedRenderbuffer>(aGL)
{
MOZ_ASSERT(mGL->IsCurrent());
mGL->fGenRenderbuffers(1, &mRB);
}
void
ScopedRenderbuffer::UnwrapImpl()
{
// Check that we're not falling out of scope after
// the current context changed.
MOZ_ASSERT(mGL->IsCurrent());
mGL->fDeleteRenderbuffers(1, &mRB);
}
/* ScopedBindTexture **********************************************************/
void
ScopedBindTexture::Init(GLenum aTarget)

View File

@ -120,6 +120,40 @@ protected:
};
struct ScopedFramebuffer
: public ScopedGLWrapper<ScopedFramebuffer>
{
friend struct ScopedGLWrapper<ScopedFramebuffer>;
protected:
GLuint mFB;
public:
ScopedFramebuffer(GLContext* aGL);
GLuint FB() { return mFB; }
protected:
void UnwrapImpl();
};
struct ScopedRenderbuffer
: public ScopedGLWrapper<ScopedRenderbuffer>
{
friend struct ScopedGLWrapper<ScopedRenderbuffer>;
protected:
GLuint mRB;
public:
ScopedRenderbuffer(GLContext* aGL);
GLuint RB() { return mRB; }
protected:
void UnwrapImpl();
};
struct ScopedBindTexture
: public ScopedGLWrapper<ScopedBindTexture>
{