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.
This commit is contained in:
parent
b7bd8472f2
commit
9b89a3d967
12 changed files with 193 additions and 258 deletions
|
@ -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
|
||||
)
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
51
plugins/qpa/eglplatformcontext.h
Normal file
51
plugins/qpa/eglplatformcontext.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
QSurfaceFormat format() const override;
|
||||
bool isValid() const override;
|
||||
|
||||
EGLSurface nativeHandle() const;
|
||||
EGLSurface eglSurface() const;
|
||||
|
||||
private:
|
||||
QSurfaceFormat m_format;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue