From c07182490d77a7ea66970b2c3e345d21b1887ba1 Mon Sep 17 00:00:00 2001 From: Aleix Pol Date: Mon, 11 Oct 2021 15:56:53 +0200 Subject: [PATCH] pipewire: Fix downloading software-rotated textures At the moment we'll be setting the YInverted setting, but in practice that won't have any effect as it only changes the render matrix and we'll end up streaming inverted textures. This change addresses it by rendering it into another texture first to resolve this situation and then download that new texture instead. --- src/libkwineffects/kwinglplatform.cpp | 5 +++++ src/libkwineffects/kwinglplatform.h | 6 +++++ src/plugins/screencast/pipewirestream.cpp | 27 +++++++++++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/src/libkwineffects/kwinglplatform.cpp b/src/libkwineffects/kwinglplatform.cpp index 617fba59d8..01a4c962c4 100644 --- a/src/libkwineffects/kwinglplatform.cpp +++ b/src/libkwineffects/kwinglplatform.cpp @@ -721,6 +721,7 @@ GLPlatform::GLPlatform() m_limitedGLSL(false), m_textureNPOT(false), m_limitedNPOT(false), + m_packInvert(false), m_virtualMachine(false), m_preferBufferSubData(false), m_platformInterface(NoOpenGLPlatformInterface), @@ -801,6 +802,7 @@ void GLPlatform::detect(OpenGLPlatformInterface platformInterface) m_chipset = QByteArrayLiteral("Unknown"); m_preferBufferSubData = false; + m_packInvert = m_extensions.contains("GL_MESA_pack_invert"); // Mesa classic drivers @@ -1200,6 +1202,9 @@ bool GLPlatform::supports(GLFeature feature) const case LimitedNPOT: return m_limitedNPOT; + case PackInvert: + return m_packInvert; + default: return false; } diff --git a/src/libkwineffects/kwinglplatform.h b/src/libkwineffects/kwinglplatform.h index 94129ad42c..f799eea83f 100644 --- a/src/libkwineffects/kwinglplatform.h +++ b/src/libkwineffects/kwinglplatform.h @@ -72,6 +72,11 @@ enum GLFeature { * - GL_CLAMP_TO_BORDER */ LimitedNPOT, + + /** + * Set if the extension GL_MESA_pack_invert is present + */ + PackInvert, }; enum Driver { @@ -444,6 +449,7 @@ private: bool m_limitedGLSL: 1; bool m_textureNPOT: 1; bool m_limitedNPOT: 1; + bool m_packInvert: 1; bool m_virtualMachine: 1; bool m_preferBufferSubData: 1; OpenGLPlatformInterface m_platformInterface; diff --git a/src/plugins/screencast/pipewirestream.cpp b/src/plugins/screencast/pipewirestream.cpp index f014644c20..dc73befd1a 100644 --- a/src/plugins/screencast/pipewirestream.cpp +++ b/src/plugins/screencast/pipewirestream.cpp @@ -327,6 +327,19 @@ static GLTexture *copyTexture(GLTexture *texture) return copy; } +// in-place vertical mirroring +static void mirrorVertically(uchar *data, int height, int stride) +{ + const int halfHeight = height / 2; + std::vector temp(stride); + for (int y = 0; y < halfHeight; ++y) { + auto cur = &data[y * stride], dest = &data[(height - y - 1) * stride]; + memcpy(temp.data(), cur, stride); + memcpy(cur, dest, stride); + memcpy(dest, temp.data(), stride); + } +} + void PipeWireStream::recordFrame(GLTexture *frameTexture, const QRegion &damagedRegion) { Q_ASSERT(!m_stopped); @@ -383,6 +396,12 @@ void PipeWireStream::recordFrame(GLTexture *frameTexture, const QRegion &damaged spa_data->chunk->size = bufferSize; spa_data->chunk->stride = stride; + const bool invertNeededAndSupported = frameTexture->isYInverted() && GLPlatform::instance()->supports(PackInvert); + GLboolean prev; + if (invertNeededAndSupported) { + glGetBooleanv(GL_PACK_INVERT_MESA, &prev); + glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE); + } frameTexture->bind(); if (GLPlatform::instance()->isGLES()) { @@ -392,6 +411,14 @@ void PipeWireStream::recordFrame(GLTexture *frameTexture, const QRegion &damaged } else { glGetTexImage(frameTexture->target(), 0, m_hasAlpha ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, data); } + + if (invertNeededAndSupported) { + if (!prev) { + glPixelStorei(GL_PACK_INVERT_MESA, prev); + } + } else if (frameTexture->isYInverted()) { + mirrorVertically(data, size.height(), stride); + } auto cursor = Cursors::self()->currentCursor(); if (m_cursor.mode == KWaylandServer::ScreencastV1Interface::Embedded && m_cursor.viewport.contains(cursor->pos())) { QImage dest(data, size.width(), size.height(), QImage::Format_RGBA8888_Premultiplied);