Bug 980647 - Part 1 - Move the compositor's texture recycling startegy behind a pool interface. r=Cwiiis

This commit is contained in:
Nicolas Silva 2014-03-12 17:28:47 +01:00
parent f172daa343
commit 7d15ed1003
3 changed files with 219 additions and 142 deletions

View File

@ -137,72 +137,6 @@ DrawQuads(GLContext *aGLContext,
aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
}
#ifdef MOZ_WIDGET_GONK
CompositorOGLGonkBackendSpecificData::CompositorOGLGonkBackendSpecificData(CompositorOGL* aCompositor)
: mCompositor(aCompositor)
{
}
CompositorOGLGonkBackendSpecificData::~CompositorOGLGonkBackendSpecificData()
{
// Delete all textures by calling EndFrame twice
gl()->MakeCurrent();
EndFrame();
EndFrame();
}
GLContext*
CompositorOGLGonkBackendSpecificData::gl() const
{
return mCompositor->gl();
}
GLuint
CompositorOGLGonkBackendSpecificData::GetTexture()
{
GLuint texture = 0;
if (!mUnusedTextures.IsEmpty()) {
// Try to reuse one from the unused pile first
texture = mUnusedTextures[0];
mUnusedTextures.RemoveElementAt(0);
} else if (gl()->MakeCurrent()) {
// There isn't one to reuse, create one.
gl()->fGenTextures(1, &texture);
}
if (texture) {
mCreatedTextures.AppendElement(texture);
}
return texture;
}
void
CompositorOGLGonkBackendSpecificData::EndFrame()
{
gl()->MakeCurrent();
// Some platforms have issues unlocking Gralloc buffers even when they're
// rebound.
if (gfxPrefs::OverzealousGrallocUnlocking()) {
mUnusedTextures.AppendElements(mCreatedTextures);
mCreatedTextures.Clear();
}
// Delete unused textures
for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
GLuint texture = mUnusedTextures[i];
gl()->fDeleteTextures(1, &texture);
}
mUnusedTextures.Clear();
// Move all created textures into the unused pile
mUnusedTextures.AppendElements(mCreatedTextures);
mCreatedTextures.Clear();
}
#endif
CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
int aSurfaceHeight, bool aUseExternalSurfaceSize)
: mWidget(aWidget)
@ -246,38 +180,18 @@ CompositorOGL::CreateContext()
return context.forget();
}
GLuint
CompositorOGL::GetTemporaryTexture(GLenum aTextureUnit)
{
size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
// lazily grow the array of temporary textures
if (mTextures.Length() <= index) {
size_t prevLength = mTextures.Length();
mTextures.SetLength(index + 1);
for(unsigned int i = prevLength; i <= index; ++i) {
mTextures[i] = 0;
}
}
// lazily initialize the temporary textures
if (!mTextures[index]) {
if (!gl()->MakeCurrent()) {
return 0;
}
gl()->fGenTextures(1, &mTextures[index]);
}
return mTextures[index];
}
void
CompositorOGL::Destroy()
{
if (gl() && gl()->MakeCurrent()) {
if (mTextures.Length() > 0) {
gl()->fDeleteTextures(mTextures.Length(), &mTextures[0]);
}
mVBOs.Flush(gl());
}
mTextures.SetLength(0);
if (mTexturePool) {
mTexturePool->Clear();
mTexturePool = nullptr;
}
if (!mDestroyed) {
mDestroyed = true;
CleanupResources();
@ -1366,11 +1280,9 @@ CompositorOGL::EndFrame()
mCurrentRenderTarget = nullptr;
#ifdef MOZ_WIDGET_GONK
if (mCompositorBackendSpecificData) {
static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositorBackendSpecificData.get())->EndFrame();
if (mTexturePool) {
mTexturePool->EndFrame();
}
#endif
mGLContext->SwapBuffers();
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
@ -1480,17 +1392,6 @@ CompositorOGL::Resume()
return true;
}
#ifdef MOZ_WIDGET_GONK
CompositorBackendSpecificData*
CompositorOGL::GetCompositorBackendSpecificData()
{
if (!mCompositorBackendSpecificData) {
mCompositorBackendSpecificData = new CompositorOGLGonkBackendSpecificData(this);
}
return mCompositorBackendSpecificData;
}
#endif
TemporaryRef<DataTextureSource>
CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
{
@ -1593,5 +1494,120 @@ CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
aFlipped, aDrawMode);
}
GLuint
CompositorOGL::GetTemporaryTexture(GLenum aUnit)
{
if (!mTexturePool) {
#ifdef MOZ_WIDGET_GONK
mTexturePool = new PerFrameTexturePoolOGL(gl());
#else
mTexturePool = new PerUnitTexturePoolOGL(gl());
#endif
}
return mTexturePool->GetTexture(aUnit);
}
GLuint
PerUnitTexturePoolOGL::GetTexture(GLenum aTextureUnit)
{
size_t index = aTextureUnit - LOCAL_GL_TEXTURE0;
// lazily grow the array of temporary textures
if (mTextures.Length() <= index) {
size_t prevLength = mTextures.Length();
mTextures.SetLength(index + 1);
for(unsigned int i = prevLength; i <= index; ++i) {
mTextures[i] = 0;
}
}
// lazily initialize the temporary textures
if (!mTextures[index]) {
if (!mGL->MakeCurrent()) {
return 0;
}
mGL->fGenTextures(1, &mTextures[index]);
}
return mTextures[index];
}
void
PerUnitTexturePoolOGL::DestroyTextures()
{
if (mGL && mGL->MakeCurrent()) {
if (mTextures.Length() > 0) {
mGL->fDeleteTextures(mTextures.Length(), &mTextures[0]);
}
}
mTextures.SetLength(0);
}
void
PerFrameTexturePoolOGL::DestroyTextures()
{
if (!mGL->MakeCurrent()) {
return;
}
if (mUnusedTextures.Length() > 0) {
mGL->fDeleteTextures(mUnusedTextures.Length(), &mUnusedTextures[0]);
mUnusedTextures.Clear();
}
if (mCreatedTextures.Length() > 0) {
mGL->fDeleteTextures(mCreatedTextures.Length(), &mCreatedTextures[0]);
mCreatedTextures.Clear();
}
}
GLuint
PerFrameTexturePoolOGL::GetTexture(GLenum)
{
GLuint texture = 0;
if (!mUnusedTextures.IsEmpty()) {
// Try to reuse one from the unused pile first
texture = mUnusedTextures[0];
mUnusedTextures.RemoveElementAt(0);
} else if (mGL->MakeCurrent()) {
// There isn't one to reuse, create one.
mGL->fGenTextures(1, &texture);
}
if (texture) {
mCreatedTextures.AppendElement(texture);
}
return texture;
}
void
PerFrameTexturePoolOGL::EndFrame()
{
if (!mGL->MakeCurrent()) {
// this means the context got destroyed underneith us somehow, and the driver
// already has destroyed the textures.
mCreatedTextures.Clear();
mUnusedTextures.Clear();
return;
}
// Some platforms have issues unlocking Gralloc buffers even when they're
// rebound.
if (gfxPrefs::OverzealousGrallocUnlocking()) {
mUnusedTextures.AppendElements(mCreatedTextures);
mCreatedTextures.Clear();
}
// Delete unused textures
for (size_t i = 0; i < mUnusedTextures.Length(); i++) {
GLuint texture = mUnusedTextures[i];
mGL->fDeleteTextures(1, &texture);
}
mUnusedTextures.Clear();
// Move all created textures into the unused pile
mUnusedTextures.AppendElements(mCreatedTextures);
mCreatedTextures.Clear();
}
} /* layers */
} /* mozilla */

