2 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/event/rendering/shader-impl.h> // Dali::Internal::Shader
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>
36 * |name |type |writable|animatable|constraint-input|enum for index-checking|
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)
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}};
47 const uint32_t ShaderHintsTableSize = static_cast<uint32_t>(sizeof(ShaderHintsTable) / sizeof(ShaderHintsTable[0]));
49 static constexpr uint32_t DEFAULT_RENDER_PASS_TAG = 0u;
50 static constexpr std::string_view DEFAULT_SHADER_NAME = "";
54 return Dali::BaseHandle();
57 TypeRegistration mType(typeid(Dali::Shader), typeid(Dali::Handle), Create, ShaderDefaultProperties);
59 #define TOKEN_STRING(x) (#x)
61 void AppendString(std::string& to, const std::string& append)
70 Property::Value HintString(const Dali::Shader::Hint::Value& hints)
74 if(hints == Dali::Shader::Hint::NONE)
79 if(hints & Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT)
81 AppendString(s, "OUTPUT_IS_TRANSPARENT");
84 if(hints & Dali::Shader::Hint::MODIFIES_GEOMETRY)
86 AppendString(s, "MODIFIES_GEOMETRY");
89 return Property::Value(s);
92 void GetShaderData(const Property::Map& shaderMap, std::string& vertexShader, std::string& fragmentShader, uint32_t& renderPassTag, Dali::Shader::Hint::Value& hints, std::string& name)
94 hints = Dali::Shader::Hint::NONE;
95 renderPassTag = DEFAULT_RENDER_PASS_TAG;
96 name = DEFAULT_SHADER_NAME;
98 if(Property::Value* value = shaderMap.Find("vertex"))
100 vertexShader = value->Get<std::string>();
103 if(Property::Value* value = shaderMap.Find("fragment"))
105 fragmentShader = value->Get<std::string>();
108 if(Property::Value* value = shaderMap.Find("renderPassTag"))
110 renderPassTag = static_cast<uint32_t>(value->Get<int32_t>());
113 if(Property::Value* value = shaderMap.Find("name"))
115 name = value->Get<std::string>();
118 if(Property::Value* value = shaderMap.Find("hints"))
120 int32_t hintInteger = 0;
121 if(value->Get(hintInteger))
123 hints = static_cast<Dali::Shader::Hint::Value>(hintInteger);
127 static_cast<void>( // ignore return
128 Scripting::GetEnumeration<Dali::Shader::Hint::Value>(value->Get<std::string>().c_str(),
130 ShaderHintsTableSize,
136 } // unnamed namespace
138 ShaderPtr Shader::New(std::string_view vertexShader,
139 std::string_view fragmentShader,
140 Dali::Shader::Hint::Value hints,
141 std::string_view shaderName)
143 // create scene object first so it's guaranteed to exist for the event side
144 auto sceneObject = new SceneGraph::Shader();
145 OwnerPointer<SceneGraph::Shader> transferOwnership(sceneObject);
146 // pass the pointer to base for message passing
147 ShaderPtr shader(new Shader(sceneObject));
148 // transfer scene object ownership to update manager
149 auto&& services = shader->GetEventThreadServices();
150 SceneGraph::UpdateManager& updateManager = services.GetUpdateManager();
151 AddShaderMessage(updateManager, transferOwnership);
153 services.RegisterObject(shader.Get());
154 shader->UpdateShaderData(vertexShader, fragmentShader, DEFAULT_RENDER_PASS_TAG, hints, shaderName);
159 ShaderPtr Shader::New(Dali::Property::Value shaderMap)
161 // create scene object first so it's guaranteed to exist for the event side
162 auto sceneObject = new SceneGraph::Shader();
163 OwnerPointer<SceneGraph::Shader> transferOwnership(sceneObject);
164 // pass the pointer to base for message passing
165 ShaderPtr shader(new Shader(sceneObject));
166 // transfer scene object ownership to update manager
167 auto&& services = shader->GetEventThreadServices();
168 SceneGraph::UpdateManager& updateManager = services.GetUpdateManager();
169 AddShaderMessage(updateManager, transferOwnership);
171 services.RegisterObject(shader.Get());
172 shader->SetShaderProperty(shaderMap);
177 const SceneGraph::Shader& Shader::GetShaderSceneObject() const
179 return static_cast<const SceneGraph::Shader&>(GetSceneObject());
182 void Shader::SetDefaultProperty(Property::Index index, const Property::Value& propertyValue)
186 case Dali::Shader::Property::PROGRAM:
188 SetShaderProperty(propertyValue);
194 Property::Value Shader::GetDefaultProperty(Property::Index index) const
196 Property::Value value;
200 case Dali::Shader::Property::PROGRAM:
202 if(mShaderDataList.size() == 1u)
204 Dali::Property::Map map;
205 map["vertex"] = Property::Value(mShaderDataList.front()->GetVertexShader());
206 map["fragment"] = Property::Value(mShaderDataList.front()->GetFragmentShader());
207 map["renderPassTag"] = Property::Value(static_cast<int32_t>(mShaderDataList.front()->GetRenderPassTag()));
208 map["hints"] = HintString(mShaderDataList.front()->GetHints());
209 map["name"] = Property::Value(mShaderDataList.front()->GetName());
214 Dali::Property::Array array;
215 for(auto&& shaderData : mShaderDataList)
219 Dali::Property::Map map;
220 map["vertex"] = Property::Value(shaderData->GetVertexShader());
221 map["fragment"] = Property::Value(shaderData->GetFragmentShader());
222 map["renderPassTag"] = Property::Value(static_cast<int32_t>(shaderData->GetRenderPassTag()));
223 map["hints"] = HintString(shaderData->GetHints());
224 map["name"] = Property::Value(shaderData->GetName());
237 Property::Value Shader::GetDefaultPropertyCurrentValue(Property::Index index) const
239 return GetDefaultProperty(index); // Event-side only properties
242 Shader::Shader(const SceneGraph::Shader* sceneObject)
243 : Object(sceneObject)
247 void Shader::UpdateShaderData(std::string_view vertexSource,
248 std::string_view fragmentSource,
249 uint32_t renderPassTag,
250 Dali::Shader::Hint::Value hints,
251 std::string_view name)
253 // Try to load a pre-compiled shader binary for the source pair:
254 ThreadLocalStorage& tls = ThreadLocalStorage::Get();
255 ShaderFactory& shaderFactory = tls.GetShaderFactory();
257 Internal::ShaderDataPtr shaderData = shaderFactory.Load(vertexSource, fragmentSource, hints, renderPassTag, name, shaderHash);
259 std::vector<Internal::ShaderDataPtr>::iterator shaderDataIterator = std::find_if(mShaderDataList.begin(), mShaderDataList.end(), [&shaderData](const Internal::ShaderDataPtr& shaderDataItem) { return shaderDataItem->GetRenderPassTag() == shaderData->GetRenderPassTag(); });
260 if(shaderDataIterator != mShaderDataList.end())
262 *shaderDataIterator = shaderData;
266 mShaderDataList.push_back(shaderData);
269 // Add shader data to scene-object
270 SceneGraph::UpdateShaderDataMessage(GetEventThreadServices(), GetShaderSceneObject(), shaderData);
273 void Shader::SetShaderProperty(const Dali::Property::Value& shaderMap)
275 if(shaderMap.GetType() == Property::MAP)
277 const Dali::Property::Map* map = shaderMap.GetMap();
281 std::string fragment;
282 uint32_t renderPassTag{DEFAULT_RENDER_PASS_TAG};
283 Dali::Shader::Hint::Value hints(Dali::Shader::Hint::NONE);
284 std::string name(DEFAULT_SHADER_NAME);
285 GetShaderData(*map, vertex, fragment, renderPassTag, hints, name);
287 UpdateShaderData(vertex, fragment, renderPassTag, hints, name);
290 else if(shaderMap.GetType() == Property::ARRAY)
292 const Dali::Property::Array* array = shaderMap.GetArray();
295 uint32_t arraySize = array->Count();
296 for(uint32_t i = 0; i < arraySize; ++i)
298 const Dali::Property::Map* map = array->GetElementAt(i).GetMap();
302 std::string fragment;
303 uint32_t renderPassTag{DEFAULT_RENDER_PASS_TAG};
304 Dali::Shader::Hint::Value hints(Dali::Shader::Hint::NONE);
305 std::string name(DEFAULT_SHADER_NAME);
306 GetShaderData(*map, vertex, fragment, renderPassTag, hints, name);
308 UpdateShaderData(vertex, fragment, renderPassTag, hints, name);
315 DALI_LOG_ERROR("Shader program property should be a map or array of map.\n");
321 if(EventThreadServices::IsCoreRunning())
323 EventThreadServices& eventThreadServices = GetEventThreadServices();
324 SceneGraph::UpdateManager& updateManager = eventThreadServices.GetUpdateManager();
325 RemoveShaderMessage(updateManager, &GetShaderSceneObject());
327 eventThreadServices.UnregisterObject(this);
331 uint32_t Shader::GetShaderLanguageVersion()
333 Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get();
334 return tls.GetShaderLanguageVersion();
337 std::string Shader::GetShaderVersionPrefix()
339 Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get();
340 return tls.GetShaderVersionPrefix();
343 std::string Shader::GetVertexShaderPrefix()
345 Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get();
346 return tls.GetVertexShaderPrefix();
349 std::string Shader::GetFragmentShaderPrefix()
351 Dali::Internal::ThreadLocalStorage& tls = Dali::Internal::ThreadLocalStorage::Get();
352 return tls.GetFragmentShaderPrefix();
355 } // namespace Internal