Merge "BufferImage mirrors an external Pixel Buffer on creation." into devel/master
authorKimmo Hoikka <kimmo.hoikka@samsung.com>
Wed, 9 Sep 2015 14:24:14 +0000 (07:24 -0700)
committerGerrit Code Review <gerrit@review.vlan103.tizen.org>
Wed, 9 Sep 2015 14:24:14 +0000 (07:24 -0700)
15 files changed:
automated-tests/src/dali-devel/utc-Dali-Atlas.cpp
automated-tests/src/dali-internal/utc-Dali-Internal-ResourceClient.cpp
dali/integration-api/bitmap.cpp
dali/integration-api/bitmap.h
dali/integration-api/resource-policies.h
dali/internal/event/images/atlas-impl.cpp
dali/internal/event/images/buffer-image-impl.cpp
dali/internal/event/images/buffer-image-impl.h
dali/internal/event/images/nine-patch-image-impl.cpp
dali/internal/event/resources/resource-client.cpp
dali/internal/event/resources/resource-client.h
dali/internal/file.list
dali/internal/render/gl-resources/bitmap-texture.cpp
dali/internal/render/gl-resources/bitmap-texture.h
dali/internal/render/gl-resources/compressed-bitmap-texture.cpp

index ef83df1..7e033ab 100644 (file)
@@ -84,7 +84,7 @@ int UtcDaliAtlasUpload01(void)
   DALI_TEST_CHECK( atlas );
 
   // Using correct pixel format
-  PixelBuffer* buffer = new PixelBuffer[16 * 16];
+  PixelBuffer* buffer = new PixelBuffer[16 * 16 * 4];
   BufferImage image = BufferImage::New( buffer, 16, 16, Pixel::RGBA8888 );
   DALI_TEST_CHECK( atlas.Upload( image, 0, 0 ) );
 
@@ -122,7 +122,7 @@ int UtcDaliAtlasUpload03(void)
   DALI_TEST_CHECK( atlas );
 
   // Using image too big for atlas
-  PixelBuffer* buffer = new PixelBuffer[16 * 16];
+  PixelBuffer* buffer = new PixelBuffer[16 * 16 * 4];
   BufferImage image = BufferImage::New( buffer, 16, 16, Pixel::RGBA8888 );
   DALI_TEST_CHECK( !atlas.Upload( image, 0, 0 ) );
 
@@ -141,7 +141,7 @@ int UtcDaliAtlasUpload04(void)
   DALI_TEST_CHECK( atlas );
 
   // Using valid offsets
-  PixelBuffer* buffer = new PixelBuffer[16 * 16];
+  PixelBuffer* buffer = new PixelBuffer[16 * 16 * 4];
   BufferImage image = BufferImage::New( buffer, 16, 16, Pixel::RGBA8888 );
 
   DALI_TEST_CHECK( atlas.Upload( image,  0,  0 ) );
@@ -167,7 +167,7 @@ int UtcDaliAtlasUpload05(void)
   DALI_TEST_CHECK( atlas );
 
   // Using invalid offsets
-  PixelBuffer* buffer = new PixelBuffer[16 * 16];
+  PixelBuffer* buffer = new PixelBuffer[16 * 16 * 4];
   BufferImage image = BufferImage::New( buffer, 16, 16, Pixel::RGBA8888 );
 
   DALI_TEST_CHECK( !atlas.Upload( image,  0, 17 ) );
index 71855fc..f7adbb1 100644 (file)
@@ -723,40 +723,6 @@ int UtcDaliInternalRequestResourceTicket02(void)
   END_TEST;
 }
 
-int UtcDaliInternalAllocateBitmapImage01(void)
-{
-  TestApplication application;
-  tet_infoline("Testing AllocateBitmapImage()");
-  testTicketObserver.Reset();
-
-  Internal::ResourceClient& resourceClient  = Internal::ThreadLocalStorage::Get().GetResourceClient();
-  Internal::ImageTicketPtr imageTicket = resourceClient.AllocateBitmapImage(80, 80, 80, 80, Pixel::RGB565);
-  imageTicket->AddObserver( testTicketObserver );
-
-  DALI_TEST_CHECK( imageTicket );
-  DALI_TEST_EQUALS ( imageTicket->GetLoadingState(), ResourceLoadingSucceeded, TEST_LOCATION );
-  DALI_TEST_EQUALS ( imageTicket->GetWidth(), 80, TEST_LOCATION );
-  DALI_TEST_EQUALS ( imageTicket->GetHeight(), 80, TEST_LOCATION );
-
-  application.SendNotification(); // Flush update queue
-  application.Render(0); // Process message
-  application.SendNotification(); // Send message to tickets
-
-  DALI_TEST_CHECK ( 0 == testTicketObserver.LoadSucceededCalled() ); // Check no message was sent
-  DALI_TEST_EQUALS ( imageTicket->GetLoadingState(), ResourceLoadingSucceeded, TEST_LOCATION );
-  DALI_TEST_EQUALS ( imageTicket->GetWidth(), 80, TEST_LOCATION );
-  DALI_TEST_EQUALS ( imageTicket->GetHeight(), 80, TEST_LOCATION );
-
-  Integration::Bitmap* bitmap = resourceClient.GetBitmap(imageTicket);
-  DALI_TEST_CHECK ( bitmap != NULL );
-  DALI_TEST_EQUALS ( bitmap->GetImageWidth(), 80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetImageHeight(), 80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPackedPixelsProfile()->GetBufferWidth(), 80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPackedPixelsProfile()->GetBufferHeight(), 80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPixelFormat(), Pixel::RGB565, TEST_LOCATION );
-  END_TEST;
-}
-
 int UtcDaliInternalAddBitmapImage01(void)
 {
   TestApplication application;
@@ -782,15 +748,6 @@ int UtcDaliInternalAddBitmapImage01(void)
   DALI_TEST_EQUALS ( imageTicket->GetLoadingState(), ResourceLoadingSucceeded, TEST_LOCATION );
   DALI_TEST_EQUALS ( imageTicket->GetWidth(), 80, TEST_LOCATION );
   DALI_TEST_EQUALS ( imageTicket->GetHeight(), 80, TEST_LOCATION );
-
-  Integration::Bitmap* theBitmap = resourceClient.GetBitmap(imageTicket);
-  DALI_TEST_CHECK ( theBitmap != NULL );
-  DALI_TEST_CHECK ( bitmap == theBitmap );
-  DALI_TEST_EQUALS ( bitmap->GetImageWidth(), 80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetImageHeight(), 80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPackedPixelsProfile()->GetBufferWidth(), 80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPackedPixelsProfile()->GetBufferHeight(), 80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPixelFormat(), Pixel::RGB565, TEST_LOCATION );
   END_TEST;
 }
 
