[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-toolkit / internal / controls / gl-view / gl-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/gl-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/object/any.h>
27 #include <dali/public-api/rendering/renderer.h>
28 #include <dali/public-api/rendering/texture-set.h>
29 #include <dali/public-api/rendering/texture.h>
30
31 // INTERNAL INCLUDES
32 #include <dali-toolkit/internal/graphics/builtin-shader-extern-gen.h>
33 #include <dali-toolkit/internal/visuals/visual-factory-cache.h>
34
35 namespace Dali
36 {
37 namespace Toolkit
38 {
39 namespace Internal
40 {
41 Dali::Toolkit::GlView GlView::New(Dali::Toolkit::GlView::ColorFormat colorFormat)
42 {
43   auto*                 impl   = new Dali::Toolkit::Internal::GlView(colorFormat);
44   Dali::Toolkit::GlView handle = Dali::Toolkit::GlView(*impl);
45   impl->Initialize();
46   return handle;
47 }
48
49 GlView::GlView(Dali::Toolkit::GlView::ColorFormat colorFormat)
50 : Dali::Toolkit::Internal::GlViewImpl(Toolkit::GlView::BackendMode::EGL_IMAGE_OFFSCREEN_RENDERING),
51   mRenderThread(nullptr),
52   mNativeImageQueue(nullptr),
53   mRenderingMode(Toolkit::GlView::RenderingMode::CONTINUOUS),
54   mColorFormat(colorFormat),
55   mDepth(false),
56   mStencil(false),
57   mMSAA(0)
58 {
59 }
60
61 GlView::~GlView()
62 {
63   if(mRenderThread)
64   {
65     mRenderThread->Stop();
66     mRenderThread->Join();
67   }
68 }
69
70 void GlView::RegisterGlCallbacks(CallbackBase* initCallback, CallbackBase* renderFrameCallback, CallbackBase* terminateCallback)
71 {
72   if(mRenderThread)
73   {
74     mRenderThread->RegisterGlCallbacks(initCallback, renderFrameCallback, terminateCallback);
75   }
76 }
77
78 void GlView::SetResizeCallback(CallbackBase* resizeCallback)
79 {
80   if(mRenderThread)
81   {
82     mRenderThread->SetResizeCallback(resizeCallback);
83   }
84 }
85
86 bool GlView::SetGraphicsConfig(bool depth, bool stencil, int msaa, Dali::Toolkit::GlView::GraphicsApiVersion version)
87 {
88   // Init Graphics
89   mDepth   = depth;
90   mStencil = stencil;
91   mMSAA    = msaa;
92
93   int rVersion;
94
95   if(version == Dali::Toolkit::GlView::GraphicsApiVersion::GLES_VERSION_2_0)
96   {
97     rVersion = 20;
98   }
99   else
100   {
101     rVersion = 30;
102   }
103
104   if(mRenderThread)
105   {
106     return mRenderThread->SetGraphicsConfig(depth, stencil, msaa, rVersion);
107   }
108
109   return false;
110 }
111
112 void GlView::SetRenderingMode(Dali::Toolkit::GlView::RenderingMode mode)
113 {
114   mRenderingMode    = mode;
115   Renderer renderer = Self().GetRendererAt(0);
116
117   if(mRenderingMode == Dali::Toolkit::GlView::RenderingMode::ON_DEMAND)
118   {
119     renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::IF_REQUIRED);
120
121     if(mRenderThread)
122     {
123       mRenderThread->SetOnDemandRenderMode(true);
124     }
125   }
126   else
127   {
128     renderer.SetProperty(DevelRenderer::Property::RENDERING_BEHAVIOR, DevelRenderer::Rendering::CONTINUOUSLY);
129
130     if(mRenderThread)
131     {
132       mRenderThread->SetOnDemandRenderMode(false);
133     }
134   }
135 }
136
137 Dali::Toolkit::GlView::RenderingMode GlView::GetRenderingMode() const
138 {
139   return mRenderingMode;
140 }
141
142 void GlView::RenderOnce()
143 {
144   if(mRenderThread)
145   {
146     mRenderThread->RenderOnce();
147   }
148 }
149
150 void GlView::BindTextureResources(std::vector<Dali::Texture> textures)
151 {
152   // Not supported in the indirect mode
153 }
154
155 void GlView::OnInitialize()
156 {
157   //Create NativeImageSourceQueue with the size of 1,1
158   mNativeImageQueue = Dali::NativeImageSourceQueue::New(1, 1, GetColorFormat(mColorFormat));
159
160   if(!mNativeImageQueue)
161   {
162     DALI_LOG_ERROR("NativeImageSourceQueue is NULL");
163     return;
164   }
165
166   AddRenderer();
167
168   Actor self = Self();
169
170   //Create a RenderThread
171   mRenderThread = std::unique_ptr<GlViewRenderThread>(new GlViewRenderThread(mNativeImageQueue));
172   if(!mRenderThread)
173   {
174     DALI_LOG_ERROR("Fail to create GlView Render Thread!!!!\n");
175     return;
176   }
177
178   //Adding VisibilityChange Signal.
179   Dali::DevelActor::VisibilityChangedSignal(self).Connect(this, &GlView::OnControlVisibilityChanged);
180 }
181
182 void GlView::OnSizeSet(const Vector3& targetSize)
183 {
184   Control::OnSizeSet(targetSize);
185
186   if(mRenderThread)
187   {
188     if(mNativeImageQueue)
189     {
190       mRenderThread->AcquireSurface();
191       mNativeImageQueue->SetSize(static_cast<uint32_t>(targetSize.x), static_cast<uint32_t>(targetSize.y));
192       mRenderThread->SetSurfaceSize(Vector2(targetSize.x, targetSize.y));
193       mRenderThread->ReleaseSurface();
194     }
195   }
196 }
197
198 Shader GlView::CreateShader()
199 {
200   std::string fragmentShader = std::string(SHADER_GL_VIEW_FRAG);
201
202   if(mNativeImageQueue)
203   {
204     mNativeImageQueue->ApplyNativeFragmentShader(fragmentShader);
205   }
206
207   return Shader::New(SHADER_GL_VIEW_VERT, fragmentShader, Shader::Hint::NONE, "GL_VIEW");
208 }
209
210 void GlView::OnControlVisibilityChanged(Dali::Actor actor, bool visible, Dali::DevelActor::VisibilityChange::Type type)
211 {
212   Actor self = Self();
213   if(self.GetProperty<bool>(Actor::Property::CONNECTED_TO_SCENE))
214   {
215     if(mRenderThread)
216     {
217       if(visible && DevelWindow::Get(self).IsVisible())
218       {
219         mRenderThread->Resume();
220       }
221       else
222       {
223         mRenderThread->Pause();
224       }
225     }
226   }
227 }
228
229 void GlView::OnWindowVisibilityChanged(Window window, bool visible)
230 {
231   if(mRenderThread)
232   {
233     if(visible && Self().GetProperty<bool>(Actor::Property::VISIBLE))
234     {
235       mRenderThread->Resume();
236     }
237     else
238     {
239       mRenderThread->Pause();
240     }
241   }
242 }
243
244 void GlView::OnSceneConnection(int depth)
245 {
246   Control::OnSceneConnection(depth);
247
248   Actor  self   = Self();
249   Window window = DevelWindow::Get(self);
250
251   if(window)
252   {
253     DevelWindow::VisibilityChangedSignal(window).Connect(this, &GlView::OnWindowVisibilityChanged);
254   }
255
256   if(mRenderThread)
257   {
258     if(self.GetProperty<bool>(Actor::Property::VISIBLE) && window.IsVisible())
259     {
260       mRenderThread->Resume();
261     }
262   }
263 }
264
265 void GlView::OnSceneDisconnection()
266 {
267   Control::OnSceneDisconnection();
268   if(mRenderThread)
269   {
270     mRenderThread->Pause();
271   }
272 }
273
274 Dali::Geometry GlView::CreateTexturedQuad()
275 {
276   struct Vertex
277   {
278     Dali::Vector2 position;
279   };
280
281   static const Vertex data[] = {{Dali::Vector2(-0.5f, -0.5f)},
282                                 {Dali::Vector2(0.5f, -0.5f)},
283                                 {Dali::Vector2(-0.5f, 0.5f)},
284                                 {Dali::Vector2(0.5f, 0.5f)}};
285
286   uint32_t numberOfVertices = sizeof(data) / sizeof(Vertex);
287
288   Dali::VertexBuffer  vertexBuffer;
289   Dali::Property::Map vertexFormat;
290   vertexFormat["aPosition"] = Dali::Property::VECTOR2;
291
292   //Create a vertex buffer for vertex positions and texture coordinates
293   vertexBuffer = Dali::VertexBuffer::New(vertexFormat);
294   vertexBuffer.SetData(data, numberOfVertices);
295
296   //Create the geometry
297   Dali::Geometry geometry = Dali::Geometry::New();
298   geometry.AddVertexBuffer(vertexBuffer);
299   geometry.SetType(Dali::Geometry::TRIANGLE_STRIP);
300
301   return geometry;
302 }
303
304 void GlView::AddRenderer()
305 {
306   if(!mNativeImageQueue)
307   {
308     DALI_LOG_ERROR("Target Surface is NULL");
309     return;
310   }
311
312   Actor    self     = Self();
313   Geometry geometry = CreateTexturedQuad();
314   Shader   shader   = CreateShader();
315   Renderer renderer = Renderer::New(geometry, shader);
316
317   Texture    nativeTexture = Texture::New(*mNativeImageQueue);
318   TextureSet textureSet    = TextureSet::New();
319   textureSet.SetTexture(0u, nativeTexture);
320
321   renderer.SetTextures(textureSet);
322
323   self.AddRenderer(renderer);
324 }
325
326 Dali::NativeImageSourceQueue::ColorFormat GlView::GetColorFormat(Dali::Toolkit::GlView::ColorFormat format)
327 {
328   switch(format)
329   {
330     case Toolkit::GlView::ColorFormat::RGBA8888:
331     {
332       return Dali::NativeImageSourceQueue::ColorFormat::RGBA8888;
333     }
334
335     case Toolkit::GlView::ColorFormat::RGB888:
336     default:
337     {
338       return Dali::NativeImageSourceQueue::ColorFormat::RGBX8888;
339     }
340   }
341 }
342
343 } // namespace Internal
344
345 } // namespace Toolkit
346
347 } // namespace Dali