127de82534ecb40255a341e76e288be65ec2ea46
[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_OUTPUT_IS_TRANSPARENT",    Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT},
54     { "HINT_MODIFIES_GEOMETRY",        Dali::Shader::HINT_MODIFIES_GEOMETRY}
55   };
56
57 const unsigned int ShaderHintsTableSize = sizeof( ShaderHintsTable ) / sizeof( ShaderHintsTable[0] );
58
59 BaseHandle Create()
60 {
61   return Dali::BaseHandle();
62 }
63
64 TypeRegistration mType( typeid( Dali::Shader ), typeid( Dali::Handle ), Create );
65
66 #define TOKEN_STRING(x) (#x)
67
68 void AppendString(std::string& to, const std::string& append)
69 {
70   if(to.size())
71   {
72     to += ",";
73   }
74   to += append;
75 }
76
77 Property::Value HintString(const Dali::Shader::ShaderHints& hints)
78 {
79   std::string s;
80
81   if(hints == Dali::Shader::HINT_NONE)
82   {
83     s = "HINT_NONE";
84   }
85
86   if(hints & Dali::Shader::HINT_OUTPUT_IS_TRANSPARENT)
87   {
88     AppendString(s, "HINT_OUTPUT_IS_TRANSPARENT");
89   }
90
91   if(hints & Dali::Shader::HINT_MODIFIES_GEOMETRY)
92   {
93     AppendString(s, "HINT_MODIFIES_GEOMETRY");
94   }
95
96   return Property::Value(s);
97 }
98
99
100 } // unnamed namespace
101
102 ShaderPtr Shader::New( const std::string& vertexShader,
103                        const std::string& fragmentShader,
104                        Dali::Shader::ShaderHints hints )
105 {
106   ShaderPtr shader( new Shader() );
107   shader->Initialize( vertexShader, fragmentShader, hints );
108   return shader;
109 }
110
111 const SceneGraph::Shader* Shader::GetShaderSceneObject() const
112 {
113   return mSceneObject;
114 }
115
116 SceneGraph::Shader* Shader::GetShaderSceneObject()
117 {
118   return mSceneObject;
119 }
120
121 unsigned int Shader::GetDefaultPropertyCount() const
122 {
123   return SHADER_IMPL.GetDefaultPropertyCount();
124 }
125
126 void Shader::GetDefaultPropertyIndices( Property::IndexContainer& indices ) const
127 {
128   SHADER_IMPL.GetDefaultPropertyIndices( indices );
129 }
130
131 const char* Shader::GetDefaultPropertyName(Property::Index index) const
132 {
133   return SHADER_IMPL.GetDefaultPropertyName( index );
134 }
135
136 Property::Index Shader::GetDefaultPropertyIndex( const std::string& name ) const
137 {
138   return SHADER_IMPL.GetDefaultPropertyIndex( name );
139 }
140
141 bool Shader::IsDefaultPropertyWritable( Property::Index index ) const
142 {
143   return SHADER_IMPL.IsDefaultPropertyWritable( index );
144 }
145
146 bool Shader::IsDefaultPropertyAnimatable( Property::Index index ) const
147 {
148   return SHADER_IMPL.IsDefaultPropertyAnimatable( index );
149 }
150
151 bool Shader::IsDefaultPropertyAConstraintInput( Property::Index index ) const
152 {
153   return SHADER_IMPL.IsDefaultPropertyAConstraintInput( index );
154 }
155
156 Property::Type Shader::GetDefaultPropertyType( Property::Index index ) const
157 {
158   return SHADER_IMPL.GetDefaultPropertyType( index );
159 }
160
161 void Shader::SetDefaultProperty( Property::Index index,
162                                  const Property::Value& propertyValue )
163 {
164   switch(index)
165   {
166     case Dali::Shader::Property::PROGRAM:
167     {
168       if( propertyValue.GetType() == Property::MAP )
169       {
170         Dali::Property::Map* map = propertyValue.GetMap();
171         if( map )
172         {
173           std::string vertex;
174           std::string fragment;
175           Dali::Shader::ShaderHints hints(Dali::Shader::HINT_NONE);
176
177           if( Property::Value* value = map->Find("vertex") )
178           {
179             vertex = value->Get<std::string>();
180           }
181
182           if( Property::Value* value = map->Find("fragment") )
183           {
184             fragment = value->Get<std::string>();
185           }
186
187           if( Property::Value* value = map->Find("hints") )
188           {
189             static_cast<void>( // ignore return
190               Scripting::GetEnumeration< Dali::Shader::ShaderHints >(value->Get<std::string>().c_str(),
191                                                                      ShaderHintsTable, ShaderHintsTableSize, hints)
192               );
193           }
194
195           Initialize(vertex, fragment, hints );
196         }
197       }
198       else
199       {
200         DALI_LOG_WARNING( "Shader program property should be a map\n" );
201       }
202       break;
203     }
204   }
205 }
206
207 void Shader::SetSceneGraphProperty( Property::Index index,
208                                     const PropertyMetadata& entry,
209                                     const Property::Value& value )
210 {
211   SHADER_IMPL.SetSceneGraphProperty( GetEventThreadServices(), this, index, entry, value );
212   OnPropertySet(index, value);
213 }
214
215 Property::Value Shader::GetDefaultProperty( Property::Index index ) const
216 {
217   Property::Value value;
218
219   switch(index)
220   {
221     case Dali::Shader::Property::PROGRAM:
222     {
223       Dali::Property::Map map;
224       if( mShaderData )
225       {
226         map["vertex"] = Property::Value(mShaderData->GetVertexShader());
227         map["fragment"] = Property::Value(mShaderData->GetFragmentShader());
228         map["hints"] = HintString(mShaderData->GetHints());
229       }
230       value = map;
231       break;
232     }
233   }
234
235   return value;
236 }
237
238 const SceneGraph::PropertyOwner* Shader::GetPropertyOwner() const
239 {
240   return mSceneObject;
241 }
242
243 const SceneGraph::PropertyOwner* Shader::GetSceneObject() const
244 {
245   return mSceneObject;
246 }
247
248 const SceneGraph::PropertyBase* Shader::GetSceneObjectAnimatableProperty( Property::Index index ) const
249 {
250   DALI_ASSERT_ALWAYS( IsPropertyAnimatable( index ) && "Property is not animatable" );
251   const SceneGraph::PropertyBase* property = NULL;
252
253   property = SHADER_IMPL.GetRegisteredSceneGraphProperty( this,
254                                                           &Shader::FindAnimatableProperty,
255                                                           &Shader::FindCustomProperty,
256                                                           index );
257
258   if( property == NULL && index < DEFAULT_PROPERTY_MAX_COUNT )
259   {
260     DALI_ASSERT_ALWAYS( 0 && "Property is not animatable" );
261   }
262
263   return property;
264 }
265
266 const PropertyInputImpl* Shader::GetSceneObjectInputProperty( Property::Index index ) const
267 {
268   PropertyMetadata* property = NULL;
269
270   if(index >= PROPERTY_CUSTOM_START_INDEX )
271   {
272     property = FindCustomProperty( index );
273   }
274   else
275   {
276     property = FindAnimatableProperty( index );
277   }
278
279   DALI_ASSERT_ALWAYS( property && "property index is invalid" );
280   return property->GetSceneGraphProperty();
281 }
282
283 int Shader::GetPropertyComponentIndex( Property::Index index ) const
284 {
285   return Property::INVALID_COMPONENT_INDEX;
286 }
287
288 Shader::Shader()
289   : mSceneObject( NULL ),
290     mShaderData( NULL )
291 {
292 }
293
294 void Shader::Initialize(
295   const std::string& vertexSource,
296   const std::string& fragmentSource,
297   Dali::Shader::ShaderHints hints )
298 {
299   EventThreadServices& eventThreadServices = GetEventThreadServices();
300   SceneGraph::UpdateManager& updateManager = eventThreadServices.GetUpdateManager();
301   mSceneObject = new SceneGraph::Shader( hints );
302
303   // Add to update manager
304   AddShaderMessage( updateManager, *mSceneObject );
305
306   // Try to load a precompiled shader binary for the source pair:
307   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
308   ShaderFactory& shaderFactory = tls.GetShaderFactory();
309   size_t shaderHash;
310   mShaderData = shaderFactory.Load( vertexSource, fragmentSource, hints, shaderHash );
311
312   // Add shader program to scene-object using a message to the UpdateManager
313   SetShaderProgramMessage( updateManager, *mSceneObject, mShaderData, (hints & Dali::Shader::HINT_MODIFIES_GEOMETRY) != 0x0 );
314   eventThreadServices.RegisterObject( this );
315 }
316
317 Shader::~Shader()
318 {
319   if( EventThreadServices::IsCoreRunning() )
320   {
321     EventThreadServices& eventThreadServices = GetEventThreadServices();
322     SceneGraph::UpdateManager& updateManager = eventThreadServices.GetUpdateManager();
323     RemoveShaderMessage( updateManager, *mSceneObject);
324
325     eventThreadServices.UnregisterObject( this );
326   }
327 }
328
329
330 } // namespace Internal
331 } // namespace Dali