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