DrawableViewNativeRenderer for Direct Rendering
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / gl-view / drawable-view-impl.cpp
1 /*
2  * Copyright (c) 2021 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::OnInitialize()
104 {
105   AddRenderer();
106
107   // Adding VisibilityChange Signal.
108   Actor self = Self();
109   Dali::DevelActor::VisibilityChangedSignal(self).Connect(this, &DrawableView::OnControlVisibilityChanged);
110 }
111
112 void DrawableView::OnSizeSet(const Vector3& targetSize)
113 {
114   Control::OnSizeSet(targetSize);
115
116   mSurfaceSize = targetSize;
117
118   // If the callbacks are set then schedule execution of resize callback
119   if(mRenderCallback && mNativeRenderer)
120   {
121     mNativeRenderer->Resize( uint32_t(targetSize.width), uint32_t(targetSize.height));
122     mSurfaceResized = true;
123   }
124 }
125
126 void DrawableView::OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type)
127 {
128   // Ignored due to lack dedicated rendering thread
129 }
130
131 void DrawableView::OnWindowVisibilityChanged(Window window, bool visible)
132 {
133   // Ignored due to lack dedicated rendering thread
134 }
135
136 void DrawableView::OnSceneConnection(int depth)
137 {
138   Control::OnSceneConnection(depth);
139
140   Actor  self   = Self();
141   Window window = DevelWindow::Get(self);
142
143   // Despite OnWindowVisibilityChanged() is ignored it still should follow
144   // the designed behaviour of GlView so signal is connected regardless
145   if(window)
146   {
147     DevelWindow::VisibilityChangedSignal(window).Connect(this, &DrawableView::OnWindowVisibilityChanged);
148   }
149 }
150
151 void DrawableView::OnSceneDisconnection()
152 {
153   Control::OnSceneDisconnection();
154
155   mNativeRenderer->Terminate();
156 }
157
158 void DrawableView::AddRenderer()
159 {
160   Actor    self     = Self();
161   Renderer renderer = Renderer::New( *mRenderCallback );
162   self.AddRenderer(renderer);
163 }
164
165 bool DrawableView::OnRenderCallback( const RenderCallbackInput& renderCallbackInput )
166 {
167   if(mNativeRenderer)
168   {
169     mNativeRenderer->PushRenderCallbackInputData( renderCallbackInput );
170   }
171
172   // Init state
173   if( mCurrentViewState == ViewState::INIT )
174   {
175     mNativeRenderer->InvokeGlInitCallback(renderCallbackInput);
176     mCurrentViewState = ViewState::RENDER;
177   }
178
179   if(mSurfaceResized)
180   {
181     mNativeRenderer->Resize( uint32_t(mSurfaceSize.width), uint32_t(mSurfaceSize.height) );
182     mSurfaceResized = false;
183   }
184
185   if( mCurrentViewState == ViewState::RENDER )
186   {
187     // The mSurfaceResized is set by another thread so atomic check must be provided
188     bool expected{ true };
189     if(mSurfaceResized.compare_exchange_weak( expected, false,
190                                              std::memory_order_release,
191                                              std::memory_order_relaxed
192                                              ) && mOnResizeCallback)
193     {
194       CallbackBase::Execute(*mOnResizeCallback, static_cast<int>(mSurfaceSize.x), static_cast<int>(mSurfaceSize.y));
195     }
196
197     mNativeRenderer->InvokeGlRenderCallback(renderCallbackInput);
198   }
199
200   // The terminate callback isn't easy to implement for DR. The NativeImage backend
201   // calls it when the GlView is being destroyed. For DrawableView it means that
202   // the RenderCallback won't be executed (as it is a part of graphics pipeline).
203   // We don't have currently have any way to know whether the View will be destroyed and
204   // to execute last native draw command in the pipeline.
205   //
206   // else if( mCurrentViewState == ViewState::TERMINATE )
207   // {
208   //    CallbackBase::Execute(*mOnTerminateCallback);
209   // }
210
211   return true;
212 }
213
214 } // namespace Dali