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