vcl: fix lifecycle errors & memory corruption.

FixedTextureAtlasManager should use ref-counted textures properly.
Also - dispose embedded textures early in VCL shutdown while we have
a valid OpenGLContext.
Also - dispose the native widget control cache earlier too.

Change-Id: Id3f7a1c3b331496616f36cbf02f83737505278a5
Reviewed-on: https://gerrit.libreoffice.org/21148
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Michael Meeks <michael.meeks@collabora.com>
This commit is contained in:
Michael Meeks
2016-01-06 12:12:51 +00:00
parent 43de9a5b0f
commit 50c9d1f965
5 changed files with 42 additions and 24 deletions

View File

@@ -16,7 +16,7 @@
class VCL_PLUGIN_PUBLIC FixedTextureAtlasManager class VCL_PLUGIN_PUBLIC FixedTextureAtlasManager
{ {
std::vector<std::unique_ptr<ImplOpenGLTexture>> mpTextures; std::vector<ImplOpenGLTexture *> mpTextures;
int mWidthFactor; int mWidthFactor;
int mHeightFactor; int mHeightFactor;
@@ -26,6 +26,7 @@ class VCL_PLUGIN_PUBLIC FixedTextureAtlasManager
public: public:
FixedTextureAtlasManager(int nWidthFactor, int nHeightFactor, int nTextureSize); FixedTextureAtlasManager(int nWidthFactor, int nHeightFactor, int nTextureSize);
~FixedTextureAtlasManager();
OpenGLTexture InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData); OpenGLTexture InsertBuffer(int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData);
int GetSubtextureSize() int GetSubtextureSize()

View File

@@ -31,8 +31,8 @@
class ImplOpenGLTexture class ImplOpenGLTexture
{ {
public:
int mnRefCount; int mnRefCount;
public:
GLuint mnTexture; GLuint mnTexture;
int mnWidth; int mnWidth;
int mnHeight; int mnHeight;
@@ -46,6 +46,7 @@ public:
ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData ); ImplOpenGLTexture( int nWidth, int nHeight, int nFormat, int nType, void const * pData );
ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight ); ImplOpenGLTexture( int nX, int nY, int nWidth, int nHeight );
~ImplOpenGLTexture(); ~ImplOpenGLTexture();
void Dispose();
bool InsertBuffer(int nX, int nY, int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData); bool InsertBuffer(int nX, int nY, int nWidth, int nHeight, int nFormat, int nType, sal_uInt8* pData);
@@ -69,11 +70,14 @@ public:
if (mpSlotReferences->at(nSlotNumber) == 0) if (mpSlotReferences->at(nSlotNumber) == 0)
mnFreeSlots++; mnFreeSlots++;
} }
if (mnRefCount <= 0)
delete this;
} }
bool ExistRefs() bool IsUnique()
{ {
return mnRefCount > 0; return mnRefCount == 1;
} }
bool InitializeSlots(int nSlotSize); bool InitializeSlots(int nSlotSize);

View File

