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