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 "pixmap-render-surface.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>
32 #include <dali/devel-api/threading/conditional-wait.h>
36 #include <integration-api/thread-synchronization-interface.h>
37 #include <ecore-x-types.h>
38 #include <trigger-event.h>
39 #include <gl/egl-implementation.h>
40 #include <base/display-connection.h>
45 #if defined(DEBUG_ENABLED)
46 extern Debug::Filter* gRenderSurfaceLogFilter;
54 static const int INITIAL_PRODUCE_BUFFER_INDEX = 0;
55 static const int INITIAL_CONSUME_BUFFER_INDEX = 1;
56 static const int BUFFER_COUNT = 2;
59 struct PixmapRenderSurface::Impl
62 : mProduceBufferIndex( INITIAL_PRODUCE_BUFFER_INDEX ),
63 mConsumeBufferIndex( INITIAL_CONSUME_BUFFER_INDEX ),
64 mThreadSynchronization(NULL)
66 for (int i = 0; i != BUFFER_COUNT; ++i)
73 int mProduceBufferIndex;
74 int mConsumeBufferIndex;
75 XPixmap mX11Pixmaps[BUFFER_COUNT]; ///< X-Pixmap
76 EGLSurface mEglSurfaces[BUFFER_COUNT];
77 ThreadSynchronizationInterface* mThreadSynchronization; ///< A pointer to the thread-synchronization
78 ConditionalWait mPixmapCondition; ///< condition to share pixmap
81 PixmapRenderSurface::PixmapRenderSurface(Dali::PositionSize positionSize,
83 const std::string& name,
85 : EcoreXRenderSurface( positionSize, surface, name, isTransparent ),
91 PixmapRenderSurface::~PixmapRenderSurface()
93 // release the surface if we own one
96 for (int i = 0; i < BUFFER_COUNT; ++i)
98 Ecore_X_Pixmap pixmap = mImpl->mX11Pixmaps[i];
100 // if we did create the pixmap, delete the pixmap
101 DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::General, "Own pixmap (%x) freed\n", pixmap );
102 ecore_x_pixmap_free( pixmap );
109 Ecore_X_Drawable PixmapRenderSurface::GetDrawable()
111 Ecore_X_Pixmap pixmap = 0;
113 ConditionalWait::ScopedLock lock( mImpl->mPixmapCondition );
114 pixmap = mImpl->mX11Pixmaps[mImpl->mConsumeBufferIndex];
117 return Ecore_X_Drawable( pixmap );
120 Any PixmapRenderSurface::GetSurface()
122 Ecore_X_Pixmap pixmap = 0;
124 ConditionalWait::ScopedLock lock( mImpl->mPixmapCondition );
125 pixmap = mImpl->mX11Pixmaps[mImpl->mProduceBufferIndex];
128 return Any( pixmap );
131 void PixmapRenderSurface::InitializeEgl( EglInterface& egl )
133 DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
135 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
137 eglImpl.ChooseConfig(false, mColorDepth);
140 void PixmapRenderSurface::CreateEglSurface( EglInterface& egl )
142 DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
144 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
146 for (int i = 0; i < BUFFER_COUNT; ++i)
148 // create the EGL surface
149 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
150 XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmaps[i] );
151 mImpl->mEglSurfaces[i] = eglImpl.CreateSurfacePixmap( EGLNativePixmapType( pixmap ), mColorDepth ); // reinterpret_cast does not compile
155 void PixmapRenderSurface::DestroyEglSurface( EglInterface& egl )
157 DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
159 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
161 for (int i = 0; i < BUFFER_COUNT; ++i)
163 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
164 XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmaps[i] );
165 eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mImpl->mEglSurfaces[i] );
166 eglImpl.DestroySurface();
170 bool PixmapRenderSurface::ReplaceEGLSurface( EglInterface& egl )
172 DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
174 bool contextLost = false;
176 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
178 for (int i = 0; i < BUFFER_COUNT; ++i)
180 // a new surface for the new pixmap
181 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
182 XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmaps[i] );
183 contextLost = eglImpl.ReplaceSurfacePixmap( EGLNativePixmapType( pixmap ), mImpl->mEglSurfaces[i] ); // reinterpret_cast does not compile
186 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
187 XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmaps[mImpl->mProduceBufferIndex] );
188 eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mImpl->mEglSurfaces[mImpl->mProduceBufferIndex] );
193 void PixmapRenderSurface::StartRender()
197 bool PixmapRenderSurface::PreRender( EglInterface& egl, Integration::GlAbstraction& )
199 // Nothing to do for pixmaps
203 void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
205 // flush gl instruction queue
206 glAbstraction.Flush();
208 if( mImpl->mThreadSynchronization )
210 mImpl->mThreadSynchronization->PostRenderStarted();
214 ConditionalWait::ScopedLock lock( mImpl->mPixmapCondition );
215 mImpl->mConsumeBufferIndex = __sync_fetch_and_xor( &mImpl->mProduceBufferIndex, 1 ); // Swap buffer indexes.
217 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
219 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
220 XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmaps[mImpl->mProduceBufferIndex] );
221 eglImpl.MakeCurrent( EGLNativePixmapType( pixmap ), mImpl->mEglSurfaces[mImpl->mProduceBufferIndex] );
224 // create damage for client applications which wish to know the update timing
225 if( mRenderNotification )
227 // use notification trigger
228 // Tell the event-thread to render the pixmap
229 mRenderNotification->Trigger();
233 // as a fallback, send damage event.
234 Ecore_X_Drawable drawable = Ecore_X_Drawable( mImpl->mX11Pixmaps[mImpl->mProduceBufferIndex] );
239 XserverRegion region;
243 rect.width = mPosition.width;
244 rect.height = mPosition.height;
246 XDisplay* display = AnyCast<XDisplay*>(displayConnection->GetDisplay());
248 // make a fixes region as updated area
249 region = XFixesCreateRegion( display, &rect, 1 );
250 // add damage event to updated drawable
251 Drawable xdrawable( drawable ); // ecore type is unsigned int whereas in 64bit linux Drawable is long unsigned int
252 XDamageAdd( display, xdrawable, region );
253 XFixesDestroyRegion( display, region );
259 if( mImpl->mThreadSynchronization )
261 mImpl->mThreadSynchronization->PostRenderWaitForCompletion();
265 void PixmapRenderSurface::StopRender()
270 void PixmapRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
272 mImpl->mThreadSynchronization = &threadSynchronization;
275 void PixmapRenderSurface::CreateXRenderable()
277 // check we're creating one with a valid size
278 DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid" );
280 for (int i = 0; i < BUFFER_COUNT; ++i)
283 mImpl->mX11Pixmaps[i] = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
286 unsigned int foreground;
289 gc = ecore_x_gc_new( mImpl->mX11Pixmaps[i],
290 ECORE_X_GC_VALUE_MASK_FOREGROUND,
293 DALI_ASSERT_ALWAYS( gc && "CreateXRenderable(): failed to get gc" );
295 ecore_x_drawable_rectangle_fill( mImpl->mX11Pixmaps[i], gc, 0, 0, mPosition.width, mPosition.height );
297 DALI_ASSERT_ALWAYS( mImpl->mX11Pixmaps[i] && "Failed to create X pixmap" );
299 // we SHOULD guarantee the xpixmap/x11 window was created in x server.
306 void PixmapRenderSurface::UseExistingRenderable( unsigned int surfaceId )
310 void PixmapRenderSurface::ReleaseLock()
312 if( mImpl->mThreadSynchronization )
314 mImpl->mThreadSynchronization->PostRenderComplete();
318 RenderSurface::Type PixmapRenderSurface::GetSurfaceType()
320 return RenderSurface::ECORE_RENDER_SURFACE;