[Tizen] Add screen and client rotation itself function
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / tizen-wayland / native-render-surface-ecore-wl.cpp
1 /*
2  * Copyright (c) 2020 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/tizen-wayland/native-render-surface-ecore-wl.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/debug.h>
24
25 #ifdef ECORE_WAYLAND2
26 #include <Ecore_Wl2.h>
27 #else
28 #include <Ecore_Wayland.h>
29 #endif
30
31 #include <tbm_bufmgr.h>
32 #include <tbm_surface_internal.h>
33
34 // INTERNAL INCLUDES
35 #include <dali/integration-api/adaptor-framework/thread-synchronization-interface.h>
36 #include <dali/internal/adaptor/common/adaptor-impl.h>
37 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
38 #include <dali/internal/graphics/gles/egl-graphics.h>
39 #include <dali/internal/graphics/gles/egl-implementation.h>
40 #include <dali/internal/system/common/trigger-event.h>
41 #include <dali/internal/window-system/common/display-connection.h>
42 #include <dali/internal/window-system/common/window-system.h>
43
44 namespace Dali
45 {
46
47 namespace
48 {
49
50 #if defined(DEBUG_ENABLED)
51 Debug::Filter* gNativeSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_NATIVE_RENDER_SURFACE");
52 #endif
53
54 } // unnamed namespace
55
56 NativeRenderSurfaceEcoreWl::NativeRenderSurfaceEcoreWl( SurfaceSize surfaceSize, Any surface, bool isTransparent )
57 : mRenderNotification( NULL ),
58   mGraphics( NULL ),
59   mEGL( nullptr ),
60   mEGLSurface( nullptr ),
61   mEGLContext( nullptr ),
62   mOwnSurface( false ),
63   mDrawableCompleted( false ),
64   mTbmQueue( NULL ),
65   mConsumeSurface( NULL ),
66   mThreadSynchronization( NULL )
67 {
68   Dali::Internal::Adaptor::WindowSystem::Initialize();
69
70   if( surface.Empty() )
71   {
72     mSurfaceSize = surfaceSize;
73     mColorDepth = isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24;
74     mTbmFormat = isTransparent ? TBM_FORMAT_ARGB8888 : TBM_FORMAT_RGB888;
75     CreateNativeRenderable();
76   }
77   else
78   {
79     mTbmQueue = AnyCast< tbm_surface_queue_h >( surface );
80
81     uint16_t width = static_cast<uint16_t>( tbm_surface_queue_get_width( mTbmQueue ) );
82     uint16_t height = static_cast<uint16_t>( tbm_surface_queue_get_height( mTbmQueue ) );
83     mSurfaceSize = SurfaceSize( width, height );
84
85     mTbmFormat = tbm_surface_queue_get_format( mTbmQueue );
86
87     mColorDepth = ( mTbmFormat == TBM_FORMAT_ARGB8888 ) ? COLOR_DEPTH_32 : COLOR_DEPTH_24;
88   }
89 }
90
91 NativeRenderSurfaceEcoreWl::~NativeRenderSurfaceEcoreWl()
92 {
93   if ( mEGLSurface )
94   {
95     DestroySurface();
96   }
97
98   // release the surface if we own one
99   if( mOwnSurface )
100   {
101     ReleaseDrawable();
102
103     if( mTbmQueue )
104     {
105       tbm_surface_queue_destroy( mTbmQueue );
106     }
107
108     DALI_LOG_INFO( gNativeSurfaceLogFilter, Debug::General, "Own tbm surface queue destroy\n" );
109   }
110
111   Dali::Internal::Adaptor::WindowSystem::Shutdown();
112 }
113
114 Any NativeRenderSurfaceEcoreWl::GetDrawable()
115 {
116   return mConsumeSurface;
117 }
118
119 void NativeRenderSurfaceEcoreWl::SetRenderNotification( TriggerEventInterface* renderNotification )
120 {
121   mRenderNotification = renderNotification;
122 }
123
124 void NativeRenderSurfaceEcoreWl::WaitUntilSurfaceReplaced()
125 {
126   ConditionalWait::ScopedLock lock( mTbmSurfaceCondition );
127   while( !mDrawableCompleted )
128   {
129     mTbmSurfaceCondition.Wait( lock );
130   }
131
132   mDrawableCompleted = false;
133 }
134
135 Any NativeRenderSurfaceEcoreWl::GetNativeRenderable()
136 {
137   return mTbmQueue;
138 }
139
140 PositionSize NativeRenderSurfaceEcoreWl::GetPositionSize() const
141 {
142   return PositionSize( 0, 0, static_cast<int>( mSurfaceSize.GetWidth() ), static_cast<int>( mSurfaceSize.GetHeight() ) );
143 }
144
145 void NativeRenderSurfaceEcoreWl::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
146 {
147   // calculate DPI
148   float xres, yres;
149
150   // 1 inch = 25.4 millimeters
151 #ifdef ECORE_WAYLAND2
152   // TODO: Application should set dpi value in wayland2
153   xres = 96;
154   yres = 96;
155 #else
156   xres = ecore_wl_dpi_get();
157   yres = ecore_wl_dpi_get();
158 #endif
159
160   dpiHorizontal = int( xres + 0.5f );  // rounding
161   dpiVertical   = int( yres + 0.5f );
162 }
163
164 int NativeRenderSurfaceEcoreWl::GetOrientation() const
165 {
166   return 0;
167 }
168
169 void NativeRenderSurfaceEcoreWl::InitializeGraphics()
170 {
171   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
172
173   mGraphics = &mAdaptor->GetGraphicsInterface();
174   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
175
176   mEGL = &eglGraphics->GetEglInterface();
177
178   if ( mEGLContext == NULL )
179   {
180     // Create the OpenGL context for this window
181     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
182     eglImpl.CreateWindowContext( mEGLContext );
183
184     // Create the OpenGL surface
185     CreateSurface();
186   }
187 }
188
189 void NativeRenderSurfaceEcoreWl::CreateSurface()
190 {
191   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
192
193   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
194   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
195
196   mEGLSurface = eglImpl.CreateSurfaceWindow( reinterpret_cast< EGLNativeWindowType >( mTbmQueue ), mColorDepth );
197 }
198
199 void NativeRenderSurfaceEcoreWl::DestroySurface()
200 {
201   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
202
203   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
204   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
205
206   eglImpl.DestroySurface( mEGLSurface );
207 }
208
209 bool NativeRenderSurfaceEcoreWl::ReplaceGraphicsSurface()
210 {
211   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
212
213   if( !mTbmQueue )
214   {
215     return false;
216   }
217
218   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
219   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
220
221   return eglImpl.ReplaceSurfaceWindow( reinterpret_cast< EGLNativeWindowType >( mTbmQueue ), mEGLSurface, mEGLContext );
222 }
223
224 void NativeRenderSurfaceEcoreWl::MoveResize( Dali::PositionSize positionSize )
225 {
226   tbm_surface_queue_error_e error = TBM_SURFACE_QUEUE_ERROR_NONE;
227
228   error = tbm_surface_queue_reset( mTbmQueue, positionSize.width, positionSize.height, mTbmFormat );
229
230   if( error != TBM_SURFACE_QUEUE_ERROR_NONE )
231   {
232     DALI_LOG_ERROR( "Failed to resize tbm_surface_queue" );
233   }
234
235   mSurfaceSize.SetWidth( static_cast<uint16_t>( positionSize.width ) );
236   mSurfaceSize.SetHeight( static_cast<uint16_t>( positionSize.height ) );
237 }
238
239 void NativeRenderSurfaceEcoreWl::StartRender()
240 {
241 }
242
243 bool NativeRenderSurfaceEcoreWl::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
244 {
245   //TODO: Need to support partial update
246   return true;
247 }
248
249 void NativeRenderSurfaceEcoreWl::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
250 {
251   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
252   if (eglGraphics)
253   {
254     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
255     eglImpl.SwapBuffers( mEGLSurface, damagedRects );
256   }
257
258   //TODO: Move calling tbm_surface_queue_acruie to OffscreenWindow and Scene in EvasPlugin
259   if ( mOwnSurface )
260   {
261     if( mThreadSynchronization )
262     {
263       mThreadSynchronization->PostRenderStarted();
264     }
265
266     if( tbm_surface_queue_can_acquire( mTbmQueue, 1 ) )
267     {
268       if( tbm_surface_queue_acquire( mTbmQueue, &mConsumeSurface ) != TBM_SURFACE_QUEUE_ERROR_NONE )
269       {
270         DALI_LOG_ERROR( "Failed to acquire a tbm_surface\n" );
271         return;
272       }
273     }
274
275     if ( mConsumeSurface )
276     {
277       tbm_surface_internal_ref( mConsumeSurface );
278     }
279
280     if( replacingSurface )
281     {
282       ConditionalWait::ScopedLock lock( mTbmSurfaceCondition );
283       mDrawableCompleted = true;
284       mTbmSurfaceCondition.Notify( lock );
285     }
286
287    // create damage for client applications which wish to know the update timing
288     if( !replacingSurface && mRenderNotification )
289     {
290       // use notification trigger
291       // Tell the event-thread to render the tbm_surface
292       mRenderNotification->Trigger();
293     }
294
295     if( mThreadSynchronization )
296     {
297       // wait until the event-thread completed to use the tbm_surface
298       mThreadSynchronization->PostRenderWaitForCompletion();
299     }
300
301     // release the consumed surface after post render was completed
302     ReleaseDrawable();
303   }
304   else
305   {
306     // create damage for client applications which wish to know the update timing
307     if( !replacingSurface && mRenderNotification )
308     {
309       // use notification trigger
310       // Tell the event-thread to render the tbm_surface
311       mRenderNotification->Trigger();
312     }
313   }
314 }
315
316 void NativeRenderSurfaceEcoreWl::StopRender()
317 {
318   ReleaseLock();
319 }
320
321 void NativeRenderSurfaceEcoreWl::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
322 {
323   mThreadSynchronization = &threadSynchronization;
324 }
325
326 Dali::RenderSurfaceInterface::Type NativeRenderSurfaceEcoreWl::GetSurfaceType()
327 {
328   return Dali::RenderSurfaceInterface::NATIVE_RENDER_SURFACE;
329 }
330
331 void NativeRenderSurfaceEcoreWl::MakeContextCurrent()
332 {
333   if ( mEGL != nullptr )
334   {
335     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
336   }
337 }
338
339 Integration::DepthBufferAvailable NativeRenderSurfaceEcoreWl::GetDepthBufferRequired()
340 {
341   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
342 }
343
344 Integration::StencilBufferAvailable NativeRenderSurfaceEcoreWl::GetStencilBufferRequired()
345 {
346   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
347 }
348
349 void NativeRenderSurfaceEcoreWl::ReleaseLock()
350 {
351   if( mThreadSynchronization )
352   {
353     mThreadSynchronization->PostRenderComplete();
354   }
355 }
356
357 void NativeRenderSurfaceEcoreWl::CreateNativeRenderable()
358 {
359   int width = static_cast<int>( mSurfaceSize.GetWidth() );
360   int height = static_cast<int>( mSurfaceSize.GetHeight() );
361
362   // check we're creating one with a valid size
363   DALI_ASSERT_ALWAYS( width > 0 && height > 0 && "tbm_surface size is invalid" );
364
365   mTbmQueue = tbm_surface_queue_create( 3, width, height, mTbmFormat, TBM_BO_DEFAULT );
366
367   if( mTbmQueue )
368   {
369     mOwnSurface = true;
370   }
371   else
372   {
373     mOwnSurface = false;
374   }
375 }
376
377 void NativeRenderSurfaceEcoreWl::ReleaseDrawable()
378 {
379   if( mConsumeSurface )
380   {
381     tbm_surface_internal_unref( mConsumeSurface );
382
383     if( tbm_surface_internal_is_valid( mConsumeSurface ) )
384     {
385       tbm_surface_queue_release( mTbmQueue, mConsumeSurface );
386     }
387     mConsumeSurface = NULL;
388   }
389 }
390
391 } // namespace Dali