qpa: Merge OpenGL platform context classes

This makes our QPlatformOpenGLContext private subclass simpler.

As a slightly unrelated change, this patch also fixes a bug where our
platform opengl context may return a wrong surface format if surfaceless
contexts are unsupported.
icc-effect-5.26.4
Vlad Zahorodnii 2020-10-12 09:27:27 +03:00
parent b7bd8472f2
commit 9b89a3d967
12 changed files with 193 additions and 258 deletions

View File

@ -2,15 +2,14 @@ include_directories(${Qt5Core_PRIVATE_INCLUDE_DIRS})
include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS})
set(QPA_SOURCES
abstractplatformcontext.cpp
backingstore.cpp
eglhelpers.cpp
eglplatformcontext.cpp
integration.cpp
main.cpp
offscreensurface.cpp
platformcursor.cpp
screen.cpp
sharingplatformcontext.cpp
window.cpp
)

View File

@ -1,56 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef KWIN_QPA_ABSTRACTPLATFORMCONTEXT_H
#define KWIN_QPA_ABSTRACTPLATFORMCONTEXT_H
#include <epoxy/egl.h>
#include "fixqopengl.h"
#include <fixx11h.h>
#include <qpa/qplatformopenglcontext.h>
namespace KWin
{
namespace QPA
{
class AbstractPlatformContext : public QPlatformOpenGLContext
{
public:
AbstractPlatformContext(QOpenGLContext *context, EGLDisplay display, EGLConfig config = nullptr);
~AbstractPlatformContext() override;
void doneCurrent() override;
QSurfaceFormat format() const override;
bool isValid() const override;
QFunctionPointer getProcAddress(const char *procName) override;
protected:
EGLDisplay eglDisplay() const {
return m_eglDisplay;
}
EGLConfig config() const {
return m_config;
}
bool bindApi();
EGLContext eglContext() const {
return m_context;
}
void createContext(EGLContext shareContext = EGL_NO_CONTEXT);
private:
EGLDisplay m_eglDisplay;
EGLConfig m_config;
EGLContext m_context = EGL_NO_CONTEXT;
QSurfaceFormat m_format;
};
}
}
#endif

View File

@ -10,6 +10,10 @@
#ifndef KWIN_QPA_BACKINGSTORE_H
#define KWIN_QPA_BACKINGSTORE_H
#include <epoxy/egl.h>
#include "fixqopengl.h"
#include <fixx11h.h>
#include <qpa/qplatformbackingstore.h>
namespace KWin

View File

