Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 75 additions & 8 deletions src/VBox/Frontends/VirtualBox/src/runtime/UIFrameBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

/* Qt includes: */
#include <QImage>
#include <QList>
#include <QRegion>
#include <QPainter>
#include <QPaintEvent>
Expand Down Expand Up @@ -77,8 +78,8 @@ class ATL_NO_VTABLE UIFrameBufferPrivate : public QObject,

/** Notifies listener about guest-screen resolution changes. */
void sigNotifyChange(int iWidth, int iHeight);
/** Notifies listener about guest-screen updates. */
void sigNotifyUpdate(int iX, int iY, int iWidth, int iHeight);
/** Notifies listener that one or more guest-screen updates are pending. */
void sigNotifyUpdatePending();
/** Notifies listener about guest-screen visible-region changes. */
void sigSetVisibleRegion(QRegion region);

Expand Down Expand Up @@ -262,6 +263,8 @@ class ATL_NO_VTABLE UIFrameBufferPrivate : public QObject,

protected slots:

/** Handles coalesced guest-screen updates. */
void sltHandlePendingNotifyUpdate();
/** Handles guest requests to change mouse pointer shape or position. */
void sltMousePointerShapeOrPositionChange();

Expand All @@ -274,6 +277,8 @@ protected slots:

/** Updates coordinate-system: */
void updateCoordinateSystem();
/** Queues a guest-screen update rectangle for asynchronous GUI-thread processing. */
void queueNotifyUpdate(ULONG uX, ULONG uY, ULONG uWidth, ULONG uHeight);

/** Default paint routine. */
void paintDefault(QPaintEvent *pEvent);
Expand Down Expand Up @@ -312,6 +317,10 @@ protected slots:
CDisplaySourceBitmap m_pendingSourceBitmap;
/** Holds whether there is a pending source bitmap which must be applied. */
bool m_fPendingSourceBitmap;
/** Holds pending guest-screen update rectangles. */
QList<QRect> m_pendingUpdateRectangles;
/** Holds whether a pending-update flush has already been queued. */
bool m_fNotifyUpdatePending;

