Bug 859608 - Flush GL on overdraw on Tegra devices. - r=bjacob

This commit is contained in:
Jeff Gilbert 2013-05-22 00:05:38 -07:00
parent e32f79e41c
commit 717900bdd3
5 changed files with 85 additions and 51 deletions

View File

@ -158,7 +158,7 @@ WebGLContext::WebGLContext()
mScissorTestEnabled = 0;
mDitherEnabled = 1;
// initialize some GL values: we're going to get them from the GL and use them as the sizes of arrays,
// so in case glGetIntegerv leaves them uninitialized because of a GL bug, we would have very weird crashes.
mGLMaxVertexAttribs = 0;
@ -198,6 +198,8 @@ WebGLContext::WebGLContext()
mIsScreenCleared = false;
mDisableFragHighP = false;
mDrawCallsSinceLastFlush = 0;
}
WebGLContext::~WebGLContext()
@ -520,12 +522,12 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
// try the default provider, whatever that is
if (!gl && useOpenGL) {
GLContext::ContextFlags flag = useMesaLlvmPipe
GLContext::ContextFlags flag = useMesaLlvmPipe
? GLContext::ContextFlagsMesaLLVMPipe
: GLContext::ContextFlagsNone;
gl = gl::GLContextProvider::CreateOffscreen(size, caps, flag);
if (gl && !InitAndValidateGL()) {
GenerateWarning("Error during %s initialization",
GenerateWarning("Error during %s initialization",
useMesaLlvmPipe ? "Mesa LLVMpipe" : "OpenGL");
return NS_ERROR_FAILURE;
}
@ -806,6 +808,7 @@ public:
// Present our screenbuffer, if needed.
context->PresentScreenBuffer();
context->mDrawCallsSinceLastFlush = 0;
}
/** DidTransactionCallback gets called by the Layers code everytime the WebGL canvas gets composite,
@ -975,9 +978,9 @@ bool WebGLContext::IsExtensionSupported(JSContext *cx, WebGLExtensionID ext) con
case WEBGL_compressed_texture_pvrtc:
return gl->IsExtensionSupported(GLContext::IMG_texture_compression_pvrtc);
case WEBGL_depth_texture:
if (gl->IsGLES2() &&
if (gl->IsGLES2() &&
gl->IsExtensionSupported(GLContext::OES_packed_depth_stencil) &&
gl->IsExtensionSupported(GLContext::OES_depth_texture))
gl->IsExtensionSupported(GLContext::OES_depth_texture))
{
return true;
}
@ -1389,7 +1392,7 @@ WebGLContext::MaybeRestoreContext()
resetStatus = GLContext::CONTEXT_GUILTY_CONTEXT_RESET_ARB;
}
}
if (resetStatus != GLContext::CONTEXT_NO_ERROR) {
// It's already lost, but clean up after it and signal to JS that it is
// lost.

View File

@ -1128,6 +1128,10 @@ protected:
ContextStatus mContextStatus;
bool mContextLostErrorSet;
// Used for some hardware (particularly Tegra 2 and 4) that likes to
// be Flushed while doing hundreds of draw calls.
int mDrawCallsSinceLastFlush;
int mAlreadyGeneratedWarnings;
bool mAlreadyWarnedAboutFakeVertexAttrib0;

View File

@ -38,6 +38,9 @@ using namespace mozilla::dom;
static bool BaseTypeAndSizeFromUniformType(WebGLenum uType, WebGLenum *baseType, WebGLint *unitSize);
static WebGLenum InternalFormatForFormatAndType(WebGLenum format, WebGLenum type, bool isGLES2);
// For a Tegra workaround.
static const int MAX_DRAW_CALLS_SINCE_FLUSH = 100;
//
// WebGL API
//
@ -1477,6 +1480,17 @@ WebGLContext::DrawArrays(GLenum mode, WebGLint first, WebGLsizei count)
mShouldPresent = true;
mIsScreenCleared = false;
}
if (gl->WorkAroundDriverBugs()) {
if (gl->Renderer() == gl::GLContext::RendererTegra) {
mDrawCallsSinceLastFlush++;
if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
gl->fFlush();
mDrawCallsSinceLastFlush = 0;
}
}
}
}
void
@ -1576,6 +1590,17 @@ WebGLContext::DrawElements(WebGLenum mode, WebGLsizei count, WebGLenum type,
mShouldPresent = true;
mIsScreenCleared = false;
}
if (gl->WorkAroundDriverBugs()) {
if (gl->Renderer() == gl::GLContext::RendererTegra) {
mDrawCallsSinceLastFlush++;
if (mDrawCallsSinceLastFlush >= MAX_DRAW_CALLS_SINCE_FLUSH) {
gl->fFlush();
mDrawCallsSinceLastFlush = 0;
}
}
}
}
void

View File

@ -355,7 +355,8 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
"Adreno (TM) 205",
"Adreno (TM) 320",
"PowerVR SGX 530",
"PowerVR SGX 540"
"PowerVR SGX 540",
"NVIDIA Tegra"
};
mRenderer = RendererOther;
@ -534,7 +535,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
mSymbols.fEGLImageTargetRenderbufferStorage = nullptr;
}
}
// Load developer symbols, don't fail if we can't find them.
SymLoadStruct auxSymbols[] = {
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
@ -779,10 +780,10 @@ GLContext::ListHasExtension(const GLubyte *extensions, const char *extension)
if (where || *extension == '\0')
return false;
/*
/*
* It takes a bit of care to be fool-proof about parsing the
* OpenGL extensions string. Don't be fooled by sub-strings,
* etc.
* etc.
*/
start = extensions;
for (;;) {
@ -1385,7 +1386,7 @@ GLContext::GetTexImage(GLuint aTexture, bool aYInvert, ShaderProgramType aShader
gfxIntSize size;
fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_WIDTH, &size.width);
fGetTexLevelParameteriv(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_TEXTURE_HEIGHT, &size.height);
nsRefPtr<gfxImageSurface> surf = new gfxImageSurface(size, gfxASurface::ImageFormatARGB32);
if (!surf || surf->CairoStatus()) {
return NULL;
@ -1400,7 +1401,7 @@ GLContext::GetTexImage(GLuint aTexture, bool aYInvert, ShaderProgramType aShader
if (currentPackAlignment != 4) {
fPixelStorei(LOCAL_GL_PACK_ALIGNMENT, currentPackAlignment);
}
if (aShader == RGBALayerProgramType || aShader == RGBXLayerProgramType) {
SwapRAndBComponents(surf);
}
@ -1838,8 +1839,8 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
if (srcSubRect.IsEmpty()) {
continue;
}
// We now have the intersection of
// the current source tile
// We now have the intersection of
// the current source tile
// and the desired source rectangle
// and the destination tile
// and the desired destination rectange
@ -1922,7 +1923,7 @@ GLContext::BlitTextureImage(TextureImage *aSrc, const nsIntRect& aSrcRect,
fEnable(LOCAL_GL_BLEND);
}
static unsigned int
static unsigned int
DataOffset(gfxImageSurface *aSurf, const nsIntPoint &aPoint)
{
unsigned int data = aPoint.y * aSurf->Stride();
@ -1930,8 +1931,8 @@ DataOffset(gfxImageSurface *aSurf, const nsIntPoint &aPoint)
return data;
}
ShaderProgramType
GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
ShaderProgramType
GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
bool aOverwrite,
@ -1942,21 +1943,21 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
bool textureInited = aOverwrite ? false : true;
MakeCurrent();
fActiveTexture(aTextureUnit);
if (!aTexture) {
fGenTextures(1, &aTexture);
fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MIN_FILTER,
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MIN_FILTER,
LOCAL_GL_LINEAR);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MAG_FILTER,
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MAG_FILTER,
LOCAL_GL_LINEAR);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_S,
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_T,
fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
textureInited = false;
} else {
@ -1973,17 +1974,17 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
nsRefPtr<gfxImageSurface> imageSurface = aSurface->GetAsImageSurface();
unsigned char* data = NULL;
if (!imageSurface ||
if (!imageSurface ||
(imageSurface->Format() != gfxASurface::ImageFormatARGB32 &&
imageSurface->Format() != gfxASurface::ImageFormatRGB24 &&
imageSurface->Format() != gfxASurface::ImageFormatRGB16_565 &&
imageSurface->Format() != gfxASurface::ImageFormatA8)) {
// We can't get suitable pixel data for the surface, make a copy
nsIntRect bounds = aDstRegion.GetBounds();
imageSurface =
new gfxImageSurface(gfxIntSize(bounds.width, bounds.height),
imageSurface =
new gfxImageSurface(gfxIntSize(bounds.width, bounds.height),
gfxASurface::ImageFormatARGB32);
nsRefPtr<gfxContext> context = new gfxContext(imageSurface);
context->Translate(-gfxPoint(aSrcPoint.x, aSrcPoint.y));
@ -2052,10 +2053,10 @@ GLContext::UploadSurfaceToTexture(gfxASurface *aSurface,
// The inital data pointer is at the top left point of the region's
// bounding rectangle. We need to find the offset of this rect
// within the region and adjust the data pointer accordingly.
unsigned char *rectData =
unsigned char *rectData =
data + DataOffset(imageSurface, iterRect->TopLeft() - topLeft);
NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
NS_ASSERTION(textureInited || (iterRect->x == 0 && iterRect->y == 0),
"Must be uploading to the origin when we don't have an existing texture");
if (textureInited && CanUploadSubTextures()) {
@ -2545,7 +2546,7 @@ GLContext::UseBlitProgram()
shaders[0] = fCreateShader(LOCAL_GL_VERTEX_SHADER);
shaders[1] = fCreateShader(LOCAL_GL_FRAGMENT_SHADER);
const char *blitVSSrc =
const char *blitVSSrc =
"attribute vec2 aVertex;"
"attribute vec2 aTexCoord;"
"varying vec2 vTexCoord;"

View File

@ -262,7 +262,7 @@ public:
bool IsGLES2() const {
return mIsGLES2;
}
/**
* Returns true if either this is the GLES2 API, or had the GL_ARB_ES2_compatibility extension
*/
@ -301,6 +301,7 @@ public:
RendererAdrenoTM320,
RendererSGX530,
RendererSGX540,
RendererTegra,
RendererOther
};
@ -859,14 +860,14 @@ public:
* The aDstPoint parameter is ignored if no texture was provided
* or aOverwrite is true.
*
* \param aSurface Surface to upload.
* \param aSurface Surface to upload.
* \param aDstRegion Region of texture to upload to.
* \param aTexture Texture to use, or 0 to have one created for you.
* \param aOverwrite Over an existing texture with a new one.
* \param aSrcPoint Offset into aSrc where the region's bound's
* \param aSrcPoint Offset into aSrc where the region's bound's
* TopLeft() sits.
* \param aPixelBuffer Pass true to upload texture data with an
* offset from the base data (generally for pixel buffer objects),
* offset from the base data (generally for pixel buffer objects),
* otherwise textures are upload with an absolute pointer to the data.
* \param aTextureUnit, the texture unit used temporarily to upload the
* surface. This testure may be overridden, clients should not rely on
@ -874,7 +875,7 @@ public:
* texture unit being active.
* \return Shader program needed to render this texture.
*/
ShaderProgramType UploadSurfaceToTexture(gfxASurface *aSurface,
ShaderProgramType UploadSurfaceToTexture(gfxASurface *aSurface,
const nsIntRegion& aDstRegion,
GLuint& aTexture,
bool aOverwrite = false,
@ -882,16 +883,16 @@ public:
bool aPixelBuffer = false,
GLenum aTextureUnit = LOCAL_GL_TEXTURE0);
void TexImage2D(GLenum target, GLint level, GLint internalformat,
void TexImage2D(GLenum target, GLint level, GLint internalformat,
GLsizei width, GLsizei height, GLsizei stride,
GLint pixelsize, GLint border, GLenum format,
GLint pixelsize, GLint border, GLenum format,
GLenum type, const GLvoid *pixels);
void TexSubImage2D(GLenum target, GLint level,
GLint xoffset, GLint yoffset,
void TexSubImage2D(GLenum target, GLint level,
GLint xoffset, GLint yoffset,
GLsizei width, GLsizei height, GLsizei stride,
GLint pixelsize, GLenum format,
GLint pixelsize, GLenum format,
GLenum type, const GLvoid* pixels);
/**
@ -1399,19 +1400,19 @@ protected:
}
public:
/** \returns the first GL error, and guarantees that all GL error flags are cleared,
* i.e. that a subsequent GetError call will return NO_ERROR
*/
GLenum GetAndClearError() {
// the first error is what we want to return
GLenum error = fGetError();
if (error) {
// clear all pending errors
while(fGetError()) {}
}
return error;
}
@ -1460,7 +1461,7 @@ public:
if (DebugMode() & DebugTrace)
printf_stderr("[gl:%p] < %s [0x%04x]\n", this, glFunction, mGLError);
if (mGLError != LOCAL_GL_NO_ERROR) {
printf_stderr("GL ERROR: %s generated GL error %s(0x%04x)\n",
printf_stderr("GL ERROR: %s generated GL error %s(0x%04x)\n",
glFunction,
GLErrorToString(mGLError),
mGLError);
@ -1497,7 +1498,7 @@ public:
#define BEFORE_GL_CALL do { \
BeforeGLCall(MOZ_FUNCTION_NAME); \
} while (0)
#define AFTER_GL_CALL do { \
AfterGLCall(MOZ_FUNCTION_NAME); \
} while (0)
@ -1591,7 +1592,7 @@ private:
// we use viewport instead and assume viewport size matches the
// destination. If we ever try use partial viewports for layers we need
// to fix this, and remove the assertion.
NS_ASSERTION(!mFlipped || (x == 0 && y == 0), "TODO: Need to flip the viewport rect");
NS_ASSERTION(!mFlipped || (x == 0 && y == 0), "TODO: Need to flip the viewport rect");
mSymbols.fViewport(x, y, width, height);
AFTER_GL_CALL;
}
@ -1985,7 +1986,7 @@ public:
}
void fGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint *params)
{
{
BEFORE_GL_CALL;
ASSERT_SYMBOL_PRESENT(fGetTexLevelParameteriv);
mSymbols.fGetTexLevelParameteriv(target, level, pname, params);