[dali_1.9.18] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / common / window-render-surface.cpp
1 /*
2  * Copyright (c) 2020 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/internal/window-system/common/window-render-surface.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/debug.h>
24
25 // INTERNAL INCLUDES
26 #include <dali/integration-api/adaptor-framework/thread-synchronization-interface.h>
27 #include <dali/integration-api/adaptor-framework/trigger-event-factory.h>
28 #include <dali/internal/adaptor/common/adaptor-impl.h>
29 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
30 #include <dali/internal/graphics/gles/egl-graphics.h>
31 #include <dali/internal/graphics/gles/egl-implementation.h>
32 #include <dali/internal/window-system/common/window-base.h>
33 #include <dali/internal/window-system/common/window-factory.h>
34 #include <dali/internal/window-system/common/window-system.h>
35 #include <dali/internal/system/common/environment-variables.h>
36
37 namespace Dali
38 {
39 namespace Internal
40 {
41 namespace Adaptor
42 {
43
44 namespace
45 {
46
47 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
48
49 #if defined(DEBUG_ENABLED)
50 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
51 #endif
52
53 } // unnamed namespace
54
55 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
56 : mEGL( nullptr ),
57   mDisplayConnection( nullptr ),
58   mPositionSize( positionSize ),
59   mWindowBase(),
60   mThreadSynchronization( NULL ),
61   mRenderNotification( NULL ),
62   mRotationTrigger( NULL ),
63   mGraphics( nullptr ),
64   mEGLSurface( nullptr ),
65   mEGLContext( nullptr ),
66   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
67   mOutputTransformedSignal(),
68   mRotationAngle( 0 ),
69   mScreenRotationAngle( 0 ),
70   mOwnSurface( false ),
71   mRotationSupported( false ),
72   mRotationFinished( true ),
73   mScreenRotationFinished( true ),
74   mResizeFinished( true ),
75   mDpiHorizontal( 0 ),
76   mDpiVertical( 0 )
77 {
78   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
79   Initialize( surface );
80 }
81
82 WindowRenderSurface::~WindowRenderSurface()
83 {
84   if( mRotationTrigger )
85   {
86     delete mRotationTrigger;
87   }
88 }
89
90 void WindowRenderSurface::Initialize( Any surface )
91 {
92   // If width or height are zero, go full screen.
93   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
94   {
95     // Default window size == screen size
96     mPositionSize.x = 0;
97     mPositionSize.y = 0;
98     WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
99   }
100
101   // Create a window base
102   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
103   mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
104
105   // Connect signals
106   mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
107
108   // Check screen rotation
109   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
110   if( mScreenRotationAngle != 0 )
111   {
112     mScreenRotationFinished = false;
113   }
114 }
115
116 Any WindowRenderSurface::GetNativeWindow()
117 {
118   return mWindowBase->GetNativeWindow();
119 }
120
121 int WindowRenderSurface::GetNativeWindowId()
122 {
123   return mWindowBase->GetNativeWindowId();
124 }
125
126 void WindowRenderSurface::Map()
127 {
128   mWindowBase->Show();
129 }
130
131 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
132 {
133   mRenderNotification = renderNotification;
134 }
135
136 void WindowRenderSurface::SetTransparency( bool transparent )
137 {
138   mWindowBase->SetTransparency( transparent );
139 }
140
141 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
142 {
143   if( !mRotationSupported )
144   {
145     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
146     return;
147   }
148
149   if( !mRotationTrigger )
150   {
151     mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
152   }
153
154   mPositionSize.width = width;
155   mPositionSize.height = height;
156
157   mRotationAngle = angle;
158   mRotationFinished = false;
159
160   mWindowBase->SetWindowRotationAngle( mRotationAngle );
161
162   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
163 }
164
165 WindowBase* WindowRenderSurface::GetWindowBase()
166 {
167   return mWindowBase.get();
168 }
169
170 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
171 {
172   return mOutputTransformedSignal;
173 }
174
175 PositionSize WindowRenderSurface::GetPositionSize() const
176 {
177   return mPositionSize;
178 }
179
180 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
181 {
182   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
183   {
184     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
185     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
186
187     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
188     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
189
190     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
191     {
192       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
193     }
194   }
195
196   dpiHorizontal = mDpiHorizontal;
197   dpiVertical = mDpiVertical;
198 }
199
200 void WindowRenderSurface::InitializeGraphics()
201 {
202   mGraphics = &mAdaptor->GetGraphicsInterface();
203
204   DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
205
206   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
207   mEGL = &eglGraphics->GetEglInterface();
208
209   if ( mEGLContext == NULL )
210   {
211     // Create the OpenGL context for this window
212     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
213     eglImpl.ChooseConfig(true, mColorDepth);
214     eglImpl.CreateWindowContext( mEGLContext );
215
216     // Create the OpenGL surface
217     CreateSurface();
218   }
219 }
220
221 void WindowRenderSurface::CreateSurface()
222 {
223   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
224
225   int width, height;
226   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
227   {
228     width = mPositionSize.width;
229     height = mPositionSize.height;
230   }
231   else
232   {
233     width = mPositionSize.height;
234     height = mPositionSize.width;
235   }
236
237   // Create the EGL window
238   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
239
240   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
241
242   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
243   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
244
245   // Check rotation capability
246   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
247
248   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
249       mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
250 }
251
252 void WindowRenderSurface::DestroySurface()
253 {
254   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
255
256   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
257   if( eglGraphics )
258   {
259     DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
260
261     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
262
263     eglImpl.DestroySurface( mEGLSurface );
264     mEGLSurface = nullptr;
265
266     // Destroy context also
267     eglImpl.DestroyContext( mEGLContext );
268     mEGLContext = nullptr;
269
270     mWindowBase->DestroyEglWindow();
271   }
272 }
273
274 bool WindowRenderSurface::ReplaceGraphicsSurface()
275 {
276   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
277
278   // Destroy the old one
279   mWindowBase->DestroyEglWindow();
280
281   int width, height;
282   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
283   {
284     width = mPositionSize.width;
285     height = mPositionSize.height;
286   }
287   else
288   {
289     width = mPositionSize.height;
290     height = mPositionSize.width;
291   }
292
293   // Create the EGL window
294   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
295
296   // Set screen rotation
297   mScreenRotationFinished = false;
298
299   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
300
301   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
302   return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
303 }
304
305 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
306 {
307   bool needToMove = false;
308   bool needToResize = false;
309
310   // Check moving
311   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
312       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
313   {
314     needToMove = true;
315   }
316
317   // Check resizing
318   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
319       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
320   {
321     needToResize = true;
322   }
323
324   if( needToResize )
325   {
326     if( needToMove )
327     {
328       mWindowBase->MoveResize( positionSize );
329     }
330     else
331     {
332       mWindowBase->Resize( positionSize );
333     }
334
335     mResizeFinished = false;
336     mPositionSize = positionSize;
337   }
338   else
339   {
340     if( needToMove )
341     {
342       mWindowBase->Move( positionSize );
343
344       mPositionSize = positionSize;
345     }
346   }
347
348   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
349 }
350
351 void WindowRenderSurface::StartRender()
352 {
353 }
354
355 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
356 {
357   MakeContextCurrent();
358
359   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
360
361   if( resizingSurface )
362   {
363     // Window rotate or screen rotate
364     if( !mRotationFinished || !mScreenRotationFinished )
365     {
366       int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
367
368       mWindowBase->SetEglWindowRotation( totalAngle );
369       mWindowBase->SetEglWindowBufferTransform( totalAngle );
370
371       // Reset only screen rotation flag
372       mScreenRotationFinished = true;
373
374       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
375     }
376
377     // Only window rotate
378     if( !mRotationFinished )
379     {
380       mWindowBase->SetEglWindowTransform( mRotationAngle );
381     }
382
383     // Resize case
384     if( !mResizeFinished )
385     {
386       mWindowBase->ResizeEglWindow( mPositionSize );
387       mResizeFinished = true;
388
389       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
390     }
391
392     if (eglGraphics)
393     {
394       Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
395       eglImpl.SetFullSwapNextFrame();
396     }
397   }
398
399   if (eglGraphics)
400   {
401     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
402     eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
403   }
404
405   return true;
406 }
407
408 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
409 {
410   // Inform the gl implementation that rendering has finished before informing the surface
411   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
412   if ( eglGraphics )
413   {
414     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
415     mGLES.PostRender();
416
417     if( renderToFbo )
418     {
419       mGLES.Flush();
420       mGLES.Finish();
421     }
422     else
423     {
424       if( resizingSurface )
425       {
426         if( !mRotationFinished )
427         {
428           if( mThreadSynchronization )
429           {
430             // Enable PostRender flag
431             mThreadSynchronization->PostRenderStarted();
432           }
433
434           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
435
436           mRotationTrigger->Trigger();
437
438           if( mThreadSynchronization )
439           {
440             // Wait until the event-thread complete the rotation event processing
441             mThreadSynchronization->PostRenderWaitForCompletion();
442           }
443         }
444       }
445     }
446
447     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
448     eglImpl.SwapBuffers( mEGLSurface, damagedRects );
449
450     if( mRenderNotification )
451     {
452       mRenderNotification->Trigger();
453     }
454   }
455 }
456
457 void WindowRenderSurface::StopRender()
458 {
459 }
460
461 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
462 {
463   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
464
465   mThreadSynchronization = &threadSynchronization;
466 }
467
468 void WindowRenderSurface::ReleaseLock()
469 {
470   // Nothing to do.
471 }
472
473 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
474 {
475   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
476 }
477
478 void WindowRenderSurface::MakeContextCurrent()
479 {
480   if ( mEGL != nullptr )
481   {
482     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
483   }
484 }
485
486 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
487 {
488   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
489 }
490
491 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
492 {
493   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
494 }
495
496 void WindowRenderSurface::OutputTransformed()
497 {
498   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
499
500   if( mScreenRotationAngle != screenRotationAngle )
501   {
502     mScreenRotationAngle = screenRotationAngle;
503     mScreenRotationFinished = false;
504
505     mOutputTransformedSignal.Emit();
506
507     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
508   }
509   else
510   {
511     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
512   }
513 }
514
515 void WindowRenderSurface::ProcessRotationRequest()
516 {
517   mRotationFinished = true;
518
519   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
520
521   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
522
523   if( mThreadSynchronization )
524   {
525     mThreadSynchronization->PostRenderComplete();
526   }
527 }
528
529 } // namespace Adaptor
530
531 } // namespace internal
532
533 } // namespace Dali