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