Add support for GLX_INTEL_swap_event

Enable swap events and use them to defer rendering of the next frame
until the last glXSwapBuffers() call has completed.
This commit is contained in:
Fredrik Höglund 2014-08-07 14:16:35 +02:00
parent 29795f49e8
commit ad0abdc812
2 changed files with 77 additions and 0 deletions

View file

@ -30,6 +30,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "options.h"
#include "utils.h"
#include "overlaywindow.h"
#include "composite.h"
#include "xcbutils.h"
// kwin libs
#include <kwinglplatform.h>
#include <kwinxrenderutils.h>
@ -38,11 +40,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QOpenGLContext>
// system
#include <unistd.h>
#include <xcb/glx.h>
#include <tuple>
#if __cplusplus <= 201103L
namespace std {
// C++-14
template<class T, class... Args>
unique_ptr<T> make_unique(Args&&... args) {
return unique_ptr<T>(new T(std::forward<Args>(args)...));
}
}
#endif
namespace KWin
{
SwapEventFilter::SwapEventFilter(xcb_drawable_t drawable)
: X11EventFilter(Xcb::Extensions::self()->glxEventBase() + XCB_GLX_BUFFER_SWAP_COMPLETE),
m_drawable(drawable)
{
}
bool SwapEventFilter::event(xcb_generic_event_t *event)
{
xcb_glx_buffer_swap_complete_event_t *ev =
reinterpret_cast<xcb_glx_buffer_swap_complete_event_t *>(event);
if (ev->drawable == m_drawable) {
Compositor::self()->bufferSwapComplete();
return true;
}
return false;
}
// -----------------------------------------------------------------------
GlxBackend::GlxBackend()
: OpenGLBackend()
, m_overlayWindow(new OverlayWindow())
@ -116,6 +155,21 @@ void GlxBackend::init()
m_haveMESASwapControl = hasGLExtension(QByteArrayLiteral("GLX_MESA_swap_control"));
m_haveEXTSwapControl = hasGLExtension(QByteArrayLiteral("GLX_EXT_swap_control"));
m_haveSGISwapControl = hasGLExtension(QByteArrayLiteral("GLX_SGI_swap_control"));
m_haveINTELSwapEvent = hasGLExtension(QByteArrayLiteral("GLX_INTEL_swap_event"));
if (m_haveINTELSwapEvent) {
const QList<QByteArray> tokens = QByteArray(qVersion()).split('.');
uint32_t version = tokens[0].toInt() << 16 | tokens[1].toInt() << 8 | tokens[2].toInt();
// Qt 5.3 doesn't forward swap events to the native event filter
if (version < 0x00050400)
m_haveINTELSwapEvent = false;
}
if (m_haveINTELSwapEvent) {
m_swapEventFilter = std::make_unique<SwapEventFilter>(window);
glXSelectEvent(display(), glxWindow, GLX_BUFFER_SWAP_COMPLETE_INTEL_MASK);
}
haveSwapInterval = m_haveMESASwapControl || m_haveEXTSwapControl || m_haveSGISwapControl;
@ -473,6 +527,9 @@ void GlxBackend::present()
const bool fullRepaint = supportsBufferAge() || (lastDamage() == displayRegion);
if (fullRepaint) {
if (m_haveINTELSwapEvent)
Compositor::self()->aboutToSwapBuffers();
if (haveSwapInterval) {
if (gs_tripleBufferNeedsDetection) {
glXWaitGL();

View file

@ -20,6 +20,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef KWIN_GLX_BACKEND_H
#define KWIN_GLX_BACKEND_H
#include "scene_opengl.h"
#include "x11eventfilter.h"
#include <memory>
namespace KWin
{
@ -34,6 +37,21 @@ public:
int mipmap;
};
// ------------------------------------------------------------------
class SwapEventFilter : public X11EventFilter
{
public:
SwapEventFilter(xcb_drawable_t drawable);
bool event(xcb_generic_event_t *event) override;
private:
xcb_drawable_t m_drawable;
};
/**
* @brief OpenGL Backend using GLX over an X overlay window.
**/
@ -76,11 +94,13 @@ private:
GLXContext ctx;
QHash<xcb_visualid_t, FBConfigInfo *> m_fbconfigHash;
QHash<xcb_visualid_t, int> m_visualDepthHash;
std::unique_ptr<SwapEventFilter> m_swapEventFilter;
int m_bufferAge;
bool m_haveMESACopySubBuffer;
bool m_haveMESASwapControl;
bool m_haveEXTSwapControl;
bool m_haveSGISwapControl;
bool m_haveINTELSwapEvent;
bool haveSwapInterval, haveWaitSync;
friend class GlxTexture;
};