utc-Dali-Matrix3.cpp
utc-Dali-MeshMaterial.cpp
utc-Dali-Mutex.cpp
+ utc-Dali-Semaphore.cpp
utc-Dali-ObjectRegistry.cpp
utc-Dali-PanGesture.cpp
utc-Dali-PanGestureDetector.cpp
DALI_TEST_ASSERT(e, assertstring, TEST_LOCATION); \
}
+/**
+ * Test that given piece of code triggers an exception
+ * Fails the test if the exception didn't occur.
+ * Turns off logging during the execution of the code to avoid excessive false positive log output from the assertions
+ * @param expressions code to execute
+ * @param except the exception expected in the assert
+ */
+#define DALI_TEST_THROWS(expressions, except) \
+ try \
+ { \
+ TestApplication::EnableLogging(false); \
+ expressions; \
+ TestApplication::EnableLogging(true); \
+ fprintf(stderr, "Test failed in %s, expected exception: '%s' didn't occur\n", __FILELINE__, #except); \
+ tet_result(TET_FAIL); \
+ throw("TET_FAIL"); \
+ } \
+ catch(except &) \
+ { \
+ tet_result(TET_PASS); \
+ } \
+ catch(...) \
+ { \
+ fprintf(stderr, "Test failed in %s, unexpected exception\n", __FILELINE__); \
+ tet_result(TET_FAIL); \
+ throw; \
+ }
+
// Functor to test whether an Applied signal is emitted
struct ConstraintAppliedCheck
{
END_TEST;
}
+#define CLIPPING_RECT_X (16)
+#define CLIPPING_RECT_Y (768)
+#define CLIPPING_RECT_WIDTH (32)
+#define CLIPPING_RECT_HEIGHT (32)
+
+int UtcDaliSceneSurfaceRotatedWithAngle0(void)
+{
+ tet_infoline("Ensure rotation of the surface is handled properly with Angle 0");
+
+ TestApplication application(
+ TestApplication::DEFAULT_SURFACE_WIDTH,
+ TestApplication::DEFAULT_SURFACE_HEIGHT,
+ TestApplication::DEFAULT_HORIZONTAL_DPI,
+ TestApplication::DEFAULT_VERTICAL_DPI,
+ true,
+ true);
+
+ const TestGlAbstraction::ScissorParams& glScissorParams(application.GetGlAbstraction().GetScissorParams());
+
+ std::vector<Rect<int>> damagedRects;
+ Rect<int> clippingRect;
+ application.SendNotification();
+ application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+
+ DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION);
+ application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+ Actor actor = CreateRenderableActor();
+ actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ actor.SetProperty(Actor::Property::POSITION, Vector3(16.0f, 16.0f, 0.0f));
+ actor.SetProperty(Actor::Property::SIZE, Vector3(16.0f, 16.0f, 0.0f));
+ actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+
+ damagedRects.clear();
+ application.GetScene().SurfaceRotated(TestApplication::DEFAULT_SURFACE_WIDTH,
+ TestApplication::DEFAULT_SURFACE_HEIGHT, 0);
+ application.SendNotification();
+ application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+ DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+
+ clippingRect = Rect<int>(CLIPPING_RECT_X, CLIPPING_RECT_Y, CLIPPING_RECT_WIDTH, CLIPPING_RECT_HEIGHT); // in screen coordinates, includes 3 last frames updates
+ DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+ application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+ DALI_TEST_EQUALS(clippingRect.x, glScissorParams.x, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.y, glScissorParams.y, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.width, glScissorParams.width, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.height, glScissorParams.height, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliSceneSurfaceRotatedWithAngle90(void)
+{
+ tet_infoline("Ensure rotation of the surface is handled properly with Angle 90");
+
+ TestApplication application(
+ TestApplication::DEFAULT_SURFACE_WIDTH,
+ TestApplication::DEFAULT_SURFACE_HEIGHT,
+ TestApplication::DEFAULT_HORIZONTAL_DPI,
+ TestApplication::DEFAULT_VERTICAL_DPI,
+ true,
+ true);
+
+ const TestGlAbstraction::ScissorParams& glScissorParams(application.GetGlAbstraction().GetScissorParams());
+
+ std::vector<Rect<int>> damagedRects;
+ Rect<int> clippingRect;
+ application.SendNotification();
+ application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+
+ DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION);
+ application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+ Actor actor = CreateRenderableActor();
+ actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ actor.SetProperty(Actor::Property::POSITION, Vector3(16.0f, 16.0f, 0.0f));
+ actor.SetProperty(Actor::Property::SIZE, Vector3(16.0f, 16.0f, 0.0f));
+ actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+
+ damagedRects.clear();
+ application.GetScene().SurfaceRotated(TestApplication::DEFAULT_SURFACE_WIDTH,
+ TestApplication::DEFAULT_SURFACE_HEIGHT, 90);
+ application.SendNotification();
+ application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+ DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+
+ clippingRect = Rect<int>(CLIPPING_RECT_X, CLIPPING_RECT_Y, CLIPPING_RECT_WIDTH, CLIPPING_RECT_HEIGHT); // in screen coordinates, includes 3 last frames updates
+ DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+ application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+ // It is recalculation for glScissor.
+ // Because surface is rotated and glScissor is called with recalcurated value.
+ clippingRect.x = TestApplication::DEFAULT_SURFACE_HEIGHT - (CLIPPING_RECT_Y + CLIPPING_RECT_HEIGHT);
+ clippingRect.y = CLIPPING_RECT_X;
+ clippingRect.width = CLIPPING_RECT_HEIGHT;
+ clippingRect.height = CLIPPING_RECT_WIDTH;
+
+ DALI_TEST_EQUALS(clippingRect.x, glScissorParams.x, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.y, glScissorParams.y, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.width, glScissorParams.width, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.height, glScissorParams.height, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliSceneSurfaceRotatedWithAngle180(void)
+{
+ tet_infoline("Ensure rotation of the surface is handled properly with Angle 180");
+
+ TestApplication application(
+ TestApplication::DEFAULT_SURFACE_WIDTH,
+ TestApplication::DEFAULT_SURFACE_HEIGHT,
+ TestApplication::DEFAULT_HORIZONTAL_DPI,
+ TestApplication::DEFAULT_VERTICAL_DPI,
+ true,
+ true);
+
+ const TestGlAbstraction::ScissorParams& glScissorParams(application.GetGlAbstraction().GetScissorParams());
+
+ std::vector<Rect<int>> damagedRects;
+ Rect<int> clippingRect;
+ application.SendNotification();
+ application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+
+ DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION);
+ application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+ Actor actor = CreateRenderableActor();
+ actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ actor.SetProperty(Actor::Property::POSITION, Vector3(16.0f, 16.0f, 0.0f));
+ actor.SetProperty(Actor::Property::SIZE, Vector3(16.0f, 16.0f, 0.0f));
+ actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+
+ damagedRects.clear();
+ application.GetScene().SurfaceRotated(TestApplication::DEFAULT_SURFACE_WIDTH,
+ TestApplication::DEFAULT_SURFACE_HEIGHT, 180);
+ application.SendNotification();
+ application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+ DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+
+ clippingRect = Rect<int>(CLIPPING_RECT_X, CLIPPING_RECT_Y, CLIPPING_RECT_WIDTH, CLIPPING_RECT_HEIGHT); // in screen coordinates, includes 3 last frames updates
+ DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+ application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+ // It is recalculation for glScissor.
+ // Because surface is rotated and glScissor is called with recalcurated value.
+ clippingRect.x = TestApplication::DEFAULT_SURFACE_WIDTH - (CLIPPING_RECT_X + CLIPPING_RECT_WIDTH);
+ clippingRect.y = TestApplication::DEFAULT_SURFACE_HEIGHT - (CLIPPING_RECT_Y +CLIPPING_RECT_HEIGHT);
+ clippingRect.width = CLIPPING_RECT_WIDTH;
+ clippingRect.height = CLIPPING_RECT_HEIGHT;
+
+ DALI_TEST_EQUALS(clippingRect.x, glScissorParams.x, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.y, glScissorParams.y, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.width, glScissorParams.width, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.height, glScissorParams.height, TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliSceneSurfaceRotatedWithAngle270(void)
+{
+ tet_infoline("Ensure rotation of the surface is handled properly with Angle 270");
+
+ TestApplication application(
+ TestApplication::DEFAULT_SURFACE_WIDTH,
+ TestApplication::DEFAULT_SURFACE_HEIGHT,
+ TestApplication::DEFAULT_HORIZONTAL_DPI,
+ TestApplication::DEFAULT_VERTICAL_DPI,
+ true,
+ true);
+
+ const TestGlAbstraction::ScissorParams& glScissorParams(application.GetGlAbstraction().GetScissorParams());
+
+ std::vector<Rect<int>> damagedRects;
+ Rect<int> clippingRect;
+ application.SendNotification();
+ application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+
+ DALI_TEST_EQUALS(damagedRects.size(), 0, TEST_LOCATION);
+ application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+ Actor actor = CreateRenderableActor();
+ actor.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT);
+ actor.SetProperty(Actor::Property::POSITION, Vector3(16.0f, 16.0f, 0.0f));
+ actor.SetProperty(Actor::Property::SIZE, Vector3(16.0f, 16.0f, 0.0f));
+ actor.SetResizePolicy(ResizePolicy::FIXED, Dimension::ALL_DIMENSIONS);
+ application.GetScene().Add(actor);
+
+ application.SendNotification();
+
+ damagedRects.clear();
+ application.GetScene().SurfaceRotated(TestApplication::DEFAULT_SURFACE_WIDTH,
+ TestApplication::DEFAULT_SURFACE_HEIGHT, 270);
+ application.SendNotification();
+ application.PreRenderWithPartialUpdate(TestApplication::RENDER_FRAME_INTERVAL, nullptr, damagedRects);
+ DALI_TEST_EQUALS(damagedRects.size(), 1, TEST_LOCATION);
+
+ clippingRect = Rect<int>(CLIPPING_RECT_X, CLIPPING_RECT_Y, CLIPPING_RECT_WIDTH, CLIPPING_RECT_HEIGHT); // in screen coordinates, includes 3 last frames updates
+ DALI_TEST_EQUALS<Rect<int>>(clippingRect, damagedRects[0], TEST_LOCATION);
+ application.RenderWithPartialUpdate(damagedRects, clippingRect);
+
+ // It is recalculation for glScissor.
+ // Because surface is rotated and glScissor is called with recalcurated value.
+ clippingRect.x = CLIPPING_RECT_Y;
+ clippingRect.y = TestApplication::DEFAULT_SURFACE_WIDTH - (CLIPPING_RECT_X + CLIPPING_RECT_WIDTH);
+ clippingRect.width = CLIPPING_RECT_HEIGHT;
+ clippingRect.height = CLIPPING_RECT_WIDTH;
+
+ DALI_TEST_EQUALS(clippingRect.x, glScissorParams.x, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.y, glScissorParams.y, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.width, glScissorParams.width, TEST_LOCATION);
+ DALI_TEST_EQUALS(clippingRect.height, glScissorParams.height, TEST_LOCATION);
+
+ END_TEST;
+}
+
int UtcDaliSceneKeyEventGeneratedSignalP(void)
{
TestApplication application;
--- /dev/null
+/*
+ * Copyright (c) 2020 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 <dali-test-suite-utils.h>
+#include <dali/devel-api/threading/semaphore.h>
+#include <dali/public-api/dali-core.h>
+#include <algorithm>
+#include <chrono>
+#include <stdexcept>
+#include <thread>
+#include <future>
+
+int UtcDaliSemaphoreTryAcquire(void)
+{
+ using namespace std::chrono_literals;
+ constexpr auto waitTime{100ms};
+
+ tet_infoline("Testing Dali::Semaphore try acquire methods");
+ Dali::Semaphore<3> sem(0);
+
+ DALI_TEST_EQUALS(false, sem.TryAcquire(), TEST_LOCATION);
+ DALI_TEST_EQUALS(false, sem.TryAcquireFor(waitTime), TEST_LOCATION);
+ DALI_TEST_EQUALS(false, sem.TryAcquireUntil(std::chrono::system_clock::now() + waitTime), TEST_LOCATION);
+
+ sem.Release(3);
+
+ DALI_TEST_EQUALS(true, sem.TryAcquire(), TEST_LOCATION);
+ DALI_TEST_EQUALS(true, sem.TryAcquireFor(waitTime), TEST_LOCATION);
+ DALI_TEST_EQUALS(true, sem.TryAcquireUntil(std::chrono::system_clock::now() + waitTime), TEST_LOCATION);
+
+ DALI_TEST_EQUALS(false, sem.TryAcquire(), TEST_LOCATION);
+ DALI_TEST_EQUALS(false, sem.TryAcquireFor(waitTime), TEST_LOCATION);
+ DALI_TEST_EQUALS(false, sem.TryAcquireUntil(std::chrono::system_clock::now() + waitTime), TEST_LOCATION);
+
+ END_TEST;
+}
+
+int UtcDaliSemaphoreInvalidArguments(void)
+{
+ tet_infoline("Testing Dali::Semaphore invalid arguments");
+
+ Dali::Semaphore<2> sem(0);
+
+ DALI_TEST_THROWS(sem.Release(3), std::invalid_argument);
+ DALI_TEST_THROWS(sem.Release(-1), std::invalid_argument);
+ sem.Release(1);
+ DALI_TEST_THROWS(sem.Release(2), std::invalid_argument);
+ sem.Release(1);
+ DALI_TEST_THROWS(sem.Release(1), std::invalid_argument);
+
+ DALI_TEST_THROWS(Dali::Semaphore<1>(2), std::invalid_argument);
+ DALI_TEST_THROWS(Dali::Semaphore<>(-1), std::invalid_argument);
+
+ END_TEST;
+}
+
+int UtcDaliSemaphoreAcquire(void)
+{
+ tet_infoline("Testing Dali::Semaphore multithread acquire");
+
+ using namespace std::chrono_literals;
+
+ constexpr std::ptrdiff_t numTasks{2};
+
+ auto f = [](Dali::Semaphore<numTasks> &sem, bool &flag)
+ {
+ sem.Acquire();
+ flag = true;
+ };
+
+ auto flag1{false}, flag2{false};
+ Dali::Semaphore<numTasks> sem(0);
+
+ auto fut1 = std::async(std::launch::async, f, std::ref(sem), std::ref(flag1));
+ auto fut2 = std::async(std::launch::async, f, std::ref(sem), std::ref(flag2));
+
+ DALI_TEST_EQUALS(std::future_status::timeout, fut1.wait_for(100ms), TEST_LOCATION);
+ DALI_TEST_EQUALS(std::future_status::timeout, fut2.wait_for(100ms), TEST_LOCATION);
+ DALI_TEST_EQUALS(false, flag1, TEST_LOCATION);
+ DALI_TEST_EQUALS(false, flag2, TEST_LOCATION);
+ sem.Release(numTasks);
+ fut1.wait();
+ DALI_TEST_EQUALS(true, flag1, TEST_LOCATION);
+ fut2.wait();
+ DALI_TEST_EQUALS(true, flag2, TEST_LOCATION);
+
+ END_TEST;
+}
SET( 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/semaphore.h
${devel_api_src_dir}/threading/thread.h
${devel_api_src_dir}/threading/thread-pool.h
)
--- /dev/null
+#pragma once
+
+/*
+ * Copyright (c) 2020 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 <mutex>
+#include <condition_variable>
+#include <stdexcept>
+#include <sstream>
+#include <limits>
+
+namespace Dali
+{
+/**
+ * @brief Class that implements a C++20 counting_semaphore like interface
+ */
+template<std::ptrdiff_t LeastMaxValue = std::numeric_limits<std::ptrdiff_t>::max()>
+class Semaphore
+{
+public:
+ /**
+ * @brief Returns the internal counter's maximum possible value,
+ * which is greater than or equal to LeastMaxValue.
+ *
+ * @return the maximum value of the semaphore
+ */
+ static constexpr std::ptrdiff_t Max() noexcept
+ {
+ return LeastMaxValue;
+ }
+
+ /**
+ * @brief class constructor
+ *
+ * @param[in] desired the desired initial value of the semaphore
+ */
+ explicit Semaphore(std::ptrdiff_t desired)
+ : mCount(desired)
+ {
+ if (mCount < 0 || mCount > Max())
+ {
+ ThrowInvalidParamException(desired);
+ }
+ }
+
+ /**
+ * @brief Atomically increments the internal counter by the value of update.
+ *
+ * Any thread waiting for the counter to be greater than 0 will subsequently
+ * be unlocked.
+ *
+ * @param[in] update value to increment the semaphore
+ */
+ void Release(std::ptrdiff_t update = 1)
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (update < 0 || update > Max() - mCount)
+ {
+ ThrowInvalidParamException(update);
+ }
+
+ mCount += update;
+ while (update--)
+ {
+ mCondVar.notify_one();
+ }
+ }
+
+ /**
+ * @brief Atomically decrements the internal counter by one if it is greater
+ * than zero; otherwise blocks until it is greater than zero and can
+ * successfully decrement the internal counter.
+ */
+ void Acquire()
+ {
+ std::unique_lock<std::mutex> lock(mLock);
+ while (mCount == 0)
+ {
+ mCondVar.wait(lock);
+ }
+ --mCount;
+ }
+
+ /**
+ * @brief Tries to atomically decrement the internal counter by one if it is
+ * greater than zero; no blocking occurs regardless.
+ *
+ * @return true if it decremented the counter, otherwise false.
+ */
+ bool TryAcquire()
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mCount)
+ {
+ --mCount;
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * @brief Tries to atomically decrement the internal counter by one if it is greater
+ * than zero; otherwise blocks until it is greater than zero can successfully
+ * decrement the internal counter, or the relTime duration has been exceeded.
+ *
+ * @param[in] relTime the minimum duration the function must wait for to fail
+ *
+ * @return true if it decremented the internal counter, otherwise false
+ */
+ template<typename Rep, typename Period>
+ bool TryAcquireFor(const std::chrono::duration<Rep, Period> &relTime)
+ {
+ std::unique_lock<std::mutex> lock(mLock);
+ while (mCount == 0)
+ {
+ if (mCondVar.wait_for(lock, relTime) == std::cv_status::timeout)
+ {
+ return false;
+ }
+ }
+ --mCount;
+ return true;
+ }
+
+ /**
+ * @brief Tries to atomically decrement the internal counter by one if it is greater
+ * than zero; otherwise blocks until it is greater than zero can successfully
+ * decrement the internal counter, or the absTime duration point has been passed.
+ *
+ * @param[in] absTime the earliest time the function must wait until in order to fail
+ *
+ * @return true if it decremented the internal counter, otherwise false
+ */
+ template<typename Clock, typename Duration>
+ bool TryAcquireUntil(const std::chrono::time_point<Clock, Duration> &absTime)
+ {
+ std::unique_lock<std::mutex> lock(mLock);
+ while (mCount == 0)
+ {
+ if (mCondVar.wait_until(lock, absTime) == std::cv_status::timeout)
+ {
+ return false;
+ }
+ }
+ --mCount;
+ return true;
+ }
+
+private:
+ void ThrowInvalidParamException(std::ptrdiff_t param) const
+ {
+ std::stringstream ss("Invalid parameter value ");
+ ss << param;
+ throw std::invalid_argument(ss.str());
+ }
+
+ std::condition_variable mCondVar;
+ std::mutex mLock;
+ std::ptrdiff_t mCount;
+};
+}
{
namespace Integration
{
-Scene Scene::New(Size size)
+Scene Scene::New(Size size, int orientation)
{
- Internal::ScenePtr internal = Internal::Scene::New(size);
+ Internal::ScenePtr internal = Internal::Scene::New(size, orientation);
return Scene(internal.Get());
}
GetImplementation(*this).GetFramePresentedCallback(callbacks);
}
+void Scene::SurfaceRotated(float width, float height, int orientation)
+{
+ GetImplementation(*this).SurfaceRotated(width, height, orientation);
+}
+
Scene::EventProcessingFinishedSignalType& Scene::EventProcessingFinishedSignal()
{
return GetImplementation(*this).EventProcessingFinishedSignal();
* @brief Create an initialized Scene handle.
*
* @param[in] size The size of the set surface for this scene
+ * @param[in] orientation The rotated angle of the set surface for this scene
*
* @return a handle to a newly allocated Dali resource.
*/
- static Scene New(Size size);
+ static Scene New(Size size, int orientation = 0);
/**
* @brief Downcast an Object handle to Scene handle.
void GetFramePresentedCallback(FrameCallbackContainer& callbacks);
/**
+ * @brief Informs the scene that the set surface has been rotated.
+ *
+ * @param[in] width The width of rotated surface
+ * @param[in] height The height of rotated surface
+ * @param[in] orientation The orientation of rotated surface
+ */
+ void SurfaceRotated(float width, float height, int orientation);
+
+ /**
* @brief This signal is emitted just after the event processing is finished.
*
* @return The signal to connect to
return mSceneObject;
}
+void CameraActor::RotateProjection(int rotationAngle)
+{
+ // sceneObject is being used in a separate thread; queue a message to set
+ RotateProjectionMessage(GetEventThreadServices(), *mSceneObject, rotationAngle);
+}
+
void CameraActor::SetDefaultProperty( Property::Index index, const Property::Value& propertyValue )
{
if(index < DEFAULT_ACTOR_PROPERTY_MAX_COUNT)
*/
const SceneGraph::Camera* GetCamera() const;
+ /**
+ * Rotate the projection.
+ * It is used in case that the target buffer direction is different from the window direction.
+ * @param [in] rotationAngle The rotation angle
+ */
+ void RotateProjection(int rotationAngle);
+
public: // properties
/**
namespace Internal
{
-ScenePtr Scene::New( Size size )
+ScenePtr Scene::New(Size size, int orientation)
{
ScenePtr scene = new Scene;
// Second-phase construction
- scene->Initialize( size );
+ scene->Initialize(size, orientation);
return scene;
}
Scene::Scene()
-: mSceneObject( nullptr ),
+: mSceneObject(nullptr),
mSize(), // Don't set the proper value here, this will be set when the surface is set later
mDpi(),
- mBackgroundColor( DEFAULT_BACKGROUND_COLOR ),
- mDepthTreeDirty( false ),
- mEventProcessor( *this, ThreadLocalStorage::GetInternal()->GetGestureEventProcessor() )
+ mBackgroundColor(DEFAULT_BACKGROUND_COLOR),
+ mDepthTreeDirty(false),
+ mEventProcessor(*this, ThreadLocalStorage::GetInternal()->GetGestureEventProcessor()),
+ mSurfaceOrientation(0)
{
}
// When this destructor is called, the scene has either already been removed from Core or Core has already been destroyed
}
-void Scene::Initialize( Size size )
+void Scene::Initialize(Size size, int orientation)
{
ThreadLocalStorage* tls = ThreadLocalStorage::GetInternal();
// Create the default render-task and ensure clear is enabled on it to show the background color
RenderTaskPtr renderTask = mRenderTaskList->CreateTask( mRootLayer.Get(), mDefaultCamera.Get() );
renderTask->SetClearEnabled(true);
+ mSurfaceOrientation = orientation;
- SurfaceResized( size.width, size.height );
+ SurfaceRotated( size.width, size.height, mSurfaceOrientation );
// Create scene graph object
mSceneObject = new SceneGraph::Scene();
return *mRootLayer;
}
-void Scene::SurfaceResized( float width, float height )
+void Scene::SurfaceResized(float width, float height)
{
- if( ( fabsf( mSize.width - width ) > Math::MACHINE_EPSILON_1 ) || ( fabsf( mSize.height - height ) > Math::MACHINE_EPSILON_1 ) )
+ if((fabsf(mSize.width - width) > Math::MACHINE_EPSILON_1) || (fabsf(mSize.height - height) > Math::MACHINE_EPSILON_1))
{
- Rect< int32_t > newSize( 0, 0, static_cast< int32_t >( width ), static_cast< int32_t >( height ) ); // truncated
-
- mSize.width = width;
- mSize.height = height;
-
- // Calculates the aspect ratio, near and far clipping planes, field of view and camera Z position.
- mDefaultCamera->SetPerspectiveProjection( mSize );
-
- mRootLayer->SetSize( mSize.width, mSize.height );
-
- ThreadLocalStorage* tls = ThreadLocalStorage::GetInternal();
- SceneGraph::UpdateManager& updateManager = tls->GetUpdateManager();
- SetDefaultSurfaceRectMessage( updateManager, newSize );
-
- // set default render-task viewport parameters
- RenderTaskPtr defaultRenderTask = mRenderTaskList->GetTask( 0u );
- defaultRenderTask->SetViewport( newSize );
+ ChangedSurface(width, height, mSurfaceOrientation);
}
}
}
}
+void Scene::SurfaceRotated(float width, float height, int orientation)
+{
+ mSurfaceOrientation = orientation;
+ ChangedSurface(width, height, orientation);
+}
+
+int Scene::GetSurfaceOrientation()
+{
+ return mSurfaceOrientation;
+}
+
+void Scene::ChangedSurface(float width, float height, int orientation)
+{
+ Rect<int32_t> newSize(0, 0, static_cast<int32_t>(width), static_cast<int32_t>(height)); // truncated
+
+ mSize.width = width;
+ mSize.height = height;
+
+ // Calculates the aspect ratio, near and far clipping planes, field of view and camera Z position.
+ mDefaultCamera->SetPerspectiveProjection(mSize);
+ // Set the surface orientation to Default camera for window/screen rotation
+ mDefaultCamera->RotateProjection(orientation);
+
+ mRootLayer->SetSize(width, height);
+
+ ThreadLocalStorage* tls = ThreadLocalStorage::GetInternal();
+ SceneGraph::UpdateManager& updateManager = tls->GetUpdateManager();
+ SetDefaultSurfaceRectMessage(updateManager, newSize);
+
+ // Send the surface orientation to render manager for calculating glViewport/Scissor
+ SetDefaultSurfaceOrientationMessage(updateManager, orientation);
+
+ // set default render-task viewport parameters
+ RenderTaskPtr defaultRenderTask = mRenderTaskList->GetTask(0u);
+ defaultRenderTask->SetViewport(newSize);
+}
+
bool Scene::EmitKeyEventGeneratedSignal(const Dali::KeyEvent& event)
{
// Emit the KeyEventGenerated signal when KeyEvent is generated
/**
* @copydoc Dali::Integration::Scene::New
*/
- static ScenePtr New( Size size );
+ static ScenePtr New(Size size, int orientation = 0);
/**
* virtual destructor
SceneGraph::Scene* GetSceneObject() const;
/**
+ * Notify the surface has been rotated.
+ * When the device is rotated or the rotation event is received by display manager,
+ * this function will be called by window implementation.
+ *
+ * @param[in] width The width of rotated surface
+ * @param[in] height The height of rotated surface
+ * @param[in] orientation The orientation of rotated surface
+ */
+ void SurfaceRotated(float width, float height, int orientation);
+
+ /**
+ * @brief Get surface's current orientation
+ *
+ * @return surface orientation
+ */
+ int GetSurfaceOrientation();
+
+ /**
* Used by the EventProcessor to emit key event signals.
* @param[in] event The key event.
*/
* Second-phase constructor.
*
* @param[in] size The size of the set surface
+ * @param[in] orientation The orientation of the set surface for this scene
*/
- void Initialize( Size size );
+ void Initialize(Size size, int orientation);
// Undefined
Scene(const Scene&) = delete;
// Undefined
Scene& operator=(const Scene& rhs) = delete;
+ /**
+ * Informs the scene that the set surface has been resized or rotated.
+ *
+ * @param[in] width The width of rotated surface
+ * @param[in] height The height of rotated surface
+ * @param[in] orientation The orientation of rotated surface
+ */
+ void ChangedSurface(float width, float height, int orientation);
+
private:
Internal::SceneGraph::Scene* mSceneObject;
EventProcessor mEventProcessor;
+ // The Surface's orientation
+ int mSurfaceOrientation;
+
// The key event signal
Integration::Scene::KeyEventSignalType mKeyEventSignal;
Integration::Scene::KeyEventGeneratedSignalType mKeyEventGeneratedSignal;
const Matrix* GetProjectionMatrix( BufferIndex index ) const
{
// inlined as this is called once per frame per render instruction
- return &mCamera->GetProjectionMatrix( index );
+ return &mCamera->GetFinalProjectionMatrix(index);
}
// for reflection effect
const Camera* GetCamera() const
programController( glAbstraction ),
depthBufferAvailable( depthBufferAvailableParam ),
stencilBufferAvailable( stencilBufferAvailableParam ),
- partialUpdateAvailable( partialUpdateAvailableParam )
+ partialUpdateAvailable( partialUpdateAvailableParam ),
+ defaultSurfaceOrientation(0)
{
// Create thread pool with just one thread ( there may be a need to create more threads in the future ).
threadPool = std::unique_ptr<Dali::ThreadPool>( new Dali::ThreadPool() );
std::unique_ptr<Dali::ThreadPool> threadPool; ///< The thread pool
Vector<GLuint> boundTextures; ///< The textures bound for rendering
Vector<GLuint> textureDependencyList; ///< The dependency list of binded textures
+
+ int defaultSurfaceOrientation; ///< defaultSurfaceOrientation for the default surface we are rendering to
+
};
RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction,
mImpl->defaultSurfaceRect = rect;
}
+void RenderManager::SetDefaultSurfaceOrientation(int orientation)
+{
+ mImpl->defaultSurfaceOrientation = orientation;
+}
+
void RenderManager::AddRenderer( OwnerPointer< Render::Renderer >& renderer )
{
// Initialize the renderer as we are now in render thread
Rect<int32_t> surfaceRect = mImpl->defaultSurfaceRect;
Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable;
Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable;
+ int surfaceOrientation = sceneInternal.GetSurfaceOrientation();
if ( instruction.mFrameBuffer )
{
{
viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() );
}
+ surfaceOrientation = 0;
}
else // No Offscreen frame buffer rendering
{
}
}
+ // Set surface orientation
+ mImpl->currentContext->SetSurfaceOrientation(surfaceOrientation);
+
bool clearFullFrameRect = true;
if( instruction.mFrameBuffer != nullptr )
{
GLenum attachments[] = { GL_DEPTH, GL_STENCIL };
mImpl->currentContext->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments);
+
}
void RenderManager::PostRender( bool uploadOnly )
void SetDefaultSurfaceRect( const Rect<int>& rect );
/**
+ * Returns the orintation for the default surface (probably the application window).
+ * @param[in] orientation the surface's orientation.
+ */
+ void SetDefaultSurfaceOrientation(int orientation);
+
+ /**
* Add a Renderer to the render manager.
* @param[in] renderer The renderer to add.
* @post renderer is owned by RenderManager
mClearColor(Color::WHITE), // initial color, never used until it's been set by the user
mCullFaceMode( FaceCullingMode::NONE ),
mViewPort( 0, 0, 0, 0 ),
- mSceneContexts( contexts )
+ mSceneContexts( contexts ),
+ mSurfaceOrientation(0)
{
}
*/
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
{
- LOG_GL("Scissor %d %d %d %d\n", x, y, width, height);
- CHECK_GL( mGlAbstraction, mGlAbstraction.Scissor(x, y, width, height) );
+ GLint cx, cy, cw, ch;
+
+ // scissor's value should be set based on the default system coordinates.
+ // when the surface is rotated, the input valus already were set with the rotated angle.
+ // So, re-calculation is needed.
+ if(mSurfaceOrientation == 90)
+ {
+ cx = mViewPort.height - (y + height);
+ cy = x;
+ cw = height;
+ ch = width;
+ }
+ else if(mSurfaceOrientation == 180)
+ {
+ cx = mViewPort.width - (x + width);
+ cy = mViewPort.height - (y + height);
+ cw = width;
+ ch = height;
+ }
+ else if(mSurfaceOrientation == 270)
+ {
+ cx = y;
+ cy = mViewPort.width - (x + width);
+ cw = height;
+ ch = width;
+ }
+ else
+ {
+ cx = x;
+ cy = y;
+ cw = width;
+ ch = height;
+ }
+
+ LOG_GL("Scissor %d %d %d %d\n", cx, cy, cw, ch);
+ CHECK_GL(mGlAbstraction, mGlAbstraction.Scissor(cx, cy, cw, ch));
}
/**
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height)
{
// check if its same as already set
- Rect<int> newViewport( x, y, width, height );
+ GLsizei cw, ch;
+
+ // viewport's value shoud be set based on the default system size.
+ // when the surface is rotated, the input width and height already were swapped.
+ // So, re-swapping is needed.
+ if(mSurfaceOrientation == 90 || mSurfaceOrientation == 270)
+ {
+ cw = height;
+ ch = width;
+ }
+ else
+ {
+ cw = width;
+ ch = height;
+ }
+
+ // User uses the rotated viewport size.
+ Rect<int> newViewport(x, y, width, height);
// Temporarily disable the viewport caching, as the implementation of GLES driver in Tizen platform
// share a global viewport between multiple contexts, therefore glViewport has to be called every
// time after glBindFramebuffer regardless of the same vewport size in the same context.
-// if( mViewPort != newViewport )
+ // if( mViewPort != newViewport )
{
// set new one
- LOG_GL("Viewport %d %d %d %d\n", x, y, width, height);
- CHECK_GL( mGlAbstraction, mGlAbstraction.Viewport(x, y, width, height) );
+ LOG_GL("Viewport %d %d %d %d\n", x, y, cw, ch);
+ CHECK_GL(mGlAbstraction, mGlAbstraction.Viewport(x, y, cw, ch));
mViewPort = newViewport; // remember new one
}
}
return mMaxTextureSize;
}
+ void SetSurfaceOrientation(int orientation)
+ {
+ LOG_GL( "SetSurfaceOrientation: orientation: %d\n", orientation );
+ mSurfaceOrientation = orientation;
+ }
+
/**
* Get the current viewport.
* @return Viewport rectangle.
FrameBufferStateCache mFrameBufferStateCache; ///< frame buffer state cache
OwnerContainer< Context* >* mSceneContexts; ///< The pointer of the container of contexts for surface rendering
+
+ int mSurfaceOrientation;
};
} // namespace Internal
new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SurfaceReplaced, scene );
}
+void UpdateManager::SetDefaultSurfaceOrientation(int orientation)
+{
+ using DerivedType = MessageValue1<RenderManager, int>;
+
+ // Reserve some memory inside the render queue
+ unsigned int* slot = mImpl->renderQueue.ReserveMessageSlot(mSceneGraphBuffers.GetUpdateBufferIndex(), sizeof(DerivedType));
+
+ // Construct message in the render queue memory; note that delete should not be called on the return value
+ new(slot) DerivedType(&mImpl->renderManager, &RenderManager::SetDefaultSurfaceOrientation, orientation);
+}
+
void UpdateManager::KeepRendering( float durationSeconds )
{
mImpl->keepRenderingSeconds = std::max( mImpl->keepRenderingSeconds, durationSeconds );
void SetDefaultSurfaceRect( const Rect<int>& rect );
/**
+ * Set the default surface orientation.
+ * @param[in] orientation The orientation value representing the surface.
+ */
+ void SetDefaultSurfaceOrientation(int orientation);
+
+ /**
* @copydoc Dali::Stage::KeepRendering()
*/
void KeepRendering( float durationSeconds );
new (slot) LocalType( &manager, &UpdateManager::SurfaceReplaced, &scene );
}
+inline void SetDefaultSurfaceOrientationMessage(UpdateManager& manager, int orientation)
+{
+ using LocalType = MessageValue1<UpdateManager, int>;
+
+ // Reserve some memory inside the message queue
+ unsigned int* slot = manager.ReserveMessageSlot(sizeof(LocalType));
+
+ // Construct message in the message queue memory; note that delete should not be called on the return value
+ new(slot) LocalType(&manager, &UpdateManager::SetDefaultSurfaceOrientation, orientation);
+}
+
inline void KeepRenderingMessage( UpdateManager& manager, float durationSeconds )
{
using LocalType = MessageValue1<UpdateManager, float>;
Camera::Camera()
: mUpdateViewFlag( UPDATE_COUNT ),
mUpdateProjectionFlag( UPDATE_COUNT ),
+ mProjectionRotation(0),
mNode( nullptr ),
mType( DEFAULT_TYPE ),
mProjectionMode( DEFAULT_MODE ),
mTargetPosition( DEFAULT_TARGET_POSITION ),
mViewMatrix(),
mProjectionMatrix(),
- mInverseViewProjection( Matrix::IDENTITY )
+ mInverseViewProjection( Matrix::IDENTITY ),
+ mFinalProjection(Matrix::IDENTITY)
{
}
mUpdateViewFlag = UPDATE_COUNT;
}
-
-
void VectorReflectedByPlane(Vector4 &out, Vector4 &in, Vector4 &plane)
{
float d = float(2.0) * plane.Dot(in);
mUpdateViewFlag = UPDATE_COUNT;
}
+void Camera::RotateProjection(int rotationAngle)
+{
+ mProjectionRotation = rotationAngle;
+ mUpdateViewFlag = UPDATE_COUNT;
+}
+
const Matrix& Camera::GetProjectionMatrix( BufferIndex bufferIndex ) const
{
return mProjectionMatrix[ bufferIndex ];
return mInverseViewProjection[ bufferIndex ];
}
+const Matrix& Camera::GetFinalProjectionMatrix(BufferIndex bufferIndex) const
+{
+ return mFinalProjection[ bufferIndex ];
+}
+
const PropertyInputImpl* Camera::GetProjectionMatrix() const
{
return &mProjectionMatrix;
}
}
- mProjectionMatrix.SetDirty( updateBufferIndex );
+ mProjectionMatrix.SetDirty(updateBufferIndex);
+
+ Matrix& finalProjection = mFinalProjection[updateBufferIndex];
+ finalProjection.SetIdentity();
+
+ Quaternion rotationAngle;
+ switch(mProjectionRotation)
+ {
+ case 90:
+ {
+ rotationAngle = Quaternion(Dali::ANGLE_90, Vector3::ZAXIS);
+ break;
+ }
+ case 180:
+ {
+ rotationAngle = Quaternion(Dali::ANGLE_180, Vector3::ZAXIS);
+ break;
+ }
+ case 270:
+ {
+ rotationAngle = Quaternion(Dali::ANGLE_270, Vector3::ZAXIS);
+ break;
+ }
+ default:
+ rotationAngle = Quaternion(Dali::ANGLE_0, Vector3::ZAXIS);
+ break;
+ }
+
+ Matrix rotation;
+ rotation.SetIdentity();
+ rotation.SetTransformComponents(Vector3(1.0f, 1.0f, 1.0f), rotationAngle, Vector3(0.0f, 0.0f, 0.0f));
+
+ Matrix::Multiply(finalProjection, mProjectionMatrix.Get(updateBufferIndex), rotation);
}
--mUpdateProjectionFlag;
}
void SetFarClippingPlane( float farClippingPlane );
/**
+ * @copydoc Dali::Internal::CameraActor::RotateProjection
+ */
+ void RotateProjection(int rotationAngle);
+
+ /**
* @copydoc Dali::Internal::CameraActor::SetTarget
*/
void SetTargetPosition( const Vector3& targetPosition );
const Matrix& GetInverseViewProjectionMatrix( BufferIndex bufferIndex ) const;
/**
+ * Retrieve the final projection-matrix; this is double buffered for input handling.
+ * @param[in] bufferIndex The buffer to read from.
+ * @return The projection-matrix that should be used to render.
+ */
+ const Matrix& GetFinalProjectionMatrix(BufferIndex bufferIndex) const;
+
+ /**
* Retrieve the projection-matrix property querying interface.
* @pre The camera is on-stage.
* @return The projection-matrix property querying interface.
uint32_t mUpdateViewFlag; ///< This is non-zero if the view matrix requires an update
uint32_t mUpdateProjectionFlag; ///< This is non-zero if the projection matrix requires an update
+ int mProjectionRotation; ///< The rotaion angle of the projection
const Node* mNode; ///< The node this scene graph camera belongs to
public: // PROPERTIES
DoubleBuffered< FrustumPlanes > mFrustum; ///< Clipping frustum; double buffered for input handling
DoubleBuffered< Matrix > mInverseViewProjection; ///< Inverted viewprojection; double buffered for input handling
+ DoubleBuffered< Matrix > mFinalProjection; ///< Final projection matrix; double buffered for input handling
};
new (slot) LocalType( &camera, &Camera::SetInvertYAxis, parameter );
}
+inline void RotateProjectionMessage( EventThreadServices& eventThreadServices, const Camera& camera, int parameter )
+{
+ typedef MessageValue1< Camera, int > 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( &camera, &Camera::RotateProjection, parameter );
+}
+
} // namespace SceneGraph
} // namespace Internal
{
const uint32_t CORE_MAJOR_VERSION = 2;
const uint32_t CORE_MINOR_VERSION = 0;
-const uint32_t CORE_MICRO_VERSION = 2;
+const uint32_t CORE_MICRO_VERSION = 3;
const char* const CORE_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
Name: dali2
Summary: DALi 3D Engine
-Version: 2.0.2
+Version: 2.0.3
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT