1e670c9507b794c1e7ee0460f77a3b537783d018
[platform/core/uifw/dali-core.git] / dali / internal / event / rendering / shader-impl.cpp
1 /*
2  * Copyright (c) 2018 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/devel-api/scripting/scripting.h>
24 #include <dali/internal/event/common/object-impl-helper.h> // Dali::Internal::ObjectHelper
25 #include <dali/internal/event/common/property-helper.h> // DALI_PROPERTY_TABLE_BEGIN, DALI_PROPERTY, DALI_PROPERTY_TABLE_END
26 #include <dali/internal/event/common/thread-local-storage.h>
27 #include <dali/internal/event/effects/shader-factory.h>
28 #include <dali/internal/update/manager/update-manager.h>
29
30 namespace Dali
31 {
32 namespace Internal
33 {
34
35 namespace
36 {
37
38 /**
39  *            |name             |type    |writable|animatable|constraint-input|enum for index-checking|
40  */
41 DALI_PROPERTY_TABLE_BEGIN
42 DALI_PROPERTY( "program",       MAP,     true,     false,     false,  Dali::Shader::Property::PROGRAM )
43 DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX, ShaderDefaultProperties )
44
45 Dali::Scripting::StringEnum ShaderHintsTable[] =
46   { { "NONE",                     Dali::Shader::Hint::NONE},
47     { "OUTPUT_IS_TRANSPARENT",    Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT},
48     { "MODIFIES_GEOMETRY",        Dali::Shader::Hint::MODIFIES_GEOMETRY}
49   };
50
51 const uint32_t ShaderHintsTableSize = static_cast<uint32_t>( sizeof( ShaderHintsTable ) / sizeof( ShaderHintsTable[0] ) );
52
53 BaseHandle Create()
54 {
55   return Dali::BaseHandle();
56 }
57
58 TypeRegistration mType( typeid( Dali::Shader ), typeid( Dali::Handle ), Create, ShaderDefaultProperties );
59
60 #define TOKEN_STRING(x) (#x)
61
62 void AppendString(std::string& to, const std::string& append)
63 {
64   if(to.size())
65   {
66     to += ",";
67   }
68   to += append;
69 }
70
71 Property::Value HintString(const Dali::Shader::Hint::Value& hints)
72 {
73   std::string s;
74
75   if(hints == Dali::Shader::Hint::NONE)
76   {
77     s = "NONE";
78   }
79
80   if(hints & Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT)
81   {
82     AppendString(s, "OUTPUT_IS_TRANSPARENT");
83   }
84
85   if(hints & Dali::Shader::Hint::MODIFIES_GEOMETRY)
86   {
87     AppendString(s, "MODIFIES_GEOMETRY");
88   }
89
90   return Property::Value(s);
91 }
92
93
94 } // unnamed namespace
95
96 ShaderPtr Shader::New( const std::string& vertexShader,
97                        const std::string& fragmentShader,
98                        Dali::Shader::Hint::Value hints )
99 {
100   ShaderPtr shader( new Shader() );
101   shader->Initialize( vertexShader, fragmentShader, hints );
102   return shader;
103 }
104
105 const SceneGraph::Shader* Shader::GetShaderSceneObject() const
106 {
107   return mSceneObject;
108 }
109
110 SceneGraph::Shader* Shader::GetShaderSceneObject()
111 {
112   return mSceneObject;
113 }
114
115 void Shader::SetDefaultProperty( Property::Index index,
116                                  const Property::Value& propertyValue )
117 {
118   switch(index)
119   {
120     case Dali::Shader::Property::PROGRAM:
121     {
122       if( propertyValue.GetType() == Property::MAP )
123       {
124         Dali::Property::Map* map = propertyValue.GetMap();
125         if( map )
126         {
127           std::string vertex;
128           std::string fragment;
129           Dali::Shader::Hint::Value hints(Dali::Shader::Hint::NONE);
130
131           if( Property::Value* value = map->Find("vertex") )
132           {
133             vertex = value->Get<std::string>();
134           }
135
136           if( Property::Value* value = map->Find("fragment") )
137           {
138             fragment = value->Get<std::string>();
139           }
140
141           if( Property::Value* value = map->Find("hints") )
142           {
143             static_cast<void>( // ignore return
144               Scripting::GetEnumeration< Dali::Shader::Hint::Value >(value->Get<std::string>().c_str(),
145                                                                      ShaderHintsTable, ShaderHintsTableSize, hints)
146               );
147           }
148
149           Initialize(vertex, fragment, hints );
150         }
151       }
152       else
153       {
154         DALI_LOG_WARNING( "Shader program property should be a map\n" );
155       }
156       break;
157     }
158   }
159 }
160
161 void Shader::SetSceneGraphProperty( Property::Index index,
162                                     const PropertyMetadata& entry,
163                                     const Property::Value& value )
164 {
165   ObjectImplHelper::SetSceneGraphProperty( GetEventThreadServices(), this, index, entry, value );
166   OnPropertySet(index, value);
167 }
168
169 Property::Value Shader::GetDefaultProperty( Property::Index index ) const
170 {
171   Property::Value value;
172
173   switch(index)
174   {
175     case Dali::Shader::Property::PROGRAM:
176     {
177       Dali::Property::Map map;
178       if( mShaderData )
179       {
180         map["vertex"] = Property::Value(mShaderData->GetVertexShader());
181         map["fragment"] = Property::Value(mShaderData->GetFragmentShader());
182         map["hints"] = HintString(mShaderData->GetHints());
183       }
184       value = map;
185       break;
186     }
187   }
188
189   return value;
190 }
191
192 Property::Value Shader::GetDefaultPropertyCurrentValue( Property::Index index ) const
193 {
194   return GetDefaultProperty( index ); // Event-side only properties
195 }
196
197 const SceneGraph::PropertyOwner* Shader::GetPropertyOwner() const
198 {
199   return mSceneObject;
200 }
201
202 const SceneGraph::PropertyOwner* Shader::GetSceneObject() const
203 {
204   return mSceneObject;
205 }
206
207 const SceneGraph::PropertyBase* Shader::GetSceneObjectAnimatableProperty( Property::Index index ) const
208 {
209   DALI_ASSERT_ALWAYS( IsPropertyAnimatable( index ) && "Property is not animatable" );
210   const SceneGraph::PropertyBase* property = NULL;
211
212   property = ObjectImplHelper::GetRegisteredSceneGraphProperty( this,
213                                                                 &Shader::FindAnimatableProperty,
214                                                                 &Shader::FindCustomProperty,
215                                                                 index );
216
217   if( property == NULL && index < DEFAULT_PROPERTY_MAX_COUNT )
218   {
219     DALI_ASSERT_ALWAYS( 0 && "Property is not animatable" );
220   }
221
222   return property;
223 }
224
225 const PropertyInputImpl* Shader::GetSceneObjectInputProperty( Property::Index index ) const
226 {
227   PropertyMetadata* property = NULL;
228
229   if( ( index >= CHILD_PROPERTY_REGISTRATION_START_INDEX ) && // Child properties are also stored as custom properties
230       ( index <= PROPERTY_CUSTOM_MAX_INDEX ) )
231   {
232     property = FindCustomProperty( index );
233   }
234   else if( ( index >= ANIMATABLE_PROPERTY_REGISTRATION_START_INDEX ) && ( index <= ANIMATABLE_PROPERTY_REGISTRATION_MAX_INDEX ) )
235   {
236     property = FindAnimatableProperty( index );
237   }
238
239   DALI_ASSERT_ALWAYS( property && "property index is invalid" );
240   return property->GetSceneGraphProperty();
241 }
242
243 int Shader::GetPropertyComponentIndex( Property::Index index ) const
244 {
245   return Property::INVALID_COMPONENT_INDEX;
246 }
247
248 Shader::Shader()
249   : mSceneObject( NULL ),
250     mShaderData( NULL )
251 {
252 }
253
254 void Shader::Initialize(
255   const std::string& vertexSource,
256   const std::string& fragmentSource,
257   Dali::Shader::Hint::Value hints )
258 {
259   EventThreadServices& eventThreadServices = GetEventThreadServices();
260   SceneGraph::UpdateManager& updateManager = eventThreadServices.GetUpdateManager();
261   mSceneObject = new SceneGraph::Shader( hints );
262
263   OwnerPointer< SceneGraph::Shader > transferOwnership( mSceneObject );
264   AddShaderMessage( updateManager, transferOwnership );
265
266   // Try to load a precompiled shader binary for the source pair:
267   ThreadLocalStorage& tls = ThreadLocalStorage::Get();
268   ShaderFactory& shaderFactory = tls.GetShaderFactory();
269   size_t shaderHash;
270   mShaderData = shaderFactory.Load( vertexSource, fragmentSource, hints, shaderHash );
271
272   // Add shader program to scene-object using a message to the UpdateManager
273   SetShaderProgramMessage( updateManager, *mSceneObject, mShaderData, (hints & Dali::Shader::Hint::MODIFIES_GEOMETRY) != 0x0 );
274   eventThreadServices.RegisterObject( this );
275 }
276
277 Shader::~Shader()
278 {
279   if( EventThreadServices::IsCoreRunning() )
280   {
281     EventThreadServices& eventThreadServices = GetEventThreadServices();
282     SceneGraph::UpdateManager& updateManager = eventThreadServices.GetUpdateManager();
283     RemoveShaderMessage( updateManager, *mSceneObject);
284
285     eventThreadServices.UnregisterObject( this );
286   }
287 }
288
289
290 } // namespace Internal
291 } // namespace Dali