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