2 * Copyright (c) 2020 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/adaptor-framework/thread-synchronization-interface.h>
27 #include <dali/integration-api/adaptor-framework/trigger-event-factory.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>
47 const int MINIMUM_DIMENSION_CHANGE( 1 ); ///< Minimum change for window to be considered to have moved
49 #if defined(DEBUG_ENABLED)
50 Debug::Filter* gWindowRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_WINDOW_RENDER_SURFACE");
53 } // unnamed namespace
55 WindowRenderSurface::WindowRenderSurface( Dali::PositionSize positionSize, Any surface, bool isTransparent )
57 mDisplayConnection( nullptr ),
58 mPositionSize( positionSize ),
60 mThreadSynchronization( NULL ),
61 mRenderNotification( NULL ),
62 mRotationTrigger( NULL ),
64 mEGLSurface( nullptr ),
65 mEGLContext( nullptr ),
66 mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
67 mOutputTransformedSignal(),
69 mScreenRotationAngle( 0 ),
71 mRotationSupported( false ),
72 mRotationFinished( true ),
73 mScreenRotationFinished( true ),
74 mResizeFinished( true ),
78 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "Creating Window\n" );
79 Initialize( surface );
82 WindowRenderSurface::~WindowRenderSurface()
84 if( mRotationTrigger )
86 delete mRotationTrigger;
90 void WindowRenderSurface::Initialize( Any surface )
92 // If width or height are zero, go full screen.
93 if ( (mPositionSize.width == 0) || (mPositionSize.height == 0) )
95 // Default window size == screen size
98 WindowSystem::GetScreenSize( mPositionSize.width, mPositionSize.height );
101 // Create a window base
102 auto windowFactory = Dali::Internal::Adaptor::GetWindowFactory();
103 mWindowBase = windowFactory->CreateWindowBase( mPositionSize, surface, ( mColorDepth == COLOR_DEPTH_32 ? true : false ) );
106 mWindowBase->OutputTransformedSignal().Connect( this, &WindowRenderSurface::OutputTransformed );
108 // Check screen rotation
109 mScreenRotationAngle = mWindowBase->GetScreenRotationAngle();
110 if( mScreenRotationAngle != 0 )
112 mScreenRotationFinished = false;
113 mResizeFinished = false;
117 Any WindowRenderSurface::GetNativeWindow()
119 return mWindowBase->GetNativeWindow();
122 int WindowRenderSurface::GetNativeWindowId()
124 return mWindowBase->GetNativeWindowId();
127 void WindowRenderSurface::Map()
132 void WindowRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
134 mRenderNotification = renderNotification;
137 void WindowRenderSurface::SetTransparency( bool transparent )
139 mWindowBase->SetTransparency( transparent );
142 void WindowRenderSurface::RequestRotation( int angle, int width, int height )
144 if( !mRotationTrigger )
146 mRotationTrigger = TriggerEventFactory::CreateTriggerEvent( MakeCallback( this, &WindowRenderSurface::ProcessRotationRequest ), TriggerEventInterface::KEEP_ALIVE_AFTER_TRIGGER );
149 mPositionSize.width = width;
150 mPositionSize.height = height;
152 mRotationAngle = angle;
153 mRotationFinished = false;
155 mWindowBase->SetWindowRotationAngle( mRotationAngle );
157 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::Rotate: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
160 WindowBase* WindowRenderSurface::GetWindowBase()
162 return mWindowBase.get();
165 WindowBase::OutputSignalType& WindowRenderSurface::OutputTransformedSignal()
167 return mOutputTransformedSignal;
170 PositionSize WindowRenderSurface::GetPositionSize() const
172 return mPositionSize;
175 void WindowRenderSurface::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
177 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
179 const char* environmentDpiHorizontal = std::getenv( DALI_ENV_DPI_HORIZONTAL );
180 mDpiHorizontal = environmentDpiHorizontal ? std::atoi( environmentDpiHorizontal ) : 0;
182 const char* environmentDpiVertical = std::getenv( DALI_ENV_DPI_VERTICAL );
183 mDpiVertical = environmentDpiVertical ? std::atoi( environmentDpiVertical ) : 0;
185 if( mDpiHorizontal == 0 || mDpiVertical == 0 )
187 mWindowBase->GetDpi( mDpiHorizontal, mDpiVertical );
191 dpiHorizontal = mDpiHorizontal;
192 dpiVertical = mDpiVertical;
195 int WindowRenderSurface::GetOrientation() const
197 return mWindowBase->GetOrientation();
200 void WindowRenderSurface::InitializeGraphics()
202 mGraphics = &mAdaptor->GetGraphicsInterface();
204 DALI_ASSERT_ALWAYS( mGraphics && "Graphics interface is not created" );
206 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
207 mEGL = &eglGraphics->GetEglInterface();
209 if ( mEGLContext == NULL )
211 // Create the OpenGL context for this window
212 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
213 eglImpl.ChooseConfig(true, mColorDepth);
214 eglImpl.CreateWindowContext( mEGLContext );
216 // Create the OpenGL surface
221 void WindowRenderSurface::CreateSurface()
223 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
226 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
228 width = mPositionSize.width;
229 height = mPositionSize.height;
233 width = mPositionSize.height;
234 height = mPositionSize.width;
237 // Create the EGL window
238 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
240 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
242 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
243 mEGLSurface = eglImpl.CreateSurfaceWindow( window, mColorDepth );
245 // Check rotation capability
246 mRotationSupported = mWindowBase->IsEglWindowRotationSupported();
248 DALI_LOG_RELEASE_INFO("WindowRenderSurface::CreateSurface: WinId (%d), w = %d h = %d angle = %d screen rotation = %d\n",
249 mWindowBase->GetNativeWindowId(), mPositionSize.width, mPositionSize.height, mRotationAngle, mScreenRotationAngle );
252 void WindowRenderSurface::DestroySurface()
254 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
256 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
259 DALI_LOG_RELEASE_INFO("WindowRenderSurface::DestroySurface: WinId (%d)\n", mWindowBase->GetNativeWindowId() );
261 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
263 eglImpl.DestroySurface( mEGLSurface );
264 mEGLSurface = nullptr;
266 // Destroy context also
267 eglImpl.DestroyContext( mEGLContext );
268 mEGLContext = nullptr;
270 mWindowBase->DestroyEglWindow();
274 bool WindowRenderSurface::ReplaceGraphicsSurface()
276 DALI_LOG_TRACE_METHOD( gWindowRenderSurfaceLogFilter );
278 // Destroy the old one
279 mWindowBase->DestroyEglWindow();
282 if( mScreenRotationAngle == 0 || mScreenRotationAngle == 180 )
284 width = mPositionSize.width;
285 height = mPositionSize.height;
289 width = mPositionSize.height;
290 height = mPositionSize.width;
293 // Create the EGL window
294 EGLNativeWindowType window = mWindowBase->CreateEglWindow( width, height );
296 // Set screen rotation
297 mScreenRotationFinished = false;
299 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
301 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
302 return eglImpl.ReplaceSurfaceWindow( window, mEGLSurface, mEGLContext );
305 void WindowRenderSurface::MoveResize( Dali::PositionSize positionSize )
307 bool needToMove = false;
308 bool needToResize = false;
311 if( (fabs(positionSize.x - mPositionSize.x) > MINIMUM_DIMENSION_CHANGE) ||
312 (fabs(positionSize.y - mPositionSize.y) > MINIMUM_DIMENSION_CHANGE) )
318 if( (fabs(positionSize.width - mPositionSize.width) > MINIMUM_DIMENSION_CHANGE) ||
319 (fabs(positionSize.height - mPositionSize.height) > MINIMUM_DIMENSION_CHANGE) )
328 mWindowBase->MoveResize( positionSize );
332 mWindowBase->Resize( positionSize );
335 mResizeFinished = false;
336 mPositionSize = positionSize;
342 mWindowBase->Move( positionSize );
344 mPositionSize = positionSize;
348 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::MoveResize: %d, %d, %d, %d\n", mPositionSize.x, mPositionSize.y, mPositionSize.width, mPositionSize.height );
351 void WindowRenderSurface::StartRender()
355 bool WindowRenderSurface::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
357 MakeContextCurrent();
359 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
361 if( resizingSurface )
363 int totalAngle = (mRotationAngle + mScreenRotationAngle) % 360;
365 // Window rotate or screen rotate
366 if( !mRotationFinished || !mScreenRotationFinished )
368 mWindowBase->SetEglWindowRotation( totalAngle );
369 mWindowBase->SetEglWindowBufferTransform( totalAngle );
371 // Reset only screen rotation flag
372 mScreenRotationFinished = true;
374 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set rotation [%d] [%d]\n", mRotationAngle, mScreenRotationAngle );
377 // Only window rotate
378 if( !mRotationFinished )
380 mWindowBase->SetEglWindowTransform( mRotationAngle );
384 if ( !mResizeFinished )
386 Dali::PositionSize positionSize;
387 positionSize.x = mPositionSize.x;
388 positionSize.y = mPositionSize.y;
389 if( totalAngle == 0 || totalAngle == 180 )
391 positionSize.width = mPositionSize.width;
392 positionSize.height = mPositionSize.height;
396 positionSize.width = mPositionSize.height;
397 positionSize.height = mPositionSize.width;
399 mWindowBase->ResizeEglWindow( positionSize );
400 mResizeFinished = true;
402 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::PreRender: Set resize\n" );
407 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
408 eglImpl.SetFullSwapNextFrame();
414 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
415 eglImpl.SetDamage( mEGLSurface, damagedRects, clippingRect );
421 void WindowRenderSurface::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
423 // Inform the gl implementation that rendering has finished before informing the surface
424 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
427 GlImplementation& mGLES = eglGraphics->GetGlesInterface();
437 if( resizingSurface )
439 if( !mRotationFinished )
441 if( mThreadSynchronization )
443 // Enable PostRender flag
444 mThreadSynchronization->PostRenderStarted();
447 DALI_LOG_RELEASE_INFO("WindowRenderSurface::PostRender: Trigger rotation event\n" );
449 mRotationTrigger->Trigger();
451 if( mThreadSynchronization )
453 // Wait until the event-thread complete the rotation event processing
454 mThreadSynchronization->PostRenderWaitForCompletion();
460 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
461 eglImpl.SwapBuffers( mEGLSurface, damagedRects );
463 if( mRenderNotification )
465 mRenderNotification->Trigger();
470 void WindowRenderSurface::StopRender()
474 void WindowRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
476 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::SetThreadSynchronization: called\n" );
478 mThreadSynchronization = &threadSynchronization;
481 void WindowRenderSurface::ReleaseLock()
486 Dali::RenderSurfaceInterface::Type WindowRenderSurface::GetSurfaceType()
488 return Dali::RenderSurfaceInterface::WINDOW_RENDER_SURFACE;
491 void WindowRenderSurface::MakeContextCurrent()
493 if ( mEGL != nullptr )
495 mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
499 Integration::DepthBufferAvailable WindowRenderSurface::GetDepthBufferRequired()
501 return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
504 Integration::StencilBufferAvailable WindowRenderSurface::GetStencilBufferRequired()
506 return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
509 void WindowRenderSurface::OutputTransformed()
511 int screenRotationAngle = mWindowBase->GetScreenRotationAngle();
513 if( mScreenRotationAngle != screenRotationAngle )
515 mScreenRotationAngle = screenRotationAngle;
516 mScreenRotationFinished = false;
517 mResizeFinished = false;
519 mOutputTransformedSignal.Emit();
521 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: angle = %d screen rotation = %d\n", mRotationAngle, mScreenRotationAngle );
525 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::OutputTransformed: Ignore output transform [%d]\n", mScreenRotationAngle );
529 void WindowRenderSurface::ProcessRotationRequest()
531 mRotationFinished = true;
533 mWindowBase->WindowRotationCompleted( mRotationAngle, mPositionSize.width, mPositionSize.height );
535 DALI_LOG_INFO( gWindowRenderSurfaceLogFilter, Debug::Verbose, "WindowRenderSurface::ProcessRotationRequest: Rotation Done\n" );
537 if( mThreadSynchronization )
539 mThreadSynchronization->PostRenderComplete();
543 } // namespace Adaptor
545 } // namespace internal