@@ -819,19 +776,6 @@ int UtcDaliInternalAddBitmapImage02(void)
   DALI_TEST_EQUALS ( imageTicket->GetWidth(), 0, TEST_LOCATION );
   DALI_TEST_EQUALS ( imageTicket->GetHeight(), 0, TEST_LOCATION );
   DALI_TEST_CHECK ( 0 == testTicketObserver.LoadSucceededCalled() ); // Check no message was sent
-
-  Integration::Bitmap* theBitmap = resourceClient.GetBitmap(imageTicket);
-  DALI_TEST_CHECK ( theBitmap != NULL );
-  DALI_TEST_CHECK ( bitmap == theBitmap );
-  DALI_TEST_EQUALS ( bitmap->GetImageWidth(), 0u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetImageHeight(), 0u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPackedPixelsProfile()->GetBufferWidth(), 0u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPackedPixelsProfile()->GetBufferHeight(), 0u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
-
-  // There is no way for the ticket's image attributes to be updated if the bitmap
-  // reserves a buffer after ticket generation.
-  // Probably not an issue - there is no public API in BufferImage to change the image size.
   END_TEST;
 }
 
@@ -858,77 +802,6 @@ int UtcDaliInternalAddBitmapImage03(void)
   END_TEST;
 }
 
-int UtcDaliInternalGetBitmapImage01(void)
-{
-  TestApplication application;
-  tet_infoline("Testing GetBitmap() with valid ticket");
-  testTicketObserver.Reset();
-
-  Internal::ResourceClient& resourceClient  = Internal::ThreadLocalStorage::Get().GetResourceClient();
-  Integration::Bitmap* bitmap = Integration::Bitmap::New( Integration::Bitmap::BITMAP_2D_PACKED_PIXELS,  ResourcePolicy::OWNED_RETAIN  );
-  bitmap->GetPackedPixelsProfile()->ReserveBuffer( Pixel::RGBA8888, 20, 20, 80, 80 );
-  Internal::ImageTicketPtr imageTicket = resourceClient.AddBitmapImage( bitmap );
-
-  Integration::Bitmap* theBitmap = resourceClient.GetBitmap(imageTicket);
-  DALI_TEST_CHECK ( theBitmap != NULL );
-  DALI_TEST_CHECK ( bitmap == theBitmap );
-  DALI_TEST_EQUALS ( bitmap->GetImageWidth(),   20u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetImageHeight(),  20u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPackedPixelsProfile()->GetBufferWidth(),  80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPackedPixelsProfile()->GetBufferHeight(), 80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
-
-  imageTicket->AddObserver( testTicketObserver );
-  application.SendNotification(); // Flush update queue
-  application.Render(0);          // Process message
-  application.SendNotification(); // Send message to tickets
-
-  theBitmap = resourceClient.GetBitmap(imageTicket);
-  DALI_TEST_CHECK ( theBitmap != NULL );
-  DALI_TEST_CHECK ( bitmap == theBitmap );
-  DALI_TEST_EQUALS ( bitmap->GetImageWidth(),   20u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetImageHeight(),  20u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPackedPixelsProfile()->GetBufferWidth(),  80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPackedPixelsProfile()->GetBufferHeight(), 80u, TEST_LOCATION );
-  DALI_TEST_EQUALS ( bitmap->GetPixelFormat(), Pixel::RGBA8888, TEST_LOCATION );
-  END_TEST;
-}
-
-int UtcDaliInternalGetBitmapImage02(void)
-{
-  TestApplication application;
-  tet_infoline("Testing GetBitmap() with invalid ticket");
-
-  Internal::ResourceClient& resourceClient  = Internal::ThreadLocalStorage::Get().GetResourceClient();
-  Internal::ImageTicketPtr imageTicket;
-  Integration::Bitmap* theBitmap = NULL;
-  bool exceptionRaised = false;
-  try
-  {
-    theBitmap = resourceClient.GetBitmap(imageTicket);
-  } catch (DaliException& e)
-  {
-    exceptionRaised = true;
-  }
-  DALI_TEST_CHECK( exceptionRaised );
-  DALI_TEST_CHECK( ! theBitmap );
-  END_TEST;
-}
-
-int UtcDaliInternalGetBitmapImage03(void)
-{
-  TestApplication application;
-  tet_infoline("Testing GetBitmap() with valid ticket for incorrect type");
-
-  Internal::ResourceClient& resourceClient  = Internal::ThreadLocalStorage::Get().GetResourceClient();  Internal::ResourceTicketPtr imageTicket = CheckLoadBitmap( application, "Stuff.png", 100, 100 );
-
-  Integration::Bitmap* theBitmap = NULL;
-  theBitmap = resourceClient.GetBitmap(imageTicket);
-  DALI_TEST_CHECK( ! theBitmap );
-
-  END_TEST;
-}
-
 int UtcDaliInternalAllocateTexture01(void)
 {
   TestApplication application;
@@ -982,11 +855,6 @@ int UtcDaliInternalAddNativeImage(void)
   DALI_TEST_EQUALS ( imageTicket->GetWidth(),  80, TEST_LOCATION );
   DALI_TEST_EQUALS ( imageTicket->GetHeight(), 80, TEST_LOCATION );
   DALI_TEST_CHECK ( 0 == testTicketObserver.LoadSucceededCalled() ); // Check no message was sent
-
-  Integration::Bitmap* theBitmap = NULL;
-  theBitmap = resourceClient.GetBitmap(imageTicket);
-
-  DALI_TEST_CHECK ( theBitmap == NULL );
   END_TEST;
 }
 
@@ -1014,9 +882,5 @@ int UtcDaliInternalAddFrameBufferImage(void)
   DALI_TEST_EQUALS ( imageTicket->GetWidth(), 80, TEST_LOCATION );
   DALI_TEST_EQUALS ( imageTicket->GetHeight(), 80, TEST_LOCATION );
   DALI_TEST_CHECK ( 0 == testTicketObserver.LoadSucceededCalled() ); // Check no message was sent
-
-  Integration::Bitmap* theBitmap = NULL;
-  theBitmap = resourceClient.GetBitmap(imageTicket);
-  DALI_TEST_CHECK ( theBitmap == NULL );
   END_TEST;
 }
