8ecc906f374d3e3574f9d2af93cfefdaa8d6cc50
[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 )
356 {
357   MakeContextCurrent();
358
359   if( resizingSurface )
360   {
361     int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
362
363     // Window rotate or screen rotate
364     if( !mRotationFinished || !mScreenRotationFinished )
365     {
366       mWindowBase->SetEglWindowRotation( totalAngle );
367       mWindowBase->SetEglWindowBufferTransform( totalAngle );
368
369       // Reset only screen rotation flag
370       mScreenRotationFinished = true;
371
372       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
373     }
374
375     // Only window rotate
376     if( !mRotationFinished )
377     {
378       mWindowBase->SetEglWindowTransform( mRotationAngle );
379     }
380
381     // Resize case
382     if ( !mResizeFinished )
383     {
384       Dali::PositionSize positionSize;
385       positionSize.x = mPositionSize.x;
386       positionSize.y = mPositionSize.y;
387       if( totalAngle == 0 || totalAngle == 180 )
388       {
389         positionSize.width = mPositionSize.width;
390         positionSize.height = mPositionSize.height;
391       }
392       else
393       {
394         positionSize.width = mPositionSize.height;
395         positionSize.height = mPositionSize.width;
396       }
397       mWindowBase->ResizeEglWindow( positionSize );
398       mResizeFinished = true;
399
400       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
401     }
402   }
403
404   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
405   if ( eglGraphics )
406   {
407     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
408     mGLES.PreRender();
409   }
410
411   return true;
412 }
413
414 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
415 {
416   // Inform the gl implementation that rendering has finished before informing the surface
417   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
418   if ( eglGraphics )
419   {
420     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
421     mGLES.PostRender();
422
423     if( renderToFbo )
424     {
425       mGLES.Flush();
426       mGLES.Finish();
427     }
428     else
429     {
430       if( resizingSurface )
431       {
432         if( !mRotationFinished )
433         {
434           if( mThreadSynchronization )
435           {
436             // Enable PostRender flag
437             mThreadSynchronization->PostRenderStarted();
438           }
439
440           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
441
442           mRotationTrigger->Trigger();
443
444           if( mThreadSynchronization )
445           {
446             // Wait until the event-thread complete the rotation event processing
447             mThreadSynchronization->PostRenderWaitForCompletion();
448           }
449         }
450       }
451     }
452
453     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
454     eglImpl.SwapBuffers( mEGLSurface );
455
456     if( mRenderNotification )
457     {
458       mRenderNotification->Trigger();
459     }
460   }
461 }
462
463 void WindowRenderSurface::StopRender()
464 {
465 }
466
467 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
468 {
469   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
470
471   mThreadSynchronization = &threadSynchronization;
472 }
473
474 void WindowRenderSurface::ReleaseLock()
475 {
476   // Nothing to do.
477 }
478
479 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
480 {
481   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
482 }
483
484 void WindowRenderSurface::MakeContextCurrent()
485 {
486   if ( mEGL != nullptr )
487   {
488     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
489   }
490 }
491
492 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
493 {
494   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
495 }
496
497 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
498 {
499   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
500 }
501
502 void WindowRenderSurface::OutputTransformed()
503 {
504   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
505
506   if( mScreenRotationAngle != screenRotationAngle )
507   {
508     mScreenRotationAngle = screenRotationAngle;
509     mScreenRotationFinished = false;
510     mResizeFinished = false;
511
512     mOutputTransformedSignal.Emit();
513
514     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
515   }
516   else
517   {
518     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
519   }
520 }
521
522 void WindowRenderSurface::ProcessRotationRequest()
523 {
524   mRotationFinished = true;
525
526   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
527
528   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
529
530   if( mThreadSynchronization )
531   {
532     mThreadSynchronization->PostRenderComplete();
533   }
534 }
535
536 } // namespace Adaptor
537
538 } // namespace internal
539
540 } // namespace Dali