From 02b996cf9c0c43542a10ca599c79cdbd65530e3c Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Thu, 3 Aug 2023 13:02:59 +0200 Subject: [PATCH] platformsupport/scenes/opengl: add opengl render query class --- .../libkwineffects/kwinglplatformtest.cpp | 20 +++--- src/composite.cpp | 2 +- src/libkwineffects/kwinglplatform.cpp | 34 ++++++---- src/libkwineffects/kwinglplatform.h | 8 ++- src/libkwineffects/kwinglutils.cpp | 4 +- .../scenes/opengl/CMakeLists.txt | 1 + .../scenes/opengl/glrendertimequery.cpp | 65 +++++++++++++++++++ .../scenes/opengl/glrendertimequery.h | 40 ++++++++++++ src/plugins/screencast/screencastutils.h | 2 +- src/workspace.cpp | 12 ++-- 10 files changed, 153 insertions(+), 35 deletions(-) create mode 100644 src/platformsupport/scenes/opengl/glrendertimequery.cpp create mode 100644 src/platformsupport/scenes/opengl/glrendertimequery.h diff --git a/autotests/libkwineffects/kwinglplatformtest.cpp b/autotests/libkwineffects/kwinglplatformtest.cpp index ad6a209241..98bf006512 100644 --- a/autotests/libkwineffects/kwinglplatformtest.cpp +++ b/autotests/libkwineffects/kwinglplatformtest.cpp @@ -146,11 +146,11 @@ void GLPlatformTest::testPriorDetect() { auto *gl = GLPlatform::instance(); QVERIFY(gl); - QCOMPARE(gl->supports(LooseBinding), false); - QCOMPARE(gl->supports(GLSL), false); - QCOMPARE(gl->supports(LimitedGLSL), false); - QCOMPARE(gl->supports(TextureNPOT), false); - QCOMPARE(gl->supports(LimitedNPOT), false); + QCOMPARE(gl->supports(GLFeature::LooseBinding), false); + QCOMPARE(gl->supports(GLFeature::GLSL), false); + QCOMPARE(gl->supports(GLFeature::LimitedGLSL), false); + QCOMPARE(gl->supports(GLFeature::TextureNPOT), false); + QCOMPARE(gl->supports(GLFeature::LimitedNPOT), false); QCOMPARE(gl->glVersion(), Version()); QCOMPARE(gl->glslVersion(), Version()); @@ -248,11 +248,11 @@ void GLPlatformTest::testDetect() const KConfigGroup settingsGroup = config.group("Settings"); - QCOMPARE(gl->supports(LooseBinding), settingsGroup.readEntry("LooseBinding", false)); - QCOMPARE(gl->supports(GLSL), settingsGroup.readEntry("GLSL", false)); - QCOMPARE(gl->supports(LimitedGLSL), settingsGroup.readEntry("LimitedGLSL", false)); - QCOMPARE(gl->supports(TextureNPOT), settingsGroup.readEntry("TextureNPOT", false)); - QCOMPARE(gl->supports(LimitedNPOT), settingsGroup.readEntry("LimitedNPOT", false)); + QCOMPARE(gl->supports(GLFeature::LooseBinding), settingsGroup.readEntry("LooseBinding", false)); + QCOMPARE(gl->supports(GLFeature::GLSL), settingsGroup.readEntry("GLSL", false)); + QCOMPARE(gl->supports(GLFeature::LimitedGLSL), settingsGroup.readEntry("LimitedGLSL", false)); + QCOMPARE(gl->supports(GLFeature::TextureNPOT), settingsGroup.readEntry("TextureNPOT", false)); + QCOMPARE(gl->supports(GLFeature::LimitedNPOT), settingsGroup.readEntry("LimitedNPOT", false)); QCOMPARE(gl->glVersion(), readVersion(settingsGroup, "GLVersion")); QCOMPARE(gl->glslVersion(), readVersion(settingsGroup, "GLSLVersion")); diff --git a/src/composite.cpp b/src/composite.cpp index a106209e43..3c7841d1b1 100644 --- a/src/composite.cpp +++ b/src/composite.cpp @@ -212,7 +212,7 @@ bool Compositor::attemptOpenGLCompositing() // set strict binding if (options->isGlStrictBindingFollowsDriver()) { - options->setGlStrictBinding(!GLPlatform::instance()->supports(LooseBinding)); + options->setGlStrictBinding(!GLPlatform::instance()->supports(GLFeature::LooseBinding)); } qCDebug(KWIN_CORE) << "OpenGL compositing has been successfully initialized"; diff --git a/src/libkwineffects/kwinglplatform.cpp b/src/libkwineffects/kwinglplatform.cpp index 4f90947211..16766dbdf9 100644 --- a/src/libkwineffects/kwinglplatform.cpp +++ b/src/libkwineffects/kwinglplatform.cpp @@ -807,6 +807,16 @@ void GLPlatform::detect(OpenGLPlatformInterface platformInterface) m_textureNPOT = m_extensions.contains("GL_ARB_texture_non_power_of_two"); } + if (!qEnvironmentVariableIsSet("KWIN_NO_TIMER_QUERY")) { + if (isGLES()) { + // 3.0 is required so query functions can be used without "EXT" suffix. + // Timer queries are still not part of the core OpenGL ES specification. + m_supportsTimerQuery = glVersion() >= Version(3, 0) && m_extensions.contains("GL_EXT_disjoint_timer_query"); + } else { + m_supportsTimerQuery = glVersion() >= Version(3, 3) || m_extensions.contains("GL_ARB_timer_query"); + } + } + m_serverVersion = getXServerVersion(); m_kernelVersion = getKernelVersion(); @@ -1193,32 +1203,28 @@ void GLPlatform::printResults() const print(QByteArrayLiteral("GLSL shaders:"), m_supportsGLSL ? (m_limitedGLSL ? QByteArrayLiteral("limited") : QByteArrayLiteral("yes")) : QByteArrayLiteral("no")); print(QByteArrayLiteral("Texture NPOT support:"), m_textureNPOT ? (m_limitedNPOT ? QByteArrayLiteral("limited") : QByteArrayLiteral("yes")) : QByteArrayLiteral("no")); print(QByteArrayLiteral("Virtual Machine:"), m_virtualMachine ? QByteArrayLiteral("yes") : QByteArrayLiteral("no")); + print(QByteArrayLiteral("Timer query support:"), m_supportsTimerQuery ? QByteArrayLiteral("yes") : QByteArrayLiteral("no")); } bool GLPlatform::supports(GLFeature feature) const { switch (feature) { - case LooseBinding: + case GLFeature::LooseBinding: return m_looseBinding; - - case GLSL: + case GLFeature::GLSL: return m_supportsGLSL; - - case LimitedGLSL: + case GLFeature::LimitedGLSL: return m_limitedGLSL; - - case TextureNPOT: + case GLFeature::TextureNPOT: return m_textureNPOT; - - case LimitedNPOT: + case GLFeature::LimitedNPOT: return m_limitedNPOT; - - case PackInvert: + case GLFeature::PackInvert: return m_packInvert; - - default: - return false; + case GLFeature::TimerQuery: + return m_supportsTimerQuery; } + return false; } Version GLPlatform::glVersion() const diff --git a/src/libkwineffects/kwinglplatform.h b/src/libkwineffects/kwinglplatform.h index 75f1c85cb4..da0430d83c 100644 --- a/src/libkwineffects/kwinglplatform.h +++ b/src/libkwineffects/kwinglplatform.h @@ -24,7 +24,7 @@ void cleanupGL(); class Version; -enum GLFeature { +enum class GLFeature { /** * Set when a texture bound to a pixmap uses the same storage as the pixmap, * and thus doesn't need to be rebound when the contents of the pixmap @@ -75,6 +75,11 @@ enum GLFeature { * Set if the extension GL_MESA_pack_invert is present */ PackInvert, + + /** + * Set if the driver supports GL_ARB_timer_query extension or OpenGL 3.3. + */ + TimerQuery, }; enum Driver { @@ -479,6 +484,7 @@ private: bool m_textureNPOT : 1; bool m_limitedNPOT : 1; bool m_packInvert : 1; + bool m_supportsTimerQuery : 1; bool m_virtualMachine : 1; bool m_preferBufferSubData : 1; OpenGLPlatformInterface m_platformInterface; diff --git a/src/libkwineffects/kwinglutils.cpp b/src/libkwineffects/kwinglutils.cpp index e6c08992c9..408ddbf28d 100644 --- a/src/libkwineffects/kwinglutils.cpp +++ b/src/libkwineffects/kwinglutils.cpp @@ -357,9 +357,9 @@ bool GLShader::compile(GLuint program, GLenum shaderType, const QByteArray &sour bool GLShader::load(const QByteArray &vertexSource, const QByteArray &fragmentSource) { // Make sure shaders are actually supported - if (!(GLPlatform::instance()->supports(GLSL) && + if (!(GLPlatform::instance()->supports(GLFeature::GLSL) && // we lack shader branching for Texture2DRectangle everywhere - and it's probably not worth it - GLPlatform::instance()->supports(TextureNPOT))) { + GLPlatform::instance()->supports(GLFeature::TextureNPOT))) { qCCritical(LIBKWINGLUTILS) << "Shaders are not supported"; return false; } diff --git a/src/platformsupport/scenes/opengl/CMakeLists.txt b/src/platformsupport/scenes/opengl/CMakeLists.txt index be311f238e..f3eaaeab6d 100644 --- a/src/platformsupport/scenes/opengl/CMakeLists.txt +++ b/src/platformsupport/scenes/opengl/CMakeLists.txt @@ -5,6 +5,7 @@ target_sources(kwin PRIVATE egldisplay.cpp eglnativefence.cpp eglswapchain.cpp + glrendertimequery.cpp kwineglimagetexture.cpp openglbackend.cpp openglsurfacetexture.cpp diff --git a/src/platformsupport/scenes/opengl/glrendertimequery.cpp b/src/platformsupport/scenes/opengl/glrendertimequery.cpp new file mode 100644 index 0000000000..4f3c3a04e2 --- /dev/null +++ b/src/platformsupport/scenes/opengl/glrendertimequery.cpp @@ -0,0 +1,65 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2023 Xaver Hugl + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#include "glrendertimequery.h" +#include "libkwineffects/kwinglplatform.h" + +namespace KWin +{ + +GLRenderTimeQuery::GLRenderTimeQuery() +{ + if (GLPlatform::instance()->supports(GLFeature::TimerQuery)) { + glGenQueries(1, &m_query); + } +} + +GLRenderTimeQuery::~GLRenderTimeQuery() +{ + if (m_query) { + glDeleteQueries(1, &m_query); + } +} + +void GLRenderTimeQuery::begin() +{ + if (m_query) { + GLint64 nanos = 0; + glGetInteger64v(GL_TIMESTAMP, &nanos); + m_cpuStart = std::chrono::nanoseconds(nanos); + } else { + m_cpuStart = std::chrono::steady_clock::now().time_since_epoch(); + } +} + +void GLRenderTimeQuery::end() +{ + if (m_query) { + glQueryCounter(m_query, GL_TIMESTAMP); + } else { + m_cpuEnd = std::chrono::steady_clock::now().time_since_epoch(); + } + m_hasResult = true; +} + +std::chrono::nanoseconds GLRenderTimeQuery::result() +{ + if (!m_hasResult) { + return std::chrono::nanoseconds::zero(); + } + m_hasResult = false; + if (m_query) { + uint64_t nanos = 0; + glGetQueryObjectui64v(m_query, GL_QUERY_RESULT, &nanos); + return std::chrono::nanoseconds(nanos) - m_cpuStart; + } else { + return m_cpuEnd - m_cpuStart; + } +} + +} diff --git a/src/platformsupport/scenes/opengl/glrendertimequery.h b/src/platformsupport/scenes/opengl/glrendertimequery.h new file mode 100644 index 0000000000..7850985d60 --- /dev/null +++ b/src/platformsupport/scenes/opengl/glrendertimequery.h @@ -0,0 +1,40 @@ +/* + KWin - the KDE window manager + This file is part of the KDE project. + + SPDX-FileCopyrightText: 2023 Xaver Hugl + + SPDX-License-Identifier: GPL-2.0-or-later +*/ +#pragma once + +#include +#include + +#include "kwin_export.h" + +namespace KWin +{ + +class KWIN_EXPORT GLRenderTimeQuery +{ +public: + explicit GLRenderTimeQuery(); + ~GLRenderTimeQuery(); + + void begin(); + void end(); + + /** + * fetches the result of the query. If rendering is not done yet, this will block! + */ + std::chrono::nanoseconds result(); + +private: + GLuint m_query = 0; + bool m_hasResult = false; + std::chrono::nanoseconds m_cpuStart = std::chrono::nanoseconds::zero(); + std::chrono::nanoseconds m_cpuEnd = std::chrono::nanoseconds::zero(); +}; + +} diff --git a/src/plugins/screencast/screencastutils.h b/src/plugins/screencast/screencastutils.h index e65f8d7064..8c9359aa58 100644 --- a/src/plugins/screencast/screencastutils.h +++ b/src/plugins/screencast/screencastutils.h @@ -51,7 +51,7 @@ static void doGrabTexture(GLTexture *texture, spa_data *spa, spa_video_format fo { const QSize size = texture->size(); const bool invertNeeded = GLPlatform::instance()->isGLES() ^ !(texture->contentTransforms() & TextureTransform::MirrorY); - const bool invertNeededAndSupported = invertNeeded && GLPlatform::instance()->supports(PackInvert); + const bool invertNeededAndSupported = invertNeeded && GLPlatform::instance()->supports(GLFeature::PackInvert); GLboolean prev; if (invertNeededAndSupported) { glGetBooleanv(GL_PACK_INVERT_MESA, &prev); diff --git a/src/workspace.cpp b/src/workspace.cpp index 784a02b5af..327eebf96f 100644 --- a/src/workspace.cpp +++ b/src/workspace.cpp @@ -1775,7 +1775,7 @@ QString Workspace::supportInformation() const } support.append(QStringLiteral("\n")); - if (platform->supports(LimitedGLSL) || platform->supports(GLSL)) { + if (platform->supports(GLFeature::LimitedGLSL) || platform->supports(GLFeature::GLSL)) { support.append(QStringLiteral("OpenGL shading language version string: ") + QString::fromUtf8(platform->glShadingLanguageVersionString()) + QStringLiteral("\n")); } @@ -1788,7 +1788,7 @@ QString Workspace::supportInformation() const support.append(QStringLiteral("OpenGL version: ") + GLPlatform::versionToString(platform->glVersion()) + QStringLiteral("\n")); - if (platform->supports(LimitedGLSL) || platform->supports(GLSL)) { + if (platform->supports(GLFeature::LimitedGLSL) || platform->supports(GLFeature::GLSL)) { support.append(QStringLiteral("GLSL version: ") + GLPlatform::versionToString(platform->glslVersion()) + QStringLiteral("\n")); } @@ -1810,8 +1810,8 @@ QString Workspace::supportInformation() const support.append(QStringLiteral("no\n")); } support.append(QStringLiteral("GLSL shaders: ")); - if (platform->supports(GLSL)) { - if (platform->supports(LimitedGLSL)) { + if (platform->supports(GLFeature::GLSL)) { + if (platform->supports(GLFeature::LimitedGLSL)) { support.append(QStringLiteral(" limited\n")); } else { support.append(QStringLiteral(" yes\n")); @@ -1820,8 +1820,8 @@ QString Workspace::supportInformation() const support.append(QStringLiteral(" no\n")); } support.append(QStringLiteral("Texture NPOT support: ")); - if (platform->supports(TextureNPOT)) { - if (platform->supports(LimitedNPOT)) { + if (platform->supports(GLFeature::TextureNPOT)) { + if (platform->supports(GLFeature::LimitedNPOT)) { support.append(QStringLiteral(" limited\n")); } else { support.append(QStringLiteral(" yes\n"));