Bug 631420 - OS X WebGL crash with too-small attrib 0 + optimizations - r=vlad, a=blocking2.0

This commit is contained in:
Benoit Jacob 2011-02-24 17:17:34 -05:00
parent 184d25116b
commit d6905754de
3 changed files with 89 additions and 27 deletions

View File

@ -113,11 +113,17 @@ WebGLContext::WebGLContext()
mBlackTexturesAreInitialized = PR_FALSE;
mFakeBlackStatus = DoNotNeedFakeBlack;
mFakeVertexAttrib0Array = nsnull;
mVertexAttrib0Vector[0] = 0;
mVertexAttrib0Vector[1] = 0;
mVertexAttrib0Vector[2] = 0;
mVertexAttrib0Vector[3] = 1;
mFakeVertexAttrib0BufferObjectVector[0] = 0;
mFakeVertexAttrib0BufferObjectVector[1] = 0;
mFakeVertexAttrib0BufferObjectVector[2] = 0;
mFakeVertexAttrib0BufferObjectVector[3] = 1;
mFakeVertexAttrib0BufferObjectSize = 0;
mFakeVertexAttrib0BufferObject = 0;
mFakeVertexAttrib0BufferStatus = VertexAttrib0Status::Default;
}
WebGLContext::~WebGLContext()
@ -223,6 +229,10 @@ WebGLContext::DestroyResourcesAndContext()
mBlackTexturesAreInitialized = PR_FALSE;
}
if (mFakeVertexAttrib0BufferObject) {
gl->fDeleteBuffers(1, &mFakeVertexAttrib0BufferObject);
}
// We just got rid of everything, so the context had better
// have been going away.
#ifdef DEBUG

View File

