Revert "License conversion from Flora to Apache 2.0"
[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 void TextureCache::GlContextDestroyed()
358 {
359   TextureIter end = mTextures.end();
360   TextureIter iter = mTextures.begin();
361   for( ; iter != end; ++iter )
362   {
363     (*iter->second).GlContextDestroyed(); // map holds intrusive pointers
364   }
365 }
366
367 /********************************************************************************
368  **********************  Implements TextureCacheDispatcher  *********************
369  ********************************************************************************/
370
371 void TextureCache::DispatchCreateTexture( ResourceId        id,
372                                           unsigned int      width,
373                                           unsigned int      height,
374                                           Pixel::Format     pixelFormat,
375                                           bool              clearPixels )
376 {
377   // NULL, means being shutdown, so ignore msgs
378   if( mSceneGraphBuffers != NULL )
379   {
380     typedef MessageValue5< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format, bool > DerivedType;
381
382     // Reserve some memory inside the render queue
383     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
384
385     // Construct message in the render queue memory; note that delete should not be called on the return value
386     new (slot) DerivedType( this, &TextureCache::CreateTexture, id, width, height, pixelFormat, clearPixels );
387   }
388 }
389
390 void TextureCache::DispatchCreateTextureForBitmap( ResourceId id, Bitmap* bitmap )
391 {
392   // NULL, means being shutdown, so ignore msgs
393   if( mSceneGraphBuffers != NULL )
394   {
395     typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
396
397     // Reserve some memory inside the render queue
398     unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
399
400     // Construct message in the render queue memory; note that delete should not be called on the return value
401     new (slot) DerivedType( this, &TextureCache::AddBitmap, id, bitmap );
402   }
403 }
404
405 void TextureCache::DispatchCreateTextureForNativeImage( ResourceId id, NativeImagePtr nativeImage )
406 {
407   // NULL, means being shutdown, so ignore msgs
408   if( mSceneGraphBuffers != NULL )
409   {
410     typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > 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::AddNativeImage, id, nativeImage );
417   }
418 }
419
420 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
421 {
422   // NULL, means being shutdown, so ignore msgs
423   if( mSceneGraphBuffers != NULL )
424   {
425     typedef MessageValue4< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format > 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::AddFrameBuffer, id, width, height, pixelFormat );
432   }
433 }
434
435 void TextureCache::DispatchCreateTextureForFrameBuffer( 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::AddFrameBuffer, id, nativeImage );
447   }
448 }
449
450 void TextureCache::DispatchUpdateTexture( ResourceId id, Bitmap* bitmap )
451 {
452   // NULL, means being shutdown, so ignore msgs
453   if( mSceneGraphBuffers != NULL )
454   {
455     typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > 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::UpdateTexture, id, bitmap );
462   }
463 }
464
465 void TextureCache::DispatchUpdateTextureArea( ResourceId id, const Dali::RectArea& area )
466 {
467   // NULL, means being shutdown, so ignore msgs
468   if( mSceneGraphBuffers != NULL )
469   {
470     typedef MessageValue2< TextureCache, ResourceId, Dali::RectArea > 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::UpdateTextureArea, id, area );
477   }
478 }
479
480 void TextureCache::DispatchUploadBitmapArrayToTexture( ResourceId id, const BitmapUploadArray& uploadArray )
481 {
482   // NULL, means being shutdown, so ignore msgs
483   if( mSceneGraphBuffers != NULL )
484   {
485     typedef MessageValue2< TextureCache, ResourceId, BitmapUploadArray > 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::AddBitmapUploadArray, id, uploadArray );
492   }
493 }
494
495 void TextureCache::DispatchClearAreas( ResourceId id, const BitmapClearArray& areaArray, std::size_t blockSize, uint32_t color )
496 {
497   // NULL, means being shutdown, so ignore msgs
498   if( mSceneGraphBuffers != NULL )
499   {
500     typedef MessageValue4< TextureCache, ResourceId, BitmapClearArray, std::size_t, uint32_t > 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::ClearAreas, id, areaArray, blockSize, color );
507   }
508 }
509
510 void TextureCache::DispatchDiscardTexture( ResourceId id )
511 {
512   // NULL, means being shutdown, so ignore msgs
513   if( mSceneGraphBuffers != NULL )
514   {
515     typedef MessageValue1< TextureCache, ResourceId > 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::DiscardTexture, id );
522   }
523 }
524
525 } // SceneGraph
526
527 } // Internal
528
529 } // Dali