diff --git a/content/canvas/src/WebGLContext.cpp b/content/canvas/src/WebGLContext.cpp index 4d8e2531b3a3..7ae9a2ba125f 100644 --- a/content/canvas/src/WebGLContext.cpp +++ b/content/canvas/src/WebGLContext.cpp @@ -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 diff --git a/content/canvas/src/WebGLContext.h b/content/canvas/src/WebGLContext.h index 9309a6b55d42..3a71086be74b 100644 --- a/content/canvas/src/WebGLContext.h +++ b/content/canvas/src/WebGLContext.h @@ -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 mCanvasElement; nsHTMLCanvasElement *HTMLCanvasElement() { return static_cast(mCanvasElement.get()); @@ -550,7 +555,10 @@ protected: PRBool mBlackTexturesAreInitialized; WebGLfloat mVertexAttrib0Vector[4]; - nsAutoArrayPtr mFakeVertexAttrib0Array; + WebGLfloat mFakeVertexAttrib0BufferObjectVector[4]; + size_t mFakeVertexAttrib0BufferObjectSize; + GLuint mFakeVertexAttrib0BufferObject; + int mFakeVertexAttrib0BufferStatus; WebGLint mStencilRef; WebGLuint mStencilValueMask, mStencilWriteMask; diff --git a/content/canvas/src/WebGLContextGL.cpp b/content/canvas/src/WebGLContextGL.cpp index 130bde396163..9cae0aca9db7 100644 --- a/content/canvas/src/WebGLContextGL.cpp +++ b/content/canvas/src/WebGLContextGL.cpp @@ -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 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); }