Add ApplyCustomFragmentPrefix
[platform/core/uifw/dali-core.git] / dali / internal / event / rendering / shader-impl.cpp
1 /*
2  * Copyright (c) 2021 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/devel-api/scripting/scripting.h>
23 #include <dali/internal/event/common/property-helper.h> // DALI_PROPERTY_TABLE_BEGIN, DALI_PROPERTY, DALI_PROPERTY_TABLE_END
24 #include <dali/internal/event/common/thread-local-storage.h>
25 #include <dali/internal/event/effects/shader-factory.h>
26 #include <dali/internal/update/manager/update-manager.h>
27 #include <dali/public-api/object/type-registry.h>
28
29 namespace Dali
30 {
31 namespace Internal
32 {
33 namespace
34 {
35 /**
36  *            |name             |type    |writable|animatable|constraint-input|enum for index-checking|
37  */
38 DALI_PROPERTY_TABLE_BEGIN
39 DALI_PROPERTY("program", MAP, true, false, false, Dali::Shader::Property::PROGRAM)
40 DALI_PROPERTY_TABLE_END(DEFAULT_ACTOR_PROPERTY_START_INDEX, ShaderDefaultProperties)
41
42 Dali::Scripting::StringEnum ShaderHintsTable[] =
43   {{"NONE", Dali::Shader::Hint::NONE},
44    {"OUTPUT_IS_TRANSPARENT", Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT},
45    {"MODIFIES_GEOMETRY", Dali::Shader::Hint::MODIFIES_GEOMETRY}};
46
47 const uint32_t ShaderHintsTableSize = static_cast<uint32_t>(sizeof(ShaderHintsTable) / sizeof(ShaderHintsTable[0]));
48
49 BaseHandle Create()
50 {
51   return Dali::BaseHandle();
52 }
53
54 TypeRegistration mType(typeid(Dali::Shader), typeid(Dali::Handle), Create, ShaderDefaultProperties);
55
56 #define TOKEN_STRING(x) (#x)
57
58 void AppendString(std::string& to, const std::string& append)
59 {
60   if(to.size())
61   {
62     to += ",";
63   }
64   to += append;
65 }
66
67 Property::Value HintString(const Dali::Shader::Hint::Value& hints)
68 {
69   std::string s;
70
71   if(hints == Dali::Shader::Hint::NONE)
72   {
73     s = "NONE";
74   }
75
76   if(hints & Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT)
77   {
78     AppendString(s, "OUTPUT_IS_TRANSPARENT");
79   }
80
81   if(hints & Dali::Shader::Hint::MODIFIES_GEOMETRY)
82   {
83     AppendString(s, "MODIFIES_GEOMETRY");
84   }
85
86   return Property::Value(s);
87 }
88
89 } // unnamed namespace
90
91 ShaderPtr Shader::New(std::string_view          vertexShader,
92                       std::string_view          fragmentShader,
93                       Dali::Shader::Hint::Value hints)
94 {
95   // create scene object first so it's guaranteed to exist for the event side
96   auto                             sceneObject = new SceneGraph::Shader(hints);
97   OwnerPointer<SceneGraph::Shader> transferOwnership(sceneObject);
98   // pass the pointer to base for message passing
99   ShaderPtr shader(new Shader(sceneObject));
100   // transfer scene object ownership to update manager
101   auto&&                     services      = shader->GetEventThreadServices();
102   SceneGraph::UpdateManager& updateManager = services.GetUpdateManager();
103   AddShaderMessage(updateManager, transferOwnership);
104
105   services.RegisterObject(shader.Get());
106   shader->SetShader(vertexShader, fragmentShader, hints);
107
108   return shader;
109 }
110
111 const SceneGraph::Shader& Shader::GetShaderSceneObject() const
112 {
113   return static_cast<const SceneGraph::Shader&>(GetSceneObject());
114 }
115
116 void Shader::SetDefaultProperty(Property::Index index, const Property::Value& propertyValue)
117 {
118   switch(index)
119   {
120     case Dali::Shader::Property::PROGRAM:
121     {
122       if(propertyValue.GetType() == Property::MAP)
123       {
124         const 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,
146                                                                    ShaderHintsTableSize,
147                                                                    hints));
148           }
149
150           SetShader(vertex, fragment, hints);
151         }
152       }
153       else
154       {
155         DALI_LOG_WARNING("Shader program property should be a map\n");
156       }
157       break;
158     }
159   }
160 }
161
162 Property::Value Shader::GetDefaultProperty(Property::Index index) const
163 {
164   Property::Value value;
165
166   switch(index)
167   {
168     case Dali::Shader::Property::PROGRAM:
169     {
170       Dali::Property::Map map;
171       if(mShaderData)
172       {
173         map["vertex"]   = Property::Value(mShaderData->GetVertexShader());
174         map["fragment"] = Property::Value(mShaderData->GetFragmentShader());
175         map["hints"]    = HintString(mShaderData->GetHints());
176       }
177       value = map;
178       break;
179     }
180   }
181
182   return value;
183 }
184
185 Property::Value Shader::GetDefaultPropertyCurrentValue(Property::Index index) const
186 {
187   return GetDefaultProperty(index); // Event-side only properties
188 }
189
190 Shader::Shader(const SceneGraph::Shader* sceneObject)
191 : Object(sceneObject),
192   mShaderData(nullptr)
193 {
194 }
195
196 void Shader::SetShader(std::string_view          vertexSource,
197                        std::string_view          fragmentSource,
198                        Dali::Shader::Hint::Value hints)
199 {
200   // Try to load a pre-compiled shader binary for the source pair:
201   ThreadLocalStorage& tls           = ThreadLocalStorage::Get();
202   ShaderFactory&      shaderFactory = tls.GetShaderFactory();
203   size_t              shaderHash;
204   mShaderData = shaderFactory.Load(vertexSource, fragmentSource, hints, shaderHash);
205
206   // Add shader data to scene-object
207
208   SceneGraph::SetShaderDataMessage(GetEventThreadServices(), GetShaderSceneObject(), mShaderData);
209 }
210
211 Shader::~Shader()
212 {
213   if(EventThreadServices::IsCoreRunning())
214   {
215     EventThreadServices&       eventThreadServices = GetEventThreadServices();
216     SceneGraph::UpdateManager& updateManager       = eventThreadServices.GetUpdateManager();
217     RemoveShaderMessage(updateManager, &GetShaderSceneObject());
218
219     eventThreadServices.UnregisterObject(this);
220   }
221 }
222
223 std::string Shader::GetShaderVersionPrefix()
224 {
225   Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get();
226   return tls.GetShaderVersionPrefix();
227 }
228
229 std::string Shader::GetVertexShaderPrefix()
230 {
231   Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get();
232   return tls.GetVertexShaderPrefix();
233 }
234
235 std::string Shader::GetFragmentShaderPrefix()
236 {
237   Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get();
238   return tls.GetFragmentShaderPrefix();
239 }
240
241 } // namespace Internal
242 } // namespace Dali