[platforms/x11] Use a GlxContextAttributeBuilder

Summary:
Based on the work of 3f4995fb9b this change
introduces a GlxContextAttributeBuilder to make the requesting of context
attributes cleaner, more verbose and less error prone copy and paste.

Test Plan:
Switched between Core and legacy and verified the output;
extended auto test

Reviewers: #kwin, #plasma

Subscribers: plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D6411
icc-effect-5.14.5
Martin Flöser 2017-06-27 21:08:19 +02:00
parent 36a3189863
commit f88c322a3b
7 changed files with 233 additions and 67 deletions

View File

@ -86,6 +86,14 @@ public:
return m_compatibilityProfile;
}
void setResetOnVideoMemoryPurge(bool reset) {
m_resetOnVideoMemoryPurge = reset;
}
bool isResetOnVideoMemoryPurge() const {
return m_resetOnVideoMemoryPurge;
}
virtual std::vector<int> build() const = 0;
QDebug operator<<(QDebug dbg) const;
@ -98,6 +106,7 @@ private:
bool m_forwardCompatible = false;
bool m_coreProfile = false;
bool m_compatibilityProfile = false;
bool m_resetOnVideoMemoryPurge = false;
};
inline QDebug operator<<(QDebug dbg, const AbstractOpenGLContextAttributeBuilder *attribs)

View File

@ -366,7 +366,16 @@ target_link_libraries(testX11TimestampUpdate
add_test(kwin-testX11TimestampUpdate testX11TimestampUpdate)
ecm_mark_as_test(testX11TimestampUpdate)
add_executable(testOpenGLContextAttributeBuilder opengl_context_attribute_builder_test.cpp ../abstract_opengl_context_attribute_builder.cpp ../egl_context_attribute_builder.cpp)
set(testOpenGLContextAttributeBuilder_SRCS
opengl_context_attribute_builder_test.cpp
../abstract_opengl_context_attribute_builder.cpp
../egl_context_attribute_builder.cpp
)
if(HAVE_EPOXY_GLX)
set(testOpenGLContextAttributeBuilder_SRCS ${testOpenGLContextAttributeBuilder_SRCS} ../plugins/platforms/x11/standalone/glx_context_attribute_builder.cpp)
endif()
add_executable(testOpenGLContextAttributeBuilder ${testOpenGLContextAttributeBuilder_SRCS})
target_link_libraries(testOpenGLContextAttributeBuilder Qt5::Test)
add_test(kwin-testOpenGLContextAttributeBuilder testOpenGLContextAttributeBuilder)
ecm_mark_as_test(testOpenGLContextAttributeBuilder)

View File

@ -22,6 +22,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <QtTest/QtTest>
#include <epoxy/egl.h>
#include <kwinconfig.h>
#if HAVE_EPOXY_GLX
#include "../plugins/platforms/x11/standalone/glx_context_attribute_builder.h"
#include <epoxy/glx.h>
#ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
#define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7
#endif
#endif
using namespace KWin;
class OpenGLContextAttributeBuilderTest : public QObject
@ -32,12 +42,15 @@ private Q_SLOTS:
void testRobust();
void testForwardCompatible();
void testProfile();
void testResetOnVideoMemoryPurge();
void testVersionMajor();
void testVersionMajorAndMinor();
void testEgl_data();
void testEgl();
void testGles_data();
void testGles();
void testGlx_data();
void testGlx();
};
class MockOpenGLContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
@ -61,6 +74,7 @@ void OpenGLContextAttributeBuilderTest::testCtor()
QCOMPARE(builder.isForwardCompatible(), false);
QCOMPARE(builder.isCoreProfile(), false);
QCOMPARE(builder.isCompatibilityProfile(), false);
QCOMPARE(builder.isResetOnVideoMemoryPurge(), false);
}
void OpenGLContextAttributeBuilderTest::testRobust()
@ -99,6 +113,16 @@ void OpenGLContextAttributeBuilderTest::testProfile()
QCOMPARE(builder.isCompatibilityProfile(), false);
}
void OpenGLContextAttributeBuilderTest::testResetOnVideoMemoryPurge()
{
MockOpenGLContextAttributeBuilder builder;
QCOMPARE(builder.isResetOnVideoMemoryPurge(), false);
builder.setResetOnVideoMemoryPurge(true);
QCOMPARE(builder.isResetOnVideoMemoryPurge(), true);
builder.setResetOnVideoMemoryPurge(false);
QCOMPARE(builder.isResetOnVideoMemoryPurge(), false);
}
void OpenGLContextAttributeBuilderTest::testVersionMajor()
{
MockOpenGLContextAttributeBuilder builder;
@ -249,5 +273,73 @@ void OpenGLContextAttributeBuilderTest::testGles()
QTEST(attribs, "expectedAttribs");
}
void OpenGLContextAttributeBuilderTest::testGlx_data()
{
#if HAVE_EPOXY_GLX
QTest::addColumn<bool>("requestVersion");
QTest::addColumn<int>("major");
QTest::addColumn<int>("minor");
QTest::addColumn<bool>("robust");
QTest::addColumn<bool>("videoPurge");
QTest::addColumn<std::vector<int>>("expectedAttribs");
QTest::newRow("fallback") << true << 2 << 1 << false << false << std::vector<int>{
GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
0};
QTest::newRow("legacy/robust") << false << 0 << 0 << true << false << std::vector<int>{
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB,
0
};
QTest::newRow("legacy/robust/videoPurge") << false << 0 << 0 << true << true << std::vector<int>{
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB,
GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_TRUE,
0
};
QTest::newRow("core") << true << 3 << 1 << false << false << std::vector<int>{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
0};
QTest::newRow("core/robust") << true << 3 << 1 << true << false << std::vector<int>{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB,
0
};
QTest::newRow("core/robust/videoPurge") << true << 3 << 1 << true << true << std::vector<int>{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB,
GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_TRUE,
0
};
#endif
}
void OpenGLContextAttributeBuilderTest::testGlx()
{
#if HAVE_EPOXY_GLX
QFETCH(bool, requestVersion);
QFETCH(int, major);
QFETCH(int, minor);
QFETCH(bool, robust);
QFETCH(bool, videoPurge);
GlxContextAttributeBuilder builder;
if (requestVersion) {
builder.setVersion(major, minor);
}
builder.setRobust(robust);
builder.setResetOnVideoMemoryPurge(videoPurge);
auto attribs = builder.build();
QTEST(attribs, "expectedAttribs");
#endif
}
QTEST_GUILESS_MAIN(OpenGLContextAttributeBuilderTest)
#include "opengl_context_attribute_builder_test.moc"

