Moved framebuffer messages from UpdateManager to FrameBuffer
[platform/core/uifw/dali-core.git] / dali / internal / update / rendering / scene-graph-renderer.cpp
1 /*
2  * Copyright (c) 2018 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 #pragma GCC diagnostic push
18 #pragma GCC diagnostic ignored "-Wunused-variable"
19 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
20 #pragma GCC diagnostic ignored "-Wunused-function"
21
22 // CLASS HEADER
23 #include "scene-graph-renderer.h"
24
25 // INTERNAL INCLUDES
26 #include <dali/internal/common/internal-constants.h>
27 #include <dali/internal/common/memory-pool-object-allocator.h>
28 #include <dali/internal/update/nodes/node.h>
29 #include <dali/internal/update/rendering/data-providers/node-data-provider.h>
30 #include <dali/internal/update/rendering/scene-graph-geometry.h>
31 #include <dali/internal/update/rendering/scene-graph-property-buffer.h>
32 #include <dali/internal/update/rendering/scene-graph-texture-set.h>
33 #include <dali/internal/update/rendering/scene-graph-shader.h>
34
35 #include <dali/graphics-api/graphics-api-controller.h>
36 #include <dali/graphics-api/graphics-api-render-command.h>
37 #include <dali/graphics-api/graphics-api-shader.h>
38 #include <dali/graphics-api/graphics-api-shader-details.h>
39
40 #include <cstring>
41
42
43 namespace
44 {
45
46 /**
47  * Helper to set view and projection matrices once per program
48  * @param program to set the matrices to
49  * @param modelMatrix to set
50  * @param viewMatrix to set
51  * @param projectionMatrix to set
52  * @param modelViewMatrix to set
53  * @param modelViewProjectionMatrix to set
54  */
55 inline void SetMatrices(
56                          const Dali::Matrix& modelMatrix,
57                          const Dali::Matrix& viewMatrix,
58                          const Dali::Matrix& projectionMatrix,
59                          const Dali::Matrix& modelViewMatrix )
60 {
61
62 }
63
64 }
65
66 namespace // unnamed namespace
67 {
68
69 const unsigned int UNIFORM_MAP_READY      = 0;
70 const unsigned int COPY_UNIFORM_MAP       = 1;
71 const unsigned int REGENERATE_UNIFORM_MAP = 2;
72
73 //Memory pool used to allocate new renderers. Memory used by this pool will be released when shutting down DALi
74 Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Renderer> gRendererMemoryPool;
75
76 void AddMappings( Dali::Internal::SceneGraph::CollectedUniformMap& localMap, const Dali::Internal::SceneGraph::UniformMap& uniformMap )
77 {
78   // Iterate thru uniformMap.
79   //   Any maps that aren't in localMap should be added in a single step
80   Dali::Internal::SceneGraph::CollectedUniformMap newUniformMappings;
81
82   for( unsigned int i=0, count=uniformMap.Count(); i<count; ++i )
83   {
84     Dali::Internal::SceneGraph::UniformPropertyMapping::Hash nameHash = uniformMap[i].uniformNameHash;
85     bool found = false;
86
87     for( Dali::Internal::SceneGraph::CollectedUniformMap::Iterator iter = localMap.Begin() ; iter != localMap.End() ; ++iter )
88     {
89       const Dali::Internal::SceneGraph::UniformPropertyMapping* map = (*iter);
90       if( map->uniformNameHash == nameHash )
91       {
92         if( map->uniformName == uniformMap[i].uniformName )
93         {
94           found = true;
95           break;
96         }
97       }
98     }
99     if( !found )
100     {
101       // it's a new mapping. Add raw ptr to temporary list
102       newUniformMappings.PushBack( &uniformMap[i] );
103     }
104   }
105
106   if( newUniformMappings.Count() > 0 )
107   {
108     localMap.Reserve( localMap.Count() + newUniformMappings.Count() );
109
110     for( Dali::Internal::SceneGraph::CollectedUniformMap::Iterator iter = newUniformMappings.Begin(),
111            end = newUniformMappings.End() ;
112          iter != end ;
113          ++iter )
114     {
115       const Dali::Internal::SceneGraph::UniformPropertyMapping* map = (*iter);
116       localMap.PushBack( map );
117     }
118   }
119 }
120
121 } // Anonymous namespace
122
123 namespace Dali
124 {
125 namespace Internal
126 {
127 namespace SceneGraph
128 {
129
130 Renderer* Renderer::New()
131 {
132   return new ( gRendererMemoryPool.AllocateRawThreadSafe() ) Renderer();
133 }
134
135 Renderer::Renderer()
136 : mGraphics( nullptr ),
137   mRenderDataProvider(),
138   mTextureSet( NULL ),
139   mGeometry( NULL ),
140   mShader( NULL ),
141   mBlendColor( NULL ),
142   mStencilParameters( RenderMode::AUTO, StencilFunction::ALWAYS, 0xFF, 0x00, 0xFF, StencilOperation::KEEP, StencilOperation::KEEP, StencilOperation::KEEP ),
143   mIndexedDrawFirstElement( 0u ),
144   mIndexedDrawElementsCount( 0u ),
145   mBlendBitmask( 0u ),
146   mRegenerateUniformMap( 0u ),
147   mDepthFunction( DepthFunction::LESS ),
148   mFaceCullingMode( FaceCullingMode::NONE ),
149   mBlendMode( BlendMode::AUTO ),
150   mDepthWriteMode( DepthWriteMode::AUTO ),
151   mDepthTestMode( DepthTestMode::AUTO ),
152   mPremultipledAlphaEnabled( false ),
153   mGfxRenderCommand(),
154   mDepthIndex( 0 )
155 {
156   mUniformMapChanged[0] = false;
157   mUniformMapChanged[1] = false;
158
159   // Observe our own PropertyOwner's uniform map
160   AddUniformMapObserver( *this );
161 }
162
163 Renderer::~Renderer()
164 {
165   if( mTextureSet )
166   {
167     mTextureSet->RemoveObserver( this );
168     mTextureSet = NULL;
169   }
170   if( mShader )
171   {
172     mShader->RemoveConnectionObserver( *this );
173     mShader = NULL;
174   }
175 }
176
177 void Renderer::operator delete( void* ptr )
178 {
179   gRendererMemoryPool.FreeThreadSafe( static_cast<Renderer*>( ptr ) );
180 }
181
182 void Renderer::Initialize( Integration::Graphics::Graphics& graphics )
183 {
184   mGraphics = &graphics;
185
186   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
187
188   mRenderDataProvider = std::make_unique< RenderDataProvider >();
189
190   mRenderDataProvider->mUniformMapDataProvider = this;
191   mRenderDataProvider->mShader = mShader;
192
193   if( mTextureSet )
194   {
195     size_t textureCount = mTextureSet->GetTextureCount();
196     mRenderDataProvider->mTextures.resize( textureCount );
197     mRenderDataProvider->mSamplers.resize( textureCount );
198     for( unsigned int i(0); i<textureCount; ++i )
199     {
200       mRenderDataProvider->mTextures[i] = mTextureSet->GetTexture(i);
201       mRenderDataProvider->mSamplers[i] = mTextureSet->GetTextureSampler(i);
202     }
203   }
204 }
205
206
207 void* AllocateUniformBufferMemory( size_t size )
208 {
209   return nullptr;
210 }
211
212
213 void Renderer::UpdateUniformMap( BufferIndex updateBufferIndex )
214 {
215
216   if( mRegenerateUniformMap > UNIFORM_MAP_READY )
217   {
218     if( mRegenerateUniformMap == REGENERATE_UNIFORM_MAP)
219     {
220       CollectedUniformMap& localMap = mCollectedUniformMap[ updateBufferIndex ];
221       localMap.Resize(0);
222
223       const UniformMap& rendererUniformMap = PropertyOwner::GetUniformMap();
224       AddMappings( localMap, rendererUniformMap );
225
226       if( mShader )
227       {
228         AddMappings( localMap, mShader->GetUniformMap() );
229       }
230     }
231     else if( mRegenerateUniformMap == COPY_UNIFORM_MAP )
232     {
233       // Copy old map into current map
234       CollectedUniformMap& localMap = mCollectedUniformMap[ updateBufferIndex ];
235       CollectedUniformMap& oldMap = mCollectedUniformMap[ 1-updateBufferIndex ];
236
237       localMap.Resize( oldMap.Count() );
238
239       unsigned int index=0;
240       for( CollectedUniformMap::Iterator iter = oldMap.Begin(), end = oldMap.End() ; iter != end ; ++iter, ++index )
241       {
242         localMap[index] = *iter;
243       }
244     }
245
246     mUniformMapChanged[updateBufferIndex] = true;
247     mRegenerateUniformMap--;
248   }
249 }
250
251 void Renderer::PrepareRender( BufferIndex updateBufferIndex )
252 {
253   auto& controller = mGraphics->GetController();
254
255   // prepare all stuff
256   auto gfxShader = mShader->GetGfxObject();
257
258   if( !mGfxRenderCommand )
259   {
260     mGfxRenderCommand = controller.AllocateRenderCommand();
261   }
262
263   /**
264    * Prepare vertex attribute buffer bindings
265    */
266   uint32_t bindingIndex { 0u };
267   uint32_t locationIndex { 0u };
268   auto vertexAttributeBindings = Graphics::API::RenderCommand::NewVertexAttributeBufferBindings();
269   for( auto&& vertexBuffer : mGeometry->GetVertexBuffers() )
270   {
271     auto attributeCountInForBuffer = vertexBuffer->GetAttributeCount();
272
273     // update vertex buffer if necessary
274     vertexBuffer->Update( controller );
275
276     for( auto i = 0u; i < attributeCountInForBuffer; ++i )
277     {
278       // create binding per attribute
279       auto binding = Graphics::API::RenderCommand::VertexAttributeBufferBinding{}
280         .SetOffset( (vertexBuffer->GetFormat()->components[i]).offset )
281         .SetBinding( bindingIndex )
282         .SetBuffer( vertexBuffer->GetGfxObject() )
283         .SetInputAttributeRate( Graphics::API::RenderCommand::InputAttributeRate::PER_VERTEX )
284         .SetLocation( locationIndex + i )
285         .SetStride( vertexBuffer->GetFormat()->size );
286       vertexAttributeBindings.emplace_back( binding );
287     }
288   }
289
290   UpdateUniformMap( updateBufferIndex );
291
292   auto& shader = mShader->GetGfxObject().Get();
293   auto uboCount = shader.GetUniformBlockCount();
294
295   auto pushConstantsBindings = Graphics::API::RenderCommand::NewPushConstantsBindings( uboCount );
296
297   // allocate new command ( may be not necessary at all )
298   // mGfxRenderCommand = Graphics::API::RenderCommandBuilder().Build();
299
300   // see if we need to reallocate memory for each UBO
301   // todo: do it only when shader has changed
302   if( mUboMemory.size() != uboCount )
303   {
304     mUboMemory.resize(uboCount);
305   }
306
307   for( auto i = 0u; i < uboCount; ++i )
308   {
309     Graphics::API::ShaderDetails::UniformBlockInfo ubInfo;
310
311     std::cout<<sizeof(ubInfo) << std::endl;
312
313     shader.GetUniformBlock( i, ubInfo );
314
315     if( mUboMemory[i].size() != ubInfo.size )
316     {
317       mUboMemory[i].resize( ubInfo.size );
318     }
319
320     // Set push constant bindings
321     auto &pushBinding = pushConstantsBindings[i];
322     pushBinding.data = mUboMemory[i].data();
323     pushBinding.size = uint32_t(mUboMemory[i].size());
324     pushBinding.binding = ubInfo.binding;
325   }
326
327   // add built-in uniforms
328
329   // write to memory
330   for( auto&& i : mCollectedUniformMap )
331   {
332     for( auto&& j : i )
333     {
334       auto uniformInfo = Graphics::API::ShaderDetails::UniformInfo{};
335       if( shader.GetNamedUniform( j->uniformName, uniformInfo ) )
336       {
337         // write into correct uniform buffer
338         auto dst = (mUboMemory[uniformInfo.bufferIndex].data()+uniformInfo.offset);
339         switch( j->propertyPtr->GetType() )
340         {
341           case Property::Type::FLOAT:
342           case Property::Type::INTEGER:
343           case Property::Type::BOOLEAN:
344           {
345             std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing 32bit offset: " << uniformInfo.offset << ", size: " << sizeof(float) << std::endl;
346             memcpy( dst, &j->propertyPtr->GetFloat( updateBufferIndex ), sizeof(float) );
347             break;
348           }
349           case Property::Type::VECTOR2:
350           {
351             std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing vec2 offset: " << uniformInfo.offset << ", size: " << sizeof(Vector2) << std::endl;
352             memcpy( dst, &j->propertyPtr->GetVector2( updateBufferIndex ), sizeof(Vector2) );
353             break;
354           }
355           case Property::Type::VECTOR3:
356           {
357             std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " <<  "Writing vec3 offset: " << uniformInfo.offset << ", size: " << sizeof(Vector3) << std::endl;
358             memcpy( dst, &j->propertyPtr->GetVector3( updateBufferIndex ), sizeof(Vector3) );
359             break;
360           }
361           case Property::Type::VECTOR4:
362           {
363             std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing vec4 offset: " << uniformInfo.offset << ", size: " << sizeof(Vector4) << std::endl;
364             memcpy( dst, &j->propertyPtr->GetVector4( updateBufferIndex ), sizeof(Vector4) );
365             break;
366           }
367           case Property::Type::MATRIX:
368           {
369             std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing mat4 offset: " << uniformInfo.offset << ", size: " << sizeof(Matrix) << std::endl;
370             memcpy( dst, &j->propertyPtr->GetMatrix( updateBufferIndex ), sizeof(Matrix) );
371             break;
372           }
373           case Property::Type::MATRIX3:
374           {
375             std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing mat3 offset: " << uniformInfo.offset << ", size: " << sizeof(Matrix3) << std::endl;
376             memcpy( dst, &j->propertyPtr->GetMatrix3( updateBufferIndex ), sizeof(Matrix3) );
377             break;
378           }
379           default:
380           {}
381         }
382       }
383     }
384   }
385
386   /**
387    * Prepare textures
388    */
389   auto textureBindings = Graphics::API::RenderCommand::NewTextureBindings();
390   auto samplers = shader.GetSamplers();
391
392   for( auto i = 0u; i < mTextureSet->GetTextureCount(); ++i )
393   {
394     auto texture = mTextureSet->GetTexture( i );
395     auto gfxTexture = texture->GetGfxObject();
396     auto binding = Graphics::API::RenderCommand::TextureBinding{}
397         .SetBinding( samplers[i].binding )
398         .SetTexture( texture->GetGfxObject() )
399         .SetSampler( nullptr );
400
401     textureBindings.emplace_back( binding );
402   }
403
404   // Build render command
405   // todo: this may be deferred until all render items are sorted, otherwise
406   // certain optimisations cannot be done
407
408   const auto& vb = mGeometry->GetVertexBuffers()[0];
409   //vb->Update()
410   mGfxRenderCommand->PushConstants( std::move(pushConstantsBindings) );
411   mGfxRenderCommand->BindVertexBuffers( std::move(vertexAttributeBindings) );
412   mGfxRenderCommand->BindTextures( std::move(textureBindings) );
413   mGfxRenderCommand->BindRenderState( std::move( Graphics::API::RenderCommand::RenderState{}
414                                        .SetShader( mShader->GetGfxObject() ) ) );
415   mGfxRenderCommand->Draw( std::move(Graphics::API::RenderCommand::DrawCommand{}
416                    .SetFirstVertex(0u)
417                    .SetDrawType( Graphics::API::RenderCommand::DrawType::VERTEX_DRAW )
418                    .SetFirstInstance(0u)
419                    .SetVertexCount( vb->GetElementCount() )
420                    .SetInstanceCount( 1u )));
421
422   std::cout << "done\n";
423 }
424
425 void Renderer::WriteUniform( const std::string& name, const void* data, uint32_t size )
426 {
427   auto& gfxShader = mShader->GetGfxObject().Get();
428   auto uniformInfo = Graphics::API::ShaderDetails::UniformInfo{};
429   if( gfxShader.GetNamedUniform( name, uniformInfo ) )
430   {
431     auto dst = (mUboMemory[uniformInfo.bufferIndex].data()+uniformInfo.offset);
432     memcpy( dst, data, size );
433   }
434 }
435
436
437 void Renderer::SetTextures( TextureSet* textureSet )
438 {
439   DALI_ASSERT_DEBUG( textureSet != NULL && "Texture set pointer is NULL" );
440
441   if( mTextureSet )
442   {
443     mTextureSet->RemoveObserver(this);
444   }
445
446   mTextureSet = textureSet;
447   mTextureSet->AddObserver( this );
448   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
449 }
450
451 void Renderer::SetShader( Shader* shader )
452 {
453   DALI_ASSERT_DEBUG( shader != NULL && "Shader pointer is NULL" );
454
455   if( mShader )
456   {
457     mShader->RemoveConnectionObserver(*this);
458   }
459
460   mShader = shader;
461   mShader->AddConnectionObserver( *this );
462   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
463 }
464
465 void Renderer::SetGeometry( SceneGraph::Geometry* geometry )
466 {
467   DALI_ASSERT_DEBUG( geometry != NULL && "Geometry pointer is NULL");
468   mGeometry = geometry;
469 }
470
471 void Renderer::SetDepthIndex( int depthIndex )
472 {
473   mDepthIndex = depthIndex;
474 }
475
476 void Renderer::SetFaceCullingMode( FaceCullingMode::Type faceCullingMode )
477 {
478   mFaceCullingMode = faceCullingMode;
479 }
480
481 void Renderer::SetBlendMode( BlendMode::Type blendingMode )
482 {
483   mBlendMode = blendingMode;
484 }
485
486 void Renderer::SetBlendingOptions( unsigned int options )
487 {
488   if( mBlendBitmask != options)
489   {
490     mBlendBitmask = options;
491   }
492 }
493
494 void Renderer::SetBlendColor( const Vector4& blendColor )
495 {
496   if( blendColor == Color::TRANSPARENT )
497   {
498     mBlendColor = NULL;
499   }
500   else
501   {
502     if( !mBlendColor )
503     {
504       mBlendColor = new Vector4( blendColor );
505     }
506     else
507     {
508       *mBlendColor = blendColor;
509     }
510   }
511 }
512
513 void Renderer::SetIndexedDrawFirstElement( size_t firstElement )
514 {
515   mIndexedDrawFirstElement = firstElement;
516 }
517
518 void Renderer::SetIndexedDrawElementsCount( size_t elementsCount )
519 {
520   mIndexedDrawElementsCount = elementsCount;
521 }
522
523 void Renderer::EnablePreMultipliedAlpha( bool preMultipled )
524 {
525   mPremultipledAlphaEnabled = preMultipled;
526 }
527
528 void Renderer::SetDepthWriteMode( DepthWriteMode::Type depthWriteMode )
529 {
530   mDepthWriteMode = depthWriteMode;
531 }
532
533 void Renderer::SetDepthTestMode( DepthTestMode::Type depthTestMode )
534 {
535   mDepthTestMode = depthTestMode;
536 }
537
538 void Renderer::SetDepthFunction( DepthFunction::Type depthFunction )
539 {
540   mDepthFunction = depthFunction;
541 }
542
543 void Renderer::SetRenderMode( RenderMode::Type mode )
544 {
545   mStencilParameters.renderMode = mode;
546 }
547
548 void Renderer::SetStencilFunction( StencilFunction::Type stencilFunction )
549 {
550   mStencilParameters.stencilFunction = stencilFunction;
551 }
552
553 void Renderer::SetStencilFunctionMask( int stencilFunctionMask )
554 {
555   mStencilParameters.stencilFunctionMask = stencilFunctionMask;
556 }
557
558 void Renderer::SetStencilFunctionReference( int stencilFunctionReference )
559 {
560   mStencilParameters.stencilFunctionReference = stencilFunctionReference;
561 }
562
563 void Renderer::SetStencilMask( int stencilMask )
564 {
565   mStencilParameters.stencilMask = stencilMask;
566 }
567
568 void Renderer::SetStencilOperationOnFail( StencilOperation::Type stencilOperationOnFail )
569 {
570   mStencilParameters.stencilOperationOnFail = stencilOperationOnFail;
571 }
572
573 void Renderer::SetStencilOperationOnZFail( StencilOperation::Type stencilOperationOnZFail )
574 {
575   mStencilParameters.stencilOperationOnZFail = stencilOperationOnZFail;
576 }
577
578 void Renderer::SetStencilOperationOnZPass( StencilOperation::Type stencilOperationOnZPass )
579 {
580   mStencilParameters.stencilOperationOnZPass = stencilOperationOnZPass;
581 }
582
583 const Vector4& Renderer::GetBlendColor() const
584 {
585   if( mBlendColor )
586   {
587     return *mBlendColor;
588   }
589   return Color::TRANSPARENT;
590 }
591
592 const CollectedUniformMap& Renderer::GetUniformMap( BufferIndex bufferIndex ) const
593 {
594   return mCollectedUniformMap[bufferIndex];
595 }
596
597 Renderer::Opacity Renderer::GetOpacity( BufferIndex updateBufferIndex, const Node& node ) const
598 {
599   Renderer::Opacity opacity = Renderer::OPAQUE;
600
601   switch( mBlendMode )
602   {
603     case BlendMode::ON: // If the renderer should always be use blending
604     {
605       opacity = Renderer::TRANSLUCENT;
606       break;
607     }
608     case BlendMode::AUTO:
609     {
610       bool shaderRequiresBlending( mShader->HintEnabled( Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT ) );
611       if( shaderRequiresBlending || ( mTextureSet && mTextureSet->HasAlpha() ) )
612       {
613         opacity = Renderer::TRANSLUCENT;
614       }
615       else // renderer should determine opacity using the actor color
616       {
617         float alpha = node.GetWorldColor( updateBufferIndex ).a;
618         if( alpha <= FULLY_TRANSPARENT )
619         {
620           opacity = TRANSPARENT;
621         }
622         else if( alpha <= FULLY_OPAQUE )
623         {
624           opacity = TRANSLUCENT;
625         }
626       }
627       break;
628     }
629     case BlendMode::OFF: // the renderer should never use blending
630     default:
631     {
632       opacity = Renderer::OPAQUE;
633       break;
634     }
635   }
636
637   return opacity;
638 }
639
640 void Renderer::TextureSetChanged()
641 {
642 }
643
644 void Renderer::TextureSetDeleted()
645 {
646   mTextureSet = NULL;
647 }
648
649 void Renderer::ConnectionsChanged( PropertyOwner& object )
650 {
651   // One of our child objects has changed it's connections. Ensure the uniform
652   // map gets regenerated during PrepareRender
653   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
654 }
655
656 void Renderer::ConnectedUniformMapChanged()
657 {
658   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
659 }
660
661 void Renderer::UniformMappingsChanged( const UniformMap& mappings )
662 {
663   // The mappings are either from PropertyOwner base class, or the Actor
664   mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
665 }
666
667 void Renderer::ObservedObjectDestroyed(PropertyOwner& owner)
668 {
669   if( reinterpret_cast<PropertyOwner*>(mShader) == &owner )
670   {
671     mShader = NULL;
672   }
673 }
674
675 } // namespace SceneGraph
676 } // namespace Internal
677 } // namespace Dali
678
679 #pragma GCC diagnostic pop