Bug 980647 - Part 1 - Move the compositor's texture recycling startegy behind a pool interface. r=Cwiiis
This commit is contained in:
@@ -137,72 +137,6 @@ DrawQuads(GLContext *aGLContext,
|
|||||||
aGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
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,
|
CompositorOGL::CompositorOGL(nsIWidget *aWidget, int aSurfaceWidth,
|
||||||
int aSurfaceHeight, bool aUseExternalSurfaceSize)
|
int aSurfaceHeight, bool aUseExternalSurfaceSize)
|
||||||
: mWidget(aWidget)
|
: mWidget(aWidget)
|
||||||
@@ -246,38 +180,18 @@ CompositorOGL::CreateContext()
|
|||||||
return context.forget();
|
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
|
void
|
||||||
CompositorOGL::Destroy()
|
CompositorOGL::Destroy()
|
||||||
{
|
{
|
||||||
if (gl() && gl()->MakeCurrent()) {
|
if (gl() && gl()->MakeCurrent()) {
|
||||||
if (mTextures.Length() > 0) {
|
|
||||||
gl()->fDeleteTextures(mTextures.Length(), &mTextures[0]);
|
|
||||||
}
|
|
||||||
mVBOs.Flush(gl());
|
mVBOs.Flush(gl());
|
||||||
}
|
}
|
||||||
mTextures.SetLength(0);
|
|
||||||
|
if (mTexturePool) {
|
||||||
|
mTexturePool->Clear();
|
||||||
|
mTexturePool = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mDestroyed) {
|
if (!mDestroyed) {
|
||||||
mDestroyed = true;
|
mDestroyed = true;
|
||||||
CleanupResources();
|
CleanupResources();
|
||||||
@@ -1366,11 +1280,9 @@ CompositorOGL::EndFrame()
|
|||||||
|
|
||||||
mCurrentRenderTarget = nullptr;
|
mCurrentRenderTarget = nullptr;
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_GONK
|
if (mTexturePool) {
|
||||||
if (mCompositorBackendSpecificData) {
|
mTexturePool->EndFrame();
|
||||||
static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositorBackendSpecificData.get())->EndFrame();
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
mGLContext->SwapBuffers();
|
mGLContext->SwapBuffers();
|
||||||
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
mGLContext->fBindBuffer(LOCAL_GL_ARRAY_BUFFER, 0);
|
||||||
@@ -1480,17 +1392,6 @@ CompositorOGL::Resume()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_GONK
|
|
||||||
CompositorBackendSpecificData*
|
|
||||||
CompositorOGL::GetCompositorBackendSpecificData()
|
|
||||||
{
|
|
||||||
if (!mCompositorBackendSpecificData) {
|
|
||||||
mCompositorBackendSpecificData = new CompositorOGLGonkBackendSpecificData(this);
|
|
||||||
}
|
|
||||||
return mCompositorBackendSpecificData;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
TemporaryRef<DataTextureSource>
|
TemporaryRef<DataTextureSource>
|
||||||
CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
|
CompositorOGL::CreateDataTextureSource(TextureFlags aFlags)
|
||||||
{
|
{
|
||||||
@@ -1593,5 +1494,120 @@ CompositorOGL::BindAndDrawQuad(ShaderProgramOGL *aProg,
|
|||||||
aFlipped, aDrawMode);
|
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 */
|
} /* layers */
|
||||||
} /* mozilla */
|
} /* mozilla */
|
||||||
|
|||||||
@@ -55,6 +55,99 @@ class TextureSource;
|
|||||||
struct Effect;
|
struct Effect;
|
||||||
struct EffectChain;
|
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
|
class CompositorOGL : public Compositor
|
||||||
{
|
{
|
||||||
typedef mozilla::gl::GLContext GLContext;
|
typedef mozilla::gl::GLContext GLContext;
|
||||||
@@ -162,10 +255,6 @@ public:
|
|||||||
|
|
||||||
virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
|
virtual nsIWidget* GetWidget() const MOZ_OVERRIDE { return mWidget; }
|
||||||
|
|
||||||
#ifdef MOZ_WIDGET_GONK
|
|
||||||
virtual CompositorBackendSpecificData* GetCompositorBackendSpecificData() MOZ_OVERRIDE;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GLContext* gl() const { return mGLContext; }
|
GLContext* gl() const { return mGLContext; }
|
||||||
gfx::SurfaceFormat GetFBOFormat() const {
|
gfx::SurfaceFormat GetFBOFormat() const {
|
||||||
return gfx::SurfaceFormat::R8G8B8A8;
|
return gfx::SurfaceFormat::R8G8B8A8;
|
||||||
@@ -309,43 +398,17 @@ private:
|
|||||||
*/
|
*/
|
||||||
GLint FlipY(GLint y) const { return mHeight - y; }
|
GLint FlipY(GLint y) const { return mHeight - y; }
|
||||||
|
|
||||||
bool mDestroyed;
|
RefPtr<CompositorTexturePoolOGL> mTexturePool;
|
||||||
|
|
||||||
// Textures used for direct texturing of buffers like gralloc.
|
bool mDestroyed;
|
||||||
// The index of the texture in this array must correspond to the texture unit.
|
|
||||||
nsTArray<GLuint> mTextures;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Height of the OpenGL context's primary framebuffer in pixels. Used by
|
* Height of the OpenGL context's primary framebuffer in pixels. Used by
|
||||||
* FlipY for the y-flipping calculation.
|
* FlipY for the y-flipping calculation.
|
||||||
*/
|
*/
|
||||||
GLint mHeight;
|
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
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -147,9 +147,7 @@ void GrallocTextureSourceOGL::Lock()
|
|||||||
|
|
||||||
MOZ_ASSERT(IsValid());
|
MOZ_ASSERT(IsValid());
|
||||||
|
|
||||||
CompositorOGLGonkBackendSpecificData* backendData =
|
mTexture = mCompositor->GetTemporaryTexture(LOCAL_GL_TEXTURE0);
|
||||||
static_cast<CompositorOGLGonkBackendSpecificData*>(mCompositor->GetCompositorBackendSpecificData());
|
|
||||||
mTexture = backendData->GetTexture();
|
|
||||||
|
|
||||||
GLuint textureTarget = GetTextureTarget();
|
GLuint textureTarget = GetTextureTarget();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user