[dali_1.3.27] Merge branch 'devel/master'
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / ubuntu-x11 / pixmap-render-surface-ecore-x.cpp
1 /*
2  * Copyright (c) 2017 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/ubuntu-x11/pixmap-render-surface-ecore-x.h>
20
21 // EXTERNAL INCLUDES
22 #include <X11/Xatom.h>
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25
26 #include <X11/extensions/Xfixes.h> // for damage notify
27 #include <X11/extensions/Xdamage.h> // for damage notify
28
29 #include <dali/integration-api/gl-abstraction.h>
30 #include <dali/integration-api/debug.h>
31 #include <dali/devel-api/threading/mutex.h>
32
33 // INTERNAL INCLUDES
34 #include <dali/integration-api/thread-synchronization-interface.h>
35 #include <dali/internal/system/common/trigger-event.h>
36 #include <dali/internal/window-system/common/display-connection.h>
37
38 namespace Dali
39 {
40 namespace Internal
41 {
42 namespace Adaptor
43 {
44
45 #if defined(DEBUG_ENABLED)
46 Debug::Filter* gPixmapRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_PIXMAP_RENDER_SURFACE_ECORE_X");
47 #endif
48
49 namespace
50 {
51 static const int INITIAL_PRODUCE_BUFFER_INDEX = 0;
52 static const int INITIAL_CONSUME_BUFFER_INDEX = 1;
53 }
54
55 PixmapRenderSurfaceEcoreX::PixmapRenderSurfaceEcoreX( Dali::PositionSize positionSize, Any surface, bool isTransparent )
56 : mPosition( positionSize ),
57   mRenderNotification( NULL ),
58   mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
59   mOwnSurface( false ),
60   mProduceBufferIndex( INITIAL_PRODUCE_BUFFER_INDEX ),
61   mConsumeBufferIndex( INITIAL_CONSUME_BUFFER_INDEX ),
62   mThreadSynchronization(NULL)
63 {
64   for( int i = 0; i != BUFFER_COUNT; ++i )
65   {
66     mX11Pixmaps[i] = 0;
67     mEglSurfaces[i] = 0;
68   }
69
70   Initialize( surface );
71 }
72
73 PixmapRenderSurfaceEcoreX::~PixmapRenderSurfaceEcoreX()
74 {
75   // release the surface if we own one
76   if( mOwnSurface )
77   {
78     for (int i = 0; i < BUFFER_COUNT; ++i)
79     {
80       Ecore_X_Pixmap pixmap = mX11Pixmaps[i];
81
82       // if we did create the pixmap, delete the pixmap
83       DALI_LOG_INFO( gPixmapRenderSurfaceLogFilter, Debug::General, "Own pixmap (%x) freed\n", pixmap );
84       ecore_x_pixmap_free( pixmap );
85     }
86   }
87 }
88
89 void PixmapRenderSurfaceEcoreX::Initialize( Any surface )
90 {
91   // see if there is a surface in Any surface
92   unsigned int surfaceId  = GetSurfaceId( surface );
93
94   // if the surface is empty, create a new one.
95   if ( surfaceId == 0 )
96   {
97     // we own the surface about to created
98     mOwnSurface = true;
99     CreateRenderable();
100   }
101   else
102   {
103     // XLib should already be initialized so no point in calling XInitThreads
104     UseExistingRenderable( surfaceId );
105   }
106 }
107
108 Any PixmapRenderSurfaceEcoreX::GetSurface()
109 {
110   Ecore_X_Pixmap pixmap = 0;
111   {
112     ConditionalWait::ScopedLock lock( mPixmapCondition );
113     pixmap = mX11Pixmaps[mProduceBufferIndex];
114   }
115
116   return Any( pixmap );
117 }
118
119 void PixmapRenderSurfaceEcoreX::SetRenderNotification(TriggerEventInterface* renderNotification)
120 {
121   mRenderNotification = renderNotification;
122 }
123
124 PositionSize PixmapRenderSurfaceEcoreX::GetPositionSize() const
125 {
126   return mPosition;
127 }
128
129 void PixmapRenderSurfaceEcoreX::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
130 {
131   // calculate DPI
132   float xres, yres;
133
134   // 1 inch = 25.4 millimeters
135   xres = ecore_x_dpi_get();
136   yres = ecore_x_dpi_get();
137
138   dpiHorizontal = int( xres + 0.5f );  // rounding
139   dpiVertical   = int( yres + 0.5f );
140 }
141
142 void PixmapRenderSurfaceEcoreX::InitializeEgl( EglInterface& egl )
143 {
144   DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
145
146   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
147
148   eglImpl.ChooseConfig(false, mColorDepth);
149 }
150
151 void PixmapRenderSurfaceEcoreX::CreateEglSurface( EglInterface& egl )
152 {
153   DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
154
155   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
156
157   for (int i = 0; i < BUFFER_COUNT; ++i)
158   {
159     // create the EGL surface
160     // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
161     XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[i] );
162     mEglSurfaces[i] = eglImpl.CreateSurfacePixmap( EGLNativePixmapType( pixmap ), mColorDepth ); // reinterpret_cast does not compile
163   }
164 }
165
166 void PixmapRenderSurfaceEcoreX::DestroyEglSurface( EglInterface& egl )
167 {
168   DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
169
170   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
171
172   for (int i = 0; i < BUFFER_COUNT; ++i)
173   {
174     // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
175     XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[i] );
176     eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mEglSurfaces[i] );
177     eglImpl.DestroySurface();
178   }
179 }
180
181 bool PixmapRenderSurfaceEcoreX::ReplaceEGLSurface( EglInterface& egl )
182 {
183   DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
184
185   bool contextLost = false;
186
187   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
188
189   for (int i = 0; i < BUFFER_COUNT; ++i)
190   {
191     // a new surface for the new pixmap
192     // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
193     XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[i] );
194     contextLost = eglImpl.ReplaceSurfacePixmap( EGLNativePixmapType( pixmap ), mEglSurfaces[i] ); // reinterpret_cast does not compile
195   }
196
197   // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
198   XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[mProduceBufferIndex] );
199   eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mEglSurfaces[mProduceBufferIndex] );
200
201   return contextLost;
202 }
203
204 void PixmapRenderSurfaceEcoreX::StartRender()
205 {
206 }
207
208 bool PixmapRenderSurfaceEcoreX::PreRender( EglInterface& egl, Integration::GlAbstraction&, bool )
209 {
210   // Nothing to do for pixmaps
211   return true;
212 }
213
214 void PixmapRenderSurfaceEcoreX::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, Dali::DisplayConnection* displayConnection, bool replacingSurface, bool resizingSurface )
215 {
216   // flush gl instruction queue
217   glAbstraction.Flush();
218
219   if( mThreadSynchronization )
220   {
221     mThreadSynchronization->PostRenderStarted();
222   }
223
224   {
225     ConditionalWait::ScopedLock lock( mPixmapCondition );
226     mConsumeBufferIndex = __sync_fetch_and_xor( &mProduceBufferIndex, 1 ); // Swap buffer indexes.
227
228     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
229
230     // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
231     XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[mProduceBufferIndex] );
232     eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mEglSurfaces[mProduceBufferIndex] );
233   }
234
235   // create damage for client applications which wish to know the update timing
236   if( mRenderNotification )
237   {
238     // use notification trigger
239     // Tell the event-thread to render the pixmap
240     mRenderNotification->Trigger();
241   }
242   else
243   {
244     // as a fallback, send damage event.
245     Ecore_X_Drawable drawable = Ecore_X_Drawable( mX11Pixmaps[mProduceBufferIndex] );
246
247     if( drawable )
248     {
249       XRectangle rect;
250       XserverRegion region;
251
252       rect.x = 0;
253       rect.y = 0;
254       rect.width = mPosition.width;
255       rect.height = mPosition.height;
256
257       XDisplay* display = AnyCast<XDisplay*>(displayConnection->GetDisplay());
258
259       // make a fixes region as updated area
260       region = XFixesCreateRegion( display, &rect, 1 );
261       // add damage event to updated drawable
262       Drawable xdrawable( drawable ); // ecore type is unsigned int whereas in 64bit linux Drawable is long unsigned int
263       XDamageAdd( display, xdrawable, region );
264       XFixesDestroyRegion( display, region );
265
266       XFlush( display );
267     }
268   }
269
270   if( mThreadSynchronization )
271   {
272     mThreadSynchronization->PostRenderWaitForCompletion();
273   }
274 }
275
276 void PixmapRenderSurfaceEcoreX::StopRender()
277 {
278   ReleaseLock();
279 }
280
281 void PixmapRenderSurfaceEcoreX::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
282 {
283   mThreadSynchronization = &threadSynchronization;
284 }
285
286 void PixmapRenderSurfaceEcoreX::ReleaseLock()
287 {
288   if( mThreadSynchronization )
289   {
290     mThreadSynchronization->PostRenderComplete();
291   }
292 }
293
294 RenderSurface::Type PixmapRenderSurfaceEcoreX::GetSurfaceType()
295 {
296   return RenderSurface::PIXMAP_RENDER_SURFACE;
297 }
298
299 void PixmapRenderSurfaceEcoreX::CreateRenderable()
300 {
301   // check we're creating one with a valid size
302   DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid" );
303
304   for (int i = 0; i < BUFFER_COUNT; ++i)
305   {
306     // create the pixmap
307     mX11Pixmaps[i] = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
308
309     // clear the pixmap
310     unsigned int foreground;
311     Ecore_X_GC gc;
312     foreground = 0;
313     gc = ecore_x_gc_new( mX11Pixmaps[i],
314                          ECORE_X_GC_VALUE_MASK_FOREGROUND,
315                          &foreground );
316
317     DALI_ASSERT_ALWAYS( gc && "CreateRenderable(): failed to get gc" );
318
319     ecore_x_drawable_rectangle_fill( mX11Pixmaps[i], gc, 0, 0, mPosition.width, mPosition.height );
320
321     DALI_ASSERT_ALWAYS( mX11Pixmaps[i] && "Failed to create X pixmap" );
322
323     // we SHOULD guarantee the xpixmap/x11 window was created in x server.
324     ecore_x_sync();
325
326     ecore_x_gc_free(gc);
327   }
328 }
329
330 void PixmapRenderSurfaceEcoreX::UseExistingRenderable( unsigned int surfaceId )
331 {
332 }
333
334 unsigned int PixmapRenderSurfaceEcoreX::GetSurfaceId( Any surface ) const
335 {
336   unsigned int surfaceId = 0;
337
338   if ( surface.Empty() == false )
339   {
340     // check we have a valid type
341     DALI_ASSERT_ALWAYS( ( (surface.GetType() == typeid (XWindow) ) ||
342                           (surface.GetType() == typeid (Ecore_X_Window) ) )
343                         && "Surface type is invalid" );
344
345     if ( surface.GetType() == typeid (Ecore_X_Window) )
346     {
347       surfaceId = AnyCast<Ecore_X_Window>( surface );
348     }
349     else
350     {
351       surfaceId = AnyCast<XWindow>( surface );
352     }
353   }
354   return surfaceId;
355 }
356
357 } // namespace Adaptor
358
359 } // namespace internal
360
361 } // namespace Dali