Fix for signals not being received on an Atlas upload
[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     mTicket->AddObserver( *this );
206     mImageFactory.RegisterForContextRecovery( this );
207   }
208 }
209
210 void Atlas::ReleaseAtlas()
211 {
212   mTicket.Reset();
213   ClearCache();
214   mImageFactory.UnregisterFromContextRecovery( this );
215 }
216
217 void Atlas::ClearBackground(const Vector4& color )
218 {
219   AllocateAtlas();
220   ResourceId destId = GetResourceId();
221   if( destId )
222   {
223     const unsigned int numPixels = mWidth * mHeight;
224     unsigned int bytesPerPixel = Pixel::GetBytesPerPixel(mPixelFormat);
225     BufferImagePtr imageData = BufferImage::New( mWidth, mHeight, mPixelFormat );
226     PixelBuffer* pixbuf = imageData->GetBuffer();
227
228     // converting color value from float 0.f~1.f to byte 0~255
229     unsigned char r =  static_cast<unsigned char>( 255.f * Clamp( color.r, 0.f, 1.f ) );
230     unsigned char g =  static_cast<unsigned char>( 255.f * Clamp( color.g, 0.f, 1.f ) );
231     unsigned char b =  static_cast<unsigned char>( 255.f * Clamp( color.b, 0.f, 1.f ) );
232     unsigned char a =  static_cast<unsigned char>( 255.f * Clamp( color.a, 0.f, 1.f ) );
233     if( mPixelFormat == Pixel::RGBA8888 )
234     {
235       // For little-endian byte order, the RGBA channels needs to be reversed for bit shifting.
236       uint32_t clearColor = ( (uint32_t) a<<24 | (uint32_t)b << 16 | (uint32_t)g << 8 | (uint32_t)r );
237       uint32_t* buf = (uint32_t *) pixbuf;
238       for( unsigned int i = 0; i < numPixels; ++i )
239       {
240         buf[i] = clearColor;
241       }
242     }
243     else if( mPixelFormat == Pixel::RGB888 )
244     {
245       for( unsigned int i = 0; i < numPixels; ++i )
246       {
247         pixbuf[i*bytesPerPixel] = r;
248         pixbuf[i*bytesPerPixel+1] = g;
249         pixbuf[i*bytesPerPixel+2] = b;
250       }
251     }
252     else if( mPixelFormat == Pixel::A8 )
253     {
254       memset( pixbuf, a, numPixels );
255     }
256
257     RectArea area;
258     imageData->Update(area);
259
260     mClearColor = color;
261     mClear = true;
262     mResourceClient.UploadBitmap( destId, imageData->GetResourceId(), 0, 0 );
263   }
264 }
265
266 void Atlas::ClearCache()
267 {
268   Vector< Tile* >::ConstIterator end = mTiles.End();
269   for( Vector<Tile*>::Iterator iter = mTiles.Begin(); iter != end; iter++ )
270   {
271     delete *iter;
272   }
273   mTiles.Clear();
274 }
275
276 Integration::BitmapPtr Atlas::LoadBitmap( const std::string& url )
277 {
278   Integration::BitmapResourceType resourceType;
279   Integration::PlatformAbstraction& platformAbstraction = Internal::ThreadLocalStorage::Get().GetPlatformAbstraction();
280
281   Integration::ResourcePointer resource = platformAbstraction.LoadResourceSynchronously(resourceType, url);
282   Integration::BitmapPtr bitmap = static_cast<Integration::Bitmap*>( resource.Get());
283
284   return bitmap;
285 }
286
287 } // namespace Internal
288
289 } // namespace Dali