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