@ -3,71 +3,156 @@
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "abstractplatformcontext.h"
#include "eglplatformcontext.h"
#include "egl_context_attribute_builder.h"
#include "eglhelpers.h"
#include "internal_client.h"
#include "offscreensurface.h"
#include "platform.h"
#include "window.h"
#include <logging.h>
#include "logging.h"
#include <QOpenGLContext>
#include <QOpenGLFramebufferObject>
#include <private/qopenglcontext_p.h>
#include <memory>
namespace KWin
{
namespace QPA
{
AbstractPlatformContext::AbstractPlatformContext(QOpenGLContext *context, EGLDisplay display, EGLConfig config)
: QPlatformOpenGLContext()
, m_eglDisplay(display)
, m_config(config ? config : configFromFormat(m_eglDisplay, context->format()))
, m_format(formatFromConfig(m_eglDisplay, m_config))
EGLPlatformContext::EGLPlatformContext(QOpenGLContext *context, EGLDisplay display)
: m_eglDisplay(display)
{
create(context->format(), kwinApp()->platform()->sceneEglContext());
}
AbstractPlatformContext::~AbstractPlatformContext()
EGLPlatformContext::~EGLPlatformContext()
{
if (m_context != EGL_NO_CONTEXT) {
eglDestroyContext(m_eglDisplay, m_context);
}
}
void AbstractPlatformContext::doneCurrent()
EGLDisplay EGLPlatformContext::eglDisplay() const
{
return m_eglDisplay;
}
EGLContext EGLPlatformContext::eglContext() const
{
return m_context;
}
static EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
if (surface->surface()->surfaceClass() == QSurface::Window) {
return static_cast<Window *>(surface)->eglSurface();
} else {
return static_cast<OffscreenSurface *>(surface)->eglSurface();
}
}
bool EGLPlatformContext::makeCurrent(QPlatformSurface *surface)
{
const EGLSurface eglSurface = eglSurfaceForPlatformSurface(surface);
const bool ok = eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext());
if (!ok) {
qCWarning(KWIN_QPA, "eglMakeCurrent failed: %x", eglGetError());
return false;
}
if (surface->surface()->surfaceClass() == QSurface::Window) {
// QOpenGLContextPrivate::setCurrentContext will be called after this
// method returns, but that's too late, as we need a current context in
// order to bind the content framebuffer object.
QOpenGLContextPrivate::setCurrentContext(context());
Window *window = static_cast<Window *>(surface);
window->bindContentFBO();
}
return true;
}
void EGLPlatformContext::doneCurrent()
{
eglMakeCurrent(m_eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
QSurfaceFormat AbstractPlatformContext::format() const
{
return m_format;
}
QFunctionPointer AbstractPlatformContext::getProcAddress(const char *procName)
{
return eglGetProcAddress(procName);
}
bool AbstractPlatformContext::isValid() const
bool EGLPlatformContext::isValid() const
{
return m_context != EGL_NO_CONTEXT;
}
bool AbstractPlatformContext::bindApi()
bool EGLPlatformContext::isSharing() const
{
if (eglBindAPI(isOpenGLES() ? EGL_OPENGL_ES_API : EGL_OPENGL_API) == EGL_FALSE) {
qCWarning(KWIN_QPA) << "eglBindAPI failed";
return false;
}
return true;
return false;
}
void AbstractPlatformContext::createContext(EGLContext shareContext)
QSurfaceFormat EGLPlatformContext::format() const
{
return m_format;
}
QFunctionPointer EGLPlatformContext::getProcAddress(const char *procName)
{
return eglGetProcAddress(procName);
}
void EGLPlatformContext::swapBuffers(QPlatformSurface *surface)
{
if (surface->surface()->surfaceClass() == QSurface::Window) {
Window *window = static_cast<Window *>(surface);
InternalClient *client = window->client();
if (!client) {
return;
}
context()->makeCurrent(surface->surface());
glFlush();
client->present(window->swapFBO());
window->bindContentFBO();
}
}
GLuint EGLPlatformContext::defaultFramebufferObject(QPlatformSurface *surface) const
{
if (Window *window = dynamic_cast<Window *>(surface)) {
const auto &fbo = window->contentFBO();
if (!fbo.isNull()) {
return fbo->handle();
}
qCDebug(KWIN_QPA) << "No default framebuffer object for internal window";
}
return 0;
}
void EGLPlatformContext::create(const QSurfaceFormat &format, EGLContext shareContext)
{
if (!eglBindAPI(isOpenGLES() ? EGL_OPENGL_ES_API : EGL_OPENGL_API)) {
qCWarning(KWIN_QPA, "eglBindAPI failed: 0x%x", eglGetError());
return;
}
m_config = configFromFormat(m_eglDisplay, format);
if (m_config == EGL_NO_CONFIG_KHR) {
qCWarning(KWIN_QPA) << "Could not find suitable EGLConfig for" << format;
return;
}
m_format = formatFromConfig(m_eglDisplay, m_config);
const QByteArray eglExtensions = eglQueryString(eglDisplay(), EGL_EXTENSIONS);
const QList<QByteArray> extensions = eglExtensions.split(' ');
const bool haveRobustness = extensions.contains(QByteArrayLiteral("EGL_EXT_create_context_robustness"));
@ -165,7 +250,7 @@ void AbstractPlatformContext::createContext(EGLContext shareContext)
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());
context = eglCreateContext(eglDisplay(), m_config, shareContext, attribs.data());
if (context != EGL_NO_CONTEXT) {
qCDebug(KWIN_QPA) << "Created EGL context with attributes:" << (*it).get();
break;
@ -179,5 +264,5 @@ void AbstractPlatformContext::createContext(EGLContext shareContext)
m_context = context;
}
}
}
} // namespace QPA
} // namespace KWin

