40858ed0355e239e84fb2ccc19789bb1d3dd4698
[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   mEglWindow( NULL ),
62   mThreadSynchronization( NULL ),
63   mRotationTrigger( NULL ),
64   mRotationSupported( false ),
65   mRotated( false )
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   if( mLibHandle != NULL )
90   {
91     dlclose( mLibHandle );
92   }
93 }
94
95 Ecore_Wl_Window* WindowRenderSurface::GetDrawable()
96 {
97   // already an e-core type
98   return mWlWindow;
99 }
100
101 Any WindowRenderSurface::GetSurface()
102 {
103   // already an e-core type
104   return Any( mWlWindow );
105 }
106
107 Ecore_Wl_Window* WindowRenderSurface::GetWlWindow()
108 {
109   return mWlWindow;
110 }
111
112 void WindowRenderSurface::RequestRotation( Dali::Window::WindowOrientation orientation, int width, int height )
113 {
114   if( !mRotationSupported )
115   {
116     DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
117     return;
118   }
119
120   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: orientation = %d\n", orientation );
121
122   if( !mRotationTrigger )
123   {
124     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
125     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
126   }
127
128   mPosition.width = width;
129   mPosition.height = height;
130
131   mRotated = true;
132
133   int angle;
134   wl_egl_window_rotation rotation;
135
136   switch( orientation )
137   {
138     case Dali::Window::PORTRAIT:
139     {
140       angle = 0;
141       rotation = ROTATION_0;
142       break;
143     }
144     case Dali::Window::LANDSCAPE:
145     {
146       angle = 90;
147       rotation = ROTATION_270;
148       break;
149     }
150     case Dali::Window::PORTRAIT_INVERSE:
151     {
152       angle = 180;
153       rotation = ROTATION_180;
154       break;
155     }
156     case Dali::Window::LANDSCAPE_INVERSE:
157     {
158       angle = 270;
159       rotation = ROTATION_90;
160       break;
161     }
162     default:
163     {
164       angle = 0;
165       rotation = ROTATION_0;
166       break;
167     }
168   }
169
170   ecore_wl_window_rotation_set( mWlWindow, angle );
171
172   if( mEglWinSetRotationPtr )
173   {
174     mEglWinSetRotationPtr( mEglWindow, rotation );
175   }
176 }
177
178 void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
179 {
180   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
181
182   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
183
184   eglImpl.ChooseConfig(true, mColorDepth);
185 }
186
187 void WindowRenderSurface::CreateEglSurface( EglInterface& eglIf )
188 {
189   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
190
191   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
192
193   // Temporary code for opaque window. We have to modify it after wayland team finish the work.
194   if( mColorDepth == COLOR_DEPTH_32 )
195   {
196     ecore_wl_window_alpha_set( mWlWindow, true );
197   }
198   else
199   {
200     ecore_wl_window_alpha_set( mWlWindow, false );
201   }
202
203   // create the EGL surface
204   ecore_wl_window_surface_create(mWlWindow);
205   mEglWindow = wl_egl_window_create(ecore_wl_window_surface_get(mWlWindow), 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(ecore_wl_window_surface_get(mWlWindow), 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_move(mWlWindow, positionSize.x, positionSize.y);
310     mPosition = positionSize;
311   }
312   if (needToResize)
313   {
314     ecore_wl_window_resize(mWlWindow, positionSize.width, positionSize.height, 0);
315     mPosition = positionSize;
316   }
317
318 }
319
320 void WindowRenderSurface::Map()
321 {
322   ecore_wl_window_show(mWlWindow);
323 }
324
325 void WindowRenderSurface::StartRender()
326 {
327 }
328
329 bool WindowRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
330 {
331   // nothing to do for windows
332   return true;
333 }
334
335 void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
336 {
337   if( mRotated )
338   {
339     // Check viewport size
340     Dali::Vector< GLint > viewportSize;
341     viewportSize.Resize( 4 );
342
343     glAbstraction.GetIntegerv( GL_VIEWPORT, &viewportSize[0] );
344
345     if( viewportSize[2] == mPosition.width && viewportSize[3] == mPosition.height )
346     {
347       DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
348
349       mRotationTrigger->Trigger();
350
351       if( mThreadSynchronization )
352       {
353         // Wait until the event-thread complete the rotation event processing
354         mThreadSynchronization->PostRenderWaitForCompletion();
355       }
356     }
357   }
358
359   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
360   eglImpl.SwapBuffers();
361
362   if( mRenderNotification )
363   {
364     mRenderNotification->Trigger();
365   }
366 }
367
368 void WindowRenderSurface::StopRender()
369 {
370 }
371
372 void WindowRenderSurface::SetViewMode( ViewMode viewMode )
373 {
374   //FIXME
375 }
376
377 void WindowRenderSurface::CreateWlRenderable()
378 {
379    // if width or height are zero, go full screen.
380   if ( (mPosition.width == 0) || (mPosition.height == 0) )
381   {
382     // Default window size == screen size
383     mPosition.x = 0;
384     mPosition.y = 0;
385
386     ecore_wl_screen_size_get( &mPosition.width, &mPosition.height );
387   }
388
389   mWlWindow = ecore_wl_window_new( 0, mPosition.x, mPosition.y, mPosition.width, mPosition.height, ECORE_WL_WINDOW_BUFFER_TYPE_EGL_WINDOW );
390
391   if ( mWlWindow == 0 )
392   {
393     DALI_ASSERT_ALWAYS(0 && "Failed to create Wayland window");
394   }
395 }
396
397 void WindowRenderSurface::UseExistingRenderable( unsigned int surfaceId )
398 {
399   mWlWindow = AnyCast< Ecore_Wl_Window* >( surfaceId );
400 }
401
402 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
403 {
404   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
405
406   mThreadSynchronization = &threadSynchronization;
407 }
408
409 void WindowRenderSurface::ReleaseLock()
410 {
411   // Nothing to do.
412 }
413
414 void WindowRenderSurface::ProcessRotationRequest()
415 {
416   mRotated = false;
417
418   ecore_wl_window_rotation_change_done_send( mWlWindow );
419
420   DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
421
422   if( mThreadSynchronization )
423   {
424     mThreadSynchronization->PostRenderComplete();
425   }
426 }
427
428 } // namespace ECore
429
430 } // namespace Dali