Introduce a shared base class for the EGL backends

There's quite some overlap and duplicated code. This AbstractEglBackend
tries to merge the two backends a little bit again.

This also introduces an AbstractEglTexture which supports both X11 and
Wayland "pixmaps" so that EglOnXBackend can support Wayland buffers.
icc-effect-5.14.5
Martin Gräßlin 2015-03-19 14:46:39 +01:00
parent a1642a85d3
commit dae8eed3a8
7 changed files with 570 additions and 447 deletions

View File

@ -415,7 +415,7 @@ if(KWIN_BUILD_ACTIVITIES)
endif()
if(KWIN_HAVE_EGL)
set(kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} eglonxbackend.cpp)
set(kwin_KDEINIT_SRCS ${kwin_KDEINIT_SRCS} abstract_egl_backend.cpp eglonxbackend.cpp)
endif()
if(HAVE_WAYLAND)

381
abstract_egl_backend.cpp Normal file
View File

@ -0,0 +1,381 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#include "abstract_egl_backend.h"
#include "options.h"
#if HAVE_WAYLAND
#include "wayland_server.h"
#include <KWayland/Server/buffer_interface.h>
#include <KWayland/Server/display.h>
#endif
// kwin libs
#include <kwinglplatform.h>
// Qt
#include <QOpenGLContext>
namespace KWin
{
#if HAVE_WAYLAND
typedef GLboolean(*eglBindWaylandDisplayWL_func)(EGLDisplay dpy, wl_display *display);
typedef GLboolean(*eglUnbindWaylandDisplayWL_func)(EGLDisplay dpy, wl_display *display);
typedef GLboolean(*eglQueryWaylandBufferWL_func)(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
eglBindWaylandDisplayWL_func eglBindWaylandDisplayWL = nullptr;
eglUnbindWaylandDisplayWL_func eglUnbindWaylandDisplayWL = nullptr;
eglQueryWaylandBufferWL_func eglQueryWaylandBufferWL = nullptr;
#ifndef EGL_WAYLAND_BUFFER_WL
#define EGL_WAYLAND_BUFFER_WL 0x31D5
#endif
#ifndef EGL_WAYLAND_PLANE_WL
#define EGL_WAYLAND_PLANE_WL 0x31D6
#endif
#ifndef EGL_WAYLAND_Y_INVERTED_WL
#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB
#endif
#endif
AbstractEglBackend::AbstractEglBackend()
: OpenGLBackend()
{
}
AbstractEglBackend::~AbstractEglBackend() = default;
void AbstractEglBackend::cleanup()
{
#if HAVE_WAYLAND
if (eglUnbindWaylandDisplayWL && eglDisplay() != EGL_NO_DISPLAY) {
eglUnbindWaylandDisplayWL(eglDisplay(), *(WaylandServer::self()->display()));
}
#endif
cleanupGL();
doneCurrent();
eglDestroyContext(m_display, m_context);
eglDestroySurface(m_display, m_surface);
eglTerminate(m_display);
eglReleaseThread();
}
bool AbstractEglBackend::initEglAPI()
{
EGLint major, minor;
if (eglInitialize(m_display, &major, &minor) == EGL_FALSE) {
return false;
}
EGLint error = eglGetError();
if (error != EGL_SUCCESS) {
qCWarning(KWIN_CORE) << "Error during eglInitialize " << error;
return false;
}
qCDebug(KWIN_CORE) << "Egl Initialize succeeded";
#ifdef KWIN_HAVE_OPENGLES
eglBindAPI(EGL_OPENGL_ES_API);
#else
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
qCCritical(KWIN_CORE) << "bind OpenGL API failed";
return false;
}
#endif
qCDebug(KWIN_CORE) << "EGL version: " << major << "." << minor;
return true;
}
void AbstractEglBackend::initKWinGL()
{
initEGL();
GLPlatform *glPlatform = GLPlatform::instance();
glPlatform->detect(EglPlatformInterface);
if (GLPlatform::instance()->driver() == Driver_Intel)
options->setUnredirectFullscreen(false); // bug #252817
options->setGlPreferBufferSwap(options->glPreferBufferSwap()); // resolve autosetting
if (options->glPreferBufferSwap() == Options::AutoSwapStrategy)
options->setGlPreferBufferSwap('e'); // for unknown drivers - should not happen
glPlatform->printResults();
initGL(EglPlatformInterface);
}
void AbstractEglBackend::initBufferAge()
{
setSupportsBufferAge(false);
if (hasGLExtension(QByteArrayLiteral("EGL_EXT_buffer_age"))) {
const QByteArray useBufferAge = qgetenv("KWIN_USE_BUFFER_AGE");
if (useBufferAge != "0")
setSupportsBufferAge(true);
}
}
void AbstractEglBackend::initWayland()
{
#if HAVE_WAYLAND
if (!WaylandServer::self()) {
return;
}
if (hasGLExtension(QByteArrayLiteral("EGL_WL_bind_wayland_display"))) {
eglBindWaylandDisplayWL = (eglBindWaylandDisplayWL_func)eglGetProcAddress("eglBindWaylandDisplayWL");
eglUnbindWaylandDisplayWL = (eglUnbindWaylandDisplayWL_func)eglGetProcAddress("eglUnbindWaylandDisplayWL");
eglQueryWaylandBufferWL = (eglQueryWaylandBufferWL_func)eglGetProcAddress("eglQueryWaylandBufferWL");
if (!eglBindWaylandDisplayWL(eglDisplay(), *(WaylandServer::self()->display()))) {
eglUnbindWaylandDisplayWL = nullptr;
eglQueryWaylandBufferWL = nullptr;
}
}
#endif
}
void AbstractEglBackend::initClientExtensions()
{
// Get the list of client extensions
const char* clientExtensionsCString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
const QByteArray clientExtensionsString = QByteArray::fromRawData(clientExtensionsCString, qstrlen(clientExtensionsCString));
if (clientExtensionsString.isEmpty()) {
// If eglQueryString() returned NULL, the implementation doesn't support
// EGL_EXT_client_extensions. Expect an EGL_BAD_DISPLAY error.
(void) eglGetError();
}
m_clientExtensions = clientExtensionsString.split(' ');
}
bool AbstractEglBackend::hasClientExtension(const QByteArray &ext) const
{
return m_clientExtensions.contains(ext);
}
bool AbstractEglBackend::makeCurrent()
{
if (QOpenGLContext *context = QOpenGLContext::currentContext()) {
// Workaround to tell Qt that no QOpenGLContext is current
context->doneCurrent();
}
const bool current = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
return current;
}
void AbstractEglBackend::doneCurrent()
{
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
AbstractEglTexture::AbstractEglTexture(SceneOpenGL::Texture *texture, AbstractEglBackend *backend)
: SceneOpenGL::TexturePrivate()
, q(texture)
, m_backend(backend)
{
m_target = GL_TEXTURE_2D;
}
AbstractEglTexture::~AbstractEglTexture()
{
if (m_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
}
}
OpenGLBackend *AbstractEglTexture::backend()
{
return m_backend;
}
bool AbstractEglTexture::loadTexture(WindowPixmap *pixmap)
{
#if HAVE_WAYLAND
const auto &buffer = pixmap->buffer();
if (buffer.isNull()) {
// try X11 loading
return loadTexture(pixmap->pixmap(), pixmap->toplevel()->size());
}
// try Wayland loading
if (buffer->shmBuffer()) {
return loadShmTexture(buffer);
} else {
return loadEglTexture(buffer);
}
#else
return loadTexture(pixmap->pixmap(), pixmap->toplevel()->size());
#endif
}
bool AbstractEglTexture::loadTexture(xcb_pixmap_t pix, const QSize &size)
{
if (pix == XCB_NONE)
return false;
glGenTextures(1, &m_texture);
q->setWrapMode(GL_CLAMP_TO_EDGE);
q->setFilter(GL_LINEAR);
q->bind();
const EGLint attribs[] = {
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE
};
m_image = eglCreateImageKHR(m_backend->eglDisplay(), EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
(EGLClientBuffer)pix, attribs);
if (EGL_NO_IMAGE_KHR == m_image) {
qCDebug(KWIN_CORE) << "failed to create egl image";
q->unbind();
q->discard();
return false;
}
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)m_image);
q->unbind();
q->setYInverted(true);
m_size = size;
updateMatrix();
return true;
}
void AbstractEglTexture::updateTexture(WindowPixmap *pixmap)
{
const auto &buffer = pixmap->buffer();
if (buffer.isNull()) {
return;
}
if (!buffer->shmBuffer()) {
q->bind();
EGLImageKHR image = attach(buffer);
q->unbind();
if (image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(m_backend->eglDisplay(), m_image);
m_image = image;
}
return;
}
// shm fallback
if (GLPlatform::instance()->isGLES()) {
// FIXME
return;
}
const QImage &image = buffer->data();
if (image.isNull()) {
return;
}
Q_ASSERT(image.size() == m_size);
q->bind();
const QRegion &damage = pixmap->toplevel()->damage();
// TODO: this should be shared with GLTexture::update
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
for (const QRect &rect : damage.rects()) {
glTexSubImage2D(m_target, 0, rect.x(), rect.y(), rect.width(), rect.height(),
GL_BGRA, GL_UNSIGNED_BYTE, im.copy(rect).bits());
}
q->unbind();
}
#if HAVE_WAYLAND
bool AbstractEglTexture::loadShmTexture(const QPointer< KWayland::Server::BufferInterface > &buffer)
{
if (GLPlatform::instance()->isGLES()) {
// FIXME
return false;
}
const QImage &image = buffer->data();
if (image.isNull()) {
return false;
}
glGenTextures(1, &m_texture);
q->setWrapMode(GL_CLAMP_TO_EDGE);
q->setFilter(GL_LINEAR);
q->bind();
const QSize &size = image.size();
// TODO: this should be shared with GLTexture(const QImage&, GLenum)
GLenum format = 0;
switch (image.format()) {
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
format = GL_RGBA8;
break;
case QImage::Format_RGB32:
format = GL_RGB8;
break;
default:
return false;
}
glTexImage2D(m_target, 0, format, size.width(), size.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
q->unbind();
q->setYInverted(true);
m_size = size;
updateMatrix();
return true;
}
bool AbstractEglTexture::loadEglTexture(const QPointer< KWayland::Server::BufferInterface > &buffer)
{
if (!eglQueryWaylandBufferWL) {
return false;
}
if (!buffer->resource()) {
return false;
}
glGenTextures(1, &m_texture);
q->setWrapMode(GL_CLAMP_TO_EDGE);
q->setFilter(GL_LINEAR);
q->bind();
m_image = attach(buffer);
q->unbind();
if (EGL_NO_IMAGE_KHR == m_image) {
qCDebug(KWIN_CORE) << "failed to create egl image";
q->discard();
return false;
}
return true;
}
EGLImageKHR AbstractEglTexture::attach(const QPointer< KWayland::Server::BufferInterface > &buffer)
{
EGLint format, width, height, yInverted;
eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), EGL_TEXTURE_FORMAT, &format);
if (format != EGL_TEXTURE_RGB && format != EGL_TEXTURE_RGBA) {
qCDebug(KWIN_CORE) << "Unsupported texture format: " << format;
return EGL_NO_IMAGE_KHR;
}
eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), EGL_WAYLAND_Y_INVERTED_WL, &yInverted);
eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), EGL_WIDTH, &width);
eglQueryWaylandBufferWL(m_backend->eglDisplay(), buffer->resource(), EGL_HEIGHT, &height);
const EGLint attribs[] = {
EGL_WAYLAND_PLANE_WL, 0,
EGL_NONE
};
EGLImageKHR image = eglCreateImageKHR(m_backend->eglDisplay(), EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL,
(EGLClientBuffer)buffer->resource(), attribs);
if (image != EGL_NO_IMAGE_KHR) {
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
m_size = QSize(width, height);
updateMatrix();
q->setYInverted(yInverted);
}
return image;
}
#endif
}

