Revert "[Tizen] Revert "Support screen rotation""
[platform/core/uifw/dali-adaptor.git] / adaptors / ecore / wayland / window-render-surface-ecore-wl.cpp
1 /*
2  * Copyright (c) 2017 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 <window-render-surface.h>
20
21 // EXTERNAL INCLUDES
22 #include <dlfcn.h>
23 #include <dali/integration-api/gl-abstraction.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/integration-api/gl-defines.h>
26
27 // INTERNAL INCLUDES
28 #include <wl-types.h>
29 #include <gl/egl-implementation.h>
30 #include <adaptors/common/adaptor-impl.h>
31 #include <integration-api/trigger-event-factory-interface.h>
32
33 namespace Dali
34 {
35
36 #if defined(DEBUG_ENABLED)
37 extern Debug::Filter* gRenderSurfaceLogFilter;
38 #endif
39
40 namespace ECore
41 {
42
43 namespace
44 {
45
46 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
47
48 } // unnamed namespace
49
50 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize,
51                                           Any surface,
52                                           const std::string& name,
53                                           bool isTransparent)
54 : EcoreWlRenderSurface( positionSize, surface, name, isTransparent ),
55   mWlWindow( NULL ),
56   mWlSurface( NULL ),
57   mEglWindow( NULL ),
58   mThreadSynchronization( NULL ),
59   mRotationTrigger( NULL ),
60   mRotationAngle( 0 ),
61   mScreenRotationAngle( 0 ),
62   mRotationSupported( false ),
63   mRotationFinished( true ),
64   mScreenRotationFinished( true ),
65   mResizeFinished( true )
66 {
67   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
68   Init( surface );
69 }
70
71 WindowRenderSurface::~WindowRenderSurface()
72 {
73   if( mEglWindow != NULL )
74   {
75     wl_egl_window_destroy(mEglWindow);
76     mEglWindow = NULL;
77   }
78
79   if( mOwnSurface )
80   {
81     ecore_wl_window_free( mWlWindow );
82   }
83
84   if( mRotationTrigger )
85   {
86     delete mRotationTrigger;
87   }
88
89 }
90
91 Ecore_Wl_Window* WindowRenderSurface::GetDrawable()
92 {
93   // already an e-core type
94   return mWlWindow;
95 }
96
97 Any WindowRenderSurface::GetSurface()
98 {
99   // already an e-core type
100   return Any( mWlWindow );
101 }
102
103 Ecore_Wl_Window* WindowRenderSurface::GetWlWindow()
104 {
105   return mWlWindow;
106 }
107
108 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
109 {
110   if( !mRotationSupported )
111   {
112     DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
113     return;
114   }
115
116   if( !mRotationTrigger )
117   {
118     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
119     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
120   }
121
122   mPositionSize.width = width;
123   mPositionSize.height = height;
124
125   mRotationAngle = angle;
126   mRotationFinished = false;
127
128   ecore_wl_window_rotation_set( mWlWindow, mRotationAngle );
129
130   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
131 }
132
133 void WindowRenderSurface::OutputTransformed()
134 {
135   int transform;
136
137   if( ecore_wl_window_ignore_output_transform_get( mWlWindow ) )
138   {
139     transform = 0;
140   }
141   else
142   {
143     transform = ecore_wl_output_transform_get( ecore_wl_window_output_find( mWlWindow ) );
144   }
145
146   ecore_wl_window_buffer_transform_set( mWlWindow, transform );
147
148   mScreenRotationAngle = transform * 90;
149   mScreenRotationFinished = false;
150
151   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
152 }
153
154 void WindowRenderSurface::SetTransparency( bool transparent )
155 {
156   ecore_wl_window_alpha_set( mWlWindow, transparent );
157 }
158
159 void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
160 {
161   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
162
163   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
164
165   eglImpl.ChooseConfig(true, mColorDepth);
166 }
167
168 void WindowRenderSurface::CreateEglSurface( EglInterface& eglIf )
169 {
170   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
171
172   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
173
174   // create the EGL window
175   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
176   {
177     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.width, mPositionSize.height );
178   }
179   else
180   {
181     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.height, mPositionSize.width );
182   }
183
184   EGLNativeWindowType windowType( mEglWindow );
185   eglImpl.CreateSurfaceWindow( windowType, mColorDepth );
186
187   // Check capability
188   wl_egl_window_capability capability = static_cast< wl_egl_window_capability >( wl_egl_window_get_capabilities( mEglWindow ) );
189   if( capability == WL_EGL_WINDOW_CAPABILITY_ROTATION_SUPPORTED )
190   {
191     DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: capability = %d\n", capability );
192     mRotationSupported = true;
193   }
194
195   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: w = %d h = %d angle = %d screen rotation = %d\n", mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
196 }
197
198 void WindowRenderSurface::DestroyEglSurface( EglInterface& eglIf )
199 {
200   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
201
202   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
203   eglImpl.DestroySurface();
204
205   if( mEglWindow != NULL )
206   {
207     wl_egl_window_destroy(mEglWindow);
208     mEglWindow = NULL;
209   }
210 }
211
212 bool WindowRenderSurface::ReplaceEGLSurface( EglInterface& egl )
213 {
214   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
215
216   if( mEglWindow != NULL )
217   {
218     wl_egl_window_destroy(mEglWindow);
219     mEglWindow = NULL;
220   }
221
222   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
223   {
224     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.width, mPositionSize.height );
225   }
226   else
227   {
228     mEglWindow = wl_egl_window_create( mWlSurface, mPositionSize.height, mPositionSize.width );
229   }
230
231   // Set screen rotation
232   mScreenRotationFinished = false;
233
234   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
235   EGLNativeWindowType windowType( mEglWindow );
236   return eglImpl.ReplaceSurfaceWindow( windowType );
237 }
238
239 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
240 {
241   bool needToMove = false;
242   bool needToResize = false;
243
244   // check moving
245   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
246       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
247   {
248     needToMove = true;
249   }
250
251   // check resizing
252   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
253       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
254   {
255     needToResize = true;
256   }
257
258   if( needToMove )
259   {
260     ecore_wl_window_position_set( mWlWindow, positionSize.x, positionSize.y );
261   }
262   if( needToResize )
263   {
264     ecore_wl_window_update_size( mWlWindow, positionSize.width, positionSize.height );
265     mResizeFinished = false;
266   }
267
268   mPositionSize = positionSize;
269
270   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
271 }
272
273 void WindowRenderSurface::Map()
274 {
275   ecore_wl_window_show(mWlWindow);
276 }
277
278 void WindowRenderSurface::StartRender()
279 {
280 }
281
282 bool WindowRenderSurface::PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, bool resizingSurface )
283 {
284   if( resizingSurface )
285   {
286 #ifdef OVER_TIZEN_VERSION_4
287     // Window rotate or screen rotate
288     if( !mRotationFinished || !mScreenRotationFinished )
289     {
290       wl_egl_window_rotation rotation;
291       wl_output_transform bufferTransform;
292       int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
293
294       switch( totalAngle )
295       {
296         case 0:
297         {
298           rotation = ROTATION_0;
299           bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
300           break;
301         }
302         case 90:
303         {
304           rotation = ROTATION_270;
305           bufferTransform = WL_OUTPUT_TRANSFORM_90;
306           break;
307         }
308         case 180:
309         {
310           rotation = ROTATION_180;
311           bufferTransform = WL_OUTPUT_TRANSFORM_180;
312           break;
313         }
314         case 270:
315         {
316           rotation = ROTATION_90;
317           bufferTransform = WL_OUTPUT_TRANSFORM_270;
318           break;
319         }
320         default:
321         {
322           rotation = ROTATION_0;
323           bufferTransform = WL_OUTPUT_TRANSFORM_NORMAL;
324           break;
325         }
326       }
327
328       wl_egl_window_set_rotation( mEglWindow, rotation );
329
330       wl_egl_window_set_buffer_transform( mEglWindow, bufferTransform );
331
332       // Reset only screen rotation flag
333       mScreenRotationFinished = true;
334
335       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
336     }
337
338     // Only window rotate
339     if( !mRotationFinished )
340     {
341       wl_output_transform windowTransform;
342
343       switch( mRotationAngle )
344       {
345         case 0:
346         {
347           windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
348           break;
349         }
350         case 90:
351         {
352           windowTransform = WL_OUTPUT_TRANSFORM_90;
353           break;
354         }
355         case 180:
356         {
357           windowTransform = WL_OUTPUT_TRANSFORM_180;
358           break;
359         }
360         case 270:
361         {
362           windowTransform = WL_OUTPUT_TRANSFORM_270;
363           break;
364         }
365         default:
366         {
367           windowTransform = WL_OUTPUT_TRANSFORM_NORMAL;
368           break;
369         }
370       }
371
372       wl_egl_window_set_window_transform( mEglWindow, windowTransform );
373     }
374 #endif
375
376     // Resize case
377     if( !mResizeFinished )
378     {
379       wl_egl_window_resize( mEglWindow, mPositionSize.width, mPositionSize.height, mPositionSize.x, mPositionSize.y );
380       mResizeFinished = true;
381
382       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
383     }
384   }
385
386   return true;
387 }
388
389 void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface, bool resizingSurface )
390 {
391   if( resizingSurface )
392   {
393     if( !mRotationFinished )
394     {
395       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
396
397       mRotationTrigger->Trigger();
398
399       if( mThreadSynchronization )
400       {
401         // Wait until the event-thread complete the rotation event processing
402         mThreadSynchronization->PostRenderWaitForCompletion();
403       }
404     }
405   }
406
407   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
408   eglImpl.SwapBuffers();
409
410   if( mRenderNotification )
411   {
412     mRenderNotification->Trigger();
413   }
414 }
415
416 void WindowRenderSurface::StopRender()
417 {
418 }
419
420 void WindowRenderSurface::SetViewMode( ViewMode viewMode )
421 {
422   //FIXME
423 }
424
425 void WindowRenderSurface::CreateWlRenderable()
426 {
427    // if width or height are zero, go full screen.
428   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
429   {
430     // Default window size == screen size
431     mPositionSize.x = 0;
432     mPositionSize.y = 0;
433
434     ecore_wl_screen_size_get( &mPositionSize.width, &mPositionSize.height );
435   }
436
437   mWlWindow = ecore_wl_window_new( 0, mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW );
438
439   if ( mWlWindow == 0 )
440   {
441     DALI_ASSERT_ALWAYS(0 && "Failed to create Wayland window");
442   }
443
444   mWlSurface = ecore_wl_window_surface_create( mWlWindow );
445
446   if( mColorDepth == COLOR_DEPTH_32 )
447   {
448     ecore_wl_window_alpha_set( mWlWindow, true );
449   }
450   else
451   {
452     ecore_wl_window_alpha_set( mWlWindow, false );
453   }
454
455   // Get output transform
456   if( !ecore_wl_window_ignore_output_transform_get( mWlWindow ) )
457   {
458     Ecore_Wl_Output* output = ecore_wl_window_output_find( mWlWindow );
459
460     int transform = ecore_wl_output_transform_get( output );
461     ecore_wl_window_buffer_transform_set( mWlWindow, transform );
462
463     mScreenRotationAngle = transform * 90;
464     mScreenRotationFinished = false;
465   }
466 }
467
468 void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId )
469 {
470   mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId );
471 }
472
473 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
474 {
475   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
476
477   mThreadSynchronization = &threadSynchronization;
478 }
479
480 void WindowRenderSurface::ReleaseLock()
481 {
482   // Nothing to do.
483 }
484
485 void WindowRenderSurface::ProcessRotationRequest()
486 {
487   mRotationFinished = true;
488
489   ecore_wl_window_rotation_change_done_send( mWlWindow );
490
491   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
492
493   if( mThreadSynchronization )
494   {
495     mThreadSynchronization->PostRenderComplete();
496   }
497 }
498
499 } // namespace ECore
500
501 } // namespace Dali