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