[qpa] Use the new OpenGLContextAttributeBuilder to create Qt's OpenGL context

Summary:
Introduces a few more attributes needed for creating the OpenGL context
used by the QPA.

Test Plan:
Extended test and run KWin/Wayland and verified that OpenGL context
gets created correctly.

Reviewers: #kwin, #plasma

Subscribers: plasma-devel, kwin

Tags: #kwin

Differential Revision: https://phabricator.kde.org/D6734
This commit is contained in:
Martin Flöser 2017-07-16 17:31:09 +02:00
parent ea5d611de1
commit 73fa7b21a1
6 changed files with 188 additions and 57 deletions

View file

@ -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;
}

View file

@ -19,11 +19,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#pragma once
#include <QDebug>
#include <kwin_export.h>
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<int> 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)

View file

@ -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<int>("major");
QTest::addColumn<int>("minor");
QTest::addColumn<bool>("robust");
QTest::addColumn<bool>("forwardCompatible");
QTest::addColumn<bool>("coreProfile");
QTest::addColumn<bool>("compatibilityProfile");
QTest::addColumn<std::vector<int>>("expectedAttribs");
QTest::newRow("fallback") << false << 0 << 0 << false << std::vector<int>{EGL_NONE};
QTest::newRow("legacy/robust") << false << 0 << 0 << true <<
QTest::newRow("fallback") << false << 0 << 0 << false << false << false << false << std::vector<int>{EGL_NONE};
QTest::newRow("legacy/robust") << false << 0 << 0 << true << false << false << false <<
std::vector<int>{
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<int>{
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<int>{
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<int>{
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<int>{
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<int>{
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<int>{
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<int>{
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<int>{
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");

View file

@ -31,11 +31,26 @@ std::vector<int> 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;

View file

@ -19,17 +19,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#pragma once
#include "abstract_opengl_context_attribute_builder.h"
#include <kwin_export.h>
namespace KWin
{
class EglContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
class KWIN_EXPORT EglContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
{
public:
std::vector<int> build() const override;
};
class EglOpenGLESContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
class KWIN_EXPORT EglOpenGLESContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder
{
public:
std::vector<int> build() const override;

View file

@ -19,8 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "abstractplatformcontext.h"
#include "integration.h"
#include "egl_context_attribute_builder.h"
#include <logging.h>
#include <memory>
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<std::unique_ptr<AbstractOpenGLContextAttributeBuilder>> 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<AbstractOpenGLContextAttributeBuilder>(new EglOpenGLESContextAttributeBuilder);
glesRobust->setVersion(2);
glesRobust->setRobust(true);
candidates.push_back(std::move(glesRobust));
}
auto gles = std::unique_ptr<AbstractOpenGLContextAttributeBuilder>(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<AbstractOpenGLContextAttributeBuilder>(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);
}
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);
candidates.push_back(std::move(robustCore));
}
auto core = std::unique_ptr<AbstractOpenGLContextAttributeBuilder>(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<AbstractOpenGLContextAttributeBuilder>(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;
}
}