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::UpdateTextureArea( ResourceId id, const Dali::RectArea& area )
142 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTextureArea(id=%i)\n", id );
144 TextureIter textureIter = mTextures.find(id);
145 if( textureIter != mTextures.end() )
147 TexturePointer texturePtr = textureIter->second;
150 texturePtr->UpdateArea( area );
152 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
153 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
158 void TextureCache::AddBitmapUploadArray( ResourceId id, const BitmapUploadArray& uploadArray )
160 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddBitmapUploadArray(id=%i )\n", id);
162 TextureIter textureIter = mTextures.find(id);
164 DALI_ASSERT_DEBUG( textureIter != mTextures.end() );
165 if( textureIter != mTextures.end() )
167 TexturePointer texturePtr = textureIter->second;
170 BitmapTexture* texture = static_cast< BitmapTexture* >( texturePtr.Get() );
171 texture->UploadBitmapArray( uploadArray );
176 void TextureCache::ClearAreas( ResourceId id,
177 const BitmapClearArray& areaArray,
178 std::size_t blockSize,
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() )
186 TexturePointer texturePtr = textureIter->second;
189 BitmapTexture* texture = static_cast< BitmapTexture* >( texturePtr.Get() );
190 texture->ClearAreas( areaArray, blockSize, color );
195 void TextureCache::DiscardTexture( ResourceId id )
197 bool deleted = false;
199 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::DiscardTexture(id:%u)\n", id);
201 if( mTextures.size() > 0)
203 TextureIter iter = mTextures.find(id);
204 if( iter != mTextures.end() )
206 TexturePointer texturePtr = iter->second;
209 // if valid texture pointer, cleanup GL resources
210 texturePtr->GlCleanup();
212 mTextures.erase(iter);
217 if( mFramebufferTextures.size() > 0)
219 TextureIter iter = mFramebufferTextures.find(id);
220 if( iter != mFramebufferTextures.end() )
222 TexturePointer texturePtr = iter->second;
225 // if valid texture pointer, cleanup GL resources
226 texturePtr->GlCleanup();
228 mFramebufferTextures.erase(iter);
235 if( mObservers.size() > 0 )
237 TextureResourceObserversIter observersIter = mObservers.find(id);
238 if( observersIter != mObservers.end() )
240 TextureObservers observers = observersIter->second;
241 for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
243 TextureObserver* observer = *iter;
244 observer->TextureDiscarded( id );
247 mObservers.erase( observersIter );
251 // Tell resource manager
252 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::DELETED );
253 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
257 void TextureCache::BindTexture( Texture *texture, ResourceId id, GLenum target, GLenum textureunit )
259 bool created = texture->Bind(target, textureunit);
260 if( created && texture->UpdateOnCreate() ) // i.e. the pixel data was sent to GL
262 ResourcePostProcessRequest ppRequest( id, ResourcePostProcessRequest::UPLOADED );
263 mPostProcessResourceDispatcher.DispatchPostProcessRequest(ppRequest);
268 Texture* TextureCache::GetTexture(ResourceId id)
270 Texture* texture = NULL;
271 TextureIter iter = mTextures.find(id);
273 if( iter != mTextures.end() )
275 TexturePointer texturePtr = iter->second;
278 texture = texturePtr.Get();
282 if( texture == NULL )
284 TextureIter iter = mFramebufferTextures.find(id);
285 if( iter != mFramebufferTextures.end() )
287 TexturePointer texturePtr = iter->second;
290 texture = texturePtr.Get();
295 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetTexture(id:%u) : %p\n", id, texture);
300 FrameBufferTexture* TextureCache::GetFramebuffer(ResourceId id)
302 FrameBufferTexture* offscreen = NULL;
303 TextureIter iter = mFramebufferTextures.find(id);
305 DALI_ASSERT_DEBUG( iter != mFramebufferTextures.end() );
307 if( iter != mFramebufferTextures.end() )
309 TexturePointer texturePtr = iter->second;
312 offscreen = dynamic_cast< FrameBufferTexture* >( texturePtr.Get() );
315 DALI_ASSERT_DEBUG( offscreen );
317 DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetFramebuffer(id:%u) : %p\n", id, offscreen);
322 void TextureCache::AddObserver( ResourceId id, TextureObserver* observer )
324 TextureResourceObserversIter observersIter = mObservers.find(id);
325 if( observersIter != mObservers.end() )
327 TextureObservers& observers = observersIter->second;
328 bool foundObserver = false;
329 for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
331 if( *iter == observer )
333 foundObserver = true;
337 if( ! foundObserver )
339 observers.push_back(observer);
344 TextureObservers observers;
345 observers.push_back(observer);
346 mObservers.insert(std::pair<ResourceId, TextureObservers>(id, observers));
350 void TextureCache::RemoveObserver( ResourceId id, TextureObserver* observer )
352 TextureResourceObserversIter observersIter = mObservers.find(id);
353 if( observersIter != mObservers.end() )
355 TextureObservers& observers = observersIter->second;
356 for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
358 if(*iter == observer)
360 observers.erase(iter);
367 void TextureCache::GlContextDestroyed()
369 TextureIter end = mTextures.end();
370 TextureIter iter = mTextures.begin();
371 for( ; iter != end; ++iter )
373 (*iter->second).GlContextDestroyed(); // map holds intrusive pointers
376 end = mFramebufferTextures.end();
377 iter = mFramebufferTextures.begin();
378 for( ; iter != end; ++iter )
380 (*iter->second).GlContextDestroyed(); // map holds intrusive pointers
384 void TextureCache::SetDiscardBitmapsPolicy( ResourcePolicy::Discardable policy )
386 DALI_LOG_INFO( gTextureCacheFilter, Debug::General, "TextureCache::SetDiscardBitmapsPolicy(%s)\n",
387 policy==ResourcePolicy::RETAIN?"RETAIN":"DISCARD" );
388 mDiscardBitmapsPolicy = policy;
391 ResourcePolicy::Discardable TextureCache::GetDiscardBitmapsPolicy()
393 return mDiscardBitmapsPolicy;
397 /********************************************************************************
398 ********************** Implements TextureCacheDispatcher *********************
399 ********************************************************************************/
401 void TextureCache::DispatchCreateTexture( ResourceId id,
404 Pixel::Format pixelFormat,
407 // NULL, means being shutdown, so ignore msgs
408 if( mSceneGraphBuffers != NULL )
410 typedef MessageValue5< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format, bool > DerivedType;
412 // Reserve some memory inside the render queue
413 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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 );
420 void TextureCache::DispatchCreateTextureForBitmap( ResourceId id, Bitmap* bitmap )
422 // NULL, means being shutdown, so ignore msgs
423 if( mSceneGraphBuffers != NULL )
425 typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
427 // Reserve some memory inside the render queue
428 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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 );
435 void TextureCache::DispatchCreateTextureForNativeImage( ResourceId id, NativeImagePtr nativeImage )
437 // NULL, means being shutdown, so ignore msgs
438 if( mSceneGraphBuffers != NULL )
440 typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > DerivedType;
442 // Reserve some memory inside the render queue
443 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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 );
450 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat )
452 // NULL, means being shutdown, so ignore msgs
453 if( mSceneGraphBuffers != NULL )
455 typedef MessageValue4< TextureCache, ResourceId, unsigned int, unsigned int, Pixel::Format > DerivedType;
457 // Reserve some memory inside the render queue
458 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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 );
465 void TextureCache::DispatchCreateTextureForFrameBuffer( ResourceId id, NativeImagePtr nativeImage )
467 // NULL, means being shutdown, so ignore msgs
468 if( mSceneGraphBuffers != NULL )
470 typedef MessageValue2< TextureCache, ResourceId, NativeImagePtr > DerivedType;
472 // Reserve some memory inside the render queue
473 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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 );
480 void TextureCache::DispatchUpdateTexture( ResourceId id, Bitmap* bitmap )
482 // NULL, means being shutdown, so ignore msgs
483 if( mSceneGraphBuffers != NULL )
485 typedef MessageValue2< TextureCache, ResourceId, Integration::BitmapPtr > DerivedType;
487 // Reserve some memory inside the render queue
488 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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 );
495 void TextureCache::DispatchUpdateTextureArea( ResourceId id, const Dali::RectArea& area )
497 // NULL, means being shutdown, so ignore msgs
498 if( mSceneGraphBuffers != NULL )
500 typedef MessageValue2< TextureCache, ResourceId, Dali::RectArea > DerivedType;
502 // Reserve some memory inside the render queue
503 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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 );
510 void TextureCache::DispatchUploadBitmapArrayToTexture( ResourceId id, const BitmapUploadArray& uploadArray )
512 // NULL, means being shutdown, so ignore msgs
513 if( mSceneGraphBuffers != NULL )
515 typedef MessageValue2< TextureCache, ResourceId, BitmapUploadArray > DerivedType;
517 // Reserve some memory inside the render queue
518 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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 );
525 void TextureCache::DispatchClearAreas( ResourceId id, const BitmapClearArray& areaArray, std::size_t blockSize, uint32_t color )
527 // NULL, means being shutdown, so ignore msgs
528 if( mSceneGraphBuffers != NULL )
530 typedef MessageValue4< TextureCache, ResourceId, BitmapClearArray, std::size_t, uint32_t > DerivedType;
532 // Reserve some memory inside the render queue
533 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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 );
540 void TextureCache::DispatchDiscardTexture( ResourceId id )
542 // NULL, means being shutdown, so ignore msgs
543 if( mSceneGraphBuffers != NULL )
545 typedef MessageValue1< TextureCache, ResourceId > DerivedType;
547 // Reserve some memory inside the render queue
548 unsigned int* slot = mRenderQueue.ReserveMessageSlot( mSceneGraphBuffers->GetUpdateBufferIndex(), sizeof( DerivedType ) );
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 );