[Tizen] Revert "Support screen rotation"
[platform/core/uifw/dali-adaptor.git] / adaptors / x11 / pixmap-render-surface-x.cpp
1 /*
2  * Copyright (c) 2017 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/threading/mutex.h>
32 #include <dali/devel-api/threading/conditional-wait.h>
33
34 // INTERNAL INCLUDES
35
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>
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 namespace
53 {
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;
57 }
58
59 struct PixmapRenderSurface::Impl
60 {
61   Impl()
62   : mProduceBufferIndex( INITIAL_PRODUCE_BUFFER_INDEX ),
63     mConsumeBufferIndex( INITIAL_CONSUME_BUFFER_INDEX ),
64     mThreadSynchronization(NULL)
65   {
66     for (int i = 0; i != BUFFER_COUNT; ++i)
67     {
68       mX11Pixmaps[i] = 0;
69       mEglSurfaces[i] = 0;
70     }
71   }
72
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
79 };
80
81 PixmapRenderSurface::PixmapRenderSurface(Dali::PositionSize positionSize,
82                                          Any surface,
83                                          const std::string& name,
84                                          bool isTransparent)
85 : EcoreXRenderSurface( positionSize, surface, name, isTransparent ),
86   mImpl( new Impl )
87 {
88   Init( surface );
89 }
90
91 PixmapRenderSurface::~PixmapRenderSurface()
92 {
93   // release the surface if we own one
94   if( mOwnSurface )
95   {
96     for (int i = 0; i < BUFFER_COUNT; ++i)
97     {
98       Ecore_X_Pixmap pixmap = mImpl->mX11Pixmaps[i];
99
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 );
103     }
104   }
105
106   delete mImpl;
107 }
108
109 Ecore_X_Drawable PixmapRenderSurface::GetDrawable()
110 {
111   Ecore_X_Pixmap pixmap = 0;
112   {
113     ConditionalWait::ScopedLock lock( mImpl->mPixmapCondition );
114     pixmap = mImpl->mX11Pixmaps[mImpl->mConsumeBufferIndex];
115   }
116
117   return Ecore_X_Drawable( pixmap );
118 }
119
120 Any PixmapRenderSurface::GetSurface()
121 {
122   Ecore_X_Pixmap pixmap = 0;
123   {
124     ConditionalWait::ScopedLock lock( mImpl->mPixmapCondition );
125     pixmap = mImpl->mX11Pixmaps[mImpl->mProduceBufferIndex];
126   }
127
128   return Any( pixmap );
129 }
130
131 void PixmapRenderSurface::InitializeEgl( EglInterface& egl )
132 {
133   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
134
135   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
136
137   eglImpl.ChooseConfig(false, mColorDepth);
138 }
139
140 void PixmapRenderSurface::CreateEglSurface( EglInterface& egl )
141 {
142   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
143
144   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
145
146   for (int i = 0; i < BUFFER_COUNT; ++i)
147   {
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
152   }
153 }
154
155 void PixmapRenderSurface::DestroyEglSurface( EglInterface& egl )
156 {
157   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
158
159   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
160
161   for (int i = 0; i < BUFFER_COUNT; ++i)
162   {
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();
167   }
168 }
169
170 bool PixmapRenderSurface::ReplaceEGLSurface( EglInterface& egl )
171 {
172   DALI_LOG_TRACE_METHOD( gRenderSurfaceLogFilter );
173
174   bool contextLost = false;
175
176   Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
177
178   for (int i = 0; i < BUFFER_COUNT; ++i)
179   {
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
184   }
185
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] );
189
190   return contextLost;
191 }
192
193 void PixmapRenderSurface::StartRender()
194 {
195 }
196
197 bool PixmapRenderSurface::PreRender( EglInterface& egl, Integration::GlAbstraction& )
198 {
199   // Nothing to do for pixmaps
200   return true;
201 }
202
203 void PixmapRenderSurface::PostRender( EglInterface& egl, Integration::GlAbstraction& glAbstraction, DisplayConnection* displayConnection, bool replacingSurface )
204 {
205   // flush gl instruction queue
206   glAbstraction.Flush();
207
208   if( mImpl->mThreadSynchronization )
209   {
210     mImpl->mThreadSynchronization->PostRenderStarted();
211   }
212
213   {
214     ConditionalWait::ScopedLock lock( mImpl->mPixmapCondition );
215     mImpl->mConsumeBufferIndex = __sync_fetch_and_xor( &mImpl->mProduceBufferIndex, 1 ); // Swap buffer indexes.
216
217     Internal::Adaptor::EglImplementation& eglImpl = static_cast<Internal::Adaptor::EglImplementation&>( egl );
218
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] );
222   }
223
224   // create damage for client applications which wish to know the update timing
225   if( mRenderNotification )
226   {
227     // use notification trigger
228     // Tell the event-thread to render the pixmap
229     mRenderNotification->Trigger();
230   }
231   else
232   {
233     // as a fallback, send damage event.
234     Ecore_X_Drawable drawable = Ecore_X_Drawable( mImpl->mX11Pixmaps[mImpl->mProduceBufferIndex] );
235
236     if( drawable )
237     {
238       XRectangle rect;
239       XserverRegion region;
240
241       rect.x = 0;
242       rect.y = 0;
243       rect.width = mPosition.width;
244       rect.height = mPosition.height;
245
246       XDisplay* display = AnyCast<XDisplay*>(displayConnection->GetDisplay());
247
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 );
254
255       XFlush( display );
256     }
257   }
258
259   if( mImpl->mThreadSynchronization )
260   {
261     mImpl->mThreadSynchronization->PostRenderWaitForCompletion();
262   }
263 }
264
265 void PixmapRenderSurface::StopRender()
266 {
267   ReleaseLock();
268 }
269
270 void PixmapRenderSurface::SetThreadSynchronization( ThreadSynchronizationInterface& threadSynchronization )
271 {
272   mImpl->mThreadSynchronization = &threadSynchronization;
273 }
274
275 void PixmapRenderSurface::CreateXRenderable()
276 {
277   // check we're creating one with a valid size
278   DALI_ASSERT_ALWAYS( mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid" );
279
280   for (int i = 0; i < BUFFER_COUNT; ++i)
281   {
282     // create the pixmap
283     mImpl->mX11Pixmaps[i] = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
284
285     // clear the pixmap
286     unsigned int foreground;
287     Ecore_X_GC gc;
288     foreground = 0;
289     gc = ecore_x_gc_new( mImpl->mX11Pixmaps[i],
290                          ECORE_X_GC_VALUE_MASK_FOREGROUND,
291                          &foreground );
292
293     DALI_ASSERT_ALWAYS( gc && "CreateXRenderable(): failed to get gc" );
294
295     ecore_x_drawable_rectangle_fill( mImpl->mX11Pixmaps[i], gc, 0, 0, mPosition.width, mPosition.height );
296
297     DALI_ASSERT_ALWAYS( mImpl->mX11Pixmaps[i] && "Failed to create X pixmap" );
298
299     // we SHOULD guarantee the xpixmap/x11 window was created in x server.
300     ecore_x_sync();
301
302     ecore_x_gc_free(gc);
303   }
304 }
305
306 void PixmapRenderSurface::UseExistingRenderable( unsigned int surfaceId )
307 {
308 }
309
310 void PixmapRenderSurface::ReleaseLock()
311 {
312   if( mImpl->mThreadSynchronization )
313   {
314     mImpl->mThreadSynchronization->PostRenderComplete();
315   }
316 }
317
318 RenderSurface::Type PixmapRenderSurface::GetSurfaceType()
319 {
320   return RenderSurface::ECORE_RENDER_SURFACE;
321 }
322
323 } // namespace ECore
324
325 } // namespace Dali