[dali_1.0.1] Merge branch 'tizen'
[platform/core/uifw/dali-core.git] / dali / internal / render / gl-resources / texture-cache.cpp
1 /*
2  * Copyright (c) 2014 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 #include <dali/internal/render/gl-resources/texture-cache.h>
19
20 #include <dali/integration-api/bitmap.h>
21
22 #include <dali/internal/update/resources/resource-manager-declarations.h>
23 #include <dali/internal/render/common/post-process-resource-dispatcher.h>
24 #include <dali/internal/render/queue/render-queue.h>
25 #include <dali/internal/render/gl-resources/context.h>
26 #include <dali/internal/render/gl-resources/texture-factory.h>
27 #include <dali/internal/render/gl-resources/texture.h>
28 #include <dali/internal/render/gl-resources/texture-observer.h>
29 #include <dali/internal/render/gl-resources/bitmap-texture.h>
30 #include <dali/internal/render/gl-resources/native-texture.h>
31 #include <dali/internal/render/gl-resources/frame-buffer-texture.h>
32
33 #include <dali/integration-api/debug.h>
34
35 using Dali::Internal::Texture;
36 using Dali::Internal::FrameBufferTexture;
37 using Dali::Integration::Bitmap;
38
39 namespace Dali
40 {
41 namespace Internal
42 {
43
44 // value types used by messages
45 template <> struct ParameterType< Pixel::Format > : public BasicType< Pixel::Format > {};
46
47 namespace SceneGraph
48 {
49
50 TextureCache::TextureCache( RenderQueue& renderQueue,
51                             PostProcessResourceDispatcher& postProcessResourceDispatcher,
52                             Context& context)
53 : TextureCacheDispatcher(renderQueue),
54   mPostProcessResourceDispatcher(postProcessResourceDispatcher),
55   mContext(context)
56 {
57 }
58
59 TextureCache::~TextureCache()
60 {
61 }
62
63 void TextureCache::CreateTexture( ResourceId        id,
64                                   unsigned int      width,
65                                   unsigned int      height,
66                                   Pixel::Format     pixelFormat,
67                                   bool              clearPixels )
68 {
69   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::CreateTexture(id=%i width:%u height:%u)\n", id, width, height);
70
71   Texture* texture = TextureFactory::NewBitmapTexture(width, height, pixelFormat, clearPixels, mContext);
72   mTextures.insert(TexturePair(id, texture));
73 }
74
75 void TextureCache::AddBitmap(ResourceId id, Integration::BitmapPtr bitmap)
76 {
77   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddBitmap(id=%i Bitmap:%p)\n", id, bitmap.Get());
78
79   Texture* texture = TextureFactory::NewBitmapTexture(bitmap.Get(), mContext);
80   mTextures.insert(TexturePair(id, texture));
81 }
82
83 void TextureCache::AddNativeImage(ResourceId id, NativeImagePtr nativeImage)
84 {
85   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddNativeImage(id=%i NativeImg:%p)\n", id, nativeImage.Get());
86
87   /// TODO - currently a new Texture is created even if we reuse the same NativeImage
88   Texture* texture = TextureFactory::NewNativeImageTexture(*nativeImage, mContext);
89   mTextures.insert(TexturePair(id, texture));
90 }
91
92 void TextureCache::AddFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
93 {
94   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddFrameBuffer(id=%i width:%u height:%u)\n", id, width, height);
95
96   // Note: Do not throttle framebuffer generation - a request for a framebuffer should always be honoured
97   // as soon as possible.
98   Texture* texture = TextureFactory::NewFrameBufferTexture( width, height, pixelFormat, mContext );
99   mFramebufferTextures.insert(TexturePair(id, texture));
100 }
101
102 void TextureCache::AddFrameBuffer( ResourceId id, NativeImagePtr nativeImage )
103 {
104   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddFrameBuffer(id=%i width:%u height:%u)\n", id, nativeImage->GetWidth(), nativeImage->GetHeight());
105
106   // Note: Do not throttle framebuffer generation - a request for a framebuffer should always be honoured
107   // as soon as possible.
108   Texture* texture = TextureFactory::NewFrameBufferTexture( nativeImage, mContext );
109   mFramebufferTextures.insert(TexturePair(id, texture));
110 }
111
112 void TextureCache::UpdateTexture( ResourceId id, Integration::BitmapPtr bitmap )
113 {
114   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(id=%i bitmap:%p )\n", id, bitmap.Get());
115
116   TextureIter textureIter = mTextures.find(id);
117   if( textureIter != mTextures.end() )
118   {
119     // we have reloaded the image from file, update texture
120     TexturePointer texturePtr = textureIter->second;
121     if( texturePtr )
122     {
123       texturePtr->Update(bitmap.Get());
124
125       ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
126       mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
127     }
128   }
129 }
130
131 void TextureCache::UpdateTextureArea( ResourceId id, const Dali::RectArea& area )
132 {
133   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTextureArea(id=%i)\n", id );
134
135   TextureIter textureIter = mTextures.find(id);
136   if( textureIter != mTextures.end() )
137   {
138     TexturePointer texturePtr = textureIter->second;
139     if( texturePtr )
140     {
141       texturePtr->UpdateArea( area );
142
143       ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
144       mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
145     }
146   }
147 }
148
149 void TextureCache::AddBitmapUploadArray( ResourceId id, const BitmapUploadArray& uploadArray )
150 {
151   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddBitmapUploadArray(id=%i )\n", id);
152
153   TextureIter textureIter = mTextures.find(id);
154
155   DALI_ASSERT_DEBUG( textureIter != mTextures.end() );
156   if( textureIter != mTextures.end() )
157   {
158     TexturePointer texturePtr = textureIter->second;
159     if( texturePtr )
160     {
161       BitmapTexture* texture = static_cast< BitmapTexture* >( texturePtr.Get() );
162       texture->UploadBitmapArray( uploadArray );
163     }
164   }
165 }
166
167 void TextureCache::ClearAreas( ResourceId id,
168                                const BitmapClearArray& areaArray,
169                                std::size_t blockSize,
170                                uint32_t color )
171 {
172   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::ClearAreas(id: %d)\n", id);
173   TextureIter textureIter = mTextures.find(id);
174   DALI_ASSERT_DEBUG( textureIter != mTextures.end() );
175   if( textureIter != mTextures.end() )
176   {
177     TexturePointer texturePtr = textureIter->second;
178     if( texturePtr )
179     {
180       BitmapTexture* texture = static_cast< BitmapTexture* >( texturePtr.Get() );
181       texture->ClearAreas( areaArray, blockSize, color );
182     }
183   }
184 }
185
186 void TextureCache::DiscardTexture( ResourceId id )
187 {
188   bool deleted = false;
189
190   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::DiscardTexture(id:%u)\n", id);
191
192   if( mTextures.size() > 0)
193   {
194     TextureIter iter = mTextures.find(id);
195     if( iter != mTextures.end() )
196     {
197       TexturePointer texturePtr = iter->second;
198       if( texturePtr )
199       {
200         // if valid texture pointer, cleanup GL resources
201         texturePtr->GlCleanup();
202       }
203       mTextures.erase(iter);
204       deleted = true;
205     }
206   }
207
208   if( mFramebufferTextures.size() > 0)
209   {
210     TextureIter iter = mFramebufferTextures.find(id);
211     if( iter != mFramebufferTextures.end() )
212     {
213       TexturePointer texturePtr = iter->second;
214       if( texturePtr )
215       {
216         // if valid texture pointer, cleanup GL resources
217         texturePtr->GlCleanup();
218       }
219       mFramebufferTextures.erase(iter);
220       deleted = true;
221     }
222   }
223
224   if(deleted)
225   {
226     if( mObservers.size() > 0 )
227     {
228       TextureResourceObserversIter observersIter = mObservers.find(id);
229       if( observersIter != mObservers.end() )
230       {
231         TextureObservers observers = observersIter->second;
232         for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
233         {
234           TextureObserver* observer = *iter;
235           observer->TextureDiscarded( id );
236         }
237
238         mObservers.erase( observersIter );
239       }
240     }
241
242     // Tell resource manager
243     ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::DELETED );
244     mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
245   }
246 }
247
248 void TextureCache::BindTexture( Texture *texture, ResourceId id, GLenum target, GLenum textureunit )
249 {
250   bool created = texture->Bind(target, textureunit);
251   if( created && texture->UpdateOnCreate() ) // i.e. the pixel data was sent to GL
252   {
253     ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
254     mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
255   }
256 }
257
258
259 Texture* TextureCache::GetTexture(ResourceId id)
260 {
261   Texture* texture = NULL;
262   TextureIter iter = mTextures.find(id);
263
264   if( iter != mTextures.end() )
265   {
266     TexturePointer texturePtr = iter->second;
267     if( texturePtr )
268     {
269       texture = texturePtr.Get();
270     }
271   }
272
273   if( texture == NULL )
274   {
275     TextureIter iter = mFramebufferTextures.find(id);
276     if( iter != mFramebufferTextures.end() )
277     {
278       TexturePointer texturePtr = iter->second;
279       if( texturePtr )
280       {
281         texture = texturePtr.Get();
282       }
283     }
284   }
285
286   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetTexture(id:%u) : %p\n", id, texture);
287
288   return texture;
289 }
290
291 FrameBufferTexture* TextureCache::GetFramebuffer(ResourceId id)
292 {
293   FrameBufferTexture* offscreen = NULL;
294   TextureIter iter = mFramebufferTextures.find(id);
295
296   DALI_ASSERT_DEBUG( iter != mFramebufferTextures.end() );
297
298   if( iter != mFramebufferTextures.end() )
299   {
300     TexturePointer texturePtr = iter->second;
301     if( texturePtr )
302     {
303       offscreen = dynamic_cast< FrameBufferTexture* >( texturePtr.Get() );
304     }
305   }
306   DALI_ASSERT_DEBUG( offscreen );
307
308   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetFramebuffer(id:%u) : %p\n", id, offscreen);
309
310   return offscreen;
311 }
312
313 void TextureCache::AddObserver( ResourceId id, TextureObserver* observer )
314 {
315   TextureResourceObserversIter observersIter = mObservers.find(id);
316   if( observersIter != mObservers.end() )
317   {
318     TextureObservers& observers = observersIter->second;
319     bool foundObserver = false;
320     for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
321     {
322       if( *iter == observer )
323       {
324         foundObserver = true;
325         break;
326       }
327     }
328     if( ! foundObserver )
329     {
330       observers.push_back(observer);
331     }
332   }
333   else
334   {
335     TextureObservers observers;
336     observers.push_back(observer);
337     mObservers.insert(std::pair<ResourceId, TextureObservers>(id, observers));
338   }
339 }
340
341 void TextureCache::RemoveObserver( ResourceId id, TextureObserver* observer )
342 {
343   TextureResourceObserversIter observersIter = mObservers.find(id);
344   if( observersIter != mObservers.end() )
345   {
346     TextureObservers& observers = observersIter->second;
347     for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
348     {
349       if(*iter == observer)
350       {
351         observers.erase(iter);
352         break;
353       }
354     }
355   }
356 }
357
358 void TextureCache::GlContextDestroyed()
359 {
360   TextureIter end = mTextures.end();
361   TextureIter iter = mTextures.begin();
362   for( ; iter != end; ++iter )
363   {
364     (*iter->second).GlContextDestroyed(); // map holds intrusive pointers
365   }
366 }
367
368 /********************************************************************************
369  **********************  Implements TextureCacheDispatcher  *********************
370  ********************************************************************************/
371
372 void TextureCache::DispatchCreateTexture( ResourceId        id,
373                                           unsigned int      width,
374                                           unsigned int      height,
375                                           Pixel::Format     pixelFormat,
376                                           bool              clearPixels )
377 {
378   // NULL, means being shutdown, so ignore msgs
379   if( mSceneGraphBuffers != NULL )
380   {
381     typedef MessageValue5< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format, bool > DerivedType;
382
383     // Reserve some memory inside the render queue
384     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
385
386     // Construct message in the render queue memory; note that delete should not be called on the return value
387     new (slot) DerivedType( this, &TextureCache::CreateTexture, id, width, height, pixelFormat, clearPixels );
388   }
389 }
390
391 void TextureCache::DispatchCreateTextureForBitmap( ResourceId id, Bitmap* bitmap )
392 {
393   // NULL, means being shutdown, so ignore msgs
394   if( mSceneGraphBuffers != NULL )
395   {
396     typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
397
398     // Reserve some memory inside the render queue
399     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
400
401     // Construct message in the render queue memory; note that delete should not be called on the return value
402     new (slot) DerivedType( this, &TextureCache::AddBitmap, id, bitmap );
403   }
404 }
405
406 void TextureCache::DispatchCreateTextureForNativeImage( ResourceId id, NativeImagePtr nativeImage )
407 {
408   // NULL, means being shutdown, so ignore msgs
409   if( mSceneGraphBuffers != NULL )
410   {
411     typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > DerivedType;
412
413     // Reserve some memory inside the render queue
414     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
415
416     // Construct message in the render queue memory; note that delete should not be called on the return value
417     new (slot) DerivedType( this, &TextureCache::AddNativeImage, id, nativeImage );
418   }
419 }
420
421 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
422 {
423   // NULL, means being shutdown, so ignore msgs
424   if( mSceneGraphBuffers != NULL )
425   {
426     typedef MessageValue4< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format > DerivedType;
427
428     // Reserve some memory inside the render queue
429     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
430
431     // Construct message in the render queue memory; note that delete should not be called on the return value
432     new (slot) DerivedType( this, &TextureCache::AddFrameBuffer, id, width, height, pixelFormat );
433   }
434 }
435
436 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, NativeImagePtr nativeImage )
437 {
438   // NULL, means being shutdown, so ignore msgs
439   if( mSceneGraphBuffers != NULL )
440   {
441     typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > DerivedType;
442
443     // Reserve some memory inside the render queue
444     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
445
446     // Construct message in the render queue memory; note that delete should not be called on the return value
447     new (slot) DerivedType( this, &TextureCache::AddFrameBuffer, id, nativeImage );
448   }
449 }
450
451 void TextureCache::DispatchUpdateTexture( ResourceId id, Bitmap* bitmap )
452 {
453   // NULL, means being shutdown, so ignore msgs
454   if( mSceneGraphBuffers != NULL )
455   {
456     typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
457
458     // Reserve some memory inside the render queue
459     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
460
461     // Construct message in the render queue memory; note that delete should not be called on the return value
462     new (slot) DerivedType( this, &TextureCache::UpdateTexture, id, bitmap );
463   }
464 }
465
466 void TextureCache::DispatchUpdateTextureArea( ResourceId id, const Dali::RectArea& area )
467 {
468   // NULL, means being shutdown, so ignore msgs
469   if( mSceneGraphBuffers != NULL )
470   {
471     typedef MessageValue2< TextureCache, ResourceId, Dali::RectArea > DerivedType;
472
473     // Reserve some memory inside the render queue
474     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
475
476     // Construct message in the render queue memory; note that delete should not be called on the return value
477     new (slot) DerivedType( this, &TextureCache::UpdateTextureArea, id, area );
478   }
479 }
480
481 void TextureCache::DispatchUploadBitmapArrayToTexture( ResourceId id, const BitmapUploadArray& uploadArray )
482 {
483   // NULL, means being shutdown, so ignore msgs
484   if( mSceneGraphBuffers != NULL )
485   {
486     typedef MessageValue2< TextureCache, ResourceId, BitmapUploadArray > DerivedType;
487
488     // Reserve some memory inside the render queue
489     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
490
491     // Construct message in the render queue memory; note that delete should not be called on the return value
492     new (slot) DerivedType( this, &TextureCache::AddBitmapUploadArray, id, uploadArray );
493   }
494 }
495
496 void TextureCache::DispatchClearAreas( ResourceId id, const BitmapClearArray& areaArray, std::size_t blockSize, uint32_t color )
497 {
498   // NULL, means being shutdown, so ignore msgs
499   if( mSceneGraphBuffers != NULL )
500   {
501     typedef MessageValue4< TextureCache, ResourceId, BitmapClearArray, std::size_t, uint32_t > DerivedType;
502
503     // Reserve some memory inside the render queue
504     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
505
506     // Construct message in the render queue memory; note that delete should not be called on the return value
507     new (slot) DerivedType( this, &TextureCache::ClearAreas, id, areaArray, blockSize, color );
508   }
509 }
510
511 void TextureCache::DispatchDiscardTexture( ResourceId id )
512 {
513   // NULL, means being shutdown, so ignore msgs
514   if( mSceneGraphBuffers != NULL )
515   {
516     typedef MessageValue1< TextureCache, ResourceId > DerivedType;
517
518     // Reserve some memory inside the render queue
519     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
520
521     // Construct message in the render queue memory; note that delete should not be called on the return value
522     new (slot) DerivedType( this, &TextureCache::DiscardTexture, id );
523   }
524 }
525
526 } // SceneGraph
527
528 } // Internal
529
530 } // Dali