6d4ba4f09f15104a37338408e200ffd1d89f7bcc
[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.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
208   mGraphics = &mAdaptor->GetGraphicsInterface();
209
210   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
211   mEGL = &eglGraphics->GetEglInterface();
212
213   if ( mEGLContext == NULL )
214   {
215     // Create the OpenGL context for this window
216     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
217     eglImpl.ChooseConfig(true, mColorDepth);
218     eglImpl.CreateWindowContext( mEGLContext );
219
220     // Create the OpenGL surface
221     CreateSurface();
222   }
223 }
224
225 void WindowRenderSurface::CreateSurface()
226 {
227   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
228
229   int width, height;
230   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
231   {
232     width = mPositionSize.width;
233     height = mPositionSize.height;
234   }
235   else
236   {
237     width = mPositionSize.height;
238     height = mPositionSize.width;
239   }
240
241   // Create the EGL window
242   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
243
244   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
245
246   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
247   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
248
249   // Check rotation capability
250   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
251
252   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
253       mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
254 }
255
256 void WindowRenderSurface::DestroySurface()
257 {
258   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
259
260   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
261
262   DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
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           if( mThreadSynchronization )
418           {
419             // Enable PostRender flag
420             mThreadSynchronization->PostRenderStarted();
421           }
422
423           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
424
425           mRotationTrigger->Trigger();
426
427           if( mThreadSynchronization )
428           {
429             // Wait until the event-thread complete the rotation event processing
430             mThreadSynchronization->PostRenderWaitForCompletion();
431           }
432         }
433       }
434     }
435
436     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
437     eglImpl.SwapBuffers( mEGLSurface );
438
439     if( mRenderNotification )
440     {
441       mRenderNotification->Trigger();
442     }
443   }
444 }
445
446 void WindowRenderSurface::StopRender()
447 {
448 }
449
450 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
451 {
452   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
453
454   mThreadSynchronization = &threadSynchronization;
455 }
456
457 void WindowRenderSurface::ReleaseLock()
458 {
459   // Nothing to do.
460 }
461
462 Integration::RenderSurface::Type WindowRenderSurface::GetSurfaceType()
463 {
464   return RenderSurface::WINDOW_RENDER_SURFACE;
465 }
466
467 void WindowRenderSurface::MakeContextCurrent()
468 {
469   if ( mEGL != nullptr )
470   {
471     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
472   }
473 }
474
475 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
476 {
477   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
478 }
479
480 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
481 {
482   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
483 }
484
485 void WindowRenderSurface::OutputTransformed()
486 {
487   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
488
489   if( mScreenRotationAngle != screenRotationAngle )
490   {
491     mScreenRotationAngle = screenRotationAngle;
492     mScreenRotationFinished = false;
493
494     mOutputTransformedSignal.Emit();
495
496     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
497   }
498   else
499   {
500     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
501   }
502 }
503
504 void WindowRenderSurface::ProcessRotationRequest()
505 {
506   mRotationFinished = true;
507
508   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
509
510   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
511
512   if( mThreadSynchronization )
513   {
514     mThreadSynchronization->PostRenderComplete();
515   }
516 }
517
518 } // namespace Adaptor
519
520 } // namespace internal
521
522 } // namespace Dali