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