[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/trigger-event-factory-interface.h>
27 #include <dali/integration-api/thread-synchronization-interface.h>
28 #include <dali/internal/graphics/gles/egl-implementation.h>
29 #include <dali/internal/adaptor/common/adaptor-impl.h>
30 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
31 #include <dali/internal/window-system/common/window-base.h>
32 #include <dali/internal/window-system/common/window-factory.h>
33 #include <dali/internal/window-system/common/window-system.h>
34 #include <dali/internal/graphics/gles/egl-graphics.h>
35 #include <dali/internal/system/common/environment-variables.h>
36
37
38 namespace Dali
39 {
40 namespace Internal
41 {
42 namespace Adaptor
43 {
44
45 namespace
46 {
47
48 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
49
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
52 #endif
53
54 } // unnamed namespace
55
56 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
57 : mEGL( nullptr ),
58   mDisplayConnection( nullptr ),
59   mPositionSize( positionSize ),
60   mWindowBase(),
61   mThreadSynchronization( NULL ),
62   mRenderNotification( NULL ),
63   mRotationTrigger( NULL ),
64   mGraphics( nullptr ),
65   mEGLSurface( nullptr ),
66   mEGLContext( nullptr ),
67   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
68   mOutputTransformedSignal(),
69   mRotationAngle( 0 ),
70   mScreenRotationAngle( 0 ),
71   mOwnSurface( false ),
72   mRotationSupported( false ),
73   mRotationFinished( true ),
74   mScreenRotationFinished( true ),
75   mResizeFinished( true ),
76   mDpiHorizontal( 0 ),
77   mDpiVertical( 0 )
78 {
79   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
80   Initialize( surface );
81 }
82
83 WindowRenderSurface::~WindowRenderSurface()
84 {
85   if( mRotationTrigger )
86   {
87     delete mRotationTrigger;
88   }
89
90   if ( mEGLSurface )
91   {
92     DestroySurface();
93   }
94 }
95
96 void WindowRenderSurface::Initialize( Any surface )
97 {
98   // If width or height are zero, go full screen.
99   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
100   {
101     // Default window size == screen size
102     mPositionSize.x = 0;
103     mPositionSize.y = 0;
104
105     WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
106   }
107
108   // Create a window base
109   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
110   mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
111
112   // Connect signals
113   mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
114
115   // Check screen rotation
116   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
117   if( mScreenRotationAngle != 0 )
118   {
119     mScreenRotationFinished = false;
120     mResizeFinished = false;
121   }
122 }
123
124 Any WindowRenderSurface::GetNativeWindow()
125 {
126   return mWindowBase->GetNativeWindow();
127 }
128
129 int WindowRenderSurface::GetNativeWindowId()
130 {
131   return mWindowBase->GetNativeWindowId();
132 }
133
134 void WindowRenderSurface::Map()
135 {
136   mWindowBase->Show();
137 }
138
139 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
140 {
141   mRenderNotification = renderNotification;
142 }
143
144 void WindowRenderSurface::SetTransparency( bool transparent )
145 {
146   mWindowBase->SetTransparency( transparent );
147 }
148
149 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
150 {
151   if( !mRotationTrigger )
152   {
153     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
154     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
155   }
156
157   mPositionSize.width = width;
158   mPositionSize.height = height;
159
160   mRotationAngle = angle;
161   mRotationFinished = false;
162
163   mWindowBase->SetWindowRotationAngle( mRotationAngle );
164
165   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
166 }
167
168 WindowBase* WindowRenderSurface::GetWindowBase()
169 {
170   return mWindowBase.get();
171 }
172
173 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
174 {
175   return mOutputTransformedSignal;
176 }
177
178 PositionSize WindowRenderSurface::GetPositionSize() const
179 {
180   return mPositionSize;
181 }
182
183 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
184 {
185   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
186   {
187     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
188     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
189
190     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
191     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
192
193     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
194     {
195       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
196     }
197   }
198
199   dpiHorizontal = mDpiHorizontal;
200   dpiVertical = mDpiVertical;
201 }
202
203 int WindowRenderSurface::GetOrientation() const
204 {
205   return mWindowBase->GetOrientation();
206 }
207
208 void WindowRenderSurface::InitializeGraphics()
209 {
210
211   mGraphics = &mAdaptor->GetGraphicsInterface();
212
213   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
214   mEGL = &eglGraphics->GetEglInterface();
215
216   if ( mEGLContext == NULL )
217   {
218     // Create the OpenGL context for this window
219     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
220     eglImpl.ChooseConfig(true, mColorDepth);
221     eglImpl.CreateWindowContext( mEGLContext );
222
223     // Create the OpenGL surface
224     CreateSurface();
225   }
226 }
227
228 void WindowRenderSurface::CreateSurface()
229 {
230   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
231
232   int width, height;
233   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
234   {
235     width = mPositionSize.width;
236     height = mPositionSize.height;
237   }
238   else
239   {
240     width = mPositionSize.height;
241     height = mPositionSize.width;
242   }
243
244   // Create the EGL window
245   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
246
247   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
248
249   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
250   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
251
252   // Check rotation capability
253   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
254
255   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: w = %d h = %d angle = %d screen rotation = %d\n",
256       mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
257 }
258
259 void WindowRenderSurface::DestroySurface()
260 {
261   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
262
263   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
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