View File

@ -0,0 +1,51 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#pragma once
#include <epoxy/egl.h>
#include "fixqopengl.h"
#include <fixx11h.h>
#include <qpa/qplatformopenglcontext.h>
namespace KWin
{
namespace QPA
{
class EGLPlatformContext : public QPlatformOpenGLContext
{
public:
EGLPlatformContext(QOpenGLContext *context, EGLDisplay display);
~EGLPlatformContext() override;
bool makeCurrent(QPlatformSurface *surface) override;
void doneCurrent() override;
QSurfaceFormat format() const override;
bool isValid() const override;
bool isSharing() const override;
GLuint defaultFramebufferObject(QPlatformSurface *surface) const override;
QFunctionPointer getProcAddress(const char *procName) override;
void swapBuffers(QPlatformSurface *surface) override;
EGLDisplay eglDisplay() const;
EGLContext eglContext() const;
private:
void create(const QSurfaceFormat &format, EGLContext shareContext);
EGLDisplay m_eglDisplay;
EGLConfig m_config = EGL_NO_CONFIG_KHR;
EGLContext m_context = EGL_NO_CONTEXT;
QSurfaceFormat m_format;
};
} // namespace QPA
} // namespace KWin

View File

@ -9,9 +9,9 @@
*/
#include "integration.h"
#include "backingstore.h"
#include "eglplatformcontext.h"
#include "offscreensurface.h"
#include "screen.h"
#include "sharingplatformcontext.h"
#include "window.h"
#include "../../main.h"
#include "../../platform.h"
@ -122,15 +122,10 @@ QStringList Integration::themeNames() const
QPlatformOpenGLContext *Integration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
if (kwinApp()->platform()->supportsQpaContext()) {
return new SharingPlatformContext(context);
}
if (kwinApp()->platform()->sceneEglDisplay() != EGL_NO_DISPLAY) {
auto s = kwinApp()->platform()->sceneEglSurface();
if (s != EGL_NO_SURFACE) {
// try a SharingPlatformContext with a created surface
return new SharingPlatformContext(context, s, kwinApp()->platform()->sceneEglConfig());
}
const EGLDisplay eglDisplay = kwinApp()->platform()->sceneEglDisplay();
if (eglDisplay != EGL_NO_DISPLAY) {
EGLPlatformContext *platformContext = new EGLPlatformContext(context, eglDisplay);
return platformContext;
}
return nullptr;
}

View File

@ -62,7 +62,7 @@ bool OffscreenSurface::isValid() const
return m_surface != EGL_NO_SURFACE;
}
EGLSurface OffscreenSurface::nativeHandle() const
EGLSurface OffscreenSurface::eglSurface() const
{
return m_surface;
}

View File

@ -29,7 +29,7 @@ public:
QSurfaceFormat format() const override;
bool isValid() const override;
EGLSurface nativeHandle() const;
EGLSurface eglSurface() const;
private:
QSurfaceFormat m_format;

View File

