DALi Version 2.2.11
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / gl-view / drawable-view-impl.cpp
1 /*
2  * Copyright (c) 2022 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   mRenderCallback = RenderCallback::New(this, &DrawableView::OnRenderCallback);
47
48   // Create NativeRenderer
49   Dali::Internal::NativeRendererCreateInfo createInfo;
50   createInfo.maxOffscreenBuffers = 2u;
51   createInfo.threadEnabled       = (backendMode == GlView::BackendMode::DIRECT_RENDERING_THREADED);
52   createInfo.presentationMode    = Dali::Internal::NativeRendererCreateInfo::PresentationMode::FIFO;
53   mNativeRenderer                = std::make_unique<Dali::Internal::DrawableViewNativeRenderer>(createInfo);
54 }
55
56 DrawableView::~DrawableView() = default;
57
58 void DrawableView::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
59 {
60   mNativeRenderer->RegisterGlCallbacks(initCallback, renderFrameCallback, terminateCallback);
61 }
62
63 void DrawableView::SetResizeCallback(CallbackBase* resizeCallback)
64 {
65   mOnResizeCallback.reset(resizeCallback);
66 }
67
68 bool DrawableView::SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version)
69 {
70   // Currently, the settings are not relevant for the DirectRendering feature as all the
71   // setup is inherited from DALi graphics backend.
72   return true;
73 }
74
75 void DrawableView::SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode)
76 {
77   mRenderingMode    = mode;
78   Renderer renderer = Self().GetRendererAt(0);
79
80   if(mRenderingMode == Dali::Toolkit::GlView::RenderingMode::ON_DEMAND)
81   {
82     renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
83   }
84   else
85   {
86     renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY);
87   }
88 }
89
90 Dali::Toolkit::GlView::RenderingMode DrawableView::GetRenderingMode() const
91 {
92   return mRenderingMode;
93 }
94
95 void DrawableView::RenderOnce()
96 {
97   // Ignored.
98   // TODO: without rendering on the separate thread the RenderOnce won't
99   // work as expected. Potential implementation of threading may enable that
100   // feature.
101 }
102
103 void DrawableView::BindTextureResources(std::vector<Dali::Texture> textures)
104 {
105   mRenderCallback->BindTextureResources(std::move(textures));
106 }
107
108 void DrawableView::OnInitialize()
109 {
110   AddRenderer();
111
112   // Adding VisibilityChange Signal.
113   Actor self = Self();
114   Dali::DevelActor::VisibilityChangedSignal(self).Connect(this, &DrawableView::OnControlVisibilityChanged);
115 }
116
117 void DrawableView::OnSizeSet(const Vector3& targetSize)
118 {
119   Control::OnSizeSet(targetSize);
120
121   mSurfaceSize = targetSize;
122
123   // If the callbacks are set then schedule execution of resize callback
124   if(mRenderCallback && mNativeRenderer)
125   {
126     mNativeRenderer->Resize(uint32_t(targetSize.width), uint32_t(targetSize.height));
127     mSurfaceResized = true;
128   }
129 }
130
131 void DrawableView::OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type)
132 {
133   // Ignored due to lack dedicated rendering thread
134 }
135
136 void DrawableView::OnWindowVisibilityChanged(Window window, bool visible)
137 {
138   // Ignored due to lack dedicated rendering thread
139 }
140
141 void DrawableView::OnSceneConnection(int depth)
142 {
143   Control::OnSceneConnection(depth);
144
145   Actor  self   = Self();
146   Window window = DevelWindow::Get(self);
147
148   // Despite OnWindowVisibilityChanged() is ignored it still should follow
149   // the designed behaviour of GlView so signal is connected regardless
150   if(window)
151   {
152     DevelWindow::VisibilityChangedSignal(window).Connect(this, &DrawableView::OnWindowVisibilityChanged);
153   }
154 }
155
156 void DrawableView::OnSceneDisconnection()
157 {
158   Control::OnSceneDisconnection();
159
160   mNativeRenderer->Terminate();
161 }
162
163 void DrawableView::AddRenderer()
164 {
165   Actor    self     = Self();
166   Renderer renderer = Renderer::New(*mRenderCallback);
167   self.AddRenderer(renderer);
168 }
169
170 bool DrawableView::OnRenderCallback(const RenderCallbackInput& renderCallbackInput)
171 {
172   if(mNativeRenderer)
173   {
174     mNativeRenderer->PushRenderCallbackInputData(renderCallbackInput);
175   }
176
177   // Init state
178   if(mCurrentViewState == ViewState::INIT)
179   {
180     mNativeRenderer->InvokeGlInitCallback(renderCallbackInput);
181     mCurrentViewState = ViewState::RENDER;
182   }
183
184   if(mSurfaceResized)
185   {
186     mNativeRenderer->Resize(uint32_t(mSurfaceSize.width), uint32_t(mSurfaceSize.height));
187     mSurfaceResized = false;
188   }
189
190   if(mCurrentViewState == ViewState::RENDER)
191   {
192     // The mSurfaceResized is set by another thread so atomic check must be provided
193     bool expected{true};
194     if(mSurfaceResized.compare_exchange_weak(expected, false, std::memory_order_release, std::memory_order_relaxed) && mOnResizeCallback)
195     {
196       CallbackBase::Execute(*mOnResizeCallback, static_cast<int>(mSurfaceSize.x), static_cast<int>(mSurfaceSize.y));
197     }
198
199     mNativeRenderer->InvokeGlRenderCallback(renderCallbackInput);
200   }
201
202   // The terminate callback isn't easy to implement for DR. The NativeImage backend
203   // calls it when the GlView is being destroyed. For DrawableView it means that
204   // the RenderCallback won't be executed (as it is a part of graphics pipeline).
205   // We don't have currently have any way to know whether the View will be destroyed and
206   // to execute last native draw command in the pipeline.
207   //
208   // else if( mCurrentViewState == ViewState::TERMINATE )
209   // {
210   //    CallbackBase::Execute(*mOnTerminateCallback);
211   // }
212
213   return true;
214 }
215
216 } // namespace Dali::Toolkit::Internal