Make SceneView FBO multisampling + Sync utc harness
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / controls / scene-view / scene-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-scene3d/internal/controls/scene-view/scene-view-impl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali-toolkit/dali-toolkit.h>
23 #include <dali-toolkit/devel-api/controls/control-devel.h>
24 #include <dali-toolkit/devel-api/visual-factory/visual-factory.h>
25 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
26 #include <dali-toolkit/public-api/image-loader/image-url.h>
27 #include <dali-toolkit/public-api/image-loader/image.h>
28 #include <dali/devel-api/actors/camera-actor-devel.h>
29 #include <dali/devel-api/adaptor-framework/window-devel.h>
30 #include <dali/devel-api/common/stage.h>
31 #include <dali/devel-api/rendering/frame-buffer-devel.h>
32 #include <dali/integration-api/debug.h>
33 #include <dali/public-api/object/type-registry-helper.h>
34 #include <dali/public-api/object/type-registry.h>
35 #include <string_view>
36
37 // INTERNAL INCLUDES
38 #include <dali-scene3d/internal/controls/model/model-impl.h>
39 #include <dali-scene3d/internal/graphics/builtin-shader-extern-gen.h>
40 #include <dali-scene3d/public-api/loader/cube-map-loader.h>
41
42 using namespace Dali;
43
44 namespace Dali
45 {
46 namespace Scene3D
47 {
48 namespace Internal
49 {
50 namespace
51 {
52 BaseHandle Create()
53 {
54   return Scene3D::SceneView::New();
55 }
56
57 // Setup properties, signals and actions using the type-registry.
58 DALI_TYPE_REGISTRATION_BEGIN(Scene3D::SceneView, Toolkit::Control, Create);
59 DALI_TYPE_REGISTRATION_END()
60
61 Property::Index   RENDERING_BUFFER    = Dali::Toolkit::Control::CONTROL_PROPERTY_END_INDEX + 1;
62 constexpr int32_t DEFAULT_ORIENTATION = 0;
63
64 constexpr uint8_t DEFAULT_FRAME_BUFFER_MULTI_SAMPLING_LEVEL = 4u;
65
66 static constexpr std::string_view SKYBOX_INTENSITY_STRING = "uIntensity";
67
68 Dali::Actor CreateSkybox(const std::string& skyboxUrl)
69 {
70   struct Vertex
71   {
72     Vector3 aPosition;
73   };
74
75   Vertex skyboxVertices[] = {
76     // back
77     {Vector3(-1.0f, 1.0f, -1.0f)},
78     {Vector3(-1.0f, -1.0f, -1.0f)},
79     {Vector3(1.0f, -1.0f, -1.0f)},
80     {Vector3(1.0f, -1.0f, -1.0f)},
81     {Vector3(1.0f, 1.0f, -1.0f)},
82     {Vector3(-1.0f, 1.0f, -1.0f)},
83
84     // left
85     {Vector3(-1.0f, -1.0f, 1.0f)},
86     {Vector3(-1.0f, -1.0f, -1.0f)},
87     {Vector3(-1.0f, 1.0f, -1.0f)},
88     {Vector3(-1.0f, 1.0f, -1.0f)},
89     {Vector3(-1.0f, 1.0f, 1.0f)},
90     {Vector3(-1.0f, -1.0f, 1.0f)},
91
92     // right
93     {Vector3(1.0f, -1.0f, -1.0f)},
94     {Vector3(1.0f, -1.0f, 1.0f)},
95     {Vector3(1.0f, 1.0f, 1.0f)},
96     {Vector3(1.0f, 1.0f, 1.0f)},
97     {Vector3(1.0f, 1.0f, -1.0f)},
98     {Vector3(1.0f, -1.0f, -1.0f)},
99
100     // front
101     {Vector3(-1.0f, -1.0f, 1.0f)},
102     {Vector3(-1.0f, 1.0f, 1.0f)},
103     {Vector3(1.0f, 1.0f, 1.0f)},
104     {Vector3(1.0f, 1.0f, 1.0f)},
105     {Vector3(1.0f, -1.0f, 1.0f)},
106     {Vector3(-1.0f, -1.0f, 1.0f)},
107
108     // botton
109     {Vector3(-1.0f, 1.0f, -1.0f)},
110     {Vector3(1.0f, 1.0f, -1.0f)},
111     {Vector3(1.0f, 1.0f, 1.0f)},
112     {Vector3(1.0f, 1.0f, 1.0f)},
113     {Vector3(-1.0f, 1.0f, 1.0f)},
114     {Vector3(-1.0f, 1.0f, -1.0f)},
115
116     // top
117     {Vector3(-1.0f, -1.0f, -1.0f)},
118     {Vector3(-1.0f, -1.0f, 1.0f)},
119     {Vector3(1.0f, -1.0f, -1.0f)},
120     {Vector3(1.0f, -1.0f, -1.0f)},
121     {Vector3(-1.0f, -1.0f, 1.0f)},
122     {Vector3(1.0f, -1.0f, 1.0f)}};
123
124   Dali::Shader       shaderSkybox = Shader::New(SHADER_SKYBOX_SHADER_VERT.data(), SHADER_SKYBOX_SHADER_FRAG.data());
125   Dali::VertexBuffer vertexBuffer = Dali::VertexBuffer::New(Property::Map().Add("aPosition", Property::VECTOR3));
126   vertexBuffer.SetData(skyboxVertices, sizeof(skyboxVertices) / sizeof(Vertex));
127
128   Dali::Geometry skyboxGeometry = Geometry::New();
129   skyboxGeometry.AddVertexBuffer(vertexBuffer);
130   skyboxGeometry.SetType(Geometry::TRIANGLES);
131
132   Dali::Texture    skyboxTexture  = Dali::Scene3D::Loader::LoadCubeMap(skyboxUrl);
133   Dali::TextureSet skyboxTextures = TextureSet::New();
134   skyboxTextures.SetTexture(0, skyboxTexture);
135
136   Dali::Renderer skyboxRenderer = Renderer::New(skyboxGeometry, shaderSkybox);
137   skyboxRenderer.SetTextures(skyboxTextures);
138   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_INDEX, 2.0f);
139   // Enables the depth test.
140   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_TEST_MODE, DepthTestMode::ON);
141   // The fragment shader will run only is those pixels that have the max depth value.
142   skyboxRenderer.SetProperty(Renderer::Property::DEPTH_FUNCTION, DepthFunction::LESS_EQUAL);
143
144   Dali::Actor skyboxActor = Actor::New();
145   skyboxActor.SetProperty(Dali::Actor::Property::NAME, "SkyBox");
146   skyboxActor.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
147   skyboxActor.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
148   skyboxActor.AddRenderer(skyboxRenderer);
149   return skyboxActor;
150 }
151
152 } // anonymous namespace
153
154 SceneView::SceneView()
155 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
156   mWindowOrientation(DEFAULT_ORIENTATION),
157   mSkybox(),
158   mSkyboxOrientation(Quaternion()),
159   mSkyboxIntensity(1.0f)
160 {
161 }
162
163 SceneView::~SceneView() = default;
164
165 Dali::Scene3D::SceneView SceneView::New()
166 {
167   SceneView* impl = new SceneView();
168
169   Dali::Scene3D::SceneView handle = Dali::Scene3D::SceneView(*impl);
170
171   // Second-phase init of the implementation
172   // This can only be done after the CustomActor connection has been made...
173   impl->Initialize();
174
175   return handle;
176 }
177
178 void SceneView::AddCamera(CameraActor camera)
179 {
180   if(camera)
181   {
182     if(mCameras.empty())
183     {
184       UpdateCamera(camera);
185     }
186     mCameras.push_back(camera);
187   }
188 }
189
190 void SceneView::RemoveCamera(CameraActor camera)
191 {
192   if(camera == mDefaultCamera)
193   {
194     DALI_LOG_ERROR("Default Camera cannot removed.\n");
195     return;
196   }
197
198   if(camera)
199   {
200     for(uint32_t i = 0; i < mCameras.size(); ++i)
201     {
202       if(mCameras[i] == camera)
203       {
204         mCameras.erase(mCameras.begin() + i);
205         break;
206       }
207     }
208
209     if(mSelectedCamera == camera)
210     {
211       CameraActor newCurrentCamera = *mCameras.begin();
212       UpdateCamera(newCurrentCamera);
213     }
214   }
215 }
216
217 uint32_t SceneView::GetCameraCount() const
218 {
219   return mCameras.size();
220 }
221
222 CameraActor SceneView::GetSelectedCamera() const
223 {
224   return mSelectedCamera;
225 }
226
227 CameraActor SceneView::GetCamera(uint32_t index) const
228 {
229   if(index < mCameras.size())
230   {
231     return mCameras[index];
232   }
233   DALI_LOG_ERROR("Input index is out of bounds\n");
234   return CameraActor();
235 }
236
237 CameraActor SceneView::GetCamera(const std::string& name) const
238 {
239   CameraActor returnCamera;
240   for(auto&& camera : mCameras)
241   {
242     if(camera.GetProperty<std::string>(Actor::Property::NAME) == name)
243     {
244       returnCamera = camera;
245       break;
246     }
247   }
248   return returnCamera;
249 }
250
251 void SceneView::SelectCamera(uint32_t index)
252 {
253   UpdateCamera(GetCamera(index));
254 }
255
256 void SceneView::SelectCamera(const std::string& name)
257 {
258   UpdateCamera(GetCamera(name));
259 }
260
261 void SceneView::RegisterSceneItem(Scene3D::Internal::ImageBasedLightObserver* item)
262 {
263   if(item)
264   {
265     item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
266     mItems.push_back(item);
267   }
268 }
269
270 void SceneView::UnregisterSceneItem(Scene3D::Internal::ImageBasedLightObserver* item)
271 {
272   if(item)
273   {
274     for(uint32_t i = 0; i < mItems.size(); ++i)
275     {
276       if(mItems[i] == item)
277       {
278         mItems.erase(mItems.begin() + i);
279         break;
280       }
281     }
282   }
283 }
284
285 void SceneView::SetImageBasedLightSource(const std::string& diffuseUrl, const std::string& specularUrl, float scaleFactor)
286 {
287   mIBLResourceReady = false;
288
289   // If url is empty or invalid, reset IBL.
290   mDiffuseTexture  = (!diffuseUrl.empty()) ? Dali::Scene3D::Loader::LoadCubeMap(diffuseUrl) : Texture();
291   mSpecularTexture = (!specularUrl.empty()) ? Dali::Scene3D::Loader::LoadCubeMap(specularUrl) : Texture();
292
293   mIblScaleFactor = scaleFactor;
294
295   for(auto&& item : mItems)
296   {
297     if(item)
298     {
299       item->NotifyImageBasedLightTexture(mDiffuseTexture, mSpecularTexture, mIblScaleFactor);
300     }
301   }
302
303   mIBLResourceReady = true;
304   if(IsResourceReady())
305   {
306     Control::SetResourceReady(false);
307   }
308 }
309
310 void SceneView::SetImageBasedLightScaleFactor(float scaleFactor)
311 {
312   mIblScaleFactor = scaleFactor;
313   for(auto&& item : mItems)
314   {
315     if(item)
316     {
317       item->NotifyImageBasedLightScaleFactor(scaleFactor);
318     }
319   }
320 }
321
322 float SceneView::GetImageBasedLightScaleFactor() const
323 {
324   return mIblScaleFactor;
325 }
326
327 void SceneView::UseFramebuffer(bool useFramebuffer)
328 {
329   if(mUseFrameBuffer != useFramebuffer)
330   {
331     mUseFrameBuffer = useFramebuffer;
332     UpdateRenderTask();
333   }
334 }
335
336 bool SceneView::IsUsingFramebuffer() const
337 {
338   return mUseFrameBuffer;
339 }
340
341 void SceneView::SetSkybox(const std::string& skyboxUrl)
342 {
343   mSkyboxResourceReady = false;
344   if(mSkybox)
345   {
346     mSkybox.Unparent();
347     mSkybox.Reset();
348   }
349   mSkybox = CreateSkybox(skyboxUrl);
350   SetSkyboxIntensity(mSkyboxIntensity);
351   SetSkyboxOrientation(mSkyboxOrientation);
352   if(mRootLayer)
353   {
354     mRootLayer.Add(mSkybox);
355   }
356
357   mSkyboxResourceReady = true;
358   if(IsResourceReady())
359   {
360     Control::SetResourceReady(false);
361   }
362 }
363
364 void SceneView::SetSkyboxIntensity(float intensity)
365 {
366   mSkyboxIntensity = intensity;
367   if(intensity < 0)
368   {
369     DALI_LOG_ERROR("Intensity should be greater than or equal to 0.\n");
370     mSkyboxIntensity = 0.0f;
371   }
372
373   if(mSkybox)
374   {
375     mSkybox.RegisterProperty(SKYBOX_INTENSITY_STRING.data(), mSkyboxIntensity);
376   }
377 }
378
379 float SceneView::GetSkyboxIntensity() const
380 {
381   return mSkyboxIntensity;
382 }
383
384 void SceneView::SetSkyboxOrientation(const Quaternion& orientation)
385 {
386   mSkyboxOrientation = orientation;
387   if(mSkybox)
388   {
389     mSkybox.SetProperty(Dali::Actor::Property::ORIENTATION, orientation);
390   }
391 }
392
393 Quaternion SceneView::GetSkyboxOrientation() const
394 {
395   return mSkyboxOrientation;
396 }
397
398 ///////////////////////////////////////////////////////////
399 //
400 // Private methods
401 //
402
403 void SceneView::OnSceneConnection(int depth)
404 {
405   Window window = DevelWindow::Get(Self());
406   if(window)
407   {
408     window.ResizeSignal().Connect(this, &SceneView::OnWindowResized);
409     RenderTaskList taskList = window.GetRenderTaskList();
410     mRenderTask             = taskList.CreateTask();
411     mRenderTask.SetSourceActor(mRootLayer);
412     mRenderTask.SetExclusive(true);
413     mRenderTask.SetInputEnabled(true);
414     mRenderTask.SetCullMode(false);
415     mRenderTask.SetScreenToFrameBufferMappingActor(Self());
416
417     UpdateRenderTask();
418     mWindow = window;
419   }
420
421   Control::OnSceneConnection(depth);
422 }
423
424 void SceneView::OnSceneDisconnection()
425 {
426   mItems.clear();
427
428   Window window = mWindow.GetHandle();
429   if(window)
430   {
431     window.ResizeSignal().Disconnect(this, &SceneView::OnWindowResized);
432     RenderTaskList taskList = window.GetRenderTaskList();
433     if(mRenderTask)
434     {
435       taskList.RemoveTask(mRenderTask);
436       mFrameBuffer.Reset();
437     }
438   }
439   mWindow.Reset();
440
441   Control::OnSceneDisconnection();
442 }
443
444 void SceneView::OnInitialize()
445 {
446   Actor self = Self();
447   mRootLayer = Layer::New();
448   mRootLayer.SetProperty(Layer::Property::BEHAVIOR, Layer::LAYER_3D);
449   mRootLayer.SetProperty(Layer::Property::DEPTH_TEST, true);
450   // The models in the SceneView should be have independent coordinate with DALi default coordinate.
451   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_POSITION, false);
452   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_ORIENTATION, false);
453   mRootLayer.SetProperty(Dali::Actor::Property::INHERIT_SCALE, false);
454   self.Add(mRootLayer);
455
456   mDefaultCamera = Dali::CameraActor::New();
457   mDefaultCamera.SetProperty(Dali::Actor::Property::PARENT_ORIGIN, ParentOrigin::CENTER);
458   mDefaultCamera.SetProperty(Dali::Actor::Property::ANCHOR_POINT, AnchorPoint::CENTER);
459   mDefaultCamera.SetNearClippingPlane(1.0f);
460   AddCamera(mDefaultCamera);
461   UpdateCamera(mDefaultCamera);
462 }
463
464 void SceneView::OnChildAdd(Actor& child)
465 {
466   if(child != mRootLayer)
467   {
468     mRootLayer.Add(child);
469   }
470   Control::OnChildAdd(child);
471 }
472
473 void SceneView::OnChildRemove(Actor& child)
474 {
475   mRootLayer.Remove(child);
476   Control::OnChildRemove(child);
477 }
478
479 float SceneView::GetHeightForWidth(float width)
480 {
481   Extents padding;
482   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
483   return Control::GetHeightForWidth(width) + padding.top + padding.bottom;
484 }
485
486 float SceneView::GetWidthForHeight(float height)
487 {
488   Extents padding;
489   padding = Self().GetProperty<Extents>(Toolkit::Control::Property::PADDING);
490   return Control::GetWidthForHeight(height) + padding.start + padding.end;
491 }
492
493 void SceneView::OnRelayout(const Vector2& size, RelayoutContainer& container)
494 {
495   Control::OnRelayout(size, container);
496   // Change canvas size of camera actor.
497   UpdateRenderTask();
498 }
499
500 bool SceneView::IsResourceReady() const
501 {
502   return mIBLResourceReady & mSkyboxResourceReady;
503 }
504
505 void SceneView::UpdateCamera(CameraActor camera)
506 {
507   if(camera)
508   {
509     if(mSelectedCamera && mSelectedCamera.GetParent())
510     {
511       mSelectedCamera.Unparent();
512     }
513     mRootLayer.Add(camera);
514   }
515
516   mSelectedCamera = camera;
517   UpdateRenderTask();
518 }
519
520 void SceneView::UpdateRenderTask()
521 {
522   if(mRenderTask)
523   {
524     if(mSelectedCamera != mRenderTask.GetCameraActor())
525     {
526       mRenderTask.SetCameraActor(mSelectedCamera);
527     }
528
529     Vector3     size        = Self().GetProperty<Vector3>(Dali::Actor::Property::SIZE);
530     const float aspectRatio = size.width / size.height;
531     mSelectedCamera.SetAspectRatio(aspectRatio);
532
533     if(mUseFrameBuffer)
534     {
535       Dali::FrameBuffer currentFrameBuffer = mRenderTask.GetFrameBuffer();
536       if(!currentFrameBuffer ||
537          currentFrameBuffer.GetColorTexture().GetWidth() != size.width ||
538          currentFrameBuffer.GetColorTexture().GetHeight() != size.height)
539       {
540         mRenderTask.ResetViewportGuideActor();
541         mRenderTask.SetViewport(Dali::Viewport(Vector4::ZERO));
542
543         // create offscreen buffer of new size to render our child actors to
544         mTexture     = Dali::Texture::New(TextureType::TEXTURE_2D, Pixel::RGBA8888, unsigned(size.width), unsigned(size.height));
545         mFrameBuffer = FrameBuffer::New(size.width, size.height, FrameBuffer::Attachment::DEPTH_STENCIL);
546         mFrameBuffer.AttachColorTexture(mTexture);
547         DevelFrameBuffer::SetMultiSamplingLevel(mFrameBuffer, DEFAULT_FRAME_BUFFER_MULTI_SAMPLING_LEVEL);
548         Dali::Toolkit::ImageUrl imageUrl = Dali::Toolkit::Image::GenerateUrl(mFrameBuffer, 0u);
549
550         Property::Map imagePropertyMap;
551         imagePropertyMap.Insert(Toolkit::Visual::Property::TYPE, Toolkit::Visual::IMAGE);
552         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::URL, imageUrl.GetUrl());
553         // To flip rendered scene without CameraActor::SetInvertYAxis() to avoid backface culling.
554         imagePropertyMap.Insert(Toolkit::ImageVisual::Property::PIXEL_AREA, Vector4(0.0f, 1.0f, 1.0f, -1.0f));
555         mVisual = Toolkit::VisualFactory::Get().CreateVisual(imagePropertyMap);
556
557         Toolkit::DevelControl::RegisterVisual(*this, RENDERING_BUFFER, mVisual);
558
559         mRenderTask.SetFrameBuffer(mFrameBuffer);
560         mRenderTask.SetClearEnabled(true);
561         mRenderTask.SetClearColor(Color::TRANSPARENT);
562       }
563     }
564     else
565     {
566       mRenderTask.SetViewportGuideActor(Self());
567       if(mRenderTask.GetFrameBuffer())
568       {
569         FrameBuffer framebuffer;
570         mRenderTask.SetFrameBuffer(framebuffer);
571         mRenderTask.SetClearEnabled(false);
572
573         Toolkit::DevelControl::UnregisterVisual(*this, RENDERING_BUFFER);
574
575         mVisual.Reset();
576         mFrameBuffer.Reset();
577         mTexture.Reset();
578       }
579     }
580
581     RotateCamera();
582   }
583 }
584
585 void SceneView::OnWindowResized(Window window, Window::WindowSize size)
586 {
587   mWindowOrientation = DevelWindow::GetPhysicalOrientation(window);
588   RotateCamera();
589 }
590
591 void SceneView::RotateCamera()
592 {
593   if(mUseFrameBuffer)
594   {
595     DevelCameraActor::RotateProjection(mSelectedCamera, DEFAULT_ORIENTATION);
596   }
597   else
598   {
599     DevelCameraActor::RotateProjection(mSelectedCamera, mWindowOrientation);
600   }
601 }
602
603 } // namespace Internal
604 } // namespace Scene3D
605 } // namespace Dali