Merge "DALi Version 1.1.37" into devel/master
[platform/core/uifw/dali-core.git] / dali / internal / render / gl-resources / texture-cache.cpp
1 /*
2  * Copyright (c) 2016 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 // CLASS HEADER
19 #include <dali/internal/render/gl-resources/texture-cache.h>
20
21 // INTERNAL HEADERS
22 #include <dali/integration-api/debug.h>
23 #include <dali/integration-api/bitmap.h>
24 #include <dali/internal/event/resources/resource-client.h> // For RectArea
25 #include <dali/internal/render/common/texture-uploaded-dispatcher.h>
26 #include <dali/internal/render/queue/render-queue.h>
27 #include <dali/internal/render/gl-resources/context.h>
28 #include <dali/internal/render/gl-resources/texture-factory.h>
29 #include <dali/internal/render/gl-resources/texture-cache.h>
30 #include <dali/internal/render/gl-resources/texture-observer.h>
31 #include <dali/internal/render/gl-resources/bitmap-texture.h>
32 #include <dali/internal/render/gl-resources/native-texture.h>
33 #include <dali/internal/render/gl-resources/frame-buffer-texture.h>
34 #include <dali/internal/update/resources/resource-manager-declarations.h>
35 #include <dali/internal/render/gl-resources/gl-texture.h>
36
37 using Dali::Internal::Texture;
38 using Dali::Internal::FrameBufferTexture;
39 using Dali::Integration::Bitmap;
40
41 namespace
42 {
43 #if defined(DEBUG_ENABLED)
44 Debug::Filter* gTextureCacheFilter = Debug::Filter::New(Debug::Concise, false, "LOG_TEXTURE_CACHE");
45 #endif
46 }
47
48
49 namespace Dali
50 {
51 namespace Internal
52 {
53
54
55 namespace SceneGraph
56 {
57
58 namespace
59 {
60
61 /**
62  * @brief Forward to all textures in container the news that the GL Context is down.
63  */
64 void GlContextDestroyed( TextureContainer& textures )
65 {
66   TextureIter end = textures.end();
67   TextureIter iter = textures.begin();
68   for( ; iter != end; ++iter )
69   {
70     (*iter->second).GlContextDestroyed();
71   }
72 }
73
74 }
75
76 TextureCache::TextureCache( RenderQueue& renderQueue,
77                             TextureUploadedDispatcher& postProcessResourceDispatcher,
78                             Context& context)
79 : mTextureUploadedDispatcher(postProcessResourceDispatcher),
80   mContext(context),
81   mDiscardBitmapsPolicy(ResourcePolicy::OWNED_DISCARD)
82 {
83 }
84
85 TextureCache::~TextureCache()
86 {
87 }
88
89 void TextureCache::CreateTexture( ResourceId        id,
90                                   unsigned int      width,
91                                   unsigned int      height,
92                                   Pixel::Format     pixelFormat,
93                                   bool              clearPixels )
94 {
95   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::CreateTexture(id=%i width:%u height:%u)\n", id, width, height);
96
97   Texture* texture = TextureFactory::NewBitmapTexture(width, height, pixelFormat, clearPixels, mContext, GetDiscardBitmapsPolicy() );
98   mTextures.insert(TexturePair(id, texture));
99 }
100
101 void TextureCache::AddBitmap(ResourceId id, Integration::BitmapPtr bitmap)
102 {
103   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddBitmap(id=%i Bitmap:%p)\n", id, bitmap.Get());
104
105   Texture* texture = TextureFactory::NewBitmapTexture(bitmap.Get(), mContext, GetDiscardBitmapsPolicy());
106   mTextures.insert(TexturePair(id, texture));
107 }
108
109 void TextureCache::AddNativeImage(ResourceId id, NativeImageInterfacePtr nativeImage)
110 {
111   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddNativeImage(id=%i NativeImg:%p)\n", id, nativeImage.Get());
112
113   /// WARNING - currently a new Texture is created even if we reuse the same NativeImage
114   Texture* texture = TextureFactory::NewNativeImageTexture(*nativeImage, mContext);
115   mTextures.insert(TexturePair(id, texture));
116 }
117
118 void TextureCache::AddFrameBuffer( ResourceId id, unsigned int width, unsigned int height, Pixel::Format pixelFormat, RenderBuffer::Format bufferFormat )
119 {
120   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddFrameBuffer(id=%i width:%u height:%u)\n", id, width, height);
121
122   // Note: Do not throttle framebuffer generation - a request for a framebuffer should always be honoured
123   // as soon as possible.
124   Texture* texture = TextureFactory::NewFrameBufferTexture( width, height, pixelFormat, bufferFormat, mContext );
125   mFramebufferTextures.insert(TexturePair(id, texture));
126 }
127
128 void TextureCache::AddFrameBuffer( ResourceId id, NativeImageInterfacePtr nativeImage )
129 {
130   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::AddFrameBuffer(id=%i width:%u height:%u)\n", id, nativeImage->GetWidth(), nativeImage->GetHeight());
131
132   // Note: Do not throttle framebuffer generation - a request for a framebuffer should always be honoured
133   // as soon as possible.
134   Texture* texture = TextureFactory::NewFrameBufferTexture( nativeImage, mContext );
135   mFramebufferTextures.insert(TexturePair(id, texture));
136 }
137
138 void TextureCache::CreateGlTexture( ResourceId id )
139 {
140   TextureIter textureIter = mTextures.find(id);
141   // If we found a non-null texture object pointer for the resource id, force it
142   // to eagerly allocate a backing GL texture:
143   if( textureIter != mTextures.end() )
144   {
145     TexturePointer texturePtr = textureIter->second;
146     if( texturePtr )
147     {
148       texturePtr->CreateGlTexture();
149     }
150   }
151 }
152
153 void TextureCache::UpdateTexture( ResourceId id, Integration::BitmapPtr bitmap )
154 {
155   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(id=%i bitmap:%p )\n", id, bitmap.Get());
156
157   TextureIter textureIter = mTextures.find(id);
158   if( textureIter != mTextures.end() )
159   {
160     // we have reloaded the image from file, update texture
161     TexturePointer texturePtr = textureIter->second;
162     if( texturePtr )
163     {
164       texturePtr->Update( bitmap.Get() );
165
166       ResourceId ppRequest( id );
167       mTextureUploadedDispatcher.DispatchTextureUploaded(ppRequest);
168     }
169   }
170 }
171
172 void TextureCache::UpdateTexture( ResourceId id, Integration::BitmapPtr bitmap, std::size_t xOffset, std::size_t yOffset )
173 {
174   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(id=%i bitmap:%p )\n", id, bitmap.Get());
175
176   TextureIter textureIter = mTextures.find(id);
177   if( textureIter != mTextures.end() )
178   {
179     TexturePointer texturePtr = textureIter->second;
180     if( texturePtr )
181     {
182       texturePtr->Update( bitmap.Get(), xOffset, yOffset );
183
184       ResourceId ppRequest( id  );
185       mTextureUploadedDispatcher.DispatchTextureUploaded(ppRequest);
186     }
187   }
188 }
189
190 void TextureCache::UpdateTexture( ResourceId destId, ResourceId srcId, std::size_t xOffset, std::size_t yOffset )
191 {
192   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(destId=%i srcId=%i )\n", destId, srcId );
193
194   BitmapTexture* srcTexture = TextureCache::GetBitmapTexture( srcId );
195   Integration::BitmapPtr srcBitmap = ( srcTexture != NULL ) ? srcTexture->GetBitmap() : NULL;
196
197   if( srcBitmap )
198   {
199     UpdateTexture( destId, srcBitmap, xOffset, yOffset );
200   }
201 }
202
203 void TextureCache::UpdateTexture( ResourceId id, PixelDataPtr pixelData, std::size_t xOffset, std::size_t yOffset )
204 {
205   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTexture(id=%i pixel data:%p )\n", id, pixelData.Get());
206
207   TextureIter textureIter = mTextures.find(id);
208   if( textureIter != mTextures.end() )
209   {
210     TexturePointer texturePtr = textureIter->second;
211     if( texturePtr )
212     {
213       texturePtr->Update( pixelData.Get(), xOffset, yOffset );
214
215       ResourceId ppRequest( id );
216       mTextureUploadedDispatcher.DispatchTextureUploaded(ppRequest);
217     }
218   }
219 }
220
221 void TextureCache::UpdateTextureArea( ResourceId id, const RectArea& area )
222 {
223   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::UpdateTextureArea(id=%i)\n", id );
224
225   TextureIter textureIter = mTextures.find(id);
226   if( textureIter != mTextures.end() )
227   {
228     TexturePointer texturePtr = textureIter->second;
229     if( texturePtr )
230     {
231       texturePtr->UpdateArea( area );
232
233       ResourceId ppRequest( id );
234       mTextureUploadedDispatcher.DispatchTextureUploaded(ppRequest);
235     }
236   }
237 }
238
239 void TextureCache::DiscardTexture( ResourceId id )
240 {
241   bool deleted = false;
242
243   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::DiscardTexture(id:%u)\n", id);
244
245   if( mTextures.size() > 0)
246   {
247     TextureIter iter = mTextures.find(id);
248     if( iter != mTextures.end() )
249     {
250       TexturePointer texturePtr = iter->second;
251       if( texturePtr )
252       {
253         // if valid texture pointer, cleanup GL resources
254         texturePtr->GlCleanup();
255       }
256       mTextures.erase(iter);
257       deleted = true;
258     }
259   }
260
261   if( mFramebufferTextures.size() > 0)
262   {
263     TextureIter iter = mFramebufferTextures.find(id);
264     if( iter != mFramebufferTextures.end() )
265     {
266       TexturePointer texturePtr = iter->second;
267       if( texturePtr )
268       {
269         // if valid texture pointer, cleanup GL resources
270         texturePtr->GlCleanup();
271       }
272       mFramebufferTextures.erase(iter);
273       deleted = true;
274     }
275   }
276
277   if(deleted)
278   {
279     if( mObservers.size() > 0 )
280     {
281       TextureResourceObserversIter observersIter = mObservers.find(id);
282       if( observersIter != mObservers.end() )
283       {
284         TextureObservers observers = observersIter->second;
285         for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
286         {
287           TextureObserver* observer = *iter;
288           observer->TextureDiscarded( id );
289         }
290
291         mObservers.erase( observersIter );
292       }
293     }
294   }
295 }
296
297 bool TextureCache::BindTexture( Texture *texture, ResourceId id, GLenum target, TextureUnit textureunit )
298 {
299   unsigned int glTextureId = texture->GetTextureId();
300
301   bool success = texture->Bind(target, textureunit);
302   bool created = ( glTextureId == 0 ) && ( texture->GetTextureId() != 0 );
303
304   if( created && texture->UpdateOnCreate() ) // i.e. the pixel data was sent to GL
305   {
306     ResourceId ppRequest( id );
307     mTextureUploadedDispatcher.DispatchTextureUploaded(ppRequest);
308   }
309   return success;
310 }
311
312 Texture* TextureCache::GetTexture(ResourceId id)
313 {
314   Texture* texture = NULL;
315   TextureIter iter = mTextures.find(id);
316
317   if( iter != mTextures.end() )
318   {
319     TexturePointer texturePtr = iter->second;
320     if( texturePtr )
321     {
322       texture = texturePtr.Get();
323     }
324   }
325
326   if( texture == NULL )
327   {
328     TextureIter iter = mFramebufferTextures.find(id);
329     if( iter != mFramebufferTextures.end() )
330     {
331       TexturePointer texturePtr = iter->second;
332       if( texturePtr )
333       {
334         texture = texturePtr.Get();
335       }
336     }
337   }
338
339   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetTexture(id:%u) : %p\n", id, texture);
340
341   return texture;
342 }
343
344 BitmapTexture* TextureCache::GetBitmapTexture(ResourceId id)
345 {
346   BitmapTexture* texture = NULL;
347   TextureIter iter = mTextures.find( id );
348
349   if( iter != mTextures.end() )
350   {
351     TexturePointer texturePtr = iter->second;
352     if( texturePtr )
353     {
354       texture = dynamic_cast< BitmapTexture* >( texturePtr.Get() );
355     }
356   }
357
358   return texture;
359 }
360
361 FrameBufferTexture* TextureCache::GetFramebuffer(ResourceId id)
362 {
363   FrameBufferTexture* offscreen = NULL;
364   TextureIter iter = mFramebufferTextures.find(id);
365
366   DALI_ASSERT_DEBUG( iter != mFramebufferTextures.end() );
367
368   if( iter != mFramebufferTextures.end() )
369   {
370     TexturePointer texturePtr = iter->second;
371     if( texturePtr )
372     {
373       offscreen = dynamic_cast< FrameBufferTexture* >( texturePtr.Get() );
374     }
375   }
376   DALI_ASSERT_DEBUG( offscreen );
377
378   DALI_LOG_INFO(Debug::Filter::gGLResource, Debug::General, "TextureCache::GetFramebuffer(id:%u) : %p\n", id, offscreen);
379
380   return offscreen;
381 }
382
383 void TextureCache::AddObserver( ResourceId id, TextureObserver* observer )
384 {
385   TextureResourceObserversIter observersIter = mObservers.find(id);
386   if( observersIter != mObservers.end() )
387   {
388     TextureObservers& observers = observersIter->second;
389     bool foundObserver = false;
390     for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
391     {
392       if( *iter == observer )
393       {
394         foundObserver = true;
395         break;
396       }
397     }
398     if( ! foundObserver )
399     {
400       observers.push_back(observer);
401     }
402   }
403   else
404   {
405     TextureObservers observers;
406     observers.push_back(observer);
407     mObservers.insert(std::pair<ResourceId, TextureObservers>(id, observers));
408   }
409 }
410
411 void TextureCache::RemoveObserver( ResourceId id, TextureObserver* observer )
412 {
413   TextureResourceObserversIter observersIter = mObservers.find(id);
414   if( observersIter != mObservers.end() )
415   {
416     TextureObservers& observers = observersIter->second;
417     for( TextureObserversIter iter = observers.begin(); iter != observers.end(); ++iter )
418     {
419       if(*iter == observer)
420       {
421         observers.erase(iter);
422         break;
423       }
424     }
425   }
426 }
427
428 void TextureCache::GlContextDestroyed()
429 {
430   SceneGraph::GlContextDestroyed( mTextures );
431   SceneGraph::GlContextDestroyed( mFramebufferTextures );
432 }
433
434 void TextureCache::SetDiscardBitmapsPolicy( ResourcePolicy::Discardable policy )
435 {
436   DALI_LOG_INFO( gTextureCacheFilter, Debug::General, "TextureCache::SetDiscardBitmapsPolicy(%s)\n",
437                  policy==ResourcePolicy::OWNED_DISCARD?"DISCARD":"RETAIN" );
438   mDiscardBitmapsPolicy = policy;
439 }
440
441 ResourcePolicy::Discardable TextureCache::GetDiscardBitmapsPolicy()
442 {
443   return mDiscardBitmapsPolicy;
444 }
445
446 } // SceneGraph
447
448 } // Internal
449
450 } // Dali