2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/window-system/common/window-render-surface.h>
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/debug.h>
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>
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
51 #if defined(DEBUG_ENABLED)
52 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
55 } // unnamed namespace
57 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
59 mDisplayConnection( nullptr ),
60 mPositionSize( positionSize ),
62 mThreadSynchronization( NULL ),
63 mRenderNotification( NULL ),
64 mRotationTrigger( NULL ),
66 mEGLSurface( nullptr ),
67 mEGLContext( nullptr ),
68 mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
69 mOutputTransformedSignal(),
71 mScreenRotationAngle( 0 ),
75 mRotationSupported( false ),
76 mRotationFinished( true ),
77 mScreenRotationFinished( true ),
78 mResizeFinished( true ),
83 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
84 Initialize( surface );
87 WindowRenderSurface::~WindowRenderSurface()
89 if( mRotationTrigger )
91 delete mRotationTrigger;
100 void WindowRenderSurface::Initialize( Any surface )
102 // If width or height are zero, go full screen.
103 if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
105 // Default window size == screen size
109 WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
112 // Create a window base
113 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
114 mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
117 mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
119 // Check screen rotation
120 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
121 if( mScreenRotationAngle != 0 )
123 mScreenRotationFinished = false;
124 mResizeFinished = false;
128 Any WindowRenderSurface::GetNativeWindow()
130 return mWindowBase->GetNativeWindow();
133 int WindowRenderSurface::GetNativeWindowId()
135 return mWindowBase->GetNativeWindowId();
138 void WindowRenderSurface::Map()
143 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
145 mRenderNotification = renderNotification;
148 void WindowRenderSurface::SetTransparency( bool transparent )
150 mWindowBase->SetTransparency( transparent );
153 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
155 if( !mRotationTrigger )
157 TriggerEventFactoryInterface& triggerFactory = Internal::Adaptor::Adaptor::GetImplementation( Adaptor::Get() ).GetTriggerEventFactoryInterface();
158 mRotationTrigger = triggerFactory.CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
161 mPositionSize.width = width;
162 mPositionSize.height = height;
164 mRotationAngle = angle;
165 mRotationFinished = false;
167 mWindowBase->SetWindowRotationAngle( mRotationAngle );
169 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
172 WindowBase* WindowRenderSurface::GetWindowBase()
174 return mWindowBase.get();
177 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
179 return mOutputTransformedSignal;
182 PositionSize WindowRenderSurface::GetPositionSize() const
184 return mPositionSize;
187 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
189 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
191 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
192 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
194 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
195 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
197 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
199 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
203 dpiHorizontal = mDpiHorizontal;
204 dpiVertical = mDpiVertical;
207 int WindowRenderSurface::GetOrientation() const
209 return mWindowBase->GetOrientation();
212 void WindowRenderSurface::InitializeGraphics()
215 mGraphics = &mAdaptor->GetGraphicsInterface();
217 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
218 mEGL = &eglGraphics->GetEglInterface();
220 if ( mEGLContext == NULL )
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 );
227 // Create the OpenGL surface
232 void WindowRenderSurface::CreateSurface()
234 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
237 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
239 width = mPositionSize.width;
240 height = mPositionSize.height;
244 width = mPositionSize.height;
245 height = mPositionSize.width;
248 // Create the EGL window
249 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
251 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
253 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
254 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
256 // Check rotation capability
257 mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
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 );
265 void WindowRenderSurface::DestroySurface()
267 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
269 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
271 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
272 eglImpl.DestroySurface( mEGLSurface );
274 mWindowBase->DestroyEglWindow();
277 bool WindowRenderSurface::ReplaceGraphicsSurface()
279 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
281 // Destroy the old one
282 mWindowBase->DestroyEglWindow();
285 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
287 width = mPositionSize.width;
288 height = mPositionSize.height;
292 width = mPositionSize.height;
293 height = mPositionSize.width;
296 // Create the EGL window
297 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
299 // Set screen rotation
300 mScreenRotationFinished = false;
302 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
304 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
305 return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
308 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
310 bool needToMove = false;
311 bool needToResize = false;
314 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
315 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
321 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
322 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
331 mWindowBase->MoveResize( positionSize );
335 mWindowBase->Resize( positionSize );
338 mResizeFinished = false;
339 mPositionSize = positionSize;
345 mWindowBase->Move( positionSize );
347 mPositionSize = positionSize;
351 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
354 void WindowRenderSurface::StartRender()
358 bool WindowRenderSurface::PreRender( bool resizingSurface )
360 MakeContextCurrent();
362 if( resizingSurface )
364 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
366 // Window rotate or screen rotate
367 if( !mRotationFinished || !mScreenRotationFinished )
369 mWindowBase->SetEglWindowRotation( totalAngle );
370 mWindowBase->SetEglWindowBufferTransform( totalAngle );
372 // Reset only screen rotation flag
373 mScreenRotationFinished = true;
375 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
378 // Only window rotate
379 if( !mRotationFinished )
381 mWindowBase->SetEglWindowTransform( mRotationAngle );
385 if ( !mResizeFinished )
387 Dali::PositionSize positionSize;
388 positionSize.x = mPositionSize.x;
389 positionSize.y = mPositionSize.y;
390 if( totalAngle == 0 || totalAngle == 180 )
392 positionSize.width = mPositionSize.width;
393 positionSize.height = mPositionSize.height;
397 positionSize.width = mPositionSize.height;
398 positionSize.height = mPositionSize.width;
401 mWindowBase->ResizeEglWindow( positionSize );
402 mResizeFinished = true;
404 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
408 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
411 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
418 std::vector<int32_t> WindowRenderSurface::MergeRect( const Rect<int32_t>& damagedRect, int bufferAge )
420 std::vector<int32_t> mergedRectArray;
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;
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 );
431 for( int j = 0; j <= bufferAge; j++ )
433 if( !mPreDamagedRect[j].IsEmpty() )
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 );
440 if( dx1 < TILE_SIZE && dx2 > checkWidth && dy1 < TILE_SIZE && dy2 > checkHeight )
442 dx1 = 0, dx2 = mPositionSize.width, dy1 = 0, dy2 = mPositionSize.height;
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);
453 mergedRectArray.push_back( dx1 );
454 mergedRectArray.push_back( dy1 );
455 mergedRectArray.push_back( dx2 - dx1 );
456 mergedRectArray.push_back( dy2 - dy1 );
458 return mergedRectArray;
462 Rect<int32_t> WindowRenderSurface::SetDamagedRect( const Rect<int32_t>& damagedRect )
464 auto eglGraphics = static_cast<EglGraphics *>( mGraphics );
465 std::vector<int32_t> rectArray;
466 Rect<int32_t> mergedDamagedRect;
469 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
471 rectArray = MergeRect( damagedRect, mBufferAge );
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 );
479 eglImpl.SetDamagedRect( rectArray, mEGLSurface );
482 if( !rectArray.empty() )
484 mergedDamagedRect.x = rectArray[0];
485 mergedDamagedRect.y = rectArray[1];
486 mergedDamagedRect.width = rectArray[2];
487 mergedDamagedRect.height = rectArray[3];
490 return mergedDamagedRect;
493 int32_t WindowRenderSurface::GetBufferAge()
495 int result = mBufferAge = 0;
496 auto eglGraphics = static_cast<EglGraphics *>( mGraphics );
499 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
500 mBufferAge = eglImpl.GetBufferAge( mEGLSurface );;
501 result = ( mBufferAge != mPreBufferAge ) ? 0 : mBufferAge;
502 mPreBufferAge = mBufferAge;
507 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
509 // Inform the gl implementation that rendering has finished before informing the surface
510 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
513 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
523 if( resizingSurface )
525 if( !mRotationFinished )
527 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PostRender: Trigger rotation event\n" );
529 mRotationTrigger->Trigger();
531 if( mThreadSynchronization )
533 // Wait until the event-thread complete the rotation event processing
534 mThreadSynchronization->PostRenderWaitForCompletion();
540 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
542 eglImpl.SwapBuffers( mEGLSurface );
544 if( mRenderNotification )
546 mRenderNotification->Trigger();
551 void WindowRenderSurface::StopRender()
555 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
557 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
559 mThreadSynchronization = &threadSynchronization;
562 void WindowRenderSurface::ReleaseLock()
567 Integration::RenderSurface::Type WindowRenderSurface::GetSurfaceType()
569 return RenderSurface::WINDOW_RENDER_SURFACE;
572 void WindowRenderSurface::MakeContextCurrent()
574 if ( mEGL != nullptr )
576 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
580 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
582 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
585 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
587 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
590 void WindowRenderSurface::OutputTransformed()
592 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
594 if( mScreenRotationAngle != screenRotationAngle )
596 mScreenRotationAngle = screenRotationAngle;
597 mScreenRotationFinished = false;
598 mResizeFinished = false;
600 mOutputTransformedSignal.Emit();
602 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
606 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
610 void WindowRenderSurface::ProcessRotationRequest()
612 mRotationFinished = true;
614 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
616 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
618 if( mThreadSynchronization )
620 mThreadSynchronization->PostRenderComplete();
624 } // namespace Adaptor
626 } // namespace internal