2 * Copyright (c) 2022 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/x11/pixmap-render-surface-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>
38 #include <dali/internal/window-system/x11/window-system-x.h>
46 #if defined(DEBUG_ENABLED)
47 Debug::Filter* gPixmapRenderSurfaceLogFilter = Debug::Filter::New(Debug::Verbose, false, "LOG_PIXMAP_RENDER_SURFACE_X");
52 static const int INITIAL_PRODUCE_BUFFER_INDEX = 0;
53 static const int INITIAL_CONSUME_BUFFER_INDEX = 1;
56 PixmapRenderSurfaceX::PixmapRenderSurfaceX(Dali::PositionSize positionSize, Any surface, bool isTransparent)
58 mDisplayConnection(nullptr),
59 mPosition(positionSize),
60 mRenderNotification(NULL),
61 mColorDepth(isTransparent ? COLOR_DEPTH_32 : COLOR_DEPTH_24),
63 mProduceBufferIndex(INITIAL_PRODUCE_BUFFER_INDEX),
64 mConsumeBufferIndex(INITIAL_CONSUME_BUFFER_INDEX),
67 mThreadSynchronization(nullptr),
70 for(int i = 0; i != BUFFER_COUNT; ++i)
79 PixmapRenderSurfaceX::~PixmapRenderSurfaceX()
83 // release the surface if we own one
86 for(int i = 0; i < BUFFER_COUNT; ++i)
88 ::Pixmap pixmap = mX11Pixmaps[i];
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);
97 void PixmapRenderSurfaceX::Initialize(Any surface)
99 // see if there is a surface in Any surface
100 unsigned int surfaceId = GetSurfaceId(surface);
102 // if the surface is empty, create a new one.
105 // we own the surface about to created
111 // XLib should already be initialized so no point in calling XInitThreads
112 UseExistingRenderable(surfaceId);
116 Any PixmapRenderSurfaceX::GetSurface()
120 ConditionalWait::ScopedLock lock(mPixmapCondition);
121 pixmap = mX11Pixmaps[mProduceBufferIndex];
127 void PixmapRenderSurfaceX::SetRenderNotification(TriggerEventInterface* renderNotification)
129 mRenderNotification = renderNotification;
132 PositionSize PixmapRenderSurfaceX::GetPositionSize() const
137 void PixmapRenderSurfaceX::GetDpi(unsigned int& dpiHorizontal, unsigned int& dpiVertical)
139 WindowSystem::GetImplementation().GetDPI(dpiHorizontal, dpiVertical);
142 int PixmapRenderSurfaceX::GetOrientation() const
147 void PixmapRenderSurfaceX::InitializeGraphics()
149 mGraphics = &mAdaptor->GetGraphicsInterface();
150 mDisplayConnection = &mAdaptor->GetDisplayConnectionInterface();
152 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
153 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
154 eglImpl.ChooseConfig(false, mColorDepth);
157 void PixmapRenderSurfaceX::CreateSurface()
159 DALI_LOG_TRACE_METHOD(gPixmapRenderSurfaceLogFilter);
161 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
162 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
164 for(int i = 0; i < BUFFER_COUNT; ++i)
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
173 void PixmapRenderSurfaceX::DestroySurface()
175 DALI_LOG_TRACE_METHOD(gPixmapRenderSurfaceLogFilter);
177 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
179 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
181 for(int i = 0; i < BUFFER_COUNT; ++i)
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]);
190 bool PixmapRenderSurfaceX::ReplaceGraphicsSurface()
192 DALI_LOG_TRACE_METHOD(gPixmapRenderSurfaceLogFilter);
194 bool contextLost = false;
196 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
198 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
200 for(int i = 0; i < BUFFER_COUNT; ++i)
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
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]);
215 void PixmapRenderSurfaceX::StartRender()
219 bool PixmapRenderSurfaceX::PreRender(bool, const std::vector<Rect<int>>&, Rect<int>&)
221 // Nothing to do for pixmaps
225 void PixmapRenderSurfaceX::PostRender()
227 auto eglGraphics = static_cast<EglGraphics*>(mGraphics);
229 // flush gl instruction queue
230 Integration::GlAbstraction& glAbstraction = eglGraphics->GetGlAbstraction();
231 glAbstraction.Flush();
233 if(mThreadSynchronization)
235 mThreadSynchronization->PostRenderStarted();
239 ConditionalWait::ScopedLock lock(mPixmapCondition);
240 mConsumeBufferIndex = __sync_fetch_and_xor(&mProduceBufferIndex, 1); // Swap buffer indexes.
242 Internal::Adaptor::EglImplementation& eglImpl = eglGraphics->GetEglImplementation();
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]);
249 // create damage for client applications which wish to know the update timing
250 if(mRenderNotification)
252 // use notification trigger
253 // Tell the event-thread to render the pixmap
254 mRenderNotification->Trigger();
258 // as a fallback, send damage event.
259 ::Drawable drawable = ::Drawable(mX11Pixmaps[mProduceBufferIndex]);
264 XserverRegion region;
268 rect.width = mPosition.width;
269 rect.height = mPosition.height;
271 ::Display* display = AnyCast<::Display*>(mDisplayConnection->GetDisplay());
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);
284 if(mThreadSynchronization)
286 mThreadSynchronization->PostRenderWaitForCompletion();
290 void PixmapRenderSurfaceX::StopRender()
295 void PixmapRenderSurfaceX::SetThreadSynchronization(ThreadSynchronizationInterface& threadSynchronization)
297 mThreadSynchronization = &threadSynchronization;
300 void PixmapRenderSurfaceX::ReleaseLock()
302 if(mThreadSynchronization)
304 mThreadSynchronization->PostRenderComplete();
308 Dali::RenderSurfaceInterface::Type PixmapRenderSurfaceX::GetSurfaceType()
310 return Dali::RenderSurfaceInterface::PIXMAP_RENDER_SURFACE;
313 void PixmapRenderSurfaceX::MakeContextCurrent()
317 void PixmapRenderSurfaceX::CreateRenderable()
319 // check we're creating one with a valid size
320 DALI_ASSERT_ALWAYS(mPosition.width > 0 && mPosition.height > 0 && "Pixmap size is invalid");
322 auto display = WindowSystem::GetImplementation().GetXDisplay();
324 int colorDepth = (mColorDepth != 0 ? mColorDepth : DefaultDepth(display, DefaultScreen(display)));
326 for(int i = 0; i < BUFFER_COUNT; ++i)
329 mX11Pixmaps[i] = XCreatePixmap(display, DefaultRootWindow(display), mPosition.width, mPosition.height, colorDepth);
333 XGCValues graphicsContextValues{0};
334 graphicsContextValues.foreground = 0;
336 graphicsContext = XCreateGC(display, mX11Pixmaps[i], GCForeground, &graphicsContextValues);
338 DALI_ASSERT_ALWAYS(graphicsContext && "CreateRenderable(): failed to get graphics context");
340 XFillRectangle(display, mX11Pixmaps[i], graphicsContext, 0, 0, mPosition.width, mPosition.height);
341 DALI_ASSERT_ALWAYS(mX11Pixmaps[i] && "Failed to create X pixmap");
343 // we SHOULD guarantee the xpixmap/x11 window was created in x server.
344 XSync(display, False);
345 XFreeGC(display, graphicsContext);
349 void PixmapRenderSurfaceX::UseExistingRenderable(unsigned int surfaceId)
353 unsigned int PixmapRenderSurfaceX::GetSurfaceId(Any surface) const
355 unsigned int surfaceId = 0;
357 if(surface.Empty() == false)
359 // check we have a valid type
360 DALI_ASSERT_ALWAYS(surface.GetType() == typeid(::Window) && "Surface type is invalid");
361 surfaceId = AnyCast<::Window>(surface);
366 } // namespace Adaptor
368 } // namespace Internal