index bfff2d5..56d58c5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 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.
@@ -24,7 +24,6 @@
 #include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/internal/event/images/bitmap-packed-pixel.h>
 #include <dali/internal/event/images/bitmap-compressed.h>
-#include <dali/internal/event/images/bitmap-external.h>
 #include <dali/integration-api/gl-abstraction.h>
 #include <dali/integration-api/gl-defines.h>
 
@@ -291,13 +290,7 @@ void Bitmap::DiscardBuffer()
 Bitmap::~Bitmap()
 {
   DALI_LOG_TRACE_METHOD(Debug::Filter::gImage);
-
-  // If owned
-  if( mDiscardable == ResourcePolicy::OWNED_DISCARD ||
-      mDiscardable == ResourcePolicy::OWNED_RETAIN )
-  {
-    DeletePixelBuffer();
-  }
+  DeletePixelBuffer();
 }
 
 /**
index 6319ae1..fb099ef 100644 (file)
@@ -98,8 +98,6 @@ public:
    * and may released away after uploading to GPU.
    * OWNED_RETAIN means that the data is owned and must be kept in CPU memory
    * e.g. for an image that cannot be reloaded from disk.
-   * NOT_OWNED means that the data is managed by an external component and is
-   * guaranteed to remain dereferenceable at least as long as the Bitmap remains alive.
    */
   static Bitmap* New( Profile profile, ResourcePolicy::Discardable discardable );
 
index 4713fb3..95a72f2 100644 (file)
@@ -32,14 +32,13 @@ enum DataRetention
 };
 
 /**
- * The discardable policy describes whether a resource is owned or can be discarded.
+ * The discardable policy determines if a resource can be discarded.
  * Discarded means that it can be released after uploading to GPU.
  */
 enum Discardable
 {
   OWNED_DISCARD,
   OWNED_RETAIN,
-  NOT_OWNED
 };
 
 } // namespace ResourcePolicy
index e5231de..d84c3b5 100644 (file)
@@ -67,11 +67,10 @@ bool Atlas::Upload( BufferImage& bufferImage,
   {
     AllocateAtlas();
     ResourceId destId = GetResourceId();
-    ResourceId srcId = bufferImage.GetResourceId();
 
-    if( destId && srcId )
+    if( destId )
     {
-      mResourceClient.UploadBitmap( destId, srcId, xOffset, yOffset );
+      bufferImage.UploadBitmap( destId, xOffset, yOffset );
       uploadSuccess = true;
     }
   }
index e87f0a1..e945930 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 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/buffer-image-impl.h>
 
+// EXTERNAL INCLUDES
+#include <string.h>
+
 // INTERNAL INCLUDES
 #include <dali/public-api/object/type-registry.h>
-#include <dali/integration-api/bitmap.h>
-#include <dali/internal/event/images/bitmap-external.h>
 #include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/internal/event/resources/resource-client.h>
 #include <dali/internal/update/manager/update-manager.h>
 #include <dali/internal/event/images/image-factory.h>
 
+using namespace Dali::Integration;
+
 namespace Dali
 {
 namespace Internal
@@ -53,177 +56,181 @@ BufferImagePtr BufferImage::New( PixelBuffer* pixBuf, unsigned int width, unsign
 
 BufferImage::BufferImage(unsigned int width, unsigned int height, Pixel::Format pixelformat, ReleasePolicy releasePol)
 : Image(releasePol),
-  mIsDataExternal(false)
+  mInternalBuffer(NULL),
+  mExternalBuffer(NULL),
+  mBitmap(NULL)
 {
   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
   mResourceClient = &tls.GetResourceClient();
   mWidth  = width;
   mHeight = height;
+  mPixelFormat = pixelformat;
+  mBytesPerPixel = Pixel::GetBytesPerPixel( pixelformat );
+  mByteStride = width * mBytesPerPixel;
+  mBufferSize = height * mByteStride;
 
-  const ImageTicketPtr& t = mResourceClient->AllocateBitmapImage(width, height, width, height, pixelformat);
-  mTicket = t.Get();
+  // Allocate a persistent internal buffer
+  mInternalBuffer = new PixelBuffer[ mBufferSize ];
 
-  mTicket->AddObserver(*this);
+  // Respect the desired release policy
+  mResourcePolicy = releasePol == Dali::Image::UNUSED ? ResourcePolicy::OWNED_DISCARD : ResourcePolicy::OWNED_RETAIN;
 }
 
-BufferImage::BufferImage(PixelBuffer* pixBuf, unsigned int width, unsigned int height, Pixel::Format pixelformat, unsigned int stride, ReleasePolicy releasePol)
+BufferImage::BufferImage(PixelBuffer* pixBuf, unsigned int width, unsigned int height, Pixel::Format pixelformat, unsigned int stride, ReleasePolicy releasePol )
 : Image(releasePol),
-  mIsDataExternal(true)
+  mInternalBuffer(NULL),
+  mExternalBuffer(pixBuf),
+  mBitmap(NULL)
 {
   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
   mResourceClient = &tls.GetResourceClient();
   mWidth  = width;
   mHeight = height;
-  Integration::Bitmap* bitmap = new BitmapExternal(pixBuf, width, height, pixelformat, stride);
-  const ImageTicketPtr& t = mResourceClient->AddBitmapImage(bitmap);
-  mTicket = t.Get();
+  mPixelFormat = pixelformat;
+  mBytesPerPixel = Pixel::GetBytesPerPixel( pixelformat );
+  mByteStride = ( stride ? stride : mWidth ) * mBytesPerPixel;
+  mBufferSize = height * mByteStride;
+
+  // Respect the desired release policy
+  mResourcePolicy = releasePol == Dali::Image::UNUSED ? ResourcePolicy::OWNED_DISCARD : ResourcePolicy::OWNED_RETAIN;
+
+  // Create a bitmap to hold copy of external buffer
+  ReserveBitmap();
 
-  mTicket->AddObserver(*this);
+  // Take a copy of the external buffer immediately, so it can be released if desired
+  RectArea area;
+  MirrorExternal( area );
 }
 
 BufferImage::~BufferImage()
 {
+  delete[] mInternalBuffer;
+}
+
+bool BufferImage::IsDataExternal() const
+{
+  return ( mExternalBuffer ? true : false );
 }
 
 void BufferImage::Update( RectArea& updateArea )
 {
+  ValidateBitmap();
+  UpdateBitmap( updateArea );
+
   if (mTicket)
   {
-    // TODO:
-    // If updateArea is empty or same as image size, then pass on.
-    // If updateArea is larger than image size, throw exception
-    // Otherwise, copy updateArea window of pixelBuffer into newly
-    // allocated buffer and pass that to resource client. (it will
-    // tramp through to BitmapTexture eventually!)
+    DALI_ASSERT_DEBUG( updateArea.x + updateArea.width <= mWidth && updateArea.y + updateArea.height <= mHeight );
     mResourceClient->UpdateBitmapArea( mTicket, updateArea );
-  }
-  else if (mIsDataExternal && mBitmapCached)
-  {
-    // previously freed up resource memory, dali was informed about external BufferImage put back on screen
-    Integration::Bitmap* bitmap = mBitmapCached.Get();
-    mTicket.Reset((mResourceClient->AddBitmapImage(bitmap)).Get());
 
-    mTicket->AddObserver(*this);
+    // Bitmap ownership has been passed on, so any subsequent update will need another bitmap
+    mBitmap = NULL;
   }
 }
 
-bool BufferImage::IsDataExternal() const
+void BufferImage::UpdateBitmap( RectArea& updateArea )
 {
-  return mIsDataExternal;
-}
-
-PixelBuffer* BufferImage::GetBuffer()
-{
-  PixelBuffer* buffer = NULL;
-
-  Integration::Bitmap* const bitmap = GetBitmap();
-
-  if(bitmap)
+  if ( mExternalBuffer )
+  {
+    MirrorExternal( updateArea );
+  }
+  else
   {
-    buffer = bitmap->GetBuffer();
+    // Copy the internal buffer to the bitmap area
+    memcpy( mBitmap->GetBuffer(), mInternalBuffer, mBufferSize );
   }
-  return buffer;
 }
 
-unsigned int BufferImage::GetBufferSize() const
+void BufferImage::ValidateBitmap()
 {
-  unsigned int bufferSize = 0;
-
-  Integration::Bitmap* const bitmap = GetBitmap();
-
-  if(bitmap)
+  ReserveBitmap();
+  if ( !mTicket )
   {
-    bufferSize = bitmap->GetBufferSize();
+    mTicket = mResourceClient->AddBitmapImage( mBitmap );
+    mTicket->AddObserver(*this);
   }
-  return bufferSize;
 }
 
-unsigned int BufferImage::GetBufferStride() const
+void BufferImage::ReserveBitmap()
 {
-  unsigned int bufferStride = 0;
-
-  Integration::Bitmap* const bitmap = GetBitmap();
+   // Does a bitmap currently exist ?
+  if ( !mBitmap )
+  {
+    mBitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, mResourcePolicy );
+  }
 
-  if(bitmap)
+  if ( !mBitmap->GetBuffer() )
   {
-    Integration::Bitmap::PackedPixelsProfile* packedBitmap = bitmap->GetPackedPixelsProfile();
+    Bitmap::PackedPixelsProfile* const packedBitmap = mBitmap->GetPackedPixelsProfile();
     DALI_ASSERT_DEBUG(packedBitmap);
-    bufferStride = packedBitmap->GetBufferStride();
-  }
 
-  return bufferStride;
+    packedBitmap->ReserveBuffer( mPixelFormat, mWidth, mHeight, mByteStride / mBytesPerPixel, mHeight );
+    DALI_ASSERT_DEBUG(mBitmap->GetBuffer() != 0);
+    DALI_ASSERT_DEBUG(mBitmap->GetBufferSize() >= mWidth * mHeight * Pixel::GetBytesPerPixel( mBitmap->GetPixelFormat() ) );
+  }
 }
 
-Pixel::Format BufferImage::GetPixelFormat() const
+void BufferImage::UploadBitmap( ResourceId destId, std::size_t xOffset, std::size_t yOffset )
 {
-  Pixel::Format format( Pixel::RGBA8888 );
+  // Make sure we have a bitmap for transport
+  ReserveBitmap();
 
-  Integration::Bitmap* const bitmap = GetBitmap();
+  // Copy source pixel data into bitmap
+  RectArea area;
+  UpdateBitmap( area );
 
-  if( bitmap )
-  {
-    format = bitmap->GetPixelFormat();
-  }
-
-  return format;
+  mResourceClient->UploadBitmap( destId, mBitmap, xOffset, yOffset);
+  mBitmap = NULL;
 }
 
-void BufferImage::Connect()
+void BufferImage::UpdateBufferArea( PixelBuffer* src, const RectArea& area )
 {
-  ++mConnectionCount;
+  DALI_ASSERT_DEBUG( area.x + area.width <= mWidth && area.y + area.height <= mHeight );
 
-  // application owns bitmap buffer, don't do anything. Update() has to be called manually.
-  if (mIsDataExternal)
-  {
-    return;
-  }
+  PixelBuffer* dest = mBitmap->GetBuffer();
+  uint32_t width = area.width * mBytesPerPixel;
+  uint32_t stride = mWidth * mBytesPerPixel;
 
-  if (mConnectionCount == 1)
+  src += ( area.y * mByteStride ) + ( area.x * mBytesPerPixel );
+  dest +=( ( area.y * mWidth ) + area.x ) * mBytesPerPixel;
+  for ( uint32_t i = 0; i < area.height; ++i )
   {
-    if (!mTicket && mBitmapCached)
-    {
-      const ImageTicketPtr& t = mResourceClient->AddBitmapImage(mBitmapCached.Get());
-      mTicket = t.Get();
-      mTicket->AddObserver(*this);
-    }
+    memcpy( dest, src, width );
+    src += mByteStride;
+    dest += stride;
   }
 }
 
-void BufferImage::Disconnect()
+void BufferImage::MirrorExternal( const RectArea& area )
 {
-  if (!mTicket)
+  if( ( mByteStride == mWidth * mBytesPerPixel ) && area.IsEmpty() )
   {
-    return;
+    memcpy( mBitmap->GetBuffer(), mExternalBuffer, mBufferSize );
   }
-
-  --mConnectionCount;
-
-  if (mConnectionCount == 0 && mReleasePolicy == Dali::Image::UNUSED)
+  else
   {
-    mBitmapCached = mResourceClient->GetBitmap(mTicket);
-    // release image memory when it's not visible anymore (decrease ref. count of texture)
-    mTicket->RemoveObserver(*this);
-    mTicket.Reset();
+    UpdateBufferArea( mExternalBuffer, area );
   }
 }
 
-Integration::Bitmap * BufferImage::GetBitmap() const
+void BufferImage::Connect()
 {
-  Integration::Bitmap* bitmap = NULL;
-
-  if (mTicket)
+  if ( !mConnectionCount++ )
   {
-    bitmap = mResourceClient->GetBitmap(mTicket);
+    RectArea area;
+    Update( area );
   }
-  else
+}
+
+void BufferImage::Disconnect()
+{
+  if ( mTicket )
   {
-    // off screen and freeing memory was requested
-    bitmap = mBitmapCached.Get();
+    if ( !( --mConnectionCount ) && mReleasePolicy == Dali::Image::UNUSED )
+    {
+      mTicket->RemoveObserver(*this);
+      mTicket.Reset();
+    }
   }
-
-  DALI_ASSERT_DEBUG(bitmap);
-
-  return bitmap;
 }
 
 } // namespace Internal
