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