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