index 618846f..a307692 100644 (file)
@@ -2,7 +2,7 @@
 #define __DALI_INTERNAL_BUFFER_IMAGE_H__
 
 /*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2015 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.
@@ -64,10 +64,15 @@ public:
   /**
    * Create a new BufferImage, which uses external data source.
    * Pixel buffer has to be allocated by application.
-   * Application holds ownership of the buffer.
+   * An internal copy is made of the Pixel Buffer, which can then be freed by the Application, unless if there will be a call to Update() later.
+   * The buffer should only be freed when there is no chance of an Update() being called again.
+   * Obtaining the buffer with GetBuffer() and altering the contents, then Update() will not work with externally owned buffers.
    * For better performance and portability use power of two dimensions.
    * The maximum size of the image is limited by GL_MAX_TEXTURE_SIZE.
-   * @note  in case releasePol is "OffStage", application has to call Update() whenever image is re-added to the stage
+   *
+   * @deprecated Support for externally owned Pixel Buffers is due to be removed TBA.
+   * It is recommended that a BufferImage owned Buffer be used instead.
+
    * @param [in] pixBuf      pixel buffer. has to be allocated by application.
    * @param [in] width       image width in pixels
    * @param [in] height      image height in pixels
@@ -101,10 +106,12 @@ public:
   /**
    * Create a new BufferImage, which uses external data source.
    * Pixel buffer has to be allocated by application.
-   * Application holds ownership of the buffer.
+   * An internal copy is made of the Pixel Buffer, which can then be freed by the Application, unless if there will be a call to Update() later.
+   * The buffer should only be freed when there is no chance of Update() being called again.
+   * Note: obtaining the buffer with GetBuffer(), writing changes, then Update() will cause any changes to be lost.
+   * In this case, the BufferImage will update from the external buffer and so changes should be written there.
    * For better performance and portability use power of two dimensions.
    * The maximum size of the image is limited by GL_MAX_TEXTURE_SIZE.
-   * @note  in case releasePol is "OffStage", application has to call Update() whenever image is re-added to the stage
    * @param [in] pixBuf      pixel buffer. has to be allocated by application.
    * @param [in] width       image width in pixels
    * @param [in] height      image height in pixels
@@ -143,27 +150,48 @@ public:
    * Upload the modified contents with Update().
    * @return the pixel buffer
    */
