Wayland: Allow to take single screen screenshots using scale factor without loss
Summary: The screenshot made on screens with scale factor were downscaled by their scale factor making them blurry. It prevents taking screenshots of missing Hidpi related bugs showing the issues under Wayland. This fix the case of a single screenshot, but not the rest: Multiscreen screenshot downscales the screen using scale factor. Spectacle rectangular selection screenshot is broken as soon as some scale factor different than 1 is used on any screen. Test Plan: Under Wayland with a scale factor on a screen, take a screenshot using spectacle. The output image is not downscaled and has the same size as the screen resolution. No other change to any other screenshot mode, or under X. Reviewers: davidedmundson, #kwin Reviewed By: davidedmundson, #kwin Subscribers: kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D29010
This commit is contained in:
parent
e95d1dc950
commit
66898e7f46
7 changed files with 40 additions and 16 deletions
|
@ -159,6 +159,7 @@ static xcb_pixmap_t xpixmapFromImage(const QImage &image)
|
|||
void ScreenShotEffect::paintScreen(int mask, const QRegion ®ion, ScreenPaintData &data)
|
||||
{
|
||||
m_cachedOutputGeometry = data.outputGeometry();
|
||||
m_cachedScale = data.screenScale();
|
||||
effects->paintScreen(mask, region, data);
|
||||
}
|
||||
|
||||
|
@ -287,12 +288,13 @@ void ScreenShotEffect::postPaintScreen()
|
|||
// doesn't intersect, not going onto this screenshot
|
||||
return;
|
||||
}
|
||||
const QImage img = blitScreenshot(intersection);
|
||||
if (img.size() == m_scheduledGeometry.size()) {
|
||||
QImage img = blitScreenshot(intersection, m_cachedScale);
|
||||
if (img.size() == (m_scheduledGeometry.size() * m_cachedScale)) {
|
||||
// we are done
|
||||
sendReplyImage(img);
|
||||
return;
|
||||
}
|
||||
img.setDevicePixelRatio(m_cachedScale);
|
||||
if (m_multipleOutputsImage.isNull()) {
|
||||
m_multipleOutputsImage = QImage(m_scheduledGeometry.size(), QImage::Format_ARGB32);
|
||||
m_multipleOutputsImage.fill(Qt::transparent);
|
||||
|
@ -604,24 +606,31 @@ QString ScreenShotEffect::screenshotArea(int x, int y, int width, int height, bo
|
|||
return QString();
|
||||
}
|
||||
|
||||
QImage ScreenShotEffect::blitScreenshot(const QRect &geometry)
|
||||
QImage ScreenShotEffect::blitScreenshot(const QRect &geometry, const qreal scale)
|
||||
{
|
||||
QImage img;
|
||||
if (effects->isOpenGLCompositing())
|
||||
{
|
||||
img = QImage(geometry.size(), QImage::Format_ARGB32);
|
||||
int width = geometry.width();
|
||||
int height = geometry.height();
|
||||
if (GLRenderTarget::blitSupported() && !GLPlatform::instance()->isGLES()) {
|
||||
GLTexture tex(GL_RGBA8, geometry.width(), geometry.height());
|
||||
|
||||
width = static_cast<int>(width * scale);
|
||||
height = static_cast<int>(height * scale);
|
||||
|
||||
img = QImage(width, height, QImage::Format_ARGB32);
|
||||
GLTexture tex(GL_RGBA8, width, height);
|
||||
GLRenderTarget target(tex);
|
||||
target.blitFromFramebuffer(geometry);
|
||||
// copy content from framebuffer into image
|
||||
tex.bind();
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)img.bits());
|
||||
glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, static_cast<GLvoid*>(img.bits()));
|
||||
tex.unbind();
|
||||
} else {
|
||||
glReadPixels(0, 0, img.width(), img.height(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)img.bits());
|
||||
img = QImage(width, height, QImage::Format_ARGB32);
|
||||
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)img.bits());
|
||||
}
|
||||
ScreenShotEffect::convertFromGLImage(img, geometry.width(), geometry.height());
|
||||
ScreenShotEffect::convertFromGLImage(img, width, height);
|
||||
}
|
||||
|
||||
#ifdef KWIN_HAVE_XRENDER_COMPOSITING
|
||||
|
@ -635,7 +644,7 @@ QImage ScreenShotEffect::blitScreenshot(const QRect &geometry)
|
|||
#endif
|
||||
|
||||
if (m_captureCursor) {
|
||||
grabPointerImage(img, geometry.x(), geometry.y());
|
||||
grabPointerImage(img, geometry.x() * scale, geometry.y() * scale);
|
||||
}
|
||||
|
||||
return img;
|
||||
|
|
|
@ -141,7 +141,7 @@ private Q_SLOTS:
|
|||
|
||||
private:
|
||||
void grabPointerImage(QImage& snapshot, int offsetx, int offsety);
|
||||
QImage blitScreenshot(const QRect &geometry);
|
||||
QImage blitScreenshot(const QRect &geometry, const qreal scale = 1.0);
|
||||
QString saveTempImage(const QImage &img);
|
||||
void sendReplyImage(const QImage &img);
|
||||
enum class InfoMessageMode {
|
||||
|
@ -167,6 +167,7 @@ private:
|
|||
};
|
||||
WindowMode m_windowMode = WindowMode::NoCapture;
|
||||
int m_fd = -1;
|
||||
qreal m_cachedScale;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -423,6 +423,7 @@ class ScreenPaintData::Private
|
|||
public:
|
||||
QMatrix4x4 projectionMatrix;
|
||||
QRect outputGeometry;
|
||||
qreal screenScale;
|
||||
};
|
||||
|
||||
ScreenPaintData::ScreenPaintData()
|
||||
|
@ -431,12 +432,13 @@ ScreenPaintData::ScreenPaintData()
|
|||
{
|
||||
}
|
||||
|
||||
ScreenPaintData::ScreenPaintData(const QMatrix4x4 &projectionMatrix, const QRect &outputGeometry)
|
||||
ScreenPaintData::ScreenPaintData(const QMatrix4x4 &projectionMatrix, const QRect &outputGeometry, const qreal screenScale)
|
||||
: PaintData()
|
||||
, d(new Private())
|
||||
{
|
||||
d->projectionMatrix = projectionMatrix;
|
||||
d->outputGeometry = outputGeometry;
|
||||
d->screenScale = screenScale;
|
||||
}
|
||||
|
||||
ScreenPaintData::~ScreenPaintData() = default;
|
||||
|
@ -526,6 +528,11 @@ QRect ScreenPaintData::outputGeometry() const
|
|||
return d->outputGeometry;
|
||||
}
|
||||
|
||||
qreal ScreenPaintData::screenScale() const
|
||||
{
|
||||
return d->screenScale;
|
||||
}
|
||||
|
||||
//****************************************
|
||||
// Effect
|
||||
//****************************************
|
||||
|
|
|
@ -2991,7 +2991,7 @@ class KWINEFFECTS_EXPORT ScreenPaintData : public PaintData
|
|||
{
|
||||
public:
|
||||
ScreenPaintData();
|
||||
ScreenPaintData(const QMatrix4x4 &projectionMatrix, const QRect &outputGeometry = QRect());
|
||||
ScreenPaintData(const QMatrix4x4 &projectionMatrix, const QRect &outputGeometry = QRect(), const qreal screenScale = 1.0);
|
||||
ScreenPaintData(const ScreenPaintData &other);
|
||||
~ScreenPaintData() override;
|
||||
/**
|
||||
|
@ -3053,6 +3053,13 @@ public:
|
|||
* @since 5.9
|
||||
*/
|
||||
QRect outputGeometry() const;
|
||||
|
||||
/**
|
||||
* The scale factor for the output
|
||||
*
|
||||
* @since 5.19
|
||||
*/
|
||||
qreal screenScale() const;
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
|
|
|
@ -649,7 +649,7 @@ qint64 SceneOpenGL::paint(const QRegion &damage, const QList<Toplevel *> &toplev
|
|||
|
||||
int mask = 0;
|
||||
updateProjectionMatrix();
|
||||
paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, projectionMatrix(), geo); // call generic implementation
|
||||
paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, projectionMatrix(), geo, screens()->scale(i)); // call generic implementation
|
||||
paintCursor();
|
||||
|
||||
GLVertexBuffer::streamingBuffer()->endOfFrame();
|
||||
|
|
|
@ -105,7 +105,7 @@ Scene::~Scene()
|
|||
|
||||
// returns mask and possibly modified region
|
||||
void Scene::paintScreen(int* mask, const QRegion &damage, const QRegion &repaint,
|
||||
QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection, const QRect &outputGeometry)
|
||||
QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection, const QRect &outputGeometry, const qreal screenScale)
|
||||
{
|
||||
const QSize &screenSize = screens()->size();
|
||||
const QRegion displayRegion(0, 0, screenSize.width(), screenSize.height());
|
||||
|
@ -145,7 +145,7 @@ void Scene::paintScreen(int* mask, const QRegion &damage, const QRegion &repaint
|
|||
paintBackground(region);
|
||||
}
|
||||
|
||||
ScreenPaintData data(projection, outputGeometry);
|
||||
ScreenPaintData data(projection, outputGeometry, screenScale);
|
||||
effects->paintScreen(*mask, region, data);
|
||||
|
||||
foreach (Window *w, stacking_order) {
|
||||
|
|
2
scene.h
2
scene.h
|
@ -213,7 +213,7 @@ protected:
|
|||
void clearStackingOrder();
|
||||
// shared implementation, starts painting the screen
|
||||
void paintScreen(int *mask, const QRegion &damage, const QRegion &repaint,
|
||||
QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection = QMatrix4x4(), const QRect &outputGeometry = QRect());
|
||||
QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection = QMatrix4x4(), const QRect &outputGeometry = QRect(), const qreal screenScale = 1.0);
|
||||
// Render cursor texture in case hardware cursor is disabled/non-applicable
|
||||
virtual void paintCursor() = 0;
|
||||
friend class EffectsHandlerImpl;
|
||||
|
|
Loading…
Reference in a new issue