787507fd35f3895256b81b0375253b059cd3af8f
[platform/core/uifw/dali-adaptor.git] / adaptors / tizen / native-render-surface-tizen.cpp
1 /*
2  * Copyright (c) 2016 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 <native-render-surface.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/integration-api/gl-abstraction.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/devel-api/threading/conditional-wait.h>
25
26 #include <Ecore_Wayland.h>
27 #include <tbm_bufmgr.h>
28 #include <tbm_surface_queue.h>
29 #include <tbm_surface_internal.h>
30
31 // INTERNAL INCLUDES
32 #include <trigger-event.h>
33 #include <gl/egl-implementation.h>
34 #include <base/display-connection.h>
35 #include <integration-api/thread-synchronization-interface.h>
36
37 namespace Dali
38 {
39
40 #if defined(DEBUG_ENABLED)
41 extern Debug::Filter* gRenderSurfaceLogFilter;
42 #endif
43
44 struct NativeRenderSurface::Impl
45 {
46   Impl( Dali::PositionSize positionSize, const std::string& name, bool isTransparent )
47   : mPosition( positionSize ),
48     mTitle( name ),
49     mRenderNotification( NULL ),
50     mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
51     mTbmFormat( isTransparent ? TBM_FORMAT_ARGB8888 : TBM_FORMAT_RGB888 ),
52     mOwnSurface( false ),
53     mDrawableCompleted( false ),
54     mConsumeSurface( NULL ),
55     mThreadSynchronization( NULL )
56   {
57   }
58
59   PositionSize mPosition;
60   std::string mTitle;
61   TriggerEventInterface* mRenderNotification;
62   ColorDepth mColorDepth;
63   tbm_format mTbmFormat;
64   bool mOwnSurface;
65   bool mDrawableCompleted;
66
67   tbm_surface_queue_h mTbmQueue;
68   tbm_surface_h mConsumeSurface;
69   ThreadSynchronizationInterface* mThreadSynchronization;     ///< A pointer to the thread-synchronization
70   ConditionalWait mTbmSurfaceCondition;
71 };
72
73 NativeRenderSurface::NativeRenderSurface(Dali::PositionSize positionSize,
74                                          const std::string& name,
75                                          bool isTransparent)
76 : mImpl( new Impl( positionSize, name, isTransparent ) )
77 {
78   ecore_wl_init(NULL);
79   CreateNativeRenderable();
80   setenv( "EGL_PLATFORM", "tbm", 1 );
81 }
82
83 NativeRenderSurface::~NativeRenderSurface()
84 {
85   // release the surface if we own one
86   if( mImpl->mOwnSurface )
87   {
88     ReleaseDrawable();
89
90     if( mImpl->mTbmQueue )
91     {
92       tbm_surface_queue_destroy( mImpl->mTbmQueue );
93     }
94
95     delete mImpl;
96
97     DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::General, "Own tbm surface queue destroy\n" );
98   }
99 }
100
101 void NativeRenderSurface::SetRenderNotification( TriggerEventInterface* renderNotification )
102 {
103   mImpl->mRenderNotification = renderNotification;
104 }
105
106 tbm_surface_h NativeRenderSurface::GetDrawable()
107 {
108   return mImpl->mConsumeSurface;
109 }
110
111 Any NativeRenderSurface::GetSurface()
112 {
113   return Any( NULL );
114 }
115
116 void NativeRenderSurface::InitializeEgl( EglInterface& egl )
117 {
118   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
119   unsetenv( "EGL_PLATFORM" );
120
121   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
122
123   eglImpl.ChooseConfig( true, mImpl->mColorDepth );
124 }
125
126 void NativeRenderSurface::CreateEglSurface( EglInterface& egl )
127 {
128   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
129
130   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
131
132   eglImpl.CreateSurfaceWindow( (EGLNativeWindowType)mImpl->mTbmQueue, mImpl->mColorDepth );
133 }
134
135 void NativeRenderSurface::DestroyEglSurface( EglInterface& egl )
136 {
137   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
138
139   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
140   eglImpl.DestroySurface();
141 }
142
143 bool NativeRenderSurface::ReplaceEGLSurface( EglInterface& egl )
144 {
145   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
146
147   if( !mImpl->mTbmQueue )
148   {
149     return false;
150   }
151
152   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
153
154   return eglImpl.ReplaceSurfaceWindow( (EGLNativeWindowType)mImpl->mTbmQueue ); // reinterpret_cast does not compile
155 }
156
157 void NativeRenderSurface::StartRender()
158 {
159 }
160
161 bool NativeRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
162 {
163   // nothing to do for pixmaps
164   return true;
165 }
166
167 void NativeRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
168 {
169   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
170   eglImpl.SwapBuffers();
171
172   if( mImpl->mThreadSynchronization )
173   {
174     mImpl->mThreadSynchronization->PostRenderStarted();
175   }
176
177   if( tbm_surface_queue_can_acquire( mImpl->mTbmQueue, 1 ) )
178   {
179     if( tbm_surface_queue_acquire( mImpl->mTbmQueue, &mImpl->mConsumeSurface ) != TBM_SURFACE_QUEUE_ERROR_NONE )
180     {
181       DALI_LOG_ERROR( "Failed to aquire a tbm_surface\n" );
182       return;
183     }
184   }
185
186   tbm_surface_internal_ref( mImpl->mConsumeSurface );
187
188   if( replacingSurface )
189   {
190     ConditionalWait::ScopedLock lock( mImpl->mTbmSurfaceCondition );
191     mImpl->mDrawableCompleted = true;
192     mImpl->mTbmSurfaceCondition.Notify( lock );
193   }
194
195  // create damage for client applications which wish to know the update timing
196   if( !replacingSurface && mImpl->mRenderNotification )
197   {
198     // use notification trigger
199     // Tell the event-thread to render the tbm_surface
200     mImpl->mRenderNotification->Trigger();
201   }
202
203   if( mImpl->mThreadSynchronization )
204   {
205     // wait until the event-thread completed to use the tbm_surface
206     mImpl->mThreadSynchronization->PostRenderWaitForCompletion();
207   }
208
209   // release the consumed surface after post render was completed
210   ReleaseDrawable();
211 }
212
213 void NativeRenderSurface::StopRender()
214 {
215   ReleaseLock();
216 }
217
218 PositionSize NativeRenderSurface::GetPositionSize() const
219 {
220   return mImpl->mPosition;
221 }
222
223 void NativeRenderSurface::MoveResize( Dali::PositionSize positionSize )
224 {
225 }
226
227 void NativeRenderSurface::SetViewMode( ViewMode viewMode )
228 {
229 }
230
231 void NativeRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
232 {
233   mImpl->mThreadSynchronization = &threadSynchronization;
234 }
235
236 RenderSurface::Type NativeRenderSurface::GetSurfaceType()
237 {
238   return RenderSurface::NATIVE_RENDER_SURFACE;
239 }
240
241 void NativeRenderSurface::CreateNativeRenderable()
242 {
243   // check we're creating one with a valid size
244   DALI_ASSERT_ALWAYS( mImpl->mPosition.width > 0 && mImpl->mPosition.height > 0 && "tbm_surface size is invalid" );
245
246   mImpl->mTbmQueue = tbm_surface_queue_create( 3, mImpl->mPosition.width, mImpl->mPosition.height, mImpl->mTbmFormat, TBM_BO_DEFAULT );
247
248   if( mImpl->mTbmQueue )
249   {
250     mImpl->mOwnSurface = true;
251   }
252   else
253   {
254     mImpl->mOwnSurface = false;
255   }
256 }
257
258 void NativeRenderSurface::ReleaseLock()
259 {
260   if( mImpl->mThreadSynchronization )
261   {
262     mImpl->mThreadSynchronization->PostRenderComplete();
263   }
264 }
265
266 void NativeRenderSurface::WaitUntilSurfaceReplaced()
267 {
268   ConditionalWait::ScopedLock lock( mImpl->mTbmSurfaceCondition );
269   while( !mImpl->mDrawableCompleted )
270   {
271     mImpl->mTbmSurfaceCondition.Wait( lock );
272   }
273
274   mImpl->mDrawableCompleted = false;
275 }
276
277 void NativeRenderSurface::ReleaseDrawable()
278 {
279   if( mImpl->mConsumeSurface )
280   {
281     tbm_surface_internal_unref( mImpl->mConsumeSurface );
282
283     if( tbm_surface_internal_is_valid( mImpl->mConsumeSurface ) )
284     {
285       tbm_surface_queue_release( mImpl->mTbmQueue, mImpl->mConsumeSurface );
286     }
287     mImpl->mConsumeSurface = NULL;
288   }
289 }
290
291 } // namespace Dali