From: dongsug.song Date: Mon, 14 Nov 2016 13:57:16 +0000 (+0900) Subject: Revert "[3.0] Version downgrade (1.2.0 to 1.1.45)" X-Git-Tag: accepted/tizen/common/20161115.200949~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F16%2F97616%2F1;p=platform%2Fcore%2Fuifw%2Fdali-core.git Revert "[3.0] Version downgrade (1.2.0 to 1.1.45)" This reverts commit 22bbf88067ca1c914055b2aa91f469760f12502f. Change-Id: I3a84bf6fa8817109ecbcda2b8e00f8212c66977f --- diff --git a/automated-tests/src/dali-internal/CMakeLists.txt b/automated-tests/src/dali-internal/CMakeLists.txt index 4bc9f10..afedb0d 100644 --- a/automated-tests/src/dali-internal/CMakeLists.txt +++ b/automated-tests/src/dali-internal/CMakeLists.txt @@ -12,6 +12,7 @@ SET(TC_SOURCES utc-Dali-Internal-FixedSizeMemoryPool.cpp utc-Dali-Internal-MemoryPoolObjectAllocator.cpp utc-Dali-Internal-FrustumCulling.cpp + utc-Dali-Internal-GeometryBatcher.cpp ) LIST(APPEND TC_SOURCES diff --git a/automated-tests/src/dali-internal/utc-Dali-Internal-GeometryBatcher.cpp b/automated-tests/src/dali-internal/utc-Dali-Internal-GeometryBatcher.cpp new file mode 100644 index 0000000..f2c679f --- /dev/null +++ b/automated-tests/src/dali-internal/utc-Dali-Internal-GeometryBatcher.cpp @@ -0,0 +1,403 @@ +#include +#include +#include + +#include + +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( &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( &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( &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; +} diff --git a/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.cpp b/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.cpp index 467bb52..b50f506 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.cpp +++ b/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.cpp @@ -337,3 +337,51 @@ BufferImage CreateBufferImage() { 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 diff --git a/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.h b/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.h index 7f81872..8cefb7c 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.h +++ b/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.h @@ -499,4 +499,45 @@ struct DefaultFunctionCoverage 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__ diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.cpp b/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.cpp index d42a548..6e9b9f0 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.cpp +++ b/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.cpp @@ -70,6 +70,7 @@ void TestGlAbstraction::Initialize() mLastShaderIdUsed = 0; mLastProgramIdUsed = 0; mLastUniformIdUsed = 0; + mLastDepthMask = false; mUniforms.clear(); mProgramUniforms1i.clear(); @@ -79,8 +80,10 @@ void TestGlAbstraction::Initialize() mProgramUniforms4f.clear(); mCullFaceTrace.Reset(); + mDepthFunctionTrace.Reset(); mEnableDisableTrace.Reset(); mShaderTrace.Reset(); + mStencilFunctionTrace.Reset(); mTextureTrace.Reset(); mTexParamaterTrace.Reset(); mDrawTrace.Reset(); diff --git a/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h b/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h index 1f55977..10c3264 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h +++ b/automated-tests/src/dali/dali-test-suite-utils/test-gl-abstraction.h @@ -1,8 +1,8 @@ -#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. @@ -468,6 +468,12 @@ public: inline void DepthMask(GLboolean flag) { + mLastDepthMask = flag; + } + + inline bool GetLastDepthMask() const + { + return mLastDepthMask; } inline void DepthRangef(GLclampf zNear, GLclampf zFar) @@ -2059,6 +2065,8 @@ private: GLenum mLastBlendFuncSrcAlpha; GLenum mLastBlendFuncDstAlpha; + GLboolean mLastDepthMask; + // Data for manipulating the IDs returned by GenTextures GLuint mLastAutoTextureIdUsed; std::vector mNextTextureIds; @@ -2258,6 +2266,4 @@ bool BlendEnabled(const Dali::TraceCallStack& callStack); bool BlendDisabled(const Dali::TraceCallStack& callStack); - - -#endif // __TEST_GL_ES_H__ +#endif // TEST_GL_ABSTRACTION_H diff --git a/automated-tests/src/dali/utc-Dali-Renderer.cpp b/automated-tests/src/dali/utc-Dali-Renderer.cpp index a812941..3bfbacf 100644 --- a/automated-tests/src/dali/utc-Dali-Renderer.cpp +++ b/automated-tests/src/dali/utc-Dali-Renderer.cpp @@ -36,8 +36,8 @@ const BlendFactor::Type DEFAULT_BLEND_FACTOR_DEST_RGB( BlendFactor::ONE_MINU 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. @@ -50,6 +50,17 @@ std::string GetStencilTestString(void) 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(); @@ -1047,8 +1058,6 @@ int UtcDaliRendererConstraint02(void) END_TEST; } - - int UtcDaliRendererAnimatedProperty01(void) { TestApplication application; @@ -1391,7 +1400,6 @@ int UtcDaliRendererUniformMapMultipleUniforms02(void) END_TEST; } - int UtcDaliRendererRenderOrder2DLayer(void) { TestApplication application; @@ -2037,7 +2045,60 @@ int UtcDaliRendererSetDepthFunction(void) 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( propertyIndex ) == static_cast( initialValue ) ); + renderer.SetProperty( propertyIndex, firstCheckEnumeration ); + DALI_TEST_CHECK( renderer.GetProperty( propertyIndex ) == static_cast( firstCheckEnumeration ) ); + renderer.SetProperty( propertyIndex, secondCheckString ); + DALI_TEST_CHECK( renderer.GetProperty( propertyIndex ) == static_cast( 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(); @@ -2053,12 +2114,124 @@ Renderer StencilTestFixture( TestApplication& application ) 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 ); @@ -2084,7 +2257,7 @@ int UtcDaliRendererSetStencilMode(void) 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 ); @@ -2117,7 +2290,7 @@ int UtcDaliRendererSetStencilFunction(void) 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 ); @@ -2207,7 +2380,7 @@ int UtcDaliRendererSetStencilOperation(void) 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 ); @@ -2294,7 +2467,7 @@ int UtcDaliRendererSetStencilMask(void) 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 ); @@ -2339,7 +2512,7 @@ int UtcDaliRendererSetWriteToColorBuffer(void) 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. diff --git a/dali/devel-api/threading/conditional-wait.cpp b/dali/devel-api/threading/conditional-wait.cpp index 4a1ed8b..adc5760 100644 --- a/dali/devel-api/threading/conditional-wait.cpp +++ b/dali/devel-api/threading/conditional-wait.cpp @@ -52,11 +52,11 @@ ConditionalWait::ConditionalWait() { 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; } @@ -65,11 +65,11 @@ ConditionalWait::~ConditionalWait() { 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; } @@ -86,7 +86,7 @@ void ConditionalWait::Notify() { 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 ); @@ -105,7 +105,7 @@ void ConditionalWait::Notify( const ScopedLock& scope ) { if( pthread_cond_broadcast( &mImpl->condition ) ) { - DALI_LOG_ERROR( "Error calling pthread_cond_broadcast" ); + DALI_LOG_ERROR( "Error calling pthread_cond_broadcast\n" ); } } } @@ -121,7 +121,7 @@ void ConditionalWait::Wait() // 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; } } @@ -144,7 +144,7 @@ void ConditionalWait::Wait( const ScopedLock& scope ) // 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; } } diff --git a/dali/devel-api/threading/mutex.cpp b/dali/devel-api/threading/mutex.cpp index fdb9cde..4e0cb30 100644 --- a/dali/devel-api/threading/mutex.cpp +++ b/dali/devel-api/threading/mutex.cpp @@ -39,7 +39,7 @@ Mutex::Mutex() { 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; } @@ -48,7 +48,7 @@ Mutex::~Mutex() { 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 diff --git a/dali/internal/common/core-impl.cpp b/dali/internal/common/core-impl.cpp index c9ca158..b415482 100644 --- a/dali/internal/common/core-impl.cpp +++ b/dali/internal/common/core-impl.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #include #include @@ -97,6 +98,7 @@ Core::Core( RenderController& renderController, PlatformAbstraction& platform, mNotificationManager(NULL), mImageFactory(NULL), mShaderFactory(NULL), + mGeometryBatcher( NULL ), mIsActive(true), mProcessingEvent(false) { @@ -114,7 +116,9 @@ Core::Core( RenderController& renderController, PlatformAbstraction& platform, 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(); @@ -145,7 +149,8 @@ Core::Core( RenderController& renderController, PlatformAbstraction& platform, renderController, *mRenderManager, renderQueue, - *mTextureCacheDispatcher ); + *mTextureCacheDispatcher, + *mGeometryBatcher ); mRenderManager->SetShaderSaver( *mUpdateManager ); @@ -210,6 +215,7 @@ Core::~Core() delete mTextureCacheDispatcher; delete mUpdateManager; delete mRenderManager; + delete mGeometryBatcher; delete mTextureUploadedQueue; } @@ -313,7 +319,7 @@ void Core::ProcessEvents() // 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; } diff --git a/dali/internal/common/core-impl.h b/dali/internal/common/core-impl.h index b9472cd..d40f827 100644 --- a/dali/internal/common/core-impl.h +++ b/dali/internal/common/core-impl.h @@ -66,6 +66,7 @@ class UpdateManager; class RenderManager; class DiscardQueue; class TextureCacheDispatcher; +class GeometryBatcher; } /** @@ -294,7 +295,7 @@ private: 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() diff --git a/dali/internal/common/math.cpp b/dali/internal/common/math.cpp index 1e3c051..3b0baf9 100644 --- a/dali/internal/common/math.cpp +++ b/dali/internal/common/math.cpp @@ -57,3 +57,80 @@ float Dali::Internal::Length( const Vec3 v ) { 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]); + } +} diff --git a/dali/internal/common/math.h b/dali/internal/common/math.h index ebb6291..4fce869 100644 --- a/dali/internal/common/math.h +++ b/dali/internal/common/math.h @@ -24,9 +24,11 @@ namespace Dali 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 @@ -45,6 +47,70 @@ void TransformVector3( Vec3 result, const Mat4 m, const Vec3 v ); */ 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 diff --git a/dali/internal/common/mutex-impl.cpp b/dali/internal/common/mutex-impl.cpp index c046dc3..06d1ddf 100644 --- a/dali/internal/common/mutex-impl.cpp +++ b/dali/internal/common/mutex-impl.cpp @@ -109,7 +109,7 @@ void Lock( pthread_mutex_t* mutex ) if( pthread_mutex_lock( mutex ) ) { - DALI_LOG_ERROR( "Error calling pthread_mutex_lock" ); + DALI_LOG_ERROR( "Error calling pthread_mutex_lock\n" ); } } @@ -117,7 +117,7 @@ void Unlock( pthread_mutex_t* mutex ) { if( pthread_mutex_unlock( mutex ) ) { - DALI_LOG_ERROR( "Error calling pthread_mutex_unlock" ); + DALI_LOG_ERROR( "Error calling pthread_mutex_unlock\n" ); } --gThreadLockCount; } diff --git a/dali/internal/event/actors/actor-impl.cpp b/dali/internal/event/actors/actor-impl.cpp index 5df7b5c..7b19757 100644 --- a/dali/internal/event/actors/actor-impl.cpp +++ b/dali/internal/event/actors/actor-impl.cpp @@ -200,6 +200,7 @@ DALI_PROPERTY( "padding", VECTOR4, true, false, false, Dali::Actor:: 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 @@ -1974,7 +1975,8 @@ Actor::Actor( DerivedType derivedType ) mInheritScale( true ), mDrawMode( DrawMode::NORMAL ), mPositionInheritanceMode( Node::DEFAULT_POSITION_INHERITANCE_MODE ), - mColorMode( Node::DEFAULT_COLOR_MODE ) + mColorMode( Node::DEFAULT_COLOR_MODE ), + mIsBatchParent( false ) { } @@ -2648,6 +2650,20 @@ void Actor::SetDefaultProperty( Property::Index index, const Property::Value& pr 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 @@ -3139,6 +3155,12 @@ Property::Value Actor::GetDefaultProperty( Property::Index index ) const break; } + case Dali::Actor::Property::BATCH_PARENT: + { + value = mIsBatchParent; + break; + } + default: { DALI_ASSERT_ALWAYS( false && "Actor Property index invalid" ); // should not come here diff --git a/dali/internal/event/actors/actor-impl.h b/dali/internal/event/actors/actor-impl.h index d38493b..d40bde1 100644 --- a/dali/internal/event/actors/actor-impl.h +++ b/dali/internal/event/actors/actor-impl.h @@ -1833,6 +1833,8 @@ private: 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 diff --git a/dali/internal/event/actors/image-actor-impl.cpp b/dali/internal/event/actors/image-actor-impl.cpp index 93d1ab4..92016de 100644 --- a/dali/internal/event/actors/image-actor-impl.cpp +++ b/dali/internal/event/actors/image-actor-impl.cpp @@ -271,25 +271,25 @@ void ImageActor::ClearPixelArea() 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; } diff --git a/dali/internal/event/animation/constraint-base.cpp b/dali/internal/event/animation/constraint-base.cpp index f781543..c702014 100644 --- a/dali/internal/event/animation/constraint-base.cpp +++ b/dali/internal/event/animation/constraint-base.cpp @@ -71,7 +71,7 @@ void ConstraintBase::AddSource( Source source ) } else { - DALI_LOG_ERROR( "Constraint source object not found" ); + DALI_LOG_ERROR( "Constraint source object not found\n" ); } } } diff --git a/dali/internal/event/common/stage-impl.cpp b/dali/internal/event/common/stage-impl.cpp index fe95c3e..aea8308 100644 --- a/dali/internal/event/common/stage-impl.cpp +++ b/dali/internal/event/common/stage-impl.cpp @@ -412,7 +412,7 @@ void Stage::SetStereoBase( float stereoBase ) { 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 ) @@ -572,7 +572,7 @@ Dali::Stage::EventProcessingFinishedSignalType& Stage::EventProcessingFinishedSi Dali::Stage::TouchedSignalType& Stage::TouchedSignal() { - DALI_LOG_WARNING( "Deprecated. Use TouchSignal() instead." ); + DALI_LOG_WARNING( "Deprecated. Use TouchSignal() instead.\n" ); return mTouchedSignal; } diff --git a/dali/internal/event/common/type-info-impl.cpp b/dali/internal/event/common/type-info-impl.cpp index b0809a7..479f2e8 100644 --- a/dali/internal/event/common/type-info-impl.cpp +++ b/dali/internal/event/common/type-info-impl.cpp @@ -349,7 +349,7 @@ void TypeInfo::AddActionFunction( const std::string &actionName, Dali::TypeInfo: } 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()); } } } @@ -371,7 +371,7 @@ void TypeInfo::AddConnectorFunction( const std::string& signalName, Dali::TypeIn } 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()); } } } diff --git a/dali/internal/event/rendering/renderer-impl.cpp b/dali/internal/event/rendering/renderer-impl.cpp index 0bd59c7..0b89b26 100644 --- a/dali/internal/event/rendering/renderer-impl.cpp +++ b/dali/internal/event/rendering/renderer-impl.cpp @@ -19,6 +19,7 @@ #include // Dali::Internal::Renderer // INTERNAL INCLUDES +#include #include #include // Dali::Internal::ObjectHelper #include // DALI_PROPERTY_TABLE_BEGIN, DALI_PROPERTY, DALI_PROPERTY_TABLE_END @@ -36,7 +37,7 @@ namespace { /** - * |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 ) @@ -64,8 +65,99 @@ DALI_PROPERTY( "stencilOperationOnFail", INTEGER, true, false, false 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 RENDERER_IMPL = { DEFAULT_PROPERTY_DETAILS }; BaseHandle Create() @@ -135,21 +227,6 @@ int Renderer::GetDepthIndex() const 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 ) @@ -271,6 +348,11 @@ bool Renderer::IsPreMultipliedAlphaEnabled() const return mPremultipledAlphaEnabled; } +bool Renderer::IsBatchingEnabled() const +{ + return mBatchingEnabled; +} + SceneGraph::Renderer* Renderer::GetRendererSceneObject() { return mSceneObject; @@ -328,109 +410,88 @@ void Renderer::SetDefaultProperty( Property::Index index, } 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( 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( 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( 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( 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( 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( blendingFactor ) ); + SetBlendFunc( sourceFactorRgb, destinationFactorRgb, sourceFactorAlpha, destinationFactorAlpha ); } break; } @@ -472,61 +533,51 @@ void Renderer::SetDefaultProperty( Property::Index index, } case Dali::Renderer::Property::DEPTH_WRITE_MODE: { - int value; - propertyValue.Get( value ); - DepthWriteMode::Type mode = static_cast(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(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(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( 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( 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; } @@ -571,37 +622,31 @@ void Renderer::SetDefaultProperty( Property::Index index, } case Dali::Renderer::Property::STENCIL_OPERATION_ON_FAIL: { - int value; - propertyValue.Get( value ); - StencilOperation::Type stencilOperation = static_cast( 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( 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( 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; } @@ -618,6 +663,19 @@ void Renderer::SetDefaultProperty( Property::Index index, } break; } + case Dali::Renderer::Property::BATCHING_ENABLED: + { + bool enabled; + if( propertyValue.Get( enabled ) ) + { + if( mBatchingEnabled != enabled ) + { + mBatchingEnabled = enabled; + SetBatchingEnabledMessage( GetEventThreadServices(), *mSceneObject, mBatchingEnabled ); + } + } + break; + } } } @@ -731,6 +789,11 @@ Property::Value Renderer::GetDefaultProperty( Property::Index index ) const value = mDepthWriteMode; break; } + case Dali::Renderer::Property::BATCHING_ENABLED: + { + value = mBatchingEnabled; + break; + } case Dali::Renderer::Property::DEPTH_FUNCTION: { value = mDepthFunction; @@ -877,7 +940,8 @@ Renderer::Renderer() mDepthWriteMode( DepthWriteMode::AUTO ), mDepthTestMode( DepthTestMode::AUTO ), mWriteToColorBuffer( true ), - mPremultipledAlphaEnabled( false ) + mPremultipledAlphaEnabled( false ), + mBatchingEnabled( false ) { } diff --git a/dali/internal/event/rendering/renderer-impl.h b/dali/internal/event/rendering/renderer-impl.h index 64d99ba..14a2b79 100644 --- a/dali/internal/event/rendering/renderer-impl.h +++ b/dali/internal/event/rendering/renderer-impl.h @@ -95,16 +95,6 @@ public: */ int GetDepthIndex() const; - /** - * @copydoc Dali::Renderer::SetFaceCullingMode() - */ - void SetFaceCullingMode( FaceCullingMode::Type cullingMode ); - - /** - * @copydoc Dali::Renderer::GetFaceCullingMode() - */ - FaceCullingMode::Type GetFaceCullingMode(); - /** * @copydoc Dali::Renderer::SetBlendMode() */ @@ -181,12 +171,18 @@ public: */ 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 @@ -324,6 +320,7 @@ private: // data 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 diff --git a/dali/internal/event/rendering/texture-impl.cpp b/dali/internal/event/rendering/texture-impl.cpp index 704ab40..c0f658c 100644 --- a/dali/internal/event/rendering/texture-impl.cpp +++ b/dali/internal/event/rendering/texture-impl.cpp @@ -108,14 +108,14 @@ bool NewTexture::Upload( PixelDataPtr pixelData, { 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 { @@ -124,12 +124,12 @@ bool NewTexture::Upload( PixelDataPtr pixelData, { 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< ( mHeight / (1< #include #include +#include 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 { @@ -215,6 +217,7 @@ inline void SetupDepthBuffer( const RenderItem& item, Context& context, bool isL * @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, @@ -223,7 +226,8 @@ inline void ProcessRenderList( SceneGraph::Shader& defaultShader, BufferIndex bufferIndex, const Matrix& viewMatrix, - const Matrix& projectionMatrix ) + const Matrix& projectionMatrix, + GeometryBatcher* geometryBatcher ) { DALI_PRINT_RENDER_LIST( renderList ); @@ -241,14 +245,34 @@ inline void ProcessRenderList( 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 @@ -264,7 +288,7 @@ inline void ProcessRenderList( 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 ); } } } @@ -273,6 +297,7 @@ void ProcessRenderInstruction( const RenderInstruction& instruction, Context& context, SceneGraph::TextureCache& textureCache, SceneGraph::Shader& defaultShader, + GeometryBatcher& geometryBatcher, BufferIndex bufferIndex ) { DALI_PRINT_RENDER_INSTRUCTION( instruction, bufferIndex ); @@ -297,7 +322,7 @@ void ProcessRenderInstruction( const RenderInstruction& instruction, if( renderList && !renderList->IsEmpty() ) { - ProcessRenderList( *renderList, context, textureCache, defaultShader, bufferIndex, *viewMatrix, *projectionMatrix ); + ProcessRenderList( *renderList, context, textureCache, defaultShader, bufferIndex, *viewMatrix, *projectionMatrix, &geometryBatcher ); } } } diff --git a/dali/internal/render/common/render-algorithms.h b/dali/internal/render/common/render-algorithms.h index a2e4c57..1bf2dd0 100644 --- a/dali/internal/render/common/render-algorithms.h +++ b/dali/internal/render/common/render-algorithms.h @@ -32,6 +32,7 @@ namespace SceneGraph class RenderInstruction; class Shader; class TextureCache; +class GeometryBatcher; } namespace Render @@ -43,12 +44,14 @@ 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 diff --git a/dali/internal/render/common/render-item.cpp b/dali/internal/render/common/render-item.cpp index d81f068..d7fd016 100644 --- a/dali/internal/render/common/render-item.cpp +++ b/dali/internal/render/common/render-item.cpp @@ -47,8 +47,10 @@ RenderItem::RenderItem() mSize(), mRenderer( NULL ), mNode( NULL ), + mBatchRenderGeometry( NULL ), mDepthIndex( 0 ), - mIsOpaque( true ) + mIsOpaque( true ), + mBatched( false ) { } diff --git a/dali/internal/render/common/render-item.h b/dali/internal/render/common/render-item.h index d429452..bd37bda 100644 --- a/dali/internal/render/common/render-item.h +++ b/dali/internal/render/common/render-item.h @@ -33,6 +33,7 @@ namespace Internal namespace Render { class Renderer; +class RenderGeometry; } namespace SceneGraph @@ -59,14 +60,18 @@ struct RenderItem */ 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: diff --git a/dali/internal/render/common/render-manager.cpp b/dali/internal/render/common/render-manager.cpp index a4281eb..497b0e5 100644 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -81,7 +81,8 @@ struct RenderManager::Impl Impl( Integration::GlAbstraction& glAbstraction, Integration::GlSyncAbstraction& glSyncAbstraction, LockedResourceQueue& textureUploadedQ, - TextureUploadedDispatcher& postProcessDispatcher ) + TextureUploadedDispatcher& postProcessDispatcher, + GeometryBatcher& geometryBatcher ) : context( glAbstraction ), glSyncAbstraction( glSyncAbstraction ), renderQueue(), @@ -99,7 +100,8 @@ struct RenderManager::Impl renderersAdded( false ), firstRenderCompleted( false ), defaultShader( NULL ), - programController( glAbstraction ) + programController( glAbstraction ), + geometryBatcher( geometryBatcher ) { } @@ -168,14 +170,17 @@ struct RenderManager::Impl 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; } @@ -685,6 +690,7 @@ void RenderManager::DoRender( RenderInstruction& instruction, Shader& defaultSha mImpl->context, mImpl->textureCache, defaultShader, + mImpl->geometryBatcher, mImpl->renderBufferIndex ); if(instruction.mOffscreenTextureId != 0) diff --git a/dali/internal/render/common/render-manager.h b/dali/internal/render/common/render-manager.h index 93b9661..40cc7c1 100644 --- a/dali/internal/render/common/render-manager.h +++ b/dali/internal/render/common/render-manager.h @@ -63,6 +63,7 @@ class RenderInstruction; class RenderInstructionContainer; class Shader; class PropertyBufferDataProvider; +class GeometryBatcher; /** * RenderManager is responsible for rendering the result of the previous "update", which @@ -76,10 +77,12 @@ public: * 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 ); /** diff --git a/dali/internal/render/gl-resources/bitmap-texture.cpp b/dali/internal/render/gl-resources/bitmap-texture.cpp index 19061e7..58d80c2 100644 --- a/dali/internal/render/gl-resources/bitmap-texture.cpp +++ b/dali/internal/render/gl-resources/bitmap-texture.cpp @@ -189,7 +189,7 @@ void BitmapTexture::Update( Integration::Bitmap* bitmap ) 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; } @@ -199,7 +199,7 @@ void BitmapTexture::Update( Integration::Bitmap* bitmap ) 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; diff --git a/dali/internal/render/gl-resources/compressed-bitmap-texture.cpp b/dali/internal/render/gl-resources/compressed-bitmap-texture.cpp index 7a23adb..3ec72db 100644 --- a/dali/internal/render/gl-resources/compressed-bitmap-texture.cpp +++ b/dali/internal/render/gl-resources/compressed-bitmap-texture.cpp @@ -101,7 +101,7 @@ void CompressedBitmapTexture::Update( Integration::Bitmap* 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; } diff --git a/dali/internal/render/gl-resources/frame-buffer-texture.cpp b/dali/internal/render/gl-resources/frame-buffer-texture.cpp index 9d0259a..e1c697e 100644 --- a/dali/internal/render/gl-resources/frame-buffer-texture.cpp +++ b/dali/internal/render/gl-resources/frame-buffer-texture.cpp @@ -136,7 +136,7 @@ bool FrameBufferTexture::CreateGlTexture() if( mNativeImage && !mNativeImage->GlExtensionCreate() ) { - DALI_LOG_ERROR( "Error creating native image!" ); + DALI_LOG_ERROR( "Error creating native image!\n" ); return false; } diff --git a/dali/internal/render/gl-resources/native-texture.cpp b/dali/internal/render/gl-resources/native-texture.cpp index 43a5db1..8110880 100644 --- a/dali/internal/render/gl-resources/native-texture.cpp +++ b/dali/internal/render/gl-resources/native-texture.cpp @@ -104,7 +104,7 @@ bool NativeTexture::CreateGlTexture() } else { - DALI_LOG_ERROR( "Error creating native image!" ); + DALI_LOG_ERROR( "Error creating native image!\n" ); } return mId != 0; diff --git a/dali/internal/render/renderers/render-geometry.cpp b/dali/internal/render/renderers/render-geometry.cpp index 803b6eb..0c3bd0a 100644 --- a/dali/internal/render/renderers/render-geometry.cpp +++ b/dali/internal/render/renderers/render-geometry.cpp @@ -50,7 +50,7 @@ void Geometry::GlContextDestroyed() { } -void Geometry::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer ) +void Geometry::AddPropertyBuffer( Render::PropertyBuffer* propertyBuffer) { mVertexBuffers.PushBack( propertyBuffer ); mAttributesChanged = true; @@ -62,6 +62,11 @@ void Geometry::SetIndexBuffer( Dali::Vector& indices ) mIndicesChanged = true; } +const Dali::Vector* Geometry::GetIndexBuffer() const +{ + return &mIndices; +} + void Geometry::RemovePropertyBuffer( const Render::PropertyBuffer* propertyBuffer ) { size_t bufferCount = mVertexBuffers.Size(); @@ -70,13 +75,22 @@ void Geometry::RemovePropertyBuffer( const Render::PropertyBuffer* propertyBuffe 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& attributeLocation, Program& program, BufferIndex bufferIndex ) const { attributeLocation.Clear(); @@ -136,8 +150,10 @@ void Geometry::UploadAndDraw( 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 ) diff --git a/dali/internal/render/renderers/render-geometry.h b/dali/internal/render/renderers/render-geometry.h index 205e0f1..6075858 100644 --- a/dali/internal/render/renderers/render-geometry.h +++ b/dali/internal/render/renderers/render-geometry.h @@ -78,12 +78,25 @@ public: void SetIndexBuffer( Dali::Vector& indices ); /** + * Obtains pointer to the storage of indexed elements + * @return Pointer to the index buffer + */ + const Dali::Vector* 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 @@ -142,7 +155,6 @@ private: bool mIndicesChanged : 1; bool mHasBeenUpdated : 1; bool mAttributesChanged : 1; - }; } // namespace Render diff --git a/dali/internal/render/renderers/render-property-buffer.cpp b/dali/internal/render/renderers/render-property-buffer.cpp index 6be4623..9664318 100644 --- a/dali/internal/render/renderers/render-property-buffer.cpp +++ b/dali/internal/render/renderers/render-property-buffer.cpp @@ -125,6 +125,11 @@ void PropertyBuffer::SetData( Dali::Vector* data, size_t size ) mDataChanged = true; } +void PropertyBuffer::UpdateData() +{ + mDataChanged = true; +} + bool PropertyBuffer::Update( Context& context ) { if( !mData || !mFormat || !mSize ) diff --git a/dali/internal/render/renderers/render-property-buffer.h b/dali/internal/render/renderers/render-property-buffer.h index ed1e0b2..47748a1 100644 --- a/dali/internal/render/renderers/render-property-buffer.h +++ b/dali/internal/render/renderers/render-property-buffer.h @@ -80,6 +80,12 @@ public: void SetData( Dali::Vector* 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 */ @@ -156,14 +162,39 @@ public: 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 + inline T* GetDataTypedPtr() + { + Dali::Vector< char >* data = mData.Release(); + mData = data; + return reinterpret_cast( &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 diff --git a/dali/internal/render/renderers/render-renderer.cpp b/dali/internal/render/renderers/render-renderer.cpp index 01c03e3..cfaa2be 100644 --- a/dali/internal/render/renderers/render-renderer.cpp +++ b/dali/internal/render/renderers/render-renderer.cpp @@ -154,7 +154,8 @@ Renderer::Renderer( SceneGraph::RenderDataProvider* dataProvider, mDepthTestMode( depthTestMode ), mWriteToColorBuffer( writeToColorBuffer ), mUpdateAttributesLocation( true ), - mPremultipledAlphaEnabled( preMultipliedAlphaEnabled ) + mPremultipledAlphaEnabled( preMultipliedAlphaEnabled ), + mBatchingEnabled( false ) { if( blendingBitmask != 0u ) { @@ -572,6 +573,11 @@ bool Renderer::GetWriteToColorBuffer() const return mWriteToColorBuffer; } +void Renderer::SetBatchingEnabled( bool batchingEnabled ) +{ + mBatchingEnabled = batchingEnabled; +} + void Renderer::Render( Context& context, SceneGraph::TextureCache& textureCache, BufferIndex bufferIndex, @@ -582,6 +588,7 @@ void Renderer::Render( Context& context, const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector3& size, + Render::Geometry* externalGeometry, bool blend ) { // Get the program to use: @@ -593,7 +600,7 @@ void Renderer::Render( Context& context, 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; } } @@ -630,14 +637,15 @@ void Renderer::Render( Context& context, } 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 ); } } diff --git a/dali/internal/render/renderers/render-renderer.h b/dali/internal/render/renderers/render-renderer.h index d7e6575..8011c31 100644 --- a/dali/internal/render/renderers/render-renderer.h +++ b/dali/internal/render/renderers/render-renderer.h @@ -166,12 +166,22 @@ public: * @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 ); @@ -362,6 +372,12 @@ public: 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 @@ -371,6 +387,9 @@ public: * @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, @@ -382,6 +401,7 @@ public: const Matrix& viewMatrix, const Matrix& projectionMatrix, const Vector3& size, + Render::Geometry* externalGeometry, bool blend); /** @@ -468,6 +488,7 @@ private: 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 diff --git a/dali/internal/render/renderers/render-texture.cpp b/dali/internal/render/renderers/render-texture.cpp index 59c1206..8ca2647 100644 --- a/dali/internal/render/renderers/render-texture.cpp +++ b/dali/internal/render/renderers/render-texture.cpp @@ -625,6 +625,11 @@ void NewTexture::Destroy( Context& context ) if( mId ) { context.DeleteTextures( 1, &mId ); + + if( mNativeImage ) + { + mNativeImage->GlExtensionDestroy(); + } } } @@ -645,7 +650,12 @@ void NewTexture::Initialize(Context& context) 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 @@ -803,6 +813,12 @@ bool NewTexture::Bind( Context& context, unsigned int textureUnit, Render::Sampl ApplySampler( context, sampler ); + if( mNativeImage ) + { + //Allow implementation specific operations after binding the texture + mNativeImage->PrepareTexture(); + } + return true; } diff --git a/dali/internal/update/common/discard-queue.cpp b/dali/internal/update/common/discard-queue.cpp index e0114b4..e89c964 100644 --- a/dali/internal/update/common/discard-queue.cpp +++ b/dali/internal/update/common/discard-queue.cpp @@ -26,6 +26,7 @@ #include #include #include +#include namespace Dali { @@ -52,14 +53,21 @@ void DiscardQueue::Add( BufferIndex updateBufferIndex, Node* node ) // 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 ) @@ -71,14 +79,7 @@ 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 ) @@ -88,48 +89,28 @@ 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 diff --git a/dali/internal/update/common/discard-queue.h b/dali/internal/update/common/discard-queue.h index a8a35ef..899d856 100644 --- a/dali/internal/update/common/discard-queue.h +++ b/dali/internal/update/common/discard-queue.h @@ -35,6 +35,7 @@ namespace Internal namespace SceneGraph { +class GeometryBatcher; class RenderQueue; class Shader; class Camera; @@ -107,6 +108,12 @@ public: */ void Clear( BufferIndex updateBufferIndex ); + /** + * Sets pointer to the GeometryBatcher instance + * @param[in] geometryBatcher Instance of the GeometryBatcher + */ + void SetGeometryBatcher( GeometryBatcher* geometryBatcher ); + private: // Undefined @@ -119,17 +126,14 @@ private: 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 diff --git a/dali/internal/update/manager/geometry-batcher.cpp b/dali/internal/update/manager/geometry-batcher.cpp new file mode 100644 index 0000000..58a9dbb --- /dev/null +++ b/dali/internal/update/manager/geometry-batcher.cpp @@ -0,0 +1,581 @@ +/* + * 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 + +// INTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 +void TransformVertexBuffer( TransformVertexBufferData& data ) +{ + const PositionType* source = reinterpret_cast( data.sourcePtr ); + PositionType* destination = reinterpret_cast( data.destinationPtr ); + + size_t componentSize = data.componentSize ? data.componentSize : sizeof( PositionType ); + const void* sourceEnd = (reinterpret_cast( source ) + ( data.vertexCount*componentSize )); + for( ; source < sourceEnd; + *(reinterpret_cast( &destination )) += componentSize, + *(reinterpret_cast( &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 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 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 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 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::iterator iter = mImpl->batchParents.begin(); + std::vector::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& vertexBufferDest = *( new Vector() ); + 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( transformParameters ); + break; + } + case Dali::Property::VECTOR3: + { + TransformVertexBuffer( transformParameters ); + break; + } + case Dali::Property::VECTOR4: + { + TransformVertexBuffer( 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::iterator iter = batchParentData.batches.begin(); + std::vector::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::Iterator iter = batchParent.batchedChildren.Begin(); + Vector::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 diff --git a/dali/internal/update/manager/geometry-batcher.h b/dali/internal/update/manager/geometry-batcher.h new file mode 100644 index 0000000..c19e034 --- /dev/null +++ b/dali/internal/update/manager/geometry-batcher.h @@ -0,0 +1,146 @@ +#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 +#include +#include + +// PUBLIC INCLUDES +#include + +/// 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 + diff --git a/dali/internal/update/manager/prepare-render-instructions.cpp b/dali/internal/update/manager/prepare-render-instructions.cpp index 41616a1..350d66e 100644 --- a/dali/internal/update/manager/prepare-render-instructions.cpp +++ b/dali/internal/update/manager/prepare-render-instructions.cpp @@ -34,6 +34,8 @@ #include #include #include +#include +#include namespace { @@ -58,6 +60,7 @@ namespace SceneGraph * @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 */ @@ -66,19 +69,37 @@ inline void AddRendererToRenderList( BufferIndex updateBufferIndex, 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 ) { @@ -97,7 +118,7 @@ inline void AddRendererToRenderList( BufferIndex updateBufferIndex, item.mDepthIndex = renderable.mRenderer->GetDepthIndex() + static_cast( 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 ); } } @@ -111,6 +132,7 @@ inline void AddRendererToRenderList( BufferIndex updateBufferIndex, * 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 */ @@ -119,6 +141,7 @@ inline void AddRenderersToRenderList( BufferIndex updateBufferIndex, RenderableContainer& renderers, const Matrix& viewMatrix, SceneGraph::Camera& camera, + GeometryBatcher* geometryBatcher, bool isLayer3d, bool cull) { @@ -127,7 +150,7 @@ inline void AddRenderersToRenderList( BufferIndex updateBufferIndex, unsigned int rendererCount( renderers.Size() ); for( unsigned int i(0); i #include #include +#include +#include #include #include #include #include #include -#include -#include -#include // Un-comment to enable node tree debug logging //#define NODE_TREE_LOGGING 1 @@ -131,7 +130,8 @@ struct UpdateManager::Impl RenderController& renderController, RenderManager& renderManager, RenderQueue& renderQueue, - SceneGraphBuffers& sceneGraphBuffers ) + SceneGraphBuffers& sceneGraphBuffers, + GeometryBatcher& geometryBatcher ) : renderMessageDispatcher( renderManager, renderQueue, sceneGraphBuffers ), notificationManager( notificationManager ), transformManager(), @@ -145,6 +145,7 @@ struct UpdateManager::Impl renderManager( renderManager ), renderQueue( renderQueue ), renderInstructions( renderManager.GetRenderInstructionContainer() ), + geometryBatcher( geometryBatcher ), backgroundColor( Dali::Stage::DEFAULT_BACKGROUND_COLOR ), taskList( renderMessageDispatcher, resourceManager ), systemLevelTaskList( renderMessageDispatcher, resourceManager ), @@ -165,6 +166,8 @@ struct UpdateManager::Impl renderers.SetSceneController( *sceneController ); + discardQueue.SetGeometryBatcher( &geometryBatcher ); + // create first 'dummy' node nodes.PushBack(0u); } @@ -227,6 +230,7 @@ struct UpdateManager::Impl 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. @@ -278,7 +282,8 @@ UpdateManager::UpdateManager( NotificationManager& notificationManager, RenderController& controller, RenderManager& renderManager, RenderQueue& renderQueue, - TextureCacheDispatcher& textureCacheDispatcher ) + TextureCacheDispatcher& textureCacheDispatcher, + GeometryBatcher& geometryBatcher ) : mImpl(NULL) { mImpl = new Impl( notificationManager, @@ -289,9 +294,11 @@ UpdateManager::UpdateManager( NotificationManager& notificationManager, controller, renderManager, renderQueue, - mSceneGraphBuffers ); + mSceneGraphBuffers, + geometryBatcher ); textureCacheDispatcher.SetBufferIndices( &mSceneGraphBuffers ); + mImpl->geometryBatcher.SetUpdateManager( this ); } UpdateManager::~UpdateManager() @@ -308,13 +315,13 @@ void UpdateManager::InstallRoot( SceneGraph::Layer* layer, bool systemLevel ) { 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); @@ -332,7 +339,8 @@ void UpdateManager::AddNode( Node* node ) if(node > (*iter)) { mImpl->nodes.Insert((iter+1), node); - node->CreateTransform( &mImpl->transformManager); + node->CreateTransform( &mImpl->transformManager ); + node->mGeometryBatcher = &mImpl->geometryBatcher; break; } } @@ -979,6 +987,9 @@ unsigned int UpdateManager::Update( float elapsedSeconds, //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, @@ -991,6 +1002,7 @@ unsigned int UpdateManager::Update( float elapsedSeconds, *mImpl->root, mImpl->sortedLayers, mImpl->renderSortingHelper, + mImpl->geometryBatcher, mImpl->renderInstructions ); // Process the system-level RenderTasks last @@ -1001,6 +1013,7 @@ unsigned int UpdateManager::Update( float elapsedSeconds, *mImpl->systemLevelRoot, mImpl->systemLevelSortedLayers, mImpl->renderSortingHelper, + mImpl->geometryBatcher, mImpl->renderInstructions ); } } diff --git a/dali/internal/update/manager/update-manager.h b/dali/internal/update/manager/update-manager.h index e90ab9d..7f15563 100644 --- a/dali/internal/update/manager/update-manager.h +++ b/dali/internal/update/manager/update-manager.h @@ -104,6 +104,7 @@ public: * @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, @@ -113,7 +114,8 @@ public: Integration::RenderController& controller, RenderManager& renderManager, RenderQueue& renderQueue, - TextureCacheDispatcher& textureCacheDispatcher ); + TextureCacheDispatcher& textureCacheDispatcher, + GeometryBatcher& geometryBatcher ); /** * Destructor. diff --git a/dali/internal/update/nodes/node.cpp b/dali/internal/update/nodes/node.cpp index b3a9767..0a7dc5a 100644 --- a/dali/internal/update/nodes/node.cpp +++ b/dali/internal/update/nodes/node.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -49,7 +50,7 @@ Node* Node::New() } Node::Node() -: mTransformManager(0), +: mTransformManager( NULL ), mTransformId( INVALID_TRANSFORM_ID ), mParentOrigin( TRANSFORM_PROPERTY_PARENT_ORIGIN ), mAnchorPoint( TRANSFORM_PROPERTY_ANCHOR_POINT ), @@ -64,7 +65,11 @@ Node::Node() 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 ), @@ -211,6 +216,35 @@ void Node::DisconnectChild( BufferIndex updateBufferIndex, Node& childNode ) 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); imBatchingEnabled ) + { + mGeometryBatcher->AddNode( this ); + } +} + void Node::RemoveRenderer( Renderer* renderer ) { unsigned int rendererCount( mRenderer.Size() ); @@ -252,7 +286,7 @@ void Node::ResetDefaultProperties( BufferIndex updateBufferIndex ) mDirtyFlags = NothingFlag; } -void Node::SetParent(Node& parentNode) +void Node::SetParent( Node& parentNode ) { DALI_ASSERT_ALWAYS(this != &parentNode); DALI_ASSERT_ALWAYS(!mIsRoot); @@ -267,6 +301,29 @@ void Node::SetParent(Node& parentNode) } } +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); diff --git a/dali/internal/update/nodes/node.h b/dali/internal/update/nodes/node.h index 4846122..3f8bbac 100644 --- a/dali/internal/update/nodes/node.h +++ b/dali/internal/update/nodes/node.h @@ -56,6 +56,7 @@ class DiscardQueue; class Layer; class RenderTask; class UpdateManager; +class GeometryBatcher; /** * Flag whether property has changed, during the Update phase. @@ -145,28 +146,7 @@ public: * 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); iIsLocalMatrixDirty( mTransformId )); } - /** * Retrieve the cached world-matrix of a node. * @param[in] bufferIndex The buffer to read from. @@ -685,6 +664,36 @@ public: 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 @@ -717,7 +726,9 @@ protected: * 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() @@ -799,11 +810,16 @@ public: // Default properties 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 @@ -927,6 +943,19 @@ inline void RemoveRendererMessage( EventThreadServices& eventThreadServices, con // 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 diff --git a/dali/internal/update/render-tasks/scene-graph-camera.cpp b/dali/internal/update/render-tasks/scene-graph-camera.cpp index 158ed37..c9e4b7a 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.cpp +++ b/dali/internal/update/render-tasks/scene-graph-camera.cpp @@ -65,7 +65,7 @@ void Frustum(Matrix& result, float left, float right, float bottom, float top, f 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; } @@ -104,7 +104,7 @@ void Orthographic(Matrix& result, float left, float right, float bottom, float t { 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; } diff --git a/dali/internal/update/rendering/scene-graph-renderer.cpp b/dali/internal/update/rendering/scene-graph-renderer.cpp index 17b402f..c28a236 100644 --- a/dali/internal/update/rendering/scene-graph-renderer.cpp +++ b/dali/internal/update/rendering/scene-graph-renderer.cpp @@ -107,7 +107,8 @@ enum Flags 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 @@ -146,6 +147,7 @@ Renderer::Renderer() mResourcesReady( false ), mFinishedResourceAcquisition( false ), mPremultipledAlphaEnabled( false ), + mBatchingEnabled( false ), mDepthIndex( 0 ) { mUniformMapChanged[0] = false; @@ -376,6 +378,13 @@ void Renderer::PrepareRender( BufferIndex updateBufferIndex ) 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; } } @@ -550,6 +559,12 @@ void Renderer::SetWriteToColorBuffer( bool writeToColorBuffer ) 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 ) { diff --git a/dali/internal/update/rendering/scene-graph-renderer.h b/dali/internal/update/rendering/scene-graph-renderer.h index 4249b0f..1a86cb9 100644 --- a/dali/internal/update/rendering/scene-graph-renderer.h +++ b/dali/internal/update/rendering/scene-graph-renderer.h @@ -87,6 +87,14 @@ public: */ 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 @@ -98,7 +106,7 @@ public: * Get the shader used by this renderer * @return the shader this renderer uses */ - Shader& GetShader() + const Shader& GetShader() const { return *mShader; } @@ -110,6 +118,15 @@ public: 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 */ @@ -239,6 +256,21 @@ public: 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. @@ -390,6 +422,7 @@ private: public: + bool mBatchingEnabled : 1; ///< Flag indicating whether the render supports batching int mDepthIndex; ///< Used only in PrepareRenderInstructions }; @@ -629,6 +662,16 @@ inline void SetWriteToColorBufferMessage( EventThreadServices& eventThreadServic 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 diff --git a/dali/public-api/actors/actor.h b/dali/public-api/actors/actor.h index 2008faf..0103c63 100644 --- a/dali/public-api/actors/actor.h +++ b/dali/public-api/actors/actor.h @@ -307,7 +307,8 @@ public: 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 }; }; diff --git a/dali/public-api/dali-core-version.cpp b/dali/public-api/dali-core-version.cpp index 4b18845..97ed015 100644 --- a/dali/public-api/dali-core-version.cpp +++ b/dali/public-api/dali-core-version.cpp @@ -27,8 +27,8 @@ namespace Dali { 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 diff --git a/dali/public-api/object/ref-object.cpp b/dali/public-api/object/ref-object.cpp index 5805e36..3060f4b 100644 --- a/dali/public-api/object/ref-object.cpp +++ b/dali/public-api/object/ref-object.cpp @@ -42,7 +42,7 @@ RefObject::~RefObject() #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 } diff --git a/dali/public-api/rendering/renderer.h b/dali/public-api/rendering/renderer.h index 9c06ea3..1a48391 100644 --- a/dali/public-api/rendering/renderer.h +++ b/dali/public-api/rendering/renderer.h @@ -420,7 +420,15 @@ public: * @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 }; }; diff --git a/dali/public-api/signals/base-signal.cpp b/dali/public-api/signals/base-signal.cpp index 6150994..8d759e7 100644 --- a/dali/public-api/signals/base-signal.cpp +++ b/dali/public-api/signals/base-signal.cpp @@ -314,7 +314,7 @@ BaseSignal::EmitGuard::EmitGuard( bool& flag ) 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" ); } } diff --git a/packaging/dali.spec b/packaging/dali.spec index 72d6453..a2a94d6 100644 --- a/packaging/dali.spec +++ b/packaging/dali.spec @@ -1,6 +1,6 @@ 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