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