View File

@ -13,7 +13,7 @@ if(X11_Xinput_FOUND)
endif()
if(HAVE_EPOXY_GLX)
set(X11PLATFORM_SOURCES ${X11PLATFORM_SOURCES} glxbackend.cpp)
set(X11PLATFORM_SOURCES ${X11PLATFORM_SOURCES} glxbackend.cpp glx_context_attribute_builder.cpp)
endif()
add_library(KWinX11Platform MODULE ${X11PLATFORM_SOURCES})

View File

@ -0,0 +1,53 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2017 Martin Flöser <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "glx_context_attribute_builder.h"
#include <epoxy/glx.h>
#ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
#define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7
#endif
namespace KWin
{
std::vector<int> GlxContextAttributeBuilder::build() const
{
std::vector<int> attribs;
if (isVersionRequested()) {
attribs.emplace_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
attribs.emplace_back(majorVersion());
attribs.emplace_back(GLX_CONTEXT_MINOR_VERSION_ARB);
attribs.emplace_back(minorVersion());
}
if (isRobust()) {
attribs.emplace_back(GLX_CONTEXT_FLAGS_ARB);
attribs.emplace_back(GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB);
attribs.emplace_back(GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB);
attribs.emplace_back(GLX_LOSE_CONTEXT_ON_RESET_ARB);
if (isResetOnVideoMemoryPurge()) {
attribs.emplace_back(GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV);
attribs.emplace_back(GL_TRUE);
}
}
attribs.emplace_back(0);
return attribs;
}
}

View File

@ -0,0 +1,32 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2017 Martin Flöser <mgraesslin@kde.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#pragma once
#include "abstract_opengl_context_attribute_builder.h"
namespace KWin
{
class GlxContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
{
public:
std::vector<int> build() const override;
};
}

