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