2561bb2273f183de1557e79b765889311c59aee9
[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/adaptor-framework/thread-synchronization-interface.h>
27 #include <dali/integration-api/adaptor-framework/trigger-event-factory-interface.h>
28 #include <dali/internal/adaptor/common/adaptor-impl.h>
29 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
30 #include <dali/internal/graphics/gles/egl-graphics.h>
31 #include <dali/internal/graphics/gles/egl-implementation.h>
32 #include <dali/internal/window-system/common/window-base.h>
33 #include <dali/internal/window-system/common/window-factory.h>
34 #include <dali/internal/window-system/common/window-system.h>
35 #include <dali/internal/system/common/environment-variables.h>
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   mDpiHorizontal( 0 ),
76   mDpiVertical( 0 )
77 {
78   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
79   Initialize( surface );
80 }
81
82 WindowRenderSurface::~WindowRenderSurface()
83 {
84   if( mRotationTrigger )
85   {
86     delete mRotationTrigger;
87   }
88
89   if ( mEGLSurface )
90   {
91     DestroySurface();
92   }
93 }
94
95 void WindowRenderSurface::Initialize( Any surface )
96 {
97   // If width or height are zero, go full screen.
98   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
99   {
100     // Default window size == screen size
101     mPositionSize.x = 0;
102     mPositionSize.y = 0;
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   }
119 }
120
121 Any WindowRenderSurface::GetNativeWindow()
122 {
123   return mWindowBase->GetNativeWindow();
124 }
125
126 int WindowRenderSurface::GetNativeWindowId()
127 {
128   return mWindowBase->GetNativeWindowId();
129 }
130
131 void WindowRenderSurface::Map()
132 {
133   mWindowBase->Show();
134 }
135
136 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
137 {
138   mRenderNotification = renderNotification;
139 }
140
141 void WindowRenderSurface::SetTransparency( bool transparent )
142 {
143   mWindowBase->SetTransparency( transparent );
144 }
145
146 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
147 {
148   if( !mRotationSupported )
149   {
150     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
151     return;
152   }
153
154   if( !mRotationTrigger )
155   {
156     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
157     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
158   }
159
160   mPositionSize.width = width;
161   mPositionSize.height = height;
162
163   mRotationAngle = angle;
164   mRotationFinished = false;
165
166   mWindowBase->SetWindowRotationAngle( mRotationAngle );
167
168   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
169 }
170
171 WindowBase* WindowRenderSurface::GetWindowBase()
172 {
173   return mWindowBase.get();
174 }
175
176 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
177 {
178   return mOutputTransformedSignal;
179 }
180
181 PositionSize WindowRenderSurface::GetPositionSize() const
182 {
183   return mPositionSize;
184 }
185
186 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
187 {
188   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
189   {
190     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
191     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
192
193     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
194     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
195
196     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
197     {
198       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
199     }
200   }
201
202   dpiHorizontal = mDpiHorizontal;
203   dpiVertical = mDpiVertical;
204 }
205
206 void WindowRenderSurface::InitializeGraphics()
207 {
208
209   mGraphics = &mAdaptor->GetGraphicsInterface();
210
211   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
212   mEGL = &eglGraphics->GetEglInterface();
213
214   if ( mEGLContext == NULL )
215   {
216     // Create the OpenGL context for this window
217     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
218     eglImpl.ChooseConfig(true, mColorDepth);
219     eglImpl.CreateWindowContext( mEGLContext );
220
221     // Create the OpenGL surface
222     CreateSurface();
223   }
224 }
225
226 void WindowRenderSurface::CreateSurface()
227 {
228   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
229
230   int width, height;
231   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
232   {
233     width = mPositionSize.width;
234     height = mPositionSize.height;
235   }
236   else
237   {
238     width = mPositionSize.height;
239     height = mPositionSize.width;
240   }
241
242   // Create the EGL window
243   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
244
245   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
246
247   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
248   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
249
250   // Check rotation capability
251   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
252
253   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
254       mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
255 }
256
257 void WindowRenderSurface::DestroySurface()
258 {
259   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
260
261   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
262
263   DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
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