From: Richard Huang Date: Fri, 27 Nov 2020 11:57:40 +0000 (+0000) Subject: [dali_2.0.3] Merge branch 'devel/master' X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5b712a1b5fda4ee48e03f5ce462dd4c506fec014;hp=a51075d0e226ae5aff2df1bc715a175e710467d6;p=platform%2Fcore%2Fuifw%2Fdali-core.git [dali_2.0.3] Merge branch 'devel/master' Change-Id: I6a02abaa41405a5e288843ec7578caa669fb7a3d --- diff --git a/automated-tests/src/dali/CMakeLists.txt b/automated-tests/src/dali/CMakeLists.txt index bab6fb6..67aceac 100644 --- a/automated-tests/src/dali/CMakeLists.txt +++ b/automated-tests/src/dali/CMakeLists.txt @@ -47,6 +47,7 @@ SET(TC_SOURCES 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 diff --git a/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.h b/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.h index 2c1c703..b8de978 100644 --- a/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.h +++ b/automated-tests/src/dali/dali-test-suite-utils/dali-test-suite-utils.h @@ -378,6 +378,34 @@ inline void DALI_TEST_PRINT_ASSERT(DaliException& e) 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 { diff --git a/automated-tests/src/dali/utc-Dali-Scene.cpp b/automated-tests/src/dali/utc-Dali-Scene.cpp index 2fb7d3c..688f7c3 100644 --- a/automated-tests/src/dali/utc-Dali-Scene.cpp +++ b/automated-tests/src/dali/utc-Dali-Scene.cpp @@ -1050,6 +1050,232 @@ int UtcDaliSceneSurfaceResizedAdditionalScene(void) 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> damagedRects; + Rect 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(CLIPPING_RECT_X, CLIPPING_RECT_Y, CLIPPING_RECT_WIDTH, CLIPPING_RECT_HEIGHT); // in screen coordinates, includes 3 last frames updates + DALI_TEST_EQUALS>(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> damagedRects; + Rect 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(CLIPPING_RECT_X, CLIPPING_RECT_Y, CLIPPING_RECT_WIDTH, CLIPPING_RECT_HEIGHT); // in screen coordinates, includes 3 last frames updates + DALI_TEST_EQUALS>(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> damagedRects; + Rect 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(CLIPPING_RECT_X, CLIPPING_RECT_Y, CLIPPING_RECT_WIDTH, CLIPPING_RECT_HEIGHT); // in screen coordinates, includes 3 last frames updates + DALI_TEST_EQUALS>(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> damagedRects; + Rect 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(CLIPPING_RECT_X, CLIPPING_RECT_Y, CLIPPING_RECT_WIDTH, CLIPPING_RECT_HEIGHT); // in screen coordinates, includes 3 last frames updates + DALI_TEST_EQUALS>(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; diff --git a/automated-tests/src/dali/utc-Dali-Semaphore.cpp b/automated-tests/src/dali/utc-Dali-Semaphore.cpp new file mode 100644 index 0000000..4cda5e6 --- /dev/null +++ b/automated-tests/src/dali/utc-Dali-Semaphore.cpp @@ -0,0 +1,102 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +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 &sem, bool &flag) + { + sem.Acquire(); + flag = true; + }; + + auto flag1{false}, flag2{false}; + Dali::Semaphore 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; +} diff --git a/dali/devel-api/file.list b/dali/devel-api/file.list index d65e823..1973073 100644 --- a/dali/devel-api/file.list +++ b/dali/devel-api/file.list @@ -128,6 +128,7 @@ SET( devel_api_core_scripting_header_files 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 ) diff --git a/dali/devel-api/threading/semaphore.h b/dali/devel-api/threading/semaphore.h new file mode 100644 index 0000000..9ecb41a --- /dev/null +++ b/dali/devel-api/threading/semaphore.h @@ -0,0 +1,180 @@ +#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 + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include + +namespace Dali +{ +/** + * @brief Class that implements a C++20 counting_semaphore like interface + */ +template::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 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 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 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 + bool TryAcquireFor(const std::chrono::duration &relTime) + { + std::unique_lock 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 + bool TryAcquireUntil(const std::chrono::time_point &absTime) + { + std::unique_lock 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; +}; +} diff --git a/dali/integration-api/scene.cpp b/dali/integration-api/scene.cpp index 9a6af8e..8650fea 100644 --- a/dali/integration-api/scene.cpp +++ b/dali/integration-api/scene.cpp @@ -27,9 +27,9 @@ namespace Dali { 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()); } @@ -156,6 +156,11 @@ void Scene::GetFramePresentedCallback(FrameCallbackContainer& callbacks) 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(); diff --git a/dali/integration-api/scene.h b/dali/integration-api/scene.h index 7d97dd3..d5920da 100644 --- a/dali/integration-api/scene.h +++ b/dali/integration-api/scene.h @@ -66,10 +66,11 @@ public: * @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. @@ -284,6 +285,15 @@ public: 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 diff --git a/dali/internal/event/actors/camera-actor-impl.cpp b/dali/internal/event/actors/camera-actor-impl.cpp index fecea3c..b81341a 100644 --- a/dali/internal/event/actors/camera-actor-impl.cpp +++ b/dali/internal/event/actors/camera-actor-impl.cpp @@ -524,6 +524,12 @@ const SceneGraph::Camera* CameraActor::GetCamera() const 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) diff --git a/dali/internal/event/actors/camera-actor-impl.h b/dali/internal/event/actors/camera-actor-impl.h index 4463ba1..97b62bd 100644 --- a/dali/internal/event/actors/camera-actor-impl.h +++ b/dali/internal/event/actors/camera-actor-impl.h @@ -204,6 +204,13 @@ public: */ 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 /** diff --git a/dali/internal/event/common/scene-impl.cpp b/dali/internal/event/common/scene-impl.cpp index 496fba4..4ab5142 100755 --- a/dali/internal/event/common/scene-impl.cpp +++ b/dali/internal/event/common/scene-impl.cpp @@ -43,23 +43,24 @@ namespace Dali 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) { } @@ -94,7 +95,7 @@ Scene::~Scene() // 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(); @@ -130,8 +131,9 @@ void Scene::Initialize( Size size ) // 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(); @@ -199,27 +201,11 @@ Actor& Scene::GetDefaultRootActor() 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); } } @@ -294,6 +280,43 @@ void Scene::EmitKeyEventSignal(const Dali::KeyEvent& event) } } +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 newSize(0, 0, static_cast(width), static_cast(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 diff --git a/dali/internal/event/common/scene-impl.h b/dali/internal/event/common/scene-impl.h index 67d08d5..44a5e3b 100755 --- a/dali/internal/event/common/scene-impl.h +++ b/dali/internal/event/common/scene-impl.h @@ -114,7 +114,7 @@ public: /** * @copydoc Dali::Integration::Scene::New */ - static ScenePtr New( Size size ); + static ScenePtr New(Size size, int orientation = 0); /** * virtual destructor @@ -232,6 +232,24 @@ public: 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. */ @@ -338,8 +356,9 @@ private: * 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; @@ -347,6 +366,15 @@ private: // 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; @@ -370,6 +398,9 @@ private: EventProcessor mEventProcessor; + // The Surface's orientation + int mSurfaceOrientation; + // The key event signal Integration::Scene::KeyEventSignalType mKeyEventSignal; Integration::Scene::KeyEventGeneratedSignalType mKeyEventGeneratedSignal; diff --git a/dali/internal/render/common/render-instruction.h b/dali/internal/render/common/render-instruction.h index 8f59b13..7ebecee 100644 --- a/dali/internal/render/common/render-instruction.h +++ b/dali/internal/render/common/render-instruction.h @@ -122,7 +122,7 @@ public: 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 diff --git a/dali/internal/render/common/render-manager.cpp b/dali/internal/render/common/render-manager.cpp index e885c33..3f3d319 100755 --- a/dali/internal/render/common/render-manager.cpp +++ b/dali/internal/render/common/render-manager.cpp @@ -77,7 +77,8 @@ struct RenderManager::Impl 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( new Dali::ThreadPool() ); @@ -174,6 +175,9 @@ struct RenderManager::Impl std::unique_ptr threadPool; ///< The thread pool Vector boundTextures; ///< The textures bound for rendering Vector textureDependencyList; ///< The dependency list of binded textures + + int defaultSurfaceOrientation; ///< defaultSurfaceOrientation for the default surface we are rendering to + }; RenderManager* RenderManager::New( Integration::GlAbstraction& glAbstraction, @@ -257,6 +261,11 @@ void RenderManager::SetDefaultSurfaceRect(const Rect& rect) 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 @@ -822,6 +831,7 @@ void RenderManager::RenderScene( Integration::RenderStatus& status, Integration: Rect surfaceRect = mImpl->defaultSurfaceRect; Integration::DepthBufferAvailable depthBufferAvailable = mImpl->depthBufferAvailable; Integration::StencilBufferAvailable stencilBufferAvailable = mImpl->stencilBufferAvailable; + int surfaceOrientation = sceneInternal.GetSurfaceOrientation(); if ( instruction.mFrameBuffer ) { @@ -921,6 +931,7 @@ void RenderManager::RenderScene( Integration::RenderStatus& status, Integration: { viewportRect.Set( 0, 0, instruction.mFrameBuffer->GetWidth(), instruction.mFrameBuffer->GetHeight() ); } + surfaceOrientation = 0; } else // No Offscreen frame buffer rendering { @@ -937,6 +948,9 @@ void RenderManager::RenderScene( Integration::RenderStatus& status, Integration: } } + // Set surface orientation + mImpl->currentContext->SetSurfaceOrientation(surfaceOrientation); + bool clearFullFrameRect = true; if( instruction.mFrameBuffer != nullptr ) { @@ -1079,6 +1093,7 @@ void RenderManager::RenderScene( Integration::RenderStatus& status, Integration: GLenum attachments[] = { GL_DEPTH, GL_STENCIL }; mImpl->currentContext->InvalidateFramebuffer(GL_FRAMEBUFFER, 2, attachments); + } void RenderManager::PostRender( bool uploadOnly ) diff --git a/dali/internal/render/common/render-manager.h b/dali/internal/render/common/render-manager.h index 2e3ea2d..8474a8a 100644 --- a/dali/internal/render/common/render-manager.h +++ b/dali/internal/render/common/render-manager.h @@ -131,6 +131,12 @@ public: void SetDefaultSurfaceRect( const Rect& 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 diff --git a/dali/internal/render/gl-resources/context.cpp b/dali/internal/render/gl-resources/context.cpp index f92d0d0..279113f 100644 --- a/dali/internal/render/gl-resources/context.cpp +++ b/dali/internal/render/gl-resources/context.cpp @@ -107,7 +107,8 @@ Context::Context( Integration::GlAbstraction& glAbstraction, OwnerContainer< Con 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) { } diff --git a/dali/internal/render/gl-resources/context.h b/dali/internal/render/gl-resources/context.h index fe4d2dd..a66cee1 100644 --- a/dali/internal/render/gl-resources/context.h +++ b/dali/internal/render/gl-resources/context.h @@ -1580,8 +1580,42 @@ public: */ 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)); } /** @@ -1750,16 +1784,33 @@ public: void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) { // check if its same as already set - Rect 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 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 } } @@ -1782,6 +1833,12 @@ public: return mMaxTextureSize; } + void SetSurfaceOrientation(int orientation) + { + LOG_GL( "SetSurfaceOrientation: orientation: %d\n", orientation ); + mSurfaceOrientation = orientation; + } + /** * Get the current viewport. * @return Viewport rectangle. @@ -1893,6 +1950,8 @@ private: // Data FrameBufferStateCache mFrameBufferStateCache; ///< frame buffer state cache OwnerContainer< Context* >* mSceneContexts; ///< The pointer of the container of contexts for surface rendering + + int mSurfaceOrientation; }; } // namespace Internal diff --git a/dali/internal/update/manager/update-manager.cpp b/dali/internal/update/manager/update-manager.cpp index a7ca327..3127eab 100644 --- a/dali/internal/update/manager/update-manager.cpp +++ b/dali/internal/update/manager/update-manager.cpp @@ -1148,6 +1148,17 @@ void UpdateManager::SurfaceReplaced( Scene* scene ) new (slot) DerivedType( &mImpl->renderManager, &RenderManager::SurfaceReplaced, scene ); } +void UpdateManager::SetDefaultSurfaceOrientation(int orientation) +{ + using DerivedType = MessageValue1; + + // 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 ); diff --git a/dali/internal/update/manager/update-manager.h b/dali/internal/update/manager/update-manager.h index 8f272d8..4f2214a 100644 --- a/dali/internal/update/manager/update-manager.h +++ b/dali/internal/update/manager/update-manager.h @@ -634,6 +634,12 @@ public: void SetDefaultSurfaceRect( const Rect& 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 ); @@ -1095,6 +1101,17 @@ inline void SurfaceReplacedMessage( UpdateManager& manager, const SceneGraph::Sc new (slot) LocalType( &manager, &UpdateManager::SurfaceReplaced, &scene ); } +inline void SetDefaultSurfaceOrientationMessage(UpdateManager& manager, int orientation) +{ + using LocalType = MessageValue1; + + // 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; diff --git a/dali/internal/update/render-tasks/scene-graph-camera.cpp b/dali/internal/update/render-tasks/scene-graph-camera.cpp index e644bb3..d07c8c7 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.cpp +++ b/dali/internal/update/render-tasks/scene-graph-camera.cpp @@ -161,6 +161,7 @@ const Vector3 Camera::DEFAULT_TARGET_POSITION( 0.0f, 0.0f, 0.0f ); Camera::Camera() : mUpdateViewFlag( UPDATE_COUNT ), mUpdateProjectionFlag( UPDATE_COUNT ), + mProjectionRotation(0), mNode( nullptr ), mType( DEFAULT_TYPE ), mProjectionMode( DEFAULT_MODE ), @@ -176,7 +177,8 @@ Camera::Camera() mTargetPosition( DEFAULT_TARGET_POSITION ), mViewMatrix(), mProjectionMatrix(), - mInverseViewProjection( Matrix::IDENTITY ) + mInverseViewProjection( Matrix::IDENTITY ), + mFinalProjection(Matrix::IDENTITY) { } @@ -268,8 +270,6 @@ void Camera::SetTargetPosition( const Vector3& targetPosition ) mUpdateViewFlag = UPDATE_COUNT; } - - void VectorReflectedByPlane(Vector4 &out, Vector4 &in, Vector4 &plane) { float d = float(2.0) * plane.Dot(in); @@ -331,6 +331,12 @@ void Camera::SetReflectByPlane( const Vector4& plane ) mUpdateViewFlag = UPDATE_COUNT; } +void Camera::RotateProjection(int rotationAngle) +{ + mProjectionRotation = rotationAngle; + mUpdateViewFlag = UPDATE_COUNT; +} + const Matrix& Camera::GetProjectionMatrix( BufferIndex bufferIndex ) const { return mProjectionMatrix[ bufferIndex ]; @@ -346,6 +352,11 @@ const Matrix& Camera::GetInverseViewProjectionMatrix( BufferIndex bufferIndex ) return mInverseViewProjection[ bufferIndex ]; } +const Matrix& Camera::GetFinalProjectionMatrix(BufferIndex bufferIndex) const +{ + return mFinalProjection[ bufferIndex ]; +} + const PropertyInputImpl* Camera::GetProjectionMatrix() const { return &mProjectionMatrix; @@ -654,7 +665,39 @@ uint32_t Camera::UpdateProjection( BufferIndex updateBufferIndex ) } } - 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; } diff --git a/dali/internal/update/render-tasks/scene-graph-camera.h b/dali/internal/update/render-tasks/scene-graph-camera.h index c5917a0..d752b5c 100644 --- a/dali/internal/update/render-tasks/scene-graph-camera.h +++ b/dali/internal/update/render-tasks/scene-graph-camera.h @@ -161,6 +161,11 @@ public: void SetFarClippingPlane( float farClippingPlane ); /** + * @copydoc Dali::Internal::CameraActor::RotateProjection + */ + void RotateProjection(int rotationAngle); + + /** * @copydoc Dali::Internal::CameraActor::SetTarget */ void SetTargetPosition( const Vector3& targetPosition ); @@ -224,6 +229,13 @@ public: 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. @@ -295,6 +307,7 @@ private: 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 @@ -323,6 +336,7 @@ 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 }; @@ -460,6 +474,17 @@ inline void SetInvertYAxisMessage( EventThreadServices& eventThreadServices, con 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 diff --git a/dali/public-api/dali-core-version.cpp b/dali/public-api/dali-core-version.cpp index f77181b..371199a 100644 --- a/dali/public-api/dali-core-version.cpp +++ b/dali/public-api/dali-core-version.cpp @@ -27,7 +27,7 @@ namespace Dali { 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 diff --git a/packaging/dali.spec b/packaging/dali.spec index 3a6a159..d060792 100644 --- a/packaging/dali.spec +++ b/packaging/dali.spec @@ -1,6 +1,6 @@ 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