[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           if( mThreadSynchronization )
523           {
524             // Enable PostRender flag
525             mThreadSynchronization->PostRenderStarted();
526           }
527
528           DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
529
530           mRotationTrigger->Trigger();
531
532           if( mThreadSynchronization )
533           {
534             // Wait until the event-thread complete the rotation event processing
535             mThreadSynchronization->PostRenderWaitForCompletion();
536           }
537         }
538       }
539     }
540
541     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
542
543     eglImpl.SwapBuffers( mEGLSurface );
544
545     if( mRenderNotification )
546     {
547       mRenderNotification->Trigger();
548     }
549   }
550 }
551
552 void WindowRenderSurface::StopRender()
553 {
554 }
555
556 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
557 {
558   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
559
560   mThreadSynchronization = &threadSynchronization;
561 }
562
563 void WindowRenderSurface::ReleaseLock()
564 {
565   // Nothing to do.
566 }
567
568 Integration::RenderSurface::Type WindowRenderSurface::GetSurfaceType()
569 {
570   return RenderSurface::WINDOW_RENDER_SURFACE;
571 }
572
573 void WindowRenderSurface::MakeContextCurrent()
574 {
575   if ( mEGL != nullptr )
576   {
577     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
578   }
579 }
580
581 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
582 {
583   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
584 }
585
586 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
587 {
588   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
589 }
590
591 void WindowRenderSurface::OutputTransformed()
592 {
593   int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
594
595   if( mScreenRotationAngle != screenRotationAngle )
596   {
597     mScreenRotationAngle = screenRotationAngle;
598     mScreenRotationFinished = false;
599     mResizeFinished = false;
600
601     mOutputTransformedSignal.Emit();
602
603     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
604   }
605   else
606   {
607     DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
608   }
609 }
610
611 void WindowRenderSurface::ProcessRotationRequest()
612 {
613   mRotationFinished = true;
614
615   mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
616
617   DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
618
619   if( mThreadSynchronization )
620   {
621     mThreadSynchronization->PostRenderComplete();
622   }
623 }
624
625 } // namespace Adaptor
626
627 } // namespace internal
628
629 } // namespace Dali