Avoid setting all the programs in all the shaders, NULL means use default
[platform/core/uifw/dali-core.git] / dali / internal / event / effects / shader-effect-impl.cpp
1 /*
2  * Copyright (c) 2014 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/event/effects/shader-effect-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <fstream>
23
24 // INTERNAL INCLUDES
25 #include <dali/public-api/math/vector2.h>
26 #include <dali/public-api/math/matrix.h>
27 #include <dali/public-api/math/matrix3.h>
28 #include <dali/public-api/shader-effects/shader-effect.h>
29 #include <dali/public-api/object/type-registry.h>
30 #include <dali/public-api/scripting/scripting.h>
31 #include "dali-shaders.h"
32 #include <dali/internal/event/effects/shader-declarations.h>
33 #include <dali/internal/event/effects/shader-factory.h>
34 #include <dali/internal/event/images/image-impl.h>
35 #include <dali/internal/update/common/animatable-property.h>
36 #include <dali/internal/update/manager/update-manager.h>
37 #include <dali/internal/event/common/stage-impl.h>
38 #include <dali/internal/event/common/thread-local-storage.h>
39 #include <dali/internal/render/shaders/shader.h>
40 #include <dali/internal/update/common/property-owner-messages.h>
41 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
42
43 using Dali::Internal::SceneGraph::UpdateManager;
44 using Dali::Internal::SceneGraph::UniformMeta;
45 using Dali::Internal::SceneGraph::Shader;
46 using Dali::Internal::SceneGraph::AnimatableProperty;
47 using Dali::Internal::SceneGraph::PropertyBase;
48 using Dali::Internal::SceneGraph::PropertyBase;
49 using Dali::Internal::SceneGraph::RenderQueue;
50 using std::string;
51
52 namespace Dali
53 {
54
55 const Property::Index ShaderEffect::GRID_DENSITY        = 0;
56 const Property::Index ShaderEffect::IMAGE               = 1;
57 const Property::Index ShaderEffect::PROGRAM             = 2;
58 const Property::Index ShaderEffect::GEOMETRY_HINTS      = 3;
59
60 namespace Internal
61 {
62
63 ShaderEffect::DefaultPropertyLookup* ShaderEffect::mDefaultPropertyLookup = NULL;
64
65 namespace
66 {
67
68 struct WrapperStrings
69 {
70   const char* vertexShaderPrefix;
71   const char* fragmentShaderPrefix;
72   const char* vertexShaderPostfix;
73   const char* fragmentShaderPostfix;
74 };
75
76 WrapperStrings customShaderWrappers [] =
77 {
78   {
79     CustomImagePrefixVertex, CustomImagePrefixFragment,
80     CustomImagePostfixVertex, CustomImagePostfixFragment
81   },
82   {
83     CustomFontPrefixVertex, CustomFontPrefixFragment,
84     CustomFontPostfixVertex, CustomFontPostfixFragment
85   },
86   {
87     CustomMeshPrefixVertex, CustomMeshPrefixFragment,
88     CustomMeshPostfixVertex, CustomMeshPostfixFragment
89   }
90 };
91
92 BaseHandle Create()
93 {
94   Internal::ShaderEffectPtr internal = Internal::ShaderEffect::New();
95
96   return Dali::ShaderEffect(internal.Get());
97 }
98
99 TypeRegistration mType( typeid(Dali::ShaderEffect), typeid(Dali::Handle), Create );
100
101 const std::string DEFAULT_PROPERTY_NAMES[] =
102 {
103   "grid-density",
104   "image",
105   "program",
106   "geometry-hints",
107 };
108 const int DEFAULT_PROPERTY_COUNT = sizeof( DEFAULT_PROPERTY_NAMES ) / sizeof( std::string );
109
110 const Property::Type DEFAULT_PROPERTY_TYPES[DEFAULT_PROPERTY_COUNT] =
111 {
112   Property::FLOAT,    // "grid-density",
113   Property::MAP,      // "image",
114   Property::MAP,      // "program",
115   Property::INTEGER,  // "geometry-hints",
116 };
117
118 std::string GetFileContents( const std::string& filename )
119 {
120   std::ifstream input( filename.c_str() );
121   return std::string( std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>() );
122 }
123
124 std::string GetShader(const std::string& field, const Property::Value& property)
125 {
126   if( property.HasKey(field) )
127   {
128     DALI_ASSERT_ALWAYS(property.GetValue(field).GetType() == Property::STRING && "Shader property is not a string" );
129
130     // we could also check here for an array of strings as convenience for json not having multi line strings
131     return property.GetValue(field).Get<std::string>();
132   }
133   else
134   {
135     // convention of shader field appended with -filename signifies a file
136     std::string filenameKey(std::string(field) + std::string("-filename"));
137
138     if( property.HasKey( filenameKey ) )
139     {
140       DALI_ASSERT_ALWAYS(property.GetValue(filenameKey).GetType() == Property::STRING && "Shader filename property is not a string" );
141       // this should eventually be done by an adaptor interface
142       return GetFileContents( property.GetValue(filenameKey).Get<std::string>() );
143     }
144   }
145
146   return std::string();
147 }
148
149 } // anon namespace
150
151
152 ShaderEffectPtr ShaderEffect::New( const string& vertexShader,
153                                    const string& fragmentShader,
154                                    GeometryType geometryType,
155                                    Dali::ShaderEffect::GeometryHints hints )
156 {
157   return NewWithPrefix( "", vertexShader, "", fragmentShader, geometryType, hints);
158 }
159
160 ShaderEffectPtr ShaderEffect::NewWithPrefix( const string& vertexShaderPrefix,
161                                              const string& vertexShader,
162                                              const string& fragmentShaderPrefix,
163                                              const string& fragmentShader,
164                                              GeometryType geometryTypes,
165                                              Dali::ShaderEffect::GeometryHints hints )
166 {
167   ShaderEffectPtr shaderEffect( New(hints) );
168
169   shaderEffect->SetPrograms( geometryTypes, vertexShaderPrefix, vertexShader, fragmentShaderPrefix, fragmentShader );
170   return shaderEffect;
171 }
172
173 ShaderEffectPtr ShaderEffect::New( const string& imageVertexShader,
174                                    const string& imageFragmentShader,
175                                    const string& textVertexShader,
176                                    const string& textFragmentShader,
177                                    const string& texturedMeshVertexShader,
178                                    const string& texturedMeshFragmentShader,
179                                    const string& meshVertexShader,
180                                    const string& meshFragmentShader,
181                                    Dali::ShaderEffect::GeometryHints hints )
182 {
183   ShaderEffectPtr shaderEffect( New(hints) );
184
185   shaderEffect->SetWrappedProgram( GEOMETRY_TYPE_IMAGE, SHADER_SUBTYPE_ALL, "", "", imageVertexShader, imageFragmentShader );
186   shaderEffect->SetWrappedProgram( GEOMETRY_TYPE_TEXT, SHADER_DEFAULT, "", "", textVertexShader, textFragmentShader );
187   shaderEffect->SetWrappedProgram( GEOMETRY_TYPE_TEXTURED_MESH, SHADER_SUBTYPE_ALL, "", "", texturedMeshVertexShader, texturedMeshFragmentShader );
188   shaderEffect->SetWrappedProgram( GEOMETRY_TYPE_MESH, SHADER_SUBTYPE_ALL, "", "", meshVertexShader, meshFragmentShader );
189
190   return shaderEffect;
191 }
192
193 ShaderEffectPtr ShaderEffect::New( Dali::ShaderEffect::GeometryHints hints )
194 {
195   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
196   UpdateManager& updateManager = tls.GetUpdateManager();
197
198   ShaderEffectPtr shaderEffect( new ShaderEffect( updateManager, hints ) );
199   shaderEffect->RegisterObject();
200
201   return shaderEffect;
202 }
203
204 ShaderEffect::ShaderEffect( UpdateManager& updateManager, Dali::ShaderEffect::GeometryHints hints )
205 : mUpdateManager( updateManager ),
206   mConnectionCount (0),
207   mGeometryHints( hints )
208 {
209   mSceneObject = new Shader( hints );
210   DALI_ASSERT_DEBUG( NULL != mSceneObject );
211
212   // Transfer shader ownership to a scene message
213   AddShaderMessage( mUpdateManager, *mSceneObject );
214 }
215
216 ShaderEffect::~ShaderEffect()
217 {
218   DALI_ASSERT_DEBUG( mSceneObject != NULL );
219
220   // Guard to allow handle destruction after Core has been destroyed
221   if ( Stage::IsInstalled() )
222   {
223     // Remove scene-object using a message to the UpdateManager
224     RemoveShaderMessage( mUpdateManager, *mSceneObject );
225
226     UnregisterObject();
227   }
228 }
229
230 void ShaderEffect::SetEffectImage( Dali::Image image )
231 {
232   // if images are the same, do nothing
233   if (mImage == image)
234   {
235     return;
236   }
237
238   if (mImage && mConnectionCount > 0)
239   {
240     // unset previous image
241     GetImplementation(mImage).Disconnect();
242   }
243
244   // in case image is empty this will reset our image handle
245   mImage = image;
246
247   if (!image)
248   {
249     // mSceneShader can be in a separate thread; queue a setter message
250     SetTextureIdMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, 0 );
251   }
252   else
253   {
254     // tell image that we're using it
255     if (mConnectionCount > 0)
256     {
257       GetImplementation(mImage).Connect();
258     }
259     // mSceneShader can be in a separate thread; queue a setter message
260     SetTextureIdMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, GetImplementation(mImage).GetResourceId() );
261   }
262 }
263
264 void ShaderEffect::SetUniform( const std::string& name, Property::Value value, UniformCoordinateType uniformCoordinateType )
265 {
266   // Register the property if it does not exist
267   Property::Index index = GetPropertyIndex( name );
268   if ( Property::INVALID_INDEX == index )
269   {
270     index = RegisterProperty( name, value );
271   }
272
273   SetProperty( index, value );
274
275   SetCoordinateTypeMessage( mUpdateManager.GetEventToUpdate(), *mCustomMetadata[index], uniformCoordinateType );
276 }
277
278 void ShaderEffect::AttachExtension( Dali::ShaderEffect::Extension *extension )
279 {
280   DALI_ASSERT_ALWAYS( extension != NULL && "Attaching uninitialized extension" );
281   mExtension = IntrusivePtr<Dali::ShaderEffect::Extension>( extension );
282 }
283
284 Dali::ShaderEffect::Extension& ShaderEffect::GetExtension()
285 {
286   DALI_ASSERT_ALWAYS( mExtension && "Getting uninitialized extension" );
287   return *mExtension;
288 }
289
290 const Dali::ShaderEffect::Extension& ShaderEffect::GetExtension() const
291 {
292   DALI_ASSERT_ALWAYS( mExtension && "Getting uninitialized extension" );
293   return *mExtension;
294 }
295
296 void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType,
297                                const string& vertexSource, const string& fragmentSource,
298                                GeometryState modifiesGeometry )
299 {
300   SetProgramImpl(geometryType, subType, vertexSource, fragmentSource, modifiesGeometry);
301 }
302
303 void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType,
304                                const std::string& vertexPrefix, const std::string& fragmentPrefix,
305                                const std::string& vertexSource, const std::string& fragmentSource,
306                                GeometryState modifiesGeometry )
307 {
308   const std::string vertex( vertexPrefix + vertexSource );
309   const std::string fragment( fragmentPrefix + fragmentSource );
310   SetProgramImpl( geometryType, subType, vertex, fragment, modifiesGeometry );
311 }
312
313 void ShaderEffect::Connect()
314 {
315   ++mConnectionCount;
316
317   if (mImage && mConnectionCount == 1)
318   {
319     GetImplementation(mImage).Connect();
320
321     // Image may have changed resource due to load/release policy. Ensure correct texture ID is set on scene graph object
322     SetTextureIdMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, GetImplementation(mImage).GetResourceId() );
323   }
324 }
325
326 void ShaderEffect::Disconnect()
327 {
328   DALI_ASSERT_DEBUG(mConnectionCount > 0);
329   --mConnectionCount;
330
331   if (mImage && mConnectionCount == 0)
332   {
333      GetImplementation(mImage).Disconnect();
334   }
335 }
336
337 bool ShaderEffect::IsSceneObjectRemovable() const
338 {
339   return false; // The Shader is not removed during this proxy's lifetime
340 }
341
342 unsigned int ShaderEffect::GetDefaultPropertyCount() const
343 {
344   return DEFAULT_PROPERTY_COUNT;
345 }
346
347 void ShaderEffect::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
348 {
349   indices.reserve( DEFAULT_PROPERTY_COUNT );
350
351   for ( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
352   {
353     indices.push_back( i );
354   }
355 }
356
357 const std::string& ShaderEffect::GetDefaultPropertyName(Property::Index index) const
358 {
359   if( index < DEFAULT_PROPERTY_COUNT )
360   {
361     return DEFAULT_PROPERTY_NAMES[index];
362   }
363   else
364   {
365     // index out of range..return empty string
366     static const std::string INVALID_PROPERTY_NAME;
367     return INVALID_PROPERTY_NAME;
368   }
369 }
370
371 Property::Index ShaderEffect::GetDefaultPropertyIndex(const std::string& name) const
372 {
373   Property::Index index = Property::INVALID_INDEX;
374
375   // Lazy initialization of static mDefaultPropertyLookup
376   if (!mDefaultPropertyLookup)
377   {
378     mDefaultPropertyLookup = new DefaultPropertyLookup();
379
380     for (int i=0; i<DEFAULT_PROPERTY_COUNT; ++i)
381     {
382       (*mDefaultPropertyLookup)[DEFAULT_PROPERTY_NAMES[i]] = i;
383     }
384   }
385   DALI_ASSERT_DEBUG( NULL != mDefaultPropertyLookup );
386
387   // Look for name in default properties
388   DefaultPropertyLookup::const_iterator result = mDefaultPropertyLookup->find( name );
389   if ( mDefaultPropertyLookup->end() != result )
390   {
391     index = result->second;
392   }
393
394   return index;
395 }
396
397 bool ShaderEffect::IsDefaultPropertyWritable(Property::Index index) const
398 {
399   return true;
400 }
401
402 bool ShaderEffect::IsDefaultPropertyAnimatable(Property::Index index) const
403 {
404   return false;
405 }
406
407 bool ShaderEffect::IsDefaultPropertyAConstraintInput( Property::Index index ) const
408 {
409   return false;
410 }
411
412 Property::Type ShaderEffect::GetDefaultPropertyType(Property::Index index) const
413 {
414   if( index < DEFAULT_PROPERTY_COUNT )
415   {
416     return DEFAULT_PROPERTY_TYPES[index];
417   }
418   else
419   {
420     // index out of range...return Property::NONE
421     return Property::NONE;
422   }
423 }
424
425 void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
426 {
427   switch ( index )
428   {
429     case Dali::ShaderEffect::GRID_DENSITY:
430     {
431       SetGridDensityMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, propertyValue.Get<float>() );
432       break;
433     }
434
435     case Dali::ShaderEffect::IMAGE:
436     {
437       Dali::Image img(Scripting::NewImage( propertyValue ));
438       if(img)
439       {
440         SetEffectImage( img );
441       }
442       else
443       {
444         DALI_LOG_WARNING("Cannot create image from property value for ShaderEffect image\n");
445       }
446       break;
447     }
448
449     case Dali::ShaderEffect::PROGRAM:
450     {
451       std::string vertexPrefix   = GetShader("vertex-prefix", propertyValue);
452       std::string fragmentPrefix = GetShader("fragment-prefix", propertyValue);
453       std::string vertex         = GetShader("vertex", propertyValue);
454       std::string fragment       = GetShader("fragment", propertyValue);
455
456       GeometryType geometryType      = GEOMETRY_TYPE_IMAGE;
457
458       if( propertyValue.HasKey("geometry-type") )
459       {
460         Property::Value geometryValue  = propertyValue.GetValue("geometry-type");
461         DALI_ASSERT_ALWAYS(geometryValue.GetType() == Property::STRING && "Geometry type is not a string" );
462
463         std::string s = geometryValue.Get<std::string>();
464         if(s == "GEOMETRY_TYPE_IMAGE")
465         {
466           geometryType  = GEOMETRY_TYPE_IMAGE;
467         }
468         else if (s == "GEOMETRY_TYPE_TEXT")
469         {
470           geometryType  = GEOMETRY_TYPE_TEXT;
471         }
472         else if( s == "GEOMETRY_TYPE_MESH")
473         {
474           geometryType  = GEOMETRY_TYPE_MESH;
475         }
476         else if( s == "GEOMETRY_TYPE_TEXTURED_MESH")
477         {
478           geometryType  = GEOMETRY_TYPE_TEXTURED_MESH;
479         }
480         else
481         {
482           DALI_ASSERT_ALWAYS(!"Geometry type unknown" );
483         }
484       }
485       SetPrograms( geometryType, vertexPrefix, vertex, fragmentPrefix, fragment );
486       break;
487     }
488
489     case Dali::ShaderEffect::GEOMETRY_HINTS:
490     {
491       Dali::ShaderEffect::GeometryHints hint = Dali::ShaderEffect::HINT_NONE;
492       Property::Value geometryHintsValue   = propertyValue.GetValue("geometry-hints");
493
494       std::string s = geometryHintsValue.Get<std::string>();
495       if(s == "HINT_NONE")
496       {
497         hint = Dali::ShaderEffect::HINT_NONE;
498       }
499       else if(s == "HINT_GRID_X")
500       {
501         hint = Dali::ShaderEffect::HINT_GRID_X;
502       }
503       else if(s == "HINT_GRID_Y")
504       {
505         hint = Dali::ShaderEffect::HINT_GRID_Y;
506       }
507       else if(s == "HINT_GRID")
508       {
509         hint = Dali::ShaderEffect::HINT_GRID;
510       }
511       else if(s == "HINT_DEPTH_BUFFER")
512       {
513         hint = Dali::ShaderEffect::HINT_DEPTH_BUFFER;
514       }
515       else if(s == "HINT_BLENDING")
516       {
517         hint = Dali::ShaderEffect::HINT_BLENDING;
518       }
519       else if(s == "HINT_DOESNT_MODIFY_GEOMETRY")
520       {
521         hint = Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY;
522       }
523       else
524       {
525         DALI_ASSERT_ALWAYS(!"Geometry hint unknown" );
526       }
527
528       SetHintsMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, hint );
529
530       break;
531     }
532
533     default:
534     {
535       DALI_ASSERT_ALWAYS(false && "ShaderEffect property enumeration out of range"); // should not come here
536       break;
537     }
538   }
539 }
540
541 Property::Value ShaderEffect::GetDefaultProperty(Property::Index /*index*/) const
542 {
543   // none of our properties are readable so return empty
544   return Property::Value();
545 }
546
547 void ShaderEffect::InstallSceneObjectProperty( PropertyBase& newProperty, const std::string& name, unsigned int index )
548 {
549   // Warning - the property is added to the Shader object in the Update thread and the meta-data is added in the Render thread (through a secondary message)
550
551   // mSceneObject is being used in a separate thread; queue a message to add the property
552   InstallCustomPropertyMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, newProperty ); // Message takes ownership
553
554   // mSceneObject requires metadata for each custom property (uniform)
555   UniformMeta* meta = UniformMeta::New( name, newProperty, Dali::ShaderEffect::COORDINATE_TYPE_DEFAULT );
556   // mSceneObject is being used in a separate thread; queue a message to add the property
557   InstallUniformMetaMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, *meta ); // Message takes ownership
558
559   // Add entry to the metadata lookup
560   mCustomMetadata[index] = meta;
561 }
562
563 const SceneGraph::PropertyOwner* ShaderEffect::GetSceneObject() const
564 {
565   return mSceneObject;
566 }
567
568 const PropertyBase* ShaderEffect::GetSceneObjectAnimatableProperty( Property::Index index ) const
569 {
570   CustomPropertyLookup::const_iterator entry = GetCustomPropertyLookup().find( index );
571
572   DALI_ASSERT_ALWAYS( GetCustomPropertyLookup().end() != entry && "Property index is invalid" );
573
574   DALI_ASSERT_ALWAYS( entry->second.IsAnimatable() && "shader effect has only animatable properties" );
575
576   return dynamic_cast<const PropertyBase*>( entry->second.GetSceneGraphProperty() );
577 }
578
579 const PropertyInputImpl* ShaderEffect::GetSceneObjectInputProperty( Property::Index index ) const
580 {
581   CustomPropertyLookup::const_iterator entry = GetCustomPropertyLookup().find( index );
582
583   DALI_ASSERT_ALWAYS( GetCustomPropertyLookup().end() != entry && "Property index is invalid" );
584
585   DALI_ASSERT_ALWAYS( entry->second.IsAnimatable() && "shader effect has only animatable properties" );
586
587   return entry->second.GetSceneGraphProperty();
588 }
589
590 void ShaderEffect::SetPrograms( GeometryType  geometryTypes,
591                                 const std::string& vertexShaderPrefix,
592                                 const std::string& vertexShader,
593                                 const std::string& fragmentShaderPrefix,
594                                 const std::string& fragmentShader )
595 {
596   static std::string emptyStr;
597
598   if( geometryTypes & GEOMETRY_TYPE_IMAGE )
599   {
600     SetWrappedProgram( GEOMETRY_TYPE_IMAGE, SHADER_SUBTYPE_ALL, vertexShaderPrefix, fragmentShaderPrefix, vertexShader, fragmentShader );
601   }
602
603   if( geometryTypes & GEOMETRY_TYPE_TEXT )
604   {
605     // Only change the default program, leaving the other sub-types as-is.
606     SetWrappedProgram( GEOMETRY_TYPE_TEXT, SHADER_DEFAULT, vertexShaderPrefix, fragmentShaderPrefix, vertexShader, fragmentShader );
607   }
608
609   if( geometryTypes & GEOMETRY_TYPE_TEXTURED_MESH )
610   {
611     SetWrappedProgram( GEOMETRY_TYPE_TEXTURED_MESH, SHADER_SUBTYPE_ALL, vertexShaderPrefix, fragmentShaderPrefix, vertexShader, fragmentShader );
612   }
613
614   if( geometryTypes & GEOMETRY_TYPE_MESH )
615   {
616     SetWrappedProgram( GEOMETRY_TYPE_MESH, SHADER_SUBTYPE_ALL, vertexShaderPrefix, fragmentShaderPrefix, vertexShader, fragmentShader );
617   }
618 }
619
620 void ShaderEffect::SetWrappedProgram( GeometryType geometryType, ShaderSubTypes subType,
621                                       const string& vertexPrefix, const string& fragmentPrefix,
622                                       const string& vertexSnippet, const string& fragmentSnippet )
623 {
624   // create complete shader program strings for the given geometry type
625   unsigned int index = 0;
626   switch( geometryType )
627   {
628     case GEOMETRY_TYPE_IMAGE:
629     {
630       index = 0;
631       break;
632     }
633     case GEOMETRY_TYPE_TEXT:
634     {
635       index = 1;
636       break;
637     }
638     case GEOMETRY_TYPE_MESH:
639     case GEOMETRY_TYPE_TEXTURED_MESH:
640     {
641       index = 2;
642       break;
643     }
644     case GEOMETRY_TYPE_LAST:
645     {
646       DALI_ASSERT_DEBUG(0 && "Wrong geometry type");
647       break;
648     }
649   }
650
651   string vertexSource = vertexPrefix + customShaderWrappers[index].vertexShaderPrefix;
652   string fragmentSource = fragmentPrefix + customShaderWrappers[index].fragmentShaderPrefix;
653
654   // Append the custom vertex shader code if supplied, otherwise append the default
655   if ( vertexSnippet.length() > 0 )
656   {
657     vertexSource.append( vertexSnippet );
658   }
659   else
660   {
661     vertexSource.append( customShaderWrappers[index].vertexShaderPostfix );
662   }
663
664   // Append the custom fragment shader code if supplied, otherwise append the default
665   if ( fragmentSnippet.length() > 0 )
666   {
667     fragmentSource.append( fragmentSnippet );
668   }
669   else
670   {
671     fragmentSource.append( customShaderWrappers[index].fragmentShaderPostfix );
672   }
673
674   // Add the program
675   SetProgramImpl( geometryType, subType, vertexSource, fragmentSource );
676 }
677
678 void ShaderEffect::SetProgramImpl( GeometryType geometryType, ShaderSubTypes subType,
679                                    const string& vertexSource, const string& fragmentSource )
680 {
681   GeometryState modifiesGeometry = MODIFIES_GEOMETRY;
682
683   if( (mGeometryHints & Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY ) != 0 )
684   {
685     modifiesGeometry = DOESNT_MODIFY_GEOMETRY;
686   }
687
688   SetProgramImpl( geometryType, subType, vertexSource, fragmentSource, modifiesGeometry );
689 }
690
691 void ShaderEffect::SetProgramImpl( GeometryType geometryType, ShaderSubTypes subType,
692                                    const string& vertexSource, const string& fragmentSource,
693                                    GeometryState modifiesGeometry )
694 {
695   // Load done asynchronously in update thread. SetProgram message below must be processed afterwards.
696   // Therefore, resource manager cannot farm out the loading to the adaptor resource threads,
697   // but must instead use synchronous loading via PlatformAbstraction::LoadFile()
698
699   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
700   ShaderFactory& shaderFactory = tls.GetShaderFactory();
701   size_t shaderHash;
702
703   ResourceTicketPtr ticket( shaderFactory.Load(vertexSource, fragmentSource, shaderHash) );
704
705   DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "ShaderEffect: SetProgram(geometryType %d subType:%d ticket.id:%d)\n", geometryType, subType, ticket->GetId() );
706
707   // Add shader program to scene-object using a message to the UpdateManager
708   SetShaderProgramMessage( mUpdateManager, *mSceneObject, geometryType, subType, ticket->GetId(), shaderHash, modifiesGeometry==MODIFIES_GEOMETRY );
709
710   mTickets.push_back(ticket);       // add ticket to collection to keep it alive.
711 }
712
713
714 } // namespace Internal
715
716 } // namespace Dali