-  PixelBuffer* GetBuffer();
+  PixelBuffer* GetBuffer() const
+  {
+    return ( mExternalBuffer ? mExternalBuffer : mInternalBuffer );
+  }
 
   /**
    * Returns buffer size in bytes.
    * @return the buffer size in bytes
    */
-  unsigned int GetBufferSize() const;
+  unsigned int GetBufferSize() const
+  {
+    return mBufferSize;
+  }
 
   /**
    * Returns buffer stride (in bytes).
    * @return the buffer stride
    */
-  unsigned int GetBufferStride() const;
+  unsigned int GetBufferStride() const
+  {
+    return mByteStride;
+  }
 
   /**
    * Get the pixel format
    * @return The pixel format
    */
-  Pixel::Format GetPixelFormat() const;
+  Pixel::Format GetPixelFormat() const
+  {
+    return mPixelFormat;
+  }
+
+  /**
+   * @brief Upload pixel data to another resource at an offset
+   *
+   * @param destId ResourceId of the destination
+   * @param xOffset x offset in the destination
+   * @param yOffset y offset in the destination
+   */
+  void UploadBitmap( ResourceId destId, std::size_t xOffset, std::size_t yOffset );
 
-protected: // From Resource
+protected: // From Image
   /**
    * @copydoc Dali::Internal::Image::Connect
    */
@@ -174,18 +202,29 @@ protected: // From Resource
    */
   virtual void Disconnect();
 
-  /**
-   * Get the bitmap from local cache or ticket.
-   **/
-  Integration::Bitmap * GetBitmap() const;
-
 private:
-  bool mIsDataExternal; ///< whether application holds ownership of pixel buffer or not
 
-  ResourceClient*            mResourceClient;
+  void ValidateBitmap();
 
-protected:
-  Integration::BitmapPtr     mBitmapCached;
+  void ReserveBitmap();
+
+  void UpdateBitmap( RectArea& updateArea );
+
+  void MirrorExternal( const RectArea& area );
+
+  void UpdateBufferArea( PixelBuffer* src, const RectArea& area );
+
+private:
+
+  PixelBuffer*                 mInternalBuffer;       ///< NULL if the data is supplied by an external buffer.
+  PixelBuffer*                 mExternalBuffer;       ///< NULL if there is no external pixel data (this is never owned by BufferImage).
+  ResourceClient*              mResourceClient;       ///< pointer to the resource client.
+  Integration::Bitmap*         mBitmap;               ///< pointer to the bitmap object containing the pixel buffer used to update GL.
+  uint32_t                     mBufferSize;           ///< size of the pixel buffer.
+  uint32_t                     mByteStride;           ///< width of the pixel buffer in bytes.
+  uint32_t                     mBytesPerPixel;        ///< width of a pixel in bytes.
+  Pixel::Format                mPixelFormat;          ///< pixel format of bitmap.
+  ResourcePolicy::Discardable  mResourcePolicy;       ///< whether to discard the pixel buffer when removed from the stage or to retain the data.
 };
 
 } // namespace Internal
