Revert "Remove EGL surface in the update thread"
[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   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     mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
157   }
158
159   mPositionSize.width = width;
160   mPositionSize.height = height;
161
162   mRotationAngle = angle;
163   mRotationFinished = false;
164
165   mWindowBase->SetWindowRotationAngle( mRotationAngle );
166
167   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
168 }
169
170 WindowBase* WindowRenderSurface::GetWindowBase()
171 {
172   return mWindowBase.get();
173 }
174
175 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
176 {
177   return mOutputTransformedSignal;
178 }
179
180 PositionSize WindowRenderSurface::GetPositionSize() const
181 {
182   return mPositionSize;
183 }
184
185 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
186 {
187   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
188   {
189     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
190     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
191
192     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
193     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
194
195     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
196     {
197       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
198     }
199   }
200
201   dpiHorizontal = mDpiHorizontal;
202   dpiVertical = mDpiVertical;
203 }
204
205 void WindowRenderSurface::InitializeGraphics()
206 {
207   mGraphics = &mAdaptor->GetGraphicsInterface();
208
209   DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
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   if( eglGraphics )
263   {
264     DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
265
266     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
267     eglImpl.DestroySurface( mEGLSurface );
268
269     mWindowBase->DestroyEglWindow();
270   }
271 }
272
273 bool WindowRenderSurface::ReplaceGraphicsSurface()
274 {
275   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
276
277   // Destroy the old one
278   mWindowBase->DestroyEglWindow();
279
280   int width, height;
281   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
282   {
283     width = mPositionSize.width;
284     height = mPositionSize.height;
285   }
286   else
287   {
288     width = mPositionSize.height;
289     height = mPositionSize.width;
290   }
291
292   // Create the EGL window
293   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
294
295   // Set screen rotation
296   mScreenRotationFinished = false;
297
298   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
299
300   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
301   return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
302 }
303
304 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
305 {
306   bool needToMove = false;
307   bool needToResize = false;
308
309   // Check moving
310   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
311       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
312   {
313     needToMove = true;
314   }
315
316   // Check resizing
317   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
318       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
319   {
320     needToResize = true;
321   }
322
323   if( needToResize )
324   {
325     if( needToMove )
326     {
327       mWindowBase->MoveResize( positionSize );
328     }
329     else
330     {
331       mWindowBase->Resize( positionSize );
332     }
333
334     mResizeFinished = false;
335     mPositionSize = positionSize;
336   }
337   else
338   {
339     if( needToMove )
340     {
341       mWindowBase->Move( positionSize );
342
343       mPositionSize = positionSize;
344     }
345   }
346
347   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
348 }
349
350 void WindowRenderSurface::StartRender()
351 {
352 }
353
354 bool WindowRenderSurface::PreRender( bool resizingSurface )
355 {
356   MakeContextCurrent();
357
358   if( resizingSurface )
359   {
360     // Window rotate or screen rotate
361     if( !mRotationFinished || !mScreenRotationFinished )
362     {
363       int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
364
365       mWindowBase->SetEglWindowRotation( totalAngle );
366       mWindowBase->SetEglWindowBufferTransform( totalAngle );
367
368       // Reset only screen rotation flag
369       mScreenRotationFinished = true;
370
371       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
372     }
373
374     // Only window rotate
375     if( !mRotationFinished )
376     {
377       mWindowBase->SetEglWindowTransform( mRotationAngle );
378     }
379
380     // Resize case
381     if( !mResizeFinished )
382     {
383       mWindowBase->ResizeEglWindow( mPositionSize );
384       mResizeFinished = true;
385
386       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
387     }
388   }
389
390   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
391   if ( eglGraphics )
392   {
393     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
394     mGLES.PreRender();
395   }
396
397   return true;
398 }
399
400 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
401 {
402   // Inform the gl implementation that rendering has finished before informing the surface
403   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
404   if ( eglGraphics )
405   {
406     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
407     mGLES.PostRender();
408
409     if( renderToFbo )
410     {
411       mGLES.Flush();
412       mGLES.Finish();
413     }
414     else
415     {
416       if( resizingSurface )
417       {
418         if( !mRotationFinished )
419         {
420           if( mThreadSynchronization )
421           {
422             // Enable PostRender flag
423             mThreadSynchronization->PostRenderStarted();
424           }
425
426           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
427
428           mRotationTrigger->Trigger();
429
430           if( mThreadSynchronization )
431           {
432             // Wait until the event-thread complete the rotation event processing
433             mThreadSynchronization->PostRenderWaitForCompletion();
434           }
435         }
436       }
437     }
438
439     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
440     eglImpl.SwapBuffers( mEGLSurface );
441
442     if( mRenderNotification )
443     {
444       mRenderNotification->Trigger();
445     }
446   }
447 }
448
449 void WindowRenderSurface::StopRender()
450 {
451 }
452
453 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
454 {
455   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
456
457   mThreadSynchronization = &threadSynchronization;
458 }
459
460 void WindowRenderSurface::ReleaseLock()
461 {
462   // Nothing to do.
463 }
464
465 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
466 {
467   return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
468 }
469
470 void WindowRenderSurface::MakeContextCurrent()
471 {
472   if ( mEGL != nullptr )
473   {
474     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
475   }
476 }
477
478 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
479 {
480   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
481 }
482
483 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
484 {
485   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
486 }
487
488 void WindowRenderSurface::OutputTransformed()
489 {
490   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
491
492   if( mScreenRotationAngle != screenRotationAngle )
493   {
494     mScreenRotationAngle = screenRotationAngle;
495     mScreenRotationFinished = false;
496
497     mOutputTransformedSignal.Emit();
498
499     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
500   }
501   else
502   {
503     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
504   }
505 }
506
507 void WindowRenderSurface::ProcessRotationRequest()
508 {
509   mRotationFinished = true;
510
511   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
512
513   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
514
515   if( mThreadSynchronization )
516   {
517     mThreadSynchronization->PostRenderComplete();
518   }
519 }
520
521 } // namespace Adaptor
522
523 } // namespace internal
524
525 } // namespace Dali