2 * Copyright (c) 2023 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-scene3d/public-api/loader/shader-definition.h>
22 #include <dali/public-api/object/property-array.h>
26 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
27 #include <dali-scene3d/public-api/loader/utils.h>
29 #include <dali/integration-api/debug.h>
33 #if defined(DEBUG_ENABLED)
34 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_MODEL_SHADER_DEFINITION");
38 namespace Dali::Scene3D::Loader
42 const char* SHADER_HINT_OUTPUT_IS_TRANSPARENT("OUTPUT_IS_TRANSPARENT"); ///< Might generate transparent alpha from opaque inputs.
43 const char* SHADER_HINT_MODIFIES_GEOMETRY("MODIFIES_GEOMETRY"); ///< Might change position of vertices, this option disables any culling optimizations.
46 ShaderDefinition::ShaderDefinition(const ShaderDefinition& other)
47 : mRendererState(other.mRendererState),
48 mVertexShaderPath(other.mVertexShaderPath),
49 mFragmentShaderPath(other.mFragmentShaderPath),
50 mDefines(other.mDefines),
52 mUniforms(other.mUniforms),
53 mUseBuiltInShader(other.mUseBuiltInShader)
57 void ApplyDefine(std::string& shaderCode, const std::string& definevar)
59 const std::string IF_1 = "#if 1";
61 std::size_t found = shaderCode.find(definevar);
62 while(found != std::string::npos)
64 // Greater then "@" character means is a letter,
65 // therefore is not has the definevar we looking for.
66 if((found + definevar.length()) < shaderCode.length() && shaderCode.at(found + definevar.length()) > '@')
68 found = shaderCode.find(definevar, found + definevar.length());
71 if(found > 0u && shaderCode.at(found - 1) > '@')
73 found = shaderCode.find(definevar, found + definevar.length());
77 std::size_t defidx = shaderCode.rfind("#ifdef", found);
78 std::size_t newlineidx = shaderCode.rfind("\n", found);
79 if(newlineidx < defidx && defidx != std::string::npos)
81 shaderCode.replace(defidx, found - defidx + definevar.length(), IF_1);
82 found = defidx + IF_1.length();
86 found += definevar.length();
88 found = shaderCode.find(definevar, found);
92 void RedefineMacro(std::string& shaderCode, const std::string& macro, const std::string& value)
96 std::string definition = "#define " + macro;
97 std::size_t found = shaderCode.find(definition);
98 if(found != std::string::npos)
100 std::size_t insertionPoint = found + definition.length();
102 // Automatically insert line-continuation character into value
104 std::sregex_token_iterator first{value.begin(), value.end(), re, -1}, last;
105 for(auto i = first; i != last; ++i)
107 std::string line = std::string(" \\\n") + (*i).str();
108 shaderCode.insert(insertionPoint, line);
109 insertionPoint += line.length();
115 std::size_t invocation = shaderCode.rfind(macro);
116 if(invocation != std::string::npos)
118 std::size_t start = shaderCode.rfind("\n", invocation);
119 std::size_t end = shaderCode.find("\n", invocation);
120 shaderCode.erase(start, end - start);
125 ShaderDefinition::RawData
126 ShaderDefinition::LoadRaw(const std::string& shadersPath) const
131 if(!mUseBuiltInShader)
133 raw.mVertexShaderSource = LoadTextFile((shadersPath + mVertexShaderPath).c_str(), &fail);
136 raw.mFragmentShaderSource = LoadTextFile((shadersPath + mFragmentShaderPath).c_str(), &fail);
139 ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mFragmentShaderPath << "'.";
144 ExceptionFlinger(ASSERT_LOCATION) << "Failed to load shader source from '" << shadersPath + mVertexShaderPath << "'.";
149 raw.mVertexShaderSource = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_VERT.data();
150 raw.mFragmentShaderSource = SHADER_DEFAULT_PHYSICALLY_BASED_SHADER_FRAG.data();
151 raw.mShadowVertexShaderSource = SHADER_SHADOW_MAP_SHADER_VERT.data();
152 raw.mShadowFragmentShaderSource = SHADER_SHADOW_MAP_SHADER_FRAG.data();
157 for(const auto& definevar : mDefines)
159 ApplyDefine(raw.mVertexShaderSource, definevar);
160 ApplyDefine(raw.mFragmentShaderSource, definevar);
161 ApplyDefine(raw.mShadowVertexShaderSource, definevar);
163 for(const auto& macroDef : mMacros)
165 RedefineMacro(raw.mVertexShaderSource, macroDef.macro, macroDef.definition);
166 RedefineMacro(raw.mFragmentShaderSource, macroDef.macro, macroDef.definition);
167 RedefineMacro(raw.mShadowVertexShaderSource, macroDef.macro, macroDef.definition);
174 Shader ShaderDefinition::Load(RawData&& raw) const
176 uint32_t hints = Shader::Hint::NONE;
177 for(const auto& hint : mHints)
179 if(hint == SHADER_HINT_OUTPUT_IS_TRANSPARENT)
181 hints |= Shader::Hint::OUTPUT_IS_TRANSPARENT;
183 else if(hint == SHADER_HINT_MODIFIES_GEOMETRY)
185 hints |= Shader::Hint::MODIFIES_GEOMETRY;
189 Property::Map map[2];
190 map[0]["vertex"] = raw.mVertexShaderSource;
191 map[0]["fragment"] = raw.mFragmentShaderSource;
192 map[0]["renderPassTag"] = 0;
193 map[0]["hints"] = static_cast<Shader::Hint::Value>(hints);
195 map[1]["vertex"] = raw.mShadowVertexShaderSource;
196 map[1]["fragment"] = raw.mShadowFragmentShaderSource;
197 map[1]["renderPassTag"] = 10;
199 Property::Array array;
200 array.PushBack(map[0]);
201 array.PushBack(map[1]);
203 DALI_LOG_INFO(gLogFilter, Debug::Verbose, "Vert Shader src: \n%s\n", raw.mVertexShaderSource.c_str());
204 Shader shader = Shader::New(array);
205 for(Property::Map::SizeType i0 = 0, i1 = mUniforms.Count(); i0 != i1; ++i0)
207 auto pair = mUniforms.GetKeyValue(i0);
208 DALI_ASSERT_ALWAYS(pair.first.type == Property::Key::STRING);
209 shader.RegisterProperty(pair.first.stringKey, pair.second);
215 } // namespace Dali::Scene3D::Loader