[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) 2019 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-interface.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     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
152     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
153   }
154
155   mPositionSize.width = width;
156   mPositionSize.height = height;
157
158   mRotationAngle = angle;
159   mRotationFinished = false;
160
161   mWindowBase->SetWindowRotationAngle( mRotationAngle );
162
163   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
164 }
165
166 WindowBase* WindowRenderSurface::GetWindowBase()
167 {
168   return mWindowBase.get();
169 }
170
171 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
172 {
173   return mOutputTransformedSignal;
174 }
175
176 PositionSize WindowRenderSurface::GetPositionSize() const
177 {
178   return mPositionSize;
179 }
180
181 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
182 {
183   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
184   {
185     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
186     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
187
188     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
189     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
190
191     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
192     {
193       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
194     }
195   }
196
197   dpiHorizontal = mDpiHorizontal;
198   dpiVertical = mDpiVertical;
199 }
200
201 int WindowRenderSurface::GetOrientation() const
202 {
203   return mWindowBase->GetOrientation();
204 }
205
206 void WindowRenderSurface::InitializeGraphics()
207 {
208
209   mGraphics = &mAdaptor->GetGraphicsInterface();
210
211   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
212   mEGL = &eglGraphics->GetEglInterface();
213
214   if ( mEGLContext == NULL )
215   {
216     // Create the OpenGL context for this window
217     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
218     eglImpl.ChooseConfig(true, mColorDepth);
219     eglImpl.CreateWindowContext( mEGLContext );
220
221     // Create the OpenGL surface
222     CreateSurface();
223   }
224 }
225
226 void WindowRenderSurface::CreateSurface()
227 {
228   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
229
230   int width, height;
231   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
232   {
233     width = mPositionSize.width;
234     height = mPositionSize.height;
235   }
236   else
237   {
238     width = mPositionSize.height;
239     height = mPositionSize.width;
240   }
241
242   // Create the EGL window
243   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
244
245   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
246
247   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
248   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
249
250   // Check rotation capability
251   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
252
253   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
254       mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
255 }
256
257 void WindowRenderSurface::DestroySurface()
258 {
259   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
260
261   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
262
263   DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
264
265   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
266   eglImpl.DestroySurface( mEGLSurface );
267
268   mWindowBase->DestroyEglWindow();
269 }
270
271 bool WindowRenderSurface::ReplaceGraphicsSurface()
272 {
273   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
274
275   // Destroy the old one
276   mWindowBase->DestroyEglWindow();
277
278   int width, height;
279   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
280   {
281     width = mPositionSize.width;
282     height = mPositionSize.height;
283   }
284   else
285   {
286     width = mPositionSize.height;
287     height = mPositionSize.width;
288   }
289
290   // Create the EGL window
291   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
292
293   // Set screen rotation
294   mScreenRotationFinished = false;
295
296   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
297
298   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
299   return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
300 }
301
302 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
303 {
304   bool needToMove = false;
305   bool needToResize = false;
306
307   // Check moving
308   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
309       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
310   {
311     needToMove = true;
312   }
313
314   // Check resizing
315   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
316       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
317   {
318     needToResize = true;
319   }
320
321   if( needToResize )
322   {
323     if( needToMove )
324     {
325       mWindowBase->MoveResize( positionSize );
326     }
327     else
328     {
329       mWindowBase->Resize( positionSize );
330     }
331
332     mResizeFinished = false;
333     mPositionSize = positionSize;
334   }
335   else
336   {
337     if( needToMove )
338     {
339       mWindowBase->Move( positionSize );
340
341       mPositionSize = positionSize;
342     }
343   }
344
345   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
346 }
347
348 void WindowRenderSurface::StartRender()
349 {
350 }
351
352 bool WindowRenderSurface::PreRender( bool resizingSurface )
353 {
354   MakeContextCurrent();
355
356   if( resizingSurface )
357   {
358     int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
359
360     // Window rotate or screen rotate
361     if( !mRotationFinished || !mScreenRotationFinished )
362     {
363       mWindowBase->SetEglWindowRotation( totalAngle );
364       mWindowBase->SetEglWindowBufferTransform( totalAngle );
365
366       // Reset only screen rotation flag
367       mScreenRotationFinished = true;
368
369       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
370     }
371
372     // Only window rotate
373     if( !mRotationFinished )
374     {
375       mWindowBase->SetEglWindowTransform( mRotationAngle );
376     }
377
378     // Resize case
379     if ( !mResizeFinished )
380     {
381       Dali::PositionSize positionSize;
382       positionSize.x = mPositionSize.x;
383       positionSize.y = mPositionSize.y;
384       if( totalAngle == 0 || totalAngle == 180 )
385       {
386         positionSize.width = mPositionSize.width;
387         positionSize.height = mPositionSize.height;
388       }
389       else
390       {
391         positionSize.width = mPositionSize.height;
392         positionSize.height = mPositionSize.width;
393       }
394
395       mWindowBase->ResizeEglWindow( positionSize );
396       mResizeFinished = true;
397
398       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
399     }
400   }
401
402   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
403   if ( eglGraphics )
404   {
405     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
406     mGLES.PreRender();
407   }
408
409   return true;
410 }
411
412 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
413 {
414   // Inform the gl implementation that rendering has finished before informing the surface
415   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
416   if ( eglGraphics )
417   {
418     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
419     mGLES.PostRender();
420
421     if( renderToFbo )
422     {
423       mGLES.Flush();
424       mGLES.Finish();
425     }
426     else
427     {
428       if( resizingSurface )
429       {
430         if( !mRotationFinished )
431         {
432           if( mThreadSynchronization )
433           {
434             // Enable PostRender flag
435             mThreadSynchronization->PostRenderStarted();
436           }
437
438           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
439
440           mRotationTrigger->Trigger();
441
442           if( mThreadSynchronization )
443           {
444             // Wait until the event-thread complete the rotation event processing
445             mThreadSynchronization->PostRenderWaitForCompletion();
446           }
447         }
448       }
449     }
450
451     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
452     eglImpl.SwapBuffers( mEGLSurface );
453
454     if( mRenderNotification )
455     {
456       mRenderNotification->Trigger();
457     }
458   }
459 }
460
461 void WindowRenderSurface::StopRender()
462 {
463 }
464
465 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
466 {
467   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
468
469   mThreadSynchronization = &threadSynchronization;
470 }
471
472 void WindowRenderSurface::ReleaseLock()
473 {
474   // Nothing to do.
475 }
476
477 Integration::RenderSurface::Type WindowRenderSurface::GetSurfaceType()
478 {
479   return RenderSurface::WINDOW_RENDER_SURFACE;
480 }
481
482 void WindowRenderSurface::MakeContextCurrent()
483 {
484   if ( mEGL != nullptr )
485   {
486     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
487   }
488 }
489
490 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
491 {
492   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
493 }
494
495 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
496 {
497   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
498 }
499
500 void WindowRenderSurface::OutputTransformed()
501 {
502   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
503
504   if( mScreenRotationAngle != screenRotationAngle )
505   {
506     mScreenRotationAngle = screenRotationAngle;
507     mScreenRotationFinished = false;
508     mResizeFinished = false;
509
510     mOutputTransformedSignal.Emit();
511
512     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
513   }
514   else
515   {
516     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
517   }
518 }
519
520 void WindowRenderSurface::ProcessRotationRequest()
521 {
522   mRotationFinished = true;
523
524   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
525
526   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
527
528   if( mThreadSynchronization )
529   {
530     mThreadSynchronization->PostRenderComplete();
531   }
532 }
533
534 } // namespace Adaptor
535
536 } // namespace internal
537
538 } // namespace Dali