@@ -24,11 +24,21 @@ FixedTextureAtlasManager::FixedTextureAtlasManager(int nWidthFactor, int nHeight
{ {
} }
FixedTextureAtlasManager::~FixedTextureAtlasManager()
{
for (auto i = mpTextures.begin(); i != mpTextures.end(); ++i)
{
// Free texture early in VCL shutdown while we have a context.
(*i)->Dispose();
(*i)->DecreaseRefCount(0);
}
}
void FixedTextureAtlasManager::CreateNewTexture() void FixedTextureAtlasManager::CreateNewTexture()
{ {
int nTextureWidth = mWidthFactor * mSubTextureSize; int nTextureWidth = mWidthFactor * mSubTextureSize;
int nTextureHeight = mHeightFactor * mSubTextureSize; int nTextureHeight = mHeightFactor * mSubTextureSize;
mpTextures.push_back(std::unique_ptr<ImplOpenGLTexture>(new ImplOpenGLTexture(nTextureWidth, nTextureHeight, true))); mpTextures.push_back(new ImplOpenGLTexture(nTextureWidth, nTextureHeight, true));
mpTextures.back()->InitializeSlots(mWidthFactor * mHeightFactor); mpTextures.back()->InitializeSlots(mWidthFactor * mHeightFactor);
} }
@@ -36,21 +46,21 @@ OpenGLTexture FixedTextureAtlasManager::InsertBuffer(int nWidth, int nHeight, in
{ {
ImplOpenGLTexture* pTexture = nullptr; ImplOpenGLTexture* pTexture = nullptr;
auto funFreeSlot = [] (std::unique_ptr<ImplOpenGLTexture>& mpTexture) auto funFreeSlot = [] (ImplOpenGLTexture *mpTexture)
{ {
return mpTexture->mnFreeSlots > 0; return mpTexture->mnFreeSlots > 0;
}; };
auto aIterator = std::find_if(mpTextures.begin(), mpTextures.end(), funFreeSlot); auto it = std::find_if(mpTextures.begin(), mpTextures.end(), funFreeSlot);
if (aIterator != mpTextures.end()) if (it != mpTextures.end())
{ {
pTexture = (*aIterator).get(); pTexture = *it;
} }
else else
{ {
CreateNewTexture(); CreateNewTexture();
pTexture = mpTextures.back().get(); pTexture = mpTextures.back();
} }
int nSlot = pTexture->FindFreeSlot(); int nSlot = pTexture->FindFreeSlot();

View File

@@ -157,6 +157,11 @@ GLuint ImplOpenGLTexture::AddStencil()
ImplOpenGLTexture::~ImplOpenGLTexture() ImplOpenGLTexture::~ImplOpenGLTexture()
{ {
VCL_GL_INFO( "~OpenGLTexture " << mnTexture ); VCL_GL_INFO( "~OpenGLTexture " << mnTexture );
Dispose();
}
void ImplOpenGLTexture::Dispose()
{
if( mnTexture != 0 ) if( mnTexture != 0 )
{ {
OpenGLVCLContextZone aContextZone; OpenGLVCLContextZone aContextZone;
@@ -173,8 +178,12 @@ ImplOpenGLTexture::~ImplOpenGLTexture()
} }
if( mnOptStencil != 0 ) if( mnOptStencil != 0 )
{
glDeleteRenderbuffers( 1, &mnOptStencil ); glDeleteRenderbuffers( 1, &mnOptStencil );
mnOptStencil = 0;
}
glDeleteTextures( 1, &mnTexture ); glDeleteTextures( 1, &mnTexture );
mnTexture = 0;
} }
} }
@@ -285,16 +294,12 @@ OpenGLTexture::OpenGLTexture( const OpenGLTexture& rTexture,
OpenGLTexture::~OpenGLTexture() OpenGLTexture::~OpenGLTexture()
{ {
if (mpImpl) if (mpImpl)
{
mpImpl->DecreaseRefCount(mnSlotNumber); mpImpl->DecreaseRefCount(mnSlotNumber);
if (!mpImpl->ExistRefs())
delete mpImpl;
}
} }
bool OpenGLTexture::IsUnique() const bool OpenGLTexture::IsUnique() const
{ {
return ( mpImpl == nullptr || mpImpl->mnRefCount == 1 ); return mpImpl == nullptr || mpImpl->IsUnique();
} }
GLuint OpenGLTexture::Id() const GLuint OpenGLTexture::Id() const
@@ -484,11 +489,7 @@ OpenGLTexture& OpenGLTexture::operator=( const OpenGLTexture& rTexture )
} }
if (mpImpl) if (mpImpl)
{
mpImpl->DecreaseRefCount(mnSlotNumber); mpImpl->DecreaseRefCount(mnSlotNumber);
if (!mpImpl->ExistRefs())
delete mpImpl;
}
maRect = rTexture.maRect; maRect = rTexture.maRect;
mpImpl = rTexture.mpImpl; mpImpl = rTexture.mpImpl;

View File

@@ -8,6 +8,7 @@
*/ */
#include <vcl/salbtype.hxx> #include <vcl/salbtype.hxx>
#include <vcl/lazydelete.hxx>
#include <svdata.hxx> #include <svdata.hxx>
@@ -105,7 +106,7 @@ bool X11OpenGLSalGraphicsImpl::FillPixmapFromScreen( X11Pixmap* pPixmap, int nX,
typedef typename std::pair<ControlCacheKey, std::unique_ptr<TextureCombo>> ControlCachePair; typedef typename std::pair<ControlCacheKey, std::unique_ptr<TextureCombo>> ControlCachePair;
typedef o3tl::lru_map<ControlCacheKey, std::unique_ptr<TextureCombo>, ControlCacheHashFunction> ControlCacheType; typedef o3tl::lru_map<ControlCacheKey, std::unique_ptr<TextureCombo>, ControlCacheHashFunction> ControlCacheType;
ControlCacheType gTextureCache(200); vcl::DeleteOnDeinit<ControlCacheType> gTextureCache(new ControlCacheType(200));
bool X11OpenGLSalGraphicsImpl::RenderPixmap(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, TextureCombo& rCombo) bool X11OpenGLSalGraphicsImpl::RenderPixmap(X11Pixmap* pPixmap, X11Pixmap* pMask, int nX, int nY, TextureCombo& rCombo)
{ {
@@ -190,12 +191,12 @@ bool X11OpenGLSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey& rCo
{ {
static bool gbCacheEnabled = !getenv("SAL_WITHOUT_WIDGET_CACHE"); static bool gbCacheEnabled = !getenv("SAL_WITHOUT_WIDGET_CACHE");
if (!gbCacheEnabled) if (!gbCacheEnabled || !gTextureCache.get())
return false; return false;
ControlCacheType::const_iterator iterator = gTextureCache.find(rControlCacheKey); ControlCacheType::const_iterator iterator = gTextureCache.get()->find(rControlCacheKey);
if (iterator == gTextureCache.end()) if (iterator == gTextureCache.get()->end())
return false; return false;
const std::unique_ptr<TextureCombo>& pCombo = iterator->second; const std::unique_ptr<TextureCombo>& pCombo = iterator->second;
@@ -229,7 +230,8 @@ bool X11OpenGLSalGraphicsImpl::RenderAndCacheNativeControl(X11Pixmap* pPixmap, X
return true; return true;
ControlCachePair pair(aControlCacheKey, std::move(pCombo)); ControlCachePair pair(aControlCacheKey, std::move(pCombo));
gTextureCache.insert(std::move(pair)); if (gTextureCache.get())
gTextureCache.get()->insert(std::move(pair));
return bResult; return bResult;
} }