2 * Copyright (c) 2017 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>
26 #include <X11/extensions/Xfixes.h> // for damage notify
27 #include <X11/extensions/Xdamage.h> // for damage notify
29 #include <dali/integration-api/gl-abstraction.h>
30 #include <dali/integration-api/debug.h>
31 #include <dali/devel-api/threading/mutex.h>
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>
45 #if defined(DEBUG_ENABLED)
46 Debug::Filter* gPixmapRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_PIXMAP_RENDER_SURFACE_ECORE_X");
51 static const int INITIAL_PRODUCE_BUFFER_INDEX = 0;
52 static const int INITIAL_CONSUME_BUFFER_INDEX = 1;
55 PixmapRenderSurfaceEcoreX::PixmapRenderSurfaceEcoreX(Dali::PositionSize positionSize,
57 const std::string& name,
59 : mPosition( positionSize ),
61 mRenderNotification( NULL ),
62 mColorDepth( isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24 ),
64 mProduceBufferIndex( INITIAL_PRODUCE_BUFFER_INDEX ),
65 mConsumeBufferIndex( INITIAL_CONSUME_BUFFER_INDEX ),
66 mThreadSynchronization(NULL)
68 for( int i = 0; i != BUFFER_COUNT; ++i )
74 Initialize( surface );
77 PixmapRenderSurfaceEcoreX::~PixmapRenderSurfaceEcoreX()
79 // release the surface if we own one
82 for (int i = 0; i < BUFFER_COUNT; ++i)
84 Ecore_X_Pixmap pixmap = mX11Pixmaps[i];
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 );
93 void PixmapRenderSurfaceEcoreX::Initialize( Any surface )
95 // see if there is a surface in Any surface
96 unsigned int surfaceId = GetSurfaceId( surface );
98 // if the surface is empty, create a new one.
101 // we own the surface about to created
107 // XLib should already be initialized so no point in calling XInitThreads
108 UseExistingRenderable( surfaceId );
112 Any PixmapRenderSurfaceEcoreX::GetSurface()
114 Ecore_X_Pixmap pixmap = 0;
116 ConditionalWait::ScopedLock lock( mPixmapCondition );
117 pixmap = mX11Pixmaps[mProduceBufferIndex];
120 return Any( pixmap );
123 void PixmapRenderSurfaceEcoreX::SetRenderNotification(TriggerEventInterface* renderNotification)
125 mRenderNotification = renderNotification;
128 PositionSize PixmapRenderSurfaceEcoreX::GetPositionSize() const
133 void PixmapRenderSurfaceEcoreX::InitializeEgl( EglInterface& egl )
135 DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
137 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
139 eglImpl.ChooseConfig(false, mColorDepth);
142 void PixmapRenderSurfaceEcoreX::CreateEglSurface( EglInterface& egl )
144 DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
146 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
148 for (int i = 0; i < BUFFER_COUNT; ++i)
150 // create the EGL surface
151 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
152 XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[i] );
153 mEglSurfaces[i] = eglImpl.CreateSurfacePixmap( EGLNativePixmapType( pixmap ), mColorDepth ); // reinterpret_cast does not compile
157 void PixmapRenderSurfaceEcoreX::DestroyEglSurface( EglInterface& egl )
159 DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
161 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
163 for (int i = 0; i < BUFFER_COUNT; ++i)
165 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
166 XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[i] );
167 eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mEglSurfaces[i] );
168 eglImpl.DestroySurface();
172 bool PixmapRenderSurfaceEcoreX::ReplaceEGLSurface( EglInterface& egl )
174 DALI_LOG_TRACE_METHOD( gPixmapRenderSurfaceLogFilter );
176 bool contextLost = false;
178 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
180 for (int i = 0; i < BUFFER_COUNT; ++i)
182 // a new surface for the new pixmap
183 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
184 XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[i] );
185 contextLost = eglImpl.ReplaceSurfacePixmap( EGLNativePixmapType( pixmap ), mEglSurfaces[i] ); // reinterpret_cast does not compile
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[mProduceBufferIndex] );
190 eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mEglSurfaces[mProduceBufferIndex] );
195 void PixmapRenderSurfaceEcoreX::StartRender()
199 bool PixmapRenderSurfaceEcoreX::PreRender( EglInterface& egl, Integration::GlAbstraction&, bool )
201 // Nothing to do for pixmaps
205 void PixmapRenderSurfaceEcoreX::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, Dali::DisplayConnection* displayConnection, bool replacingSurface, bool resizingSurface )
207 // flush gl instruction queue
208 glAbstraction.Flush();
210 if( mThreadSynchronization )
212 mThreadSynchronization->PostRenderStarted();
216 ConditionalWait::ScopedLock lock( mPixmapCondition );
217 mConsumeBufferIndex = __sync_fetch_and_xor( &mProduceBufferIndex, 1 ); // Swap buffer indexes.
219 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
221 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
222 XPixmap pixmap = static_cast<XPixmap>( mX11Pixmaps[mProduceBufferIndex] );
223 eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mEglSurfaces[mProduceBufferIndex] );
226 // create damage for client applications which wish to know the update timing
227 if( mRenderNotification )
229 // use notification trigger
230 // Tell the event-thread to render the pixmap
231 mRenderNotification->Trigger();
235 // as a fallback, send damage event.
236 Ecore_X_Drawable drawable = Ecore_X_Drawable( mX11Pixmaps[mProduceBufferIndex] );
241 XserverRegion region;
245 rect.width = mPosition.width;
246 rect.height = mPosition.height;
248 XDisplay* display = AnyCast<XDisplay*>(displayConnection->GetDisplay());
250 // make a fixes region as updated area
251 region = XFixesCreateRegion( display, &rect, 1 );
252 // add damage event to updated drawable
253 Drawable xdrawable( drawable ); // ecore type is unsigned int whereas in 64bit linux Drawable is long unsigned int
254 XDamageAdd( display, xdrawable, region );
255 XFixesDestroyRegion( display, region );
261 if( mThreadSynchronization )
263 mThreadSynchronization->PostRenderWaitForCompletion();
267 void PixmapRenderSurfaceEcoreX::StopRender()
272 void PixmapRenderSurfaceEcoreX::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
274 mThreadSynchronization = &threadSynchronization;
277 void PixmapRenderSurfaceEcoreX::ReleaseLock()
279 if( mThreadSynchronization )
281 mThreadSynchronization->PostRenderComplete();
285 RenderSurface::Type PixmapRenderSurfaceEcoreX::GetSurfaceType()
287 return RenderSurface::PIXMAP_RENDER_SURFACE;
290 void PixmapRenderSurfaceEcoreX::CreateRenderable()
292 // check we're creating one with a valid size
293 DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid" );
295 for (int i = 0; i < BUFFER_COUNT; ++i)
298 mX11Pixmaps[i] = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
301 unsigned int foreground;
304 gc = ecore_x_gc_new( mX11Pixmaps[i],
305 ECORE_X_GC_VALUE_MASK_FOREGROUND,
308 DALI_ASSERT_ALWAYS( gc && "CreateRenderable(): failed to get gc" );
310 ecore_x_drawable_rectangle_fill( mX11Pixmaps[i], gc, 0, 0, mPosition.width, mPosition.height );
312 DALI_ASSERT_ALWAYS( mX11Pixmaps[i] && "Failed to create X pixmap" );
314 // we SHOULD guarantee the xpixmap/x11 window was created in x server.
321 void PixmapRenderSurfaceEcoreX::UseExistingRenderable( unsigned int surfaceId )
325 unsigned int PixmapRenderSurfaceEcoreX::GetSurfaceId( Any surface ) const
327 unsigned int surfaceId = 0;
329 if ( surface.Empty() == false )
331 // check we have a valid type
332 DALI_ASSERT_ALWAYS( ( (surface.GetType() == typeid (XWindow) ) ||
333 (surface.GetType() == typeid (Ecore_X_Window) ) )
334 && "Surface type is invalid" );
336 if ( surface.GetType() == typeid (Ecore_X_Window) )
338 surfaceId = AnyCast<Ecore_X_Window>( surface );
342 surfaceId = AnyCast<XWindow>( surface );
348 } // namespace Adaptor
350 } // namespace internal