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