2 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <dali-toolkit/internal/atlas-manager/atlas-manager-impl.h>
23 #include <dali/integration-api/debug.h>
36 const uint32_t DEFAULT_ATLAS_WIDTH( 512u );
37 const uint32_t DEFAULT_ATLAS_HEIGHT( 512u );
38 const uint32_t DEFAULT_BLOCK_WIDTH( 16u );
39 const uint32_t DEFAULT_BLOCK_HEIGHT( 16u );
40 const uint32_t SINGLE_PIXEL_PADDING( 1u );
41 const uint32_t DOUBLE_PIXEL_PADDING( SINGLE_PIXEL_PADDING << 1 );
42 const uint32_t FILLED_PIXEL( -1 );
43 Toolkit::AtlasManager::AtlasSize EMPTY_SIZE;
46 AtlasManager::AtlasManager()
47 : mAddFailPolicy( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES ),
48 mFilledPixel( FILLED_PIXEL )
50 mNewAtlasSize.mWidth = DEFAULT_ATLAS_WIDTH;
51 mNewAtlasSize.mHeight = DEFAULT_ATLAS_HEIGHT;
52 mNewAtlasSize.mBlockWidth = DEFAULT_BLOCK_WIDTH;
53 mNewAtlasSize.mBlockHeight = DEFAULT_BLOCK_HEIGHT;
56 AtlasManagerPtr AtlasManager::New()
58 AtlasManagerPtr internal = new AtlasManager();
62 AtlasManager::~AtlasManager()
64 for ( uint32_t i = 0; i < mAtlasList.size(); ++i )
66 delete[] mAtlasList[ i ].mStripBuffer;
70 Toolkit::AtlasManager::AtlasId AtlasManager::CreateAtlas( const Toolkit::AtlasManager::AtlasSize& size, Pixel::Format pixelformat )
72 SizeType width = size.mWidth;
73 SizeType height = size.mHeight;
74 SizeType blockWidth = size.mBlockWidth;
75 SizeType blockHeight = size.mBlockHeight;
77 // Check to see if the atlas is large enough to hold a single block even ?
78 if ( blockWidth > width || blockHeight > height )
80 DALI_LOG_ERROR("Atlas %i x %i too small. Dimensions need to be at least %ix%i\n",
81 width, height, blockWidth, blockHeight );
85 Dali::Atlas atlas = Dali::Atlas::New( width, height, pixelformat );
86 AtlasDescriptor atlasDescriptor;
87 atlasDescriptor.mAtlas = atlas;
88 atlasDescriptor.mSize = size;
89 atlasDescriptor.mPixelFormat = pixelformat;
90 std::stringstream materialLabel;
91 materialLabel << "Atlas Material - ";
92 materialLabel << mAtlasList.size();
93 atlasDescriptor.mMaterial = Material::New( materialLabel.str() );
94 atlasDescriptor.mMaterial.SetDiffuseTexture( atlas );
95 atlasDescriptor.mNextFreeBlock = 1u; // indicate next free block will be the first ( +1 )
97 // What size do we need for this atlas' strip buffer ( assume 32bit pixel format )?
98 uint32_t neededStripSize =( blockWidth > blockHeight - DOUBLE_PIXEL_PADDING ? blockWidth : blockHeight - DOUBLE_PIXEL_PADDING ) << 2;
99 atlasDescriptor.mStripBuffer = new PixelBuffer[ neededStripSize ];
100 memset( atlasDescriptor.mStripBuffer, 0, neededStripSize );
102 atlasDescriptor.mHorizontalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
104 SINGLE_PIXEL_PADDING,
107 atlasDescriptor.mVerticalStrip = BufferImage::New( atlasDescriptor.mStripBuffer,
108 SINGLE_PIXEL_PADDING,
109 blockHeight - DOUBLE_PIXEL_PADDING,
111 atlasDescriptor.mFilledPixelImage = BufferImage::New( reinterpret_cast< PixelBuffer* >( &mFilledPixel ), 1, 1, pixelformat );
112 atlas.Upload( atlasDescriptor.mFilledPixelImage, 0, 0 );
113 mAtlasList.push_back( atlasDescriptor );
114 return mAtlasList.size();
117 void AtlasManager::SetAddPolicy( Toolkit::AtlasManager::AddFailPolicy policy )
119 mAddFailPolicy = policy;
122 void AtlasManager::Add( const BufferImage& image,
123 Toolkit::AtlasManager::AtlasSlot& slot,
124 Toolkit::AtlasManager::AtlasId atlas )
126 // See if there's a slot in an atlas that matches the requirements of this image
127 // A bitmap must be sliceable into a single atlas
128 Pixel::Format pixelFormat = image.GetPixelFormat();
129 SizeType width = image.GetWidth();
130 SizeType height = image.GetHeight();
131 SizeType blockArea = 0;
132 SizeType totalBlocks = 0;
133 SizeType foundAtlas = 0;
137 AtlasSlotDescriptor desc;
139 // If there is a preferred atlas then check for room in that first
142 foundAtlas = CheckAtlas( atlas, width, height, pixelFormat, blockArea, totalBlocks );
145 // Search current atlases to see if there is a good match
147 while( !foundAtlas && index < mAtlasList.size() )
149 foundAtlas = CheckAtlas( index, width, height, pixelFormat, blockArea, totalBlocks );
153 // If we can't find a suitable atlas then check the policy to determine action
156 if ( Toolkit::AtlasManager::FAIL_ON_ADD_CREATES == mAddFailPolicy )
158 SizeType newAtlas = CreateAtlas( mNewAtlasSize, pixelFormat );
165 foundAtlas = CheckAtlas( newAtlas, width, height, pixelFormat, blockArea, totalBlocks );
169 if ( Toolkit::AtlasManager::FAIL_ON_ADD_FAILS == mAddFailPolicy || !foundAtlas-- )
171 // Haven't found an atlas for this image!!!!!!
176 // Work out where the blocks are we're going to use
177 for ( SizeType i = 0; i < blockArea; ++i )
179 // Is there currently a next free block available ?
180 if ( mAtlasList[ foundAtlas ].mNextFreeBlock )
182 // Yes, so use this for our next block
183 SizeType selectedBlock = mAtlasList[ foundAtlas ].mNextFreeBlock - 1u;
184 desc.mBlocksList.PushBack( selectedBlock );
186 // Any blocks going to be available after this one (adjust to store +1 )?
189 if ( selectedBlock > totalBlocks )
191 // No so start trying to use free blocks list
194 mAtlasList[ foundAtlas ].mNextFreeBlock = selectedBlock;
198 // Our next block must be from the free list, fetch from the start of the list
199 desc.mBlocksList.PushBack( mAtlasList[ foundAtlas ].mFreeBlocksList[ 0 ] );
200 mAtlasList[ foundAtlas ].mFreeBlocksList.Remove( mAtlasList[ foundAtlas ].mFreeBlocksList.Begin() );
204 desc.mImageWidth = width;
205 desc.mImageHeight = height;
206 desc.mAtlasId = foundAtlas + 1u;
209 // See if there's a previously freed image ID that we can assign to this new image
210 uint32_t imageId = 0;
211 for ( uint32_t i = 0; i < mImageList.size(); ++i )
213 if ( !mImageList[ i ].mCount )
221 mImageList.push_back( desc );
222 slot.mImageId = mImageList.size();
226 mImageList[ imageId - 1u ] = desc;
227 slot.mImageId = imageId;
229 slot.mAtlasId = foundAtlas + 1u;
230 UploadImage( image, desc );
233 AtlasManager::SizeType AtlasManager::CheckAtlas( SizeType atlas,
236 Pixel::Format pixelFormat,
238 SizeType& totalBlocks )
240 if ( pixelFormat == mAtlasList[ atlas ].mPixelFormat )
242 // Check to see if there are any unused blocks in this atlas to accomodate our image
243 SizeType blocksInX = mAtlasList[ atlas ].mSize.mWidth / mAtlasList[ atlas ].mSize.mBlockWidth;
244 SizeType blocksInY = mAtlasList[ atlas ].mSize.mHeight / mAtlasList[ atlas ].mSize.mBlockHeight;
245 totalBlocks = blocksInX * blocksInY;
246 SizeType blocksFree = mAtlasList[ atlas ].mNextFreeBlock ?
247 totalBlocks - mAtlasList[ atlas ].mNextFreeBlock + 1u :
248 mAtlasList[ atlas ].mFreeBlocksList.Size();
250 // Check to see if the image will fit in these blocks, if not we'll need to create a new atlas
252 && width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockWidth
253 && height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mBlockHeight )
256 return ( atlas + 1u );
262 void AtlasManager::CreateMesh( SizeType atlas,
264 SizeType imageHeight,
265 const Vector2& position,
266 SizeType widthInBlocks,
267 SizeType heightInBlocks,
268 Dali::MeshData& meshData,
269 AtlasSlotDescriptor& desc )
271 Dali::MeshData::Vertex vertex;
272 Dali::MeshData::VertexContainer vertices;
273 Dali::MeshData::FaceIndices faces;
274 Dali::MeshData::FaceIndex faceIndex = 0;
275 meshData.SetHasNormals( false );
276 meshData.SetHasColor( true );
277 meshData.SetHasTextureCoords( true );
279 SizeType blockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
280 SizeType blockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
282 float vertexBlockWidth = static_cast< float >( blockWidth );
283 float vertexBlockHeight = static_cast< float >( blockHeight );
285 SizeType width = mAtlasList[ atlas ].mSize.mWidth;
286 SizeType height = mAtlasList[ atlas ].mSize.mHeight;
288 SizeType atlasWidthInBlocks = width / blockWidth;
290 // Get the normalized size of a texel in both directions
291 // TODO when texture resizing and passing texture size via uniforms is available,
292 // we will encode pixel positions into the vertex data rather than normalized
293 // meaning that geometry needn't be changed on an atlas resize
294 float texelX = 1.0f / static_cast< float >( width );
295 float texelY = 1.0f / static_cast< float >( height );
297 // Get the normalized size of a block in texels
298 float texelBlockWidth = texelX * vertexBlockWidth;
299 float texelBlockHeight = texelY * vertexBlockHeight;
301 // Get partial block space
302 float vertexEdgeWidth = static_cast< float >( imageWidth % blockWidth );
303 float vertexEdgeHeight = static_cast< float >( imageHeight % blockHeight );
306 float texelEdgeWidth = vertexEdgeWidth * texelX;
307 float texelEdgeHeight = vertexEdgeHeight * texelY;
309 // Block by block create the two triangles for the quad
310 SizeType blockIndex = 0;
316 Vector2 topLeft = position;
318 for ( SizeType y = 0; y < heightInBlocks; ++y )
321 float currentX = position.x;
323 if ( ( heightInBlocks - 1u ) == y && vertexEdgeHeight > 0.0f )
325 ndcHeight = texelEdgeHeight;
326 ndcVHeight = vertexEdgeHeight;
330 ndcHeight = texelBlockHeight;
331 ndcVHeight = vertexBlockHeight;
334 for ( SizeType x = 0; x < widthInBlocks; ++x )
336 SizeType block = desc.mBlocksList[ blockIndex++ ];
338 float fBlockX = texelBlockWidth * static_cast< float >( block % atlasWidthInBlocks );
339 float fBlockY = texelBlockHeight * static_cast< float >( block / atlasWidthInBlocks );
341 // Add on texture filtering compensation
345 if ( ( widthInBlocks - 1u ) == x && vertexEdgeWidth > 0.0f )
347 ndcWidth = texelEdgeWidth;
348 ndcVWidth = vertexEdgeWidth;
352 ndcWidth = texelBlockWidth;
353 ndcVWidth = vertexBlockWidth;
357 vertex.x = topLeft.x;
358 vertex.y = topLeft.y;
363 vertices.push_back( vertex );
366 vertex.x = topLeft.x + ndcVWidth;
367 vertex.y = topLeft.y;
369 vertex.u = fBlockX + ndcWidth;
372 vertices.push_back( vertex );
375 vertex.x = topLeft.x;
376 vertex.y = topLeft.y + ndcVHeight;
379 vertex.v = fBlockY + ndcHeight;
381 vertices.push_back( vertex );
384 topLeft.x += ndcVWidth;
385 vertex.x = topLeft.x;
386 vertex.y = topLeft.y + ndcVHeight;
388 vertex.u = fBlockX + ndcWidth;
389 vertex.v = fBlockY + ndcHeight;
391 vertices.push_back( vertex );
393 // Six indices in counter clockwise winding
394 faces.push_back( faceIndex + 1u );
395 faces.push_back( faceIndex );
396 faces.push_back( faceIndex + 2u );
397 faces.push_back( faceIndex + 2u );
398 faces.push_back( faceIndex + 3u );
399 faces.push_back( faceIndex + 1u );
404 topLeft.x = currentX;
405 topLeft.y += vertexBlockHeight;
408 // If there's only one block then skip this next vertex optimisation
409 if ( widthInBlocks * heightInBlocks > 1 )
411 Dali::MeshData::VertexContainer optimizedVertices;
412 OptimizeVertices( vertices, faces, optimizedVertices );
413 meshData.SetVertices( optimizedVertices );
417 meshData.SetVertices( vertices );
420 meshData.SetFaceIndices( faces );
421 meshData.SetMaterial( mAtlasList[ atlas ].mMaterial );
424 void AtlasManager::PrintMeshData( const MeshData& meshData )
426 std::cout << "\nMesh Data for Image: VertexCount = " << meshData.GetVertexCount();
427 std::cout << ", Triangles = " << meshData.GetFaceCount() << std::endl;
429 Dali::MeshData::VertexContainer vertices = meshData.GetVertices();
430 Dali::MeshData::FaceIndices faces = meshData.GetFaces();
432 for ( SizeType v = 0; v < vertices.size(); ++v )
434 std::cout << " Vertex(" << v << ") x = " << vertices[v].x << ", ";
435 std::cout << "y = " << vertices[v].y << ", " << "z = " << vertices[v].z << ", ";
436 std::cout << "u = " << vertices[v].u << ", " << "v = " << vertices[v].v << std::endl;
439 std::cout << "\n Indices: ";
440 for ( SizeType i = 0; i < faces.size(); ++i )
442 std::cout << " " << faces[ i ];
444 std::cout << std::endl;
447 void AtlasManager::OptimizeVertices( const MeshData::VertexContainer& in,
448 MeshData::FaceIndices& faces,
449 MeshData::VertexContainer& out )
451 unsigned short vertexIndex = 0;
453 // We could check to see if blocks are next to each other, but it's probably just as quick to compare verts
454 for ( SizeType i = 0; i < faces.size(); ++i )
456 // Fetch a vertex, has it already been assigned?
457 bool foundVertex = false;
458 Dali::MeshData::Vertex v = in[ faces [ i ] ];
459 for ( SizeType j = 0; j < vertexIndex; ++j )
461 if ( v.x == out[ j ].x && v.y == out[ j ].y && v.z == out[ j ].z &&
462 v.u == out[ j ].u && v.v == out[ j ].v && v.nX == out[ j ].nX &&
463 v.nY == out[ j ].nY && v.nZ == out[ j ].nZ )
465 // Yes, so store this down as the vertex to use
472 // Did we find a vertex ?
476 faces[ i ] = vertexIndex++;
482 void AtlasManager::StitchMesh( MeshData& first,
483 const MeshData& second,
487 // Would be much quicker to be able to get a non-const reference to these containers and update in situ
488 MeshData::VertexContainer v1 = first.GetVertices();
489 MeshData::VertexContainer v2 = second.GetVertices();
490 MeshData::FaceIndices f1 = first.GetFaces();
491 MeshData::FaceIndices f2 = second.GetFaces();
493 uint32_t vc1 = first.GetVertexCount();
494 uint32_t vc2 = second.GetVertexCount();
496 for ( uint32_t v = 0; v < vc2; ++v )
498 v1.push_back( v2[ v ] );
501 for ( uint32_t f = 0; f < f2.size(); ++f )
503 f1.push_back( f2[ f ] + vc1 );
508 MeshData::VertexContainer optimizedVertices;
509 OptimizeVertices( v1, f1, optimizedVertices );
510 first.SetVertices( optimizedVertices );
514 first.SetVertices( v1 );
517 first.SetFaceIndices( f1 );
520 void AtlasManager::StitchMesh( const MeshData& first,
521 const MeshData& second,
525 MeshData::VertexContainer v1 = first.GetVertices();
526 MeshData::VertexContainer v2 = second.GetVertices();
527 MeshData::FaceIndices f1 = first.GetFaces();
528 MeshData::FaceIndices f2 = second.GetFaces();
530 uint32_t vc1 = first.GetVertexCount();
531 uint32_t vc2 = second.GetVertexCount();
533 MeshData::VertexContainer vertices;
535 MeshData::FaceIndices faces;
537 MeshData::Vertex vertex;
539 for ( uint32_t v = 0; v < vc1; ++v )
541 vertices.push_back( v1[ v ] );
544 for ( uint32_t v = 0; v < vc2; ++v )
546 vertices.push_back( v2[ v ] );
549 for ( uint32_t f = 0; f < f1.size(); ++f )
551 faces.push_back( f1[ f ] );
554 for ( uint32_t f = 0; f < f2.size(); ++f )
556 faces.push_back( f2[ f ] + vc1 );
561 MeshData::VertexContainer optimizedVertices;
562 OptimizeVertices( vertices, faces, optimizedVertices );
563 out.SetVertices( optimizedVertices );
567 out.SetVertices( vertices );
570 out.SetMaterial( first.GetMaterial() );
571 out.SetFaceIndices( faces );
574 void AtlasManager::UploadImage( const BufferImage& image,
575 const AtlasSlotDescriptor& desc )
577 // Get the atlas to upload the image to
578 SizeType atlas = desc.mAtlasId - 1u;
580 // Check to see that the pixel formats are compatible
581 if ( image.GetPixelFormat() != mAtlasList[ atlas ].mPixelFormat )
583 DALI_LOG_ERROR("Cannot upload an image with a different PixelFormat to the Atlas.\n");
587 SizeType atlasBlockWidth = mAtlasList[ atlas ].mSize.mBlockWidth;
588 SizeType atlasBlockHeight = mAtlasList[ atlas ].mSize.mBlockHeight;
589 SizeType atlasWidthInBlocks = mAtlasList[ atlas ].mSize.mWidth / mAtlasList[ atlas ].mSize.mBlockWidth;
591 SizeType block = desc.mBlocksList[ 0 ];
592 SizeType blockX = block % atlasWidthInBlocks;
593 SizeType blockY = block / atlasWidthInBlocks;
594 SizeType blockOffsetX = blockX * atlasBlockWidth;
595 SizeType blockOffsetY = blockY * atlasBlockHeight;
597 SizeType width = image.GetWidth();
598 SizeType height = image.GetHeight();
600 // Blit image 1 pixel to the right and down into the block to compensate for texture filtering
601 if ( !mAtlasList[ atlas ].mAtlas.Upload( image,
602 blockOffsetX + SINGLE_PIXEL_PADDING,
603 blockOffsetY + SINGLE_PIXEL_PADDING ) )
605 DALI_LOG_ERROR("Uploading image to Atlas Failed!.\n");
608 // If this is the first block then we need to keep the first pixel free for underline texture
613 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
617 DALI_LOG_ERROR("Uploading top strip to Atlas Failed!\n");
621 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
623 blockOffsetY + SINGLE_PIXEL_PADDING ) )
625 DALI_LOG_ERROR("Uploading left strip to Atlas Failed!\n");
630 if ( blockOffsetY + height + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mHeight )
632 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mHorizontalStrip,
634 blockOffsetY + height + SINGLE_PIXEL_PADDING ) )
636 DALI_LOG_ERROR("Uploading bottom strip to Atlas Failed!.\n");
641 if ( blockOffsetX + width + DOUBLE_PIXEL_PADDING <= mAtlasList[ atlas ].mSize.mWidth )
643 if ( !mAtlasList[ atlas ].mAtlas.Upload( mAtlasList[ atlas ].mVerticalStrip,
644 blockOffsetX + width + SINGLE_PIXEL_PADDING,
645 blockOffsetY + SINGLE_PIXEL_PADDING ) )
647 DALI_LOG_ERROR("Uploading right strip to Atlas Failed!.\n");
652 void AtlasManager::GenerateMeshData( ImageId id,
653 const Vector2& position,
656 // Read the atlas Id to use for this image
657 SizeType imageId = id - 1u;
658 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
659 SizeType width = mImageList[ imageId ].mImageWidth;
660 SizeType height = mImageList[ imageId ].mImageHeight;
662 SizeType widthInBlocks = width / mAtlasList[ atlas ].mSize.mBlockWidth;
663 if ( width % mAtlasList[ atlas ].mSize.mBlockWidth )
667 SizeType heightInBlocks = height / mAtlasList[ atlas ].mSize.mBlockHeight;
668 if ( height % mAtlasList[ atlas ].mSize.mBlockHeight )
673 CreateMesh( atlas, width, height, position, widthInBlocks, heightInBlocks, meshData, mImageList[ imageId ] );
675 // Mesh created so increase the reference count
676 mImageList[ imageId ].mCount++;
679 Dali::Atlas AtlasManager::GetAtlasContainer( AtlasId atlas ) const
682 if ( !atlas || atlas > mAtlasList.size( ) )
685 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
688 return mAtlasList[ atlas -1u ].mAtlas;
691 bool AtlasManager::Remove( ImageId id )
693 // Decrements the reference count of this image, and removes the blocks if zero.
694 SizeType imageId = id - 1u;
695 bool removed = false;
697 if ( id > mImageList.size() )
699 DALI_LOG_ERROR("Atlas was asked to free an invalid imageID: %i\n", id );
703 // If we attempt to free an image that is already freed then do nothing, other than log
704 if ( !mImageList[ imageId ].mCount )
706 DALI_LOG_ERROR("Atlas was asked to free an imageID: %i, that has already been freed!\n", id );
710 if ( 2u > --mImageList[ imageId ].mCount )
712 // 'Remove the blocks' from this image and add to the atlas' freelist
714 mImageList[ imageId ].mCount = 0;
715 SizeType atlas = mImageList[ imageId ].mAtlasId - 1u;
716 for ( uint32_t i = 0; i < mImageList[ imageId ].mBlocksList.Size(); ++i )
718 mAtlasList[ atlas ].mFreeBlocksList.PushBack( mImageList[ imageId ].mBlocksList[ i ] );
724 AtlasManager::AtlasId AtlasManager::GetAtlas( ImageId id ) const
726 if ( id && id <= mImageList.size() )
728 return mImageList[ id - 1u ].mAtlasId;
736 void AtlasManager::SetNewAtlasSize( const Toolkit::AtlasManager::AtlasSize& size )
738 mNewAtlasSize = size;
739 mNewAtlasSize.mBlockWidth += DOUBLE_PIXEL_PADDING;
740 mNewAtlasSize.mBlockHeight += DOUBLE_PIXEL_PADDING;
743 const Toolkit::AtlasManager::AtlasSize& AtlasManager::GetAtlasSize( AtlasId atlas )
745 if ( atlas && atlas-- <= mAtlasList.size() )
747 return mAtlasList[ atlas ].mSize;
752 AtlasManager::SizeType AtlasManager::GetFreeBlocks( AtlasId atlas ) const
754 if ( atlas && atlas <= mAtlasList.size() )
756 uint32_t index = atlas - 1u;
757 uint32_t width = mAtlasList[ index ].mSize.mWidth;
758 uint32_t height = mAtlasList[ index ].mSize.mHeight;
759 uint32_t blockWidth = mAtlasList[ index ].mSize.mBlockWidth;
760 uint32_t blockHeight = mAtlasList[ index ].mSize.mBlockHeight;
762 SizeType widthInBlocks = width / blockWidth;
763 SizeType heightInBlocks = height / blockHeight;
764 uint32_t blockCount = widthInBlocks * heightInBlocks;
766 // Check free previously unallocated blocks and any free blocks
767 if ( mAtlasList[ index ].mNextFreeBlock )
769 blockCount -= mAtlasList[ index ].mNextFreeBlock -1u - mAtlasList[ index ].mFreeBlocksList.Size();
773 blockCount = mAtlasList[ index ].mFreeBlocksList.Size();
783 AtlasManager::SizeType AtlasManager::GetAtlasCount() const
785 return mAtlasList.size();
788 Pixel::Format AtlasManager::GetPixelFormat( AtlasId atlas )
790 if ( !atlas || atlas > mAtlasList.size( ) )
793 DALI_LOG_ERROR("Cannot get Atlas from AtlasID ( doesn't exist ).\n");
796 return mAtlasList[ atlas -1u ].mPixelFormat;
799 void AtlasManager::GetMetrics( Toolkit::AtlasManager::Metrics& metrics )
801 Toolkit::AtlasManager::AtlasMetricsEntry entry;
802 uint32_t textureMemoryUsed = 0;
803 uint32_t atlasCount = mAtlasList.size();
804 metrics.mAtlasCount = atlasCount;
805 metrics.mAtlasMetrics.Resize(0);
807 for ( uint32_t i = 0; i < atlasCount; ++i )
809 entry.mSize = mAtlasList[ i ].mSize;
810 entry.mTotalBlocks = ( entry.mSize.mWidth / entry.mSize.mBlockWidth ) * ( entry.mSize.mHeight / entry.mSize.mBlockHeight );
811 uint32_t reuseBlocks = mAtlasList[ i ].mFreeBlocksList.Size();
812 entry.mBlocksUsed = mAtlasList[ i ].mNextFreeBlock ? mAtlasList[ i ].mNextFreeBlock - reuseBlocks - 1u: entry.mTotalBlocks - reuseBlocks;
813 entry.mPixelFormat = GetPixelFormat( i + 1 );
815 metrics.mAtlasMetrics.PushBack( entry );
817 uint32_t size = entry.mSize.mWidth * entry.mSize.mHeight;
818 if ( entry.mPixelFormat == Pixel::BGRA8888 )
823 textureMemoryUsed += size;
826 metrics.mTextureMemoryUsed = textureMemoryUsed;
830 } // namespace Internal
832 } // namespace Toolkit