summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorAnders Bakken <anders.bakken@nokia.com>2009-07-22 09:50:49 -0700
committerAnders Bakken <anders.bakken@nokia.com>2009-07-22 10:34:19 -0700
commiteb6fa7e03a5c91e3da93d0c6203d9bad52dfcbb9 (patch)
tree3b2bd86168318f29cf5966468a2729255f02492e /src/plugins
parent95baddfc2f5dc719188f52519c95206959983206 (diff)
Fix dfbwindowsurface handling for offscreen mode
This patch vastly simplifies the geometry handling (setGeometry/move) It also implements a mode in which DirectFB implementations that do not support windows can use an offscreen buffer as its backing store. Previously the only way to do this was to paint directly on the primary surface. This didn't work when the dfb driver didn't support an accelerated mouse cursor. It also detects the situation when the cursor isn't accelerated and takes care of painting it manually when needed. Reviewed-by: Donald <qt-info@nokia.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp268
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h10
2 files changed, 151 insertions, 127 deletions
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp
index 7dcf398314..ed4b2d900a 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp
@@ -44,10 +44,10 @@
#include "qdirectfbpaintengine.h"
#include <qwidget.h>
+#include <qwindowsystem_qws.h>
#include <qpaintdevice.h>
#include <qvarlengtharray.h>
-
//#define QT_DIRECTFB_DEBUG_SURFACES 1
QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirectFBScreen *scr)
@@ -59,6 +59,11 @@ QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirect
, flipFlags(flip)
, boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
{
+#ifdef QT_NO_DIRECTFB_WM
+ mode = Offscreen;
+#else
+ mode = Window;
+#endif
setSurfaceFlags(Opaque | Buffered);
#ifdef QT_DIRECTFB_TIMING
frames = 0;
@@ -75,11 +80,17 @@ QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirect
, flipFlags(flip)
, boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
{
- onscreen = widget->testAttribute(Qt::WA_PaintOnScreen);
- if (onscreen)
+ if (widget && widget->testAttribute(Qt::WA_PaintOnScreen)) {
setSurfaceFlags(Opaque | RegionReserved);
- else
+ mode = Primary;
+ } else {
+#ifdef QT_NO_DIRECTFB_WM
+ mode = Offscreen;
+#else
+ mode = Window;
+#endif
setSurfaceFlags(Opaque | Buffered);
+ }
#ifdef QT_DIRECTFB_TIMING
frames = 0;
timer.start();
@@ -99,7 +110,7 @@ bool QDirectFBWindowSurface::isValid() const
void QDirectFBWindowSurface::createWindow()
{
#ifdef QT_NO_DIRECTFB_LAYER
-#warning QT_NO_DIRECTFB_LAYER requires QT_NO_DIRECTFB_WM
+#error QT_NO_DIRECTFB_LAYER requires QT_NO_DIRECTFB_WM
#else
IDirectFBDisplayLayer *layer = screen->dfbDisplayLayer();
if (!layer)
@@ -129,8 +140,40 @@ void QDirectFBWindowSurface::createWindow()
}
#endif // QT_NO_DIRECTFB_WM
-void QDirectFBWindowSurface::setGeometry(const QRect &rect, const QRegion &mask)
+#ifndef QT_NO_DIRECTFB_WM
+static DFBResult setGeometry(IDirectFBWindow *dfbWindow, const QRect &old, const QRect &rect)
+{
+ DFBResult result = DFB_OK;
+ const bool isMove = old.isEmpty() || rect.topLeft() != old.topLeft();
+ const bool isResize = rect.size() != old.size();
+
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ if (isResize && isMove) {
+ result = dfbWindow->SetBounds(dfbWindow, rect.x(), rect.y(),
+ rect.width(), rect.height());
+ } else if (isResize) {
+ result = dfbWindow->Resize(dfbWindow,
+ rect.width(), rect.height());
+ } else if (isMove) {
+ result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
+ }
+#else
+ if (isResize) {
+ result = dfbWindow->Resize(dfbWindow,
+ rect.width(), rect.height());
+ }
+ if (isMove) {
+ result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
+ }
+#endif
+ return result;
+}
+#endif
+
+void QDirectFBWindowSurface::setGeometry(const QRect &rect)
{
+ IDirectFBSurface *primarySurface = screen->dfbSurface();
+ Q_ASSERT(primarySurface);
if (rect.isNull()) {
#ifndef QT_NO_DIRECTFB_WM
if (dfbWindow) {
@@ -138,22 +181,21 @@ void QDirectFBWindowSurface::setGeometry(const QRect &rect, const QRegion &mask)
dfbWindow = 0;
}
#endif
- if (dfbSurface && dfbSurface != screen->dfbSurface()) {
- dfbSurface->Release(dfbSurface);
+ if (dfbSurface) {
+ if (dfbSurface != primarySurface) {
+ dfbSurface->Release(dfbSurface);
+ }
dfbSurface = 0;
}
} else if (rect != geometry()) {
+ const QRect oldRect = geometry();
DFBResult result = DFB_OK;
-
// If we're in a resize, the surface shouldn't be locked
Q_ASSERT((lockedImage == 0) || (rect.size() == geometry().size()));
-
- if (onscreen) {
- IDirectFBSurface *primarySurface = screen->dfbSurface();
- Q_ASSERT(primarySurface);
+ switch (mode) {
+ case Primary:
if (dfbSurface && dfbSurface != primarySurface)
dfbSurface->Release(dfbSurface);
-
if (rect == screen->region().boundingRect()) {
dfbSurface = primarySurface;
} else {
@@ -161,58 +203,32 @@ void QDirectFBWindowSurface::setGeometry(const QRect &rect, const QRegion &mask)
rect.width(), rect.height() };
result = primarySurface->GetSubSurface(primarySurface, &r, &dfbSurface);
}
- } else {
- const bool isResize = rect.size() != geometry().size();
-#ifdef QT_NO_DIRECTFB_WM
- if (isResize) {
+ break;
+ case Window:
+#ifndef QT_NO_DIRECTFB_WM
+ if (!dfbWindow)
+ createWindow();
+ ::setGeometry(dfbWindow, oldRect, rect);
+ // ### do I need to release and get the surface again here?
+#endif
+ break;
+ case Offscreen: {
+ if (!dfbSurface || oldRect.size() != rect.size()) {
if (dfbSurface)
dfbSurface->Release(dfbSurface);
-
- IDirectFB *dfb = screen->dfb();
- if (!dfb) {
- qFatal("QDirectFBWindowSurface::setGeometry(): "
- "Unable to get DirectFB handle!");
- }
-
dfbSurface = screen->createDFBSurface(rect.size(), screen->pixelFormat(), QDirectFBScreen::DontTrackSurface);
- } else {
- Q_ASSERT(dfbSurface);
- }
-#else
- const QRect oldRect = geometry();
- const bool isMove = oldRect.isEmpty() ||
- rect.topLeft() != oldRect.topLeft();
-
- if (!dfbWindow)
- createWindow();
-
-#if (Q_DIRECTFB_VERSION >= 0x010000)
- if (isResize && isMove) {
- result = dfbWindow->SetBounds(dfbWindow, rect.x(), rect.y(),
- rect.width(), rect.height());
- } else if (isResize) {
- result = dfbWindow->Resize(dfbWindow,
- rect.width(), rect.height());
- } else if (isMove) {
- result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
- }
-#else
- if (isResize) {
- result = dfbWindow->Resize(dfbWindow,
- rect.width(), rect.height());
}
- if (isMove) {
- result = dfbWindow->MoveTo(dfbWindow, rect.x(), rect.y());
- }
-#endif
-#endif
+ const QRegion region = QRegion(oldRect.isEmpty() ? screen->region() : QRegion(oldRect)).subtracted(rect);
+ screen->erase(region);
+ screen->flipSurface(primarySurface, flipFlags, region, QPoint());
+ break; }
}
if (result != DFB_OK)
DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result);
}
- QWSWindowSurface::setGeometry(rect, mask);
+ QWSWindowSurface::setGeometry(rect);
}
QByteArray QDirectFBWindowSurface::permanentState() const
@@ -254,7 +270,6 @@ static inline void scrollSurface(IDirectFBSurface *surface, const QRect &r, int
surface->Blit(surface, surface, &rect, r.x() + dx, r.y() + dy);
}
-
bool QDirectFBWindowSurface::scroll(const QRegion &region, int dx, int dy)
{
if (!dfbSurface || !(flipFlags & DSFLIP_BLIT) || region.isEmpty())
@@ -272,35 +287,13 @@ bool QDirectFBWindowSurface::scroll(const QRegion &region, int dx, int dy)
return true;
}
-bool QDirectFBWindowSurface::move(const QPoint &offset)
-{
- QWSWindowSurface::move(offset);
-
-#ifdef QT_NO_DIRECTFB_WM
- return true; // buffered
-#else
- if (!dfbWindow)
- return false;
-
- DFBResult status = dfbWindow->Move(dfbWindow, offset.x(), offset.y());
- return (status == DFB_OK);
-#endif
-}
-
-QRegion QDirectFBWindowSurface::move(const QPoint &offset, const QRegion &newClip)
+bool QDirectFBWindowSurface::move(const QPoint &moveBy)
{
-#ifdef QT_NO_DIRECTFB_WM
- return QWSWindowSurface::move(offset, newClip);
-#else
- Q_UNUSED(offset);
- Q_UNUSED(newClip);
-
- // DirectFB handles the entire move, so there's no need to blit.
- return QRegion();
-#endif
+ setGeometry(geometry().translated(moveBy));
+ return true;
}
-QPaintEngine* QDirectFBWindowSurface::paintEngine() const
+QPaintEngine *QDirectFBWindowSurface::paintEngine() const
{
if (!engine) {
QDirectFBWindowSurface *that = const_cast<QDirectFBWindowSurface*>(this);
@@ -333,57 +326,86 @@ inline bool isWidgetOpaque(const QWidget *w)
return false;
}
-void QDirectFBWindowSurface::flush(QWidget *widget, const QRegion &region,
+
+void QDirectFBWindowSurface::flush(QWidget *, const QRegion &region,
const QPoint &offset)
{
- Q_UNUSED(widget);
-#ifdef QT_NO_DIRECTFB_WM
- Q_UNUSED(region);
- Q_UNUSED(offset);
-#endif
-
- QWidget *win = window();
-
// hw: make sure opacity information is updated before compositing
- const bool opaque = isWidgetOpaque(win);
- if (opaque != isOpaque()) {
- SurfaceFlags flags = Buffered;
- if (opaque)
- flags |= Opaque;
- setSurfaceFlags(flags);
- }
+ if (QWidget *win = window()) {
+
+ const bool opaque = isWidgetOpaque(win);
+ if (opaque != isOpaque()) {
+ SurfaceFlags flags = surfaceFlags();
+ if (opaque) {
+ flags |= Opaque;
+ } else {
+ flags &= ~Opaque;
+ }
+ setSurfaceFlags(flags);
+ }
#ifndef QT_NO_DIRECTFB_WM
- const quint8 winOpacity = quint8(win->windowOpacity() * 255);
- quint8 opacity;
+ const quint8 winOpacity = quint8(win->windowOpacity() * 255);
+ quint8 opacity;
- if (dfbWindow) {
- dfbWindow->GetOpacity(dfbWindow, &opacity);
- if (winOpacity != opacity)
- dfbWindow->SetOpacity(dfbWindow, winOpacity);
- }
+ if (dfbWindow) {
+ dfbWindow->GetOpacity(dfbWindow, &opacity);
+ if (winOpacity != opacity)
+ dfbWindow->SetOpacity(dfbWindow, winOpacity);
+ }
#endif
- if (!(flipFlags & DSFLIP_BLIT)) {
- dfbSurface->Flip(dfbSurface, 0, flipFlags);
- } else {
- if (!boundingRectFlip && region.numRects() > 1) {
+ }
+
+ if (mode == Offscreen) {
+ IDirectFBSurface *primarySurface = screen->dfbSurface();
+ primarySurface->SetBlittingFlags(primarySurface, DSBLIT_NOFX);
+ const QRect windowGeometry = QDirectFBWindowSurface::geometry();
+ const QRect windowRect(0, 0, windowGeometry.width(), windowGeometry.height());
+ if (boundingRectFlip || region.numRects() == 1) {
+ const QRect regionBoundingRect = region.boundingRect().translated(offset);
+ const QRect source = windowRect & regionBoundingRect;
+ const DFBRectangle rect = {
+ source.x(), source.y(), source.width(), source.height()
+ };
+ primarySurface->Blit(primarySurface, dfbSurface, &rect,
+ windowGeometry.x() + source.x(),
+ windowGeometry.y() + source.y());
+ } else {
const QVector<QRect> rects = region.rects();
- const DFBSurfaceFlipFlags nonWaitFlags = flipFlags & ~DSFLIP_WAIT;
- for (int i=0; i<rects.size(); ++i) {
- const QRect &r = rects.at(i);
- const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(),
- r.x() + r.width() + offset.x(),
- r.y() + r.height() + offset.y() };
- dfbSurface->Flip(dfbSurface, &dfbReg, i + 1 < rects.size() ? nonWaitFlags : flipFlags);
+ const int count = rects.size();
+ for (int i=0; i<count; ++i) {
+ const QRect &r = rects.at(i).translated(offset);
+ const QRect source = windowRect & r;
+ const DFBRectangle rect = {
+ source.x(), source.y(), source.width(), source.height()
+ };
+ primarySurface->Blit(primarySurface, dfbSurface, &rect,
+ windowGeometry.x() + source.x(),
+ windowGeometry.y() + source.y());
}
- } else {
- const QRect r = region.boundingRect();
- const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(),
- r.x() + r.width() + offset.x(),
- r.y() + r.height() + offset.y() };
- dfbSurface->Flip(dfbSurface, &dfbReg, flipFlags);
}
+ if (QScreenCursor *cursor = QScreenCursor::instance()) {
+ const QRect cursorRectangle = cursor->boundingRect();
+ if (cursor->isVisible() && !cursor->isAccelerated()
+ && region.intersects(cursorRectangle.translated(-(offset + windowGeometry.topLeft())))) {
+ const QImage image = cursor->image();
+
+ IDirectFBSurface *surface = screen->createDFBSurface(image, QDirectFBScreen::DontTrackSurface);
+ primarySurface->SetBlittingFlags(primarySurface, DSBLIT_BLEND_ALPHACHANNEL);
+ primarySurface->Blit(primarySurface, surface, 0, cursorRectangle.x(), cursorRectangle.y());
+ surface->Release(surface);
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ primarySurface->ReleaseSource(primarySurface);
+#endif
+ }
+ }
+
+ screen->flipSurface(primarySurface, flipFlags, region, offset + windowGeometry.topLeft());
+ } else {
+ screen->flipSurface(dfbSurface, flipFlags, region, offset);
}
+
+
#ifdef QT_DIRECTFB_TIMING
enum { Secs = 3 };
++frames;
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h
index 7885b735b5..c46d93bf40 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h
@@ -67,7 +67,7 @@ public:
bool isValid() const;
- void setGeometry(const QRect &rect, const QRegion &mask);
+ void setGeometry(const QRect &rect);
QString key() const { return QLatin1String("directfb"); }
QByteArray permanentState() const;
@@ -76,7 +76,6 @@ public:
bool scroll(const QRegion &area, int dx, int dy);
bool move(const QPoint &offset);
- QRegion move(const QPoint &offset, const QRegion &newClip);
QImage image() const { return QImage(); }
QPaintDevice *paintDevice() { return this; }
@@ -88,7 +87,6 @@ public:
void endPaint(const QRegion &);
QImage *buffer(const QWidget *widget);
-
private:
#ifndef QT_NO_DIRECTFB_WM
void createWindow();
@@ -96,7 +94,11 @@ private:
#endif
QDirectFBPaintEngine *engine;
- bool onscreen;
+ enum Mode {
+ Primary,
+ Offscreen,
+ Window
+ } mode;
QList<QImage*> bufferImages;
DFBSurfaceFlipFlags flipFlags;