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