/** Holds machine-view this frame-buffer is bounded to. */
UIMachineView *m_pMachineView;
Expand Down Expand Up @@ -391,6 +400,7 @@ UIFrameBufferPrivate::UIFrameBufferPrivate()
: m_uScreenId(0)
, m_iWidth(0), m_iHeight(0)
, m_fPendingSourceBitmap(false)
, m_fNotifyUpdatePending(false)
, m_pMachineView(NULL)
, m_iWinId(0)
, m_fUpdatesAllowed(false)
Expand Down Expand Up @@ -695,7 +705,7 @@ STDMETHODIMP UIFrameBufferPrivate::NotifyUpdate(ULONG uX, ULONG uY, ULONG uWidth
LogRel3(("GUI: UIFrameBufferPrivate::NotifyUpdate: Origin=%lux%lu, Size=%lux%lu, Sending to async-handler\n",
(unsigned long)uX, (unsigned long)uY,
(unsigned long)uWidth, (unsigned long)uHeight));
emit sigNotifyUpdate(uX, uY, uWidth, uHeight);
queueNotifyUpdate(uX, uY, uWidth, uHeight);

/* Unlock access to frame-buffer: */
unlock();
Expand Down Expand Up @@ -748,7 +758,7 @@ STDMETHODIMP UIFrameBufferPrivate::NotifyUpdateImage(ULONG uX, ULONG uY,
LogRel3(("GUI: UIFrameBufferPrivate::NotifyUpdateImage: Origin=%lux%lu, Size=%lux%lu, Sending to async-handler\n",
(unsigned long)uX, (unsigned long)uY,
(unsigned long)uWidth, (unsigned long)uHeight));
emit sigNotifyUpdate(uX, uY, uWidth, uHeight);
queueNotifyUpdate(uX, uY, uWidth, uHeight);
}

/* Unlock access to frame-buffer: */
Expand Down Expand Up @@ -1221,8 +1231,8 @@ void UIFrameBufferPrivate::prepareConnections()
connect(this, &UIFrameBufferPrivate::sigNotifyChange,
m_pMachineView, &UIMachineView::sltHandleNotifyChange,
Qt::QueuedConnection);
connect(this, &UIFrameBufferPrivate::sigNotifyUpdate,
m_pMachineView, &UIMachineView::sltHandleNotifyUpdate,
connect(this, &UIFrameBufferPrivate::sigNotifyUpdatePending,
this, &UIFrameBufferPrivate::sltHandlePendingNotifyUpdate,
Qt::QueuedConnection);
connect(this, &UIFrameBufferPrivate::sigSetVisibleRegion,
m_pMachineView, &UIMachineView::sltHandleSetVisibleRegion,
Expand All @@ -1240,8 +1250,8 @@ void UIFrameBufferPrivate::cleanupConnections()
/* Detach EMT connections: */
disconnect(this, &UIFrameBufferPrivate::sigNotifyChange,
m_pMachineView, &UIMachineView::sltHandleNotifyChange);
disconnect(this, &UIFrameBufferPrivate::sigNotifyUpdate,
m_pMachineView, &UIMachineView::sltHandleNotifyUpdate);
disconnect(this, &UIFrameBufferPrivate::sigNotifyUpdatePending,
this, &UIFrameBufferPrivate::sltHandlePendingNotifyUpdate);
disconnect(this, &UIFrameBufferPrivate::sigSetVisibleRegion,
m_pMachineView, &UIMachineView::sltHandleSetVisibleRegion);

Expand All @@ -1266,6 +1276,63 @@ void UIFrameBufferPrivate::updateCoordinateSystem()
m_transform = m_transform.scale(1.0 / devicePixelRatio(), 1.0 / devicePixelRatio());
}

void UIFrameBufferPrivate::queueNotifyUpdate(ULONG uX, ULONG uY, ULONG uWidth, ULONG uHeight)
{
const QRect rect((int)uX, (int)uY, (int)uWidth, (int)uHeight);
if (rect.isEmpty())
return;

m_pendingUpdateRectangles << rect;
if (!m_fNotifyUpdatePending)
{
m_fNotifyUpdatePending = true;
emit sigNotifyUpdatePending();
}
}

void UIFrameBufferPrivate::sltHandlePendingNotifyUpdate()
{
if (!m_pMachineView)
{
lock();
m_pendingUpdateRectangles.clear();
m_fNotifyUpdatePending = false;
unlock();
return;
}

lock();

if ( m_fUnused
|| m_pendingUpdateRectangles.isEmpty())
{
m_pendingUpdateRectangles.clear();
m_fNotifyUpdatePending = false;
unlock();
return;
}

const int cMaxUpdateRectanglesPerPass = 8;
QList<QRect> updateRectangles;
updateRectangles.reserve(cMaxUpdateRectanglesPerPass);
/* Keep the batch deliberately small. Large Retina update bursts are cheaper
* as a few bounded viewport updates than as one huge Qt backing-store flush. */
while ( updateRectangles.size() < cMaxUpdateRectanglesPerPass
&& !m_pendingUpdateRectangles.isEmpty())
updateRectangles << m_pendingUpdateRectangles.takeFirst();

const bool fHasMoreUpdates = !m_pendingUpdateRectangles.isEmpty();
m_fNotifyUpdatePending = fHasMoreUpdates;

unlock();

for (QList<QRect>::const_iterator it = updateRectangles.begin(); it != updateRectangles.end(); ++it)
m_pMachineView->sltHandleNotifyUpdate(it->x(), it->y(), it->width(), it->height());

if (fHasMoreUpdates)
emit sigNotifyUpdatePending();
}

void UIFrameBufferPrivate::paintDefault(QPaintEvent *pEvent)
{
/* Make sure cached image is valid: */
Expand Down
28 changes: 19 additions & 9 deletions src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -763,13 +763,23 @@ void UIMachineView::sltHandleNotifyChange(int iWidth, int iHeight)
}

void UIMachineView::sltHandleNotifyUpdate(int iX, int iY, int iWidth, int iHeight)
{
/* Prepare corresponding viewport part: */
const QRect rect = viewportRectangleForGuestUpdate(QRect(iX, iY, iWidth, iHeight));
if (rect.isEmpty())
return;

/* Update corresponding viewport part: */
viewport()->update(rect);
}

QRect UIMachineView::viewportRectangleForGuestUpdate(const QRect &guestRect)
{
/* Sanity check: */
if (!frameBuffer())
return;
return QRect();

/* Prepare corresponding viewport part: */
QRect rect(iX, iY, iWidth, iHeight);
QRect rect = guestRect;

/* Take the scaling into account: */
const double dScaleFactor = frameBuffer()->scaleFactor();
Expand Down Expand Up @@ -804,11 +814,7 @@ void UIMachineView::sltHandleNotifyUpdate(int iX, int iY, int iWidth, int iHeigh

/* Limit the resulting part by the viewport rectangle: */
rect &= viewport()->rect();
if (rect.isEmpty())
return;

/* Update corresponding viewport part: */
viewport()->update(rect);
return rect;
}

void UIMachineView::sltHandleSetVisibleRegion(QRegion region)
Expand Down Expand Up @@ -1253,8 +1259,12 @@ void UIMachineView::prepareViewport()
/* Prepare viewport: */
AssertPtrReturnVoid(viewport());
{
/* Enable manual painting: */
/* The framebuffer paints the requested update itself; avoid widget-level
* background fills and let Qt preserve static contents where possible. */
viewport()->setAutoFillBackground(false);
viewport()->setAttribute(Qt::WA_OpaquePaintEvent);
viewport()->setAttribute(Qt::WA_NoSystemBackground);
viewport()->setAttribute(Qt::WA_StaticContents);
/* Enable multi-touch support: */
viewport()->setAttribute(Qt::WA_AcceptTouchEvents);
}
Expand Down
2 changes: 2 additions & 0 deletions src/VBox/Frontends/VirtualBox/src/runtime/UIMachineView.h
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,8 @@ protected slots:
QSize scaledForward(QSize size) const;
/** Scales passed size backward. */
QSize scaledBackward(QSize size) const;
/** Converts a guest dirty rectangle to a viewport dirty rectangle. */
QRect viewportRectangleForGuestUpdate(const QRect &rect);

/** Updates mouse pointer @a pixmap, @a iXHot and @a iYHot according to scaling attributes. */
void updateMousePointerPixmapScaling(QPixmap &pixmap, int &iXHot, int &iYHot);
Expand Down