Merge "Fix the framebuffer texture context loss handling" into 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   end = mFramebufferTextures.end();
368   iter = mFramebufferTextures.begin();
369   for( ; iter != end; ++iter )
370   {
371     (*iter->second).GlContextDestroyed(); // map holds intrusive pointers
372   }
373 }
374
375 /********************************************************************************
376  **********************  Implements TextureCacheDispatcher  *********************
377  ********************************************************************************/
378
379 void TextureCache::DispatchCreateTexture( ResourceId        id,
380                                           unsigned int      width,
381                                           unsigned int      height,
382                                           Pixel::Format     pixelFormat,
383                                           bool              clearPixels )
384 {
385   // NULL, means being shutdown, so ignore msgs
386   if( mSceneGraphBuffers != NULL )
387   {
388     typedef MessageValue5< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format, bool > DerivedType;
389
390     // Reserve some memory inside the render queue
391     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
392
393     // Construct message in the render queue memory; note that delete should not be called on the return value
394     new (slot) DerivedType( this, &TextureCache::CreateTexture, id, width, height, pixelFormat, clearPixels );
395   }
396 }
397
398 void TextureCache::DispatchCreateTextureForBitmap( ResourceId id, Bitmap* bitmap )
399 {
400   // NULL, means being shutdown, so ignore msgs
401   if( mSceneGraphBuffers != NULL )
402   {
403     typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
404
405     // Reserve some memory inside the render queue
406     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
407
408     // Construct message in the render queue memory; note that delete should not be called on the return value
409     new (slot) DerivedType( this, &TextureCache::AddBitmap, id, bitmap );
410   }
411 }
412
413 void TextureCache::DispatchCreateTextureForNativeImage( ResourceId id, NativeImagePtr nativeImage )
414 {
415   // NULL, means being shutdown, so ignore msgs
416   if( mSceneGraphBuffers != NULL )
417   {
418     typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > DerivedType;
419
420     // Reserve some memory inside the render queue
421     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
422
423     // Construct message in the render queue memory; note that delete should not be called on the return value
424     new (slot) DerivedType( this, &TextureCache::AddNativeImage, id, nativeImage );
425   }
426 }
427
428 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
429 {
430   // NULL, means being shutdown, so ignore msgs
431   if( mSceneGraphBuffers != NULL )
432   {
433     typedef MessageValue4< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format > DerivedType;
434
435     // Reserve some memory inside the render queue
436     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
437
438     // Construct message in the render queue memory; note that delete should not be called on the return value
439     new (slot) DerivedType( this, &TextureCache::AddFrameBuffer, id, width, height, pixelFormat );
440   }
441 }
442
443 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, NativeImagePtr nativeImage )
444 {
445   // NULL, means being shutdown, so ignore msgs
446   if( mSceneGraphBuffers != NULL )
447   {
448     typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > DerivedType;
449
450     // Reserve some memory inside the render queue
451     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
452
453     // Construct message in the render queue memory; note that delete should not be called on the return value
454     new (slot) DerivedType( this, &TextureCache::AddFrameBuffer, id, nativeImage );
455   }
456 }
457
458 void TextureCache::DispatchUpdateTexture( ResourceId id, Bitmap* bitmap )
459 {
460   // NULL, means being shutdown, so ignore msgs
461   if( mSceneGraphBuffers != NULL )
462   {
463     typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
464
465     // Reserve some memory inside the render queue
466     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
467
468     // Construct message in the render queue memory; note that delete should not be called on the return value
469     new (slot) DerivedType( this, &TextureCache::UpdateTexture, id, bitmap );
470   }
471 }
472
473 void TextureCache::DispatchUpdateTextureArea( ResourceId id, const Dali::RectArea& area )
474 {
475   // NULL, means being shutdown, so ignore msgs
476   if( mSceneGraphBuffers != NULL )
477   {
478     typedef MessageValue2< TextureCache, ResourceId, Dali::RectArea > DerivedType;
479
480     // Reserve some memory inside the render queue
481     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
482
483     // Construct message in the render queue memory; note that delete should not be called on the return value
484     new (slot) DerivedType( this, &TextureCache::UpdateTextureArea, id, area );
485   }
486 }
487
488 void TextureCache::DispatchUploadBitmapArrayToTexture( ResourceId id, const BitmapUploadArray& uploadArray )
489 {
490   // NULL, means being shutdown, so ignore msgs
491   if( mSceneGraphBuffers != NULL )
492   {
493     typedef MessageValue2< TextureCache, ResourceId, BitmapUploadArray > DerivedType;
494
495     // Reserve some memory inside the render queue
496     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
497
498     // Construct message in the render queue memory; note that delete should not be called on the return value
499     new (slot) DerivedType( this, &TextureCache::AddBitmapUploadArray, id, uploadArray );
500   }
501 }
502
503 void TextureCache::DispatchClearAreas( ResourceId id, const BitmapClearArray& areaArray, std::size_t blockSize, uint32_t color )
504 {
505   // NULL, means being shutdown, so ignore msgs
506   if( mSceneGraphBuffers != NULL )
507   {
508     typedef MessageValue4< TextureCache, ResourceId, BitmapClearArray, std::size_t, uint32_t > DerivedType;
509
510     // Reserve some memory inside the render queue
511     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
512
513     // Construct message in the render queue memory; note that delete should not be called on the return value
514     new (slot) DerivedType( this, &TextureCache::ClearAreas, id, areaArray, blockSize, color );
515   }
516 }
517
518 void TextureCache::DispatchDiscardTexture( ResourceId id )
519 {
520   // NULL, means being shutdown, so ignore msgs
521   if( mSceneGraphBuffers != NULL )
522   {
523     typedef MessageValue1< TextureCache, ResourceId > DerivedType;
524
525     // Reserve some memory inside the render queue
526     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
527
528     // Construct message in the render queue memory; note that delete should not be called on the return value
529     new (slot) DerivedType( this, &TextureCache::DiscardTexture, id );
530   }
531 }
532
533 } // SceneGraph
534
535 } // Internal
536
537 } // Dali