diff --git a/CMakeLists.txt b/CMakeLists.txt
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -440,6 +440,8 @@
xkb.cpp
gestures.cpp
popup_input_filter.cpp
+ abstract_opengl_context_attribute_builder.cpp
+ egl_context_attribute_builder.cpp
)
if(KWIN_BUILD_TABBOX)
diff --git a/abstract_egl_backend.cpp b/abstract_egl_backend.cpp
--- a/abstract_egl_backend.cpp
+++ b/abstract_egl_backend.cpp
@@ -18,6 +18,7 @@
along with this program. If not, see .
*********************************************************************/
#include "abstract_egl_backend.h"
+#include "egl_context_attribute_builder.h"
#include "options.h"
#include "platform.h"
#include "wayland_server.h"
@@ -30,6 +31,8 @@
#include
#include
+#include
+
namespace KWin
{
@@ -206,63 +209,44 @@
const bool haveRobustness = hasExtension(QByteArrayLiteral("EGL_EXT_create_context_robustness"));
const bool haveCreateContext = hasExtension(QByteArrayLiteral("EGL_KHR_create_context"));
- EGLContext ctx = EGL_NO_CONTEXT;
+ std::vector> candidates;
if (isOpenGLES()) {
if (haveCreateContext && haveRobustness) {
- const EGLint context_attribs[] = {
- EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE,
- EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET_EXT,
- EGL_NONE
- };
- ctx = eglCreateContext(m_display, config(), EGL_NO_CONTEXT, context_attribs);
- }
- if (ctx == EGL_NO_CONTEXT) {
- const EGLint context_attribs[] = {
- EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL_NONE
- };
-
- ctx = eglCreateContext(m_display, config(), EGL_NO_CONTEXT, context_attribs);
+ auto glesRobust = std::unique_ptr(new EglOpenGLESContextAttributeBuilder);
+ glesRobust->setVersion(2);
+ glesRobust->setRobust(true);
+ candidates.push_back(std::move(glesRobust));
}
+ auto gles = std::unique_ptr(new EglOpenGLESContextAttributeBuilder);
+ gles->setVersion(2);
+ candidates.push_back(std::move(gles));
} else {
- // Try to create a 3.1 core context
if (options->glCoreProfile() && haveCreateContext) {
if (haveRobustness) {
- const int attribs[] = {
- EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
- EGL_CONTEXT_MINOR_VERSION_KHR, 1,
- EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR,
- EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR,
- EGL_NONE
- };
- ctx = eglCreateContext(m_display, config(), EGL_NO_CONTEXT, attribs);
- }
- if (ctx == EGL_NO_CONTEXT) {
- // try without robustness
- const EGLint attribs[] = {
- EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
- EGL_CONTEXT_MINOR_VERSION_KHR, 1,
- EGL_NONE
- };
- ctx = eglCreateContext(m_display, config(), EGL_NO_CONTEXT, attribs);
+ auto robustCore = std::unique_ptr(new EglContextAttributeBuilder);
+ robustCore->setVersion(3, 1);
+ robustCore->setRobust(true);
+ candidates.push_back(std::move(robustCore));
}
+ auto core = std::unique_ptr(new EglContextAttributeBuilder);
+ core->setVersion(3, 1);
+ candidates.push_back(std::move(core));
}
-
- if (ctx == EGL_NO_CONTEXT && haveRobustness && haveCreateContext) {
- const int attribs[] = {
- EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR,
- EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR,
- EGL_NONE
- };
- ctx = eglCreateContext(m_display, config(), EGL_NO_CONTEXT, attribs);
+ if (haveRobustness && haveCreateContext) {
+ auto robust = std::unique_ptr(new EglContextAttributeBuilder);
+ robust->setRobust(true);
+ candidates.push_back(std::move(robust));
}
- if (ctx == EGL_NO_CONTEXT) {
- // and last but not least: try without robustness
- const EGLint attribs[] = {
- EGL_NONE
- };
- ctx = eglCreateContext(m_display, config(), EGL_NO_CONTEXT, attribs);
+ candidates.emplace_back(new EglContextAttributeBuilder);
+ }
+
+ EGLContext ctx = EGL_NO_CONTEXT;
+ for (auto it = candidates.begin(); it != candidates.end(); it++) {
+ const auto attribs = (*it)->build();
+ ctx = eglCreateContext(m_display, config(), EGL_NO_CONTEXT, attribs.data());
+ if (ctx != EGL_NO_CONTEXT) {
+ qCDebug(KWIN_CORE) << "Created EGL context with attributes:" << (*it).get();
+ break;
}
}
diff --git a/abstract_opengl_context_attribute_builder.h b/abstract_opengl_context_attribute_builder.h
new file mode 100644
--- /dev/null
+++ b/abstract_opengl_context_attribute_builder.h
@@ -0,0 +1,74 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2017 Martin Flöser
+
+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 .
+*********************************************************************/
+#pragma once
+#include
+
+namespace KWin
+{
+
+class AbstractOpenGLContextAttributeBuilder
+{
+public:
+ virtual ~AbstractOpenGLContextAttributeBuilder() {
+ }
+
+ void setVersion(int major, int minor = 0) {
+ m_versionRequested = true;
+ m_majorVersion = major;
+ m_minorVersion = minor;
+ }
+
+ bool isVersionRequested() const {
+ return m_versionRequested;
+ }
+
+ int majorVersion() const {
+ return m_majorVersion;
+ }
+
+ int minorVersion() const {
+ return m_minorVersion;
+ }
+
+ void setRobust(bool robust) {
+ m_robust = robust;
+ }
+
+ bool isRobust() const {
+ return m_robust;
+ }
+
+ virtual std::vector build() const = 0;
+
+ QDebug operator<<(QDebug dbg) const;
+
+private:
+ bool m_versionRequested = false;
+ int m_majorVersion = 0;
+ int m_minorVersion = 0;
+ bool m_robust = false;
+};
+
+inline QDebug operator<<(QDebug dbg, const AbstractOpenGLContextAttributeBuilder *attribs)
+{
+ return attribs->operator<<(dbg);
+}
+
+}
diff --git a/abstract_opengl_context_attribute_builder.cpp b/abstract_opengl_context_attribute_builder.cpp
new file mode 100644
--- /dev/null
+++ b/abstract_opengl_context_attribute_builder.cpp
@@ -0,0 +1,36 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2017 Martin Flöser
+
+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 .
+*********************************************************************/
+#include "abstract_opengl_context_attribute_builder.h"
+
+namespace KWin
+{
+
+QDebug AbstractOpenGLContextAttributeBuilder::operator<<(QDebug dbg) const
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace() << "\nVersion requested:\t" << isVersionRequested() << "\n";
+ if (isVersionRequested()) {
+ dbg.nospace() << "Version:\t" << majorVersion() << "." << minorVersion() << "\n";
+ }
+ dbg.nospace() << "Robust:\t" << isRobust();
+ return dbg;
+}
+
+}
diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt
--- a/autotests/CMakeLists.txt
+++ b/autotests/CMakeLists.txt
@@ -361,3 +361,8 @@
)
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)
+target_link_libraries(testOpenGLContextAttributeBuilder Qt5::Test)
+add_test(kwin-testOpenGLContextAttributeBuilder testOpenGLContextAttributeBuilder)
+ecm_mark_as_test(testOpenGLContextAttributeBuilder)
diff --git a/autotests/opengl_context_attribute_builder_test.cpp b/autotests/opengl_context_attribute_builder_test.cpp
new file mode 100644
--- /dev/null
+++ b/autotests/opengl_context_attribute_builder_test.cpp
@@ -0,0 +1,170 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2017 Martin Flöser
+
+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 .
+*********************************************************************/
+#include "../abstract_opengl_context_attribute_builder.h"
+#include "../egl_context_attribute_builder.h"
+#include
+#include
+
+using namespace KWin;
+
+class OpenGLContextAttributeBuilderTest : public QObject
+{
+ Q_OBJECT
+private Q_SLOTS:
+ void testCtor();
+ void testRobust();
+ void testVersionMajor();
+ void testVersionMajorAndMinor();
+ void testEgl_data();
+ void testEgl();
+ void testGles_data();
+ void testGles();
+};
+
+class MockOpenGLContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
+{
+public:
+ std::vector build() const override;
+};
+
+std::vector MockOpenGLContextAttributeBuilder::build() const
+{
+ return std::vector();
+}
+
+void OpenGLContextAttributeBuilderTest::testCtor()
+{
+ MockOpenGLContextAttributeBuilder builder;
+ QCOMPARE(builder.isVersionRequested(), false);
+ QCOMPARE(builder.majorVersion(), 0);
+ QCOMPARE(builder.minorVersion(), 0);
+ QCOMPARE(builder.isRobust(), false);
+}
+
+void OpenGLContextAttributeBuilderTest::testRobust()
+{
+ MockOpenGLContextAttributeBuilder builder;
+ QCOMPARE(builder.isRobust(), false);
+ builder.setRobust(true);
+ QCOMPARE(builder.isRobust(), true);
+ builder.setRobust(false);
+ QCOMPARE(builder.isRobust(), false);
+}
+
+void OpenGLContextAttributeBuilderTest::testVersionMajor()
+{
+ MockOpenGLContextAttributeBuilder builder;
+ builder.setVersion(2);
+ QCOMPARE(builder.isVersionRequested(), true);
+ QCOMPARE(builder.majorVersion(), 2);
+ QCOMPARE(builder.minorVersion(), 0);
+ builder.setVersion(3);
+ QCOMPARE(builder.isVersionRequested(), true);
+ QCOMPARE(builder.majorVersion(), 3);
+ QCOMPARE(builder.minorVersion(), 0);
+}
+
+void OpenGLContextAttributeBuilderTest::testVersionMajorAndMinor()
+{
+ MockOpenGLContextAttributeBuilder builder;
+ builder.setVersion(2, 1);
+ QCOMPARE(builder.isVersionRequested(), true);
+ QCOMPARE(builder.majorVersion(), 2);
+ QCOMPARE(builder.minorVersion(), 1);
+ builder.setVersion(3, 2);
+ QCOMPARE(builder.isVersionRequested(), true);
+ QCOMPARE(builder.majorVersion(), 3);
+ QCOMPARE(builder.minorVersion(), 2);
+}
+
+void OpenGLContextAttributeBuilderTest::testEgl_data()
+{
+ QTest::addColumn("requestVersion");
+ QTest::addColumn("major");
+ QTest::addColumn("minor");
+ QTest::addColumn("robust");
+ QTest::addColumn>("expectedAttribs");
+
+ QTest::newRow("fallback") << false << 0 << 0 << false << std::vector{EGL_NONE};
+ QTest::newRow("legacy/robust") << false << 0 << 0 << true <<
+ std::vector{
+ EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR,
+ EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR,
+ EGL_NONE};
+ QTest::newRow("core") << true << 3 << 1 << false <<
+ std::vector{
+ EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
+ EGL_CONTEXT_MINOR_VERSION_KHR, 1,
+ EGL_NONE};
+ QTest::newRow("core/robust") << true << 3 << 1 << true <<
+ std::vector{
+ EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
+ EGL_CONTEXT_MINOR_VERSION_KHR, 1,
+ EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR, EGL_LOSE_CONTEXT_ON_RESET_KHR,
+ EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR,
+ EGL_NONE};
+}
+
+void OpenGLContextAttributeBuilderTest::testEgl()
+{
+ QFETCH(bool, requestVersion);
+ QFETCH(int, major);
+ QFETCH(int, minor);
+ QFETCH(bool, robust);
+
+ EglContextAttributeBuilder builder;
+ if (requestVersion) {
+ builder.setVersion(major, minor);
+ }
+ builder.setRobust(robust);
+
+ auto attribs = builder.build();
+ QTEST(attribs, "expectedAttribs");
+}
+
+void OpenGLContextAttributeBuilderTest::testGles_data()
+{
+ QTest::addColumn("robust");
+ QTest::addColumn>("expectedAttribs");
+
+ QTest::newRow("robust") << true << std::vector{
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT, EGL_TRUE,
+ EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT, EGL_LOSE_CONTEXT_ON_RESET_EXT,
+ EGL_NONE};
+ QTest::newRow("normal") << false << std::vector{
+ EGL_CONTEXT_CLIENT_VERSION, 2,
+ EGL_NONE};
+}
+
+void OpenGLContextAttributeBuilderTest::testGles()
+{
+ QFETCH(bool, robust);
+
+ EglOpenGLESContextAttributeBuilder builder;
+ builder.setVersion(2);
+ builder.setRobust(robust);
+
+ auto attribs = builder.build();
+ QTEST(attribs, "expectedAttribs");
+}
+
+QTEST_GUILESS_MAIN(OpenGLContextAttributeBuilderTest)
+#include "opengl_context_attribute_builder_test.moc"
diff --git a/egl_context_attribute_builder.h b/egl_context_attribute_builder.h
new file mode 100644
--- /dev/null
+++ b/egl_context_attribute_builder.h
@@ -0,0 +1,38 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2017 Martin Flöser
+
+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 .
+*********************************************************************/
+#pragma once
+#include "abstract_opengl_context_attribute_builder.h"
+
+namespace KWin
+{
+
+class EglContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
+{
+public:
+ std::vector build() const override;
+};
+
+class EglOpenGLESContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
+{
+public:
+ std::vector build() const override;
+};
+
+}
diff --git a/egl_context_attribute_builder.cpp b/egl_context_attribute_builder.cpp
new file mode 100644
--- /dev/null
+++ b/egl_context_attribute_builder.cpp
@@ -0,0 +1,59 @@
+/********************************************************************
+ KWin - the KDE window manager
+ This file is part of the KDE project.
+
+Copyright (C) 2017 Martin Flöser
+
+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 .
+*********************************************************************/
+#include "egl_context_attribute_builder.h"
+#include
+
+namespace KWin
+{
+std::vector EglContextAttributeBuilder::build() const
+{
+ std::vector attribs;
+ if (isVersionRequested()) {
+ attribs.emplace_back(EGL_CONTEXT_MAJOR_VERSION_KHR);
+ attribs.emplace_back(majorVersion());
+ attribs.emplace_back(EGL_CONTEXT_MINOR_VERSION_KHR);
+ attribs.emplace_back(minorVersion());
+ }
+ if (isRobust()) {
+ attribs.emplace_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
+ attribs.emplace_back(EGL_LOSE_CONTEXT_ON_RESET_KHR);
+ attribs.emplace_back(EGL_CONTEXT_FLAGS_KHR);
+ attribs.emplace_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
+ }
+ attribs.emplace_back(EGL_NONE);
+ return attribs;
+}
+
+std::vector EglOpenGLESContextAttributeBuilder::build() const
+{
+ std::vector attribs;
+ attribs.emplace_back(EGL_CONTEXT_CLIENT_VERSION);
+ attribs.emplace_back(majorVersion());
+ if (isRobust()) {
+ attribs.emplace_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT);
+ attribs.emplace_back(EGL_TRUE);
+ attribs.emplace_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT);
+ attribs.emplace_back(EGL_LOSE_CONTEXT_ON_RESET_EXT);
+ }
+ attribs.emplace_back(EGL_NONE);
+ return attribs;
+}
+
+}