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.
This commit is contained in:
Aleix Pol 2021-10-11 15:56:53 +02:00
parent 67ec16c335
commit c07182490d
3 changed files with 38 additions and 0 deletions

View file

@ -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;
}

View file

@ -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;

View file

@ -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<uchar> 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);