From 7301564e4ff884f5a83ccb20bdbcbd9d81ecc96c Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 20 Oct 2020 11:16:31 +0300 Subject: [PATCH] Use bilinear interpolation to compute texture coords of subquads On Wayland, a surface must be displayed the same way no matter how the attached buffer is transformed. In order to guarantee that, we build the surface-to-buffer matrix, which is used to compute the texture coords. The surface-to-buffer matrix represents an affine transformation. Thus, performing linear interpolation between texture coordinates won't end up in corrupted rendered results. This is the main assumption that we make during generation of contents window quads. After creating a sub-quad, the new quad's texture coordinates are computed by interpolating between the source quad's texture coords. However, WindowQuad::makeSubQuad() makes a concrete assumption about the order of texture coords, which might be false if the attached wayland buffer is rotated 90 or 270 degrees. This issue went unnoticed after merging the viewporter patches because the developer who was working on it had been using primarily nested kwin_wayland for testing purposes. And it appears like kwin schedules full screen repaints even though it supports buffer age. It still needs some investigation why that happens. BUG: 428003 --- .../libkwineffects/windowquadlisttest.cpp | 16 ++--- libkwineffects/kwineffects.cpp | 60 +++++++++---------- 2 files changed, 35 insertions(+), 41 deletions(-) diff --git a/autotests/libkwineffects/windowquadlisttest.cpp b/autotests/libkwineffects/windowquadlisttest.cpp index 2bcc4acaee..8c60a1b49e 100644 --- a/autotests/libkwineffects/windowquadlisttest.cpp +++ b/autotests/libkwineffects/windowquadlisttest.cpp @@ -98,12 +98,12 @@ void WindowQuadListTest::testMakeGrid() const KWin::WindowVertex &expectedVertex = expectedQuad[index]; if (actualVertex.x() != expectedVertex.x()) return false; if (actualVertex.y() != expectedVertex.y()) return false; - if (actualVertex.u() != expectedVertex.u()) return false; - if (actualVertex.v() != expectedVertex.v()) return false; + if (!qFuzzyIsNull(actualVertex.u() - expectedVertex.u())) return false; + if (!qFuzzyIsNull(actualVertex.v() - expectedVertex.v())) return false; if (actualVertex.originalX() != expectedVertex.originalX()) return false; if (actualVertex.originalY() != expectedVertex.originalY()) return false; - if (actualVertex.textureX() != expectedVertex.textureX()) return false; - if (actualVertex.textureY() != expectedVertex.textureY()) return false; + if (!qFuzzyIsNull(actualVertex.textureX() - expectedVertex.textureX())) return false; + if (!qFuzzyIsNull(actualVertex.textureY() - expectedVertex.textureY())) return false; return true; }; found = vertexTest(0) && vertexTest(1) && vertexTest(2) && vertexTest(3); @@ -185,12 +185,12 @@ void WindowQuadListTest::testMakeRegularGrid() const KWin::WindowVertex &expectedVertex = expectedQuad[index]; if (actualVertex.x() != expectedVertex.x()) return false; if (actualVertex.y() != expectedVertex.y()) return false; - if (actualVertex.u() != expectedVertex.u()) return false; - if (actualVertex.v() != expectedVertex.v()) return false; + if (!qFuzzyIsNull(actualVertex.u() - expectedVertex.u())) return false; + if (!qFuzzyIsNull(actualVertex.v() - expectedVertex.v())) return false; if (actualVertex.originalX() != expectedVertex.originalX()) return false; if (actualVertex.originalY() != expectedVertex.originalY()) return false; - if (actualVertex.textureX() != expectedVertex.textureX()) return false; - if (actualVertex.textureY() != expectedVertex.textureY()) return false; + if (!qFuzzyIsNull(actualVertex.textureX() - expectedVertex.textureX())) return false; + if (!qFuzzyIsNull(actualVertex.textureY() - expectedVertex.textureY())) return false; return true; }; found = vertexTest(0) && vertexTest(1) && vertexTest(2) && vertexTest(3); diff --git a/libkwineffects/kwineffects.cpp b/libkwineffects/kwineffects.cpp index d1c3e2d13b..f53086e283 100644 --- a/libkwineffects/kwineffects.cpp +++ b/libkwineffects/kwineffects.cpp @@ -866,45 +866,39 @@ WindowQuad WindowQuad::makeSubQuad(double x1, double y1, double x2, double y2) c ret.verts[ 2 ].oy = y2; ret.verts[ 3 ].oy = y2; - const double my_u0 = verts[0].tx; - const double my_u1 = verts[2].tx; - const double my_v0 = verts[0].ty; - const double my_v1 = verts[2].ty; + const double xOrigin = left(); + const double yOrigin = top(); - const double width = right() - left(); - const double height = bottom() - top(); - - const double texWidth = my_u1 - my_u0; - const double texHeight = my_v1 - my_v0; + const double widthReciprocal = 1 / (right() - xOrigin); + const double heightReciprocal = 1 / (bottom() - yOrigin); if (!uvAxisSwapped()) { - const double u0 = (x1 - left()) / width * texWidth + my_u0; - const double u1 = (x2 - left()) / width * texWidth + my_u0; - const double v0 = (y1 - top()) / height * texHeight + my_v0; - const double v1 = (y2 - top()) / height * texHeight + my_v0; + for (int i = 0; i < 4; ++i) { + const double w1 = (ret.verts[i].px - xOrigin) * widthReciprocal; + const double w2 = (ret.verts[i].py - yOrigin) * heightReciprocal; - ret.verts[0].tx = u0; - ret.verts[3].tx = u0; - ret.verts[1].tx = u1; - ret.verts[2].tx = u1; - ret.verts[0].ty = v0; - ret.verts[1].ty = v0; - ret.verts[2].ty = v1; - ret.verts[3].ty = v1; + // Use bilinear interpolation to compute the texture coords. + ret.verts[i].tx = (1 - w1) * (1 - w2) * verts[0].tx + + w1 * (1 - w2) * verts[1].tx + + w1 * w2 * verts[2].tx + (1 - w1) * w2 * verts[3].tx; + ret.verts[i].ty = (1 - w1) * (1 - w2) * verts[0].ty + + w1 * (1 - w2) * verts[1].ty + + w1 * w2 * verts[2].ty + (1 - w1) * w2 * verts[3].ty; + } } else { - const double u0 = (y1 - top()) / height * texWidth + my_u0; - const double u1 = (y2 - top()) / height * texWidth + my_u0; - const double v0 = (x1 - left()) / width * texHeight + my_v0; - const double v1 = (x2 - left()) / width * texHeight + my_v0; + // Same as above, with just verts[1] and verts[3] being swapped. + for (int i = 0; i < 4; ++i) { + const double w1 = (ret.verts[i].py - yOrigin) * heightReciprocal; + const double w2 = (ret.verts[i].px - xOrigin) * widthReciprocal; - ret.verts[0].tx = u0; - ret.verts[1].tx = u0; - ret.verts[2].tx = u1; - ret.verts[3].tx = u1; - ret.verts[0].ty = v0; - ret.verts[3].ty = v0; - ret.verts[1].ty = v1; - ret.verts[2].ty = v1; + // Use bilinear interpolation to compute the texture coords. + ret.verts[i].tx = (1 - w1) * (1 - w2) * verts[0].tx + + w1 * (1 - w2) * verts[3].tx + + w1 * w2 * verts[2].tx + (1 - w1) * w2 * verts[1].tx; + ret.verts[i].ty = (1 - w1) * (1 - w2) * verts[0].ty + + w1 * (1 - w2) * verts[3].ty + + w1 * w2 * verts[2].ty + (1 - w1) * w2 * verts[1].ty; + } } ret.setUVAxisSwapped(uvAxisSwapped());