created a seperate page for performance-tips ( was hidden in performance profiling
before).
Also included the DALi exporter script for TexturePacker
Change-Id: I247be3d665ebd93ef6e70f88246346b98688dec2
* - \link resource-tracking Resource Tracking \endlink
* - \link performance-profiling Performance Profiling \endlink
*
-*/
+ * \section Performance
+ * - \link performance-tips Performance Tips \endlink
+ * - \link texture-atlases Texture Atlases \endlink
+ * - \link Texture_Compression Compressing Textures \endlink
+ *
+ */
/*! \page scene-graph
*
* <h2 class="pg">Background</h2>
* The Dali rendering pipeline has 2 stages.
* Each stage is typically run once per frame.
- *
- * <ul>
- * <li> 1. Update
+ * <h3> 1. Update </h3>
* <ul>
- * <li> Run animations
- * <li> Run constraints
- * <li> Run physics
- * <li> Update the scene-graph
+ * <li> Run animations</li>
+ * <li> Run constraints</li>
+ * <li> Run physics</li>
+ * <li> Update the scene-graph</li>
* </ul>
- * <li> 2. Render
+ * <h3> 2. Render </h3>
* <ul>
- * <li> Upload 3D data using OpenGL ( textures, vertex buffers etc).
- * <li> Draw the scene using OpenGL
- * </ul>
+ * <li> Upload 3D data using OpenGL ( textures, vertex buffers etc).</li>
+ * <li> Draw the scene using OpenGL</li>
* </ul>
*
+ *
* To run at 60 FPS (16 milliseconds per frame), it is recommended to stay below the following times:
* <ul>
- * <li> Update: 4 milliseconds
- * <li> Render: 4 milliseconds
+ * <li> Update: 4 milliseconds</li>
+ * <li> Render: 4 milliseconds</li>
* </ul>
*
* This will leave enough time for the output to be composited (if the system uses a compositor) and to avoid using
* If nothing is animating Dali will enter a paused state to save power. At this
* point nothing will be logged.
*
- * <h2 class="pg">Performance advice </h2>
- *
- *
- * <h3> Tips to reduce update times: </h3>
- * <ul>
- * <li> Keep the actor count as small as possible.
- * <ul>
- * <li> Less actors == less processing
- * <li> Try to keep invisible or un-used actors off the stage. Don't have hidden views on the stage.
- * </ul>
- * <li> Ensure constraints are kept as simple as possible
- * </ul>
- *
- * <h3> Tips to reduce render times: </h3>
- *
- * <ul>
- * <li> Keep the visible actor count as small as possible == less draw calls
- * <li> If using a fixed set of images, try pre-generating a texture-atlas.
- * <ul>
- * <li> For each image within the Atlas, use ImageActor.SetPixelArea() to use it.
- * <li> This reduces texture state changes when rendering.
- * </ul>
- * <li> Try to use 9-patch when you need to stretch an image while maintaining the border size.
- * <ul>
- * <li> See ImageActor::STYLE_NINE_PATCH
- * </ul>
- * <li> When using layers try to disable the depth test to avoid the depth buffer being cleared.
- * <li> If writing custom shaders, try to keep them as simple as possible.
- * <li> Try to keep texture sizes as small as possible.
- * </ul>
*
* <h2 class="pg">Application profiling</h2>
*
* <li> DALI_RENDER_END. Dali render task has finished
* </ul>
*
- * <h3> Checking ftrace is working on Tizen</h3>
+ * <h3> Checking ftrace is working on Linux</h3>
*
* Documentation for ftrace:
* Follow these instructions to ensure the debugfs has been mounted, and the kernel you are using
--- /dev/null
+/*! \page performance-tips Performance Tips
+
+
+<table>
+ <tr>
+ <th>High CPU occupancy <br></th>
+ </tr>
+ <tr>
+ <td>
+ - Try to reduce actor count ( less actors == less processing) <br>
+ - Delete any actors that are not visible, or move them off stage <br>
+ - Use TextureAtlases ( greatly reduces OpenGL driver calls to glBindTexture <br>
+ - Optimise / reduce any constraints used
+ </td>
+ </tr>
+</table>
+<br><br>
+<table>
+ <tr>
+ <th>High GPU occupancy <br></th>
+ </tr>
+ <tr>
+ <td>
+ - Reduce visible actor count ( == less draw calls) <br>
+ - For 2D UI graphics which require no z sorting use @code Actor::SetDrawMode( DrawMode::OVERLAY );
+// In this mode depth testing is turned off and order is determined by the hierachy (depth-first search order).
+ @endcode
+ - Use TextureAtlases ( reduces state changes in the GPU) <br>
+ - Use compressed textures
+ - Use lower quality textures, e.g. smaller, lower number of bits per pixel
+ - Use Dali::NinePatchImage where possible.
+ - Avoid using too many textures which contain alpha and require blending
+ - Avoid using too many Dali::Layer with depth testing enabled. Otherwise the layer has to clear the depth buffer.
+ - Optimise any shaders used. Pixel shaders should be kept as lean as possible.
+ </td>
+ </tr>
+</table>
+
+ */
--- /dev/null
+/*! \page texture-atlases Texture Atlases
+ *
+ * <h2 class="pg">Using Texture Atlases in DALi </h2>
+ *
+ *
+ * <h3> Example demo application </h3>
+
+ \image html image-wall.jpg
+
+
+<h3> Application above is running slow as there are many small individual images displayed (50)</h3>
+
+<table>
+ <tr>
+ <td> Launch Time </td>
+ <td> Slow </td>
+ <td> Has to perform: <br>- 50 file open requests and multiple reads for each image</td>
+ </tr>
+ <tr>
+ <td> Memory Usage </td>
+ <td> High </td>
+ <td> Has to create:
+ <br>- 50 Dali::Image objects
+ <br>- 50 OpenGL Textures
+ </td>
+ </tr>
+ <tr>
+ <td>Rendering Performance </td>
+ <td> Slow </td>
+ <td> Has to perform:
+ <br>- 50 glBindTexture calls per frame ( each OpenGL calls takes time)
+ <br>- 50 a frame = 3000 calls per second @60 FPS.
+ <br>- Texture switching is a major state change in the GPU
+ </td>
+ </tr>
+</table>
+<br><br>
+
+
+* <h3> Solutions to problem: Use a Texture Atlas</h3>
+
+A texture atlas is simply one larger image that contains smaller images. A texture atlas is sometimes called a
+sprite sheet, bitmap sheet or texture pack.
+
+ \image html atlas.jpg
+
+<br>
+Dali::ImageActor has the ability to display a portion of an image using ImageActor::PixelArea setting.
+For example to display the first 3 image in the atlas
+
+ \image html example-code.jpg
+
+<h3> Result of using an Atlas</h3>
+<table>
+ <tr>
+ <td> Launch Time </td>
+ <td> Fast </td>
+ <td> Has to perform: <br>- 1 file open request </td>
+ </tr>
+ <tr>
+ <td> Memory Usage </td>
+ <td> Better </td>
+ <td> Has to create:
+ <br>- 1 Dali::Image objects
+ <br>- 1 OpenGL Textures
+ </td>
+ </tr>
+ <tr>
+ <td>Rendering Performance </td>
+ <td> Fast </td>
+ <td> Has to perform:
+ <br>- 1 glBindTexture calls per frame ( each OpenGL calls takes time)
+ <br>- 1 a frame = 6- calls per second @60 FPS.
+ </td>
+ </tr>
+</table>
+<br>
+<h2> Atlas creation guide </h2>
+
+Many tools exist for creating texture atlases.<br>
+In the following example we are using a tool called TexturePacker as DALi has an exporter script for it.
+The exporter automatically generates a source file that has the ImageActor::PixelArea pre-defined.
+<br>
+<ul>
+ <li> Download http://www.codeandweb.com/texturepacker </li>
+ <li> Launch TexturePacker </li>
+ <li> Go to the menu File -> Preferences</li>
+ <li> Set the "Exporter directory" to be the location of dali-toolkit/texture-atlas-exporter <br></li>
+ \image html texture-packer-preferences.jpg
+ <br>
+ <li> <b> Restart the application! </b></li>
+ <li> Select DALi 3D framework for new project</li>
+ <br>
+ \image html texture-packer-startup.jpg
+ <br>
+ <li><h3> Create the atlas </h3> <br></li>
+ \image html texture-packer-add-sprites.jpg <br><br>
+ <li><h3> Click publish to produce the files </h3></li><br><br>
+ \image html texture-packer-publish.jpg <br><br>
+</ul>
+<h2> Using the generated cpp file </h2>
+
+The generated cpp file contains 3 different ways of describing the atlas. <br>
+Copy and paste the section that best suits your application.
+<ul><li> Lookup table. Includes code for storing the table in a std::map for fast lookup.</li>
+<li> constants. </li>
+<li> JavaScript property map ( see the Dali JavaScript programming guide on how to use it).
+</ul>
+<h3> Using the lookup table </h3>
+
+Cut and paste the lookup table code into your application.
+
+\code
+
+\\ The following code is automatically generated.
+\\
+const char* ATLAS_FILE_NAME( "my_first_atlas.png" ); ///< Atlas image filename
+
+/**
+ * Structure to hold image name and position within the atlas.
+ *
+ */
+struct ImageInfo
+{
+ const char* name;
+ unsigned int x,y,w,h;
+ Dali::BlendingMode::Type blendMode; // only enable blending if image has alpha
+};
+
+/**
+ * lookup table
+ */
+const ImageInfo ImageAtlas[]=
+{
+ { "blocks-ball", 2, 198, 51, 51, BlendingMode::ON },
+ { "bubble-ball", 288, 74, 32, 32, BlendingMode::ON },
+ { "gallery-small-52", 2, 2, 128, 128, BlendingMode::OFF },
+ { "icon-change", 219, 2, 37, 34, BlendingMode::ON },
+ { "icon-cluster-carousel", 180, 2, 37, 34, BlendingMode::ON }
+};
+
+const ImageInfo* GetImageInfo(const char* name)
+{
+ typedef std::map< const char*, const ImageInfo* > LookupMap;
+ static LookupMap lookup;
+ if( lookup.empty() )
+ {
+ for( unsigned int i = 0; i < ATLAS_IMAGE_COUNT; ++i)
+ {
+ lookup[ ImageAtlas[i].name ] = &ImageAtlas[i];
+ }
+ }
+ LookupMap::const_iterator iter = lookup.find(name);
+ if( iter != lookup.end() )
+ {
+ return (*iter).second;
+ }
+ DALI_ASSERT_ALWAYS(0 && "image name not found in atlas");
+ return NULL;
+}
+
+\endcode
+
+To use the lookup table you can do something like this:
+\code
+
+// Example function on how to get an image info from the table
+
+std::string fileName = std::string( DALI_IMAGE_DIR ) + ATLAS_FILE_NAME;
+Image imageImage = Image::New( fileName );
+
+const ImageInfo* info(NULL);
+
+info = GetImageInfo("blocks-ball");
+if( info)
+{
+ ImageActor ballActor = ImageActor::New( imageAtlas, ImageActor::PixelArea( info->x, info->y, info->w, info->h) );
+ ballActor->SetBlendMode( info->blendMode );
+}
+info = GetImageInfo("bubble-ball");
+if( info)
+{
+ ImageActor bubbleActor = ImageActor::New( imageAtlas, ImageActor::PixelArea( info->x, info->y, info->w, info->h) );
+ bubbleActor->SetBlendMode( info->blendMode );
+}
+
+\endcode
+<h3> Using the constant definitions </h3>
+
+1. Cut and paste the constant definition code into your application.
+
+You'll notice the code below won't compile because C++ variables can't have a dash character.<br>
+E.g. BLOCKS-BALL, BUBBLE-BALL will cause errors. Do a search and replace for - and replace with underscores.
+This is one reason why using lookup table which holds the filename as a string maybe easier to use.
+
+\code
+\\ The following code is automatically generated.
+\\
+const char* ATLAS_FILE_NAME( "my_first_atlas.png" );
+
+/**
+ * Structure to hold position / blend mode within the atlas.
+ *
+ */
+struct ImageInfo
+{
+ ImageInfo(unsigned int x,unsigned int y,unsigned int w,unsigned int h, Dali::BlendingMode::Type mode)
+ :pixelArea(x,y,w,h),blendMode(mode)
+ {}
+ ImageActor::PixelArea pixelArea;
+ Dali::BlendingMode::Type blendMode; // only enable blending if image has alpha
+};
+
+
+const ImageInfo BLOCKS-BALL( 2, 198, 51, 51 ,BlendingMode::ON );
+const ImageInfo BUBBLE-BALL( 288, 74, 32, 32 ,BlendingMode::ON );
+const ImageInfo GALLERY-SMALL-52( 2, 2, 128, 128 ,BlendingMode::OFF );
+\endcode
+
+2. To use it, you can copy example code from the generated cpp file which looks
+like this
+\code
+void LoadAtlasImages()
+{
+ std::string fileName = std::string(DALI_IMAGE_DIR) + ATLAS_FILE_NAME;
+ Image atlasImage = Image::New( fileName );
+ ImageActor Blocksball = ImageActor::New( atlasImage, BLOCKS_BALL.pixelArea);
+ Blocksball.SetBlendMode( BLOCKS_BALL.blendMode );
+
+ ImageActor Bubbleball = ImageActor::New( atlasImage, BUBBLE_BALL.pixelArea);
+ Bubbleball.SetBlendMode( BUBBLE_BALL.blendMode );
+ ...
+ \endcode
+
+
+
+<br><br>
+<h2> Atlas creation tips </h2>
+
+<ul>
+ <li> Compress the atlas - \link Texture_Compression Compressing Textures \endlink <br></li>
+ <li> Avoid adding large images to the Atlas.<br>
+ E.g. don't add background images to it. Medium to large images should
+ be kept seperate. <br><br>
+ \image html atlas-size.jpg
+ <br><br>
+ </li>
+ <li> Try to ensure the atlas contains only images that are frequently used. <br>
+ There's no point in having images taking up GPU texture memory if they're not displayed.<br>
+ </li>
+ <li> Avoid very large atlases <br>
+ Try to create multiple atlases based on how they are used within your application.<br>
+ <br>
+ Alternatively Texture packer has the option to split atlases ( search help for Multipack)
+ </li>
+</ul>
+
+
+
+ */
+
--- /dev/null
+
+/*! \page Texture_Compression Texture Compression
+
+
+Using compressing the textures will:
+<ul>
+<li> Speed up rendering in time the GPU == less power used due to less texture data being transferred.
+<li> Reduce texture memory usage.
+<li> Speed up load times. Smaller files mean quicker load times.
+</ul>
+<br><br>
+DALi supports the KTX file format.
+You just load the compressed texture like you would any other image.
+\code
+Image::New("my_compressed_file.ktx");
+\endcode
+<br>
+ARMS texture compression tool<br>
+http://malideveloper.arm.com/develop-for-mali/tools/asset-creation/mali-gpu-texture-compression-tool/ <br>
+
+Here is an example of using the ARM compression tool.
+\image html compression-options.jpg
+
+<br><br>
+
+\image html compression-example.jpg
+<br>
+<br>
+As shown above the ETC-1 compression format does not support alpha.<br> As a work around the tool will export
+the alpha as a seperate compressed image.<br>
+In order to combine both the images you need to use a custom shader.<br>
+Here is an example shader:<br>
+\code
+ const char* const COMPRESSED_RGB_PLUS_SEPARATE_ALPHA_FRAGMENT_SOURCE =
+ "\n"
+ "void main()\n"
+ "{\n"
+ " vec4 v4Color = (texture2D(sTexture, vTexCoord) * uColor);\n"
+ " v4Color.a = texture2D(sEffect, vTexCoord ).r;\n"
+ " gl_FragColor = v4Color;"
+ "}\n";
+
+
+ mShaderEffect = ShaderEffect::New( "", COMPRESSED_RGB_PLUS_SEPARATE_ALPHA_FRAGMENT_SOURCE);
+
+ mAtlasImageRGB = Image::New( ATLAS_RGB_FILENAME.KTX);
+
+ mAtlasImageAlpha = Image::New( ATLAS_ALPHA_FILENAME.KTX );
+
+ mShaderEffect.SetEffectImage( mAtlasImageAlpha );
+
+
+
+ // to create Image Actor
+ ImageActor imageActor = ImageActor::New( mAtlasImageRGB, GetImagePosition( info) );
+
+ imageActor.SetShaderEffect( mShaderEffect );
+
+ imageActor.SetBlendMode(BlendingMode::ON);
+
+\endcode
+
+
+ */
--- /dev/null
+// Created with TexturePacker (http://www.codeandweb.com/texturepacker)
+// DALi Exporter: nick.holland@partner.samsung.com
+//
+// {{smartUpdateKey}}
+
+// For your application cut and paste either:
+//
+// 1. Lookup table.
+// 2. Constants.
+// 3. JavaScript property map for using with DALi JS.
+
+// Note: If you use one option, then delete code for the other two
+
+
+
+
+//
+// 1. ------ lookup table method ------
+//
+// Handy if you want to get image with a postfix, e.g. image_1, image_2, image_3
+// Or if some of the image names contain special characters which are not allowed
+// in constant definitions ( e.g. spaces and full stops).
+
+
+const char* ATLAS_FILE_NAME( "{{texture.fullName}}" ); ///< Atlas image filename
+
+
+/**
+ * Structure to hold image name and position within the atlas.
+ *
+ */
+struct ImageInfo
+{
+ const char* name;
+ unsigned int x,y,w,h;
+ Dali::BlendingMode::Type blendMode; // only enable blending if image has alpha
+};
+
+/**
+ * lookup table
+ */
+const ImageInfo ImageAtlas[]=
+{
+{% for sprite in allSprites %} { "{{sprite.trimmedName}}", {{sprite.frameRect.x}}, {{sprite.frameRect.y}}, {{sprite.frameRect.width}}, {{sprite.frameRect.height}}, {%if sprite.isSolid %}BlendingMode::OFF{% else%}BlendingMode::ON{% endif %} }{% if not forloop.last %},{% endif %}
+{% endfor %}
+};
+
+const unsigned int ATLAS_IMAGE_COUNT = sizeof(ImageAtlas)/sizeof(ImageAtlas[0]);
+
+// Example function on how to get an image info from the table
+//
+// std::string fileName = std::string( DALI_IMAGE_DIR ) + ATLAS_FILE_NAME;
+// Image imageAtlas = Image::New( fileName );
+//
+//
+// const ImageInfo* info = GetImageInfo("left_icon");
+//
+// if( info)
+// {
+// ImageActor myActor = ImageActor::New( imageAtlas, ImageActor::PixelArea( info->x, info->y, info->w, info->h) );
+// myActor->SetBlendMode( info->blendMode );
+//
+//
+
+const ImageInfo* GetImageInfo(const char* name)
+{
+ typedef std::map< const char*, const ImageInfo* > LookupMap;
+ static LookupMap lookup;
+ if( lookup.empty() )
+ {
+ for( unsigned int i = 0; i < ATLAS_IMAGE_COUNT; ++i)
+ {
+ lookup[ ImageAtlas[i].name ] = &ImageAtlas[i];
+ }
+ }
+ LookupMap::const_iterator iter = lookup.find(name);
+ if( iter != lookup.end() )
+ {
+ return (*iter).second;
+ }
+ DALI_ASSERT_ALWAYS(0 && "image name not found in atlas");
+ return NULL;
+}
+
+//
+//
+// 2. ------ constants code ------
+//
+//
+
+const char* ATLAS_FILE_NAME( "{{texture.fullName}}" );
+
+/**
+ * Structure to hold position / blend mode within the atlas.
+ *
+ */
+struct ImageInfo
+{
+ ImageInfo(unsigned int x,unsigned int y,unsigned int w,unsigned int h, Dali::BlendingMode::Type mode)
+ :pixelArea(x,y,w,h),blendMode(mode)
+ {}
+ ImageActor::PixelArea pixelArea;
+ Dali::BlendingMode::Type blendMode; // only enable blending if image had alpha
+};
+
+{% for sprite in allSprites %}const ImageInfo {{ sprite.trimmedName|upper}}( {{sprite.frameRect.x}}, {{sprite.frameRect.y}}, {{sprite.frameRect.width}}, {{sprite.frameRect.height}} ,{%if sprite.isSolid %}BlendingMode::OFF{% else%}BlendingMode::ON{% endif %} );
+{% endfor %}
+
+
+// Example on using the Atlas, please delete this code.
+void LoadAtlasImages()
+{
+ std::string fileName = std::string(DALI_IMAGE_DIR) + ATLAS_FILE_NAME;
+ Image atlasImage = Image::New( fileName );
+ {% for sprite in allSprites %}ImageActor {{sprite.trimmedName|capfirst}} = ImageActor::New( atlasImage, {{sprite.trimmedName|upper}}.pixelArea);
+ {{sprite.trimmedName|capfirst}}.SetBlendMode( {{sprite.trimmedName|upper}}.blendMode );
+
+ {% endfor %}
+}
+
+//
+//
+// 3. ------ JavaScript key/value lookup table ------
+//
+//
+//
+
+ATLAS_IMAGE_LIST : [
+{% for sprite in allSprites %} { name: "{{sprite.trimmedName}}", x: {{sprite.frameRect.x}}, y:{{sprite.frameRect.y}}, w:{{sprite.frameRect.width}}, h:{{sprite.frameRect.height}}, {%if sprite.isSolid %}dali.BLENDING_OFF{% else%}dali.BLENDING_ON{% endif %} }{% if not forloop.last %},{% endif %}
+{% endfor %}
+]
\ No newline at end of file
--- /dev/null
+<exporter version="1.0">
+ <!-- identifier of the exporter -->
+ <name>dali_exporter</name>
+
+ <!-- display name of the exporter for the combo box -->
+ <displayName>DALi 3D</displayName>
+
+ <!-- description of the exporter -->
+ <description>DALi 3D exporter for TexturePacker</description>
+
+ <!-- exporter version -->
+ <version>1.0</version>
+
+ <!-- currently only one file allowed - more to come soon -->
+ <files>
+ <file>
+ <!-- name of this file variable -->
+ <name>maintext</name>
+
+ <!-- human readable name (for GUI) -->
+ <displayName>.cpp file</displayName>
+
+ <!-- file extension for the file -->
+ <fileExtension>cpp</fileExtension>
+
+ <!-- name of the template file -->
+ <template>dali3d_exporter.cpp</template>
+ </file>
+ </files>
+
+ <!-- target framework supports trimming -->
+ <supportsTrimming>no</supportsTrimming>
+
+ <!-- target framework supports rotated sprites -->
+ <supportsRotation>no</supportsRotation>
+
+ <!-- supports npot sizes -->
+ <supportsNPOT>yes</supportsNPOT>
+
+ <!-- supports file name stripping (remove .png etc.) -->
+ <supportsTrimSpriteNames>yes</supportsTrimSpriteNames>
+
+ <!-- supports texture subpath -->
+ <supportsTextureSubPath>yes</supportsTextureSubPath>
+</exporter>
\ No newline at end of file