author | Vladimir Vukicevic <vladimir@pobox.com> |
Fri, 06 Aug 2010 22:09:18 -0700 | |
changeset 49072 | 0ebbc02a5c8726cb61224758767200a9d8c21db4 |
parent 49071 | de9137456817269f99751e8bccea7e039ddcb655 |
child 49073 | 6636c00d1945d8a0b3f3e3aad3c22ee07cf10502 |
push id | 1 |
push user | root |
push date | Tue, 26 Apr 2011 22:38:44 +0000 |
treeherder | mozilla-beta@bfdb6e623a36 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bas |
bugs | 574481 |
milestone | 2.0b4pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/gfx/layers/opengl/CanvasLayerOGL.cpp +++ b/gfx/layers/opengl/CanvasLayerOGL.cpp @@ -49,22 +49,27 @@ #ifdef XP_MACOSX #include <OpenGL/OpenGL.h> #endif using namespace mozilla; using namespace mozilla::layers; using namespace mozilla::gl; -CanvasLayerOGL::~CanvasLayerOGL() +void +CanvasLayerOGL::Destroy() { - mOGLManager->MakeCurrent(); + if (!mDestroyed) { + if (mTexture) { + GLContext *cx = mOGLManager->glForResources(); + cx->MakeCurrent(); + cx->fDeleteTextures(1, &mTexture); + } - if (mTexture) { - gl()->fDeleteTextures(1, &mTexture); + mDestroyed = PR_TRUE; } } void CanvasLayerOGL::Initialize(const Data& aData) { NS_ASSERTION(mCanvasSurface == nsnull, "BasicCanvasLayer::Initialize called twice!"); @@ -111,16 +116,20 @@ CanvasLayerOGL::MakeTexture() gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); gl()->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); } void CanvasLayerOGL::Updated(const nsIntRect& aRect) { + if (mDestroyed) { + return; + } + NS_ASSERTION(mUpdatedRect.IsEmpty(), "CanvasLayer::Updated called more than once during a transaction!"); mOGLManager->MakeCurrent(); mUpdatedRect.UnionRect(mUpdatedRect, aRect); if (mCanvasGLContext) {
--- a/gfx/layers/opengl/CanvasLayerOGL.h +++ b/gfx/layers/opengl/CanvasLayerOGL.h @@ -51,24 +51,24 @@ class THEBES_API CanvasLayerOGL : public: CanvasLayerOGL(LayerManagerOGL *aManager) : CanvasLayer(aManager, NULL), LayerOGL(aManager), mTexture(0) { mImplData = static_cast<LayerOGL*>(this); } - - ~CanvasLayerOGL(); + ~CanvasLayerOGL() { Destroy(); } // CanvasLayer implementation virtual void Initialize(const Data& aData); virtual void Updated(const nsIntRect& aRect); // LayerOGL implementation + virtual void Destroy(); virtual Layer* GetLayer() { return this; } virtual void RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset); protected: nsRefPtr<gfxASurface> mCanvasSurface; nsRefPtr<GLContext> mCanvasGLContext;
--- a/gfx/layers/opengl/ColorLayerOGL.h +++ b/gfx/layers/opengl/ColorLayerOGL.h @@ -48,19 +48,22 @@ class THEBES_API ColorLayerOGL : public { public: ColorLayerOGL(LayerManagerOGL *aManager) : ColorLayer(aManager, NULL) , LayerOGL(aManager) { mImplData = static_cast<LayerOGL*>(this); } + ~ColorLayerOGL() { Destroy(); } // LayerOGL Implementation virtual Layer* GetLayer(); + virtual void Destroy() { mDestroyed = PR_TRUE; } + virtual void RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset); }; } /* layers */ } /* mozilla */ #endif /* GFX_COLORLAYEROGL_H */
--- a/gfx/layers/opengl/ContainerLayerOGL.cpp +++ b/gfx/layers/opengl/ContainerLayerOGL.cpp @@ -44,18 +44,28 @@ ContainerLayerOGL::ContainerLayerOGL(Lay : ContainerLayer(aManager, NULL) , LayerOGL(aManager) { mImplData = static_cast<LayerOGL*>(this); } ContainerLayerOGL::~ContainerLayerOGL() { - while (mFirstChild) { - RemoveChild(mFirstChild); + Destroy(); +} + +void +ContainerLayerOGL::Destroy() +{ + if (!mDestroyed) { + while (mFirstChild) { + GetFirstChildOGL()->Destroy(); + RemoveChild(mFirstChild); + } + mDestroyed = PR_TRUE; } } void ContainerLayerOGL::InsertAfter(Layer* aChild, Layer* aAfter) { aChild->SetParent(this); if (!aAfter) {
--- a/gfx/layers/opengl/ContainerLayerOGL.h +++ b/gfx/layers/opengl/ContainerLayerOGL.h @@ -1,9 +1,9 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * @@ -55,16 +55,18 @@ public: void InsertAfter(Layer* aChild, Layer* aAfter); void RemoveChild(Layer* aChild); /** LayerOGL implementation */ Layer* GetLayer(); + void Destroy(); + LayerOGL* GetFirstChildOGL(); PRBool IsEmpty(); virtual void RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset); };
--- a/gfx/layers/opengl/ImageLayerOGL.cpp +++ b/gfx/layers/opengl/ImageLayerOGL.cpp @@ -52,39 +52,44 @@ using mozilla::MutexAutoLock; * optionally delete a texture associated with that context. */ class TextureDeleter : public nsRunnable { public: TextureDeleter(already_AddRefed<GLContext> aContext, GLuint aTexture) : mContext(aContext), mTexture(aTexture) { + NS_ASSERTION(aTexture, "TextureDeleter instantiated with nothing to do"); } + NS_IMETHOD Run() { - if (mTexture) { - mContext->DestroyTexture(mTexture); - } + mContext->MakeCurrent(); + mContext->fDeleteTextures(1, &mTexture); + // Ensure context is released on the main thread mContext = nsnull; return NS_OK; } nsRefPtr<GLContext> mContext; GLuint mTexture; }; void GLTexture::Allocate(GLContext *aContext) { - NS_ASSERTION(NS_IsMainThread(), "Can only allocate texture on main thread"); + NS_ASSERTION(aContext->IsGlobalSharedContext() || + NS_IsMainThread(), "Can only allocate texture on main thread or with cx sharing"); Release(); mContext = aContext; - mTexture = mContext->CreateTexture(); + + mContext->MakeCurrent(); + mContext->fGenTextures(1, &mTexture); } void GLTexture::TakeFrom(GLTexture *aOther) { Release(); mContext = aOther->mContext.forget(); @@ -95,29 +100,30 @@ GLTexture::TakeFrom(GLTexture *aOther) void GLTexture::Release() { if (!mContext) { NS_ASSERTION(!mTexture, "Can't delete texture without a context"); return; } - if (NS_IsMainThread()) { - if (mTexture) { - mContext->DestroyTexture(mTexture); - mTexture = 0; + if (mTexture) { + if (NS_IsMainThread() || mContext->IsGlobalSharedContext()) { + mContext->MakeCurrent(); + mContext->fDeleteTextures(1, &mTexture); + } else { + nsCOMPtr<nsIRunnable> runnable = + new TextureDeleter(mContext.forget(), mTexture); + NS_DispatchToMainThread(runnable); } - mContext = nsnull; - return; + + mTexture = 0; } - nsCOMPtr<nsIRunnable> runnable = - new TextureDeleter(mContext.forget(), mTexture); - NS_DispatchToMainThread(runnable); - mTexture = 0; + mContext = nsnull; } RecycleBin::RecycleBin() : mLock("mozilla.layers.RecycleBin.mLock") { } void @@ -128,17 +134,17 @@ RecycleBin::RecycleBuffer(PRUint8* aBuff if (!mRecycledBuffers.IsEmpty() && aSize != mRecycledBufferSize) { mRecycledBuffers.Clear(); } mRecycledBufferSize = aSize; mRecycledBuffers.AppendElement(aBuffer); } PRUint8* -RecycleBin::TakeBuffer(PRUint32 aSize) +RecycleBin::GetBuffer(PRUint32 aSize) { MutexAutoLock lock(mLock); if (mRecycledBuffers.IsEmpty() || mRecycledBufferSize != aSize) return new PRUint8[aSize]; PRUint32 last = mRecycledBuffers.Length() - 1; PRUint8* result = mRecycledBuffers[last].forget(); @@ -158,18 +164,18 @@ RecycleBin::RecycleTexture(GLTexture *aT if (!mRecycledTextures[aType].IsEmpty() && aSize != mRecycledTextureSizes[aType]) { mRecycledTextures[aType].Clear(); } mRecycledTextureSizes[aType] = aSize; mRecycledTextures[aType].AppendElement()->TakeFrom(aTexture); } void -RecycleBin::TakeTexture(TextureType aType, const gfxIntSize& aSize, - GLContext *aContext, GLTexture *aOutTexture) +RecycleBin::GetTexture(TextureType aType, const gfxIntSize& aSize, + GLContext *aContext, GLTexture *aOutTexture) { MutexAutoLock lock(mLock); if (mRecycledTextures[aType].IsEmpty() || mRecycledTextureSizes[aType] != aSize) { aOutTexture->Allocate(aContext); return; } PRUint32 last = mRecycledTextures[aType].Length() - 1; @@ -179,26 +185,36 @@ RecycleBin::TakeTexture(TextureType aTyp ImageContainerOGL::ImageContainerOGL(LayerManagerOGL *aManager) : ImageContainer(aManager) , mRecycleBin(new RecycleBin()) , mActiveImageLock("mozilla.layers.ImageContainerOGL.mActiveImageLock") { } +ImageContainerOGL::~ImageContainerOGL() +{ + if (mManager) { + NS_ASSERTION(mManager->GetBackendType() == LayerManager::LAYERS_OPENGL, "Wrong layer manager got assigned to ImageContainerOGL!"); + + static_cast<LayerManagerOGL*>(mManager)->ForgetImageContainer(this); + } +} + already_AddRefed<Image> ImageContainerOGL::CreateImage(const Image::Format *aFormats, PRUint32 aNumFormats) { if (!aNumFormats) { return nsnull; } nsRefPtr<Image> img; if (aFormats[0] == Image::PLANAR_YCBCR) { - img = new PlanarYCbCrImageOGL(mRecycleBin); + img = new PlanarYCbCrImageOGL(static_cast<LayerManagerOGL*>(mManager), + mRecycleBin); } else if (aFormats[0] == Image::CAIRO_SURFACE) { img = new CairoImageOGL(static_cast<LayerManagerOGL*>(mManager)); } return img.forget(); } void ImageContainerOGL::SetCurrentImage(Image *aImage) @@ -223,43 +239,118 @@ ImageContainerOGL::GetCurrentImage() nsRefPtr<Image> retval = mActiveImage; return retval.forget(); } already_AddRefed<gfxASurface> ImageContainerOGL::GetCurrentAsSurface(gfxIntSize *aSize) { - return nsnull; + MutexAutoLock lock(mActiveImageLock); + + if (!mActiveImage) { + *aSize = gfxIntSize(0,0); + return nsnull; + } + + GLContext *gl = nsnull; + // tex1 will be RGBA or Y, tex2 will Cb, tex3 will be Cr + GLuint tex1 = 0, tex2 = 0, tex3 = 0; + gfxIntSize size; + + if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) { + PlanarYCbCrImageOGL *yuvImage = + static_cast<PlanarYCbCrImageOGL*>(mActiveImage.get()); + if (!yuvImage->HasData() || !yuvImage->HasTextures()) { + *aSize = gfxIntSize(0, 0); + return nsnull; + } + + size = yuvImage->mSize; + gl = yuvImage->mTextures[0].GetGLContext(); + tex1 = yuvImage->mTextures[0].GetTextureID(); + tex2 = yuvImage->mTextures[1].GetTextureID(); + tex3 = yuvImage->mTextures[2].GetTextureID(); + } + + if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) { + CairoImageOGL *cairoImage = + static_cast<CairoImageOGL*>(mActiveImage.get()); + size = cairoImage->mSize; + gl = cairoImage->mTexture.GetGLContext(); + tex1 = cairoImage->mTexture.GetTextureID(); + } + + // XXX TODO: read all textures in YCbCr case and convert to RGB + // XXX Or maybe add a ReadYCbCrTextureImage that will take 3 textures + // and return RGB, since we can render YCbCr to the temporary framebuffer. + nsRefPtr<gfxImageSurface> s = gl->ReadTextureImage(tex1, size, LOCAL_GL_RGBA); + *aSize = size; + return s.forget(); } gfxIntSize ImageContainerOGL::GetCurrentSize() { MutexAutoLock lock(mActiveImageLock); if (!mActiveImage) { return gfxIntSize(0,0); } + if (mActiveImage->GetFormat() == Image::PLANAR_YCBCR) { PlanarYCbCrImageOGL *yuvImage = static_cast<PlanarYCbCrImageOGL*>(mActiveImage.get()); if (!yuvImage->HasData()) { return gfxIntSize(0,0); } return yuvImage->mSize; - } else if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) { + } + + if (mActiveImage->GetFormat() == Image::CAIRO_SURFACE) { CairoImageOGL *cairoImage = static_cast<CairoImageOGL*>(mActiveImage.get()); return cairoImage->mSize; } return gfxIntSize(0,0); } +PRBool +ImageContainerOGL::SetLayerManager(LayerManager *aManager) +{ + if (!aManager) { + // the layer manager just entirely went away + + // XXX if we don't have context sharing, we should tell our images + // that their textures are no longer valid. + mManager = nsnull; + return PR_TRUE; + } + + if (aManager->GetBackendType() != LayerManager::LAYERS_OPENGL) { + return PR_FALSE; + } + + LayerManagerOGL* lmOld = static_cast<LayerManagerOGL*>(mManager); + LayerManagerOGL* lmNew = static_cast<LayerManagerOGL*>(aManager); + + if (lmOld) { + NS_ASSERTION(lmNew->glForResources() == lmOld->glForResources(), + "We require GL context sharing here!"); + lmOld->ForgetImageContainer(this); + } + + mManager = aManager; + + lmNew->RememberImageContainer(this); + + return PR_TRUE; +} + Layer* ImageLayerOGL::GetLayer() { return this; } void ImageLayerOGL::RenderLayer(int, @@ -271,21 +362,25 @@ ImageLayerOGL::RenderLayer(int, mOGLManager->MakeCurrent(); nsRefPtr<Image> image = GetContainer()->GetCurrentImage(); if (image->GetFormat() == Image::PLANAR_YCBCR) { PlanarYCbCrImageOGL *yuvImage = static_cast<PlanarYCbCrImageOGL*>(image.get()); - if (!yuvImage->HasData()) + if (!yuvImage->HasData()) { return; + } + + if (!yuvImage->HasTextures()) { + yuvImage->AllocateTextures(gl()); + } - if (!yuvImage->HasTextures()) - yuvImage->AllocateTextures(mOGLManager); + yuvImage->UpdateTextures(gl()); gl()->fActiveTexture(LOCAL_GL_TEXTURE0); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[0].GetTextureID()); gl()->fActiveTexture(LOCAL_GL_TEXTURE1); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[1].GetTextureID()); gl()->fActiveTexture(LOCAL_GL_TEXTURE2); gl()->fBindTexture(LOCAL_GL_TEXTURE_2D, yuvImage->mTextures[2].GetTextureID()); @@ -330,30 +425,62 @@ ImageLayerOGL::RenderLayer(int, program->SetTextureUnit(0); mOGLManager->BindAndDrawQuad(program); } DEBUG_GL_ERROR_CHECK(gl()); } -PlanarYCbCrImageOGL::PlanarYCbCrImageOGL(RecycleBin *aRecycleBin) +static void +InitTexture(GLContext* aGL, GLuint aTexture, GLenum aFormat, const gfxIntSize& aSize) +{ + aGL->fBindTexture(LOCAL_GL_TEXTURE_2D, aTexture); + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); + aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + + aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, + 0, + aFormat, + aSize.width, + aSize.height, + 0, + aFormat, + LOCAL_GL_UNSIGNED_BYTE, + NULL); +} + +PlanarYCbCrImageOGL::PlanarYCbCrImageOGL(LayerManagerOGL *aManager, + RecycleBin *aRecycleBin) : PlanarYCbCrImage(nsnull), mRecycleBin(aRecycleBin), mHasData(PR_FALSE) { +#if 0 + // We really want to allocate this on the decode thread -- but to do that, + // we need to create a per-thread shared GL context, and it will only work + // if we have context sharing. For now, create the textures on the main + // thread the first time we render. + if (aManager) { + AllocateTextures(aManager->glForResources()); + } +#endif } PlanarYCbCrImageOGL::~PlanarYCbCrImageOGL() { if (mBuffer) { mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize); } - mRecycleBin->RecycleTexture(&mTextures[0], RecycleBin::TEXTURE_Y, mData.mYSize); - mRecycleBin->RecycleTexture(&mTextures[1], RecycleBin::TEXTURE_C, mData.mCbCrSize); - mRecycleBin->RecycleTexture(&mTextures[2], RecycleBin::TEXTURE_C, mData.mCbCrSize); + if (HasTextures()) { + mRecycleBin->RecycleTexture(&mTextures[0], RecycleBin::TEXTURE_Y, mData.mYSize); + mRecycleBin->RecycleTexture(&mTextures[1], RecycleBin::TEXTURE_C, mData.mCbCrSize); + mRecycleBin->RecycleTexture(&mTextures[2], RecycleBin::TEXTURE_C, mData.mCbCrSize); + } } void PlanarYCbCrImageOGL::SetData(const PlanarYCbCrImage::Data &aData) { // For now, we copy the data int width_shift = 0; int height_shift = 0; @@ -379,17 +506,17 @@ PlanarYCbCrImageOGL::SetData(const Plana mData = aData; mData.mCbCrStride = mData.mCbCrSize.width = aData.mPicSize.width >> width_shift; mData.mCbCrSize.height = aData.mPicSize.height >> height_shift; mData.mYSize = aData.mPicSize; mData.mYStride = mData.mYSize.width; mBufferSize = mData.mCbCrStride * mData.mCbCrSize.height * 2 + mData.mYStride * mData.mYSize.height; - mBuffer = mRecycleBin->TakeBuffer(mBufferSize); + mBuffer = mRecycleBin->GetBuffer(mBufferSize); if (!mBuffer) return; mData.mYChannel = mBuffer; mData.mCbChannel = mData.mYChannel + mData.mYStride * mData.mYSize.height; mData.mCrChannel = mData.mCbChannel + mData.mCbCrStride * mData.mCbCrSize.height; int cbcr_x = aData.mPicX >> width_shift; int cbcr_y = aData.mPicY >> height_shift; @@ -412,165 +539,144 @@ PlanarYCbCrImageOGL::SetData(const Plana // Fix picture rect to be correct mData.mPicX = mData.mPicY = 0; mSize = aData.mPicSize; mHasData = PR_TRUE; } -static void -SetupPlaneTexture(GLContext* aGL, const gfxIntSize& aSize, PRUint8* aData, PRBool aIsNew) +void +PlanarYCbCrImageOGL::AllocateTextures(mozilla::gl::GLContext *gl) { - aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); - aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); - aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); - aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + gl->MakeCurrent(); - if (aIsNew) { - aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - LOCAL_GL_LUMINANCE, - aSize.width, - aSize.height, - 0, - LOCAL_GL_LUMINANCE, - LOCAL_GL_UNSIGNED_BYTE, - aData); - } else { - aGL->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, - 0, - 0, 0, - aSize.width, - aSize.height, - LOCAL_GL_LUMINANCE, - LOCAL_GL_UNSIGNED_BYTE, - aData); - } + mRecycleBin->GetTexture(RecycleBin::TEXTURE_Y, mData.mYSize, gl, &mTextures[0]); + InitTexture(gl, mTextures[0].GetTextureID(), LOCAL_GL_LUMINANCE, mData.mYSize); + + mRecycleBin->GetTexture(RecycleBin::TEXTURE_C, mData.mCbCrSize, gl, &mTextures[1]); + InitTexture(gl, mTextures[1].GetTextureID(), LOCAL_GL_LUMINANCE, mData.mCbCrSize); + + mRecycleBin->GetTexture(RecycleBin::TEXTURE_C, mData.mCbCrSize, gl, &mTextures[2]); + InitTexture(gl, mTextures[2].GetTextureID(), LOCAL_GL_LUMINANCE, mData.mCbCrSize); } void -PlanarYCbCrImageOGL::AllocateTextures(LayerManagerOGL *aManager) +PlanarYCbCrImageOGL::UpdateTextures(GLContext *gl) { - aManager->MakeCurrent(); - - mozilla::gl::GLContext *gl = aManager->gl(); - - PRPackedBool isNewTexture[3]; - for (PRUint32 i = 0; i < 3; ++i) { - isNewTexture[i] = !mTextures[i].IsAllocated(); - } - - mRecycleBin->TakeTexture(RecycleBin::TEXTURE_Y, mData.mYSize, gl, &mTextures[0]); - mRecycleBin->TakeTexture(RecycleBin::TEXTURE_C, mData.mCbCrSize, gl, &mTextures[1]); - mRecycleBin->TakeTexture(RecycleBin::TEXTURE_C, mData.mCbCrSize, gl, &mTextures[2]); - if (!HasTextures()) - return; - GLint alignment; if (!((ptrdiff_t)mData.mYStride & 0x7) && !((ptrdiff_t)mData.mYChannel & 0x7)) { alignment = 8; } else if (!((ptrdiff_t)mData.mYStride & 0x3)) { alignment = 4; } else if (!((ptrdiff_t)mData.mYStride & 0x1)) { alignment = 2; } else { alignment = 1; } // Set texture alignment for Y plane. gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, alignment); gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTextures[0].GetTextureID()); - - SetupPlaneTexture(gl, mData.mYSize, mData.mYChannel, isNewTexture[0]); + gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, + 0, 0, mData.mYSize.width, mData.mYSize.height, + LOCAL_GL_LUMINANCE, + LOCAL_GL_UNSIGNED_BYTE, + mData.mYChannel); if (!((ptrdiff_t)mData.mCbCrStride & 0x7) && !((ptrdiff_t)mData.mCbChannel & 0x7) && - !((ptrdiff_t)mData.mCrChannel & 0x7)) { + !((ptrdiff_t)mData.mCrChannel & 0x7)) + { alignment = 8; } else if (!((ptrdiff_t)mData.mCbCrStride & 0x3)) { alignment = 4; } else if (!((ptrdiff_t)mData.mCbCrStride & 0x1)) { alignment = 2; } else { alignment = 1; } // Set texture alignment for Cb/Cr plane gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, alignment); gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTextures[1].GetTextureID()); - - SetupPlaneTexture(gl, mData.mCbCrSize, mData.mCbChannel, isNewTexture[1]); + gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, + 0, 0, mData.mCbCrSize.width, mData.mCbCrSize.height, + LOCAL_GL_LUMINANCE, + LOCAL_GL_UNSIGNED_BYTE, + mData.mCbChannel); gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTextures[2].GetTextureID()); - - SetupPlaneTexture(gl, mData.mCbCrSize, mData.mCrChannel, isNewTexture[2]); + gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, + 0, 0, mData.mCbCrSize.width, mData.mCbCrSize.height, + LOCAL_GL_LUMINANCE, + LOCAL_GL_UNSIGNED_BYTE, + mData.mCrChannel); // Reset alignment to default gl->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 4); // Recycle main-memory buffer now that we've got the data in our textures if (mBuffer) { mRecycleBin->RecycleBuffer(mBuffer.forget(), mBufferSize); } } -CairoImageOGL::CairoImageOGL(LayerManagerOGL *aManager) : CairoImage(nsnull) +CairoImageOGL::CairoImageOGL(LayerManagerOGL *aManager) + : CairoImage(nsnull) { NS_ASSERTION(NS_IsMainThread(), "Should be on main thread to create a cairo image"); - // Allocate texture now to grab a reference to the GLContext - mTexture.Allocate(aManager->gl()); + if (aManager) { + // Allocate texture now to grab a reference to the GLContext + mTexture.Allocate(aManager->glForResources()); + } } void CairoImageOGL::SetData(const CairoImage::Data &aData) { if (!mTexture.IsAllocated()) return; mozilla::gl::GLContext *gl = mTexture.GetGLContext(); gl->MakeCurrent(); - mSize = aData.mSize; - - gl->fActiveTexture(LOCAL_GL_TEXTURE0); - gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture.GetTextureID()); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); - gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); + if (mSize != aData.mSize) { + gl->fActiveTexture(LOCAL_GL_TEXTURE0); + InitTexture(gl, mTexture.GetTextureID(), LOCAL_GL_RGBA, aData.mSize); + mSize = aData.mSize; + } else { + gl->fBindTexture(LOCAL_GL_TEXTURE_2D, mTexture.GetTextureID()); + } if (!mASurfaceAsGLContext) { mASurfaceAsGLContext = GLContextProvider::CreateForNativePixmapSurface(aData.mSurface); if (mASurfaceAsGLContext) mASurfaceAsGLContext->BindTexImage(); } + if (mASurfaceAsGLContext) return; // XXX This could be a lot more efficient if we already have an image-compatible // surface // XXX if we ever create an ImageFormatRGB24 surface, make sure that we use // a BGRX program in that case (instead of BGRA) nsRefPtr<gfxImageSurface> imageSurface = new gfxImageSurface(aData.mSize, gfxASurface::ImageFormatARGB32); nsRefPtr<gfxContext> context = new gfxContext(imageSurface); context->SetSource(aData.mSurface); context->Paint(); - gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, - 0, - LOCAL_GL_RGBA, - mSize.width, - mSize.height, - 0, - LOCAL_GL_RGBA, - LOCAL_GL_UNSIGNED_BYTE, - imageSurface->Data()); + gl->fTexSubImage2D(LOCAL_GL_TEXTURE_2D, 0, + 0, 0, mSize.width, mSize.height, + LOCAL_GL_RGBA, + LOCAL_GL_UNSIGNED_BYTE, + imageSurface->Data()); } } /* layers */ } /* mozilla */
--- a/gfx/layers/opengl/ImageLayerOGL.h +++ b/gfx/layers/opengl/ImageLayerOGL.h @@ -1,9 +1,9 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * @@ -97,27 +97,27 @@ class RecycleBin { typedef mozilla::gl::GLContext GLContext; public: RecycleBin(); void RecycleBuffer(PRUint8* aBuffer, PRUint32 aSize); // Returns a recycled buffer of the right size, or allocates a new buffer. - PRUint8* TakeBuffer(PRUint32 aSize); + PRUint8* GetBuffer(PRUint32 aSize); enum TextureType { TEXTURE_Y, TEXTURE_C }; void RecycleTexture(GLTexture *aTexture, TextureType aType, const gfxIntSize& aSize); - void TakeTexture(TextureType aType, const gfxIntSize& aSize, - GLContext *aContext, GLTexture *aOutTexture); + void GetTexture(TextureType aType, const gfxIntSize& aSize, + GLContext *aContext, GLTexture *aOutTexture); private: typedef mozilla::Mutex Mutex; // This protects mRecycledBuffers, mRecycledBufferSize, mRecycledTextures // and mRecycledTextureSizes Mutex mLock; @@ -130,29 +130,31 @@ private: nsTArray<GLTexture> mRecycledTextures[2]; gfxIntSize mRecycledTextureSizes[2]; }; class THEBES_API ImageContainerOGL : public ImageContainer { public: ImageContainerOGL(LayerManagerOGL *aManager); - virtual ~ImageContainerOGL() {} + virtual ~ImageContainerOGL(); virtual already_AddRefed<Image> CreateImage(const Image::Format* aFormats, PRUint32 aNumFormats); virtual void SetCurrentImage(Image* aImage); virtual already_AddRefed<Image> GetCurrentImage(); virtual already_AddRefed<gfxASurface> GetCurrentAsSurface(gfxIntSize* aSize); virtual gfxIntSize GetCurrentSize(); + virtual PRBool SetLayerManager(LayerManager *aManager); + private: typedef mozilla::Mutex Mutex; nsRefPtr<RecycleBin> mRecycleBin; // This protects mActiveImage Mutex mActiveImageLock; @@ -164,39 +166,44 @@ class THEBES_API ImageLayerOGL : public { public: ImageLayerOGL(LayerManagerOGL *aManager) : ImageLayer(aManager, NULL) , LayerOGL(aManager) { mImplData = static_cast<LayerOGL*>(this); } + ~ImageLayerOGL() { Destroy(); } // LayerOGL Implementation + virtual void Destroy() { mDestroyed = PR_TRUE; } virtual Layer* GetLayer(); virtual void RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset); }; class THEBES_API PlanarYCbCrImageOGL : public PlanarYCbCrImage { typedef mozilla::gl::GLContext GLContext; public: - PlanarYCbCrImageOGL(RecycleBin *aRecycleBin); + PlanarYCbCrImageOGL(LayerManagerOGL *aManager, + RecycleBin *aRecycleBin); ~PlanarYCbCrImageOGL(); virtual void SetData(const Data &aData); /** * Upload the data from out mData into our textures. For now we use this to * make sure the textures are created and filled on the main thread. */ - void AllocateTextures(LayerManagerOGL *aManager); + void AllocateTextures(GLContext *gl); + void UpdateTextures(GLContext *gl); + PRBool HasData() { return mHasData; } PRBool HasTextures() { return mTextures[0].IsAllocated() && mTextures[1].IsAllocated() && mTextures[2].IsAllocated(); } nsAutoArrayPtr<PRUint8> mBuffer;
--- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -71,31 +71,53 @@ LayerManagerOGL::LayerManagerOGL(nsIWidg , mBackBufferTexture(0) , mBackBufferSize(-1, -1) , mHasBGRA(0) { } LayerManagerOGL::~LayerManagerOGL() { - mRoot = nsnull; - CleanupResources(); + Destroy(); +} + +void +LayerManagerOGL::Destroy() +{ + if (!mDestroyed) { + if (mRoot) { + RootLayer()->Destroy(); + } + mRoot = nsnull; + + // Make a copy, since SetLayerManager will cause mImageContainers + // to get mutated. + nsTArray<ImageContainer*> imageContainers(mImageContainers); + for (PRUint32 i = 0; i < imageContainers.Length(); ++i) { + ImageContainer *c = imageContainers[i]; + c->SetLayerManager(nsnull); + } + + CleanupResources(); + + mDestroyed = PR_TRUE; + } } void LayerManagerOGL::CleanupResources() { if (!mGLContext) return; nsRefPtr<GLContext> ctx = mGLContext->GetSharedContext(); if (!ctx) { ctx = mGLContext; } - + ctx->MakeCurrent(); for (unsigned int i = 0; i < mPrograms.Length(); ++i) delete mPrograms[i]; mPrograms.Clear(); ctx->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0); @@ -120,16 +142,17 @@ LayerManagerOGL::CleanupResources() PRBool LayerManagerOGL::Initialize(GLContext *aExistingContext) { if (aExistingContext) { mGLContext = aExistingContext; } else { if (mGLContext) CleanupResources(); + mGLContext = gl::GLContextProvider::CreateForWindow(mWidget); if (!mGLContext) { NS_WARNING("Failed to create LayerManagerOGL context"); return PR_FALSE; } } @@ -322,91 +345,167 @@ LayerManagerOGL::SetClippingRegion(const void LayerManagerOGL::BeginTransaction() { } void LayerManagerOGL::BeginTransactionWithTarget(gfxContext *aTarget) { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return; + } + mTarget = aTarget; } void LayerManagerOGL::EndTransaction(DrawThebesLayerCallback aCallback, void* aCallbackData) { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return; + } + mThebesLayerCallback = aCallback; mThebesLayerCallbackData = aCallbackData; Render(); mThebesLayerCallback = nsnull; mThebesLayerCallbackData = nsnull; mTarget = NULL; } already_AddRefed<ThebesLayer> LayerManagerOGL::CreateThebesLayer() { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nsnull; + } + nsRefPtr<ThebesLayer> layer = new ThebesLayerOGL(this); return layer.forget(); } already_AddRefed<ContainerLayer> LayerManagerOGL::CreateContainerLayer() { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nsnull; + } + nsRefPtr<ContainerLayer> layer = new ContainerLayerOGL(this); return layer.forget(); } already_AddRefed<ImageContainer> LayerManagerOGL::CreateImageContainer() { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nsnull; + } + nsRefPtr<ImageContainer> container = new ImageContainerOGL(this); + RememberImageContainer(container); return container.forget(); } already_AddRefed<ImageLayer> LayerManagerOGL::CreateImageLayer() { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nsnull; + } + nsRefPtr<ImageLayer> layer = new ImageLayerOGL(this); return layer.forget(); } already_AddRefed<ColorLayer> LayerManagerOGL::CreateColorLayer() { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nsnull; + } + nsRefPtr<ColorLayer> layer = new ColorLayerOGL(this); return layer.forget(); } already_AddRefed<CanvasLayer> LayerManagerOGL::CreateCanvasLayer() { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nsnull; + } + nsRefPtr<CanvasLayer> layer = new CanvasLayerOGL(this); return layer.forget(); } void +LayerManagerOGL::ForgetImageContainer(ImageContainer *aContainer) +{ + NS_ASSERTION(aContainer->Manager() == this, + "ForgetImageContainer called on non-owned container!"); + + if (!mImageContainers.RemoveElement(aContainer)) { + NS_WARNING("ForgetImageContainer couldn't find container it was supposed to forget!"); + return; + } +} + +void +LayerManagerOGL::RememberImageContainer(ImageContainer *aContainer) +{ + NS_ASSERTION(aContainer->Manager() == this, + "RememberImageContainer called on non-owned container!"); + mImageContainers.AppendElement(aContainer); +} + +void LayerManagerOGL::MakeCurrent() { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return; + } + mGLContext->MakeCurrent(); } LayerOGL* LayerManagerOGL::RootLayer() const { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return nsnull; + } + return static_cast<LayerOGL*>(mRoot->ImplData()); } void LayerManagerOGL::Render() { + if (mDestroyed) { + NS_WARNING("Call on destroyed layer manager"); + return; + } + nsIntRect rect; mWidget->GetBounds(rect); GLint width = rect.width; GLint height = rect.height; MakeCurrent(); DEBUG_GL_ERROR_CHECK(mGLContext); @@ -734,11 +833,10 @@ LayerManagerOGL::CreateFBOWithTexture(in LOCAL_GL_FRAMEBUFFER_COMPLETE, "Error setting up framebuffer."); *aFBO = fbo; *aTexture = tex; DEBUG_GL_ERROR_CHECK(gl()); } - } /* layers */ } /* mozilla */
--- a/gfx/layers/opengl/LayerManagerOGL.h +++ b/gfx/layers/opengl/LayerManagerOGL.h @@ -78,16 +78,18 @@ class THEBES_API LayerManagerOGL : publi typedef mozilla::gl::GLContext GLContext; public: LayerManagerOGL(nsIWidget *aWidget); virtual ~LayerManagerOGL(); void CleanupResources(); + void Destroy(); + /** * Initializes the layer manager, this is when the layer manager will * actually access the device and attempt to create the swap chain used * to draw to the window. If this method fails the device cannot be used. * This function is not threadsafe. * * \param aExistingContext an existing GL context to use, instead of creating * our own for the widget. @@ -131,16 +133,26 @@ public: virtual already_AddRefed<CanvasLayer> CreateCanvasLayer(); virtual already_AddRefed<ImageContainer> CreateImageContainer(); virtual LayersBackend GetBackendType() { return LAYERS_OPENGL; } /** + * Image Container management. + */ + + /* Forget this image container. Should be called by ImageContainerOGL + * on its current layer manager before switching to a new one. + */ + void ForgetImageContainer(ImageContainer* aContainer); + void RememberImageContainer(ImageContainer* aContainer); + + /** * Helper methods. */ void MakeCurrent(); ColorTextureLayerProgram *GetRGBALayerProgram() { return static_cast<ColorTextureLayerProgram*>(mPrograms[RGBALayerProgramType]); } ColorTextureLayerProgram *GetBGRALayerProgram() { @@ -177,16 +189,26 @@ public: GLContext *gl() const { return mGLContext; } DrawThebesLayerCallback GetThebesLayerCallback() const { return mThebesLayerCallback; } void* GetThebesLayerCallbackData() const { return mThebesLayerCallbackData; } + // This is a GLContext that can be used for resource + // management (creation, destruction). It is guaranteed + // to be either the same as the gl() context, or a context + // that is in the same share pool. + GLContext *glForResources() const { + if (mGLContext->GetSharedContext()) + return mGLContext->GetSharedContext(); + return mGLContext; + } + /* * Helper functions for our layers */ void CallThebesLayerDrawCallback(ThebesLayer* aLayer, gfxContext* aContext, const nsIntRegion& aRegionToDraw) { NS_ASSERTION(mThebesLayerCallback, @@ -276,16 +298,21 @@ private: nsIWidget *mWidget; /** * Context target, NULL when drawing directly to our swap chain. */ nsRefPtr<gfxContext> mTarget; nsRefPtr<GLContext> mGLContext; + // The image containers that this layer manager has created. + // The destructor will tell the layer manager to remove + // it from the list. + nsTArray<ImageContainer*> mImageContainers; + enum ProgramType { RGBALayerProgramType, BGRALayerProgramType, RGBXLayerProgramType, BGRXLayerProgramType, RGBARectLayerProgramType, ColorLayerProgramType, YCbCrLayerProgramType, @@ -359,31 +386,39 @@ private: /** * General information and tree management for OGL layers. */ class LayerOGL { public: LayerOGL(LayerManagerOGL *aManager) - : mOGLManager(aManager) + : mOGLManager(aManager), mDestroyed(PR_FALSE) { } + virtual ~LayerOGL() { } + virtual LayerOGL *GetFirstChildOGL() { return nsnull; } + /* Do NOT call this from the generic LayerOGL destructor. Only from the + * concrete class destructor + */ + virtual void Destroy() = 0; + virtual Layer* GetLayer() = 0; virtual void RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset) = 0; typedef mozilla::gl::GLContext GLContext; GLContext *gl() const { return mOGLManager->gl(); } protected: LayerManagerOGL *mOGLManager; + PRPackedBool mDestroyed; }; } /* layers */ } /* mozilla */ #endif /* GFX_LAYERMANAGEROGL_H */
--- a/gfx/layers/opengl/LayerManagerOGLProgram.h +++ b/gfx/layers/opengl/LayerManagerOGLProgram.h @@ -295,29 +295,27 @@ protected: if (!success) { fprintf (stderr, "=== PROGRAM LINKING FAILED ===\n"); } else { fprintf (stderr, "=== PROGRAM LINKING WARNINGS ===\n"); } fprintf (stderr, "=== Log:\n%s\n", nsPromiseFlatCString(log).get()); fprintf (stderr, "============\n"); - - // We can mark the shaders for deletion; they're attached to the program - // and will remain attached. - mGL->fDeleteShader(vertexShader); - mGL->fDeleteShader(fragmentShader); + } - if (!success) { - mGL->fDeleteProgram(mProgram); + // We can mark the shaders for deletion; they're attached to the program + // and will remain attached. + mGL->fDeleteShader(vertexShader); + mGL->fDeleteShader(fragmentShader); - mProgram = 0; - - return false; - } + if (!success) { + mGL->fDeleteProgram(mProgram); + mProgram = 0; + return false; } // Now query uniforms, so that we can initialize mUniformValues // note that for simplicity, mUniformLocations is indexed by the // uniform -location-, and not the uniform -index-. This means // that it might have a bunch of unused space as locations dense // like indices are; however, there are unlikely to be enough for // our shaders for this to become a significant memory issue.
--- a/gfx/layers/opengl/ThebesLayerOGL.cpp +++ b/gfx/layers/opengl/ThebesLayerOGL.cpp @@ -326,18 +326,28 @@ ThebesLayerOGL::ThebesLayerOGL(LayerMana , LayerOGL(aManager) , mBuffer(nsnull) { mImplData = static_cast<LayerOGL*>(this); } ThebesLayerOGL::~ThebesLayerOGL() { - mBuffer = nsnull; - DEBUG_GL_ERROR_CHECK(gl()); + Destroy(); +} + +void +ThebesLayerOGL::Destroy() +{ + if (!mDestroyed) { + mBuffer = nsnull; + DEBUG_GL_ERROR_CHECK(gl()); + + mDestroyed = PR_TRUE; + } } PRBool ThebesLayerOGL::CreateSurface() { NS_ASSERTION(!mBuffer, "buffer already created?"); if (mVisibleRegion.IsEmpty()) {
--- a/gfx/layers/opengl/ThebesLayerOGL.h +++ b/gfx/layers/opengl/ThebesLayerOGL.h @@ -45,31 +45,32 @@ namespace mozilla { namespace layers { class ThebesLayerBufferOGL; class ThebesLayerOGL : public ThebesLayer, - public LayerOGL + public LayerOGL { typedef ThebesLayerBufferOGL Buffer; public: ThebesLayerOGL(LayerManagerOGL *aManager); virtual ~ThebesLayerOGL(); /** Layer implementation */ void SetVisibleRegion(const nsIntRegion& aRegion); /** ThebesLayer implementation */ void InvalidateRegion(const nsIntRegion& aRegion); /** LayerOGL implementation */ + void Destroy(); Layer* GetLayer(); virtual PRBool IsEmpty(); virtual void RenderLayer(int aPreviousFrameBuffer, const nsIntPoint& aOffset); private: PRBool CreateSurface();