Simplified uniform write
[platform/core/uifw/dali-core.git] / dali / internal / render / shaders / program.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/render/shaders/program.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstring>
23 #include <map>
24
25 // INTERNAL INCLUDES
26 #include <dali/devel-api/common/hash.h>
27 #include <dali/graphics-api/graphics-controller.h>
28 #include <dali/graphics-api/graphics-program.h>
29 #include <dali/graphics-api/graphics-reflection.h>
30 #include <dali/integration-api/debug.h>
31 #include <dali/internal/common/shader-data.h>
32 #include <dali/internal/render/common/performance-monitor.h>
33 #include <dali/internal/render/shaders/program-cache.h>
34 #include <dali/public-api/common/constants.h>
35 #include <dali/public-api/common/dali-common.h>
36 #include <dali/public-api/common/dali-vector.h>
37
38 namespace Dali
39 {
40 namespace Internal
41 {
42 // LOCAL STUFF
43 namespace
44 {
45 const unsigned int NUMBER_OF_DEFAULT_UNIFORMS = static_cast<unsigned int>(Program::DefaultUniformIndex::COUNT);
46
47 /**
48  * List of all default uniforms used for quicker lookup
49  */
50 size_t DEFAULT_UNIFORM_HASHTABLE[NUMBER_OF_DEFAULT_UNIFORMS] =
51   {
52     CalculateHash(std::string("uModelMatrix")),
53     CalculateHash(std::string("uMvpMatrix")),
54     CalculateHash(std::string("uViewMatrix")),
55     CalculateHash(std::string("uModelView")),
56     CalculateHash(std::string("uNormalMatrix")),
57     CalculateHash(std::string("uProjection")),
58     CalculateHash(std::string("uSize")),
59     CalculateHash(std::string("uColor"))};
60
61 /**
62  * Helper function to calculate the correct alignment of data for uniform buffers
63  * @param dataSize size of uniform buffer
64  * @return aligned offset of data
65  */
66 inline uint32_t GetUniformBufferDataAlignment(uint32_t dataSize)
67 {
68   return ((dataSize / 256u) + ((dataSize % 256u) ? 1u : 0u)) * 256u;
69 }
70
71 } // namespace
72
73 // IMPLEMENTATION
74
75 Program* Program::New(ProgramCache& cache, Internal::ShaderDataPtr shaderData, Graphics::Controller& gfxController, Graphics::UniquePtr<Graphics::Program>&& gfxProgram)
76 {
77   uint32_t programId{0u};
78
79   // Get program id and use it as hash for the cache
80   // in order to maintain current functionality as long as needed
81   gfxController.GetProgramParameter(*gfxProgram, 1, &programId);
82
83   size_t shaderHash = programId;
84
85   Program* program = cache.GetProgram(shaderHash);
86
87   if(nullptr == program)
88   {
89     // program not found so create it
90     program = new Program(cache, shaderData, gfxController, std::move(gfxProgram));
91     cache.AddProgram(shaderHash, program);
92   }
93
94   return program;
95 }
96
97 Program::Program(ProgramCache& cache, Internal::ShaderDataPtr shaderData, Graphics::Controller& controller, Graphics::UniquePtr<Graphics::Program>&& gfxProgram)
98 : mCache(cache),
99   mProjectionMatrix(nullptr),
100   mViewMatrix(nullptr),
101   mGfxProgram(std::move(gfxProgram)),
102   mGfxController(controller),
103   mProgramData(shaderData)
104 {
105   BuildReflection(controller.GetProgramReflection(*mGfxProgram.get()));
106 }
107
108 Program::~Program() = default;
109
110 void Program::BuildReflection(const Graphics::Reflection& graphicsReflection)
111 {
112   mReflectionDefaultUniforms.clear();
113   mReflectionDefaultUniforms.resize(NUMBER_OF_DEFAULT_UNIFORMS);
114
115   auto uniformBlockCount = graphicsReflection.GetUniformBlockCount();
116
117   // add uniform block fields
118   for(auto i = 0u; i < uniformBlockCount; ++i)
119   {
120     Graphics::UniformBlockInfo uboInfo;
121     graphicsReflection.GetUniformBlock(i, uboInfo);
122
123     // for each member store data
124     for(const auto& item : uboInfo.members)
125     {
126       auto hashValue = CalculateHash(item.name);
127       mReflection.emplace_back(ReflectionUniformInfo{hashValue, false, item});
128
129       // update buffer index
130       mReflection.back().uniformInfo.bufferIndex = i;
131
132       // Update default uniforms
133       for(auto j = 0u; j < NUMBER_OF_DEFAULT_UNIFORMS; ++j)
134       {
135         if(hashValue == DEFAULT_UNIFORM_HASHTABLE[j])
136         {
137           mReflectionDefaultUniforms[j] = mReflection.back();
138           break;
139         }
140       }
141     }
142   }
143
144   // add samplers
145   auto samplers = graphicsReflection.GetSamplers();
146   for(const auto& sampler : samplers)
147   {
148     mReflection.emplace_back(ReflectionUniformInfo{CalculateHash(sampler.name), false, sampler});
149   }
150
151   // check for potential collisions
152   std::map<size_t, bool> hashTest;
153   bool                   hasCollisions(false);
154   for(auto&& item : mReflection)
155   {
156     if(hashTest.find(item.hashValue) == hashTest.end())
157     {
158       hashTest[item.hashValue] = false;
159     }
160     else
161     {
162       hashTest[item.hashValue] = true;
163       hasCollisions            = true;
164     }
165   }
166
167   // update collision flag for further use
168   if(hasCollisions)
169   {
170     for(auto&& item : mReflection)
171     {
172       item.hasCollision = hashTest[item.hashValue];
173     }
174   }
175
176   // Calculate size of memory for uniform blocks
177   mUniformBlockRequirements.totalSizeRequired = 0;
178   mUniformBlockRequirements.blockCount = graphicsReflection.GetUniformBlockCount();
179   for (auto i = 0u; i < mUniformBlockRequirements.blockCount; ++i)
180   {
181     auto blockSize = GetUniformBufferDataAlignment(graphicsReflection.GetUniformBlockSize(i));
182     mUniformBlockRequirements.totalSizeRequired += blockSize;
183   }
184 }
185
186 bool Program::GetUniform(const std::string& name, size_t hashedName, Graphics::UniformInfo& out) const
187 {
188   if(mReflection.empty())
189   {
190     return false;
191   }
192
193   hashedName = !hashedName ? CalculateHash(name, '[') : hashedName;
194
195   for(const ReflectionUniformInfo& item : mReflection)
196   {
197     if(item.hashValue == hashedName)
198     {
199       if(!item.hasCollision || item.uniformInfo.name == name)
200       {
201         out = item.uniformInfo;
202         return true;
203       }
204       else
205       {
206         return false;
207       }
208     }
209   }
210   return false;
211 }
212
213 const Graphics::UniformInfo* Program::GetDefaultUniform(DefaultUniformIndex defaultUniformIndex) const
214 {
215   if(mReflectionDefaultUniforms.empty())
216   {
217     return nullptr;
218   }
219
220   const auto value = &mReflectionDefaultUniforms[static_cast<uint32_t>(defaultUniformIndex)];
221   return &value->uniformInfo;
222 }
223
224 } // namespace Internal
225
226 } // namespace Dali