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