2 * Copyright (c) 2021 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 <dali/internal/window-system/ubuntu-x11/pixmap-render-surface-ecore-x.h>
22 #include <X11/Xatom.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>
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>
45 #if defined(DEBUG_ENABLED)
46 Debug::Filter* gPixmapRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_PIXMAP_RENDER_SURFACE_ECORE_X");
51 static const int INITIAL_PRODUCE_BUFFER_INDEX = 0;
52 static const int INITIAL_CONSUME_BUFFER_INDEX = 1;
55 PixmapRenderSurfaceEcoreX::PixmapRenderSurfaceEcoreX(Dali::PositionSize positionSize, Any surface, bool isTransparent)
57 mDisplayConnection(nullptr),
58 mPosition(positionSize),
59 mRenderNotification(NULL),
60 mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
62 mProduceBufferIndex(INITIAL_PRODUCE_BUFFER_INDEX),
63 mConsumeBufferIndex(INITIAL_CONSUME_BUFFER_INDEX),
66 mThreadSynchronization(nullptr),
69 for(int i = 0; i != BUFFER_COUNT; ++i)
78 PixmapRenderSurfaceEcoreX::~PixmapRenderSurfaceEcoreX()
82 // release the surface if we own one
85 for(int i = 0; i < BUFFER_COUNT; ++i)
87 Ecore_X_Pixmap pixmap = mX11Pixmaps[i];
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);
96 void PixmapRenderSurfaceEcoreX::Initialize(Any surface)
98 // see if there is a surface in Any surface
99 unsigned int surfaceId = GetSurfaceId(surface);
101 // if the surface is empty, create a new one.
104 // we own the surface about to created
110 // XLib should already be initialized so no point in calling XInitThreads
111 UseExistingRenderable(surfaceId);
115 Any PixmapRenderSurfaceEcoreX::GetSurface()
117 Ecore_X_Pixmap pixmap = 0;
119 ConditionalWait::ScopedLock lock(mPixmapCondition);
120 pixmap = mX11Pixmaps[mProduceBufferIndex];
126 void PixmapRenderSurfaceEcoreX::SetRenderNotification(TriggerEventInterface* renderNotification)
128 mRenderNotification = renderNotification;
131 PositionSize PixmapRenderSurfaceEcoreX::GetPositionSize() const
136 void PixmapRenderSurfaceEcoreX::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
141 // 1 inch = 25.4 millimeters
142 xres = ecore_x_dpi_get();
143 yres = ecore_x_dpi_get();
145 dpiHorizontal = int(xres + 0.5f); // rounding
146 dpiVertical = int(yres + 0.5f);
149 int PixmapRenderSurfaceEcoreX::GetOrientation() const
154 void PixmapRenderSurfaceEcoreX::InitializeGraphics()
156 mGraphics = &mAdaptor->GetGraphicsInterface();
157 mDisplayConnection = &mAdaptor->GetDisplayConnectionInterface();
159 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
160 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
161 eglImpl.ChooseConfig(false, mColorDepth);
164 void PixmapRenderSurfaceEcoreX::CreateSurface()
166 DALI_LOG_TRACE_METHOD(gPixmapRenderSurfaceLogFilter);
168 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
169 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
171 for(int i = 0; i < BUFFER_COUNT; ++i)
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
180 void PixmapRenderSurfaceEcoreX::DestroySurface()
182 DALI_LOG_TRACE_METHOD(gPixmapRenderSurfaceLogFilter);
184 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
186 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
188 for(int i = 0; i < BUFFER_COUNT; ++i)
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]);
197 bool PixmapRenderSurfaceEcoreX::ReplaceGraphicsSurface()
199 DALI_LOG_TRACE_METHOD(gPixmapRenderSurfaceLogFilter);
201 bool contextLost = false;
203 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
205 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
207 for(int i = 0; i < BUFFER_COUNT; ++i)
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
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]);
222 void PixmapRenderSurfaceEcoreX::StartRender()
226 bool PixmapRenderSurfaceEcoreX::PreRender(bool, const std::vector<Rect<int>>&, Rect<int>&)
228 // Nothing to do for pixmaps
232 void PixmapRenderSurfaceEcoreX::PostRender()
234 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
236 // flush gl instruction queue
237 Integration::GlAbstraction& glAbstraction = eglGraphics->GetGlAbstraction();
238 glAbstraction.Flush();
240 if(mThreadSynchronization)
242 mThreadSynchronization->PostRenderStarted();
246 ConditionalWait::ScopedLock lock(mPixmapCondition);
247 mConsumeBufferIndex = __sync_fetch_and_xor(&mProduceBufferIndex, 1); // Swap buffer indexes.
249 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
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]);
256 // create damage for client applications which wish to know the update timing
257 if(mRenderNotification)
259 // use notification trigger
260 // Tell the event-thread to render the pixmap
261 mRenderNotification->Trigger();
265 // as a fallback, send damage event.
266 Ecore_X_Drawable drawable = Ecore_X_Drawable(mX11Pixmaps[mProduceBufferIndex]);
271 XserverRegion region;
275 rect.width = mPosition.width;
276 rect.height = mPosition.height;
278 XDisplay* display = AnyCast<XDisplay*>(mDisplayConnection->GetDisplay());
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);
291 if(mThreadSynchronization)
293 mThreadSynchronization->PostRenderWaitForCompletion();
297 void PixmapRenderSurfaceEcoreX::StopRender()
302 void PixmapRenderSurfaceEcoreX::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
304 mThreadSynchronization = &threadSynchronization;
307 void PixmapRenderSurfaceEcoreX::ReleaseLock()
309 if(mThreadSynchronization)
311 mThreadSynchronization->PostRenderComplete();
315 Dali::RenderSurfaceInterface::Type PixmapRenderSurfaceEcoreX::GetSurfaceType()
317 return Dali::RenderSurfaceInterface::PIXMAP_RENDER_SURFACE;
320 void PixmapRenderSurfaceEcoreX::MakeContextCurrent()
324 void PixmapRenderSurfaceEcoreX::CreateRenderable()
326 // check we're creating one with a valid size
327 DALI_ASSERT_ALWAYS(mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid");
329 for(int i = 0; i < BUFFER_COUNT; ++i)
332 mX11Pixmaps[i] = ecore_x_pixmap_new(0, mPosition.width, mPosition.height, mColorDepth);
335 unsigned int foreground;
338 gc = ecore_x_gc_new(mX11Pixmaps[i],
339 ECORE_X_GC_VALUE_MASK_FOREGROUND,
342 DALI_ASSERT_ALWAYS(gc && "CreateRenderable(): failed to get gc");
344 ecore_x_drawable_rectangle_fill(mX11Pixmaps[i], gc, 0, 0, mPosition.width, mPosition.height);
346 DALI_ASSERT_ALWAYS(mX11Pixmaps[i] && "Failed to create X pixmap");
348 // we SHOULD guarantee the xpixmap/x11 window was created in x server.
355 void PixmapRenderSurfaceEcoreX::UseExistingRenderable(unsigned int surfaceId)
359 unsigned int PixmapRenderSurfaceEcoreX::GetSurfaceId(Any surface) const
361 unsigned int surfaceId = 0;
363 if(surface.Empty() == false)
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");
370 if(surface.GetType() == typeid(Ecore_X_Window))
372 surfaceId = AnyCast<Ecore_X_Window>(surface);
376 surfaceId = AnyCast<XWindow>(surface);
382 } // namespace Adaptor
384 } // namespace Internal