9eda5e8db45e1a1ef731657a24dd5b6c01b7056f
[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 : mSurfaceSize( surfaceSize ),
58   mRenderNotification( NULL ),
59   mGraphics( NULL ),
60   mEGL( nullptr ),
61   mEGLSurface( nullptr ),
62   mEGLContext( nullptr ),
63   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
64   mTbmFormat( isTransparent ? TBM_FORMAT_ARGB8888 : TBM_FORMAT_RGB888 ),
65   mOwnSurface( false ),
66   mDrawableCompleted( false ),
67   mTbmQueue( NULL ),
68   mConsumeSurface( NULL ),
69   mThreadSynchronization( NULL )
70 {
71   Dali::Internal::Adaptor::WindowSystem::Initialize();
72
73   if( surface.Empty() )
74   {
75     CreateNativeRenderable();
76   }
77   else
78   {
79     // check we have a valid type
80     DALI_ASSERT_ALWAYS( ( surface.GetType() == typeid (tbm_surface_queue_h) ) && "Surface type is invalid" );
81     mTbmQueue = AnyCast< tbm_surface_queue_h >( surface );
82   }
83
84   setenv( "EGL_PLATFORM", "tbm", 1 );
85 }
86
87 NativeRenderSurfaceEcoreWl::~NativeRenderSurfaceEcoreWl()
88 {
89   if ( mEGLSurface )
90   {
91     DestroySurface();
92   }
93
94   // release the surface if we own one
95   if( mOwnSurface )
96   {
97     ReleaseDrawable();
98
99     if( mTbmQueue )
100     {
101       tbm_surface_queue_destroy( mTbmQueue );
102     }
103
104     DALI_LOG_INFO( gNativeSurfaceLogFilter, Debug::General, "Own tbm surface queue destroy\n" );
105   }
106
107   Dali::Internal::Adaptor::WindowSystem::Shutdown();
108 }
109
110 Any NativeRenderSurfaceEcoreWl::GetDrawable()
111 {
112   return mConsumeSurface;
113 }
114
115 void NativeRenderSurfaceEcoreWl::SetRenderNotification( TriggerEventInterface* renderNotification )
116 {
117   mRenderNotification = renderNotification;
118 }
119
120 void NativeRenderSurfaceEcoreWl::WaitUntilSurfaceReplaced()
121 {
122   ConditionalWait::ScopedLock lock( mTbmSurfaceCondition );
123   while( !mDrawableCompleted )
124   {
125     mTbmSurfaceCondition.Wait( lock );
126   }
127
128   mDrawableCompleted = false;
129 }
130
131 PositionSize NativeRenderSurfaceEcoreWl::GetPositionSize() const
132 {
133   return PositionSize( 0, 0, static_cast<int>( mSurfaceSize.GetWidth() ), static_cast<int>( mSurfaceSize.GetHeight() ) );
134 }
135
136 void NativeRenderSurfaceEcoreWl::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
137 {
138   // calculate DPI
139   float xres, yres;
140
141   // 1 inch = 25.4 millimeters
142 #ifdef ECORE_WAYLAND2
143   // TODO: Application should set dpi value in wayland2
144   xres = 96;
145   yres = 96;
146 #else
147   xres = ecore_wl_dpi_get();
148   yres = ecore_wl_dpi_get();
149 #endif
150
151   dpiHorizontal = int( xres + 0.5f );  // rounding
152   dpiVertical   = int( yres + 0.5f );
153 }
154
155 int NativeRenderSurfaceEcoreWl::GetOrientation() const
156 {
157   return 0;
158 }
159
160 void NativeRenderSurfaceEcoreWl::InitializeGraphics()
161 {
162   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
163   unsetenv( "EGL_PLATFORM" );
164
165   mGraphics = &mAdaptor->GetGraphicsInterface();
166   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
167
168   mEGL = &eglGraphics->GetEglInterface();
169
170   if ( mEGLContext == NULL )
171   {
172     // Create the OpenGL context for this window
173     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
174     eglImpl.CreateWindowContext( mEGLContext );
175
176     // Create the OpenGL surface
177     CreateSurface();
178   }
179 }
180
181 void NativeRenderSurfaceEcoreWl::CreateSurface()
182 {
183   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
184
185   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
186   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
187
188   mEGLSurface = eglImpl.CreateSurfaceWindow( reinterpret_cast< EGLNativeWindowType >( mTbmQueue ), mColorDepth );
189 }
190
191 void NativeRenderSurfaceEcoreWl::DestroySurface()
192 {
193   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
194
195   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
196   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
197
198   eglImpl.DestroySurface( mEGLSurface );
199 }
200
201 bool NativeRenderSurfaceEcoreWl::ReplaceGraphicsSurface()
202 {
203   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
204
205   if( !mTbmQueue )
206   {
207     return false;
208   }
209
210   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
211   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
212
213   return eglImpl.ReplaceSurfaceWindow( reinterpret_cast< EGLNativeWindowType >( mTbmQueue ), mEGLSurface, mEGLContext );
214 }
215
216 void NativeRenderSurfaceEcoreWl::MoveResize( Dali::PositionSize positionSize )
217 {
218   tbm_surface_queue_error_e error = TBM_SURFACE_QUEUE_ERROR_NONE;
219
220   error = tbm_surface_queue_reset( mTbmQueue, positionSize.width, positionSize.height, mTbmFormat );
221
222   if( error != TBM_SURFACE_QUEUE_ERROR_NONE )
223   {
224     DALI_LOG_ERROR( "Failed to resize tbm_surface_queue" );
225   }
226
227   mSurfaceSize.SetWidth( static_cast<uint16_t>( positionSize.width ) );
228   mSurfaceSize.SetHeight( static_cast<uint16_t>( positionSize.height ) );
229 }
230
231 void NativeRenderSurfaceEcoreWl::StartRender()
232 {
233 }
234
235 bool NativeRenderSurfaceEcoreWl::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
236 {
237   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics*>(mGraphics);
238   if (eglGraphics)
239   {
240     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
241     if (resizingSurface)
242     {
243       eglImpl.SetFullSwapNextFrame();
244     }
245
246     eglImpl.SetDamage(mEGLSurface, damagedRects, clippingRect);
247   }
248
249   return true;
250 }
251
252 void NativeRenderSurfaceEcoreWl::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
253 {
254   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
255   if (eglGraphics)
256   {
257     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
258     eglImpl.SwapBuffers( mEGLSurface, damagedRects );
259   }
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   tbm_surface_internal_ref( mConsumeSurface );
276
277   if( replacingSurface )
278   {
279     ConditionalWait::ScopedLock lock( mTbmSurfaceCondition );
280     mDrawableCompleted = true;
281     mTbmSurfaceCondition.Notify( lock );
282   }
283
284  // create damage for client applications which wish to know the update timing
285   if( !replacingSurface && mRenderNotification )
286   {
287     // use notification trigger
288     // Tell the event-thread to render the tbm_surface
289     mRenderNotification->Trigger();
290   }
291
292   if( mThreadSynchronization )
293   {
294     // wait until the event-thread completed to use the tbm_surface
295     mThreadSynchronization->PostRenderWaitForCompletion();
296   }
297
298   // release the consumed surface after post render was completed
299   ReleaseDrawable();
300 }
301
302 void NativeRenderSurfaceEcoreWl::StopRender()
303 {
304   ReleaseLock();
305 }
306
307 void NativeRenderSurfaceEcoreWl::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
308 {
309   mThreadSynchronization = &threadSynchronization;
310 }
311
312 Dali::RenderSurfaceInterface::Type NativeRenderSurfaceEcoreWl::GetSurfaceType()
313 {
314   return Dali::RenderSurfaceInterface::NATIVE_RENDER_SURFACE;
315 }
316
317 void NativeRenderSurfaceEcoreWl::MakeContextCurrent()
318 {
319   if ( mEGL != nullptr )
320   {
321     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
322   }
323 }
324
325 Integration::DepthBufferAvailable NativeRenderSurfaceEcoreWl::GetDepthBufferRequired()
326 {
327   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
328 }
329
330 Integration::StencilBufferAvailable NativeRenderSurfaceEcoreWl::GetStencilBufferRequired()
331 {
332   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
333 }
334
335 void NativeRenderSurfaceEcoreWl::ReleaseLock()
336 {
337   if( mThreadSynchronization )
338   {
339     mThreadSynchronization->PostRenderComplete();
340   }
341 }
342
343 void NativeRenderSurfaceEcoreWl::CreateNativeRenderable()
344 {
345   int width = static_cast<int>( mSurfaceSize.GetWidth() );
346   int height = static_cast<int>( mSurfaceSize.GetHeight() );
347
348   // check we're creating one with a valid size
349   DALI_ASSERT_ALWAYS( width > 0 && height > 0 && "tbm_surface size is invalid" );
350
351   mTbmQueue = tbm_surface_queue_create( 3, width, height, mTbmFormat, TBM_BO_DEFAULT );
352
353   if( mTbmQueue )
354   {
355     mOwnSurface = true;
356   }
357   else
358   {
359     mOwnSurface = false;
360   }
361 }
362
363 void NativeRenderSurfaceEcoreWl::ReleaseDrawable()
364 {
365   if( mConsumeSurface )
366   {
367     tbm_surface_internal_unref( mConsumeSurface );
368
369     if( tbm_surface_internal_is_valid( mConsumeSurface ) )
370     {
371       tbm_surface_queue_release( mTbmQueue, mConsumeSurface );
372     }
373     mConsumeSurface = NULL;
374   }
375 }
376
377 } // namespace Dali