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