View File

@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// own
#include "glxbackend.h"
#include "logging.h"
#include "glx_context_attribute_builder.h"
// kwin
#include "options.h"
#include "overlaywindow.h"
@ -65,10 +66,6 @@ typedef struct xcb_glx_buffer_swap_complete_event_t {
} xcb_glx_buffer_swap_complete_event_t;
#endif
#ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
#define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7
#endif
#include <tuple>
#include <memory>
@ -288,77 +285,51 @@ bool GlxBackend::initRenderingContext()
// Use glXCreateContextAttribsARB() when it's available
if (hasExtension(QByteArrayLiteral("GLX_ARB_create_context"))) {
const int attribs_31_core_nv_robustness[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB,
GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_TRUE,
0
};
const int attribs_31_core_robustness[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB,
0
};
const int attribs_31_core[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
0
};
const int attribs_legacy_nv_robustness[] = {
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB,
GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV, GL_TRUE,
0
};
const int attribs_legacy_robustness[] = {
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB,
GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB, GLX_LOSE_CONTEXT_ON_RESET_ARB,
0
};
const int attribs_legacy[] = {
GLX_CONTEXT_MAJOR_VERSION_ARB, 2,
GLX_CONTEXT_MINOR_VERSION_ARB, 1,
0
};
const bool have_robustness = hasExtension(QByteArrayLiteral("GLX_ARB_create_context_robustness"));
const bool haveVideoMemoryPurge = hasExtension(QByteArrayLiteral("GLX_NV_robustness_video_memory_purge"));
// Try to create a 3.1 context first
std::vector<GlxContextAttributeBuilder> candidates;
if (options->glCoreProfile()) {
if (have_robustness) {
if (have_robustness) {
if (haveVideoMemoryPurge) {
ctx = glXCreateContextAttribsARB(display(), fbconfig, 0, direct, attribs_31_core_nv_robustness);
}
if (!ctx) {
ctx = glXCreateContextAttribsARB(display(), fbconfig, 0, direct, attribs_31_core_robustness);
GlxContextAttributeBuilder purgeMemoryCore;
purgeMemoryCore.setVersion(3, 1);
purgeMemoryCore.setRobust(true);
purgeMemoryCore.setResetOnVideoMemoryPurge(true);
candidates.emplace_back(std::move(purgeMemoryCore));
}
GlxContextAttributeBuilder robustCore;
robustCore.setVersion(3, 1);
robustCore.setRobust(true);
candidates.emplace_back(std::move(robustCore));
}
if (!ctx)
ctx = glXCreateContextAttribsARB(display(), fbconfig, 0, direct, attribs_31_core);
GlxContextAttributeBuilder core;
core.setVersion(3, 1);
candidates.emplace_back(std::move(core));
} else {
if (have_robustness) {
if (haveVideoMemoryPurge) {
GlxContextAttributeBuilder purgeMemoryLegacy;
purgeMemoryLegacy.setRobust(true);
purgeMemoryLegacy.setResetOnVideoMemoryPurge(true);
candidates.emplace_back(std::move(purgeMemoryLegacy));
}
GlxContextAttributeBuilder robustLegacy;
robustLegacy.setRobust(true);
candidates.emplace_back(std::move(robustLegacy));
}
GlxContextAttributeBuilder legacy;
legacy.setVersion(2, 1);
candidates.emplace_back(std::move(legacy));
}
if (!ctx && have_robustness) {
if (haveVideoMemoryPurge) {
ctx = glXCreateContextAttribsARB(display(), fbconfig, 0, direct, attribs_legacy_nv_robustness);
}
if (!ctx) {
ctx = glXCreateContextAttribsARB(display(), fbconfig, 0, direct, attribs_legacy_robustness);
for (auto it = candidates.begin(); it != candidates.end(); it++) {
const auto attribs = it->build();
ctx = glXCreateContextAttribsARB(display(), fbconfig, 0, true, attribs.data());
if (ctx) {
qCDebug(KWIN_X11STANDALONE) << "Created GLX context with attributes:" << &(*it);
break;
}
}
if (!ctx)
ctx = glXCreateContextAttribsARB(display(), fbconfig, 0, direct, attribs_legacy);
}
if (!ctx)