From 3a012b5ebf038a166d187ab173d229fd835b1eb9 Mon Sep 17 00:00:00 2001 From: Daekwang Ryu Date: Fri, 17 Sep 2021 18:01:42 +0900 Subject: [PATCH] Add GlView GlView allows drawing with OpenGL. It creates a context, a surface and a render thread. The render thread invokes user's callbacks. Change-Id: I936313d32f1ce6653e1b1ce0a45f16f216c3f665 --- automated-tests/src/dali-toolkit/CMakeLists.txt | 1 + .../dali-toolkit-test-utils/toolkit-window-impl.h | 1 + .../dali-toolkit-test-utils/toolkit-window.cpp | 7 + .../dali-toolkit-test-utils/toolkit-window.h | 1 + .../src/dali-toolkit/utc-Dali-GlView.cpp | 333 ++++++++++++++++++++ dali-toolkit/dali-toolkit.h | 1 + .../internal/controls/gl-view/gl-view-impl.cpp | 342 +++++++++++++++++++++ .../internal/controls/gl-view/gl-view-impl.h | 176 +++++++++++ .../controls/gl-view/gl-view-render-thread.cpp | 295 ++++++++++++++++++ .../controls/gl-view/gl-view-render-thread.h | 179 +++++++++++ dali-toolkit/internal/file.list | 2 + .../internal/graphics/shaders/gl-view.frag | 8 + .../internal/graphics/shaders/gl-view.vert | 11 + .../public-api/controls/gl-view/gl-view.cpp | 97 ++++++ dali-toolkit/public-api/controls/gl-view/gl-view.h | 240 +++++++++++++++ dali-toolkit/public-api/file.list | 6 + 16 files changed, 1700 insertions(+) create mode 100644 automated-tests/src/dali-toolkit/utc-Dali-GlView.cpp create mode 100644 dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp create mode 100644 dali-toolkit/internal/controls/gl-view/gl-view-impl.h create mode 100644 dali-toolkit/internal/controls/gl-view/gl-view-render-thread.cpp create mode 100644 dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h create mode 100644 dali-toolkit/internal/graphics/shaders/gl-view.frag create mode 100644 dali-toolkit/internal/graphics/shaders/gl-view.vert create mode 100644 dali-toolkit/public-api/controls/gl-view/gl-view.cpp create mode 100644 dali-toolkit/public-api/controls/gl-view/gl-view.h diff --git a/automated-tests/src/dali-toolkit/CMakeLists.txt b/automated-tests/src/dali-toolkit/CMakeLists.txt index 8990a0f..b1aece3 100755 --- a/automated-tests/src/dali-toolkit/CMakeLists.txt +++ b/automated-tests/src/dali-toolkit/CMakeLists.txt @@ -78,6 +78,7 @@ SET(TC_SOURCES utc-Dali-ControlWrapper.cpp utc-Dali-DragAndDropDetector.cpp utc-Dali-NPatchUtilities.cpp + utc-Dali-GlView.cpp ) # List of test harness files (Won't get parsed for test cases) diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window-impl.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window-impl.h index dc7a206..9044964 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window-impl.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window-impl.h @@ -54,6 +54,7 @@ public: FocusChangeSignalType mFocusChangeSignal; ResizeSignalType mResizeSignal; int mRotationAngle; + bool mVisible; DevelWindow::VisibilityChangedSignalType mVisibilityChangedSignal; }; diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp index d0a3e4f..b8cc1bc 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.cpp @@ -48,6 +48,7 @@ Window::Window( const PositionSize& positionSize ) mFocusChangeSignal(), mResizeSignal(), mRotationAngle(90), // dummy angle for test coverage + mVisible(true), mVisibilityChangedSignal() { } @@ -183,6 +184,12 @@ void Window::Raise() void Window::Hide() { GetImplementation( *this ).mVisibilityChangedSignal.Emit( *this, false ); + GetImplementation( *this ).mVisible = false; +} + +bool Window::IsVisible() const +{ + return GetImplementation( *this ).mVisible; } FocusChangeSignalType& Window::FocusChangeSignal() diff --git a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h index a696684..d102f6a 100644 --- a/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h +++ b/automated-tests/src/dali-toolkit/dali-toolkit-test-utils/toolkit-window.h @@ -77,6 +77,7 @@ public: Vector4 GetBackgroundColor() const; void Raise(); void Hide(); + bool IsVisible() const; FocusChangeSignalType& FocusChangeSignal(); KeyEventSignalType& KeyEventSignal(); TouchEventSignalType& TouchedSignal(); diff --git a/automated-tests/src/dali-toolkit/utc-Dali-GlView.cpp b/automated-tests/src/dali-toolkit/utc-Dali-GlView.cpp new file mode 100644 index 0000000..9f74b72 --- /dev/null +++ b/automated-tests/src/dali-toolkit/utc-Dali-GlView.cpp @@ -0,0 +1,333 @@ +/* + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +using namespace Dali; +using namespace Dali::Toolkit; + +// Positive test case for a method +int UtcDaliGlViewNew(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliGlViewNew"); + GlView view = GlView::New(GlView::ColorFormat::RGBA8888); + DALI_TEST_CHECK( view ); + END_TEST; +} + +// Positive test case for a method +int UtcDaliGlViewDownCast(void) +{ + ToolkitTestApplication application; + tet_infoline(" UtcDaliGlViewDownCast"); + + GlView view = GlView::New(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 UtcDaliGlViewCopyAndAssignment(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewCopyAndAssignment"); + + GlView view = Toolkit::GlView::New(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 UtcDaliGlViewMoveAssignment(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewMoveAssignment"); + + GlView view = Toolkit::GlView::New(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 UtcDaliGlViewSetGraphicsConfigGles20N(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewSetGraphicsConfigGles20"); + 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 UtcDaliGlViewSetGraphicsConfigGles30(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewSetGraphicsConfigGles30"); + GlView view = Toolkit::GlView::New(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 UtcDaliGlViewRenderingMode(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewRenderingMode"); + GlView view = Toolkit::GlView::New(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 UtcDaliGlViewOnSizeSet(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewOnSizeSet"); + GlView view = Toolkit::GlView::New(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< Vector3 >( Actor::Property::SIZE ), size, TEST_LOCATION ); + + END_TEST; +} + + +// Internal callback function +void glInit(void) +{ +} + +int glRenderFrame(void) +{ + static unsigned int retFlag = 0; + return retFlag++; +} + +void glTerminate(void) +{ +} + +void resizeCB(Vector2 size) +{ +} + +int UtcDaliGlViewRegisterGlCallbackN(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewRegisterGlCallback"); + GlView view; + + try + { + view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate)); + DALI_TEST_CHECK(false); + } + catch(...) + { + DALI_TEST_CHECK(true); + } + END_TEST; +} + +int UtcDaliGlViewSetResizeCallbackN(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewSetResizeCallback"); + GlView view; + + try + { + view.SetResizeCallback(Dali::MakeCallback(resizeCB)); + DALI_TEST_CHECK(false); + } + catch(...) + { + DALI_TEST_CHECK(true); + } + END_TEST; +} + +int UtcDaliGlViewRenderOnce(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewRenderOnce"); + GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888); + + try + { + view.RenderOnce(); + DALI_TEST_CHECK(true); + } + catch(...) + { + DALI_TEST_CHECK(false); + } + END_TEST; +} + +int UtcDaliGlViewWindowVisibilityChanged(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewWindowVisibilityChanged"); + GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888); + application.GetScene().Add( view ); + view.SetRenderingMode(GlView::RenderingMode::CONTINUOUS); + view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0); + view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate)); + view.SetResizeCallback(Dali::MakeCallback(resizeCB)); + + application.SendNotification(); + application.Render(); + + Window window = DevelWindow::Get( view ); + window.Hide(); + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK(true); + END_TEST; +} + +int UtcDaliGlViewOnScene(void) +{ + ToolkitTestApplication application; + + GlView view = Toolkit::GlView::New(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.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate)); + + application.SendNotification(); + application.Render(); + + //Offscene + application.GetScene().Remove(view); + + application.SendNotification(); + application.Render(); + + DALI_TEST_CHECK(true); + END_TEST; +} + +int UtcDaliGlViewControlVisibilityChanged(void) +{ + ToolkitTestApplication application; + + GlView view = Toolkit::GlView::New(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 UtcDaliGlViewResize(void) +{ + ToolkitTestApplication application; + tet_infoline("UtcDaliGlViewResize"); + GlView view = Toolkit::GlView::New(GlView::ColorFormat::RGB888); + + application.GetScene().Add( view ); + view.SetGraphicsConfig(true, true, 0, GlView::GraphicsApiVersion::GLES_VERSION_2_0); + view.RegisterGlCallback(Dali::MakeCallback(glInit), Dali::MakeCallback(glRenderFrame), Dali::MakeCallback(glTerminate)); + view.SetResizeCallback(Dali::MakeCallback(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; +} diff --git a/dali-toolkit/dali-toolkit.h b/dali-toolkit/dali-toolkit.h index 1ec7fa3..99621c8 100644 --- a/dali-toolkit/dali-toolkit.h +++ b/dali-toolkit/dali-toolkit.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp b/dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp new file mode 100644 index 0000000..64e31d6 --- /dev/null +++ b/dali-toolkit/internal/controls/gl-view/gl-view-impl.cpp @@ -0,0 +1,342 @@ +/* + * 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 +#include +#include +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ +Dali::Toolkit::GlView GlView::New(Dali::Toolkit::GlView::ColorFormat colorFormat) +{ + GlView* impl = new 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)), + mRenderThread(nullptr), + mNativeImageQueue(nullptr), + mRenderingMode(Toolkit::GlView::RenderingMode::CONTINUOUS), + mColorFormat(colorFormat), + mDepth(false), + mStencil(false), + mMSAA(0) +{ +} + +GlView::~GlView() +{ + if(mRenderThread) + { + mRenderThread->Stop(); + mRenderThread->Join(); + } +} + +void GlView::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) +{ + if(mRenderThread) + { + mRenderThread->RegisterGlCallback(initCallback, renderFrameCallback, terminateCallback); + } +} + +void GlView::SetResizeCallback(CallbackBase* resizeCallback) +{ + if(mRenderThread) + { + mRenderThread->SetResizeCallback(resizeCallback); + } +} + +bool GlView::SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version) +{ + // Init Graphics + mDepth = depth; + mStencil = stencil; + mMSAA = msaa; + + int rVersion; + + if(version == Dali::Toolkit::GlView::GraphicsApiVersion::GLES_VERSION_2_0) + { + rVersion = 20; + } + else + { + rVersion = 30; + } + + if(mRenderThread) + { + return mRenderThread->SetGraphicsConfig(depth, stencil, msaa, rVersion); + } + + return false; +} + +void GlView::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); + + if(mRenderThread) + { + mRenderThread->SetOnDemandRenderMode(true); + } + } + else + { + renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY); + + if(mRenderThread) + { + mRenderThread->SetOnDemandRenderMode(false); + } + } +} + +Dali::Toolkit::GlView::RenderingMode GlView::GetRenderingMode() const +{ + return mRenderingMode; +} + +void GlView::RenderOnce() +{ + if(mRenderThread) + { + mRenderThread->RenderOnce(); + } +} + +void GlView::OnInitialize() +{ + //Create NativeImageSourceQueue with the size of 1,1 + mNativeImageQueue = Dali::NativeImageSourceQueue::New(1, 1, GetColorFormat(mColorFormat)); + + if(!mNativeImageQueue) + { + DALI_LOG_ERROR("NativeImageSourceQueue is NULL"); + return; + } + + AddRenderer(); + + Actor self = Self(); + + //Create a RenderThread + mRenderThread = std::unique_ptr(new GlViewRenderThread(mNativeImageQueue)); + if(!mRenderThread) + { + DALI_LOG_ERROR("Fail to create GlView Render Thread!!!!\n"); + return; + } + + //Adding VisibilityChange Signal. + Dali::DevelActor::VisibilityChangedSignal(self).Connect(this, &GlView::OnControlVisibilityChanged); +} + +void GlView::OnSizeSet(const Vector3& targetSize) +{ + Control::OnSizeSet(targetSize); + + if(mRenderThread) + { + if(mNativeImageQueue) + { + mRenderThread->AcquireSurface(); + mNativeImageQueue->SetSize(static_cast(targetSize.x), static_cast(targetSize.y)); + mRenderThread->SetSurfaceSize(Vector2(targetSize.x, targetSize.y)); + mRenderThread->ReleaseSurface(); + } + } +} + +Shader GlView::CreateShader() +{ + std::string fragmentShader = std::string(SHADER_GL_VIEW_FRAG); + + if(mNativeImageQueue) + { + mNativeImageQueue->ApplyNativeFragmentShader(fragmentShader); + } + + return Shader::New(SHADER_GL_VIEW_VERT, fragmentShader); +} + +void GlView::OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type) +{ + Actor self = Self(); + if(self.GetProperty(Actor::Property::CONNECTED_TO_SCENE)) + { + if(mRenderThread) + { + if(visible && DevelWindow::Get(self).IsVisible()) + { + mRenderThread->Resume(); + } + else + { + mRenderThread->Pause(); + } + } + } +} + +void GlView::OnWindowVisibilityChanged(Window window, bool visible) +{ + if(mRenderThread) + { + if(visible && Self().GetProperty(Actor::Property::VISIBLE)) + { + mRenderThread->Resume(); + } + else + { + mRenderThread->Pause(); + } + } +} + +void GlView::OnSceneConnection(int depth) +{ + Control::OnSceneConnection(depth); + + Actor self = Self(); + Window window = DevelWindow::Get(self); + + if(window) + { + DevelWindow::VisibilityChangedSignal(window).Connect(this, &GlView::OnWindowVisibilityChanged); + } + + if(mRenderThread) + { + if(self.GetProperty(Actor::Property::VISIBLE) && window.IsVisible()) + { + mRenderThread->Resume(); + } + } +} + +void GlView::OnSceneDisconnection() +{ + Control::OnSceneDisconnection(); + if(mRenderThread) + { + mRenderThread->Pause(); + } +} + +Dali::Geometry GlView::CreateTexturedQuad() +{ + struct Vertex + { + Dali::Vector2 position; + }; + + static const Vertex data[] = {{Dali::Vector2(-0.5f, -0.5f)}, + {Dali::Vector2(0.5f, -0.5f)}, + {Dali::Vector2(-0.5f, 0.5f)}, + {Dali::Vector2(0.5f, 0.5f)}}; + + uint32_t numberOfVertices = sizeof(data) / sizeof(Vertex); + + Dali::VertexBuffer vertexBuffer; + Dali::Property::Map vertexFormat; + vertexFormat["aPosition"] = Dali::Property::VECTOR2; + + //Create a vertex buffer for vertex positions and texture coordinates + vertexBuffer = Dali::VertexBuffer::New(vertexFormat); + vertexBuffer.SetData(data, numberOfVertices); + + //Create the geometry + Dali::Geometry geometry = Dali::Geometry::New(); + geometry.AddVertexBuffer(vertexBuffer); + geometry.SetType(Dali::Geometry::TRIANGLE_STRIP); + + return geometry; +} + +void GlView::AddRenderer() +{ + if(!mNativeImageQueue) + { + DALI_LOG_ERROR("Target Surface is NULL"); + return; + } + + Actor self = Self(); + Geometry geometry = CreateTexturedQuad(); + Shader shader = CreateShader(); + Renderer renderer = Renderer::New(geometry, shader); + + Texture nativeTexture = Texture::New(*mNativeImageQueue); + TextureSet textureSet = TextureSet::New(); + textureSet.SetTexture(0u, nativeTexture); + + renderer.SetTextures(textureSet); + + self.AddRenderer(renderer); +} + +Dali::NativeImageSourceQueue::ColorFormat GlView::GetColorFormat(Dali::Toolkit::GlView::ColorFormat format) +{ + switch(format) + { + case Toolkit::GlView::ColorFormat::RGBA8888: + { + return Dali::NativeImageSourceQueue::ColorFormat::RGBA8888; + } + + case Toolkit::GlView::ColorFormat::RGB888: + default: + { + return Dali::NativeImageSourceQueue::ColorFormat::RGBX8888; + } + } +} + +} // namespace Internal + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/controls/gl-view/gl-view-impl.h b/dali-toolkit/internal/controls/gl-view/gl-view-impl.h new file mode 100644 index 0000000..c0114ca --- /dev/null +++ b/dali-toolkit/internal/controls/gl-view/gl-view-impl.h @@ -0,0 +1,176 @@ +#ifndef DALI_TOOLKIT_INTERNAL_GL_VIEW_H +#define DALI_TOOLKIT_INTERNAL_GL_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 + +// INTERNAL INCLUDES +#include +#include +#include + +namespace Dali +{ +namespace Toolkit +{ +class GlView; + +namespace Internal +{ +class GlView : public Dali::Toolkit::Internal::Control +{ +protected: + virtual ~GlView(); + +public: + /** + * @copydoc Dali::Toolkit::GlView::New() + */ + static Dali::Toolkit::GlView New(Dali::Toolkit::GlView::ColorFormat colorFormat); + + /** + * Construct a new GlView. + */ + GlView(Dali::Toolkit::GlView::ColorFormat colorFormat); + + /** + * @copydoc Dali::Toolkit::GlView::RegisterGlCallback() + */ + void RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback); + + /** + * @copydoc Dali::Toolkit::GlView::SetResizeCallback() + */ + void SetResizeCallback(CallbackBase* resizeCallback); + + /** + * @copydoc Dali::Toolkit::GlView::SetGraphisConfig() + */ + bool SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version); + + /** + * @copydoc Dali::Toolkit::GlView::SetRenderingMode() + */ + void SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode); + + /** + * @copydoc Dali::Toolkit::GlView::GetRenderingMode() + */ + Dali::Toolkit::GlView::RenderingMode GetRenderingMode() const; + + /** + * @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 + GlView(const GlView& GlView); + GlView& operator=(const GlView& 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); + + /** + * Creates the geometry for texturing. + */ + Dali::Geometry CreateTexturedQuad(); + + /** + * Adds renderer to Actor. + */ + void AddRenderer(); + + /** + * Creates shader for rendering. + */ + Dali::Shader CreateShader(); + + /** + * @brief Gets the NativeImageSourceQueue's ColorFormat with the GlView's ColorFormat. + * @param[in] colorFormat the color format of the GlView. + * @return The color format of NativeImageSourceQueue + */ + Dali::NativeImageSourceQueue::ColorFormat GetColorFormat(Dali::Toolkit::GlView::ColorFormat format); + +private: + std::unique_ptr mRenderThread; + Dali::NativeImageSourceQueuePtr mNativeImageQueue; + Dali::Toolkit::GlView::RenderingMode mRenderingMode; + Dali::Toolkit::GlView::ColorFormat mColorFormat; + + bool mDepth; + bool mStencil; + int mMSAA; +}; + +} // 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-render-thread.cpp b/dali-toolkit/internal/controls/gl-view/gl-view-render-thread.cpp new file mode 100644 index 0000000..db2e98c --- /dev/null +++ b/dali-toolkit/internal/controls/gl-view/gl-view-render-thread.cpp @@ -0,0 +1,295 @@ +/* + * 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 +{ +namespace Toolkit +{ +namespace Internal +{ +namespace +{ +constexpr unsigned int NANOSECONDS_PER_SECOND(1e+9); + +// The following values will get calculated at compile time +constexpr float DEFAULT_FRAME_DURATION_IN_SECONDS(1.0f / 60.0f); +constexpr uint64_t DEFAULT_FRAME_DURATION_IN_NANOSECONDS(DEFAULT_FRAME_DURATION_IN_SECONDS* NANOSECONDS_PER_SECOND); + +} // namespace + +GlViewRenderThread::GlViewRenderThread(Dali::NativeImageSourceQueuePtr queue) +: mLogFactory(Dali::Adaptor::Get().GetLogFactory()), + mSurfaceSize(1, 1), + mNativeImageSurface(), + mNativeImageQueue(queue), + mSurfaceSemaphore(1), + mGlInitCallback(nullptr), + mGlRenderFrameCallback(nullptr), + mGlTerminateCallback(nullptr), + mResizeCallback(nullptr), + mDepth(false), + mStencil(false), + mMSAA(0), + mGraphicsApiVersion(20), + mConditionalWait(), + mIsThreadStarted(0), + mIsThreadStopped(0), + mIsThreadPaused(0), + mIsRenderRequested(0), + mRenderingMode(0), + mIsSurfaceResized(0), + mDefaultFrameDurationNanoseconds(DEFAULT_FRAME_DURATION_IN_NANOSECONDS) +{ + mNativeImageSurface = Dali::NativeImageSurface::New(mNativeImageQueue); + + if(!mNativeImageSurface) + { + DALI_LOG_ERROR("Creating NativeImageSurface Failed, Could not start GlView Render Thread"); + } +} + +void GlViewRenderThread::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) +{ + if(!mGlInitCallback && !mGlRenderFrameCallback && !mGlTerminateCallback) + { + mGlInitCallback = std::unique_ptr(initCallback); + mGlRenderFrameCallback = std::unique_ptr(renderFrameCallback); + mGlTerminateCallback = std::unique_ptr(terminateCallback); + } +} + +void GlViewRenderThread::SetResizeCallback(CallbackBase* resizeCallback) +{ + if(!mResizeCallback) + { + mResizeCallback = std::unique_ptr(resizeCallback); + } +} + +bool GlViewRenderThread::SetGraphicsConfig(bool depth, bool stencil, int msaa, int version) +{ + mDepth = depth; + mStencil = stencil; + mMSAA = msaa; + mGraphicsApiVersion = version; + + if(mNativeImageSurface) + { + return mNativeImageSurface->SetGraphicsConfig(mDepth, mStencil, mMSAA, mGraphicsApiVersion); + } + + return false; +} + +void GlViewRenderThread::SetOnDemandRenderMode(bool onDemand) +{ + ConditionalWait::ScopedLock lock(mConditionalWait); + mRenderingMode = static_cast(onDemand); + DALI_LOG_RELEASE_INFO("GlViewRenderThread::SetOnDemandRenderMode(): mRenderingMode: %d\n", mRenderingMode); + if(!onDemand && !mIsThreadPaused) + { + mConditionalWait.Notify(lock); + } +} + +void GlViewRenderThread::SetSurfaceSize(Dali::Vector2 size) +{ + //GlViewRenderThread::Run was already blocked in Internal::GlView::OnSizeSet + mSurfaceSize = size; + mIsSurfaceResized = 1; +} + +void GlViewRenderThread::RenderOnce() +{ + //Notify GLRender thread. + Dali::ConditionalWait::ScopedLock lock(mConditionalWait); + mIsRenderRequested = 1; + mConditionalWait.Notify(lock); +} + +void GlViewRenderThread::GetNanoSeconds(uint64_t& timeInNanoseconds) +{ + // Get the time of a monotonic clock since its epoch. + auto epoch = std::chrono::steady_clock::now().time_since_epoch(); + auto duration = std::chrono::duration_cast(epoch); + timeInNanoseconds = static_cast(duration.count()); +} + +void GlViewRenderThread::SleepUntil(uint64_t timeInNanoseconds) +{ + using Clock = std::chrono::steady_clock; + using TimePoint = std::chrono::time_point; + + const Clock::duration duration = std::chrono::nanoseconds(timeInNanoseconds); + const TimePoint timePoint(duration); + + std::this_thread::sleep_until(timePoint); +} + +void GlViewRenderThread::Run() +{ + Dali::SetThreadName("GlViewRenderer"); + mLogFactory.InstallLogFunction(); + + int renderFrameResult = 0; + + if(!mNativeImageSurface) + { + DALI_LOG_ERROR("NativeImageSurface is null, Could not start GlView Render Thread"); + return; + } + + AcquireSurface(); + mNativeImageSurface->InitializeGraphics(); + ReleaseSurface(); + + mNativeImageSurface->PreRender(); + if(mGlInitCallback) + { + CallbackBase::Execute(*mGlInitCallback); + } + + uint64_t timeToSleepUntil = 0; + + while(RenderReady(timeToSleepUntil)) + { + uint64_t currentFrameStartTime = 0; + GetNanoSeconds(currentFrameStartTime); + + AcquireSurface(); + mNativeImageSurface->PreRender(); + if(mIsSurfaceResized) + { + if(mResizeCallback) + { + CallbackBase::Execute(*mResizeCallback, static_cast(mSurfaceSize.x), static_cast(mSurfaceSize.y)); + } + mIsSurfaceResized = 0; + } + + if(mNativeImageSurface->CanRender()) + { + if(mGlRenderFrameCallback) + { + renderFrameResult = CallbackBase::ExecuteReturn(*mGlRenderFrameCallback); + if(renderFrameResult) + { + mNativeImageSurface->PostRender(); + } + } + } + + ReleaseSurface(); + + if(timeToSleepUntil == 0) + { + timeToSleepUntil = currentFrameStartTime + mDefaultFrameDurationNanoseconds; + } + else + { + timeToSleepUntil += mDefaultFrameDurationNanoseconds; + uint64_t currentFrameEndTime = 0; + GetNanoSeconds(currentFrameEndTime); + while(currentFrameEndTime > timeToSleepUntil + mDefaultFrameDurationNanoseconds) + { + timeToSleepUntil += mDefaultFrameDurationNanoseconds; + } + } + + SleepUntil(timeToSleepUntil); + } + + if(mGlTerminateCallback) + { + CallbackBase::Execute(*mGlTerminateCallback); + } + + mNativeImageSurface->TerminateGraphics(); + + return; +} + +void GlViewRenderThread::Stop() +{ + // Set to come out Render Thread out of waiting condition. + Dali::ConditionalWait::ScopedLock lock(mConditionalWait); + mIsThreadStopped = 1; + mIsThreadPaused = 0; + mConditionalWait.Notify(lock); +} + +void GlViewRenderThread::Pause() +{ + //Notify GLRender thread, If actor visibility is change + Dali::ConditionalWait::ScopedLock lock(mConditionalWait); + mIsThreadPaused = 1; + mConditionalWait.Notify(lock); +} + +void GlViewRenderThread::Resume() +{ + Dali::ConditionalWait::ScopedLock lock(mConditionalWait); + if(!mIsThreadStarted) + { + Start(); + mIsThreadStarted = 1; + } + mIsThreadPaused = 0; + mConditionalWait.Notify(lock); +} + +bool GlViewRenderThread::RenderReady(uint64_t& timeToSleepUntil) +{ + ConditionalWait::ScopedLock lock(mConditionalWait); + while((!mIsThreadStopped && mRenderingMode && !mIsRenderRequested) || mIsThreadPaused) + { + timeToSleepUntil = 0; + mConditionalWait.Wait(lock); + } + + mIsRenderRequested = 0; + // Keep the update-render thread alive if this thread is NOT to be destroyed + return !mIsThreadStopped; +} + +void GlViewRenderThread::AcquireSurface() +{ + mSurfaceSemaphore.Acquire(); +} + +void GlViewRenderThread::ReleaseSurface() +{ + mSurfaceSemaphore.Release(1); +} + +GlViewRenderThread::~GlViewRenderThread() +{ +} + +} // namespace Internal +} // namespace Toolkit +} // namespace Dali diff --git a/dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h b/dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h new file mode 100644 index 0000000..c27c832 --- /dev/null +++ b/dali-toolkit/internal/controls/gl-view/gl-view-render-thread.h @@ -0,0 +1,179 @@ +#ifndef DALI_TOOLKIT_INTERNAL_GL_VIEW_THREAD_H +#define DALI_TOOLKIT_INTERNAL_GL_VIEW_THREAD_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 +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal +{ +/** + * @brief GlViewRenderThread is a render thread for GlView. + * This invokes user's callbacks. + */ +class GlViewRenderThread : public Dali::Thread +{ +public: + /** + * Constructor + * + * @param[in] queue The NativeImageSourceQueue that GL renders onto + */ + GlViewRenderThread(Dali::NativeImageSourceQueuePtr queue); + + /** + * destructor. + */ + virtual ~GlViewRenderThread(); + + /** + * @copydoc Dali::Toolkit::GlView::RegisterGlCallback() + */ + void RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback); + + /** + * @copydoc Dali::Toolkit::GlView::SetResizeCallback() + */ + void SetResizeCallback(CallbackBase* resizeCallback); + + /** + * @copydoc Dali::Toolkit::GlView::SetGraphicsConfig() + */ + bool SetGraphicsConfig(bool depth, bool stencil, int msaa, int version); + + /** + * Enable OnDemand Rendering Mode + * + * @param[in] onDemand the flag of OnDemand Rendering Mode. If the flag is true, the rendering mode is set OnDemand, + * otherwise the flag is false, rendering mode is set continuous mode. + */ + void SetOnDemandRenderMode(bool onDemand); + + /** + * Sets the surface size + * + * @param[in] size the size of the NaitveImageSurface + */ + void SetSurfaceSize(Dali::Vector2 size); + + /** + * @copydoc Dali::Toolkit::RenderOnce() + */ + void RenderOnce(); + + /** + * Pauses the render thread. + */ + void Pause(); + + /** + * Resumes the render thread. + */ + void Resume(); + + /** + * Stops the render thread. + * @note Should only be called in Stop as calling this will kill the render thread. + */ + void Stop(); + + /** + * Acquires the surface resource + */ + void AcquireSurface(); + + /** + * Releases the surface resource + */ + void ReleaseSurface(); + +protected: + /** + * The routine that the thread will execute once it is started. + */ + void Run() override; + +private: + GlViewRenderThread(const GlViewRenderThread& obj) = delete; + GlViewRenderThread operator=(const GlViewRenderThread& obj) = delete; + + /** + * Called by the Render Thread which ensures a wait if required. + * + * @param[out] timeToSleepUntil The time remaining in nanoseconds to keep the thread sleeping before resuming. + * @return false, if the thread should stop. + */ + bool RenderReady(uint64_t& timeToSleepUntil); + + /** + * @brief Get the monotonic time since the clock's epoch. + * @param[out] timeInNanoseconds The time in nanoseconds since the reference point. + */ + void GetNanoSeconds(uint64_t& timeInNanoseconds); + + /** + * Blocks the execution of the current thread until specified sleep_time + * @param[in] timeInNanoseconds The time blocking for + */ + void SleepUntil(uint64_t timeInNanoseconds); + +private: + const Dali::LogFactoryInterface& mLogFactory; + Dali::Vector2 mSurfaceSize; ///< The size of mNativeImageQueue + Dali::NativeImageSurfacePtr mNativeImageSurface; + Dali::NativeImageSourceQueuePtr mNativeImageQueue; + Semaphore<> mSurfaceSemaphore; ///< The semaphore to avoid race condition to the render target + + std::unique_ptr mGlInitCallback; + std::unique_ptr mGlRenderFrameCallback; + std::unique_ptr mGlTerminateCallback; + std::unique_ptr mResizeCallback; + + bool mDepth : 1; + bool mStencil : 1; + int mMSAA; + int mGraphicsApiVersion; + + Dali::ConditionalWait mConditionalWait; + volatile unsigned int mIsThreadStarted; ///< Whether this thread has been started. + volatile unsigned int mIsThreadStopped; ///< Stop render thread. It means this render thread will be destroyed. + volatile unsigned int mIsThreadPaused; ///< Sleep render thread by pause. + volatile unsigned int mIsRenderRequested; ///< Request rendering once + volatile unsigned int mRenderingMode; ///< Rendering Mode, 0: Continuous, 1:OnDemand + volatile unsigned int mIsSurfaceResized; ///< Invoke ResizeCallback when NativeImageSurface is resized. + + uint64_t mDefaultFrameDurationNanoseconds; ///< Default duration of a frame (used for sleeping if not enough time elapsed). Not protected by lock, but written to rarely so not worth adding a lock when reading. +}; + +} // namespace Internal +} // namespace Toolkit +} // namespace Dali + +#endif // DALI_TOOLKIT_INTERNAL_GL_SURFACE_VIEW_THREAD_H diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 7f02340..f1aa866 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -109,6 +109,8 @@ 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/gl-view-impl.cpp + ${toolkit_src_dir}/controls/gl-view/gl-view-render-thread.cpp ${toolkit_src_dir}/accessibility-manager/accessibility-manager-impl.cpp ${toolkit_src_dir}/feedback/feedback-style.cpp diff --git a/dali-toolkit/internal/graphics/shaders/gl-view.frag b/dali-toolkit/internal/graphics/shaders/gl-view.frag new file mode 100644 index 0000000..9b0b917 --- /dev/null +++ b/dali-toolkit/internal/graphics/shaders/gl-view.frag @@ -0,0 +1,8 @@ +uniform lowp vec4 uColor; +varying mediump vec2 vTexCoord; +uniform samplerExternalOES sTexture; + +void main() +{ + gl_FragColor = texture2D(sTexture, vTexCoord) * uColor; +} \ No newline at end of file diff --git a/dali-toolkit/internal/graphics/shaders/gl-view.vert b/dali-toolkit/internal/graphics/shaders/gl-view.vert new file mode 100644 index 0000000..eeec383 --- /dev/null +++ b/dali-toolkit/internal/graphics/shaders/gl-view.vert @@ -0,0 +1,11 @@ +attribute mediump vec2 aPosition; +uniform mediump mat4 uMvpMatrix; +uniform mediump vec3 uSize; +varying mediump vec2 vTexCoord; + +void main() +{ + vec4 position = vec4(aPosition, 0.0, 1.0) * vec4(uSize, 1.0); + vTexCoord = aPosition + vec2(0.5); + gl_Position = uMvpMatrix * position; +} \ No newline at end of file diff --git a/dali-toolkit/public-api/controls/gl-view/gl-view.cpp b/dali-toolkit/public-api/controls/gl-view/gl-view.cpp new file mode 100644 index 0000000..b5f6a8c --- /dev/null +++ b/dali-toolkit/public-api/controls/gl-view/gl-view.cpp @@ -0,0 +1,97 @@ +/* + * 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 + +// INTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Toolkit +{ +GlView::GlView() +{ +} + +GlView::GlView(const GlView& GlView) = default; + +GlView::GlView(GlView&& rhs) = default; + +GlView& GlView::operator=(const GlView& GlView) = default; + +GlView& GlView::operator=(GlView&& rhs) = default; + +GlView::~GlView() +{ +} + +GlView GlView::New(ColorFormat colorFormat) +{ + return Internal::GlView::New(colorFormat); +} + +GlView GlView::DownCast(BaseHandle handle) +{ + return Control::DownCast(handle); +} + +void GlView::RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback) +{ + Dali::Toolkit::GetImpl(*this).RegisterGlCallback(initCallback, renderFrameCallback, terminateCallback); +} + +void GlView::SetResizeCallback(CallbackBase* resizeCallback) +{ + Dali::Toolkit::GetImpl(*this).SetResizeCallback(resizeCallback); +} + +bool GlView::SetGraphicsConfig(bool depth, bool stencil, int msaa, GraphicsApiVersion version) +{ + return Dali::Toolkit::GetImpl(*this).SetGraphicsConfig(depth, stencil, msaa, version); +} + +void GlView::SetRenderingMode(RenderingMode mode) +{ + Dali::Toolkit::GetImpl(*this).SetRenderingMode(mode); +} + +Dali::Toolkit::GlView::RenderingMode GlView::GetRenderingMode() const +{ + return Dali::Toolkit::GetImpl(*this).GetRenderingMode(); +} + +void GlView::RenderOnce() +{ + Dali::Toolkit::GetImpl(*this).RenderOnce(); +} + +GlView::GlView(Internal::GlView& implementation) +: Control(implementation) +{ +} + +GlView::GlView(Dali::Internal::CustomActor* internal) +: Control(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 new file mode 100644 index 0000000..be13db9 --- /dev/null +++ b/dali-toolkit/public-api/controls/gl-view/gl-view.h @@ -0,0 +1,240 @@ +#ifndef DALI_TOOLKIT_GL_VIEW_H +#define DALI_TOOLKIT_GL_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. + * + */ + +// INTERNAL INCLUDES +#include + +namespace Dali +{ +namespace Toolkit +{ +namespace Internal DALI_INTERNAL +{ +class GlView; +} + +/** + * @brief GlView is a class for rendering with GL + * + * GlView allows drawing with OpenGL. + * GlView creates a GL context, a GL surface and a render thread. + * The render thread invokes user's callbacks. + * + */ +class DALI_TOOLKIT_API GlView : public Dali::Toolkit::Control +{ +public: + /** + * @brief Enumeration for rendering mode + * + * This Enumeration is used to choose the rendering mode. + * 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. + */ + enum class RenderingMode + { + CONTINUOUS, ///< continuous mode + ON_DEMAND ///< on demand by application + }; + + /** + * @brief Enumeration for Graphics API version + * + * This Enumeration is used to set a GLES version for EGL configuration. + */ + enum class GraphicsApiVersion + { + GLES_VERSION_2_0 = 0, ///< GLES version 2.0 + GLES_VERSION_3_0, ///< GLES version 3.0 + }; + + /** + * @brief Enumeration for color buffer format + * + * This Enumeration is used to set a color buffer format of GlView + */ + enum class ColorFormat + { + RGB888, ///< 8 red bits, 8 green bits, 8 blue bits + RGBA8888 ///< 8 red bits, 8 green bits, 8 blue bits, alpha 8 bits + }; + + /** + * @brief Creates a GlView control. + * @param[in] colorFormat the format of the color buffer. + * @return A handle to a GlView control + */ + static GlView New(ColorFormat colorFormat); + + /** + * @brief Creates an uninitialized GlView. + */ + GlView(); + + /** + * @brief Destructor. + * + * This is non-virtual since derived Handle types must not contain data or virtual methods. + */ + ~GlView(); + + /** + * @brief Copy constructor. + * + * @param[in] GlView GlView to copy. The copied GlView will point at the same implementation + */ + GlView(const GlView& GlView); + + /** + * @brief Move constructor + * + * @param[in] rhs A reference to the moved handle + */ + GlView(GlView&& rhs); + + /** + * @brief Assignment operator. + * + * @param[in] GlView The GlView to assign from + * @return A reference to this + */ + GlView& operator=(const GlView& GlView); + + /** + * @brief Move assignment + * + * @param[in] rhs A reference to the moved handle + * @return A reference to this + */ + GlView& operator=(GlView&& rhs); + + /** + * @brief Downcasts a handle to GlView handle. + * + * If handle points to a GlView, the downcast produces valid handle. + * If not, the returned handle is left uninitialized. + * + * @param[in] handle Handle to an object + * @return Handle to a GlView or an uninitialized handle + */ + static GlView DownCast(BaseHandle handle); + + /** + * @brief Registers GL callback functions for GlView. + * + * @param[in] initCallback the callback function to create GL resources. + * @param[in] renderFrameCallback the callback function to render for the frame. + * @param[in] terminateCallback the callback function to clean-up GL resources. + * + * A initCallback of the following type have to be used: + * @code + * void intializeGL(); + * @endcode + * This callback will be called before renderFrame callback is called once. + * + * A renderFrameCallback of the following type have to be used: + * @code + * int renderFrameGL(); + * @endcode + * If the return value of this callback is not 0, the eglSwapBuffers() will be called. + * + * A terminateCallback of the following type have to be used: + * @code + * void terminateGL(); + * @endcode + * This callback is called when GlView is deleted. + * + * @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. + */ + void RegisterGlCallback(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback); + + /** + * @brief Sets the ResizeCallback of the GlView. + * When GlView is resized, ResizeCallback would be invoked. + * You can get the resized width and height of the GlView. + * + * @param[in] resizeCallback The ResizeCallback function + * + * A resizeCallback of the following type have to be used: + * @code + * void resizeCallback(int width, int height); + * @endcode + * + * @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. + */ + void SetResizeCallback(CallbackBase* resizeCallback); + + /** + * @brief Sets the rendering mode. + * + * @param[in] mode the rendering mode for GlView + * + * @note The default Rendering mode is CONTINUOUS. + * If ON_DEMAND mode is set, it is rendered by RenderOnce() + */ + void SetRenderingMode(RenderingMode mode); + + /** + * @brief Gets the rendering mode. + */ + RenderingMode GetRenderingMode() const; + + /** + * @brief Sets egl configuration for GlView + * + * @param[in] depth the flag of depth buffer. If the value is true, 24bit depth buffer is enabled. + * @param[in] stencil the flag of stencil. If the value is true, 8bit stencil buffer is enabled. + * @param[in] msaa the expected sampling number per pixel. + * @param[in] version the graphics API version + * @return True if the config exists, false otherwise. + */ + 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 + */ + void RenderOnce(); + +public: // Not intended for application developers + /// @cond internal + /** + * @brief Creates a handle using the Toolkit::Internal implementation. + * @param[in] implementation The GlView implementation + */ + DALI_INTERNAL GlView(Internal::GlView& implementation); + + /** + * @brief Allows the creation of this GlView from an Internal::CustomActor pointer. + * @param[in] internal A pointer to the internal CustomActor + */ + DALI_INTERNAL GlView(Dali::Internal::CustomActor* internal); + /// @endcond +}; + +} // namespace Toolkit + +} // namespace Dali + +#endif // DALI_TOOLKIT_GL_VIEW_H diff --git a/dali-toolkit/public-api/file.list b/dali-toolkit/public-api/file.list index 7b72745..ffd306b 100644 --- a/dali-toolkit/public-api/file.list +++ b/dali-toolkit/public-api/file.list @@ -27,6 +27,7 @@ SET( public_api_src_files ${public_api_src_dir}/controls/text-controls/text-field.cpp ${public_api_src_dir}/controls/video-view/video-view.cpp ${public_api_src_dir}/controls/camera-view/camera-view.cpp + ${public_api_src_dir}/controls/gl-view/gl-view.cpp ${public_api_src_dir}/image-loader/image.cpp ${public_api_src_dir}/image-loader/image-url.cpp ${public_api_src_dir}/image-loader/async-image-loader.cpp @@ -141,6 +142,10 @@ SET( public_api_camera_view_header_files ${public_api_src_dir}/controls/camera-view/camera-view.h ) +SET( public_api_gl_view_header_files + ${public_api_src_dir}/controls/gl-view/gl-view.h +) + SET( public_api_visuals_header_files ${public_api_src_dir}/visuals/border-visual-properties.h ${public_api_src_dir}/visuals/color-visual-properties.h @@ -186,4 +191,5 @@ SET( PUBLIC_API_HEADERS ${PUBLIC_API_HEADERS} ${public_api_video_view_header_files} ${public_api_visuals_header_files} ${public_api_camera_view_header_files} + ${public_api_gl_view_header_files} ) -- 2.7.4