[Tizen] Add OffscreenApplication
[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   MakeContextCurrent();
246
247   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics*>(mGraphics);
248   if (eglGraphics)
249   {
250     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
251     if (resizingSurface)
252     {
253       eglImpl.SetFullSwapNextFrame();
254     }
255
256     eglImpl.SetDamage(mEGLSurface, damagedRects, clippingRect);
257   }
258
259   return true;
260 }
261
262 void NativeRenderSurfaceEcoreWl::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
263 {
264   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
265   if (eglGraphics)
266   {
267     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
268     eglImpl.SwapBuffers( mEGLSurface, damagedRects );
269   }
270
271   if ( mOwnSurface )
272   {
273     if( mThreadSynchronization )
274     {
275       mThreadSynchronization->PostRenderStarted();
276     }
277
278     if( tbm_surface_queue_can_acquire( mTbmQueue, 1 ) )
279     {
280       if( tbm_surface_queue_acquire( mTbmQueue, &mConsumeSurface ) != TBM_SURFACE_QUEUE_ERROR_NONE )
281       {
282         DALI_LOG_ERROR( "Failed to acquire a tbm_surface\n" );
283         return;
284       }
285     }
286
287     if ( mConsumeSurface )
288     {
289       tbm_surface_internal_ref( mConsumeSurface );
290     }
291
292     if( replacingSurface )
293     {
294       ConditionalWait::ScopedLock lock( mTbmSurfaceCondition );
295       mDrawableCompleted = true;
296       mTbmSurfaceCondition.Notify( lock );
297     }
298
299    // create damage for client applications which wish to know the update timing
300     if( !replacingSurface && mRenderNotification )
301     {
302       // use notification trigger
303       // Tell the event-thread to render the tbm_surface
304       mRenderNotification->Trigger();
305     }
306
307     if( mThreadSynchronization )
308     {
309       // wait until the event-thread completed to use the tbm_surface
310       mThreadSynchronization->PostRenderWaitForCompletion();
311     }
312
313     // release the consumed surface after post render was completed
314     ReleaseDrawable();
315   }
316   else
317   {
318     // create damage for client applications which wish to know the update timing
319     if( !replacingSurface && mRenderNotification )
320     {
321       // use notification trigger
322       // Tell the event-thread to render the tbm_surface
323       mRenderNotification->Trigger();
324     }
325   }
326 }
327
328 void NativeRenderSurfaceEcoreWl::StopRender()
329 {
330   ReleaseLock();
331 }
332
333 void NativeRenderSurfaceEcoreWl::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
334 {
335   mThreadSynchronization = &threadSynchronization;
336 }
337
338 Dali::RenderSurfaceInterface::Type NativeRenderSurfaceEcoreWl::GetSurfaceType()
339 {
340   return Dali::RenderSurfaceInterface::NATIVE_RENDER_SURFACE;
341 }
342
343 void NativeRenderSurfaceEcoreWl::MakeContextCurrent()
344 {
345   if ( mEGL != nullptr )
346   {
347     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
348   }
349 }
350
351 Integration::DepthBufferAvailable NativeRenderSurfaceEcoreWl::GetDepthBufferRequired()
352 {
353   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
354 }
355
356 Integration::StencilBufferAvailable NativeRenderSurfaceEcoreWl::GetStencilBufferRequired()
357 {
358   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
359 }
360
361 void NativeRenderSurfaceEcoreWl::ReleaseLock()
362 {
363   if( mThreadSynchronization )
364   {
365     mThreadSynchronization->PostRenderComplete();
366   }
367 }
368
369 void NativeRenderSurfaceEcoreWl::CreateNativeRenderable()
370 {
371   int width = static_cast<int>( mSurfaceSize.GetWidth() );
372   int height = static_cast<int>( mSurfaceSize.GetHeight() );
373
374   // check we're creating one with a valid size
375   DALI_ASSERT_ALWAYS( width > 0 && height > 0 && "tbm_surface size is invalid" );
376
377   mTbmQueue = tbm_surface_queue_create( 3, width, height, mTbmFormat, TBM_BO_DEFAULT );
378
379   if( mTbmQueue )
380   {
381     mOwnSurface = true;
382   }
383   else
384   {
385     mOwnSurface = false;
386   }
387 }
388
389 void NativeRenderSurfaceEcoreWl::ReleaseDrawable()
390 {
391   if( mConsumeSurface )
392   {
393     tbm_surface_internal_unref( mConsumeSurface );
394
395     if( tbm_surface_internal_is_valid( mConsumeSurface ) )
396     {
397       tbm_surface_queue_release( mTbmQueue, mConsumeSurface );
398     }
399     mConsumeSurface = NULL;
400   }
401 }
402
403 } // namespace Dali