2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.h>
22 #include <X11/Xatom.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>
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>
46 #if defined(DEBUG_ENABLED)
47 Debug::Filter* gPixmapRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_PIXMAP_RENDER_SURFACE_ECORE_X");
52 static const int INITIAL_PRODUCE_BUFFER_INDEX = 0;
53 static const int INITIAL_CONSUME_BUFFER_INDEX = 1;
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 ),
63 mProduceBufferIndex( INITIAL_PRODUCE_BUFFER_INDEX ),
64 mConsumeBufferIndex( INITIAL_CONSUME_BUFFER_INDEX ),
67 mThreadSynchronization( nullptr ),
70 for( int i = 0; i != BUFFER_COUNT; ++i )
76 Initialize( surface );
79 PixmapRenderSurfaceEcoreX::~PixmapRenderSurfaceEcoreX()
83 // release the surface if we own one
86 for (int i = 0; i < BUFFER_COUNT; ++i)
88 Ecore_X_Pixmap pixmap = mX11Pixmaps[i];
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 );
97 void PixmapRenderSurfaceEcoreX::Initialize( Any surface )
99 // see if there is a surface in Any surface
100 unsigned int surfaceId = GetSurfaceId( surface );
102 // if the surface is empty, create a new one.
103 if ( surfaceId == 0 )
105 // we own the surface about to created
111 // XLib should already be initialized so no point in calling XInitThreads
112 UseExistingRenderable( surfaceId );
116 Any PixmapRenderSurfaceEcoreX::GetSurface()
118 Ecore_X_Pixmap pixmap = 0;
120 ConditionalWait::ScopedLock lock( mPixmapCondition );
121 pixmap = mX11Pixmaps[mProduceBufferIndex];
124 return Any( pixmap );
127 void PixmapRenderSurfaceEcoreX::SetRenderNotification(TriggerEventInterface* renderNotification)
129 mRenderNotification = renderNotification;
132 PositionSize PixmapRenderSurfaceEcoreX::GetPositionSize() const
137 void PixmapRenderSurfaceEcoreX::GetDpi( unsigned int& dpiHorizontal, unsigned int& dpiVertical )
142 // 1 inch = 25.4 millimeters
143 xres = ecore_x_dpi_get();
144 yres = ecore_x_dpi_get();
146 dpiHorizontal = int( xres + 0.5f ); // rounding
147 dpiVertical = int( yres + 0.5f );
150 int PixmapRenderSurfaceEcoreX::GetOrientation() const
155 void PixmapRenderSurfaceEcoreX::InitializeGraphics()
157 mGraphics = &mAdaptor->GetGraphicsInterface();
158 mDisplayConnection = &mAdaptor->GetDisplayConnectionInterface();
161 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
162 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
163 eglImpl.ChooseConfig(false, mColorDepth);
166 void PixmapRenderSurfaceEcoreX::CreateSurface()
168 DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
170 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
171 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
173 for (int i = 0; i < BUFFER_COUNT; ++i)
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
182 void PixmapRenderSurfaceEcoreX::DestroySurface()
184 DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
186 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
188 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
190 for (int i = 0; i < BUFFER_COUNT; ++i)
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] );
199 bool PixmapRenderSurfaceEcoreX::ReplaceGraphicsSurface()
201 DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
203 bool contextLost = false;
205 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
207 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
209 for (int i = 0; i < BUFFER_COUNT; ++i)
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
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] );
224 void PixmapRenderSurfaceEcoreX::StartRender()
228 bool PixmapRenderSurfaceEcoreX::PreRender( bool )
230 // Nothing to do for pixmaps
234 void PixmapRenderSurfaceEcoreX::SetDamagedRect( const Dali::DamagedRect& damagedRect, Dali::DamagedRect& mergedRect )
238 int32_t PixmapRenderSurfaceEcoreX::GetBufferAge()
243 void PixmapRenderSurfaceEcoreX::PostRender( bool renderToFbo, bool replacingSurface, bool resizingSurface )
245 auto eglGraphics = static_cast<EglGraphics *>(mGraphics);
247 // flush gl instruction queue
248 Integration::GlAbstraction& glAbstraction = eglGraphics->GetGlAbstraction();
249 glAbstraction.Flush();
251 if( mThreadSynchronization )
253 mThreadSynchronization->PostRenderStarted();
257 ConditionalWait::ScopedLock lock( mPixmapCondition );
258 mConsumeBufferIndex = __sync_fetch_and_xor( &mProduceBufferIndex, 1 ); // Swap buffer indexes.
260 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
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] );
267 // create damage for client applications which wish to know the update timing
268 if( mRenderNotification )
270 // use notification trigger
271 // Tell the event-thread to render the pixmap
272 mRenderNotification->Trigger();
276 // as a fallback, send damage event.
277 Ecore_X_Drawable drawable = Ecore_X_Drawable( mX11Pixmaps[mProduceBufferIndex] );
282 XserverRegion region;
286 rect.width = mPosition.width;
287 rect.height = mPosition.height;
289 XDisplay* display = AnyCast<XDisplay*>(mDisplayConnection->GetDisplay());
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 );
302 if( mThreadSynchronization )
304 mThreadSynchronization->PostRenderWaitForCompletion();
308 void PixmapRenderSurfaceEcoreX::StopRender()
313 void PixmapRenderSurfaceEcoreX::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
315 mThreadSynchronization = &threadSynchronization;
318 void PixmapRenderSurfaceEcoreX::ReleaseLock()
320 if( mThreadSynchronization )
322 mThreadSynchronization->PostRenderComplete();
326 Integration::RenderSurface::Type PixmapRenderSurfaceEcoreX::GetSurfaceType()
328 return Integration::RenderSurface::PIXMAP_RENDER_SURFACE;
331 void PixmapRenderSurfaceEcoreX::MakeContextCurrent()
335 void PixmapRenderSurfaceEcoreX::CreateRenderable()
337 // check we're creating one with a valid size
338 DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid" );
340 for (int i = 0; i < BUFFER_COUNT; ++i)
343 mX11Pixmaps[i] = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
346 unsigned int foreground;
349 gc = ecore_x_gc_new( mX11Pixmaps[i],
350 ECORE_X_GC_VALUE_MASK_FOREGROUND,
353 DALI_ASSERT_ALWAYS( gc && "CreateRenderable(): failed to get gc" );
355 ecore_x_drawable_rectangle_fill( mX11Pixmaps[i], gc, 0, 0, mPosition.width, mPosition.height );
357 DALI_ASSERT_ALWAYS( mX11Pixmaps[i] && "Failed to create X pixmap" );
359 // we SHOULD guarantee the xpixmap/x11 window was created in x server.
366 void PixmapRenderSurfaceEcoreX::UseExistingRenderable( unsigned int surfaceId )
370 unsigned int PixmapRenderSurfaceEcoreX::GetSurfaceId( Any surface ) const
372 unsigned int surfaceId = 0;
374 if ( surface.Empty() == false )
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" );
381 if ( surface.GetType() == typeid (Ecore_X_Window) )
383 surfaceId = AnyCast<Ecore_X_Window>( surface );
387 surfaceId = AnyCast<XWindow>( surface );
393 } // namespace Adaptor
395 } // namespace internal