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