2 * Copyright (c) 2014 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/common/mutex.h>
35 #include <ecore-x-types.h>
36 #include <trigger-event.h>
37 #include <gl/egl-implementation.h>
38 #include <base/display-connection.h>
39 #include <base/conditional-wait.h>
45 #if defined(DEBUG_ENABLED)
46 extern Debug::Filter* gRenderSurfaceLogFilter;
53 struct PixmapRenderSurface::Impl
55 Internal::Adaptor::ConditionalWait mSyncNotify; ///< condition to notify main thread that pixmap was flushed to onscreen
56 Dali::Mutex mSyncMutex; ///< mutex to lock during waiting sync
57 Ecore_X_Pixmap mX11Pixmap; ///< X-Pixmap
58 SyncMode mSyncMode; ///< Stores whether the post render should block waiting for compositor
59 bool mSyncReceived; ///< true, when a pixmap sync has occurred, (cleared after reading)
62 PixmapRenderSurface::PixmapRenderSurface(Dali::PositionSize positionSize,
64 const std::string& name,
66 : EcoreXRenderSurface( positionSize, surface, name, isTransparent ),
69 mImpl->mSyncMode = SYNC_MODE_NONE;
70 mImpl->mSyncReceived = false;
74 PixmapRenderSurface::~PixmapRenderSurface()
76 // release the surface if we own one
79 // if we did create the pixmap, delete the pixmap
80 DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::General, "Own pixmap (%x) freed\n", mImpl->mX11Pixmap );
81 ecore_x_pixmap_free( mImpl->mX11Pixmap );
87 Ecore_X_Drawable PixmapRenderSurface::GetDrawable()
89 return (Ecore_X_Drawable) mImpl->mX11Pixmap;
92 Any PixmapRenderSurface::GetSurface()
94 return Any( mImpl->mX11Pixmap );
97 void PixmapRenderSurface::InitializeEgl( EglInterface& egl )
99 DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
101 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
103 eglImpl.ChooseConfig(false, mColorDepth);
106 void PixmapRenderSurface::CreateEglSurface( EglInterface& egl )
108 DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
110 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
112 // create the EGL surface
113 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
114 XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmap );
115 eglImpl.CreateSurfacePixmap( (EGLNativePixmapType)pixmap, mColorDepth ); // reinterpret_cast does not compile
118 void PixmapRenderSurface::DestroyEglSurface( EglInterface& egl )
120 DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
122 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
123 eglImpl.DestroySurface();
126 bool PixmapRenderSurface::ReplaceEGLSurface( EglInterface& egl )
128 DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
130 // a new surface for the new pixmap
131 // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
132 XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmap );
133 Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
135 return eglImpl.ReplaceSurfacePixmap( (EGLNativePixmapType)pixmap ); // reinterpret_cast does not compile
139 void PixmapRenderSurface::StartRender()
141 mImpl->mSyncMode = SYNC_MODE_WAIT;
144 bool PixmapRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
146 // nothing to do for pixmaps
150 void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, unsigned int deltaTime, bool replacingSurface )
152 // flush gl instruction queue
153 glAbstraction.Flush();
155 // create damage for client applications which wish to know the update timing
156 if( mRenderNotification )
158 // use notification trigger
159 // Tell the event-thread to render the pixmap
160 mRenderNotification->Trigger();
164 // as a fallback, send damage event.
165 Ecore_X_Drawable drawable = GetDrawable();
170 XserverRegion region;
174 rect.width = mPosition.width;
175 rect.height = mPosition.height;
177 XDisplay* display = AnyCast<XDisplay*>(displayConnection->GetDisplay());
179 // make a fixes region as updated area
180 region = XFixesCreateRegion( display, &rect, 1 );
181 // add damage event to updated drawable
182 XDamageAdd( display, (Drawable)drawable, region );
183 XFixesDestroyRegion( display, region );
189 AcquireLock( replacingSurface ? SYNC_MODE_NONE : SYNC_MODE_WAIT );
192 void PixmapRenderSurface::StopRender()
194 SetSyncMode(SYNC_MODE_NONE);
198 void PixmapRenderSurface::CreateXRenderable()
200 // check we're creating one with a valid size
201 DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid" );
204 mImpl->mX11Pixmap = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
207 unsigned int foreground;
210 gc = ecore_x_gc_new( mImpl->mX11Pixmap,
211 ECORE_X_GC_VALUE_MASK_FOREGROUND,
214 DALI_ASSERT_ALWAYS( gc && "CreateXRenderable(): failed to get gc" );
216 ecore_x_drawable_rectangle_fill( mImpl->mX11Pixmap, gc, 0, 0, mPosition.width, mPosition.height );
218 DALI_ASSERT_ALWAYS( mImpl->mX11Pixmap && "Failed to create X pixmap" );
220 // we SHOULD guarantee the xpixmap/x11 window was created in x server.
226 void PixmapRenderSurface::UseExistingRenderable( unsigned int surfaceId )
228 mImpl->mX11Pixmap = static_cast< Ecore_X_Pixmap >( surfaceId );
231 void PixmapRenderSurface::SetSyncMode( SyncMode syncMode )
233 mImpl->mSyncMode = syncMode;
236 void PixmapRenderSurface::AcquireLock( SyncMode syncMode )
238 Dali::Mutex::ScopedLock lock( mImpl->mSyncMutex );
241 if( syncMode != SYNC_MODE_NONE &&
242 mImpl->mSyncMode != SYNC_MODE_NONE &&
243 !mImpl->mSyncReceived )
245 mImpl->mSyncNotify.Wait( );
247 mImpl->mSyncReceived = false;
250 void PixmapRenderSurface::ReleaseLock()
253 Dali::Mutex::ScopedLock lock( mImpl->mSyncMutex );
254 mImpl->mSyncReceived = true;
257 // wake render thread if it was waiting for the notify
258 mImpl->mSyncNotify.Notify();