[3.0] Valgrind detected TextureSet leak and invalid access
[platform/core/uifw/dali-core.git] / dali / internal / update / rendering / scene-graph-texture-set.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 // CLASS HEADER
18 #include "scene-graph-texture-set.h"
19
20 // INTERNAL HEADERS
21 #include <dali/integration-api/resource-declarations.h>
22 #include <dali/internal/common/internal-constants.h>
23 #include <dali/internal/update/resources/texture-metadata.h>
24 #include <dali/internal/update/resources/resource-manager.h>
25 #include <dali/internal/common/memory-pool-object-allocator.h>
26 #include <dali/internal/update/rendering/scene-graph-renderer.h>
27
28 namespace //Unnamed namespace
29 {
30 //Memory pool used to allocate new texture sets. Memory used by this pool will be released when shutting down DALi
31 Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::TextureSet> gTextureSetMemoryPool;
32 }
33
34 namespace Dali
35 {
36
37 namespace Internal
38 {
39
40 namespace SceneGraph
41 {
42
43 TextureSet* TextureSet::New()
44 {
45   return new ( gTextureSetMemoryPool.AllocateRawThreadSafe() ) TextureSet();
46 }
47
48 TextureSet::TextureSet()
49 : mSamplers(),
50   mTextureId(),
51   mRenderers(),
52   mResourcesReady( true ),
53   mFinishedResourceAcquisition( true ),
54   mChanged( true ),
55   mHasAlpha( false )
56 {
57 }
58
59 TextureSet::~TextureSet()
60 {
61   size_t rendererCount = mRenderers.Size();
62   for( size_t i(0); i<rendererCount; ++i )
63   {
64     mRenderers[i]->TextureSetDeleted();
65   }
66 }
67
68 void TextureSet::operator delete( void* ptr )
69 {
70   gTextureSetMemoryPool.FreeThreadSafe( static_cast<TextureSet*>( ptr ) );
71 }
72
73 void TextureSet::Prepare( const ResourceManager& resourceManager )
74 {
75   if( mChanged && mTextures.Empty() )
76   {
77     unsigned int opaqueCount = 0;
78     unsigned int completeCount = 0;
79     unsigned int failedCount = 0;
80     unsigned int frameBufferCount = 0;
81     const std::size_t textureCount( mTextureId.Count() );
82     if( textureCount > 0 )
83     {
84       for( unsigned int i(0); i<textureCount; ++i )
85       {
86         const ResourceId textureId = mTextureId[ i ];
87         TextureMetadata* metadata = NULL;
88         if( textureId != Integration::InvalidResourceId )
89         {
90           // if there is metadata, resource is loaded
91           if( resourceManager.GetTextureMetadata( textureId, metadata ) )
92           {
93             DALI_ASSERT_DEBUG( metadata );
94             // metadata is valid pointer from now on
95             if( metadata->IsFullyOpaque() )
96             {
97               ++opaqueCount;
98             }
99
100             if( metadata->IsFramebuffer() )
101             {
102               if( metadata->HasFrameBufferBeenRenderedTo() )
103               {
104                 ++completeCount;
105               }
106               else
107               {
108                 frameBufferCount++;
109               }
110             }
111             else
112             {
113               // loaded so will complete this frame
114               ++completeCount;
115             }
116             // no point checking failure as there is no metadata for failed loads
117           }
118           // if no metadata, loading can be failed
119           else if( resourceManager.HasResourceLoadFailed( textureId ) )
120           {
121             ++failedCount;
122           }
123         }
124         else
125         {
126           //If the texture is not valid it is considerer opaque and complete
127           ++opaqueCount;
128           ++completeCount;
129         }
130       }
131     }
132
133     mHasAlpha = ( opaqueCount != textureCount );
134
135     // ready for rendering when all textures are either successfully loaded or they are FBOs
136     mResourcesReady = (completeCount + frameBufferCount >= textureCount);
137
138     // Texture set is complete if all resources are either loaded or failed or, if they are FBOs have been rendererd to
139     mFinishedResourceAcquisition = ( completeCount + failedCount == textureCount );
140
141     if( mFinishedResourceAcquisition )
142     {
143       // Texture set is now considered not changed
144       mChanged = false;
145     }
146   }
147 }
148
149 void TextureSet::SetImage( size_t index,  ResourceId imageId )
150 {
151   size_t textureCount( mTextureId.Size() );
152   if( textureCount < index + 1 )
153   {
154     mTextureId.Resize( index + 1 );
155     mSamplers.Resize( index + 1 );
156     for( size_t i(textureCount); i<=index; ++i )
157     {
158       mTextureId[i] = Integration::InvalidResourceId;
159       mSamplers[i] = NULL;
160     }
161   }
162
163   mTextureId[index] = imageId;
164   mChanged = true;
165   NotifyChangeToRenderers();
166 }
167
168 void TextureSet::SetSampler( size_t index, Render::Sampler* sampler )
169 {
170   size_t samplerCount( mSamplers.Size() );
171   if( samplerCount < index + 1 )
172   {
173     mSamplers.Resize( index + 1 );
174     mTextureId.Resize( index + 1 );
175     for( size_t i(samplerCount); i<=index; ++i )
176     {
177       mTextureId[i] = Integration::InvalidResourceId;
178       mSamplers[i] = NULL;
179     }
180   }
181
182   mSamplers[index] = sampler;
183   NotifyChangeToRenderers();
184 }
185
186 void TextureSet::SetTexture( size_t index, Render::NewTexture* texture )
187 {
188   const size_t textureCount( mTextures.Size() );
189   if( textureCount < index + 1 )
190   {
191     mTextures.Resize( index + 1 );
192     mSamplers.Resize( index + 1 );
193
194     for( size_t i(textureCount); i<=index; ++i )
195     {
196       mTextures[i] = 0;
197       mSamplers[i] = 0;
198     }
199   }
200
201   mTextures[index] = texture;
202   mHasAlpha |= texture->HasAlphaChannel();
203   NotifyChangeToRenderers();
204 }
205
206 bool TextureSet::HasAlpha() const
207 {
208   return mHasAlpha;
209 }
210
211 void TextureSet::GetResourcesStatus( bool& resourcesReady, bool& finishedResourceAcquisition )
212 {
213   resourcesReady = mResourcesReady;
214   finishedResourceAcquisition = mFinishedResourceAcquisition;
215 }
216
217 void TextureSet::AddObserver( Renderer* renderer )
218 {
219   size_t rendererCount( mRenderers.Size() );
220   for( size_t i(0); i<rendererCount; ++i )
221   {
222     if( mRenderers[i] == renderer )
223     {
224       //Renderer already in the list
225       return;
226     }
227   }
228
229   mRenderers.PushBack( renderer );
230 }
231
232 void TextureSet::RemoveObserver( Renderer* renderer )
233 {
234   size_t rendererCount( mRenderers.Size() );
235   for( size_t i(0); i<rendererCount; ++i )
236   {
237     if( mRenderers[i] == renderer )
238     {
239       mRenderers.Remove( mRenderers.Begin() + i );
240       return;
241     }
242   }
243 }
244
245 void TextureSet::NotifyChangeToRenderers()
246 {
247   size_t rendererCount = mRenderers.Size();
248   for( size_t i(0); i<rendererCount; ++i )
249   {
250     mRenderers[i]->TextureSetChanged();
251   }
252 }
253
254 } // namespace SceneGraph
255
256 } // namespace Internal
257
258 } // namespace Dali