105
abstract_egl_backend.h Normal file
View File

@ -0,0 +1,105 @@
/********************************************************************
KWin - the KDE window manager
This file is part of the KDE project.
Copyright (C) 2015 Martin Gräßlin <mgraesslin@kde.org>
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 <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_ABSTRACT_EGL_BACKEND_H
#define KWIN_ABSTRACT_EGL_BACKEND_H
#include "scene_opengl.h"
namespace KWin
{
class AbstractEglBackend : public OpenGLBackend
{
public:
virtual ~AbstractEglBackend();
bool makeCurrent() override;
void doneCurrent() override;
EGLDisplay eglDisplay() const {
return m_display;
}
protected:
AbstractEglBackend();
EGLContext context() const {
return m_context;
}
EGLSurface surface() const {
return m_surface;
}
EGLConfig config() const {
return m_config;
}
void setEglDisplay(const EGLDisplay &display) {
m_display = display;
}
void setContext(const EGLContext &context) {
m_context = context;
}
void setSurface(const EGLSurface &surface) {
m_surface = surface;
}
void setConfig(const EGLConfig &config) {
m_config = config;
}
void cleanup();
bool initEglAPI();
void initKWinGL();
void initBufferAge();
void initClientExtensions();
void initWayland();
bool hasClientExtension(const QByteArray &ext) const;
private:
EGLDisplay m_display = EGL_NO_DISPLAY;
EGLSurface m_surface = EGL_NO_SURFACE;
EGLContext m_context = EGL_NO_CONTEXT;
EGLConfig m_config = nullptr;
QList<QByteArray> m_clientExtensions;
};
class AbstractEglTexture : public SceneOpenGL::TexturePrivate
{
public:
virtual ~AbstractEglTexture();
bool loadTexture(WindowPixmap *pixmap) override;
void updateTexture(WindowPixmap *pixmap) override;
OpenGLBackend *backend() override;
protected:
AbstractEglTexture(SceneOpenGL::Texture *texture, AbstractEglBackend *backend);
EGLImageKHR image() const {
return m_image;
}
private:
bool loadTexture(xcb_pixmap_t pix, const QSize &size);
#if HAVE_WAYLAND
bool loadShmTexture(const QPointer<KWayland::Server::BufferInterface> &buffer);
bool loadEglTexture(const QPointer<KWayland::Server::BufferInterface> &buffer);
EGLImageKHR attach(const QPointer<KWayland::Server::BufferInterface> &buffer);
#endif
SceneOpenGL::Texture *q;
AbstractEglBackend *m_backend;
EGLImageKHR m_image;
};
}
#endif

View File

@ -37,27 +37,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
namespace KWin
{
typedef GLboolean(*eglBindWaylandDisplayWL_func)(EGLDisplay dpy, wl_display *display);
typedef GLboolean(*eglUnbindWaylandDisplayWL_func)(EGLDisplay dpy, wl_display *display);
typedef GLboolean(*eglQueryWaylandBufferWL_func)(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
eglBindWaylandDisplayWL_func eglBindWaylandDisplayWL = nullptr;
eglUnbindWaylandDisplayWL_func eglUnbindWaylandDisplayWL = nullptr;
eglQueryWaylandBufferWL_func eglQueryWaylandBufferWL = nullptr;
#ifndef EGL_WAYLAND_BUFFER_WL
#define EGL_WAYLAND_BUFFER_WL 0x31D5
#endif
#ifndef EGL_WAYLAND_PLANE_WL
#define EGL_WAYLAND_PLANE_WL 0x31D6
#endif
#ifndef EGL_WAYLAND_Y_INVERTED_WL
#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB
#endif
EglWaylandBackend::EglWaylandBackend()
: QObject(NULL)
, OpenGLBackend()
, m_context(EGL_NO_CONTEXT)
, AbstractEglBackend()
, m_bufferAge(0)
, m_wayland(Wayland::WaylandBackend::self())
, m_overlay(NULL)
@ -84,15 +66,7 @@ EglWaylandBackend::EglWaylandBackend()
EglWaylandBackend::~EglWaylandBackend()
{
if (eglUnbindWaylandDisplayWL && m_display != EGL_NO_DISPLAY) {
eglUnbindWaylandDisplayWL(m_display, *(WaylandServer::self()->display()));
}
cleanupGL();
doneCurrent();
eglDestroyContext(m_display, m_context);
eglDestroySurface(m_display, m_surface);
eglTerminate(m_display);
eglReleaseThread();
cleanup();
if (m_overlay) {
wl_egl_window_destroy(m_overlay);
}
@ -100,53 +74,26 @@ EglWaylandBackend::~EglWaylandBackend()
bool EglWaylandBackend::initializeEgl()
{
// Get the list of client extensions
const char* clientExtensionsCString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
const QByteArray clientExtensionsString = QByteArray::fromRawData(clientExtensionsCString, qstrlen(clientExtensionsCString));
if (clientExtensionsString.isEmpty()) {
// If eglQueryString() returned NULL, the implementation doesn't support
// EGL_EXT_client_extensions. Expect an EGL_BAD_DISPLAY error.
(void) eglGetError();
}
const QList<QByteArray> clientExtensions = clientExtensionsString.split(' ');
initClientExtensions();
EGLDisplay display = EGL_NO_DISPLAY;
// Use eglGetPlatformDisplayEXT() to get the display pointer
// if the implementation supports it.
m_havePlatformBase = clientExtensions.contains(QByteArrayLiteral("EGL_EXT_platform_base"));
m_havePlatformBase = hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_base"));
if (m_havePlatformBase) {
// Make sure that the wayland platform is supported
if (!clientExtensions.contains(QByteArrayLiteral("EGL_EXT_platform_wayland")))
if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_wayland")))
return false;
m_display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, m_wayland->display(), nullptr);
display = eglGetPlatformDisplayEXT(EGL_PLATFORM_WAYLAND_EXT, m_wayland->display(), nullptr);
} else {
m_display = eglGetDisplay(m_wayland->display());
display = eglGetDisplay(m_wayland->display());
}
if (m_display == EGL_NO_DISPLAY)
if (display == EGL_NO_DISPLAY)
return false;
EGLint major, minor;
if (eglInitialize(m_display, &major, &minor) == EGL_FALSE)
return false;
EGLint error = eglGetError();
if (error != EGL_SUCCESS) {
qCWarning(KWIN_CORE) << "Error during eglInitialize " << error;
return false;
}
qCDebug(KWIN_CORE) << "Egl Initialize succeeded";
#ifdef KWIN_HAVE_OPENGLES
eglBindAPI(EGL_OPENGL_ES_API);
#else
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
qCCritical(KWIN_CORE) << "bind OpenGL API failed";
return false;
}
#endif
qCDebug(KWIN_CORE) << "EGL version: " << major << "." << minor;
return true;
setEglDisplay(display);
return initEglAPI();
}
void EglWaylandBackend::init()
@ -156,43 +103,23 @@ void EglWaylandBackend::init()
return;
}
initEGL();
GLPlatform *glPlatform = GLPlatform::instance();
glPlatform->detect(EglPlatformInterface);
glPlatform->printResults();
initGL(EglPlatformInterface);
setSupportsBufferAge(false);
if (hasGLExtension(QByteArrayLiteral("EGL_EXT_buffer_age"))) {
const QByteArray useBufferAge = qgetenv("KWIN_USE_BUFFER_AGE");
if (useBufferAge != "0")
setSupportsBufferAge(true);
}
if (hasGLExtension(QByteArrayLiteral("EGL_WL_bind_wayland_display"))) {
eglBindWaylandDisplayWL = (eglBindWaylandDisplayWL_func)eglGetProcAddress("eglBindWaylandDisplayWL");
eglUnbindWaylandDisplayWL = (eglUnbindWaylandDisplayWL_func)eglGetProcAddress("eglUnbindWaylandDisplayWL");
eglQueryWaylandBufferWL = (eglQueryWaylandBufferWL_func)eglGetProcAddress("eglQueryWaylandBufferWL");
if (!eglBindWaylandDisplayWL(m_display, *(WaylandServer::self()->display()))) {
eglUnbindWaylandDisplayWL = nullptr;
eglQueryWaylandBufferWL = nullptr;
}
}
initKWinGL();
initBufferAge();
initWayland();
}
bool EglWaylandBackend::initRenderingContext()
{
initBufferConfigs();
EGLContext context = EGL_NO_CONTEXT;
#ifdef KWIN_HAVE_OPENGLES
const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, context_attribs);
context = eglCreateContext(eglDisplay(), config(), EGL_NO_CONTEXT, context_attribs);
#else
const EGLint context_attribs_31_core[] = {
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
@ -205,21 +132,22 @@ bool EglWaylandBackend::initRenderingContext()
EGL_NONE
};
const char* eglExtensionsCString = eglQueryString(m_display, EGL_EXTENSIONS);
const char* eglExtensionsCString = eglQueryString(eglDisplay(), EGL_EXTENSIONS);
const QList<QByteArray> extensions = QByteArray::fromRawData(eglExtensionsCString, qstrlen(eglExtensionsCString)).split(' ');
// Try to create a 3.1 core context
if (options->glCoreProfile() && extensions.contains(QByteArrayLiteral("EGL_KHR_create_context")))
m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, context_attribs_31_core);
context = eglCreateContext(eglDisplay(), config(), EGL_NO_CONTEXT, context_attribs_31_core);
if (m_context == EGL_NO_CONTEXT)
m_context = eglCreateContext(m_display, m_config, EGL_NO_CONTEXT, context_attribs_legacy);
if (context == EGL_NO_CONTEXT)
context = eglCreateContext(eglDisplay(), config(), EGL_NO_CONTEXT, context_attribs_legacy);
#endif
if (m_context == EGL_NO_CONTEXT) {
if (context == EGL_NO_CONTEXT) {
qCCritical(KWIN_CORE) << "Create Context failed";
return false;
}
setContext(context);
if (!m_wayland->surface()) {
return false;
@ -234,22 +162,24 @@ bool EglWaylandBackend::initRenderingContext()
return false;
}
EGLSurface surface = EGL_NO_SURFACE;
if (m_havePlatformBase)
m_surface = eglCreatePlatformWindowSurfaceEXT(m_display, m_config, (void *) m_overlay, nullptr);
surface = eglCreatePlatformWindowSurfaceEXT(eglDisplay(), config(), (void *) m_overlay, nullptr);
else
m_surface = eglCreateWindowSurface(m_display, m_config, m_overlay, nullptr);
surface = eglCreateWindowSurface(eglDisplay(), config(), m_overlay, nullptr);
if (m_surface == EGL_NO_SURFACE) {
if (surface == EGL_NO_SURFACE) {
qCCritical(KWIN_CORE) << "Create Window Surface failed";
return false;
}
setSurface(surface);
return makeContextCurrent();
}
bool EglWaylandBackend::makeContextCurrent()
{
if (eglMakeCurrent(m_display, m_surface, m_surface, m_context) == EGL_FALSE) {
if (eglMakeCurrent(eglDisplay(), surface(), surface(), context()) == EGL_FALSE) {
qCCritical(KWIN_CORE) << "Make Context Current failed";
return false;
}
@ -281,7 +211,7 @@ bool EglWaylandBackend::initBufferConfigs()
EGLint count;
EGLConfig configs[1024];
if (eglChooseConfig(m_display, config_attribs, configs, 1, &count) == EGL_FALSE) {
if (eglChooseConfig(eglDisplay(), config_attribs, configs, 1, &count) == EGL_FALSE) {
qCCritical(KWIN_CORE) << "choose config failed";
return false;
}
@ -289,7 +219,7 @@ bool EglWaylandBackend::initBufferConfigs()
qCCritical(KWIN_CORE) << "choose config did not return a config" << count;
return false;
}
m_config = configs[0];
setConfig(configs[0]);
return true;
}
@ -300,12 +230,12 @@ void EglWaylandBackend::present()
Compositor::self()->aboutToSwapBuffers();
if (supportsBufferAge()) {
eglSwapBuffers(m_display, m_surface);
eglQuerySurface(m_display, m_surface, EGL_BUFFER_AGE_EXT, &m_bufferAge);
eglSwapBuffers(eglDisplay(), surface());
eglQuerySurface(eglDisplay(), surface(), EGL_BUFFER_AGE_EXT, &m_bufferAge);
setLastDamage(QRegion());
return;
} else {
eglSwapBuffers(m_display, m_surface);
eglSwapBuffers(eglDisplay(), surface());
setLastDamage(QRegion());
}
}
@ -373,21 +303,6 @@ void EglWaylandBackend::endRenderingFrame(const QRegion &renderedRegion, const Q
addToDamageHistory(damagedRegion);
}
bool EglWaylandBackend::makeCurrent()
{
if (QOpenGLContext *context = QOpenGLContext::currentContext()) {
// Workaround to tell Qt that no QOpenGLContext is current
context->doneCurrent();
}
const bool current = eglMakeCurrent(m_display, m_surface, m_surface, m_context);
return current;
}
void EglWaylandBackend::doneCurrent()
{
eglMakeCurrent(m_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
void EglWaylandBackend::overlaySizeChanged(const QSize &size)
{
wl_egl_window_resize(m_overlay, size.width(), size.height(), 0, 0);
@ -403,166 +318,10 @@ bool EglWaylandBackend::usesOverlayWindow() const
************************************************/
EglWaylandTexture::EglWaylandTexture(KWin::SceneOpenGL::Texture *texture, KWin::EglWaylandBackend *backend)
: SceneOpenGL::TexturePrivate()
, q(texture)
, m_backend(backend)
: AbstractEglTexture(texture, backend)
{
m_target = GL_TEXTURE_2D;
}
EglWaylandTexture::~EglWaylandTexture()
{
if (m_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(m_backend->m_display, m_image);
}
}
OpenGLBackend *EglWaylandTexture::backend()
{
return m_backend;
}
bool EglWaylandTexture::loadTexture(WindowPixmap *pixmap)
{
const auto &buffer = pixmap->buffer();
if (buffer.isNull()) {
return false;
}
if (buffer->shmBuffer()) {
return loadShmTexture(buffer);
} else {
return loadEglTexture(buffer);
}
}
bool EglWaylandTexture::loadShmTexture(const QPointer< KWayland::Server::BufferInterface > &buffer)
{
if (GLPlatform::instance()->isGLES()) {
// FIXME
return false;
}
const QImage &image = buffer->data();
if (image.isNull()) {
return false;
}
glGenTextures(1, &m_texture);
q->setWrapMode(GL_CLAMP_TO_EDGE);
q->setFilter(GL_LINEAR);
q->bind();
const QSize &size = image.size();
// TODO: this should be shared with GLTexture(const QImage&, GLenum)
GLenum format = 0;
switch (image.format()) {
case QImage::Format_ARGB32:
case QImage::Format_ARGB32_Premultiplied:
format = GL_RGBA8;
break;
case QImage::Format_RGB32:
format = GL_RGB8;
break;
default:
return false;
}
glTexImage2D(m_target, 0, format, size.width(), size.height(), 0,
GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
q->unbind();
q->setYInverted(true);
m_size = size;
updateMatrix();
return true;
}
bool EglWaylandTexture::loadEglTexture(const QPointer< KWayland::Server::BufferInterface > &buffer)
{
if (!eglQueryWaylandBufferWL) {
return false;
}
if (!buffer->resource()) {
return false;
}
glGenTextures(1, &m_texture);
q->setWrapMode(GL_CLAMP_TO_EDGE);
q->setFilter(GL_LINEAR);
q->bind();
m_image = attach(buffer);
q->unbind();
if (EGL_NO_IMAGE_KHR == m_image) {
qCDebug(KWIN_CORE) << "failed to create egl image";
q->discard();
return false;
}
return true;
}
void EglWaylandTexture::updateTexture(WindowPixmap *pixmap)
{
const auto &buffer = pixmap->buffer();
if (buffer.isNull()) {
return;
}
if (!buffer->shmBuffer()) {
q->bind();
EGLImageKHR image = attach(buffer);
q->unbind();
if (image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(m_backend->m_display, m_image);
m_image = image;
}
return;
}
// shm fallback
if (GLPlatform::instance()->isGLES()) {
// FIXME
return;
}
const QImage &image = buffer->data();
if (image.isNull()) {
return;
}
Q_ASSERT(image.size() == m_size);
q->bind();
const QRegion &damage = pixmap->toplevel()->damage();
// TODO: this should be shared with GLTexture::update
const QImage im = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
for (const QRect &rect : damage.rects()) {
glTexSubImage2D(m_target, 0, rect.x(), rect.y(), rect.width(), rect.height(),
GL_BGRA, GL_UNSIGNED_BYTE, im.copy(rect).bits());
}
q->unbind();
}
EGLImageKHR EglWaylandTexture::attach(const QPointer< KWayland::Server::BufferInterface > &buffer)
{
EGLint format, width, height, yInverted;
eglQueryWaylandBufferWL(m_backend->m_display, buffer->resource(), EGL_TEXTURE_FORMAT, &format);
if (format != EGL_TEXTURE_RGB && format != EGL_TEXTURE_RGBA) {
qCDebug(KWIN_CORE) << "Unsupported texture format: " << format;
return EGL_NO_IMAGE_KHR;
}
eglQueryWaylandBufferWL(m_backend->m_display, buffer->resource(), EGL_WAYLAND_Y_INVERTED_WL, &yInverted);
eglQueryWaylandBufferWL(m_backend->m_display, buffer->resource(), EGL_WIDTH, &width);
eglQueryWaylandBufferWL(m_backend->m_display, buffer->resource(), EGL_HEIGHT, &height);
const EGLint attribs[] = {
EGL_WAYLAND_PLANE_WL, 0,
EGL_NONE
};
EGLImageKHR image = eglCreateImageKHR(m_backend->m_display, EGL_NO_CONTEXT, EGL_WAYLAND_BUFFER_WL,
(EGLClientBuffer)buffer->resource(), attribs);
if (image != EGL_NO_IMAGE_KHR) {
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)image);
m_size = QSize(width, height);
updateMatrix();
q->setYInverted(yInverted);
}
return image;
}
EglWaylandTexture::~EglWaylandTexture() = default;
} // namespace

