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