Cleaning up the property framework; removal of duplicate methods and incorrect assers
[platform/core/uifw/dali-core.git] / dali / internal / event / effects / shader-effect-impl.cpp
index b25cf01..bd41274 100644 (file)
@@ -1,25 +1,23 @@
-//
-// Copyright (c) 2014 Samsung Electronics Co., Ltd.
-//
-// Licensed under the Flora License, Version 1.0 (the License);
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://floralicense.org/license/
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an AS IS BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
 
 // CLASS HEADER
 #include <dali/internal/event/effects/shader-effect-impl.h>
 
-// EXTERNAL INCLUDES
-#include <fstream>
-
 // INTERNAL INCLUDES
 #include <dali/public-api/math/vector2.h>
 #include <dali/public-api/math/matrix.h>
@@ -27,7 +25,6 @@
 #include <dali/public-api/shader-effects/shader-effect.h>
 #include <dali/public-api/object/type-registry.h>
 #include <dali/public-api/scripting/scripting.h>
-#include "dali-shaders.h"
 #include <dali/internal/event/effects/shader-declarations.h>
 #include <dali/internal/event/effects/shader-factory.h>
 #include <dali/internal/event/images/image-impl.h>
 #include <dali/internal/event/common/stage-impl.h>
 #include <dali/internal/event/common/thread-local-storage.h>
 #include <dali/internal/render/shaders/shader.h>
-#include <dali/internal/update/common/property-owner-messages.h>
+#include <dali/internal/render/shaders/uniform-meta.h>
 #include <dali/internal/update/animation/scene-graph-constraint-base.h>
+#include "dali-shaders.h"
 
 using Dali::Internal::SceneGraph::UpdateManager;
 using Dali::Internal::SceneGraph::UniformMeta;
 using Dali::Internal::SceneGraph::Shader;
 using Dali::Internal::SceneGraph::AnimatableProperty;
 using Dali::Internal::SceneGraph::PropertyBase;
-using Dali::Internal::SceneGraph::PropertyBase;
 using Dali::Internal::SceneGraph::RenderQueue;
