[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / gl-view / drawable-view-impl.cpp
1 /*
2  * Copyright (c) 2024 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-toolkit/internal/controls/gl-view/drawable-view-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/lifecycle-controller.h>
23 #include <dali/devel-api/adaptor-framework/window-devel.h>
24 #include <dali/devel-api/rendering/renderer-devel.h>
25 #include <dali/integration-api/debug.h>
26 #include <dali/public-api/rendering/renderer.h>
27 #include <dali/public-api/signals/render-callback.h>
28
29 namespace Dali::Toolkit::Internal
30 {
31 Dali::Toolkit::GlView DrawableView::New(GlView::BackendMode backendMode)
32 {
33   auto*                 impl   = new DrawableView(backendMode);
34   Dali::Toolkit::GlView handle = Dali::Toolkit::GlView(*impl);
35   impl->Initialize();
36   return handle;
37 }
38
39 DrawableView::DrawableView(GlView::BackendMode backendMode)
40 : Dali::Toolkit::Internal::GlViewImpl(backendMode),
41   mRenderingMode(Toolkit::GlView::RenderingMode::CONTINUOUS),
42   mDepth(false),
43   mStencil(false),
44   mMSAA(0)
45 {
46   // Create NativeRenderer
47   Dali::Internal::NativeRendererCreateInfo createInfo;
48   createInfo.maxOffscreenBuffers = 2u;
49   createInfo.threadEnabled       = (backendMode == GlView::BackendMode::DIRECT_RENDERING_THREADED);
50   createInfo.directExecution     = (backendMode == GlView::BackendMode::UNSAFE_DIRECT_RENDERING);
51   createInfo.presentationMode    = Dali::Internal::NativeRendererCreateInfo::PresentationMode::FIFO;
52
53   mRenderCallback = RenderCallback::New(this, &DrawableView::OnRenderCallback, createInfo.directExecution ? RenderCallback::ExecutionMode::UNSAFE : RenderCallback::ExecutionMode::ISOLATED);
54
55   mNativeRenderer = std::make_unique<Dali::Internal::DrawableViewNativeRenderer>(createInfo);
56 }
57
58 DrawableView::~DrawableView() = default;
59
60 void DrawableView::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
61 {
62   mNativeRenderer->RegisterGlCallbacks(initCallback, renderFrameCallback, terminateCallback);
63 }
64
65 void DrawableView::SetResizeCallback(CallbackBase* resizeCallback)
66 {
67   mOnResizeCallback.reset(resizeCallback);
68 }
69
70 bool DrawableView::SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version)
71 {
72   // Currently, the settings are not relevant for the DirectRendering feature as all the
73   // setup is inherited from DALi graphics backend.
74   return true;
75 }
76
77 void DrawableView::SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode)
78 {
79   mRenderingMode    = mode;
80   Renderer renderer = Self().GetRendererAt(0);
81
82   if(mRenderingMode == Dali::Toolkit::GlView::RenderingMode::ON_DEMAND)
83   {
84     renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
85   }
86   else
87   {
88     renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY);
89   }
90 }
91
92 Dali::Toolkit::GlView::RenderingMode DrawableView::GetRenderingMode() const
93 {
94   return mRenderingMode;
95 }
96
97 void DrawableView::RenderOnce()
98 {
99   // Ignored.
100   // TODO: without rendering on the separate thread the RenderOnce won't
101   // work as expected. Potential implementation of threading may enable that
102   // feature.
103 }
104
105 void DrawableView::BindTextureResources(std::vector<Dali::Texture> textures)
106 {
107   mRenderCallback->BindTextureResources(std::move(textures));
108 }
109
110 void DrawableView::OnInitialize()
111 {
112   AddRenderer();
113
114   // Adding VisibilityChange Signal.
115   Actor self = Self();
116   Dali::DevelActor::VisibilityChangedSignal(self).Connect(this, &DrawableView::OnControlVisibilityChanged);
117 }
118
119 void DrawableView::OnSizeSet(const Vector3& targetSize)
120 {
121   Control::OnSizeSet(targetSize);
122
123   mSurfaceSize = targetSize;
124
125   // If the callbacks are set then schedule execution of resize callback
126   if(mRenderCallback && mNativeRenderer)
127   {
128     mNativeRenderer->Resize(uint32_t(targetSize.width), uint32_t(targetSize.height));
129     mSurfaceResized = true;
130   }
131 }
132
133 void DrawableView::OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type)
134 {
135   // Ignored due to lack dedicated rendering thread
136 }
137
138 void DrawableView::OnWindowVisibilityChanged(Window window, bool visible)
139 {
140   // Ignored due to lack dedicated rendering thread
141 }
142
143 void DrawableView::OnSceneConnection(int depth)
144 {
145   Control::OnSceneConnection(depth);
146
147   Actor  self   = Self();
148   Window window = DevelWindow::Get(self);
149
150   // Despite OnWindowVisibilityChanged() is ignored it still should follow
151   // the designed behaviour of GlView so signal is connected regardless
152   if(window)
153   {
154     DevelWindow::VisibilityChangedSignal(window).Connect(this, &DrawableView::OnWindowVisibilityChanged);
155   }
156 }
157
158 void DrawableView::OnSceneDisconnection()
159 {
160   Control::OnSceneDisconnection();
161
162   mNativeRenderer->Terminate();
163 }
164
165 void DrawableView::AddRenderer()
166 {
167   Actor    self     = Self();
168   Renderer renderer = Renderer::New(*mRenderCallback);
169   self.AddRenderer(renderer);
170 }
171
172 bool DrawableView::OnRenderCallback(const RenderCallbackInput& renderCallbackInput)
173 {
174   if(mNativeRenderer)
175   {
176     mNativeRenderer->PushRenderCallbackInputData(renderCallbackInput);
177   }
178
179   // Init state
180   if(mCurrentViewState == ViewState::INIT)
181   {
182     mNativeRenderer->InvokeGlInitCallback(renderCallbackInput);
183     mCurrentViewState = ViewState::RENDER;
184   }
185
186   if(mSurfaceResized)
187   {
188     mNativeRenderer->Resize(uint32_t(mSurfaceSize.width), uint32_t(mSurfaceSize.height));
189     mSurfaceResized = false;
190   }
191
192   if(mCurrentViewState == ViewState::RENDER)
193   {
194     // The mSurfaceResized is set by another thread so atomic check must be provided
195     bool expected{true};
196     if(mSurfaceResized.compare_exchange_weak(expected, false, std::memory_order_release, std::memory_order_relaxed) && mOnResizeCallback)
197     {
198       CallbackBase::Execute(*mOnResizeCallback, static_cast<int>(mSurfaceSize.x), static_cast<int>(mSurfaceSize.y));
199     }
200
201     mNativeRenderer->InvokeGlRenderCallback(renderCallbackInput);
202   }
203
204   // The terminate callback isn't easy to implement for DR. The NativeImage backend
205   // calls it when the GlView is being destroyed. For DrawableView it means that
206   // the RenderCallback won't be executed (as it is a part of graphics pipeline).
207   // We don't have currently have any way to know whether the View will be destroyed and
208   // to execute last native draw command in the pipeline.
209   //
210   // else if( mCurrentViewState == ViewState::TERMINATE )
211   // {
212   //    CallbackBase::Execute(*mOnTerminateCallback);
213   // }
214
215   return true;
216 }
217
218 } // namespace Dali::Toolkit::Internal