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 > {};
54 template <> struct ParameterType< RenderBuffer::Format > : public BasicType< RenderBuffer::Format > {};
63 * @brief Forward to all textures in container the news that the GL Context is down.
65 void GlContextDestroyed( TextureContainer& textures )
67 TextureIter end = textures.end();
68 TextureIter iter = textures.begin();
69 for( ; iter != end; ++iter )
71 (*iter->second).GlContextDestroyed();
77 TextureCache::TextureCache( RenderQueue& renderQueue,
78 PostProcessResourceDispatcher& postProcessResourceDispatcher,
80 : TextureCacheDispatcher(renderQueue),
81 mPostProcessResourceDispatcher(postProcessResourceDispatcher),
83 mDiscardBitmapsPolicy(ResourcePolicy::OWNED_DISCARD)
87 TextureCache::~TextureCache()
91 void TextureCache::CreateTexture( ResourceId id,
94 Pixel::Format pixelFormat,
97 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::CreateTexture(id=%i width:%u height:%u)\n", id, width, height);
99 Texture* texture = TextureFactory::NewBitmapTexture(width, height, pixelFormat, clearPixels, mContext, GetDiscardBitmapsPolicy() );
100 mTextures.insert(TexturePair(id, texture));
103 void TextureCache::AddBitmap(ResourceId id, Integration::BitmapPtr bitmap)
105 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddBitmap(id=%i Bitmap:%p)\n", id, bitmap.Get());
107 Texture* texture = TextureFactory::NewBitmapTexture(bitmap.Get(), mContext, GetDiscardBitmapsPolicy());
108 mTextures.insert(TexturePair(id, texture));
111 void TextureCache::AddNativeImage(ResourceId id, NativeImageInterfacePtr nativeImage)
113 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddNativeImage(id=%i NativeImg:%p)\n", id, nativeImage.Get());
115 /// TODO - currently a new Texture is created even if we reuse the same NativeImage
116 Texture* texture = TextureFactory::NewNativeImageTexture(*nativeImage, mContext);
117 mTextures.insert(TexturePair(id, texture));
120 void TextureCache::AddFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat, RenderBuffer::Format bufferFormat )
122 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddFrameBuffer(id=%i width:%u height:%u)\n", id, width, height);
124 // Note: Do not throttle framebuffer generation - a request for a framebuffer should always be honoured
125 // as soon as possible.
126 Texture* texture = TextureFactory::NewFrameBufferTexture( width, height, pixelFormat, bufferFormat, mContext );
127 mFramebufferTextures.insert(TexturePair(id, texture));
130 void TextureCache::AddFrameBuffer( ResourceId id, NativeImageInterfacePtr nativeImage )
132 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddFrameBuffer(id=%i width:%u height:%u)\n", id, nativeImage->GetWidth(), nativeImage->GetHeight());
134 // Note: Do not throttle framebuffer generation - a request for a framebuffer should always be honoured
135 // as soon as possible.
136 Texture* texture = TextureFactory::NewFrameBufferTexture( nativeImage, mContext );
137 mFramebufferTextures.insert(TexturePair(id, texture));
140 void TextureCache::CreateGlTexture( ResourceId id )
142 TextureIter textureIter = mTextures.find(id);
143 // If we found a non-null texture object pointer for the resource id, force it
144 // to eagerly allocate a backing GL texture:
145 if( textureIter != mTextures.end() )
147 TexturePointer texturePtr = textureIter->second;
150 texturePtr->CreateGlTexture();
155 void TextureCache::UpdateTexture( ResourceId id, Integration::BitmapPtr bitmap )
157 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(id=%i bitmap:%p )\n", id, bitmap.Get());
159 TextureIter textureIter = mTextures.find(id);
160 if( textureIter != mTextures.end() )
162 // we have reloaded the image from file, update texture
163 TexturePointer texturePtr = textureIter->second;
166 texturePtr->Update( bitmap.Get() );
168 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
169 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
174 void TextureCache::UpdateTexture( ResourceId id, Integration::BitmapPtr bitmap, std::size_t xOffset, std::size_t yOffset )
176 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(id=%i bitmap:%p )\n", id, bitmap.Get());
178 TextureIter textureIter = mTextures.find(id);
179 if( textureIter != mTextures.end() )
181 TexturePointer texturePtr = textureIter->second;
184 texturePtr->Update( bitmap.Get(), xOffset, yOffset );
186 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
187 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
192 void TextureCache::UpdateTexture( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
194 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(destId=%i srcId=%i )\n", destId, srcId );
196 BitmapTexture* srcTexture = TextureCache::GetBitmapTexture( srcId );
197 Integration::BitmapPtr srcBitmap = ( srcTexture != NULL ) ? srcTexture->GetBitmap() : NULL;
201 UpdateTexture( destId, srcBitmap, xOffset, yOffset );
205 void TextureCache::UpdateTexture( ResourceId id, PixelDataPtr pixelData, std::size_t xOffset, std::size_t yOffset )
207 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(id=%i pixel data:%p )\n", id, pixelData.Get());
209 TextureIter textureIter = mTextures.find(id);
210 if( textureIter != mTextures.end() )
212 TexturePointer texturePtr = textureIter->second;
215 texturePtr->Update( pixelData.Get(), xOffset, yOffset );
217 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
218 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
223 void TextureCache::UpdateTextureArea( ResourceId id, const Dali::RectArea& area )
225 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTextureArea(id=%i)\n", id );
227 TextureIter textureIter = mTextures.find(id);
228 if( textureIter != mTextures.end() )
230 TexturePointer texturePtr = textureIter->second;
233 texturePtr->UpdateArea( area );
235 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
236 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
241 void TextureCache::DiscardTexture( ResourceId id )
243 bool deleted = false;
245 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::DiscardTexture(id:%u)\n", id);
247 if( mTextures.size() > 0)
249 TextureIter iter = mTextures.find(id);
250 if( iter != mTextures.end() )
252 TexturePointer texturePtr = iter->second;
255 // if valid texture pointer, cleanup GL resources
256 texturePtr->GlCleanup();
258 mTextures.erase(iter);
263 if( mFramebufferTextures.size() > 0)
265 TextureIter iter = mFramebufferTextures.find(id);
266 if( iter != mFramebufferTextures.end() )
268 TexturePointer texturePtr = iter->second;
271 // if valid texture pointer, cleanup GL resources
272 texturePtr->GlCleanup();
274 mFramebufferTextures.erase(iter);
281 if( mObservers.size() > 0 )
283 TextureResourceObserversIter observersIter = mObservers.find(id);
284 if( observersIter != mObservers.end() )
286 TextureObservers observers = observersIter->second;
287 for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
289 TextureObserver* observer = *iter;
290 observer->TextureDiscarded( id );
293 mObservers.erase( observersIter );
297 // Tell resource manager
298 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::DELETED );
299 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
303 void TextureCache::BindTexture( Texture *texture, ResourceId id, GLenum target, TextureUnit textureunit )
305 bool created = texture->Bind(target, textureunit);
306 if( created && texture->UpdateOnCreate() ) // i.e. the pixel data was sent to GL
308 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
309 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
313 Texture* TextureCache::GetTexture(ResourceId id)
315 Texture* texture = NULL;
316 TextureIter iter = mTextures.find(id);
318 if( iter != mTextures.end() )
320 TexturePointer texturePtr = iter->second;
323 texture = texturePtr.Get();
327 if( texture == NULL )
329 TextureIter iter = mFramebufferTextures.find(id);
330 if( iter != mFramebufferTextures.end() )
332 TexturePointer texturePtr = iter->second;
335 texture = texturePtr.Get();
340 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetTexture(id:%u) : %p\n", id, texture);
345 BitmapTexture* TextureCache::GetBitmapTexture(ResourceId id)
347 BitmapTexture* texture = NULL;
348 TextureIter iter = mTextures.find( id );
350 if( iter != mTextures.end() )
352 TexturePointer texturePtr = iter->second;
355 texture = dynamic_cast< BitmapTexture* >( texturePtr.Get() );
362 FrameBufferTexture* TextureCache::GetFramebuffer(ResourceId id)
364 FrameBufferTexture* offscreen = NULL;
365 TextureIter iter = mFramebufferTextures.find(id);
367 DALI_ASSERT_DEBUG( iter != mFramebufferTextures.end() );
369 if( iter != mFramebufferTextures.end() )
371 TexturePointer texturePtr = iter->second;
374 offscreen = dynamic_cast< FrameBufferTexture* >( texturePtr.Get() );
377 DALI_ASSERT_DEBUG( offscreen );
379 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetFramebuffer(id:%u) : %p\n", id, offscreen);
384 void TextureCache::AddObserver( ResourceId id, TextureObserver* observer )
386 TextureResourceObserversIter observersIter = mObservers.find(id);
387 if( observersIter != mObservers.end() )
389 TextureObservers& observers = observersIter->second;
390 bool foundObserver = false;
391 for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
393 if( *iter == observer )
395 foundObserver = true;
399 if( ! foundObserver )
401 observers.push_back(observer);
406 TextureObservers observers;
407 observers.push_back(observer);
408 mObservers.insert(std::pair<ResourceId, TextureObservers>(id, observers));
412 void TextureCache::RemoveObserver( ResourceId id, TextureObserver* observer )
414 TextureResourceObserversIter observersIter = mObservers.find(id);
415 if( observersIter != mObservers.end() )
417 TextureObservers& observers = observersIter->second;
418 for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
420 if(*iter == observer)
422 observers.erase(iter);
429 void TextureCache::GlContextDestroyed()
431 SceneGraph::GlContextDestroyed( mTextures );
432 SceneGraph::GlContextDestroyed( mFramebufferTextures );
435 void TextureCache::SetDiscardBitmapsPolicy( ResourcePolicy::Discardable policy )
437 DALI_LOG_INFO( gTextureCacheFilter, Debug::General, "TextureCache::SetDiscardBitmapsPolicy(%s)\n",
438 policy==ResourcePolicy::OWNED_DISCARD?"DISCARD":"RETAIN" );
439 mDiscardBitmapsPolicy = policy;
442 ResourcePolicy::Discardable TextureCache::GetDiscardBitmapsPolicy()
444 return mDiscardBitmapsPolicy;
448 /********************************************************************************
449 ********************** Implements TextureCacheDispatcher *********************
450 ********************************************************************************/
452 void TextureCache::DispatchCreateTexture( ResourceId id,
455 Pixel::Format pixelFormat,
458 // NULL, means being shutdown, so ignore msgs
459 if( mSceneGraphBuffers != NULL )
461 typedef MessageValue5< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format, bool > DerivedType;
463 // Reserve some memory inside the render queue
464 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
466 // Construct message in the render queue memory; note that delete should not be called on the return value
467 new (slot) DerivedType( this, &TextureCache::CreateTexture, id, width, height, pixelFormat, clearPixels );
471 void TextureCache::DispatchCreateTextureForBitmap( ResourceId id, Bitmap* bitmap )
473 // NULL, means being shutdown, so ignore msgs
474 if( mSceneGraphBuffers != NULL )
476 typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
478 // Reserve some memory inside the render queue
479 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
481 // Construct message in the render queue memory; note that delete should not be called on the return value
482 new (slot) DerivedType( this, &TextureCache::AddBitmap, id, bitmap );
486 void TextureCache::DispatchCreateTextureForNativeImage( ResourceId id, NativeImageInterfacePtr nativeImage )
488 // NULL, means being shutdown, so ignore msgs
489 if( mSceneGraphBuffers != NULL )
491 typedef MessageValue2< TextureCache, ResourceId, NativeImageInterfacePtr > DerivedType;
493 // Reserve some memory inside the render queue
494 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
496 // Construct message in the render queue memory; note that delete should not be called on the return value
497 new (slot) DerivedType( this, &TextureCache::AddNativeImage, id, nativeImage );
501 void TextureCache::DispatchCreateGlTexture( ResourceId id )
503 // NULL, means being shutdown, so ignore msgs
504 if( mSceneGraphBuffers != NULL )
506 typedef MessageValue1< TextureCache, ResourceId > DerivedType;
508 // Reserve some memory inside the render queue
509 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
511 // Construct message in the render queue memory; note that delete should not be called on the return value
512 new (slot) DerivedType( this, &TextureCache::CreateGlTexture, id );
516 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat, RenderBuffer::Format bufferFormat )
518 // NULL, means being shutdown, so ignore msgs
519 if( mSceneGraphBuffers != NULL )
521 typedef MessageValue5< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format, RenderBuffer::Format > DerivedType;
523 // Reserve some memory inside the render queue
524 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
526 // Construct message in the render queue memory; note that delete should not be called on the return value
527 new (slot) DerivedType( this, &TextureCache::AddFrameBuffer, id, width, height, pixelFormat, bufferFormat );
531 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, NativeImageInterfacePtr nativeImage )
533 // NULL, means being shutdown, so ignore msgs
534 if( mSceneGraphBuffers != NULL )
536 typedef MessageValue2< TextureCache, ResourceId, NativeImageInterfacePtr > DerivedType;
538 // Reserve some memory inside the render queue
539 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
541 // Construct message in the render queue memory; note that delete should not be called on the return value
542 new (slot) DerivedType( this, &TextureCache::AddFrameBuffer, id, nativeImage );
546 void TextureCache::DispatchUpdateTexture( ResourceId id, Bitmap* bitmap )
548 // NULL, means being shutdown, so ignore msgs
549 if( mSceneGraphBuffers != NULL )
551 typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
553 // Reserve some memory inside the render queue
554 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
556 // Construct message in the render queue memory; note that delete should not be called on the return value
557 new (slot) DerivedType( this, &TextureCache::UpdateTexture, id, bitmap );
561 void TextureCache::DispatchUpdateTexture( ResourceId id, Integration::BitmapPtr bitmap , std::size_t xOffset, std::size_t yOffset)
563 // NULL, means being shutdown, so ignore msgs
564 if( mSceneGraphBuffers != NULL )
566 typedef MessageValue4< TextureCache, ResourceId, Integration::BitmapPtr, std::size_t, std::size_t > DerivedType;
568 // Reserve some memory inside the render queue
569 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
571 // Construct message in the render queue memory; note that delete should not be called on the return value
572 new (slot) DerivedType( this, &TextureCache::UpdateTexture, id, bitmap, xOffset, yOffset );
576 void TextureCache::DispatchUpdateTexture( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
578 // NULL, means being shutdown, so ignore msgs
579 if( mSceneGraphBuffers != NULL )
581 typedef MessageValue4< TextureCache, ResourceId, ResourceId, std::size_t, std::size_t > DerivedType;
583 // Reserve some memory inside the render queue
584 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
586 // Construct message in the render queue memory; note that delete should not be called on the return value
587 new (slot) DerivedType( this, &TextureCache::UpdateTexture, destId, srcId, xOffset, yOffset );
591 void TextureCache::DispatchUpdateTexture( ResourceId id, PixelDataPtr pixelData , std::size_t xOffset, std::size_t yOffset)
593 // NULL, means being shutdown, so ignore msgs
594 if( mSceneGraphBuffers != NULL )
596 typedef MessageValue4< TextureCache, ResourceId, PixelDataPtr, std::size_t, std::size_t > DerivedType;
598 // Reserve some memory inside the render queue
599 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
601 // Construct message in the render queue memory; note that delete should not be called on the return value
602 new (slot) DerivedType( this, &TextureCache::UpdateTexture, id, pixelData, xOffset, yOffset );
606 void TextureCache::DispatchUpdateTextureArea( ResourceId id, const Dali::RectArea& area )
608 // NULL, means being shutdown, so ignore msgs
609 if( mSceneGraphBuffers != NULL )
611 typedef MessageValue2< TextureCache, ResourceId, Dali::RectArea > DerivedType;
613 // Reserve some memory inside the render queue
614 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
616 // Construct message in the render queue memory; note that delete should not be called on the return value
617 new (slot) DerivedType( this, &TextureCache::UpdateTextureArea, id, area );
621 void TextureCache::DispatchDiscardTexture( ResourceId id )
623 // NULL, means being shutdown, so ignore msgs
624 if( mSceneGraphBuffers != NULL )
626 typedef MessageValue1< TextureCache, ResourceId > DerivedType;
628 // Reserve some memory inside the render queue
629 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
631 // Construct message in the render queue memory; note that delete should not be called on the return value
632 new (slot) DerivedType( this, &TextureCache::DiscardTexture, id );