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