+Graphics::UniquePtr<Graphics::Pipeline> Renderer::PrepareGraphicsPipeline(
+ Program& program,
+ const Dali::Internal::SceneGraph::RenderInstruction& instruction,
+ bool blend,
+ Graphics::UniquePtr<Graphics::Pipeline>&& oldPipeline)
+{
+ Graphics::InputAssemblyState inputAssemblyState{};
+ Graphics::VertexInputState vertexInputState{};
+ Graphics::ProgramState programState{};
+ uint32_t bindingIndex{0u};
+
+ if(mUpdateAttributeLocations || mGeometry->AttributesChanged())
+ {
+ mAttributeLocations.Clear();
+ mUpdateAttributeLocations = true;
+ }
+
+ auto& reflection = mGraphicsController->GetProgramReflection(program.GetGraphicsProgram());
+
+ /**
+ * Bind Attributes
+ */
+ uint32_t base = 0;
+ for(auto&& vertexBuffer : mGeometry->GetVertexBuffers())
+ {
+ const VertexBuffer::Format& vertexFormat = *vertexBuffer->GetFormat();
+
+ vertexInputState.bufferBindings.emplace_back(vertexFormat.size, // stride
+ Graphics::VertexInputRate::PER_VERTEX);
+
+ const uint32_t attributeCount = vertexBuffer->GetAttributeCount();
+ for(uint32_t i = 0; i < attributeCount; ++i)
+ {
+ if(mUpdateAttributeLocations)
+ {
+ auto attributeName = vertexBuffer->GetAttributeName(i);
+ int32_t pLocation = reflection.GetVertexAttributeLocation(std::string(attributeName.GetStringView()));
+ if(-1 == pLocation)
+ {
+ DALI_LOG_WARNING("Attribute not found in the shader: %s\n", attributeName.GetCString());
+ }
+ mAttributeLocations.PushBack(pLocation);
+ }
+
+ uint32_t location = static_cast<uint32_t>(mAttributeLocations[base + i]);
+
+ vertexInputState.attributes.emplace_back(location,
+ bindingIndex,
+ vertexFormat.components[i].offset,
+ GetPropertyVertexFormat(vertexFormat.components[i].type));
+ }
+ base += attributeCount;
+ ++bindingIndex;
+ }
+ mUpdateAttributeLocations = false;
+
+ // Get the topology
+ inputAssemblyState.SetTopology(mGeometry->GetTopology());
+
+ // Get the program
+ programState.SetProgram(program.GetGraphicsProgram());
+
+ Graphics::RasterizationState rasterizationState{};
+
+ //Set cull face mode
+ const Dali::Internal::SceneGraph::Camera* cam = instruction.GetCamera();
+ if(cam->GetReflectionUsed())
+ {
+ auto adjFaceCullingMode = mFaceCullingMode;
+ switch(mFaceCullingMode)
+ {
+ case FaceCullingMode::Type::FRONT:
+ {
+ adjFaceCullingMode = FaceCullingMode::Type::BACK;
+ break;
+ }
+ case FaceCullingMode::Type::BACK:
+ {
+ adjFaceCullingMode = FaceCullingMode::Type::FRONT;
+ break;
+ }
+ default:
+ {
+ // nothing to do, leave culling as it is
+ }
+ }
+ rasterizationState.SetCullMode(ConvertCullFace(adjFaceCullingMode));
+ }
+ else
+ {
+ rasterizationState.SetCullMode(ConvertCullFace(mFaceCullingMode));
+ }
+
+ rasterizationState.SetFrontFace(Graphics::FrontFace::COUNTER_CLOCKWISE);
+
+ /**
+ * Set Polygon mode
+ */
+ switch(mGeometry->GetTopology())
+ {
+ case Graphics::PrimitiveTopology::TRIANGLE_LIST:
+ case Graphics::PrimitiveTopology::TRIANGLE_STRIP:
+ case Graphics::PrimitiveTopology::TRIANGLE_FAN:
+ rasterizationState.SetPolygonMode(Graphics::PolygonMode::FILL);
+ break;
+ case Graphics::PrimitiveTopology::LINE_LIST:
+ case Graphics::PrimitiveTopology::LINE_LOOP:
+ case Graphics::PrimitiveTopology::LINE_STRIP:
+ rasterizationState.SetPolygonMode(Graphics::PolygonMode::LINE);
+ break;
+ case Graphics::PrimitiveTopology::POINT_LIST:
+ rasterizationState.SetPolygonMode(Graphics::PolygonMode::POINT);
+ break;
+ }
+
+ // @todo How to signal a blend barrier is needed?
+ //if(mBlendingOptions.IsAdvancedBlendEquationApplied() && mPremultipledAlphaEnabled)
+ //{
+ // context.BlendBarrier();
+ //}
+
+ Graphics::ColorBlendState colorBlendState{};
+ colorBlendState.SetBlendEnable(false);
+
+ if(blend)
+ {
+ colorBlendState.SetBlendEnable(true);
+
+ Graphics::BlendOp rgbOp = ConvertBlendEquation(mBlendingOptions.GetBlendEquationRgb());
+ Graphics::BlendOp alphaOp = ConvertBlendEquation(mBlendingOptions.GetBlendEquationRgb());
+ if(mBlendingOptions.IsAdvancedBlendEquationApplied() && mPremultipledAlphaEnabled)
+ {
+ if(rgbOp != alphaOp)
+ {
+ DALI_LOG_ERROR("Advanced Blend Equation MUST be applied by using BlendEquation.\n");
+ alphaOp = rgbOp;
+ }
+ }
+
+ colorBlendState
+ .SetSrcColorBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendSrcFactorRgb()))
+ .SetSrcAlphaBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendSrcFactorAlpha()))
+ .SetDstColorBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendDestFactorRgb()))
+ .SetDstAlphaBlendFactor(ConvertBlendFactor(mBlendingOptions.GetBlendDestFactorAlpha()))
+ .SetColorBlendOp(rgbOp)
+ .SetAlphaBlendOp(alphaOp);
+
+ // Blend color is optional and rarely used
+ Vector4* blendColor = const_cast<Vector4*>(mBlendingOptions.GetBlendColor());
+ if(blendColor)
+ {
+ colorBlendState.SetBlendConstants(blendColor->AsFloat());
+ }
+ }
+
+ // Take the program into use so we can send uniforms to it
+ // @todo Remove this call entirely!
+ program.Use();
+
+ mUpdated = true;
+
+ // @todo Should instead set framebuffer once through Renderpass, rather than modifying
+ // pipeline repeatedly.
+ Graphics::FramebufferState framebufferState{};
+ if(instruction.mFrameBuffer)
+ {
+ instruction.mFrameBuffer->Bind(); // Ensure graphics object is created.
+ framebufferState.SetFramebuffer(*instruction.mFrameBuffer->GetGraphicsObject());
+ }
+
+ // Create a new pipeline
+ // @todo Passed as pointers - shallow copy will break. Implementation MUST deep copy.
+ return mGraphicsController->CreatePipeline(
+ Graphics::PipelineCreateInfo()
+ .SetInputAssemblyState(&inputAssemblyState)
+ .SetVertexInputState(&vertexInputState)
+ .SetRasterizationState(&rasterizationState)
+ .SetColorBlendState(&colorBlendState)
+ .SetFramebufferState(&framebufferState)
+ .SetProgramState(&programState)
+ .SetNextExtension(&mLegacyProgram),
+ std::move(oldPipeline));
+}
+
+} // namespace Render