@ -1,115 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "sharingplatformcontext.h"
#include "offscreensurface.h"
#include "window.h"
#include "../../internal_client.h"
#include "../../main.h"
#include "../../platform.h"
#include <logging.h>
#include <QOpenGLFramebufferObject>
#include <private/qopenglcontext_p.h>
namespace KWin
{
namespace QPA
{
SharingPlatformContext::SharingPlatformContext(QOpenGLContext *context)
: SharingPlatformContext(context, EGL_NO_SURFACE)
{
}
SharingPlatformContext::SharingPlatformContext(QOpenGLContext *context, const EGLSurface &surface, EGLConfig config)
: AbstractPlatformContext(context, kwinApp()->platform()->sceneEglDisplay(), config)
, m_surface(surface)
{
create();
}
bool SharingPlatformContext::makeCurrent(QPlatformSurface *surface)
{
EGLSurface eglSurface;
if (surface->surface()->surfaceClass() == QSurface::Window) {
eglSurface = m_surface;
} else {
eglSurface = static_cast<OffscreenSurface *>(surface)->nativeHandle();
}
const bool ok = eglMakeCurrent(eglDisplay(), eglSurface, eglSurface, eglContext());
if (!ok) {
qCWarning(KWIN_QPA, "eglMakeCurrent failed: %x", eglGetError());
return false;
}
if (surface->surface()->surfaceClass() == QSurface::Window) {
// QOpenGLContextPrivate::setCurrentContext will be called after this
// method returns, but that's too late, as we need a current context in
// order to bind the content framebuffer object.
QOpenGLContextPrivate::setCurrentContext(context());
Window *window = static_cast<Window *>(surface);
window->bindContentFBO();
}
return true;
}
bool SharingPlatformContext::isSharing() const
{
return false;
}
void SharingPlatformContext::swapBuffers(QPlatformSurface *surface)
{
if (surface->surface()->surfaceClass() == QSurface::Window) {
Window *window = static_cast<Window *>(surface);
InternalClient *client = window->client();
if (!client) {
return;
}
context()->makeCurrent(surface->surface());
glFlush();
client->present(window->swapFBO());
window->bindContentFBO();
}
}
GLuint SharingPlatformContext::defaultFramebufferObject(QPlatformSurface *surface) const
{
if (Window *window = dynamic_cast<Window*>(surface)) {
const auto &fbo = window->contentFBO();
if (!fbo.isNull()) {
return fbo->handle();
}
qCDebug(KWIN_QPA) << "No default framebuffer object for internal window";
}
return 0;
}
void SharingPlatformContext::create()
{
if (!config()) {
qCWarning(KWIN_QPA) << "Did not get an EGL config";
return;
}
if (!bindApi()) {
qCWarning(KWIN_QPA) << "Could not bind API.";
return;
}
createContext(kwinApp()->platform()->sceneEglContext());
}
}
}

View File

@ -1,42 +0,0 @@
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#ifndef KWIN_QPA_SHARINGPLATFORMCONTEXT_H
#define KWIN_QPA_SHARINGPLATFORMCONTEXT_H
#include "abstractplatformcontext.h"
namespace KWin
{
namespace QPA
{
class SharingPlatformContext : public AbstractPlatformContext
{
public:
explicit SharingPlatformContext(QOpenGLContext *context);
SharingPlatformContext(QOpenGLContext *context, const EGLSurface &surface, EGLConfig config = nullptr);
void swapBuffers(QPlatformSurface *surface) override;
GLuint defaultFramebufferObject(QPlatformSurface *surface) const override;
bool makeCurrent(QPlatformSurface *surface) override;
bool isSharing() const override;
private:
void create();
EGLSurface m_surface;
};
}
}
#endif

View File

@ -8,6 +8,7 @@
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "window.h"
#include "platform.h"
#include "screens.h"
#include "internal_client.h"
@ -143,5 +144,13 @@ void Window::unmap()
m_contentFBO = nullptr;
}
EGLSurface Window::eglSurface() const
{
if (kwinApp()->platform()->supportsQpaContext()) {
return EGL_NO_SURFACE;
}
return kwinApp()->platform()->sceneEglSurface();
}
}
}

View File

@ -10,6 +10,10 @@
#ifndef KWIN_QPA_WINDOW_H
#define KWIN_QPA_WINDOW_H
#include <epoxy/egl.h>
#include "fixqopengl.h"
#include <fixx11h.h>
#include <QPointer>
#include <qpa/qplatformwindow.h>
@ -39,6 +43,7 @@ public:
QSharedPointer<QOpenGLFramebufferObject> swapFBO();
InternalClient *client() const;
EGLSurface eglSurface() const;
private:
void createFBO();