diff --git a/egl_wayland_backend.cpp b/egl_wayland_backend.cpp
index a58e4a8c4e..12108ab74f 100644
--- a/egl_wayland_backend.cpp
+++ b/egl_wayland_backend.cpp
@@ -387,15 +387,15 @@ void EglWaylandTexture::findTarget()
}
}
-bool EglWaylandTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, int depth)
+bool EglWaylandTexture::loadTexture(xcb_pixmap_t pix, const QSize &size)
{
// HACK: egl wayland platform doesn't support texture from X11 pixmap through the KHR_image_pixmap
// extension. To circumvent this problem we copy the pixmap content into a SHM image and from there
// to the OpenGL texture. This is a temporary solution. In future we won't need to get the content
// from X11 pixmaps. That's what we have XWayland for to get the content into a nice Wayland buffer.
- Q_UNUSED(depth)
if (pix == XCB_PIXMAP_NONE)
return false;
+
m_referencedPixmap = pix;
Xcb::Shm *shm = m_backend->shm();
@@ -430,6 +430,20 @@ bool EglWaylandTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, int dep
return true;
}
+bool EglWaylandTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, int depth)
+{
+ Q_UNUSED(depth)
+
+ return loadTexture(pix, size);
+}
+
+bool EglWaylandTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual)
+{
+ Q_UNUSED(visual)
+
+ return loadTexture(pix, size);
+}
+
bool EglWaylandTexture::update(const QRegion &damage)
{
if (m_referencedPixmap == XCB_PIXMAP_NONE) {
diff --git a/egl_wayland_backend.h b/egl_wayland_backend.h
index fded887e88..4541e7f328 100644
--- a/egl_wayland_backend.h
+++ b/egl_wayland_backend.h
@@ -104,12 +104,14 @@ public:
virtual ~EglWaylandTexture();
virtual void findTarget();
virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, int depth);
+ virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual) override;
virtual OpenGLBackend *backend();
virtual bool update(const QRegion &damage);
private:
friend class EglWaylandBackend;
EglWaylandTexture(SceneOpenGL::Texture *texture, EglWaylandBackend *backend);
+ bool loadTexture(xcb_pixmap_t pix, const QSize &size);
SceneOpenGL::Texture *q;
EglWaylandBackend *m_backend;
/**
diff --git a/eglonxbackend.cpp b/eglonxbackend.cpp
index 06d40ddd51..463260d0b4 100644
--- a/eglonxbackend.cpp
+++ b/eglonxbackend.cpp
@@ -466,10 +466,9 @@ void EglTexture::findTarget()
}
}
-bool EglTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, int depth)
+bool EglTexture::loadTexture(xcb_pixmap_t pix, const QSize &size)
{
- Q_UNUSED(depth)
- if (pix == None)
+ if (pix == XCB_NONE)
return false;
glGenTextures(1, &m_texture);
@@ -498,6 +497,20 @@ bool EglTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, int depth)
return true;
}
+bool EglTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, int depth)
+{
+ Q_UNUSED(depth)
+
+ return loadTexture(pix, size);
+}
+
+bool EglTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual)
+{
+ Q_UNUSED(visual)
+
+ return loadTexture(pix, size);
+}
+
void KWin::EglTexture::onDamage()
{
if (options->isGlStrictBinding()) {
diff --git a/eglonxbackend.h b/eglonxbackend.h
index aee2abf82c..f1a7a7d99c 100644
--- a/eglonxbackend.h
+++ b/eglonxbackend.h
@@ -71,9 +71,12 @@ public:
virtual void onDamage();
virtual void findTarget();
virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, int depth);
+ virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual) override;
virtual OpenGLBackend *backend();
private:
+ bool loadTexture(xcb_pixmap_t pix, const QSize &size);
+
friend class EglOnXBackend;
EglTexture(SceneOpenGL::Texture *texture, EglOnXBackend *backend);
SceneOpenGL::Texture *q;
diff --git a/glxbackend.cpp b/glxbackend.cpp
index 9fde3e8a75..59f7408403 100644
--- a/glxbackend.cpp
+++ b/glxbackend.cpp
@@ -32,12 +32,15 @@ along with this program. If not, see .
#include "overlaywindow.h"
// kwin libs
#include
+#include
// Qt
#include
#include
// system
#include
+#include
+
namespace KWin
{
GlxBackend::GlxBackend()
@@ -100,6 +103,7 @@ void GlxBackend::init()
setFailed(QStringLiteral("Could not initialize rendering context"));
return;
}
+
// Initialize OpenGL
GLPlatform *glPlatform = GLPlatform::instance();
glPlatform->detect(GlxPlatformInterface);
@@ -417,6 +421,109 @@ bool GlxBackend::initDrawableConfigs()
return true;
}
+FBConfigInfo *GlxBackend::infoForVisual(xcb_visualid_t visual)
+{
+ FBConfigInfo *&info = m_fbconfigHash[visual];
+
+ if (info)
+ return info;
+
+ info = new FBConfigInfo;
+ info->fbconfig = nullptr;
+ info->bind_texture_format = 0;
+ info->texture_targets = 0;
+ info->y_inverted = 0;
+ info->mipmap = 0;
+
+ const xcb_render_pictformat_t format = XRenderUtils::findPictFormat(visual);
+ const xcb_render_directformat_t *direct = XRenderUtils::findPictFormatInfo(format);
+
+ if (!direct) {
+ qCritical().nospace() << "Could not find a picture format for visual 0x" << hex << visual;
+ return info;
+ }
+
+ const int red_bits = bitCount(direct->red_mask);
+ const int green_bits = bitCount(direct->green_mask);
+ const int blue_bits = bitCount(direct->blue_mask);
+ const int alpha_bits = bitCount(direct->alpha_mask);
+
+ const auto rgb_sizes = std::tie(red_bits, green_bits, blue_bits);
+
+ const int attribs[] = {
+ GLX_RENDER_TYPE, GLX_RGBA_BIT,
+ GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT | GLX_PIXMAP_BIT,
+ GLX_X_VISUAL_TYPE, GLX_TRUE_COLOR,
+ GLX_X_RENDERABLE, True,
+ GLX_CONFIG_CAVEAT, int(GLX_DONT_CARE), // The ARGB32 visual is marked non-conformant in Catalyst
+ GLX_BUFFER_SIZE, red_bits + green_bits + blue_bits + alpha_bits,
+ GLX_RED_SIZE, red_bits,
+ GLX_GREEN_SIZE, green_bits,
+ GLX_BLUE_SIZE, blue_bits,
+ GLX_ALPHA_SIZE, alpha_bits,
+ GLX_STENCIL_SIZE, 0,
+ GLX_DEPTH_SIZE, 0,
+ 0
+ };
+
+ int count = 0;
+ GLXFBConfig *configs = glXChooseFBConfig(display(), DefaultScreen(display()), attribs, &count);
+
+ if (count < 1) {
+ qCritical().nospace() << "Could not find a framebuffer configuration for visual 0x" << hex << visual;
+ return info;
+ }
+
+ for (int i = 0; i < count; i++) {
+ int red, green, blue;
+ glXGetFBConfigAttrib(display(), configs[i], GLX_RED_SIZE, &red);
+ glXGetFBConfigAttrib(display(), configs[i], GLX_GREEN_SIZE, &green);
+ glXGetFBConfigAttrib(display(), configs[i], GLX_BLUE_SIZE, &blue);
+
+ if (std::tie(red, green, blue) != rgb_sizes)
+ continue;
+
+ int bind_rgb, bind_rgba;
+ glXGetFBConfigAttrib(display(), configs[i], GLX_BIND_TO_TEXTURE_RGBA_EXT, &bind_rgba);
+ glXGetFBConfigAttrib(display(), configs[i], GLX_BIND_TO_TEXTURE_RGB_EXT, &bind_rgb);
+
+ if (!bind_rgb && !bind_rgba)
+ continue;
+
+ int texture_format;
+ if (alpha_bits)
+ texture_format = bind_rgba ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT;
+ else
+ texture_format = bind_rgb ? GLX_TEXTURE_FORMAT_RGB_EXT : GLX_TEXTURE_FORMAT_RGBA_EXT;
+
+ int y_inverted, texture_targets;
+ glXGetFBConfigAttrib(display(), configs[i], GLX_BIND_TO_TEXTURE_TARGETS_EXT, &texture_targets);
+ glXGetFBConfigAttrib(display(), configs[i], GLX_Y_INVERTED_EXT, &y_inverted);
+
+ info->fbconfig = configs[i];
+ info->bind_texture_format = texture_format;
+ info->texture_targets = texture_targets;
+ info->y_inverted = y_inverted;
+ info->mipmap = 0;
+ break;
+ }
+
+ if (count > 0)
+ XFree(configs);
+
+ if (info->fbconfig) {
+ int fbc_id = 0;
+ int visual_id = 0;
+
+ glXGetFBConfigAttrib(display(), info->fbconfig, GLX_FBCONFIG_ID, &fbc_id);
+ glXGetFBConfigAttrib(display(), info->fbconfig, GLX_VISUAL_ID, &visual_id);
+
+ qDebug().nospace() << "Using FBConfig 0x" << hex << fbc_id << " for visual 0x" << hex << visual_id;
+ }
+
+ return info;
+}
+
void GlxBackend::setSwapInterval(int interval)
{
if (m_haveEXTSwapControl)
@@ -675,6 +782,53 @@ void GlxTexture::findTarget()
}
}
+bool GlxTexture::loadTexture(xcb_pixmap_t pixmap, const QSize &size, xcb_visualid_t visual)
+{
+ if (pixmap == XCB_NONE || size.isEmpty() || visual == XCB_NONE)
+ return false;
+
+ const FBConfigInfo *info = m_backend->infoForVisual(visual);
+ if (!info || info->fbconfig == nullptr)
+ return false;
+
+ if ((info->texture_targets & GLX_TEXTURE_2D_BIT_EXT) &&
+ (GLTexture::NPOTTextureSupported() ||
+ (isPowerOfTwo(size.width()) && isPowerOfTwo(size.height())))) {
+ m_target = GL_TEXTURE_2D;
+ m_scale.setWidth(1.0f / m_size.width());
+ m_scale.setHeight(1.0f / m_size.height());
+ } else {
+ assert(info->texture_targets & GLX_TEXTURE_RECTANGLE_BIT_EXT);
+
+ m_target = GL_TEXTURE_RECTANGLE;
+ m_scale.setWidth(1.0f);
+ m_scale.setHeight(1.0f);
+ }
+
+ const int attrs[] = {
+ GLX_TEXTURE_FORMAT_EXT, info->bind_texture_format,
+ GLX_MIPMAP_TEXTURE_EXT, info->mipmap,
+ GLX_TEXTURE_TARGET_EXT, m_target == GL_TEXTURE_2D ? GLX_TEXTURE_2D_EXT : GLX_TEXTURE_RECTANGLE_EXT,
+ 0
+ };
+
+ m_glxpixmap = glXCreatePixmap(display(), info->fbconfig, pixmap, attrs);
+ m_size = size;
+ m_yInverted = info->y_inverted ? true : false;
+ m_canUseMipmaps = info->mipmap;
+
+ glGenTextures(1, &m_texture);
+
+ q->setDirty();
+ q->setFilter(info->mipmap > 0 ? GL_NEAREST_MIPMAP_LINEAR : GL_NEAREST);
+
+ glBindTexture(m_target, m_texture);
+ glXBindTexImageEXT(display(), m_glxpixmap, GLX_FRONT_LEFT_EXT, nullptr);
+
+ updateMatrix();
+ return true;
+}
+
bool GlxTexture::loadTexture(xcb_pixmap_t pix, const QSize &size, int depth)
{
#ifdef CHECK_GL_ERROR
diff --git a/glxbackend.h b/glxbackend.h
index 0e8c8096d9..98b50fc851 100644
--- a/glxbackend.h
+++ b/glxbackend.h
@@ -63,6 +63,8 @@ private:
bool initFbConfig();
void setSwapInterval(int interval);
+ FBConfigInfo *infoForVisual(xcb_visualid_t visual);
+
/**
* @brief The OverlayWindow used by this Backend.
**/
@@ -72,6 +74,7 @@ private:
GLXFBConfig fbconfig;
GLXWindow glxWindow;
GLXContext ctx;
+ QHash m_fbconfigHash;
int m_bufferAge;
bool m_haveMESACopySubBuffer;
bool m_haveMESASwapControl;
@@ -91,6 +94,7 @@ public:
virtual void onDamage();
virtual void findTarget();
virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, int depth);
+ virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual) override;
virtual OpenGLBackend *backend();
private:
diff --git a/scene_opengl.cpp b/scene_opengl.cpp
index 7be14e284b..7a31bc56ef 100644
--- a/scene_opengl.cpp
+++ b/scene_opengl.cpp
@@ -787,6 +787,19 @@ bool SceneOpenGL::Texture::load(xcb_pixmap_t pix, const QSize &size, int depth)
return d->loadTexture(pix, size, depth);
}
+bool SceneOpenGL::Texture::load(xcb_pixmap_t pix, const QSize &size,
+ xcb_visualid_t visual)
+{
+ if (pix == XCB_NONE)
+ return false;
+
+ // decrease the reference counter for the old texture
+ d_ptr = d_func()->backend()->createBackendTexture(this); //new TexturePrivate();
+
+ Q_D(Texture);
+ return d->loadTexture(pix, size, visual);
+}
+
void SceneOpenGL::Texture::findTarget()
{
Q_D(Texture);
@@ -1199,7 +1212,7 @@ bool OpenGLWindowPixmap::bind()
return false;
}
- bool success = m_texture->load(pixmap(), toplevel()->size(), toplevel()->depth());
+ bool success = m_texture->load(pixmap(), toplevel()->size(), toplevel()->visual());
if (success)
toplevel()->resetDamage();
diff --git a/scene_opengl.h b/scene_opengl.h
index 04c91df4ea..b702361f02 100644
--- a/scene_opengl.h
+++ b/scene_opengl.h
@@ -145,6 +145,7 @@ public:
virtual void findTarget() = 0;
virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, int depth) = 0;
+ virtual bool loadTexture(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t visual) = 0;
virtual OpenGLBackend *backend() = 0;
protected:
@@ -170,6 +171,7 @@ public:
protected:
void findTarget();
virtual bool load(xcb_pixmap_t pix, const QSize &size, int depth);
+ virtual bool load(xcb_pixmap_t pix, const QSize &size, xcb_visualid_t);
Texture(TexturePrivate& dd);