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