index c2eb89a..6609c55 100644 (file)
@@ -24,7 +24,6 @@
 // INTERNAL INCLUDES
 #include <dali/public-api/object/type-registry.h>
 #include <dali/integration-api/bitmap.h>
-#include <dali/internal/event/images/bitmap-external.h>
 #include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/internal/event/resources/resource-client.h>
 #include <dali/internal/update/manager/update-manager.h>
index 4d8a755..3b68bcf 100644 (file)
@@ -39,9 +39,6 @@ typedef TicketContainer::iterator                    TicketContainerIter;
 typedef TicketContainer::size_type                   TicketContainerSize;
 typedef std::pair<ResourceId, ResourceTicket*>       TicketPair;
 
-typedef std::map<ResourceId, Bitmap*>                BitmapCache;
-typedef BitmapCache::iterator                        BitmapCacheIter;
-
 struct ResourceClient::Impl
 {
   Impl()
@@ -51,7 +48,6 @@ struct ResourceClient::Impl
 
   ResourceId       mNextId;
   TicketContainer  mTickets;
-  BitmapCache      mBitmaps;
 };
 
 ResourceClient::ResourceClient( ResourceManager& resourceManager,
@@ -213,28 +209,6 @@ ResourceTicketPtr ResourceClient::RequestResourceTicket( ResourceId id )
   return ticket;
 }
 
-ImageTicketPtr ResourceClient::AllocateBitmapImage( unsigned int width,
-                                                    unsigned int height,
-                                                    unsigned int bufferWidth,
-                                                    unsigned int bufferHeight,
-                                                    Pixel::Format pixelformat )
-{
-  /* buffer is available via public-api, therefore not discardable */
-  Bitmap* const bitmap = Bitmap::New( Bitmap::BITMAP_2D_PACKED_PIXELS, ResourcePolicy::OWNED_RETAIN );
-  Bitmap::PackedPixelsProfile* const packedBitmap = bitmap->GetPackedPixelsProfile();
-  DALI_ASSERT_DEBUG(packedBitmap);
-
-  packedBitmap->ReserveBuffer(pixelformat, width, height, bufferWidth, bufferHeight);
-  DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
-  DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
-
-  ImageTicketPtr ticket = AddBitmapImage(bitmap);
-
-  DALI_ASSERT_DEBUG(bitmap->GetBuffer() != 0);
-  DALI_ASSERT_DEBUG(bitmap->GetBufferSize() >= width * height);
-  return ticket;
-}
-
 ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
 {
   DALI_ASSERT_DEBUG( bitmap != NULL );
@@ -252,9 +226,6 @@ ImageTicketPtr ResourceClient::AddBitmapImage(Bitmap* bitmap)
 
   mImpl->mTickets.insert(TicketPair(newId, newTicket.Get()));
 
-  // Store bitmap for immediate access.
-  mImpl->mBitmaps[newId] = bitmap;
-
   DALI_LOG_INFO(Debug::Filter::gResource, Debug::General, "ResourceClient: AddBitmapImage() New id = %u\n", newId);
   RequestAddBitmapImageMessage( mEventThreadServices, mResourceManager, newId, bitmap );
 
@@ -376,20 +347,6 @@ void ResourceClient::UploadBitmap( ResourceId destId,Integration::BitmapPtr bitm
                               yOffset );
 }
 
