2 * Copyright (c) 2018 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.
17 #pragma GCC diagnostic push
18 #pragma GCC diagnostic ignored "-Wunused-variable"
19 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
20 #pragma GCC diagnostic ignored "-Wunused-function"
23 #include "scene-graph-renderer.h"
26 #include <dali/internal/common/internal-constants.h>
27 #include <dali/internal/common/memory-pool-object-allocator.h>
28 #include <dali/internal/update/nodes/node.h>
29 #include <dali/internal/update/rendering/data-providers/node-data-provider.h>
30 #include <dali/internal/update/rendering/scene-graph-geometry.h>
31 #include <dali/internal/update/rendering/scene-graph-property-buffer.h>
32 #include <dali/internal/update/rendering/scene-graph-texture-set.h>
33 #include <dali/internal/update/rendering/scene-graph-shader.h>
35 #include <dali/graphics-api/graphics-api-controller.h>
36 #include <dali/graphics-api/graphics-api-render-command.h>
37 #include <dali/graphics-api/graphics-api-shader.h>
38 #include <dali/graphics-api/graphics-api-shader-details.h>
47 * Helper to set view and projection matrices once per program
48 * @param program to set the matrices to
49 * @param modelMatrix to set
50 * @param viewMatrix to set
51 * @param projectionMatrix to set
52 * @param modelViewMatrix to set
53 * @param modelViewProjectionMatrix to set
55 inline void SetMatrices(
56 const Dali::Matrix& modelMatrix,
57 const Dali::Matrix& viewMatrix,
58 const Dali::Matrix& projectionMatrix,
59 const Dali::Matrix& modelViewMatrix )
66 namespace // unnamed namespace
69 const unsigned int UNIFORM_MAP_READY = 0;
70 const unsigned int COPY_UNIFORM_MAP = 1;
71 const unsigned int REGENERATE_UNIFORM_MAP = 2;
73 //Memory pool used to allocate new renderers. Memory used by this pool will be released when shutting down DALi
74 Dali::Internal::MemoryPoolObjectAllocator<Dali::Internal::SceneGraph::Renderer> gRendererMemoryPool;
76 void AddMappings( Dali::Internal::SceneGraph::CollectedUniformMap& localMap, const Dali::Internal::SceneGraph::UniformMap& uniformMap )
78 // Iterate thru uniformMap.
79 // Any maps that aren't in localMap should be added in a single step
80 Dali::Internal::SceneGraph::CollectedUniformMap newUniformMappings;
82 for( unsigned int i=0, count=uniformMap.Count(); i<count; ++i )
84 Dali::Internal::SceneGraph::UniformPropertyMapping::Hash nameHash = uniformMap[i].uniformNameHash;
87 for( Dali::Internal::SceneGraph::CollectedUniformMap::Iterator iter = localMap.Begin() ; iter != localMap.End() ; ++iter )
89 const Dali::Internal::SceneGraph::UniformPropertyMapping* map = (*iter);
90 if( map->uniformNameHash == nameHash )
92 if( map->uniformName == uniformMap[i].uniformName )
101 // it's a new mapping. Add raw ptr to temporary list
102 newUniformMappings.PushBack( &uniformMap[i] );
106 if( newUniformMappings.Count() > 0 )
108 localMap.Reserve( localMap.Count() + newUniformMappings.Count() );
110 for( Dali::Internal::SceneGraph::CollectedUniformMap::Iterator iter = newUniformMappings.Begin(),
111 end = newUniformMappings.End() ;
115 const Dali::Internal::SceneGraph::UniformPropertyMapping* map = (*iter);
116 localMap.PushBack( map );
121 } // Anonymous namespace
130 Renderer* Renderer::New()
132 return new ( gRendererMemoryPool.AllocateRawThreadSafe() ) Renderer();
136 : mGraphics( nullptr ),
137 mRenderDataProvider(),
142 mStencilParameters( RenderMode::AUTO, StencilFunction::ALWAYS, 0xFF, 0x00, 0xFF, StencilOperation::KEEP, StencilOperation::KEEP, StencilOperation::KEEP ),
143 mIndexedDrawFirstElement( 0u ),
144 mIndexedDrawElementsCount( 0u ),
146 mRegenerateUniformMap( 0u ),
147 mDepthFunction( DepthFunction::LESS ),
148 mFaceCullingMode( FaceCullingMode::NONE ),
149 mBlendMode( BlendMode::AUTO ),
150 mDepthWriteMode( DepthWriteMode::AUTO ),
151 mDepthTestMode( DepthTestMode::AUTO ),
152 mPremultipledAlphaEnabled( false ),
156 mUniformMapChanged[0] = false;
157 mUniformMapChanged[1] = false;
159 // Observe our own PropertyOwner's uniform map
160 AddUniformMapObserver( *this );
163 Renderer::~Renderer()
167 mTextureSet->RemoveObserver( this );
172 mShader->RemoveConnectionObserver( *this );
177 void Renderer::operator delete( void* ptr )
179 gRendererMemoryPool.FreeThreadSafe( static_cast<Renderer*>( ptr ) );
182 void Renderer::Initialize( Integration::Graphics::Graphics& graphics )
184 mGraphics = &graphics;
186 mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
188 mRenderDataProvider = std::make_unique< RenderDataProvider >();
190 mRenderDataProvider->mUniformMapDataProvider = this;
191 mRenderDataProvider->mShader = mShader;
195 size_t textureCount = mTextureSet->GetTextureCount();
196 mRenderDataProvider->mTextures.resize( textureCount );
197 mRenderDataProvider->mSamplers.resize( textureCount );
198 for( unsigned int i(0); i<textureCount; ++i )
200 mRenderDataProvider->mTextures[i] = mTextureSet->GetTexture(i);
201 mRenderDataProvider->mSamplers[i] = mTextureSet->GetTextureSampler(i);
207 void* AllocateUniformBufferMemory( size_t size )
213 void Renderer::UpdateUniformMap( BufferIndex updateBufferIndex )
216 if( mRegenerateUniformMap > UNIFORM_MAP_READY )
218 if( mRegenerateUniformMap == REGENERATE_UNIFORM_MAP)
220 CollectedUniformMap& localMap = mCollectedUniformMap[ updateBufferIndex ];
223 const UniformMap& rendererUniformMap = PropertyOwner::GetUniformMap();
224 AddMappings( localMap, rendererUniformMap );
228 AddMappings( localMap, mShader->GetUniformMap() );
231 else if( mRegenerateUniformMap == COPY_UNIFORM_MAP )
233 // Copy old map into current map
234 CollectedUniformMap& localMap = mCollectedUniformMap[ updateBufferIndex ];
235 CollectedUniformMap& oldMap = mCollectedUniformMap[ 1-updateBufferIndex ];
237 localMap.Resize( oldMap.Count() );
239 unsigned int index=0;
240 for( CollectedUniformMap::Iterator iter = oldMap.Begin(), end = oldMap.End() ; iter != end ; ++iter, ++index )
242 localMap[index] = *iter;
246 mUniformMapChanged[updateBufferIndex] = true;
247 mRegenerateUniformMap--;
251 void Renderer::PrepareRender( BufferIndex updateBufferIndex )
253 auto& controller = mGraphics->GetController();
256 auto gfxShader = mShader->GetGfxObject();
258 if( !mGfxRenderCommand )
260 mGfxRenderCommand = controller.AllocateRenderCommand();
264 * Prepare vertex attribute buffer bindings
266 uint32_t bindingIndex { 0u };
267 uint32_t locationIndex { 0u };
268 auto vertexAttributeBindings = Graphics::API::RenderCommand::NewVertexAttributeBufferBindings();
269 for( auto&& vertexBuffer : mGeometry->GetVertexBuffers() )
271 auto attributeCountInForBuffer = vertexBuffer->GetAttributeCount();
273 // update vertex buffer if necessary
274 vertexBuffer->Update( controller );
276 for( auto i = 0u; i < attributeCountInForBuffer; ++i )
278 // create binding per attribute
279 auto binding = Graphics::API::RenderCommand::VertexAttributeBufferBinding{}
280 .SetOffset( (vertexBuffer->GetFormat()->components[i]).offset )
281 .SetBinding( bindingIndex )
282 .SetBuffer( vertexBuffer->GetGfxObject() )
283 .SetInputAttributeRate( Graphics::API::RenderCommand::InputAttributeRate::PER_VERTEX )
284 .SetLocation( locationIndex + i )
285 .SetStride( vertexBuffer->GetFormat()->size );
286 vertexAttributeBindings.emplace_back( binding );
290 UpdateUniformMap( updateBufferIndex );
292 auto& shader = mShader->GetGfxObject().Get();
293 auto uboCount = shader.GetUniformBlockCount();
295 auto pushConstantsBindings = Graphics::API::RenderCommand::NewPushConstantsBindings( uboCount );
297 // allocate new command ( may be not necessary at all )
298 // mGfxRenderCommand = Graphics::API::RenderCommandBuilder().Build();
300 // see if we need to reallocate memory for each UBO
301 // todo: do it only when shader has changed
302 if( mUboMemory.size() != uboCount )
304 mUboMemory.resize(uboCount);
307 for( auto i = 0u; i < uboCount; ++i )
309 Graphics::API::ShaderDetails::UniformBlockInfo ubInfo;
311 std::cout<<sizeof(ubInfo) << std::endl;
313 shader.GetUniformBlock( i, ubInfo );
315 if( mUboMemory[i].size() != ubInfo.size )
317 mUboMemory[i].resize( ubInfo.size );
320 // Set push constant bindings
321 auto &pushBinding = pushConstantsBindings[i];
322 pushBinding.data = mUboMemory[i].data();
323 pushBinding.size = uint32_t(mUboMemory[i].size());
324 pushBinding.binding = ubInfo.binding;
327 // add built-in uniforms
330 for( auto&& i : mCollectedUniformMap )
334 auto uniformInfo = Graphics::API::ShaderDetails::UniformInfo{};
335 if( shader.GetNamedUniform( j->uniformName, uniformInfo ) )
337 // write into correct uniform buffer
338 auto dst = (mUboMemory[uniformInfo.bufferIndex].data()+uniformInfo.offset);
339 switch( j->propertyPtr->GetType() )
341 case Property::Type::FLOAT:
342 case Property::Type::INTEGER:
343 case Property::Type::BOOLEAN:
345 std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing 32bit offset: " << uniformInfo.offset << ", size: " << sizeof(float) << std::endl;
346 memcpy( dst, &j->propertyPtr->GetFloat( updateBufferIndex ), sizeof(float) );
349 case Property::Type::VECTOR2:
351 std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing vec2 offset: " << uniformInfo.offset << ", size: " << sizeof(Vector2) << std::endl;
352 memcpy( dst, &j->propertyPtr->GetVector2( updateBufferIndex ), sizeof(Vector2) );
355 case Property::Type::VECTOR3:
357 std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing vec3 offset: " << uniformInfo.offset << ", size: " << sizeof(Vector3) << std::endl;
358 memcpy( dst, &j->propertyPtr->GetVector3( updateBufferIndex ), sizeof(Vector3) );
361 case Property::Type::VECTOR4:
363 std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing vec4 offset: " << uniformInfo.offset << ", size: " << sizeof(Vector4) << std::endl;
364 memcpy( dst, &j->propertyPtr->GetVector4( updateBufferIndex ), sizeof(Vector4) );
367 case Property::Type::MATRIX:
369 std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing mat4 offset: " << uniformInfo.offset << ", size: " << sizeof(Matrix) << std::endl;
370 memcpy( dst, &j->propertyPtr->GetMatrix( updateBufferIndex ), sizeof(Matrix) );
373 case Property::Type::MATRIX3:
375 std::cout << uniformInfo.name << ":["<<uniformInfo.bufferIndex<<"]: " << "Writing mat3 offset: " << uniformInfo.offset << ", size: " << sizeof(Matrix3) << std::endl;
376 memcpy( dst, &j->propertyPtr->GetMatrix3( updateBufferIndex ), sizeof(Matrix3) );
389 auto textureBindings = Graphics::API::RenderCommand::NewTextureBindings();
390 auto samplers = shader.GetSamplers();
392 for( auto i = 0u; i < mTextureSet->GetTextureCount(); ++i )
394 auto texture = mTextureSet->GetTexture( i );
395 auto gfxTexture = texture->GetGfxObject();
396 auto binding = Graphics::API::RenderCommand::TextureBinding{}
397 .SetBinding( samplers[i].binding )
398 .SetTexture( texture->GetGfxObject() )
399 .SetSampler( nullptr );
401 textureBindings.emplace_back( binding );
404 // Build render command
405 // todo: this may be deferred until all render items are sorted, otherwise
406 // certain optimisations cannot be done
408 const auto& vb = mGeometry->GetVertexBuffers()[0];
410 mGfxRenderCommand->PushConstants( std::move(pushConstantsBindings) );
411 mGfxRenderCommand->BindVertexBuffers( std::move(vertexAttributeBindings) );
412 mGfxRenderCommand->BindTextures( std::move(textureBindings) );
413 mGfxRenderCommand->BindRenderState( std::move( Graphics::API::RenderCommand::RenderState{}
414 .SetShader( mShader->GetGfxObject() ) ) );
415 mGfxRenderCommand->Draw( std::move(Graphics::API::RenderCommand::DrawCommand{}
417 .SetDrawType( Graphics::API::RenderCommand::DrawType::VERTEX_DRAW )
418 .SetFirstInstance(0u)
419 .SetVertexCount( vb->GetElementCount() )
420 .SetInstanceCount( 1u )));
422 std::cout << "done\n";
425 void Renderer::WriteUniform( const std::string& name, const void* data, uint32_t size )
427 auto& gfxShader = mShader->GetGfxObject().Get();
428 auto uniformInfo = Graphics::API::ShaderDetails::UniformInfo{};
429 if( gfxShader.GetNamedUniform( name, uniformInfo ) )
431 auto dst = (mUboMemory[uniformInfo.bufferIndex].data()+uniformInfo.offset);
432 memcpy( dst, data, size );
437 void Renderer::SetTextures( TextureSet* textureSet )
439 DALI_ASSERT_DEBUG( textureSet != NULL && "Texture set pointer is NULL" );
443 mTextureSet->RemoveObserver(this);
446 mTextureSet = textureSet;
447 mTextureSet->AddObserver( this );
448 mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
451 void Renderer::SetShader( Shader* shader )
453 DALI_ASSERT_DEBUG( shader != NULL && "Shader pointer is NULL" );
457 mShader->RemoveConnectionObserver(*this);
461 mShader->AddConnectionObserver( *this );
462 mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
465 void Renderer::SetGeometry( SceneGraph::Geometry* geometry )
467 DALI_ASSERT_DEBUG( geometry != NULL && "Geometry pointer is NULL");
468 mGeometry = geometry;
471 void Renderer::SetDepthIndex( int depthIndex )
473 mDepthIndex = depthIndex;
476 void Renderer::SetFaceCullingMode( FaceCullingMode::Type faceCullingMode )
478 mFaceCullingMode = faceCullingMode;
481 void Renderer::SetBlendMode( BlendMode::Type blendingMode )
483 mBlendMode = blendingMode;
486 void Renderer::SetBlendingOptions( unsigned int options )
488 if( mBlendBitmask != options)
490 mBlendBitmask = options;
494 void Renderer::SetBlendColor( const Vector4& blendColor )
496 if( blendColor == Color::TRANSPARENT )
504 mBlendColor = new Vector4( blendColor );
508 *mBlendColor = blendColor;
513 void Renderer::SetIndexedDrawFirstElement( size_t firstElement )
515 mIndexedDrawFirstElement = firstElement;
518 void Renderer::SetIndexedDrawElementsCount( size_t elementsCount )
520 mIndexedDrawElementsCount = elementsCount;
523 void Renderer::EnablePreMultipliedAlpha( bool preMultipled )
525 mPremultipledAlphaEnabled = preMultipled;
528 void Renderer::SetDepthWriteMode( DepthWriteMode::Type depthWriteMode )
530 mDepthWriteMode = depthWriteMode;
533 void Renderer::SetDepthTestMode( DepthTestMode::Type depthTestMode )
535 mDepthTestMode = depthTestMode;
538 void Renderer::SetDepthFunction( DepthFunction::Type depthFunction )
540 mDepthFunction = depthFunction;
543 void Renderer::SetRenderMode( RenderMode::Type mode )
545 mStencilParameters.renderMode = mode;
548 void Renderer::SetStencilFunction( StencilFunction::Type stencilFunction )
550 mStencilParameters.stencilFunction = stencilFunction;
553 void Renderer::SetStencilFunctionMask( int stencilFunctionMask )
555 mStencilParameters.stencilFunctionMask = stencilFunctionMask;
558 void Renderer::SetStencilFunctionReference( int stencilFunctionReference )
560 mStencilParameters.stencilFunctionReference = stencilFunctionReference;
563 void Renderer::SetStencilMask( int stencilMask )
565 mStencilParameters.stencilMask = stencilMask;
568 void Renderer::SetStencilOperationOnFail( StencilOperation::Type stencilOperationOnFail )
570 mStencilParameters.stencilOperationOnFail = stencilOperationOnFail;
573 void Renderer::SetStencilOperationOnZFail( StencilOperation::Type stencilOperationOnZFail )
575 mStencilParameters.stencilOperationOnZFail = stencilOperationOnZFail;
578 void Renderer::SetStencilOperationOnZPass( StencilOperation::Type stencilOperationOnZPass )
580 mStencilParameters.stencilOperationOnZPass = stencilOperationOnZPass;
583 const Vector4& Renderer::GetBlendColor() const
589 return Color::TRANSPARENT;
592 const CollectedUniformMap& Renderer::GetUniformMap( BufferIndex bufferIndex ) const
594 return mCollectedUniformMap[bufferIndex];
597 Renderer::Opacity Renderer::GetOpacity( BufferIndex updateBufferIndex, const Node& node ) const
599 Renderer::Opacity opacity = Renderer::OPAQUE;
603 case BlendMode::ON: // If the renderer should always be use blending
605 opacity = Renderer::TRANSLUCENT;
608 case BlendMode::AUTO:
610 bool shaderRequiresBlending( mShader->HintEnabled( Dali::Shader::Hint::OUTPUT_IS_TRANSPARENT ) );
611 if( shaderRequiresBlending || ( mTextureSet && mTextureSet->HasAlpha() ) )
613 opacity = Renderer::TRANSLUCENT;
615 else // renderer should determine opacity using the actor color
617 float alpha = node.GetWorldColor( updateBufferIndex ).a;
618 if( alpha <= FULLY_TRANSPARENT )
620 opacity = TRANSPARENT;
622 else if( alpha <= FULLY_OPAQUE )
624 opacity = TRANSLUCENT;
629 case BlendMode::OFF: // the renderer should never use blending
632 opacity = Renderer::OPAQUE;
640 void Renderer::TextureSetChanged()
644 void Renderer::TextureSetDeleted()
649 void Renderer::ConnectionsChanged( PropertyOwner& object )
651 // One of our child objects has changed it's connections. Ensure the uniform
652 // map gets regenerated during PrepareRender
653 mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
656 void Renderer::ConnectedUniformMapChanged()
658 mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
661 void Renderer::UniformMappingsChanged( const UniformMap& mappings )
663 // The mappings are either from PropertyOwner base class, or the Actor
664 mRegenerateUniformMap = REGENERATE_UNIFORM_MAP;
667 void Renderer::ObservedObjectDestroyed(PropertyOwner& owner)
669 if( reinterpret_cast<PropertyOwner*>(mShader) == &owner )
675 } // namespace SceneGraph
676 } // namespace Internal
679 #pragma GCC diagnostic pop