+using std::string;
 
 namespace Dali
 {
@@ -58,334 +56,193 @@ const Property::Index ShaderEffect::GEOMETRY_HINTS      = 3;
 namespace Internal
 {
 
-ShaderEffect::DefaultPropertyLookup* ShaderEffect::mDefaultPropertyLookup = NULL;
-
 namespace
 {
+const PropertyDetails DEFAULT_PROPERTY_DETAILS[] =
+{
+ // Name               Type            writable animatable constraint-input
+ { "grid-density",   Property::FLOAT,   true,    false,   false  }, // GRID_DENSITY
+ { "image",          Property::MAP,     true,    false,   false  }, // IMAGE
+ { "program",        Property::MAP,     true,    false,   false  }, // PROGRAM
+ { "geometry-hints", Property::INTEGER, true,    false,   false  }, // GEOMETRY_HINTS
+};
+
+const int DEFAULT_PROPERTY_COUNT = sizeof( DEFAULT_PROPERTY_DETAILS ) / sizeof( DEFAULT_PROPERTY_DETAILS[0] );
 
 BaseHandle Create()
 {
-  Internal::ShaderEffectPtr internal = Internal::ShaderEffect::New( );
-
-  ShaderFactory::LoadTextSubtypeShaders(internal);
+  Internal::ShaderEffectPtr internal = Internal::ShaderEffect::New();
 
   return Dali::ShaderEffect(internal.Get());
 }
 
 TypeRegistration mType( typeid(Dali::ShaderEffect), typeid(Dali::Handle), Create );
 
-const std::string DEFAULT_PROPERTY_NAMES[] =
-{
-  "grid-density",
-  "image",
-  "program",
-  "geometry-hints",
-};
-const int DEFAULT_PROPERTY_COUNT = sizeof( DEFAULT_PROPERTY_NAMES ) / sizeof( std::string );
-
-const Property::Type DEFAULT_PROPERTY_TYPES[DEFAULT_PROPERTY_COUNT] =
+struct WrapperStrings
 {
-  Property::FLOAT,    // "grid-density",
-  Property::MAP,      // "image",
-  Property::MAP,      // "program",
-  Property::INTEGER,  // "geometry-hints",
+  const char* vertexShaderPrefix;
+  const char* fragmentShaderPrefix;
+  const char* vertexShaderPostfix;
+  const char* fragmentShaderPostfix;
 };
 
-void SetShaderProgram( const std::string& imageVertexSnippet, const std::string& imageFragmentSnippet,
-                       const std::string& textVertexSnippet, const std::string& textFragmentSnippet,
-                       const std::string& texturedMeshVertexSnippet, const std::string& texturedMeshFragmentSnippet,
-                       const std::string& meshVertexSnippet, const std::string& meshFragmentSnippet,
-                       const std::string& vertexShaderPrefix, const std::string& fragmentShaderPrefix,
-                       ShaderEffectPtr shaderEffect )
+WrapperStrings customShaderWrappers [] =
 {
-  DALI_ASSERT_DEBUG(shaderEffect);
-
-  // create complete shader program strings for GEOMETRY_TYPE_IMAGE
-  std::string vertexSource = vertexShaderPrefix + CustomImagePrefixVertex;
-  std::string fragmentSource = fragmentShaderPrefix + CustomImagePrefixFragment;
-
-  // Append the custom vertex shader code if supplied, otherwise append the default
-  if ( imageVertexSnippet.length() > 0 )
   {
-    vertexSource.append( imageVertexSnippet );
-  }
-  else
+    CustomImagePrefixVertex, CustomImagePrefixFragment,
+    CustomImagePostfixVertex, CustomImagePostfixFragment
+  },
   {
-    vertexSource.append( CustomImagePostfixVertex );
-  }
-
-  // Append the custom fragment shader code if supplied, otherwise append the default
-  if ( imageFragmentSnippet.length() > 0 )
-  {
-    fragmentSource.append( imageFragmentSnippet );
-  }
-  else
+    CustomTextDistanceFieldPrefixVertex, CustomTextDistanceFieldPrefixFragment,
+    CustomTextDistanceFieldPostfixVertex, CustomTextDistanceFieldPostfixFragment
+  },
   {
-    fragmentSource.append( CustomImagePostfixFragment );
-  }
-
-  // Add the program
-  shaderEffect->SetProgram( GEOMETRY_TYPE_IMAGE, SHADER_SUBTYPE_ALL, vertexSource, fragmentSource );
-
-
-  // create complete shader program strings for GEOMETRY_TYPE_TEXT
-  vertexSource = CustomFontPrefixVertex;
-  fragmentSource = CustomFontPrefixFragment;
-
-  // Append the custom vertex shader code if supplied, otherwise append the default
-  if ( textVertexSnippet.length() > 0 )
-  {
-    vertexSource.append( textVertexSnippet );
-  }
-  else
-  {
-    vertexSource.append( CustomFontPostfixVertex );
-  }
-
-  // Append the custom fragment shader code if supplied, otherwise append the default
-  if ( textFragmentSnippet.length() > 0 )
-  {
-    fragmentSource.append( textFragmentSnippet );
-  }
-  else
-  {
-    fragmentSource.append( CustomFontPostfixFragment );
-  }
-
-  // Add Program. Note, we only change the default program here, and leave the other sub-types as-is
-  shaderEffect->SetProgram(GEOMETRY_TYPE_TEXT, SHADER_DEFAULT, vertexSource, fragmentSource);
-
-  // create complete shader program strings for GEOMETRY_TYPE_TEXTURED_MESH
-  if( texturedMeshVertexSnippet.length() > 0 )
-  {
-    vertexSource = CustomMeshPrefixVertex;
-    vertexSource.append( texturedMeshVertexSnippet );
-  }
-  else
-  {
-    vertexSource = MeshVertex;
-  }
-
-  if( texturedMeshFragmentSnippet.length() > 0 )
-  {
-    fragmentSource = CustomMeshPrefixFragment;
-    fragmentSource.append( texturedMeshFragmentSnippet );
-  }
-  else
-  {
-    fragmentSource = MeshFragment;
-  }
-
-  // Add Program
-  shaderEffect->SetProgram( GEOMETRY_TYPE_TEXTURED_MESH, SHADER_SUBTYPE_ALL, vertexSource, fragmentSource );
-
-  // create complete shader program strings for GEOMETRY_TYPE_MESH
-  if( meshVertexSnippet.length() > 0 )
-  {
-    vertexSource = CustomMeshPrefixVertex;
-    vertexSource.append( meshVertexSnippet );
-  }
-  else
-  {
-    vertexSource = MeshVertex;
-  }
-
-  if( meshFragmentSnippet.length() > 0 )
-  {
-    fragmentSource = CustomMeshPrefixFragment;
-    fragmentSource.append( meshFragmentSnippet );
-  }
-  else
+    CustomUntexturedMeshPrefixVertex, CustomUntexturedMeshPrefixFragment,
+    CustomUntexturedMeshPostfixVertex, CustomUntexturedMeshPostfixFragment
+  },
   {
-    fragmentSource = MeshFragment;
+    CustomTexturedMeshPrefixVertex, CustomTexturedMeshPrefixFragment,
+    CustomTexturedMeshPostfixVertex, CustomTexturedMeshPostfixFragment
   }
+};
 
