Updates to handle context loss and regain
[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, NativeImagePtr 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, NativeImagePtr 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::UpdateTextureArea( ResourceId id, const Dali::RectArea& area )
141 {
142   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTextureArea(id=%i)\n", id );
143
144   TextureIter textureIter = mTextures.find(id);
145   if( textureIter != mTextures.end() )
146   {
147     TexturePointer texturePtr = textureIter->second;
148     if( texturePtr )
149     {
150       texturePtr->UpdateArea( area );
151
152       ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
153       mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
154     }
155   }
156 }
157
158 void TextureCache::AddBitmapUploadArray( ResourceId id, const BitmapUploadArray& uploadArray )
159 {
160   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddBitmapUploadArray(id=%i )\n", id);
161
162   TextureIter textureIter = mTextures.find(id);
163
164   DALI_ASSERT_DEBUG( textureIter != mTextures.end() );
165   if( textureIter != mTextures.end() )
166   {
167     TexturePointer texturePtr = textureIter->second;
168     if( texturePtr )
169     {
170       BitmapTexture* texture = static_cast< BitmapTexture* >( texturePtr.Get() );
171       texture->UploadBitmapArray( uploadArray );
172     }
173   }
174 }
175
176 void TextureCache::ClearAreas( ResourceId id,
177                                const BitmapClearArray& areaArray,
178                                std::size_t blockSize,
179                                uint32_t color )
180 {
181   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::ClearAreas(id: %d)\n", id);
182   TextureIter textureIter = mTextures.find(id);
183   DALI_ASSERT_DEBUG( textureIter != mTextures.end() );
184   if( textureIter != mTextures.end() )
185   {
186     TexturePointer texturePtr = textureIter->second;
187     if( texturePtr )
188     {
189       BitmapTexture* texture = static_cast< BitmapTexture* >( texturePtr.Get() );
190       texture->ClearAreas( areaArray, blockSize, color );
191     }
192   }
193 }
194
195 void TextureCache::DiscardTexture( ResourceId id )
196 {
197   bool deleted = false;
198
199   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::DiscardTexture(id:%u)\n", id);
200
201   if( mTextures.size() > 0)
202   {
203     TextureIter iter = mTextures.find(id);
204     if( iter != mTextures.end() )
205     {
206       TexturePointer texturePtr = iter->second;
207       if( texturePtr )
208       {
209         // if valid texture pointer, cleanup GL resources
210         texturePtr->GlCleanup();
211       }
212       mTextures.erase(iter);
213       deleted = true;
214     }
215   }
216
217   if( mFramebufferTextures.size() > 0)
218   {
219     TextureIter iter = mFramebufferTextures.find(id);
220     if( iter != mFramebufferTextures.end() )
221     {
222       TexturePointer texturePtr = iter->second;
223       if( texturePtr )
224       {
225         // if valid texture pointer, cleanup GL resources
226         texturePtr->GlCleanup();
227       }
228       mFramebufferTextures.erase(iter);
229       deleted = true;
230     }
231   }
232
233   if(deleted)
234   {
235     if( mObservers.size() > 0 )
236     {
237       TextureResourceObserversIter observersIter = mObservers.find(id);
238       if( observersIter != mObservers.end() )
239       {
240         TextureObservers observers = observersIter->second;
241         for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
242         {
243           TextureObserver* observer = *iter;
244           observer->TextureDiscarded( id );
245         }
246
247         mObservers.erase( observersIter );
248       }
249     }
250
251     // Tell resource manager
252     ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::DELETED );
253     mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
254   }
255 }
256
257 void TextureCache::BindTexture( Texture *texture, ResourceId id, GLenum target, GLenum textureunit )
258 {
259   bool created = texture->Bind(target, textureunit);
260   if( created && texture->UpdateOnCreate() ) // i.e. the pixel data was sent to GL
261   {
262     ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
263     mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
264   }
265 }
266
267
268 Texture* TextureCache::GetTexture(ResourceId id)
269 {
270   Texture* texture = NULL;
271   TextureIter iter = mTextures.find(id);
272
273   if( iter != mTextures.end() )
274   {
275     TexturePointer texturePtr = iter->second;
276     if( texturePtr )
277     {
278       texture = texturePtr.Get();
279     }
280   }
281
282   if( texture == NULL )
283   {
284     TextureIter iter = mFramebufferTextures.find(id);
285     if( iter != mFramebufferTextures.end() )
286     {
287       TexturePointer texturePtr = iter->second;
288       if( texturePtr )
289       {
290         texture = texturePtr.Get();
291       }
292     }
293   }
294
295   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetTexture(id:%u) : %p\n", id, texture);
296
297   return texture;
298 }
299
300 FrameBufferTexture* TextureCache::GetFramebuffer(ResourceId id)
301 {
302   FrameBufferTexture* offscreen = NULL;
303   TextureIter iter = mFramebufferTextures.find(id);
304
305   DALI_ASSERT_DEBUG( iter != mFramebufferTextures.end() );
306
307   if( iter != mFramebufferTextures.end() )
308   {
309     TexturePointer texturePtr = iter->second;
310     if( texturePtr )
311     {
312       offscreen = dynamic_cast< FrameBufferTexture* >( texturePtr.Get() );
313     }
314   }
315   DALI_ASSERT_DEBUG( offscreen );
316
317   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetFramebuffer(id:%u) : %p\n", id, offscreen);
318
319   return offscreen;
320 }
321
322 void TextureCache::AddObserver( ResourceId id, TextureObserver* observer )
323 {
324   TextureResourceObserversIter observersIter = mObservers.find(id);
325   if( observersIter != mObservers.end() )
326   {
327     TextureObservers& observers = observersIter->second;
328     bool foundObserver = false;
329     for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
330     {
331       if( *iter == observer )
332       {
333         foundObserver = true;
334         break;
335       }
336     }
337     if( ! foundObserver )
338     {
339       observers.push_back(observer);
340     }
341   }
342   else
343   {
344     TextureObservers observers;
345     observers.push_back(observer);
346     mObservers.insert(std::pair<ResourceId, TextureObservers>(id, observers));
347   }
348 }
349
350 void TextureCache::RemoveObserver( ResourceId id, TextureObserver* observer )
351 {
352   TextureResourceObserversIter observersIter = mObservers.find(id);
353   if( observersIter != mObservers.end() )
354   {
355     TextureObservers& observers = observersIter->second;
356     for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
357     {
358       if(*iter == observer)
359       {
360         observers.erase(iter);
361         break;
362       }
363     }
364   }
365 }
366
367 void TextureCache::GlContextDestroyed()
368 {
369   TextureIter end = mTextures.end();
370   TextureIter iter = mTextures.begin();
371   for( ; iter != end; ++iter )
372   {
373     (*iter->second).GlContextDestroyed(); // map holds intrusive pointers
374   }
375
376   end = mFramebufferTextures.end();
377   iter = mFramebufferTextures.begin();
378   for( ; iter != end; ++iter )
379   {
380     (*iter->second).GlContextDestroyed(); // map holds intrusive pointers
381   }
382 }
383
384 void TextureCache::SetDiscardBitmapsPolicy( ResourcePolicy::Discardable policy )
385 {
386   DALI_LOG_INFO( gTextureCacheFilter, Debug::General, "TextureCache::SetDiscardBitmapsPolicy(%s)\n",
387                  policy==ResourcePolicy::RETAIN?"RETAIN":"DISCARD" );
388   mDiscardBitmapsPolicy = policy;
389 }
390
391 ResourcePolicy::Discardable TextureCache::GetDiscardBitmapsPolicy()
392 {
393   return mDiscardBitmapsPolicy;
394 }
395
396
397 /********************************************************************************
398  **********************  Implements TextureCacheDispatcher  *********************
399  ********************************************************************************/
400
401 void TextureCache::DispatchCreateTexture( ResourceId        id,
402                                           unsigned int      width,
403                                           unsigned int      height,
404                                           Pixel::Format     pixelFormat,
405                                           bool              clearPixels )
406 {
407   // NULL, means being shutdown, so ignore msgs
408   if( mSceneGraphBuffers != NULL )
409   {
410     typedef MessageValue5< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format, bool > DerivedType;
411
412     // Reserve some memory inside the render queue
413     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
414
415     // Construct message in the render queue memory; note that delete should not be called on the return value
416     new (slot) DerivedType( this, &TextureCache::CreateTexture, id, width, height, pixelFormat, clearPixels );
417   }
418 }
419
420 void TextureCache::DispatchCreateTextureForBitmap( ResourceId id, Bitmap* bitmap )
421 {
422   // NULL, means being shutdown, so ignore msgs
423   if( mSceneGraphBuffers != NULL )
424   {
425     typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
426
427     // Reserve some memory inside the render queue
428     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
429
430     // Construct message in the render queue memory; note that delete should not be called on the return value
431     new (slot) DerivedType( this, &TextureCache::AddBitmap, id, bitmap );
432   }
433 }
434
435 void TextureCache::DispatchCreateTextureForNativeImage( ResourceId id, NativeImagePtr nativeImage )
436 {
437   // NULL, means being shutdown, so ignore msgs
438   if( mSceneGraphBuffers != NULL )
439   {
440     typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > DerivedType;
441
442     // Reserve some memory inside the render queue
443     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
444
445     // Construct message in the render queue memory; note that delete should not be called on the return value
446     new (slot) DerivedType( this, &TextureCache::AddNativeImage, id, nativeImage );
447   }
448 }
449
450 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
451 {
452   // NULL, means being shutdown, so ignore msgs
453   if( mSceneGraphBuffers != NULL )
454   {
455     typedef MessageValue4< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format > DerivedType;
456
457     // Reserve some memory inside the render queue
458     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
459
460     // Construct message in the render queue memory; note that delete should not be called on the return value
461     new (slot) DerivedType( this, &TextureCache::AddFrameBuffer, id, width, height, pixelFormat );
462   }
463 }
464
465 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, NativeImagePtr nativeImage )
466 {
467   // NULL, means being shutdown, so ignore msgs
468   if( mSceneGraphBuffers != NULL )
469   {
470     typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > DerivedType;
471
472     // Reserve some memory inside the render queue
473     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
474
475     // Construct message in the render queue memory; note that delete should not be called on the return value
476     new (slot) DerivedType( this, &TextureCache::AddFrameBuffer, id, nativeImage );
477   }
478 }
479
480 void TextureCache::DispatchUpdateTexture( ResourceId id, Bitmap* bitmap )
481 {
482   // NULL, means being shutdown, so ignore msgs
483   if( mSceneGraphBuffers != NULL )
484   {
485     typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
486
487     // Reserve some memory inside the render queue
488     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
489
490     // Construct message in the render queue memory; note that delete should not be called on the return value
491     new (slot) DerivedType( this, &TextureCache::UpdateTexture, id, bitmap );
492   }
493 }
494
495 void TextureCache::DispatchUpdateTextureArea( ResourceId id, const Dali::RectArea& area )
496 {
497   // NULL, means being shutdown, so ignore msgs
498   if( mSceneGraphBuffers != NULL )
499   {
500     typedef MessageValue2< TextureCache, ResourceId, Dali::RectArea > DerivedType;
501
502     // Reserve some memory inside the render queue
503     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
504
505     // Construct message in the render queue memory; note that delete should not be called on the return value
506     new (slot) DerivedType( this, &TextureCache::UpdateTextureArea, id, area );
507   }
508 }
509
510 void TextureCache::DispatchUploadBitmapArrayToTexture( ResourceId id, const BitmapUploadArray& uploadArray )
511 {
512   // NULL, means being shutdown, so ignore msgs
513   if( mSceneGraphBuffers != NULL )
514   {
515     typedef MessageValue2< TextureCache, ResourceId, BitmapUploadArray > DerivedType;
516
517     // Reserve some memory inside the render queue
518     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
519
520     // Construct message in the render queue memory; note that delete should not be called on the return value
521     new (slot) DerivedType( this, &TextureCache::AddBitmapUploadArray, id, uploadArray );
522   }
523 }
524
525 void TextureCache::DispatchClearAreas( ResourceId id, const BitmapClearArray& areaArray, std::size_t blockSize, uint32_t color )
526 {
527   // NULL, means being shutdown, so ignore msgs
528   if( mSceneGraphBuffers != NULL )
529   {
530     typedef MessageValue4< TextureCache, ResourceId, BitmapClearArray, std::size_t, uint32_t > DerivedType;
531
532     // Reserve some memory inside the render queue
533     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
534
535     // Construct message in the render queue memory; note that delete should not be called on the return value
536     new (slot) DerivedType( this, &TextureCache::ClearAreas, id, areaArray, blockSize, color );
537   }
538 }
539
540 void TextureCache::DispatchDiscardTexture( ResourceId id )
541 {
542   // NULL, means being shutdown, so ignore msgs
543   if( mSceneGraphBuffers != NULL )
544   {
545     typedef MessageValue1< TextureCache, ResourceId > DerivedType;
546
547     // Reserve some memory inside the render queue
548     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
549
550     // Construct message in the render queue memory; note that delete should not be called on the return value
551     new (slot) DerivedType( this, &TextureCache::DiscardTexture, id );
552   }
553 }
554
555 } // SceneGraph
556
557 } // Internal
558
559 } // Dali