Changeset View
Changeset View
Standalone View
Standalone View
plugins/platforms/x11/common/eglonxbackend.cpp
Show First 20 Lines • Show All 67 Lines • ▼ Show 20 Line(s) | 60 | EglOnXBackend::EglOnXBackend(xcb_connection_t *connection, Display *display, xcb_window_t rootWindow, int screenNumber, xcb_window_t renderingWindow) | |||
---|---|---|---|---|---|
68 | , m_rootWindow(rootWindow) | 68 | , m_rootWindow(rootWindow) | ||
69 | , m_x11ScreenNumber(screenNumber) | 69 | , m_x11ScreenNumber(screenNumber) | ||
70 | , m_renderingWindow(renderingWindow) | 70 | , m_renderingWindow(renderingWindow) | ||
71 | { | 71 | { | ||
72 | // Egl is always direct rendering | 72 | // Egl is always direct rendering | ||
73 | setIsDirectRendering(true); | 73 | setIsDirectRendering(true); | ||
74 | } | 74 | } | ||
75 | 75 | | |||
76 | static bool gs_tripleBufferUndetected = true; | | |||
77 | static bool gs_tripleBufferNeedsDetection = false; | | |||
78 | | ||||
79 | EglOnXBackend::~EglOnXBackend() | 76 | EglOnXBackend::~EglOnXBackend() | ||
80 | { | 77 | { | ||
81 | if (isFailed() && m_overlayWindow) { | 78 | if (isFailed() && m_overlayWindow) { | ||
82 | m_overlayWindow->destroy(); | 79 | m_overlayWindow->destroy(); | ||
83 | } | 80 | } | ||
84 | cleanup(); | 81 | cleanup(); | ||
85 | 82 | | |||
86 | gs_tripleBufferUndetected = true; | | |||
87 | gs_tripleBufferNeedsDetection = false; | | |||
88 | | ||||
89 | if (m_overlayWindow) { | 83 | if (m_overlayWindow) { | ||
90 | if (overlayWindow()->window()) { | 84 | if (overlayWindow()->window()) { | ||
91 | overlayWindow()->destroy(); | 85 | overlayWindow()->destroy(); | ||
92 | } | 86 | } | ||
93 | delete m_overlayWindow; | 87 | delete m_overlayWindow; | ||
94 | } | 88 | } | ||
95 | } | 89 | } | ||
96 | 90 | | |||
Show All 26 Lines | 115 | if (error != EGL_SUCCESS && error != EGL_BAD_ATTRIBUTE) { | |||
123 | return; | 117 | return; | ||
124 | } else { | 118 | } else { | ||
125 | surfaceHasSubPost = EGL_FALSE; | 119 | surfaceHasSubPost = EGL_FALSE; | ||
126 | } | 120 | } | ||
127 | } | 121 | } | ||
128 | } | 122 | } | ||
129 | 123 | | |||
130 | setSyncsToVBlank(false); | 124 | setSyncsToVBlank(false); | ||
131 | setBlocksForRetrace(false); | 125 | setBlocksForRetrace(true); | ||
132 | gs_tripleBufferNeedsDetection = false; | | |||
133 | m_swapProfiler.init(); | | |||
134 | if (surfaceHasSubPost) { | 126 | if (surfaceHasSubPost) { | ||
135 | qCDebug(KWIN_CORE) << "EGL implementation and surface support eglPostSubBufferNV, let's use it"; | 127 | qCDebug(KWIN_CORE) << "EGL implementation and surface support eglPostSubBufferNV, let's use it"; | ||
136 | 128 | | |||
137 | if (options->glPreferBufferSwap() != Options::NoSwapEncourage) { | 129 | if (options->glPreferBufferSwap() != Options::NoSwapEncourage) { | ||
138 | // check if swap interval 1 is supported | 130 | // check if swap interval 1 is supported | ||
139 | EGLint val; | 131 | EGLint val; | ||
140 | eglGetConfigAttrib(eglDisplay(), config(), EGL_MAX_SWAP_INTERVAL, &val); | 132 | eglGetConfigAttrib(eglDisplay(), config(), EGL_MAX_SWAP_INTERVAL, &val); | ||
141 | if (val >= 1) { | 133 | if (val >= 1) { | ||
142 | if (eglSwapInterval(eglDisplay(), 1)) { | 134 | if (eglSwapInterval(eglDisplay(), 1)) { | ||
143 | qCDebug(KWIN_CORE) << "Enabled v-sync"; | 135 | qCDebug(KWIN_CORE) << "Enabled v-sync"; | ||
144 | setSyncsToVBlank(true); | 136 | setSyncsToVBlank(true); | ||
145 | const QByteArray tripleBuffer = qgetenv("KWIN_TRIPLE_BUFFER"); | | |||
146 | if (!tripleBuffer.isEmpty()) { | | |||
147 | setBlocksForRetrace(qstrcmp(tripleBuffer, "0") == 0); | | |||
148 | gs_tripleBufferUndetected = false; | | |||
149 | } | | |||
150 | gs_tripleBufferNeedsDetection = gs_tripleBufferUndetected; | | |||
151 | } | 137 | } | ||
152 | } else { | 138 | } else { | ||
153 | qCWarning(KWIN_CORE) << "Cannot enable v-sync as max. swap interval is" << val; | 139 | qCWarning(KWIN_CORE) << "Cannot enable v-sync as max. swap interval is" << val; | ||
154 | } | 140 | } | ||
155 | } else { | 141 | } else { | ||
156 | // disable v-sync | 142 | // disable v-sync | ||
157 | eglSwapInterval(eglDisplay(), 0); | 143 | eglSwapInterval(eglDisplay(), 0); | ||
158 | } | 144 | } | ||
▲ Show 20 Lines • Show All 179 Lines • ▼ Show 20 Line(s) | |||||
338 | void EglOnXBackend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry) | 324 | void EglOnXBackend::presentSurface(EGLSurface surface, const QRegion &damage, const QRect &screenGeometry) | ||
339 | { | 325 | { | ||
340 | if (damage.isEmpty()) { | 326 | if (damage.isEmpty()) { | ||
341 | return; | 327 | return; | ||
342 | } | 328 | } | ||
343 | const bool fullRepaint = supportsBufferAge() || (damage == screenGeometry); | 329 | const bool fullRepaint = supportsBufferAge() || (damage == screenGeometry); | ||
344 | 330 | | |||
345 | if (fullRepaint || !surfaceHasSubPost) { | 331 | if (fullRepaint || !surfaceHasSubPost) { | ||
346 | if (gs_tripleBufferNeedsDetection) { | | |||
347 | eglWaitGL(); | | |||
348 | m_swapProfiler.begin(); | | |||
349 | } | | |||
350 | // the entire screen changed, or we cannot do partial updates (which implies we enabled surface preservation) | 332 | // the entire screen changed, or we cannot do partial updates (which implies we enabled surface preservation) | ||
351 | eglSwapBuffers(eglDisplay(), surface); | 333 | eglSwapBuffers(eglDisplay(), surface); | ||
352 | if (gs_tripleBufferNeedsDetection) { | | |||
353 | eglWaitGL(); | | |||
354 | if (char result = m_swapProfiler.end()) { | | |||
355 | gs_tripleBufferUndetected = gs_tripleBufferNeedsDetection = false; | | |||
356 | if (result == 'd' && GLPlatform::instance()->driver() == Driver_NVidia) { | | |||
357 | // TODO this is a workaround, we should get __GL_YIELD set before libGL checks it | | |||
358 | if (qstrcmp(qgetenv("__GL_YIELD"), "USLEEP")) { | | |||
359 | options->setGlPreferBufferSwap(0); | | |||
360 | eglSwapInterval(eglDisplay(), 0); | | |||
361 | result = 0; // hint proper behavior | | |||
362 | qCWarning(KWIN_CORE) << "\nIt seems you are using the nvidia driver without triple buffering\n" | | |||
363 | "You must export __GL_YIELD=\"USLEEP\" to prevent large CPU overhead on synced swaps\n" | | |||
364 | "Preferably, enable the TripleBuffer Option in the xorg.conf Device\n" | | |||
365 | "For this reason, the tearing prevention has been disabled.\n" | | |||
366 | "See https://bugs.kde.org/show_bug.cgi?id=322060\n"; | | |||
367 | } | | |||
368 | } | | |||
369 | setBlocksForRetrace(result == 'd'); | | |||
370 | } | | |||
371 | } | | |||
372 | if (supportsBufferAge()) { | 334 | if (supportsBufferAge()) { | ||
373 | eglQuerySurface(eglDisplay(), surface, EGL_BUFFER_AGE_EXT, &m_bufferAge); | 335 | eglQuerySurface(eglDisplay(), surface, EGL_BUFFER_AGE_EXT, &m_bufferAge); | ||
374 | } | 336 | } | ||
375 | } else { | 337 | } else { | ||
376 | // a part of the screen changed, and we can use eglPostSubBufferNV to copy the updated area | 338 | // a part of the screen changed, and we can use eglPostSubBufferNV to copy the updated area | ||
377 | for (const QRect &r : damage) { | 339 | for (const QRect &r : damage) { | ||
378 | eglPostSubBufferNV(eglDisplay(), surface, r.left(), screenGeometry.height() - r.bottom() - 1, r.width(), r.height()); | 340 | eglPostSubBufferNV(eglDisplay(), surface, r.left(), screenGeometry.height() - r.bottom() - 1, r.width(), r.height()); | ||
379 | } | 341 | } | ||
Show All 14 Lines | |||||
394 | { | 356 | { | ||
395 | return new EglTexture(texture, this); | 357 | return new EglTexture(texture, this); | ||
396 | } | 358 | } | ||
397 | 359 | | |||
398 | QRegion EglOnXBackend::prepareRenderingFrame() | 360 | QRegion EglOnXBackend::prepareRenderingFrame() | ||
399 | { | 361 | { | ||
400 | QRegion repaint; | 362 | QRegion repaint; | ||
401 | 363 | | |||
402 | if (gs_tripleBufferNeedsDetection) { | | |||
403 | // the composite timer floors the repaint frequency. This can pollute our triple buffering | | |||
404 | // detection because the glXSwapBuffers call for the new frame has to wait until the pending | | |||
405 | // one scanned out. | | |||
406 | // So we compensate for that by waiting an extra milisecond to give the driver the chance to | | |||
407 | // fllush the buffer queue | | |||
408 | usleep(1000); | | |||
409 | } | | |||
410 | | ||||
411 | present(); | 364 | present(); | ||
412 | 365 | | |||
413 | if (supportsBufferAge()) | 366 | if (supportsBufferAge()) | ||
414 | repaint = accumulatedDamageHistory(m_bufferAge); | 367 | repaint = accumulatedDamageHistory(m_bufferAge); | ||
415 | 368 | | |||
416 | startRenderTimer(); | 369 | startRenderTimer(); | ||
417 | eglWaitNative(EGL_CORE_NATIVE_ENGINE); | 370 | eglWaitNative(EGL_CORE_NATIVE_ENGINE); | ||
418 | 371 | | |||
▲ Show 20 Lines • Show All 126 Lines • Show Last 20 Lines |