[dali_2.3.20] 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     mPlacementWindow = window;
254     DevelWindow::VisibilityChangedSignal(window).Connect(this, &GlView::OnWindowVisibilityChanged);
255   }
256
257   if(mRenderThread)
258   {
259     if(self.GetProperty<bool>(Actor::Property::VISIBLE) && window.IsVisible())
260     {
261       mRenderThread->Resume();
262     }
263   }
264 }
265
266 void GlView::OnSceneDisconnection()
267 {
268   Control::OnSceneDisconnection();
269   if(mRenderThread)
270   {
271     mRenderThread->Pause();
272   }
273
274   Window window = mPlacementWindow.GetHandle();
275   if(window)
276   {
277     DevelWindow::VisibilityChangedSignal(window).Disconnect(this, &GlView::OnWindowVisibilityChanged);
278     mPlacementWindow.Reset();
279   }
280 }
281
282 Dali::Geometry GlView::CreateTexturedQuad()
283 {
284   struct Vertex
285   {
286     Dali::Vector2 position;
287   };
288
289   static const Vertex data[] = {{Dali::Vector2(-0.5f, -0.5f)},
290                                 {Dali::Vector2(0.5f, -0.5f)},
291                                 {Dali::Vector2(-0.5f, 0.5f)},
292                                 {Dali::Vector2(0.5f, 0.5f)}};
293
294   uint32_t numberOfVertices = sizeof(data) / sizeof(Vertex);
295
296   Dali::VertexBuffer  vertexBuffer;
297   Dali::Property::Map vertexFormat;
298   vertexFormat["aPosition"] = Dali::Property::VECTOR2;
299
300   //Create a vertex buffer for vertex positions and texture coordinates
301   vertexBuffer = Dali::VertexBuffer::New(vertexFormat);
302   vertexBuffer.SetData(data, numberOfVertices);
303
304   //Create the geometry
305   Dali::Geometry geometry = Dali::Geometry::New();
306   geometry.AddVertexBuffer(vertexBuffer);
307   geometry.SetType(Dali::Geometry::TRIANGLE_STRIP);
308
309   return geometry;
310 }
311
312 void GlView::AddRenderer()
313 {
314   if(!mNativeImageQueue)
315   {
316     DALI_LOG_ERROR("Target Surface is NULL");
317     return;
318   }
319
320   Actor    self     = Self();
321   Geometry geometry = CreateTexturedQuad();
322   Shader   shader   = CreateShader();
323   Renderer renderer = Renderer::New(geometry, shader);
324
325   Texture    nativeTexture = Texture::New(*mNativeImageQueue);
326   TextureSet textureSet    = TextureSet::New();
327   textureSet.SetTexture(0u, nativeTexture);
328
329   renderer.SetTextures(textureSet);
330
331   self.AddRenderer(renderer);
332 }
333
334 Dali::NativeImageSourceQueue::ColorFormat GlView::GetColorFormat(Dali::Toolkit::GlView::ColorFormat format)
335 {
336   switch(format)
337   {
338     case Toolkit::GlView::ColorFormat::RGBA8888:
339     {
340       return Dali::NativeImageSourceQueue::ColorFormat::RGBA8888;
341     }
342
343     case Toolkit::GlView::ColorFormat::RGB888:
344     default:
345     {
346       return Dali::NativeImageSourceQueue::ColorFormat::RGBX8888;
347     }
348   }
349 }
350
351 } // namespace Internal
352
353 } // namespace Toolkit
354
355 } // namespace Dali