Implemented shader program property
[platform/core/uifw/dali-core.git] / dali / internal / event / rendering / shader-impl.cpp
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali/internal/event/rendering/shader-impl.h> // Dali::Internal::Shader
20
21 // INTERNAL INCLUDES
22 #include <dali/public-api/object/type-registry.h>
23 #include <dali/public-api/shader-effects/shader-effect.h> // Dali::ShaderEffect::GeometryHints // TODO: MESH_REWORK REMOVE
24 #include <dali/devel-api/rendering/shader.h> // Dali::Shader
25 #include <dali/devel-api/scripting/scripting.h>
26
27 #include <dali/internal/event/common/object-impl-helper.h> // Dali::Internal::ObjectHelper
28 #include <dali/internal/event/common/property-helper.h> // DALI_PROPERTY_TABLE_BEGIN, DALI_PROPERTY, DALI_PROPERTY_TABLE_END
29 #include <dali/internal/event/common/thread-local-storage.h>
30 #include <dali/internal/event/effects/shader-factory.h>
31 #include <dali/internal/event/resources/resource-ticket.h>
32 #include <dali/internal/update/manager/update-manager.h>
33
34 namespace Dali
35 {
36 namespace Internal
37 {
38
39 namespace
40 {
41
42 /**
43  *            |name             |type    |writable|animatable|constraint-input|enum for index-checking|
44  */
45 DALI_PROPERTY_TABLE_BEGIN
46 DALI_PROPERTY( "program",       MAP,     true,     false,     false,  Dali::Shader::Property::PROGRAM )
47 DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX )
48
49 const ObjectImplHelper<DEFAULT_PROPERTY_COUNT> SHADER_IMPL = { DEFAULT_PROPERTY_DETAILS };
50
51 Dali::Scripting::StringEnum ShaderHintsTable[] =
52   { { "HINT_NONE",                     Dali::Shader::HINT_NONE},
53     { "HINT_REQUIRES_SELF_DEPTH_TEST", Dali::Shader::HINT_REQUIRES_SELF_DEPTH_TEST},
54     { "HINT_OUTPUT_IS_TRANSPARENT",    Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT},
55     { "HINT_OUTPUT_IS_OPAQUE",         Dali::Shader::HINT_OUTPUT_IS_OPAQUE},
56     { "HINT_MODIFIES_GEOMETRY",        Dali::Shader::HINT_MODIFIES_GEOMETRY}
57   };
58
59 const unsigned int ShaderHintsTableSize = sizeof( ShaderHintsTable ) / sizeof( ShaderHintsTable[0] );
60
61 BaseHandle Create()
62 {
63   return Dali::BaseHandle();
64 }
65
66 TypeRegistration mType( typeid( Dali::Shader ), typeid( Dali::Handle ), Create );
67
68 #define TOKEN_STRING(x) (#x)
69
70 void AppendString(std::string& to, const std::string& append)
71 {
72   if(to.size())
73   {
74     to += ",";
75   }
76   to += append;
77 }
78
79 Property::Value HintString(const Dali::Shader::ShaderHints& hints)
80 {
81   std::string s;
82
83   if(hints == Dali::Shader::HINT_NONE)
84   {
85     s = "HINT_NONE";
86   }
87
88   if(hints & Dali::Shader::HINT_REQUIRES_SELF_DEPTH_TEST)
89   {
90     AppendString(s, "HINT_REQUIRES_SELF_DEPTH_TEST");
91   }
92
93   if(hints & Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT)
94   {
95     AppendString(s, "HINT_OUTPUT_IS_TRANSPARENT");
96   }
97
98   if(hints & Dali::Shader::HINT_OUTPUT_IS_OPAQUE)
99   {
100     AppendString(s, "HINT_OUTPUT_IS_OPAQUE");
101   }
102
103   if(hints & Dali::Shader::HINT_MODIFIES_GEOMETRY)
104   {
105     AppendString(s, "HINT_MODIFIES_GEOMETRY");
106   }
107
108   return Property::Value(s);
109 }
110
111
112 } // unnamed namespace
113
114 ShaderPtr Shader::New( const std::string& vertexShader,
115                        const std::string& fragmentShader,
116                        Dali::Shader::ShaderHints hints )
117 {
118   //TODO: MESH_REWORK
119   ShaderPtr shader( new Shader() );
120   shader->Initialize( vertexShader, fragmentShader, hints );
121   return shader;
122 }
123
124 const SceneGraph::Shader* Shader::GetShaderSceneObject() const
125 {
126   return mSceneObject;
127 }
128
129 SceneGraph::Shader* Shader::GetShaderSceneObject()
130 {
131   return mSceneObject;
132 }
133
134 unsigned int Shader::GetDefaultPropertyCount() const
135 {
136   return SHADER_IMPL.GetDefaultPropertyCount();
137 }
138
139 void Shader::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
140 {
141   SHADER_IMPL.GetDefaultPropertyIndices( indices );
142 }
143
144 const char* Shader::GetDefaultPropertyName(Property::Index index) const
145 {
146   return SHADER_IMPL.GetDefaultPropertyName( index );
147 }
148
149 Property::Index Shader::GetDefaultPropertyIndex( const std::string& name ) const
150 {
151   return SHADER_IMPL.GetDefaultPropertyIndex( name );
152 }
153
154 bool Shader::IsDefaultPropertyWritable( Property::Index index ) const
155 {
156   return SHADER_IMPL.IsDefaultPropertyWritable( index );
157 }
158
159 bool Shader::IsDefaultPropertyAnimatable( Property::Index index ) const
160 {
161   return SHADER_IMPL.IsDefaultPropertyAnimatable( index );
162 }
163
164 bool Shader::IsDefaultPropertyAConstraintInput( Property::Index index ) const
165 {
166   return SHADER_IMPL.IsDefaultPropertyAConstraintInput( index );
167 }
168
169 Property::Type Shader::GetDefaultPropertyType( Property::Index index ) const
170 {
171   return SHADER_IMPL.GetDefaultPropertyType( index );
172 }
173
174 void Shader::SetDefaultProperty( Property::Index index,
175                                  const Property::Value& propertyValue )
176 {
177   switch(index)
178   {
179     case Dali::Shader::Property::PROGRAM:
180     {
181       if( propertyValue.GetType() == Property::MAP )
182       {
183         Dali::Property::Map* map = propertyValue.GetMap();
184         std::string vertex;
185         std::string fragment;
186         Dali::Shader::ShaderHints hints(Dali::Shader::HINT_NONE);
187
188         if( Property::Value* value = map->Find("vertex") )
189         {
190           vertex = value->Get<std::string>();
191         }
192
193         if( Property::Value* value = map->Find("fragment") )
194         {
195           fragment = value->Get<std::string>();
196         }
197
198         if( Property::Value* value = map->Find("hints") )
199         {
200           static_cast<void>( // ignore return
201             Scripting::GetEnumeration< Dali::Shader::ShaderHints >(value->Get<std::string>().c_str(),
202                                                                    ShaderHintsTable, ShaderHintsTableSize, hints)
203             );
204         }
205
206         Initialize(vertex, fragment, hints );
207       }
208       else
209       {
210         DALI_LOG_WARNING( "Shader program property should be a map\n" );
211       }
212       break;
213     }
214   }
215 }
216
217 void Shader::SetSceneGraphProperty( Property::Index index,
218                                     const PropertyMetadata& entry,
219                                     const Property::Value& value )
220 {
221   SHADER_IMPL.SetSceneGraphProperty( GetEventThreadServices(), this, index, entry, value );
222   OnPropertySet(index, value);
223 }
224
225 Property::Value Shader::GetDefaultProperty( Property::Index index ) const
226 {
227   Property::Value value;
228
229   switch(index)
230   {
231     case Dali::Shader::Property::PROGRAM:
232     {
233       Dali::Property::Map map;
234       if( mShaderData )
235       {
236         map["vertex"] = Property::Value(mShaderData->GetVertexShader());
237         map["fragment"] = Property::Value(mShaderData->GetFragmentShader());
238         map["hints"] = HintString(mShaderData->GetHints());
239       }
240       value = map;
241       break;
242     }
243   }
244
245   return value;
246 }
247
248 const SceneGraph::PropertyOwner* Shader::GetPropertyOwner() const
249 {
250   return mSceneObject;
251 }
252
253 const SceneGraph::PropertyOwner* Shader::GetSceneObject() const
254 {
255   return mSceneObject;
256 }
257
258 const SceneGraph::PropertyBase* Shader::GetSceneObjectAnimatableProperty( Property::Index index ) const
259 {
260   DALI_ASSERT_ALWAYS( IsPropertyAnimatable( index ) && "Property is not animatable" );
261   const SceneGraph::PropertyBase* property = NULL;
262
263   property = SHADER_IMPL.GetRegisteredSceneGraphProperty( this,
264                                                           &Shader::FindAnimatableProperty,
265                                                           &Shader::FindCustomProperty,
266                                                           index );
267
268   if( property == NULL && index < DEFAULT_PROPERTY_MAX_COUNT )
269   {
270     DALI_ASSERT_ALWAYS( 0 && "Property is not animatable" );
271   }
272
273   return property;
274 }
275
276 const PropertyInputImpl* Shader::GetSceneObjectInputProperty( Property::Index index ) const
277 {
278   PropertyMetadata* property = NULL;
279
280   if(index >= PROPERTY_CUSTOM_START_INDEX )
281   {
282     property = FindCustomProperty( index );
283   }
284   else
285   {
286     property = FindAnimatableProperty( index );
287   }
288
289   DALI_ASSERT_ALWAYS( property && "property index is invalid" );
290   return property->GetSceneGraphProperty();
291 }
292
293 int Shader::GetPropertyComponentIndex( Property::Index index ) const
294 {
295   return Property::INVALID_COMPONENT_INDEX;
296 }
297
298 Shader::Shader()
299   : mSceneObject( NULL ),
300     mShaderData( NULL )
301 {
302 }
303
304 void Shader::Initialize(
305   const std::string& vertexSource,
306   const std::string& fragmentSource,
307   Dali::Shader::ShaderHints hints )
308 {
309   EventThreadServices& eventThreadServices = GetEventThreadServices();
310   SceneGraph::UpdateManager& updateManager = eventThreadServices.GetUpdateManager();
311
312   // @todo MESH_REWORK - Pass hints directly to a new scene graph shader
313   int effectHint = Dali::ShaderEffect::HINT_NONE;
314   if( hints & Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT )
315   {
316     effectHint |= Dali::ShaderEffect::HINT_BLENDING;
317   }
318
319   if( hints & Dali::Shader::HINT_REQUIRES_SELF_DEPTH_TEST )
320   {
321     effectHint |= Dali::ShaderEffect::HINT_DEPTH_BUFFER;
322   }
323
324   if( (hints & Dali::Shader::HINT_MODIFIES_GEOMETRY) == 0x0 )
325   {
326     effectHint |= Dali::ShaderEffect::HINT_DOESNT_MODIFY_GEOMETRY;
327   }
328   Dali::ShaderEffect::GeometryHints shaderEffectHint = static_cast<Dali::ShaderEffect::GeometryHints>( effectHint );
329
330   mSceneObject = new SceneGraph::Shader( shaderEffectHint );
331
332   // Add to update manager
333   AddShaderMessage( updateManager, *mSceneObject );
334
335   // Try to load a precompiled shader binary for the source pair:
336   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
337   ShaderFactory& shaderFactory = tls.GetShaderFactory();
338   size_t shaderHash;
339   mShaderData = shaderFactory.Load( vertexSource, fragmentSource, hints, shaderHash );
340
341   // Add shader program to scene-object using a message to the UpdateManager
342   SetShaderProgramMessage( updateManager, *mSceneObject, mShaderData, (hints & Dali::Shader::HINT_MODIFIES_GEOMETRY) != 0x0 );
343   eventThreadServices.RegisterObject( this );
344 }
345
346 Shader::~Shader()
347 {
348   if( EventThreadServices::IsCoreRunning() )
349   {
350     EventThreadServices& eventThreadServices = GetEventThreadServices();
351     SceneGraph::UpdateManager& updateManager = eventThreadServices.GetUpdateManager();
352     RemoveShaderMessage( updateManager, *mSceneObject);
353
354     eventThreadServices.UnregisterObject( this );
355   }
356 }
357
358
359 } // namespace Internal
360 } // namespace Dali