Add Default Uniform : uActorColor
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / pipeline-cache.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 // CLASS HEADER
18 #include <dali/internal/render/renderers/pipeline-cache.h>
19
20 // INTERNAL INCLUDES
21 #include <dali/internal/render/renderers/render-renderer.h>
22 #include <dali/graphics-api/graphics-types.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/internal/render/common/render-instruction.h>
25 #include <dali/internal/render/renderers/render-vertex-buffer.h>
26 #include <dali/internal/render/shaders/program.h>
27
28 namespace Dali::Internal::Render
29 {
30 namespace
31 {
32 // Helper to get the vertex input format
33 Dali::Graphics::VertexInputFormat GetPropertyVertexFormat(Property::Type propertyType)
34 {
35   Dali::Graphics::VertexInputFormat type{};
36
37   switch (propertyType)
38   {
39     case Property::BOOLEAN:
40     {
41       type = Dali::Graphics::VertexInputFormat::UNDEFINED; // type = GL_BYTE; @todo new type for this?
42       break;
43     }
44     case Property::INTEGER:
45     {
46       type = Dali::Graphics::VertexInputFormat::INTEGER; // (short)
47       break;
48     }
49     case Property::FLOAT:
50     {
51       type = Dali::Graphics::VertexInputFormat::FLOAT;
52       break;
53     }
54     case Property::VECTOR2:
55     {
56       type = Dali::Graphics::VertexInputFormat::FVECTOR2;
57       break;
58     }
59     case Property::VECTOR3:
60     {
61       type = Dali::Graphics::VertexInputFormat::FVECTOR3;
62       break;
63     }
64     case Property::VECTOR4:
65     {
66       type = Dali::Graphics::VertexInputFormat::FVECTOR4;
67       break;
68     }
69     default:
70     {
71       type = Dali::Graphics::VertexInputFormat::UNDEFINED;
72     }
73   }
74
75   return type;
76 }
77
78 constexpr Graphics::CullMode ConvertCullFace(Dali::FaceCullingMode::Type mode)
79 {
80   switch (mode)
81   {
82     case Dali::FaceCullingMode::NONE:
83     {
84       return Graphics::CullMode::NONE;
85     }
86     case Dali::FaceCullingMode::FRONT:
87     {
88       return Graphics::CullMode::FRONT;
89     }
90     case Dali::FaceCullingMode::BACK:
91     {
92       return Graphics::CullMode::BACK;
93     }
94     case Dali::FaceCullingMode::FRONT_AND_BACK:
95     {
96       return Graphics::CullMode::FRONT_AND_BACK;
97     }
98     default:
99     {
100       return Graphics::CullMode::NONE;
101     }
102   }
103 }
104
105 constexpr Graphics::BlendFactor ConvertBlendFactor(BlendFactor::Type blendFactor)
106 {
107   switch (blendFactor)
108   {
109     case BlendFactor::ZERO:
110       return Graphics::BlendFactor::ZERO;
111     case BlendFactor::ONE:
112       return Graphics::BlendFactor::ONE;
113     case BlendFactor::SRC_COLOR:
114       return Graphics::BlendFactor::SRC_COLOR;
115     case BlendFactor::ONE_MINUS_SRC_COLOR:
116       return Graphics::BlendFactor::ONE_MINUS_SRC_COLOR;
117     case BlendFactor::SRC_ALPHA:
118       return Graphics::BlendFactor::SRC_ALPHA;
119     case BlendFactor::ONE_MINUS_SRC_ALPHA:
120       return Graphics::BlendFactor::ONE_MINUS_SRC_ALPHA;
121     case BlendFactor::DST_ALPHA:
122       return Graphics::BlendFactor::DST_ALPHA;
123     case BlendFactor::ONE_MINUS_DST_ALPHA:
124       return Graphics::BlendFactor::ONE_MINUS_DST_ALPHA;
125     case BlendFactor::DST_COLOR:
126       return Graphics::BlendFactor::DST_COLOR;
127     case BlendFactor::ONE_MINUS_DST_COLOR:
128       return Graphics::BlendFactor::ONE_MINUS_DST_COLOR;
129     case BlendFactor::SRC_ALPHA_SATURATE:
130       return Graphics::BlendFactor::SRC_ALPHA_SATURATE;
131     case BlendFactor::CONSTANT_COLOR:
132       return Graphics::BlendFactor::CONSTANT_COLOR;
133     case BlendFactor::ONE_MINUS_CONSTANT_COLOR:
134       return Graphics::BlendFactor::ONE_MINUS_CONSTANT_COLOR;
135     case BlendFactor::CONSTANT_ALPHA:
136       return Graphics::BlendFactor::CONSTANT_ALPHA;
137     case BlendFactor::ONE_MINUS_CONSTANT_ALPHA:
138       return Graphics::BlendFactor::ONE_MINUS_CONSTANT_ALPHA;
139     default:
140       return Graphics::BlendFactor();
141   }
142 }
143
144 constexpr Graphics::BlendOp ConvertBlendEquation(DevelBlendEquation::Type blendEquation)
145 {
146   switch (blendEquation)
147   {
148     case DevelBlendEquation::ADD:
149       return Graphics::BlendOp::ADD;
150     case DevelBlendEquation::SUBTRACT:
151       return Graphics::BlendOp::SUBTRACT;
152     case DevelBlendEquation::REVERSE_SUBTRACT:
153       return Graphics::BlendOp::REVERSE_SUBTRACT;
154     case DevelBlendEquation::COLOR:
155     case DevelBlendEquation::COLOR_BURN:
156     case DevelBlendEquation::COLOR_DODGE:
157     case DevelBlendEquation::DARKEN:
158     case DevelBlendEquation::DIFFERENCE:
159     case DevelBlendEquation::EXCLUSION:
160     case DevelBlendEquation::HARD_LIGHT:
161     case DevelBlendEquation::HUE:
162     case DevelBlendEquation::LIGHTEN:
163     case DevelBlendEquation::LUMINOSITY:
164     case DevelBlendEquation::MAX:
165     case DevelBlendEquation::MIN:
166     case DevelBlendEquation::MULTIPLY:
167     case DevelBlendEquation::OVERLAY:
168     case DevelBlendEquation::SATURATION:
169     case DevelBlendEquation::SCREEN:
170     case DevelBlendEquation::SOFT_LIGHT:
171       return Graphics::BlendOp{};
172   }
173   return Graphics::BlendOp{};
174 }
175 }
176
177
178 PipelineCacheL0 *PipelineCache::GetPipelineCacheL0(Program *program, Render::Geometry *geometry)
179 {
180   auto it = std::find_if(level0nodes.begin(), level0nodes.end(), [program, geometry](
181     PipelineCacheL0 &item)
182   {
183     return ((item.program == program && item.geometry == geometry));
184   });
185
186   std::vector<int32_t> attributeLocations;
187
188   // Add new node to cache
189   if (it == level0nodes.end())
190   {
191     uint32_t bindingIndex{0u};
192     auto     &reflection            = graphicsController->GetProgramReflection(program->GetGraphicsProgram());
193
194     Graphics::VertexInputState vertexInputState{};
195     uint32_t                   base = 0;
196
197     for (auto &&vertexBuffer : geometry->GetVertexBuffers())
198     {
199       const VertexBuffer::Format &vertexFormat = *vertexBuffer->GetFormat();
200
201       vertexInputState.bufferBindings.emplace_back(vertexFormat.size, // stride
202                                                    Graphics::VertexInputRate::PER_VERTEX);
203
204       const uint32_t attributeCount = vertexBuffer->GetAttributeCount();
205       for (uint32_t  i              = 0; i < attributeCount; ++i)
206       {
207         auto    attributeName = vertexBuffer->GetAttributeName(i);
208         int32_t pLocation     = reflection.GetVertexAttributeLocation(std::string(attributeName.GetStringView()));
209         if (-1 == pLocation)
210         {
211           DALI_LOG_WARNING("Attribute not found in the shader: %s\n", attributeName.GetCString());
212         }
213         attributeLocations.emplace_back(pLocation);
214
215         auto location = static_cast<uint32_t>(attributeLocations[base + i]);
216
217         vertexInputState.attributes.emplace_back(location,
218                                                  bindingIndex,
219                                                  vertexFormat.components[i].offset,
220                                                  GetPropertyVertexFormat(vertexFormat.components[i].type));
221       }
222       base += attributeCount;
223       ++bindingIndex;
224     }
225     PipelineCacheL0 level0;
226     level0.program    = program;
227     level0.geometry   = geometry;
228     level0.inputState = vertexInputState;
229     level0nodes.emplace_back(std::move(level0));
230     it = level0nodes.end() - 1;
231   }
232
233   return &*it;
234 }
235
236 PipelineCacheL1 *PipelineCacheL0::GetPipelineCacheL1(Render::Renderer *renderer, bool usingReflection)
237 {
238   // hash must be collision free
239   uint32_t hash = 0;
240   auto     topo = (uint32_t(geometry->GetTopology()) & 0xffu);
241   auto     cull = (uint32_t(renderer->GetFaceCullMode()) & 0xffu);
242
243   static const Graphics::PolygonMode polyTable[] = {
244     Graphics::PolygonMode::POINT,
245     Graphics::PolygonMode::LINE,
246     Graphics::PolygonMode::LINE,
247     Graphics::PolygonMode::LINE,
248     Graphics::PolygonMode::FILL,
249     Graphics::PolygonMode::FILL,
250     Graphics::PolygonMode::FILL
251   };
252
253   auto poly = polyTable[topo];
254
255   static const FaceCullingMode::Type adjFaceCullingMode[4] =
256                                        {
257                                          FaceCullingMode::NONE,
258                                          FaceCullingMode::BACK,
259                                          FaceCullingMode::FRONT,
260                                          FaceCullingMode::FRONT_AND_BACK,
261                                        };
262
263   static const FaceCullingMode::Type normalFaceCullingMode[4] =
264                                        {
265                                          FaceCullingMode::NONE,
266                                          FaceCullingMode::FRONT,
267                                          FaceCullingMode::BACK,
268                                          FaceCullingMode::FRONT_AND_BACK,
269                                        };
270
271   static const FaceCullingMode::Type *cullModeTable[2] = {
272     normalFaceCullingMode,
273     adjFaceCullingMode
274   };
275
276   // Retrieve cull mode
277   auto cullModeTableIndex = uint32_t(usingReflection) & 1u;
278   cull = cullModeTable[cullModeTableIndex][renderer->GetFaceCullMode()];
279
280   hash = (topo & 0xffu) | ((cull << 8u) & 0xff00u) | ((uint32_t(poly) << 16u) & 0xff0000u);
281
282   // If L1 not found by hash, create rasterization state describing pipeline and store it
283   auto it = std::find_if(level1nodes.begin(), level1nodes.end(),
284                          [hash](PipelineCacheL1 &item)
285                          {
286                            return item.hashCode == hash;
287                          });
288
289   PipelineCacheL1 *retval = nullptr;
290   if (it == level1nodes.end())
291   {
292     PipelineCacheL1 item;
293     item.hashCode       = hash;
294     item.rs.cullMode    = ConvertCullFace(FaceCullingMode::Type(cull));
295     item.rs.frontFace   = Graphics::FrontFace::COUNTER_CLOCKWISE;
296     item.rs.polygonMode = poly; // not in use
297     item.ia.topology    = geometry->GetTopology();
298     level1nodes.emplace_back(std::move(item));
299     retval = &level1nodes.back();
300   }
301   else
302   {
303     retval = &*it;
304   }
305   return retval;
306 }
307
308 PipelineCacheL2 *PipelineCacheL1::GetPipelineCacheL2(bool blend, bool premul, BlendingOptions &blendingOptions)
309 {
310   // early out
311   if (!blend)
312   {
313     if (noBlend.pipeline == nullptr)
314     {
315       // reset all before returning if pipeline has never been created for that case
316       noBlend.hash = 0;
317       memset(&noBlend.colorBlendState, 0, sizeof(Graphics::ColorBlendState));
318     }
319     return &noBlend;
320   }
321
322   auto bitmask = uint32_t(blendingOptions.GetBitmask());
323
324   // Find by bitmask (L2 entries must be sorted by bitmask)
325   auto it = std::find_if(level2nodes.begin(), level2nodes.end(), [bitmask](PipelineCacheL2 &item)
326   {
327     return item.hash == bitmask;
328   });
329
330   // TODO: find better way of blend constants lookup
331   PipelineCacheL2 *retval = nullptr;
332   if (it != level2nodes.end())
333   {
334     bool hasBlendColor = blendingOptions.GetBlendColor();
335     while(hasBlendColor && it != level2nodes.end() && (*it).hash == bitmask)
336     {
337       Vector4 v( it->colorBlendState.blendConstants );
338       if( v == *blendingOptions.GetBlendColor() )
339       {
340         retval = &*it;
341       }
342       ++it;
343     }
344     if(!hasBlendColor)
345     {
346       retval = &*it;
347     }
348   }
349
350   if (!retval)
351   {
352     // create new entry and return it with null pipeline
353     PipelineCacheL2 l2;
354     l2.pipeline = nullptr;
355     auto &colorBlendState = l2.colorBlendState;
356     colorBlendState.SetBlendEnable(true);
357     Graphics::BlendOp rgbOp   = ConvertBlendEquation(blendingOptions.GetBlendEquationRgb());
358     Graphics::BlendOp alphaOp = ConvertBlendEquation(blendingOptions.GetBlendEquationRgb());
359     if (blendingOptions.IsAdvancedBlendEquationApplied() && premul)
360     {
361       if (rgbOp != alphaOp)
362       {
363         DALI_LOG_ERROR("Advanced Blend Equation MUST be applied by using BlendEquation.\n");
364         alphaOp = rgbOp;
365       }
366     }
367
368     colorBlendState
369       .SetSrcColorBlendFactor(ConvertBlendFactor(blendingOptions.GetBlendSrcFactorRgb()))
370       .SetSrcAlphaBlendFactor(ConvertBlendFactor(blendingOptions.GetBlendSrcFactorAlpha()))
371       .SetDstColorBlendFactor(ConvertBlendFactor(blendingOptions.GetBlendDestFactorRgb()))
372       .SetDstAlphaBlendFactor(ConvertBlendFactor(blendingOptions.GetBlendDestFactorAlpha()))
373       .SetColorBlendOp(rgbOp)
374       .SetAlphaBlendOp(alphaOp);
375
376     // Blend color is optional and rarely used
377     auto *blendColor = const_cast<Vector4 *>(blendingOptions.GetBlendColor());
378     if (blendColor)
379     {
380       colorBlendState.SetBlendConstants(blendColor->AsFloat());
381     }
382
383     l2.hash = blendingOptions.GetBitmask();
384     level2nodes.emplace_back(std::move(l2));
385
386     std::sort(level2nodes.begin(), level2nodes.end(), [](PipelineCacheL2 &lhs, PipelineCacheL2 &rhs)
387     {
388       return lhs.hash < rhs.hash;
389     });
390
391     // run same function to retrieve retval
392     retval = GetPipelineCacheL2(blend, premul, blendingOptions);
393   }
394
395   return retval;
396 }
397
398 PipelineCache::PipelineCache(Graphics::Controller& controller) :
399 graphicsController(&controller)
400 {
401 }
402
403 PipelineResult PipelineCache::GetPipeline(const PipelineCacheQueryInfo &queryInfo, bool createNewIfNotFound)
404 {
405   auto *level0 = GetPipelineCacheL0(queryInfo.program, queryInfo.geometry);
406   auto *level1 = level0->GetPipelineCacheL1(queryInfo.renderer, queryInfo.cameraUsingReflection);
407   auto *level2 = level1->GetPipelineCacheL2(queryInfo.blendingEnabled, queryInfo.alphaPremultiplied, *queryInfo.blendingOptions);
408
409   // Create new pipeline at level2 if requested
410   if (level2->pipeline == nullptr && createNewIfNotFound)
411   {
412     Graphics::ProgramState programState{};
413     programState.program = &queryInfo.program->GetGraphicsProgram();
414     // Create the pipeline
415     Graphics::PipelineCreateInfo createInfo;
416     createInfo
417       .SetInputAssemblyState(&level1->ia)
418       .SetVertexInputState(&level0->inputState)
419       .SetRasterizationState(&level1->rs)
420       .SetColorBlendState(&level2->colorBlendState)
421       .SetProgramState(&programState);
422
423     // Store a pipeline per renderer per render (renderer can be owned by multiple nodes,
424     // and re-drawn in multiple instructions).
425     // @todo This is only needed because ColorBlend state can change. Fixme!
426     // This is ameliorated by the fact that implementation caches pipelines, and we're only storing
427     // handles.
428     level2->pipeline = graphicsController->CreatePipeline(createInfo, nullptr);
429   }
430
431   PipelineResult result{};
432
433   result.pipeline = level2->pipeline.get();
434   result.level0   = level0;
435   result.level1   = level1;
436   result.level2   = level2;
437
438   return result;
439 }
440
441 }