Merge "DALi Version 1.0.33" into tizen
[platform/core/uifw/dali-core.git] / dali / internal / event / images / atlas-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/images/atlas-impl.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/internal/event/common/thread-local-storage.h>
24
25 #include <dali/internal/event/images/image-factory.h>
26 #include <dali/internal/event/resources/resource-client.h>
27 #include <dali/integration-api/bitmap.h>
28 #include <dali/integration-api/platform-abstraction.h>
29
30 namespace Dali
31 {
32
33 namespace Internal
34 {
35
36 namespace
37 {
38 TypeRegistration mType( typeid( Dali::Atlas ), typeid( Dali::Image ), NULL );
39 }
40
41 Atlas* Atlas::New( SizeType width,
42                    SizeType height,
43                    Pixel::Format pixelFormat,
44                    bool recoverContext)
45 {
46   return new Atlas( width, height, pixelFormat, recoverContext );
47 }
48
49 void Atlas::Clear(const Vector4& color)
50 {
51   ClearCache();
52   ClearBackground( color );
53 }
54
55 bool Atlas::Upload( BufferImage& bufferImage,
56                     SizeType xOffset,
57                     SizeType yOffset )
58 {
59   bool uploadSuccess( false );
60
61   if( Compatible(bufferImage.GetPixelFormat(),
62                  xOffset + bufferImage.GetWidth(),
63                  yOffset + bufferImage.GetHeight() ) )
64   {
65     AllocateAtlas();
66     ResourceId destId = GetResourceId();
67     ResourceId srcId = bufferImage.GetResourceId();
68
69     if( destId && srcId )
70     {
71       mResourceClient.UploadBitmap( destId, srcId, xOffset, yOffset );
72       uploadSuccess = true;
73     }
74   }
75
76   return uploadSuccess;
77 }
78
79 bool Atlas::Upload( const std::string& url,
80                     SizeType xOffset,
81                     SizeType yOffset)
82 {
83   bool uploadSuccess( false );
84
85   Integration::BitmapPtr bitmap = LoadBitmap( url );
86
87   if( bitmap && Compatible(bitmap->GetPixelFormat(), xOffset + bitmap->GetImageWidth(), yOffset + bitmap->GetImageHeight()) )
88   {
89     AllocateAtlas();
90     ResourceId destId = GetResourceId();
91     if( destId )
92     {
93       mResourceClient.UploadBitmap( destId, bitmap, xOffset, yOffset  );
94       uploadSuccess = true;
95
96       if( mRecoverContext )
97       {
98         mTiles.PushBack( new Tile(xOffset, yOffset, url) );
99       }
100     }
101   }
102   return uploadSuccess;
103 }
104
105 void Atlas::RecoverFromContextLoss()
106 {
107   ResourceId destId = GetResourceId();
108   if( destId )
109   {
110     if( mClear )
111     {
112       ClearBackground( mClearColor );
113     }
114
115     if( mRecoverContext )
116     {
117       // Restore the atlas by re-uploading the url resources
118       Vector< Tile* >::ConstIterator end = mTiles.End();
119       for( Vector<Tile*>::Iterator iter = mTiles.Begin(); iter != end; iter++ )
120       {
121         Integration::BitmapPtr bitmap = LoadBitmap( (*iter)->url );
122         mResourceClient.UploadBitmap( destId, bitmap, (*iter)->xOffset, (*iter)->yOffset  );
123       }
124     }
125   }
126 }
127
128 Atlas::~Atlas()
129 {
130   ReleaseAtlas();
131 }
132
133 Atlas::Atlas( SizeType width,
134               SizeType height,
135               Pixel::Format pixelFormat,
136               bool recoverContext )
137 : mResourceClient( ThreadLocalStorage::Get().GetResourceClient() ),
138   mImageFactory( ThreadLocalStorage::Get().GetImageFactory() ),
139   mClearColor( Vector4::ZERO ),
140   mPixelFormat( pixelFormat ),
141   mClear( false ),
142   mRecoverContext( recoverContext )
143 {
144   mWidth  = width;
145   mHeight = height;
146 }
147
148 void Atlas::Connect()
149 {
150   ++mConnectionCount;
151
152   if( mConnectionCount == 1 )
153   {
154     AllocateAtlas();
155   }
156 }
157
158 void Atlas::Disconnect()
159 {
160   if( mConnectionCount )
161   {
162     --mConnectionCount;
163
164     if ( Dali::Image::UNUSED == mReleasePolicy &&
165          mConnectionCount == 0 )
166     {
167       ReleaseAtlas();
168     }
169   }
170 }
171
172 bool Atlas::Compatible( Pixel::Format pixelFormat,
173                         SizeType x,
174                         SizeType y )
175 {
176   bool Compatible(false);
177
178   if( mPixelFormat != pixelFormat )
179   {
180     DALI_LOG_ERROR( "Pixel format %d does not match Atlas format %d\n", pixelFormat, mPixelFormat );
181   }
182   else
183   {
184     if( x <= mWidth  && y <= mHeight )
185     {
186       Compatible = true;
187     }
188     else
189     {
190       DALI_LOG_ERROR( "image does not fit within the atlas \n" );
191     }
192   }
193
194   return Compatible;
195 }
196
197 void Atlas::AllocateAtlas()
198 {
199   if( !mTicket )
200   {
201     mTicket = mResourceClient.AllocateTexture( mWidth, mHeight, mPixelFormat );
202     mImageFactory.RegisterForContextRecovery( this );
203   }
204 }
205
206 void Atlas::ReleaseAtlas()
207 {
208   mTicket.Reset();
209   ClearCache();
210   mImageFactory.UnregisterFromContextRecovery( this );
211 }
212
213 void Atlas::ClearBackground(const Vector4& color )
214 {
215   AllocateAtlas();
216   ResourceId destId = GetResourceId();
217   if( destId )
218   {
219     const unsigned int numPixels = mWidth * mHeight;
220     unsigned int bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
221     BufferImagePtr imageData = BufferImage::New( mWidth, mHeight, mPixelFormat );
222     PixelBuffer* pixbuf = imageData->GetBuffer();
223
224     // converting color value from float 0.f~1.f to byte 0~255
225     unsigned char r =  static_cast<unsigned char>( 255.f * Clamp( color.r, 0.f, 1.f ) );
226     unsigned char g =  static_cast<unsigned char>( 255.f * Clamp( color.g, 0.f, 1.f ) );
227     unsigned char b =  static_cast<unsigned char>( 255.f * Clamp( color.b, 0.f, 1.f ) );
228     unsigned char a =  static_cast<unsigned char>( 255.f * Clamp( color.a, 0.f, 1.f ) );
229     if( mPixelFormat == Pixel::RGBA8888 )
230     {
231       // For little-endian byte order, the RGBA channels needs to be reversed for bit shifting.
232       uint32_t clearColor = ( (uint32_t) a<<24 | (uint32_t)b << 16 | (uint32_t)g << 8 | (uint32_t)r );
233       uint32_t* buf = (uint32_t *) pixbuf;
234       for( unsigned int i = 0; i < numPixels; ++i )
235       {
236         buf[i] = clearColor;
237       }
238     }
239     else if( mPixelFormat == Pixel::RGB888 )
240     {
241       for( unsigned int i = 0; i < numPixels; ++i )
242       {
243         pixbuf[i*bytesPerPixel] = r;
244         pixbuf[i*bytesPerPixel+1] = g;
245         pixbuf[i*bytesPerPixel+2] = b;
246       }
247     }
248     else if( mPixelFormat == Pixel::A8 )
249     {
250       memset( pixbuf, a, numPixels );
251     }
252
253     RectArea area;
254     imageData->Update(area);
255
256     mClearColor = color;
257     mClear = true;
258     mResourceClient.UploadBitmap( destId, imageData->GetResourceId(), 0, 0 );
259   }
260 }
261
262 void Atlas::ClearCache()
263 {
264   Vector< Tile* >::ConstIterator end = mTiles.End();
265   for( Vector<Tile*>::Iterator iter = mTiles.Begin(); iter != end; iter++ )
266   {
267     delete *iter;
268   }
269   mTiles.Clear();
270 }
271
272 Integration::BitmapPtr Atlas::LoadBitmap( const std::string& url )
273 {
274   ImageAttributes loadedAttrs;
275   Integration::BitmapResourceType resourceType( loadedAttrs );
276   Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction();
277
278   Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously(resourceType, url);
279   Integration::BitmapPtr bitmap = static_cast<Integration::Bitmap*>( resource.Get());
280
281   return bitmap;
282 }
283
284 } // namespace Internal
285
286 } // namespace Dali