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