Restructure Render::Renderer
[platform/core/uifw/dali-core.git] / dali / internal / render / renderers / render-renderer.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/renderers/render-renderer.h>
20
21 // INTERNAL INCLUDES
22 #include <dali/graphics-api/graphics-program.h>
23 #include <dali/graphics-api/graphics-types.h>
24 #include <dali/internal/common/image-sampler.h>
25 #include <dali/internal/render/common/render-instruction.h>
26 #include <dali/internal/render/data-providers/node-data-provider.h>
27 #include <dali/internal/render/data-providers/uniform-map-data-provider.h>
28 #include <dali/internal/render/gl-resources/context.h>
29 #include <dali/internal/render/renderers/render-sampler.h>
30 #include <dali/internal/render/renderers/render-texture.h>
31 #include <dali/internal/render/renderers/render-vertex-buffer.h>
32 #include <dali/internal/render/renderers/shader-cache.h>
33 #include <dali/internal/render/shaders/program.h>
34 #include <dali/internal/render/shaders/scene-graph-shader.h>
35 #include <dali/internal/update/common/uniform-map.h>
36
37 namespace Dali
38 {
39 namespace Internal
40 {
41 namespace
42 {
43 // Size of uniform buffer page used when resizing
44 constexpr uint32_t UBO_PAGE_SIZE = 8192u;
45
46 // UBO allocation threshold below which the UBO will shrink
47 constexpr auto UBO_SHRINK_THRESHOLD = 0.75f;
48
49 // Helper to get the vertex input format
50 Dali::Graphics::VertexInputFormat GetPropertyVertexFormat(Property::Type propertyType)
51 {
52   Dali::Graphics::VertexInputFormat type{};
53
54   switch(propertyType)
55   {
56     case Property::NONE:
57     case Property::STRING:
58     case Property::ARRAY:
59     case Property::MAP:
60     case Property::EXTENTS:   // i4?
61     case Property::RECTANGLE: // i4/f4?
62     case Property::ROTATION:
63     {
64       type = Dali::Graphics::VertexInputFormat::UNDEFINED;
65       break;
66     }
67     case Property::BOOLEAN:
68     {
69       type = Dali::Graphics::VertexInputFormat::UNDEFINED; // type = GL_BYTE; @todo new type for this?
70       break;
71     }
72     case Property::INTEGER:
73     {
74       type = Dali::Graphics::VertexInputFormat::INTEGER; // (short)
75       break;
76     }
77     case Property::FLOAT:
78     {
79       type = Dali::Graphics::VertexInputFormat::FLOAT;
80       break;
81     }
82     case Property::VECTOR2:
83     {
84       type = Dali::Graphics::VertexInputFormat::FVECTOR2;
85       break;
86     }
87     case Property::VECTOR3:
88     {
89       type = Dali::Graphics::VertexInputFormat::FVECTOR3;
90       break;
91     }
92     case Property::VECTOR4:
93     {
94       type = Dali::Graphics::VertexInputFormat::FVECTOR4;
95       break;
96     }
97     case Property::MATRIX3:
98     {
99       type = Dali::Graphics::VertexInputFormat::FLOAT;
100       break;
101     }
102     case Property::MATRIX:
103     {
104       type = Dali::Graphics::VertexInputFormat::FLOAT;
105       break;
106     }
107   }
108
109   return type;
110 }
111
112 constexpr Graphics::CullMode ConvertCullFace(Dali::FaceCullingMode::Type mode)
113 {
114   switch(mode)
115   {
116     case Dali::FaceCullingMode::NONE:
117     {
118       return Graphics::CullMode::NONE;
119     }
120     case Dali::FaceCullingMode::FRONT:
121     {
122       return Graphics::CullMode::FRONT;
123     }
124     case Dali::FaceCullingMode::BACK:
125     {
126       return Graphics::CullMode::BACK;
127     }
128     case Dali::FaceCullingMode::FRONT_AND_BACK:
129     {
130       return Graphics::CullMode::FRONT_AND_BACK;
131     }
132   }
133   return Graphics::CullMode::NONE;
134 }
135
136 constexpr Graphics::BlendFactor ConvertBlendFactor(BlendFactor::Type blendFactor)
137 {
138   switch(blendFactor)
139   {
140     case BlendFactor::ZERO:
141       return Graphics::BlendFactor::ZERO;
142     case BlendFactor::ONE:
143       return Graphics::BlendFactor::ONE;
144     case BlendFactor::SRC_COLOR:
145       return Graphics::BlendFactor::SRC_COLOR;
146     case BlendFactor::ONE_MINUS_SRC_COLOR:
147       return Graphics::BlendFactor::ONE_MINUS_SRC_COLOR;
148     case BlendFactor::SRC_ALPHA:
149       return Graphics::BlendFactor::SRC_ALPHA;
150     case BlendFactor::ONE_MINUS_SRC_ALPHA:
151       return Graphics::BlendFactor::ONE_MINUS_SRC_ALPHA;
152     case BlendFactor::DST_ALPHA:
153       return Graphics::BlendFactor::DST_ALPHA;
154     case BlendFactor::ONE_MINUS_DST_ALPHA:
155       return Graphics::BlendFactor::ONE_MINUS_DST_ALPHA;
156     case BlendFactor::DST_COLOR:
157       return Graphics::BlendFactor::DST_COLOR;
158     case BlendFactor::ONE_MINUS_DST_COLOR:
159       return Graphics::BlendFactor::ONE_MINUS_DST_COLOR;
160     case BlendFactor::SRC_ALPHA_SATURATE:
161       return Graphics::BlendFactor::SRC_ALPHA_SATURATE;
162     case BlendFactor::CONSTANT_COLOR:
163       return Graphics::BlendFactor::CONSTANT_COLOR;
164     case BlendFactor::ONE_MINUS_CONSTANT_COLOR:
165       return Graphics::BlendFactor::ONE_MINUS_CONSTANT_COLOR;
166     case BlendFactor::CONSTANT_ALPHA:
167       return Graphics::BlendFactor::CONSTANT_ALPHA;
168     case BlendFactor::ONE_MINUS_CONSTANT_ALPHA:
169       return Graphics::BlendFactor::ONE_MINUS_CONSTANT_ALPHA;
170   }
171   return Graphics::BlendFactor{};
172 }
173
174 constexpr Graphics::BlendOp ConvertBlendEquation(DevelBlendEquation::Type blendEquation)
175 {
176   switch(blendEquation)
177   {
178     case DevelBlendEquation::ADD:
179       return Graphics::BlendOp::ADD;
180     case DevelBlendEquation::SUBTRACT:
181       return Graphics::BlendOp::SUBTRACT;
182     case DevelBlendEquation::REVERSE_SUBTRACT:
183       return Graphics::BlendOp::REVERSE_SUBTRACT;
184     case DevelBlendEquation::COLOR:
185     case DevelBlendEquation::COLOR_BURN:
186     case DevelBlendEquation::COLOR_DODGE:
187     case DevelBlendEquation::DARKEN:
188     case DevelBlendEquation::DIFFERENCE:
189     case DevelBlendEquation::EXCLUSION:
190     case DevelBlendEquation::HARD_LIGHT:
191     case DevelBlendEquation::HUE:
192     case DevelBlendEquation::LIGHTEN:
193     case DevelBlendEquation::LUMINOSITY:
194     case DevelBlendEquation::MAX:
195     case DevelBlendEquation::MIN:
196     case DevelBlendEquation::MULTIPLY:
197     case DevelBlendEquation::OVERLAY:
198     case DevelBlendEquation::SATURATION:
199     case DevelBlendEquation::SCREEN:
200     case DevelBlendEquation::SOFT_LIGHT:
201       return Graphics::BlendOp{};
202   }
203   return Graphics::BlendOp{};
204 }
205
206 /**
207  * Helper function to calculate the correct alignment of data for uniform buffers
208  * @param dataSize size of uniform buffer
209  * @return aligned offset of data
210  */
211 inline uint32_t GetUniformBufferDataAlignment(uint32_t dataSize)
212 {
213   return ((dataSize / 256u) + ((dataSize % 256u) ? 1u : 0u)) * 256u;
214 }
215
216 } // namespace
217
218 namespace Render
219 {
220 Renderer* Renderer::New(SceneGraph::RenderDataProvider* dataProvider,
221                         Render::Geometry*               geometry,
222                         uint32_t                        blendingBitmask,
223                         const Vector4&                  blendColor,
224                         FaceCullingMode::Type           faceCullingMode,
225                         bool                            preMultipliedAlphaEnabled,
226                         DepthWriteMode::Type            depthWriteMode,
227                         DepthTestMode::Type             depthTestMode,
228                         DepthFunction::Type             depthFunction,
229                         StencilParameters&              stencilParameters)
230 {
231   return new Renderer(dataProvider, geometry, blendingBitmask, blendColor, faceCullingMode, preMultipliedAlphaEnabled, depthWriteMode, depthTestMode, depthFunction, stencilParameters);
232 }
233
234 Renderer::Renderer(SceneGraph::RenderDataProvider* dataProvider,
235                    Render::Geometry*               geometry,
236                    uint32_t                        blendingBitmask,
237                    const Vector4&                  blendColor,
238                    FaceCullingMode::Type           faceCullingMode,
239                    bool                            preMultipliedAlphaEnabled,
240                    DepthWriteMode::Type            depthWriteMode,
241                    DepthTestMode::Type             depthTestMode,
242                    DepthFunction::Type             depthFunction,
243                    StencilParameters&              stencilParameters)
244 : mRenderDataProvider(dataProvider),
245   mContext(nullptr),
246   mGeometry(geometry),
247   mProgramCache(nullptr),
248   mUniformIndexMap(),
249   mAttributeLocations(),
250   mUniformsHash(),
251   mStencilParameters(stencilParameters),
252   mBlendingOptions(),
253   mIndexedDrawFirstElement(0),
254   mIndexedDrawElementsCount(0),
255   mDepthFunction(depthFunction),
256   mFaceCullingMode(faceCullingMode),
257   mDepthWriteMode(depthWriteMode),
258   mDepthTestMode(depthTestMode),
259   mUpdateAttributeLocations(true),
260   mPremultipledAlphaEnabled(preMultipliedAlphaEnabled),
261   mShaderChanged(false),
262   mUpdated(true)
263 {
264   if(blendingBitmask != 0u)
265   {
266     mBlendingOptions.SetBitmask(blendingBitmask);
267   }
268
269   mBlendingOptions.SetBlendColor(blendColor);
270 }
271
272 void Renderer::Initialize(Context& context, Graphics::Controller& graphicsController, ProgramCache& programCache, Render::ShaderCache& shaderCache, Render::UniformBufferManager& uniformBufferManager)
273 {
274   mContext              = &context;
275   mGraphicsController   = &graphicsController;
276   mProgramCache         = &programCache;
277   mShaderCache          = &shaderCache;
278   mUniformBufferManager = &uniformBufferManager;
279 }
280
281 Renderer::~Renderer() = default;
282
283 void Renderer::SetGeometry(Render::Geometry* geometry)
284 {
285   mGeometry                 = geometry;
286   mUpdateAttributeLocations = true;
287 }
288 void Renderer::SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands, uint32_t size)
289 {
290   mDrawCommands.clear();
291   mDrawCommands.insert(mDrawCommands.end(), pDrawCommands, pDrawCommands + size);
292 }
293
294 void Renderer::GlContextDestroyed()
295 {
296   mGeometry->GlContextDestroyed();
297 }
298
299 void Renderer::GlCleanup()
300 {
301 }
302
303 void Renderer::SetUniformFromProperty(BufferIndex bufferIndex, Program& program, UniformIndexMap& map)
304 {
305   GLint location = program.GetUniformLocation(map.uniformIndex);
306   if(Program::UNIFORM_UNKNOWN != location)
307   {
308     // switch based on property type to use correct GL uniform setter
309     switch(map.propertyValue->GetType())
310     {
311       case Property::INTEGER:
312       {
313         program.SetUniform1i(location, map.propertyValue->GetInteger(bufferIndex));
314         break;
315       }
316       case Property::FLOAT:
317       {
318         program.SetUniform1f(location, map.propertyValue->GetFloat(bufferIndex));
319         break;
320       }
321       case Property::VECTOR2:
322       {
323         Vector2 value(map.propertyValue->GetVector2(bufferIndex));
324         program.SetUniform2f(location, value.x, value.y);
325         break;
326       }
327
328       case Property::VECTOR3:
329       {
330         Vector3 value(map.propertyValue->GetVector3(bufferIndex));
331         program.SetUniform3f(location, value.x, value.y, value.z);
332         break;
333       }
334
335       case Property::VECTOR4:
336       {
337         Vector4 value(map.propertyValue->GetVector4(bufferIndex));
338         program.SetUniform4f(location, value.x, value.y, value.z, value.w);
339         break;
340       }
341
342       case Property::ROTATION:
343       {
344         Quaternion value(map.propertyValue->GetQuaternion(bufferIndex));
345         program.SetUniform4f(location, value.mVector.x, value.mVector.y, value.mVector.z, value.mVector.w);
346         break;
347       }
348
349       case Property::MATRIX:
350       {
351         const Matrix& value = map.propertyValue->GetMatrix(bufferIndex);
352         program.SetUniformMatrix4fv(location, 1, value.AsFloat());
353         break;
354       }
355
356       case Property::MATRIX3:
357       {
358         const Matrix3& value = map.propertyValue->GetMatrix3(bufferIndex);
359         program.SetUniformMatrix3fv(location, 1, value.AsFloat());
360         break;
361       }
362
363       default:
364       {
365         // Other property types are ignored
366         break;
367       }
368     }
369   }
370 }
371
372 void Renderer::BindTextures(Program& program, Graphics::CommandBuffer& commandBuffer, Vector<Graphics::Texture*>& boundTextures)
373 {
374   uint32_t textureUnit = 0;
375
376   GLint                          uniformLocation(-1);
377   std::vector<Render::Sampler*>& samplers(mRenderDataProvider->GetSamplers());
378   std::vector<Render::Texture*>& textures(mRenderDataProvider->GetTextures());
379
380   std::vector<Graphics::TextureBinding> textureBindings;
381   for(uint32_t i = 0; i < static_cast<uint32_t>(textures.size()); ++i) // not expecting more than uint32_t of textures
382   {
383     if(textures[i] && textures[i]->GetGraphicsObject())
384     {
385       if(program.GetSamplerUniformLocation(i, uniformLocation))
386       {
387         // if the sampler exists,
388         //   if it's default, delete the graphics object
389         //   otherwise re-initialize it if dirty
390
391         const Graphics::Sampler* graphicsSampler = (samplers[i] ? samplers[i]->GetGraphicsObject()
392                                                                 : nullptr);
393
394         boundTextures.PushBack(textures[i]->GetGraphicsObject());
395         const Graphics::TextureBinding textureBinding{textures[i]->GetGraphicsObject(), graphicsSampler, textureUnit};
396         textureBindings.push_back(textureBinding);
397
398         program.SetUniform1i(uniformLocation, textureUnit); // Get through shader reflection
399         ++textureUnit;
400       }
401     }
402   }
403
404   if(textureBindings.size() > 0)
405   {
406     commandBuffer.BindTextures(textureBindings);
407   }
408 }
409
410 void Renderer::SetFaceCullingMode(FaceCullingMode::Type mode)
411 {
412   mFaceCullingMode = mode;
413   mUpdated         = true;
414 }
415
416 void Renderer::SetBlendingBitMask(uint32_t bitmask)
417 {
418   mBlendingOptions.SetBitmask(bitmask);
419   mUpdated = true;
420 }
421
422 void Renderer::SetBlendColor(const Vector4& color)
423 {
424   mBlendingOptions.SetBlendColor(color);
425   mUpdated = true;
426 }
427
428 void Renderer::SetIndexedDrawFirstElement(uint32_t firstElement)
429 {
430   mIndexedDrawFirstElement = firstElement;
431   mUpdated                 = true;
432 }
433
434 void Renderer::SetIndexedDrawElementsCount(uint32_t elementsCount)
435 {
436   mIndexedDrawElementsCount = elementsCount;
437   mUpdated                  = true;
438 }
439
440 void Renderer::EnablePreMultipliedAlpha(bool enable)
441 {
442   mPremultipledAlphaEnabled = enable;
443   mUpdated                  = true;
444 }
445
446 void Renderer::SetDepthWriteMode(DepthWriteMode::Type depthWriteMode)
447 {
448   mDepthWriteMode = depthWriteMode;
449   mUpdated        = true;
450 }
451
452 void Renderer::SetDepthTestMode(DepthTestMode::Type depthTestMode)
453 {
454   mDepthTestMode = depthTestMode;
455   mUpdated       = true;
456 }
457
458 DepthWriteMode::Type Renderer::GetDepthWriteMode() const
459 {
460   return mDepthWriteMode;
461 }
462
463 DepthTestMode::Type Renderer::GetDepthTestMode() const
464 {
465   return mDepthTestMode;
466 }
467
468 void Renderer::SetDepthFunction(DepthFunction::Type depthFunction)
469 {
470   mDepthFunction = depthFunction;
471   mUpdated       = true;
472 }
473
474 DepthFunction::Type Renderer::GetDepthFunction() const
475 {
476   return mDepthFunction;
477 }
478
479 void Renderer::SetRenderMode(RenderMode::Type renderMode)
480 {
481   mStencilParameters.renderMode = renderMode;
482   mUpdated                      = true;
483 }
484
485 RenderMode::Type Renderer::GetRenderMode() const
486 {
487   return mStencilParameters.renderMode;
488 }
489
490 void Renderer::SetStencilFunction(StencilFunction::Type stencilFunction)
491 {
492   mStencilParameters.stencilFunction = stencilFunction;
493   mUpdated                           = true;
494 }
495
496 StencilFunction::Type Renderer::GetStencilFunction() const
497 {
498   return mStencilParameters.stencilFunction;
499 }
500
501 void Renderer::SetStencilFunctionMask(int stencilFunctionMask)
502 {
503   mStencilParameters.stencilFunctionMask = stencilFunctionMask;
504   mUpdated                               = true;
505 }
506
507 int Renderer::GetStencilFunctionMask() const
508 {
509   return mStencilParameters.stencilFunctionMask;
510 }
511
512 void Renderer::SetStencilFunctionReference(int stencilFunctionReference)
513 {
514   mStencilParameters.stencilFunctionReference = stencilFunctionReference;
515   mUpdated                                    = true;
516 }
517
518 int Renderer::GetStencilFunctionReference() const
519 {
520   return mStencilParameters.stencilFunctionReference;
521 }
522
523 void Renderer::SetStencilMask(int stencilMask)
524 {
525   mStencilParameters.stencilMask = stencilMask;
526   mUpdated                       = true;
527 }
528
529 int Renderer::GetStencilMask() const
530 {
531   return mStencilParameters.stencilMask;
532 }
533
534 void Renderer::SetStencilOperationOnFail(StencilOperation::Type stencilOperationOnFail)
535 {
536   mStencilParameters.stencilOperationOnFail = stencilOperationOnFail;
537   mUpdated                                  = true;
538 }
539
540 StencilOperation::Type Renderer::GetStencilOperationOnFail() const
541 {
542   return mStencilParameters.stencilOperationOnFail;
543 }
544
545 void Renderer::SetStencilOperationOnZFail(StencilOperation::Type stencilOperationOnZFail)
546 {
547   mStencilParameters.stencilOperationOnZFail = stencilOperationOnZFail;
548   mUpdated                                   = true;
549 }
550
551 StencilOperation::Type Renderer::GetStencilOperationOnZFail() const
552 {
553   return mStencilParameters.stencilOperationOnZFail;
554 }
555
556 void Renderer::SetStencilOperationOnZPass(StencilOperation::Type stencilOperationOnZPass)
557 {
558   mStencilParameters.stencilOperationOnZPass = stencilOperationOnZPass;
559   mUpdated                                   = true;
560 }
561
562 StencilOperation::Type Renderer::GetStencilOperationOnZPass() const
563 {
564   return mStencilParameters.stencilOperationOnZPass;
565 }
566
567 void Renderer::Upload()
568 {
569   mGeometry->Upload(*mGraphicsController);
570 }
571
572 void Renderer::Render(Context&                                             context,
573                       BufferIndex                                          bufferIndex,
574                       const SceneGraph::NodeDataProvider&                  node,
575                       const Matrix&                                        modelMatrix,
576                       const Matrix&                                        modelViewMatrix,
577                       const Matrix&                                        viewMatrix,
578                       const Matrix&                                        projectionMatrix,
579                       const Vector3&                                       size,
580                       bool                                                 blend,
581                       Vector<Graphics::Texture*>&                          boundTextures,
582                       const Dali::Internal::SceneGraph::RenderInstruction& instruction,
583                       uint32_t                                             queueIndex)
584 {
585   // Before doing anything test if the call happens in the right queue
586   if(mDrawCommands.empty() && queueIndex > 0)
587   {
588     return;
589   }
590
591   // Prepare commands
592   std::vector<DevelRenderer::DrawCommand*> commands;
593   for(auto& cmd : mDrawCommands)
594   {
595     if(cmd.queue == queueIndex)
596     {
597       commands.emplace_back(&cmd);
598     }
599   }
600
601   // Have commands but nothing to be drawn - abort
602   if(!mDrawCommands.empty() && commands.empty())
603   {
604     return;
605   }
606
607   // Create command buffer if not present
608   if(!mGraphicsCommandBuffer)
609   {
610     mGraphicsCommandBuffer = mGraphicsController->CreateCommandBuffer(
611       Graphics::CommandBufferCreateInfo()
612         .SetLevel(Graphics::CommandBufferLevel::SECONDARY),
613       nullptr);
614   }
615   else
616   {
617     mGraphicsCommandBuffer->Reset();
618   }
619
620   auto& commandBuffer = mGraphicsCommandBuffer;
621
622   // Set blending mode
623   if(!mDrawCommands.empty())
624   {
625     blend = (commands[0]->queue == DevelRenderer::RENDER_QUEUE_OPAQUE ? false : blend);
626   }
627
628   // Create Program
629   ShaderDataPtr            shaderData   = mRenderDataProvider->GetShader().GetShaderData();
630   const std::vector<char>& vertShader   = shaderData->GetShaderForPipelineStage(Graphics::PipelineStage::VERTEX_SHADER);
631   const std::vector<char>& fragShader   = shaderData->GetShaderForPipelineStage(Graphics::PipelineStage::FRAGMENT_SHADER);
632   Dali::Graphics::Shader&  vertexShader = mShaderCache->GetShader(
633     vertShader,
634     Graphics::PipelineStage::VERTEX_SHADER,
635     shaderData->GetSourceMode());
636
637   Dali::Graphics::Shader& fragmentShader = mShaderCache->GetShader(
638     fragShader,
639     Graphics::PipelineStage::FRAGMENT_SHADER,
640     shaderData->GetSourceMode());
641
642   std::vector<Graphics::ShaderState> shaderStates{
643     Graphics::ShaderState()
644       .SetShader(vertexShader)
645       .SetPipelineStage(Graphics::PipelineStage::VERTEX_SHADER),
646     Graphics::ShaderState()
647       .SetShader(fragmentShader)
648       .SetPipelineStage(Graphics::PipelineStage::FRAGMENT_SHADER)};
649
650   auto createInfo = Graphics::ProgramCreateInfo();
651   createInfo.SetShaderState(shaderStates);
652
653   auto     graphicsProgram = mGraphicsController->CreateProgram(createInfo, nullptr);
654   Program* program         = Program::New(*mProgramCache,
655                                   shaderData,
656                                   *mGraphicsController,
657                                   std::move(graphicsProgram),
658                                   (shaderData->GetHints() & Dali::Shader::Hint::MODIFIES_GEOMETRY) != 0x0);
659
660   if(!program)
661   {
662     DALI_LOG_ERROR("Failed to get program for shader at address %p.\n", reinterpret_cast<void*>(&mRenderDataProvider->GetShader()));
663     return;
664   }
665
666   // Temporarily create a pipeline here - this will be used for transporting
667   // topology, vertex format, attrs, rasterization state
668   mGraphicsPipeline = PrepareGraphicsPipeline(*program, instruction, blend, std::move(mGraphicsPipeline));
669
670   commandBuffer->BindPipeline(*mGraphicsPipeline.get());
671
672   BindTextures(*program, *commandBuffer.get(), boundTextures);
673
674   BuildUniformIndexMap(bufferIndex, node, size, *program);
675
676   WriteUniformBuffer(bufferIndex, *commandBuffer.get(), program, instruction, node, modelMatrix, modelViewMatrix, viewMatrix, projectionMatrix, size);
677
678   bool drawn = false; // Draw can fail if there are no vertex buffers or they haven't been uploaded yet
679                       // @todo We should detect this case much earlier to prevent unnecessary work
680
681   //@todo manage mDrawCommands in the same way as above command buffer?!
682   if(mDrawCommands.empty())
683   {
684     drawn = mGeometry->Draw(*mGraphicsController, *commandBuffer.get(), mIndexedDrawFirstElement, mIndexedDrawElementsCount);
685   }
686   else
687   {
688     for(auto& cmd : commands)
689     {
690       // @todo This should generate a command buffer per cmd
691       // Tests WILL fail. (Temporarily commented out)
692       mGeometry->Draw(*mGraphicsController, *commandBuffer.get(), cmd->firstIndex, cmd->elementCount);
693     }
694   }
695
696   // Command buffer contains Texture bindings, vertex bindings, index buffer binding, pipeline(vertex format)
697   // @todo We should return the command buffer(s) and let the calling method submit
698   // If not drawn, then don't add command buffer to submit info, and if empty, don't
699   // submit.
700   if(drawn)
701   {
702     Graphics::SubmitInfo submitInfo{{}, 0 | Graphics::SubmitFlagBits::FLUSH};
703     submitInfo.cmdBuffer.push_back(commandBuffer.get());
704     mGraphicsController->SubmitCommandBuffers(submitInfo);
705   }
706
707   mUpdated = false;
708 }
709
710 void Renderer::BuildUniformIndexMap(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider& node, const Vector3& size, Program& program)
711 {
712   // Check if the map has changed
713   DALI_ASSERT_DEBUG(mRenderDataProvider && "No Uniform map data provider available");
714
715   const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMap();
716
717   if(uniformMapDataProvider.GetUniformMapChanged(bufferIndex) ||
718      node.GetUniformMapChanged(bufferIndex) ||
719      mUniformIndexMap.Count() == 0 ||
720      mShaderChanged)
721   {
722     // Reset shader pointer
723     mShaderChanged = false;
724
725     const SceneGraph::CollectedUniformMap& uniformMap     = uniformMapDataProvider.GetUniformMap(bufferIndex);
726     const SceneGraph::CollectedUniformMap& uniformMapNode = node.GetUniformMap(bufferIndex);
727
728     uint32_t maxMaps = static_cast<uint32_t>(uniformMap.Count() + uniformMapNode.Count()); // 4,294,967,295 maps should be enough
729     mUniformIndexMap.Clear();                                                              // Clear contents, but keep memory if we don't change size
730     mUniformIndexMap.Resize(maxMaps);
731
732     uint32_t mapIndex = 0;
733     for(; mapIndex < uniformMap.Count(); ++mapIndex)
734     {
735       mUniformIndexMap[mapIndex].propertyValue          = uniformMap[mapIndex].propertyPtr;
736       mUniformIndexMap[mapIndex].uniformIndex           = program.RegisterUniform(uniformMap[mapIndex].uniformName);
737       mUniformIndexMap[mapIndex].uniformName            = uniformMap[mapIndex].uniformName;
738       mUniformIndexMap[mapIndex].uniformNameHash        = uniformMap[mapIndex].uniformNameHash;
739       mUniformIndexMap[mapIndex].uniformNameHashNoArray = uniformMap[mapIndex].uniformNameHashNoArray;
740       mUniformIndexMap[mapIndex].arrayIndex             = uniformMap[mapIndex].arrayIndex;
741     }
742
743     for(uint32_t nodeMapIndex = 0; nodeMapIndex < uniformMapNode.Count(); ++nodeMapIndex)
744     {
745       uint32_t uniformIndex = program.RegisterUniform(uniformMapNode[nodeMapIndex].uniformName);
746       bool     found(false);
747       for(uint32_t i = 0; i < uniformMap.Count(); ++i)
748       {
749         if(mUniformIndexMap[i].uniformIndex == uniformIndex)
750         {
751           mUniformIndexMap[i].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr;
752           found                             = true;
753           break;
754         }
755       }
756
757       if(!found)
758       {
759         mUniformIndexMap[mapIndex].propertyValue          = uniformMapNode[nodeMapIndex].propertyPtr;
760         mUniformIndexMap[mapIndex].uniformName            = uniformMapNode[nodeMapIndex].uniformName;
761         mUniformIndexMap[mapIndex].uniformIndex           = uniformIndex;
762         mUniformIndexMap[mapIndex].uniformNameHash        = uniformMapNode[nodeMapIndex].uniformNameHash;
763         mUniformIndexMap[mapIndex].uniformNameHashNoArray = uniformMapNode[nodeMapIndex].uniformNameHashNoArray;
764         mUniformIndexMap[mapIndex].arrayIndex             = uniformMapNode[nodeMapIndex].arrayIndex;
765         ++mapIndex;
766       }
767     }
768
769     mUniformIndexMap.Resize(mapIndex);
770   }
771 }
772
773 void Renderer::WriteUniformBuffer(
774   BufferIndex                          bufferIndex,
775   Graphics::CommandBuffer&             commandBuffer,
776   Program*                             program,
777   const SceneGraph::RenderInstruction& instruction,
778   const SceneGraph::NodeDataProvider&  node,
779   const Matrix&                        modelMatrix,
780   const Matrix&                        modelViewMatrix,
781   const Matrix&                        viewMatrix,
782   const Matrix&                        projectionMatrix,
783   const Vector3&                       size)
784 {
785   // Create the UBO
786   uint32_t uniformBlockAllocationBytes{0u};
787   uint32_t uniformBlockMaxSize{0u};
788   uint32_t uboOffset{0u};
789
790   auto& reflection = mGraphicsController->GetProgramReflection(program->GetGraphicsProgram());
791   for(auto i = 0u; i < reflection.GetUniformBlockCount(); ++i)
792   {
793     auto blockSize = GetUniformBufferDataAlignment(reflection.GetUniformBlockSize(i));
794     if(uniformBlockMaxSize < blockSize)
795     {
796       uniformBlockMaxSize = blockSize;
797     }
798     uniformBlockAllocationBytes += blockSize;
799   }
800
801   auto pagedAllocation = ((uniformBlockAllocationBytes / UBO_PAGE_SIZE + 1u)) * UBO_PAGE_SIZE;
802
803   // Allocate twice memory as required by the uniform buffers
804   // todo: memory usage backlog to use optimal allocation
805   if(uniformBlockAllocationBytes && !mUniformBuffer[bufferIndex])
806   {
807     mUniformBuffer[bufferIndex] = mUniformBufferManager->AllocateUniformBuffer(pagedAllocation);
808   }
809   else if(uniformBlockAllocationBytes && (mUniformBuffer[bufferIndex]->GetSize() < pagedAllocation ||
810                                           (pagedAllocation < uint32_t(float(mUniformBuffer[bufferIndex]->GetSize()) * UBO_SHRINK_THRESHOLD))))
811   {
812     mUniformBuffer[bufferIndex]->Reserve(pagedAllocation);
813   }
814
815   // Clear UBO
816   if(mUniformBuffer[bufferIndex])
817   {
818     mUniformBuffer[bufferIndex]->Fill(0, 0u, 0u);
819   }
820
821   // update the uniform buffer
822   // pass shared UBO and offset, return new offset for next item to be used
823   // don't process bindings if there are no uniform buffers allocated
824   auto ubo = mUniformBuffer[bufferIndex].get();
825   if(ubo)
826   {
827     auto uboCount = reflection.GetUniformBlockCount();
828     mUniformBufferBindings.resize(uboCount);
829
830     std::vector<Graphics::UniformBufferBinding>* bindings{&mUniformBufferBindings};
831
832     // Write default uniforms
833     WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::MODEL_MATRIX), *ubo, *bindings, modelMatrix);
834     WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::VIEW_MATRIX), *ubo, *bindings, viewMatrix);
835     WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::PROJECTION_MATRIX), *ubo, *bindings, projectionMatrix);
836     WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::MODEL_VIEW_MATRIX), *ubo, *bindings, modelViewMatrix);
837
838     auto mvpUniformInfo = program->GetDefaultUniform(Program::DefaultUniformIndex::MVP_MATRIX);
839     if(mvpUniformInfo && !mvpUniformInfo->name.empty())
840     {
841       Matrix modelViewProjectionMatrix(false);
842       Matrix::Multiply(modelViewProjectionMatrix, modelViewMatrix, projectionMatrix);
843       WriteDefaultUniform(mvpUniformInfo, *ubo, *bindings, modelViewProjectionMatrix);
844     }
845
846     auto normalUniformInfo = program->GetDefaultUniform(Program::DefaultUniformIndex::NORMAL_MATRIX);
847     if(normalUniformInfo && !normalUniformInfo->name.empty())
848     {
849       Matrix3 normalMatrix(modelViewMatrix);
850       normalMatrix.Invert();
851       normalMatrix.Transpose();
852       WriteDefaultUniform(normalUniformInfo, *ubo, *bindings, normalMatrix);
853     }
854
855     Vector4        finalColor;
856     const Vector4& color = node.GetRenderColor(bufferIndex);
857     if(mPremultipledAlphaEnabled)
858     {
859       float alpha = color.a * mRenderDataProvider->GetOpacity(bufferIndex);
860       finalColor  = Vector4(color.r * alpha, color.g * alpha, color.b * alpha, alpha);
861     }
862     else
863     {
864       finalColor = Vector4(color.r, color.g, color.b, color.a * mRenderDataProvider->GetOpacity(bufferIndex));
865     }
866     WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::COLOR), *ubo, *bindings, finalColor);
867
868     // Write uniforms from the uniform map
869     FillUniformBuffer(*program, instruction, *ubo, bindings, uboOffset, bufferIndex);
870
871     // Write uSize in the end, as it shouldn't be overridable by dynamic properties.
872     WriteDefaultUniform(program->GetDefaultUniform(Program::DefaultUniformIndex::SIZE), *ubo, *bindings, size);
873
874     commandBuffer.BindUniformBuffers(*bindings);
875   }
876 }
877
878 template<class T>
879 bool Renderer::WriteDefaultUniform(const Graphics::UniformInfo* uniformInfo, Render::UniformBuffer& ubo, const std::vector<Graphics::UniformBufferBinding>& bindings, const T& data)
880 {
881   if(uniformInfo && !uniformInfo->name.empty())
882   {
883     WriteUniform(ubo, bindings, *uniformInfo, data);
884     return true;
885   }
886   return false;
887 }
888
889 template<class T>
890 void Renderer::WriteUniform(Render::UniformBuffer& ubo, const std::vector<Graphics::UniformBufferBinding>& bindings, const Graphics::UniformInfo& uniformInfo, const T& data)
891 {
892   WriteUniform(ubo, bindings, uniformInfo, &data, sizeof(T));
893 }
894
895 void Renderer::WriteUniform(Render::UniformBuffer& ubo, const std::vector<Graphics::UniformBufferBinding>& bindings, const Graphics::UniformInfo& uniformInfo, const void* data, uint32_t size)
896 {
897   ubo.Write(data, size, bindings[uniformInfo.bufferIndex].offset + uniformInfo.offset);
898 }
899
900 void Renderer::FillUniformBuffer(Program&                                      program,
901                                  const SceneGraph::RenderInstruction&          instruction,
902                                  Render::UniformBuffer&                        ubo,
903                                  std::vector<Graphics::UniformBufferBinding>*& outBindings,
904                                  uint32_t&                                     offset,
905                                  BufferIndex                                   updateBufferIndex)
906 {
907   auto& reflection = mGraphicsController->GetProgramReflection(program.GetGraphicsProgram());
908   auto  uboCount   = reflection.GetUniformBlockCount();
909
910   // Setup bindings
911   uint32_t dataOffset = offset;
912   for(auto i = 0u; i < uboCount; ++i)
913   {
914     mUniformBufferBindings[i].dataSize = reflection.GetUniformBlockSize(i);
915     mUniformBufferBindings[i].binding  = reflection.GetUniformBlockBinding(i);
916     mUniformBufferBindings[i].offset   = dataOffset;
917
918     dataOffset += GetUniformBufferDataAlignment(mUniformBufferBindings[i].dataSize);
919     mUniformBufferBindings[i].buffer = ubo.GetBuffer();
920
921     for(UniformIndexMappings::Iterator iter = mUniformIndexMap.Begin(),
922                                        end  = mUniformIndexMap.End();
923         iter != end;
924         ++iter)
925     {
926       // @todo This means parsing the uniform string every frame. Instead, store the array index if present.
927       int arrayIndex = (*iter).arrayIndex;
928
929       auto uniformInfo  = Graphics::UniformInfo{};
930       auto uniformFound = program.GetUniform((*iter).uniformName.GetCString(),
931                                              (*iter).uniformNameHashNoArray ? (*iter).uniformNameHashNoArray
932                                                                             : (*iter).uniformNameHash,
933                                              uniformInfo);
934
935       if(uniformFound)
936       {
937         auto dst = mUniformBufferBindings[uniformInfo.bufferIndex].offset + uniformInfo.offset;
938
939         switch((*iter).propertyValue->GetType())
940         {
941           case Property::Type::BOOLEAN:
942           {
943             ubo.Write(&(*iter).propertyValue->GetBoolean(updateBufferIndex),
944                       sizeof(bool),
945                       dst + static_cast<uint32_t>(sizeof(bool)) * arrayIndex);
946             break;
947           }
948           case Property::Type::INTEGER:
949           {
950             ubo.Write(&(*iter).propertyValue->GetInteger(updateBufferIndex),
951                       sizeof(int32_t),
952                       dst + static_cast<int32_t>(sizeof(int32_t)) * arrayIndex);
953             break;
954           }
955           case Property::Type::FLOAT:
956           {
957             ubo.Write(&(*iter).propertyValue->GetFloat(updateBufferIndex),
958                       sizeof(float),
959                       dst + static_cast<uint32_t>(sizeof(float)) * arrayIndex);
960             break;
961           }
962           case Property::Type::VECTOR2:
963           {
964             ubo.Write(&(*iter).propertyValue->GetVector2(updateBufferIndex),
965                       sizeof(Vector2),
966                       dst + static_cast<uint32_t>(sizeof(Vector2)) * arrayIndex);
967             break;
968           }
969           case Property::Type::VECTOR3:
970           {
971             ubo.Write(&(*iter).propertyValue->GetVector3(updateBufferIndex),
972                       sizeof(Vector3),
973                       dst + static_cast<uint32_t>(sizeof(Vector3)) * arrayIndex);
974             break;
975           }
976           case Property::Type::VECTOR4:
977           {
978             ubo.Write(&(*iter).propertyValue->GetVector4(updateBufferIndex),
979                       sizeof(Vector4),
980                       dst + static_cast<uint32_t>(sizeof(Vector4)) * arrayIndex);
981             break;
982           }
983           case Property::Type::MATRIX:
984           {
985             ubo.Write(&(*iter).propertyValue->GetMatrix(updateBufferIndex),
986                       sizeof(Matrix),
987                       dst + static_cast<uint32_t>(sizeof(Matrix)) * arrayIndex);
988             break;
989           }
990           case Property::Type::MATRIX3:
991           {
992             // todo: handle data padding properly
993             // Vulkan:
994             //
995             //const auto& matrix = &(*iter).propertyValue->GetMatrix3(updateBufferIndex);
996             //for(int i = 0; i < 3; ++i)
997             //{
998             //ubo.Write(&matrix->AsFloat()[i * 3],
999             //          sizeof(float) * 3,
1000             //          dst + (i * static_cast<uint32_t>(sizeof(Vector4))));
1001             //}
1002             // GL:
1003             ubo.Write(&(*iter).propertyValue->GetMatrix3(updateBufferIndex),
1004                       sizeof(Matrix3),
1005                       dst + static_cast<uint32_t>(sizeof(Matrix3)) * arrayIndex);
1006             break;
1007           }
1008           default:
1009           {
1010           }
1011         }
1012       }
1013     }
1014   }
1015   // write output bindings
1016   outBindings = &mUniformBufferBindings;
1017
1018   // Update offset
1019   offset = dataOffset;
1020 }
1021
1022 void Renderer::SetSortAttributes(BufferIndex                                             bufferIndex,
1023                                  SceneGraph::RenderInstructionProcessor::SortAttributes& sortAttributes) const
1024 {
1025   sortAttributes.shader   = &(mRenderDataProvider->GetShader());
1026   sortAttributes.geometry = mGeometry;
1027 }
1028
1029 void Renderer::SetShaderChanged(bool value)
1030 {
1031   mShaderChanged = value;
1032 }
1033
1034 bool Renderer::Updated(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider* node)
1035 {
1036   if(mUpdated)
1037   {
1038     mUpdated = false;
1039     return true;
1040   }
1041
1042   if(mShaderChanged || mUpdateAttributeLocations || mGeometry->AttributesChanged())
1043   {
1044     return true;
1045   }
1046
1047   for(const auto& texture : mRenderDataProvider->GetTextures())
1048   {
1049     if(texture && texture->IsNativeImage())
1050     {
1051       return true;
1052     }
1053   }
1054
1055   uint64_t                               hash           = 0xc70f6907UL;
1056   const SceneGraph::CollectedUniformMap& uniformMapNode = node->GetUniformMap(bufferIndex);
1057   for(const auto& uniformProperty : uniformMapNode)
1058   {
1059     hash = uniformProperty.propertyPtr->Hash(bufferIndex, hash);
1060   }
1061
1062   const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMap();
1063   const SceneGraph::CollectedUniformMap&    uniformMap             = uniformMapDataProvider.GetUniformMap(bufferIndex);
1064   for(const auto& uniformProperty : uniformMap)
1065   {
1066     hash = uniformProperty.propertyPtr->Hash(bufferIndex, hash);
1067   }
1068
1069   if(mUniformsHash != hash)
1070   {
1071     mUniformsHash = hash;
1072     return true;
1073   }
1074
1075   return false;
1076 }
1077
1078 Graphics::UniquePtr<Graphics::Pipeline> Renderer::PrepareGraphicsPipeline(
1079   Program&                                             program,
1080   const Dali::Internal::SceneGraph::RenderInstruction& instruction,
1081   bool                                                 blend,
1082   Graphics::UniquePtr<Graphics::Pipeline>&&            oldPipeline)
1083 {
1084   Graphics::InputAssemblyState inputAssemblyState{};
1085   Graphics::VertexInputState   vertexInputState{};
1086   Graphics::ProgramState       programState{};
1087   uint32_t                     bindingIndex{0u};
1088
1089   if(mUpdateAttributeLocations || mGeometry->AttributesChanged())
1090   {
1091     mAttributeLocations.Clear();
1092     mUpdateAttributeLocations = true;
1093   }
1094
1095   auto& reflection = mGraphicsController->GetProgramReflection(program.GetGraphicsProgram());
1096
1097   /**
1098    * Bind Attributes
1099    */
1100   uint32_t base = 0;
1101   for(auto&& vertexBuffer : mGeometry->GetVertexBuffers())
1102   {
1103     const VertexBuffer::Format& vertexFormat = *vertexBuffer->GetFormat();
1104
1105     vertexInputState.bufferBindings.emplace_back(vertexFormat.size, // stride
1106                                                  Graphics::VertexInputRate::PER_VERTEX);
1107
1108     const uint32_t attributeCount = vertexBuffer->GetAttributeCount();
1109     for(uint32_t i = 0; i < attributeCount; ++i)
1110     {
1111       if(mUpdateAttributeLocations)
1112       {
1113         auto    attributeName = vertexBuffer->GetAttributeName(i);
1114         int32_t pLocation     = reflection.GetVertexAttributeLocation(std::string(attributeName.GetStringView()));
1115         if(-1 == pLocation)
1116         {
1117           DALI_LOG_WARNING("Attribute not found in the shader: %s\n", attributeName.GetCString());
1118         }
1119         mAttributeLocations.PushBack(pLocation);
1120       }
1121
1122       uint32_t location = static_cast<uint32_t>(mAttributeLocations[base + i]);
1123
1124       vertexInputState.attributes.emplace_back(location,
1125                                                bindingIndex,
1126                                                vertexFormat.components[i].offset,
1127                                                GetPropertyVertexFormat(vertexFormat.components[i].type));
1128     }
1129     base += attributeCount;
1130     ++bindingIndex;
1131   }
1132   mUpdateAttributeLocations = false;
1133
1134   // Get the topology
1135   inputAssemblyState.SetTopology(mGeometry->GetTopology());
1136
1137   // Get the program
1138   programState.SetProgram(program.GetGraphicsProgram());
1139
1140   Graphics::RasterizationState rasterizationState{};
1141
1142   //Set cull face  mode
1143   const Dali::Internal::SceneGraph::Camera* cam = instruction.GetCamera();
1144   if(cam->GetReflectionUsed())
1145   {
1146     auto adjFaceCullingMode = mFaceCullingMode;
1147     switch(mFaceCullingMode)
1148     {
1149       case FaceCullingMode::Type::FRONT:
1150       {
1151         adjFaceCullingMode = FaceCullingMode::Type::BACK;
1152         break;
1153       }
1154       case FaceCullingMode::Type::BACK:
1155       {
1156         adjFaceCullingMode = FaceCullingMode::Type::FRONT;
1157         break;
1158       }
1159       default:
1160       {
1161         // nothing to do, leave culling as it is
1162       }
1163     }
1164     rasterizationState.SetCullMode(ConvertCullFace(adjFaceCullingMode));
1165   }
1166   else
1167   {
1168     rasterizationState.SetCullMode(ConvertCullFace(mFaceCullingMode));
1169   }
1170
1171   rasterizationState.SetFrontFace(Graphics::FrontFace::COUNTER_CLOCKWISE);
1172
1173   /**
1174    * Set Polygon mode
1175    */
1176   switch(mGeometry->GetTopology())
1177   {
1178     case Graphics::PrimitiveTopology::TRIANGLE_LIST:
1179     case Graphics::PrimitiveTopology::TRIANGLE_STRIP:
1180     case Graphics::PrimitiveTopology::TRIANGLE_FAN:
1181       rasterizationState.SetPolygonMode(Graphics::PolygonMode::FILL);
1182       break;
1183     case Graphics::PrimitiveTopology::LINE_LIST:
1184     case Graphics::PrimitiveTopology::LINE_LOOP:
1185     case Graphics::PrimitiveTopology::LINE_STRIP:
1186       rasterizationState.SetPolygonMode(Graphics::PolygonMode::LINE);
1187       break;
1188     case Graphics::PrimitiveTopology::POINT_LIST:
1189       rasterizationState.SetPolygonMode(Graphics::PolygonMode::POINT);
1190       break;
1191   }
1192
1193   // @todo How to signal a blend barrier is needed?
1194   //if(mBlendingOptions.IsAdvancedBlendEquationApplied() && mPremultipledAlphaEnabled)
1195   //{
1196   //  context.BlendBarrier();
1197   //}
1198
1199   Graphics::ColorBlendState colorBlendState{};
1200   colorBlendState.SetBlendEnable(false);
1201
1202   if(blend)
1203   {
1204     colorBlendState.SetBlendEnable(true);
1205
1206     Graphics::BlendOp rgbOp   = ConvertBlendEquation(mBlendingOptions.GetBlendEquationRgb());
1207     Graphics::BlendOp alphaOp = ConvertBlendEquation(mBlendingOptions.GetBlendEquationRgb());
1208     if(mBlendingOptions.IsAdvancedBlendEquationApplied() && mPremultipledAlphaEnabled)
1209     {
1210       if(rgbOp != alphaOp)
1211       {
1212         DALI_LOG_ERROR("Advanced Blend Equation MUST be applied by using BlendEquation.\n");
1213         alphaOp = rgbOp;
1214       }
1215     }
1216
1217     colorBlendState
1218       .SetSrcColorBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendSrcFactorRgb()))
1219       .SetSrcAlphaBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendSrcFactorAlpha()))
1220       .SetDstColorBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendDestFactorRgb()))
1221       .SetDstAlphaBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendDestFactorAlpha()))
1222       .SetColorBlendOp(rgbOp)
1223       .SetAlphaBlendOp(alphaOp);
1224
1225     // Blend color is optional and rarely used
1226     Vector4* blendColor = const_cast<Vector4*>(mBlendingOptions.GetBlendColor());
1227     if(blendColor)
1228     {
1229       colorBlendState.SetBlendConstants(blendColor->AsFloat());
1230     }
1231   }
1232
1233   // Take the program into use so we can send uniforms to it
1234   // @todo Remove this call entirely!
1235   program.Use();
1236
1237   mUpdated = true;
1238
1239   // Create a new pipeline
1240   return mGraphicsController->CreatePipeline(
1241     Graphics::PipelineCreateInfo()
1242       .SetInputAssemblyState(&inputAssemblyState) // Passed as pointers - shallow copy will break. TOO C LIKE
1243       .SetVertexInputState(&vertexInputState)
1244       .SetRasterizationState(&rasterizationState)
1245       .SetColorBlendState(&colorBlendState)
1246       .SetProgramState(&programState)
1247       .SetNextExtension(&mLegacyProgram),
1248     std::move(oldPipeline));
1249 }
1250
1251 } // namespace Render
1252
1253 } // namespace Internal
1254
1255 } // namespace Dali