This fixes a bug found when opening/closing the text-selection popup.
The reference counts are not incremented correctly e.g. when a word contains
the same letter twice. This results in the atlas becoming corrupted.
+ More Debug macros for glyph-atlas
Change-Id: Ib91681bc76e037ec4f6765bdc6ecbc9f592c20e3
// EXTERNAL INCLUDES
#include <dali/public-api/actors/image-actor.h>
#include <dali/public-api/common/stage.h>
+#include <dali/integration-api/debug.h>
#define MAKE_SHADER(A)#A
namespace
{
+
+#if defined(DEBUG_ENABLED)
+ Debug::Filter* gLogFilter = Debug::Filter::New(Debug::Concise, true, "LOG_TEXT_RENDERING");
+#endif
+
const char* VERTEX_SHADER = MAKE_SHADER(
attribute mediump vec2 aPosition;
attribute mediump vec2 aTexCoord;
gl_FragColor = vec4(uColor.rgb, uColor.a*color.r);
}
);
-}
+
+} // unnamed namespace
namespace Dali
{
mShadowShader = Shader::New( VERTEX_SHADER_SHADOW, FRAGMENT_SHADER_SHADOW, Dali::Shader::HINT_MODIFIES_GEOMETRY );
}
-AtlasGlyphManager::~AtlasGlyphManager()
-{
- // Clear up any remaining references
- for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
- fontGlyphRecordIt != mFontGlyphRecords.end();
- ++fontGlyphRecordIt )
- {
- for ( Vector< GlyphRecordEntry >::Iterator glyphRecordEntryIt = fontGlyphRecordIt->mGlyphRecords.Begin();
- glyphRecordEntryIt != fontGlyphRecordIt->mGlyphRecords.End();
- ++glyphRecordEntryIt )
- {
- mAtlasManager.Remove( glyphRecordEntryIt->mImageId );
- }
- }
-}
-
-AtlasGlyphManagerPtr AtlasGlyphManager::New()
-{
- AtlasGlyphManagerPtr internal = new AtlasGlyphManager();
- return internal;
-}
-
void AtlasGlyphManager::Add( const Text::GlyphInfo& glyph,
const BufferImage& bitmap,
Dali::Toolkit::AtlasManager::AtlasSlot& slot )
{
+ DALI_LOG_INFO( gLogFilter, Debug::General, "Added glyph, font: %d index: %d\n", glyph.fontId, glyph.index );
+
mAtlasManager.Add( bitmap, slot );
GlyphRecordEntry record;
}
bool AtlasGlyphManager::Cached( Text::FontId fontId,
- uint32_t index,
+ Text::GlyphIndex index,
Dali::Toolkit::AtlasManager::AtlasSlot& slot )
{
for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
const Toolkit::AtlasGlyphManager::Metrics& AtlasGlyphManager::GetMetrics()
{
+ std::ostringstream verboseMetrics;
+
mMetrics.mGlyphCount = 0u;
for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
fontGlyphRecordIt != mFontGlyphRecords.end();
++fontGlyphRecordIt )
{
mMetrics.mGlyphCount += fontGlyphRecordIt->mGlyphRecords.Size();
+
+ verboseMetrics << "[FontId " << fontGlyphRecordIt->mFontId << " Glyph ";
+ for ( Vector< GlyphRecordEntry >::Iterator glyphRecordEntryIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+ glyphRecordEntryIt != fontGlyphRecordIt->mGlyphRecords.End();
+ ++glyphRecordEntryIt )
+ {
+ verboseMetrics << glyphRecordEntryIt->mIndex << "(" << glyphRecordEntryIt->mCount << ") ";
+ }
+ verboseMetrics << "] ";
}
+ mMetrics.mVerboseGlyphCounts = verboseMetrics.str();
+
mAtlasManager.GetMetrics( mMetrics.mAtlasMetrics );
+
return mMetrics;
}
-void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta )
+void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, int32_t delta )
{
- for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
- fontGlyphRecordIt != mFontGlyphRecords.end();
- ++fontGlyphRecordIt )
+ if( 0 != delta )
{
- if ( fontGlyphRecordIt->mFontId == fontId )
+ DALI_LOG_INFO( gLogFilter, Debug::General, "AdjustReferenceCount %d, font: %d index: %d\n", delta, fontId, index );
+
+ for ( std::vector< FontGlyphRecord >::iterator fontGlyphRecordIt = mFontGlyphRecords.begin();
+ fontGlyphRecordIt != mFontGlyphRecords.end();
+ ++fontGlyphRecordIt )
{
- for ( Vector< GlyphRecordEntry >::Iterator glyphRecordIt = fontGlyphRecordIt->mGlyphRecords.Begin();
- glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End();
- ++glyphRecordIt )
+ if ( fontGlyphRecordIt->mFontId == fontId )
{
- if ( glyphRecordIt->mImageId == imageId )
+ for ( Vector< GlyphRecordEntry >::Iterator glyphRecordIt = fontGlyphRecordIt->mGlyphRecords.Begin();
+ glyphRecordIt != fontGlyphRecordIt->mGlyphRecords.End();
+ ++glyphRecordIt )
{
- glyphRecordIt->mCount += delta;
- if ( !glyphRecordIt->mCount )
+ if ( glyphRecordIt->mIndex == index )
{
- mAtlasManager.Remove( glyphRecordIt->mImageId );
- fontGlyphRecordIt->mGlyphRecords.Remove( glyphRecordIt );
+ glyphRecordIt->mCount += delta;
+ DALI_ASSERT_DEBUG( glyphRecordIt->mCount >= 0 && "Glyph ref-count should not be negative" );
+
+ if ( !glyphRecordIt->mCount )
+ {
+ mAtlasManager.Remove( glyphRecordIt->mImageId );
+ fontGlyphRecordIt->mGlyphRecords.Remove( glyphRecordIt );
+ }
+ return;
}
- return;
}
}
}
+
+ // Should not arrive here
+ DALI_ASSERT_DEBUG( false && "Failed to adjust ref-count" );
}
}
return mAtlasManager.GetSampler( atlasId );
}
+AtlasGlyphManager::~AtlasGlyphManager()
+{
+ // mAtlasManager handle is automatically released here
+}
+
} // namespace Internal
} // namespace Toolkit
Vector< GlyphRecordEntry > mGlyphRecords;
};
- AtlasGlyphManager();
-
- virtual ~AtlasGlyphManager();
-
-/**
- * Create a new AtlasGlyphManager
+ /**
+ * @brief Constructor
*/
- static AtlasGlyphManagerPtr New();
+ AtlasGlyphManager();
/**
* @copydoc Toolkit::AtlasGlyphManager::Add
/**
* @copydoc toolkit::AtlasGlyphManager::AdjustReferenceCount
*/
- void AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta );
+ void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, int32_t delta );
/**
* @copydoc Toolkit::AtlasGlyphManager::GetMaterial
return mShadowShader;
}
+protected:
+
+ /**
+ * A reference counted object may only be deleted by calling Unreference()
+ */
+ virtual ~AtlasGlyphManager();
+
private:
Dali::Toolkit::AtlasManager mAtlasManager; ///> Atlas Manager created by GlyphManager
return GetImplementation(*this).GetMetrics();
}
-void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta )
+void AtlasGlyphManager::AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, int32_t delta )
{
- GetImplementation(*this).AdjustReferenceCount( fontId, imageId, delta );
+ GetImplementation(*this).AdjustReferenceCount( fontId, index, delta );
}
Shader AtlasGlyphManager::GetEffectBufferShader() const
{}
uint32_t mGlyphCount; // number of glyphs being managed
+ std::string mVerboseGlyphCounts; // a verbose list of the glyphs + ref counts
AtlasManager::Metrics mAtlasMetrics; // metrics from the Atlas Manager
};
const Metrics& GetMetrics();
/**
- * @brief Adjust the reference count for an imageId and remove cache entry if it becomes free
+ * @brief Adjust the reference count for glyph
*
- * @param[in] fontId the font this image came from
- * @param[in] imageId The imageId
- * @param[in] delta adjustment to make to reference count
+ * @param[in] fontId The font this image came from
+ * @param[in] index The index of the glyph
+ * @param[in] delta The adjustment to make to the reference count
*/
- void AdjustReferenceCount( Text::FontId fontId, uint32_t imageId, int32_t delta );
+ void AdjustReferenceCount( Text::FontId fontId, Text::GlyphIndex index, int32_t delta );
/**
* @brief Get Shader used for rendering glyph effect buffers
style = STYLE_DROP_SHADOW;
}
- if ( mTextCache.Size() )
- {
- // Update the glyph cache with any changes to current text
- RemoveText( glyphs );
- }
-
CalculateBlocksSize( glyphs );
+ // Avoid emptying mTextCache (& removing references) until after incremented references for the new text
+ Vector< TextCacheEntry > newTextCache;
+
for( uint32_t i = 0, glyphSize = glyphs.Size(); i < glyphSize; ++i )
{
const GlyphInfo& glyph = glyphs[ i ];
mGlyphManager.Add( glyph, bitmap, slot );
}
}
+ else
+ {
+ // We have 2+ copies of the same glyph
+ mGlyphManager.AdjustReferenceCount( glyph.fontId, glyph.index, 1/*increment*/ );
+ }
// Generate mesh data for this quad, plugging in our supplied position
mGlyphManager.GenerateMeshData( slot.mImageId, position, newMesh );
textCacheEntry.mFontId = glyph.fontId;
textCacheEntry.mImageId = slot.mImageId;
textCacheEntry.mIndex = glyph.index;
- mTextCache.PushBack( textCacheEntry );
+ newTextCache.PushBack( textCacheEntry );
// Find an existing mesh data object to attach to ( or create a new one, if we can't find one using the same atlas)
StitchTextMesh( meshContainer,
}
}
+ // Now remove references for the old text
+ RemoveText();
+ mTextCache.Swap( newTextCache );
+
if ( underlineEnabled )
{
// Check to see if any of the text needs an underline
metrics.mGlyphCount,
metrics.mAtlasMetrics.mAtlasCount,
metrics.mAtlasMetrics.mTextureMemoryUsed / 1024 );
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "%s\n", metrics.mVerboseGlyphCounts.c_str() );
+
for ( uint32_t i = 0; i < metrics.mAtlasMetrics.mAtlasCount; ++i )
{
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, " Atlas [%i] %sPixels: %s Size: %ix%i, BlockSize: %ix%i, BlocksUsed: %i/%i\n",
i + 1, i > 8 ? "" : " ",
metrics.mAtlasMetrics.mAtlasMetrics[ i ].mPixelFormat == Pixel::L8 ? "L8 " : "BGRA",
metrics.mAtlasMetrics.mAtlasMetrics[ i ].mSize.mWidth,
#endif
}
+ void RemoveText()
+ {
+ for ( Vector< TextCacheEntry >::Iterator oldTextIter = mTextCache.Begin(); oldTextIter != mTextCache.End(); ++oldTextIter )
+ {
+ mGlyphManager.AdjustReferenceCount( oldTextIter->mFontId, oldTextIter->mIndex, -1/*decrement*/ );
+ }
+ mTextCache.Resize( 0 );
+ }
+
Actor CreateMeshActor( const MeshRecord& meshRecord )
{
PropertyBuffer quadVertices = PropertyBuffer::New( mQuadVertexFormat, meshRecord.mMesh.mVertices.Size() );
}
}
- void RemoveText( const Vector<GlyphInfo>& glyphs )
- {
- Vector< CheckEntry > checked;
- CheckEntry checkEntry;
-
- for ( Vector< TextCacheEntry >::Iterator tCit = mTextCache.Begin(); tCit != mTextCache.End(); ++tCit )
- {
- uint32_t index = tCit->mIndex;
- uint32_t fontId = tCit->mFontId;
-
- // Check that this character has not already been checked...
- bool wasChecked = false;
- for ( Vector< CheckEntry >::Iterator cEit = checked.Begin(); cEit != checked.End(); ++cEit )
- {
- if ( fontId == cEit->mFontId && index == cEit->mIndex )
- {
- wasChecked = true;
- }
- }
-
- if ( !wasChecked )
- {
-
- int32_t newCount = 0;
- int32_t oldCount = 0;
-
- // How many times does this character occur in the old text ?
- for ( Vector< TextCacheEntry >::Iterator oTcit = mTextCache.Begin(); oTcit != mTextCache.End(); ++oTcit )
- {
- if ( fontId == oTcit->mFontId && index == oTcit->mIndex )
- {
- oldCount++;
- }
- }
-
- // And how many times in the new ?
- for ( Vector< GlyphInfo >::Iterator cGit = glyphs.Begin(); cGit != glyphs.End(); ++cGit )
- {
- if ( fontId == cGit->fontId && index == cGit->index )
- {
- newCount++;
- }
- }
- mGlyphManager.AdjustReferenceCount( fontId, tCit->mImageId, newCount - oldCount );
- checkEntry.mIndex = index;
- checkEntry.mFontId = fontId;
- checked.PushBack( checkEntry );
- }
- }
- mTextCache.Resize( 0 );
- }
-
void CalculateBlocksSize( const Vector<GlyphInfo>& glyphs )
{
MaxBlockSize maxBlockSize;
AtlasRenderer::~AtlasRenderer()
{
- Vector< GlyphInfo > emptyGlyphs;
- mImpl->RemoveText( emptyGlyphs );
+ mImpl->RemoveText();
delete mImpl;
}