View File

@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_EGL_WAYLAND_BACKEND_H
#define KWIN_EGL_WAYLAND_BACKEND_H
#include "abstract_egl_backend.h"
#include "scene_opengl.h"
// wayland
#include <wayland-egl.h>
@ -46,7 +47,7 @@ namespace Wayland {
* repaints, which is obviously not optimal. Best solution is probably to go for buffer_age extension
* and make it the only available solution next to fullscreen repaints.
**/
class EglWaylandBackend : public QObject, public OpenGLBackend
class EglWaylandBackend : public QObject, public AbstractEglBackend
{
Q_OBJECT
public:
@ -56,8 +57,6 @@ public:
virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture);
virtual QRegion prepareRenderingFrame();
virtual void endRenderingFrame(const QRegion &renderedRegion, const QRegion &damagedRegion);
virtual bool makeCurrent() override;
virtual void doneCurrent() override;
virtual bool usesOverlayWindow() const override;
protected:
@ -72,10 +71,6 @@ private:
bool initBufferConfigs();
bool initRenderingContext();
bool makeContextCurrent();
EGLDisplay m_display;
EGLConfig m_config;
EGLSurface m_surface;
EGLContext m_context;
int m_bufferAge;
Wayland::WaylandBackend *m_wayland;
wl_egl_window *m_overlay;
@ -86,23 +81,14 @@ private:
/**
* @brief Texture using an EGLImageKHR.
**/
class EglWaylandTexture : public SceneOpenGL::TexturePrivate
class EglWaylandTexture : public AbstractEglTexture
{
public:
virtual ~EglWaylandTexture();
virtual bool loadTexture(WindowPixmap *pixmap) override;
virtual void updateTexture(WindowPixmap *pixmap) override;
virtual OpenGLBackend *backend();
private:
friend class EglWaylandBackend;
EglWaylandTexture(SceneOpenGL::Texture *texture, EglWaylandBackend *backend);
bool loadShmTexture(const QPointer<KWayland::Server::BufferInterface> &buffer);
bool loadEglTexture(const QPointer<KWayland::Server::BufferInterface> &buffer);
EGLImageKHR attach(const QPointer<KWayland::Server::BufferInterface> &buffer);
SceneOpenGL::Texture *q;
EglWaylandBackend *m_backend;
EGLImageKHR m_image;
};
} // namespace