-  // Add Program
-  shaderEffect->SetProgram( GEOMETRY_TYPE_MESH, SHADER_SUBTYPE_ALL, vertexSource, fragmentSource );
-}
-
-void SetShaderProgram( const std::string& vertexShaderPrefix, const std::string& vertexShader,
-                       const std::string& fragmentShaderPrefix, const std::string& fragmentShader,
-                       GeometryType geometryTypes,
-                       ShaderEffectPtr shaderEffect )
-{
-  DALI_ASSERT_DEBUG(shaderEffect);
-
-  if( geometryTypes & GEOMETRY_TYPE_IMAGE )
-  {
-    shaderEffect->SetProgram( GEOMETRY_TYPE_IMAGE, SHADER_SUBTYPE_ALL,
-                              vertexShaderPrefix + CustomImagePrefixVertex + ( !vertexShader.empty() ? vertexShader : CustomImagePostfixVertex ),
-                              fragmentShaderPrefix + CustomImagePrefixFragment + ( !fragmentShader.empty() ? fragmentShader : CustomImagePostfixFragment ) );
-  }
-  else
-  {
-    shaderEffect->SetProgram( GEOMETRY_TYPE_IMAGE, SHADER_SUBTYPE_ALL,
-                              CustomImagePrefixVertex + CustomImagePostfixVertex,
-                              CustomImagePrefixFragment + CustomImagePostfixFragment );
-  }
+/**
+ * Helper to wrap the program with our default pre and postfix if needed and then send it to update/render thread
+ * @param[in] effect of the shader
+ * @param[in] actualGeometryType of the shader
+ * @param[in] expectedGeometryType of the shader
+ * @param[in] vertexPrefix from application
+ * @param[in] fragmentPrefix from application
+ * @param[in] vertexBody from application
+ * @param[in] fragmentBody from application
+ * @param[in] modifiesGeometry based on flags and vertex shader
+ */
+void WrapAndSetProgram( Internal::ShaderEffect& effect,
+                        GeometryType actualGeometryType, GeometryType expectedGeometryType,
+                        const std::string& vertexPrefix, const std::string& fragmentPrefix,
+                        const std::string& vertexBody, const std::string& fragmentBody,
+                        bool modifiesGeometry )
+{
+  // if geometry type matches and there is some real data in the strings
+  if( ( actualGeometryType & expectedGeometryType )&&
+      ( ( vertexPrefix.length() > 0   )||
+        ( fragmentPrefix.length() > 0 )||
+        ( vertexBody.length() > 0     )||
+        ( fragmentBody.length() > 0   ) ) )
+  {
+    std::string vertexSource = vertexPrefix;
+    std::string fragmentSource = fragmentPrefix;
+
+    // create complete shader program strings for the given geometry type
+    unsigned int index = 0;
+    switch( expectedGeometryType )
+    {
+      case GEOMETRY_TYPE_IMAGE:
+      {
+        index = 0;
+        break;
+      }
+      case GEOMETRY_TYPE_TEXT:
+      {
+        index = 1;
+        break;
+      }
+      case GEOMETRY_TYPE_UNTEXTURED_MESH:
+      {
+        index = 2;
+        break;
+      }
+      case GEOMETRY_TYPE_TEXTURED_MESH:
+      {
+        index = 3;
+        break;
+      }
+      case GEOMETRY_TYPE_LAST:
+      {
+        DALI_ASSERT_DEBUG(0 && "Wrong geometry type");
+        break;
+      }
+    }
 
-  if( geometryTypes & GEOMETRY_TYPE_TEXT )
-  {
-    shaderEffect->SetProgram( GEOMETRY_TYPE_TEXT, SHADER_DEFAULT,
-                              vertexShaderPrefix + CustomFontPrefixVertex + ( !vertexShader.empty() ? vertexShader : CustomFontPostfixVertex ),
-                              fragmentShaderPrefix + CustomFontPrefixFragment + ( !fragmentShader.empty() ? fragmentShader : CustomFontPostfixFragment ) );
-  }
-  else
-  {
-    shaderEffect->SetProgram( GEOMETRY_TYPE_TEXT, SHADER_DEFAULT,
-                              CustomFontPrefixVertex + CustomFontPostfixVertex,
-                              CustomFontPrefixFragment + CustomFontPostfixFragment );
-  }
+    vertexSource += customShaderWrappers[index].vertexShaderPrefix;
+    // Append the custom vertex shader code if supplied, otherwise append the default
+    if ( vertexBody.length() > 0 )
+    {
+      vertexSource.append( vertexBody );
+    }
+    else
+    {
+      vertexSource.append( customShaderWrappers[index].vertexShaderPostfix );
+    }
 
-  if( geometryTypes & GEOMETRY_TYPE_TEXTURED_MESH )
-  {
-    shaderEffect->SetProgram( GEOMETRY_TYPE_TEXTURED_MESH, SHADER_SUBTYPE_ALL,
-                              vertexShaderPrefix + ( !vertexShader.empty() ? CustomMeshPrefixVertex + vertexShader : MeshVertex ),
-                              fragmentShaderPrefix + ( !fragmentShader.empty() ? CustomMeshPrefixFragment + fragmentShader : MeshFragment ) );
-  }
-  else
-  {
-    shaderEffect->SetProgram( GEOMETRY_TYPE_TEXTURED_MESH, SHADER_SUBTYPE_ALL, MeshVertex, MeshFragment );
-  }
+    fragmentSource += customShaderWrappers[index].fragmentShaderPrefix;
+    // Append the custom fragment shader code if supplied, otherwise append the default
+    if ( fragmentBody.length() > 0 )
+    {
+      fragmentSource.append( fragmentBody );
+    }
+    else
+    {
+      fragmentSource.append( customShaderWrappers[index].fragmentShaderPostfix );
+    }
 
-  if( geometryTypes & GEOMETRY_TYPE_MESH )
-  {
-    shaderEffect->SetProgram( GEOMETRY_TYPE_MESH, SHADER_SUBTYPE_ALL,
-                              vertexShaderPrefix + ( !vertexShader.empty() ? CustomMeshPrefixVertex + vertexShader : MeshColorNoTextureVertex ),
-                              fragmentShaderPrefix + ( !fragmentShader.empty() ? CustomMeshPrefixFragment + fragmentShader : MeshColorNoTextureFragment ) );
+    effect.SendProgramMessage( expectedGeometryType, SHADER_SUBTYPE_ALL, vertexSource, fragmentSource, modifiesGeometry );
   }
-  else
-  {
-    shaderEffect->SetProgram( GEOMETRY_TYPE_MESH, SHADER_SUBTYPE_ALL, MeshColorNoTextureVertex, MeshColorNoTextureFragment );
-  }
-}
-
-std::string GetFileContents( const std::string& filename )
-{
-  std::ifstream input( filename.c_str() );
-  return std::string( std::istreambuf_iterator<char>(input), std::istreambuf_iterator<char>() );
 }
 
 std::string GetShader(const std::string& field, const Property::Value& property)
 {
+  std::string value;
   if( property.HasKey(field) )
   {
     DALI_ASSERT_ALWAYS(property.GetValue(field).GetType() == Property::STRING && "Shader property is not a string" );
 
     // we could also check here for an array of strings as convenience for json not having multi line strings
-    return property.GetValue(field).Get<std::string>();
-  }
-  else
-  {
-    // convention of shader field appended with -filename signifies a file
-    std::string filenameKey(std::string(field) + std::string("-filename"));
-
-    if( property.HasKey( filenameKey ) )
-    {
-      DALI_ASSERT_ALWAYS(property.GetValue(filenameKey).GetType() == Property::STRING && "Shader filename property is not a string" );
-      // this should eventually be done by an adaptor interface
-      return GetFileContents( property.GetValue(filenameKey).Get<std::string>() );
-    }
+    value = property.GetValue(field).Get<std::string>();
   }
 
-  // if we got here
-  return std::string();
+  return value;
 }
 
-} // anon namespace
-
+} // unnamed namespace
 
 ShaderEffectPtr ShaderEffect::New( Dali::ShaderEffect::GeometryHints hints )
 {
   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
   UpdateManager& updateManager = tls.GetUpdateManager();
-  ShaderFactory& shaderFactory = tls.GetShaderFactory();
 
-  // Create a new scene-object, temporarily owned
-  Shader* sceneObject = new Shader( hints );
-  DALI_ASSERT_DEBUG( NULL != sceneObject );
-
-  ShaderEffectPtr shaderEffect( new ShaderEffect( updateManager, shaderFactory, *sceneObject ) );
+  ShaderEffectPtr shaderEffect( new ShaderEffect( updateManager, hints ) );
   shaderEffect->RegisterObject();
 
   return shaderEffect;
 }
 
