utc-Dali-Texture.cpp
utc-Dali-TextureSet.cpp
utc-Dali-Thread.cpp
+ utc-Dali-ThreadPool.cpp
utc-Dali-TouchEventCombiner.cpp
utc-Dali-TouchProcessing.cpp
utc-Dali-TouchDataProcessing.cpp
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
DALI_TEST_EQUALS( propertySetCheck.mValue, Property::Value( 29 ), TEST_LOCATION );
END_TEST;
}
+
+int UtcDaliHandlePropertySetProperties(void)
+{
+ TestApplication application;
+ const Vector3 actorSize( 10.0f, 20.0f, 30.0f );
+ const Vector3 anchorPoint( 1.0f, 0.5f, 0.0f );
+ const Vector4 color( 0.1f, 0.2, 0.3f, 0.4f );
+
+ Handle handle = Actor::New();
+ DevelHandle::SetProperties(
+ handle,
+ Property::Map
+ {
+ { Actor::Property::SIZE, actorSize },
+ { Actor::Property::ANCHOR_POINT, anchorPoint },
+ { "color", color },
+ { "invalid", Vector2::ZERO } // It should quietly ignore invalid data
+ }
+ );
+ DALI_TEST_EQUALS( handle.GetProperty( Actor::Property::SIZE ).Get< Vector3 >(), actorSize, TEST_LOCATION );
+ DALI_TEST_EQUALS( handle.GetProperty( Actor::Property::ANCHOR_POINT ).Get< Vector3 >(), anchorPoint, TEST_LOCATION );
+ DALI_TEST_EQUALS( handle.GetProperty( Actor::Property::COLOR ).Get< Vector4 >(), color, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliHandleTemplateNew(void)
+{
+ TestApplication application;
+ const Vector3 actorSize( 10.0f, 20.0f, 30.0f );
+ const Vector3 anchorPoint( 1.0f, 0.5f, 0.0f );
+ const Vector4 color( 0.1f, 0.2, 0.3f, 0.4f );
+
+ Handle handle = DevelHandle::New< Actor >(
+ Property::Map
+ {
+ { Actor::Property::SIZE, actorSize },
+ { Actor::Property::ANCHOR_POINT, anchorPoint },
+ { "color", color },
+ { "invalid", Vector2::ZERO } // It should quietly ignore invalid data
+ }
+ );
+
+ DALI_TEST_EQUALS( handle.GetProperty( Actor::Property::SIZE ).Get< Vector3 >(), actorSize, TEST_LOCATION );
+ DALI_TEST_EQUALS( handle.GetProperty( Actor::Property::ANCHOR_POINT ).Get< Vector3 >(), anchorPoint, TEST_LOCATION );
+ DALI_TEST_EQUALS( handle.GetProperty( Actor::Property::COLOR ).Get< Vector4 >(), color, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliHandleGetProperties(void)
+{
+ TestApplication application;
+
+ Handle handle = Actor::New();
+ DevelHandle::SetProperties(
+ handle,
+ Property::Map
+ {
+ { Actor::Property::SIZE, Vector3( 400.0f, 200.0f, 100.0f ) },
+ { Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_CENTER },
+ { Actor::Property::PARENT_ORIGIN, ParentOrigin::BOTTOM_CENTER },
+ { Actor::Property::NAME, "Actor" },
+ { Actor::Property::LEAVE_REQUIRED, true },
+ { "color", Color::RED },
+ }
+ );
+
+ Property::Map map;
+ DevelHandle::GetProperties( handle, map );
+
+ // Get all the properties and ensure they match
+
+ DALI_TEST_EQUALS( handle.GetPropertyCount(), map.Count(), TEST_LOCATION );
+
+ for( auto position = 0u; position < map.Count(); ++position )
+ {
+ auto keyValuePair = map.GetKeyValue( position );
+ const auto& index = keyValuePair.first.indexKey;
+ const auto& value = keyValuePair.second;
+ auto handleValue = handle.GetProperty( index );
+
+ switch( value.GetType() )
+ {
+ case Property::NONE: break;
+ case Property::BOOLEAN: DALI_TEST_EQUALS( value.Get< bool >(), handleValue.Get< bool >(), TEST_LOCATION ); break;
+ case Property::FLOAT: DALI_TEST_EQUALS( value.Get< float >(), handleValue.Get< float >(), TEST_LOCATION ); break;
+ case Property::INTEGER: DALI_TEST_EQUALS( value.Get< int >(), handleValue.Get< int >(), TEST_LOCATION ); break;
+ case Property::VECTOR2: DALI_TEST_EQUALS( value.Get< Vector2 >(), handleValue.Get< Vector2 >(), TEST_LOCATION ); break;
+ case Property::VECTOR3: DALI_TEST_EQUALS( value.Get< Vector3 >(), handleValue.Get< Vector3 >(), TEST_LOCATION ); break;
+ case Property::VECTOR4: DALI_TEST_EQUALS( value.Get< Vector4 >(), handleValue.Get< Vector4 >(), TEST_LOCATION ); break;
+ case Property::MATRIX3: DALI_TEST_EQUALS( value.Get< Matrix3 >(), handleValue.Get< Matrix3 >(), TEST_LOCATION ); break;
+ case Property::MATRIX: DALI_TEST_EQUALS( value.Get< Matrix >(), handleValue.Get< Matrix >(), TEST_LOCATION ); break;
+ case Property::RECTANGLE: DALI_TEST_EQUALS( value.Get< Rect< int > >(), handleValue.Get< Rect< int > >(), TEST_LOCATION ); break;
+ case Property::ROTATION: DALI_TEST_EQUALS( value.Get< Quaternion >(), handleValue.Get< Quaternion >(), TEST_LOCATION ); break;
+ case Property::STRING: DALI_TEST_EQUALS( value.Get< std::string >(), handleValue.Get< std::string >(), TEST_LOCATION ); break;
+ case Property::ARRAY: DALI_TEST_EQUALS( value.GetArray()->Count(), handleValue.GetArray()->Count(), TEST_LOCATION ); break;
+ case Property::MAP: DALI_TEST_EQUALS( value.GetMap()->Count(), handleValue.GetMap()->Count(), TEST_LOCATION ); break;
+ case Property::EXTENTS: DALI_TEST_EQUALS( value.Get< Extents >(), handleValue.Get< Extents >(), TEST_LOCATION ); break;
+ }
+ }
+
+ // Add a custom property and ensure the count goes up by one.
+ const auto countBefore = map.Count();
+ handle.RegisterProperty( "tempProperty", Color::GREEN );
+ DevelHandle::GetProperties( handle, map );
+ DALI_TEST_EQUALS( countBefore + 1, map.Count(), TEST_LOCATION );
+
+ END_TEST;
+}
#include <stdlib.h>
#include <dali/public-api/dali-core.h>
#include <dali/integration-api/events/key-event-integ.h>
+#include <dali/devel-api/events/key-event-devel.h>
#include <dali-test-suite-utils.h>
END_TEST;
}
+
+int UtcDaliKeyEventSetLogicalKey(void)
+{
+ TestApplication application;
+
+ KeyEvent event(TEST_STRING_1,"i", 99, SHIFT_MODIFIER, 0lu, KeyEvent::Down);
+
+ DALI_TEST_EQUALS( DevelKeyEvent::GetLogicalKey( event ), "", TEST_LOCATION );
+
+ END_TEST;
+}
END_TEST;
}
+int UtcDaliSceneRootLayerAndSceneAlignment(void)
+{
+ TestApplication application;
+
+ // Create a Scene
+ Dali::Integration::Scene scene = Dali::Integration::Scene::New( Vector2( 480.0f, 800.0f ) );
+ DALI_TEST_CHECK( scene );
+
+ // One reference of scene kept here and the other one kept in the Core
+ DALI_TEST_CHECK( scene.GetBaseObject().ReferenceCount() == 2 );
+
+ // Render and notify.
+ application.SendNotification();
+ application.Render(0);
+
+ // Keep the reference of the root layer handle so it will still be alive after the scene is deleted
+ Layer rootLayer = scene.GetRootLayer();
+ DALI_TEST_CHECK( rootLayer );
+ DALI_TEST_CHECK( rootLayer.GetBaseObject().ReferenceCount() == 2 );
+
+ // Request to discard the scene from the Core
+ scene.Discard();
+ DALI_TEST_CHECK( scene.GetBaseObject().ReferenceCount() == 1 );
+
+ // Reset the scene handle
+ scene.Reset();
+
+ // Render and notify.
+ application.SendNotification();
+ application.Render(0);
+
+ // At this point, the scene should have been automatically deleted
+ // To prove this, the ref count of the root layer handle should be decremented to 1
+ DALI_TEST_CHECK( rootLayer.GetBaseObject().ReferenceCount() == 1 );
+
+ // Create a new Scene while the root layer of the deleted scene is still alive
+ Dali::Integration::Scene newScene = Dali::Integration::Scene::New( Vector2( 480.0f, 800.0f ) );
+ DALI_TEST_CHECK( newScene );
+
+ // Render and notify.
+ application.SendNotification();
+ application.Render(0);
+
+ // At this point, we have only one scene but two root layers
+ // The root layer of the deleted scene is still alive
+ DALI_TEST_CHECK( rootLayer.GetBaseObject().ReferenceCount() == 1 );
+
+ // Delete the root layer of the deleted scene
+ rootLayer.Reset();
+
+ // Render and notify.
+ application.SendNotification();
+ application.Render(0);
+
+ END_TEST;
+}
+
int UtcDaliSceneEventProcessingFinishedP(void)
{
TestApplication application;
out << GL_TEXTURE_2D <<", "<< 0u << ", " << width/2 << ", " << height/2 << ", " << width/2 << ", " << height/2;
DALI_TEST_CHECK( callStack.FindMethodAndParams("CompressedTexSubImage2D", out.str().c_str() ) );
}
+
+ application.GetGlAbstraction().ResetTextureCallStack();
}
END_TEST;
--- /dev/null
+/*
+ * Copyright (c) 2017 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.
+ *
+ */
+
+#include <iostream>
+#include <stdlib.h>
+#include <unistd.h>
+#include <type_traits>
+#include <dali-test-suite-utils.h>
+#include <dali/devel-api/threading/thread-pool.h>
+
+namespace
+{
+Dali::ThreadPool gThreadPool;
+
+// Helper function dividing workload into N batches
+// the loop lambda contains
+Dali::UniqueFutureGroup ForEachMT( Dali::ThreadPool* pThreadPool,
+ uint32_t first,
+ uint32_t size,
+ std::function<void( uint32_t, uint32_t, uint32_t )> task )
+{
+ uint32_t i = 0;
+ uint32_t j = 0;
+ const auto workerCount = uint32_t(pThreadPool->GetWorkerCount());
+ const auto step = size / workerCount;
+ j = workerCount + step;
+
+ std::vector<Dali::Task> tasks;
+ tasks.reserve( workerCount );
+
+ for( auto threadIndex = 0u; threadIndex < workerCount; ++threadIndex )
+ {
+ Dali::Task lambda = [task, i, j]( int workerIndex )
+ {
+ task( uint32_t(workerIndex), i, j );
+ };
+ tasks.emplace_back( lambda );
+ i = j;
+ j = i + step;
+ if( j > size )
+ j = size;
+ }
+ return pThreadPool->SubmitTasks( tasks, workerCount );
+}
+
+}
+
+int UtcDaliThreadPoolMultipleTasks(void)
+{
+ // initialise global thread pool
+ if( !gThreadPool.GetWorkerCount() )
+ {
+ gThreadPool.Initialize( 0u );
+ }
+
+ // populate inputs
+ std::array<int, 8192> inputs;
+ int checksum = 0;
+ for( auto i = 0; i < decltype(i)(inputs.size()); ++i )
+ {
+ inputs[i] = i;
+ checksum += i;
+ }
+
+ // allocate outputs ( number of outputs equals number of worker threads
+ auto workerCount = gThreadPool.GetWorkerCount();
+
+ std::vector<int> outputs;
+ outputs.resize( workerCount );
+ std::fill( outputs.begin(), outputs.end(), 0 );
+
+ // submit
+ auto future = ForEachMT( &gThreadPool, 0, inputs.size(), [&inputs, &outputs]( uint32_t workerIndex, uint32_t begin, uint32_t end )
+ {
+ for( auto i = begin; i < end; ++i )
+ {
+ outputs[workerIndex] += inputs[i];
+ }
+ });
+
+ future->Wait();
+
+ // check outputs
+ int checksum2 = 0;
+ for( auto output : outputs )
+ {
+ checksum2 += output;
+ }
+
+ printf("sum: %d, sum2: %d\n", checksum, checksum2);
+
+
+ DALI_TEST_EQUALS( checksum, checksum2, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliThreadPoolSingleTask(void)
+{
+ // initialise global thread pool
+ if( !gThreadPool.GetWorkerCount() )
+ {
+ gThreadPool.Initialize( 0u );
+ }
+
+ // some long lasting task
+ int counter = 0;
+ auto task = [&counter]( int workerIndex ){
+ for( int i = 0; i < 10; ++i )
+ {
+ counter++;
+ usleep( 16 * 1000 );
+ }
+ };
+
+ auto future = gThreadPool.SubmitTask( 0, task );
+ future->Wait();
+ DALI_TEST_EQUALS( counter, 10, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliThreadPoolSubmitTasksCopyArray(void)
+{
+ // initialise global thread pool
+ if( !gThreadPool.GetWorkerCount() )
+ {
+ gThreadPool.Initialize( 0u );
+ }
+
+ std::array<uint8_t, 1024*1024> dataSrc;
+ for( auto i = 0; i < decltype(i)(dataSrc.size()); ++i)
+ {
+ dataSrc[i] = (std::rand() % 0xff);
+ }
+
+ std::array<uint8_t, 1024*1024> dataDst;
+
+ // each task copies 1kb od data
+ std::vector<Dali::Task> tasks;
+ for( int i = 0; i < 1024; ++i )
+ {
+ auto task = [&dataSrc, &dataDst, i ]( int workerIndex )
+ {
+ for( int k = 0; k < 1024; ++k )
+ {
+ dataDst[i*1024+k] = dataSrc[i*1024+k];
+ }
+ };
+ tasks.push_back( task );
+ }
+
+ DALI_TEST_EQUALS( 1024, tasks.size(), TEST_LOCATION );
+
+ gThreadPool.SubmitTasks( tasks );
+
+ // wait for pool to finish
+ gThreadPool.Wait();
+
+ // compare arrays
+ for( auto i = 0; i < decltype(i)(dataSrc.size()); ++i )
+ {
+ DALI_TEST_EQUALS( dataSrc[i], dataDst[i], TEST_LOCATION );
+ if( dataSrc[i] != dataDst[i] )
+ {
+ break;
+ }
+ }
+
+ END_TEST;
+}
\ No newline at end of file
${CMAKE_CURRENT_SOURCE_DIR}/common/hash.cpp
${CMAKE_CURRENT_SOURCE_DIR}/common/stage-devel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/events/hit-test-algorithm.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/events/key-event-devel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/events/touch-data-devel.cpp
${CMAKE_CURRENT_SOURCE_DIR}/images/distance-field.cpp
${CMAKE_CURRENT_SOURCE_DIR}/images/texture-set-image.cpp
${CMAKE_CURRENT_SOURCE_DIR}/common/stage-devel.h
${CMAKE_CURRENT_SOURCE_DIR}/events/hit-test-algorithm.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/events/key-event-devel.h
${CMAKE_CURRENT_SOURCE_DIR}/events/touch-data-devel.h
${CMAKE_CURRENT_SOURCE_DIR}/images/distance-field.h
--- /dev/null
+/*\r
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/devel-api/events/key-event-devel.h>\r
+#include <dali/internal/event/events/key-event-impl.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace DevelKeyEvent\r
+{\r
+\r
+std::string GetLogicalKey( KeyEvent keyEvent )\r
+{\r
+ return GetImplementation( &keyEvent )->GetLogicalKey();\r
+}\r
+\r
+} // namespace DevelKeyEvent\r
+\r
+} // namespace Dali\r
+\r
--- /dev/null
+#ifndef DALI_KEY_EVENT_DEVEL_H\r
+#define DALI_KEY_EVENT_DEVEL_H\r
+\r
+/*\r
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ *\r
+ */\r
+\r
+// INTERNAL INCLUDES\r
+#include <dali/public-api/events/key-event.h>\r
+\r
+namespace Dali\r
+{\r
+\r
+namespace DevelKeyEvent\r
+{\r
+\r
+/**\r
+ * @brief Gets the logical key string.\r
+ *\r
+ * For example, when the user presses 'shift' key and '1' key together, the logical key is "exclamation".\r
+ * Plus, the keyPressedName is "1", and the keyPressed is "!".\r
+ *\r
+ * @param[in] keyEvent The instance of KeyEvent.\r
+ * @return The logical key symbol\r
+ */\r
+DALI_CORE_API std::string GetLogicalKey( KeyEvent keyEvent );\r
+\r
+} // namespace DevelKeyEvent\r
+\r
+} // namespace Dali\r
+\r
+#endif // DALI_KEY_EVENT_DEVEL_H\r
$(devel_api_src_dir)/common/stage-devel.cpp \
$(devel_api_src_dir)/events/hit-test-algorithm.cpp \
$(devel_api_src_dir)/events/touch-data-devel.cpp \
+ $(devel_api_src_dir)/events/key-event-devel.cpp \
$(devel_api_src_dir)/images/distance-field.cpp \
$(devel_api_src_dir)/images/texture-set-image.cpp \
$(devel_api_src_dir)/images/nine-patch-image.cpp \
$(devel_api_src_dir)/threading/conditional-wait.cpp \
$(devel_api_src_dir)/threading/mutex.cpp \
$(devel_api_src_dir)/threading/thread.cpp \
+ $(devel_api_src_dir)/threading/thread-pool.cpp \
$(devel_api_src_dir)/update/frame-callback-interface.cpp \
$(devel_api_src_dir)/update/update-proxy.cpp
devel_api_core_events_header_files = \
$(devel_api_src_dir)/events/hit-test-algorithm.h \
- $(devel_api_src_dir)/events/touch-data-devel.h
+ $(devel_api_src_dir)/events/touch-data-devel.h \
+ $(devel_api_src_dir)/events/key-event-devel.h
devel_api_core_images_header_files = \
$(devel_api_src_dir)/images/distance-field.h \
devel_api_core_threading_header_files = \
$(devel_api_src_dir)/threading/conditional-wait.h \
$(devel_api_src_dir)/threading/mutex.h \
- $(devel_api_src_dir)/threading/thread.h
+ $(devel_api_src_dir)/threading/thread.h \
+ $(devel_api_src_dir)/threading/thread-pool.h
devel_api_core_update_header_files = \
$(devel_api_src_dir)/update/frame-callback-interface.h \
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
return GetImplementation( handle ).RegisterProperty( name, key, propertyValue );
}
+void SetProperties( Handle handle, const Property::Map& properties )
+{
+ GetImplementation( handle ).SetProperties( properties );
+}
+
+void GetProperties( Handle handle, Property::Map& properties )
+{
+ GetImplementation( handle ).GetProperties( properties );
+}
+
void SetTypeInfo( Handle& handle, const TypeInfo& typeInfo )
{
GetImplementation( handle ).SetTypeInfo( &GetImplementation( typeInfo ) );
#define DALI_HANDLE_DEVEL_H
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
DALI_CORE_API Property::Index RegisterProperty( Handle handle, Property::Index key, const std::string& name, const Property::Value& propertyValue );
/**
+ * @brief Sets all the properties in the given property map.
+ *
+ * @param[in] handle The handle to set the properties on
+ * @param[in] properties The properties to set
+ */
+DALI_CORE_API void SetProperties( Handle handle, const Property::Map& properties );
+
+/**
+ * @brief Retrieves all the properties and the values for a handle.
+ *
+ * @param[in] handle The handle to retrieve properties from
+ * @param[out] properties A map which is populated with the index-value pairs
+ *
+ * @note The properties map will be cleared by this method first.
+ */
+DALI_CORE_API void GetProperties( Handle handle, Property::Map& properties );
+
+/**
* @brief Set the type-info that the object is created by.
*
* @note This is particularly useful to link C# custom control with its correct type-info in the native side
*/
DALI_CORE_API PropertySetSignalType& PropertySetSignal( Handle handle );
+/**
+ * @brief Template to create a derived handle and set properties on it.
+ *
+ * @tparam T The derived class to create
+ *
+ * @param[in] properties The properties to set
+ */
+template< typename T >
+DALI_INTERNAL T New( const Property::Map& properties )
+{
+ T handle = T::New();
+ SetProperties( handle, properties );
+ return handle;
+}
} // namespace DevelHandle
--- /dev/null
+/*
+ * Copyright (c) 2018 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.
+ *
+ */
+
+#include "thread-pool.h"
+#include <cmath>
+
+
+
+namespace Dali
+{
+namespace
+{
+template<typename T, typename... Args>
+std::unique_ptr<T> make_unique(Args&&... args)
+{
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+}
+
+/**
+ * WorkerThread executes tasks submitted to the pool
+ */
+class WorkerThread
+{
+public:
+
+ /**
+ * @brief Constructor of worker thread
+ * @param index Thread index assigned to the object during pool initialisation
+ */
+ explicit WorkerThread( uint32_t index );
+
+ /**
+ * @brief Destructor of the worker thread
+ */
+ ~WorkerThread();
+
+ WorkerThread(const WorkerThread &other) = delete;
+ WorkerThread &operator=(const WorkerThread &other) = delete;
+
+ /**
+ * @brief Adds task to the task queue
+ * @param task Task to be executed by the thread
+ */
+ void AddTask( Task task );
+
+ /**
+ * @brief Wakes up thread.
+ */
+ void Notify();
+
+ /**
+ * @brief Waits for the thread to complete all the tasks currently in the queue.
+ */
+ void Wait();
+
+private:
+
+ /**
+ * @brief Internal thread loop function
+ */
+ void WaitAndExecute();
+
+ std::thread mWorker;
+ uint32_t mIndex;
+ TaskQueue mTaskQueue;
+ std::mutex mTaskQueueMutex;
+ std::condition_variable mConditionVariable;
+
+ bool mTerminating {false} ;
+};
+
+void WorkerThread::WaitAndExecute()
+{
+ while( true )
+ {
+ Task task;
+
+ {
+ std::unique_lock< std::mutex > lock{ mTaskQueueMutex };
+
+ mConditionVariable.wait( lock, [ this ]() -> bool {
+ return !mTaskQueue.empty() || mTerminating;
+ } );
+
+ if( mTerminating )
+ {
+ break;
+ }
+
+ task = mTaskQueue.front();
+ }
+
+ task( mIndex );
+
+ {
+ std::lock_guard< std::mutex > lock{ mTaskQueueMutex };
+
+ mTaskQueue.pop();
+
+ mConditionVariable.notify_one();
+ }
+ }
+}
+
+WorkerThread::WorkerThread(uint32_t index) : mIndex( index )
+{
+ // Have to pass "this" as an argument because WaitAndExecute is a member function.
+ mWorker = std::thread{ &WorkerThread::WaitAndExecute, this };
+}
+
+WorkerThread::~WorkerThread()
+{
+ if( mWorker.joinable() )
+ {
+ Notify();
+ Wait();
+
+ {
+ std::lock_guard< std::mutex > lock{ mTaskQueueMutex };
+ mTerminating = true;
+ mConditionVariable.notify_one();
+ }
+
+ mWorker.join();
+ }
+}
+
+void WorkerThread::AddTask( Task task )
+{
+ std::lock_guard< std::mutex > lock{ mTaskQueueMutex };
+ mTaskQueue.push( std::move( task ) );
+ mConditionVariable.notify_one();
+}
+
+void WorkerThread::Notify()
+{
+ std::lock_guard< std::mutex > lock{ mTaskQueueMutex };
+ mConditionVariable.notify_one();
+}
+
+void WorkerThread::Wait()
+{
+ std::unique_lock< std::mutex > lock{ mTaskQueueMutex };
+ mConditionVariable.wait( lock, [ this ]() -> bool {
+ return mTaskQueue.empty();
+ } );
+}
+
+// ThreadPool -----------------------------------------------------------------------------------------------
+
+struct ThreadPool::Impl
+{
+ std::vector<std::unique_ptr<WorkerThread>> mWorkers;
+ uint32_t mWorkerIndex{ 0u };
+};
+
+ThreadPool::ThreadPool()
+{
+ mImpl = make_unique<Impl>();
+}
+
+ThreadPool::~ThreadPool() = default;
+
+bool ThreadPool::Initialize( uint32_t threadCount )
+{
+ /**
+ * Get the system's supported thread count.
+ */
+ auto thread_count = threadCount + 1;
+ if( !threadCount )
+ {
+ thread_count = std::thread::hardware_concurrency();
+ if( !thread_count )
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Spawn the worker threads.
+ */
+ for( auto i = 0u; i < thread_count - 1; i++ )
+ {
+ /**
+ * The workers will execute an infinite loop function
+ * and will wait for a job to enter the job queue. Once a job is in the the queue
+ * the threads will wake up to acquire and execute it.
+ */
+ mImpl->mWorkers.push_back( make_unique< WorkerThread >( i ) );
+ }
+
+ return true;
+}
+
+
+void ThreadPool::Wait()
+{
+ for( auto& worker : mImpl->mWorkers )
+ {
+ worker->Wait();
+ }
+}
+
+SharedFuture ThreadPool::SubmitTask( uint32_t workerIndex, const Task& task )
+{
+ auto future = std::shared_ptr< Future< void > >( new Future< void > );
+ mImpl->mWorkers[workerIndex]->AddTask( [task, future]( uint32_t index )
+ {
+ task( index );
+
+ future->mPromise.set_value();
+ });
+
+ return future;
+}
+
+SharedFuture ThreadPool::SubmitTasks( const std::vector< Task >& tasks )
+{
+ auto future = std::shared_ptr< Future< void > >( new Future< void > );
+
+ mImpl->mWorkers[ mImpl->mWorkerIndex++ % static_cast< uint32_t >( mImpl->mWorkers.size() )]->AddTask(
+ [ future, tasks ]( uint32_t index ) {
+ for( auto& task : tasks )
+ {
+ task( index );
+ }
+
+ future->mPromise.set_value();
+
+ } );
+
+ return future;
+}
+
+UniqueFutureGroup ThreadPool::SubmitTasks( const std::vector< Task >& tasks, uint32_t threadMask )
+{
+ auto retval = make_unique<FutureGroup<void>>();
+
+ /**
+ * Use square root of number of sumbitted tasks to estimate optimal number of threads
+ * used to execute jobs
+ */
+ auto threads = uint32_t(std::log2(float(tasks.size())));
+
+ if( threadMask != 0 )
+ {
+ threads = threadMask;
+ }
+
+ if( threads > mImpl->mWorkers.size() )
+ {
+ threads = uint32_t(mImpl->mWorkers.size());
+ }
+ else if( !threads )
+ {
+ threads = 1;
+ }
+
+ auto payloadPerThread = uint32_t(tasks.size() / threads);
+ auto remaining = uint32_t(tasks.size() % threads);
+
+ uint32_t taskIndex = 0;
+ uint32_t taskSize = uint32_t(remaining + payloadPerThread); // add 'remaining' tasks to the very first job list
+
+ for( auto wt = 0u; wt < threads; ++wt )
+ {
+ auto future = std::shared_ptr< Future< void > >( new Future< void > );
+ retval->mFutures.emplace_back( future );
+ mImpl->mWorkers[ mImpl->mWorkerIndex++ % static_cast< uint32_t >( mImpl->mWorkers.size() )]->AddTask(
+ [ future, tasks, taskIndex, taskSize ]( uint32_t index ) {
+ auto begin = tasks.begin() + int(taskIndex);
+ auto end = begin + int(taskSize);
+ for( auto it = begin; it < end; ++it )
+ {
+ (*it)( index );
+ }
+ future->mPromise.set_value();
+ } );
+
+ taskIndex += taskSize;
+ taskSize = payloadPerThread;
+ }
+
+ return retval;
+}
+
+size_t ThreadPool::GetWorkerCount() const
+{
+ return mImpl->mWorkers.size();
+}
+
+} //namespace Dali
--- /dev/null
+#ifndef DALI_THREAD_POOL_H
+#define DALI_THREAD_POOL_H
+
+/*
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+// INTERNAL INCLUDES
+#include <dali/public-api/common/dali-common.h>
+
+// EXTERNAL INCLUDES
+#include <thread>
+#include <functional>
+#include <mutex>
+#include <queue>
+#include <condition_variable>
+#include <future>
+#include <algorithm>
+#include <iostream>
+#include <memory>
+
+namespace Dali
+{
+using Task = std::function<void(uint32_t)>;
+
+using TaskQueue = std::queue<Task>;
+
+/**
+ * Future contains the result of submitted task. When queried
+ * it applies internal synchronization mechanism to make sure
+ * the value is available.
+ */
+template<typename T>
+class DALI_INTERNAL Future final
+{
+ friend class ThreadPool;
+
+public:
+
+ /**
+ * @brief Constructor of Future
+ */
+ Future()
+ {
+ mFuture = mPromise.get_future();
+ }
+
+ /**
+ * @brief Destructor of Future
+ */
+ ~Future()
+ {
+ Wait();
+ }
+
+ /**
+ * @brief Returns value of future, blocks if needed.
+ * @return Value stored by the future
+ */
+ T Get() const
+ {
+ return mFuture.get();
+ }
+
+ /**
+ * @brief Waits until the value of future is ready. This function
+ * is a fencing mechanism.
+ */
+ void Wait() const
+ {
+ if( IsValid() )
+ {
+ mFuture.wait();
+ }
+ }
+
+ /**
+ * @brief Tests whether the future is valid
+ * @return True if valid, False otherwise
+ */
+ bool IsValid() const
+ {
+ return mFuture.valid();
+ }
+
+ /**
+ * @brief Resets the future bringing it to the initial state.
+ * It's required in order to reuse the same Future object.
+ */
+ void Reset()
+ {
+ mPromise = std::promise<T>();
+ mFuture = mPromise.get_future();
+ }
+
+private:
+
+ std::promise<T> mPromise{};
+ std::future<T> mFuture{};
+};
+
+using SharedFuture = std::shared_ptr<Future<void>>;
+
+/**
+ * FutureGroup binds many Future objects and applies synchronization.
+ */
+template<typename T>
+class FutureGroup final
+{
+ friend class ThreadPool;
+
+public:
+
+ /**
+ * Waits for all the Futures to complete.
+ */
+ void Wait()
+ {
+ for (auto &future : mFutures)
+ {
+ future->Wait();
+ }
+ }
+
+private:
+
+ std::vector<std::shared_ptr<Future<T> > > mFutures;
+};
+
+using UniqueFutureGroup = std::unique_ptr<FutureGroup<void>>;
+
+
+
+/**
+ * ThreadPool creates and manages worker threads and tasks submitted for execution.
+ */
+class DALI_CORE_API ThreadPool final
+{
+public:
+
+ /**
+ * @brief Constructor of thread pool.
+ */
+ ThreadPool();
+
+ /**
+ * @brief Destructor of thread pool.
+ */
+ ~ThreadPool();
+
+ /**
+ * @brief Intializes thread pool
+ * @param threadCount Number of worker threads to use. If 0 then thread count equals hardware thread count.
+ * @return True if success
+ */
+ bool Initialize( uint32_t threadCount = 0u );
+
+ /**
+ * @brief Waits until all threads finish execution and go back to the idle state.
+ */
+ void Wait();
+
+ /**
+ * @brief Submits a single task to specified ( by the index ) worker thread.
+ * @param workerIndex Index of thread to be used
+ * @param task Task submitted for execution
+ * @return Shared pointer to the Future object
+ */
+ SharedFuture SubmitTask(uint32_t workerIndex, const Task &task);
+
+ /**
+ * @brief Submits vector of tasks to the pool
+ * @param tasks Vector containing tasks to be executed
+ * @return Shared pointer to the Future object
+ */
+ SharedFuture SubmitTasks(const std::vector<Task>& tasks);
+
+ /**
+ * @brief Submits tasks to threads specified by thread mask.
+ * @param tasks Vector of tasks
+ * @param threadMask Mask of threads to be used or 0 to use all available threads
+ * @return Unique pointer to the FutureGroup object
+ */
+ UniqueFutureGroup SubmitTasks(const std::vector<Task>& tasks, uint32_t threadMask);
+
+ /**
+ * @brief Returns number of worker threads
+ * @return Number of worker threads
+ */
+ size_t GetWorkerCount() const;
+
+private:
+
+ struct Impl;
+ std::unique_ptr<Impl> mImpl;
+};
+
+} //namespace Dali
+
+#endif // DALI_THREAD_POOL_H
/*
- * Copyright (c) 2018 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2019 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.
return RegisterProperty( name, key, propertyValue, Property::ANIMATABLE );
}
+void Object::SetProperties( const Property::Map& properties )
+{
+ const auto count = properties.Count();
+ for( auto position = 0u; position < count; ++position )
+ {
+ // GetKeyAt and GetValue both return references which means no potential copying of maps/arrays.
+ // Iterating twice to get the value we want should still be fairly quick in a Property::Map.
+
+ const auto& key = properties.GetKeyAt( position );
+ const auto propertyIndex = ( key.type == Property::Key::INDEX ) ? key.indexKey : GetPropertyIndex( key.stringKey );
+
+ if( propertyIndex != Property::INVALID_INDEX )
+ {
+ const auto& value = properties.GetValue( position );
+ SetProperty( propertyIndex, value );
+ }
+ }
+}
+
+void Object::GetProperties( Property::Map& properties )
+{
+ properties.Clear();
+
+ Property::IndexContainer indexContainer;
+ GetPropertyIndices( indexContainer );
+
+ for( auto index : indexContainer )
+ {
+ properties[ index ] = GetProperty( index );
+ }
+}
+
Property::Index Object::RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode )
{
return RegisterProperty( name, Property::INVALID_KEY, propertyValue, accessMode );
#include <dali/public-api/object/property.h>
#include <dali/public-api/object/property-index-ranges.h>
#include <dali/public-api/object/property-input.h>
+#include <dali/public-api/object/property-map.h>
#include <dali/public-api/object/property-notification.h>
#include <dali/devel-api/common/owner-container.h>
#include <dali/devel-api/object/handle-devel.h>
Property::Index RegisterProperty( const std::string& name, Property::Index key, const Property::Value& propertyValue );
/**
+ * @copydoc Dali::DevelHandle::SetProperties()
+ */
+ void SetProperties( const Property::Map& properties );
+
+ /**
+ * @copydoc Dali::DevelHandle::GetProperties()
+ */
+ void GetProperties( Property::Map& properties );
+
+ /**
* @copydoc Dali::Handle::RegisterProperty(std::string name, Property::Value propertyValue, Property::AccessMode accessMode)
*/
Property::Index RegisterProperty( const std::string& name, const Property::Value& propertyValue, Property::AccessMode accessMode );
template <typename T>
inline T* GetDataTypedPtr()
{
- Dali::Vector< char >* data = mData.Release();
+ Dali::Vector< uint8_t >* data = mData.Release();
mData = data;
return reinterpret_cast<T*>( &data->operator[]( 0 ) );
}
*
*/
+// EXTERNAL INCLUDES
+#include <cmath>
+
// INTERNAL INCLUDES
#include <dali/public-api/animation/alpha-function.h>
#include <dali/public-api/animation/animation.h>
const uint32_t FRAME_COUNT_TRIGGER = 16;\
if( mImpl->frameCounter >= FRAME_COUNT_TRIGGER )\
{\
- for( auto root : mImpl->roots )
+ for( auto&& scene : mImpl->scenes )
{\
- if ( NULL != root )\
+ if ( scene && scene->root )\
{\
mImpl->frameCounter = 0;\
- PrintNodeTree( *root, mSceneGraphBuffers.GetUpdateBufferIndex(), "" );\
+ PrintNodeTree( *scene->root, mSceneGraphBuffers.GetUpdateBufferIndex(), "" );\
}\
}\
}\
*/
struct UpdateManager::Impl
{
+ // SceneInfo keeps the root node of the Scene, its scene graph render task list, and the list of Layer pointers sorted by depth
+ struct SceneInfo
+ {
+ SceneInfo( Layer* root ) ///< Constructor
+ : root( root )
+ {
+ }
+
+ ~SceneInfo() = default; ///< Default non-virtual destructor
+ SceneInfo( SceneInfo&& rhs ) = default; ///< Move constructor
+ SceneInfo& operator=( SceneInfo&& rhs ) = default; ///< Move assignment operator
+ SceneInfo& operator=( const SceneInfo& rhs ) = delete; ///< Assignment operator
+ SceneInfo( const SceneInfo& rhs ) = delete; ///< Copy constructor
+
+ Layer* root{ nullptr }; ///< Root node (root is a layer). The layer is not stored in the node memory pool.
+ OwnerPointer< RenderTaskList > taskList; ///< Scene graph render task list
+ SortedLayerPointers sortedLayerList; ///< List of Layer pointers sorted by depth (one list of sorted layers per root)
+ };
+
Impl( NotificationManager& notificationManager,
CompleteNotificationInterface& animationPlaylist,
PropertyNotifier& propertyNotifier,
~Impl()
{
// Disconnect render tasks from nodes, before destroying the nodes
- for( auto taskList : taskLists )
+ for( auto&& scene : scenes )
{
- RenderTaskList::RenderTaskContainer& tasks = taskList->GetTasks();
- for ( auto&& task : tasks )
+ if ( scene && scene->taskList )
{
- task->SetSourceNode( NULL );
+ RenderTaskList::RenderTaskContainer& tasks = scene->taskList->GetTasks();
+ for ( auto&& task : tasks )
+ {
+ task->SetSourceNode( NULL );
+ }
}
}
Node::Delete(*iter);
}
- for( auto root : roots )
+ for( auto&& scene : scenes )
{
- root->OnDestroy();
- Node::Delete(root);
+ if ( scene && scene->root )
+ {
+ scene->root->OnDestroy();
+ Node::Delete( scene->root );
+ }
}
+ scenes.clear();
delete sceneController;
}
Vector4 backgroundColor; ///< The glClear color used at the beginning of each frame.
- OwnerContainer<RenderTaskList*> taskLists; ///< A container of scene graph render task lists
-
- Vector<Layer*> roots; ///< A container of root nodes (root is a layer). The layers are not stored in the node memory pool.
+ using SceneInfoPtr = std::unique_ptr< SceneInfo >;
+ std::vector< SceneInfoPtr > scenes; ///< A container of SceneInfo.
Vector<Node*> nodes; ///< A container of all instantiated nodes
- std::vector<SortedLayerPointers> sortedLayerLists; ///< A container of lists of Layer pointers sorted by depth (one list of sorted layers per root)
-
OwnerContainer< Camera* > cameras; ///< A container of cameras
OwnerContainer< PropertyOwner* > customObjects; ///< A container of owned objects (with custom properties)
Layer* rootLayer = layer.Release();
- DALI_ASSERT_DEBUG( std::find( mImpl->roots.begin(), mImpl->roots.end(), rootLayer ) == mImpl->roots.end() && "Root Node already installed" );
+ DALI_ASSERT_DEBUG( std::find_if( mImpl->scenes.begin(), mImpl->scenes.end(),
+ [rootLayer]( Impl::SceneInfoPtr& scene )
+ {
+ return scene && scene->root == rootLayer;
+ }
+ ) == mImpl->scenes.end() && "Root Node already installed" );
rootLayer->CreateTransform( &mImpl->transformManager );
rootLayer->SetRoot(true);
- mImpl->roots.PushBack( rootLayer );
+
+ mImpl->scenes.emplace_back( new Impl::SceneInfo( rootLayer ) );
}
void UpdateManager::UninstallRoot( Layer* layer )
DALI_ASSERT_DEBUG( layer->IsLayer() );
DALI_ASSERT_DEBUG( layer->GetParent() == NULL );
- for ( auto&& iter : mImpl->roots )
+ for (auto iter = mImpl->scenes.begin(); iter != mImpl->scenes.end(); ++iter)
{
- if( ( *iter ) == layer )
+ if( (*iter) && (*iter)->root == layer )
{
- mImpl->roots.Erase( &iter );
+ mImpl->scenes.erase( iter );
break;
}
}
{
RenderTaskList* taskListPointer = taskList.Release();
taskListPointer->SetRenderMessageDispatcher( &mImpl->renderMessageDispatcher );
- mImpl->taskLists.PushBack( taskListPointer );
+
+ mImpl->scenes.back()->taskList = taskListPointer;
}
void UpdateManager::RemoveRenderTaskList( RenderTaskList* taskList )
{
- mImpl->taskLists.EraseObject( taskList );
+ for ( auto&& scene : mImpl->scenes )
+ {
+ if ( scene && scene->taskList == taskList )
+ {
+ scene->taskList.Reset();
+ break;
+ }
+ }
}
void UpdateManager::AddAnimation( OwnerPointer< SceneGraph::Animation >& animation )
void UpdateManager::ConstrainRenderTasks( BufferIndex bufferIndex )
{
// Constrain render-tasks
- for( auto taskList : mImpl->taskLists )
+ for ( auto&& scene : mImpl->scenes )
{
- RenderTaskList::RenderTaskContainer& tasks = taskList->GetTasks();
- for ( auto&& task : tasks )
+ if ( scene && scene->taskList )
{
- ConstrainPropertyOwner( *task, bufferIndex );
+ RenderTaskList::RenderTaskContainer& tasks = scene->taskList->GetTasks();
+ for ( auto&& task : tasks )
+ {
+ ConstrainPropertyOwner( *task, bufferIndex );
+ }
}
}
}
{
mImpl->nodeDirtyFlags = NodePropertyFlags::NOTHING;
- for( auto&& rootLayer : mImpl->roots )
+ for ( auto&& scene : mImpl->scenes )
{
- // Prepare resources, update shaders, for each node
- // And add the renderers to the sorted layers. Start from root, which is also a layer
- mImpl->nodeDirtyFlags |= UpdateNodeTree( *rootLayer,
- bufferIndex,
- mImpl->renderQueue );
+ if ( scene && scene->root )
+ {
+ // Prepare resources, update shaders, for each node
+ // And add the renderers to the sorted layers. Start from root, which is also a layer
+ mImpl->nodeDirtyFlags |= UpdateNodeTree( *scene->root,
+ bufferIndex,
+ mImpl->renderQueue );
+ }
}
}
ConstrainCustomObjects( bufferIndex );
//Clear the lists of renderers from the previous update
- for( auto sortedLayers : mImpl->sortedLayerLists )
+ for( auto&& scene : mImpl->scenes )
{
- for( auto&& layer : sortedLayers )
+ if ( scene )
{
- layer->ClearRenderables();
+ for( auto&& layer : scene->sortedLayerList )
+ {
+ if ( layer )
+ {
+ layer->ClearRenderables();
+ }
+ }
}
}
if( mImpl->renderersAdded )
{
// Calculate how many render tasks we have in total
- VectorBase::SizeType numberOfRenderTasks = 0;
-
- const VectorBase::SizeType taskListCount = mImpl->taskLists.Count();
- for ( VectorBase::SizeType index = 0u; index < taskListCount; index++ )
+ std::size_t numberOfRenderTasks = 0;
+ for (auto&& scene : mImpl->scenes )
{
- numberOfRenderTasks += mImpl->taskLists[index]->GetTasks().Count();
+ if ( scene && scene->taskList )
+ {
+ numberOfRenderTasks += scene->taskList->GetTasks().Count();
+ }
}
mImpl->renderInstructions.ResetAndReserve( bufferIndex,
static_cast<uint32_t>( numberOfRenderTasks ) );
- for ( VectorBase::SizeType index = 0u; index < taskListCount; index++ )
+ for ( auto&& scene : mImpl->scenes )
{
- if ( NULL != mImpl->roots[index] )
+ if ( scene && scene->root && scene->taskList )
{
keepRendererRendering |= mImpl->renderTaskProcessor.Process( bufferIndex,
- *mImpl->taskLists[index],
- *mImpl->roots[index],
- mImpl->sortedLayerLists[index],
+ *scene->taskList,
+ *scene->root,
+ scene->sortedLayerList,
mImpl->renderInstructions,
renderToFboEnabled,
isRenderingToFbo );
}
DALI_LOG_INFO( gLogFilter, Debug::General,
- "Update: numberOfRenderTasks(%d), taskListCount(%d), Render Instructions(%d)\n",
- numberOfRenderTasks, taskListCount, mImpl->renderInstructions.Count( bufferIndex ) );
+ "Update: numberOfRenderTasks(%d), Render Instructions(%d)\n",
+ numberOfRenderTasks, mImpl->renderInstructions.Count( bufferIndex ) );
}
}
- for( auto taskList : mImpl->taskLists )
+ for ( auto&& scene : mImpl->scenes )
{
- RenderTaskList::RenderTaskContainer& tasks = taskList->GetTasks();
-
- // check the countdown and notify
- bool doRenderOnceNotify = false;
- mImpl->renderTaskWaiting = false;
- for ( auto&& renderTask : tasks )
+ if ( scene && scene->root && scene->taskList )
{
- renderTask->UpdateState();
+ RenderTaskList::RenderTaskContainer& tasks = scene->taskList->GetTasks();
- if( renderTask->IsWaitingToRender() &&
- renderTask->ReadyToRender( bufferIndex ) /*avoid updating forever when source actor is off-stage*/ )
+ // check the countdown and notify
+ bool doRenderOnceNotify = false;
+ mImpl->renderTaskWaiting = false;
+ for ( auto&& renderTask : tasks )
{
- mImpl->renderTaskWaiting = true; // keep update/render threads alive
+ renderTask->UpdateState();
+
+ if( renderTask->IsWaitingToRender() &&
+ renderTask->ReadyToRender( bufferIndex ) /*avoid updating forever when source actor is off-stage*/ )
+ {
+ mImpl->renderTaskWaiting = true; // keep update/render threads alive
+ }
+
+ if( renderTask->HasRendered() )
+ {
+ doRenderOnceNotify = true;
+ }
}
- if( renderTask->HasRendered() )
+ if( doRenderOnceNotify )
{
- doRenderOnceNotify = true;
+ DALI_LOG_INFO(gRenderTaskLogFilter, Debug::General, "Notify a render task has finished\n");
+ mImpl->notificationManager.QueueCompleteNotification( scene->taskList->GetCompleteNotificationInterface() );
}
}
-
- if( doRenderOnceNotify )
- {
- DALI_LOG_INFO(gRenderTaskLogFilter, Debug::General, "Notify a render task has finished\n");
- mImpl->notificationManager.QueueCompleteNotification( taskList->GetCompleteNotificationInterface() );
- }
}
// Macro is undefined in release build.
void UpdateManager::SetLayerDepths( const SortedLayerPointers& layers, const Layer* rootLayer )
{
- const VectorBase::SizeType rootCount = mImpl->roots.Count();
-
- // Make sure we reserve the correct size for the container so that
- // we can save the sorted layers in the same order as the root layer
- mImpl->sortedLayerLists.resize( rootCount );
-
- for ( VectorBase::SizeType rootIndex = 0u; rootIndex < rootCount; rootIndex++ )
+ for ( auto&& scene : mImpl->scenes )
{
- Layer* root = mImpl->roots[rootIndex];
- if ( root == rootLayer )
+ if ( scene && scene->root == rootLayer )
{
- mImpl->sortedLayerLists[rootIndex] = layers;
+ scene->sortedLayerList = layers;
break;
}
}
iter.node->SetDepthIndex( iter.sortedDepth );
}
- for( auto root : mImpl->roots )
+ for ( auto&& scene : mImpl->scenes )
{
- // Go through node hierarchy and rearrange siblings according to depth-index
- SortSiblingNodesRecursively( *root );
+ if ( scene )
+ {
+ // Go through node hierarchy and rearrange siblings according to depth-index
+ SortSiblingNodesRecursively( *scene->root );
+ }
}
}
#include <string>
#include <cstdio>
+#if defined(BACKTRACE_ENABLED)
+#if defined(__GLIBC__)
#include <execinfo.h>
+#endif
#include <cxxabi.h>
-
+#endif
#include <cstring>
// INTERNAL INCLUDES
const uint32_t CORE_MAJOR_VERSION = 1;
const uint32_t CORE_MINOR_VERSION = 4;
-const uint32_t CORE_MICRO_VERSION = 26;
+const uint32_t CORE_MICRO_VERSION = 27;
const char * const CORE_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali
Summary: DALi 3D Engine
-Version: 1.4.26
+Version: 1.4.27
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT