1df0faaf4817cc69a7cb84a7e48265e6471ba735
[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::SetTransparency( bool transparent )
180 {
181   ecore_wl_window_alpha_set( mWlWindow, transparent );
182 }
183
184 void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
185 {
186   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
187
188   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
189
190   eglImpl.ChooseConfig(true, mColorDepth);
191 }
192
193 void WindowRenderSurface::CreateEglSurface( EglInterface& eglIf )
194 {
195   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
196
197   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
198
199   // Temporary code for opaque window. We have to modify it after wayland team finish the work.
200   if( mColorDepth == COLOR_DEPTH_32 )
201   {
202     ecore_wl_window_alpha_set( mWlWindow, true );
203   }
204   else
205   {
206     ecore_wl_window_alpha_set( mWlWindow, false );
207   }
208
209   // create the EGL window
210   mEglWindow = wl_egl_window_create( mWlSurface, mPosition.width, mPosition.height );
211   EGLNativeWindowType windowType( mEglWindow );
212   eglImpl.CreateSurfaceWindow( windowType, mColorDepth );
213
214   // Check capability
215   if( !mLibHandle )
216   {
217     mLibHandle = dlopen( WAYLAND_EGL_SO, RTLD_LAZY );
218
219     char* error = dlerror();
220     if( mLibHandle == NULL || error != NULL )
221     {
222       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: dlopen error: %s\n", error );
223       return;
224     }
225
226     mEglWinGetCapabilitiesPtr = reinterpret_cast< EglWinGetCapabilitiesFunction >( dlsym( mLibHandle, "wl_egl_window_get_capabilities" ) );
227     if( !mEglWinGetCapabilitiesPtr )
228     {
229       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: Can't load wl_egl_window_get_capabilities\n" );
230       return;
231     }
232
233     mEglWinSetRotationPtr = reinterpret_cast< EglWinSetRotationFunction >( dlsym( mLibHandle, "wl_egl_window_set_rotation" ) );
234     if( !mEglWinSetRotationPtr )
235     {
236       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: Can't load wl_egl_window_set_rotation\n" );
237       return;
238     }
239   }
240
241   if( mEglWinGetCapabilitiesPtr )
242   {
243     wl_egl_window_capability capability = static_cast< wl_egl_window_capability >( mEglWinGetCapabilitiesPtr( mEglWindow ) );
244     if( capability == WL_EGL_WINDOW_CAPABILITY_ROTATION_SUPPORTED )
245     {
246       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: capability = %d\n", capability );
247       mRotationSupported = true;
248     }
249   }
250 }
251
252 void WindowRenderSurface::DestroyEglSurface( EglInterface& eglIf )
253 {
254   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
255
256   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
257   eglImpl.DestroySurface();
258
259   if( mEglWindow != NULL )
260   {
261     wl_egl_window_destroy(mEglWindow);
262     mEglWindow = NULL;
263   }
264 }
265
266 bool WindowRenderSurface::ReplaceEGLSurface( EglInterface& egl )
267 {
268   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
269
270   if( mEglWindow != NULL )
271   {
272     wl_egl_window_destroy(mEglWindow);
273     mEglWindow = NULL;
274   }
275
276   // Temporary code for opaque window. We have to modify it after wayland team finish the work.
277   if( mColorDepth == COLOR_DEPTH_32 )
278   {
279     ecore_wl_window_alpha_set( mWlWindow, true );
280   }
281   else
282   {
283     ecore_wl_window_alpha_set( mWlWindow, false );
284   }
285
286   mEglWindow = wl_egl_window_create( mWlSurface, mPosition.width, mPosition.height );
287
288   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
289   EGLNativeWindowType windowType( mEglWindow );
290   return eglImpl.ReplaceSurfaceWindow( windowType );
291 }
292
293 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
294 {
295   bool needToMove = false;
296   bool needToResize = false;
297
298   // check moving
299   if( (fabs(positionSize.x - mPosition.x) > MINIMUM_DIMENSION_CHANGE) ||
300       (fabs(positionSize.y - mPosition.y) > MINIMUM_DIMENSION_CHANGE) )
301   {
302     needToMove = true;
303   }
304
305   // check resizing
306   if( (fabs(positionSize.width - mPosition.width) > MINIMUM_DIMENSION_CHANGE) ||
307       (fabs(positionSize.height - mPosition.height) > MINIMUM_DIMENSION_CHANGE) )
308   {
309     needToResize = true;
310   }
311
312   if(needToMove)
313   {
314     ecore_wl_window_position_set( mWlWindow, positionSize.x, positionSize.y );
315   }
316   if (needToResize)
317   {
318     ecore_wl_window_update_size( mWlWindow, positionSize.width, positionSize.height );
319   }
320
321   mPosition = positionSize;
322
323   wl_egl_window_resize( mEglWindow, mPosition.width, mPosition.height, mPosition.x, mPosition.y );
324
325   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPosition.x, mPosition.y, mPosition.width, mPosition.height );
326 }
327
328 void WindowRenderSurface::Map()
329 {
330   ecore_wl_window_show(mWlWindow);
331 }
332
333 void WindowRenderSurface::StartRender()
334 {
335 }
336
337 bool WindowRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
338 {
339   // nothing to do for windows
340   return true;
341 }
342
343 void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
344 {
345   if( mRotated )
346   {
347     // Check viewport size
348     Dali::Vector< GLint > viewportSize;
349     viewportSize.Resize( 4 );
350
351     glAbstraction.GetIntegerv( GL_VIEWPORT, &viewportSize[0] );
352
353     if( viewportSize[2] == mPosition.width && viewportSize[3] == mPosition.height )
354     {
355       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
356
357       mRotationTrigger->Trigger();
358
359       if( mThreadSynchronization )
360       {
361         // Wait until the event-thread complete the rotation event processing
362         mThreadSynchronization->PostRenderWaitForCompletion();
363       }
364     }
365   }
366
367   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
368   eglImpl.SwapBuffers();
369
370   if( mRenderNotification )
371   {
372     mRenderNotification->Trigger();
373   }
374 }
375
376 void WindowRenderSurface::StopRender()
377 {
378 }
379
380 void WindowRenderSurface::SetViewMode( ViewMode viewMode )
381 {
382   //FIXME
383 }
384
385 void WindowRenderSurface::CreateWlRenderable()
386 {
387    // if width or height are zero, go full screen.
388   if ( (mPosition.width == 0) || (mPosition.height == 0) )
389   {
390     // Default window size == screen size
391     mPosition.x = 0;
392     mPosition.y = 0;
393
394     ecore_wl_screen_size_get( &mPosition.width, &mPosition.height );
395   }
396
397   mWlWindow = ecore_wl_window_new( 0, mPosition.x, mPosition.y, mPosition.width, mPosition.height, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW );
398
399   if ( mWlWindow == 0 )
400   {
401     DALI_ASSERT_ALWAYS(0 && "Failed to create Wayland window");
402   }
403
404   mWlSurface = ecore_wl_window_surface_create( mWlWindow );
405 }
406
407 void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId )
408 {
409   mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId );
410 }
411
412 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
413 {
414   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
415
416   mThreadSynchronization = &threadSynchronization;
417 }
418
419 void WindowRenderSurface::ReleaseLock()
420 {
421   // Nothing to do.
422 }
423
424 void WindowRenderSurface::ProcessRotationRequest()
425 {
426   mRotated = false;
427
428   ecore_wl_window_rotation_change_done_send( mWlWindow );
429
430   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
431
432   if( mThreadSynchronization )
433   {
434     mThreadSynchronization->PostRenderComplete();
435   }
436 }
437
438 } // namespace ECore
439
440 } // namespace Dali