-ShaderEffectPtr ShaderEffect::New( const std::string& vertexShader,
-                                   const std::string& fragmentShader,
-                                   GeometryType geometryType,
-                                   Dali::ShaderEffect::GeometryHints hints )
-{
-  return NewWithPrefix( "", vertexShader, "", fragmentShader, geometryType, hints);
-}
-
-ShaderEffectPtr ShaderEffect::NewWithPrefix( const std::string& vertexShaderPrefix,
-                                             const std::string& vertexShader,
-                                             const std::string& fragmentShaderPrefix,
-                                             const std::string& fragmentShader,
-                                             GeometryType geometryTypes,
-                                             Dali::ShaderEffect::GeometryHints hints )
-{
-  ShaderEffectPtr shaderEffect( New(hints) );
-
-  ShaderFactory::LoadTextSubtypeShaders(shaderEffect);
-
-  SetShaderProgram( vertexShaderPrefix, vertexShader,
-                    fragmentShaderPrefix, fragmentShader,
-                    geometryTypes,
-                    shaderEffect );
-
-  return shaderEffect;
-}
-
-ShaderEffectPtr ShaderEffect::New( const std::string& imageVertexShader,
-                                   const std::string& imageFragmentShader,
-                                   const std::string& textVertexShader,
-                                   const std::string& textFragmentShader,
-                                   const std::string& texturedMeshVertexShader,
-                                   const std::string& texturedMeshFragmentShader,
-                                   const std::string& meshVertexShader,
-                                   const std::string& meshFragmentShader,
-                                   Dali::ShaderEffect::GeometryHints hints )
+ShaderEffect::ShaderEffect( UpdateManager& updateManager, Dali::ShaderEffect::GeometryHints hints )
+: mUpdateManager( updateManager ),
+  mConnectionCount (0),
+  mGeometryHints( hints )
 {
-  ShaderEffectPtr shaderEffect( New(hints) );
-
-  ShaderFactory::LoadTextSubtypeShaders(shaderEffect);
+  mSceneObject = new Shader( hints );
+  DALI_ASSERT_DEBUG( NULL != mSceneObject );
 
-  SetShaderProgram( imageVertexShader, imageFragmentShader,
-                    textVertexShader,  textFragmentShader,
-                    texturedMeshVertexShader, texturedMeshFragmentShader,
-                    meshVertexShader,  meshFragmentShader,
-                    "", "",
-                    shaderEffect );
-
-  return shaderEffect;
+  // Transfer shader ownership to a scene message
+  AddShaderMessage( mUpdateManager, *mSceneObject );
 }
 
 ShaderEffect::~ShaderEffect()
 {
-  DALI_ASSERT_DEBUG( mSceneObject != NULL );
-
   // Guard to allow handle destruction after Core has been destroyed
   if ( Stage::IsInstalled() )
   {
     // Remove scene-object using a message to the UpdateManager
-    RemoveShaderMessage( mUpdateManager, *mSceneObject );
-
+    if( mSceneObject )
+    {
+      RemoveShaderMessage( mUpdateManager, *mSceneObject );
+    }
     UnregisterObject();
   }
 }
 
