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