From: Nick Holland Date: Wed, 17 Sep 2014 13:53:05 +0000 (+0100) Subject: Added documentation on texture-atlas creation, texture-compression and X-Git-Tag: accepted/tizen/common/20140925.172059~11 X-Git-Url: http://review.tizen.org/git/?p=platform%2Fcore%2Fuifw%2Fdali-toolkit.git;a=commitdiff_plain;h=refs%2Fchanges%2F00%2F27700%2F8 Added documentation on texture-atlas creation, texture-compression and created a seperate page for performance-tips ( was hidden in performance profiling before). Also included the DALi exporter script for TexturePacker Change-Id: I247be3d665ebd93ef6e70f88246346b98688dec2 --- diff --git a/docs/content/images/texture-atlas/atlas-size.jpg b/docs/content/images/texture-atlas/atlas-size.jpg new file mode 100644 index 0000000..084278d Binary files /dev/null and b/docs/content/images/texture-atlas/atlas-size.jpg differ diff --git a/docs/content/images/texture-atlas/atlas.jpg b/docs/content/images/texture-atlas/atlas.jpg new file mode 100644 index 0000000..d2e03b2 Binary files /dev/null and b/docs/content/images/texture-atlas/atlas.jpg differ diff --git a/docs/content/images/texture-atlas/compression-example.jpg b/docs/content/images/texture-atlas/compression-example.jpg new file mode 100644 index 0000000..474c572 Binary files /dev/null and b/docs/content/images/texture-atlas/compression-example.jpg differ diff --git a/docs/content/images/texture-atlas/compression-options.jpg b/docs/content/images/texture-atlas/compression-options.jpg new file mode 100644 index 0000000..1540315 Binary files /dev/null and b/docs/content/images/texture-atlas/compression-options.jpg differ diff --git a/docs/content/images/texture-atlas/example-code.jpg b/docs/content/images/texture-atlas/example-code.jpg new file mode 100644 index 0000000..4e2b576 Binary files /dev/null and b/docs/content/images/texture-atlas/example-code.jpg differ diff --git a/docs/content/images/texture-atlas/image-wall.jpg b/docs/content/images/texture-atlas/image-wall.jpg new file mode 100644 index 0000000..f06d258 Binary files /dev/null and b/docs/content/images/texture-atlas/image-wall.jpg differ diff --git a/docs/content/images/texture-atlas/texture-packer-add-sprites.jpg b/docs/content/images/texture-atlas/texture-packer-add-sprites.jpg new file mode 100644 index 0000000..67b65e7 Binary files /dev/null and b/docs/content/images/texture-atlas/texture-packer-add-sprites.jpg differ diff --git a/docs/content/images/texture-atlas/texture-packer-preferences.jpg b/docs/content/images/texture-atlas/texture-packer-preferences.jpg new file mode 100644 index 0000000..fa0b067 Binary files /dev/null and b/docs/content/images/texture-atlas/texture-packer-preferences.jpg differ diff --git a/docs/content/images/texture-atlas/texture-packer-publish.jpg b/docs/content/images/texture-atlas/texture-packer-publish.jpg new file mode 100644 index 0000000..e1564b0 Binary files /dev/null and b/docs/content/images/texture-atlas/texture-packer-publish.jpg differ diff --git a/docs/content/images/texture-atlas/texture-packer-startup.jpg b/docs/content/images/texture-atlas/texture-packer-startup.jpg new file mode 100644 index 0000000..5ed29b5 Binary files /dev/null and b/docs/content/images/texture-atlas/texture-packer-startup.jpg differ diff --git a/docs/content/main-page.h b/docs/content/main-page.h index 53851e3..61619dd 100644 --- a/docs/content/main-page.h +++ b/docs/content/main-page.h @@ -64,7 +64,12 @@ * - \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 * diff --git a/docs/content/programming-guide/performance-profiling.h b/docs/content/programming-guide/performance-profiling.h index d95a60d..c4a1d98 100644 --- a/docs/content/programming-guide/performance-profiling.h +++ b/docs/content/programming-guide/performance-profiling.h @@ -18,26 +18,24 @@ *

Background

* The Dali rendering pipeline has 2 stages. * Each stage is typically run once per frame. - * - * * + * * To run at 60 FPS (16 milliseconds per frame), it is recommended to stay below the following times: * * * This will leave enough time for the output to be composited (if the system uses a compositor) and to avoid using @@ -60,36 +58,6 @@ * If nothing is animating Dali will enter a paused state to save power. At this * point nothing will be logged. * - *

Performance advice

- * - * - *

Tips to reduce update times:

- * - * - *

Tips to reduce render times:

- * - * * *

Application profiling

