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