Rendering API clean-up
[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-texture-set.h>
26 #include <dali/internal/render/shaders/scene-graph-shader.h>
27 #include <dali/internal/render/renderers/render-renderer.h>
28 #include <dali/internal/render/data-providers/node-data-provider.h>
29 #include <dali/internal/update/nodes/node.h>
30 #include <dali/internal/render/queue/render-queue.h>
31 #include <dali/internal/common/internal-constants.h>
32 #include <dali/internal/common/memory-pool-object-allocator.h>
33
34
35 namespace // unnamed namespace
36 {
37
38 const unsigned int UNIFORM_MAP_READY      = 0;
39 const unsigned int COPY_UNIFORM_MAP       = 1;
40 const unsigned int REGENERATE_UNIFORM_MAP = 2;
41
42 //Memory pool used to allocate new renderers. Memory used by this pool will be released when shutting down DALi
43 Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Renderer> gRendererMemoryPool;
44
45 void AddMappings( Dali::Internal::SceneGraph::CollectedUniformMap& localMap, const Dali::Internal::SceneGraph::UniformMap& uniformMap )
46 {
47   // Iterate thru uniformMap.
48   //   Any maps that aren't in localMap should be added in a single step
49   Dali::Internal::SceneGraph::CollectedUniformMap newUniformMappings;
50
51   for( unsigned int i=0, count=uniformMap.Count(); i<count; ++i )
52   {
53     Dali::Internal::SceneGraph::UniformPropertyMapping::Hash nameHash = uniformMap[i].uniformNameHash;
54     bool found = false;
55
56     for( Dali::Internal::SceneGraph::CollectedUniformMap::Iterator iter = localMap.Begin() ; iter != localMap.End() ; ++iter )
57     {
58       const Dali::Internal::SceneGraph::UniformPropertyMapping* map = (*iter);
59       if( map->uniformNameHash == nameHash )
60       {
61         if( map->uniformName == uniformMap[i].uniformName )
62         {
63           found = true;
64           break;
65         }
66       }
67     }
68     if( !found )
69     {
70       // it's a new mapping. Add raw ptr to temporary list
71       newUniformMappings.PushBack( &uniformMap[i] );
72     }
73   }
74
75   if( newUniformMappings.Count() > 0 )
76   {
77     localMap.Reserve( localMap.Count() + newUniformMappings.Count() );
78
79     for( Dali::Internal::SceneGraph::CollectedUniformMap::Iterator iter = newUniformMappings.Begin(),
80            end = newUniformMappings.End() ;
81          iter != end ;
82          ++iter )
83     {
84       const Dali::Internal::SceneGraph::UniformPropertyMapping* map = (*iter);
85       localMap.PushBack( map );
86     }
87   }
88 }
89
90 // flags for resending data to renderer
91 enum Flags
92 {
93   RESEND_DATA_PROVIDER = 1,
94   RESEND_GEOMETRY = 1 << 1,
95   RESEND_FACE_CULLING_MODE = 1 << 2,
96   RESEND_BLEND_COLOR = 1 << 3,
97   RESEND_BLEND_BIT_MASK = 1 << 4,
98   RESEND_PREMULTIPLIED_ALPHA = 1 << 5
99 };
100
101 }
102
103 namespace Dali
104 {
105 namespace Internal
106 {
107 namespace SceneGraph
108 {
109
110 Renderer* Renderer::New()
111 {
112   return new ( gRendererMemoryPool.AllocateRawThreadSafe() ) Renderer();
113 }
114
115 Renderer::Renderer()
116 :mSceneController(0),
117  mRenderer(NULL),
118  mTextureSet(NULL),
119  mGeometry(NULL),
120  mShader(NULL),
121  mBlendColor(NULL),
122  mBlendBitmask(0u),
123  mFaceCullingMode( Dali::Renderer::NONE ),
124  mBlendingMode( Dali::BlendingMode::AUTO ),
125  mReferenceCount(0),
126  mRegenerateUniformMap(0),
127  mResendFlag(0),
128  mResourcesReady(false),
129  mFinishedResourceAcquisition(false),
130  mDepthIndex(0)
131 {
132   mUniformMapChanged[0]=false;
133   mUniformMapChanged[1]=false;
134
135   // Observe our own PropertyOwner's uniform map
136   AddUniformMapObserver( *this );
137 }
138
139 Renderer::~Renderer()
140 {
141   if (mTextureSet)
142   {
143     mTextureSet->RemoveConnectionObserver(*this);
144     mTextureSet=NULL;
145   }
146   if (mGeometry)
147   {
148     mGeometry->RemoveConnectionObserver(*this);
149     mGeometry=NULL;
150   }
151   if( mShader )
152   {
153     mShader->RemoveConnectionObserver(*this);
154     mShader=NULL;
155   }
156
157 }
158
159 void Renderer::operator delete( void* ptr )
160 {
161   gRendererMemoryPool.FreeThreadSafe( static_cast<Renderer*>( ptr ) );
162 }
163
164
165 void Renderer::PrepareRender( BufferIndex updateBufferIndex )
166 {
167   mResourcesReady = false;
168   mFinishedResourceAcquisition = false;
169
170   // Can only be considered ready when all the scene graph objects are connected to the renderer
171   if( ( mGeometry ) && ( mGeometry->GetVertexBuffers().Count() > 0 ) && ( mShader ) )
172   {
173     if( mTextureSet )
174     {
175       mTextureSet->GetResourcesStatus( mResourcesReady, mFinishedResourceAcquisition );
176     }
177     else
178     {
179       mResourcesReady = true;
180       mFinishedResourceAcquisition = true;
181     }
182   }
183
184   if( mRegenerateUniformMap > UNIFORM_MAP_READY )
185   {
186     DALI_ASSERT_DEBUG( mGeometry != NULL && "No geometry available in PrepareRender()" );
187     DALI_ASSERT_DEBUG( mShader != NULL && "No shader available in PrepareRender()" );
188
189     if( mRegenerateUniformMap == REGENERATE_UNIFORM_MAP)
190     {
191       CollectedUniformMap& localMap = mCollectedUniformMap[ updateBufferIndex ];
192       localMap.Resize(0);
193
194       const UniformMap& rendererUniformMap = PropertyOwner::GetUniformMap();
195       AddMappings( localMap, rendererUniformMap );
196
197       if( mTextureSet )
198       {
199         AddMappings( localMap, mTextureSet->GetUniformMap() );
200       }
201
202       AddMappings( localMap, mShader->GetUniformMap() );
203       AddMappings( localMap, mGeometry->GetUniformMap() );
204
205     }
206     else if( mRegenerateUniformMap == COPY_UNIFORM_MAP )
207     {
208       // Copy old map into current map
209       CollectedUniformMap& localMap = mCollectedUniformMap[ updateBufferIndex ];
210       CollectedUniformMap& oldMap = mCollectedUniformMap[ 1-updateBufferIndex ];
211
212       localMap.Resize( oldMap.Count() );
213
214       unsigned int index=0;
215       for( CollectedUniformMap::Iterator iter = oldMap.Begin(), end = oldMap.End() ; iter != end ; ++iter, ++index )
216       {
217         localMap[index] = *iter;
218       }
219     }
220
221     mUniformMapChanged[updateBufferIndex] = true;
222     mRegenerateUniformMap--;
223   }
224
225   if( mResendFlag == 0 )
226   {
227     return;
228   }
229
230   if( mResendFlag & RESEND_DATA_PROVIDER )
231   {
232     RenderDataProvider* dataProvider = NewRenderDataProvider();
233
234     typedef MessageValue1< Render::Renderer, OwnerPointer<RenderDataProvider> > DerivedType;
235     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
236     new (slot) DerivedType( mRenderer, &Render::Renderer::SetRenderDataProvider, dataProvider );
237     mResendFlag &= ~RESEND_DATA_PROVIDER;
238   }
239
240   if( mResendFlag & RESEND_GEOMETRY )
241   {
242     // The first call to GetRenderGeometry() creates the geometry and sends it in a message
243     RenderGeometry* geometry = mGeometry->GetRenderGeometry( mSceneController );
244
245     typedef MessageValue1< Render::Renderer, RenderGeometry* > DerivedType;
246     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
247
248     new (slot) DerivedType( mRenderer, &Render::Renderer::SetGeometry, geometry );
249     mResendFlag &= ~RESEND_GEOMETRY;
250   }
251
252   if( mResendFlag & RESEND_FACE_CULLING_MODE )
253   {
254     typedef MessageValue1< Render::Renderer, Dali::Renderer::FaceCullingMode > DerivedType;
255     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
256     new (slot) DerivedType( mRenderer, &Render::Renderer::SetFaceCullingMode, mFaceCullingMode );
257     mResendFlag &= ~RESEND_FACE_CULLING_MODE;
258   }
259
260   if( mResendFlag & RESEND_BLEND_BIT_MASK )
261   {
262     typedef MessageValue1< Render::Renderer, unsigned int > DerivedType;
263     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
264     new (slot) DerivedType( mRenderer, &Render::Renderer::SetBlendingBitMask, mBlendBitmask );
265     mResendFlag &= ~RESEND_BLEND_BIT_MASK;
266   }
267
268   if( mResendFlag & RESEND_BLEND_COLOR )
269   {
270     typedef MessageValue1< Render::Renderer, const Vector4* > DerivedType;
271     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
272     new (slot) DerivedType( mRenderer, &Render::Renderer::SetBlendColor, mBlendColor );
273     mResendFlag &= ~RESEND_BLEND_COLOR;
274   }
275
276   if( mResendFlag & RESEND_PREMULTIPLIED_ALPHA  )
277   {
278     typedef MessageValue1< Render::Renderer, bool > DerivedType;
279     unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
280     new (slot) DerivedType( mRenderer, &Render::Renderer::EnablePreMultipliedAlpha, mPremultipledAlphaEnabled );
281     mResendFlag &= ~RESEND_PREMULTIPLIED_ALPHA;
282   }
283 }
284
285 void Renderer::SetTextures( TextureSet* textureSet )
286 {
287   DALI_ASSERT_DEBUG( textureSet != NULL && "Texture set pointer is NULL" );
288
289   if( mTextureSet )
290   {
291     mTextureSet->RemoveConnectionObserver(*this);
292   }
293
294   mTextureSet = textureSet;
295   mTextureSet->AddConnectionObserver( *this );
296   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
297   mResendFlag |= RESEND_DATA_PROVIDER;
298 }
299
300 void Renderer::SetShader( Shader* shader )
301 {
302   DALI_ASSERT_DEBUG( shader != NULL && "Shader pointer is NULL" );
303
304   if( mShader )
305   {
306     mShader->RemoveConnectionObserver(*this);
307   }
308
309   mShader = shader;
310   mShader->AddConnectionObserver( *this );
311   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
312   mResendFlag |= RESEND_DATA_PROVIDER;
313 }
314
315 void Renderer::SetGeometry( Geometry* geometry )
316 {
317   DALI_ASSERT_DEBUG( geometry != NULL && "Geometry pointer is NULL");
318   if( mGeometry)
319   {
320     mGeometry->RemoveConnectionObserver(*this);
321     mGeometry->OnRendererDisconnect();
322   }
323
324   mGeometry = geometry;
325   mGeometry->AddConnectionObserver( *this ); // Observe geometry connections / uniform mapping changes
326   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
327
328   if( mRenderer )
329   {
330     mResendFlag |= RESEND_GEOMETRY;
331   }
332 }
333
334 void Renderer::SetDepthIndex( int depthIndex )
335 {
336   mDepthIndex = depthIndex;
337 }
338
339 void Renderer::SetFaceCullingMode( unsigned int faceCullingMode )
340 {
341   mFaceCullingMode = static_cast<Dali::Renderer::FaceCullingMode>(faceCullingMode);
342   mResendFlag |= RESEND_FACE_CULLING_MODE;
343 }
344
345 void Renderer::SetBlendingMode( unsigned int blendingMode )
346 {
347   mBlendingMode = static_cast< BlendingMode::Type >( blendingMode );
348 }
349
350 void Renderer::SetBlendingOptions( unsigned int options )
351 {
352   if( mBlendBitmask != options)
353   {
354     mBlendBitmask = options;
355     mResendFlag |= RESEND_BLEND_BIT_MASK;
356   }
357 }
358
359 void Renderer::SetBlendColor( const Vector4& blendColor )
360 {
361   if( !mBlendColor )
362   {
363     mBlendColor = new Vector4( blendColor );
364   }
365   else
366   {
367     *mBlendColor = blendColor;
368   }
369
370   mResendFlag |= RESEND_BLEND_COLOR;
371 }
372
373 void Renderer::EnablePreMultipliedAlpha( bool preMultipled )
374 {
375   mPremultipledAlphaEnabled = preMultipled;
376   mResendFlag |= RESEND_PREMULTIPLIED_ALPHA;
377 }
378
379 //Called when a node with this renderer is added to the stage
380 void Renderer::OnStageConnect()
381 {
382   ++mReferenceCount;
383   if( !mRenderer)
384   {
385     RenderDataProvider* dataProvider = NewRenderDataProvider();
386
387     RenderGeometry* renderGeometry = mGeometry->GetRenderGeometry(mSceneController);
388     mRenderer = Render::Renderer::New( dataProvider, renderGeometry,
389                                        mBlendBitmask, mBlendColor,
390                                        static_cast< Dali::Renderer::FaceCullingMode >( mFaceCullingMode ),
391                                        mPremultipledAlphaEnabled );
392     mSceneController->GetRenderMessageDispatcher().AddRenderer( *mRenderer );
393     mResendFlag = 0;
394   }
395 }
396
397 //Called when the node with this renderer has gone out of the stage
398 void Renderer::OnStageDisconnect()
399 {
400   --mReferenceCount;
401   if( mReferenceCount == 0 )
402   {
403     mSceneController->GetRenderMessageDispatcher().RemoveRenderer( *mRenderer );
404     if( mGeometry )
405     {
406       mGeometry->OnRendererDisconnect();
407     }
408     mRenderer = NULL;
409   }
410 }
411
412 //Called when SceneGraph::Renderer is added to update manager ( that happens when an "event-thread renderer" is created )
413 void Renderer::ConnectToSceneGraph( SceneController& sceneController, BufferIndex bufferIndex )
414 {
415   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
416   mSceneController = &sceneController;
417 }
418
419
420 //Called just before destroying the scene-graph renderer ( when the "event-thread renderer" is no longer referenced )
421 void Renderer::DisconnectFromSceneGraph( SceneController& sceneController, BufferIndex bufferIndex )
422 {
423   //Remove renderer from RenderManager
424   if( mRenderer )
425   {
426     mSceneController->GetRenderMessageDispatcher().RemoveRenderer( *mRenderer );
427     mRenderer = NULL;
428     mSceneController = NULL;
429   }
430 }
431
432 RenderDataProvider* Renderer::NewRenderDataProvider()
433 {
434   RenderDataProvider* dataProvider = new RenderDataProvider();
435
436   dataProvider->mUniformMapDataProvider = this;
437   dataProvider->mShader = mShader;
438
439   if( mTextureSet )
440   {
441     size_t textureCount( mTextureSet->GetTextureCount() );
442     dataProvider->mTextures.resize( textureCount );
443     for( unsigned int i(0); i<textureCount; ++i )
444     {
445       dataProvider->mTextures[i] = Render::Texture( mTextureSet->GetTextureId(i),
446                                                     mTextureSet->GetTextureSampler(i));
447     }
448   }
449
450   return dataProvider;
451 }
452
453 Render::Renderer& Renderer::GetRenderer()
454 {
455   return *mRenderer;
456 }
457
458 const CollectedUniformMap& Renderer::GetUniformMap( BufferIndex bufferIndex ) const
459 {
460   return mCollectedUniformMap[bufferIndex];
461 };
462
463 void Renderer::GetReadyAndComplete( bool& ready, bool& complete ) const
464 {
465   ready = mResourcesReady;
466   complete = mFinishedResourceAcquisition;
467 }
468
469 Renderer::Opacity Renderer::GetOpacity( BufferIndex updateBufferIndex, const Node& node ) const
470 {
471   Renderer::Opacity opacity = Renderer::OPAQUE;
472
473   switch( mBlendingMode )
474   {
475     case BlendingMode::ON: // If the renderer should always be use blending
476     {
477       opacity = Renderer::TRANSLUCENT;
478       break;
479     }
480     case BlendingMode::AUTO:
481     {
482       bool shaderRequiresBlending( mShader->GeometryHintEnabled( Dali::ShaderEffect::HINT_BLENDING ) );
483       if( shaderRequiresBlending || ( mTextureSet && mTextureSet->HasAlpha() ) )
484       {
485         opacity = Renderer::TRANSLUCENT;
486       }
487       else // renderer should determine opacity using the actor color
488       {
489         float alpha = node.GetWorldColor( updateBufferIndex ).a;
490         if( alpha <= FULLY_TRANSPARENT )
491         {
492           opacity = TRANSPARENT;
493         }
494         else if( alpha <= FULLY_OPAQUE )
495         {
496           opacity = TRANSLUCENT;
497         }
498       }
499       break;
500     }
501     case BlendingMode::OFF: // the renderer should never use blending
502     default:
503     {
504       opacity = Renderer::OPAQUE;
505       break;
506     }
507   }
508
509
510   return opacity;
511 }
512
513 void Renderer::ConnectionsChanged( PropertyOwner& object )
514 {
515   // One of our child objects has changed it's connections. Ensure the uniform
516   // map gets regenerated during PrepareRender
517   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
518
519   // Ensure the child object pointers get re-sent to the renderer
520   mResendFlag |= RESEND_DATA_PROVIDER;
521 }
522
523 void Renderer::ConnectedUniformMapChanged()
524 {
525   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
526 }
527
528 void Renderer::UniformMappingsChanged( const UniformMap& mappings )
529 {
530   // The mappings are either from PropertyOwner base class, or the Actor
531   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
532 }
533
534 void Renderer::ObservedObjectDestroyed(PropertyOwner& owner)
535 {
536   if( reinterpret_cast<PropertyOwner*>(mGeometry) == &owner )
537   {
538     mGeometry = NULL;
539   }
540   else if( reinterpret_cast<PropertyOwner*>(mTextureSet) == &owner )
541   {
542     mTextureSet = NULL;
543   }
544   else if( reinterpret_cast<PropertyOwner*>(mShader) == &owner )
545   {
546     mShader = NULL;
547   }
548 }
549
550 } // namespace SceneGraph
551 } // namespace Internal
552 } // namespace Dali