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