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