View File

@ -55,6 +55,99 @@ class TextureSource;
struct Effect;
struct EffectChain;
/**
* Interface for pools of temporary gl textures for the compositor.
* The textures are fully owned by the pool, so the latter is responsible
* calling fDeleteTextures accordingly.
* Users of GetTexture receive a texture that is only valid for the duration
* of the current frame.
* This is primarily intended for direct texturing APIs that need to attach
* shared objects (such as an EGLImage) to a gl texture.
*/
class CompositorTexturePoolOGL : public RefCounted<CompositorTexturePoolOGL>
{
public:
MOZ_DECLARE_REFCOUNTED_TYPENAME(CompositorTexturePoolOGL)
virtual ~CompositorTexturePoolOGL() {}
virtual void Clear() = 0;
virtual GLuint GetTexture(GLenum aUnit) = 0;
virtual void EndFrame() = 0;
};
/**
* Agressively reuses textures. One gl texture per texture unit in total.
* So far this hasn't shown the best results on b2g.
*/
class PerUnitTexturePoolOGL : public CompositorTexturePoolOGL
{
public:
PerUnitTexturePoolOGL(gl::GLContext* aGL)
: mGL(aGL)
{}
virtual ~PerUnitTexturePoolOGL()
{
DestroyTextures();
}
virtual void Clear() MOZ_OVERRIDE
{
DestroyTextures();
}
virtual GLuint GetTexture(GLenum aUnit) MOZ_OVERRIDE;
virtual void EndFrame() MOZ_OVERRIDE {}
protected:
void DestroyTextures();
nsTArray<GLuint> mTextures;
RefPtr<gl::GLContext> mGL;
};
/**
* Reuse gl textures from a pool of textures that haven't yet been
* used during the current frame.
* All the textures that are not used at the end of a frame are
* deleted.
* This strategy seems to work well with gralloc textures because destroying
* unused textures which are bound to gralloc buffers let drivers know that it
* can unlock the gralloc buffers.
*/
class PerFrameTexturePoolOGL : public CompositorTexturePoolOGL
{
public:
PerFrameTexturePoolOGL(gl::GLContext* aGL)
: mGL(aGL)
{}
virtual ~PerFrameTexturePoolOGL()
{
DestroyTextures();
}
virtual void Clear() MOZ_OVERRIDE
{
DestroyTextures();
}
virtual GLuint GetTexture(GLenum aUnit) MOZ_OVERRIDE;
virtual void EndFrame() MOZ_OVERRIDE;
protected:
void DestroyTextures();
RefPtr<gl::GLContext> mGL;
nsTArray<GLuint> mCreatedTextures;
nsTArray<GLuint> mUnusedTextures;
};
class CompositorOGL : public Compositor
{
typedef mozilla::gl::GLContext GLContext;
@ -162,10 +255,6 @@ public:
virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
#ifdef MOZ_WIDGET_GONK
virtual CompositorBackendSpecificData* GetCompositorBackendSpecificData() MOZ_OVERRIDE;
#endif
GLContext* gl() const { return mGLContext; }
gfx::SurfaceFormat GetFBOFormat() const {
return gfx::SurfaceFormat::R8G8B8A8;
@ -309,43 +398,17 @@ private:
*/
GLint FlipY(GLint y) const { return mHeight - y; }
bool mDestroyed;
RefPtr<CompositorTexturePoolOGL> mTexturePool;
// Textures used for direct texturing of buffers like gralloc.
// The index of the texture in this array must correspond to the texture unit.
nsTArray<GLuint> mTextures;
bool mDestroyed;
/**
* Height of the OpenGL context's primary framebuffer in pixels. Used by
* FlipY for the y-flipping calculation.
*/
GLint mHeight;
#ifdef MOZ_WIDGET_GONK
RefPtr<CompositorBackendSpecificData> mCompositorBackendSpecificData;
#endif
};
#ifdef MOZ_WIDGET_GONK
class CompositorOGLGonkBackendSpecificData : public CompositorBackendSpecificData
{
public:
CompositorOGLGonkBackendSpecificData(CompositorOGL* aCompositor);
virtual ~CompositorOGLGonkBackendSpecificData();
GLuint GetTexture();
void EndFrame();
private:
gl::GLContext* gl() const;
RefPtr<CompositorOGL> mCompositor;
nsTArray<GLuint> mCreatedTextures;
nsTArray<GLuint> mUnusedTextures;
};
#endif
}
}

View File

@ -147,9 +147,7 @@ void GrallocTextureSourceOGL::Lock()
MOZ_ASSERT(IsValid());
CompositorOGLGonkBackendSpecificData* backendData =
static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositor->GetCompositorBackendSpecificData());
mTexture = backendData->GetTexture();
mTexture = mCompositor->GetTemporaryTexture(LOCAL_GL_TEXTURE0);
GLuint textureTarget = GetTextureTarget();