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