Optimize blending requirement resolution
[platform/core/uifw/dali-core.git] / dali / internal / update / rendering / scene-graph-renderer.cpp
1 /*
2  * Copyright (c) 2015 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-renderer.h"
19
20 // INTERNAL HEADERS
21 #include <dali/internal/update/controllers/scene-controller.h>
22 #include <dali/internal/render/renderers/render-geometry.h>
23 #include <dali/internal/update/controllers/render-message-dispatcher.h>
24 #include <dali/internal/update/rendering/scene-graph-geometry.h>
25 #include <dali/internal/update/rendering/scene-graph-material.h>
26 #include <dali/internal/render/shaders/scene-graph-shader.h>
27 #include <dali/internal/render/renderers/render-new-renderer.h>
28 #include <dali/internal/render/data-providers/node-data-provider.h>
29 #include <dali/internal/update/resources/complete-status-manager.h>
30 #include <dali/internal/update/nodes/node.h>
31 #include <dali/internal/update/resources/resource-tracker.h>
32 #include <dali/internal/render/queue/render-queue.h>
33 #include <dali/internal/common/internal-constants.h>
34
35
36 namespace // unnamed namespace
37 {
38
39 const unsigned int UNIFORM_MAP_READY      = 0;
40 const unsigned int COPY_UNIFORM_MAP       = 1;
41 const unsigned int REGENERATE_UNIFORM_MAP = 2;
42
43 void AddMappings( Dali::Internal::SceneGraph::CollectedUniformMap& localMap, const Dali::Internal::SceneGraph::UniformMap& uniformMap )
44 {
45   // Iterate thru uniformMap.
46   //   Any maps that aren't in localMap should be added in a single step
47   Dali::Internal::SceneGraph::CollectedUniformMap newUniformMappings;
48
49   for( unsigned int i=0, count=uniformMap.Count(); i<count; ++i )
50   {
51     Dali::Internal::SceneGraph::UniformPropertyMapping::Hash nameHash = uniformMap[i].uniformNameHash;
52     bool found = false;
53
54     for( Dali::Internal::SceneGraph::CollectedUniformMap::Iterator iter = localMap.Begin() ; iter != localMap.End() ; ++iter )
55     {
56       const Dali::Internal::SceneGraph::UniformPropertyMapping* map = (*iter);
57       if( map->uniformNameHash == nameHash )
58       {
59         if( map->uniformName == uniformMap[i].uniformName )
60         {
61           found = true;
62           break;
63         }
64       }
65     }
66     if( !found )
67     {
68       // it's a new mapping. Add raw ptr to temporary list
69       newUniformMappings.PushBack( &uniformMap[i] );
70     }
71   }
72
73   if( newUniformMappings.Count() > 0 )
74   {
75     localMap.Reserve( localMap.Count() + newUniformMappings.Count() );
76
77     for( Dali::Internal::SceneGraph::CollectedUniformMap::Iterator iter = newUniformMappings.Begin(),
78            end = newUniformMappings.End() ;
79          iter != end ;
80          ++iter )
81     {
82       const Dali::Internal::SceneGraph::UniformPropertyMapping* map = (*iter);
83       localMap.PushBack( map );
84     }
85     //@todo MESH_REWORK Use memcpy to copy ptrs from one array to the other
86   }
87 }
88 }
89
90 namespace Dali
91 {
92 namespace Internal
93 {
94 namespace SceneGraph
95 {
96
97 Renderer::Renderer()
98 :mSceneController(0),
99  mRenderer(NULL),
100  mMaterial(NULL),
101  mGeometry(NULL),
102  mReferenceCount(0),
103  mRegenerateUniformMap(0),
104  mResendDataProviders(false),
105  mResendGeometry(false),
106  mHasUntrackedResources(false),
107  mFinishedResourceAcquisition(false),
108  mResourcesReady(false),
109  mDepthIndex(0)
110 {
111   mUniformMapChanged[0]=false;
112   mUniformMapChanged[1]=false;
113
114   // Observe our own PropertyOwner's uniform map
115   AddUniformMapObserver( *this );
116 }
117
118 Renderer::~Renderer()
119 {
120   if (mMaterial)
121   {
122     mMaterial->RemoveConnectionObserver(*this);
123     mMaterial=NULL;
124   }
125   if (mGeometry)
126   {
127     mGeometry->RemoveConnectionObserver(*this);
128     mGeometry=NULL;
129   }
130 }
131
132 void Renderer::PrepareRender( BufferIndex updateBufferIndex )
133 {
134   mMaterial->PrepareRender( updateBufferIndex );
135
136   if( mRegenerateUniformMap > UNIFORM_MAP_READY )
137   {
138     DALI_ASSERT_DEBUG( mGeometry != NULL && "No geometry available in DoPrepareRender()" );
139     DALI_ASSERT_DEBUG( mMaterial != NULL && "No geometry available in DoPrepareRender()" );
140
141     if( mRegenerateUniformMap == REGENERATE_UNIFORM_MAP)
142     {
143       CollectedUniformMap& localMap = mCollectedUniformMap[ updateBufferIndex ];
144       localMap.Resize(0);
145
146       const UniformMap& rendererUniformMap = PropertyOwner::GetUniformMap();
147       AddMappings( localMap, rendererUniformMap );
148
149       AddMappings( localMap, mMaterial->GetUniformMap() );
150       AddMappings( localMap, mMaterial->GetShader()->GetUniformMap() );
151       AddMappings( localMap, mGeometry->GetUniformMap() );
152
153     }
154     else if( mRegenerateUniformMap == COPY_UNIFORM_MAP )
155     {
156       // Copy old map into current map
157       CollectedUniformMap& localMap = mCollectedUniformMap[ updateBufferIndex ];
158       CollectedUniformMap& oldMap = mCollectedUniformMap[ 1-updateBufferIndex ];
159
160       localMap.Resize( oldMap.Count() );
161
162       unsigned int index=0;
163       for( CollectedUniformMap::Iterator iter = oldMap.Begin(), end = oldMap.End() ; iter != end ; ++iter, ++index )
164       {
165         localMap[index] = *iter;
166       }
167     }
168
169     mUniformMapChanged[updateBufferIndex] = true;
170     mRegenerateUniformMap--;
171   }
172
173   if( mResendDataProviders )
174   {
175     RenderDataProvider* dataProvider = NewRenderDataProvider();
176
177     // Tell renderer about a new provider
178     // @todo MESH_REWORK Should we instead create a new renderer when these change?
179
180     typedef MessageValue1< Render::NewRenderer, OwnerPointer<RenderDataProvider> > DerivedType;
181     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
182     new (slot) DerivedType( mRenderer, &Render::NewRenderer::SetRenderDataProvider, dataProvider );
183     mResendDataProviders = false;
184   }
185
186   if( mResendGeometry )
187   {
188     // The first call to GetRenderGeometry() creates the geometry and sends it in a message
189     RenderGeometry* geometry = mGeometry->GetRenderGeometry( mSceneController );
190
191     typedef MessageValue1< Render::NewRenderer, RenderGeometry* > DerivedType;
192     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
193
194     new (slot) DerivedType( mRenderer, &Render::NewRenderer::SetGeometry, geometry );
195     mResendGeometry = false;
196   }
197 }
198
199 void Renderer::SetMaterial( BufferIndex bufferIndex, Material* material)
200 {
201   DALI_ASSERT_DEBUG( material != NULL && "Material pointer is NULL" );
202
203   mMaterial = material;
204   mMaterial->AddConnectionObserver( *this );
205   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
206
207   mResendDataProviders = true;
208 }
209
210 void Renderer::SetGeometry( BufferIndex bufferIndex, Geometry* geometry)
211 {
212   DALI_ASSERT_DEBUG( geometry != NULL && "Geometry pointer is NULL");
213   if( mGeometry)
214   {
215     mGeometry->RemoveConnectionObserver(*this);
216     mGeometry->OnRendererDisconnect();
217   }
218
219   mGeometry = geometry;
220   mGeometry->AddConnectionObserver( *this ); // Observe geometry connections / uniform mapping changes
221   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
222
223   if( mRenderer )
224   {
225     mResendGeometry = true;
226   }
227 }
228
229 void Renderer::SetDepthIndex( int depthIndex )
230 {
231   mDepthIndex = depthIndex;
232 }
233
234 //Called when a node with this renderer is added to the stage
235 void Renderer::OnStageConnect()
236 {
237   ++mReferenceCount;
238   if( !mRenderer)
239   {
240     RenderDataProvider* dataProvider = NewRenderDataProvider();
241
242     RenderGeometry* renderGeometry = mGeometry->GetRenderGeometry(mSceneController);
243     mRenderer = Render::NewRenderer::New( dataProvider, renderGeometry );
244     mSceneController->GetRenderMessageDispatcher().AddRenderer( *mRenderer );
245     mResendDataProviders = false;
246     mResendGeometry = false;
247   }
248 }
249
250 //Called when the node with this renderer has gone out of the stage
251 void Renderer::OnStageDisconnect()
252 {
253   --mReferenceCount;
254   if( mReferenceCount == 0 )
255   {
256     mSceneController->GetRenderMessageDispatcher().RemoveRenderer( *mRenderer );
257     if( mGeometry )
258     {
259       mGeometry->OnRendererDisconnect();
260     }
261     mRenderer = NULL;
262   }
263 }
264
265 //Called when SceneGraph::Renderer is added to update manager ( that happens when an "event-thread renderer" is created )
266 void Renderer::ConnectToSceneGraph( SceneController& sceneController, BufferIndex bufferIndex )
267 {
268   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
269   mSceneController = &sceneController;
270 }
271
272
273 //Called just before destroying the scene-graph renderer ( when the "event-thread renderer" is no longer referenced )
274 void Renderer::DisconnectFromSceneGraph( SceneController& sceneController, BufferIndex bufferIndex )
275 {
276   //Remove renderer from RenderManager
277   if( mRenderer )
278   {
279     mSceneController->GetRenderMessageDispatcher().RemoveRenderer( *mRenderer );
280     mRenderer = NULL;
281     mSceneController = NULL;
282   }
283 }
284
285 RenderDataProvider* Renderer::NewRenderDataProvider()
286 {
287   RenderDataProvider* dataProvider = new RenderDataProvider();
288
289   dataProvider->mMaterialDataProvider = mMaterial;
290   dataProvider->mUniformMapDataProvider = this;
291   dataProvider->mShader = mMaterial->GetShader();
292
293   size_t textureCount( mMaterial->GetTextureCount() );
294   dataProvider->mTextures.resize( textureCount );
295   for( unsigned int i(0); i<textureCount; ++i )
296   {
297     dataProvider->mTextures[i] = Render::Texture( mMaterial->GetTextureUniformName(i),
298                                                   mMaterial->GetTextureId(i),
299                                                   mMaterial->GetTextureSampler(i));
300   }
301
302   return dataProvider;
303 }
304
305 Render::Renderer& Renderer::GetRenderer()
306 {
307   return *mRenderer;
308 }
309
310 const CollectedUniformMap& Renderer::GetUniformMap( BufferIndex bufferIndex ) const
311 {
312   return mCollectedUniformMap[bufferIndex];
313 };
314
315 void Renderer::PrepareResources( BufferIndex updateBufferIndex, ResourceManager& resourceManager )
316 {
317   mHasUntrackedResources = false;
318   mTrackedResources.Clear(); // Resource trackers are only needed if not yet completea
319
320   DALI_ASSERT_DEBUG( mSceneController );
321
322   CompleteStatusManager& completeStatusManager = mSceneController->GetCompleteStatusManager();
323   mResourcesReady = false;
324
325   mFinishedResourceAcquisition = false;
326
327   // Can only be considered ready when all the scene graph objects are connected to the renderer
328   if( ( mGeometry ) && ( mGeometry->GetVertexBuffers().Count() > 0 ) &&
329       ( mMaterial ) && ( mMaterial->GetShader() != NULL ) )
330   {
331     unsigned int completeCount = 0;
332     unsigned int neverCount = 0;
333     unsigned int frameBufferCount = 0;
334
335     size_t textureCount( mMaterial->GetTextureCount() );
336     if( textureCount > 0 )
337     {
338       unsigned int opaqueCount = 0;
339       for( unsigned int i(0); i<textureCount; ++i )
340       {
341         ResourceId textureId = mMaterial->GetTextureId(i);
342         BitmapMetadata metaData = resourceManager.GetBitmapMetadata( textureId );
343         if( metaData.IsFullyOpaque() )
344         {
345           ++opaqueCount;
346         }
347
348         switch( completeStatusManager.GetStatus( textureId ) )
349         {
350           case CompleteStatusManager::NOT_READY:
351           {
352           if( metaData.GetIsFramebuffer() )
353             {
354               frameBufferCount++;
355             }
356             if( completeStatusManager.FindResourceTracker(textureId) != NULL )
357             {
358               bool found = false;
359               std::size_t numTrackedResources = mTrackedResources.Count();
360               for( size_t i=0; i < numTrackedResources; ++i )
361               {
362                 if(mTrackedResources[i] == textureId)
363                 {
364                   found = true;
365                   break;
366                 }
367               }
368               if( ! found )
369               {
370                 mTrackedResources.PushBack( textureId );
371               }
372             }
373             else
374             {
375               mHasUntrackedResources = true;
376             }
377           }
378           break;
379
380           case CompleteStatusManager::COMPLETE:
381           {
382             completeCount++;
383           }
384           break;
385
386           case CompleteStatusManager::NEVER:
387           {
388             neverCount++;
389           }
390           break;
391         }
392       }
393       mMaterial->SetTexturesRequireBlending( opaqueCount != textureCount );
394     }
395
396     // We are ready if all samplers are complete, or those that aren't are framebuffers
397     // We are complete if all samplers are either complete or will nmResendGeometryever complete
398     mResourcesReady = ( completeCount + frameBufferCount >= textureCount ) ;
399     mFinishedResourceAcquisition = ( completeCount + neverCount >= textureCount );
400   }
401 }
402
403 void Renderer::GetReadyAndComplete(bool& ready, bool& complete) const
404 {
405   ready = mResourcesReady;
406   complete = false;
407
408   CompleteStatusManager& completeStatusManager = mSceneController->GetCompleteStatusManager();
409
410   std::size_t numTrackedResources = mTrackedResources.Count();
411   if( mHasUntrackedResources || numTrackedResources == 0 )
412   {
413     complete = mFinishedResourceAcquisition;
414   }
415   else
416   {
417     // If there are tracked resources and no untracked resources, test the trackers
418     bool trackersComplete = true;
419     for( size_t i=0; i < numTrackedResources; ++i )
420     {
421       ResourceId id = mTrackedResources[i];
422       ResourceTracker* tracker = completeStatusManager.FindResourceTracker(id);
423       if( tracker  && ! tracker->IsComplete() )
424       {
425         trackersComplete = false;
426         break;
427       }
428     }
429
430     complete = mFinishedResourceAcquisition || trackersComplete;
431   }
432 }
433
434 // Called by ProcessRenderTasks after DoPrepareRender
435 bool Renderer::IsFullyOpaque( BufferIndex updateBufferIndex, const Node& node ) const
436 {
437   bool opaque = false;
438
439   if( mMaterial != NULL )
440   {
441     Material::BlendPolicy blendPolicy = mMaterial->GetBlendPolicy();
442     switch( blendPolicy )
443     {
444       case Material::OPAQUE:
445       {
446         opaque = true;
447         break;
448       }
449       case Material::TRANSPARENT:
450       {
451         opaque = false;
452         break;
453       }
454       case Material::USE_ACTOR_COLOR:
455       {
456         opaque = node.GetWorldColor( updateBufferIndex ).a >= FULLY_OPAQUE;
457         break;
458       }
459     }
460   }
461
462   return opaque;
463 }
464
465 void Renderer::ConnectionsChanged( PropertyOwner& object )
466 {
467   // One of our child objects has changed it's connections. Ensure the uniform
468   // map gets regenerated during PrepareRender
469   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
470
471   // Ensure the child object pointers get re-sent to the renderer
472   mResendDataProviders = true;
473 }
474
475 void Renderer::ConnectedUniformMapChanged()
476 {
477   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
478 }
479
480 void Renderer::UniformMappingsChanged( const UniformMap& mappings )
481 {
482   // The mappings are either from PropertyOwner base class, or the Actor
483   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
484 }
485
486 void Renderer::ObservedObjectDestroyed(PropertyOwner& owner)
487 {
488   if( reinterpret_cast<PropertyOwner*>(mGeometry) == &owner )
489   {
490     mGeometry = NULL;
491   }
492   else if( reinterpret_cast<PropertyOwner*>(mMaterial) == &owner )
493   {
494     mMaterial = NULL;
495   }
496 }
497
498 } // namespace SceneGraph
499 } // namespace Internal
500 } // namespace Dali