[3.0] Remove/move experimental features
[platform/core/uifw/dali-core.git] / dali / internal / event / images / atlas-impl.cpp
index f0a7af1..97ab217 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 // CLASS HEADER
 #include <dali/internal/event/images/atlas-impl.h>
 
+// EXTERNAL INCLUDES
+#include <cstring> // for memset()
+
 // INTERNAL INCLUDES
 #include <dali/public-api/object/type-registry.h>
 #include <dali/internal/event/common/thread-local-storage.h>
-#include <dali/internal/event/images/bitmap-image-impl.h>
+#include <dali/internal/event/images/image-factory.h>
+#include <dali/internal/event/images/bitmap-packed-pixel.h>
 #include <dali/internal/event/resources/resource-client.h>
 #include <dali/integration-api/bitmap.h>
+#include <dali/integration-api/platform-abstraction.h>
+
 
 namespace Dali
 {
@@ -36,29 +42,80 @@ namespace
 TypeRegistration mType( typeid( Dali::Atlas ), typeid( Dali::Image ), NULL );
 }
 
-Atlas* Atlas::New( std::size_t width,
-                   std::size_t height,
-                   Pixel::Format pixelFormat )
+Atlas* Atlas::New( SizeType width,
+                   SizeType height,
+                   Pixel::Format pixelFormat,
+                   bool recoverContext)
+{
+  return new Atlas( width, height, pixelFormat, recoverContext );
+}
+
+void Atlas::Clear(const Vector4& color)
 {
-  return new Atlas( width, height, pixelFormat );
+  ClearCache();
+  ClearBackground( color );
 }
 
