Fix continuous rendering issue
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / common / window-render-surface.cpp
1 /*
2  * Copyright (c) 2018 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/gles20/egl-implementation.h>
29 #include <dali/internal/adaptor/common/adaptor-impl.h>
30 #include <dali/internal/window-system/common/window-base.h>
31 #include <dali/internal/window-system/common/window-factory.h>
32 #include <dali/internal/window-system/common/window-system.h>
33
34 namespace Dali
35 {
36 namespace Internal
37 {
38 namespace Adaptor
39 {
40
41 namespace
42 {
43
44 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
45
46 #if defined(DEBUG_ENABLED)
47 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
48 #endif
49
50 } // unnamed namespace
51
52 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
53 : mPositionSize( positionSize ),
54   mWindowBase(),
55   mThreadSynchronization( NULL ),
56   mRenderNotification( NULL ),
57   mRotationTrigger( NULL ),
58   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
59   mOutputTransformedSignal(),
60   mRotationAngle( 0 ),
61   mScreenRotationAngle( 0 ),
62   mOwnSurface( false ),
63   mRotationSupported( false ),
64   mRotationFinished( true ),
65   mScreenRotationFinished( true ),
66   mResizeFinished( true )
67 {
68   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
69   Initialize( surface );
70 }
71
72 WindowRenderSurface::~WindowRenderSurface()
73 {
74   if( mRotationTrigger )
75   {
76     delete mRotationTrigger;
77   }
78 }
79
80 void WindowRenderSurface::Initialize( Any surface )
81 {
82   // if width or height are zero, go full screen.
83  if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
84  {
85    // Default window size == screen size
86    mPositionSize.x = 0;
87    mPositionSize.y = 0;
88
89    WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
90  }
91
92   // Create a window base
93   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
94   mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
95
96   // Connect signals
97   mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
98
99   // Check screen rotation
100   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
101   if( mScreenRotationAngle != 0 )
102   {
103     mScreenRotationFinished = false;
104   }
105 }
106
107 Any WindowRenderSurface::GetNativeWindow()
108 {
109   return mWindowBase->GetNativeWindow();
110 }
111
112 int WindowRenderSurface::GetNativeWindowId()
113 {
114   return mWindowBase->GetNativeWindowId();
115 }
116
117 void WindowRenderSurface::Map()
118 {
119   mWindowBase->Show();
120 }
121
122 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
123 {
124   mRenderNotification = renderNotification;
125 }
126
127 void WindowRenderSurface::SetTransparency( bool transparent )
128 {
129   mWindowBase->SetTransparency( transparent );
130 }
131
132 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
133 {
134   if( !mRotationSupported )
135   {
136     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
137     return;
138   }
139
140   if( !mRotationTrigger )
141   {
142     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
143     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
144   }
145
146   mPositionSize.width = width;
147   mPositionSize.height = height;
148
149   mRotationAngle = angle;
150   mRotationFinished = false;
151
152   mWindowBase->SetWindowRotationAngle( mRotationAngle );
153
154   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
155 }
156
157 WindowBase* WindowRenderSurface::GetWindowBase()
158 {
159   return mWindowBase.get();
160 }
161
162 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
163 {
164   return mOutputTransformedSignal;
165 }
166
167 PositionSize WindowRenderSurface::GetPositionSize() const
168 {
169   return mPositionSize;
170 }
171
172 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
173 {
174   mWindowBase->GetDpi( dpiHorizontal, dpiVertical );
175 }
176
177 void WindowRenderSurface::InitializeEgl( EglInterface& eglIf )
178 {
179   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
180
181   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
182
183   eglImpl.ChooseConfig(true, mColorDepth);
184 }
185
186 void WindowRenderSurface::CreateEglSurface( EglInterface& eglIf )
187 {
188   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
189
190   int width, height;
191   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
192   {
193     width = mPositionSize.width;
194     height = mPositionSize.height;
195   }
196   else
197   {
198     width = mPositionSize.height;
199     height = mPositionSize.width;
200   }
201
202   // create the EGL window
203   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
204
205   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
206   eglImpl.CreateSurfaceWindow( window, mColorDepth );
207
208   // Check rotation capability
209   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
210
211   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateEglSurface: w = %d h = %d angle = %d screen rotation = %d\n", mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
212 }
213
214 void WindowRenderSurface::DestroyEglSurface( EglInterface& eglIf )
215 {
216   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
217
218   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( eglIf );
219   eglImpl.DestroySurface();
220
221   mWindowBase->DestroyEglWindow();
222 }
223
224 bool WindowRenderSurface::ReplaceEGLSurface( EglInterface& egl )
225 {
226   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
227
228   // Destroy the old one
229   mWindowBase->DestroyEglWindow();
230
231   int width, height;
232   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
233   {
234     width = mPositionSize.width;
235     height = mPositionSize.height;
236   }
237   else
238   {
239     width = mPositionSize.height;
240     height = mPositionSize.width;
241   }
242
243   // create the EGL window
244   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
245
246   // Set screen rotation
247   mScreenRotationFinished = false;
248
249   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
250   return eglImpl.ReplaceSurfaceWindow( window );
251 }
252
253 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
254 {
255   bool needToMove = false;
256   bool needToResize = false;
257
258   // check moving
259   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
260       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
261   {
262     needToMove = true;
263   }
264
265   // check resizing
266   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
267       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
268   {
269     needToResize = true;
270   }
271
272   if( needToResize )
273   {
274     if( needToMove )
275     {
276       mWindowBase->MoveResize( positionSize );
277     }
278     else
279     {
280       mWindowBase->Resize( positionSize );
281     }
282
283     mResizeFinished = false;
284     mPositionSize = positionSize;
285   }
286   else
287   {
288     if( needToMove )
289     {
290       mWindowBase->Move( positionSize );
291
292       mPositionSize = positionSize;
293     }
294   }
295
296   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
297 }
298
299 void WindowRenderSurface::SetViewMode( ViewMode viewMode )
300 {
301   mWindowBase->SetViewMode( viewMode );
302 }
303
304 void WindowRenderSurface::StartRender()
305 {
306 }
307
308 bool WindowRenderSurface::PreRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, bool resizingSurface )
309 {
310   if( resizingSurface )
311   {
312 #ifdef OVER_TIZEN_VERSION_4
313     // Window rotate or screen rotate
314     if( !mRotationFinished || !mScreenRotationFinished )
315     {
316       int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
317
318       mWindowBase->SetEglWindowRotation( totalAngle );
319       mWindowBase->SetEglWindowBufferTransform( totalAngle );
320
321       // Reset only screen rotation flag
322       mScreenRotationFinished = true;
323
324       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
325     }
326
327     // Only window rotate
328     if( !mRotationFinished )
329     {
330       mWindowBase->SetEglWindowTransform( mRotationAngle );
331     }
332 #endif
333
334     // Resize case
335     if( !mResizeFinished )
336     {
337       mWindowBase->ResizeEglWindow( mPositionSize );
338       mResizeFinished = true;
339
340       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
341     }
342   }
343
344   return true;
345 }
346
347 void WindowRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, Dali::DisplayConnection* displayConnection, bool replacingSurface, bool resizingSurface )
348 {
349   if( resizingSurface )
350   {
351     if( !mRotationFinished )
352     {
353       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
354
355       mRotationTrigger->Trigger();
356
357       if( mThreadSynchronization )
358       {
359         // Wait until the event-thread complete the rotation event processing
360         mThreadSynchronization->PostRenderWaitForCompletion();
361       }
362     }
363   }
364
365   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
366   eglImpl.SwapBuffers();
367
368   if( mRenderNotification )
369   {
370     mRenderNotification->Trigger();
371   }
372 }
373
374 void WindowRenderSurface::StopRender()
375 {
376 }
377
378 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
379 {
380   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
381
382   mThreadSynchronization = &threadSynchronization;
383 }
384
385 void WindowRenderSurface::ReleaseLock()
386 {
387   // Nothing to do.
388 }
389
390 RenderSurface::Type WindowRenderSurface::GetSurfaceType()
391 {
392   return RenderSurface::WINDOW_RENDER_SURFACE;
393 }
394
395 void WindowRenderSurface::OutputTransformed()
396 {
397   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
398
399   if( mScreenRotationAngle != screenRotationAngle )
400   {
401     mScreenRotationAngle = screenRotationAngle;
402     mScreenRotationFinished = false;
403
404     mOutputTransformedSignal.Emit();
405
406     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
407   }
408   else
409   {
410     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
411   }
412 }
413
414 void WindowRenderSurface::ProcessRotationRequest()
415 {
416   mRotationFinished = true;
417
418   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
419
420   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
421
422   if( mThreadSynchronization )
423   {
424     mThreadSynchronization->PostRenderComplete();
425   }
426 }
427
428 } // namespace Adaptor
429
430 } // namespace internal
431
432 } // namespace Dali