[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           DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
433
434           mRotationTrigger->Trigger();
435
436           if( mThreadSynchronization )
437           {
438             // Wait until the event-thread complete the rotation event processing
439             mThreadSynchronization->PostRenderWaitForCompletion();
440           }
441         }
442       }
443     }
444
445     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
446     eglImpl.SwapBuffers( mEGLSurface );
447
448     if( mRenderNotification )
449     {
450       mRenderNotification->Trigger();
451     }
452   }
453 }
454
455 void WindowRenderSurface::StopRender()
456 {
457 }
458
459 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
460 {
461   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
462
463   mThreadSynchronization = &threadSynchronization;
464 }
465
466 void WindowRenderSurface::ReleaseLock()
467 {
468   // Nothing to do.
469 }
470
471 Integration::RenderSurface::Type WindowRenderSurface::GetSurfaceType()
472 {
473   return RenderSurface::WINDOW_RENDER_SURFACE;
474 }
475
476 void WindowRenderSurface::MakeContextCurrent()
477 {
478   if ( mEGL != nullptr )
479   {
480     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
481   }
482 }
483
484 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
485 {
486   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
487 }
488
489 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
490 {
491   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
492 }
493
494 void WindowRenderSurface::OutputTransformed()
495 {
496   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
497
498   if( mScreenRotationAngle != screenRotationAngle )
499   {
500     mScreenRotationAngle = screenRotationAngle;
501     mScreenRotationFinished = false;
502     mResizeFinished = false;
503
504     mOutputTransformedSignal.Emit();
505
506     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
507   }
508   else
509   {
510     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
511   }
512 }
513
514 void WindowRenderSurface::ProcessRotationRequest()
515 {
516   mRotationFinished = true;
517
518   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
519
520   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
521
522   if( mThreadSynchronization )
523   {
524     mThreadSynchronization->PostRenderComplete();
525   }
526 }
527
528 } // namespace Adaptor
529
530 } // namespace internal
531
532 } // namespace Dali