* @@ -136,7 +104,7 @@ *
  • DALI_RENDER_END. Dali render task has finished * * - *

    Checking ftrace is working on Tizen

    + *

    Checking ftrace is working on Linux

    * * Documentation for ftrace: * Follow these instructions to ensure the debugfs has been mounted, and the kernel you are using diff --git a/docs/content/programming-guide/performance-tips.h b/docs/content/programming-guide/performance-tips.h new file mode 100644 index 0000000..969054a --- /dev/null +++ b/docs/content/programming-guide/performance-tips.h @@ -0,0 +1,39 @@ +/*! \page performance-tips Performance Tips + + + + + + + + + +
    High CPU occupancy
    + - Try to reduce actor count ( less actors == less processing)
    + - Delete any actors that are not visible, or move them off stage
    + - Use TextureAtlases ( greatly reduces OpenGL driver calls to glBindTexture
    + - Optimise / reduce any constraints used +
    +

    + + + + + + + +
    High GPU occupancy
    + - Reduce visible actor count ( == less draw calls)
    + - 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)
    + - 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. +
    + + */ diff --git a/docs/content/programming-guide/texture-atlases.h b/docs/content/programming-guide/texture-atlases.h new file mode 100644 index 0000000..b664d3e --- /dev/null +++ b/docs/content/programming-guide/texture-atlases.h @@ -0,0 +1,261 @@ +/*! \page texture-atlases Texture Atlases + * + *

    Using Texture Atlases in DALi

    + * + * + *

    Example demo application

    + + \image html image-wall.jpg + + +

    Application above is running slow as there are many small individual images displayed (50)

    + + + + + + + + + + + + + + + + + +
    Launch Time Slow Has to perform:
    - 50 file open requests and multiple reads for each image
    Memory Usage High Has to create: +
    - 50 Dali::Image objects +
    - 50 OpenGL Textures +
    Rendering Performance Slow Has to perform: +
    - 50 glBindTexture calls per frame ( each OpenGL calls takes time) +
    - 50 a frame = 3000 calls per second @60 FPS. +
    - Texture switching is a major state change in the GPU +
    +

    + + +*

    Solutions to problem: Use a Texture Atlas

    + +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 + +
    +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 + +

    Result of using an Atlas

    + + + + + + + + + + + + + + + + +
    Launch Time Fast Has to perform:
    - 1 file open request
    Memory Usage Better Has to create: +
    - 1 Dali::Image objects +
    - 1 OpenGL Textures +
    Rendering Performance Fast Has to perform: +
    - 1 glBindTexture calls per frame ( each OpenGL calls takes time) +
    - 1 a frame = 6- calls per second @60 FPS. +
    +
    +

    Atlas creation guide

    + +Many tools exist for creating texture atlases.
    +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. +
    + +

    Using the generated cpp file

    + +The generated cpp file contains 3 different ways of describing the atlas.
    +Copy and paste the section that best suits your application. + +

    Using the lookup table

    + +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 +

    Using the constant definitions

    + +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.
    +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 + + + +

    +

    Atlas creation tips

    + + + + + + */ + diff --git a/docs/content/programming-guide/texture-compression.h b/docs/content/programming-guide/texture-compression.h new file mode 100644 index 0000000..62f4577 --- /dev/null +++ b/docs/content/programming-guide/texture-compression.h @@ -0,0 +1,64 @@ + +/*! \page Texture_Compression Texture Compression + + +Using compressing the textures will: + +

    +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 +
    +ARMS texture compression tool
    +http://malideveloper.arm.com/develop-for-mali/tools/asset-creation/mali-gpu-texture-compression-tool/
    + +Here is an example of using the ARM compression tool. +\image html compression-options.jpg + +

    + +\image html compression-example.jpg +
    +
    +As shown above the ETC-1 compression format does not support alpha.
    As a work around the tool will export +the alpha as a seperate compressed image.
    +In order to combine both the images you need to use a custom shader.
    +Here is an example shader:
    +\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 + + + */ diff --git a/texture-atlas-exporter/dali-exporter/dali3d_exporter.cpp b/texture-atlas-exporter/dali-exporter/dali3d_exporter.cpp new file mode 100755 index 0000000..ac505ef --- /dev/null +++ b/texture-atlas-exporter/dali-exporter/dali3d_exporter.cpp @@ -0,0 +1,131 @@ +// 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 diff --git a/texture-atlas-exporter/dali-exporter/exporter.xml b/texture-atlas-exporter/dali-exporter/exporter.xml new file mode 100755 index 0000000..bb9cbcd --- /dev/null +++ b/texture-atlas-exporter/dali-exporter/exporter.xml @@ -0,0 +1,45 @@ + + + dali_exporter + + + DALi 3D + + + DALi 3D exporter for TexturePacker + + + 1.0 + + + + + + maintext + + + .cpp file + + + cpp + + + + + + + + no + + + no + + + yes + + + yes + + + yes + \ No newline at end of file