diff --git a/gfx/gl/VBOArena.cpp b/gfx/gl/VBOArena.cpp new file mode 100644 index 000000000000..d27f9cb6ba1a --- /dev/null +++ b/gfx/gl/VBOArena.cpp @@ -0,0 +1,36 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * 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 "VBOArena.h" + +using namespace mozilla::gl; + +GLuint VBOArena::Allocate(GLContext *aGLContext) +{ + if (!mAvailableVBOs.size()) { + GLuint vbo; + aGLContext->fGenBuffers(1, &vbo); + mAllocatedVBOs.push_back(vbo); + return vbo; + } + GLuint vbo = mAvailableVBOs.back(); + mAvailableVBOs.pop_back(); + return vbo; +} + +void VBOArena::Reset() +{ + mAvailableVBOs = mAllocatedVBOs; +} + +void VBOArena::Flush(GLContext *aGLContext) +{ + if (mAvailableVBOs.size()) { +#ifdef DEBUG + printf_stderr("VBOArena::Flush for %u VBOs\n", mAvailableVBOs.size()); +#endif + aGLContext->fDeleteBuffers(mAvailableVBOs.size(), mAvailableVBOs.data()); + } +} diff --git a/gfx/gl/VBOArena.h b/gfx/gl/VBOArena.h new file mode 100644 index 000000000000..5b52945eb6c4 --- /dev/null +++ b/gfx/gl/VBOArena.h @@ -0,0 +1,33 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * 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/. */ + +#ifndef VBOARENA_H_ +#define VBOARENA_H_ + +#include "GLContext.h" +#include + +namespace mozilla { +namespace gl { + +class VBOArena { +public: + // Allocate a new VBO. + GLuint Allocate(GLContext *aGLContext); + + // Re-use previously allocated VBOs. + void Reset(); + + // Throw away all allocated VBOs. + void Flush(GLContext *aGLContext); +private: + std::vector mAllocatedVBOs; + std::vector mAvailableVBOs; +}; + +} +} + +#endif diff --git a/gfx/gl/moz.build b/gfx/gl/moz.build index d1b76d7130f5..b6d24f062ec2 100644 --- a/gfx/gl/moz.build +++ b/gfx/gl/moz.build @@ -53,6 +53,7 @@ EXPORTS += [ 'SurfaceFactory.h', 'SurfaceStream.h', 'SurfaceTypes.h', + 'VBOArena.h', ] if CONFIG['MOZ_X11']: @@ -112,6 +113,7 @@ CPP_SOURCES += [ 'SharedSurfaceGL.cpp', 'SurfaceFactory.cpp', 'SurfaceStream.cpp', + 'VBOArena.cpp', ] FAIL_ON_WARNINGS = True diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index a9b9e096e2b9..40c0ee183b42 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -9,6 +9,7 @@ #include // for free, malloc #include "FPSCounter.h" // for FPSState, FPSCounter #include "GLContextProvider.h" // for GLContextProvider +#include "LayerManagerOGL.h" // for BUFFER_OFFSET #include "Layers.h" // for WriteSnapshotToDumpFile #include "gfx2DGlue.h" // for ThebesFilter #include "gfx3DMatrix.h" // for gfx3DMatrix @@ -56,6 +57,51 @@ static inline IntSize ns2gfxSize(const nsIntSize& s) { return IntSize(s.width, s.height); } +// Draw the supplied geometry with the already selected shader. Both aArray1 +// and aArray2 are expected to have a stride of 2 * sizeof(GLfloat). +static void +DrawWithVertexBuffer2(GLContext *aGLContext, VBOArena &aVBOs, + GLenum aMode, GLsizei aElements, + GLint aAttr1, GLfloat *aArray1, + GLint aAttr2, GLfloat *aArray2) +{ + GLsizei bytes = aElements * 2 * sizeof(GLfloat); + + aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, + aVBOs.Allocate(aGLContext)); + aGLContext->fBufferData(LOCAL_GL_ARRAY_BUFFER, + 2 * bytes, + nullptr, + LOCAL_GL_STREAM_DRAW); + + aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER, + 0, + bytes, + aArray1); + aGLContext->fBufferSubData(LOCAL_GL_ARRAY_BUFFER, + bytes, + bytes, + aArray2); + + aGLContext->fEnableVertexAttribArray(aAttr1); + aGLContext->fEnableVertexAttribArray(aAttr2); + + aGLContext->fVertexAttribPointer(aAttr1, + 2, LOCAL_GL_FLOAT, + LOCAL_GL_FALSE, + 0, BUFFER_OFFSET(0)); + aGLContext->fVertexAttribPointer(aAttr2, + 2, LOCAL_GL_FLOAT, + LOCAL_GL_FALSE, + 0, BUFFER_OFFSET(bytes)); + + aGLContext->fDrawArrays(aMode, 0, aElements); + + aGLContext->fDisableVertexAttribArray(aAttr1); + aGLContext->fDisableVertexAttribArray(aAttr2); + + aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); +} void FPSState::DrawFPS(TimeStamp aNow, @@ -98,6 +144,8 @@ FPSState::DrawFPS(TimeStamp aNow, free(buf); } + mVBOs.Reset(); + struct Vertex2D { float x,y; }; @@ -191,44 +239,21 @@ FPSState::DrawFPS(TimeStamp aNow, copyprog->Activate(); copyprog->SetTextureUnit(0); - // we're going to use client-side vertex arrays for this. - context->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); - // "COPY" context->fBlendFuncSeparate(LOCAL_GL_ONE, LOCAL_GL_ZERO, LOCAL_GL_ONE, LOCAL_GL_ZERO); - // enable our vertex attribs; we'll call glVertexPointer below - // to fill with the correct data. GLint vcattr = copyprog->AttribLocation(ShaderProgramOGL::VertexCoordAttrib); GLint tcattr = copyprog->AttribLocation(ShaderProgramOGL::TexCoordAttrib); - context->fEnableVertexAttribArray(vcattr); - context->fEnableVertexAttribArray(tcattr); - - context->fVertexAttribPointer(vcattr, - 2, LOCAL_GL_FLOAT, - LOCAL_GL_FALSE, - 0, vertices); - - context->fVertexAttribPointer(tcattr, - 2, LOCAL_GL_FLOAT, - LOCAL_GL_FALSE, - 0, texCoords); - - context->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 12); - - context->fVertexAttribPointer(vcattr, - 2, LOCAL_GL_FLOAT, - LOCAL_GL_FALSE, - 0, vertices2); - - context->fVertexAttribPointer(tcattr, - 2, LOCAL_GL_FLOAT, - LOCAL_GL_FALSE, - 0, texCoords2); - - context->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 12); + DrawWithVertexBuffer2(context, mVBOs, + LOCAL_GL_TRIANGLE_STRIP, 12, + vcattr, (GLfloat *) vertices, + tcattr, (GLfloat *) texCoords); + DrawWithVertexBuffer2(context, mVBOs, + LOCAL_GL_TRIANGLE_STRIP, 12, + vcattr, (GLfloat *) vertices2, + tcattr, (GLfloat *) texCoords2); } #ifdef CHECK_CURRENT_PROGRAM @@ -312,9 +337,17 @@ CompositorOGL::GetTemporaryTexture(GLenum aTextureUnit) void CompositorOGL::Destroy() { - if (gl() && mTextures.Length() > 0) { + if (gl()) { gl()->MakeCurrent(); - gl()->fDeleteTextures(mTextures.Length(), &mTextures[0]); + if (mTextures.Length() > 0) { + gl()->fDeleteTextures(mTextures.Length(), &mTextures[0]); + } + mVBOs.Flush(gl()); + if (mFPS) { + if (mFPS->mTexture > 0) + gl()->fDeleteTextures(1, &mFPS->mTexture); + mFPS->mVBOs.Flush(gl()); + } } mTextures.SetLength(0); if (!mDestroyed) { @@ -557,10 +590,6 @@ CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg, aProg->AttribLocation(ShaderProgramOGL::TexCoordAttrib); NS_ASSERTION(texCoordAttribIndex != GLuint(-1), "no texture coords?"); - // clear any bound VBO so that glVertexAttribPointer() goes back to - // "pointer mode" - mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0); - // Given what we know about these textures and coordinates, we can // compute fmod(t, 1.0f) to get the same texture coordinate out. If // the texCoordRect dimension is < 0 or > width/height, then we have @@ -614,25 +643,10 @@ CompositorOGL::BindAndDrawQuadWithTextureRect(ShaderProgramOGL *aProg, rects, flipped); } - mGLContext->fVertexAttribPointer(vertAttribIndex, 2, - LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, - rects.vertexPointer()); - - mGLContext->fVertexAttribPointer(texCoordAttribIndex, 2, - LOCAL_GL_FLOAT, LOCAL_GL_FALSE, 0, - rects.texCoordPointer()); - - { - mGLContext->fEnableVertexAttribArray(texCoordAttribIndex); - { - mGLContext->fEnableVertexAttribArray(vertAttribIndex); - - mGLContext->fDrawArrays(LOCAL_GL_TRIANGLES, 0, rects.elements()); - - mGLContext->fDisableVertexAttribArray(vertAttribIndex); - } - mGLContext->fDisableVertexAttribArray(texCoordAttribIndex); - } + DrawWithVertexBuffer2(mGLContext, mVBOs, + LOCAL_GL_TRIANGLES, rects.elements(), + vertAttribIndex, rects.vertexPointer(), + texCoordAttribIndex, rects.texCoordPointer()); } void @@ -769,6 +783,8 @@ CompositorOGL::BeginFrame(const Rect *aClipRectIn, const gfxMatrix& aTransform, { MOZ_ASSERT(!mFrameInProgress, "frame still in progress (should have called EndFrame or AbortFrame"); + mVBOs.Reset(); + mFrameInProgress = true; gfxRect rect; if (mUseExternalSurfaceSize) { diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h index a92317051566..0ee55fbeb816 100644 --- a/gfx/layers/opengl/CompositorOGL.h +++ b/gfx/layers/opengl/CompositorOGL.h @@ -36,6 +36,8 @@ #include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc #include "nsXULAppAPI.h" // for XRE_GetProcessType #include "nscore.h" // for NS_IMETHOD +#include "VBOArena.h" // for gl::VBOArena + class gfx3DMatrix; class nsIWidget; struct gfxMatrix; @@ -235,6 +237,11 @@ private: * flipped and unflipped textures */ GLuint mQuadVBO; + /** + * When we can't use mQuadVBO, we allocate VBOs from this arena instead. + */ + gl::VBOArena mVBOs; + bool mHasBGRA; /** diff --git a/gfx/layers/opengl/FPSCounter.h b/gfx/layers/opengl/FPSCounter.h index 34f4ef54409c..95e94fe884a0 100644 --- a/gfx/layers/opengl/FPSCounter.h +++ b/gfx/layers/opengl/FPSCounter.h @@ -8,6 +8,7 @@ #include "GLDefs.h" // for GLuint #include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration #include "nsTArray.h" // for nsAutoTArray, nsTArray_Impl, etc +#include "VBOArena.h" // for gl::VBOArena namespace mozilla { namespace gl { @@ -70,6 +71,7 @@ struct FPSState { GLuint mTexture; FPSCounter mCompositionFps; FPSCounter mTransactionFps; + gl::VBOArena mVBOs; FPSState() : mTexture(0) { }