[dali_2.3.20] 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     mPlacementWindow = window;
155     DevelWindow::VisibilityChangedSignal(window).Connect(this, &DrawableView::OnWindowVisibilityChanged);
156   }
157 }
158
159 void DrawableView::OnSceneDisconnection()
160 {
161   Control::OnSceneDisconnection();
162
163   mNativeRenderer->Terminate();
164
165   Window window = mPlacementWindow.GetHandle();
166   if(window)
167   {
168     DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &DrawableView::OnWindowVisibilityChanged);
169     mPlacementWindow.Reset();
170   }
171 }
172
173 void DrawableView::AddRenderer()
174 {
175   Actor    self     = Self();
176   Renderer renderer = Renderer::New(*mRenderCallback);
177   self.AddRenderer(renderer);
178 }
179
180 bool DrawableView::OnRenderCallback(const RenderCallbackInput& renderCallbackInput)
181 {
182   if(mNativeRenderer)
183   {
184     mNativeRenderer->PushRenderCallbackInputData(renderCallbackInput);
185   }
186
187   // Init state
188   if(mCurrentViewState == ViewState::INIT)
189   {
190     mNativeRenderer->InvokeGlInitCallback(renderCallbackInput);
191     mCurrentViewState = ViewState::RENDER;
192   }
193
194   if(mSurfaceResized)
195   {
196     mNativeRenderer->Resize(uint32_t(mSurfaceSize.width), uint32_t(mSurfaceSize.height));
197     mSurfaceResized = false;
198   }
199
200   if(mCurrentViewState == ViewState::RENDER)
201   {
202     // The mSurfaceResized is set by another thread so atomic check must be provided
203     bool expected{true};
204     if(mSurfaceResized.compare_exchange_weak(expected, false, std::memory_order_release, std::memory_order_relaxed) && mOnResizeCallback)
205     {
206       CallbackBase::Execute(*mOnResizeCallback, static_cast<int>(mSurfaceSize.x), static_cast<int>(mSurfaceSize.y));
207     }
208
209     mNativeRenderer->InvokeGlRenderCallback(renderCallbackInput);
210   }
211
212   // The terminate callback isn't easy to implement for DR. The NativeImage backend
213   // calls it when the GlView is being destroyed. For DrawableView it means that
214   // the RenderCallback won't be executed (as it is a part of graphics pipeline).
215   // We don't have currently have any way to know whether the View will be destroyed and
216   // to execute last native draw command in the pipeline.
217   //
218   // else if( mCurrentViewState == ViewState::TERMINATE )
219   // {
220   //    CallbackBase::Execute(*mOnTerminateCallback);
221   // }
222
223   return true;
224 }
225
226 } // namespace Dali::Toolkit::Internal