View File

@ -39,9 +39,8 @@ namespace KWin
{
EglOnXBackend::EglOnXBackend()
: OpenGLBackend()
: AbstractEglBackend()
, m_overlayWindow(new OverlayWindow())
, ctx(EGL_NO_CONTEXT)
, surfaceHasSubPost(0)
, m_bufferAge(0)
, m_usesOverlayWindow(true)
@ -57,9 +56,8 @@ EglOnXBackend::EglOnXBackend()
#if HAVE_X11_XCB
EglOnXBackend::EglOnXBackend(X11WindowedBackend *backend)
: OpenGLBackend()
: AbstractEglBackend()
, m_overlayWindow(nullptr)
, ctx(EGL_NO_CONTEXT)
, surfaceHasSubPost(0)
, m_bufferAge(0)
, m_usesOverlayWindow(false)
@ -81,12 +79,7 @@ EglOnXBackend::~EglOnXBackend()
if (isFailed() && m_overlayWindow) {
m_overlayWindow->destroy();
}
cleanupGL();
doneCurrent();
eglDestroyContext(dpy, ctx);
eglDestroySurface(dpy, surface);
eglTerminate(dpy);
eglReleaseThread();
cleanup();
if (m_overlayWindow) {
if (overlayWindow()->window()) {
overlayWindow()->destroy();
@ -105,22 +98,13 @@ void EglOnXBackend::init()
return;
}
initEGL();
initKWinGL();
if (!hasGLExtension(QByteArrayLiteral("EGL_KHR_image")) &&
(!hasGLExtension(QByteArrayLiteral("EGL_KHR_image_base")) ||
!hasGLExtension(QByteArrayLiteral("EGL_KHR_image_pixmap")))) {
setFailed(QStringLiteral("Required support for binding pixmaps to EGLImages not found, disabling compositing"));
return;
}
GLPlatform *glPlatform = GLPlatform::instance();
glPlatform->detect(EglPlatformInterface);
if (GLPlatform::instance()->driver() == Driver_Intel)
options->setUnredirectFullscreen(false); // bug #252817
options->setGlPreferBufferSwap(options->glPreferBufferSwap()); // resolve autosetting
if (options->glPreferBufferSwap() == Options::AutoSwapStrategy)
options->setGlPreferBufferSwap('e'); // for unknown drivers - should not happen
glPlatform->printResults();
initGL(EglPlatformInterface);
if (!hasGLExtension(QByteArrayLiteral("GL_OES_EGL_image"))) {
setFailed(QStringLiteral("Required extension GL_OES_EGL_image not found, disabling compositing"));
return;
@ -128,7 +112,7 @@ void EglOnXBackend::init()
// check for EGL_NV_post_sub_buffer and whether it can be used on the surface
if (hasGLExtension(QByteArrayLiteral("EGL_NV_post_sub_buffer"))) {
if (eglQuerySurface(dpy, surface, EGL_POST_SUB_BUFFER_SUPPORTED_NV, &surfaceHasSubPost) == EGL_FALSE) {
if (eglQuerySurface(eglDisplay(), surface(), EGL_POST_SUB_BUFFER_SUPPORTED_NV, &surfaceHasSubPost) == EGL_FALSE) {
EGLint error = eglGetError();
if (error != EGL_SUCCESS && error != EGL_BAD_ATTRIBUTE) {
setFailed(QStringLiteral("query surface failed"));
@ -139,14 +123,7 @@ void EglOnXBackend::init()
}
}
setSupportsBufferAge(false);
if (hasGLExtension(QByteArrayLiteral("EGL_EXT_buffer_age"))) {
const QByteArray useBufferAge = qgetenv("KWIN_USE_BUFFER_AGE");
if (useBufferAge != "0")
setSupportsBufferAge(true);
}
initBufferAge();
setSyncsToVBlank(false);
setBlocksForRetrace(false);
@ -158,9 +135,9 @@ void EglOnXBackend::init()
if (options->glPreferBufferSwap() != Options::NoSwapEncourage) {
// check if swap interval 1 is supported
EGLint val;
eglGetConfigAttrib(dpy, config, EGL_MAX_SWAP_INTERVAL, &val);
eglGetConfigAttrib(eglDisplay(), config(), EGL_MAX_SWAP_INTERVAL, &val);
if (val >= 1) {
if (eglSwapInterval(dpy, 1)) {
if (eglSwapInterval(eglDisplay(), 1)) {
qCDebug(KWIN_CORE) << "Enabled v-sync";
setSyncsToVBlank(true);
const QByteArray tripleBuffer = qgetenv("KWIN_TRIPLE_BUFFER");
@ -175,7 +152,7 @@ void EglOnXBackend::init()
}
} else {
// disable v-sync
eglSwapInterval(dpy, 0);
eglSwapInterval(eglDisplay(), 0);
}
} else {
/* In the GLX backend, we fall back to using glCopyPixels if we have no extension providing support for partial screen updates.
@ -184,28 +161,23 @@ void EglOnXBackend::init()
* eglSwapBuffers() for each frame. eglSwapBuffers() then does the copy (no page flip possible in this mode),
* which means it is slow and not synced to the v-blank. */
qCWarning(KWIN_CORE) << "eglPostSubBufferNV not supported, have to enable buffer preservation - which breaks v-sync and performance";
eglSurfaceAttrib(dpy, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
eglSurfaceAttrib(eglDisplay(), surface(), EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
}
initWayland();
}
bool EglOnXBackend::initRenderingContext()
{
// Get the list of client extensions
const QByteArray clientExtensionString = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
if (clientExtensionString.isEmpty()) {
// If eglQueryString() returned NULL, the implementation doesn't support
// EGL_EXT_client_extensions. Expect an EGL_BAD_DISPLAY error.
(void) eglGetError();
}
const QList<QByteArray> clientExtensions = clientExtensionString.split(' ');
initClientExtensions();
EGLDisplay dpy;
// Use eglGetPlatformDisplayEXT() to get the display pointer
// if the implementation supports it.
const bool havePlatformBase = clientExtensions.contains("EGL_EXT_platform_base");
const bool havePlatformBase = hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_base"));
if (havePlatformBase) {
// Make sure that the X11 platform is supported
if (!clientExtensions.contains("EGL_EXT_platform_x11"))
if (!hasClientExtension(QByteArrayLiteral("EGL_EXT_platform_x11")))
return false;
const int attribs[] = {
@ -220,19 +192,8 @@ bool EglOnXBackend::initRenderingContext()
if (dpy == EGL_NO_DISPLAY)
return false;
EGLint major, minor;
if (eglInitialize(dpy, &major, &minor) == EGL_FALSE)
return false;
#ifdef KWIN_HAVE_OPENGLES
eglBindAPI(EGL_OPENGL_ES_API);
#else
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
qCCritical(KWIN_CORE) << "bind OpenGL API failed";
return false;
}
#endif
setEglDisplay(dpy);
initEglAPI();
initBufferConfigs();
@ -258,23 +219,30 @@ bool EglOnXBackend::initRenderingContext()
return false;
}
EGLSurface surface = EGL_NO_SURFACE;
if (havePlatformBase) {
// Note: Window is 64 bits on a 64-bit architecture whereas xcb_window_t is
// always 32 bits. eglCreatePlatformWindowSurfaceEXT() expects the
// native_window parameter to be pointer to a Window, so this variable
// cannot be an xcb_window_t.
surface = eglCreatePlatformWindowSurfaceEXT(dpy, config, (void *) &window, nullptr);
surface = eglCreatePlatformWindowSurfaceEXT(dpy, config(), (void *) &window, nullptr);
} else {
surface = eglCreateWindowSurface(dpy, config, window, nullptr);
surface = eglCreateWindowSurface(dpy, config(), window, nullptr);
}
if (surface == EGL_NO_SURFACE) {
return false;
}
setSurface(surface);
EGLContext ctx = EGL_NO_CONTEXT;
#ifdef KWIN_HAVE_OPENGLES
const EGLint context_attribs[] = {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL_NONE
};
ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, context_attribs);
ctx = eglCreateContext(dpy, config(), EGL_NO_CONTEXT, context_attribs);
#else
const EGLint context_attribs_31_core[] = {
EGL_CONTEXT_MAJOR_VERSION_KHR, 3,
@ -291,24 +259,23 @@ bool EglOnXBackend::initRenderingContext()
// Try to create a 3.1 core context
if (options->glCoreProfile() && extensions.contains("EGL_KHR_create_context"))
ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, context_attribs_31_core);
ctx = eglCreateContext(dpy, config(), EGL_NO_CONTEXT, context_attribs_31_core);
if (ctx == EGL_NO_CONTEXT)
ctx = eglCreateContext(dpy, config, EGL_NO_CONTEXT, context_attribs_legacy);
ctx = eglCreateContext(dpy, config(), EGL_NO_CONTEXT, context_attribs_legacy);
#endif
if (ctx == EGL_NO_CONTEXT) {
qCCritical(KWIN_CORE) << "Create Context failed";
return false;
}
setContext(ctx);
if (eglMakeCurrent(dpy, surface, surface, ctx) == EGL_FALSE) {
qCCritical(KWIN_CORE) << "Make Context Current failed";
return false;
}
qCDebug(KWIN_CORE) << "EGL version: " << major << "." << minor;
EGLint error = eglGetError();
if (error != EGL_SUCCESS) {
qCWarning(KWIN_CORE) << "Error occurred while creating context " << error;
@ -337,7 +304,7 @@ bool EglOnXBackend::initBufferConfigs()
EGLint count;
EGLConfig configs[1024];
if (eglChooseConfig(dpy, config_attribs, configs, 1024, &count) == EGL_FALSE) {
if (eglChooseConfig(eglDisplay(), config_attribs, configs, 1024, &count) == EGL_FALSE) {
qCCritical(KWIN_CORE) << "choose config failed";
return false;
}
@ -350,14 +317,14 @@ bool EglOnXBackend::initBufferConfigs()
return false;
}
config = configs[0];
setConfig(configs[0]);
for (int i = 0; i < count; i++) {
EGLint val;
if (eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &val) == EGL_FALSE) {
if (eglGetConfigAttrib(eglDisplay(), configs[i], EGL_NATIVE_VISUAL_ID, &val) == EGL_FALSE) {
qCCritical(KWIN_CORE) << "egl get config attrib failed";
}
if (uint32_t(val) == attribs->visual) {
config = configs[i];
setConfig(configs[i]);
break;
}
}
@ -379,7 +346,7 @@ void EglOnXBackend::present()
m_swapProfiler.begin();
}
// the entire screen changed, or we cannot do partial updates (which implies we enabled surface preservation)
eglSwapBuffers(dpy, surface);
eglSwapBuffers(eglDisplay(), surface());
if (gs_tripleBufferNeedsDetection) {
eglWaitGL();
if (char result = m_swapProfiler.end()) {
@ -388,7 +355,7 @@ void EglOnXBackend::present()
// TODO this is a workaround, we should get __GL_YIELD set before libGL checks it
if (qstrcmp(qgetenv("__GL_YIELD"), "USLEEP")) {
options->setGlPreferBufferSwap(0);
eglSwapInterval(dpy, 0);
eglSwapInterval(eglDisplay(), 0);
qCWarning(KWIN_CORE) << "\nIt seems you are using the nvidia driver without triple buffering\n"
"You must export __GL_YIELD=\"USLEEP\" to prevent large CPU overhead on synced swaps\n"
"Preferably, enable the TripleBuffer Option in the xorg.conf Device\n"
@ -400,12 +367,12 @@ void EglOnXBackend::present()
}
}
if (supportsBufferAge()) {
eglQuerySurface(dpy, surface, EGL_BUFFER_AGE_EXT, &m_bufferAge);
eglQuerySurface(eglDisplay(), surface(), EGL_BUFFER_AGE_EXT, &m_bufferAge);
}
} else {
// a part of the screen changed, and we can use eglPostSubBufferNV to copy the updated area
foreach (const QRect & r, lastDamage().rects()) {
eglPostSubBufferNV(dpy, surface, r.left(), screenSize.height() - r.bottom() - 1, r.width(), r.height());
eglPostSubBufferNV(eglDisplay(), surface(), r.left(), screenSize.height() - r.bottom() - 1, r.width(), r.height());
}
}
@ -494,21 +461,6 @@ void EglOnXBackend::endRenderingFrame(const QRegion &renderedRegion, const QRegi
addToDamageHistory(damagedRegion);
}
bool EglOnXBackend::makeCurrent()
{
if (QOpenGLContext *context = QOpenGLContext::currentContext()) {
// Workaround to tell Qt that no QOpenGLContext is current
context->doneCurrent();
}
const bool current = eglMakeCurrent(dpy, surface, surface, ctx);
return current;
}
void EglOnXBackend::doneCurrent()
{
eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
bool EglOnXBackend::usesOverlayWindow() const
{
return m_usesOverlayWindow;
@ -524,60 +476,11 @@ OverlayWindow* EglOnXBackend::overlayWindow()
************************************************/
EglTexture::EglTexture(KWin::SceneOpenGL::Texture *texture, KWin::EglOnXBackend *backend)
: SceneOpenGL::TexturePrivate()
, q(texture)
, m_backend(backend)
, m_image(EGL_NO_IMAGE_KHR)
: AbstractEglTexture(texture, backend)
{
m_target = GL_TEXTURE_2D;
}
EglTexture::~EglTexture()
{
if (m_image != EGL_NO_IMAGE_KHR) {
eglDestroyImageKHR(m_backend->dpy, m_image);
}
}
OpenGLBackend *EglTexture::backend()
{
return m_backend;
}
bool EglTexture::loadTexture(xcb_pixmap_t pix, const QSize &size)
{
if (pix == XCB_NONE)
return false;
glGenTextures(1, &m_texture);
q->setWrapMode(GL_CLAMP_TO_EDGE);
q->setFilter(GL_LINEAR);
q->bind();
const EGLint attribs[] = {
EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
EGL_NONE
};
m_image = eglCreateImageKHR(m_backend->dpy, EGL_NO_CONTEXT, EGL_NATIVE_PIXMAP_KHR,
(EGLClientBuffer)pix, attribs);
if (EGL_NO_IMAGE_KHR == m_image) {
qCDebug(KWIN_CORE) << "failed to create egl image";
q->unbind();
q->discard();
return false;
}
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES)m_image);
q->unbind();
q->setYInverted(true);
m_size = size;
updateMatrix();
return true;
}
bool EglTexture::loadTexture(WindowPixmap *pixmap)
{
return loadTexture(pixmap->pixmap(), pixmap->toplevel()->size());
}
EglTexture::~EglTexture() = default;
void KWin::EglTexture::onDamage()
{
@ -585,7 +488,7 @@ void KWin::EglTexture::onDamage()
// This is just implemented to be consistent with
// the example in mesa/demos/src/egl/opengles1/texture_from_pixmap.c
eglWaitNative(EGL_CORE_NATIVE_ENGINE);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) m_image);
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, (GLeglImageOES) image());
}
GLTexturePrivate::onDamage();
}

View File

@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/
#ifndef KWIN_EGL_ON_X_BACKEND_H
#define KWIN_EGL_ON_X_BACKEND_H
#include "abstract_egl_backend.h"
#include "scene_opengl.h"
namespace KWin
@ -29,7 +30,7 @@ class X11WindowedBackend;
/**
* @brief OpenGL Backend using Egl windowing system over an X overlay window.
**/
class EglOnXBackend : public OpenGLBackend
class EglOnXBackend : public AbstractEglBackend
{
public:
EglOnXBackend();
@ -41,8 +42,6 @@ public:
virtual SceneOpenGL::TexturePrivate *createBackendTexture(SceneOpenGL::Texture *texture);
virtual QRegion prepareRenderingFrame();
virtual void endRenderingFrame(const QRegion &damage, const QRegion &damagedRegion);
virtual bool makeCurrent() override;
virtual void doneCurrent() override;
virtual OverlayWindow* overlayWindow() override;
virtual bool usesOverlayWindow() const override;
@ -57,10 +56,6 @@ private:
* @brief The OverlayWindow used by this Backend.
**/
OverlayWindow *m_overlayWindow;
EGLDisplay dpy;
EGLConfig config;
EGLSurface surface;
EGLContext ctx;
int surfaceHasSubPost;
int m_bufferAge;
bool m_usesOverlayWindow;
@ -77,21 +72,15 @@ private:
/**
* @brief Texture using an EGLImageKHR.
**/
class EglTexture : public SceneOpenGL::TexturePrivate
class EglTexture : public AbstractEglTexture
{
public:
virtual ~EglTexture();
virtual void onDamage();
virtual bool loadTexture(WindowPixmap *pixmap) override;
virtual OpenGLBackend *backend();
private:
friend class EglOnXBackend;
EglTexture(SceneOpenGL::Texture *texture, EglOnXBackend *backend);
bool loadTexture(xcb_pixmap_t pix, const QSize &size);
SceneOpenGL::Texture *q;
EglOnXBackend *m_backend;
EGLImageKHR m_image;
};
} // namespace