2 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/render/renderers/render-renderer.h>
22 #include <dali/internal/common/image-sampler.h>
23 #include <dali/internal/render/common/render-instruction.h>
24 #include <dali/internal/render/data-providers/node-data-provider.h>
25 #include <dali/internal/render/data-providers/uniform-map-data-provider.h>
26 #include <dali/internal/render/gl-resources/context.h>
27 #include <dali/internal/render/renderers/render-sampler.h>
28 #include <dali/internal/render/renderers/render-texture.h>
29 #include <dali/internal/render/shaders/program.h>
30 #include <dali/internal/render/shaders/scene-graph-shader.h>
39 * Helper to set view and projection matrices once per program
40 * @param program to set the matrices to
41 * @param modelMatrix to set
42 * @param viewMatrix to set
43 * @param projectionMatrix to set
44 * @param modelViewMatrix to set
45 * @param modelViewProjectionMatrix to set
47 inline void SetMatrices(Program& program,
48 const Matrix& modelMatrix,
49 const Matrix& viewMatrix,
50 const Matrix& projectionMatrix,
51 const Matrix& modelViewMatrix)
53 GLint loc = program.GetUniformLocation(Program::UNIFORM_MODEL_MATRIX);
54 if(Program::UNIFORM_UNKNOWN != loc)
56 program.SetUniformMatrix4fv(loc, 1, modelMatrix.AsFloat());
58 loc = program.GetUniformLocation(Program::UNIFORM_VIEW_MATRIX);
59 if(Program::UNIFORM_UNKNOWN != loc)
61 if(program.GetViewMatrix() != &viewMatrix)
63 program.SetViewMatrix(&viewMatrix);
64 program.SetUniformMatrix4fv(loc, 1, viewMatrix.AsFloat());
67 // set projection matrix if program has not yet received it this frame or if it is dirty
68 loc = program.GetUniformLocation(Program::UNIFORM_PROJECTION_MATRIX);
69 if(Program::UNIFORM_UNKNOWN != loc)
71 if(program.GetProjectionMatrix() != &projectionMatrix)
73 program.SetProjectionMatrix(&projectionMatrix);
74 program.SetUniformMatrix4fv(loc, 1, projectionMatrix.AsFloat());
77 loc = program.GetUniformLocation(Program::UNIFORM_MODELVIEW_MATRIX);
78 if(Program::UNIFORM_UNKNOWN != loc)
80 program.SetUniformMatrix4fv(loc, 1, modelViewMatrix.AsFloat());
83 loc = program.GetUniformLocation(Program::UNIFORM_MVP_MATRIX);
84 if(Program::UNIFORM_UNKNOWN != loc)
86 Matrix modelViewProjectionMatrix(false);
87 Matrix::Multiply(modelViewProjectionMatrix, modelViewMatrix, projectionMatrix);
88 program.SetUniformMatrix4fv(loc, 1, modelViewProjectionMatrix.AsFloat());
91 loc = program.GetUniformLocation(Program::UNIFORM_NORMAL_MATRIX);
92 if(Program::UNIFORM_UNKNOWN != loc)
95 normalMatrix = modelViewMatrix;
96 normalMatrix.Invert();
97 normalMatrix.Transpose();
98 program.SetUniformMatrix3fv(loc, 1, normalMatrix.AsFloat());
106 Renderer* Renderer::New(SceneGraph::RenderDataProvider* dataProvider,
107 Render::Geometry* geometry,
108 uint32_t blendingBitmask,
109 const Vector4& blendColor,
110 FaceCullingMode::Type faceCullingMode,
111 bool preMultipliedAlphaEnabled,
112 DepthWriteMode::Type depthWriteMode,
113 DepthTestMode::Type depthTestMode,
114 DepthFunction::Type depthFunction,
115 StencilParameters& stencilParameters)
117 return new Renderer(dataProvider, geometry, blendingBitmask, blendColor, faceCullingMode, preMultipliedAlphaEnabled, depthWriteMode, depthTestMode, depthFunction, stencilParameters);
120 Renderer::Renderer(SceneGraph::RenderDataProvider* dataProvider,
121 Render::Geometry* geometry,
122 uint32_t blendingBitmask,
123 const Vector4& blendColor,
124 FaceCullingMode::Type faceCullingMode,
125 bool preMultipliedAlphaEnabled,
126 DepthWriteMode::Type depthWriteMode,
127 DepthTestMode::Type depthTestMode,
128 DepthFunction::Type depthFunction,
129 StencilParameters& stencilParameters)
130 : mRenderDataProvider(dataProvider),
134 mAttributesLocation(),
136 mStencilParameters(stencilParameters),
138 mIndexedDrawFirstElement(0),
139 mIndexedDrawElementsCount(0),
140 mDepthFunction(depthFunction),
141 mFaceCullingMode(faceCullingMode),
142 mDepthWriteMode(depthWriteMode),
143 mDepthTestMode(depthTestMode),
144 mUpdateAttributesLocation(true),
145 mPremultipledAlphaEnabled(preMultipliedAlphaEnabled),
146 mShaderChanged(false),
149 if(blendingBitmask != 0u)
151 mBlendingOptions.SetBitmask(blendingBitmask);
154 mBlendingOptions.SetBlendColor(blendColor);
157 void Renderer::Initialize(Context& context)
162 Renderer::~Renderer() = default;
164 void Renderer::SetGeometry(Render::Geometry* geometry)
166 mGeometry = geometry;
167 mUpdateAttributesLocation = true;
169 void Renderer::SetDrawCommands(Dali::DevelRenderer::DrawCommand* pDrawCommands, uint32_t size)
171 mDrawCommands.clear();
172 mDrawCommands.insert(mDrawCommands.end(), pDrawCommands, pDrawCommands + size);
175 void Renderer::SetBlending(Context& context, bool blend)
177 context.SetBlend(blend);
180 // Blend color is optional and rarely used
181 const Vector4* blendColor = mBlendingOptions.GetBlendColor();
184 context.SetCustomBlendColor(*blendColor);
188 context.SetDefaultBlendColor();
191 // Set blend source & destination factors
192 context.BlendFuncSeparate(mBlendingOptions.GetBlendSrcFactorRgb(),
193 mBlendingOptions.GetBlendDestFactorRgb(),
194 mBlendingOptions.GetBlendSrcFactorAlpha(),
195 mBlendingOptions.GetBlendDestFactorAlpha());
197 // Set blend equations
198 Dali::DevelBlendEquation::Type rgbEquation = mBlendingOptions.GetBlendEquationRgb();
199 Dali::DevelBlendEquation::Type alphaEquation = mBlendingOptions.GetBlendEquationAlpha();
201 if(mBlendingOptions.IsAdvancedBlendEquationApplied() && mPremultipledAlphaEnabled)
203 if(rgbEquation != alphaEquation)
205 DALI_LOG_ERROR("Advanced Blend Equation have to be appried by using BlendEquation.\n");
207 context.BlendEquation(rgbEquation);
211 context.BlendEquationSeparate(rgbEquation, alphaEquation);
218 void Renderer::GlContextDestroyed()
220 mGeometry->GlContextDestroyed();
223 void Renderer::GlCleanup()
227 void Renderer::SetUniforms(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider& node, const Vector3& size, Program& program)
229 // Check if the map has changed
230 DALI_ASSERT_DEBUG(mRenderDataProvider && "No Uniform map data provider available");
232 const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMap();
234 if(uniformMapDataProvider.GetUniformMapChanged(bufferIndex) ||
235 node.GetUniformMapChanged(bufferIndex) ||
236 mUniformIndexMap.Count() == 0 ||
239 // Reset shader pointer
240 mShaderChanged = false;
242 const SceneGraph::CollectedUniformMap& uniformMap = uniformMapDataProvider.GetUniformMap(bufferIndex);
243 const SceneGraph::CollectedUniformMap& uniformMapNode = node.GetUniformMap(bufferIndex);
245 uint32_t maxMaps = static_cast<uint32_t>(uniformMap.Count() + uniformMapNode.Count()); // 4,294,967,295 maps should be enough
246 mUniformIndexMap.Clear(); // Clear contents, but keep memory if we don't change size
247 mUniformIndexMap.Resize(maxMaps);
249 uint32_t mapIndex = 0;
250 for(; mapIndex < uniformMap.Count(); ++mapIndex)
252 mUniformIndexMap[mapIndex].propertyValue = uniformMap[mapIndex].propertyPtr;
253 mUniformIndexMap[mapIndex].uniformIndex = program.RegisterUniform(uniformMap[mapIndex].uniformName);
256 for(uint32_t nodeMapIndex = 0; nodeMapIndex < uniformMapNode.Count(); ++nodeMapIndex)
258 uint32_t uniformIndex = program.RegisterUniform(uniformMapNode[nodeMapIndex].uniformName);
260 for(uint32_t i = 0; i < uniformMap.Count(); ++i)
262 if(mUniformIndexMap[i].uniformIndex == uniformIndex)
264 mUniformIndexMap[i].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr;
272 mUniformIndexMap[mapIndex].propertyValue = uniformMapNode[nodeMapIndex].propertyPtr;
273 mUniformIndexMap[mapIndex].uniformIndex = uniformIndex;
278 mUniformIndexMap.Resize(mapIndex);
281 // Set uniforms in local map
282 for(UniformIndexMappings::Iterator iter = mUniformIndexMap.Begin(),
283 end = mUniformIndexMap.End();
287 SetUniformFromProperty(bufferIndex, program, *iter);
290 GLint sizeLoc = program.GetUniformLocation(Program::UNIFORM_SIZE);
293 program.SetSizeUniform3f(sizeLoc, size.x, size.y, size.z);
297 void Renderer::SetUniformFromProperty(BufferIndex bufferIndex, Program& program, UniformIndexMap& map)
299 GLint location = program.GetUniformLocation(map.uniformIndex);
300 if(Program::UNIFORM_UNKNOWN != location)
302 // switch based on property type to use correct GL uniform setter
303 switch(map.propertyValue->GetType())
305 case Property::INTEGER:
307 program.SetUniform1i(location, map.propertyValue->GetInteger(bufferIndex));
310 case Property::FLOAT:
312 program.SetUniform1f(location, map.propertyValue->GetFloat(bufferIndex));
315 case Property::VECTOR2:
317 Vector2 value(map.propertyValue->GetVector2(bufferIndex));
318 program.SetUniform2f(location, value.x, value.y);
322 case Property::VECTOR3:
324 Vector3 value(map.propertyValue->GetVector3(bufferIndex));
325 program.SetUniform3f(location, value.x, value.y, value.z);
329 case Property::VECTOR4:
331 Vector4 value(map.propertyValue->GetVector4(bufferIndex));
332 program.SetUniform4f(location, value.x, value.y, value.z, value.w);
336 case Property::ROTATION:
338 Quaternion value(map.propertyValue->GetQuaternion(bufferIndex));
339 program.SetUniform4f(location, value.mVector.x, value.mVector.y, value.mVector.z, value.mVector.w);
343 case Property::MATRIX:
345 const Matrix& value = map.propertyValue->GetMatrix(bufferIndex);
346 program.SetUniformMatrix4fv(location, 1, value.AsFloat());
350 case Property::MATRIX3:
352 const Matrix3& value = map.propertyValue->GetMatrix3(bufferIndex);
353 program.SetUniformMatrix3fv(location, 1, value.AsFloat());
359 // Other property types are ignored
366 bool Renderer::BindTextures(Context& context, Program& program, Vector<GLuint>& boundTextures)
368 uint32_t textureUnit = 0;
371 GLint uniformLocation(-1);
372 std::vector<Render::Sampler*>& samplers(mRenderDataProvider->GetSamplers());
373 std::vector<Render::Texture*>& textures(mRenderDataProvider->GetTextures());
374 for(uint32_t i = 0; i < static_cast<uint32_t>(textures.size()) && result; ++i) // not expecting more than uint32_t of textures
378 result = textures[i]->Bind(context, textureUnit, samplers[i]);
379 boundTextures.PushBack(textures[i]->GetId());
380 if(result && program.GetSamplerUniformLocation(i, uniformLocation))
382 program.SetUniform1i(uniformLocation, textureUnit);
391 void Renderer::SetFaceCullingMode(FaceCullingMode::Type mode)
393 mFaceCullingMode = mode;
397 void Renderer::SetBlendingBitMask(uint32_t bitmask)
399 mBlendingOptions.SetBitmask(bitmask);
403 void Renderer::SetBlendColor(const Vector4& color)
405 mBlendingOptions.SetBlendColor(color);
409 void Renderer::SetIndexedDrawFirstElement(uint32_t firstElement)
411 mIndexedDrawFirstElement = firstElement;
415 void Renderer::SetIndexedDrawElementsCount(uint32_t elementsCount)
417 mIndexedDrawElementsCount = elementsCount;
421 void Renderer::EnablePreMultipliedAlpha(bool enable)
423 mPremultipledAlphaEnabled = enable;
427 void Renderer::SetDepthWriteMode(DepthWriteMode::Type depthWriteMode)
429 mDepthWriteMode = depthWriteMode;
433 void Renderer::SetDepthTestMode(DepthTestMode::Type depthTestMode)
435 mDepthTestMode = depthTestMode;
439 DepthWriteMode::Type Renderer::GetDepthWriteMode() const
441 return mDepthWriteMode;
444 DepthTestMode::Type Renderer::GetDepthTestMode() const
446 return mDepthTestMode;
449 void Renderer::SetDepthFunction(DepthFunction::Type depthFunction)
451 mDepthFunction = depthFunction;
455 DepthFunction::Type Renderer::GetDepthFunction() const
457 return mDepthFunction;
460 void Renderer::SetRenderMode(RenderMode::Type renderMode)
462 mStencilParameters.renderMode = renderMode;
466 RenderMode::Type Renderer::GetRenderMode() const
468 return mStencilParameters.renderMode;
471 void Renderer::SetStencilFunction(StencilFunction::Type stencilFunction)
473 mStencilParameters.stencilFunction = stencilFunction;
477 StencilFunction::Type Renderer::GetStencilFunction() const
479 return mStencilParameters.stencilFunction;
482 void Renderer::SetStencilFunctionMask(int stencilFunctionMask)
484 mStencilParameters.stencilFunctionMask = stencilFunctionMask;
488 int Renderer::GetStencilFunctionMask() const
490 return mStencilParameters.stencilFunctionMask;
493 void Renderer::SetStencilFunctionReference(int stencilFunctionReference)
495 mStencilParameters.stencilFunctionReference = stencilFunctionReference;
499 int Renderer::GetStencilFunctionReference() const
501 return mStencilParameters.stencilFunctionReference;
504 void Renderer::SetStencilMask(int stencilMask)
506 mStencilParameters.stencilMask = stencilMask;
510 int Renderer::GetStencilMask() const
512 return mStencilParameters.stencilMask;
515 void Renderer::SetStencilOperationOnFail(StencilOperation::Type stencilOperationOnFail)
517 mStencilParameters.stencilOperationOnFail = stencilOperationOnFail;
521 StencilOperation::Type Renderer::GetStencilOperationOnFail() const
523 return mStencilParameters.stencilOperationOnFail;
526 void Renderer::SetStencilOperationOnZFail(StencilOperation::Type stencilOperationOnZFail)
528 mStencilParameters.stencilOperationOnZFail = stencilOperationOnZFail;
532 StencilOperation::Type Renderer::GetStencilOperationOnZFail() const
534 return mStencilParameters.stencilOperationOnZFail;
537 void Renderer::SetStencilOperationOnZPass(StencilOperation::Type stencilOperationOnZPass)
539 mStencilParameters.stencilOperationOnZPass = stencilOperationOnZPass;
543 StencilOperation::Type Renderer::GetStencilOperationOnZPass() const
545 return mStencilParameters.stencilOperationOnZPass;
548 void Renderer::Upload(Context& context)
550 mGeometry->Upload(context);
553 void Renderer::Render(Context& context,
554 BufferIndex bufferIndex,
555 const SceneGraph::NodeDataProvider& node,
556 const Matrix& modelMatrix,
557 const Matrix& modelViewMatrix,
558 const Matrix& viewMatrix,
559 const Matrix& projectionMatrix,
562 Vector<GLuint>& boundTextures,
563 const Dali::Internal::SceneGraph::RenderInstruction& instruction,
566 // Before doing anything test if the call happens in the right queue
567 if(mDrawCommands.empty() && queueIndex > 0)
573 std::vector<DevelRenderer::DrawCommand*> commands;
574 for(auto& cmd : mDrawCommands)
576 if(cmd.queue == queueIndex)
578 commands.emplace_back(&cmd);
582 // Have commands but nothing to be drawn - abort
583 if(!mDrawCommands.empty() && commands.empty())
588 // Get the program to use:
589 Program* program = mRenderDataProvider->GetShader().GetProgram();
592 DALI_LOG_ERROR("Failed to get program for shader at address %p.\n", reinterpret_cast<void*>(&mRenderDataProvider->GetShader()));
597 const Dali::Internal::SceneGraph::Camera* cam = instruction.GetCamera();
598 if(cam->GetReflectionUsed())
600 auto adjFaceCullingMode = mFaceCullingMode;
601 switch(mFaceCullingMode)
603 case FaceCullingMode::Type::FRONT:
605 adjFaceCullingMode = FaceCullingMode::Type::BACK;
608 case FaceCullingMode::Type::BACK:
610 adjFaceCullingMode = FaceCullingMode::Type::FRONT;
615 // nothing to do, leave culling as it is
618 context.CullFace(adjFaceCullingMode);
622 context.CullFace(mFaceCullingMode);
625 // Take the program into use so we can send uniforms to it
628 if(DALI_LIKELY(BindTextures(context, *program, boundTextures)))
630 // Only set up and draw if we have textures and they are all valid
632 // set projection and view matrix if program has not yet received them yet this frame
633 SetMatrices(*program, modelMatrix, viewMatrix, projectionMatrix, modelViewMatrix);
636 GLint loc = program->GetUniformLocation(Program::UNIFORM_COLOR);
637 if(Program::UNIFORM_UNKNOWN != loc)
639 const Vector4& color = node.GetRenderColor(bufferIndex);
640 if(mPremultipledAlphaEnabled)
642 float alpha = color.a * mRenderDataProvider->GetOpacity(bufferIndex);
643 program->SetUniform4f(loc, color.r * alpha, color.g * alpha, color.b * alpha, alpha);
647 program->SetUniform4f(loc, color.r, color.g, color.b, color.a * mRenderDataProvider->GetOpacity(bufferIndex));
651 SetUniforms(bufferIndex, node, size, *program);
653 if(mUpdateAttributesLocation || mGeometry->AttributesChanged())
655 mGeometry->GetAttributeLocationFromProgram(mAttributesLocation, *program, bufferIndex);
656 mUpdateAttributesLocation = false;
659 if(mBlendingOptions.IsAdvancedBlendEquationApplied() && mPremultipledAlphaEnabled)
661 context.BlendBarrier();
664 if(mDrawCommands.empty())
666 SetBlending(context, blend);
668 mGeometry->Draw(context,
671 mIndexedDrawFirstElement,
672 mIndexedDrawElementsCount);
676 for(auto& cmd : commands)
678 if(cmd->queue == queueIndex)
681 SetBlending(context, cmd->queue == DevelRenderer::RENDER_QUEUE_OPAQUE ? false : blend);
682 mGeometry->Draw(context, bufferIndex, mAttributesLocation, cmd->firstIndex, cmd->elementCount);
690 void Renderer::SetSortAttributes(BufferIndex bufferIndex,
691 SceneGraph::RenderInstructionProcessor::SortAttributes& sortAttributes) const
693 sortAttributes.shader = &(mRenderDataProvider->GetShader());
694 sortAttributes.geometry = mGeometry;
697 void Renderer::SetShaderChanged(bool value)
699 mShaderChanged = value;
702 bool Renderer::Updated(BufferIndex bufferIndex, const SceneGraph::NodeDataProvider* node)
710 if(mShaderChanged || mUpdateAttributesLocation || mGeometry->AttributesChanged())
715 for(const auto& texture : mRenderDataProvider->GetTextures())
717 if(texture && texture->IsNativeImage())
723 uint64_t hash = 0xc70f6907UL;
724 const SceneGraph::CollectedUniformMap& uniformMapNode = node->GetUniformMap(bufferIndex);
725 for(const auto& uniformProperty : uniformMapNode)
727 hash = uniformProperty.propertyPtr->Hash(bufferIndex, hash);
730 const SceneGraph::UniformMapDataProvider& uniformMapDataProvider = mRenderDataProvider->GetUniformMap();
731 const SceneGraph::CollectedUniformMap& uniformMap = uniformMapDataProvider.GetUniformMap(bufferIndex);
732 for(const auto& uniformProperty : uniformMap)
734 hash = uniformProperty.propertyPtr->Hash(bufferIndex, hash);
737 if(mUniformsHash != hash)
739 mUniformsHash = hash;
746 } // namespace Render
748 } // namespace Internal