c95d5082e5dafb13b2827cabdcd4f184c9c0e566
[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   }
114 }
115
116 Any WindowRenderSurface::GetNativeWindow()
117 {
118   return mWindowBase->GetNativeWindow();
119 }
120
121 int WindowRenderSurface::GetNativeWindowId()
122 {
123   return mWindowBase->GetNativeWindowId();
124 }
125
126 void WindowRenderSurface::Map()
127 {
128   mWindowBase->Show();
129 }
130
131 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
132 {
133   mRenderNotification = renderNotification;
134 }
135
136 void WindowRenderSurface::SetTransparency( bool transparent )
137 {
138   mWindowBase->SetTransparency( transparent );
139 }
140
141 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
142 {
143   if( !mRotationSupported )
144   {
145     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
146     return;
147   }
148
149   if( !mRotationTrigger )
150   {
151     mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
152   }
153
154   mPositionSize.width = width;
155   mPositionSize.height = height;
156
157   mRotationAngle = angle;
158   mRotationFinished = false;
159
160   mWindowBase->SetWindowRotationAngle( mRotationAngle );
161
162   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
163 }
164
165 WindowBase* WindowRenderSurface::GetWindowBase()
166 {
167   return mWindowBase.get();
168 }
169
170 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
171 {
172   return mOutputTransformedSignal;
173 }
174
175 PositionSize WindowRenderSurface::GetPositionSize() const
176 {
177   return mPositionSize;
178 }
179
180 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
181 {
182   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
183   {
184     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
185     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
186
187     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
188     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
189
190     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
191     {
192       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
193     }
194   }
195
196   dpiHorizontal = mDpiHorizontal;
197   dpiVertical = mDpiVertical;
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     // Window rotate or screen rotate
362     if( !mRotationFinished || !mScreenRotationFinished )
363     {
364       int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
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       mWindowBase->ResizeEglWindow( mPositionSize );
385       mResizeFinished = true;
386
387       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
388     }
389   }
390
391   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
392   if ( eglGraphics )
393   {
394     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
395     mGLES.PreRender();
396   }
397
398   return true;
399 }
400
401 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
402 {
403   // Inform the gl implementation that rendering has finished before informing the surface
404   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
405   if ( eglGraphics )
406   {
407     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
408     mGLES.PostRender();
409
410     if( renderToFbo )
411     {
412       mGLES.Flush();
413       mGLES.Finish();
414     }
415     else
416     {
417       if( resizingSurface )
418       {
419         if( !mRotationFinished )
420         {
421           if( mThreadSynchronization )
422           {
423             // Enable PostRender flag
424             mThreadSynchronization->PostRenderStarted();
425           }
426
427           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
428
429           mRotationTrigger->Trigger();
430
431           if( mThreadSynchronization )
432           {
433             // Wait until the event-thread complete the rotation event processing
434             mThreadSynchronization->PostRenderWaitForCompletion();
435           }
436         }
437       }
438     }
439
440     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
441     eglImpl.SwapBuffers( mEGLSurface );
442
443     if( mRenderNotification )
444     {
445       mRenderNotification->Trigger();
446     }
447   }
448 }
449
450 void WindowRenderSurface::StopRender()
451 {
452 }
453
454 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
455 {
456   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
457
458   mThreadSynchronization = &threadSynchronization;
459 }
460
461 void WindowRenderSurface::ReleaseLock()
462 {
463   // Nothing to do.
464 }
465
466 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
467 {
468   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
469 }
470
471 void WindowRenderSurface::MakeContextCurrent()
472 {
473   if ( mEGL != nullptr )
474   {
475     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
476   }
477 }
478
479 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
480 {
481   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
482 }
483
484 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
485 {
486   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
487 }
488
489 void WindowRenderSurface::OutputTransformed()
490 {
491   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
492
493   if( mScreenRotationAngle != screenRotationAngle )
494   {
495     mScreenRotationAngle = screenRotationAngle;
496     mScreenRotationFinished = 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