@ -80,6 +80,10 @@ class WebGLContextBoundObject;
enum FakeBlackStatus { DoNotNeedFakeBlack, DoNeedFakeBlack, DontKnowIfNeedFakeBlack };
struct VertexAttrib0Status {
enum { Default, EmulatedUninitializedArray, EmulatedInitializedArray };
};
struct WebGLTexelFormat {
enum { Generic, Auto, RGBA8, RGB8, RGBX8, BGRA8, BGR8, BGRX8, RGBA5551, RGBA4444, RGB565, R8, RA8, A8 };
};
@ -371,6 +375,7 @@ public:
// all context resources to be lost.
PRUint32 Generation() { return mGeneration.value(); }
protected:
void SetDontKnowIfNeedFakeBlack() {
mFakeBlackStatus = DontKnowIfNeedFakeBlack;
}
@ -379,11 +384,11 @@ public:
void BindFakeBlackTextures();
void UnbindFakeBlackTextures();
PRBool NeedFakeVertexAttrib0();
int WhatDoesVertexAttrib0Need();
void DoFakeVertexAttrib0(WebGLuint vertexCount);
void UndoFakeVertexAttrib0();
void InvalidateFakeVertexAttrib0();
protected:
nsCOMPtr<nsIDOMHTMLCanvasElement> mCanvasElement;
nsHTMLCanvasElement *HTMLCanvasElement() {
return static_cast<nsHTMLCanvasElement*>(mCanvasElement.get());
@ -550,7 +555,10 @@ protected:
PRBool mBlackTexturesAreInitialized;
WebGLfloat mVertexAttrib0Vector[4];
nsAutoArrayPtr<WebGLfloat> mFakeVertexAttrib0Array;
WebGLfloat mFakeVertexAttrib0BufferObjectVector[4];
size_t mFakeVertexAttrib0BufferObjectSize;
GLuint mFakeVertexAttrib0BufferObject;
int mFakeVertexAttrib0BufferStatus;
WebGLint mStencilRef;
WebGLuint mStencilValueMask, mStencilWriteMask;

View File

@ -1085,46 +1085,91 @@ WebGLContext::DisableVertexAttribArray(WebGLuint index)
return NS_OK;
}
PRBool
WebGLContext::NeedFakeVertexAttrib0()
int
WebGLContext::WhatDoesVertexAttrib0Need()
{
return !gl->IsGLES2() &&
!mAttribBuffers[0].enabled;
// here we may assume that mCurrentProgram != null
// work around Mac OSX crash, see bug 631420
#ifdef XP_MACOSX
if (mAttribBuffers[0].enabled &&
!mCurrentProgram->IsAttribInUse(0))
return VertexAttrib0Status::EmulatedUninitializedArray;
#endif
return (gl->IsGLES2() || mAttribBuffers[0].enabled) ? VertexAttrib0Status::Default
: mCurrentProgram->IsAttribInUse(0) ? VertexAttrib0Status::EmulatedInitializedArray
: VertexAttrib0Status::EmulatedUninitializedArray;
}
void
WebGLContext::DoFakeVertexAttrib0(WebGLuint vertexCount)
{
if (!NeedFakeVertexAttrib0())
int whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
if (whatDoesAttrib0Need == VertexAttrib0Status::Default)
return;
mFakeVertexAttrib0Array = new WebGLfloat[4 * vertexCount];
WebGLuint dataSize = sizeof(WebGLfloat) * 4 * vertexCount;
for(size_t i = 0; i < vertexCount; ++i) {
mFakeVertexAttrib0Array[4 * i + 0] = mVertexAttrib0Vector[0];
mFakeVertexAttrib0Array[4 * i + 1] = mVertexAttrib0Vector[1];
mFakeVertexAttrib0Array[4 * i + 2] = mVertexAttrib0Vector[2];
mFakeVertexAttrib0Array[4 * i + 3] = mVertexAttrib0Vector[3];
if (!mFakeVertexAttrib0BufferObject) {
gl->fGenBuffers(1, &mFakeVertexAttrib0BufferObject);
}
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, mFakeVertexAttrib0Array);
// if the VBO status is already exactly what we need, or if the only difference is that it's initialized and
// we don't need it to be, then consider it OK
PRBool vertexAttrib0BufferStatusOK =
mFakeVertexAttrib0BufferStatus == whatDoesAttrib0Need ||
(mFakeVertexAttrib0BufferStatus == VertexAttrib0Status::EmulatedInitializedArray &&
whatDoesAttrib0Need == VertexAttrib0Status::EmulatedUninitializedArray);
if (!vertexAttrib0BufferStatusOK ||
mFakeVertexAttrib0BufferObjectSize < dataSize ||
mFakeVertexAttrib0BufferObjectVector[0] != mVertexAttrib0Vector[0] ||
mFakeVertexAttrib0BufferObjectVector[1] != mVertexAttrib0Vector[1] ||
mFakeVertexAttrib0BufferObjectVector[2] != mVertexAttrib0Vector[2] ||
mFakeVertexAttrib0BufferObjectVector[3] != mVertexAttrib0Vector[3])
{
mFakeVertexAttrib0BufferStatus = whatDoesAttrib0Need;
mFakeVertexAttrib0BufferObjectSize = dataSize;
mFakeVertexAttrib0BufferObjectVector[0] = mVertexAttrib0Vector[0];
mFakeVertexAttrib0BufferObjectVector[1] = mVertexAttrib0Vector[1];
mFakeVertexAttrib0BufferObjectVector[2] = mVertexAttrib0Vector[2];
mFakeVertexAttrib0BufferObjectVector[3] = mVertexAttrib0Vector[3];
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
WebGLuint dataSize = sizeof(WebGLfloat) * 4 * vertexCount;
if (mFakeVertexAttrib0BufferStatus == VertexAttrib0Status::EmulatedInitializedArray) {
nsAutoArrayPtr<WebGLfloat> array(new WebGLfloat[4 * vertexCount]);
for(size_t i = 0; i < vertexCount; ++i) {
array[4 * i + 0] = mVertexAttrib0Vector[0];
array[4 * i + 1] = mVertexAttrib0Vector[1];
array[4 * i + 2] = mVertexAttrib0Vector[2];
array[4 * i + 3] = mVertexAttrib0Vector[3];
}
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, array, LOCAL_GL_DYNAMIC_DRAW);
} else {
gl->fBufferData(LOCAL_GL_ARRAY_BUFFER, dataSize, nsnull, LOCAL_GL_DYNAMIC_DRAW);
}
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
}
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mFakeVertexAttrib0BufferObject);
gl->fVertexAttribPointer(0, 4, LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, 0);
}
void
WebGLContext::UndoFakeVertexAttrib0()
{
if (!NeedFakeVertexAttrib0())
int whatDoesAttrib0Need = WhatDoesVertexAttrib0Need();
if (whatDoesAttrib0Need == VertexAttrib0Status::Default)
return;
mFakeVertexAttrib0Array = nsnull;
// first set the bound buffer as needed for subsequent gl->fVertexAttribPointer call.
// since in DoFakeVertexAttrib0() we called bindBuffer on buffer zero, we only need to do that if
// we have a nonzero buffer binding for this attrib.
if (mAttribBuffers[0].buf)
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mAttribBuffers[0].buf->GLName());
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mAttribBuffers[0].buf ? mAttribBuffers[0].buf->GLName() : 0);
gl->fVertexAttribPointer(0,
mAttribBuffers[0].size,
mAttribBuffers[0].type,
@ -1132,7 +1177,6 @@ WebGLContext::UndoFakeVertexAttrib0()
mAttribBuffers[0].stride,
(const GLvoid *) mAttribBuffers[0].byteOffset);
// now restore the bound buffer to its state before we did this whole draw call business
gl->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, mBoundArrayBuffer ? mBoundArrayBuffer->GLName() : 0);
}