From eb9496b40474252a3f522c44f352d1c3f207acaf Mon Sep 17 00:00:00 2001 From: Adam Bialogonski Date: Thu, 31 Mar 2022 16:25:46 +0100 Subject: [PATCH] GlView using DirectRendering Added GlView::BackendMode enum The backend mode can be changed only upon the GlView creation. There is no way to change the backend after that. Change-Id: I0e6c072e9b9b03c65324177ba1c2df9f6cf8d458 --- automated-tests/src/dali-toolkit/CMakeLists.txt | 1 + .../utc-Dali-GlViewDirectRendering.cpp | 388 +++++++++++++++++++++ .../controls/gl-view/drawable-view-impl.cpp | 205 +++++++++++ .../internal/controls/gl-view/drawable-view-impl.h | 168 +++++++++ .../internal/controls/gl-view/gl-view-impl.cpp | 4 +- .../internal/controls/gl-view/gl-view-impl.h | 38 +- .../controls/gl-view/gl-view-interface-impl.h | 133 +++++++ dali-toolkit/internal/file.list | 1 + .../public-api/controls/gl-view/gl-view.cpp | 49 ++- dali-toolkit/public-api/controls/gl-view/gl-view.h | 100 +++++- 10 files changed, 1041 insertions(+), 46 deletions(-) create mode 100644 automated-tests/src/dali-toolkit/utc-Dali-GlViewDirectRendering.cpp create mode 100644 dali-toolkit/internal/controls/gl-view/drawable-view-impl.cpp create mode 100644 dali-toolkit/internal/controls/gl-view/drawable-view-impl.h create mode 100644 dali-toolkit/internal/controls/gl-view/gl-view-interface-impl.h diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index 641a9df..1dbbf90 100755 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -79,6 +79,7 @@ SET(TC_SOURCES utc-Dali-DragAndDropDetector.cpp utc-Dali-NPatchUtilities.cpp utc-Dali-GlView.cpp + utc-Dali-GlViewDirectRendering.cpp ) # List of test harness files (Won't get parsed for test cases) diff --git a/automated-tests/src/dali-toolkit/utc-Dali-GlViewDirectRendering.cpp b/automated-tests/src/dali-toolkit/utc-Dali-GlViewDirectRendering.cpp new file mode 100644 index 0000000..82e3be9 --- /dev/null +++ b/automated-tests/src/dali-toolkit/utc-Dali-GlViewDirectRendering.cpp @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2022 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 + +using namespace Dali; +using namespace Dali::Toolkit; + +// Positive test case for a method +int UtcDaliGlViewDirectRenderingNew(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliGlViewDirectRenderingNew"); + GlView view = GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGBA8888); + DALI_TEST_CHECK(view); + + auto mode1 = view.GetBackendMode(); + + DALI_TEST_EQUALS(mode1, GlView::BackendMode::DIRECT_RENDERING, TEST_LOCATION); + + GlView view2 = GlView::New(GlView::BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING, GlView::ColorFormat::RGBA8888); + DALI_TEST_CHECK(view2); + + auto mode2 = view2.GetBackendMode(); + DALI_TEST_EQUALS(mode2, GlView::BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliGlViewDirectRenderingNewN(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliGlViewDirectRenderingNewN"); + // Invalid backend mode + GlView view = GlView::New(GlView::BackendMode(11111), GlView::ColorFormat::RGBA8888); + DALI_TEST_CHECK(!view); + + END_TEST; +} + +// Positive test case for a method +int UtcDaliGlViewDirectRenderingDownCast(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliGlViewDirectRenderingDownCast"); + + GlView view = GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + BaseHandle handle(view); + + Toolkit::GlView view2 = Toolkit::GlView::DownCast(handle); + DALI_TEST_CHECK(view); + DALI_TEST_CHECK(view2); + DALI_TEST_CHECK(view == view2); + END_TEST; +} + +int UtcDaliGlViewDirectRenderingCopyAndAssignment(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingCopyAndAssignment"); + + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + DALI_TEST_CHECK(view); + + GlView copy(view); + DALI_TEST_CHECK(view == copy); + + GlView assign; + DALI_TEST_CHECK(!assign); + + assign = copy; + DALI_TEST_CHECK(assign == view); + + END_TEST; +} + +int UtcDaliGlViewDirectRenderingMoveAssignment(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingMoveAssignment"); + + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + DALI_TEST_EQUALS(1, view.GetBaseObject().ReferenceCount(), TEST_LOCATION); + + GlView moved; + moved = std::move(view); + DALI_TEST_CHECK(moved); + DALI_TEST_EQUALS(1, moved.GetBaseObject().ReferenceCount(), TEST_LOCATION); + DALI_TEST_CHECK(!view); + + END_TEST; +} + +int UtcDaliGlViewDirectRenderingSetGraphicsConfigGles20N(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingSetGraphicsConfigGles20"); + GlView view; + try + { + view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0); + DALI_TEST_CHECK(false); + } + catch(...) + { + DALI_TEST_CHECK(true); + } + END_TEST; +} + +int UtcDaliGlViewDirectRenderingSetGraphicsConfigGles30(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingSetGraphicsConfigGles30"); + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + + try + { + view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_3_0); + DALI_TEST_CHECK(true); + } + catch(...) + { + DALI_TEST_CHECK(false); + } + END_TEST; +} + +int UtcDaliGlViewDirectRenderingRenderingMode(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingRenderingMode"); + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + + view.SetRenderingMode(GlView::RenderingMode::ON_DEMAND); + + GlView::RenderingMode mode = view.GetRenderingMode(); + + DALI_TEST_EQUALS(GlView::RenderingMode::ON_DEMAND, mode, TEST_LOCATION); + + END_TEST; +} + +int UtcDaliGlViewDirectRenderingOnSizeSet(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingOnSizeSet"); + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + Vector3 size(200.0f, 300.0f, 0.0f); + view.SetProperty(Actor::Property::SIZE, size); + + application.SendNotification(); + application.Render(); + + DALI_TEST_EQUALS(view.GetCurrentProperty(Actor::Property::SIZE), size, TEST_LOCATION); + + END_TEST; +} + +namespace DirectRenderingCode +{ + +// Internal callback function +void glInit(void) +{ +} + +int glRenderFrame(void) +{ + static unsigned int retFlag = 0; + return retFlag++; +} + +void glTerminate(void) +{ +} + +void resizeCB(Vector2 size) +{ +} + +} + +int UtcDaliGlViewDirectRenderingRegisterGlCallbacksN(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingRegisterGlCallbacksN"); + GlView view; + + try + { + view.RegisterGlCallbacks(Dali::MakeCallback(DirectRenderingCode::glInit), Dali::MakeCallback(DirectRenderingCode::glRenderFrame), Dali::MakeCallback(DirectRenderingCode::glTerminate)); + DALI_TEST_CHECK(false); + } + catch(...) + { + DALI_TEST_CHECK(true); + } + END_TEST; +} + +int UtcDaliGlViewDirectRenderingSetResizeCallbackN(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingSetResizeCallback"); + GlView view; + + try + { + view.SetResizeCallback(Dali::MakeCallback(DirectRenderingCode::resizeCB)); + DALI_TEST_CHECK(false); + } + catch(...) + { + DALI_TEST_CHECK(true); + } + END_TEST; +} + +int UtcDaliGlViewDirectRenderingRenderOnce(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingRenderOnce"); + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + + try + { + view.RenderOnce(); + DALI_TEST_CHECK(true); + } + catch(...) + { + DALI_TEST_CHECK(false); + } + END_TEST; +} + +int UtcDaliGlViewDirectRenderingWindowVisibilityChanged(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingWindowVisibilityChanged"); + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + application.GetScene().Add(view); + view.SetRenderingMode(GlView::RenderingMode::CONTINUOUS); + view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0); + view.RegisterGlCallbacks(Dali::MakeCallback(DirectRenderingCode::glInit), Dali::MakeCallback(DirectRenderingCode::glRenderFrame), Dali::MakeCallback(DirectRenderingCode::glTerminate)); + view.SetResizeCallback(Dali::MakeCallback(DirectRenderingCode::resizeCB)); + + application.SendNotification(); + application.Render(); + + Window window = DevelWindow::Get(view); + window.Hide(); + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK(true); + END_TEST; +} + +int UtcDaliGlViewDirectRenderingOnScene(void) +{ + ToolkitTestApplication application; + + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + + //Onscene + application.GetScene().Add(view); + view.SetRenderingMode(GlView::RenderingMode::CONTINUOUS); + view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0); + view.RegisterGlCallbacks(Dali::MakeCallback(DirectRenderingCode::glInit), Dali::MakeCallback(DirectRenderingCode::glRenderFrame), Dali::MakeCallback(DirectRenderingCode::glTerminate)); + + application.SendNotification(); + application.Render(); + + //Offscene + application.GetScene().Remove(view); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK(true); + END_TEST; +} + +int UtcDaliGlViewDirectRenderingControlVisibilityChanged(void) +{ + ToolkitTestApplication application; + + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + application.GetScene().Add(view); + + application.SendNotification(); + application.Render(); + + view.SetProperty(Actor::Property::VISIBLE, false); + application.SendNotification(); + application.Render(); + DALI_TEST_CHECK(view.GetCurrentProperty(Actor::Property::VISIBLE) == false); + + view.SetProperty(Actor::Property::VISIBLE, true); + application.SendNotification(); + application.Render(); + DALI_TEST_CHECK(view.GetCurrentProperty(Actor::Property::VISIBLE) == true); + + END_TEST; +} + +int UtcDaliGlViewDirectRenderingResize(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingResize"); + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + + application.GetScene().Add(view); + view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0); + view.RegisterGlCallbacks(Dali::MakeCallback(DirectRenderingCode::glInit), Dali::MakeCallback(DirectRenderingCode::glRenderFrame), Dali::MakeCallback(DirectRenderingCode::glTerminate)); + view.SetResizeCallback(Dali::MakeCallback(DirectRenderingCode::resizeCB)); + view.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + view.SetProperty(Actor::Property::SIZE, Vector2(360.0f, 360.0f)); + + application.SendNotification(); + application.Render(); + + //To GlViewRenderThread can recognize Resize signal the main thread have to sleep. + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK(true); + END_TEST; +} + +int UtcDaliGlViewDirectRenderingTerminateCallback(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewDirectRenderingTerminateCallback"); + GlView view = Toolkit::GlView::New(GlView::BackendMode::DIRECT_RENDERING, GlView::ColorFormat::RGB888); + + application.GetScene().Add(view); + view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0); + view.RegisterGlCallbacks(Dali::MakeCallback(DirectRenderingCode::glInit), Dali::MakeCallback(DirectRenderingCode::glRenderFrame), Dali::MakeCallback(DirectRenderingCode::glTerminate)); + view.SetResizeCallback(Dali::MakeCallback(DirectRenderingCode::resizeCB)); + view.SetProperty(Actor::Property::ANCHOR_POINT, AnchorPoint::TOP_LEFT); + view.SetProperty(Actor::Property::SIZE, Vector2(360.0f, 360.0f)); + + application.SendNotification(); + application.Render(); + + + + //To GlViewRenderThread can recognize Resize signal the main thread have to sleep. + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK(true); + END_TEST; +} \ No newline at end of file diff --git a/dali-toolkit/internal/controls/gl-view/drawable-view-impl.cpp b/dali-toolkit/internal/controls/gl-view/drawable-view-impl.cpp new file mode 100644 index 0000000..9b94546 --- /dev/null +++ b/dali-toolkit/internal/controls/gl-view/drawable-view-impl.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2021 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// CLASS HEADER +#include + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include + +namespace Dali::Toolkit::Internal +{ +Dali::Toolkit::GlView DrawableView::New() +{ + auto* impl = new DrawableView(); + Dali::Toolkit::GlView handle = Dali::Toolkit::GlView(*impl); + impl->Initialize(); + return handle; +} + +DrawableView::DrawableView() +: Dali::Toolkit::Internal::GlViewImpl( GlView::BackendMode::DIRECT_RENDERING ), + mRenderingMode(Toolkit::GlView::RenderingMode::CONTINUOUS), + mDepth(false), + mStencil(false), + mMSAA(0) +{ + mRenderCallback = RenderCallback::New( this, &DrawableView::OnRenderCallback); +} + +DrawableView::~DrawableView() = default; + +void DrawableView::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) +{ + mOnInitCallback.reset( initCallback ); + mOnRenderCallback.reset(renderFrameCallback ); + mOnTerminateCallback. reset( terminateCallback ); +} + +void DrawableView::SetResizeCallback(CallbackBase* resizeCallback) +{ + mOnResizeCallback.reset( resizeCallback ); +} + +bool DrawableView::SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version) +{ + DALI_LOG_ERROR( "DrawableView::SetGraphicsConfig() is currently not implemented"); + + return true; +} + +void DrawableView::SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode) +{ + mRenderingMode = mode; + Renderer renderer = Self().GetRendererAt(0); + + if(mRenderingMode == Dali::Toolkit::GlView::RenderingMode::ON_DEMAND) + { + renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED); + } + else + { + renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY); + } +} + +Dali::Toolkit::GlView::RenderingMode DrawableView::GetRenderingMode() const +{ + return mRenderingMode; +} + +void DrawableView::RenderOnce() +{ + // Ignored. + // TODO: without rendering on the separate thread the RenderOnce won't + // work as expected. Potential implementation of threading may enable that + // feature. +} + +void DrawableView::OnInitialize() +{ + AddRenderer(); + + // Adding VisibilityChange Signal. + Actor self = Self(); + Dali::DevelActor::VisibilityChangedSignal(self).Connect(this, &DrawableView::OnControlVisibilityChanged); +} + +void DrawableView::OnSizeSet(const Vector3& targetSize) +{ + Control::OnSizeSet(targetSize); + + mSurfaceSize = targetSize; + + // If the callbacks are set then schedule execution of resize callback + if(mRenderCallback && mOnResizeCallback) + { + mSurfaceResized = true; + } +} + +void DrawableView::OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type) +{ + // Ignored due to lack dedicated rendering thread +} + +void DrawableView::OnWindowVisibilityChanged(Window window, bool visible) +{ + // Ignored due to lack dedicated rendering thread +} + +void DrawableView::OnSceneConnection(int depth) +{ + Control::OnSceneConnection(depth); + + Actor self = Self(); + Window window = DevelWindow::Get(self); + + // Despite OnWindowVisibilityChanged() is ignored it still should follow + // the designed behaviour of GlView so signal is connected regardless + if(window) + { + DevelWindow::VisibilityChangedSignal(window).Connect(this, &DrawableView::OnWindowVisibilityChanged); + } +} + +void DrawableView::OnSceneDisconnection() +{ + Control::OnSceneDisconnection(); +} + +void DrawableView::AddRenderer() +{ + Actor self = Self(); + Renderer renderer = Renderer::New( *mRenderCallback ); + self.AddRenderer(renderer); +} + +bool DrawableView::OnRenderCallback( const RenderCallbackInput& renderCallbackInput ) +{ + // Init state + if( mCurrentViewState == ViewState::INIT ) + { + if(mOnInitCallback) + { + CallbackBase::Execute(*mOnInitCallback); + } + mCurrentViewState = ViewState::RENDER; + } + + int renderFrameResult = 0; + if( mCurrentViewState == ViewState::RENDER ) + { + // The mSurfaceResized is set by another thread so atomic check must be provided + bool expected{ true }; + if(mSurfaceResized.compare_exchange_weak( expected, false, + std::memory_order_release, + std::memory_order_relaxed + ) && mOnResizeCallback) + { + CallbackBase::Execute(*mOnResizeCallback, static_cast(mSurfaceSize.x), static_cast(mSurfaceSize.y)); + } + + if(mOnRenderCallback) + { + renderFrameResult = CallbackBase::ExecuteReturn(*mOnRenderCallback); + if(renderFrameResult) + { + // TODO: may be utilized for RenderOnce feature + } + } + } + + // The terminate callback isn't easy to implement for DR. The NativeImage backend + // calls it when the GlView is being destroyed. For DrawableView it means that + // the RenderCallback won't be executed (as it is a part of graphics pipeline). + // We don't have currenty no way to know whether the View will be destroyed and + // to execute last native draw command in the pipeline. + // + // else if( mCurrentViewState == ViewState::TERMINATE ) + // { + // CallbackBase::Execute(*mOnTerminateCallback); + // } + + return true; +} + +} // namespace Dali diff --git a/dali-toolkit/internal/controls/gl-view/drawable-view-impl.h b/dali-toolkit/internal/controls/gl-view/drawable-view-impl.h new file mode 100644 index 0000000..c61832a --- /dev/null +++ b/dali-toolkit/internal/controls/gl-view/drawable-view-impl.h @@ -0,0 +1,168 @@ +#ifndef DALI_TOOLKIT_INTERNAL_DRAWABLE_VIEW_H +#define DALI_TOOLKIT_INTERNAL_DRAWABLE_VIEW_H + +/* + * Copyright (c) 2021 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. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include +#include +#include "gl-view-interface-impl.h" + +// INTERNAL INCLUDES +#include +#include +#include + +namespace Dali::Toolkit +{ +class GlView; + +namespace Internal +{ +class DrawableView : public Dali::Toolkit::Internal::GlViewImpl +{ +protected: + virtual ~DrawableView(); + +public: + /** + * @copydoc Dali::Toolkit::GlView::New() + */ + static Dali::Toolkit::GlView New(); + + /** + * Construct a new GlView. + */ + DrawableView(); + + /** + * @copydoc Dali::Toolkit::GlView::RegisterGlCallbacks() + */ + void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) override; + + /** + * @copydoc Dali::Toolkit::GlView::SetResizeCallback() + */ + void SetResizeCallback(CallbackBase* resizeCallback) override; + + /** + * @copydoc Dali::Toolkit::GlView::SetGraphicsConfig() + */ + bool SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version) override; + + /** + * @copydoc Dali::Toolkit::GlView::SetRenderingMode() + */ + void SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode) override; + + /** + * @copydoc Dali::Toolkit::GlView::GetRenderingMode() + */ + Dali::Toolkit::GlView::RenderingMode GetRenderingMode() const override; + + /** + * @copydoc Dali::Toolkit::GlView::RenderOnce() + */ + void RenderOnce(); + +private: // From Control + /** + * @copydoc Toolkit::Control::OnInitialize() + */ + virtual void OnInitialize() override; + + /** + * @copydoc Toolkit::Control::OnSceneConnection() + */ + void OnSceneConnection(int depth) override; + + /** + * @copydoc Toolkit::Control::OnSceneDisconnection() + */ + void OnSceneDisconnection() override; + + /** + * @copydoc Toolkit::Control::OnSizeSet() + */ + void OnSizeSet(const Vector3& targetSize) override; + +private: + // Undefined copy constructor and assignment operators + DrawableView(const DrawableView& GlView); + DrawableView& operator=(const DrawableView& GlView); + + /** + * Callback when the visibility of the GlView is changed + */ + void OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type); + + /** + * Callback when the visibility of the window is changed + */ + void OnWindowVisibilityChanged(Dali::Window window, bool visible); + + /** + * Adds renderer to Actor. + */ + void AddRenderer(); + +private: + + bool OnRenderCallback( const RenderCallbackInput& renderCallbackInput ); + +private: + Dali::Toolkit::GlView::RenderingMode mRenderingMode; + + bool mDepth; + bool mStencil; + int mMSAA; + + std::unique_ptr mRenderCallback; + + /* + * Used within RenderCallback to handle the current render state + */ + enum class ViewState + { + INIT, + RENDER, + TERMINATE + }; + + ViewState mCurrentViewState{ViewState::INIT}; ///< state within RenderCallback + + // These callbacks are stored for GLView API compatibility + std::unique_ptr mOnInitCallback; + std::unique_ptr mOnRenderCallback; + std::unique_ptr mOnTerminateCallback; + std::unique_ptr mOnResizeCallback; + + std::atomic_bool mSurfaceResized{false}; ///< Flag to invoke surface resize callback + + Size mSurfaceSize{}; ///< Surface size +}; + +} // namespace Internal + +} // namespace Dali + +#endif // DALI_TOOLKIT_INTERNAL_DRAWABLE_VIEW_H diff --git a/dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp b/dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp index b37189a..2eaf78c 100644 --- a/dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp +++ b/dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp @@ -40,14 +40,14 @@ namespace Internal { Dali::Toolkit::GlView GlView::New(Dali::Toolkit::GlView::ColorFormat colorFormat) { - GlView* impl = new GlView(colorFormat); + auto* impl = new Dali::Toolkit::Internal::GlView(colorFormat); Dali::Toolkit::GlView handle = Dali::Toolkit::GlView(*impl); impl->Initialize(); return handle; } GlView::GlView(Dali::Toolkit::GlView::ColorFormat colorFormat) -: Control(ControlBehaviour(ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS)), +: Dali::Toolkit::Internal::GlViewImpl( Toolkit::GlView::BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING ), mRenderThread(nullptr), mNativeImageQueue(nullptr), mRenderingMode(Toolkit::GlView::RenderingMode::CONTINUOUS), diff --git a/dali-toolkit/internal/controls/gl-view/gl-view-impl.h b/dali-toolkit/internal/controls/gl-view/gl-view-impl.h index 2dcb0b1..306a53b 100644 --- a/dali-toolkit/internal/controls/gl-view/gl-view-impl.h +++ b/dali-toolkit/internal/controls/gl-view/gl-view-impl.h @@ -27,18 +27,18 @@ // INTERNAL INCLUDES #include +#include #include #include -namespace Dali -{ -namespace Toolkit + +namespace Dali::Toolkit { class GlView; namespace Internal { -class GlView : public Dali::Toolkit::Internal::Control +class GlView : public Dali::Toolkit::Internal::GlViewImpl { protected: virtual ~GlView(); @@ -57,32 +57,32 @@ public: /** * @copydoc Dali::Toolkit::GlView::RegisterGlCallbacks() */ - void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback); + void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) override; /** * @copydoc Dali::Toolkit::GlView::SetResizeCallback() */ - void SetResizeCallback(CallbackBase* resizeCallback); + void SetResizeCallback(CallbackBase* resizeCallback) override; /** - * @copydoc Dali::Toolkit::GlView::SetGraphisConfig() + * @copydoc Dali::Toolkit::GlView::SetGraphicsConfig() */ - bool SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version); + bool SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version) override; /** * @copydoc Dali::Toolkit::GlView::SetRenderingMode() */ - void SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode); + void SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode) override; /** * @copydoc Dali::Toolkit::GlView::GetRenderingMode() */ - Dali::Toolkit::GlView::RenderingMode GetRenderingMode() const; + Dali::Toolkit::GlView::RenderingMode GetRenderingMode() const override; /** * @copydoc Dali::Toolkit::GlView::RenderOnce() */ - void RenderOnce(); + void RenderOnce() override; private: // From Control /** @@ -155,22 +155,6 @@ private: } // namespace Internal -inline Dali::Toolkit::Internal::GlView& GetImpl(Dali::Toolkit::GlView& handle) -{ - DALI_ASSERT_ALWAYS(handle); - Dali::RefObject& impl = handle.GetImplementation(); - return static_cast(impl); -} - -inline const Dali::Toolkit::Internal::GlView& GetImpl(const Dali::Toolkit::GlView& handle) -{ - DALI_ASSERT_ALWAYS(handle); - const Dali::RefObject& impl = handle.GetImplementation(); - return static_cast(impl); -} - -} // namespace Toolkit - } // namespace Dali #endif // DALI_TOOLKIT_INTERNAL_GL_VIEW_H diff --git a/dali-toolkit/internal/controls/gl-view/gl-view-interface-impl.h b/dali-toolkit/internal/controls/gl-view/gl-view-interface-impl.h new file mode 100644 index 0000000..5547789 --- /dev/null +++ b/dali-toolkit/internal/controls/gl-view/gl-view-interface-impl.h @@ -0,0 +1,133 @@ +#ifndef DALI_TOOLKIT_INTERNAL_GL_VIEW_IMPL_H +#define DALI_TOOLKIT_INTERNAL_GL_VIEW_IMPL_H + +/* + * Copyright (c) 2022 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. + * + */ + +// EXTERNAL INCLUDES +#include +#include +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include +#include + +namespace Dali::Toolkit +{ +class GlView; + +namespace Internal +{ +class GlViewImpl : public Dali::Toolkit::Internal::Control +{ +protected: + + virtual ~GlViewImpl() = default; + +public: + + /** + * Construct a new GlView. + */ + explicit GlViewImpl( GlView::BackendMode backendMode ) : + Control(ControlBehaviour(0u | ACTOR_BEHAVIOUR_DEFAULT | DISABLE_STYLE_CHANGE_SIGNALS)), + mBackendMode(backendMode) + { + } + + /** + * @copydoc Dali::Toolkit::GlView::RegisterGlCallbacks() + */ + virtual void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) = 0; + + /** + * @copydoc Dali::Toolkit::GlView::SetResizeCallback() + */ + virtual void SetResizeCallback(CallbackBase* resizeCallback) = 0; + + /** + * @copydoc Dali::Toolkit::GlView::SetGraphisConfig() + */ + virtual bool SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version) = 0; + + /** + * @copydoc Dali::Toolkit::GlView::SetRenderingMode() + */ + virtual void SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode) = 0; + + /** + * @copydoc Dali::Toolkit::GlView::GetRenderingMode() + */ + virtual Dali::Toolkit::GlView::RenderingMode GetRenderingMode() const = 0; + + /** + * @copydoc Dali::Toolkit::GlView::GetBackendMode() + */ + [[nodiscard]] Dali::Toolkit::GlView::BackendMode GetBackendMode() const + { + return mBackendMode; + } + + /** + * @copydoc Dali::Toolkit::GlView::RenderOnce() + */ + virtual void RenderOnce() = 0; + +private: // From Control + /** + * @copydoc Toolkit::Control::OnInitialize() + */ + virtual void OnInitialize() override = 0; + + /** + * @copydoc Toolkit::Control::OnSceneConnection() + */ + virtual void OnSceneConnection(int depth) override = 0; + + /** + * @copydoc Toolkit::Control::OnSceneDisconnection() + */ + virtual void OnSceneDisconnection() override = 0; + +protected: + + GlView::BackendMode mBackendMode { GlView::BackendMode::DEFAULT }; ///< Implementation backend mode (DirectRendering, EGL image) +}; + +} // namespace Internal + +inline Dali::Toolkit::Internal::GlViewImpl& GetImpl(Dali::Toolkit::GlView& handle) +{ + DALI_ASSERT_ALWAYS(handle); + Dali::RefObject& impl = handle.GetImplementation(); + return static_cast(impl); +} + +inline const Dali::Toolkit::Internal::GlViewImpl& GetImpl(const Dali::Toolkit::GlView& handle) +{ + DALI_ASSERT_ALWAYS(handle); + const Dali::RefObject& impl = handle.GetImplementation(); + return static_cast(impl); +} + +} // namespace Dali + +#endif // DALI_TOOLKIT_INTERNAL_GL_VIEW_IMPL_H diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 355667e..3a280b3 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -117,6 +117,7 @@ SET( toolkit_src_files ${toolkit_src_dir}/controls/video-view/video-view-impl.cpp ${toolkit_src_dir}/controls/web-view/web-view-impl.cpp ${toolkit_src_dir}/controls/camera-view/camera-view-impl.cpp + ${toolkit_src_dir}/controls/gl-view/drawable-view-impl.cpp ${toolkit_src_dir}/controls/gl-view/gl-view-impl.cpp ${toolkit_src_dir}/controls/gl-view/gl-view-render-thread.cpp ${toolkit_src_dir}/accessibility-manager/accessibility-manager-impl.cpp diff --git a/dali-toolkit/public-api/controls/gl-view/gl-view.cpp b/dali-toolkit/public-api/controls/gl-view/gl-view.cpp index 958d031..91939c0 100644 --- a/dali-toolkit/public-api/controls/gl-view/gl-view.cpp +++ b/dali-toolkit/public-api/controls/gl-view/gl-view.cpp @@ -19,15 +19,13 @@ #include // INTERNAL INCLUDES +#include #include -namespace Dali +namespace Dali::Toolkit { -namespace Toolkit -{ -GlView::GlView() -{ -} + +GlView::GlView() = default; GlView::GlView(const GlView& GlView) = default; @@ -37,18 +35,38 @@ GlView& GlView::operator=(const GlView& GlView) = default; GlView& GlView::operator=(GlView&& rhs) = default; -GlView::~GlView() +GlView::~GlView() = default; + +GlView GlView::New(ColorFormat colorFormat) { + // This function is backward compatible and always returns + // backend based on NativeImage. + return Internal::GlView::New( colorFormat ); } -GlView GlView::New(ColorFormat colorFormat) +GlView GlView::New(BackendMode backendMode, ColorFormat colorFormat) { - return Internal::GlView::New(colorFormat); + switch(backendMode) + { + case BackendMode::DIRECT_RENDERING: + { + return Internal::DrawableView::New(); + } + case BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING: + { + return Internal::GlView::New(colorFormat); + } + default: + { + DALI_ASSERT_ALWAYS("Invalid BackendMode"); + } + } + return {}; } GlView GlView::DownCast(BaseHandle handle) { - return Control::DownCast(handle); + return Control::DownCast(handle); } void GlView::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) @@ -76,12 +94,17 @@ Dali::Toolkit::GlView::RenderingMode GlView::GetRenderingMode() const return Dali::Toolkit::GetImpl(*this).GetRenderingMode(); } +Dali::Toolkit::GlView::BackendMode GlView::GetBackendMode() const +{ + return Dali::Toolkit::GetImpl(*this).GetBackendMode(); +} + void GlView::RenderOnce() { Dali::Toolkit::GetImpl(*this).RenderOnce(); } -GlView::GlView(Internal::GlView& implementation) +GlView::GlView(Internal::GlViewImpl& implementation) : Control(implementation) { } @@ -89,9 +112,7 @@ GlView::GlView(Internal::GlView& implementation) GlView::GlView(Dali::Internal::CustomActor* internal) : Control(internal) { - VerifyCustomActorPointer(internal); + VerifyCustomActorPointer(internal); } -} // namespace Toolkit - } // namespace Dali diff --git a/dali-toolkit/public-api/controls/gl-view/gl-view.h b/dali-toolkit/public-api/controls/gl-view/gl-view.h index 57c3201..099b00f 100644 --- a/dali-toolkit/public-api/controls/gl-view/gl-view.h +++ b/dali-toolkit/public-api/controls/gl-view/gl-view.h @@ -26,7 +26,7 @@ namespace Toolkit { namespace Internal DALI_INTERNAL { -class GlView; +class GlViewImpl; } /** @@ -36,10 +36,42 @@ class GlView; * GlView creates a GL context, a GL surface and a render thread. * The render thread invokes user's callbacks. * + * @SINCE_2_0.45 */ class DALI_TOOLKIT_API GlView : public Dali::Toolkit::Control { public: + + /** + * @brief Implementation backend mode + * + * @SINCE_2_1.18 + */ + enum class BackendMode + { + /** + * DIRECT_RENDERING mode executes GL code within DALi graphics + * pipeline. When Renderer is about to be drawn, the callback + * will be executed and the custom code "injected" into the pipeline. + * This allows rendering directly to the surface rather than offscreen. + */ + DIRECT_RENDERING = 0, + + /** + * EGL_IMAGE_OFFSCREEN_RENDERING mode executes GL code in own thread + * and renders to the offscreen NativeImage (EGL) buffer. This backend + * will render in parallel but has higher memory footprint and may suffer + * performance issues due to using EGL image. + */ + EGL_IMAGE_OFFSCREEN_RENDERING, + + /** + * The default mode is set to EGL_IMAGE_OFFSCREEN_RENDERING for backwards + * compatibility. + */ + DEFAULT = EGL_IMAGE_OFFSCREEN_RENDERING + }; + /** * @brief Enumeration for rendering mode * @@ -47,6 +79,8 @@ public: * It has two options. * One of them is continuous mode. It is rendered continuously. * The other is on demand mode. It is rendered by application. + * + * @SINCE_2_0.45 */ enum class RenderingMode { @@ -58,6 +92,8 @@ public: * @brief Enumeration for Graphics API version * * This Enumeration is used to set a GLES version for EGL configuration. + * + * @SINCE_2_0.45 */ enum class GraphicsApiVersion { @@ -69,6 +105,8 @@ public: * @brief Enumeration for color buffer format * * This Enumeration is used to set a color buffer format of GlView + * + * @SINCE_2_0.45 */ enum class ColorFormat { @@ -78,13 +116,34 @@ public: /** * @brief Creates a GlView control. + * + * @note This function always creates the GlView with NativeImage backend. + * * @param[in] colorFormat the format of the color buffer. * @return A handle to a GlView control + * + * @SINCE_2_0.45 */ static GlView New(ColorFormat colorFormat); /** + * @brief Creates a GlView control. + * + * The new GlView will be created with specified backend. + * The colorFormat is ignored for DIRECT_RENDERING backend. + * + * @param[in] colorFormat the format of the color buffer. + * @param[in] backendMode the backend used by the GlView + * @return A handle to a GlView control + * + * @SINCE_2_1.18 + */ + static GlView New(BackendMode backendMode, ColorFormat colorFormat); + + /** * @brief Creates an uninitialized GlView. + * + * @SINCE_2_0.45 */ GlView(); @@ -92,6 +151,8 @@ public: * @brief Destructor. * * This is non-virtual since derived Handle types must not contain data or virtual methods. + * + * @SINCE_2_0.45 */ ~GlView(); @@ -99,6 +160,8 @@ public: * @brief Copy constructor. * * @param[in] GlView GlView to copy. The copied GlView will point at the same implementation + * + * @SINCE_2_0.45 */ GlView(const GlView& GlView); @@ -106,6 +169,8 @@ public: * @brief Move constructor * * @param[in] rhs A reference to the moved handle + * + * @SINCE_2_0.45 */ GlView(GlView&& rhs); @@ -114,6 +179,8 @@ public: * * @param[in] GlView The GlView to assign from * @return A reference to this + * + * @SINCE_2_0.45 */ GlView& operator=(const GlView& GlView); @@ -122,6 +189,8 @@ public: * * @param[in] rhs A reference to the moved handle * @return A reference to this + * + * @SINCE_2_0.45 */ GlView& operator=(GlView&& rhs); @@ -133,6 +202,8 @@ public: * * @param[in] handle Handle to an object * @return Handle to a GlView or an uninitialized handle + * + * @SINCE_2_0.45 */ static GlView DownCast(BaseHandle handle); @@ -164,6 +235,8 @@ public: * @note Ownership of the callbacks is passed onto this class. * You can't call Dali APIs in your callbacks because it is invoked in GlView's own render thread. * And this must be called before adding GlView to the scene. + * + * @SINCE_2_0.45 */ void RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback); @@ -182,6 +255,8 @@ public: * @note Ownership of the callback is passed onto this class. * You can't call Dali APIs in your callback because it is invoked in GlView's own render thread. * And this must be called before adding GlView to the scene. + * + * @SINCE_2_0.45 */ void SetResizeCallback(CallbackBase* resizeCallback); @@ -192,13 +267,24 @@ public: * * @note The default Rendering mode is CONTINUOUS. * If ON_DEMAND mode is set, it is rendered by RenderOnce() + * + * @SINCE_2_0.45 */ void SetRenderingMode(RenderingMode mode); /** * @brief Gets the rendering mode. + * + * @SINCE_2_0.45 + */ + [[nodiscard]] RenderingMode GetRenderingMode() const; + + /** + * @brief Gets the backend mode. + * + * @SINCE_2_1.18 */ - RenderingMode GetRenderingMode() const; + [[nodiscard]] BackendMode GetBackendMode() const; /** * @brief Sets egl configuration for GlView @@ -208,12 +294,16 @@ public: * @param[in] msaa the expected sampling number per pixel. * @param[in] version the graphics API version * @return True if the config exists, false otherwise. + * + * @SINCE_2_0.45 */ bool SetGraphicsConfig(bool depth, bool stencil, int msaa, GraphicsApiVersion version); /** * @brief Renders once more even if GL render functions are not added to idler. * @note Will not work if the window is hidden or GL render functions are added to idler + * + * @SINCE_2_0.45 */ void RenderOnce(); @@ -222,12 +312,16 @@ public: // Not intended for application developers /** * @brief Creates a handle using the Toolkit::Internal implementation. * @param[in] implementation The GlView implementation + * + * @SINCE_2_0.45 */ - DALI_INTERNAL GlView(Internal::GlView& implementation); + DALI_INTERNAL GlView(Internal::GlViewImpl& implementation); /** * @brief Allows the creation of this GlView from an Internal::CustomActor pointer. * @param[in] internal A pointer to the internal CustomActor + * + * @SINCE_2_0.45 */ DALI_INTERNAL GlView(Dali::Internal::CustomActor* internal); /// @endcond -- 2.7.4