-ShaderEffect::ShaderEffect( UpdateManager& updateManager, ShaderFactory& shaderFactory, Shader& sceneObject )
-: mUpdateManager( updateManager ),
-  mShaderFactory( shaderFactory ),
-  mSceneObject( &sceneObject ),
-  mConnectionCount (0)
-{
-  // Transfer shader ownership to a scene message
-  AddShaderMessage( mUpdateManager, *mSceneObject );
-}
-
 void ShaderEffect::SetEffectImage( Dali::Image image )
 {
   // if images are the same, do nothing
@@ -431,7 +288,20 @@ void ShaderEffect::SetUniform( const std::string& name, Property::Value value, U
 
   SetProperty( index, value );
 
-  SetCoordinateTypeMessage( mUpdateManager.GetEventToUpdate(), *mCustomMetadata[index], uniformCoordinateType );
+  // RegisterProperty guarantees a positive value as index
+  DALI_ASSERT_DEBUG( static_cast<unsigned int>(index) >= CustomPropertyStartIndex() );
+  unsigned int metaIndex = index - CustomPropertyStartIndex();
+  // check if there's space in cache
+  if( mCoordinateTypes.Count() < (metaIndex + 1) )
+  {
+    mCoordinateTypes.Resize( metaIndex + 1 );
+  }
+  // only send message if the value is different than current, initial value is COORDINATE_TYPE_DEFAULT (0)
+  if( uniformCoordinateType != mCoordinateTypes[ metaIndex ] )
+  {
+    mCoordinateTypes[ metaIndex ] = uniformCoordinateType;
+    SetCoordinateTypeMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, metaIndex, uniformCoordinateType );
+  }
 }
 
 void ShaderEffect::AttachExtension( Dali::ShaderEffect::Extension *extension )
@@ -452,33 +322,51 @@ const Dali::ShaderEffect::Extension& ShaderEffect::GetExtension() const
   return *mExtension;
 }
 
-void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType,
-                               const std::string& vertexSource, const std::string& fragmentSource )
+void ShaderEffect::SetPrograms( GeometryType geometryType, const string& vertexSource, const string& fragmentSource )
 {
-  // Load done asynchronously in update thread. SetProgram message below must be processed afterwards.
-  // Therefore, resource manager cannot farm out the loading to the adaptor resource threads,
-  // but must instead use synchronous loading via PlatformAbstraction::LoadFile()
+  SetPrograms( geometryType, "", "", vertexSource, fragmentSource );
+}
+
+void ShaderEffect::SetPrograms( GeometryType geometryType,
+                                const std::string& vertexPrefix, const std::string& fragmentPrefix,
+                                const std::string& vertexSource, const std::string& fragmentSource )
+{
+  bool modifiesGeometry = true;
+  // check if the vertex shader is empty (means it cannot modify geometry)
+  if( (vertexPrefix.length() == 0 )&&( vertexSource.length() == 0 ) )
+  {
+    modifiesGeometry = false;
+  }
+  // check the hint second
+  if( (mGeometryHints & Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY ) != 0 )
+  {
+    modifiesGeometry = false;
+  }
+
+  WrapAndSetProgram( *this, geometryType, GEOMETRY_TYPE_IMAGE, vertexPrefix, fragmentPrefix, vertexSource, fragmentSource, modifiesGeometry );
+  WrapAndSetProgram( *this, geometryType, GEOMETRY_TYPE_TEXT, vertexPrefix, fragmentPrefix, vertexSource, fragmentSource, modifiesGeometry );
+  WrapAndSetProgram( *this, geometryType, GEOMETRY_TYPE_TEXTURED_MESH, vertexPrefix, fragmentPrefix, vertexSource, fragmentSource, modifiesGeometry );
+  WrapAndSetProgram( *this, geometryType, GEOMETRY_TYPE_UNTEXTURED_MESH, vertexPrefix, fragmentPrefix, vertexSource, fragmentSource, modifiesGeometry );
+}
+
+void ShaderEffect::SendProgramMessage( GeometryType geometryType, ShaderSubTypes subType,
+                                       const string& vertexSource, const string& fragmentSource,
+                                       bool modifiesGeometry )
+{
+  ThreadLocalStorage& tls = ThreadLocalStorage::Get();
+  ShaderFactory& shaderFactory = tls.GetShaderFactory();
   size_t shaderHash;
-  ResourceTicketPtr ticket( mShaderFactory.Load(vertexSource, fragmentSource, shaderHash) );
+
+  ResourceTicketPtr ticket( shaderFactory.Load(vertexSource, fragmentSource, shaderHash) );
 
   DALI_LOG_INFO( Debug::Filter::gShader, Debug::General, "ShaderEffect: SetProgram(geometryType %d subType:%d ticket.id:%d)\n", geometryType, subType, ticket->GetId() );
 
   // Add shader program to scene-object using a message to the UpdateManager
-  SetShaderProgramMessage( mUpdateManager, *mSceneObject, geometryType, subType, ticket->GetId(), shaderHash );
+  SetShaderProgramMessage( mUpdateManager, *mSceneObject, geometryType, subType, ticket->GetId(), shaderHash, modifiesGeometry );
 
   mTickets.push_back(ticket);       // add ticket to collection to keep it alive.
 }
 
-
-void ShaderEffect::SetProgram( GeometryType geometryType, ShaderSubTypes subType,
-                               const std::string& vertexPrefix, const std::string& fragmentPrefix,
-                               const std::string& vertexSource, const std::string& fragmentSource )
-{
-  const std::string vertex( vertexPrefix + vertexSource );
-  const std::string fragment( fragmentPrefix + fragmentSource );
-  SetProgram( geometryType, subType, vertex, fragment );
-}
-
 void ShaderEffect::Connect()
 {
   ++mConnectionCount;
@@ -503,11 +391,6 @@ void ShaderEffect::Disconnect()
   }
 }
 
-bool ShaderEffect::IsSceneObjectRemovable() const
-{
-  return false; // The Shader is not removed during this proxy's lifetime
-}
-
 unsigned int ShaderEffect::GetDefaultPropertyCount() const
 {
   return DEFAULT_PROPERTY_COUNT;
@@ -523,17 +406,15 @@ void ShaderEffect::GetDefaultPropertyIndices( Property::IndexContainer& indices
   }
 }
 
-const std::string& ShaderEffect::GetDefaultPropertyName(Property::Index index) const
+const char* ShaderEffect::GetDefaultPropertyName(Property::Index index) const
 {
   if( index < DEFAULT_PROPERTY_COUNT )
   {
-    return DEFAULT_PROPERTY_NAMES[index];
+    return DEFAULT_PROPERTY_DETAILS[index].name;
   }
   else
   {
-    // index out of range..return empty string
-    static const std::string INVALID_PROPERTY_NAME;
-    return INVALID_PROPERTY_NAME;
+    return NULL;
   }
 }
 
@@ -541,43 +422,41 @@ Property::Index ShaderEffect::GetDefaultPropertyIndex(const std::string& name) c
 {
   Property::Index index = Property::INVALID_INDEX;
 
-  // Lazy initialization of static mDefaultPropertyLookup
-  if (!mDefaultPropertyLookup)
+  // Look for name in default properties
+  for( int i = 0; i < DEFAULT_PROPERTY_COUNT; ++i )
   {
-    mDefaultPropertyLookup = new DefaultPropertyLookup();
-
-    for (int i=0; i<DEFAULT_PROPERTY_COUNT; ++i)
+    const Internal::PropertyDetails* property = &DEFAULT_PROPERTY_DETAILS[ i ];
+    if( 0 == strcmp( name.c_str(), property->name ) ) // dont want to convert rhs to string
     {
-      (*mDefaultPropertyLookup)[DEFAULT_PROPERTY_NAMES[i]] = i;
+      index = i;
+      break;
     }
   }
-  DALI_ASSERT_DEBUG( NULL != mDefaultPropertyLookup );
-
-  // Look for name in default properties
-  DefaultPropertyLookup::const_iterator result = mDefaultPropertyLookup->find( name );
-  if ( mDefaultPropertyLookup->end() != result )
-  {
-    index = result->second;
-  }
 
   return index;
+
 }
 
 bool ShaderEffect::IsDefaultPropertyWritable(Property::Index index) const
 {
-  return true;
+  return true; // all properties are writable
 }
 
 bool ShaderEffect::IsDefaultPropertyAnimatable(Property::Index index) const
 {
-  return false;
+  return false; // all properties are non animatable
+}
+
+bool ShaderEffect::IsDefaultPropertyAConstraintInput( Property::Index index ) const
+{
+  return false; // all properties cannot be used as constraint input
 }
 
 Property::Type ShaderEffect::GetDefaultPropertyType(Property::Index index) const
 {
   if( index < DEFAULT_PROPERTY_COUNT )
   {
-    return DEFAULT_PROPERTY_TYPES[index];
+    return DEFAULT_PROPERTY_DETAILS[index].type;
   }
   else
   {
@@ -617,9 +496,10 @@ void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Va
       std::string vertex         = GetShader("vertex", propertyValue);
       std::string fragment       = GetShader("fragment", propertyValue);
 
+      GeometryType geometryType      = GEOMETRY_TYPE_IMAGE;
+
       if( propertyValue.HasKey("geometry-type") )
       {
-        GeometryType geometryType      = GEOMETRY_TYPE_IMAGE;
         Property::Value geometryValue  = propertyValue.GetValue("geometry-type");
         DALI_ASSERT_ALWAYS(geometryValue.GetType() == Property::STRING && "Geometry type is not a string" );
 
@@ -632,9 +512,9 @@ void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Va
         {
           geometryType  = GEOMETRY_TYPE_TEXT;
         }
-        else if( s == "GEOMETRY_TYPE_MESH")
+        else if( s == "GEOMETRY_TYPE_UNTEXTURED_MESH")
         {
-          geometryType  = GEOMETRY_TYPE_MESH;
+          geometryType  = GEOMETRY_TYPE_UNTEXTURED_MESH;
         }
         else if( s == "GEOMETRY_TYPE_TEXTURED_MESH")
         {
@@ -644,9 +524,8 @@ void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Va
         {
           DALI_ASSERT_ALWAYS(!"Geometry type unknown" );
         }
-
-        SetShaderProgram( vertexPrefix, vertex, fragmentPrefix, fragment, geometryType, ShaderEffectPtr(this) );
       }
+      SetPrograms( geometryType, vertexPrefix, fragmentPrefix, vertex, fragment );
       break;
     }
 
@@ -680,6 +559,10 @@ void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Va
       {
         hint = Dali::ShaderEffect::HINT_BLENDING;
       }
+      else if(s == "HINT_DOESNT_MODIFY_GEOMETRY")
+      {
+        hint = Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY;
+      }
       else
       {
         DALI_ASSERT_ALWAYS(!"Geometry hint unknown" );
@@ -692,101 +575,7 @@ void ShaderEffect::SetDefaultProperty( Property::Index index, const Property::Va
 
     default:
     {
-      DALI_ASSERT_ALWAYS(false && "ShaderEffect property enumeration out of range"); // should not come here
-      break;
-    }
-  }
-}
-
-void ShaderEffect::SetCustomProperty( Property::Index /* index */, const CustomProperty& entry, const Property::Value& value )
-{
-  DALI_ASSERT_ALWAYS(entry.IsAnimatable() && "shader effect has only animatable properties");
-
-  switch ( entry.type )
-  {
-    case Property::BOOLEAN:
-    {
-      AnimatableProperty<bool>* property = dynamic_cast< AnimatableProperty<bool>* >( entry.GetSceneGraphProperty() );
-      DALI_ASSERT_DEBUG( NULL != property );
-
-      // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<bool>( mUpdateManager.GetEventToUpdate(), *property, value.Get<bool>() );
-      break;
-    }
-
-    case Property::FLOAT:
-    {
-      AnimatableProperty<float>* property = dynamic_cast< AnimatableProperty<float>* >( entry.GetSceneGraphProperty() );
-      DALI_ASSERT_DEBUG( NULL != property );
-
-      // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<float>( mUpdateManager.GetEventToUpdate(), *property, value.Get<float>() );
-      break;
-    }
-
-    case Property::VECTOR2:
-    {
-      AnimatableProperty<Vector2>* property = dynamic_cast< AnimatableProperty<Vector2>* >( entry.GetSceneGraphProperty() );
-      DALI_ASSERT_DEBUG( NULL != property );
-
-      // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Vector2>( mUpdateManager.GetEventToUpdate(), *property, value.Get<Vector2>() );
-      break;
-    }
-
-    case Property::VECTOR3:
-    {
-      AnimatableProperty<Vector3>* property = dynamic_cast< AnimatableProperty<Vector3>* >( entry.GetSceneGraphProperty() );
-      DALI_ASSERT_DEBUG( NULL != property );
-
-      // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Vector3>( mUpdateManager.GetEventToUpdate(), *property, value.Get<Vector3>() );
-      break;
-    }
-
-    case Property::VECTOR4:
-    {
-      AnimatableProperty<Vector4>* property = dynamic_cast< AnimatableProperty<Vector4>* >( entry.GetSceneGraphProperty() );
-      DALI_ASSERT_DEBUG( NULL != property );
-
-      // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Vector4>( mUpdateManager.GetEventToUpdate(), *property, value.Get<Vector4>() );
-      break;
-    }
-
-    case Property::ROTATION:
-    {
-      AnimatableProperty<Quaternion>* property = dynamic_cast< AnimatableProperty<Quaternion>* >( entry.GetSceneGraphProperty() );
-      DALI_ASSERT_DEBUG( NULL != property );
-
-      // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Quaternion>( mUpdateManager.GetEventToUpdate(), *property, value.Get<Quaternion>() );
-      break;
-    }
-
-    case Property::MATRIX:
-    {
-      AnimatableProperty<Matrix>* property = dynamic_cast< AnimatableProperty<Matrix>* >( entry.GetSceneGraphProperty() );
-      DALI_ASSERT_DEBUG( NULL != property );
-
-      // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Matrix>( mUpdateManager.GetEventToUpdate(), *property, value.Get<Matrix>() );
-      break;
-    }
-
-    case Property::MATRIX3:
-    {
-      AnimatableProperty<Matrix3>* property = dynamic_cast< AnimatableProperty<Matrix3>* >( entry.GetSceneGraphProperty() );
-      DALI_ASSERT_DEBUG( NULL != property );
-
-      // property is being used in a separate thread; queue a message to set the property
-      BakeMessage<Matrix3>( mUpdateManager.GetEventToUpdate(), *property, value.Get<Matrix3>() );
-      break;
-    }
-
-    default:
-    {
-      DALI_ASSERT_ALWAYS(false && "Property type enumeration out of bounds"); // should not come here
+      // nothing to do
       break;
     }
   }
@@ -798,20 +587,14 @@ Property::Value ShaderEffect::GetDefaultProperty(Property::Index /*index*/) cons
   return Property::Value();
 }
 
-void ShaderEffect::InstallSceneObjectProperty( PropertyBase& newProperty, const std::string& name, unsigned int index )
+void ShaderEffect::NotifyScenePropertyInstalled( const SceneGraph::PropertyBase& newProperty, const std::string& name, unsigned int index )
 {
   // 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)
 
-  // mSceneObject is being used in a separate thread; queue a message to add the property
-  InstallCustomPropertyMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, newProperty ); // Message takes ownership
-
   // mSceneObject requires metadata for each custom property (uniform)
   UniformMeta* meta = UniformMeta::New( name, newProperty, Dali::ShaderEffect::COORDINATE_TYPE_DEFAULT );
   // mSceneObject is being used in a separate thread; queue a message to add the property
   InstallUniformMetaMessage( mUpdateManager.GetEventToUpdate(), *mSceneObject, *meta ); // Message takes ownership
-
-  // Add entry to the metadata lookup
-  mCustomMetadata[index] = meta;
 }
 
 const SceneGraph::PropertyOwner* ShaderEffect::GetSceneObject() const
@@ -821,24 +604,14 @@ const SceneGraph::PropertyOwner* ShaderEffect::GetSceneObject() const
 
 const PropertyBase* ShaderEffect::GetSceneObjectAnimatableProperty( Property::Index index ) const
 {
-  CustomPropertyLookup::const_iterator entry = GetCustomPropertyLookup().find( index );
-
-  DALI_ASSERT_ALWAYS( GetCustomPropertyLookup().end() != entry && "Property index is invalid" );
-
-  DALI_ASSERT_ALWAYS( entry->second.IsAnimatable() && "shader effect has only animatable properties" );
-
-  return dynamic_cast<const PropertyBase*>( entry->second.GetSceneGraphProperty() );
+  CustomProperty* custom = FindCustomProperty( index );
+  DALI_ASSERT_ALWAYS( custom && "Property index is invalid" );
+  return custom->GetSceneGraphProperty();
 }
 
 const PropertyInputImpl* ShaderEffect::GetSceneObjectInputProperty( Property::Index index ) const
 {
-  CustomPropertyLookup::const_iterator entry = GetCustomPropertyLookup().find( index );
-
-  DALI_ASSERT_ALWAYS( GetCustomPropertyLookup().end() != entry && "Property index is invalid" );
-
-  DALI_ASSERT_ALWAYS( entry->second.IsAnimatable() && "shader effect has only animatable properties" );
-
-  return entry->second.GetSceneGraphProperty();
+  return GetSceneObjectAnimatableProperty( index );
 }
 
 } // namespace Internal