eff87457e2e21e73a3e76b2615e31b467f6886fe
[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 #include <dali/internal/system/common/environment-variables.h>
36
37
38 namespace Dali
39 {
40 namespace Internal
41 {
42 namespace Adaptor
43 {
44
45 namespace
46 {
47
48 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
49 const int TILE_SIZE = 16u;  ///< Unit of tile size at GPU driver
50
51 #if defined(DEBUG_ENABLED)
52 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
53 #endif
54
55 } // unnamed namespace
56
57 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
58 : mEGL( nullptr ),
59   mDisplayConnection( nullptr ),
60   mPositionSize( positionSize ),
61   mWindowBase(),
62   mThreadSynchronization( NULL ),
63   mRenderNotification( NULL ),
64   mRotationTrigger( NULL ),
65   mGraphics( nullptr ),
66   mEGLSurface( nullptr ),
67   mEGLContext( nullptr ),
68   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
69   mOutputTransformedSignal(),
70   mRotationAngle( 0 ),
71   mScreenRotationAngle( 0 ),
72   mBufferAge( 0 ),
73   mPreBufferAge( 0 ),
74   mOwnSurface( false ),
75   mRotationSupported( false ),
76   mRotationFinished( true ),
77   mScreenRotationFinished( true ),
78   mResizeFinished( true ),
79   mDpiHorizontal( 0 ),
80   mDpiVertical( 0 ),
81   mPreDamagedRect()
82 {
83   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
84   Initialize( surface );
85 }
86
87 WindowRenderSurface::~WindowRenderSurface()
88 {
89   if( mRotationTrigger )
90   {
91     delete mRotationTrigger;
92   }
93
94   if ( mEGLSurface )
95   {
96     DestroySurface();
97   }
98 }
99
100 void WindowRenderSurface::Initialize( Any surface )
101 {
102   // If width or height are zero, go full screen.
103   if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
104   {
105     // Default window size == screen size
106     mPositionSize.x = 0;
107     mPositionSize.y = 0;
108
109     WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
110   }
111
112   // Create a window base
113   auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
114   mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
115
116   // Connect signals
117   mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
118
119   // Check screen rotation
120   mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
121   if( mScreenRotationAngle != 0 )
122   {
123     mScreenRotationFinished = false;
124     mResizeFinished = false;
125   }
126 }
127
128 Any WindowRenderSurface::GetNativeWindow()
129 {
130   return mWindowBase->GetNativeWindow();
131 }
132
133 int WindowRenderSurface::GetNativeWindowId()
134 {
135   return mWindowBase->GetNativeWindowId();
136 }
137
138 void WindowRenderSurface::Map()
139 {
140   mWindowBase->Show();
141 }
142
143 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
144 {
145   mRenderNotification = renderNotification;
146 }
147
148 void WindowRenderSurface::SetTransparency( bool transparent )
149 {
150   mWindowBase->SetTransparency( transparent );
151 }
152
153 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
154 {
155   if( !mRotationTrigger )
156   {
157     TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
158     mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
159   }
160
161   mPositionSize.width = width;
162   mPositionSize.height = height;
163
164   mRotationAngle = angle;
165   mRotationFinished = false;
166
167   mWindowBase->SetWindowRotationAngle( mRotationAngle );
168
169   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
170 }
171
172 WindowBase* WindowRenderSurface::GetWindowBase()
173 {
174   return mWindowBase.get();
175 }
176
177 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
178 {
179   return mOutputTransformedSignal;
180 }
181
182 PositionSize WindowRenderSurface::GetPositionSize() const
183 {
184   return mPositionSize;
185 }
186
187 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
188 {
189   if( mDpiHorizontal == 0 || mDpiVertical == 0 )
190   {
191     const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
192     mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
193
194     const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
195     mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
196
197     if( mDpiHorizontal == 0 || mDpiVertical == 0 )
198     {
199       mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
200     }
201   }
202
203   dpiHorizontal = mDpiHorizontal;
204   dpiVertical = mDpiVertical;
205 }
206
207 int WindowRenderSurface::GetOrientation() const
208 {
209   return mWindowBase->GetOrientation();
210 }
211
212 void WindowRenderSurface::InitializeGraphics()
213 {
214
215   mGraphics = &mAdaptor->GetGraphicsInterface();
216
217   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
218   mEGL = &eglGraphics->GetEglInterface();
219
220   if ( mEGLContext == NULL )
221   {
222     // Create the OpenGL context for this window
223     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
224     eglImpl.ChooseConfig(true, mColorDepth);
225     eglImpl.CreateWindowContext( mEGLContext );
226
227     // Create the OpenGL surface
228     CreateSurface();
229   }
230 }
231
232 void WindowRenderSurface::CreateSurface()
233 {
234   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
235
236   int width, height;
237   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
238   {
239     width = mPositionSize.width;
240     height = mPositionSize.height;
241   }
242   else
243   {
244     width = mPositionSize.height;
245     height = mPositionSize.width;
246   }
247
248   // Create the EGL window
249   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
250
251   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
252
253   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
254   mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
255
256   // Check rotation capability
257   mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
258
259   int screenWidth, screenHeight;
260   WindowSystem::GetScreenSize( screenWidth, screenHeight );
261   DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: w = %d h = %d screenWidth = %d screenHeight = %d angle = %d screen rotation = %d\n",
262       mPositionSize.width, mPositionSize.height, screenWidth, screenHeight, mRotationAngle, mScreenRotationAngle );
263 }
264
265 void WindowRenderSurface::DestroySurface()
266 {
267   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
268
269   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
270
271   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
272   eglImpl.DestroySurface( mEGLSurface );
273
274   mWindowBase->DestroyEglWindow();
275 }
276
277 bool WindowRenderSurface::ReplaceGraphicsSurface()
278 {
279   DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
280
281   // Destroy the old one
282   mWindowBase->DestroyEglWindow();
283
284   int width, height;
285   if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
286   {
287     width = mPositionSize.width;
288     height = mPositionSize.height;
289   }
290   else
291   {
292     width = mPositionSize.height;
293     height = mPositionSize.width;
294   }
295
296   // Create the EGL window
297   EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
298
299   // Set screen rotation
300   mScreenRotationFinished = false;
301
302   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
303
304   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
305   return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
306 }
307
308 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
309 {
310   bool needToMove = false;
311   bool needToResize = false;
312
313   // Check moving
314   if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
315       (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
316   {
317     needToMove = true;
318   }
319
320   // Check resizing
321   if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
322       (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
323   {
324     needToResize = true;
325   }
326
327   if( needToResize )
328   {
329     if( needToMove )
330     {
331       mWindowBase->MoveResize( positionSize );
332     }
333     else
334     {
335       mWindowBase->Resize( positionSize );
336     }
337
338     mResizeFinished = false;
339     mPositionSize = positionSize;
340   }
341   else
342   {
343     if( needToMove )
344     {
345       mWindowBase->Move( positionSize );
346
347       mPositionSize = positionSize;
348     }
349   }
350
351   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
352 }
353
354 void WindowRenderSurface::StartRender()
355 {
356 }
357
358 bool WindowRenderSurface::PreRender( bool resizingSurface )
359 {
360   MakeContextCurrent();
361
362   if( resizingSurface )
363   {
364     int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
365
366     // Window rotate or screen rotate
367     if( !mRotationFinished || !mScreenRotationFinished )
368     {
369       mWindowBase->SetEglWindowRotation( totalAngle );
370       mWindowBase->SetEglWindowBufferTransform( totalAngle );
371
372       // Reset only screen rotation flag
373       mScreenRotationFinished = true;
374
375       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
376     }
377
378     // Only window rotate
379     if( !mRotationFinished )
380     {
381       mWindowBase->SetEglWindowTransform( mRotationAngle );
382     }
383
384     // Resize case
385     if ( !mResizeFinished )
386     {
387       Dali::PositionSize positionSize;
388       positionSize.x = mPositionSize.x;
389       positionSize.y = mPositionSize.y;
390       if( totalAngle == 0 || totalAngle == 180 )
391       {
392         positionSize.width = mPositionSize.width;
393         positionSize.height = mPositionSize.height;
394       }
395       else
396       {
397         positionSize.width = mPositionSize.height;
398         positionSize.height = mPositionSize.width;
399       }
400
401       mWindowBase->ResizeEglWindow( positionSize );
402       mResizeFinished = true;
403
404       DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
405     }
406   }
407
408   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
409   if ( eglGraphics )
410   {
411     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
412     mGLES.PreRender();
413   }
414
415   return true;
416 }
417
418 std::vector<int32_t> WindowRenderSurface::MergeRect( const Rect<int32_t>& damagedRect, int bufferAge )
419 {
420   std::vector<int32_t> mergedRectArray;
421   // merge bounding
422   int dx1 = mPositionSize.width, dx2 = 0, dy1 = mPositionSize.height, dy2 = 0;
423   int checkWidth = mPositionSize.width - TILE_SIZE;
424   int checkHeight = mPositionSize.height - TILE_SIZE;
425
426   dx1 = std::min( damagedRect.x, dx1 );
427   dx2 = std::max( damagedRect.x + damagedRect.width, dx2);
428   dy1 = std::min( damagedRect.y, dy1 );
429   dy2 = std::max( damagedRect.y + damagedRect.height, dy2 );
430
431   for( int j = 0; j <= bufferAge; j++ )
432   {
433     if( !mPreDamagedRect[j].IsEmpty() )
434     {
435       dx1 = std::min( mPreDamagedRect[j].x, dx1 );
436       dx2 = std::max( mPreDamagedRect[j].x + mPreDamagedRect[j].width, dx2);
437       dy1 = std::min( mPreDamagedRect[j].y, dy1 );
438       dy2 = std::max( mPreDamagedRect[j].y + mPreDamagedRect[j].height, dy2 );
439
440       if( dx1 < TILE_SIZE && dx2 > checkWidth && dy1 < TILE_SIZE && dy2 > checkHeight )
441       {
442         dx1 = 0, dx2 = mPositionSize.width, dy1 = 0, dy2 = mPositionSize.height;
443         break;
444       }
445     }
446   }
447
448   dx1 = TILE_SIZE * (dx1 / TILE_SIZE);
449   dy1 = TILE_SIZE * (dy1 / TILE_SIZE);
450   dx2 = TILE_SIZE * ((dx2 + TILE_SIZE - 1) / TILE_SIZE);
451   dy2 = TILE_SIZE * ((dy2 + TILE_SIZE - 1) / TILE_SIZE);
452
453   mergedRectArray.push_back( dx1 );
454   mergedRectArray.push_back( dy1 );
455   mergedRectArray.push_back( dx2 - dx1 );
456   mergedRectArray.push_back( dy2 - dy1 );
457
458   return mergedRectArray;
459 }
460
461
462 Rect<int32_t> WindowRenderSurface::SetDamagedRect( const Rect<int32_t>& damagedRect )
463 {
464   auto eglGraphics = static_cast<EglGraphics *>( mGraphics );
465   std::vector<int32_t> rectArray;
466   Rect<int32_t> mergedDamagedRect;
467   if( eglGraphics )
468   {
469     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
470
471     rectArray = MergeRect( damagedRect, mBufferAge );
472
473     mPreDamagedRect[4] = std::move( mPreDamagedRect[3] );
474     mPreDamagedRect[3] = std::move( mPreDamagedRect[2] );
475     mPreDamagedRect[2] = std::move( mPreDamagedRect[1] );
476     mPreDamagedRect[1] = std::move( mPreDamagedRect[0] );
477     mPreDamagedRect[0] = std::move( damagedRect );
478
479     eglImpl.SetDamagedRect( rectArray, mEGLSurface );
480   }
481
482   if( !rectArray.empty() )
483   {
484     mergedDamagedRect.x = rectArray[0];
485     mergedDamagedRect.y = rectArray[1];
486     mergedDamagedRect.width = rectArray[2];
487     mergedDamagedRect.height = rectArray[3];
488   }
489
490   return mergedDamagedRect;
491 }
492
493 int32_t WindowRenderSurface::GetBufferAge()
494 {
495   int result = mBufferAge = 0;
496   auto eglGraphics = static_cast<EglGraphics *>( mGraphics );
497   if( eglGraphics )
498   {
499     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
500     mBufferAge = eglImpl.GetBufferAge( mEGLSurface );;
501     result = ( mBufferAge != mPreBufferAge ) ? 0 : mBufferAge;
502     mPreBufferAge = mBufferAge;
503   }
504   return result;
505 }
506
507 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
508 {
509   // Inform the gl implementation that rendering has finished before informing the surface
510   auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
511   if ( eglGraphics )
512   {
513     GlImplementation& mGLES = eglGraphics->GetGlesInterface();
514     mGLES.PostRender();
515
516     if( renderToFbo )
517     {
518       mGLES.Flush();
519       mGLES.Finish();
520     }
521     else
522     {
523       if( resizingSurface )
524       {
525         if( !mRotationFinished )
526         {
527           DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
528
529           mRotationTrigger->Trigger();
530
531           if( mThreadSynchronization )
532           {
533             // Wait until the event-thread complete the rotation event processing
534             mThreadSynchronization->PostRenderWaitForCompletion();
535           }
536         }
537       }
538     }
539
540     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
541
542     eglImpl.SwapBuffers( mEGLSurface );
543
544     if( mRenderNotification )
545     {
546       mRenderNotification->Trigger();
547     }
548   }
549 }
550
551 void WindowRenderSurface::StopRender()
552 {
553 }
554
555 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
556 {
557   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
558
559   mThreadSynchronization = &threadSynchronization;
560 }
561
562 void WindowRenderSurface::ReleaseLock()
563 {
564   // Nothing to do.
565 }
566
567 Integration::RenderSurface::Type WindowRenderSurface::GetSurfaceType()
568 {
569   return RenderSurface::WINDOW_RENDER_SURFACE;
570 }
571
572 void WindowRenderSurface::MakeContextCurrent()
573 {
574   if ( mEGL != nullptr )
575   {
576     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
577   }
578 }
579
580 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
581 {
582   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
583 }
584
585 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
586 {
587   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
588 }
589
590 void WindowRenderSurface::OutputTransformed()
591 {
592   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
593
594   if( mScreenRotationAngle != screenRotationAngle )
595   {
596     mScreenRotationAngle = screenRotationAngle;
597     mScreenRotationFinished = false;
598     mResizeFinished = false;
599
600     mOutputTransformedSignal.Emit();
601
602     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
603   }
604   else
605   {
606     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
607   }
608 }
609
610 void WindowRenderSurface::ProcessRotationRequest()
611 {
612   mRotationFinished = true;
613
614   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
615
616   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
617
618   if( mThreadSynchronization )
619   {
620     mThreadSynchronization->PostRenderComplete();
621   }
622 }
623
624 } // namespace Adaptor
625
626 } // namespace internal
627
628 } // namespace Dali