cac09c5fc15d6c5dd25dca813a55152532aded53
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / common / window-render-surface.cpp
1 /*
2  * Copyright (c) 2018 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/trigger-event-factory-interface.h>
27 #include <dali/integration-api/thread-synchronization-interface.h>
28 #include <dali/internal/graphics/gles/egl-implementation.h>
29 #include <dali/internal/adaptor/common/adaptor-impl.h>
30 #include <dali/internal/window-system/common/window-base.h>
31 #include <dali/internal/window-system/common/window-factory.h>
32 #include <dali/internal/window-system/common/window-system.h>
33 #include <dali/internal/graphics/gles/egl-graphics.h>
34
35
36 namespace Dali
37 {
38 namespace Internal
39 {
40 namespace Adaptor
41 {
42
43 namespace
44 {
45
46 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
47
48 #if defined(DEBUG_ENABLED)
49 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
50 #endif
51
52 } // unnamed namespace
53
54 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
55 : mPositionSize( positionSize ),
56   mWindowBase(),
57   mThreadSynchronization( NULL ),
58   mRenderNotification( NULL ),
59   mRotationTrigger( NULL ),
60   mGraphics( nullptr ),
61   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
62   mOutputTransformedSignal(),
63   mRotationAngle( 0 ),
64   mScreenRotationAngle( 0 ),
65   mOwnSurface( false ),
66   mRotationSupported( false ),
67   mRotationFinished( true ),
68   mScreenRotationFinished( true ),
69   mResizeFinished( true )
70 {
71   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
72   Initialize( surface );
73 }
74
75 WindowRenderSurface::~WindowRenderSurface()
76 {
77   if( mRotationTrigger )
78   {
79     delete mRotationTrigger;
80   }
81 }
82
83 void WindowRenderSurface::Initialize( Any surface )
84 {
85   // If width or height are zero, go full screen.
86   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
87   {
88     // Default window size == screen size
89     mPositionSize.x = 0;
90     mPositionSize.y = 0;
91
92     WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
93   }
94
95   // Create a window base
96   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
97   mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
98
99   // Connect signals
100   mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
101
102   // Check screen rotation
103   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
104   if( mScreenRotationAngle != 0 )
105   {
106     mScreenRotationFinished = false;
107   }
108 }
109
110 Any WindowRenderSurface::GetNativeWindow()
111 {
112   return mWindowBase->GetNativeWindow();
113 }
114
115 int WindowRenderSurface::GetNativeWindowId()
116 {
117   return mWindowBase->GetNativeWindowId();
118 }
119
120 void WindowRenderSurface::Map()
121 {
122   mWindowBase->Show();
123 }
124
125 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
126 {
127   mRenderNotification = renderNotification;
128 }
129
130 void WindowRenderSurface::SetTransparency( bool transparent )
131 {
132   mWindowBase->SetTransparency( transparent );
133 }
134
135 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
136 {
137   if( !mRotationSupported )
138   {
139     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: Rotation is not supported!\n" );
140     return;
141   }
142
143   if( !mRotationTrigger )
144   {
145     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
146     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
147   }
148
149   mPositionSize.width = width;
150   mPositionSize.height = height;
151
152   mRotationAngle = angle;
153   mRotationFinished = false;
154
155   mWindowBase->SetWindowRotationAngle( mRotationAngle );
156
157   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
158 }
159
160 WindowBase* WindowRenderSurface::GetWindowBase()
161 {
162   return mWindowBase.get();
163 }
164
165 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
166 {
167   return mOutputTransformedSignal;
168 }
169
170 PositionSize WindowRenderSurface::GetPositionSize() const
171 {
172   return mPositionSize;
173 }
174
175 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
176 {
177   mWindowBase->GetDpi( dpiHorizontal, dpiVertical );
178 }
179
180 void WindowRenderSurface::InitializeGraphics( GraphicsInterface& graphics, Dali::DisplayConnection& displayConnection )
181 {
182   mGraphics = &graphics;
183
184   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
185
186   EglInterface* mEGL = eglGraphics->Create();
187
188   // Initialize EGL & OpenGL
189   displayConnection.Initialize();
190
191   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
192   eglImpl.ChooseConfig(true, mColorDepth);
193
194   // Create the OpenGL context
195   mEGL->CreateContext();
196
197   // Create the OpenGL surface
198   CreateSurface();
199
200   // Make it current
201   mEGL->MakeContextCurrent();
202 }
203
204 void WindowRenderSurface::CreateSurface()
205 {
206   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
207
208   int width, height;
209   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
210   {
211     width = mPositionSize.width;
212     height = mPositionSize.height;
213   }
214   else
215   {
216     width = mPositionSize.height;
217     height = mPositionSize.width;
218   }
219
220   // Create the EGL window
221   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
222
223   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
224
225   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
226   eglImpl.CreateSurfaceWindow( window, mColorDepth );
227
228   // Check rotation capability
229   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
230
231   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::CreateSurface: w = %d h = %d angle = %d screen rotation = %d\n", mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
232 }
233
234 void WindowRenderSurface::DestroySurface()
235 {
236   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
237
238   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
239
240   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
241   eglImpl.DestroySurface();
242
243   mWindowBase->DestroyEglWindow();
244 }
245
246 bool WindowRenderSurface::ReplaceGraphicsSurface()
247 {
248   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
249
250   // Destroy the old one
251   mWindowBase->DestroyEglWindow();
252
253   int width, height;
254   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
255   {
256     width = mPositionSize.width;
257     height = mPositionSize.height;
258   }
259   else
260   {
261     width = mPositionSize.height;
262     height = mPositionSize.width;
263   }
264
265   // Create the EGL window
266   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
267
268   // Set screen rotation
269   mScreenRotationFinished = false;
270
271   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
272
273   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
274   return eglImpl.ReplaceSurfaceWindow( window );
275 }
276
277 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
278 {
279   bool needToMove = false;
280   bool needToResize = false;
281
282   // Check moving
283   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
284       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
285   {
286     needToMove = true;
287   }
288
289   // Check resizing
290   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
291       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
292   {
293     needToResize = true;
294   }
295
296   if( needToResize )
297   {
298     if( needToMove )
299     {
300       mWindowBase->MoveResize( positionSize );
301     }
302     else
303     {
304       mWindowBase->Resize( positionSize );
305     }
306
307     mResizeFinished = false;
308     mPositionSize = positionSize;
309   }
310   else
311   {
312     if( needToMove )
313     {
314       mWindowBase->Move( positionSize );
315
316       mPositionSize = positionSize;
317     }
318   }
319
320   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
321 }
322
323 void WindowRenderSurface::StartRender()
324 {
325 }
326
327 bool WindowRenderSurface::PreRender( bool resizingSurface )
328 {
329   if( resizingSurface )
330   {
331 #ifdef OVER_TIZEN_VERSION_4
332     // Window rotate or screen rotate
333     if( !mRotationFinished || !mScreenRotationFinished )
334     {
335       int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
336
337       mWindowBase->SetEglWindowRotation( totalAngle );
338       mWindowBase->SetEglWindowBufferTransform( totalAngle );
339
340       // Reset only screen rotation flag
341       mScreenRotationFinished = true;
342
343       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
344     }
345
346     // Only window rotate
347     if( !mRotationFinished )
348     {
349       mWindowBase->SetEglWindowTransform( mRotationAngle );
350     }
351 #endif
352
353     // Resize case
354     if( !mResizeFinished )
355     {
356       mWindowBase->ResizeEglWindow( mPositionSize );
357       mResizeFinished = true;
358
359       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
360     }
361   }
362
363   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
364   if ( eglGraphics )
365   {
366     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
367     mGLES.PreRender();
368   }
369
370   return true;
371 }
372
373 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
374 {
375   // Inform the gl implementation that rendering has finished before informing the surface
376   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
377   if ( eglGraphics )
378   {
379     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
380     mGLES.PostRender();
381
382     if( renderToFbo )
383     {
384       mGLES.Flush();
385       mGLES.Finish();
386     }
387     else
388     {
389       if( resizingSurface )
390       {
391         if( !mRotationFinished )
392         {
393           DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
394
395           mRotationTrigger->Trigger();
396
397           if( mThreadSynchronization )
398           {
399             // Wait until the event-thread complete the rotation event processing
400             mThreadSynchronization->PostRenderWaitForCompletion();
401           }
402         }
403       }
404     }
405
406     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
407     eglImpl.SwapBuffers();
408
409     if( mRenderNotification )
410     {
411       mRenderNotification->Trigger();
412     }
413   }
414 }
415
416 void WindowRenderSurface::StopRender()
417 {
418 }
419
420 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
421 {
422   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
423
424   mThreadSynchronization = &threadSynchronization;
425 }
426
427 void WindowRenderSurface::ReleaseLock()
428 {
429   // Nothing to do.
430 }
431
432 RenderSurface::Type WindowRenderSurface::GetSurfaceType()
433 {
434   return RenderSurface::WINDOW_RENDER_SURFACE;
435 }
436
437 void WindowRenderSurface::OutputTransformed()
438 {
439   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
440
441   if( mScreenRotationAngle != screenRotationAngle )
442   {
443     mScreenRotationAngle = screenRotationAngle;
444     mScreenRotationFinished = false;
445
446     mOutputTransformedSignal.Emit();
447
448     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
449   }
450   else
451   {
452     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
453   }
454 }
455
456 void WindowRenderSurface::ProcessRotationRequest()
457 {
458   mRotationFinished = true;
459
460   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
461
462   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
463
464   if( mThreadSynchronization )
465   {
466     mThreadSynchronization->PostRenderComplete();
467   }
468 }
469
470 } // namespace Adaptor
471
472 } // namespace internal
473
474 } // namespace Dali