[Tizen] Add screen and client rotation itself function
[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   if ( mEGLSurface )
90   {
91     DestroySurface();
92   }
93 }
94
95 void WindowRenderSurface::Initialize( Any surface )
96 {
97   // If width or height are zero, go full screen.
98   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
99   {
100     // Default window size == screen size
101     mPositionSize.x = 0;
102     mPositionSize.y = 0;
103     WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
104   }
105
106   // Create a window base
107   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
108   mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
109
110   // Connect signals
111   mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
112
113   // Check screen rotation
114   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
115   if( mScreenRotationAngle != 0 )
116   {
117     mScreenRotationFinished = false;
118     mResizeFinished = false;
119   }
120 }
121
122 Any WindowRenderSurface::GetNativeWindow()
123 {
124   return mWindowBase->GetNativeWindow();
125 }
126
127 int WindowRenderSurface::GetNativeWindowId()
128 {
129   return mWindowBase->GetNativeWindowId();
130 }
131
132 void WindowRenderSurface::Map()
133 {
134   mWindowBase->Show();
135 }
136
137 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
138 {
139   mRenderNotification = renderNotification;
140 }
141
142 void WindowRenderSurface::SetTransparency( bool transparent )
143 {
144   mWindowBase->SetTransparency( transparent );
145 }
146
147 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
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 int WindowRenderSurface::GetOrientation() const
201 {
202   return mWindowBase->GetOrientation();
203 }
204
205 void WindowRenderSurface::InitializeGraphics()
206 {
207
208   mGraphics = &mAdaptor->GetGraphicsInterface();
209
210   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
211   mEGL = &eglGraphics->GetEglInterface();
212
213   if ( mEGLContext == NULL )
214   {
215     // Create the OpenGL context for this window
216     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
217     eglImpl.ChooseConfig(true, mColorDepth);
218     eglImpl.CreateWindowContext( mEGLContext );
219
220     // Create the OpenGL surface
221     CreateSurface();
222   }
223 }
224
225 void WindowRenderSurface::CreateSurface()
226 {
227   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
228
229   int width, height;
230   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
231   {
232     width = mPositionSize.width;
233     height = mPositionSize.height;
234   }
235   else
236   {
237     width = mPositionSize.height;
238     height = mPositionSize.width;
239   }
240
241   // Create the EGL window
242   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
243
244   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
245
246   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
247   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
248
249   // Check rotation capability
250   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
251
252   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
253       mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
254 }
255
256 void WindowRenderSurface::DestroySurface()
257 {
258   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
259
260   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
261
262   DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
263
264   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
265   eglImpl.DestroySurface( mEGLSurface );
266
267   mWindowBase->DestroyEglWindow();
268 }
269
270 bool WindowRenderSurface::ReplaceGraphicsSurface()
271 {
272   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
273
274   // Destroy the old one
275   mWindowBase->DestroyEglWindow();
276
277   int width, height;
278   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
279   {
280     width = mPositionSize.width;
281     height = mPositionSize.height;
282   }
283   else
284   {
285     width = mPositionSize.height;
286     height = mPositionSize.width;
287   }
288
289   // Create the EGL window
290   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
291
292   // Set screen rotation
293   mScreenRotationFinished = false;
294
295   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
296
297   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
298   return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
299 }
300
301 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
302 {
303   bool needToMove = false;
304   bool needToResize = false;
305
306   // Check moving
307   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
308       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
309   {
310     needToMove = true;
311   }
312
313   // Check resizing
314   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
315       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
316   {
317     needToResize = true;
318   }
319
320   if( needToResize )
321   {
322     if( needToMove )
323     {
324       mWindowBase->MoveResize( positionSize );
325     }
326     else
327     {
328       mWindowBase->Resize( positionSize );
329     }
330
331     mResizeFinished = false;
332     mPositionSize = positionSize;
333   }
334   else
335   {
336     if( needToMove )
337     {
338       mWindowBase->Move( positionSize );
339
340       mPositionSize = positionSize;
341     }
342   }
343
344   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
345 }
346
347 void WindowRenderSurface::StartRender()
348 {
349 }
350
351 bool WindowRenderSurface::PreRender( bool resizingSurface )
352 {
353   MakeContextCurrent();
354
355   if( resizingSurface )
356   {
357     int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
358
359     // Window rotate or screen rotate
360     if( !mRotationFinished || !mScreenRotationFinished )
361     {
362       mWindowBase->SetEglWindowRotation( totalAngle );
363       mWindowBase->SetEglWindowBufferTransform( totalAngle );
364
365       // Reset only screen rotation flag
366       mScreenRotationFinished = true;
367
368       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
369     }
370
371     // Only window rotate
372     if( !mRotationFinished )
373     {
374       mWindowBase->SetEglWindowTransform( mRotationAngle );
375     }
376
377     // Resize case
378     if ( !mResizeFinished )
379     {
380       Dali::PositionSize positionSize;
381       positionSize.x = mPositionSize.x;
382       positionSize.y = mPositionSize.y;
383       if( totalAngle == 0 || totalAngle == 180 )
384       {
385         positionSize.width = mPositionSize.width;
386         positionSize.height = mPositionSize.height;
387       }
388       else
389       {
390         positionSize.width = mPositionSize.height;
391         positionSize.height = mPositionSize.width;
392       }
393       mWindowBase->ResizeEglWindow( positionSize );
394       mResizeFinished = true;
395
396       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
397     }
398   }
399
400   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
401   if ( eglGraphics )
402   {
403     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
404     mGLES.PreRender();
405   }
406
407   return true;
408 }
409
410 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
411 {
412   // Inform the gl implementation that rendering has finished before informing the surface
413   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
414   if ( eglGraphics )
415   {
416     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
417     mGLES.PostRender();
418
419     if( renderToFbo )
420     {
421       mGLES.Flush();
422       mGLES.Finish();
423     }
424     else
425     {
426       if( resizingSurface )
427       {
428         if( !mRotationFinished )
429         {
430           if( mThreadSynchronization )
431           {
432             // Enable PostRender flag
433             mThreadSynchronization->PostRenderStarted();
434           }
435
436           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
437
438           mRotationTrigger->Trigger();
439
440           if( mThreadSynchronization )
441           {
442             // Wait until the event-thread complete the rotation event processing
443             mThreadSynchronization->PostRenderWaitForCompletion();
444           }
445         }
446       }
447     }
448
449     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
450     eglImpl.SwapBuffers( mEGLSurface );
451
452     if( mRenderNotification )
453     {
454       mRenderNotification->Trigger();
455     }
456   }
457 }
458
459 void WindowRenderSurface::StopRender()
460 {
461 }
462
463 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
464 {
465   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
466
467   mThreadSynchronization = &threadSynchronization;
468 }
469
470 void WindowRenderSurface::ReleaseLock()
471 {
472   // Nothing to do.
473 }
474
475 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
476 {
477   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
478 }
479
480 void WindowRenderSurface::MakeContextCurrent()
481 {
482   if ( mEGL != nullptr )
483   {
484     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
485   }
486 }
487
488 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
489 {
490   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
491 }
492
493 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
494 {
495   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
496 }
497
498 void WindowRenderSurface::OutputTransformed()
499 {
500   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
501
502   if( mScreenRotationAngle != screenRotationAngle )
503   {
504     mScreenRotationAngle = screenRotationAngle;
505     mScreenRotationFinished = false;
506     mResizeFinished = false;
507
508     mOutputTransformedSignal.Emit();
509
510     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
511   }
512   else
513   {
514     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
515   }
516 }
517
518 void WindowRenderSurface::ProcessRotationRequest()
519 {
520   mRotationFinished = true;
521
522   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
523
524   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
525
526   if( mThreadSynchronization )
527   {
528     mThreadSynchronization->PostRenderComplete();
529   }
530 }
531
532 } // namespace Adaptor
533
534 } // namespace internal
535
536 } // namespace Dali