Revert "[Tizen] Remove to call key consumed event in ATSPI bridge"
[platform/core/uifw/dali-adaptor.git] / dali / internal / window-system / ubuntu-x11 / pixmap-render-surface-ecore-x.cpp
1 /*
2  * Copyright (c) 2021 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 <dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.h>
20
21 // EXTERNAL INCLUDES
22 #include <X11/Xatom.h>
23 #include <X11/Xlib.h>
24 #include <X11/Xutil.h>
25 #include <X11/extensions/Xdamage.h> // for damage notify
26 #include <X11/extensions/Xfixes.h>  // for damage notify
27 #include <dali/devel-api/threading/mutex.h>
28 #include <dali/integration-api/debug.h>
29 #include <dali/integration-api/gl-abstraction.h>
30
31 // INTERNAL INCLUDES
32 #include <dali/integration-api/adaptor-framework/thread-synchronization-interface.h>
33 #include <dali/internal/adaptor/common/adaptor-impl.h>
34 #include <dali/internal/adaptor/common/adaptor-internal-services.h>
35 #include <dali/internal/graphics/gles/egl-graphics.h>
36 #include <dali/internal/system/common/trigger-event.h>
37 #include <dali/internal/window-system/common/display-connection.h>
38
39 namespace Dali
40 {
41 namespace Internal
42 {
43 namespace Adaptor
44 {
45 #if defined(DEBUG_ENABLED)
46 Debug::Filter* gPixmapRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_PIXMAP_RENDER_SURFACE_ECORE_X");
47 #endif
48
49 namespace
50 {
51 static const int INITIAL_PRODUCE_BUFFER_INDEX = 0;
52 static const int INITIAL_CONSUME_BUFFER_INDEX = 1;
53 } // namespace
54
55 PixmapRenderSurfaceEcoreX::PixmapRenderSurfaceEcoreX(Dali::PositionSize positionSize, Any surface, bool isTransparent)
56 : mGraphics(nullptr),
57   mDisplayConnection(nullptr),
58   mPosition(positionSize),
59   mRenderNotification(NULL),
60   mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
61   mOwnSurface(false),
62   mProduceBufferIndex(INITIAL_PRODUCE_BUFFER_INDEX),
63   mConsumeBufferIndex(INITIAL_CONSUME_BUFFER_INDEX),
64   mX11Pixmaps(),
65   mEglSurfaces(),
66   mThreadSynchronization(nullptr),
67   mPixmapCondition()
68 {
69   for(int i = 0; i != BUFFER_COUNT; ++i)
70   {
71     mX11Pixmaps[i]  = 0;
72     mEglSurfaces[i] = 0;
73   }
74
75   Initialize(surface);
76 }
77
78 PixmapRenderSurfaceEcoreX::~PixmapRenderSurfaceEcoreX()
79 {
80   DestroySurface();
81
82   // release the surface if we own one
83   if(mOwnSurface)
84   {
85     for(int i = 0; i < BUFFER_COUNT; ++i)
86     {
87       Ecore_X_Pixmap pixmap = mX11Pixmaps[i];
88
89       // if we did create the pixmap, delete the pixmap
90       DALI_LOG_INFO(gPixmapRenderSurfaceLogFilter, Debug::General, "Own pixmap (%x) freed\n", pixmap);
91       ecore_x_pixmap_free(pixmap);
92     }
93   }
94 }
95
96 void PixmapRenderSurfaceEcoreX::Initialize(Any surface)
97 {
98   // see if there is a surface in Any surface
99   unsigned int surfaceId = GetSurfaceId(surface);
100
101   // if the surface is empty, create a new one.
102   if(surfaceId == 0)
103   {
104     // we own the surface about to created
105     mOwnSurface = true;
106     CreateRenderable();
107   }
108   else
109   {
110     // XLib should already be initialized so no point in calling XInitThreads
111     UseExistingRenderable(surfaceId);
112   }
113 }
114
115 Any PixmapRenderSurfaceEcoreX::GetSurface()
116 {
117   Ecore_X_Pixmap pixmap = 0;
118   {
119     ConditionalWait::ScopedLock lock(mPixmapCondition);
120     pixmap = mX11Pixmaps[mProduceBufferIndex];
121   }
122
123   return Any(pixmap);
124 }
125
126 void PixmapRenderSurfaceEcoreX::SetRenderNotification(TriggerEventInterface* renderNotification)
127 {
128   mRenderNotification = renderNotification;
129 }
130
131 PositionSize PixmapRenderSurfaceEcoreX::GetPositionSize() const
132 {
133   return mPosition;
134 }
135
136 void PixmapRenderSurfaceEcoreX::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
137 {
138   // calculate DPI
139   float xres, yres;
140
141   // 1 inch = 25.4 millimeters
142   xres = ecore_x_dpi_get();
143   yres = ecore_x_dpi_get();
144
145   dpiHorizontal = int(xres + 0.5f); // rounding
146   dpiVertical   = int(yres + 0.5f);
147 }
148
149 int PixmapRenderSurfaceEcoreX::GetOrientation() const
150 {
151   return 0;
152 }
153
154 void PixmapRenderSurfaceEcoreX::InitializeGraphics()
155 {
156   mGraphics          = &mAdaptor->GetGraphicsInterface();
157   mDisplayConnection = &mAdaptor->GetDisplayConnectionInterface();
158
159   auto                                  eglGraphics = static_cast<EglGraphics*>(mGraphics);
160   Internal::Adaptor::EglImplementation& eglImpl     = eglGraphics->GetEglImplementation();
161   eglImpl.ChooseConfig(false, mColorDepth);
162 }
163
164 void PixmapRenderSurfaceEcoreX::CreateSurface()
165 {
166   DALI_LOG_TRACE_METHOD(gPixmapRenderSurfaceLogFilter);
167
168   auto                                  eglGraphics = static_cast<EglGraphics*>(mGraphics);
169   Internal::Adaptor::EglImplementation& eglImpl     = eglGraphics->GetEglImplementation();
170
171   for(int i = 0; i < BUFFER_COUNT; ++i)
172   {
173     // create the EGL surface
174     // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
175     XPixmap pixmap  = static_cast<XPixmap>(mX11Pixmaps[i]);
176     mEglSurfaces[i] = eglImpl.CreateSurfacePixmap(EGLNativePixmapType(pixmap), mColorDepth); // reinterpret_cast does not compile
177   }
178 }
179
180 void PixmapRenderSurfaceEcoreX::DestroySurface()
181 {
182   DALI_LOG_TRACE_METHOD(gPixmapRenderSurfaceLogFilter);
183
184   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
185
186   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
187
188   for(int i = 0; i < BUFFER_COUNT; ++i)
189   {
190     // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
191     XPixmap pixmap = static_cast<XPixmap>(mX11Pixmaps[i]);
192     eglImpl.MakeCurrent(EGLNativePixmapType(pixmap), mEglSurfaces[i]);
193     eglImpl.DestroySurface(mEglSurfaces[i]);
194   }
195 }
196
197 bool PixmapRenderSurfaceEcoreX::ReplaceGraphicsSurface()
198 {
199   DALI_LOG_TRACE_METHOD(gPixmapRenderSurfaceLogFilter);
200
201   bool contextLost = false;
202
203   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
204
205   Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
206
207   for(int i = 0; i < BUFFER_COUNT; ++i)
208   {
209     // a new surface for the new pixmap
210     // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
211     XPixmap pixmap = static_cast<XPixmap>(mX11Pixmaps[i]);
212     contextLost    = eglImpl.ReplaceSurfacePixmap(EGLNativePixmapType(pixmap), mEglSurfaces[i]); // reinterpret_cast does not compile
213   }
214
215   // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
216   XPixmap pixmap = static_cast<XPixmap>(mX11Pixmaps[mProduceBufferIndex]);
217   eglImpl.MakeCurrent(EGLNativePixmapType(pixmap), mEglSurfaces[mProduceBufferIndex]);
218
219   return contextLost;
220 }
221
222 void PixmapRenderSurfaceEcoreX::StartRender()
223 {
224 }
225
226 bool PixmapRenderSurfaceEcoreX::PreRender(bool, const std::vector<Rect<int>>&, Rect<int>&)
227 {
228   // Nothing to do for pixmaps
229   return true;
230 }
231
232 void PixmapRenderSurfaceEcoreX::PostRender()
233 {
234   auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
235
236   // flush gl instruction queue
237   Integration::GlAbstraction& glAbstraction = eglGraphics->GetGlAbstraction();
238   glAbstraction.Flush();
239
240   if(mThreadSynchronization)
241   {
242     mThreadSynchronization->PostRenderStarted();
243   }
244
245   {
246     ConditionalWait::ScopedLock lock(mPixmapCondition);
247     mConsumeBufferIndex = __sync_fetch_and_xor(&mProduceBufferIndex, 1); // Swap buffer indexes.
248
249     Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
250
251     // need to cast to X handle as in 64bit system ECore handle is 32 bit whereas EGLnative and XWindow are 64 bit
252     XPixmap pixmap = static_cast<XPixmap>(mX11Pixmaps[mProduceBufferIndex]);
253     eglImpl.MakeCurrent(EGLNativePixmapType(pixmap), mEglSurfaces[mProduceBufferIndex]);
254   }
255
256   // create damage for client applications which wish to know the update timing
257   if(mRenderNotification)
258   {
259     // use notification trigger
260     // Tell the event-thread to render the pixmap
261     mRenderNotification->Trigger();
262   }
263   else
264   {
265     // as a fallback, send damage event.
266     Ecore_X_Drawable drawable = Ecore_X_Drawable(mX11Pixmaps[mProduceBufferIndex]);
267
268     if(drawable)
269     {
270       XRectangle    rect;
271       XserverRegion region;
272
273       rect.x      = 0;
274       rect.y      = 0;
275       rect.width  = mPosition.width;
276       rect.height = mPosition.height;
277
278       XDisplay* display = AnyCast<XDisplay*>(mDisplayConnection->GetDisplay());
279
280       // make a fixes region as updated area
281       region = XFixesCreateRegion(display, &rect, 1);
282       // add damage event to updated drawable
283       Drawable xdrawable(drawable); // ecore type is unsigned int whereas in 64bit linux Drawable is long unsigned int
284       XDamageAdd(display, xdrawable, region);
285       XFixesDestroyRegion(display, region);
286
287       XFlush(display);
288     }
289   }
290
291   if(mThreadSynchronization)
292   {
293     mThreadSynchronization->PostRenderWaitForCompletion();
294   }
295 }
296
297 void PixmapRenderSurfaceEcoreX::StopRender()
298 {
299   ReleaseLock();
300 }
301
302 void PixmapRenderSurfaceEcoreX::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
303 {
304   mThreadSynchronization = &threadSynchronization;
305 }
306
307 void PixmapRenderSurfaceEcoreX::ReleaseLock()
308 {
309   if(mThreadSynchronization)
310   {
311     mThreadSynchronization->PostRenderComplete();
312   }
313 }
314
315 Dali::RenderSurfaceInterface::Type PixmapRenderSurfaceEcoreX::GetSurfaceType()
316 {
317   return Dali::RenderSurfaceInterface::PIXMAP_RENDER_SURFACE;
318 }
319
320 void PixmapRenderSurfaceEcoreX::MakeContextCurrent()
321 {
322 }
323
324 void PixmapRenderSurfaceEcoreX::CreateRenderable()
325 {
326   // check we're creating one with a valid size
327   DALI_ASSERT_ALWAYS(mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid");
328
329   for(int i = 0; i < BUFFER_COUNT; ++i)
330   {
331     // create the pixmap
332     mX11Pixmaps[i] = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
333
334     // clear the pixmap
335     unsigned int foreground;
336     Ecore_X_GC   gc;
337     foreground = 0;
338     gc         = ecore_x_gc_new(mX11Pixmaps[i],
339                         ECORE_X_GC_VALUE_MASK_FOREGROUND,
340                         &foreground);
341
342     DALI_ASSERT_ALWAYS(gc && "CreateRenderable(): failed to get gc");
343
344     ecore_x_drawable_rectangle_fill(mX11Pixmaps[i], gc, 0, 0, mPosition.width, mPosition.height);
345
346     DALI_ASSERT_ALWAYS(mX11Pixmaps[i] && "Failed to create X pixmap");
347
348     // we SHOULD guarantee the xpixmap/x11 window was created in x server.
349     ecore_x_sync();
350
351     ecore_x_gc_free(gc);
352   }
353 }
354
355 void PixmapRenderSurfaceEcoreX::UseExistingRenderable(unsigned int surfaceId)
356 {
357 }
358
359 unsigned int PixmapRenderSurfaceEcoreX::GetSurfaceId(Any surface) const
360 {
361   unsigned int surfaceId = 0;
362
363   if(surface.Empty() == false)
364   {
365     // check we have a valid type
366     DALI_ASSERT_ALWAYS(((surface.GetType() == typeid(XWindow)) ||
367                         (surface.GetType() == typeid(Ecore_X_Window))) &&
368                        "Surface type is invalid");
369
370     if(surface.GetType() == typeid(Ecore_X_Window))
371     {
372       surfaceId = AnyCast<Ecore_X_Window>(surface);
373     }
374     else
375     {
376       surfaceId = AnyCast<XWindow>(surface);
377     }
378   }
379   return surfaceId;
380 }
381
382 } // namespace Adaptor
383
384 } // namespace Internal
385
386 } // namespace Dali