diff --git a/abstract_opengl_context_attribute_builder.h b/abstract_opengl_context_attribute_builder.h --- a/abstract_opengl_context_attribute_builder.h +++ b/abstract_opengl_context_attribute_builder.h @@ -86,6 +86,14 @@ return m_compatibilityProfile; } + void setResetOnVideoMemoryPurge(bool reset) { + m_resetOnVideoMemoryPurge = reset; + } + + bool isResetOnVideoMemoryPurge() const { + return m_resetOnVideoMemoryPurge; + } + virtual std::vector build() const = 0; QDebug operator<<(QDebug dbg) const; @@ -98,6 +106,7 @@ bool m_forwardCompatible = false; bool m_coreProfile = false; bool m_compatibilityProfile = false; + bool m_resetOnVideoMemoryPurge = false; }; inline QDebug operator<<(QDebug dbg, const AbstractOpenGLContextAttributeBuilder *attribs) diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -362,7 +362,16 @@ 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) diff --git a/autotests/opengl_context_attribute_builder_test.cpp b/autotests/opengl_context_attribute_builder_test.cpp --- a/autotests/opengl_context_attribute_builder_test.cpp +++ b/autotests/opengl_context_attribute_builder_test.cpp @@ -22,6 +22,16 @@ #include #include +#include +#if HAVE_EPOXY_GLX +#include "../plugins/platforms/x11/standalone/glx_context_attribute_builder.h" +#include + +#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 @@ 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 @@ QCOMPARE(builder.isForwardCompatible(), false); QCOMPARE(builder.isCoreProfile(), false); QCOMPARE(builder.isCompatibilityProfile(), false); + QCOMPARE(builder.isResetOnVideoMemoryPurge(), false); } void OpenGLContextAttributeBuilderTest::testRobust() @@ -99,6 +113,16 @@ 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 @@ QTEST(attribs, "expectedAttribs"); } +void OpenGLContextAttributeBuilderTest::testGlx_data() +{ +#if HAVE_EPOXY_GLX + QTest::addColumn("requestVersion"); + QTest::addColumn("major"); + QTest::addColumn("minor"); + QTest::addColumn("robust"); + QTest::addColumn("videoPurge"); + QTest::addColumn>("expectedAttribs"); + + QTest::newRow("fallback") << true << 2 << 1 << false << false << std::vector{ + GLX_CONTEXT_MAJOR_VERSION_ARB, 2, + GLX_CONTEXT_MINOR_VERSION_ARB, 1, + 0}; + QTest::newRow("legacy/robust") << false << 0 << 0 << true << false << std::vector{ + 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{ + 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{ + GLX_CONTEXT_MAJOR_VERSION_ARB, 3, + GLX_CONTEXT_MINOR_VERSION_ARB, 1, + 0}; + QTest::newRow("core/robust") << true << 3 << 1 << true << false << std::vector{ + 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{ + 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" diff --git a/plugins/platforms/x11/standalone/CMakeLists.txt b/plugins/platforms/x11/standalone/CMakeLists.txt --- a/plugins/platforms/x11/standalone/CMakeLists.txt +++ b/plugins/platforms/x11/standalone/CMakeLists.txt @@ -12,7 +12,7 @@ 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}) diff --git a/plugins/platforms/x11/standalone/glx_context_attribute_builder.h b/plugins/platforms/x11/standalone/glx_context_attribute_builder.h new file mode 100644 --- /dev/null +++ b/plugins/platforms/x11/standalone/glx_context_attribute_builder.h @@ -0,0 +1,32 @@ +/******************************************************************** + 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 GlxContextAttributeBuilder : public AbstractOpenGLContextAttributeBuilder +{ +public: + std::vector build() const override; +}; + +} diff --git a/plugins/platforms/x11/standalone/glx_context_attribute_builder.cpp b/plugins/platforms/x11/standalone/glx_context_attribute_builder.cpp new file mode 100644 --- /dev/null +++ b/plugins/platforms/x11/standalone/glx_context_attribute_builder.cpp @@ -0,0 +1,53 @@ +/******************************************************************** + 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 "glx_context_attribute_builder.h" +#include + +#ifndef GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV +#define GLX_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x20F7 +#endif + +namespace KWin +{ + +std::vector GlxContextAttributeBuilder::build() const +{ + std::vector 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; +} + +} diff --git a/plugins/platforms/x11/standalone/glxbackend.cpp b/plugins/platforms/x11/standalone/glxbackend.cpp --- a/plugins/platforms/x11/standalone/glxbackend.cpp +++ b/plugins/platforms/x11/standalone/glxbackend.cpp @@ -25,6 +25,7 @@ // own #include "glxbackend.h" #include "logging.h" +#include "glx_context_attribute_builder.h" // kwin #include "options.h" #include "overlaywindow.h" @@ -64,10 +65,6 @@ } 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 #include @@ -287,77 +284,51 @@ // 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 candidates; if (options->glCoreProfile()) { - if (have_robustness) { + if (have_robustness) { if (haveVideoMemoryPurge) { - ctx = glXCreateContextAttribsARB(display(), fbconfig, 0, direct, attribs_31_core_nv_robustness); + GlxContextAttributeBuilder purgeMemoryCore; + purgeMemoryCore.setVersion(3, 1); + purgeMemoryCore.setRobust(true); + purgeMemoryCore.setResetOnVideoMemoryPurge(true); + candidates.emplace_back(std::move(purgeMemoryCore)); } - if (!ctx) { - ctx = glXCreateContextAttribsARB(display(), fbconfig, 0, direct, attribs_31_core_robustness); + GlxContextAttributeBuilder robustCore; + robustCore.setVersion(3, 1); + robustCore.setRobust(true); + candidates.emplace_back(std::move(robustCore)); + } + 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)); } - - if (!ctx) - ctx = glXCreateContextAttribsARB(display(), fbconfig, 0, direct, attribs_31_core); + 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)