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