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