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 void NativeRenderSurfaceEcoreWl::InitializeGraphics()
165 {
166   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
167
168   mGraphics = &mAdaptor->GetGraphicsInterface();
169   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
170
171   mEGL = &eglGraphics->GetEglInterface();
172
173   if ( mEGLContext == NULL )
174   {
175     // Create the OpenGL context for this window
176     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>(*mEGL);
177     eglImpl.CreateWindowContext( mEGLContext );
178
179     // Create the OpenGL surface
180     CreateSurface();
181   }
182 }
183
184 void NativeRenderSurfaceEcoreWl::CreateSurface()
185 {
186   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
187
188   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
189   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
190
191   mEGLSurface = eglImpl.CreateSurfaceWindow( reinterpret_cast< EGLNativeWindowType >( mTbmQueue ), mColorDepth );
192 }
193
194 void NativeRenderSurfaceEcoreWl::DestroySurface()
195 {
196   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
197
198   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
199   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
200
201   eglImpl.DestroySurface( mEGLSurface );
202 }
203
204 bool NativeRenderSurfaceEcoreWl::ReplaceGraphicsSurface()
205 {
206   DALI_LOG_TRACE_METHOD( gNativeSurfaceLogFilter );
207
208   if( !mTbmQueue )
209   {
210     return false;
211   }
212
213   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
214   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
215
216   return eglImpl.ReplaceSurfaceWindow( reinterpret_cast< EGLNativeWindowType >( mTbmQueue ), mEGLSurface, mEGLContext );
217 }
218
219 void NativeRenderSurfaceEcoreWl::MoveResize( Dali::PositionSize positionSize )
220 {
221   tbm_surface_queue_error_e error = TBM_SURFACE_QUEUE_ERROR_NONE;
222
223   error = tbm_surface_queue_reset( mTbmQueue, positionSize.width, positionSize.height, mTbmFormat );
224
225   if( error != TBM_SURFACE_QUEUE_ERROR_NONE )
226   {
227     DALI_LOG_ERROR( "Failed to resize tbm_surface_queue" );
228   }
229
230   mSurfaceSize.SetWidth( static_cast<uint16_t>( positionSize.width ) );
231   mSurfaceSize.SetHeight( static_cast<uint16_t>( positionSize.height ) );
232 }
233
234 void NativeRenderSurfaceEcoreWl::StartRender()
235 {
236 }
237
238 bool NativeRenderSurfaceEcoreWl::PreRender( bool resizingSurface, const std::vector<Rect<int>>& damagedRects, Rect<int>& clippingRect )
239 {
240   MakeContextCurrent();
241
242   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics*>(mGraphics);
243   if (eglGraphics)
244   {
245     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
246     if (resizingSurface)
247     {
248       eglImpl.SetFullSwapNextFrame();
249     }
250
251     eglImpl.SetDamage(mEGLSurface, damagedRects, clippingRect);
252   }
253
254   return true;
255 }
256
257 void NativeRenderSurfaceEcoreWl::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface, const std::vector<Rect<int>>& damagedRects )
258 {
259   auto eglGraphics = static_cast<Internal::Adaptor::EglGraphics *>(mGraphics);
260   if (eglGraphics)
261   {
262     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
263     eglImpl.SwapBuffers( mEGLSurface, damagedRects );
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   if ( mConsumeSurface )
281   {
282     tbm_surface_internal_ref( mConsumeSurface );
283   }
284
285   if( replacingSurface )
286   {
287     ConditionalWait::ScopedLock lock( mTbmSurfaceCondition );
288     mDrawableCompleted = true;
289     mTbmSurfaceCondition.Notify( lock );
290   }
291
292  // create damage for client applications which wish to know the update timing
293   if( !replacingSurface && mRenderNotification )
294   {
295     // use notification trigger
296     // Tell the event-thread to render the tbm_surface
297     mRenderNotification->Trigger();
298   }
299
300   if( mThreadSynchronization )
301   {
302     // wait until the event-thread completed to use the tbm_surface
303     mThreadSynchronization->PostRenderWaitForCompletion();
304   }
305
306   // release the consumed surface after post render was completed
307   ReleaseDrawable();
308 }
309
310 void NativeRenderSurfaceEcoreWl::StopRender()
311 {
312   ReleaseLock();
313 }
314
315 void NativeRenderSurfaceEcoreWl::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
316 {
317   mThreadSynchronization = &threadSynchronization;
318 }
319
320 Dali::RenderSurfaceInterface::Type NativeRenderSurfaceEcoreWl::GetSurfaceType()
321 {
322   return Dali::RenderSurfaceInterface::NATIVE_RENDER_SURFACE;
323 }
324
325 void NativeRenderSurfaceEcoreWl::MakeContextCurrent()
326 {
327   if ( mEGL != nullptr )
328   {
329     mEGL->MakeContextCurrent( mEGLSurface, mEGLContext );
330   }
331 }
332
333 Integration::DepthBufferAvailable NativeRenderSurfaceEcoreWl::GetDepthBufferRequired()
334 {
335   return mGraphics ? mGraphics->GetDepthBufferRequired() : Integration::DepthBufferAvailable::FALSE;
336 }
337
338 Integration::StencilBufferAvailable NativeRenderSurfaceEcoreWl::GetStencilBufferRequired()
339 {
340   return mGraphics ? mGraphics->GetStencilBufferRequired() : Integration::StencilBufferAvailable::FALSE;
341 }
342
343 void NativeRenderSurfaceEcoreWl::ReleaseLock()
344 {
345   if( mThreadSynchronization )
346   {
347     mThreadSynchronization->PostRenderComplete();
348   }
349 }
350
351 void NativeRenderSurfaceEcoreWl::CreateNativeRenderable()
352 {
353   int width = static_cast<int>( mSurfaceSize.GetWidth() );
354   int height = static_cast<int>( mSurfaceSize.GetHeight() );
355
356   // check we're creating one with a valid size
357   DALI_ASSERT_ALWAYS( width > 0 && height > 0 && "tbm_surface size is invalid" );
358
359   mTbmQueue = tbm_surface_queue_create( 3, width, height, mTbmFormat, TBM_BO_DEFAULT );
360
361   if( mTbmQueue )
362   {
363     mOwnSurface = true;
364   }
365   else
366   {
367     mOwnSurface = false;
368   }
369 }
370
371 void NativeRenderSurfaceEcoreWl::ReleaseDrawable()
372 {
373   if( mConsumeSurface )
374   {
375     tbm_surface_internal_unref( mConsumeSurface );
376
377     if( tbm_surface_internal_is_valid( mConsumeSurface ) )
378     {
379       tbm_surface_queue_release( mTbmQueue, mConsumeSurface );
380     }
381     mConsumeSurface = NULL;
382   }
383 }
384
385 } // namespace Dali