/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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 oss.str();
}
+std::string GetWChan(int pid)
+{
+ std::ostringstream procwchan;
+ procwchan << "/proc/" << pid << "/wchan";
+ std::ifstream ifs;
+ ifs.open(procwchan.str(), std::ifstream::in);
+ std::string line;
+ std::getline(ifs, line);
+ ifs.close();
+ return line;
+}
+
std::string ReadAndEscape(std::string filename)
{
std::ostringstream os;
for(auto& tc : children)
{
std::chrono::steady_clock::duration timeSpan = endTime - tc.second.startTime;
- std::chrono::duration<double> seconds = std::chrono::duration_cast<std::chrono::duration<double>>(timeSpan);
- if(seconds.count() > MAXIMUM_CHILD_LIFETIME)
+ double seconds = double(timeSpan.count()) * std::chrono::steady_clock::period::num / std::chrono::steady_clock::period::den;
+
+ if(seconds > MAXIMUM_CHILD_LIFETIME)
{
// Kill the child process. A subsequent call to waitpid will process signal result below.
- kill(tc.first, SIGKILL);
+ if(!tc.second.finished)
+ {
+ printf("Child process %s WCHAN:%s\n", tc.second.name, GetWChan(tc.first).c_str());
+ kill(tc.first, SIGKILL);
+ tc.second.finished = true; // Only send kill signal once.
+ }
}
}
}
{
if(WIFEXITED(status))
{
- auto& testCase = children[childPid];
- testCase.result = WEXITSTATUS(status);
+ auto& testCase = children[childPid];
+ testCase.result = WEXITSTATUS(status);
+ testCase.finished = true;
if(testCase.result)
{
printf("Test case %s failed: %d\n", testCase.name, testCase.result);
RunningTestCases::iterator iter = children.find(childPid);
if(iter != children.end())
{
+ iter->second.finished = true;
printf("Test case %s exited with signal %s\n", iter->second.name, strsignal(status));
iter->second.result = 1;
failedTestCases.push_back(iter->second.testCase);
#define TEST_HARNESS_H
/*
- * Copyright (c) 2020 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
const char* name;
std::chrono::steady_clock::time_point startTime;
std::chrono::system_clock::time_point startSystemTime;
- int32_t result;
+ int32_t result{0};
pid_t childPid{0};
testcase* tctPtr;
+ bool finished{false};
TestCase(int32_t index, testcase* testCase)
: testCase(index),
END_TEST;
}
+
+int UtcDaliSceneGetOverlayLayer(void)
+{
+ TestApplication application;
+ tet_infoline("Testing Dali::Integration::Scene::GetOverlayLayer");
+
+ Dali::Integration::Scene scene = application.GetScene();
+
+ // Check we get a valid instance.
+ RenderTaskList tasks = scene.GetRenderTaskList();
+
+ // There should be 1 task by default.
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 1u, TEST_LOCATION);
+ RenderTask defaultTask = tasks.GetTask(0u);
+ DALI_TEST_EQUALS(scene.GetRootLayer(), defaultTask.GetSourceActor(), TEST_LOCATION);
+
+ Layer layer = scene.GetOverlayLayer();
+ // There should be 2 task by default.
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 2u, TEST_LOCATION);
+ RenderTask overlayTask = tasks.GetTask(1u);
+ DALI_TEST_EQUALS(overlayTask, tasks.GetOverlayTask(), TEST_LOCATION);
+ DALI_TEST_CHECK(scene.GetRootLayer() != overlayTask.GetSourceActor());
+ DALI_TEST_CHECK(overlayTask != defaultTask);
+ DALI_TEST_EQUALS(overlayTask.GetClearEnabled(), false, TEST_LOCATION);
+ DALI_TEST_EQUALS(overlayTask.IsExclusive(), true, TEST_LOCATION);
+
+ // If new render task is created, the last task is overlayTask
+ RenderTask newTask = scene.GetRenderTaskList().CreateTask();
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 3u, TEST_LOCATION);
+ DALI_TEST_EQUALS(newTask, tasks.GetTask(1u), TEST_LOCATION);
+ DALI_TEST_EQUALS(overlayTask, tasks.GetTask(2u), TEST_LOCATION);
+
+ // Render
+ application.SendNotification();
+ application.Render();
+
+ tasks.RemoveTask(overlayTask);
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 2u, TEST_LOCATION);
+ DALI_TEST_EQUALS(tasks.GetTask(0u), defaultTask, TEST_LOCATION);
+ DALI_TEST_EQUALS(tasks.GetTask(1u), newTask, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliSceneSurfaceResizedWithOverlayLayer(void)
+{
+ tet_infoline("Ensure resizing of the surface is handled properly");
+
+ TestApplication application;
+
+ auto scene = application.GetScene();
+ DALI_TEST_CHECK(scene);
+
+ const RenderTaskList& tasks = scene.GetRenderTaskList();
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 1u, TEST_LOCATION);
+ RenderTask defaultTask = tasks.GetTask(0u);
+ DALI_TEST_EQUALS(scene.GetRootLayer(), defaultTask.GetSourceActor(), TEST_LOCATION);
+
+ // Ensure stage size matches the scene size
+ auto stage = Stage::GetCurrent();
+ Vector2 sceneSize = stage.GetSize();
+ Viewport sceneViewport(0, 0, sceneSize.x, sceneSize.y);
+ DALI_TEST_EQUALS(stage.GetSize(), scene.GetSize(), TEST_LOCATION);
+ Viewport defaultViewport = defaultTask.GetViewport();
+ DALI_TEST_EQUALS(defaultViewport, sceneViewport, TEST_LOCATION);
+
+ Layer layer = scene.GetOverlayLayer();
+ // There should be 2 task by default.
+ DALI_TEST_EQUALS(tasks.GetTaskCount(), 2u, TEST_LOCATION);
+ RenderTask overlayTask = tasks.GetTask(1u);
+ Viewport overlayViewport = defaultTask.GetViewport();
+ DALI_TEST_EQUALS(defaultViewport, overlayViewport, TEST_LOCATION);
+
+ // Resize the scene
+ Vector2 newSize(1000.0f, 2000.0f);
+ DALI_TEST_CHECK(stage.GetSize() != newSize);
+ scene.SurfaceResized(newSize.width, newSize.height);
+ Viewport newViewport(0, 0, newSize.x, newSize.y);
+ DALI_TEST_EQUALS(newViewport, defaultTask.GetViewport(), TEST_LOCATION);
+ DALI_TEST_EQUALS(newViewport, defaultTask.GetViewport(), TEST_LOCATION);
+
+ END_TEST;
+}
return GetImplementation(*this).GetRootLayer();
}
+Layer Scene::GetOverlayLayer()
+{
+ return GetImplementation(*this).GetOverlayLayer();
+}
+
uint32_t Scene::GetLayerCount() const
{
return GetImplementation(*this).GetLayerCount();
Layer GetRootLayer() const;
/**
+ * @brief Returns the Scene's Overlay Layer.
+ * If there is no overlay layer yet, this creates the layer and an associated render task.
+ *
+ * @return The overlay layer
+ */
+ Layer GetOverlayLayer();
+
+ /**
* @brief Queries the number of on-stage layers.
*
* Note that a default layer is always provided (count >= 1).
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
Actor* parentActor = static_cast<Actor*>(parent);
mScene = parentActor->mScene;
- if(EventThreadServices::IsCoreRunning() && // Don't emit signals or send messages during Core destruction
+ if(!EventThreadServices::IsShuttingDown() && // Don't emit signals or send messages during Core destruction
parentActor->OnScene())
{
// Instruct each actor to create a corresponding node in the scene graph
mParent = nullptr;
- if(EventThreadServices::IsCoreRunning() && // Don't emit signals or send messages during Core destruction
+ if(!EventThreadServices::IsShuttingDown() && // Don't emit signals or send messages during Core destruction
OnScene())
{
// Disconnect the Node & its children from the scene-graph.
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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 ThreadLocalStorage::Created();
}
+bool EventThreadServices::IsShuttingDown()
+{
+ return ThreadLocalStorage::IsShuttingDown();
+}
+
} // namespace Internal
} // namespace Dali
#define DALI_INTERNAL_EVENT_THREAD_SERVICES_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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 true if core is still running and we can send messages
+ * @note It returns false if it is called from a thread other than the main thread.
*/
static bool IsCoreRunning();
+
+ /**
+ * @brief Check if the event thread service is shutting down.
+ *
+ * @return true if the event thread service is shutting down.
+ * @note It returns false if the core hasn't been initialised yet.
+ */
+ static bool IsShuttingDown();
};
} // namespace Internal
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
#include <dali/internal/event/actors/actor-impl.h>
#include <dali/internal/event/common/object-impl.h>
#include <dali/internal/event/common/property-notification-manager.h>
-#include <dali/internal/event/common/stage-impl.h>
#include <dali/internal/event/common/thread-local-storage.h>
#include <dali/internal/update/common/scene-graph-property-notification.h>
#include <dali/internal/update/manager/update-manager.h>
Disable();
// Guard to disallow use of PropertyNotificationManager after Core has been destroyed
- if(Stage::IsInstalled())
+ if(!EventThreadServices::IsShuttingDown())
{
// Disconnect from the property notification manager
mPropertyNotificationManager.PropertyNotificationDestroyed(*this);
void PropertyNotification::Disable()
{
// Guard to allow handle destruction after Core has been destroyed
- if(Stage::IsInstalled())
+ if(!EventThreadServices::IsShuttingDown())
{
// Stop scene-graph from monitoring the target's properties.
DestroySceneObject();
{
if(mPropertyNotification != nullptr)
{
+ DALI_ASSERT_ALWAYS(EventThreadServices::IsCoreRunning());
+
// Remove PropertyNotification using a message to the update manager
RemovePropertyNotificationMessage(mUpdateManager, *mPropertyNotification);
mPropertyNotification = nullptr;
mRootLayer.Reset();
}
+ if(mOverlayLayer)
+ {
+ mOverlayLayer.Reset();
+ }
+
if(mRenderTaskList)
{
mRenderTaskList.Reset();
return Dali::Layer(mRootLayer.Get());
}
+Dali::Layer Scene::GetOverlayLayer()
+{
+ if(!mOverlayLayer)
+ {
+ // Creates overlay layer.
+ mOverlayLayer = Layer::New();
+ mOverlayLayer->SetName("OverlayLayer");
+ mOverlayLayer->SetResizePolicy(ResizePolicy::FILL_TO_PARENT, Dimension::ALL_DIMENSIONS);
+ mOverlayLayer->SetParentOrigin(Dali::ParentOrigin::TOP_LEFT);
+ mOverlayLayer->SetAnchorPoint(Dali::AnchorPoint::TOP_LEFT);
+ mRootLayer->Add(*mOverlayLayer);
+
+ // Create the overlay render-task and set exclusive to true.
+ RenderTaskPtr renderTask = mRenderTaskList->CreateOverlayTask(mOverlayLayer.Get(), mDefaultCamera.Get());
+ renderTask->SetExclusive(true);
+ renderTask->SetInputEnabled(true);
+ }
+ return Dali::Layer(mOverlayLayer.Get());
+}
+
LayerList& Scene::GetLayerList() const
{
return *mLayerList;
// set default render-task viewport parameters
RenderTaskPtr defaultRenderTask = mRenderTaskList->GetTask(0u);
defaultRenderTask->SetViewport(newSize);
+ // set overlay render-task viewport parameters
+ RenderTaskPtr overlayRenderTask = mRenderTaskList->GetOverlayTask();
+ if(overlayRenderTask)
+ {
+ overlayRenderTask->SetViewport(newSize);
+ }
}
bool Scene::IsSurfaceRectChanged() const
Dali::Layer GetRootLayer() const;
/**
+ * @copydoc Dali::Integration::Scene::GetOverlayLayer
+ */
+ Dali::Layer GetOverlayLayer();
+
+ /**
* @copydoc Dali::Integration::Scene::GetLayerCount
*/
uint32_t GetLayerCount() const;
LayerPtr mRootLayer;
+ LayerPtr mOverlayLayer;
+
// Ordered list of currently on-stage layers
OwnerPointer<LayerList> mLayerList;
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
{
namespace
{
-thread_local ThreadLocalStorage* threadLocal = nullptr;
-}
+thread_local ThreadLocalStorage* threadLocal = nullptr;
+thread_local bool isShuttingDown = false;
+} // namespace
ThreadLocalStorage::ThreadLocalStorage(Core* core)
: mCore(core)
{
DALI_ASSERT_ALWAYS(threadLocal == nullptr && "Cannot create more than one ThreadLocalStorage object");
- threadLocal = this;
+ threadLocal = this;
+ isShuttingDown = false;
}
ThreadLocalStorage::~ThreadLocalStorage() = default;
void ThreadLocalStorage::Remove()
{
- threadLocal = nullptr;
+ threadLocal = nullptr;
+ isShuttingDown = true;
}
ThreadLocalStorage& ThreadLocalStorage::Get()
return (threadLocal != nullptr);
}
+bool ThreadLocalStorage::IsShuttingDown()
+{
+ return isShuttingDown;
+}
+
ThreadLocalStorage* ThreadLocalStorage::GetInternal()
{
return threadLocal;
#define DALI_INTERNAL_THREAD_LOCAL_STORAGE_H
/*
- * Copyright (c) 2021 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2023 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.
static bool Created();
/**
+ * Checks if the system is shutting down
+ * @return true if the system is shutting down
+ * @note It returns false if the core hasn't been initialised yet.
+ */
+ static bool IsShuttingDown();
+
+ /**
* Get a pointer to the TLS or NULL if not initialized
* @return pointer to the TLS
*/
{
namespace Internal
{
+
RenderTaskListPtr RenderTaskList::New()
{
RenderTaskListPtr taskList = new RenderTaskList();
RenderTaskPtr RenderTaskList::CreateTask(Actor* sourceActor, CameraActor* cameraActor)
{
RenderTaskPtr task = RenderTask::New(sourceActor, cameraActor, *this);
-
- mTasks.push_back(task);
+ if(mOverlayRenderTask && mTasks.back() == mOverlayRenderTask)
+ {
+ mTasks.insert(mTasks.end() - 1, task);
+ }
+ else
+ {
+ mTasks.push_back(task);
+ }
return task;
}
+RenderTaskPtr RenderTaskList::CreateOverlayTask(Actor* sourceActor, CameraActor* cameraActor)
+{
+ if(!mOverlayRenderTask)
+ {
+ mOverlayRenderTask = CreateTask(sourceActor, &mDefaults.GetDefaultCameraActor());
+ }
+ return mOverlayRenderTask;
+}
+
void RenderTaskList::RemoveTask(Internal::RenderTask& task)
{
for(RenderTaskContainer::iterator iter = mTasks.begin(); mTasks.end() != iter; ++iter)
// send a message to remove the scene-graph RenderTask
RemoveTaskMessage(mEventThreadServices, *mSceneObject, sceneObject);
- for(auto exclusiveIt = mExclusives.begin(); exclusiveIt != mExclusives.end(); ++exclusiveIt)
+ Exclusive exclusive{ptr, ActorObserver()};
+ ExclusivesContainer::iterator exclusiveIter = find(mExclusives.begin(), mExclusives.end(), exclusive);
+ if(exclusiveIter != mExclusives.end())
{
- if(exclusiveIt->renderTaskPtr == ptr)
- {
- mExclusives.erase(exclusiveIt);
- break;
- }
+ mExclusives.erase(exclusiveIter);
}
break; // we're finished
}
return mTasks[index];
}
+RenderTaskPtr RenderTaskList::GetOverlayTask() const
+{
+ RenderTaskPtr overlayRenderTask;
+ if(mOverlayRenderTask)
+ {
+ overlayRenderTask = mOverlayRenderTask;
+ }
+ return overlayRenderTask;
+}
+
void RenderTaskList::SetExclusive(RenderTask* task, bool exclusive)
{
// Check to see if this rendertask has an entry?
{
RenderTask* renderTaskPtr; ///< Pointer for comparison with current rendertask.
ActorObserver actor; ///< For comparison with current actor.
+
+ bool operator==(const Exclusive& other) const
+ {
+ return renderTaskPtr == other.renderTaskPtr;
+ }
};
using ExclusivesContainer = std::vector<Exclusive>;
+ using ExclusiveIter = ExclusivesContainer::iterator;
/**
* Create a RenderTaskList.
RenderTaskPtr CreateTask(Actor* sourceActor, CameraActor* cameraActor);
/**
+ * @brief Creates a new RenderTask for overlay.
+ * This will be appended to the end of render-task list.
+ * @param[in] sourceActor The actor and its children to be rendered for this render task.
+ * @param[in] cameraActor The actor from which the scene is viewed for this render task.
+ * @return A valid handle to a new overlay RenderTask
+ * @note The Overlay RenderTask will be rendered after all the other render tasks are rendered.
+ */
+ RenderTaskPtr CreateOverlayTask(Actor* sourceActor, CameraActor* cameraActor);
+
+ /**
* @copydoc Dali::RenderTaskList::RemoveTask()
*/
void RemoveTask(Internal::RenderTask& task);
RenderTaskPtr GetTask(uint32_t index) const;
/**
+ * @copydoc Dali::RenderTaskList::GetOverlayTask()
+ */
+ RenderTaskPtr GetOverlayTask() const;
+
+ /**
* Retrieve the container of render-tasks.
* @return The container.
*/
RenderTaskContainer mTasks; ///< Reference counted render-tasks
ExclusivesContainer mExclusives; ///< List of rendertasks with exclusively owned source actors.
+ RenderTaskPtr mOverlayRenderTask{nullptr};
};
} // namespace Internal
RenderTaskList::RenderTaskList()
: mNotificationObject(nullptr),
- mRenderMessageDispatcher(nullptr)
+ mRenderMessageDispatcher(nullptr),
+ mOverlayRenderTask(nullptr)
{
}
DALI_ASSERT_DEBUG(mRenderMessageDispatcher != NULL && "RenderMessageDispatcher is null");
newTask->Initialize(*mRenderMessageDispatcher);
- // mRenderTasks container takes ownership
- mRenderTasks.PushBack(newTask.Release());
+
+ if(mOverlayRenderTask && mRenderTasks[mRenderTasks.Size() - 1] == mOverlayRenderTask)
+ {
+ mRenderTasks.Insert(mRenderTasks.End() - 1, newTask.Release());
+ }
+ else
+ {
+ mRenderTasks.PushBack(newTask.Release());
+ }
+}
+
+void RenderTaskList::AddOverlayTask(OwnerPointer<RenderTask>& newTask)
+{
+ AddTask(newTask);
+ mOverlayRenderTask = mRenderTasks[mRenderTasks.Size() - 1];
}
void RenderTaskList::RemoveTask(RenderTask* task)
void AddTask(OwnerPointer<RenderTask>& newTask);
/**
+ * Add a overlay RenderTask to the list.
+ * @param[in] newTask The RenderTaskList takes ownership of this overlay task.
+ */
+ void AddOverlayTask(OwnerPointer<RenderTask>& newTask);
+
+ /**
* Remove a RenderTask from the list.
* @param[in] task The RenderTaskList will destroy this task.
*/
CompleteNotificationInterface* mNotificationObject; ///< object to pass in to the complete notification
RenderMessageDispatcher* mRenderMessageDispatcher; ///< for sending messages to render thread
RenderTaskContainer mRenderTasks; ///< A container of owned RenderTasks
+ RenderTask* mOverlayRenderTask; ///< OverlayRenderTask.
};
// Messages for RenderTaskList
{
const uint32_t CORE_MAJOR_VERSION = 2;
const uint32_t CORE_MINOR_VERSION = 2;
-const uint32_t CORE_MICRO_VERSION = 9;
+const uint32_t CORE_MICRO_VERSION = 10;
const char* const CORE_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
return RenderTask(GetImplementation(*this).GetTask(index).Get());
}
+RenderTask RenderTaskList::GetOverlayTask() const
+{
+ return RenderTask(GetImplementation(*this).GetOverlayTask().Get());
+}
+
RenderTaskList::RenderTaskList(Internal::RenderTaskList* internal)
: BaseHandle(internal)
{
*/
RenderTask GetTask(uint32_t index) const;
+ /**
+ * @brief Retrieves a RenderTask for Overlay
+ * @SINCE_2_2.10
+ * @return A handle to the overlay RenderTask.
+ * If the scene has not created an overlay render task, this returns empty handle.
+ */
+ RenderTask GetOverlayTask() const;
+
public: // Not intended for application developers
/// @cond internal
/**
Name: dali2
Summary: DALi 3D Engine
-Version: 2.2.9
+Version: 2.2.10
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT