Support window resizing
[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 <base/display-connection.h>
31 #include <adaptors/common/adaptor-impl.h>
32 #include <integration-api/trigger-event-factory-interface.h>
33
34 namespace Dali
35 {
36
37 #if defined(DEBUG_ENABLED)
38 extern Debug::Filter* gRenderSurfaceLogFilter;
39 #endif
40
41 namespace ECore
42 {
43
44 namespace
45 {
46
47 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
48 const char* WAYLAND_EGL_SO( "libwayland-egl.so" );
49
50 } // unnamed namespace
51
52 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize,
53                                           Any surface,
54                                           const std::string& name,
55                                           bool isTransparent)
56 : EcoreWlRenderSurface( positionSize, surface, name, isTransparent ),
57   mEglWinGetCapabilitiesPtr( NULL ),
58   mEglWinSetRotationPtr( NULL ),
59   mLibHandle( NULL ),
60   mWlWindow( NULL ),
61   mWlSurface( NULL ),
62   mEglWindow( NULL ),
63   mThreadSynchronization( NULL ),
64   mRotationTrigger( NULL ),
65   mRotationSupported( false ),
66   mRotated( false )
67 {
68   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
69   Init( surface );
70 }
71
72 WindowRenderSurface::~WindowRenderSurface()
73 {
74   if( mEglWindow != NULL )
75   {
76     wl_egl_window_destroy(mEglWindow);
77     mEglWindow = NULL;
78   }
79
80   if( mOwnSurface )
81   {
82     ecore_wl_window_free( mWlWindow );
83   }
84
85   if( mRotationTrigger )
86   {
87     delete mRotationTrigger;
88   }
89
90   if( mLibHandle != NULL )
91   {
92     dlclose( mLibHandle );
93   }
94 }
95
96 Ecore_Wl_Window* WindowRenderSurface::GetDrawable()
97 {
98   // already an e-core type
99   return mWlWindow;
100 }
101
102 Any WindowRenderSurface::GetSurface()
103 {
104   // already an e-core type
105   return Any( mWlWindow );
106 }
107
108 Ecore_Wl_Window* WindowRenderSurface::GetWlWindow()
109 {
110   return mWlWindow;
111 }
112
113 void WindowRenderSurface::RequestRotation( Dali::Window::WindowOrientation orientation, int width, int height )
114 {
115   if( !mRotationSupported )
116   {
117     DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
118     return;
119   }
120
121   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: orientation = %d\n", orientation );
122
123   if( !mRotationTrigger )
124   {
125     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
126     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
127   }
128
129   mPosition.width = width;
130   mPosition.height = height;
131
132   mRotated = true;
133
134   int angle;
135   wl_egl_window_rotation rotation;
136
137   switch( orientation )
138   {
139     case Dali::Window::PORTRAIT:
140     {
141       angle = 0;
142       rotation = ROTATION_0;
143       break;
144     }
145     case Dali::Window::LANDSCAPE:
146     {
147       angle = 90;
148       rotation = ROTATION_270;
149       break;
150     }
151     case Dali::Window::PORTRAIT_INVERSE:
152     {
153       angle = 180;
154       rotation = ROTATION_180;
155       break;
156     }
157     case Dali::Window::LANDSCAPE_INVERSE:
158     {
159       angle = 270;
160       rotation = ROTATION_90;
161       break;
162     }
163     default:
164     {
165       angle = 0;
166       rotation = ROTATION_0;
167       break;
168     }
169   }
170
171   ecore_wl_window_rotation_set( mWlWindow, angle );
172
173   if( mEglWinSetRotationPtr )
174   {
175     mEglWinSetRotationPtr( mEglWindow, rotation );
176   }
177 }
178
179 void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
180 {
181   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
182
183   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
184
185   eglImpl.ChooseConfig(true, mColorDepth);
186 }
187
188 void WindowRenderSurface::CreateEglSurface( EglInterface& eglIf )
189 {
190   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
191
192   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
193
194   // Temporary code for opaque window. We have to modify it after wayland team finish the work.
195   if( mColorDepth == COLOR_DEPTH_32 )
196   {
197     ecore_wl_window_alpha_set( mWlWindow, true );
198   }
199   else
200   {
201     ecore_wl_window_alpha_set( mWlWindow, false );
202   }
203
204   // create the EGL window
205   mEglWindow = wl_egl_window_create( mWlSurface, mPosition.width, mPosition.height );
206   EGLNativeWindowType windowType( mEglWindow );
207   eglImpl.CreateSurfaceWindow( windowType, mColorDepth );
208
209   // Check capability
210   if( !mLibHandle )
211   {
212     mLibHandle = dlopen( WAYLAND_EGL_SO, RTLD_LAZY );
213
214     char* error = dlerror();
215     if( mLibHandle == NULL || error != NULL )
216     {
217       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: dlopen error: %s\n", error );
218       return;
219     }
220
221     mEglWinGetCapabilitiesPtr = reinterpret_cast< EglWinGetCapabilitiesFunction >( dlsym( mLibHandle, "wl_egl_window_get_capabilities" ) );
222     if( !mEglWinGetCapabilitiesPtr )
223     {
224       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: Can't load wl_egl_window_get_capabilities\n" );
225       return;
226     }
227
228     mEglWinSetRotationPtr = reinterpret_cast< EglWinSetRotationFunction >( dlsym( mLibHandle, "wl_egl_window_set_rotation" ) );
229     if( !mEglWinSetRotationPtr )
230     {
231       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: Can't load wl_egl_window_set_rotation\n" );
232       return;
233     }
234   }
235
236   if( mEglWinGetCapabilitiesPtr )
237   {
238     wl_egl_window_capability capability = static_cast< wl_egl_window_capability >( mEglWinGetCapabilitiesPtr( mEglWindow ) );
239     if( capability == WL_EGL_WINDOW_CAPABILITY_ROTATION_SUPPORTED )
240     {
241       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: capability = %d\n", capability );
242       mRotationSupported = true;
243     }
244   }
245 }
246
247 void WindowRenderSurface::DestroyEglSurface( EglInterface& eglIf )
248 {
249   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
250
251   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
252   eglImpl.DestroySurface();
253
254   if( mEglWindow != NULL )
255   {
256     wl_egl_window_destroy(mEglWindow);
257     mEglWindow = NULL;
258   }
259 }
260
261 bool WindowRenderSurface::ReplaceEGLSurface( EglInterface& egl )
262 {
263   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
264
265   if( mEglWindow != NULL )
266   {
267     wl_egl_window_destroy(mEglWindow);
268     mEglWindow = NULL;
269   }
270
271   // Temporary code for opaque window. We have to modify it after wayland team finish the work.
272   if( mColorDepth == COLOR_DEPTH_32 )
273   {
274     ecore_wl_window_alpha_set( mWlWindow, true );
275   }
276   else
277   {
278     ecore_wl_window_alpha_set( mWlWindow, false );
279   }
280
281   mEglWindow = wl_egl_window_create( mWlSurface, mPosition.width, mPosition.height );
282
283   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
284   EGLNativeWindowType windowType( mEglWindow );
285   return eglImpl.ReplaceSurfaceWindow( windowType );
286 }
287
288 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
289 {
290   bool needToMove = false;
291   bool needToResize = false;
292
293   // check moving
294   if( (fabs(positionSize.x - mPosition.x) > MINIMUM_DIMENSION_CHANGE) ||
295       (fabs(positionSize.y - mPosition.y) > MINIMUM_DIMENSION_CHANGE) )
296   {
297     needToMove = true;
298   }
299
300   // check resizing
301   if( (fabs(positionSize.width - mPosition.width) > MINIMUM_DIMENSION_CHANGE) ||
302       (fabs(positionSize.height - mPosition.height) > MINIMUM_DIMENSION_CHANGE) )
303   {
304     needToResize = true;
305   }
306
307   if(needToMove)
308   {
309     ecore_wl_window_position_set( mWlWindow, positionSize.x, positionSize.y );
310   }
311   if (needToResize)
312   {
313     ecore_wl_window_update_size( mWlWindow, positionSize.width, positionSize.height );
314   }
315
316   mPosition = positionSize;
317
318   wl_egl_window_resize( mEglWindow, mPosition.width, mPosition.height, mPosition.x, mPosition.y );
319
320   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPosition.x, mPosition.y, mPosition.width, mPosition.height );
321 }
322
323 void WindowRenderSurface::Map()
324 {
325   ecore_wl_window_show(mWlWindow);
326 }
327
328 void WindowRenderSurface::StartRender()
329 {
330 }
331
332 bool WindowRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
333 {
334   // nothing to do for windows
335   return true;
336 }
337
338 void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
339 {
340   if( mRotated )
341   {
342     // Check viewport size
343     Dali::Vector< GLint > viewportSize;
344     viewportSize.Resize( 4 );
345
346     glAbstraction.GetIntegerv( GL_VIEWPORT, &viewportSize[0] );
347
348     if( viewportSize[2] == mPosition.width && viewportSize[3] == mPosition.height )
349     {
350       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
351
352       mRotationTrigger->Trigger();
353
354       if( mThreadSynchronization )
355       {
356         // Wait until the event-thread complete the rotation event processing
357         mThreadSynchronization->PostRenderWaitForCompletion();
358       }
359     }
360   }
361
362   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
363   eglImpl.SwapBuffers();
364
365   if( mRenderNotification )
366   {
367     mRenderNotification->Trigger();
368   }
369 }
370
371 void WindowRenderSurface::StopRender()
372 {
373 }
374
375 void WindowRenderSurface::SetViewMode( ViewMode viewMode )
376 {
377   //FIXME
378 }
379
380 void WindowRenderSurface::CreateWlRenderable()
381 {
382    // if width or height are zero, go full screen.
383   if ( (mPosition.width == 0) || (mPosition.height == 0) )
384   {
385     // Default window size == screen size
386     mPosition.x = 0;
387     mPosition.y = 0;
388
389     ecore_wl_screen_size_get( &mPosition.width, &mPosition.height );
390   }
391
392   mWlWindow = ecore_wl_window_new( 0, mPosition.x, mPosition.y, mPosition.width, mPosition.height, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW );
393
394   if ( mWlWindow == 0 )
395   {
396     DALI_ASSERT_ALWAYS(0 && "Failed to create Wayland window");
397   }
398
399   mWlSurface = ecore_wl_window_surface_create( mWlWindow );
400 }
401
402 void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId )
403 {
404   mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId );
405 }
406
407 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
408 {
409   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
410
411   mThreadSynchronization = &threadSynchronization;
412 }
413
414 void WindowRenderSurface::ReleaseLock()
415 {
416   // Nothing to do.
417 }
418
419 void WindowRenderSurface::ProcessRotationRequest()
420 {
421   mRotated = false;
422
423   ecore_wl_window_rotation_change_done_send( mWlWindow );
424
425   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
426
427   if( mThreadSynchronization )
428   {
429     mThreadSynchronization->PostRenderComplete();
430   }
431 }
432
433 } // namespace ECore
434
435 } // namespace Dali