diff --git a/abstract_opengl_context_attribute_builder.cpp b/abstract_opengl_context_attribute_builder.cpp
index 65ed87232f..74071072a5 100644
--- a/abstract_opengl_context_attribute_builder.cpp
+++ b/abstract_opengl_context_attribute_builder.cpp
@@ -29,7 +29,10 @@ QDebug AbstractOpenGLContextAttributeBuilder::operator<<(QDebug dbg) const
if (isVersionRequested()) {
dbg.nospace() << "Version:\t" << majorVersion() << "." << minorVersion() << "\n";
}
- dbg.nospace() << "Robust:\t" << isRobust();
+ dbg.nospace() << "Robust:\t" << isRobust() << "\n";
+ dbg.nospace() << "Forward compatible:\t" << isForwardCompatible() << "\n";
+ dbg.nospace() << "Core profile:\t" << isCoreProfile() << "\n";
+ dbg.nospace() << "Compatibility profile:\t" << isCompatibilityProfile();
return dbg;
}
diff --git a/abstract_opengl_context_attribute_builder.h b/abstract_opengl_context_attribute_builder.h
index 662bab005d..a9de941258 100644
--- a/abstract_opengl_context_attribute_builder.h
+++ b/abstract_opengl_context_attribute_builder.h
@@ -19,11 +19,12 @@ along with this program. If not, see .
*********************************************************************/
#pragma once
#include
+#include
namespace KWin
{
-class AbstractOpenGLContextAttributeBuilder
+class KWIN_EXPORT AbstractOpenGLContextAttributeBuilder
{
public:
virtual ~AbstractOpenGLContextAttributeBuilder() {
@@ -55,6 +56,36 @@ public:
return m_robust;
}
+ void setForwardCompatible(bool forward) {
+ m_forwardCompatible = forward;
+ }
+
+ bool isForwardCompatible() const {
+ return m_forwardCompatible;
+ }
+
+ void setCoreProfile(bool core) {
+ m_coreProfile = core;
+ if (m_coreProfile) {
+ setCompatibilityProfile(false);
+ }
+ }
+
+ bool isCoreProfile() const {
+ return m_coreProfile;
+ }
+
+ void setCompatibilityProfile(bool compatibility) {
+ m_compatibilityProfile = compatibility;
+ if (m_compatibilityProfile) {
+ setCoreProfile(false);
+ }
+ }
+
+ bool isCompatibilityProfile() const {
+ return m_compatibilityProfile;
+ }
+
virtual std::vector build() const = 0;
QDebug operator<<(QDebug dbg) const;
@@ -64,6 +95,9 @@ private:
int m_majorVersion = 0;
int m_minorVersion = 0;
bool m_robust = false;
+ bool m_forwardCompatible = false;
+ bool m_coreProfile = false;
+ bool m_compatibilityProfile = false;
};
inline QDebug operator<<(QDebug dbg, const AbstractOpenGLContextAttributeBuilder *attribs)
diff --git a/autotests/opengl_context_attribute_builder_test.cpp b/autotests/opengl_context_attribute_builder_test.cpp
index 26b49b69a4..0bf9c3fd36 100644
--- a/autotests/opengl_context_attribute_builder_test.cpp
+++ b/autotests/opengl_context_attribute_builder_test.cpp
@@ -30,6 +30,8 @@ class OpenGLContextAttributeBuilderTest : public QObject
private Q_SLOTS:
void testCtor();
void testRobust();
+ void testForwardCompatible();
+ void testProfile();
void testVersionMajor();
void testVersionMajorAndMinor();
void testEgl_data();
@@ -56,6 +58,9 @@ void OpenGLContextAttributeBuilderTest::testCtor()
QCOMPARE(builder.majorVersion(), 0);
QCOMPARE(builder.minorVersion(), 0);
QCOMPARE(builder.isRobust(), false);
+ QCOMPARE(builder.isForwardCompatible(), false);
+ QCOMPARE(builder.isCoreProfile(), false);
+ QCOMPARE(builder.isCompatibilityProfile(), false);
}
void OpenGLContextAttributeBuilderTest::testRobust()
@@ -68,6 +73,32 @@ void OpenGLContextAttributeBuilderTest::testRobust()
QCOMPARE(builder.isRobust(), false);
}
+void OpenGLContextAttributeBuilderTest::testForwardCompatible()
+{
+ MockOpenGLContextAttributeBuilder builder;
+ QCOMPARE(builder.isForwardCompatible(), false);
+ builder.setForwardCompatible(true);
+ QCOMPARE(builder.isForwardCompatible(), true);
+ builder.setForwardCompatible(false);
+ QCOMPARE(builder.isForwardCompatible(), false);
+}
+
+void OpenGLContextAttributeBuilderTest::testProfile()
+{
+ MockOpenGLContextAttributeBuilder builder;
+ QCOMPARE(builder.isCoreProfile(), false);
+ QCOMPARE(builder.isCompatibilityProfile(), false);
+ builder.setCoreProfile(true);
+ QCOMPARE(builder.isCoreProfile(), true);
+ QCOMPARE(builder.isCompatibilityProfile(), false);
+ builder.setCompatibilityProfile(true);
+ QCOMPARE(builder.isCoreProfile(), false);
+ QCOMPARE(builder.isCompatibilityProfile(), true);
+ builder.setCoreProfile(true);
+ QCOMPARE(builder.isCoreProfile(), true);
+ QCOMPARE(builder.isCompatibilityProfile(), false);
+}
+
void OpenGLContextAttributeBuilderTest::testVersionMajor()
{
MockOpenGLContextAttributeBuilder builder;
@@ -100,26 +131,72 @@ void OpenGLContextAttributeBuilderTest::testEgl_data()
QTest::addColumn("major");
QTest::addColumn("minor");
QTest::addColumn("robust");
+ QTest::addColumn("forwardCompatible");
+ QTest::addColumn("coreProfile");
+ QTest::addColumn("compatibilityProfile");
QTest::addColumn>("expectedAttribs");
- QTest::newRow("fallback") << false << 0 << 0 << false << std::vector{EGL_NONE};
- QTest::newRow("legacy/robust") << false << 0 << 0 << true <<
+ QTest::newRow("fallback") << false << 0 << 0 << false << false << false << false << std::vector{EGL_NONE};
+ QTest::newRow("legacy/robust") << false << 0 << 0 << true << false << false << false <<
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 <<
+ QTest::newRow("core") << true << 3 << 1 << false << false << false << 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 <<
+ QTest::newRow("core/robust") << true << 3 << 1 << true << false << false << false <<
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};
+ QTest::newRow("core/robust/forward compatible") << true << 3 << 1 << true << true << false << false <<
+ 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_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
+ EGL_NONE};
+ QTest::newRow("core/forward compatible") << true << 3 << 1 << false << true << false << false <<
+ std::vector{
+ EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
+ EGL_CONTEXT_MINOR_VERSION_KHR, 1,
+ EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
+ EGL_NONE};
+ QTest::newRow("core profile/forward compatible") << true << 3 << 2 << false << true << true << false <<
+ std::vector{
+ EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
+ EGL_CONTEXT_MINOR_VERSION_KHR, 2,
+ EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
+ EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
+ EGL_NONE};
+ QTest::newRow("compatibility profile/forward compatible") << true << 3 << 2 << false << true << false << true <<
+ std::vector{
+ EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
+ EGL_CONTEXT_MINOR_VERSION_KHR, 2,
+ EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
+ EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR,
+ EGL_NONE};
+ QTest::newRow("core profile/robust/forward compatible") << true << 3 << 2 << true << true << true << false <<
+ std::vector{
+ EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
+ EGL_CONTEXT_MINOR_VERSION_KHR, 2,
+ 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_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
+ EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR,
+ EGL_NONE};
+ QTest::newRow("compatibility profile/robust/forward compatible") << true << 3 << 2 << true << true << false << true <<
+ std::vector{
+ EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
+ EGL_CONTEXT_MINOR_VERSION_KHR, 2,
+ 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_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
+ EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR,
+ EGL_NONE};
}
void OpenGLContextAttributeBuilderTest::testEgl()
@@ -128,12 +205,18 @@ void OpenGLContextAttributeBuilderTest::testEgl()
QFETCH(int, major);
QFETCH(int, minor);
QFETCH(bool, robust);
+ QFETCH(bool, forwardCompatible);
+ QFETCH(bool, coreProfile);
+ QFETCH(bool, compatibilityProfile);
EglContextAttributeBuilder builder;
if (requestVersion) {
builder.setVersion(major, minor);
}
builder.setRobust(robust);
+ builder.setForwardCompatible(forwardCompatible);
+ builder.setCoreProfile(coreProfile);
+ builder.setCompatibilityProfile(compatibilityProfile);
auto attribs = builder.build();
QTEST(attribs, "expectedAttribs");
diff --git a/egl_context_attribute_builder.cpp b/egl_context_attribute_builder.cpp
index feb790cc85..87fa20f789 100644
--- a/egl_context_attribute_builder.cpp
+++ b/egl_context_attribute_builder.cpp
@@ -31,11 +31,26 @@ std::vector EglContextAttributeBuilder::build() const
attribs.emplace_back(EGL_CONTEXT_MINOR_VERSION_KHR);
attribs.emplace_back(minorVersion());
}
+ int contextFlags = 0;
if (isRobust()) {
attribs.emplace_back(EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR);
attribs.emplace_back(EGL_LOSE_CONTEXT_ON_RESET_KHR);
+ contextFlags |= EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR;
+ }
+ if (isForwardCompatible()) {
+ contextFlags |= EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR;
+ }
+ if (contextFlags != 0) {
attribs.emplace_back(EGL_CONTEXT_FLAGS_KHR);
- attribs.emplace_back(EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR);
+ attribs.emplace_back(contextFlags);
+ }
+ if (isCoreProfile() || isCompatibilityProfile()) {
+ attribs.emplace_back(EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR);
+ if (isCoreProfile()) {
+ attribs.emplace_back(EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR);
+ } else if (isCompatibilityProfile()) {
+ attribs.emplace_back(EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR);
+ }
}
attribs.emplace_back(EGL_NONE);
return attribs;
diff --git a/egl_context_attribute_builder.h b/egl_context_attribute_builder.h
index 100b746701..6f4c6cb12b 100644
--- a/egl_context_attribute_builder.h
+++ b/egl_context_attribute_builder.h
@@ -19,17 +19,18 @@ along with this program. If not, see .
*********************************************************************/
#pragma once
#include "abstract_opengl_context_attribute_builder.h"
+#include
namespace KWin
{
-class EglContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
+class KWIN_EXPORT EglContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
{
public:
std::vector build() const override;
};
-class EglOpenGLESContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
+class KWIN_EXPORT EglOpenGLESContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
{
public:
std::vector build() const override;
diff --git a/plugins/qpa/abstractplatformcontext.cpp b/plugins/qpa/abstractplatformcontext.cpp
index 2111b6e225..1acd8464cd 100644
--- a/plugins/qpa/abstractplatformcontext.cpp
+++ b/plugins/qpa/abstractplatformcontext.cpp
@@ -19,8 +19,11 @@ along with this program. If not, see .
*********************************************************************/
#include "abstractplatformcontext.h"
#include "integration.h"
+#include "egl_context_attribute_builder.h"
#include
+#include
+
namespace KWin
{
@@ -145,66 +148,58 @@ void AbstractPlatformContext::createContext(EGLContext shareContext)
const bool haveRobustness = extensions.contains(QByteArrayLiteral("EGL_EXT_create_context_robustness"));
const bool haveCreateContext = extensions.contains(QByteArrayLiteral("EGL_KHR_create_context"));
- EGLContext context = 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
- };
- context = eglCreateContext(eglDisplay(), config(), shareContext, context_attribs);
- }
- if (context == EGL_NO_CONTEXT) {
- const EGLint context_attribs[] = {
- EGL_CONTEXT_CLIENT_VERSION, 2,
- EGL_NONE
- };
-
- context = eglCreateContext(eglDisplay(), config(), shareContext, 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 (m_format.majorVersion() >= 3 && haveCreateContext) {
if (haveRobustness) {
- const int attribs[] = {
- EGL_CONTEXT_MAJOR_VERSION_KHR, m_format.majorVersion(),
- EGL_CONTEXT_MINOR_VERSION_KHR, m_format.minorVersion(),
- 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_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
- EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, m_format.profile() == QSurfaceFormat::CoreProfile ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR,
- EGL_NONE
- };
- context = eglCreateContext(eglDisplay(), config(), shareContext, attribs);
+ auto robustCore = std::unique_ptr(new EglContextAttributeBuilder);
+ robustCore->setVersion(m_format.majorVersion(), m_format.minorVersion());
+ robustCore->setRobust(true);
+ robustCore->setForwardCompatible(true);
+ if (m_format.profile() == QSurfaceFormat::CoreProfile) {
+ robustCore->setCoreProfile(true);
+ } else if (m_format.profile() == QSurfaceFormat::CompatibilityProfile) {
+ robustCore->setCompatibilityProfile(true);
+ }
+ candidates.push_back(std::move(robustCore));
}
- if (context == EGL_NO_CONTEXT) {
- // try without robustness
- const EGLint attribs[] = {
- EGL_CONTEXT_MAJOR_VERSION_KHR, m_format.majorVersion(),
- EGL_CONTEXT_MINOR_VERSION_KHR, m_format.minorVersion(),
- EGL_CONTEXT_FLAGS_KHR, EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR,
- EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, m_format.profile() == QSurfaceFormat::CoreProfile ? EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR : EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR,
- EGL_NONE
- };
- context = eglCreateContext(eglDisplay(), config(), shareContext, attribs);
+ auto core = std::unique_ptr(new EglContextAttributeBuilder);
+ core->setVersion(m_format.majorVersion(), m_format.minorVersion());
+ core->setForwardCompatible(true);
+ if (m_format.profile() == QSurfaceFormat::CoreProfile) {
+ core->setCoreProfile(true);
+ } else if (m_format.profile() == QSurfaceFormat::CompatibilityProfile) {
+ core->setCompatibilityProfile(true);
}
+ candidates.push_back(std::move(core));
}
- if (context == 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
- };
- context = eglCreateContext(eglDisplay(), config(), shareContext, attribs);
+ if (haveRobustness && haveCreateContext) {
+ auto robust = std::unique_ptr(new EglContextAttributeBuilder);
+ robust->setRobust(true);
+ candidates.push_back(std::move(robust));
}
- if (context == EGL_NO_CONTEXT) {
- // and last but not least: try without robustness
- const EGLint attribs[] = {
- EGL_NONE
- };
- context = eglCreateContext(eglDisplay(), config(), shareContext, attribs);
+ candidates.emplace_back(new EglContextAttributeBuilder);
+ }
+
+ EGLContext context = EGL_NO_CONTEXT;
+ for (auto it = candidates.begin(); it != candidates.end(); it++) {
+ const auto attribs = (*it)->build();
+ context = eglCreateContext(eglDisplay(), config(), shareContext, attribs.data());
+ if (context != EGL_NO_CONTEXT) {
+ qCDebug(KWIN_QPA) << "Created EGL context with attributes:" << (*it).get();
+ break;
}
}