-Bitmap* ResourceClient::GetBitmap(ResourceTicketPtr ticket)
-{
-  DALI_ASSERT_DEBUG( ticket );
-
-  Bitmap* bitmap = NULL;
-  BitmapCacheIter iter = mImpl->mBitmaps.find(ticket->GetId());
-
-  if( iter != mImpl->mBitmaps.end() )
-  {
-    bitmap = iter->second;
-  }
-  return bitmap;
-}
-
 void ResourceClient::CreateGlTexture( ResourceId id )
 {
   RequestCreateGlTextureMessage( mEventThreadServices, mResourceManager, id );
@@ -405,9 +362,6 @@ void ResourceClient::ResourceTicketDiscarded(const ResourceTicket& ticket)
   const ResourceId deadId = ticket.GetId();
   const ResourceTypePath& typePath = ticket.GetTypePath();
 
-  // Ensure associated event owned resources are also removed
-  mImpl->mBitmaps.erase(ticket.GetId());
-
   // The ticket object is dead, remove from tickets container
   TicketContainerSize erased = mImpl->mTickets.erase(deadId);
   DALI_ASSERT_DEBUG(erased != 0);
index 8433bde..57a00bb 100644 (file)
@@ -136,22 +136,6 @@ public:
   ResourceTicketPtr RequestResourceTicket( ResourceId id );
 
   /**
-   * Reqeust allocation of a bitmap resource
-   * @note Older hardware may require bufferWidth and bufferHeight to be a power of two
-   * @param[in] width         Image width in pixels
-   * @param[in] height        Image height in pixels
-   * @param[in] bufferWidth   Buffer width (stride) in pixels
-   * @param[in] bufferHeight  Buffer height in pixels
-   * @param[in] pixelformat   Pixel format
-   * @return A ref-counted request object. Keep a copy until the resource is no longer required.
-   */
-  ImageTicketPtr AllocateBitmapImage ( unsigned int width,
-                                       unsigned int height,
-                                       unsigned int bufferWidth,
-                                       unsigned int bufferHeight,
-                                       Pixel::Format pixelformat );
-
-  /**
    * Injects a bitmap resource (does not require loading).
    * @pre bitmap has to be initialized
    * @param[in] bitmap an initialized bitmap
@@ -221,17 +205,10 @@ public:
   void UploadBitmap( ResourceId destId, Integration::BitmapPtr bitmap, std::size_t xOffset, std::size_t yOffset);
 
   /**
-   * Find Bitmap by ticket.
-   * @pre ticket has to identify a Bitmap
-   * @param[in] ticket The ticket returned from AllocateBitmapImage() or AddBitmapImage()
-   * @return The bitmap, or NULL if the ticket did not reference a bitmap
+   * @brief Trigger asynchronous creation of GL texture to back resource immediately.
+   * @param[in] id The resource ID to allocate a GL texture for.
    */
-  Integration::Bitmap* GetBitmap(ResourceTicketPtr ticket);
-   /**
-    * @brief Trigger asynchronous creation of GL texture to back resource immediately.
-    * @param[in] id The resource ID to allocate a GL texture for.
-    */
-   void CreateGlTexture( ResourceId id );
+  void CreateGlTexture( ResourceId id );
 
 public: // From ResourceTicketLifetimeObserver.
 
index f8b00b2..b872f00 100644 (file)
@@ -66,7 +66,6 @@ internal_src_files = \
   $(internal_src_dir)/event/events/tap-gesture-processor.cpp \
   $(internal_src_dir)/event/events/touch-event-processor.cpp \
   $(internal_src_dir)/event/images/atlas-impl.cpp \
-  $(internal_src_dir)/event/images/bitmap-external.cpp \
   $(internal_src_dir)/event/images/bitmap-packed-pixel.cpp \
   $(internal_src_dir)/event/images/bitmap-compressed.cpp \
   $(internal_src_dir)/event/images/image-impl.cpp \
index d325162..9432bd4 100644 (file)
@@ -114,7 +114,7 @@ void BitmapTexture::AreaUpdated( const RectArea& updateArea, const unsigned char
                    updateArea.x, updateArea.y, updateArea.width ,updateArea.height );
 
     const unsigned int pitchPixels = mWidth;
-    const unsigned int pixelDepth = GetBytesPerPixel( mPixelFormat );
+    const unsigned int pixelDepth = Dali::Pixel::GetBytesPerPixel( mPixelFormat );
 
     // If the width of the source update area is the same as the pitch, then can
     // copy the contents in a single contiguous TexSubImage call.
@@ -169,6 +169,9 @@ void BitmapTexture::AssignBitmap( bool generateTexture, const unsigned char* pix
   mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
   mContext.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
+  // If the resource policy is to discard on upload then release buffer
+  DiscardBitmapBuffer();
+
   if( pixels != NULL )
   {
     INCREASE_BY( PerformanceMonitor::TEXTURE_DATA_UPLOADED, GetBytesPerPixel(mPixelFormat) * mWidth * mHeight );
@@ -372,7 +375,10 @@ void BitmapTexture::DiscardBitmapBuffer()
   if( ResourcePolicy::OWNED_DISCARD == mDiscardPolicy )
   {
     DALI_LOG_INFO(Debug::Filter::gImage, Debug::General, "  Discarding bitmap\n");
-    mBitmap->DiscardBuffer();
+    if ( mBitmap )
+    {
+      mBitmap->DiscardBuffer();
+    }
   }
 }
 
index c0ef35a..2bcf6c3 100644 (file)
@@ -164,10 +164,10 @@ private:
   void DiscardBitmapBuffer();
 
 private:
-  Integration::BitmapPtr mBitmap;      ///< The Bitmap the Texture was created from (may be NULL)
-  bool                   mClearPixels; ///< true if initial texture should be cleared on creation
-  ResourcePolicy::Discardable mDiscardPolicy; ///< The bitmap discard policy
-  Pixel::Format            mPixelFormat;
+  Integration::BitmapPtr      mBitmap;          ///< The Bitmap the Texture was created from (may be NULL)
+  bool                        mClearPixels:1;   ///< true if initial texture should be cleared on creation
+  ResourcePolicy::Discardable mDiscardPolicy:2; ///< The bitmap discard policy
+  Pixel::Format               mPixelFormat:5;   ///< Pack pixel format into bitfield
 
   // Changes scope, should be at end of class
   DALI_LOG_OBJECT_STRING_DECLARATION;
index 1830d43..78fee1b 100644 (file)
@@ -134,11 +134,6 @@ void CompressedBitmapTexture::Update( Integration::Bitmap* bitmap )
     if ( mId ) // If the texture is already bound
     {
       AssignBitmap( false, pixels, mBitmap->GetBufferSize() );
-
-      if( mDiscardPolicy == ResourcePolicy::OWNED_DISCARD )
-      {
-        mBitmap->DiscardBuffer();
-      }
     }
   }
 }