core: Port RenderTarget to OutputTransform

This commit is contained in:
Vlad Zahorodnii 2023-12-20 12:12:16 +02:00
parent c970d3261b
commit 16809e6b15
12 changed files with 69 additions and 120 deletions

View file

@ -291,18 +291,17 @@ void WaylandCompositor::addOutput(Output *output)
if (!outputLayer || forceSoftwareCursor) {
return false;
}
const QMatrix4x4 monitorMatrix = Output::logicalToNativeMatrix(output->rect(), output->scale(), output->transform());
QRectF nativeCursorRect = monitorMatrix.mapRect(outputLocalRect);
QRectF nativeCursorRect = output->transform().map(scaledRect(outputLocalRect, output->scale()), output->pixelSize());
QSize bufferSize(std::ceil(nativeCursorRect.width()), std::ceil(nativeCursorRect.height()));
if (const auto fixedSize = outputLayer->fixedSize()) {
if (fixedSize->width() < bufferSize.width() || fixedSize->height() < bufferSize.height()) {
return false;
}
bufferSize = *fixedSize;
nativeCursorRect = monitorMatrix.mapRect(QRectF(outputLocalRect.topLeft(), QSizeF(bufferSize) / output->scale()));
nativeCursorRect = output->transform().map(QRectF(outputLocalRect.topLeft() * output->scale(), bufferSize), output->pixelSize());
}
outputLayer->setPosition(nativeCursorRect.topLeft());
outputLayer->setHotspot(Output::logicalToNativeMatrix(QRectF(QPointF(), QSizeF(bufferSize) / output->scale()), output->scale(), output->transform()).map(cursor->hotspot()));
outputLayer->setHotspot(output->transform().map(cursor->hotspot() * output->scale(), bufferSize));
outputLayer->setSize(bufferSize);
if (auto beginInfo = outputLayer->beginFrame()) {
const RenderTarget &renderTarget = beginInfo->renderTarget;
@ -345,8 +344,8 @@ void WaylandCompositor::addOutput(Output *output)
bool hardwareCursor = false;
if (outputLayer) {
if (outputLayer->isEnabled()) {
const QMatrix4x4 monitorMatrix = Output::logicalToNativeMatrix(output->rect(), output->scale(), output->transform());
const QRectF nativeCursorRect = monitorMatrix.mapRect(QRectF(outputLocalRect.topLeft(), outputLayer->size() / output->scale()));
const QRectF nativeCursorRect = output->transform()
.map(QRectF(outputLocalRect.topLeft() * output->scale(), outputLayer->size()), output->pixelSize());
outputLayer->setPosition(nativeCursorRect.topLeft());
hardwareCursor = output->updateCursorLayer();
} else if (!cursorLayer->isVisible() && !forceSoftwareCursor) {

View file

@ -646,49 +646,6 @@ Output::DpmsMode Output::dpmsMode() const
return m_state.dpmsMode;
}
QMatrix4x4 Output::logicalToNativeMatrix(const QRectF &rect, qreal scale, OutputTransform transform)
{
QMatrix4x4 matrix;
matrix.scale(scale);
switch (transform.kind()) {
case OutputTransform::Normal:
case OutputTransform::FlipX:
break;
case OutputTransform::Rotate90:
case OutputTransform::FlipX90:
matrix.translate(0, rect.width());
matrix.rotate(-90, 0, 0, 1);
break;
case OutputTransform::Rotate180:
case OutputTransform::FlipX180:
matrix.translate(rect.width(), rect.height());
matrix.rotate(-180, 0, 0, 1);
break;
case OutputTransform::Rotate270:
case OutputTransform::FlipX270:
matrix.translate(rect.height(), 0);
matrix.rotate(-270, 0, 0, 1);
break;
}
switch (transform.kind()) {
case OutputTransform::FlipX:
case OutputTransform::FlipX90:
case OutputTransform::FlipX180:
case OutputTransform::FlipX270:
matrix.translate(rect.width(), 0);
matrix.scale(-1, 1);
break;
default:
break;
}
matrix.translate(-rect.x(), -rect.y());
return matrix;
}
uint32_t Output::overscan() const
{
return m_state.overscan;

View file

@ -15,7 +15,6 @@
#include <QDebug>
#include <QList>
#include <QMatrix3x3>
#include <QMatrix4x4>
#include <QObject>
#include <QRect>
@ -322,11 +321,6 @@ public:
uint32_t overscan() const;
/**
* Returns a matrix that can translate into the display's coordinates system
*/
static QMatrix4x4 logicalToNativeMatrix(const QRectF &rect, qreal scale, OutputTransform transform);
VrrPolicy vrrPolicy() const;
RgbRange rgbRange() const;

View file

@ -10,9 +10,39 @@
namespace KWin
{
static OutputTransform textureTransformToOutputTransform(TextureTransforms transforms) // TODO: Kill TextureTransform?
{
if (transforms == TextureTransforms()) {
return OutputTransform::Normal;
} else if (transforms == TextureTransform::Rotate90) {
return OutputTransform::Rotate90;
} else if (transforms == TextureTransform::Rotate180) {
return OutputTransform::Rotate180;
} else if (transforms == TextureTransform::Rotate270) {
return OutputTransform::Rotate270;
} else if (transforms == TextureTransform::MirrorX) {
return OutputTransform::FlipX;
} else if (transforms == TextureTransforms(TextureTransform::MirrorX | TextureTransform::Rotate90)) {
return OutputTransform::FlipX90;
} else if (transforms == TextureTransforms(TextureTransform::MirrorX | TextureTransform::Rotate180)) {
return OutputTransform::FlipX180;
} else if (transforms == TextureTransforms(TextureTransform::MirrorX | TextureTransform::Rotate270)) {
return OutputTransform::FlipX270;
} else if (transforms == TextureTransform::MirrorY) {
return OutputTransform::FlipY;
} else if (transforms == TextureTransforms(TextureTransform::MirrorY | TextureTransform::Rotate90)) {
return OutputTransform::FlipY90;
} else if (transforms == TextureTransforms(TextureTransform::MirrorY | TextureTransform::Rotate180)) {
return OutputTransform::FlipY180;
} else if (transforms == TextureTransforms(TextureTransform::MirrorY | TextureTransform::Rotate270)) {
return OutputTransform::FlipY270;
}
Q_UNREACHABLE();
}
RenderTarget::RenderTarget(GLFramebuffer *fbo, const ColorDescription &colorDescription)
: m_framebuffer(fbo)
, m_transformation(fbo->colorAttachment() ? fbo->colorAttachment()->contentTransformMatrix() : QMatrix4x4())
, m_transform(fbo->colorAttachment() ? textureTransformToOutputTransform(fbo->colorAttachment()->contentTransforms()) : OutputTransform())
, m_colorDescription(colorDescription)
{
}
@ -34,44 +64,9 @@ QSize RenderTarget::size() const
}
}
QRectF RenderTarget::applyTransformation(const QRectF &rect) const
OutputTransform RenderTarget::transform() const
{
const auto bounds = size();
QMatrix4x4 relativeTransformation;
relativeTransformation.translate(bounds.width() / 2.0, bounds.height() / 2.0);
relativeTransformation *= m_transformation;
relativeTransformation.translate(-bounds.width() / 2.0, -bounds.height() / 2.0);
return relativeTransformation.mapRect(rect);
}
QRect RenderTarget::applyTransformation(const QRect &rect) const
{
return applyTransformation(QRectF(rect)).toRect();
}
QPointF RenderTarget::applyTransformation(const QPointF &point) const
{
const auto bounds = size();
QMatrix4x4 relativeTransformation;
relativeTransformation.translate(bounds.width() / 2.0, bounds.height() / 2.0);
relativeTransformation *= m_transformation;
relativeTransformation.translate(-bounds.width() / 2.0, -bounds.height() / 2.0);
return relativeTransformation.map(point);
}
QPoint RenderTarget::applyTransformation(const QPoint &point) const
{
const auto bounds = size();
QMatrix4x4 relativeTransformation;
relativeTransformation.translate(bounds.width() / 2.0, bounds.height() / 2.0);
relativeTransformation *= m_transformation;
relativeTransformation.translate(-bounds.width() / 2.0, -bounds.height() / 2.0);
return relativeTransformation.map(point);
}
QMatrix4x4 RenderTarget::transformation() const
{
return m_transformation;
return m_transform;
}
GLFramebuffer *RenderTarget::framebuffer() const

View file

@ -7,10 +7,9 @@
#pragma once
#include "core/colorspace.h"
#include "core/output.h"
#include <QImage>
#include <QMatrix4x4>
#include <variant>
namespace KWin
{
@ -25,12 +24,8 @@ public:
explicit RenderTarget(QImage *image, const ColorDescription &colorDescription = ColorDescription::sRGB);
QSize size() const;
QMatrix4x4 transformation() const;
OutputTransform transform() const;
const ColorDescription &colorDescription() const;
QRectF applyTransformation(const QRectF &rect) const;
QRect applyTransformation(const QRect &rect) const;
QPointF applyTransformation(const QPointF &point) const;
QPoint applyTransformation(const QPoint &point) const;
QImage *image() const;
GLFramebuffer *framebuffer() const;
@ -39,7 +34,7 @@ public:
private:
QImage *m_image = nullptr;
GLFramebuffer *m_framebuffer = nullptr;
QMatrix4x4 m_transformation;
const OutputTransform m_transform;
const ColorDescription m_colorDescription;
};

View file

@ -13,13 +13,19 @@ namespace KWin
static QMatrix4x4 createProjectionMatrix(const RenderTarget &renderTarget, const QRect &rect)
{
QMatrix4x4 ret = renderTarget.transformation();
QMatrix4x4 ret;
ret.scale(1, -1); // flip the y axis back
ret *= renderTarget.transform().toMatrix();
ret.scale(1, -1); // undo ortho() flipping the y axis
ret.ortho(rect);
return ret;
}
RenderViewport::RenderViewport(const QRectF &renderRect, double scale, const RenderTarget &renderTarget)
: m_renderTarget(&renderTarget)
: m_transform(renderTarget.transform())
, m_transformBounds(m_transform.map(renderTarget.size()))
, m_renderRect(renderRect)
, m_deviceRenderRect(snapToPixelGrid(scaledRect(renderRect, scale)))
, m_projectionMatrix(createProjectionMatrix(renderTarget, m_deviceRenderRect))
@ -46,26 +52,26 @@ QRectF RenderViewport::mapToRenderTarget(const QRectF &logicalGeometry) const
{
const QRectF deviceGeometry = scaledRect(logicalGeometry, m_scale)
.translated(-m_deviceRenderRect.topLeft());
return m_renderTarget->applyTransformation(deviceGeometry);
return m_transform.map(deviceGeometry, m_transformBounds);
}
QRect RenderViewport::mapToRenderTarget(const QRect &logicalGeometry) const
{
const QRect deviceGeometry = snapToPixelGrid(scaledRect(logicalGeometry, m_scale))
.translated(-m_deviceRenderRect.topLeft());
return m_renderTarget->applyTransformation(deviceGeometry);
return m_transform.map(deviceGeometry, m_transformBounds);
}
QPoint RenderViewport::mapToRenderTarget(const QPoint &logicalGeometry) const
{
const QPoint devicePoint = snapToPixelGrid(QPointF(logicalGeometry) * m_scale) - m_deviceRenderRect.topLeft();
return m_renderTarget->applyTransformation(devicePoint);
return m_transform.map(devicePoint, m_transformBounds);
}
QPointF RenderViewport::mapToRenderTarget(const QPointF &logicalGeometry) const
{
const QPointF devicePoint = logicalGeometry * m_scale - m_deviceRenderRect.topLeft();
return m_renderTarget->applyTransformation(devicePoint);
return m_transform.map(devicePoint, m_transformBounds);
}
QRegion RenderViewport::mapToRenderTarget(const QRegion &logicalGeometry) const

View file

@ -6,7 +6,7 @@
#pragma once
#include "kwin_export.h"
#include "core/output.h"
#include <QMatrix4x4>
#include <QRectF>
@ -39,7 +39,8 @@ public:
QRegion mapToRenderTargetTexture(const QRegion &logicalGeometry) const;
private:
const RenderTarget *m_renderTarget;
const OutputTransform m_transform;
const QSize m_transformBounds;
const QRectF m_renderRect;
const QRect m_deviceRenderRect;
const QMatrix4x4 m_projectionMatrix;

View file

@ -161,4 +161,6 @@ protected:
} // namespace
Q_DECLARE_OPERATORS_FOR_FLAGS(KWin::TextureTransforms)
/** @} */

View file

@ -476,7 +476,7 @@ void ContrastEffect::doContrast(const RenderTarget &renderTarget, const RenderVi
QMatrix4x4 textureMatrix;
// apply texture->buffer transformation
textureMatrix.translate(0.5, 0.5);
textureMatrix *= renderTarget.transformation();
textureMatrix *= renderTarget.transform().toMatrix();
textureMatrix.translate(-0.5, -0.5);
// scaled logical to texture coordinates
textureMatrix.scale(1, -1);

View file

@ -137,7 +137,7 @@ void GlideEffect::paintWindow(const RenderTarget &renderTarget, const RenderView
// [move to the origin] -> [rotate] -> [translate] ->
// -> [perspective projection] -> [reverse "move to the origin"]
const QMatrix4x4 oldProjMatrix = createPerspectiveMatrix(viewport.renderRect(), viewport.scale(), renderTarget.transformation());
const QMatrix4x4 oldProjMatrix = createPerspectiveMatrix(viewport.renderRect(), viewport.scale(), renderTarget.transform().toMatrix());
const auto frame = w->frameGeometry();
const QRectF windowGeo = scaledRect(frame, viewport.scale());
const QVector3D invOffset = oldProjMatrix.map(QVector3D(windowGeo.center()));

View file

@ -47,7 +47,7 @@ struct ScreenShotScreenData
Output *screen = nullptr;
};
static void convertFromGLImage(QImage &img, int w, int h, const QMatrix4x4 &renderTargetTransformation)
static void convertFromGLImage(QImage &img, int w, int h, const OutputTransform &renderTargetTransformation)
{
// from QtOpenGL/qgl.cpp
// SPDX-FileCopyrightText: 2010 Nokia Corporation and /or its subsidiary(-ies)
@ -79,7 +79,7 @@ static void convertFromGLImage(QImage &img, int w, int h, const QMatrix4x4 &rend
// OpenGL textures are flipped vs QImage
matrix.scale(1, -1);
// apply render target transformation
matrix *= renderTargetTransformation.inverted();
matrix *= renderTargetTransformation.inverted().toMatrix();
img = img.transformed(matrix.toTransform());
}
@ -284,7 +284,7 @@ void ScreenShotEffect::takeScreenShot(ScreenShotWindowData *screenshot)
glReadnPixels(0, 0, img.width(), img.height(), GL_RGBA, GL_UNSIGNED_BYTE, img.sizeInBytes(),
static_cast<GLvoid *>(img.bits()));
GLFramebuffer::popFramebuffer();
convertFromGLImage(img, img.width(), img.height(), renderTarget.transformation());
convertFromGLImage(img, img.width(), img.height(), renderTarget.transform());
}
if (screenshot->flags & ScreenShotIncludeCursor) {
@ -371,10 +371,10 @@ QImage ScreenShotEffect::blitScreenshot(const RenderTarget &renderTarget, const
if (effects->isOpenGLCompositing()) {
const auto screenGeometry = m_paintedScreen ? m_paintedScreen->geometry() : effects->virtualScreenGeometry();
const QSize nativeSize = renderTarget.applyTransformation(
snapToPixelGrid(scaledRect(geometry, devicePixelRatio))
.translated(-snapToPixelGrid(scaledRect(screenGeometry, devicePixelRatio)).topLeft()))
.size();
const QSize nativeSize = renderTarget.transform().map(
snapToPixelGrid(scaledRect(geometry, devicePixelRatio))
.translated(-snapToPixelGrid(scaledRect(screenGeometry, devicePixelRatio)).topLeft())
.size());
image = QImage(nativeSize, QImage::Format_ARGB32);
const auto texture = GLTexture::allocate(GL_RGBA8, nativeSize);
@ -397,7 +397,7 @@ QImage ScreenShotEffect::blitScreenshot(const RenderTarget &renderTarget, const
glReadPixels(0, 0, nativeSize.width(), nativeSize.height(), GL_RGBA,
GL_UNSIGNED_BYTE, static_cast<GLvoid *>(image.bits()));
GLFramebuffer::popFramebuffer();
convertFromGLImage(image, nativeSize.width(), nativeSize.height(), renderTarget.transformation());
convertFromGLImage(image, nativeSize.width(), nativeSize.height(), renderTarget.transform());
}
image.setDevicePixelRatio(devicePixelRatio);

View file

@ -58,7 +58,7 @@ void CursorDelegateOpenGL::paint(const RenderTarget &renderTarget, const QRegion
renderLayer.delegate()->paint(offscreenRenderTarget, infiniteRegion());
renderLayer.delegate()->postPaint();
QMatrix4x4 mvp = renderTarget.transformation();
QMatrix4x4 mvp = renderTarget.transform().toMatrix();
mvp.ortho(QRectF(QPointF(0, 0), m_output->transform().map(renderTarget.size())));
mvp.translate(cursorRect.x(), cursorRect.y());