-bool Atlas::Upload( const BitmapImage& bitmapImage,
-                    std::size_t xOffset,
-                    std::size_t yOffset )
+bool Atlas::Upload( BufferImage& bufferImage,
+                    SizeType xOffset,
+                    SizeType yOffset )
 {
   bool uploadSuccess( false );
 
-  AllocateAtlas();
+  if( IsInside( xOffset + bufferImage.GetWidth(),  yOffset + bufferImage.GetHeight() ) )
+  {
+    AllocateAtlas();
+    ResourceId destId = GetResourceId();
 
-  if( IsWithin(bitmapImage, xOffset, yOffset) )
+    if( destId )
+    {
+      bufferImage.UploadBitmap( destId, xOffset, yOffset );
+      uploadSuccess = true;
+    }
+  }
+
+  return uploadSuccess;
+}
+
+bool Atlas::Upload( const std::string& url,
+                    SizeType xOffset,
+                    SizeType yOffset)
+{
+  bool uploadSuccess( false );
+
+  Integration::BitmapPtr bitmap = LoadBitmap( url );
+
+  if( bitmap && IsInside( xOffset + bitmap->GetImageWidth(), yOffset + bitmap->GetImageHeight()) )
+  {
+    AllocateAtlas();
+    ResourceId destId = GetResourceId();
+    if( destId )
+    {
+      mResourceClient.UploadBitmap( destId, bitmap, xOffset, yOffset  );
+      uploadSuccess = true;
+
+      if( mRecoverContext )
+      {
+        mTiles.PushBack( new Tile(xOffset, yOffset, url) );
+      }
+    }
+  }
+  return uploadSuccess;
+}
+
+bool Atlas::Upload( PixelDataPtr pixelData,
+                    SizeType xOffset,
+                    SizeType yOffset )
+{
+  bool uploadSuccess( false );
+  if( IsInside( xOffset + pixelData->GetWidth(),  yOffset + pixelData->GetHeight() ) )
   {
+    AllocateAtlas();
     ResourceId destId = GetResourceId();
-    ResourceId srcId = bitmapImage.GetResourceId();
 
-    if( destId && srcId )
+    if( destId )
     {
-      mResourceClient.UploadBitmap( destId, srcId, xOffset, yOffset );
+      mResourceClient.UploadBitmap( destId, pixelData, xOffset, yOffset  );
       uploadSuccess = true;
     }
   }
@@ -66,16 +123,44 @@ bool Atlas::Upload( const BitmapImage& bitmapImage,
   return uploadSuccess;
 }
 
+void Atlas::RecoverFromContextLoss()
+{
+  ResourceId destId = GetResourceId();
+  if( destId )
+  {
+    if( mClear )
+    {
+      ClearBackground( mClearColor );
+    }
+
+    if( mRecoverContext )
+    {
+      // Restore the atlas by re-uploading the url resources
+      Vector< Tile* >::ConstIterator end = mTiles.End();
+      for( Vector<Tile*>::Iterator iter = mTiles.Begin(); iter != end; iter++ )
+      {
+        Integration::BitmapPtr bitmap = LoadBitmap( (*iter)->url );
+        mResourceClient.UploadBitmap( destId, bitmap, (*iter)->xOffset, (*iter)->yOffset  );
+      }
+    }
+  }
+}
+
 Atlas::~Atlas()
 {
   ReleaseAtlas();
 }
 
-Atlas::Atlas( std::size_t width,
-              std::size_t height,
-              Pixel::Format pixelFormat )
+Atlas::Atlas( SizeType width,
+              SizeType height,
+              Pixel::Format pixelFormat,
+              bool recoverContext )
 : mResourceClient( ThreadLocalStorage::Get().GetResourceClient() ),
-  mPixelFormat( pixelFormat )
+  mImageFactory( ThreadLocalStorage::Get().GetImageFactory() ),
+  mClearColor( Vector4::ZERO ),
+  mPixelFormat( pixelFormat ),
+  mClear( false ),
+  mRecoverContext( recoverContext )
 {
   mWidth  = width;
   mHeight = height;
@@ -97,43 +182,24 @@ void Atlas::Disconnect()
   {
     --mConnectionCount;
 
-    if ( Dali::Image::UNUSED == mReleasePolicy &&
-         mConnectionCount == 0 )
-    {
-      ReleaseAtlas();
-    }
+    // Only release the atlas upon destruction
   }
 }
 
-bool Atlas::IsWithin( const BitmapImage& bitmapImage,
-                      std::size_t xOffset,
-                      std::size_t yOffset )
+bool Atlas::IsInside( SizeType x, SizeType y )
 {
-  bool within(false);
+  bool fit(false);
 
-  if( mPixelFormat != bitmapImage.GetPixelFormat() )
+  if( x <= mWidth  && y <= mHeight )
   {
-    DALI_LOG_ERROR( "Pixel format %d does not match Atlas format %d\n", bitmapImage.GetPixelFormat(), mPixelFormat );
+    fit = true;
   }
   else
   {
-    const unsigned int width  = bitmapImage.GetWidth();
-    const unsigned int height = bitmapImage.GetHeight();
-
-    if( xOffset < mWidth  &&
-        yOffset < mHeight &&
-        xOffset+width  <= mWidth &&
-        yOffset+height <= mHeight )
-    {
-      within = true;
-    }
-    else
-    {
-      DALI_LOG_ERROR( "%dx%d image does not fit at offset %d,%d\n", width, height, xOffset, yOffset );
-    }
+    DALI_LOG_ERROR( "image does not fit within the atlas \n" );
   }
 
-  return within;
+  return fit;
 }
 
 void Atlas::AllocateAtlas()
@@ -141,12 +207,87 @@ void Atlas::AllocateAtlas()
   if( !mTicket )
   {
     mTicket = mResourceClient.AllocateTexture( mWidth, mHeight, mPixelFormat );
+    mTicket->AddObserver( *this );
+    mImageFactory.RegisterForContextRecovery( this );
   }
 }
 
 void Atlas::ReleaseAtlas()
 {
   mTicket.Reset();
+  ClearCache();
+  mImageFactory.UnregisterFromContextRecovery( this );
+}
+
+void Atlas::ClearBackground(const Vector4& color )
+{
+  AllocateAtlas();
+  ResourceId destId = GetResourceId();
+  if( destId )
+  {
+    const unsigned int numPixels = mWidth * mHeight;
+    unsigned int bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
+    BufferImagePtr imageData = BufferImage::New( mWidth, mHeight, mPixelFormat );
+    PixelBuffer* pixbuf = imageData->GetBuffer();
+
+    if( pixbuf )
+    {
+      // converting color value from float 0.f~1.f to byte 0~255
+      unsigned char r =  static_cast<unsigned char>( 255.f * Clamp( color.r, 0.f, 1.f ) );
+      unsigned char g =  static_cast<unsigned char>( 255.f * Clamp( color.g, 0.f, 1.f ) );
+      unsigned char b =  static_cast<unsigned char>( 255.f * Clamp( color.b, 0.f, 1.f ) );
+      unsigned char a =  static_cast<unsigned char>( 255.f * Clamp( color.a, 0.f, 1.f ) );
+      if( mPixelFormat == Pixel::RGBA8888 )
+      {
+        // For little-endian byte order, the RGBA channels needs to be reversed for bit shifting.
+        uint32_t clearColor = ( (uint32_t) a<<24 | (uint32_t)b << 16 | (uint32_t)g << 8 | (uint32_t)r );
+        uint32_t* buf = (uint32_t *) pixbuf;
+        for( unsigned int i = 0; i < numPixels; ++i )
+        {
+          buf[i] = clearColor;
+        }
+      }
+      else if( mPixelFormat == Pixel::RGB888 )
+      {
+        for( unsigned int i = 0; i < numPixels; ++i )
+        {
+          pixbuf[i*bytesPerPixel] = r;
+          pixbuf[i*bytesPerPixel+1] = g;
+          pixbuf[i*bytesPerPixel+2] = b;
+        }
+      }
+      else if( mPixelFormat == Pixel::A8 )
+      {
+        memset( pixbuf, a, numPixels );
+      }
+    }
+
+    mClearColor = color;
+    mClear = true;
+
+    imageData->UploadBitmap( destId, 0, 0 );
+  }
+}
+
+void Atlas::ClearCache()
+{
+  Vector< Tile* >::ConstIterator end = mTiles.End();
+  for( Vector<Tile*>::Iterator iter = mTiles.Begin(); iter != end; iter++ )
+  {
+    delete *iter;
+  }
+  mTiles.Clear();
+}
+
+Integration::BitmapPtr Atlas::LoadBitmap( const std::string& url )
+{
+  Integration::BitmapResourceType resourceType;
+  Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction();
+
+  Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously(resourceType, url);
+  Integration::BitmapPtr bitmap = static_cast<Integration::Bitmap*>( resource.Get());
+
+  return bitmap;
 }
 
 } // namespace Internal