summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMorten Johan Sorvig <morten.sorvig@digia.com>2013-08-23 09:21:26 +0200
committerMorten Johan Sørvig <morten.sorvig@digia.com>2014-12-17 13:46:27 +0100
commit7ef5e2e4863bde5495cc17b60680271d3c09f78f (patch)
tree78afeb00fc67787286b264384555d2923242e9b3
parent198d7a51d4fc894fca691c1f8243372e876af68a (diff)
Implement high-dpi support
Wayland 1.2 added support for display scaling, where wl_output has a "scale" event informing the the client that the compositor will scale the output surfaces by the given factor. The client then has the option of providing large surfaces to match the target pixel densety and bypass the compositor's scaling. This is done by calling wl_surface::set_buffer_scale. Re-use the current high-dpi support in Qt by implementing devicePixelRatio() for QWaylandScreen and QWaylandWindow. Provide high resolution buffers both for raster and OpenGL graphics. Introduce a new coordinate system: buffer coordinates, which is related to the window coordinate system via an "int scale" scale factor. This scale factor corresponds to Qts qreal devicePixelRatio, but we keep the name and the type in the QtWayland implementation. Change-Id: Ie10d7e5b4833480a9a25d96a26ad02150eb6e83f Reviewed-by: Giulio Camuffo <giulio.camuffo@jollamobile.com>
-rw-r--r--src/client/qwaylandbuffer_p.h1
-rw-r--r--src/client/qwaylandscreen.cpp20
-rw-r--r--src/client/qwaylandscreen_p.h4
-rw-r--r--src/client/qwaylandshmbackingstore.cpp18
-rw-r--r--src/client/qwaylandshmbackingstore_p.h3
-rw-r--r--src/client/qwaylandwindow.cpp17
-rw-r--r--src/client/qwaylandwindow_p.h3
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp5
-rw-r--r--src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp5
9 files changed, 63 insertions, 13 deletions
diff --git a/src/client/qwaylandbuffer_p.h b/src/client/qwaylandbuffer_p.h
index 2bb9990f3..0c9903f5a 100644
--- a/src/client/qwaylandbuffer_p.h
+++ b/src/client/qwaylandbuffer_p.h
@@ -58,6 +58,7 @@ public:
virtual ~QWaylandBuffer() { }
wl_buffer *buffer() {return mBuffer;}
virtual QSize size() const = 0;
+ virtual int scale() const { return 1; }
protected:
struct wl_buffer *mBuffer;
diff --git a/src/client/qwaylandscreen.cpp b/src/client/qwaylandscreen.cpp
index 6e48c442e..675c84042 100644
--- a/src/client/qwaylandscreen.cpp
+++ b/src/client/qwaylandscreen.cpp
@@ -59,6 +59,7 @@ QWaylandScreen::QWaylandScreen(QWaylandDisplay *waylandDisplay, int version, uin
, m_outputId(id)
, mWaylandDisplay(waylandDisplay)
, mExtendedOutput(0)
+ , mScale(1)
, mDepth(32)
, mRefreshRate(60000)
, mTransform(-1)
@@ -83,7 +84,9 @@ QWaylandDisplay * QWaylandScreen::display() const
QRect QWaylandScreen::geometry() const
{
- return mGeometry;
+ // Scale geometry for QScreen. This makes window and screen
+ // geometry be in the same coordinate system.
+ return QRect(mGeometry.topLeft(), mGeometry.size() / mScale);
}
int QWaylandScreen::depth() const
@@ -127,6 +130,16 @@ Qt::ScreenOrientation QWaylandScreen::orientation() const
return m_orientation;
}
+int QWaylandScreen::scale() const
+{
+ return mScale;
+}
+
+qreal QWaylandScreen::devicePixelRatio() const
+{
+ return qreal(mScale);
+}
+
qreal QWaylandScreen::refreshRate() const
{
return mRefreshRate / 1000.f;
@@ -188,6 +201,11 @@ void QWaylandScreen::output_geometry(int32_t x, int32_t y,
mGeometry.moveTopLeft(QPoint(x, y));
}
+void QWaylandScreen::output_scale(int32_t factor)
+{
+ mScale = factor;
+}
+
void QWaylandScreen::output_done()
{
// the done event is sent after all the geometry and the mode events are sent,
diff --git a/src/client/qwaylandscreen_p.h b/src/client/qwaylandscreen_p.h
index d3173e0c9..d0c5d710f 100644
--- a/src/client/qwaylandscreen_p.h
+++ b/src/client/qwaylandscreen_p.h
@@ -72,6 +72,8 @@ public:
void setOrientationUpdateMask(Qt::ScreenOrientations mask);
Qt::ScreenOrientation orientation() const;
+ int scale() const;
+ qreal devicePixelRatio() const Q_DECL_OVERRIDE;
qreal refreshRate() const;
QString name() const { return mOutputName; }
@@ -95,12 +97,14 @@ private:
const QString &make,
const QString &model,
int32_t transform) Q_DECL_OVERRIDE;
+ void output_scale(int32_t factor) Q_DECL_OVERRIDE;
void output_done() Q_DECL_OVERRIDE;
int m_outputId;
QWaylandDisplay *mWaylandDisplay;
QWaylandExtendedOutput *mExtendedOutput;
QRect mGeometry;
+ int mScale;
int mDepth;
int mRefreshRate;
int mTransform;
diff --git a/src/client/qwaylandshmbackingstore.cpp b/src/client/qwaylandshmbackingstore.cpp
index d407335d3..9ec800138 100644
--- a/src/client/qwaylandshmbackingstore.cpp
+++ b/src/client/qwaylandshmbackingstore.cpp
@@ -56,7 +56,7 @@
QT_BEGIN_NAMESPACE
QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
- const QSize &size, QImage::Format format)
+ const QSize &size, QImage::Format format, int scale)
: mMarginsImage(0)
{
int stride = size.width() * 4;
@@ -87,6 +87,8 @@ QWaylandShmBuffer::QWaylandShmBuffer(QWaylandDisplay *display,
}
mImage = QImage(data, size.width(), size.height(), stride, format);
+ mImage.setDevicePixelRatio(qreal(scale));
+
mShmPool = wl_shm_create_pool(display->shm(), fd, alloc);
mBuffer = wl_shm_pool_create_buffer(mShmPool,0, size.width(), size.height(),
stride, WL_SHM_FORMAT_ARGB8888);
@@ -101,8 +103,10 @@ QWaylandShmBuffer::~QWaylandShmBuffer(void)
wl_shm_pool_destroy(mShmPool);
}
-QImage *QWaylandShmBuffer::imageInsideMargins(const QMargins &margins)
+QImage *QWaylandShmBuffer::imageInsideMargins(const QMargins &marginsIn)
{
+ QMargins margins = marginsIn * int(mImage.devicePixelRatio());
+
if (!margins.isNull() && margins != mMargins) {
if (mMarginsImage) {
delete mMarginsImage;
@@ -112,6 +116,7 @@ QImage *QWaylandShmBuffer::imageInsideMargins(const QMargins &margins)
int b_s_width = mImage.size().width() - margins.left() - margins.right();
int b_s_height = mImage.size().height() - margins.top() - margins.bottom();
mMarginsImage = new QImage(b_s_data, b_s_width,b_s_height,mImage.bytesPerLine(),mImage.format());
+ mMarginsImage->setDevicePixelRatio(mImage.devicePixelRatio());
}
if (margins.isNull()) {
delete mMarginsImage;
@@ -228,7 +233,7 @@ void QWaylandShmBackingStore::flush(QWindow *window, const QRegion &region, cons
if (damageAll) {
//need to damage it all, otherwise the attach offset may screw up
- waylandWindow()->damage(QRect(QPoint(0,0),mFrontBuffer->size()));
+ waylandWindow()->damage(QRect(QPoint(0,0), window->size()));
} else {
QVector<QRect> rects = region.rects();
for (int i = 0; i < rects.size(); i++) {
@@ -249,7 +254,8 @@ void QWaylandShmBackingStore::resize(const QSize &size, const QRegion &)
void QWaylandShmBackingStore::resize(const QSize &size)
{
QMargins margins = windowDecorationMargins();
- QSize sizeWithMargins = size + QSize(margins.left()+margins.right(),margins.top()+margins.bottom());
+ int scale = waylandWindow()->scale();
+ QSize sizeWithMargins = (size + QSize(margins.left()+margins.right(),margins.top()+margins.bottom())) * scale;
QImage::Format format = QPlatformScreen::platformScreenForWindow(window())->format();
@@ -260,7 +266,7 @@ void QWaylandShmBackingStore::resize(const QSize &size)
delete mBackBuffer; //we delete the attached buffer when we flush
}
- mBackBuffer = new QWaylandShmBuffer(mDisplay, sizeWithMargins, format);
+ mBackBuffer = new QWaylandShmBuffer(mDisplay, sizeWithMargins, format, scale);
if (windowDecoration() && window()->isVisible())
windowDecoration()->update();
@@ -354,7 +360,7 @@ void QWaylandShmBackingStore::done(void *data, wl_callback *callback, uint32_t t
delete window->attached();
}
window->attachOffset(self->mFrontBuffer);
- window->damage(QRect(QPoint(0,0),self->mFrontBuffer->size()));
+ window->damage(QRect(QPoint(0,0),window->geometry().size()));
window->commit();
}
}
diff --git a/src/client/qwaylandshmbackingstore_p.h b/src/client/qwaylandshmbackingstore_p.h
index 1212e52fe..b1e326c37 100644
--- a/src/client/qwaylandshmbackingstore_p.h
+++ b/src/client/qwaylandshmbackingstore_p.h
@@ -57,9 +57,10 @@ class QWaylandWindow;
class Q_WAYLAND_CLIENT_EXPORT QWaylandShmBuffer : public QWaylandBuffer {
public:
QWaylandShmBuffer(QWaylandDisplay *display,
- const QSize &size, QImage::Format format);
+ const QSize &size, QImage::Format format, int scale = 1);
~QWaylandShmBuffer();
QSize size() const { return mImage.size(); }
+ int scale() const Q_DECL_OVERRIDE { return int(mImage.devicePixelRatio()); }
QImage *image() { return &mImage; }
QImage *imageInsideMargins(const QMargins &margins);
diff --git a/src/client/qwaylandwindow.cpp b/src/client/qwaylandwindow.cpp
index 9f7bdda1f..fd06972ff 100644
--- a/src/client/qwaylandwindow.cpp
+++ b/src/client/qwaylandwindow.cpp
@@ -126,6 +126,12 @@ QWaylandWindow::QWaylandWindow(QWindow *window)
mShellSurface->setTopLevel();
}
+ // Enable high-dpi rendering. Scale() returns the screen scale factor and will
+ // typically be integer 1 (normal-dpi) or 2 (high-dpi). Call set_buffer_scale()
+ // to inform the compositor that high-resolution buffers will be provided.
+ if (mDisplay->compositorVersion() >= 3)
+ set_buffer_scale(scale());
+
setOrientationMask(window->screen()->orientationUpdateMask());
setWindowFlags(window->flags());
setGeometry_helper(window->geometry());
@@ -369,7 +375,6 @@ void QWaylandWindow::requestResize()
void QWaylandWindow::attach(QWaylandBuffer *buffer, int x, int y)
{
mBuffer = buffer;
-
if (mBuffer)
attach(mBuffer->buffer(), x, y);
else
@@ -707,6 +712,16 @@ bool QWaylandWindow::isExposed() const
return QPlatformWindow::isExposed();
}
+int QWaylandWindow::scale() const
+{
+ return screen()->scale();
+}
+
+qreal QWaylandWindow::devicePixelRatio() const
+{
+ return screen()->devicePixelRatio();
+}
+
bool QWaylandWindow::setMouseGrabEnabled(bool grab)
{
if (window()->type() != Qt::Popup) {
diff --git a/src/client/qwaylandwindow_p.h b/src/client/qwaylandwindow_p.h
index 0c55cd88d..0d982d43e 100644
--- a/src/client/qwaylandwindow_p.h
+++ b/src/client/qwaylandwindow_p.h
@@ -142,6 +142,9 @@ public:
void setMask(const QRegion &region) Q_DECL_OVERRIDE;
+ int scale() const;
+ qreal devicePixelRatio() const Q_DECL_OVERRIDE;
+
void requestActivateWindow() Q_DECL_OVERRIDE;
bool isExposed() const Q_DECL_OVERRIDE;
void unfocus();
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
index 9b445e10c..473e7d51d 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandeglwindow.cpp
@@ -106,7 +106,7 @@ void QWaylandEglWindow::updateSurface(bool create)
{
QMargins margins = frameMargins();
QRect rect = geometry();
- QSize sizeWithMargins = rect.size() + QSize(margins.left() + margins.right(), margins.top() + margins.bottom());
+ QSize sizeWithMargins = (rect.size() + QSize(margins.left() + margins.right(), margins.top() + margins.bottom())) * scale();
// wl_egl_windows must have both width and height > 0
// mesa's egl returns NULL if we try to create a, invalid wl_egl_window, however not all EGL
@@ -175,7 +175,8 @@ GLuint QWaylandEglWindow::contentFBO() const
if (m_resize || !m_contentFBO) {
QOpenGLFramebufferObject *old = m_contentFBO;
- m_contentFBO = new QOpenGLFramebufferObject(geometry().width(), geometry().height(), QOpenGLFramebufferObject::CombinedDepthStencil);
+ QSize fboSize = geometry().size() * scale();
+ m_contentFBO = new QOpenGLFramebufferObject(fboSize.width(), fboSize.height(), QOpenGLFramebufferObject::CombinedDepthStencil);
delete old;
m_resize = false;
diff --git a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
index 81c74a7d5..52baaf30c 100644
--- a/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
+++ b/src/hardwareintegration/client/wayland-egl/qwaylandglcontext.cpp
@@ -143,7 +143,8 @@ public:
QOpenGLTextureCache *cache = QOpenGLTextureCache::cacheForContext(m_context->context());
QRect windowRect = window->window()->frameGeometry();
- glViewport(0, 0, windowRect.width(), windowRect.height());
+ int scale = window->scale() ;
+ glViewport(0, 0, windowRect.width() * scale, windowRect.height() * scale);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
@@ -205,7 +206,7 @@ public:
m_blitProgram->setAttributeArray(0, squareVertices, 2);
glBindTexture(GL_TEXTURE_2D, window->contentTexture());
QRect r = window->contentsRect();
- glViewport(r.x(), r.y(), r.width(), r.height());
+ glViewport(r.x(), r.y(), r.width() * scale, r.height() * scale);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
//Cleanup