utc-Dali-Internal-FixedSizeMemoryPool.cpp
utc-Dali-Internal-MemoryPoolObjectAllocator.cpp
utc-Dali-Internal-FrustumCulling.cpp
+ utc-Dali-Internal-GeometryBatcher.cpp
)
LIST(APPEND TC_SOURCES
--- /dev/null
+#include <dali/public-api/dali-core.h>
+#include <dali/internal/event/actors/actor-impl.h>
+#include <dali/internal/update/manager/geometry-batcher.h>
+
+#include <dali-test-suite-utils.h>
+
+namespace
+{
+
+class MockActor : public Dali::Internal::Actor
+{
+public:
+ inline const Dali::Internal::SceneGraph::Node* GetNode()
+ {
+ return mNode;
+ }
+
+ inline const bool IsNodeBatchParent()
+ {
+ return mNode->mIsBatchParent;
+ }
+};
+
+Geometry CreateBatchQuadGeometryVector2( Vector4 texCoords )
+{
+ const float halfWidth = 0.5f;
+ const float halfHeight = 0.5f;
+ struct QuadVertex {
+ QuadVertex( const Vector2& vertexPosition, const Vector2& vertexTexCoords )
+ : position( vertexPosition ),
+ texCoords( vertexTexCoords )
+ {}
+ Vector2 position;
+ Vector2 texCoords;
+ };
+
+ // special case, when texture takes whole space
+ if( texCoords == Vector4::ZERO )
+ {
+ texCoords = Vector4(0.0f, 0.0f, 1.0f, 1.0f);
+ }
+
+ QuadVertex quadVertexData[6] =
+ {
+ QuadVertex( Vector2(-halfWidth, -halfHeight ), Vector2(texCoords.x, texCoords.y) ),
+ QuadVertex( Vector2( halfWidth, -halfHeight ), Vector2(texCoords.z, texCoords.y) ),
+ QuadVertex( Vector2(-halfWidth, halfHeight ), Vector2(texCoords.x, texCoords.w) ),
+ QuadVertex( Vector2( halfWidth, -halfHeight ), Vector2(texCoords.z, texCoords.y) ),
+ QuadVertex( Vector2(-halfWidth, halfHeight ), Vector2(texCoords.x, texCoords.w) ),
+ QuadVertex( Vector2( halfWidth, halfHeight ), Vector2(texCoords.z, texCoords.w) ),
+ };
+
+ Property::Map vertexFormat;
+ vertexFormat[ "aPosition" ] = Property::VECTOR2;
+ vertexFormat[ "aTexCoord" ] = Property::VECTOR2;
+ PropertyBuffer vertexBuffer = PropertyBuffer::New( vertexFormat );
+ vertexBuffer.SetData( quadVertexData, 6 );
+
+ // create geometry as normal, single quad
+ Geometry geometry = Geometry::New();
+ geometry.AddVertexBuffer( vertexBuffer );
+ geometry.SetType( Geometry::TRIANGLES );
+
+ return geometry;
+}
+
+Geometry CreateBatchQuadGeometryVector3( Vector4 texCoords )
+{
+ const float halfWidth = 0.5f;
+ const float halfHeight = 0.5f;
+ struct QuadVertex {
+ QuadVertex( const Vector3& vertexPosition, const Vector2& vertexTexCoords )
+ : position( vertexPosition ),
+ texCoords( vertexTexCoords )
+ {}
+ Vector3 position;
+ Vector2 texCoords;
+ };
+
+ // special case, when texture takes whole space
+ if( texCoords == Vector4::ZERO )
+ {
+ texCoords = Vector4(0.0f, 0.0f, 1.0f, 1.0f);
+ }
+
+ QuadVertex quadVertexData[6] =
+ {
+ QuadVertex( Vector3(-halfWidth, -halfHeight, 0.0f ), Vector2(texCoords.x, texCoords.y) ),
+ QuadVertex( Vector3( halfWidth, -halfHeight, 0.0f ), Vector2(texCoords.z, texCoords.y) ),
+ QuadVertex( Vector3(-halfWidth, halfHeight, 0.0f ), Vector2(texCoords.x, texCoords.w) ),
+ QuadVertex( Vector3( halfWidth, -halfHeight, 0.0f ), Vector2(texCoords.z, texCoords.y) ),
+ QuadVertex( Vector3(-halfWidth, halfHeight, 0.0f ), Vector2(texCoords.x, texCoords.w) ),
+ QuadVertex( Vector3( halfWidth, halfHeight, 0.0f ), Vector2(texCoords.z, texCoords.w) ),
+ };
+
+ Property::Map vertexFormat;
+ vertexFormat[ "aPosition" ] = Property::VECTOR3;
+ vertexFormat[ "aTexCoord" ] = Property::VECTOR2;
+ PropertyBuffer vertexBuffer = PropertyBuffer::New( vertexFormat );
+ vertexBuffer.SetData( quadVertexData, 6 );
+
+ // create geometry as normal, single quad
+ Geometry geometry = Geometry::New();
+ geometry.AddVertexBuffer( vertexBuffer );
+ geometry.SetType( Geometry::TRIANGLES );
+ return geometry;
+}
+
+Geometry CreateBatchQuadGeometryVector4( Vector4 texCoords )
+{
+ const float halfWidth = 0.5f;
+ const float halfHeight = 0.5f;
+ struct QuadVertex {
+ QuadVertex( const Vector4& vertexPosition, const Vector2& vertexTexCoords )
+ : position( vertexPosition ),
+ texCoords( vertexTexCoords )
+ {}
+ Vector4 position;
+ Vector2 texCoords;
+ };
+
+ // special case, when texture takes whole space
+ if( texCoords == Vector4::ZERO )
+ {
+ texCoords = Vector4(0.0f, 0.0f, 1.0f, 1.0f);
+ }
+
+ QuadVertex quadVertexData[6] =
+ {
+ QuadVertex( Vector4(-halfWidth, -halfHeight, 0.0f, 1.0f ), Vector2(texCoords.x, texCoords.y) ),
+ QuadVertex( Vector4( halfWidth, -halfHeight, 0.0f, 1.0f ), Vector2(texCoords.z, texCoords.y) ),
+ QuadVertex( Vector4(-halfWidth, halfHeight, 0.0f, 1.0f ), Vector2(texCoords.x, texCoords.w) ),
+ QuadVertex( Vector4( halfWidth, -halfHeight, 0.0f, 1.0f ), Vector2(texCoords.z, texCoords.y) ),
+ QuadVertex( Vector4(-halfWidth, halfHeight, 0.0f, 1.0f ), Vector2(texCoords.x, texCoords.w) ),
+ QuadVertex( Vector4( halfWidth, halfHeight, 0.0f, 1.0f ), Vector2(texCoords.z, texCoords.w) ),
+ };
+
+ Property::Map vertexFormat;
+ vertexFormat[ "aPosition" ] = Property::VECTOR4;
+ vertexFormat[ "aTexCoord" ] = Property::VECTOR2;
+ PropertyBuffer vertexBuffer = PropertyBuffer::New( vertexFormat );
+ vertexBuffer.SetData( quadVertexData, 6 );
+
+ // create geometry as normal, single quad
+ Geometry geometry = Geometry::New();
+ geometry.AddVertexBuffer( vertexBuffer );
+ geometry.SetType( Geometry::TRIANGLES );
+ return geometry;
+}
+
+
+void CreateShadersAndTextureSets( Shader* shaders, size_t shaderCount, TextureSet* textureSets, size_t textureSetCount )
+{
+ for( size_t i = 0; i < shaderCount; ++i )
+ {
+ shaders[i] = Shader::New( "", "" );
+ }
+
+ for( size_t i = 0; i < textureSetCount; ++i )
+ {
+ textureSets[i] = TextureSet::New();
+ }
+}
+
+Vector4 WHOLE_IMAGE( 0.0f, 0.0f, 1.0f, 1.0f );
+
+Actor CreateActor( Actor& parent, Shader& shader, TextureSet& textureSet, Vector3 position, Vector4 texCoords, Geometry(*geomfunc)(Vector4) = CreateBatchQuadGeometryVector2 )
+{
+ Geometry geometry = geomfunc( texCoords );
+ Renderer renderer = Renderer::New( geometry, shader );
+
+ renderer.SetTextures( textureSet );
+ renderer.SetProperty( Dali::Renderer::Property::BATCHING_ENABLED, true );
+
+ Actor actor = Actor::New();
+ actor.SetPosition( position );
+ parent.Add( actor );
+ actor.AddRenderer( renderer );
+ return actor;
+}
+
+Actor CreateActor( Vector3 position )
+{
+ Actor actor = Actor::New();
+ actor.SetPosition( position );
+ return actor;
+}
+
+
+Actor CreateBatchParent( Vector3 pos )
+{
+ Actor actor = Actor::New();
+ actor.SetProperty( Actor::Property::BATCH_PARENT, true );
+ actor.SetPosition( pos );
+ Stage::GetCurrent().Add( actor );
+ return actor;
+}
+
+void AddChildren( Actor parent, Actor* children, size_t size )
+{
+ for( size_t i = 0; i < size; ++i )
+ {
+ parent.Add( children[i] );
+ }
+}
+
+}
+
+int UtcDaliGeometryBatcherBatchLevel0(void)
+{
+ TestApplication app;
+ TestGlAbstraction& glAbstraction = app.GetGlAbstraction();
+ glAbstraction.EnableDrawCallTrace( true );
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+
+ Shader shaders[1];
+ TextureSet textureSets[1];
+
+ CreateShadersAndTextureSets( shaders, 1, textureSets, 1 );
+ Actor batchParent = CreateBatchParent( Vector3::ZERO );
+ batchParent.SetSize( Stage::GetCurrent().GetSize() );
+
+ Actor children[] = {
+ CreateActor( batchParent, shaders[0], textureSets[0], Vector3( 0.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[0], Vector3( 10.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[0], Vector3( 20.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[0], Vector3( 30.0f, 0.0f, 0.0f ), WHOLE_IMAGE )
+ };
+
+ app.SendNotification();
+ app.Render( 16 );
+ app.SendNotification();
+ app.Render( 16 );
+
+ // should be 1 draw call
+ {
+ int result = drawTrace.CountMethod( "DrawElements");
+ DALI_TEST_CHECK( result == 1 );
+ }
+
+ // remove actor
+ batchParent.Remove( children[0] );
+ children[0].Reset();
+
+ // update
+ app.SendNotification();
+ app.Render( 16 );
+
+ // test geometry for that batch, 1 batch, 3 children, 18 elements in the buffer
+ //Dali::Internal::Actor& actor = GetImplementation( children[1] );
+ MockActor* mockActor = static_cast<MockActor*>( &GetImplementation( children[1] ) );
+ Dali::Internal::SceneGraph::GeometryBatcher* geometryBatcher = mockActor->GetNode()->mGeometryBatcher;
+ DALI_TEST_CHECK( geometryBatcher ); // must not be NULL
+
+ Dali::Internal::Render::Geometry* geometry = geometryBatcher->GetGeometry( 0 );
+ int elementCount = geometry->GetPropertyBuffer(0)->GetElementCount();
+ DALI_TEST_CHECK( elementCount == 18 );
+
+ // delete batch parent
+ Stage::GetCurrent().Remove( batchParent );
+ batchParent.Reset();
+
+ // update
+ app.SendNotification();
+ app.Render( 16 );
+
+ END_TEST;
+}
+
+int UtcDaliGeometryBatcherBatchMultipleTextureSet(void)
+{
+ TestApplication app;
+ TestGlAbstraction& glAbstraction = app.GetGlAbstraction();
+ glAbstraction.EnableDrawCallTrace( true );
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+
+ Shader shaders[1];
+ TextureSet textureSets[3];
+ CreateShadersAndTextureSets( shaders, 1, textureSets, 3 );
+
+ Actor batchParent = CreateBatchParent( Vector3::ZERO );
+ batchParent.SetSize( Stage::GetCurrent().GetSize() );
+
+ Actor children[] = {
+ CreateActor( batchParent, shaders[0], textureSets[0], Vector3( 0.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[0], Vector3( 10.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[0], Vector3( 20.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[0], Vector3( 30.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[1], Vector3( 0.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[2], Vector3( 10.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[2], Vector3( 20.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[1], Vector3( 30.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[1], Vector3( 0.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[1], Vector3( 10.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[2], Vector3( 20.0f, 0.0f, 0.0f ), WHOLE_IMAGE ),
+ CreateActor( batchParent, shaders[0], textureSets[2], Vector3( 30.0f, 0.0f, 0.0f ), WHOLE_IMAGE )
+ };
+
+ // must update twice
+ app.SendNotification();
+ app.Render( 16 );
+ app.SendNotification();
+ app.Render( 16 );
+
+ // should be 3 draw calls here
+ {
+ int result = drawTrace.CountMethod( "DrawElements");
+ DALI_TEST_CHECK( result == 3 );
+ }
+
+ // test assigned indices
+ {
+ bool indicesTest( true );
+ for( size_t i = 0; i < 12; ++i )
+ {
+ MockActor* mockActor = static_cast<MockActor*>( &GetImplementation( children[1] ) );
+ if( mockActor->GetNode()->mBatchIndex == BATCH_NULL_HANDLE )
+ {
+ indicesTest = false;
+ }
+ }
+ DALI_TEST_CHECK( indicesTest );
+ }
+
+ END_TEST;
+}
+
+int UtcDaliGeometryBatcherSettingBatchParent(void)
+{
+ TestApplication app;
+
+ Shader shaders[1];
+ TextureSet textureSets[1];
+ CreateShadersAndTextureSets( shaders, 1, textureSets, 1 );
+
+ Actor batchParent = CreateBatchParent( Vector3::ZERO );
+ batchParent.SetSize( Stage::GetCurrent().GetSize() );
+ app.SendNotification();
+ app.Render( 16 );
+
+ MockActor* mockActor = static_cast<MockActor*>( &GetImplementation( batchParent ) );
+ DALI_TEST_CHECK( mockActor->IsNodeBatchParent() );
+
+ END_TEST;
+}
+
+int UtcDaliGeometryBatcherBatchMultipleParents(void)
+{
+ TestApplication app;
+ TestGlAbstraction& glAbstraction = app.GetGlAbstraction();
+ glAbstraction.EnableDrawCallTrace( true );
+ TraceCallStack& drawTrace = glAbstraction.GetDrawTrace();
+
+ Shader shaders[2];
+ TextureSet textureSets[2];
+ CreateShadersAndTextureSets( shaders, 2, textureSets, 2 );
+
+ Actor batchParent0 = CreateBatchParent( Vector3::ZERO ); // Vector2
+ batchParent0.SetSize( Stage::GetCurrent().GetSize() );
+ Actor batchParent1 = CreateBatchParent( Vector3::ZERO ); // Vector3
+ batchParent1.SetSize( Stage::GetCurrent().GetSize() );
+ Actor batchParent2 = CreateBatchParent( Vector3::ZERO ); // Vector4
+ batchParent2.SetSize( Stage::GetCurrent().GetSize() );
+
+ CreateActor( batchParent0, shaders[0], textureSets[0], Vector3( 0.0f, 0.0f, 0.0f ), WHOLE_IMAGE );
+ CreateActor( batchParent0, shaders[0], textureSets[0], Vector3( 10.0f, 0.0f, 0.0f ), WHOLE_IMAGE );
+ CreateActor( batchParent0, shaders[0], textureSets[0], Vector3( 20.0f, 0.0f, 0.0f ), WHOLE_IMAGE );
+ CreateActor( batchParent0, shaders[0], textureSets[0], Vector3( 30.0f, 0.0f, 0.0f ), WHOLE_IMAGE );
+ CreateActor( batchParent0, shaders[0], textureSets[0], Vector3( 0.0f, 0.0f, 0.0f ), WHOLE_IMAGE );
+ CreateActor( batchParent1, shaders[1], textureSets[1], Vector3( 0.0f, 0.0f, 0.0f ), WHOLE_IMAGE, CreateBatchQuadGeometryVector3 );
+ CreateActor( batchParent1, shaders[1], textureSets[1], Vector3( 10.0f, 0.0f, 0.0f ), WHOLE_IMAGE, CreateBatchQuadGeometryVector3 );
+ CreateActor( batchParent1, shaders[1], textureSets[1], Vector3( 20.0f, 0.0f, 0.0f ), WHOLE_IMAGE, CreateBatchQuadGeometryVector3 );
+ CreateActor( batchParent2, shaders[0], textureSets[1], Vector3( 30.0f, 0.0f, 0.0f ), WHOLE_IMAGE, CreateBatchQuadGeometryVector4 );
+ CreateActor( batchParent2, shaders[0], textureSets[1], Vector3( 0.0f, 0.0f, 0.0f ), WHOLE_IMAGE, CreateBatchQuadGeometryVector4 );
+ CreateActor( batchParent2, shaders[0], textureSets[1], Vector3( 30.0f, 0.0f, 0.0f ), WHOLE_IMAGE, CreateBatchQuadGeometryVector4 );
+ CreateActor( batchParent2, shaders[0], textureSets[1], Vector3( 0.0f, 0.0f, 0.0f ), WHOLE_IMAGE, CreateBatchQuadGeometryVector4 );
+
+ // must update twice
+ app.SendNotification();
+ app.Render( 16 );
+ app.SendNotification();
+ app.Render( 16 );
+
+ // should be 3 draw calls here
+ {
+ int result = drawTrace.CountMethod( "DrawElements");
+ DALI_TEST_EQUALS( result, 3, TEST_LOCATION );
+ }
+
+ // delete batch parent
+ Stage::GetCurrent().Remove( batchParent1 );
+ batchParent1.Reset();
+ drawTrace.Reset();
+ app.SendNotification();
+ app.Render( 16 );
+ // should be 2 draw calls here
+ {
+ int result = drawTrace.CountMethod( "DrawElements");
+ DALI_TEST_EQUALS( result, 2, TEST_LOCATION );
+ }
+
+ END_TEST;
+}
{
return CreateBufferImage(4, 4, Color::WHITE);
}
+
+namespace Test
+{
+
+struct ObjectDestructionFunctor
+{
+ // Create a ObjectDestructionFunctor passing in a Dali::RefObject* to be monitored and a bool variable.
+ // Create ObjectRegistry instance and connect to the ObjectDestroyedSignal passing in the above functor for the callback.
+ // Get the ObjectPointer (Actor::GetObjectPtr) of the Actor to be checked for destruction and assign it to the Dali::RefObject*
+ // Check the bool variable which would be true when object destroyed.
+ ObjectDestructionFunctor( Dali::RefObject* objectPtr, bool& refObjectDestroyed )
+ : refObjectPointerToCheck( objectPtr ),
+ refObjectDestroyedBoolean( refObjectDestroyed )
+ {
+ refObjectDestroyed = false;
+ }
+
+ void operator()( const Dali::RefObject* objectPointer )
+ {
+ if ( refObjectPointerToCheck == objectPointer )
+ {
+ refObjectDestroyedBoolean = true;
+ }
+ }
+
+ Dali::RefObject* refObjectPointerToCheck;
+ bool& refObjectDestroyedBoolean;
+};
+
+ObjectDestructionTracker::ObjectDestructionTracker()
+ :mRefObjectDestroyed( false)
+{
+}
+
+void ObjectDestructionTracker::Start( Actor actor )
+{
+ ObjectDestructionFunctor destructionFunctor( actor.GetObjectPtr(), mRefObjectDestroyed );
+
+ ObjectRegistry objectRegistry = Stage::GetCurrent().GetObjectRegistry();
+ objectRegistry.ObjectDestroyedSignal().Connect( this, destructionFunctor );
+}
+
+bool ObjectDestructionTracker::IsDestroyed()
+{
+ return mRefObjectDestroyed;
+}
+
+} // namespace Test
BufferImage CreateBufferImage();
BufferImage CreateBufferImage(int width, int height, const Vector4& color);
+// Test namespace to prevent pollution of Dali namespace, add Test helper functions here
+namespace Test
+{
+/**
+ * @brief
+ *
+ * Helper to check object destruction occurred
+ * 1) In main part of code create an ObjectDestructionTracker
+ * 2) Within sub section of main create object Actor test and call Start with Actor to test for destruction
+ * 3) Perform code which is expected to destroy Actor
+ * 4) Back in main part of code use IsDestroyed() to test if Actor was destroyed
+ */
+class ObjectDestructionTracker : public ConnectionTracker
+{
+public:
+
+ /**
+ * @brief Call in main part of code
+ */
+ ObjectDestructionTracker();
+
+ /**
+ * @brief Call in sub bock of code where the Actor being checked is still alive.
+ *
+ * @param[in] actor Actor to be checked for destruction
+ */
+ void Start( Actor actor );
+
+ /**
+ * @brief Call to check if Actor alive or destroyed.
+ *
+ * @return bool true if Actor was destroyed
+ */
+ bool IsDestroyed();
+
+private:
+ bool mRefObjectDestroyed;
+};
+
+} // namespace Test
+
#endif // __DALI_TEST_SUITE_UTILS_H__
mLastShaderIdUsed = 0;
mLastProgramIdUsed = 0;
mLastUniformIdUsed = 0;
+ mLastDepthMask = false;
mUniforms.clear();
mProgramUniforms1i.clear();
mProgramUniforms4f.clear();
mCullFaceTrace.Reset();
+ mDepthFunctionTrace.Reset();
mEnableDisableTrace.Reset();
mShaderTrace.Reset();
+ mStencilFunctionTrace.Reset();
mTextureTrace.Reset();
mTexParamaterTrace.Reset();
mDrawTrace.Reset();
-#ifndef __TEST_GL_ABSTRACTION_H__
-#define __TEST_GL_ABSTRACTION_H__
+#ifndef TEST_GL_ABSTRACTION_H
+#define TEST_GL_ABSTRACTION_H
/*
- * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
inline void DepthMask(GLboolean flag)
{
+ mLastDepthMask = flag;
+ }
+
+ inline bool GetLastDepthMask() const
+ {
+ return mLastDepthMask;
}
inline void DepthRangef(GLclampf zNear, GLclampf zFar)
GLenum mLastBlendFuncSrcAlpha;
GLenum mLastBlendFuncDstAlpha;
+ GLboolean mLastDepthMask;
+
// Data for manipulating the IDs returned by GenTextures
GLuint mLastAutoTextureIdUsed;
std::vector<GLuint> mNextTextureIds;
bool BlendDisabled(const Dali::TraceCallStack& callStack);
-
-
-#endif // __TEST_GL_ES_H__
+#endif // TEST_GL_ABSTRACTION_H
const BlendFactor::Type DEFAULT_BLEND_FACTOR_SRC_ALPHA( BlendFactor::ONE );
const BlendFactor::Type DEFAULT_BLEND_FACTOR_DEST_ALPHA( BlendFactor::ONE_MINUS_SRC_ALPHA );
-const BlendEquation::Type DEFAULT_BLEND_EQUATION_RGB( BlendEquation::ADD );
-const BlendEquation::Type DEFAULT_BLEND_EQUATION_ALPHA( BlendEquation::ADD );
+const BlendEquation::Type DEFAULT_BLEND_EQUATION_RGB( BlendEquation::ADD );
+const BlendEquation::Type DEFAULT_BLEND_EQUATION_ALPHA( BlendEquation::ADD );
/**
* @brief Get GL stencil test enumeration value as a string.
return stream.str();
}
+/**
+ * @brief Get GL depth test enumeration value as a string.
+ * @return The string representation of the value of GL_DEPTH_TEST
+ */
+std::string GetDepthTestString(void)
+{
+ std::stringstream stream;
+ stream << GL_DEPTH_TEST;
+ return stream.str();
+}
+
void ResetDebugAndFlush( TestApplication& application, TraceCallStack& glEnableDisableStack, TraceCallStack& glStencilFunctionStack )
{
glEnableDisableStack.Reset();
END_TEST;
}
-
-
int UtcDaliRendererAnimatedProperty01(void)
{
TestApplication application;
END_TEST;
}
-
int UtcDaliRendererRenderOrder2DLayer(void)
{
TestApplication application;
END_TEST;
}
-Renderer StencilTestFixture( TestApplication& application )
+/**
+ * @brief This templatized function checks an enumeration property is setting and getting correctly.
+ * The checks performed are as follows:
+ * - Check the initial/default value.
+ * - Set a different value via enum.
+ * - Check it was set.
+ * - Set a different value via string.
+ * - Check it was set.
+ */
+template< typename T >
+void CheckEnumerationProperty( Renderer& renderer, Property::Index propertyIndex, T initialValue, T firstCheckEnumeration, T secondCheckEnumeration, std::string secondCheckString )
+{
+ DALI_TEST_CHECK( renderer.GetProperty<int>( propertyIndex ) == static_cast<int>( initialValue ) );
+ renderer.SetProperty( propertyIndex, firstCheckEnumeration );
+ DALI_TEST_CHECK( renderer.GetProperty<int>( propertyIndex ) == static_cast<int>( firstCheckEnumeration ) );
+ renderer.SetProperty( propertyIndex, secondCheckString );
+ DALI_TEST_CHECK( renderer.GetProperty<int>( propertyIndex ) == static_cast<int>( secondCheckEnumeration ) );
+}
+
+int UtcDaliRendererEnumProperties(void)
+{
+ TestApplication application;
+ tet_infoline( "Test Renderer enumeration properties can be set with both integer and string values" );
+
+ Geometry geometry = CreateQuadGeometry();
+ Shader shader = CreateShader();
+ Renderer renderer = Renderer::New( geometry, shader );
+
+ /*
+ * Here we use a templatized function to perform several checks on each enumeration property.
+ * @see CheckEnumerationProperty for details of the checks performed.
+ */
+
+ CheckEnumerationProperty< FaceCullingMode::Type >( renderer, Renderer::Property::FACE_CULLING_MODE, FaceCullingMode::NONE, FaceCullingMode::FRONT, FaceCullingMode::BACK, "BACK" );
+ CheckEnumerationProperty< BlendMode::Type >( renderer, Renderer::Property::BLEND_MODE, BlendMode::AUTO, BlendMode::OFF, BlendMode::ON, "ON" );
+ CheckEnumerationProperty< BlendEquation::Type >( renderer, Renderer::Property::BLEND_EQUATION_RGB, BlendEquation::ADD, BlendEquation::SUBTRACT, BlendEquation::REVERSE_SUBTRACT, "REVERSE_SUBTRACT" );
+ CheckEnumerationProperty< BlendEquation::Type >( renderer, Renderer::Property::BLEND_EQUATION_ALPHA, BlendEquation::ADD, BlendEquation::SUBTRACT, BlendEquation::REVERSE_SUBTRACT, "REVERSE_SUBTRACT" );
+ CheckEnumerationProperty< BlendFactor::Type >( renderer, Renderer::Property::BLEND_FACTOR_SRC_RGB, BlendFactor::SRC_ALPHA, BlendFactor::ONE, BlendFactor::SRC_COLOR, "SRC_COLOR" );
+ CheckEnumerationProperty< BlendFactor::Type >( renderer, Renderer::Property::BLEND_FACTOR_DEST_RGB, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendFactor::ONE, BlendFactor::SRC_COLOR, "SRC_COLOR" );
+ CheckEnumerationProperty< BlendFactor::Type >( renderer, Renderer::Property::BLEND_FACTOR_SRC_ALPHA, BlendFactor::ONE, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendFactor::SRC_COLOR, "SRC_COLOR" );
+ CheckEnumerationProperty< BlendFactor::Type >( renderer, Renderer::Property::BLEND_FACTOR_DEST_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA, BlendFactor::ONE, BlendFactor::SRC_COLOR, "SRC_COLOR" );
+ CheckEnumerationProperty< DepthWriteMode::Type >( renderer, Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::AUTO, DepthWriteMode::OFF, DepthWriteMode::ON, "ON" );
+ CheckEnumerationProperty< DepthFunction::Type >( renderer, Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS, DepthFunction::ALWAYS, DepthFunction::GREATER, "GREATER" );
+ CheckEnumerationProperty< DepthTestMode::Type >( renderer, Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::AUTO, DepthTestMode::OFF, DepthTestMode::ON, "ON" );
+ CheckEnumerationProperty< StencilFunction::Type >( renderer, Renderer::Property::STENCIL_FUNCTION, StencilFunction::ALWAYS, StencilFunction::LESS, StencilFunction::EQUAL, "EQUAL" );
+ CheckEnumerationProperty< StencilMode::Type >( renderer, Renderer::Property::STENCIL_MODE, StencilMode::AUTO, StencilMode::OFF, StencilMode::ON, "ON" );
+ CheckEnumerationProperty< StencilOperation::Type >( renderer, Renderer::Property::STENCIL_OPERATION_ON_FAIL, StencilOperation::KEEP, StencilOperation::REPLACE, StencilOperation::INCREMENT, "INCREMENT" );
+ CheckEnumerationProperty< StencilOperation::Type >( renderer, Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL, StencilOperation::KEEP, StencilOperation::REPLACE, StencilOperation::INCREMENT, "INCREMENT" );
+ CheckEnumerationProperty< StencilOperation::Type >( renderer, Renderer::Property::STENCIL_OPERATION_ON_Z_PASS, StencilOperation::KEEP, StencilOperation::REPLACE, StencilOperation::INCREMENT, "INCREMENT" );
+
+ END_TEST;
+}
+
+Renderer RendererTestFixture( TestApplication& application )
{
Geometry geometry = CreateQuadGeometry();
Shader shader = CreateShader();
return renderer;
}
+int UtcDaliRendererSetDepthTestMode(void)
+{
+ TestApplication application;
+ tet_infoline("Test setting the DepthTestMode");
+
+ Renderer renderer = RendererTestFixture( application );
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+ glAbstraction.EnableEnableDisableCallTrace( true );
+ TraceCallStack& glEnableDisableStack = glAbstraction.GetEnableDisableTrace();
+
+ glEnableDisableStack.Reset();
+ application.SendNotification();
+ application.Render();
+
+ // Check depth-test is enabled by default.
+ DALI_TEST_CHECK( glEnableDisableStack.FindMethodAndParams( "Enable", GetDepthTestString() ) );
+ DALI_TEST_CHECK( !glEnableDisableStack.FindMethodAndParams( "Disable", GetDepthTestString() ) );
+
+ // Turn off depth-testing. We want to check if the depth buffer has been disabled, so we need to turn off depth-write as well for this case.
+ renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::OFF );
+ renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
+
+ glEnableDisableStack.Reset();
+ application.SendNotification();
+ application.Render();
+
+ // Check the depth buffer was disabled.
+ DALI_TEST_CHECK( glEnableDisableStack.FindMethodAndParams( "Disable", GetDepthTestString() ) );
+
+ // Turn on automatic mode depth-testing.
+ // Layer behavior is currently set to LAYER_3D so AUTO should enable depth-testing.
+ renderer.SetProperty( Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::AUTO );
+
+ glEnableDisableStack.Reset();
+ application.SendNotification();
+ application.Render();
+
+ // Check depth-test is now enabled.
+ DALI_TEST_CHECK( glEnableDisableStack.FindMethodAndParams( "Enable", GetDepthTestString() ) );
+ DALI_TEST_CHECK( !glEnableDisableStack.FindMethodAndParams( "Disable", GetDepthTestString() ) );
+
+ // Change the layer behavior to LAYER_2D.
+ // Note this will also disable depth testing for the layer by default, we test this first.
+ Stage::GetCurrent().GetRootLayer().SetBehavior( Layer::LAYER_2D );
+
+ glEnableDisableStack.Reset();
+ application.SendNotification();
+ application.Render();
+
+ // Check depth-test is disabled.
+ DALI_TEST_CHECK( glEnableDisableStack.FindMethodAndParams( "Disable", GetDepthTestString() ) );
+
+ // Turn the layer depth-test flag back on, and confirm that depth testing is *still* off.
+ // This is because our renderer has DepthTestMode::AUTO and our layer behavior is LAYER_2D.
+ Stage::GetCurrent().GetRootLayer().SetDepthTestDisabled( false );
+
+ glEnableDisableStack.Reset();
+ application.SendNotification();
+ application.Render();
+
+ // Check depth-test is *still* disabled.
+ DALI_TEST_CHECK( glEnableDisableStack.FindMethodAndParams( "Disable", GetDepthTestString() ) );
+
+ END_TEST;
+}
+
+int UtcDaliRendererSetDepthWriteMode(void)
+{
+ TestApplication application;
+ tet_infoline("Test setting the DepthWriteMode");
+
+ Renderer renderer = RendererTestFixture( application );
+ TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
+
+ application.SendNotification();
+ application.Render();
+
+ // Check the default depth-write status first.
+ DALI_TEST_CHECK( glAbstraction.GetLastDepthMask() );
+
+ // Turn off depth-writing.
+ renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::OFF );
+
+ application.SendNotification();
+ application.Render();
+
+ // Check depth-write is now disabled.
+ DALI_TEST_CHECK( !glAbstraction.GetLastDepthMask() );
+
+ // Test the AUTO mode for depth-writing.
+ // As our renderer is opaque, depth-testing should be enabled.
+ renderer.SetProperty( Renderer::Property::DEPTH_WRITE_MODE, DepthWriteMode::AUTO );
+
+ application.SendNotification();
+ application.Render();
+
+ // Check depth-write is now enabled.
+ DALI_TEST_CHECK( glAbstraction.GetLastDepthMask() );
+
+ // Now make the renderer be treated as translucent by enabling blending.
+ // The AUTO depth-write mode should turn depth-write off in this scenario.
+ renderer.SetProperty( Renderer::Property::BLEND_MODE, BlendMode::ON );
+
+ application.SendNotification();
+ application.Render();
+
+ // Check depth-write is now disabled.
+ DALI_TEST_CHECK( !glAbstraction.GetLastDepthMask() );
+
+ END_TEST;
+}
+
int UtcDaliRendererCheckStencilDefaults(void)
{
TestApplication application;
tet_infoline("Test the stencil defaults");
- Renderer renderer = StencilTestFixture( application );
+ Renderer renderer = RendererTestFixture( application );
TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
glAbstraction.EnableEnableDisableCallTrace( true );
glAbstraction.EnableStencilFunctionCallTrace( true );
TestApplication application;
tet_infoline("Test setting the StencilMode");
- Renderer renderer = StencilTestFixture( application );
+ Renderer renderer = RendererTestFixture( application );
TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
glAbstraction.EnableEnableDisableCallTrace( true );
glAbstraction.EnableStencilFunctionCallTrace( true );
TestApplication application;
tet_infoline("Test setting the StencilFunction");
- Renderer renderer = StencilTestFixture( application );
+ Renderer renderer = RendererTestFixture( application );
TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
glAbstraction.EnableEnableDisableCallTrace( true );
glAbstraction.EnableStencilFunctionCallTrace( true );
TestApplication application;
tet_infoline("Test setting the StencilOperation");
- Renderer renderer = StencilTestFixture( application );
+ Renderer renderer = RendererTestFixture( application );
TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
glAbstraction.EnableEnableDisableCallTrace( true );
glAbstraction.EnableStencilFunctionCallTrace( true );
TestApplication application;
tet_infoline("Test setting the StencilMask");
- Renderer renderer = StencilTestFixture( application );
+ Renderer renderer = RendererTestFixture( application );
TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
glAbstraction.EnableEnableDisableCallTrace( true );
glAbstraction.EnableStencilFunctionCallTrace( true );
TestApplication application;
tet_infoline("Test setting the WriteToColorBuffer flag");
- Renderer renderer = StencilTestFixture( application );
+ Renderer renderer = RendererTestFixture( application );
TestGlAbstraction& glAbstraction = application.GetGlAbstraction();
// Set the StencilMask property to a value.
{
if( pthread_mutex_init( &mImpl->mutex, NULL ) )
{
- DALI_LOG_ERROR( "Unable to initialise mutex in ConditionalWait" );
+ DALI_LOG_ERROR( "Unable to initialise mutex in ConditionalWait\n" );
}
if( pthread_cond_init( &mImpl->condition, NULL ) )
{
- DALI_LOG_ERROR( "Unable to initialise conditional" );
+ DALI_LOG_ERROR( "Unable to initialise conditional\n" );
}
mImpl->count = 0;
}
{
if( pthread_cond_destroy( &mImpl->condition ) )
{
- DALI_LOG_ERROR( "Unable to destroy conditional" );
+ DALI_LOG_ERROR( "Unable to destroy conditional\n" );
}
if( pthread_mutex_destroy( &mImpl->mutex ) )
{
- DALI_LOG_ERROR( "Unable to destroy mutex in ConditionalWait" );
+ DALI_LOG_ERROR( "Unable to destroy mutex in ConditionalWait\n" );
}
delete mImpl;
}
{
if( pthread_cond_broadcast( &mImpl->condition ) )
{
- DALI_LOG_ERROR( "Error calling pthread_cond_broadcast" );
+ DALI_LOG_ERROR( "Error calling pthread_cond_broadcast\n" );
}
}
Internal::Mutex::Unlock( &mImpl->mutex );
{
if( pthread_cond_broadcast( &mImpl->condition ) )
{
- DALI_LOG_ERROR( "Error calling pthread_cond_broadcast" );
+ DALI_LOG_ERROR( "Error calling pthread_cond_broadcast\n" );
}
}
}
// wait while condition changes
if( pthread_cond_wait( &mImpl->condition, &mImpl->mutex ) ) // releases the lock whilst waiting
{
- DALI_LOG_ERROR( "Error calling pthread_cond_wait" );
+ DALI_LOG_ERROR( "Error calling pthread_cond_wait\n" );
break;
}
}
// wait while condition changes
if( pthread_cond_wait( &mImpl->condition, &mImpl->mutex ) ) // releases the lock whilst waiting
{
- DALI_LOG_ERROR( "Error calling pthread_cond_wait" );
+ DALI_LOG_ERROR( "Error calling pthread_cond_wait\n" );
break;
}
}
{
if( pthread_mutex_init( &mImpl->mutex, NULL ) )
{
- DALI_LOG_ERROR( "Unable to initialise Mutex" );
+ DALI_LOG_ERROR( "Unable to initialise Mutex\n" );
}
mImpl->locked = false;
}
{
if( pthread_mutex_destroy( &mImpl->mutex ) )
{
- DALI_LOG_ERROR( "Unable to destroy Mutex" );
+ DALI_LOG_ERROR( "Unable to destroy Mutex\n" );
}
// nothing else to do as there is no Lock/Unlock API
// ScopedLock destructor will always unlock the mutex
#include <dali/internal/update/common/discard-queue.h>
#include <dali/internal/update/common/texture-cache-dispatcher.h>
#include <dali/internal/update/manager/update-manager.h>
+#include <dali/internal/update/manager/geometry-batcher.h>
#include <dali/internal/update/resources/resource-manager.h>
#include <dali/internal/render/common/performance-monitor.h>
mNotificationManager(NULL),
mImageFactory(NULL),
mShaderFactory(NULL),
+ mGeometryBatcher( NULL ),
mIsActive(true),
mProcessingEvent(false)
{
mTextureUploadedQueue = new LockedResourceQueue;
- mRenderManager = RenderManager::New( glAbstraction, glSyncAbstraction, *mTextureUploadedQueue );
+ mGeometryBatcher = new SceneGraph::GeometryBatcher();
+
+ mRenderManager = RenderManager::New( glAbstraction, glSyncAbstraction, *mGeometryBatcher, *mTextureUploadedQueue );
RenderQueue& renderQueue = mRenderManager->GetRenderQueue();
TextureCache& textureCache = mRenderManager->GetTextureCache();
renderController,
*mRenderManager,
renderQueue,
- *mTextureCacheDispatcher );
+ *mTextureCacheDispatcher,
+ *mGeometryBatcher );
mRenderManager->SetShaderSaver( *mUpdateManager );
delete mTextureCacheDispatcher;
delete mUpdateManager;
delete mRenderManager;
+ delete mGeometryBatcher;
delete mTextureUploadedQueue;
}
// Guard against calls to ProcessEvents() during ProcessEvents()
if( mProcessingEvent )
{
- DALI_LOG_ERROR( "ProcessEvents should not be called from within ProcessEvents!" );
+ DALI_LOG_ERROR( "ProcessEvents should not be called from within ProcessEvents!\n" );
mRenderController.RequestProcessEventsOnIdle();
return;
}
class RenderManager;
class DiscardQueue;
class TextureCacheDispatcher;
+class GeometryBatcher;
}
/**
ResourceClient* mResourceClient; ///< Asynchronous Resource Loading
ResourceManager* mResourceManager; ///< Asynchronous Resource Loading
IntrusivePtr< RelayoutController > mRelayoutController; ///< Size negotiation relayout controller
-
+ SceneGraph::GeometryBatcher* mGeometryBatcher; ///< Instance of the geometry batcher
bool mIsActive : 1; ///< Whether Core is active or suspended
bool mProcessingEvent : 1; ///< True during ProcessEvents()
{
return sqrtf(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
}
+
+void Dali::Internal::MultiplyVectorBySize( Vec2& result, const Vec2 v, const Size3 s )
+{
+ result[0] = v[0] * s[0];
+ result[1] = v[1] * s[1];
+}
+
+void Dali::Internal::MultiplyVectorBySize( Vec3& result, const Vec3 v, const Size3 s )
+{
+ result[0] = v[0] * s[0];
+ result[1] = v[1] * s[1];
+ result[2] = v[2] * s[2];
+}
+
+void Dali::Internal::MultiplyVectorBySize( Vec4& result, const Vec4 v, const Size3 s )
+{
+ result[0] = v[0] * s[0];
+ result[1] = v[1] * s[1];
+ result[2] = v[2] * s[2];
+ result[3] = 1.0f;
+}
+
+void Dali::Internal::MultiplyVectorByMatrix4( Vec2& result, const Mat4 m, const Vec2 v )
+{
+ result[0] = v[0] * m[0] + v[1] * m[4] + m[12];
+ result[1] = v[0] * m[1] + v[1] * m[5] + m[13];
+}
+
+void Dali::Internal::MultiplyVectorByMatrix4( Vec3& result, const Mat4 m, const Vec3 v )
+{
+ result[0] = v[0] * m[0] + v[1] * m[4] + v[2] * m[8] + m[12];
+ result[1] = v[0] * m[1] + v[1] * m[5] + v[2] * m[9] + m[13];
+ result[2] = v[0] * m[2] + v[1] * m[6] + v[2] * m[10] + m[14];
+}
+
+void Dali::Internal::MultiplyVectorByMatrix4( Vec4& result, const Mat4 m, const Vec4 rhs )
+{
+ result[0] = rhs[0] * m[0] + rhs[1] * m[4] + rhs[2] * m[8] + rhs[3] * m[12];
+ result[1] = rhs[0] * m[1] + rhs[1] * m[5] + rhs[2] * m[9] + rhs[3] * m[13];
+ result[2] = rhs[0] * m[2] + rhs[1] * m[6] + rhs[2] * m[10] + rhs[3] * m[14];
+ result[3] = rhs[0] * m[3] + rhs[1] * m[7] + rhs[2] * m[11] + rhs[3] * m[15];
+}
+
+void Dali::Internal::MultiplyMatrices( float* result, const Mat4 lhs, const Mat4 rhs )
+{
+ for( int i=0; i < 4; i++ )
+ {
+ // i<<2 gives the first vector / column
+ int loc = i<<2;
+ int loc1 = loc + 1;
+ int loc2 = loc + 2;
+ int loc3 = loc + 3;
+ float value0 = lhs[loc];
+ float value1 = lhs[loc1];
+ float value2 = lhs[loc2];
+ float value3 = lhs[loc3];
+ result[loc] = (value0 * rhs[0]) +
+ (value1 * rhs[4]) +
+ (value2 * rhs[8]) +
+ (value3 * rhs[12]);
+
+ result[loc1] = (value0 * rhs[1]) +
+ (value1 * rhs[5]) +
+ (value2 * rhs[9]) +
+ (value3 * rhs[13]);
+
+ result[loc2] = (value0 * rhs[2]) +
+ (value1 * rhs[6]) +
+ (value2 * rhs[10])+
+ (value3 * rhs[14]);
+
+ result[loc3] = (value0 * rhs[3]) +
+ (value1 * rhs[7]) +
+ (value2 * rhs[11])+
+ (value3 * rhs[15]);
+ }
+}
namespace Internal
{
+typedef float Vec2[2];
typedef float Vec3[3];
typedef float Vec4[4];
typedef float Mat4[16];
+typedef Vec3 Size3;
/**
* @brief Applies a transformation matrix to a vector
*/
float Length( const Vec3 v );
+/**
+ * @brief Transforms 2D vector by the Size3 and stores value in Vec2
+ *
+ * @param[out] result Vec2 type to store final value
+ * @param[in] v Vector to transform
+ * @param[in] s Size to transform with
+ */
+void MultiplyVectorBySize( Vec2& result, const Vec2 v, const Size3 s );
+
+/**
+ * @brief Transforms 3D vector by the Size3 and stores value in Vec3
+ *
+ * @param[out] result Vec3 type to store final value
+ * @param[in] v Vector to transform
+ * @param[in] s Size to transform with
+ */
+void MultiplyVectorBySize( Vec3& result, const Vec3 v, const Size3 s );
+
+/**
+ * @brief Transforms 4D vector by the Size3 and stores value in Vec4
+ *
+ * @param[out] result Vec4 type to store final value
+ * @param[in] v Vector to transform
+ * @param[in] s Size to transform with
+ */
+void MultiplyVectorBySize( Vec4& result, const Vec4 v, const Size3 s );
+
+/**
+ * @brief Multiplies 2D vector by the matrix
+ *
+ * @param[out] result Result of the multiplication
+ * @param[in] m Matrix to use
+ * @param[in] v Vector to multiply
+ */
+void MultiplyVectorByMatrix4( Vec2& result, const Mat4 m, const Vec2 v );
+
+/**
+ * @brief Multiplies 3D vector by the matrix
+ *
+ * @param[out] result Result of the multiplication
+ * @param[in] m Matrix to use
+ * @param[in] v Vector to multiply
+ */
+void MultiplyVectorByMatrix4( Vec3& result, const Mat4 m, const Vec3 v );
+
+/**
+ * @brief Multiplies 4D vector by the matrix
+ *
+ * @param[out] result Result of the multiplication
+ * @param[in] m Matrix to use
+ * @param[in] v Vector to multiply
+ */
+void MultiplyVectorByMatrix4( Vec4& result, const Mat4 m, const Vec4 v );
+
+/**
+ * @brief Multiplies two Mat4 matrices
+ *
+ * @param[out] result Result of multiplication
+ * @param[in] lhs Left-hand-side matrix to use
+ * @param[in] rhs Right-hand-side matrix to use
+ */
+void MultiplyMatrices( float* result, const Mat4 lhs, const Mat4 rhs );
+
+
} // namespace Internal
} // namespace Dali
if( pthread_mutex_lock( mutex ) )
{
- DALI_LOG_ERROR( "Error calling pthread_mutex_lock" );
+ DALI_LOG_ERROR( "Error calling pthread_mutex_lock\n" );
}
}
{
if( pthread_mutex_unlock( mutex ) )
{
- DALI_LOG_ERROR( "Error calling pthread_mutex_unlock" );
+ DALI_LOG_ERROR( "Error calling pthread_mutex_unlock\n" );
}
--gThreadLockCount;
}
DALI_PROPERTY( "minimumSize", VECTOR2, true, false, false, Dali::Actor::Property::MINIMUM_SIZE )
DALI_PROPERTY( "maximumSize", VECTOR2, true, false, false, Dali::Actor::Property::MAXIMUM_SIZE )
DALI_PROPERTY( "inheritPosition", BOOLEAN, true, false, false, Dali::Actor::Property::INHERIT_POSITION )
+DALI_PROPERTY( "batchParent", BOOLEAN, true, false, false, Dali::Actor::Property::BATCH_PARENT )
DALI_PROPERTY_TABLE_END( DEFAULT_ACTOR_PROPERTY_START_INDEX )
// Signals
mInheritScale( true ),
mDrawMode( DrawMode::NORMAL ),
mPositionInheritanceMode( Node::DEFAULT_POSITION_INHERITANCE_MODE ),
- mColorMode( Node::DEFAULT_COLOR_MODE )
+ mColorMode( Node::DEFAULT_COLOR_MODE ),
+ mIsBatchParent( false )
{
}
break;
}
+ case Dali::Actor::Property::BATCH_PARENT:
+ {
+ bool value;
+
+ if( property.Get( value ) )
+ {
+ if( value != mIsBatchParent )
+ {
+ mIsBatchParent = value;
+ SetIsBatchParentMessage( GetEventThreadServices(), *mNode, mIsBatchParent );
+ }
+ }
+ break;
+ }
default:
{
// this can happen in the case of a non-animatable default property so just do nothing
break;
}
+ case Dali::Actor::Property::BATCH_PARENT:
+ {
+ value = mIsBatchParent;
+ break;
+ }
+
default:
{
DALI_ASSERT_ALWAYS( false && "Actor Property index invalid" ); // should not come here
static ActorContainer mNullChildren; ///< Empty container (shared by all actors, returned by GetChildren() const)
static unsigned int mActorCounter; ///< A counter to track the actor instance creation
+ bool mIsBatchParent : 1; ///< Flag indicating that the actor is a batch parent
+
};
} // namespace Internal
void ImageActor::SetStyle( Dali::ImageActor::Style style )
{
- DALI_LOG_WARNING( "SetStyle Deprecated. Only STYLE_QUAD supported." );
+ DALI_LOG_WARNING( "SetStyle Deprecated. Only STYLE_QUAD supported.\n" );
mStyle = style;
}
Dali::ImageActor::Style ImageActor::GetStyle() const
{
- DALI_LOG_WARNING( "GetStyle Deprecated. Only STYLE_QUAD supported." );
+ DALI_LOG_WARNING( "GetStyle Deprecated. Only STYLE_QUAD supported.\n" );
return mStyle;
}
void ImageActor::SetNinePatchBorder( const Vector4& border )
{
- DALI_LOG_WARNING( "SetNinePatchBorder Deprecated. Only STYLE_QUAD supported." );
+ DALI_LOG_WARNING( "SetNinePatchBorder Deprecated. Only STYLE_QUAD supported.\n" );
mNinePatchBorder = border;
}
Vector4 ImageActor::GetNinePatchBorder() const
{
- DALI_LOG_WARNING( "GetNinePatchBorder Deprecated. Only STYLE_QUAD supported." );
+ DALI_LOG_WARNING( "GetNinePatchBorder Deprecated. Only STYLE_QUAD supported.\n" );
return mNinePatchBorder;
}
}
else
{
- DALI_LOG_ERROR( "Constraint source object not found" );
+ DALI_LOG_ERROR( "Constraint source object not found\n" );
}
}
}
{
if( ! Equals( mStereoBase, stereoBase ) )
{
- DALI_LOG_INFO( Debug::Filter::gActor, Debug::Concise, "old( %.2f) new(%.2f)", mStereoBase, stereoBase );
+ DALI_LOG_INFO( Debug::Filter::gActor, Debug::Concise, "old( %.2f) new(%.2f)\n", mStereoBase, stereoBase );
mStereoBase = stereoBase;
switch( mViewMode )
Dali::Stage::TouchedSignalType& Stage::TouchedSignal()
{
- DALI_LOG_WARNING( "Deprecated. Use TouchSignal() instead." );
+ DALI_LOG_WARNING( "Deprecated. Use TouchSignal() instead.\n" );
return mTouchedSignal;
}
}
else
{
- DALI_LOG_WARNING("Action already exists in TypeRegistry Type", actionName.c_str());
+ DALI_LOG_WARNING("Action already exists in TypeRegistry Type\n", actionName.c_str());
}
}
}
}
else
{
- DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function", signalName.c_str());
+ DALI_LOG_WARNING("Signal name already exists in TypeRegistry Type for signal connector function\n", signalName.c_str());
}
}
}
#include <dali/internal/event/rendering/renderer-impl.h> // Dali::Internal::Renderer
// INTERNAL INCLUDES
+#include <dali/devel-api/scripting/scripting.h>
#include <dali/public-api/object/type-registry.h>
#include <dali/internal/event/common/object-impl-helper.h> // Dali::Internal::ObjectHelper
#include <dali/internal/event/common/property-helper.h> // DALI_PROPERTY_TABLE_BEGIN, DALI_PROPERTY, DALI_PROPERTY_TABLE_END
{
/**
- * |name |type |writable|animatable|constraint-input|enum for index-checking|
+ * Properties: |name |type |writable|animatable|constraint-input|enum for index-checking|
*/
DALI_PROPERTY_TABLE_BEGIN
DALI_PROPERTY( "depthIndex", INTEGER, true, false, false, Dali::Renderer::Property::DEPTH_INDEX )
DALI_PROPERTY( "stencilOperationOnZFail", INTEGER, true, false, false, Dali::Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL )
DALI_PROPERTY( "stencilOperationOnZPass", INTEGER, true, false, false, Dali::Renderer::Property::STENCIL_OPERATION_ON_Z_PASS )
DALI_PROPERTY( "writeToColorBuffer", BOOLEAN, true, false, false, Dali::Renderer::Property::WRITE_TO_COLOR_BUFFER )
+DALI_PROPERTY( "batchingEnabled", BOOLEAN, true, false, false, Dali::Renderer::Property::BATCHING_ENABLED )
DALI_PROPERTY_TABLE_END( DEFAULT_RENDERER_PROPERTY_START_INDEX )
+// Property string to enumeration tables:
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( FACE_CULLING_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( FaceCullingMode, NONE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( FaceCullingMode, FRONT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( FaceCullingMode, BACK )
+DALI_ENUM_TO_STRING_WITH_SCOPE( FaceCullingMode, FRONT_AND_BACK )
+DALI_ENUM_TO_STRING_TABLE_END( FACE_CULLING_MODE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( BLEND_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendMode, OFF )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendMode, AUTO )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendMode, ON )
+DALI_ENUM_TO_STRING_TABLE_END( BLEND_MODE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( BLEND_EQUATION )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendEquation, ADD )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendEquation, SUBTRACT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendEquation, REVERSE_SUBTRACT )
+DALI_ENUM_TO_STRING_TABLE_END( BLEND_EQUATION )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( BLEND_FACTOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, ZERO )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, ONE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, SRC_COLOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, ONE_MINUS_SRC_COLOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, SRC_ALPHA )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, ONE_MINUS_SRC_ALPHA )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, DST_ALPHA )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, ONE_MINUS_DST_ALPHA )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, DST_COLOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, ONE_MINUS_DST_COLOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, SRC_ALPHA_SATURATE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, CONSTANT_COLOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, ONE_MINUS_CONSTANT_COLOR )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, CONSTANT_ALPHA )
+DALI_ENUM_TO_STRING_WITH_SCOPE( BlendFactor, ONE_MINUS_CONSTANT_ALPHA )
+DALI_ENUM_TO_STRING_TABLE_END( BLEND_FACTOR )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( DEPTH_WRITE_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthWriteMode, OFF )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthWriteMode, AUTO )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthWriteMode, ON )
+DALI_ENUM_TO_STRING_TABLE_END( DEPTH_WRITE_MODE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( DEPTH_TEST_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthTestMode, OFF )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthTestMode, AUTO )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthTestMode, ON )
+DALI_ENUM_TO_STRING_TABLE_END( DEPTH_TEST_MODE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( DEPTH_FUNCTION )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthFunction, NEVER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthFunction, ALWAYS )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthFunction, LESS )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthFunction, GREATER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthFunction, EQUAL )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthFunction, NOT_EQUAL )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthFunction, LESS_EQUAL )
+DALI_ENUM_TO_STRING_WITH_SCOPE( DepthFunction, GREATER_EQUAL )
+DALI_ENUM_TO_STRING_TABLE_END( DEPTH_FUNCTION )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( STENCIL_FUNCTION )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilFunction, NEVER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilFunction, LESS )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilFunction, EQUAL )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilFunction, LESS_EQUAL )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilFunction, GREATER )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilFunction, NOT_EQUAL )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilFunction, GREATER_EQUAL )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilFunction, ALWAYS )
+DALI_ENUM_TO_STRING_TABLE_END( STENCIL_FUNCTION )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( STENCIL_MODE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilMode, OFF )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilMode, AUTO )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilMode, ON )
+DALI_ENUM_TO_STRING_TABLE_END( STENCIL_MODE )
+
+DALI_ENUM_TO_STRING_TABLE_BEGIN( STENCIL_OPERATION )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilOperation, ZERO )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilOperation, KEEP )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilOperation, REPLACE )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilOperation, INCREMENT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilOperation, DECREMENT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilOperation, INVERT )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilOperation, INCREMENT_WRAP )
+DALI_ENUM_TO_STRING_WITH_SCOPE( StencilOperation, DECREMENT_WRAP )
+DALI_ENUM_TO_STRING_TABLE_END( STENCIL_OPERATION )
+
const ObjectImplHelper<DEFAULT_PROPERTY_COUNT> RENDERER_IMPL = { DEFAULT_PROPERTY_DETAILS };
BaseHandle Create()
return mDepthIndex;
}
-void Renderer::SetFaceCullingMode( FaceCullingMode::Type cullingMode )
-{
- if( mFaceCullingMode != cullingMode )
- {
- mFaceCullingMode = cullingMode;
-
- SetFaceCullingModeMessage( GetEventThreadServices(), *mSceneObject, mFaceCullingMode );
- }
-}
-
-FaceCullingMode::Type Renderer::GetFaceCullingMode()
-{
- return mFaceCullingMode;
-}
-
void Renderer::SetBlendMode( BlendMode::Type mode )
{
if( mBlendMode != mode )
return mPremultipledAlphaEnabled;
}
+bool Renderer::IsBatchingEnabled() const
+{
+ return mBatchingEnabled;
+}
+
SceneGraph::Renderer* Renderer::GetRendererSceneObject()
{
return mSceneObject;
}
case Dali::Renderer::Property::FACE_CULLING_MODE:
{
- int faceCullingMode;
- if( propertyValue.Get( faceCullingMode ) )
+ FaceCullingMode::Type convertedValue = mFaceCullingMode;
+ if( Scripting::GetEnumerationProperty< FaceCullingMode::Type >( propertyValue, FACE_CULLING_MODE_TABLE, FACE_CULLING_MODE_TABLE_COUNT, convertedValue ) )
{
- SetFaceCullingMode( FaceCullingMode::Type( faceCullingMode ) );
+ mFaceCullingMode = convertedValue;
+ SetFaceCullingModeMessage( GetEventThreadServices(), *mSceneObject, convertedValue );
}
break;
}
case Dali::Renderer::Property::BLEND_MODE:
{
- int blendingMode;
- if( propertyValue.Get( blendingMode ) )
+ BlendMode::Type convertedValue = mBlendMode;
+ if( Scripting::GetEnumerationProperty< BlendMode::Type >( propertyValue, BLEND_MODE_TABLE, BLEND_MODE_TABLE_COUNT, convertedValue ) )
{
- SetBlendMode( BlendMode::Type( blendingMode ) );
+ SetBlendMode( convertedValue );
}
break;
}
case Dali::Renderer::Property::BLEND_EQUATION_RGB:
{
- int blendingEquation;
- if( propertyValue.Get( blendingEquation ) )
+ BlendEquation::Type convertedValue = mBlendingOptions.GetBlendEquationRgb();
+
+ if( Scripting::GetEnumerationProperty< BlendEquation::Type >( propertyValue, BLEND_EQUATION_TABLE, BLEND_EQUATION_TABLE_COUNT, convertedValue ) )
{
BlendEquation::Type alphaEquation = mBlendingOptions.GetBlendEquationAlpha();
- mBlendingOptions.SetBlendEquation( static_cast<BlendEquation::Type>( blendingEquation ), alphaEquation );
+ mBlendingOptions.SetBlendEquation( convertedValue, alphaEquation );
SetBlendingOptionsMessage( GetEventThreadServices(), *mSceneObject, mBlendingOptions.GetBitmask() );
}
break;
}
case Dali::Renderer::Property::BLEND_EQUATION_ALPHA:
{
- int blendingEquation;
- if( propertyValue.Get( blendingEquation ) )
+ BlendEquation::Type convertedValue = mBlendingOptions.GetBlendEquationAlpha();
+
+ if( Scripting::GetEnumerationProperty< BlendEquation::Type >( propertyValue, BLEND_EQUATION_TABLE, BLEND_EQUATION_TABLE_COUNT, convertedValue ) )
{
BlendEquation::Type rgbEquation = mBlendingOptions.GetBlendEquationRgb();
- mBlendingOptions.SetBlendEquation( rgbEquation, static_cast<BlendEquation::Type>( blendingEquation ) );
+ mBlendingOptions.SetBlendEquation( rgbEquation, convertedValue );
SetBlendingOptionsMessage( GetEventThreadServices(), *mSceneObject, mBlendingOptions.GetBitmask() );
}
break;
}
case Dali::Renderer::Property::BLEND_FACTOR_SRC_RGB:
{
- int blendingFactor;
- if( propertyValue.Get( blendingFactor ) )
+ BlendFactor::Type sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha;
+ GetBlendFunc( sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha );
+
+ if( Scripting::GetEnumerationProperty< BlendFactor::Type >( propertyValue, BLEND_FACTOR_TABLE, BLEND_FACTOR_TABLE_COUNT, sourceFactorRgb ) )
{
- BlendFactor::Type srcFactorRgb;
- BlendFactor::Type destFactorRgb;
- BlendFactor::Type srcFactorAlpha;
- BlendFactor::Type destFactorAlpha;
- GetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
- SetBlendFunc( static_cast<BlendFactor::Type>( blendingFactor ),
- destFactorRgb,
- srcFactorAlpha,
- destFactorAlpha );
+ SetBlendFunc( sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha );
}
break;
}
case Dali::Renderer::Property::BLEND_FACTOR_DEST_RGB:
{
- int blendingFactor;
- if( propertyValue.Get( blendingFactor ) )
+ BlendFactor::Type sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha;
+ GetBlendFunc( sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha );
+
+ if( Scripting::GetEnumerationProperty< BlendFactor::Type >( propertyValue, BLEND_FACTOR_TABLE, BLEND_FACTOR_TABLE_COUNT, destinationFactorRgb ) )
{
- BlendFactor::Type srcFactorRgb;
- BlendFactor::Type destFactorRgb;
- BlendFactor::Type srcFactorAlpha;
- BlendFactor::Type destFactorAlpha;
- GetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
- SetBlendFunc( srcFactorRgb,
- static_cast<BlendFactor::Type>( blendingFactor ),
- srcFactorAlpha,
- destFactorAlpha );
+ SetBlendFunc( sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha );
}
break;
}
case Dali::Renderer::Property::BLEND_FACTOR_SRC_ALPHA:
{
- int blendingFactor;
- if( propertyValue.Get( blendingFactor ) )
+ BlendFactor::Type sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha;
+ GetBlendFunc( sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha );
+
+ if( Scripting::GetEnumerationProperty< BlendFactor::Type >( propertyValue, BLEND_FACTOR_TABLE, BLEND_FACTOR_TABLE_COUNT, sourceFactorAlpha ) )
{
- BlendFactor::Type srcFactorRgb;
- BlendFactor::Type destFactorRgb;
- BlendFactor::Type srcFactorAlpha;
- BlendFactor::Type destFactorAlpha;
- GetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
- SetBlendFunc( srcFactorRgb,
- destFactorRgb,
- static_cast<BlendFactor::Type>( blendingFactor ),
- destFactorAlpha );
+ SetBlendFunc( sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha );
}
break;
}
case Dali::Renderer::Property::BLEND_FACTOR_DEST_ALPHA:
{
- int blendingFactor;
- if( propertyValue.Get( blendingFactor ) )
+ BlendFactor::Type sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha;
+ GetBlendFunc( sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha );
+
+ if( Scripting::GetEnumerationProperty< BlendFactor::Type >( propertyValue, BLEND_FACTOR_TABLE, BLEND_FACTOR_TABLE_COUNT, destinationFactorAlpha ) )
{
- BlendFactor::Type srcFactorRgb;
- BlendFactor::Type destFactorRgb;
- BlendFactor::Type srcFactorAlpha;
- BlendFactor::Type destFactorAlpha;
- GetBlendFunc( srcFactorRgb, destFactorRgb, srcFactorAlpha, destFactorAlpha );
- SetBlendFunc( srcFactorRgb,
- destFactorRgb,
- srcFactorAlpha,
- static_cast<BlendFactor::Type>( blendingFactor ) );
+ SetBlendFunc( sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha );
}
break;
}
}
case Dali::Renderer::Property::DEPTH_WRITE_MODE:
{
- int value;
- propertyValue.Get( value );
- DepthWriteMode::Type mode = static_cast<DepthWriteMode::Type>(value);
- if( mode != mDepthWriteMode )
+ DepthWriteMode::Type convertedValue = mDepthWriteMode;
+ if( Scripting::GetEnumerationProperty< DepthWriteMode::Type >( propertyValue, DEPTH_WRITE_MODE_TABLE, DEPTH_WRITE_MODE_TABLE_COUNT, convertedValue ) )
{
- mDepthWriteMode = mode;
- SetDepthWriteModeMessage( GetEventThreadServices(), *mSceneObject, mode );
+ mDepthWriteMode = convertedValue;
+ SetDepthWriteModeMessage( GetEventThreadServices(), *mSceneObject, convertedValue );
}
break;
}
case Dali::Renderer::Property::DEPTH_FUNCTION:
{
- int value;
- propertyValue.Get( value );
- DepthFunction::Type depthFunction = static_cast<DepthFunction::Type>(value);
- if( depthFunction != mDepthFunction )
+ DepthFunction::Type convertedValue = mDepthFunction;
+ if( Scripting::GetEnumerationProperty< DepthFunction::Type >( propertyValue, DEPTH_FUNCTION_TABLE, DEPTH_FUNCTION_TABLE_COUNT, convertedValue ) )
{
- mDepthFunction = depthFunction;
- SetDepthFunctionMessage( GetEventThreadServices(), *mSceneObject, depthFunction );
+ mDepthFunction = convertedValue;
+ SetDepthFunctionMessage( GetEventThreadServices(), *mSceneObject, convertedValue );
}
break;
}
case Dali::Renderer::Property::DEPTH_TEST_MODE:
{
- int value;
- propertyValue.Get( value );
- DepthTestMode::Type mode = static_cast<DepthTestMode::Type>(value);
- if( mode != mDepthTestMode )
+ DepthTestMode::Type convertedValue = mDepthTestMode;
+ if( Scripting::GetEnumerationProperty< DepthTestMode::Type >( propertyValue, DEPTH_TEST_MODE_TABLE, DEPTH_TEST_MODE_TABLE_COUNT, convertedValue ) )
{
- mDepthTestMode = mode;
- SetDepthTestModeMessage( GetEventThreadServices(), *mSceneObject, mode );
+ mDepthTestMode = convertedValue;
+ SetDepthTestModeMessage( GetEventThreadServices(), *mSceneObject, convertedValue );
}
break;
}
case Dali::Renderer::Property::STENCIL_MODE:
{
- int value;
- propertyValue.Get( value );
- StencilMode::Type stencilMode = static_cast<StencilMode::Type>( value );
- if( stencilMode != mStencilParameters.stencilMode )
+ StencilMode::Type convertedValue = mStencilParameters.stencilMode;
+ if( Scripting::GetEnumerationProperty< StencilMode::Type >( propertyValue, STENCIL_MODE_TABLE, STENCIL_MODE_TABLE_COUNT, convertedValue ) )
{
- mStencilParameters.stencilMode = stencilMode;
- SetStencilModeMessage( GetEventThreadServices(), *mSceneObject, stencilMode );
+ mStencilParameters.stencilMode = convertedValue;
+ SetStencilModeMessage( GetEventThreadServices(), *mSceneObject, convertedValue );
}
break;
}
case Dali::Renderer::Property::STENCIL_FUNCTION:
{
- int value;
- propertyValue.Get( value );
- StencilFunction::Type stencilFunction = static_cast<StencilFunction::Type>( value );
- if( stencilFunction != mStencilParameters.stencilFunction )
+ StencilFunction::Type convertedValue = mStencilParameters.stencilFunction;
+ if( Scripting::GetEnumerationProperty< StencilFunction::Type >( propertyValue, STENCIL_FUNCTION_TABLE, STENCIL_FUNCTION_TABLE_COUNT, convertedValue ) )
{
- mStencilParameters.stencilFunction = stencilFunction;
- SetStencilFunctionMessage( GetEventThreadServices(), *mSceneObject, stencilFunction );
+ mStencilParameters.stencilFunction = convertedValue;
+ SetStencilFunctionMessage( GetEventThreadServices(), *mSceneObject, convertedValue );
}
break;
}
}
case Dali::Renderer::Property::STENCIL_OPERATION_ON_FAIL:
{
- int value;
- propertyValue.Get( value );
- StencilOperation::Type stencilOperation = static_cast<StencilOperation::Type>( value );
- if( stencilOperation != mStencilParameters.stencilOperationOnFail )
+ StencilOperation::Type convertedValue = mStencilParameters.stencilOperationOnFail;
+ if( Scripting::GetEnumerationProperty< StencilOperation::Type >( propertyValue, STENCIL_OPERATION_TABLE, STENCIL_OPERATION_TABLE_COUNT, convertedValue ) )
{
- mStencilParameters.stencilOperationOnFail = stencilOperation;
- SetStencilOperationOnFailMessage( GetEventThreadServices(), *mSceneObject, stencilOperation );
+ mStencilParameters.stencilOperationOnFail = convertedValue;
+ SetStencilOperationOnFailMessage( GetEventThreadServices(), *mSceneObject, convertedValue );
}
break;
}
case Dali::Renderer::Property::STENCIL_OPERATION_ON_Z_FAIL:
{
- int value;
- propertyValue.Get( value );
- StencilOperation::Type stencilOperation = static_cast<StencilOperation::Type>( value );
- if( stencilOperation != mStencilParameters.stencilOperationOnZFail )
+ StencilOperation::Type convertedValue = mStencilParameters.stencilOperationOnZFail;
+ if( Scripting::GetEnumerationProperty< StencilOperation::Type >( propertyValue, STENCIL_OPERATION_TABLE, STENCIL_OPERATION_TABLE_COUNT, convertedValue ) )
{
- mStencilParameters.stencilOperationOnZFail = stencilOperation;
- SetStencilOperationOnZFailMessage( GetEventThreadServices(), *mSceneObject, stencilOperation );
+ mStencilParameters.stencilOperationOnZFail = convertedValue;
+ SetStencilOperationOnZFailMessage( GetEventThreadServices(), *mSceneObject, convertedValue );
}
break;
}
case Dali::Renderer::Property::STENCIL_OPERATION_ON_Z_PASS:
{
- int value;
- propertyValue.Get( value );
- StencilOperation::Type stencilOperation = static_cast<StencilOperation::Type>( value );
- if( stencilOperation != mStencilParameters.stencilOperationOnZPass )
+ StencilOperation::Type convertedValue = mStencilParameters.stencilOperationOnZPass;
+ if( Scripting::GetEnumerationProperty< StencilOperation::Type >( propertyValue, STENCIL_OPERATION_TABLE, STENCIL_OPERATION_TABLE_COUNT, convertedValue ) )
{
- mStencilParameters.stencilOperationOnZPass = stencilOperation;
- SetStencilOperationOnZPassMessage( GetEventThreadServices(), *mSceneObject, stencilOperation );
+ mStencilParameters.stencilOperationOnZPass = convertedValue;
+ SetStencilOperationOnZPassMessage( GetEventThreadServices(), *mSceneObject, convertedValue );
}
break;
}
}
break;
}
+ case Dali::Renderer::Property::BATCHING_ENABLED:
+ {
+ bool enabled;
+ if( propertyValue.Get( enabled ) )
+ {
+ if( mBatchingEnabled != enabled )
+ {
+ mBatchingEnabled = enabled;
+ SetBatchingEnabledMessage( GetEventThreadServices(), *mSceneObject, mBatchingEnabled );
+ }
+ }
+ break;
+ }
}
}
value = mDepthWriteMode;
break;
}
+ case Dali::Renderer::Property::BATCHING_ENABLED:
+ {
+ value = mBatchingEnabled;
+ break;
+ }
case Dali::Renderer::Property::DEPTH_FUNCTION:
{
value = mDepthFunction;
mDepthWriteMode( DepthWriteMode::AUTO ),
mDepthTestMode( DepthTestMode::AUTO ),
mWriteToColorBuffer( true ),
- mPremultipledAlphaEnabled( false )
+ mPremultipledAlphaEnabled( false ),
+ mBatchingEnabled( false )
{
}
*/
int GetDepthIndex() const;
- /**
- * @copydoc Dali::Renderer::SetFaceCullingMode()
- */
- void SetFaceCullingMode( FaceCullingMode::Type cullingMode );
-
- /**
- * @copydoc Dali::Renderer::GetFaceCullingMode()
- */
- FaceCullingMode::Type GetFaceCullingMode();
-
/**
* @copydoc Dali::Renderer::SetBlendMode()
*/
*/
bool IsPreMultipliedAlphaEnabled() const;
- /**
- * @brief Get the scene graph object
- *
- * @return the scene object
- */
- SceneGraph::Renderer* GetRendererSceneObject();
+ /**
+ * Returns state of batching mode
+ * @return batching mode state ( true if enabled )
+ */
+ bool IsBatchingEnabled() const;
+
+ /**
+ * @brief Get the scene graph object
+ *
+ * @return the scene object
+ */
+ SceneGraph::Renderer* GetRendererSceneObject();
public: // Default property extensions from Object
DepthTestMode::Type mDepthTestMode:2; ///< Local copy of the depth test mode
bool mWriteToColorBuffer:1; ///< Local copy of the write to color buffer flag
bool mPremultipledAlphaEnabled:1; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required
+ bool mBatchingEnabled : 1; ///< Flag indicating whether render is batchable or not
};
} // namespace Internal
{
if( mNativeImage )
{
- DALI_LOG_ERROR( "OpenGL ES does not support uploading data to native texture");
+ DALI_LOG_ERROR( "OpenGL ES does not support uploading data to native texture\n");
}
else
{
unsigned int pixelDataSize = pixelData->GetWidth()*pixelData->GetHeight();
if( pixelData->GetBuffer() == NULL || pixelDataSize == 0 )
{
- DALI_LOG_ERROR( "PixelData is empty");
+ DALI_LOG_ERROR( "PixelData is empty\n");
}
else
{
{
if( pixelDataSize < width * height )
{
- DALI_LOG_ERROR( "PixelData of an incorrect size when trying to update texture");
+ DALI_LOG_ERROR( "PixelData of an incorrect size when trying to update texture\n");
}
else if( ( xOffset + width > ( mWidth / (1<<mipmap) ) ) ||
( yOffset + height > ( mHeight / (1<<mipmap) ) ) )
{
- DALI_LOG_ERROR( "Texture update area out of bounds");
+ DALI_LOG_ERROR( "Texture update area out of bounds\n");
}
else
{
}
else
{
- DALI_LOG_ERROR( "Bad format");
+ DALI_LOG_ERROR( "Bad format\n");
}
}
}
{
if( !mNewTextures.empty() )
{
- DALI_LOG_ERROR( "Error: Cannot mix images and textures in the same TextureSet");
+ DALI_LOG_ERROR( "Error: Cannot mix images and textures in the same TextureSet\n");
return;
}
{
if( !mImages.empty() )
{
- DALI_LOG_ERROR( "Error: Cannot mix images and textures in the same texture set");
+ DALI_LOG_ERROR( "Error: Cannot mix images and textures in the same texture set\n");
return;
}
}
else
{
- DALI_LOG_ERROR( "Error: Invalid index to TextureSet::GetImage");
+ DALI_LOG_ERROR( "Error: Invalid index to TextureSet::GetImage\n");
}
return result;
}
else
{
- DALI_LOG_ERROR( "Error: Invalid index to TextureSet::GetTexture");
+ DALI_LOG_ERROR( "Error: Invalid index to TextureSet::GetTexture\n");
}
return result;
}
else
{
- DALI_LOG_ERROR( "Error: Invalid index to TextureSet::GetSampler");
+ DALI_LOG_ERROR( "Error: Invalid index to TextureSet::GetSampler\n");
}
return result;
{
if(!mChunkStack.empty())
{
- DALI_LOG_ERROR("mChunkStack should be empty!");
+ DALI_LOG_ERROR("mChunkStack should be empty!\n");
}
}
case ResourceNativeImage:
case ResourceTargetImage:
{
- DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer." );
+ DALI_LOG_ERROR( "Unsupported resource type passed for decoding from a memory buffer.\n" );
}
}
$(internal_src_dir)/update/gestures/scene-graph-pan-gesture.cpp \
$(internal_src_dir)/update/queue/update-message-queue.cpp \
$(internal_src_dir)/update/manager/prepare-render-instructions.cpp \
+ $(internal_src_dir)/update/manager/geometry-batcher.cpp \
$(internal_src_dir)/update/manager/process-render-tasks.cpp \
$(internal_src_dir)/update/manager/transform-manager.cpp \
$(internal_src_dir)/update/manager/update-algorithms.cpp \
#include <dali/internal/render/gl-resources/context.h>
#include <dali/internal/render/renderers/render-renderer.h>
#include <dali/internal/update/nodes/scene-graph-layer.h>
+#include <dali/internal/update/manager/geometry-batcher.h>
using Dali::Internal::SceneGraph::RenderItem;
using Dali::Internal::SceneGraph::RenderList;
using Dali::Internal::SceneGraph::RenderListContainer;
using Dali::Internal::SceneGraph::RenderInstruction;
+using Dali::Internal::SceneGraph::GeometryBatcher;
namespace Dali
{
* @param[in] buffer The current render buffer index (previous update buffer)
* @param[in] viewMatrix The view matrix from the appropriate camera.
* @param[in] projectionMatrix The projection matrix from the appropriate camera.
+ * @param[in] geometryBatcher The instance of the geometry batcher
*/
inline void ProcessRenderList(
const RenderList& renderList,
SceneGraph::Shader& defaultShader,
BufferIndex bufferIndex,
const Matrix& viewMatrix,
- const Matrix& projectionMatrix )
+ const Matrix& projectionMatrix,
+ GeometryBatcher* geometryBatcher )
{
DALI_PRINT_RENDER_LIST( renderList );
if( DALI_LIKELY( !renderList.HasColorRenderItems() || !depthTestEnabled ) )
{
size_t count = renderList.Count();
+ bool skip( false );
for ( size_t index = 0; index < count; ++index )
{
const RenderItem& item = renderList.GetItem( index );
DALI_PRINT_RENDER_ITEM( item );
SetupPerRendererFlags( item, context, usedStencilBuffer, stencilManagedByDrawMode );
- item.mRenderer->Render( context, textureCache, bufferIndex, *item.mNode, defaultShader,
- item.mModelMatrix, item.mModelViewMatrix, viewMatrix, projectionMatrix, item.mSize, !item.mIsOpaque );
+
+ // Check if the node has a valid batch index value ( set previously by
+ // GeometryBatcher ). If so, then it queries the geometry object for this particular batch.
+ // If not, it still checks if the batch parent is set as it is possible, batching may
+ // fail ( for example if vertex format or buffers are not set ). In that case we need
+ // to skip rendering, otherwise unwanted GPU buffers will get uploaded. This is very rare case.
+ uint32_t batchIndex = item.mNode->mBatchIndex;
+ if( batchIndex != BATCH_NULL_HANDLE )
+ {
+ item.mBatchRenderGeometry = geometryBatcher->GetGeometry( batchIndex );
+ }
+ else
+ {
+ skip = item.mNode->GetBatchParent();
+ item.mBatchRenderGeometry = NULL;
+ }
+ if( !skip )
+ {
+ item.mRenderer->Render( context, textureCache, bufferIndex, *item.mNode, defaultShader,
+ item.mModelMatrix, item.mModelViewMatrix, viewMatrix, projectionMatrix, item.mSize, item.mBatchRenderGeometry, !item.mIsOpaque );
+ }
}
}
else
SetupPerRendererFlags( item, context, usedStencilBuffer, stencilManagedByDrawMode );
item.mRenderer->Render( context, textureCache, bufferIndex, *item.mNode, defaultShader,
- item.mModelMatrix, item.mModelViewMatrix, viewMatrix, projectionMatrix, item.mSize, !item.mIsOpaque );
+ item.mModelMatrix, item.mModelViewMatrix, viewMatrix, projectionMatrix, item.mSize, item.mBatchRenderGeometry, !item.mIsOpaque );
}
}
}
Context& context,
SceneGraph::TextureCache& textureCache,
SceneGraph::Shader& defaultShader,
+ GeometryBatcher& geometryBatcher,
BufferIndex bufferIndex )
{
DALI_PRINT_RENDER_INSTRUCTION( instruction, bufferIndex );
if( renderList &&
!renderList->IsEmpty() )
{
- ProcessRenderList( *renderList, context, textureCache, defaultShader, bufferIndex, *viewMatrix, *projectionMatrix );
+ ProcessRenderList( *renderList, context, textureCache, defaultShader, bufferIndex, *viewMatrix, *projectionMatrix, &geometryBatcher );
}
}
}
class RenderInstruction;
class Shader;
class TextureCache;
+class GeometryBatcher;
}
namespace Render
* @param[in] context The GL context.
* @param[in] textureCache The texture cache used to get textures.
* @param[in] defaultShader The default shader.
+ * @param[in] geometryBatcher The instace of geometry batcher.
* @param[in] bufferIndex The current render buffer index (previous update buffer)
*/
void ProcessRenderInstruction( const SceneGraph::RenderInstruction& instruction,
Context& context,
SceneGraph::TextureCache& textureCache,
SceneGraph::Shader& defaultShader,
+ SceneGraph::GeometryBatcher& geometryBatcher,
BufferIndex bufferIndex );
} // namespace Render
mSize(),
mRenderer( NULL ),
mNode( NULL ),
+ mBatchRenderGeometry( NULL ),
mDepthIndex( 0 ),
- mIsOpaque( true )
+ mIsOpaque( true ),
+ mBatched( false )
{
}
namespace Render
{
class Renderer;
+class RenderGeometry;
}
namespace SceneGraph
*/
void operator delete( void* ptr );
-
Matrix mModelMatrix;
Matrix mModelViewMatrix;
Vector3 mSize;
Render::Renderer* mRenderer;
Node* mNode;
+
+ mutable Render::Geometry* mBatchRenderGeometry;
+
int mDepthIndex;
bool mIsOpaque:1;
+ bool mBatched:1;
+
private:
Impl( Integration::GlAbstraction& glAbstraction,
Integration::GlSyncAbstraction& glSyncAbstraction,
LockedResourceQueue& textureUploadedQ,
- TextureUploadedDispatcher& postProcessDispatcher )
+ TextureUploadedDispatcher& postProcessDispatcher,
+ GeometryBatcher& geometryBatcher )
: context( glAbstraction ),
glSyncAbstraction( glSyncAbstraction ),
renderQueue(),
renderersAdded( false ),
firstRenderCompleted( false ),
defaultShader( NULL ),
- programController( glAbstraction )
+ programController( glAbstraction ),
+ geometryBatcher( geometryBatcher )
{
}
bool firstRenderCompleted; ///< False until the first render is done
Shader* defaultShader; ///< Default shader to use
ProgramController programController; ///< Owner of the GL programs
+
+ SceneGraph::GeometryBatcher& geometryBatcher; ///< Instance of geometry batcher
};
RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction,
Integration::GlSyncAbstraction& glSyncAbstraction,
+ SceneGraph::GeometryBatcher& geometryBatcher,
LockedResourceQueue& textureUploadedQ )
{
RenderManager* manager = new RenderManager;
- manager->mImpl = new Impl( glAbstraction, glSyncAbstraction, textureUploadedQ, *manager );
+ manager->mImpl = new Impl( glAbstraction, glSyncAbstraction, textureUploadedQ, *manager, geometryBatcher );
return manager;
}
mImpl->context,
mImpl->textureCache,
defaultShader,
+ mImpl->geometryBatcher,
mImpl->renderBufferIndex );
if(instruction.mOffscreenTextureId != 0)
class RenderInstructionContainer;
class Shader;
class PropertyBufferDataProvider;
+class GeometryBatcher;
/**
* RenderManager is responsible for rendering the result of the previous "update", which
* Construct a new RenderManager.
* @param[in] glAbstraction The GL abstraction used for rendering.
* @param[in] glSyncAbstraction The GL sync abstraction used fence sync creation/deletion.
- * @param[out] resourcePostProcessQueue A queue for sending rendered texture ids to the update-thread.
+ * @param[in] geometryBatcher The geometry batcher instance
+ * @param[out] resourcePostProcessQueue A queue for sending rendered texture ids to the update-thread.*
*/
static RenderManager* New( Integration::GlAbstraction& glAbstraction,
Integration::GlSyncAbstraction& glSyncAbstraction,
+ SceneGraph::GeometryBatcher& geometryBatcher,
LockedResourceQueue& resourcePostProcessQueue );
/**
DALI_ASSERT_DEBUG( bitmap != 0 );
if( !bitmap )
{
- DALI_LOG_ERROR( "Passed a null bitmap to update this bitmap texture." );
+ DALI_LOG_ERROR( "Passed a null bitmap to update this bitmap texture.\n" );
return;
}
if( !bitmapPackedPixels )
{
///! This should never happen.
- DALI_LOG_ERROR("Passed an incompatible bitmap type to update this bitmap texture.");
+ DALI_LOG_ERROR("Passed an incompatible bitmap type to update this bitmap texture.\n");
return;
}
mBitmap = bitmap;
if( !bitmap )
{
- DALI_LOG_ERROR( "Passed a null bitmap to update this compressed bitmap texture." );
+ DALI_LOG_ERROR( "Passed a null bitmap to update this compressed bitmap texture.\n" );
return;
}
if( mNativeImage &&
!mNativeImage->GlExtensionCreate() )
{
- DALI_LOG_ERROR( "Error creating native image!" );
+ DALI_LOG_ERROR( "Error creating native image!\n" );
return false;
}
}
else
{
- DALI_LOG_ERROR( "Error creating native image!" );
+ DALI_LOG_ERROR( "Error creating native image!\n" );
}
return mId != 0;
{
}
-void Geometry::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer )
+void Geometry::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer)
{
mVertexBuffers.PushBack( propertyBuffer );
mAttributesChanged = true;
mIndicesChanged = true;
}
+const Dali::Vector<unsigned short>* Geometry::GetIndexBuffer() const
+{
+ return &mIndices;
+}
+
void Geometry::RemovePropertyBuffer( const Render::PropertyBuffer* propertyBuffer )
{
size_t bufferCount = mVertexBuffers.Size();
if( propertyBuffer == mVertexBuffers[i] )
{
//This will delete the gpu buffer associated to the RenderPropertyBuffer if there is one
- mVertexBuffers.Remove( mVertexBuffers.Begin()+i);
+ mVertexBuffers.Remove( mVertexBuffers.Begin()+i );
mAttributesChanged = true;
break;
}
}
}
+const Render::PropertyBuffer* Geometry::GetPropertyBuffer( size_t index ) const
+{
+ if( index < mVertexBuffers.Size() )
+ {
+ return mVertexBuffers[ index ];
+ }
+ return NULL;
+}
+
void Geometry::GetAttributeLocationFromProgram( Vector<GLint>& attributeLocation, Program& program, BufferIndex bufferIndex ) const
{
attributeLocation.Clear();
mIndicesChanged = false;
}
- for( unsigned int i = 0; i < mVertexBuffers.Count(); ++i )
+ size_t count = mVertexBuffers.Count();
+ for( unsigned int i = 0; i < count; ++i )
{
+
if( !mVertexBuffers[i]->Update( context ) )
{
//Vertex buffer is not ready ( Size, data or format has not been specified yet )
void SetIndexBuffer( Dali::Vector<unsigned short>& indices );
/**
+ * Obtains pointer to the storage of indexed elements
+ * @return Pointer to the index buffer
+ */
+ const Dali::Vector<unsigned short>* GetIndexBuffer() const;
+
+ /**
* Removes a PropertyBuffer from the geometry
* @param[in] propertyBuffer The property buffer to be removed
*/
void RemovePropertyBuffer( const Render::PropertyBuffer* propertyBuffer );
/**
+ * Returns property buffer at specified index
+ * @param[in] index of the property buffer
+ * @return pointer to the property buffer or NULL
+ */
+ const Render::PropertyBuffer* GetPropertyBuffer( size_t index ) const;
+
+ /**
* Gets the attribute locations on the shader for the attributes defined in the geometry RenderBuffers
* @param[out] attributeLocation The vector where the attributes locations will be stored
* @param[in] program The program
bool mIndicesChanged : 1;
bool mHasBeenUpdated : 1;
bool mAttributesChanged : 1;
-
};
} // namespace Render
mDataChanged = true;
}
+void PropertyBuffer::UpdateData()
+{
+ mDataChanged = true;
+}
+
bool PropertyBuffer::Update( Context& context )
{
if( !mData || !mFormat || !mSize )
void SetData( Dali::Vector<char>* data, size_t size );
/**
+ * @brief Sets flag to update data in the buffer when next PropertyBuffer::Update()
+ * is called.
+ */
+ void UpdateData();
+
+ /**
* @brief Set the number of elements
* @param[in] size The number of elements
*/
return mSize;
}
+ /**
+ * Retrieve reference to the data storage vector
+ * @return Reference to the data storage
+ */
+ inline const Dali::Vector< char >& GetData() const
+ {
+ return *mData.Get();
+ }
+
+ /**
+ * Retrieve data writeable pointer ( direct access to the buffer data )
+ * @return Pointer to data converted to requested type
+ */
+ template <typename T>
+ inline T* GetDataTypedPtr()
+ {
+ Dali::Vector< char >* data = mData.Release();
+ mData = data;
+ return reinterpret_cast<T*>( &data->operator[]( 0 ) );
+ }
+
+ inline const PropertyBuffer::Format* GetFormat() const
+ {
+ return mFormat.Get();
+ }
+
private:
- OwnerPointer< PropertyBuffer::Format > mFormat; ///< Format of the buffer
- OwnerPointer< Dali::Vector< char > > mData; ///< Data
- OwnerPointer< GpuBuffer > mGpuBuffer; ///< Pointer to the GpuBuffer associated with this RenderPropertyBuffer
+ OwnerPointer< PropertyBuffer::Format > mFormat; ///< Format of the buffer
+ OwnerPointer< Dali::Vector< char > > mData; ///< Data
+ OwnerPointer< GpuBuffer > mGpuBuffer; ///< Pointer to the GpuBuffer associated with this RenderPropertyBuffer
size_t mSize; ///< Number of Elements in the buffer
bool mDataChanged; ///< Flag to know if data has changed in a frame
-
};
} // namespace Render
mDepthTestMode( depthTestMode ),
mWriteToColorBuffer( writeToColorBuffer ),
mUpdateAttributesLocation( true ),
- mPremultipledAlphaEnabled( preMultipliedAlphaEnabled )
+ mPremultipledAlphaEnabled( preMultipliedAlphaEnabled ),
+ mBatchingEnabled( false )
{
if( blendingBitmask != 0u )
{
return mWriteToColorBuffer;
}
+void Renderer::SetBatchingEnabled( bool batchingEnabled )
+{
+ mBatchingEnabled = batchingEnabled;
+}
+
void Renderer::Render( Context& context,
SceneGraph::TextureCache& textureCache,
BufferIndex bufferIndex,
const Matrix& viewMatrix,
const Matrix& projectionMatrix,
const Vector3& size,
+ Render::Geometry* externalGeometry,
bool blend )
{
// Get the program to use:
DALI_ASSERT_DEBUG( program && "Default shader should always have a program available." );
if( !program )
{
- DALI_LOG_ERROR( "Failed to get program for shader at address %p.", (void*)&mRenderDataProvider->GetShader() );
+ DALI_LOG_ERROR( "Failed to get program for shader at address %p.\n", (void*)&mRenderDataProvider->GetShader() );
return;
}
}
}
SetUniforms( bufferIndex, node, size, *program );
+ Render::Geometry* geometry = externalGeometry ? externalGeometry : mGeometry;
- if( mUpdateAttributesLocation || mGeometry->AttributesChanged() )
+ if( mUpdateAttributesLocation || geometry->AttributesChanged() )
{
- mGeometry->GetAttributeLocationFromProgram( mAttributesLocation, *program, bufferIndex );
+ geometry->GetAttributeLocationFromProgram( mAttributesLocation, *program, bufferIndex );
mUpdateAttributesLocation = false;
}
- mGeometry->UploadAndDraw( context, bufferIndex, mAttributesLocation, mIndexedDrawFirstElement, mIndexedDrawElementsCount );
+ geometry->UploadAndDraw( context, bufferIndex, mAttributesLocation, mIndexedDrawFirstElement, mIndexedDrawElementsCount );
}
}
* @param[in] geometry The new geometry
*/
void SetGeometry( Render::Geometry* geometry );
+
+ /**
+ * Retrieves the geometry used by the renderer
+ * @return The geometry used by the renderer
+ */
+ Render::Geometry* GetGeometry() const
+ {
+ return mGeometry;
+ }
+
/**
* Second-phase construction.
* This is called when the renderer is inside render thread
- * @param[in] context to use
- * @param[in] textureCache to use
- * @param[in] uniformNameCache to use
+ * @param[in] context Context used by the renderer
+ * @param[in] textureCache The texture cache to use
+ * @param[in] uniformNameCache Cache of uniform names to use
*/
void Initialize( Context& context, SceneGraph::TextureCache& textureCache, Render::UniformNameCache& uniformNameCache );
bool GetWriteToColorBuffer() const;
/**
+ * Sets batching mode on the renderer
+ * @param[in] batchingEnabled batching state
+ */
+ void SetBatchingEnabled( bool batchingEnabled );
+
+ /**
* Called to render during RenderManager::Render().
* @param[in] context The context used for rendering
* @param[in] textureCache The texture cache used to get textures
* @param[in] modelViewMatrix The model-view matrix.
* @param[in] viewMatrix The view matrix.
* @param[in] projectionMatrix The projection matrix.
+ * @param[in] size Size of the render item
+ * @param[in] externalGeometry Optional external geometry, if set the original geometry is ignored. If NULL, original geometry will be drawn as normal.
+ * @param[in] blend If true, blending is enabled
*/
void Render( Context& context,
SceneGraph::TextureCache& textureCache,
const Matrix& viewMatrix,
const Matrix& projectionMatrix,
const Vector3& size,
+ Render::Geometry* externalGeometry,
bool blend);
/**
bool mWriteToColorBuffer:1; ///< True if we are writing to the color buffer
bool mUpdateAttributesLocation:1; ///< Indicates attribute locations have changed
bool mPremultipledAlphaEnabled:1; ///< Flag indicating whether the Pre-multiplied Alpha Blending is required
+ bool mBatchingEnabled:1; ///< Flag indicating if the renderer is batchable
};
} // namespace SceneGraph
if( mId )
{
context.DeleteTextures( 1, &mId );
+
+ if( mNativeImage )
+ {
+ mNativeImage->GlExtensionDestroy();
+ }
}
}
context.TexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_WRAP_DEFAULT );
// platform specific implementation decides on what GL extension to use
- mNativeImage->TargetTexture();
+ if( mNativeImage->TargetTexture() != 0u )
+ {
+ context.DeleteTextures( 1, &mId );
+ mNativeImage->GlExtensionDestroy();
+ mId = 0u;
+ }
}
}
else
ApplySampler( context, sampler );
+ if( mNativeImage )
+ {
+ //Allow implementation specific operations after binding the texture
+ mNativeImage->PrepareTexture();
+ }
+
return true;
}
#include <dali/internal/render/renderers/render-renderer.h>
#include <dali/internal/render/shaders/scene-graph-shader.h>
#include <dali/internal/update/render-tasks/scene-graph-camera.h>
+#include <dali/internal/update/manager/geometry-batcher.h>
namespace Dali
{
// The GL resources will now be freed in frame N
// The Update for frame N+1 may occur in parallel with the rendering of frame N
// Queue the node for destruction in frame N+2
- if ( 0u == updateBufferIndex )
+ mNodeQueue[ updateBufferIndex ].PushBack( node );
+
+ // If batching, then mark corresponding batch to be destroyed too
+ if( node->GetIsBatchParent() )
{
- mNodeQueue0.PushBack( node );
+ mGeometryBatcher->RemoveBatchParent( node );
}
- else
+ else if( node->GetBatchParent() )
{
- mNodeQueue1.PushBack( node );
+ if( node->mBatchIndex != BATCH_NULL_HANDLE )
+ {
+ mGeometryBatcher->RemoveNode( node );
+ }
}
+
}
void DiscardQueue::Add( BufferIndex updateBufferIndex, Shader* shader )
// The GL resources will now be freed in frame N
// The Update for frame N+1 may occur in parallel with the rendering of frame N
// Queue the node for destruction in frame N+2
- if ( 0u == updateBufferIndex )
- {
- mShaderQueue0.PushBack( shader );
- }
- else
- {
- mShaderQueue1.PushBack( shader );
- }
+ mShaderQueue[ updateBufferIndex ].PushBack( shader );
}
void DiscardQueue::Add( BufferIndex updateBufferIndex, Renderer* renderer )
// The GL resources will now be freed in frame N
// The Update for frame N+1 may occur in parallel with the rendering of frame N
// Queue the node for destruction in frame N+2
- if ( 0u == updateBufferIndex )
- {
- mRendererQueue0.PushBack( renderer );
- }
- else
- {
- mRendererQueue1.PushBack( renderer );
- }
+ mRendererQueue[ updateBufferIndex ].PushBack( renderer );
}
void DiscardQueue::Add( BufferIndex updateBufferIndex, Camera* camera )
{
DALI_ASSERT_DEBUG( NULL != camera );
- if ( 0u == updateBufferIndex )
- {
- mCameraQueue0.PushBack( camera );
- }
- else
- {
- mCameraQueue1.PushBack( camera );
- }
+ mCameraQueue[ updateBufferIndex ].PushBack( camera );
}
void DiscardQueue::Clear( BufferIndex updateBufferIndex )
{
// Destroy some discarded objects; these should no longer own any GL resources
+ mNodeQueue[ updateBufferIndex ].Clear();
+ mShaderQueue[ updateBufferIndex ].Clear();
+ mRendererQueue[ updateBufferIndex ].Clear();
+ mCameraQueue[ updateBufferIndex ].Clear();
+}
- if ( 0u == updateBufferIndex )
- {
- mNodeQueue0.Clear();
- mShaderQueue0.Clear();
- mRendererQueue0.Clear();
- mCameraQueue0.Clear();
- }
- else
- {
- mNodeQueue1.Clear();
- mShaderQueue1.Clear();
- mRendererQueue1.Clear();
- mCameraQueue1.Clear();
- }
+void DiscardQueue::SetGeometryBatcher( GeometryBatcher* geometryBatcher )
+{
+ mGeometryBatcher = geometryBatcher;
}
} // namespace SceneGraph
namespace SceneGraph
{
+class GeometryBatcher;
class RenderQueue;
class Shader;
class Camera;
*/
void Clear( BufferIndex updateBufferIndex );
+ /**
+ * Sets pointer to the GeometryBatcher instance
+ * @param[in] geometryBatcher Instance of the GeometryBatcher
+ */
+ void SetGeometryBatcher( GeometryBatcher* geometryBatcher );
+
private:
// Undefined
RenderQueue& mRenderQueue; ///< Used to send GL clean-up messages for the next Render.
- // Messages are queued here when the update buffer index == 0
- NodeOwnerContainer mNodeQueue0;
- ShaderQueue mShaderQueue0;
- RendererQueue mRendererQueue0;
- CameraQueue mCameraQueue0;
-
- // Messages are queued here when the update buffer index == 1
- NodeOwnerContainer mNodeQueue1;
- ShaderQueue mShaderQueue1;
- RendererQueue mRendererQueue1;
- CameraQueue mCameraQueue1;
+ // Messages are queued here following the current update buffer number
+ NodeOwnerContainer mNodeQueue[2];
+ ShaderQueue mShaderQueue[2];
+ RendererQueue mRendererQueue[2];
+ CameraQueue mCameraQueue[2];
+
+
+ GeometryBatcher* mGeometryBatcher; ///< Geometry batcher needed to clean up batches upon node deletion
};
} // namespace SceneGraph
--- /dev/null
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// CLASS HEADER
+#include <dali/internal/update/manager/geometry-batcher.h>
+
+// INTERNAL INCLUDES
+#include <dali/internal/render/common/render-item.h>
+#include <dali/internal/render/common/render-tracker.h>
+#include <dali/internal/render/common/render-instruction.h>
+#include <dali/internal/render/common/render-instruction-container.h>
+#include <dali/internal/render/shaders/scene-graph-shader.h>
+#include <dali/internal/render/renderers/render-renderer.h>
+#include <dali/internal/render/renderers/render-property-buffer.h>
+#include <dali/internal/render/renderers/render-geometry.h>
+#include <dali/internal/update/rendering/scene-graph-renderer.h>
+#include <dali/internal/update/controllers/scene-controller.h>
+#include <dali/internal/update/manager/update-manager.h>
+#include <dali/internal/common/math.h>
+
+namespace
+{
+
+// helper macros to deal with handles
+#define BATCH_LOCAL_INDEX(x) (x&0xFFFF)
+#define BATCH_PARENT_INDEX(x) ((x>>16)&0xFFFF)
+#define BATCH_INDEX_CREATE( batchParentIndex, batchIndex ) ( ( ( (batchParentIndex)&0xFFFF ) << 16 ) | ( (batchIndex)&0xFFFF ) )
+
+/**
+ * The TransformVertexBufferInfo struct
+ * Must be filled before transforming vertices
+ */
+struct TransformVertexBufferData
+{
+ void* destinationPtr; ///< pointer to the destination vertex buffer
+ const void* sourcePtr; ///< pointer to the source vertex buffer
+ float* transform; ///< transform relative to batch parent
+ const float* worldMatrix; ///< model/world matrix of node being batched
+ const float* parentInvWorldMatrix; ///< inv world matrix of batch parent
+ unsigned componentSize; ///< size of component
+ unsigned vertexCount; ///< number of vertices to process
+ const float* size; ///< size of render item
+};
+
+/**
+ * @brief function transforms vertices from 'source' and writes into 'destination'
+ * @param[in,out] data Filled TransformVertexBufferInfo arguments structure
+ */
+template <typename PositionType >
+void TransformVertexBuffer( TransformVertexBufferData& data )
+{
+ const PositionType* source = reinterpret_cast<const PositionType*>( data.sourcePtr );
+ PositionType* destination = reinterpret_cast<PositionType*>( data.destinationPtr );
+
+ size_t componentSize = data.componentSize ? data.componentSize : sizeof( PositionType );
+ const void* sourceEnd = (reinterpret_cast<const char*>( source ) + ( data.vertexCount*componentSize ));
+ for( ; source < sourceEnd;
+ *(reinterpret_cast<char**>( &destination )) += componentSize,
+ *(reinterpret_cast<const char**>( &source )) += componentSize
+ )
+ {
+ Dali::Internal::MultiplyVectorBySize( *destination, *source, data.size );
+ Dali::Internal::MultiplyVectorByMatrix4( *destination, data.transform, *destination );
+ }
+}
+
+} //Unnamed namespace
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace SceneGraph
+{
+
+/**
+ * @brief The VertexDescriptor struct
+ * Holds details of vertex format used for batching
+ */
+struct VertexDescriptor
+{
+ VertexDescriptor()
+ : mVertexComponentSize( 0 ),
+ mVertexPositionType( Dali::Property::NONE ),
+ mVertexFormat( NULL )
+ {
+ }
+
+ unsigned int mVertexComponentSize; ///< Vertex component size in bytes
+ Dali::Property::Type mVertexPositionType; ///< Vertex position type ( may be Vector2, Vector3, Vector4 )
+ Dali::Internal::Render::PropertyBuffer::Format* mVertexFormat; ///< Vertex format cloned from the very first batched item
+};
+
+struct BatchKey
+{
+ BatchKey()
+ : batchParentNode( NULL ),
+ shader( NULL ),
+ textureSet( NULL ),
+ depthIndex( 0 )
+ {
+ }
+
+ ~BatchKey()
+ {
+ }
+
+ BatchKey( Node* node )
+ {
+ MakeFromNode( node );
+ }
+
+ inline void MakeFromNode( Node* node )
+ {
+ Renderer* renderer = node->GetRendererAt( 0 );
+ batchParentNode = node->GetBatchParent();
+ shader = &renderer->GetShader();
+ textureSet = renderer->GetTextures();
+ depthIndex = renderer->GetDepthIndex();
+ }
+
+ inline bool operator==( const BatchKey& key )
+ {
+ return batchParentNode == key.batchParentNode && shader == key.shader && textureSet == key.textureSet && depthIndex == key.depthIndex;
+ }
+
+ inline bool operator!=( const BatchKey& key )
+ {
+ return !( *this == key );
+ }
+
+ const Node* batchParentNode; /// batch parent node that owns batch
+ const Shader* shader; /// shader associated with the batch
+ const TextureSet* textureSet; /// texture set used by the batch
+ int depthIndex; /// depth index of the batch
+};
+
+/**
+ * @brief The Batch struct
+ * Stores details of single batch
+ */
+struct Batch
+{
+ Batch( const BatchKey& key, Render::Geometry* batchGeometry = NULL )
+ : batchKey( key ),
+ geometry( batchGeometry ),
+ renderedFrame( 0 ),
+ dirty( true )
+ {}
+
+
+ BatchKey batchKey; /// Unique batch key
+ Vector<unsigned short> indices; /// index buffer per batch
+ Render::Geometry* geometry; /// Batch geometry
+ size_t renderedFrame; /// Flag used to determine if batch has already rendered during a frame
+ bool dirty; /// 'dirty' flag per batch
+};
+
+typedef std::vector<Batch> BatchList;
+
+/**
+ * @brief The BatchParent struct
+ * Stores list of children of single batch parent
+ */
+struct BatchParent
+{
+ Node* node; /// Pointer to a node which is a parent for batch(es)
+ Vector<Node*> batchedChildren; /// List of batchable children
+ BatchList batches; /// List of batches which belong to this parent
+ Render::PropertyBuffer* vertexBuffer; /// Vertex buffer shared by all batches for this parent
+ bool needsUpdate; /// Flag indicating if batches should be updated
+};
+
+struct Impl
+{
+ Impl() :
+ currentFrame( 0 )
+ {}
+
+ int GetBatchKeyIndex( size_t batchParentIndex, const BatchKey& key )
+ {
+ BatchParent& batchParent = batchParents[ batchParentIndex ];
+ for( size_t j = 0; j < batchParent.batches.size(); ++j )
+ {
+ if( batchParent.batches[j].batchKey == key )
+ {
+ return BATCH_INDEX_CREATE( batchParentIndex, j );
+ }
+ }
+ return -1;
+ }
+
+ std::vector<BatchParent> batchParents; /// non-trivial type, hence std::vector
+ UpdateManager* updateManager;
+ size_t currentFrame;
+};
+
+GeometryBatcher::GeometryBatcher() :
+ mImpl( NULL )
+{
+ mImpl = new Impl();
+}
+
+void GeometryBatcher::SetUpdateManager( UpdateManager* updateManager )
+{
+ mImpl->updateManager = updateManager;
+}
+
+GeometryBatcher::~GeometryBatcher()
+{
+ delete mImpl;
+}
+
+bool GeometryBatcher::CloneVertexFormat( const Render::Geometry* sourceGeometry, VertexDescriptor& vertexDescriptor )
+{
+ const Render::Geometry* geometry = sourceGeometry;
+ const Render::PropertyBuffer::Format* format = geometry->GetPropertyBuffer( 0 )->GetFormat();
+
+ if( !format )
+ {
+ return false;
+ }
+
+ Render::PropertyBuffer::Format* clonedVertexFormat = new Render::PropertyBuffer::Format( *format );
+ Render::PropertyBuffer::Component& firstComponent = clonedVertexFormat->components[0];
+
+ vertexDescriptor.mVertexPositionType = firstComponent.type;
+ vertexDescriptor.mVertexComponentSize = clonedVertexFormat->size;
+ vertexDescriptor.mVertexFormat = clonedVertexFormat;
+
+ return true;
+}
+
+void GeometryBatcher::Update( BufferIndex bufferIndex )
+{
+ if( !mImpl->batchParents.empty() )
+ {
+ std::vector<BatchParent>::iterator iter = mImpl->batchParents.begin();
+ std::vector<BatchParent>::iterator end = mImpl->batchParents.end();
+
+ // for each Batch Parent
+ for( size_t batchParentIndex = 0; iter != end; ++iter, ++batchParentIndex )
+ {
+ BatchParent& batchParentData = *iter;
+ // Skip update if batch parent doesn't need it
+ if( !batchParentData.needsUpdate )
+ {
+ continue;
+ }
+
+ Node* batchParentNode = batchParentData.node;
+
+ // Skip if batch parent doesn't have batched children
+ size_t size = batchParentData.batchedChildren.Size();
+ if( !size )
+ {
+ batchParentData.needsUpdate = false;
+ continue;
+ }
+
+ bool batchingFailed( false );
+ uint32_t batchKeyIndex( BATCH_NULL_HANDLE );
+
+ BatchKey oldKey;
+ BatchKey key;
+ VertexDescriptor vertexDescriptor;
+
+ // Destination vertex buffer per batch parent
+ Vector<char>& vertexBufferDest = *( new Vector<char>() );
+ Render::PropertyBuffer* batchVertexBuffer = new Render::PropertyBuffer();
+
+ size_t currentElementIndex = 0;
+
+ Matrix invWorldMatrix( batchParentNode->GetWorldMatrix( bufferIndex ) );
+ invWorldMatrix.Invert();
+
+ // For each batched child of this batch parent...
+ for( size_t i = 0; i < size; ++i )
+ {
+ Node* node = batchParentData.batchedChildren[i];
+
+ const SceneGraph::Renderer* renderer = node->GetRendererAt( 0 );
+
+ // Geometry
+ const Render::Geometry* geometry = &renderer->GetGeometry();
+
+ // Generate batch key
+ key.MakeFromNode( node );
+
+ // format of first property buffer
+ const Render::PropertyBuffer* vertexBuffer = geometry->GetPropertyBuffer( 0 );
+
+ // Geometry of the node may not be ready, in that case we discard whole batch
+ if( !vertexBuffer || ( !vertexDescriptor.mVertexFormat && !CloneVertexFormat( geometry, vertexDescriptor ) ) )
+ {
+ batchingFailed = true;
+ break;
+ }
+
+ // Instantiate new batch
+ if( oldKey != key )
+ {
+ oldKey = key;
+ batchKeyIndex = mImpl->GetBatchKeyIndex( batchParentIndex, key );
+
+ if( batchKeyIndex == BATCH_NULL_HANDLE )
+ {
+ // Create new batch geometry
+ Render::Geometry* newGeometry = new Render::Geometry();
+
+ Batch batch( key, newGeometry );
+
+ // push new batch
+ batchParentData.batches.push_back( batch );
+
+ // rebuild handle
+ batchKeyIndex = BATCH_INDEX_CREATE( batchParentIndex, batchParentData.batches.size()-1 );
+
+ // Vertex buffer may be set before it's filled with data
+ newGeometry->AddPropertyBuffer( batchVertexBuffer );
+
+ // Register geometry with update manager
+ mImpl->updateManager->AddGeometry( newGeometry );
+ }
+ }
+
+ // Tell node which batch it belongs to
+ node->mBatchIndex = batchKeyIndex;
+
+ uint32_t localIndex = BATCH_LOCAL_INDEX( batchKeyIndex );
+
+ if( !batchParentData.batches[ localIndex ].dirty )
+ {
+ continue;
+ }
+
+ const uint32_t vertexBufferSize = vertexBuffer->GetDataSize();
+ const char* vertexDataSource = &vertexBuffer->GetData()[ 0 ];
+
+ uint32_t currentSize = vertexBufferDest.Size();
+ vertexBufferDest.Resize( currentSize + vertexBufferSize );
+ char* vertexDataDest = &vertexBufferDest[ currentSize ];
+
+ // copy data as they are
+ std::copy( vertexDataSource, vertexDataSource + vertexBufferSize, vertexDataDest );
+
+ // transform node
+ const Matrix& worldMatrix = node->GetWorldMatrix( bufferIndex );
+
+ // vertex count
+ const unsigned int sourceVertexCount = vertexBufferSize / vertexDescriptor.mVertexComponentSize;
+
+ // compute transform for the node
+ TransformVertexBufferData transformParameters;
+ transformParameters.destinationPtr = vertexDataDest;
+ transformParameters.sourcePtr = vertexDataSource;
+
+ // perform transformation
+ Matrix transformMatrix;
+ Dali::Internal::MultiplyMatrices( transformMatrix.AsFloat(), worldMatrix.AsFloat(), invWorldMatrix.AsFloat() );
+ transformParameters.transform = transformMatrix.AsFloat();
+ transformParameters.componentSize = vertexDescriptor.mVertexComponentSize;
+ transformParameters.vertexCount = sourceVertexCount;
+ transformParameters.size = node->GetSize( bufferIndex ).AsFloat();
+
+ // Perform vertex transform based on the vertex format
+ switch( vertexDescriptor.mVertexPositionType )
+ {
+ case Dali::Property::VECTOR2:
+ {
+ TransformVertexBuffer<Vec2>( transformParameters );
+ break;
+ }
+ case Dali::Property::VECTOR3:
+ {
+ TransformVertexBuffer<Vec3>( transformParameters );
+ break;
+ }
+ case Dali::Property::VECTOR4:
+ {
+ TransformVertexBuffer<Vec4>( transformParameters );
+ break;
+ }
+ default:
+ {
+ DALI_ASSERT_ALWAYS( true && "Incorrect vertex format! Use Vector2, Vector3 or Vector4 as position!" );
+ }
+ }
+
+ // update index buffer
+ Batch& batch = batchParentData.batches[ localIndex ];
+ uint32_t currentIndexOffset = batch.indices.Size();
+ batch.indices.Resize( batch.indices.Size() + sourceVertexCount );
+ for( size_t k = 0; k < sourceVertexCount; ++k )
+ {
+ size_t index = currentElementIndex + k;
+ batch.indices[k + currentIndexOffset] = (unsigned short)index;
+ }
+
+ currentElementIndex += sourceVertexCount;
+ }
+
+ if( batchingFailed )
+ {
+ delete &vertexBufferDest;
+ delete batchVertexBuffer;
+ continue;
+ }
+
+ // Add shared property buffer
+ mImpl->updateManager->AddPropertyBuffer( batchVertexBuffer );
+ batchVertexBuffer->SetFormat( vertexDescriptor.mVertexFormat );
+ batchVertexBuffer->SetData( &vertexBufferDest, vertexBufferDest.Size()/vertexDescriptor.mVertexComponentSize );
+
+ batchParentData.needsUpdate = false;
+ batchParentData.vertexBuffer = batchVertexBuffer;
+
+ // Update index buffers for all batches own by that batch parent
+ std::vector<Batch>::iterator iter = batchParentData.batches.begin();
+ std::vector<Batch>::iterator end = batchParentData.batches.end();
+ for( ; iter != end; ++iter )
+ {
+ Batch& batch = (*iter);
+ batch.geometry->SetIndexBuffer( batch.indices );
+ batch.dirty = false;
+ }
+ }
+ }
+ ++mImpl->currentFrame;
+}
+
+void GeometryBatcher::AddBatchParent( Node* node )
+{
+ BatchParent batchParent;
+ batchParent.node = node;
+ batchParent.needsUpdate = true;
+ batchParent.batchedChildren.Clear();
+
+ mImpl->batchParents.push_back( batchParent );
+}
+
+void GeometryBatcher::RemoveBatchParent( Node* node )
+{
+ for( size_t i = 0; i < mImpl->batchParents.size(); ++i )
+ {
+ BatchParent& batchParent = mImpl->batchParents[i];
+ if( node == batchParent.node )
+ {
+ // tell children they're not batched anymore
+ Vector<Node*>::Iterator iter = batchParent.batchedChildren.Begin();
+ Vector<Node*>::Iterator end = batchParent.batchedChildren.End();
+ for( ; iter != end; ++iter )
+ {
+ Node* child = *iter;
+ child->mBatchIndex = BATCH_NULL_HANDLE;
+ }
+
+ // delete all resources that belongs to the batch parent
+ for( size_t j = 0; j < batchParent.batches.size(); ++j )
+ {
+ Batch& batch = batchParent.batches[j];
+ mImpl->updateManager->RemoveGeometry( batch.geometry );
+ }
+
+ // delete main vertex buffer
+ mImpl->updateManager->RemovePropertyBuffer( batchParent.vertexBuffer );
+
+ return;
+ }
+ }
+}
+
+void GeometryBatcher::AddNode( Node* node )
+{
+ // look for batch parent
+ Node* currentNode = node->GetParent();
+ Node* batchParent = NULL;
+ while( currentNode )
+ {
+ if( currentNode->mIsBatchParent )
+ {
+ batchParent = currentNode;
+ }
+ currentNode = currentNode->GetParent();
+ }
+
+ if( batchParent )
+ {
+ // find batch parent
+ for( size_t i = 0; i < mImpl->batchParents.size(); ++i )
+ {
+ if( mImpl->batchParents[i].node == batchParent )
+ {
+ mImpl->batchParents[i].batchedChildren.PushBack( node );
+ node->SetBatchParent( batchParent );
+ mImpl->batchParents[i].needsUpdate = true;
+ break;
+ }
+ }
+ }
+}
+
+void GeometryBatcher::RemoveNode( Node* node )
+{
+ if( node->mBatchIndex == BATCH_NULL_HANDLE )
+ {
+ return;
+ }
+
+ uint32_t parentIndex = BATCH_PARENT_INDEX( node->mBatchIndex );
+
+ BatchParent& batchParent = mImpl->batchParents[ parentIndex ];
+
+ // delete all batches from batch parent
+ for( size_t i = 0; i < batchParent.batches.size(); ++i )
+ {
+ Batch& batch = batchParent.batches[ i ];
+
+ // delete geometry
+ mImpl->updateManager->RemoveGeometry( batch.geometry );
+ }
+
+ batchParent.batches.clear();
+
+ // for all children reset batch index to BATCH_NULL_HANDLE
+ for( size_t i = 0; i < batchParent.batchedChildren.Size(); )
+ {
+ Node* child = batchParent.batchedChildren[i];
+
+ if( node == child )
+ {
+ batchParent.batchedChildren.Erase( batchParent.batchedChildren.Begin() + i );
+ }
+ else
+ {
+ child->mBatchIndex = BATCH_NULL_HANDLE;
+ ++i;
+ }
+ }
+
+ mImpl->updateManager->RemovePropertyBuffer( batchParent.vertexBuffer );
+ batchParent.needsUpdate = true;
+}
+
+bool GeometryBatcher::HasRendered( uint32_t batchIndex )
+{
+ return mImpl->batchParents[ BATCH_PARENT_INDEX( batchIndex ) ].batches[ BATCH_LOCAL_INDEX( batchIndex ) ].renderedFrame == mImpl->currentFrame;
+}
+
+void GeometryBatcher::SetRendered( uint32_t batchIndex )
+{
+ mImpl->batchParents[ BATCH_PARENT_INDEX( batchIndex ) ].batches[ BATCH_LOCAL_INDEX( batchIndex ) ].renderedFrame = mImpl->currentFrame;
+}
+
+Render::Geometry* GeometryBatcher::GetGeometry( uint32_t batchIndex )
+{
+ return mImpl->batchParents[ BATCH_PARENT_INDEX( batchIndex) ].batches[ BATCH_LOCAL_INDEX( batchIndex ) ].geometry;
+}
+
+} // namespace SceneGraph
+
+} // namespace Internal
+
+
+} // namespace Dali
--- /dev/null
+#ifndef DALI_INTERNAL_SCENE_GRAPH_GEOMETRY_BATCHER_H
+#define DALI_INTERNAL_SCENE_GRAPH_GEOMETRY_BATCHER_H
+
+/*
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/internal/render/renderers/render-property-buffer.h>
+#include <dali/internal/update/rendering/scene-graph-texture-set.h>
+#include <dali/internal/render/common/render-list.h>
+
+// PUBLIC INCLUDES
+#include <dali/public-api/common/dali-vector.h>
+
+/// Value used by a node to indicate the batch index as null or invalid
+#define BATCH_NULL_HANDLE 0xFFFFFFFF
+
+namespace Dali
+{
+
+namespace Internal
+{
+
+namespace Render
+{
+class Geometry;
+}
+
+namespace SceneGraph
+{
+struct BatchInfo;
+struct BatchStreamMarker;
+
+class Node;
+class RenderInstructionContainer;
+
+class GeometryBatcher
+{
+
+public:
+
+ /**
+ * The constructor of GeometryBatcher
+ */
+ GeometryBatcher();
+
+ /**
+ * The destructor of GeometryBatcher
+ */
+ ~GeometryBatcher();
+
+ /**
+ * Assigns the update manager object
+ * @param[in] updateManager Pointer to instance of update manager
+ */
+ void SetUpdateManager( UpdateManager* updateManager );
+
+ /**
+ * Updates all batches
+ * @param[in] index Update buffer index
+ */
+ void Update( BufferIndex index );
+
+ /**
+ * @brief Add node to batch parents list
+ * @param[in] node instance of a node to be added
+ */
+ void AddBatchParent( Node* node );
+
+ /**
+ * @brief Remove node from list of batch parents
+ * @param[in] node valid instance of node to be removed
+ */
+ void RemoveBatchParent( Node* node );
+
+ /**
+ * @brief Add batchable node
+ * @param[in] node valid instance of the node to be added
+ */
+ void AddNode( Node* node );
+
+ /**
+ * @brief Remove batchable node
+ * @param[in] node valid instance of the node to be removed
+ */
+ void RemoveNode( Node* node );
+
+ /**
+ * @brief Return the geometry object associated with specified batch index
+ * @param[in] batchIndex VALID index of the batch
+ * @return instance of the batched geometry
+ */
+ Render::Geometry* GetGeometry( uint32_t batchIndex );
+
+ /**
+ * @brief Query if a batch at given index has been already rendered
+ * @param batchIndex VALID index of a batch to query
+ * @return true if batch has rendered, false otherwise
+ */
+ bool HasRendered( uint32_t batchIndex );
+
+ /**
+ * @brief Sets a batch at given index as rendered
+ * @param batchIndex VALID index of a batch
+ */
+ void SetRendered( uint32_t batchIndex );
+
+private:
+
+ /**
+ * @brief Clones vertex format of source geometry and stores generated data in the batchInfo object
+ * @param[in] sourceGeometry Geometry of the very first batched item
+ * @param[out] batchInfo Batch info object used to store cloned vertex format
+ * @return true on success, false otherwise
+ */
+ bool CloneVertexFormat( const Render::Geometry* sourceGeometry, struct VertexDescriptor& batchInfo );
+
+private:
+
+ struct Impl* mImpl; ///< Pointer to an instance of geometry batcher implementation
+
+};
+
+} // SceneGraph
+
+} // Internal
+
+} // Dali
+
+
+#endif //DALI_INTERNAL_SCENE_GRAPH_GEOMETRY_BATCHER_H
+
#include <dali/internal/render/common/render-instruction-container.h>
#include <dali/internal/render/shaders/scene-graph-shader.h>
#include <dali/internal/render/renderers/render-renderer.h>
+#include <dali/internal/render/renderers/render-property-buffer.h>
+#include <dali/internal/update/manager/geometry-batcher.h>
namespace
{
* @param renderable Node-Renderer pair
* @param viewMatrix used to calculate modelview matrix for the item
* @param camera The camera used to render
+ * @param geometryBatcher The instance of the geometry batcher
* @param isLayer3d Whether we are processing a 3D layer or not
* @param cull Whether frustum culling is enabled or not
*/
Renderable& renderable,
const Matrix& viewMatrix,
SceneGraph::Camera& camera,
+ GeometryBatcher& geometryBatcher,
bool isLayer3d,
bool cull )
{
+ // discard renderable early if it belongs to the batch which has been consumed in during frame
+ Node* renderableNode = renderable.mNode;
+ const bool batchingValid( renderable.mRenderer->IsBatchingEnabled() && renderableNode->mBatchIndex != BATCH_NULL_HANDLE );
+ if( batchingValid && geometryBatcher.HasRendered( renderableNode->mBatchIndex ) )
+ {
+ return;
+ }
+
bool inside( true );
+ const Node* batchParentNode = renderable.mNode->GetBatchParent();
+ const Node* node = ( renderable.mRenderer->IsBatchingEnabled() && batchParentNode ) ?
+ batchParentNode : renderableNode;
+
if ( cull && !renderable.mRenderer->GetShader().HintEnabled( Dali::Shader::Hint::MODIFIES_GEOMETRY ) )
{
- const Vector4& boundingSphere = renderable.mNode->GetBoundingSphere();
+ const Vector4& boundingSphere = node->GetBoundingSphere();
inside = (boundingSphere.w > Math::MACHINE_EPSILON_1000) &&
(camera.CheckSphereInFrustum( updateBufferIndex, Vector3(boundingSphere), boundingSphere.w ) );
}
- if ( inside )
+ if( inside )
{
+ if( batchingValid )
+ {
+ geometryBatcher.SetRendered( renderableNode->mBatchIndex );
+ }
+
Renderer::Opacity opacity = renderable.mRenderer->GetOpacity( updateBufferIndex, *renderable.mNode );
if( opacity != Renderer::TRANSPARENT )
{
item.mDepthIndex = renderable.mRenderer->GetDepthIndex() + static_cast<int>( renderable.mNode->GetDepth() ) * Dali::Layer::TREE_DEPTH_MULTIPLIER;
}
// save MV matrix onto the item
- renderable.mNode->GetWorldMatrixAndSize( item.mModelMatrix, item.mSize );
+ node->GetWorldMatrixAndSize( item.mModelMatrix, item.mSize );
Matrix::Multiply( item.mModelViewMatrix, item.mModelMatrix, viewMatrix );
}
}
* NodeRendererContainer Node-Renderer pairs
* @param viewMatrix used to calculate modelview matrix for the items
* @param camera The camera used to render
+ * @param geometryBatcher The instance of the geometry batcher
* @param isLayer3d Whether we are processing a 3D layer or not
* @param cull Whether frustum culling is enabled or not
*/
RenderableContainer& renderers,
const Matrix& viewMatrix,
SceneGraph::Camera& camera,
+ GeometryBatcher* geometryBatcher,
bool isLayer3d,
bool cull)
{
unsigned int rendererCount( renderers.Size() );
for( unsigned int i(0); i<rendererCount; ++i )
{
- AddRendererToRenderList( updateBufferIndex, renderList, renderers[i], viewMatrix, camera, isLayer3d, cull );
+ AddRendererToRenderList( updateBufferIndex, renderList, renderers[i], viewMatrix, camera, *geometryBatcher, isLayer3d, cull );
}
}
* @param stencilRenderablesExist is true if there are stencil renderers on this layer
* @param instruction to fill in
* @param sortingHelper to use for sorting the renderitems (to avoid reallocating)
+ * @param geometryBatcher the instance of the geometry batcher
* @param tryReuseRenderList whether to try to reuse the cached items from the instruction
* @param cull Whether frustum culling is enabled or not
*/
bool stencilRenderablesExist,
RenderInstruction& instruction,
RendererSortingHelper& sortingHelper,
+ GeometryBatcher& geometryBatcher,
bool tryReuseRenderList,
bool cull)
{
}
}
- AddRenderersToRenderList( updateBufferIndex, renderList, layer.colorRenderables, viewMatrix, camera, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
+ AddRenderersToRenderList( updateBufferIndex, renderList, layer.colorRenderables, viewMatrix, camera, &geometryBatcher, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
SortRenderItems( updateBufferIndex, renderList, layer, sortingHelper );
// Setup the render flags for stencil.
return;
}
}
- AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix, camera, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
+ AddRenderersToRenderList( updateBufferIndex, overlayRenderList, layer.overlayRenderables, viewMatrix, camera, NULL, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
SortRenderItems( updateBufferIndex, overlayRenderList, layer, sortingHelper );
}
return;
}
}
- AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix, camera, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
+ AddRenderersToRenderList( updateBufferIndex, stencilRenderList, layer.stencilRenderables, viewMatrix, camera, NULL, layer.GetBehavior() == Dali::Layer::LAYER_3D, cull );
}
void PrepareRenderInstruction( BufferIndex updateBufferIndex,
RenderTask& renderTask,
RendererSortingHelper& sortingHelper,
bool cull,
- RenderInstructionContainer& instructions )
+ RenderInstructionContainer& instructions,
+ GeometryBatcher& geometryBatcher )
{
// Retrieve the RenderInstruction buffer from the RenderInstructionContainer
// then populate with instructions.
stencilRenderablesExist,
instruction,
sortingHelper,
+ geometryBatcher,
tryReuseRenderList,
cull );
}
class RenderTracker;
struct RenderItem;
class Shader;
+class GeometryBatcher;
/**
* Structure to store information for sorting the renderers.
RenderTask& renderTask,
RendererSortingHelper& sortingHelper,
bool cull,
- RenderInstructionContainer& instructions );
+ RenderInstructionContainer& instructions,
+ GeometryBatcher& geometryBatcher );
} // namespace SceneGraph
}
}
-
-
// Recurse children
NodeContainer& children = node.GetChildren();
const NodeIter endIter = children.End();
Layer& rootNode,
SortedLayerPointers& sortedLayers,
RendererSortingHelper& sortingHelper,
+ GeometryBatcher& geometryBatcher,
RenderInstructionContainer& instructions )
{
RenderTaskList::RenderTaskContainer& taskContainer = renderTasks.GetTasks();
renderTask,
sortingHelper,
renderTask.GetCullMode(),
- instructions );
+ instructions,
+ geometryBatcher );
}
else
{
renderTask,
sortingHelper,
renderTask.GetCullMode(),
- instructions );
+ instructions,
+ geometryBatcher );
}
renderTask.SetResourcesFinished( resourcesFinished );
* @param[in] rootNode The root node of the scene-graph.
* @param[in] sortedLayers The layers containing lists of opaque/transparent renderables.
* @param[in] sortingHelper Helper container for sorting transparent renderables.
+ * @param[in] geometryBatcher The instance of the geometry batcher
* @param[out] instructions The instructions for rendering the next frame.
*/
void ProcessRenderTasks( BufferIndex updateBufferIndex,
Layer& rootNode,
SortedLayerPointers& sortedLayers,
RendererSortingHelper& sortingHelper,
+ GeometryBatcher& geometryBatcher,
RenderInstructionContainer& instructions );
} // namespace SceneGraph
<< " Scale (" << scale.x << ", " << scale.y << ", " << scale.z << ")"
<< std::endl;
- DALI_LOG_INFO(gNodeLogFilter, Debug::Verbose, "%s", oss.str().c_str());
+ DALI_LOG_INFO(gNodeLogFilter, Debug::Verbose, "%s\n", oss.str().c_str());
}
{
<< std::setw(level*2) << std::setfill(' ') << "";
std::string trafoMatrix = Debug::MatrixToString(node.GetWorldMatrix(updateBufferIndex), 2, level*2);
- DALI_LOG_INFO(gNodeLogFilter, Debug::Verbose, "%s", trafoMatrix.c_str());
+ DALI_LOG_INFO(gNodeLogFilter, Debug::Verbose, "%s\n", trafoMatrix.c_str());
}
++level;
#include <dali/internal/update/render-tasks/scene-graph-render-task-list.h>
#include <dali/internal/update/rendering/scene-graph-texture-set.h>
#include <dali/internal/update/resources/resource-manager.h>
+#include <dali/internal/update/manager/geometry-batcher.h>
+#include <dali/internal/update/render-tasks/scene-graph-camera.h>
#include <dali/internal/render/common/render-instruction-container.h>
#include <dali/internal/render/common/render-manager.h>
#include <dali/internal/render/queue/render-queue.h>
#include <dali/internal/render/gl-resources/texture-cache.h>
#include <dali/internal/render/shaders/scene-graph-shader.h>
-#include <dali/internal/render/renderers/render-frame-buffer.h>
-#include <dali/internal/render/renderers/render-sampler.h>
-#include <dali/internal/update/render-tasks/scene-graph-camera.h>
// Un-comment to enable node tree debug logging
//#define NODE_TREE_LOGGING 1
RenderController& renderController,
RenderManager& renderManager,
RenderQueue& renderQueue,
- SceneGraphBuffers& sceneGraphBuffers )
+ SceneGraphBuffers& sceneGraphBuffers,
+ GeometryBatcher& geometryBatcher )
: renderMessageDispatcher( renderManager, renderQueue, sceneGraphBuffers ),
notificationManager( notificationManager ),
transformManager(),
renderManager( renderManager ),
renderQueue( renderQueue ),
renderInstructions( renderManager.GetRenderInstructionContainer() ),
+ geometryBatcher( geometryBatcher ),
backgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ),
taskList( renderMessageDispatcher, resourceManager ),
systemLevelTaskList( renderMessageDispatcher, resourceManager ),
renderers.SetSceneController( *sceneController );
+ discardQueue.SetGeometryBatcher( &geometryBatcher );
+
// create first 'dummy' node
nodes.PushBack(0u);
}
RenderManager& renderManager; ///< This is responsible for rendering the results of each "update"
RenderQueue& renderQueue; ///< Used to queue messages for the next render
RenderInstructionContainer& renderInstructions; ///< Used to prepare the render instructions
+ GeometryBatcher& geometryBatcher; ///< An instance of the GeometryBatcher
Vector4 backgroundColor; ///< The glClear color used at the beginning of each frame.
RenderController& controller,
RenderManager& renderManager,
RenderQueue& renderQueue,
- TextureCacheDispatcher& textureCacheDispatcher )
+ TextureCacheDispatcher& textureCacheDispatcher,
+ GeometryBatcher& geometryBatcher )
: mImpl(NULL)
{
mImpl = new Impl( notificationManager,
controller,
renderManager,
renderQueue,
- mSceneGraphBuffers );
+ mSceneGraphBuffers,
+ geometryBatcher );
textureCacheDispatcher.SetBufferIndices( &mSceneGraphBuffers );
+ mImpl->geometryBatcher.SetUpdateManager( this );
}
UpdateManager::~UpdateManager()
{
DALI_ASSERT_DEBUG( mImpl->root == NULL && "Root Node already installed" );
mImpl->root = layer;
- mImpl->root->CreateTransform( &mImpl->transformManager);
+ mImpl->root->CreateTransform( &mImpl->transformManager );
}
else
{
DALI_ASSERT_DEBUG( mImpl->systemLevelRoot == NULL && "System-level Root Node already installed" );
mImpl->systemLevelRoot = layer;
- mImpl->systemLevelRoot->CreateTransform( &mImpl->transformManager);
+ mImpl->systemLevelRoot->CreateTransform( &mImpl->transformManager );
}
layer->SetRoot(true);
if(node > (*iter))
{
mImpl->nodes.Insert((iter+1), node);
- node->CreateTransform( &mImpl->transformManager);
+ node->CreateTransform( &mImpl->transformManager );
+ node->mGeometryBatcher = &mImpl->geometryBatcher;
break;
}
}
//Process Property Notifications
ProcessPropertyNotifications( bufferIndex );
+ //Update geometry batcher
+ mImpl->geometryBatcher.Update( bufferIndex );
+
//Process the RenderTasks; this creates the instructions for rendering the next frame.
//reset the update buffer index and make sure there is enough room in the instruction container
mImpl->renderInstructions.ResetAndReserve( bufferIndex,
*mImpl->root,
mImpl->sortedLayers,
mImpl->renderSortingHelper,
+ mImpl->geometryBatcher,
mImpl->renderInstructions );
// Process the system-level RenderTasks last
*mImpl->systemLevelRoot,
mImpl->systemLevelSortedLayers,
mImpl->renderSortingHelper,
+ mImpl->geometryBatcher,
mImpl->renderInstructions );
}
}
* @param[in] renderManager This is responsible for rendering the results of each "update".
* @param[in] renderQueue Used to queue messages for the next render.
* @param[in] textureCacheDispatcher Used for sending messages to texture cache.
+ * @param[in] geometryBatcher Used when geometry batching is enabled.
*/
UpdateManager( NotificationManager& notificationManager,
CompleteNotificationInterface& animationFinishedNotifier,
Integration::RenderController& controller,
RenderManager& renderManager,
RenderQueue& renderQueue,
- TextureCacheDispatcher& textureCacheDispatcher );
+ TextureCacheDispatcher& textureCacheDispatcher,
+ GeometryBatcher& geometryBatcher );
/**
* Destructor.
#include <dali/internal/common/internal-constants.h>
#include <dali/internal/common/memory-pool-object-allocator.h>
#include <dali/internal/update/common/discard-queue.h>
+#include <dali/internal/update/manager/geometry-batcher.h>
#include <dali/public-api/common/dali-common.h>
#include <dali/public-api/common/constants.h>
}
Node::Node()
-: mTransformManager(0),
+: mTransformManager( NULL ),
mTransformId( INVALID_TRANSFORM_ID ),
mParentOrigin( TRANSFORM_PROPERTY_PARENT_ORIGIN ),
mAnchorPoint( TRANSFORM_PROPERTY_ANCHOR_POINT ),
mWorldOrientation(), // initialized to identity by default
mWorldMatrix(),
mWorldColor( Color::WHITE ),
+ mGeometryBatcher( NULL ),
+ mBatchIndex( BATCH_NULL_HANDLE ),
+ mIsBatchParent( false ),
mParent( NULL ),
+ mBatchParent( NULL ),
mExclusiveRenderTask( NULL ),
mChildren(),
mRegenerateUniformMap( 0 ),
found->RecursiveDisconnectFromSceneGraph( updateBufferIndex );
}
+void Node::AddRenderer( Renderer* renderer )
+{
+ //Check that it has not been already added
+ unsigned int rendererCount( mRenderer.Size() );
+ for( unsigned int i(0); i<rendererCount; ++i )
+ {
+ if( mRenderer[i] == renderer )
+ {
+ //Renderer already in the list
+ return;
+ }
+ }
+
+ //If it is the first renderer added, make sure the world transform will be calculated
+ //in the next update as world transform is not computed if node has no renderers
+ if( rendererCount == 0 )
+ {
+ mDirtyFlags |= TransformFlag;
+ }
+
+ mRenderer.PushBack( renderer );
+
+ // Tell geometry batcher if should batch the child
+ if( mRenderer.Size() == 1 && mRenderer[0]->mBatchingEnabled )
+ {
+ mGeometryBatcher->AddNode( this );
+ }
+}
+
void Node::RemoveRenderer( Renderer* renderer )
{
unsigned int rendererCount( mRenderer.Size() );
mDirtyFlags = NothingFlag;
}
-void Node::SetParent(Node& parentNode)
+void Node::SetParent( Node& parentNode )
{
DALI_ASSERT_ALWAYS(this != &parentNode);
DALI_ASSERT_ALWAYS(!mIsRoot);
}
}
+void Node::SetBatchParent( Node* batchParentNode )
+{
+ DALI_ASSERT_ALWAYS(!mIsRoot);
+ mBatchParent = batchParentNode;
+}
+
+void Node::SetIsBatchParent( bool enabled )
+{
+ if( mIsBatchParent != enabled )
+ {
+ mIsBatchParent = enabled;
+
+ if( enabled )
+ {
+ mGeometryBatcher->AddBatchParent( this );
+ }
+ else
+ {
+ mGeometryBatcher->RemoveBatchParent( this );
+ }
+ }
+}
+
void Node::RecursiveDisconnectFromSceneGraph( BufferIndex updateBufferIndex )
{
DALI_ASSERT_ALWAYS(!mIsRoot);
class Layer;
class RenderTask;
class UpdateManager;
+class GeometryBatcher;
/**
* Flag whether property has changed, during the Update phase.
* Add a renderer to the node
* @param[in] renderer The renderer added to the node
*/
- void AddRenderer( Renderer* renderer )
- {
- //Check that it has not been already added
- unsigned int rendererCount( mRenderer.Size() );
- for( unsigned int i(0); i<rendererCount; ++i )
- {
- if( mRenderer[i] == renderer )
- {
- //Renderer already in the list
- return;
- }
- }
-
- //If it is the first renderer added, make sure the world transform will be calculated
- //in the next update as world transform is not computed if node has no renderers
- if( rendererCount == 0 )
- {
- mDirtyFlags |= TransformFlag;
- }
-
- mRenderer.PushBack( renderer );
- }
+ void AddRenderer( Renderer* renderer );
/**
* Remove a renderer from the node
* Get the renderer at the given index
* @param[in] index
*/
- Renderer* GetRendererAt( unsigned int index )
+ Renderer* GetRendererAt( unsigned int index ) const
{
return mRenderer[index];
}
(mTransformManager->IsLocalMatrixDirty( mTransformId ));
}
-
/**
* Retrieve the cached world-matrix of a node.
* @param[in] bufferIndex The buffer to read from.
return mDepth;
}
+ /**
+ * @brief Turns on or off being a batch parent for the node
+ * @param[in] enabled If true the node becomes a parent for batch of its children
+ */
+ void SetIsBatchParent( bool enabled );
+
+ /**
+ * @brief Tells if the node is a batch parent
+ * @return True if node is a batch parent, false otherwise.
+ */
+ inline bool GetIsBatchParent()
+ {
+ return mIsBatchParent;
+ }
+
+ /**
+ * Set the batch parent of a Node.
+ * @param[in] batchParentNode The new batch parent.
+ */
+ void SetBatchParent( Node* batchParentNode );
+
+ /**
+ * Retrieve the batch parent of a Node.
+ * @return The batch parent node, or NULL if the Node has not been added to the scene-graph.
+ */
+ Node* GetBatchParent() const
+ {
+ return mBatchParent;
+ }
+
public:
/**
* @copydoc UniformMap::Add
* Set the parent of a Node.
* @param[in] parentNode the new parent.
*/
- void SetParent(Node& parentNode);
+ void SetParent( Node& parentNode );
+
+protected:
/**
* Protected constructor; See also Node::New()
TransformManagerVector3Input mWorldScale;
TransformManagerQuaternionInput mWorldOrientation; ///< Full inherited orientation
TransformManagerMatrixInput mWorldMatrix; ///< Full inherited world matrix
- InheritedColor mWorldColor; ///< Full inherited color
+ InheritedColor mWorldColor; ///< Full inherited color
+
+ GeometryBatcher* mGeometryBatcher; ///< A pointer to an instance of geometry batcher
+ uint32_t mBatchIndex; ///< Batch 32bit handle, BATCH_NULL_HANDLE by default
+ bool mIsBatchParent:1; ///< Marks node as a batch parent
protected:
Node* mParent; ///< Pointer to parent node (a child is owned by its parent)
+ Node* mBatchParent; ///< Pointer to batch parent node
RenderTask* mExclusiveRenderTask; ///< Nodes can be marked as exclusive to a single RenderTask
RendererContainer mRenderer; ///< Container of renderers; not owned
// Construct message in the message queue memory; note that delete should not be called on the return value
new (slot) LocalType( &node, &Node::RemoveRenderer, renderer );
}
+
+inline void SetIsBatchParentMessage( EventThreadServices& eventThreadServices, const Node& node, bool isBatchParent )
+{
+ typedef MessageValue1< Node, bool > LocalType;
+
+ // Reserve some memory inside the message queue
+ unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
+
+ // Construct message in the message queue memory; note that delete should not be called on the return value
+ new (slot) LocalType( &node, &Node::SetIsBatchParent, isBatchParent );
+}
+
+
} // namespace SceneGraph
} // namespace Internal
float deltaZ = far - near;
if ((near <= 0.0f) || (far <= 0.0f) || Equals(right, left) || Equals(bottom, top) || (deltaZ <= 0.0f))
{
- DALI_LOG_ERROR("Invalid parameters passed into Frustum!");
+ DALI_LOG_ERROR("Invalid parameters passed into Frustum!\n");
DALI_ASSERT_DEBUG("Invalid parameters passed into Frustum!");
return;
}
{
if ( Equals(right, left) || Equals(top, bottom) || Equals(far, near) )
{
- DALI_LOG_ERROR( "Cannot create orthographic projection matrix with a zero dimension." );
+ DALI_LOG_ERROR( "Cannot create orthographic projection matrix with a zero dimension.\n" );
DALI_ASSERT_DEBUG( "Cannot create orthographic projection matrix with a zero dimension." );
return;
}
RESEND_STENCIL_OPERATION_ON_FAIL = 1 << 16,
RESEND_STENCIL_OPERATION_ON_Z_FAIL = 1 << 17,
RESEND_STENCIL_OPERATION_ON_Z_PASS = 1 << 18,
- RESEND_WRITE_TO_COLOR_BUFFER = 1 << 19
+ RESEND_WRITE_TO_COLOR_BUFFER = 1 << 19,
+ RESEND_BATCHING_MODE = 1 << 20,
};
} // Anonymous namespace
mResourcesReady( false ),
mFinishedResourceAcquisition( false ),
mPremultipledAlphaEnabled( false ),
+ mBatchingEnabled( false ),
mDepthIndex( 0 )
{
mUniformMapChanged[0] = false;
new (slot) DerivedType( mRenderer, &Render::Renderer::SetWriteToColorBuffer, mWriteToColorBuffer );
}
+ if( mResendFlag & RESEND_BATCHING_MODE )
+ {
+ typedef MessageValue1< Render::Renderer, bool > DerivedType;
+ unsigned int* slot = mSceneController->GetRenderQueue().ReserveMessageSlot( updateBufferIndex, sizeof( DerivedType ) );
+ new (slot) DerivedType( mRenderer, &Render::Renderer::SetBatchingEnabled, mBatchingEnabled );
+ }
+
mResendFlag = 0;
}
}
mResendFlag |= RESEND_WRITE_TO_COLOR_BUFFER;
}
+void Renderer::SetBatchingEnabled( bool batchingEnabled )
+{
+ mBatchingEnabled = batchingEnabled;
+ mResendFlag |= RESEND_BATCHING_MODE;
+}
+
//Called when SceneGraph::Renderer is added to update manager ( that happens when an "event-thread renderer" is created )
void Renderer::ConnectToSceneGraph( SceneController& sceneController, BufferIndex bufferIndex )
{
*/
void SetTextures( TextureSet* textureSet );
+ /**
+ * Returns current texture set object
+ * @return Pointer to the texture set
+ */
+ const TextureSet* GetTextures() const
+ {
+ return mTextureSet;
+ }
/**
* Set the shader for the renderer
* Get the shader used by this renderer
* @return the shader this renderer uses
*/
- Shader& GetShader()
+ const Shader& GetShader() const
{
return *mShader;
}
void SetGeometry( Render::Geometry* geometry );
/**
+ * Get the geometry of this renderer
+ * @return the geometry this renderer uses
+ */
+ const Render::Geometry& GetGeometry() const
+ {
+ return *mGeometry;
+ }
+
+ /**
* Set the depth index
* @param[in] depthIndex the new depth index to use
*/
void SetWriteToColorBuffer( bool writeToColorBuffer );
/**
+ * Turns on batching feature for the renderer
+ * @param[in] batchingEnabled if true, enables the batching mode for the renderer
+ */
+ void SetBatchingEnabled( bool batchingEnabled );
+
+ /**
+ * Tests whether batching feature is enabled for this renderer
+ * @return batching state
+ */
+ bool IsBatchingEnabled() const
+ {
+ return mBatchingEnabled;
+ }
+
+ /**
* Prepare the object for rendering.
* This is called by the UpdateManager when an object is due to be rendered in the current frame.
* @param[in] updateBufferIndex The current update buffer index.
public:
+ bool mBatchingEnabled : 1; ///< Flag indicating whether the render supports batching
int mDepthIndex; ///< Used only in PrepareRenderInstructions
};
new (slot) LocalType( &renderer, &Renderer::SetWriteToColorBuffer, writeToColorBuffer );
}
+inline void SetBatchingEnabledMessage( EventThreadServices& eventThreadServices, const Renderer& renderer, bool batchable )
+{
+ typedef MessageValue1< Renderer, bool > LocalType;
+
+ // Reserve some memory inside the message queue
+ unsigned int* slot = eventThreadServices.ReserveMessageSlot( sizeof( LocalType ) );
+
+ new (slot) LocalType( &renderer, &Renderer::SetBatchingEnabled, batchable );
+}
+
} // namespace SceneGraph
} // namespace Internal
} // namespace Dali
PADDING, ///< name "padding", type Vector4 @SINCE_1_0.0
MINIMUM_SIZE, ///< name "minimumSize", type Vector2 @SINCE_1_0.0
MAXIMUM_SIZE, ///< name "maximumSize", type Vector2 @SINCE_1_0.0
- INHERIT_POSITION, ///< name "inheritPosition", type bool @SINCE_1_1.24
+ INHERIT_POSITION, ///< name "inheritPosition", type bool @SINCE_1_1.24
+ BATCH_PARENT, ///< name "batchParent", type bool @SINCE_1_2.0
};
};
{
const unsigned int CORE_MAJOR_VERSION = 1;
-const unsigned int CORE_MINOR_VERSION = 1;
-const unsigned int CORE_MICRO_VERSION = 45;
+const unsigned int CORE_MINOR_VERSION = 2;
+const unsigned int CORE_MICRO_VERSION = 0;
const char * const CORE_BUILD_DATE = __DATE__ " " __TIME__;
#ifndef EMSCRIPTEN
#ifdef ENABLE_DEBUG
if(mCount)
{
- DALI_LOG_ERROR("mCount should be zero, deleting referenced object!");
+ DALI_LOG_ERROR("mCount should be zero, deleting referenced object!\n");
}
#endif // ENABLE_DEBUG
}
* @note The default value is True
* @SINCE_1_1.43
*/
- WRITE_TO_COLOR_BUFFER
+ WRITE_TO_COLOR_BUFFER,
+
+ /**
+ * @brief name "batchingEnabled", type BOOLEAN
+ * @SINCE_1_2.0
+ * @see Batching
+ * @note The default value is 'false'
+ */
+ BATCHING_ENABLED
};
};
else
{
// mFlag is NULL when Emit() is called during Emit()
- DALI_LOG_ERROR( "Cannot call Emit() from inside Emit()" );
+ DALI_LOG_ERROR( "Cannot call Emit() from inside Emit()\n" );
}
}
Name: dali
Summary: The OpenGLES Canvas Core Library
-Version: 1.1.45
+Version: 1.2.0
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-2-Clause and MIT