2 * Copyright (c) 2014 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <dali/internal/render/gl-resources/texture-cache.h>
20 #include <dali/integration-api/bitmap.h>
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>
33 #include <dali/integration-api/debug.h>
35 using Dali::Internal::Texture;
36 using Dali::Internal::FrameBufferTexture;
37 using Dali::Integration::Bitmap;
41 #if defined(DEBUG_ENABLED)
42 Debug::Filter* gTextureCacheFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TEXTURE_CACHE");
52 // value types used by messages
53 template <> struct ParameterType< Pixel::Format > : public BasicType< Pixel::Format > {};
58 TextureCache::TextureCache( RenderQueue& renderQueue,
59 PostProcessResourceDispatcher& postProcessResourceDispatcher,
61 : TextureCacheDispatcher(renderQueue),
62 mPostProcessResourceDispatcher(postProcessResourceDispatcher),
64 mDiscardBitmapsPolicy(ResourcePolicy::DISCARD)
68 TextureCache::~TextureCache()
72 void TextureCache::CreateTexture( ResourceId id,
75 Pixel::Format pixelFormat,
78 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::CreateTexture(id=%i width:%u height:%u)\n", id, width, height);
80 Texture* texture = TextureFactory::NewBitmapTexture(width, height, pixelFormat, clearPixels, mContext, GetDiscardBitmapsPolicy() );
81 mTextures.insert(TexturePair(id, texture));
84 void TextureCache::AddBitmap(ResourceId id, Integration::BitmapPtr bitmap)
86 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddBitmap(id=%i Bitmap:%p)\n", id, bitmap.Get());
88 Texture* texture = TextureFactory::NewBitmapTexture(bitmap.Get(), mContext, GetDiscardBitmapsPolicy());
89 mTextures.insert(TexturePair(id, texture));
92 void TextureCache::AddNativeImage(ResourceId id, NativeImagePtr nativeImage)
94 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddNativeImage(id=%i NativeImg:%p)\n", id, nativeImage.Get());
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));
101 void TextureCache::AddFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
103 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddFrameBuffer(id=%i width:%u height:%u)\n", id, width, height);
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));
111 void TextureCache::AddFrameBuffer( ResourceId id, NativeImagePtr nativeImage )
113 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddFrameBuffer(id=%i width:%u height:%u)\n", id, nativeImage->GetWidth(), nativeImage->GetHeight());
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));
121 void TextureCache::UpdateTexture( ResourceId id, Integration::BitmapPtr bitmap )
123 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(id=%i bitmap:%p )\n", id, bitmap.Get());
125 TextureIter textureIter = mTextures.find(id);
126 if( textureIter != mTextures.end() )
128 // we have reloaded the image from file, update texture
129 TexturePointer texturePtr = textureIter->second;
132 texturePtr->Update( bitmap.Get() );
134 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
135 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
140 void TextureCache::UpdateTexture( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
142 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(destId=%i srcId=%i )\n", destId, srcId );
144 BitmapTexture* srcTexture = TextureCache::GetBitmapTexture( srcId );
145 Integration::Bitmap* srcBitmap = ( srcTexture != NULL ) ? srcTexture->GetBitmap() : NULL;
149 TextureIter textureIter = mTextures.find( destId );
150 if( textureIter != mTextures.end() )
152 TexturePointer texturePtr = textureIter->second;
155 texturePtr->Update( srcBitmap, xOffset, yOffset );
157 ResourcePostProcessRequest ppRequest( srcId, ResourcePostProcessRequest::UPLOADED );
158 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
164 void TextureCache::UpdateTextureArea( ResourceId id, const Dali::RectArea& area )
166 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTextureArea(id=%i)\n", id );
168 TextureIter textureIter = mTextures.find(id);
169 if( textureIter != mTextures.end() )
171 TexturePointer texturePtr = textureIter->second;
174 texturePtr->UpdateArea( area );
176 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
177 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
182 void TextureCache::AddBitmapUploadArray( ResourceId id, const BitmapUploadArray& uploadArray )
184 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddBitmapUploadArray(id=%i )\n", id);
186 TextureIter textureIter = mTextures.find(id);
188 DALI_ASSERT_DEBUG( textureIter != mTextures.end() );
189 if( textureIter != mTextures.end() )
191 TexturePointer texturePtr = textureIter->second;
194 BitmapTexture* texture = static_cast< BitmapTexture* >( texturePtr.Get() );
195 texture->UploadBitmapArray( uploadArray );
200 void TextureCache::ClearAreas( ResourceId id,
201 const BitmapClearArray& areaArray,
202 std::size_t blockSize,
205 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::ClearAreas(id: %d)\n", id);
206 TextureIter textureIter = mTextures.find(id);
207 DALI_ASSERT_DEBUG( textureIter != mTextures.end() );
208 if( textureIter != mTextures.end() )
210 TexturePointer texturePtr = textureIter->second;
213 BitmapTexture* texture = static_cast< BitmapTexture* >( texturePtr.Get() );
214 texture->ClearAreas( areaArray, blockSize, color );
219 void TextureCache::DiscardTexture( ResourceId id )
221 bool deleted = false;
223 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::DiscardTexture(id:%u)\n", id);
225 if( mTextures.size() > 0)
227 TextureIter iter = mTextures.find(id);
228 if( iter != mTextures.end() )
230 TexturePointer texturePtr = iter->second;
233 // if valid texture pointer, cleanup GL resources
234 texturePtr->GlCleanup();
236 mTextures.erase(iter);
241 if( mFramebufferTextures.size() > 0)
243 TextureIter iter = mFramebufferTextures.find(id);
244 if( iter != mFramebufferTextures.end() )
246 TexturePointer texturePtr = iter->second;
249 // if valid texture pointer, cleanup GL resources
250 texturePtr->GlCleanup();
252 mFramebufferTextures.erase(iter);
259 if( mObservers.size() > 0 )
261 TextureResourceObserversIter observersIter = mObservers.find(id);
262 if( observersIter != mObservers.end() )
264 TextureObservers observers = observersIter->second;
265 for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
267 TextureObserver* observer = *iter;
268 observer->TextureDiscarded( id );
271 mObservers.erase( observersIter );
275 // Tell resource manager
276 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::DELETED );
277 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
281 void TextureCache::BindTexture( Texture *texture, ResourceId id, GLenum target, TextureUnit textureunit )
283 bool created = texture->Bind(target, textureunit);
284 if( created && texture->UpdateOnCreate() ) // i.e. the pixel data was sent to GL
286 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
287 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
291 Texture* TextureCache::GetTexture(ResourceId id)
293 Texture* texture = NULL;
294 TextureIter iter = mTextures.find(id);
296 if( iter != mTextures.end() )
298 TexturePointer texturePtr = iter->second;
301 texture = texturePtr.Get();
305 if( texture == NULL )
307 TextureIter iter = mFramebufferTextures.find(id);
308 if( iter != mFramebufferTextures.end() )
310 TexturePointer texturePtr = iter->second;
313 texture = texturePtr.Get();
318 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetTexture(id:%u) : %p\n", id, texture);
323 BitmapTexture* TextureCache::GetBitmapTexture(ResourceId id)
325 BitmapTexture* texture = NULL;
326 TextureIter iter = mTextures.find( id );
328 if( iter != mTextures.end() )
330 TexturePointer texturePtr = iter->second;
333 texture = dynamic_cast< BitmapTexture* >( texturePtr.Get() );
340 FrameBufferTexture* TextureCache::GetFramebuffer(ResourceId id)
342 FrameBufferTexture* offscreen = NULL;
343 TextureIter iter = mFramebufferTextures.find(id);
345 DALI_ASSERT_DEBUG( iter != mFramebufferTextures.end() );
347 if( iter != mFramebufferTextures.end() )
349 TexturePointer texturePtr = iter->second;
352 offscreen = dynamic_cast< FrameBufferTexture* >( texturePtr.Get() );
355 DALI_ASSERT_DEBUG( offscreen );
357 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetFramebuffer(id:%u) : %p\n", id, offscreen);
362 void TextureCache::AddObserver( ResourceId id, TextureObserver* observer )
364 TextureResourceObserversIter observersIter = mObservers.find(id);
365 if( observersIter != mObservers.end() )
367 TextureObservers& observers = observersIter->second;
368 bool foundObserver = false;
369 for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
371 if( *iter == observer )
373 foundObserver = true;
377 if( ! foundObserver )
379 observers.push_back(observer);
384 TextureObservers observers;
385 observers.push_back(observer);
386 mObservers.insert(std::pair<ResourceId, TextureObservers>(id, observers));
390 void TextureCache::RemoveObserver( ResourceId id, TextureObserver* observer )
392 TextureResourceObserversIter observersIter = mObservers.find(id);
393 if( observersIter != mObservers.end() )
395 TextureObservers& observers = observersIter->second;
396 for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
398 if(*iter == observer)
400 observers.erase(iter);
407 void TextureCache::GlContextDestroyed()
409 TextureIter end = mTextures.end();
410 TextureIter iter = mTextures.begin();
411 for( ; iter != end; ++iter )
413 (*iter->second).GlContextDestroyed(); // map holds intrusive pointers
416 end = mFramebufferTextures.end();
417 iter = mFramebufferTextures.begin();
418 for( ; iter != end; ++iter )
420 (*iter->second).GlContextDestroyed(); // map holds intrusive pointers
424 void TextureCache::SetDiscardBitmapsPolicy( ResourcePolicy::Discardable policy )
426 DALI_LOG_INFO( gTextureCacheFilter, Debug::General, "TextureCache::SetDiscardBitmapsPolicy(%s)\n",
427 policy==ResourcePolicy::RETAIN?"RETAIN":"DISCARD" );
428 mDiscardBitmapsPolicy = policy;
431 ResourcePolicy::Discardable TextureCache::GetDiscardBitmapsPolicy()
433 return mDiscardBitmapsPolicy;
437 /********************************************************************************
438 ********************** Implements TextureCacheDispatcher *********************
439 ********************************************************************************/
441 void TextureCache::DispatchCreateTexture( ResourceId id,
444 Pixel::Format pixelFormat,
447 // NULL, means being shutdown, so ignore msgs
448 if( mSceneGraphBuffers != NULL )
450 typedef MessageValue5< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format, bool > DerivedType;
452 // Reserve some memory inside the render queue
453 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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::CreateTexture, id, width, height, pixelFormat, clearPixels );
460 void TextureCache::DispatchCreateTextureForBitmap( ResourceId id, Bitmap* bitmap )
462 // NULL, means being shutdown, so ignore msgs
463 if( mSceneGraphBuffers != NULL )
465 typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
467 // Reserve some memory inside the render queue
468 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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::AddBitmap, id, bitmap );
475 void TextureCache::DispatchCreateTextureForNativeImage( ResourceId id, NativeImagePtr nativeImage )
477 // NULL, means being shutdown, so ignore msgs
478 if( mSceneGraphBuffers != NULL )
480 typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > DerivedType;
482 // Reserve some memory inside the render queue
483 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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::AddNativeImage, id, nativeImage );
490 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
492 // NULL, means being shutdown, so ignore msgs
493 if( mSceneGraphBuffers != NULL )
495 typedef MessageValue4< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format > DerivedType;
497 // Reserve some memory inside the render queue
498 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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::AddFrameBuffer, id, width, height, pixelFormat );
505 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, NativeImagePtr nativeImage )
507 // NULL, means being shutdown, so ignore msgs
508 if( mSceneGraphBuffers != NULL )
510 typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > DerivedType;
512 // Reserve some memory inside the render queue
513 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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::AddFrameBuffer, id, nativeImage );
520 void TextureCache::DispatchUpdateTexture( ResourceId id, Bitmap* bitmap )
522 // NULL, means being shutdown, so ignore msgs
523 if( mSceneGraphBuffers != NULL )
525 typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
527 // Reserve some memory inside the render queue
528 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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, id, bitmap );
535 void TextureCache::DispatchUpdateTexture( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
537 // NULL, means being shutdown, so ignore msgs
538 if( mSceneGraphBuffers != NULL )
540 typedef MessageValue4< TextureCache, ResourceId, ResourceId, std::size_t, std::size_t > DerivedType;
542 // Reserve some memory inside the render queue
543 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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::UpdateTexture, destId, srcId, xOffset, yOffset );
550 void TextureCache::DispatchUpdateTextureArea( ResourceId id, const Dali::RectArea& area )
552 // NULL, means being shutdown, so ignore msgs
553 if( mSceneGraphBuffers != NULL )
555 typedef MessageValue2< TextureCache, ResourceId, Dali::RectArea > DerivedType;
557 // Reserve some memory inside the render queue
558 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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::UpdateTextureArea, id, area );
565 void TextureCache::DispatchUploadBitmapArrayToTexture( ResourceId id, const BitmapUploadArray& uploadArray )
567 // NULL, means being shutdown, so ignore msgs
568 if( mSceneGraphBuffers != NULL )
570 typedef MessageValue2< TextureCache, ResourceId, BitmapUploadArray > DerivedType;
572 // Reserve some memory inside the render queue
573 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
575 // Construct message in the render queue memory; note that delete should not be called on the return value
576 new (slot) DerivedType( this, &TextureCache::AddBitmapUploadArray, id, uploadArray );
580 void TextureCache::DispatchClearAreas( ResourceId id, const BitmapClearArray& areaArray, std::size_t blockSize, uint32_t color )
582 // NULL, means being shutdown, so ignore msgs
583 if( mSceneGraphBuffers != NULL )
585 typedef MessageValue4< TextureCache, ResourceId, BitmapClearArray, std::size_t, uint32_t > DerivedType;
587 // Reserve some memory inside the render queue
588 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
590 // Construct message in the render queue memory; note that delete should not be called on the return value
591 new (slot) DerivedType( this, &TextureCache::ClearAreas, id, areaArray, blockSize, color );
595 void TextureCache::DispatchDiscardTexture( ResourceId id )
597 // NULL, means being shutdown, so ignore msgs
598 if( mSceneGraphBuffers != NULL )
600 typedef MessageValue1< TextureCache, ResourceId > DerivedType;
602 // Reserve some memory inside the render queue
603 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
605 // Construct message in the render queue memory; note that delete should not be called on the return value
606 new (slot) DerivedType( this, &TextureCache::DiscardTexture, id );