Merge "Fix for thread contention issues in FrameTime object." into devel/master
[platform/core/uifw/dali-adaptor.git] / adaptors / x11 / pixmap-render-surface-x.cpp
1 /*
2  * Copyright (c) 2014 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 "pixmap-render-surface.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/common/mutex.h>
32
33 // INTERNAL INCLUDES
34
35 #include <integration-api/thread-synchronization-interface.h>
36 #include <ecore-x-types.h>
37 #include <trigger-event.h>
38 #include <gl/egl-implementation.h>
39 #include <base/display-connection.h>
40 #include <base/conditional-wait.h>
41
42 namespace Dali
43 {
44
45 #if defined(DEBUG_ENABLED)
46 extern Debug::Filter* gRenderSurfaceLogFilter;
47 #endif
48
49 namespace ECore
50 {
51
52 struct PixmapRenderSurface::Impl
53 {
54   Ecore_X_Pixmap                  mX11Pixmap;             ///< X-Pixmap
55   ThreadSynchronizationInterface* mThreadSynchronization; ///< A pointer to the thread-synchronization
56 };
57
58 PixmapRenderSurface::PixmapRenderSurface(Dali::PositionSize positionSize,
59                                          Any surface,
60                                          const std::string& name,
61                                          bool isTransparent)
62 : EcoreXRenderSurface( positionSize, surface, name, isTransparent ),
63   mImpl( new Impl )
64 {
65   mImpl->mThreadSynchronization = NULL;
66   Init( surface );
67 }
68
69 PixmapRenderSurface::~PixmapRenderSurface()
70 {
71   // release the surface if we own one
72   if( mOwnSurface )
73   {
74     // if we did create the pixmap, delete the pixmap
75     DALI_LOG_INFO( gRenderSurfaceLogFilter, Debug::General, "Own pixmap (%x) freed\n", mImpl->mX11Pixmap );
76     ecore_x_pixmap_free( mImpl->mX11Pixmap );
77   }
78
79   delete mImpl;
80 }
81
82 Ecore_X_Drawable PixmapRenderSurface::GetDrawable()
83 {
84   return (Ecore_X_Drawable) mImpl->mX11Pixmap;
85 }
86
87 Any PixmapRenderSurface::GetSurface()
88 {
89   return Any( mImpl->mX11Pixmap );
90 }
91
92 void PixmapRenderSurface::InitializeEgl( EglInterface& egl )
93 {
94   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
95
96   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
97
98   eglImpl.ChooseConfig(false, mColorDepth);
99 }
100
101 void PixmapRenderSurface::CreateEglSurface( EglInterface& egl )
102 {
103   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
104
105   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
106
107   // create the EGL surface
108   // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
109   XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmap );
110   eglImpl.CreateSurfacePixmap( (EGLNativePixmapType)pixmap, mColorDepth ); // reinterpret_cast does not compile
111 }
112
113 void PixmapRenderSurface::DestroyEglSurface( EglInterface& egl )
114 {
115   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
116
117   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
118   eglImpl.DestroySurface();
119 }
120
121 bool PixmapRenderSurface::ReplaceEGLSurface( EglInterface& egl )
122 {
123   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
124
125   // a new surface for the new pixmap
126   // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
127   XPixmap pixmap = static_cast<XPixmap>( mImpl->mX11Pixmap );
128   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
129
130   return eglImpl.ReplaceSurfacePixmap( (EGLNativePixmapType)pixmap ); // reinterpret_cast does not compile
131
132 }
133
134 void PixmapRenderSurface::StartRender()
135 {
136 }
137
138 bool PixmapRenderSurface::PreRender( EglInterface&, Integration::GlAbstraction& )
139 {
140   // nothing to do for pixmaps
141   return true;
142 }
143
144 void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
145 {
146   // flush gl instruction queue
147   glAbstraction.Flush();
148
149   if( mImpl->mThreadSynchronization )
150   {
151     mImpl->mThreadSynchronization->PostRenderStarted();
152   }
153
154   // create damage for client applications which wish to know the update timing
155   if( mRenderNotification )
156   {
157     // use notification trigger
158     // Tell the event-thread to render the pixmap
159     mRenderNotification->Trigger();
160   }
161   else
162   {
163     // as a fallback, send damage event.
164     Ecore_X_Drawable drawable = GetDrawable();
165
166     if( drawable )
167     {
168       XRectangle rect;
169       XserverRegion region;
170
171       rect.x = 0;
172       rect.y = 0;
173       rect.width = mPosition.width;
174       rect.height = mPosition.height;
175
176       XDisplay* display = AnyCast<XDisplay*>(displayConnection->GetDisplay());
177
178       // make a fixes region as updated area
179       region = XFixesCreateRegion( display, &rect, 1 );
180       // add damage event to updated drawable
181       XDamageAdd( display, (Drawable)drawable, region );
182       XFixesDestroyRegion( display, region );
183
184       XFlush( display );
185     }
186   }
187
188   if( mImpl->mThreadSynchronization )
189   {
190     mImpl->mThreadSynchronization->PostRenderWaitForCompletion();
191   }
192 }
193
194 void PixmapRenderSurface::StopRender()
195 {
196   ReleaseLock();
197 }
198
199 void PixmapRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
200 {
201   mImpl->mThreadSynchronization = &threadSynchronization;
202 }
203
204 void PixmapRenderSurface::CreateXRenderable()
205 {
206   // check we're creating one with a valid size
207   DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid" );
208
209   // create the pixmap
210   mImpl->mX11Pixmap = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
211
212   // clear the pixmap
213   unsigned int foreground;
214   Ecore_X_GC gc;
215   foreground = 0;
216   gc = ecore_x_gc_new( mImpl->mX11Pixmap,
217                        ECORE_X_GC_VALUE_MASK_FOREGROUND,
218                        &foreground );
219
220   DALI_ASSERT_ALWAYS( gc && "CreateXRenderable(): failed to get gc" );
221
222   ecore_x_drawable_rectangle_fill( mImpl->mX11Pixmap, gc, 0, 0, mPosition.width, mPosition.height );
223
224   DALI_ASSERT_ALWAYS( mImpl->mX11Pixmap && "Failed to create X pixmap" );
225
226   // we SHOULD guarantee the xpixmap/x11 window was created in x server.
227   ecore_x_sync();
228
229   ecore_x_gc_free(gc);
230 }
231
232 void PixmapRenderSurface::UseExistingRenderable( unsigned int surfaceId )
233 {
234   mImpl->mX11Pixmap = static_cast< Ecore_X_Pixmap >( surfaceId );
235 }
236
237 void PixmapRenderSurface::ReleaseLock()
238 {
239   if( mImpl->mThreadSynchronization )
240   {
241     mImpl->mThreadSynchronization->PostRenderComplete();
242   }
243 }
244
245 } // namespace ECore
246
247 } // namespace Dali