From 8182dc12b88727c647f9bac4d9a19914e3cd8307 Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Mon, 19 Oct 2009 12:17:34 +0200 Subject: Fixed slow QPixmap::fill() when the pixmap is sharing data. If the pixmap is sharing data with other pixmaps, it must be detached before it is filled. Instead of detaching by making a copy, create a new uninitialized data object since all pixels are overwritten by fill() anyway. Task-number: QTBUG-3228 Reviewed-by: Trond --- src/gui/image/qpixmap.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index c03a364..bf6c9ae 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -959,7 +959,17 @@ void QPixmap::fill(const QColor &color) return; } - detach(); + if (data->ref == 1) { + // detach() will also remove this pixmap from caches, so + // it has to be called even when ref == 1. + detach(); + } else { + // Don't bother to make a copy of the data object, since + // it will be filled with new pixel data anyway. + QPixmapData *d = data->createCompatiblePixmapData(); + d->resize(data->width(), data->height()); + data = d; + } data->fill(color); } -- cgit v0.12 From 4d94420184fa109286a9e4233010d5d7539a35a4 Mon Sep 17 00:00:00 2001 From: Gunnar Sletta Date: Mon, 19 Oct 2009 14:20:26 +0200 Subject: Integrated new triangulating stroker into Qt --- .../gl2paintengineex/qpaintengineex_opengl2.cpp | 195 ++++++++++---- .../gl2paintengineex/qpaintengineex_opengl2_p.h | 26 +- .../gl2paintengineex/qtriangulatingstroker.cpp | 299 +++++++++++++++++++++ .../gl2paintengineex/qtriangulatingstroker_p.h | 258 ++++++++++++++++++ src/opengl/opengl.pro | 6 +- 5 files changed, 730 insertions(+), 54 deletions(-) create mode 100644 src/opengl/gl2paintengineex/qtriangulatingstroker.cpp create mode 100644 src/opengl/gl2paintengineex/qtriangulatingstroker_p.h diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index 13efbda..bcc6bdb 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -81,6 +81,8 @@ #include "qglengineshadermanager_p.h" #include "qgl2pexvertexarray_p.h" +#include "qtriangulatingstroker_p.h" + #include QT_BEGIN_NAMESPACE @@ -572,7 +574,6 @@ void QGL2PaintEngineExPrivate::updateMatrix() // // We expand out the multiplication to save the cost of a full 4x4 // matrix multiplication as most of the components are trivial. - const QTransform& transform = q->state()->matrix; if (mode == TextDrawingMode) { @@ -628,6 +629,9 @@ void QGL2PaintEngineExPrivate::updateMatrix() // The actual data has been updated so both shader program's uniforms need updating simpleShaderMatrixUniformDirty = true; shaderMatrixUniformDirty = true; + + dasher.setInvScale(inverseScale); + stroker.setInvScale(inverseScale); } @@ -838,28 +842,6 @@ void QGL2PaintEngineExPrivate::transferMode(EngineMode newMode) mode = newMode; } -void QGL2PaintEngineExPrivate::drawOutline(const QVectorPath& path) -{ - transferMode(BrushDrawingMode); - - // Might need to call updateMatrix to re-calculate inverseScale - if (matrixDirty) - updateMatrix(); - - vertexCoordinateArray.clear(); - vertexCoordinateArray.addPath(path, inverseScale); - - if (path.hasImplicitClose()) { - // Close the path's outline - vertexCoordinateArray.lineToArray(path.points()[0], path.points()[1]); - vertexCoordinateArray.stops().last() += 1; - } - - prepareForDraw(currentBrush->isOpaque()); - drawVertexArrays(vertexCoordinateArray, GL_LINE_STRIP); -} - - // Assumes everything is configured for the brush you want to use void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) { @@ -922,8 +904,14 @@ void QGL2PaintEngineExPrivate::fill(const QVectorPath& path) } -void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) +void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, + int count, + const QVector *stops, + const QGLRect &bounds, + StencilFillMode mode) { + Q_ASSERT(count || stops); + // qDebug("QGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); glStencilMask(0xff); // Enable stencil writes @@ -955,19 +943,20 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve } #endif - if (useWindingFill) { + if (mode == WindingFillMode) { + Q_ASSERT(stops && !count); if (q->state()->clipTestEnabled) { // Flatten clip values higher than current clip, and set high bit to match current clip glStencilFunc(GL_LEQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); - composite(vertexArray.boundingRect()); + composite(bounds); glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT); } else if (!stencilClean) { // Clear stencil buffer within bounding rect glStencilFunc(GL_ALWAYS, 0, 0xff); glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); - composite(vertexArray.boundingRect()); + composite(bounds); } // Inc. for front-facing triangle @@ -975,19 +964,43 @@ void QGL2PaintEngineExPrivate::fillStencilWithVertexArray(QGL2PEXVertexArray& ve // Dec. for back-facing "holes" glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP); glStencilMask(~GL_STENCIL_HIGH_BIT); - drawVertexArrays(vertexArray, GL_TRIANGLE_FAN); + drawVertexArrays(data, stops, GL_TRIANGLE_FAN); if (q->state()->clipTestEnabled) { // Clear high bit of stencil outside of path glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); glStencilMask(GL_STENCIL_HIGH_BIT); - composite(vertexArray.boundingRect()); + composite(bounds); } - } else { + } else if (mode == OddEvenFillMode) { + glStencilMask(GL_STENCIL_HIGH_BIT); + glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit + drawVertexArrays(data, stops, GL_TRIANGLE_FAN); + + } else { // TriStripStrokeFillMode + Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops glStencilMask(GL_STENCIL_HIGH_BIT); +#if 0 glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit - drawVertexArrays(vertexArray, GL_TRIANGLE_FAN); + glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); + glDrawArrays(GL_TRIANGLE_STRIP, 0, count); + glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); +#else + + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + if (q->state()->clipTestEnabled) { + glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT, + ~GL_STENCIL_HIGH_BIT); + } else { + glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff); + } + glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); + glDrawArrays(GL_TRIANGLE_STRIP, 0, count); + glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); +#endif } // Enable color writes & disable stencil writes @@ -1122,14 +1135,15 @@ void QGL2PaintEngineExPrivate::composite(const QGLRect& boundingRect) } // Draws the vertex array as a set of triangle fans. -void QGL2PaintEngineExPrivate::drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive) +void QGL2PaintEngineExPrivate::drawVertexArrays(const float *data, const QVector *stops, + GLenum primitive) { // Now setup the pointer to the vertex array: glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); - glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, vertexArray.data()); + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, data); int previousStop = 0; - foreach(int stop, vertexArray.stops()) { + foreach(int stop, *stops) { /* qDebug("Drawing triangle fan for vertecies %d -> %d:", previousStop, stop-1); for (int i=previousStop; iinRenderText) ensureActive(); + + QOpenGL2PaintEngineState *s = state(); + bool doOffset = !(s->renderHints & QPainter::Antialiasing) && style == Qt::SolidPattern; + + if (doOffset) { + d->temporaryTransform = s->matrix; + QTransform tx = QTransform::fromTranslate(.49, .49); + s->matrix = s->matrix * tx; + d->matrixDirty = true; + } + d->setBrush(&brush); d->fill(path); + + if (doOffset) { + s->matrix = d->temporaryTransform; + d->matrixDirty = true; + } } void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) @@ -1197,23 +1228,89 @@ void QGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) if (penStyle == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) return; + QOpenGL2PaintEngineState *s = state(); + ensureActive(); - qreal penWidth = qpen_widthf(pen); - if ( (pen.isCosmetic() && (penStyle == Qt::SolidLine)) && (penWidth < 2.5f) ) - { - // We only handle solid, cosmetic pens with a width of 1 pixel - const QBrush& brush = pen.brush(); - d->setBrush(&brush); + bool doOffset = !(s->renderHints & QPainter::Antialiasing); + if (doOffset) { + d->temporaryTransform = s->matrix; + QTransform tx = QTransform::fromTranslate(0.49, .49); + s->matrix = s->matrix * tx; + d->matrixDirty = true; + } - if (penWidth < 0.01f) - glLineWidth(1.0); - else - glLineWidth(penWidth); + bool opaque = penBrush.isOpaque() && s->opacity > 0.99; + d->setBrush(&penBrush); + d->transferMode(BrushDrawingMode); + + // updateMatrix() is responsible for setting the inverse scale on + // the strokers, so we need to call it here and not wait for + // prepareForDraw() down below. + d->updateMatrix(); + + if (penStyle == Qt::SolidLine) { + d->stroker.process(path, pen); + + } else { // Some sort of dash + d->dasher.process(path, pen); + + QVectorPath dashStroke(d->dasher.points(), + d->dasher.elementCount(), + d->dasher.elementTypes()); + d->stroker.process(dashStroke, pen); + } + + + QGLContext *ctx = d->ctx; + + if (opaque) { + d->prepareForDraw(opaque); + glEnableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, false, 0, d->stroker.vertices()); + glDrawArrays(GL_TRIANGLE_STRIP, 0, d->stroker.vertexCount() / 2); + +// QBrush b(Qt::green); +// d->setBrush(&b); +// d->prepareForDraw(true); +// glDrawArrays(GL_LINE_STRIP, 0, d->stroker.vertexCount() / 2); - d->drawOutline(path); - } else - return QPaintEngineEx::stroke(path, pen); + glDisableVertexAttribArray(QT_VERTEX_COORDS_ATTR); + + } else { + qreal width = qpen_widthf(pen) / 2; + if (width == 0) + width = 0.5; + qreal extra = pen.joinStyle() == Qt::MiterJoin + ? qMax(pen.miterLimit() * width, width) + : width; + + if (pen.isCosmetic()) + extra = extra * d->inverseScale; + + QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); + + d->fillStencilWithVertexArray(d->stroker.vertices(), d->stroker.vertexCount() / 2, + 0, bounds, QGL2PaintEngineExPrivate::TriStripStrokeFillMode); + + glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); + + // Pass when any bit is set, replace stencil value with 0 + glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); + d->prepareForDraw(false); + + // Stencil the brush onto the dest buffer + d->composite(bounds); + + glStencilMask(0); + + d->updateClipScissorTest(); + } + + if (doOffset) { + s->matrix = d->temporaryTransform; + d->matrixDirty = true; + } } void QGL2PaintEngineEx::penChanged() { } @@ -1542,7 +1639,7 @@ void QGL2PaintEngineEx::drawPixmaps(const QDrawPixmaps::Data *drawingData, int d s = qFastSin(drawingData[i].rotation * Q_PI / 180); c = qFastCos(drawingData[i].rotation * Q_PI / 180); } - + qreal right = 0.5 * drawingData[i].scaleX * drawingData[i].source.width(); qreal bottom = 0.5 * drawingData[i].scaleY * drawingData[i].source.height(); QGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h index 5704a04..209cd36 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h @@ -62,6 +62,7 @@ #include #include #include +#include enum EngineMode { ImageDrawingMode, @@ -160,6 +161,12 @@ class QGL2PaintEngineExPrivate : public QPaintEngineExPrivate { Q_DECLARE_PUBLIC(QGL2PaintEngineEx) public: + enum StencilFillMode { + OddEvenFillMode, + WindingFillMode, + TriStripStrokeFillMode + }; + QGL2PaintEngineExPrivate(QGL2PaintEngineEx *q_ptr) : q(q_ptr), width(0), height(0), @@ -185,15 +192,24 @@ public: // fill, drawOutline, drawTexture & drawCachedGlyphs are the rendering entry points: void fill(const QVectorPath &path); - void drawOutline(const QVectorPath& path); void drawTexture(const QGLRect& dest, const QGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); void drawCachedGlyphs(const QPointF &p, QFontEngineGlyphCache::Type glyphType, const QTextItemInt &ti); - void drawVertexArrays(QGL2PEXVertexArray& vertexArray, GLenum primitive); + void drawVertexArrays(const float *data, const QVector *stops, GLenum primitive); + void drawVertexArrays(QGL2PEXVertexArray &vertexArray, GLenum primitive) { + drawVertexArrays((const float *) vertexArray.data(), &vertexArray.stops(), primitive); + } + // ^ draws whatever is in the vertex array void composite(const QGLRect& boundingRect); // ^ Composites the bounding rect onto dest buffer - void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill); + + void fillStencilWithVertexArray(const float *data, int count, const QVector *stops, const QGLRect &bounds, StencilFillMode mode); + void fillStencilWithVertexArray(QGL2PEXVertexArray& vertexArray, bool useWindingFill) { + fillStencilWithVertexArray((const float *) vertexArray.data(), 0, &vertexArray.stops(), + vertexArray.boundingRect(), + useWindingFill ? WindingFillMode : OddEvenFillMode); + } // ^ Calls drawVertexArrays to render into stencil buffer bool prepareForDraw(bool srcPixelsAreOpaque); @@ -266,6 +282,10 @@ public: float textureInvertedY; + QTriangulatingStroker stroker; + QDashedStrokeProcessor dasher; + QTransform temporaryTransform; + QScopedPointer convolutionFilter; QScopedPointer colorizeFilter; QScopedPointer blurFilter; diff --git a/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp new file mode 100644 index 0000000..250dab6 --- /dev/null +++ b/src/opengl/gl2paintengineex/qtriangulatingstroker.cpp @@ -0,0 +1,299 @@ +#include "qtriangulatingstroker_p.h" +#include + + +#define CURVE_FLATNESS Q_PI / 8 + + + + +void QTriangulatingStroker::endCapOrJoinClosed(const qreal *start, const qreal *cur, + bool implicitClose, bool endsAtStart) +{ + if (endsAtStart) { + join(start + 2); + } else if (implicitClose) { + join(start); + lineTo(start); + join(start+2); + } else { + endCap(cur); + } +} + + +void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen) +{ + const qreal *pts = path.points(); + const QPainterPath::ElementType *types = path.elements(); + int count = path.elementCount(); + if (count < 2) + return; + + float realWidth = qpen_widthf(pen); + if (realWidth == 0) + realWidth = 1; + + m_width = realWidth / 2; + + bool cosmetic = pen.isCosmetic(); + if (cosmetic) { + m_width = m_width * m_inv_scale; + } + + m_join_style = qpen_joinStyle(pen); + m_cap_style = qpen_capStyle(pen); + m_vertices.reset(); + m_miter_limit = pen.miterLimit() * qpen_widthf(pen); + + // The curvyness is based on the notion that I originally wanted + // roughly one line segment pr 4 pixels. This may seem little, but + // because we sample at constantly incrementing B(t) E [0(4, realWidth * CURVE_FLATNESS); + } else { + m_curvyness_add = m_width; + m_curvyness_mul = CURVE_FLATNESS / m_inv_scale; + m_roundness = qMax(4, realWidth * m_curvyness_mul); + } + + // Over this level of segmentation, there doesn't seem to be any + // benefit, even for huge penWidth + if (m_roundness > 24) + m_roundness = 24; + + m_sin_theta = qSin(Q_PI / m_roundness); // ### Use qFastSin + m_cos_theta = qCos(Q_PI / m_roundness); + + const qreal *endPts = pts + (count<<1); + const qreal *startPts; + + Qt::PenCapStyle cap = m_cap_style; + + if (!types) { + startPts = pts; + + bool endsAtStart = startPts[0] == *(endPts-2) && startPts[1] == *(endPts-1); + + Qt::PenCapStyle cap = m_cap_style; + if (endsAtStart || path.hasImplicitClose()) + m_cap_style = Qt::FlatCap; + moveTo(pts); + m_cap_style = cap; + pts += 2; + lineTo(pts); + pts += 2; + while (pts < endPts) { + join(pts); + lineTo(pts); + pts += 2; + } + + endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart); + + } else { + bool endsAtStart; + while (pts < endPts) { + switch (*types) { + case QPainterPath::MoveToElement: { + if (pts != path.points()) + endCapOrJoinClosed(startPts, pts, path.hasImplicitClose(), endsAtStart); + + startPts = pts; + int end = (endPts - pts) / 2; + int i = 2; // Start looking to ahead since we never have two moveto's in a row + while (i(64, (rad + m_curvyness_add) * m_curvyness_mul); + if (threshold < 4) + threshold = 4; + qreal threshold_minus_1 = threshold - 1; + float vx, vy; + + float cx = m_cx, cy = m_cy; + float x, y; + + for (int i=1; iaddElement(QPainterPath::MoveToElement, x, y); +} + +static void qdashprocessor_lineTo(qreal x, qreal y, void *data) +{ + ((QDashedStrokeProcessor *) data)->addElement(QPainterPath::LineToElement, x, y); +} + +static void qdashprocessor_cubicTo(qreal, qreal, qreal, qreal, qreal, qreal, void *) +{ + Q_ASSERT(0); // The dasher should not produce curves... +} + +QDashedStrokeProcessor::QDashedStrokeProcessor() + : m_dash_stroker(0), m_inv_scale(1) +{ + m_dash_stroker.setMoveToHook(qdashprocessor_moveTo); + m_dash_stroker.setLineToHook(qdashprocessor_lineTo); + m_dash_stroker.setCubicToHook(qdashprocessor_cubicTo); +} + +void QDashedStrokeProcessor::process(const QVectorPath &path, const QPen &pen) +{ + + const qreal *pts = path.points(); + const QPainterPath::ElementType *types = path.elements(); + int count = path.elementCount(); + + m_points.reset(); + m_types.reset(); + + qreal width = pen.width(); + if (width == 0) + width = 1; + + m_dash_stroker.setDashPattern(pen.dashPattern()); + m_dash_stroker.setStrokeWidth(width); + m_dash_stroker.setMiterLimit(pen.miterLimit()); + qreal curvyness = sqrt(width) * m_inv_scale / 8; + + if (count < 2) + return; + + const qreal *endPts = pts + (count<<1); + + m_dash_stroker.begin(this); + + if (!types) { + m_dash_stroker.moveTo(pts[0], pts[1]); + pts += 2; + while (pts < endPts) { + m_dash_stroker.lineTo(pts[0], pts[1]); + pts += 2; + } + } else { + while (pts < endPts) { + switch (*types) { + case QPainterPath::MoveToElement: + m_dash_stroker.moveTo(pts[0], pts[1]); + pts += 2; + ++types; + break; + case QPainterPath::LineToElement: + m_dash_stroker.lineTo(pts[0], pts[1]); + pts += 2; + ++types; + break; + case QPainterPath::CurveToElement: { + QBezier b = QBezier::fromPoints(*(((const QPointF *) pts) - 1), + *(((const QPointF *) pts)), + *(((const QPointF *) pts) + 1), + *(((const QPointF *) pts) + 2)); + QRectF bounds = b.bounds(); + int threshold = qMin(64, qMax(bounds.width(), bounds.height()) * curvyness); + if (threshold < 4) + threshold = 4; + qreal threshold_minus_1 = threshold - 1; + for (int i=0; i +#include +#include +#include +#include + + +class QTriangulatingStroker +{ +public: + void process(const QVectorPath &path, const QPen &pen); + + inline int vertexCount() const { return m_vertices.size(); } + inline const float *vertices() const { return m_vertices.data(); } + + inline void setInvScale(qreal invScale) { m_inv_scale = invScale; } + +private: + inline void emitLineSegment(float x, float y, float nx, float ny); + inline void moveTo(const qreal *pts); + inline void lineTo(const qreal *pts); + void cubicTo(const qreal *pts); + inline void join(const qreal *pts); + inline void normalVector(float x1, float y1, float x2, float y2, float *nx, float *ny); + inline void endCap(const qreal *pts); + inline void arc(float x, float y); + void endCapOrJoinClosed(const qreal *start, const qreal *cur, bool implicitClose, bool endsAtStart); + + + QDataBuffer m_vertices; + + float m_cx, m_cy; // current points + float m_nvx, m_nvy; // normal vector... + float m_width; + qreal m_miter_limit; + + int m_roundness; // Number of line segments in a round join + qreal m_sin_theta; // sin(m_roundness / 360); + qreal m_cos_theta; // cos(m_roundness / 360); + qreal m_inv_scale; + float m_curvyness_mul; + float m_curvyness_add; + + Qt::PenJoinStyle m_join_style; + Qt::PenCapStyle m_cap_style; +}; + +class QDashedStrokeProcessor +{ +public: + QDashedStrokeProcessor(); + + void process(const QVectorPath &path, const QPen &pen); + + inline void addElement(QPainterPath::ElementType type, qreal x, qreal y) { + m_points.add(x); + m_points.add(y); + m_types.add(type); + } + + inline int elementCount() const { return m_types.size(); } + inline qreal *points() const { return m_points.data(); } + inline QPainterPath::ElementType *elementTypes() const { return m_types.data(); } + + inline void setInvScale(qreal invScale) { m_inv_scale = invScale; } + +private: + QDataBuffer m_points; + QDataBuffer m_types; + QDashStroker m_dash_stroker; + qreal m_inv_scale; +}; + + + + + +inline void QTriangulatingStroker::normalVector(float x1, float y1, float x2, float y2, + float *nx, float *ny) +{ + float dx = x2 - x1; + float dy = y2 - y1; + float pw = m_width / sqrt(dx*dx + dy*dy); + *nx = -dy * pw; + *ny = dx * pw; +} + + + +inline void QTriangulatingStroker::emitLineSegment(float x, float y, float vx, float vy) +{ + m_vertices.add(x + vx); + m_vertices.add(y + vy); + m_vertices.add(x - vx); + m_vertices.add(y - vy); +} + + + +// We draw a full circle for any round join or round cap which is a +// bit of overkill... +inline void QTriangulatingStroker::arc(float x, float y) +{ + float dx = m_width; + float dy = 0; + for (int i=0; i<=m_roundness; ++i) { + float tmpx = dx * m_cos_theta - dy * m_sin_theta; + float tmpy = dx * m_sin_theta + dy * m_cos_theta; + dx = tmpx; + dy = tmpy; + emitLineSegment(x, y, dx, dy); + } +} + + + +inline void QTriangulatingStroker::endCap(const qreal *pts) +{ + switch (m_cap_style) { + case Qt::FlatCap: + break; + case Qt::SquareCap: { + float dx = m_cx - *(pts - 2); + float dy = m_cy - *(pts - 1); + + float len = m_width / sqrt(dx * dx + dy * dy); + dx = dx * len; + dy = dy * len; + + emitLineSegment(m_cx + dx, m_cy + dy, m_nvx, m_nvy); + break; } + case Qt::RoundCap: + arc(m_cx, m_cy); + break; + default: break; // to shut gcc up... + } + + int count = m_vertices.size(); + m_vertices.add(m_vertices.at(count-2)); + m_vertices.add(m_vertices.at(count-1)); +} + + +void QTriangulatingStroker::moveTo(const qreal *pts) +{ + m_cx = pts[0]; + m_cy = pts[1]; + + float x2 = pts[2]; + float y2 = pts[3]; + normalVector(m_cx, m_cy, x2, y2, &m_nvx, &m_nvy); + + + // To acheive jumps we insert zero-area tringles. This is done by + // adding two identical points in both the end of previous strip + // and beginning of next strip + bool invisibleJump = m_vertices.size(); + + switch (m_cap_style) { + case Qt::FlatCap: + if (invisibleJump) { + m_vertices.add(m_cx + m_nvx); + m_vertices.add(m_cy + m_nvy); + } + break; + case Qt::SquareCap: { + float dx = x2 - m_cx; + float dy = y2 - m_cy; + float len = m_width / sqrt(dx * dx + dy * dy); + dx = dx * len; + dy = dy * len; + float sx = m_cx - dx; + float sy = m_cy - dy; + if (invisibleJump) { + m_vertices.add(sx + m_nvx); + m_vertices.add(sy + m_nvy); + } + emitLineSegment(sx, sy, m_nvx, m_nvy); + break; } + case Qt::RoundCap: + if (invisibleJump) { + m_vertices.add(m_cx + m_nvx); + m_vertices.add(m_cy + m_nvy); + } + + // This emitLineSegment is not needed for the arc, but we need + // to start where we put the invisibleJump vertex, otherwise + // we'll have visible triangles between subpaths. + emitLineSegment(m_cx, m_cy, m_nvx, m_nvy); + arc(m_cx, m_cy); + break; + default: break; // ssssh gcc... + } + emitLineSegment(m_cx, m_cy, m_nvx, m_nvy); +} + + + +void QTriangulatingStroker::lineTo(const qreal *pts) +{ + emitLineSegment(pts[0], pts[1], m_nvx, m_nvy); + m_cx = pts[0]; + m_cy = pts[1]; +} + + + + + +void QTriangulatingStroker::join(const qreal *pts) +{ + // Creates a join to the next segment (m_cx, m_cy) -> (pts[0], pts[1]) + normalVector(m_cx, m_cy, pts[0], pts[1], &m_nvx, &m_nvy); + + switch (m_join_style) { + case Qt::BevelJoin: + break; + case Qt::MiterJoin: { + int p1 = m_vertices.size() - 6; + int p2 = m_vertices.size() - 2; + QLineF line(m_vertices.at(p1), m_vertices.at(p1+1), + m_vertices.at(p2), m_vertices.at(p2+1)); + QLineF nextLine(m_cx - m_nvx, m_cy - m_nvy, + pts[0] - m_nvx, pts[1] - m_nvy); + + QPointF isect; + if (line.intersect(nextLine, &isect) != QLineF::NoIntersection + && QLineF(line.p2(), isect).length() <= m_miter_limit) { + // The intersection point mirrored over the m_cx, m_cy point + m_vertices.add(m_cx - (isect.x() - m_cx)); + m_vertices.add(m_cy - (isect.y() - m_cy)); + + // The intersection point + m_vertices.add(isect.x()); + m_vertices.add(isect.y()); + } + // else + // Do a plain bevel join if the miter limit is exceeded or if + // the lines are parallel. This is not what the raster + // engine's stroker does, but it is both faster and similar to + // what some other graphics API's do. + + break; } + case Qt::RoundJoin: + arc(m_cx, m_cy); + break; + + default: break; // gcc warn-- + } + + emitLineSegment(m_cx, m_cy, m_nvx, m_nvy); +} + + +#endif diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index e561932..058016e 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -60,7 +60,8 @@ SOURCES += qgl.cpp \ gl2paintengineex/qgl2pexvertexarray_p.h \ gl2paintengineex/qpaintengineex_opengl2_p.h \ gl2paintengineex/qglengineshadersource_p.h \ - gl2paintengineex/qglcustomshaderstage_p.h + gl2paintengineex/qglcustomshaderstage_p.h \ + gl2paintengineex/qtriangulatingstroker_p.h SOURCES += qglshaderprogram.cpp \ qglpixmapfilter.cpp \ @@ -72,7 +73,8 @@ SOURCES += qgl.cpp \ gl2paintengineex/qglengineshadermanager.cpp \ gl2paintengineex/qgl2pexvertexarray.cpp \ gl2paintengineex/qpaintengineex_opengl2.cpp \ - gl2paintengineex/qglcustomshaderstage.cpp + gl2paintengineex/qglcustomshaderstage.cpp \ + gl2paintengineex/qtriangulatingstroker.cpp } -- cgit v0.12 From e2296ba010100d007a081e0faac8066adbeb7137 Mon Sep 17 00:00:00 2001 From: Tom Cooksey Date: Fri, 2 Oct 2009 11:13:30 +0200 Subject: Stop QEglContext destroying contexts it doesn't own Reviewed-By: Rhys Weatherley --- src/gui/egl/qegl.cpp | 3 ++- src/gui/egl/qegl_p.h | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp index 840b9d6..39291d3 100644 --- a/src/gui/egl/qegl.cpp +++ b/src/gui/egl/qegl.cpp @@ -61,6 +61,7 @@ QEglContext::QEglContext() , cfg(0) , currentSurface(EGL_NO_SURFACE) , current(false) + , ownsContext(true) { } @@ -206,7 +207,7 @@ void QEglContext::destroySurface(EGLSurface surface) // Destroy the context. Note: this does not destroy the surface. void QEglContext::destroy() { - if (ctx != EGL_NO_CONTEXT) + if (ctx != EGL_NO_CONTEXT && ownsContext) eglDestroyContext(dpy, ctx); dpy = EGL_NO_DISPLAY; ctx = EGL_NO_CONTEXT; diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h index dc399da..16b5b16 100644 --- a/src/gui/egl/qegl_p.h +++ b/src/gui/egl/qegl_p.h @@ -110,7 +110,7 @@ public: EGLDisplay display() const { return dpy; } EGLContext context() const { return ctx; } - void setContext(EGLContext context) { ctx = context; } + void setContext(EGLContext context) { ctx = context; ownsContext = false;} EGLConfig config() const { return cfg; } void setConfig(EGLConfig config) { cfg = config; } @@ -131,6 +131,7 @@ private: EGLConfig cfg; EGLSurface currentSurface; bool current; + bool ownsContext; static EGLDisplay getDisplay(QPaintDevice *device); -- cgit v0.12 From 22b9079040ae0d4f35781509fa6aea7e38ac47bb Mon Sep 17 00:00:00 2001 From: Tom Cooksey Date: Mon, 12 Oct 2009 15:39:52 +0200 Subject: Separate modification & destruction pixmap cleanup hooks Before the QExplicitlySharedDataPointer change, the ref-count was 0 when calling the cleanup hooks from ~QPixmap. That enabled the hook to figure out if the pixmap is being modified or deleted. As the ref count is now 1 when calling the cleanup hooks in ~QPixmap, we need to seperate the hooks. This change should make using textre-from-pixmap faster as the EGL/glX surface wont get re-created everytime the pixmap is modified. Reviewed-By: Gunnar --- src/gui/image/qimagepixmapcleanuphooks.cpp | 35 ++++++++++++++++++++++++------ src/gui/image/qimagepixmapcleanuphooks_p.h | 17 +++++++++++---- src/gui/image/qpixmap.cpp | 7 +++--- src/opengl/qgl.cpp | 21 ++++++++++++++---- src/opengl/qgl_p.h | 6 ++++- 5 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/gui/image/qimagepixmapcleanuphooks.cpp b/src/gui/image/qimagepixmapcleanuphooks.cpp index d08d3ef..138eb0d 100644 --- a/src/gui/image/qimagepixmapcleanuphooks.cpp +++ b/src/gui/image/qimagepixmapcleanuphooks.cpp @@ -70,19 +70,30 @@ QImagePixmapCleanupHooks *QImagePixmapCleanupHooks::instance() return qt_image_and_pixmap_cleanup_hooks; } -void QImagePixmapCleanupHooks::addPixmapHook(_qt_pixmap_cleanup_hook_pm hook) +void QImagePixmapCleanupHooks::addPixmapModificationHook(_qt_pixmap_cleanup_hook_pm hook) { - pixmapHooks.append(hook); + pixmapModificationHooks.append(hook); } +void QImagePixmapCleanupHooks::addPixmapDestructionHook(_qt_pixmap_cleanup_hook_pm hook) +{ + pixmapDestructionHooks.append(hook); +} + + void QImagePixmapCleanupHooks::addImageHook(_qt_image_cleanup_hook_64 hook) { imageHooks.append(hook); } -void QImagePixmapCleanupHooks::removePixmapHook(_qt_pixmap_cleanup_hook_pm hook) +void QImagePixmapCleanupHooks::removePixmapModificationHook(_qt_pixmap_cleanup_hook_pm hook) +{ + pixmapModificationHooks.removeAll(hook); +} + +void QImagePixmapCleanupHooks::removePixmapDestructionHook(_qt_pixmap_cleanup_hook_pm hook) { - pixmapHooks.removeAll(hook); + pixmapDestructionHooks.removeAll(hook); } void QImagePixmapCleanupHooks::removeImageHook(_qt_image_cleanup_hook_64 hook) @@ -91,15 +102,25 @@ void QImagePixmapCleanupHooks::removeImageHook(_qt_image_cleanup_hook_64 hook) } -void QImagePixmapCleanupHooks::executePixmapHooks(QPixmap* pm) +void QImagePixmapCleanupHooks::executePixmapModificationHooks(QPixmap* pm) { - for (int i = 0; i < qt_image_and_pixmap_cleanup_hooks->pixmapHooks.count(); ++i) - qt_image_and_pixmap_cleanup_hooks->pixmapHooks[i](pm); + Q_ASSERT(qt_image_and_pixmap_cleanup_hooks); + for (int i = 0; i < qt_image_and_pixmap_cleanup_hooks->pixmapModificationHooks.count(); ++i) + qt_image_and_pixmap_cleanup_hooks->pixmapModificationHooks[i](pm); if (qt_pixmap_cleanup_hook_64) qt_pixmap_cleanup_hook_64(pm->cacheKey()); } +void QImagePixmapCleanupHooks::executePixmapDestructionHooks(QPixmap* pm) +{ + Q_ASSERT(qt_image_and_pixmap_cleanup_hooks); + for (int i = 0; i < qt_image_and_pixmap_cleanup_hooks->pixmapDestructionHooks.count(); ++i) + qt_image_and_pixmap_cleanup_hooks->pixmapDestructionHooks[i](pm); + + if (qt_pixmap_cleanup_hook_64) + qt_pixmap_cleanup_hook_64(pm->cacheKey()); +} void QImagePixmapCleanupHooks::executeImageHooks(qint64 key) { diff --git a/src/gui/image/qimagepixmapcleanuphooks_p.h b/src/gui/image/qimagepixmapcleanuphooks_p.h index dd2d0f7..16c8974 100644 --- a/src/gui/image/qimagepixmapcleanuphooks_p.h +++ b/src/gui/image/qimagepixmapcleanuphooks_p.h @@ -70,18 +70,27 @@ public: static QImagePixmapCleanupHooks *instance(); - void addPixmapHook(_qt_pixmap_cleanup_hook_pm); + // Gets called when a pixmap is about to be modified: + void addPixmapModificationHook(_qt_pixmap_cleanup_hook_pm); + + // Gets called when a pixmap is about to be destroyed: + void addPixmapDestructionHook(_qt_pixmap_cleanup_hook_pm); + + // Gets called when an image is about to be modified or destroyed: void addImageHook(_qt_image_cleanup_hook_64); - void removePixmapHook(_qt_pixmap_cleanup_hook_pm); + void removePixmapModificationHook(_qt_pixmap_cleanup_hook_pm); + void removePixmapDestructionHook(_qt_pixmap_cleanup_hook_pm); void removeImageHook(_qt_image_cleanup_hook_64); - static void executePixmapHooks(QPixmap*); + static void executePixmapModificationHooks(QPixmap*); + static void executePixmapDestructionHooks(QPixmap*); static void executeImageHooks(qint64 key); private: QList<_qt_image_cleanup_hook_64> imageHooks; - QList<_qt_pixmap_cleanup_hook_pm> pixmapHooks; + QList<_qt_pixmap_cleanup_hook_pm> pixmapModificationHooks; + QList<_qt_pixmap_cleanup_hook_pm> pixmapDestructionHooks; }; QT_END_NAMESPACE diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp index bf6c9ae..f94552d 100644 --- a/src/gui/image/qpixmap.cpp +++ b/src/gui/image/qpixmap.cpp @@ -322,8 +322,9 @@ QPixmap::QPixmap(const char * const xpm[]) QPixmap::~QPixmap() { - if (data->is_cached && data->ref == 1) - QImagePixmapCleanupHooks::executePixmapHooks(this); + Q_ASSERT(data->ref >= 1); // Catch if ref-counting changes again + if (data->is_cached && data->ref == 1) // ref will be decrememnted after destructor returns + QImagePixmapCleanupHooks::executePixmapDestructionHooks(this); } /*! @@ -1917,7 +1918,7 @@ void QPixmap::detach() } if (data->is_cached && data->ref == 1) - QImagePixmapCleanupHooks::executePixmapHooks(this); + QImagePixmapCleanupHooks::executePixmapModificationHooks(this); #if defined(Q_WS_MAC) QMacPixmapData *macData = id == QPixmapData::MacClass ? static_cast(data.data()) : 0; diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 39f04d4..97e3dad 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -1584,7 +1584,10 @@ QGLTextureCache::QGLTextureCache() Q_ASSERT(qt_gl_texture_cache == 0); qt_gl_texture_cache = this; - QImagePixmapCleanupHooks::instance()->addPixmapHook(pixmapCleanupHook); + QImagePixmapCleanupHooks::instance()->addPixmapModificationHook(cleanupTextures); +#ifdef Q_WS_X11 + QImagePixmapCleanupHooks::instance()->addPixmapDestructionHook(cleanupPixmapSurfaces); +#endif QImagePixmapCleanupHooks::instance()->addImageHook(imageCleanupHook); } @@ -1592,7 +1595,10 @@ QGLTextureCache::~QGLTextureCache() { qt_gl_texture_cache = 0; - QImagePixmapCleanupHooks::instance()->removePixmapHook(pixmapCleanupHook); + QImagePixmapCleanupHooks::instance()->removePixmapModificationHook(cleanupTextures); +#ifdef Q_WS_X11 + QImagePixmapCleanupHooks::instance()->removePixmapDestructionHook(cleanupPixmapSurfaces); +#endif QImagePixmapCleanupHooks::instance()->removeImageHook(imageCleanupHook); } @@ -1660,7 +1666,7 @@ void QGLTextureCache::imageCleanupHook(qint64 cacheKey) } -void QGLTextureCache::pixmapCleanupHook(QPixmap* pixmap) +void QGLTextureCache::cleanupTextures(QPixmap* pixmap) { // ### remove when the GL texture cache becomes thread-safe if (qApp->thread() == QThread::currentThread()) { @@ -1669,14 +1675,21 @@ void QGLTextureCache::pixmapCleanupHook(QPixmap* pixmap) if (texture && texture->options & QGLContext::MemoryManagedBindOption) instance()->remove(cacheKey); } +} + #if defined(Q_WS_X11) +void QGLTextureCache::cleanupPixmapSurfaces(QPixmap* pixmap) +{ + // Remove any bound textures first: + cleanupTextures(pixmap); + QPixmapData *pd = pixmap->data_ptr().data(); if (pd->classId() == QPixmapData::X11Class) { Q_ASSERT(pd->ref == 1); // Make sure reference counting isn't broken QGLContextPrivate::destroyGlSurfaceForPixmap(pd); } -#endif } +#endif void QGLTextureCache::deleteIfEmpty() { diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h index 129e7f7..9a17c67 100644 --- a/src/opengl/qgl_p.h +++ b/src/opengl/qgl_p.h @@ -498,7 +498,11 @@ public: static QGLTextureCache *instance(); static void deleteIfEmpty(); static void imageCleanupHook(qint64 cacheKey); - static void pixmapCleanupHook(QPixmap* pixmap); + static void cleanupTextures(QPixmap* pixmap); +#ifdef Q_WS_X11 + // X11 needs to catch pixmap data destruction to delete EGL/GLX pixmap surfaces + static void cleanupPixmapSurfaces(QPixmap* pixmap); +#endif private: QCache m_cache; -- cgit v0.12 From 0d0cba294980c5fbb26a2fd3e930c94606e93d03 Mon Sep 17 00:00:00 2001 From: Tom Cooksey Date: Tue, 13 Oct 2009 14:21:51 +0200 Subject: Add a new QX11GLPixmapData which renders to X pixmaps using GL Enable it by setting QT_USE_X11GL_PIXMAPS environment variable while using the -graphicssystem opengl --- src/gui/image/qpixmap_x11_p.h | 1 + src/gui/painting/qpaintengine.h | 1 + src/opengl/opengl.pro | 7 +- src/opengl/qgl.h | 1 + src/opengl/qgl_x11egl.cpp | 5 +- src/opengl/qglpaintdevice.cpp | 14 ++- src/opengl/qgraphicssystem_gl.cpp | 9 ++ src/opengl/qpixmapdata_x11gl_egl.cpp | 183 +++++++++++++++++++++++++++++++++++ src/opengl/qpixmapdata_x11gl_p.h | 88 +++++++++++++++++ 9 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 src/opengl/qpixmapdata_x11gl_egl.cpp create mode 100644 src/opengl/qpixmapdata_x11gl_p.h diff --git a/src/gui/image/qpixmap_x11_p.h b/src/gui/image/qpixmap_x11_p.h index 2d6672d..8ce7c0d 100644 --- a/src/gui/image/qpixmap_x11_p.h +++ b/src/gui/image/qpixmap_x11_p.h @@ -103,6 +103,7 @@ private: friend class QRasterWindowSurface; friend class QGLContextPrivate; // Needs to access xinfo, gl_surface & flags friend class QEglContext; // Needs gl_surface + friend class QX11GLPixmapData; // Needs gl_surface friend bool qt_createEGLSurfaceForPixmap(QPixmapData*, bool); // Needs gl_surface void release(); diff --git a/src/gui/painting/qpaintengine.h b/src/gui/painting/qpaintengine.h index 5b82e7b..bf4b4ea 100644 --- a/src/gui/painting/qpaintengine.h +++ b/src/gui/painting/qpaintengine.h @@ -278,6 +278,7 @@ private: friend class QWin32PaintEnginePrivate; friend class QMacCGContext; friend class QPreviewPaintEngine; + friend class QX11GLPixmapData; }; diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 058016e..961c781 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -82,9 +82,12 @@ x11 { contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, opengles1cl)|contains(QT_CONFIG, opengles2) { SOURCES += qgl_x11egl.cpp \ qglpixelbuffer_egl.cpp \ - qgl_egl.cpp + qgl_egl.cpp \ + qpixmapdata_x11gl_egl.cpp + + HEADERS += qgl_egl_p.h \ + qpixmapdata_x11gl_p.h - HEADERS += qgl_egl_p.h } else { SOURCES += qgl_x11.cpp \ diff --git a/src/opengl/qgl.h b/src/opengl/qgl.h index b1c1317..e14e7fb 100644 --- a/src/opengl/qgl.h +++ b/src/opengl/qgl.h @@ -411,6 +411,7 @@ private: friend class QGLFramebufferObjectPrivate; friend class QGLFBOGLPaintDevice; friend class QGLPaintDevice; + friend class QX11GLPixmapData; private: Q_DISABLE_COPY(QGLContext) }; diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index 971a660..fb08741 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -513,8 +513,11 @@ bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnl pixmapConfig, (EGLNativePixmapType) pixmapData->handle(), pixmapAttribs.properties()); +// qDebug("qt_createEGLSurfaceForPixmap() created surface 0x%x for pixmap 0x%x", +// pixmapSurface, pixmapData->handle()); if (pixmapSurface == EGL_NO_SURFACE) { - qWarning("Failed to create a pixmap surface using config %d", (int)pixmapConfig); + qWarning() << "Failed to create a pixmap surface using config" << (int)pixmapConfig + << ":" << QEglContext::errorString(eglGetError()); return false; } diff --git a/src/opengl/qglpaintdevice.cpp b/src/opengl/qglpaintdevice.cpp index e68a4b9..2867de5 100644 --- a/src/opengl/qglpaintdevice.cpp +++ b/src/opengl/qglpaintdevice.cpp @@ -44,6 +44,9 @@ #include #include #include +#ifdef Q_WS_X11 +#include +#endif #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) #include @@ -81,6 +84,7 @@ void QGLPaintDevice::beginPaint() // explicitly unbind. Otherwise the painting will go into // the previous FBO instead of to the window. m_previousFBO = ctx->d_func()->current_fbo; + if (m_previousFBO != m_thisFBO) { ctx->d_ptr->current_fbo = m_thisFBO; glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_thisFBO); @@ -186,8 +190,14 @@ QGLPaintDevice* QGLPaintDevice::getDevice(QPaintDevice* pd) case QInternal::Pixmap: { #if !defined(QT_OPENGL_ES_1) && !defined(QT_OPENGL_ES_1_CL) QPixmapData* pmd = static_cast(pd)->pixmapData(); - Q_ASSERT(pmd->classId() == QPixmapData::OpenGLClass); - glpd = static_cast(pmd)->glDevice(); + if (pmd->classId() == QPixmapData::OpenGLClass) + glpd = static_cast(pmd)->glDevice(); +#ifdef Q_WS_X11 + else if (pmd->classId() == QPixmapData::X11Class) + glpd = static_cast(pmd); +#endif + else + qWarning("Pixmap type not supported for GL rendering"); #else qWarning("Pixmap render targets not supported on OpenGL ES 1.x"); #endif diff --git a/src/opengl/qgraphicssystem_gl.cpp b/src/opengl/qgraphicssystem_gl.cpp index 3e7fece..60d58a7 100644 --- a/src/opengl/qgraphicssystem_gl.cpp +++ b/src/opengl/qgraphicssystem_gl.cpp @@ -47,12 +47,21 @@ #include "private/qgl_p.h" #include +#ifdef Q_WS_X11 +#include "private/qpixmapdata_x11gl_p.h" +#endif + QT_BEGIN_NAMESPACE extern QGLWidget *qt_gl_getShareWidget(); QPixmapData *QGLGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const { +#ifdef Q_WS_X11 + if (type == QPixmapData::PixmapType && QX11GLPixmapData::hasX11GLPixmaps()) + return new QX11GLPixmapData(); +#endif + return new QGLPixmapData(type); } diff --git a/src/opengl/qpixmapdata_x11gl_egl.cpp b/src/opengl/qpixmapdata_x11gl_egl.cpp new file mode 100644 index 0000000..1590ba5 --- /dev/null +++ b/src/opengl/qpixmapdata_x11gl_egl.cpp @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include + +#include "qpixmapdata_x11gl_p.h" + +QT_BEGIN_NAMESPACE + +extern EGLConfig qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly); // in qgl_x11egl.cpp +extern bool qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly); // in qgl_x11egl.cpp + +static EGLContext qPixmapSharedEglContext = EGL_NO_CONTEXT; + +void QX11GLPixmapData::createPixmapSharedContext(EGLConfig config) +{ + eglBindAPI(EGL_OPENGL_ES_API); + EGLint contextAttribs[] = { +#if defined(QT_OPENGL_ES_2) + EGL_CONTEXT_CLIENT_VERSION, 2, +#endif + EGL_NONE + }; + qPixmapSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0), config, 0, contextAttribs); +// qDebug("QX11GLPixmapData::createPixmapSharedContext() Created ctx 0x%x for config %d", qPixmapSharedEglContext, config); +} + +bool QX11GLPixmapData::hasX11GLPixmaps() +{ + static bool checkedForX11Pixmaps = false; + static bool haveX11Pixmaps = false; + + if (checkedForX11Pixmaps) + return haveX11Pixmaps; + + checkedForX11Pixmaps = true; + + do { + if (qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty()) + break; + + // First, check we actually have an EGL config which supports pixmaps + EGLConfig config = qt_chooseEGLConfigForPixmap(true, false); + if (config == 0) + break; + + // Now try to actually create an EGL pixmap surface + QX11PixmapData *pd = new QX11PixmapData(QPixmapData::PixmapType); + pd->resize(100, 100); + bool success = qt_createEGLSurfaceForPixmap(pd, false); + if (!success) + break; + + createPixmapSharedContext(config); + + haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0), + (EGLSurface)pd->gl_surface, (EGLSurface)pd->gl_surface, + qPixmapSharedEglContext); + + eglMakeCurrent(QEglContext::defaultDisplay(0), + EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + QGLContextPrivate::destroyGlSurfaceForPixmap(pd); + delete pd; + } while (0); + + if (haveX11Pixmaps) + qDebug("QX11GLPixmapData is supported"); + + return haveX11Pixmaps; +} + +QX11GLPixmapData::QX11GLPixmapData() + : QX11PixmapData(QPixmapData::PixmapType), + ctx(0) +{ +} + +QX11GLPixmapData::~QX11GLPixmapData() +{ +} + +static QGL2PaintEngineEx* qt_gl2_engine_for_pixmaps = 0; + +QPaintEngine* QX11GLPixmapData::paintEngine() const +{ + // We need to create the context before beginPaint - do it here: + if (!ctx) { + ctx = new QGLContext(glFormat()); + if (ctx->d_func()->eglContext == 0) + ctx->d_func()->eglContext = new QEglContext(); + ctx->d_func()->eglContext->openDisplay(0); // ;-) + ctx->d_func()->eglContext->setApi(QEgl::OpenGL); + ctx->d_func()->eglContext->setContext(qPixmapSharedEglContext); + } + + if (!qt_gl2_engine_for_pixmaps) + qt_gl2_engine_for_pixmaps = new QGL2PaintEngineEx(); + + // Support multiple painters on multiple pixmaps simultaniously + if (qt_gl2_engine_for_pixmaps->isActive()) { + QPaintEngine* engine = new QGL2PaintEngineEx(); + engine->setAutoDestruct(true); + return engine; + } + + return qt_gl2_engine_for_pixmaps; +} + +void QX11GLPixmapData::beginPaint() +{ + if ((EGLSurface)gl_surface == EGL_NO_SURFACE) { + qt_createEGLSurfaceForPixmap(this, false); + ctx->d_func()->eglSurface = (EGLSurface)gl_surface; + ctx->d_func()->valid = true; // ;-) + } + + QGLPaintDevice::beginPaint(); +} + +void QX11GLPixmapData::endPaint() +{ + glFinish(); + QGLPaintDevice::endPaint(); +} + +QGLContext* QX11GLPixmapData::context() const +{ + return ctx; +} + +QSize QX11GLPixmapData::size() const +{ + return QSize(w, h); +} + + +QGLFormat QX11GLPixmapData::glFormat() +{ + return QGLFormat::defaultFormat(); //### +} + +QT_END_NAMESPACE diff --git a/src/opengl/qpixmapdata_x11gl_p.h b/src/opengl/qpixmapdata_x11gl_p.h new file mode 100644 index 0000000..3e09ba9 --- /dev/null +++ b/src/opengl/qpixmapdata_x11gl_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QPIXMAPDATA_X11GL_P_H +#define QPIXMAPDATA_X11GL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QX11GLPixmapData : public QX11PixmapData, public QGLPaintDevice +{ +public: + QX11GLPixmapData(); + virtual ~QX11GLPixmapData(); + + // Re-implemented from QGLPaintDevice + QPaintEngine* paintEngine() const; // Also re-implements QX11PixmapData::paintEngine + void beginPaint(); + void endPaint(); + QGLContext* context() const; + QSize size() const; + + + static bool hasX11GLPixmaps(); + static QGLFormat glFormat(); +private: + static void createPixmapSharedContext(EGLConfig config); + mutable QGLContext* ctx; +}; + + +QT_END_NAMESPACE + +#endif // QPIXMAPDATA_X11GL_P_H -- cgit v0.12 From 8e6c1d52ed9c233e753fc93bec93c8d909c95002 Mon Sep 17 00:00:00 2001 From: Tom Cooksey Date: Wed, 14 Oct 2009 14:25:09 +0200 Subject: Add an assert testing the cleanup hooks exist before executing them Reviewed-By: TrustMe --- src/gui/image/qimagepixmapcleanuphooks.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/image/qimagepixmapcleanuphooks.cpp b/src/gui/image/qimagepixmapcleanuphooks.cpp index 138eb0d..ac30646 100644 --- a/src/gui/image/qimagepixmapcleanuphooks.cpp +++ b/src/gui/image/qimagepixmapcleanuphooks.cpp @@ -124,6 +124,7 @@ void QImagePixmapCleanupHooks::executePixmapDestructionHooks(QPixmap* pm) void QImagePixmapCleanupHooks::executeImageHooks(qint64 key) { + Q_ASSERT(qt_image_and_pixmap_cleanup_hooks); for (int i = 0; i < qt_image_and_pixmap_cleanup_hooks->imageHooks.count(); ++i) qt_image_and_pixmap_cleanup_hooks->imageHooks[i](key); -- cgit v0.12 From 34e25637f11972c848f78757fe023a9b1360edc9 Mon Sep 17 00:00:00 2001 From: Tom Cooksey Date: Mon, 19 Oct 2009 13:30:50 +0200 Subject: Use different GL contexts for ARGB & RGB pixmaps On 16 bpp systems, RGB pixmaps are 16-bit whereas ARGB pixmaps are 32-bit. This means two different EGL configs are used which are incompatable with each other. As a result, we have to use 2 different EGL contexts - one for each config. Reviewed-By: Trustme --- src/opengl/qpixmapdata_x11gl_egl.cpp | 131 ++++++++++++++++++++++++++--------- 1 file changed, 100 insertions(+), 31 deletions(-) diff --git a/src/opengl/qpixmapdata_x11gl_egl.cpp b/src/opengl/qpixmapdata_x11gl_egl.cpp index 1590ba5..813e6c8 100644 --- a/src/opengl/qpixmapdata_x11gl_egl.cpp +++ b/src/opengl/qpixmapdata_x11gl_egl.cpp @@ -51,20 +51,10 @@ QT_BEGIN_NAMESPACE extern EGLConfig qt_chooseEGLConfigForPixmap(bool hasAlpha, bool readOnly); // in qgl_x11egl.cpp extern bool qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnly); // in qgl_x11egl.cpp -static EGLContext qPixmapSharedEglContext = EGL_NO_CONTEXT; - -void QX11GLPixmapData::createPixmapSharedContext(EGLConfig config) -{ - eglBindAPI(EGL_OPENGL_ES_API); - EGLint contextAttribs[] = { -#if defined(QT_OPENGL_ES_2) - EGL_CONTEXT_CLIENT_VERSION, 2, -#endif - EGL_NONE - }; - qPixmapSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0), config, 0, contextAttribs); -// qDebug("QX11GLPixmapData::createPixmapSharedContext() Created ctx 0x%x for config %d", qPixmapSharedEglContext, config); -} +// On 16bpp systems, RGB & ARGB pixmaps are different bit-depths and therefore need +// different contexts: +static EGLContext qPixmapARGBSharedEglContext = EGL_NO_CONTEXT; +static EGLContext qPixmapRGBSharedEglContext = EGL_NO_CONTEXT; bool QX11GLPixmapData::hasX11GLPixmaps() { @@ -76,36 +66,113 @@ bool QX11GLPixmapData::hasX11GLPixmaps() checkedForX11Pixmaps = true; + QX11PixmapData *argbPixmapData = 0; + QX11PixmapData *rgbPixmapData = 0; do { if (qgetenv("QT_USE_X11GL_PIXMAPS").isEmpty()) break; - // First, check we actually have an EGL config which supports pixmaps - EGLConfig config = qt_chooseEGLConfigForPixmap(true, false); - if (config == 0) - break; + // Check we actually have EGL configs which support pixmaps + EGLConfig argbConfig = qt_chooseEGLConfigForPixmap(true, false); + EGLConfig rgbConfig = qt_chooseEGLConfigForPixmap(false, false); - // Now try to actually create an EGL pixmap surface - QX11PixmapData *pd = new QX11PixmapData(QPixmapData::PixmapType); - pd->resize(100, 100); - bool success = qt_createEGLSurfaceForPixmap(pd, false); - if (!success) + if (argbConfig == 0 || rgbConfig == 0) break; - createPixmapSharedContext(config); + // Create the shared contexts: + eglBindAPI(EGL_OPENGL_ES_API); + EGLint contextAttribs[] = { +#if defined(QT_OPENGL_ES_2) + EGL_CONTEXT_CLIENT_VERSION, 2, +#endif + EGL_NONE + }; + qPixmapARGBSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0), + argbConfig, 0, contextAttribs); + + if (argbConfig == rgbConfig) { + // If the configs are the same, we can re-use the same context. + qPixmapRGBSharedEglContext = qPixmapARGBSharedEglContext; + } else { + qPixmapRGBSharedEglContext = eglCreateContext(QEglContext::defaultDisplay(0), + rgbConfig, 0, contextAttribs); + } + + argbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); + argbPixmapData->resize(100, 100); + argbPixmapData->fill(Qt::transparent); // Force ARGB + + if (!qt_createEGLSurfaceForPixmap(argbPixmapData, false)) + break; haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0), - (EGLSurface)pd->gl_surface, (EGLSurface)pd->gl_surface, - qPixmapSharedEglContext); + (EGLSurface)argbPixmapData->gl_surface, + (EGLSurface)argbPixmapData->gl_surface, + qPixmapARGBSharedEglContext); + if (!haveX11Pixmaps) { + EGLint err = eglGetError(); + qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err); + break; + } + + // If the ARGB & RGB configs are the same, we don't need to check RGB too + if (haveX11Pixmaps && (argbConfig != rgbConfig)) { + rgbPixmapData = new QX11PixmapData(QPixmapData::PixmapType); + rgbPixmapData->resize(100, 100); + rgbPixmapData->fill(Qt::red); + + // Try to actually create an EGL pixmap surface + if (!qt_createEGLSurfaceForPixmap(rgbPixmapData, false)) + break; + + haveX11Pixmaps = eglMakeCurrent(QEglContext::defaultDisplay(0), + (EGLSurface)rgbPixmapData->gl_surface, + (EGLSurface)rgbPixmapData->gl_surface, + qPixmapRGBSharedEglContext); + if (!haveX11Pixmaps) { + EGLint err = eglGetError(); + qWarning() << "Unable to make pixmap config current:" << err << QEglContext::errorString(err); + break; + } + } + } while (0); + if (qPixmapARGBSharedEglContext || qPixmapRGBSharedEglContext) { eglMakeCurrent(QEglContext::defaultDisplay(0), EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - QGLContextPrivate::destroyGlSurfaceForPixmap(pd); - delete pd; - } while (0); + } + + if (argbPixmapData) { + if (argbPixmapData->gl_surface) + QGLContextPrivate::destroyGlSurfaceForPixmap(argbPixmapData); + delete argbPixmapData; + argbPixmapData = 0; + } + if (rgbPixmapData) { + if (rgbPixmapData->gl_surface) + QGLContextPrivate::destroyGlSurfaceForPixmap(rgbPixmapData); + delete rgbPixmapData; + rgbPixmapData = 0; + } + + if (!haveX11Pixmaps) { + // Clean up the context(s) if we can't use X11GL pixmaps + if (qPixmapARGBSharedEglContext != EGL_NO_CONTEXT) + eglDestroyContext(QEglContext::defaultDisplay(0), qPixmapARGBSharedEglContext); + + if (qPixmapRGBSharedEglContext != qPixmapARGBSharedEglContext && + qPixmapRGBSharedEglContext != EGL_NO_CONTEXT) + { + eglDestroyContext(QEglContext::defaultDisplay(0), qPixmapRGBSharedEglContext); + } + qPixmapRGBSharedEglContext = EGL_NO_CONTEXT; + qPixmapARGBSharedEglContext = EGL_NO_CONTEXT; + } if (haveX11Pixmaps) qDebug("QX11GLPixmapData is supported"); + else + qDebug("QX11GLPixmapData is *NOT* being used"); return haveX11Pixmaps; } @@ -131,7 +198,8 @@ QPaintEngine* QX11GLPixmapData::paintEngine() const ctx->d_func()->eglContext = new QEglContext(); ctx->d_func()->eglContext->openDisplay(0); // ;-) ctx->d_func()->eglContext->setApi(QEgl::OpenGL); - ctx->d_func()->eglContext->setContext(qPixmapSharedEglContext); + ctx->d_func()->eglContext->setContext(hasAlphaChannel() ? qPixmapARGBSharedEglContext + : qPixmapRGBSharedEglContext); } if (!qt_gl2_engine_for_pixmaps) @@ -139,6 +207,7 @@ QPaintEngine* QX11GLPixmapData::paintEngine() const // Support multiple painters on multiple pixmaps simultaniously if (qt_gl2_engine_for_pixmaps->isActive()) { + qWarning("Pixmap paint engine already active"); QPaintEngine* engine = new QGL2PaintEngineEx(); engine->setAutoDestruct(true); return engine; @@ -149,12 +218,12 @@ QPaintEngine* QX11GLPixmapData::paintEngine() const void QX11GLPixmapData::beginPaint() { +// qDebug("QX11GLPixmapData::beginPaint()"); if ((EGLSurface)gl_surface == EGL_NO_SURFACE) { qt_createEGLSurfaceForPixmap(this, false); ctx->d_func()->eglSurface = (EGLSurface)gl_surface; ctx->d_func()->valid = true; // ;-) } - QGLPaintDevice::beginPaint(); } -- cgit v0.12 From 43b3307bebb9600954e48b0a3b341d5d9b2b26de Mon Sep 17 00:00:00 2001 From: Tom Cooksey Date: Tue, 20 Oct 2009 08:57:39 +0200 Subject: Fix build on desktop X11 Hash-Define out X11GL pixmap data until the GLX implementation is ready. --- src/opengl/qgraphicssystem_gl.cpp | 2 +- src/opengl/qpixmapdata_x11gl_p.h | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/opengl/qgraphicssystem_gl.cpp b/src/opengl/qgraphicssystem_gl.cpp index 60d58a7..0ee1e82 100644 --- a/src/opengl/qgraphicssystem_gl.cpp +++ b/src/opengl/qgraphicssystem_gl.cpp @@ -57,7 +57,7 @@ extern QGLWidget *qt_gl_getShareWidget(); QPixmapData *QGLGraphicsSystem::createPixmapData(QPixmapData::PixelType type) const { -#ifdef Q_WS_X11 +#if defined(Q_WS_X11) && defined(QT_OPENGL_ES) if (type == QPixmapData::PixmapType && QX11GLPixmapData::hasX11GLPixmaps()) return new QX11GLPixmapData(); #endif diff --git a/src/opengl/qpixmapdata_x11gl_p.h b/src/opengl/qpixmapdata_x11gl_p.h index 3e09ba9..bba9bb3 100644 --- a/src/opengl/qpixmapdata_x11gl_p.h +++ b/src/opengl/qpixmapdata_x11gl_p.h @@ -74,11 +74,9 @@ public: QGLContext* context() const; QSize size() const; - static bool hasX11GLPixmaps(); static QGLFormat glFormat(); private: - static void createPixmapSharedContext(EGLConfig config); mutable QGLContext* ctx; }; -- cgit v0.12 From 9d91a56ad5e39ddb237e10819a371e78defdf359 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 19 Oct 2009 16:23:47 +0200 Subject: Backport benchmarks/qnetworkreply to 4.5 Reviewed-by: TrustMe --- tests/benchmarks/benchmarks.pro | 1 + tests/benchmarks/qnetworkreply/qnetworkreply.pro | 13 ++++ .../benchmarks/qnetworkreply/tst_qnetworkreply.cpp | 74 ++++++++++++++++++++++ 3 files changed, 88 insertions(+) create mode 100644 tests/benchmarks/qnetworkreply/qnetworkreply.pro create mode 100644 tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp diff --git a/tests/benchmarks/benchmarks.pro b/tests/benchmarks/benchmarks.pro index 8e2c243..fb2b9ea 100644 --- a/tests/benchmarks/benchmarks.pro +++ b/tests/benchmarks/benchmarks.pro @@ -8,6 +8,7 @@ SUBDIRS = containers-associative \ qpixmap \ blendbench \ qstringlist \ + qnetworkreply \ qobject \ qrect \ qregexp \ diff --git a/tests/benchmarks/qnetworkreply/qnetworkreply.pro b/tests/benchmarks/qnetworkreply/qnetworkreply.pro new file mode 100644 index 0000000..1e67d81 --- /dev/null +++ b/tests/benchmarks/qnetworkreply/qnetworkreply.pro @@ -0,0 +1,13 @@ +load(qttest_p4) +TEMPLATE = app +TARGET = tst_qnetworkreply +DEPENDPATH += . +INCLUDEPATH += . + +QT -= gui +QT += network + +CONFIG += release + +# Input +SOURCES += tst_qnetworkreply.cpp diff --git a/tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp b/tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp new file mode 100644 index 0000000..666e4f1 --- /dev/null +++ b/tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +// This file contains benchmarks for QNetworkReply functions. + +#include +#include +#include +#include +#include +#include +#include "../../auto/network-settings.h" + +class tst_qnetworkreply : public QObject +{ + Q_OBJECT +private slots: + void httpLatency(); + +}; + +void tst_qnetworkreply::httpLatency() +{ + QNetworkAccessManager manager; + QBENCHMARK{ + QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/")); + QNetworkReply* reply = manager.get(request); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + delete reply; + } +} + +QTEST_MAIN(tst_qnetworkreply) + +#include "main.moc" -- cgit v0.12 From 5fd8c58dde0c61a723ab124ac74c863f67288a14 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Mon, 19 Oct 2009 17:16:20 +0200 Subject: Add a up/down benchmark to benchmarks/qnetworkreply Reviewed-by: Peter Hartmann --- .../benchmarks/qnetworkreply/tst_qnetworkreply.cpp | 39 +++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp b/tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp index 666e4f1..e622d62 100644 --- a/tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp @@ -53,7 +53,10 @@ class tst_qnetworkreply : public QObject Q_OBJECT private slots: void httpLatency(); - +#ifndef QT_NO_OPENSSL + void echoPerformance_data(); + void echoPerformance(); +#endif }; void tst_qnetworkreply::httpLatency() @@ -69,6 +72,40 @@ void tst_qnetworkreply::httpLatency() } } +#ifndef QT_NO_OPENSSL +void tst_qnetworkreply::echoPerformance_data() +{ + QTest::addColumn("ssl"); + QTest::newRow("no_ssl") << false; + QTest::newRow("ssl") << true; +} + +void tst_qnetworkreply::echoPerformance() +{ + QFETCH(bool, ssl); + QNetworkAccessManager manager; + QNetworkRequest request(QUrl((ssl ? "https://" : "http://") + QtNetworkSettings::serverName() + "/qtest/cgi-bin/echo.cgi")); + + QByteArray data; + data.resize(1024*1024*10); // 10 MB + // init with garbage. needed so ssl cannot compress it in an efficient way. + for (int i = 0; i < data.size() / sizeof(int); i++) { + int r = qrand(); + data.data()[i*sizeof(int)] = r; + } + + QBENCHMARK{ + QNetworkReply* reply = manager.post(request, data); + connect(reply, SIGNAL(sslErrors( const QList &)), reply, SLOT(ignoreSslErrors())); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(reply->error() == QNetworkReply::NoError); + delete reply; + } +} +#endif + QTEST_MAIN(tst_qnetworkreply) #include "main.moc" -- cgit v0.12 From 23b058cdf3d98439ec784a3d430d54e5aed75c7b Mon Sep 17 00:00:00 2001 From: Trond Kjernaasen Date: Tue, 20 Oct 2009 10:37:09 +0200 Subject: Fixed a stencil clearing bug in the GL 1 engine. If the system clip changed the stencil buffer wasn't necessarily updated correctly. Use a region to keep track of the dirty areas in the stencil buffer, like we do in the GL 2 engine. Reviewed-by: Samuel --- src/opengl/qpaintengine_opengl.cpp | 40 ++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp index 80628a2..aa6b6c9 100644 --- a/src/opengl/qpaintengine_opengl.cpp +++ b/src/opengl/qpaintengine_opengl.cpp @@ -746,7 +746,6 @@ public: uint has_brush : 1; uint has_fast_pen : 1; uint use_stencil_method : 1; - uint dirty_stencil : 1; uint dirty_drawable_texture : 1; uint has_stencil_face_ext : 1; uint use_fragment_programs : 1; @@ -757,6 +756,8 @@ public: uint use_system_clip : 1; uint use_emulation : 1; + QRegion dirty_stencil; + void updateUseEmulation(); QTransform matrix; @@ -1259,7 +1260,9 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev) d->matrix = QTransform(); d->has_antialiasing = false; d->high_quality_antialiasing = false; - d->dirty_stencil = true; + + QSize sz(d->device->size()); + d->dirty_stencil = QRect(0, 0, sz.width(), sz.height()); d->use_emulation = false; @@ -1347,7 +1350,6 @@ bool QOpenGLPaintEngine::begin(QPaintDevice *pdev) d->offscreen.begin(); - QSize sz(d->device->size()); glViewport(0, 0, sz.width(), sz.height()); // XXX (Embedded): We need a solution for GLWidgets that draw in a part or a bigger surface... glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -1949,34 +1951,34 @@ void QOpenGLPaintEnginePrivate::fillVertexArray(Qt::FillRule fillRule) { Q_Q(QOpenGLPaintEngine); - if (dirty_stencil) { - disableClipping(); + QRect rect = dirty_stencil.boundingRect(); - if (use_system_clip) { - glEnable(GL_SCISSOR_TEST); + if (use_system_clip) + rect = q->systemClip().intersected(dirty_stencil).boundingRect(); - QRect rect = q->systemClip().boundingRect(); + glStencilMask(~0); - const int left = rect.left(); - const int width = rect.width(); - const int bottom = device->size().height() - (rect.bottom() + 1); - const int height = rect.height(); + if (!rect.isEmpty()) { + disableClipping(); - glScissor(left, bottom, width, height); - } + glEnable(GL_SCISSOR_TEST); + + const int left = rect.left(); + const int width = rect.width(); + const int bottom = device->size().height() - (rect.bottom() + 1); + const int height = rect.height(); + + glScissor(left, bottom, width, height); glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); - dirty_stencil = false; + dirty_stencil -= rect; - if (use_system_clip) - glDisable(GL_SCISSOR_TEST); + glDisable(GL_SCISSOR_TEST); enableClipping(); } - glStencilMask(~0); - // Enable stencil. glEnable(GL_STENCIL_TEST); -- cgit v0.12 From 5651d2547261ccecbf50f8141c634f59c0adc00d Mon Sep 17 00:00:00 2001 From: Dean Dettman Date: Tue, 20 Oct 2009 11:13:02 +0200 Subject: Adds Key_Back and Key_Forward menu glyphs on mac(carbon) This change improves the behavior of QMenu when Key_Back and Key_Forward are used as shortcuts. A dotted arrow appears on carbon, and on Cocoa the image is blank, instead of undefined as it was before. Task-number: QTBUG-4873 Reviewed-by: msorvig --- src/gui/widgets/qmenu_mac.mm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm index 354161d..a7f6f0d 100644 --- a/src/gui/widgets/qmenu_mac.mm +++ b/src/gui/widgets/qmenu_mac.mm @@ -572,6 +572,10 @@ static void qt_mac_get_accel(quint32 accel_key, quint32 *modif, quint32 *key) { *key = kMenuNorthwestArrowGlyph; else if (accel_key == Qt::Key_End) *key = kMenuSoutheastArrowGlyph; + else if (accel_key == Qt::Key_Back) + *key = kMenuLeftArrowDashedGlyph; + else if (accel_key == Qt::Key_Forward) + *key = kMenuRightArrowDashedGlyph; } } #else // Cocoa @@ -1239,6 +1243,10 @@ NSString *keySequenceToKeyEqivalent(const QKeySequence &accel) keyEquiv[0] = NSHomeFunctionKey; else if (accel_key == Qt::Key_End) keyEquiv[0] = NSEndFunctionKey; + else if (accel_key == Qt::Key_Back) + keyEquiv[0] = kMenuLeftArrowDashedGlyph; // ### Cocoa has no equivalent - no icon is displayed + else if (accel_key == Qt::Key_Forward) + keyEquiv[0] = kMenuRightArrowDashedGlyph; // ### Cocoa has no equivalent - no icon is displayed else keyEquiv[0] = unichar(QChar(accel_key).toLower().unicode()); return [NSString stringWithCharacters:keyEquiv length:1]; -- cgit v0.12 From 6e1e26741e682c869c45e4cf8dfe4c79e37b9716 Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Tue, 20 Oct 2009 11:52:42 +0200 Subject: Fixed the SVG paint engine to preserve whitespace when drawing text. Added xml:space="preserve" to the output text tag. This attribute tells the SVG user agent not to strip away excess whitespace in the text element. Reviewed-by: Trond --- src/svg/qsvggenerator.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/svg/qsvggenerator.cpp b/src/svg/qsvggenerator.cpp index da3123f..2f80a92 100644 --- a/src/svg/qsvggenerator.cpp +++ b/src/svg/qsvggenerator.cpp @@ -1063,6 +1063,7 @@ void QSvgPaintEngine::drawTextItem(const QPointF &pt, const QTextItem &textItem) "fill=\"" << d->attributes.stroke << "\" " "fill-opacity=\"" << d->attributes.strokeOpacity << "\" " "stroke=\"none\" " + "xml:space=\"preserve\" " "x=\"" << pt.x() << "\" y=\"" << pt.y() << "\" "; qfontToSvg(textItem.font()); *d->stream << " >" -- cgit v0.12 From f779d9f7e317ff3e10f015a05d349e1fa3e7ab84 Mon Sep 17 00:00:00 2001 From: Dean Dettman Date: Tue, 20 Oct 2009 12:28:32 +0200 Subject: make missing Key_Back and Key_Forward menu glyphs return 0 on mac(cocoa) This is an addition to commit 5651d2547261ccecbf50f8141c634f59c0adc00d to make it obvious that in cocoa nothing is returned. Task-number: QTBUG-4873 Reviewed-by: MortenS --- src/gui/widgets/qmenu_mac.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/qmenu_mac.mm b/src/gui/widgets/qmenu_mac.mm index 0f92ad9..ec9313f 100644 --- a/src/gui/widgets/qmenu_mac.mm +++ b/src/gui/widgets/qmenu_mac.mm @@ -1244,9 +1244,9 @@ NSString *keySequenceToKeyEqivalent(const QKeySequence &accel) else if (accel_key == Qt::Key_End) keyEquiv[0] = NSEndFunctionKey; else if (accel_key == Qt::Key_Back) - keyEquiv[0] = kMenuLeftArrowDashedGlyph; // ### Cocoa has no equivalent - no icon is displayed + keyEquiv[0] = 0 ; // ### could not find Cocoa equivalent to kMenuLeftArrowDashedGlyph else if (accel_key == Qt::Key_Forward) - keyEquiv[0] = kMenuRightArrowDashedGlyph; // ### Cocoa has no equivalent - no icon is displayed + keyEquiv[0] = 0 ; // ### could not find Cocoa equivalent to kMenuRightArrowDashedGlyph else keyEquiv[0] = unichar(QChar(accel_key).toLower().unicode()); return [NSString stringWithCharacters:keyEquiv length:1]; -- cgit v0.12 From f0a7e831394683190faf8a51bf724462f98568e9 Mon Sep 17 00:00:00 2001 From: Tom Cooksey Date: Tue, 20 Oct 2009 14:37:29 +0200 Subject: Add a new window surface which utilises QX11GLPixmapData The new surface uses XCopyArea to post updates to the window and thus, supports partial updates. --- src/opengl/opengl.pro | 7 +- src/opengl/qgraphicssystem_gl.cpp | 8 +- src/opengl/qwindowsurface_gl.cpp | 1 + src/opengl/qwindowsurface_x11gl.cpp | 146 ++++++++++++++++++++++++++++++++++++ src/opengl/qwindowsurface_x11gl_p.h | 81 ++++++++++++++++++++ 5 files changed, 239 insertions(+), 4 deletions(-) create mode 100644 src/opengl/qwindowsurface_x11gl.cpp create mode 100644 src/opengl/qwindowsurface_x11gl_p.h diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 961c781..a212675 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -83,11 +83,12 @@ x11 { SOURCES += qgl_x11egl.cpp \ qglpixelbuffer_egl.cpp \ qgl_egl.cpp \ - qpixmapdata_x11gl_egl.cpp + qpixmapdata_x11gl_egl.cpp \ + qwindowsurface_x11gl.cpp HEADERS += qgl_egl_p.h \ - qpixmapdata_x11gl_p.h - + qpixmapdata_x11gl_p.h \ + qwindowsurface_x11gl_p.h } else { SOURCES += qgl_x11.cpp \ diff --git a/src/opengl/qgraphicssystem_gl.cpp b/src/opengl/qgraphicssystem_gl.cpp index 0ee1e82..c0d9233 100644 --- a/src/opengl/qgraphicssystem_gl.cpp +++ b/src/opengl/qgraphicssystem_gl.cpp @@ -47,8 +47,9 @@ #include "private/qgl_p.h" #include -#ifdef Q_WS_X11 +#if defined(Q_WS_X11) && defined(QT_OPENGL_ES) #include "private/qpixmapdata_x11gl_p.h" +#include "private/qwindowsurface_x11gl_p.h" #endif QT_BEGIN_NAMESPACE @@ -75,6 +76,11 @@ QWindowSurface *QGLGraphicsSystem::createWindowSurface(QWidget *widget) const return new QRasterWindowSurface(widget); #endif +#if defined(Q_WS_X11) && defined(QT_OPENGL_ES) + if (QX11GLPixmapData::hasX11GLPixmaps()) + return new QX11GLWindowSurface(widget); +#endif + return new QGLWindowSurface(widget); } diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp index 2816eca..4547416 100644 --- a/src/opengl/qwindowsurface_gl.cpp +++ b/src/opengl/qwindowsurface_gl.cpp @@ -364,6 +364,7 @@ void QGLWindowSurface::hijackWindow(QWidget *widget) if (ctxpriv->eglSurface == EGL_NO_SURFACE) { qWarning() << "hijackWindow() could not create EGL surface"; } + qDebug("QGLWindowSurface - using EGLConfig %d", ctxpriv->eglContext->config()); #endif widgetPrivate->extraData()->glContext = ctx; diff --git a/src/opengl/qwindowsurface_x11gl.cpp b/src/opengl/qwindowsurface_x11gl.cpp new file mode 100644 index 0000000..2e05ab3 --- /dev/null +++ b/src/opengl/qwindowsurface_x11gl.cpp @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include +#include + +#include "qwindowsurface_x11gl_p.h" +#include "qpixmapdata_x11gl_p.h" + +QT_BEGIN_NAMESPACE + +QX11GLWindowSurface::QX11GLWindowSurface(QWidget* window) + : QWindowSurface(window), m_GC(0), m_window(window) +{ + QImagePixmapCleanupHooks::instance(); +} + +QX11GLWindowSurface::~QX11GLWindowSurface() +{ + + if (m_GC) + XFree(m_GC); +} + +QPaintDevice *QX11GLWindowSurface::paintDevice() +{ + return &m_backBuffer; +} + +extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp + +void QX11GLWindowSurface::flush(QWidget *widget, const QRegion &widgetRegion, const QPoint &offset) +{ +// qDebug("QX11GLWindowSurface::flush()"); + QTime startTime = QTime::currentTime(); + if (m_backBuffer.isNull()) { + qDebug("QHarmattanWindowSurface::flush() - backBuffer is null, not flushing anything"); + return; + } + + QPoint widgetOffset = qt_qwidget_data(widget)->wrect.topLeft(); + QRegion windowRegion(widgetRegion); + QRect boundingRect = widgetRegion.boundingRect(); + if (!widgetOffset.isNull()) + windowRegion.translate(-widgetOffset); + QRect windowBoundingRect = windowRegion.boundingRect(); + + int rectCount; + XRectangle *rects = (XRectangle *)qt_getClipRects(windowRegion, rectCount); + if (rectCount <= 0) + return; +// qDebug() << "XSetClipRectangles"; +// for (int i = 0; i < num; ++i) +// qDebug() << ' ' << i << rects[i].x << rects[i].x << rects[i].y << rects[i].width << rects[i].height; + + if (m_GC == 0) { + m_GC = XCreateGC(X11->display, m_window->handle(), 0, 0); + XSetGraphicsExposures(X11->display, m_GC, False); + } + + XSetClipRectangles(X11->display, m_GC, 0, 0, rects, rectCount, YXBanded); + XCopyArea(X11->display, m_backBuffer.handle(), m_window->handle(), m_GC, + boundingRect.x() + offset.x(), boundingRect.y() + offset.y(), + boundingRect.width(), boundingRect.height(), + windowBoundingRect.x(), windowBoundingRect.y()); +} + +void QX11GLWindowSurface::setGeometry(const QRect &rect) +{ + if (rect.width() > m_backBuffer.size().width() || rect.height() > m_backBuffer.size().height()) { + QSize newSize = rect.size(); +// QSize newSize(1024,512); + qDebug() << "QX11GLWindowSurface::setGeometry() - creating a pixmap of size" << newSize; + QX11GLPixmapData *pd = new QX11GLPixmapData; + pd->resize(newSize.width(), newSize.height()); + m_backBuffer = QPixmap(pd); + } + +// if (gc) +// XFreeGC(X11->display, gc); +// gc = XCreateGC(X11->display, d_ptr->device.handle(), 0, 0); +// XSetGraphicsExposures(X11->display, gc, False); + QWindowSurface::setGeometry(rect); +} + +bool QX11GLWindowSurface::scroll(const QRegion &area, int dx, int dy) +{ + return false; +} + +/* +void QX11GLWindowSurface::beginPaint(const QRegion ®ion) +{ +} + +void QX11GLWindowSurface::endPaint(const QRegion ®ion) +{ +} + +QImage *QX11GLWindowSurface::buffer(const QWidget *widget) +{ +} +*/ + +QT_END_NAMESPACE diff --git a/src/opengl/qwindowsurface_x11gl_p.h b/src/opengl/qwindowsurface_x11gl_p.h new file mode 100644 index 0000000..5ba4dc5 --- /dev/null +++ b/src/opengl/qwindowsurface_x11gl_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWINDOWSURFACE_X11GL_P_H +#define QWINDOWSURFACE_X11GL_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QX11GLWindowSurface : public QWindowSurface +{ +public: + QX11GLWindowSurface(QWidget* window); + virtual ~QX11GLWindowSurface(); + + // Inherreted from QWindowSurface + QPaintDevice *paintDevice(); + void flush(QWidget *widget, const QRegion ®ion, const QPoint &offset); + void setGeometry(const QRect &rect); + bool scroll(const QRegion &area, int dx, int dy); + +private: + GC m_GC; + QPixmap m_backBuffer; + QWidget *m_window; +}; + + +QT_END_NAMESPACE + +#endif // QWINDOWSURFACE_X11GL_P_H -- cgit v0.12 From bdb67474ece69a987379411f593d0b37c1400746 Mon Sep 17 00:00:00 2001 From: Tom Cooksey Date: Tue, 20 Oct 2009 14:54:22 +0200 Subject: Make sure QGLTextureCache exists when creating surfaces for pixmaps QGLTextureCache installs pixmap cleanup hooks which are used to clean up the EGL surfaces. Reviewed-By: Trustme --- src/opengl/qgl_x11egl.cpp | 8 ++++++++ src/opengl/qwindowsurface_x11gl.cpp | 2 -- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp index fb08741..3894ed1 100644 --- a/src/opengl/qgl_x11egl.cpp +++ b/src/opengl/qgl_x11egl.cpp @@ -521,6 +521,14 @@ bool Q_OPENGL_EXPORT qt_createEGLSurfaceForPixmap(QPixmapData* pmd, bool readOnl return false; } + static bool doneOnce = false; + if (!doneOnce) { + // Make sure QGLTextureCache is instanciated so it can install cleanup hooks + // which cleanup the EGL surface. + QGLTextureCache::instance(); + doneOnce = true; + } + Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure! pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface; pixmapData->is_cached = true; // Make sure the cleanup hook gets called diff --git a/src/opengl/qwindowsurface_x11gl.cpp b/src/opengl/qwindowsurface_x11gl.cpp index 2e05ab3..8ef239d 100644 --- a/src/opengl/qwindowsurface_x11gl.cpp +++ b/src/opengl/qwindowsurface_x11gl.cpp @@ -53,12 +53,10 @@ QT_BEGIN_NAMESPACE QX11GLWindowSurface::QX11GLWindowSurface(QWidget* window) : QWindowSurface(window), m_GC(0), m_window(window) { - QImagePixmapCleanupHooks::instance(); } QX11GLWindowSurface::~QX11GLWindowSurface() { - if (m_GC) XFree(m_GC); } -- cgit v0.12 From 58574ea3590fbb28da5be73b983d83f0a8824d00 Mon Sep 17 00:00:00 2001 From: Markus Goetz Date: Tue, 20 Oct 2009 15:03:56 +0200 Subject: tst_qsslsocket: new bigChunk testcase This new test is to find out if the BIO size of OpenSSL is limited or not. The test passes on my Linux, however the OpenSSL docu suggests that the BIO size is limited. From http://www.openssl.org/docs/crypto/BIO_s_bio.html "This is currently 17K". Reviewed-by: Peter Hartmann --- tests/auto/qsslsocket/tst_qsslsocket.cpp | 45 ++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/auto/qsslsocket/tst_qsslsocket.cpp b/tests/auto/qsslsocket/tst_qsslsocket.cpp index 6b330e1..2f1c2e2 100644 --- a/tests/auto/qsslsocket/tst_qsslsocket.cpp +++ b/tests/auto/qsslsocket/tst_qsslsocket.cpp @@ -173,6 +173,7 @@ private slots: void disconnectFromHostWhenConnected(); void resetProxy(); void readFromClosedSocket(); + void writeBigChunk(); static void exitLoop() { @@ -1537,6 +1538,50 @@ void tst_QSslSocket::readFromClosedSocket() QVERIFY(!socket->bytesToWrite()); } +void tst_QSslSocket::writeBigChunk() +{ + if (!QSslSocket::supportsSsl()) + return; + + QSslSocketPtr socket = newSocket(); + this->socket = socket; + + connect(socket, SIGNAL(sslErrors(const QList &)), this, SLOT(ignoreErrorSlot())); + socket->connectToHostEncrypted(QtNetworkSettings::serverName(), 443); + + QByteArray data; + data.resize(1024*1024*10); // 10 MB + // init with garbage. needed so ssl cannot compress it in an efficient way. + for (int i = 0; i < data.size() / sizeof(int); i++) { + int r = qrand(); + data.data()[i*sizeof(int)] = r; + } + + QVERIFY(socket->waitForEncrypted(10000)); + QString errorBefore = socket->errorString(); + + int ret = socket->write(data.constData(), data.size()); + QVERIFY(data.size() == ret); + + // spin the event loop once so QSslSocket::transmit() gets called + QCoreApplication::processEvents(); + QString errorAfter = socket->errorString(); + + // no better way to do this right now since the error is the same as the default error. + if (socket->errorString().startsWith(QLatin1String("Unable to write data"))) + { + qWarning() << socket->error() << socket->errorString(); + QFAIL("Error while writing! Check if the OpenSSL BIO size is limited?!"); + } + // also check the error string. If another error (than UnknownError) occured, it should be different than before + QVERIFY(errorBefore == errorAfter); + + // check that everything has been written to OpenSSL + QVERIFY(socket->bytesToWrite() == 0); + + socket->close(); +} + #endif // QT_NO_OPENSSL QTEST_MAIN(tst_QSslSocket) -- cgit v0.12 From 84cfe9af5e333872ac67368a6b14c377ceeda8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Trond=20Kjern=C3=A5sen?= Date: Tue, 20 Oct 2009 17:51:15 +0200 Subject: Fixed an assert when running the composition demo on Mac. We can't create a QGLWidget in the QGLEngineSelector, since it may be called before a QApplication object has been constructed. Reviewed-by: Kim --- src/opengl/qgl.cpp | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 97e3dad..6720ae7 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -151,22 +151,6 @@ class QGLEngineSelector public: QGLEngineSelector() : engineType(QPaintEngine::MaxUser) { -#ifdef Q_WS_MAC - // The ATI X1600 driver for Mac OS X does not support return - // values from functions in GLSL. Since working around this in - // the GL2 engine would require a big, ugly rewrite, we're - // falling back to the GL 1 engine.. - QGLWidget *tmp = 0; - if (!QGLContext::currentContext()) { - tmp = new QGLWidget(); - tmp->makeCurrent(); - } - if (strstr((char *) glGetString(GL_RENDERER), "X1600")) - setPreferredPaintEngine(QPaintEngine::OpenGL); - if (tmp) - delete tmp; -#endif - } void setPreferredPaintEngine(QPaintEngine::Type type) { @@ -175,6 +159,25 @@ public: } QPaintEngine::Type preferredPaintEngine() { +#ifdef Q_WS_MAC + // The ATI X1600 driver for Mac OS X does not support return + // values from functions in GLSL. Since working around this in + // the GL2 engine would require a big, ugly rewrite, we're + // falling back to the GL 1 engine.. + static bool mac_x1600_check_done = false; + if (!mac_x1600_check_done) { + QGLWidget *tmp = 0; + if (!QGLContext::currentContext()) { + tmp = new QGLWidget(); + tmp->makeCurrent(); + } + if (strstr((char *) glGetString(GL_RENDERER), "X1600")) + engineType = QPaintEngine::OpenGL; + if (tmp) + delete tmp; + mac_x1600_check_done = true; + } +#endif if (engineType == QPaintEngine::MaxUser) { // No user-set engine - use the defaults #if defined(QT_OPENGL_ES_2) -- cgit v0.12 From 3be273fc751624fab078878904ad3cb483cd141f Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Wed, 21 Oct 2009 13:31:07 +0200 Subject: Properly detect font smoothing setting on Mac OS X in raster engine MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We would assume font smoothing on the mac was always turned on, giving poor text rendering in the cases where it was not. This implementation mirrors querying the cleartype setting on Windows, checking the setting on application initialization and rendering into an 8 bit cache if it is turned off. Task-number: QTBUG-4881 Reviewed-by: Morten Johan Sørvig --- src/gui/kernel/qapplication_mac.mm | 11 +++++++++++ src/gui/painting/qpaintengine_raster.cpp | 6 +++++- src/gui/painting/qtextureglyphcache.cpp | 4 ++-- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index f9c8aa3..771cddc 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -203,6 +203,8 @@ static EventHandlerRef tablet_proximity_handler = 0; static EventHandlerUPP tablet_proximity_UPP = 0; bool QApplicationPrivate::native_modal_dialog_active; +Q_GUI_EXPORT bool qt_applefontsmoothing_enabled; + /***************************************************************************** External functions *****************************************************************************/ @@ -222,6 +224,12 @@ extern bool qt_sendSpontaneousEvent(QObject *obj, QEvent *event); // qapplicatio void onApplicationWindowChangedActivation( QWidget*widget, bool activated ); void onApplicationChangedActivation( bool activated ); +static void qt_mac_read_fontsmoothing_settings() +{ + NSInteger appleFontSmoothing = [[NSUserDefaults standardUserDefaults] integerForKey:@"AppleFontSmoothing"]; + qt_applefontsmoothing_enabled = (appleFontSmoothing > 0); +} + Q_GUI_EXPORT bool qt_mac_execute_apple_script(const char *script, long script_len, AEDesc *ret) { OSStatus err; AEDesc scriptTextDesc; @@ -1203,6 +1211,9 @@ void qt_init(QApplicationPrivate *priv, int) } if (QApplication::desktopSettingsAware()) QApplicationPrivate::qt_mac_apply_settings(); + + qt_mac_read_fontsmoothing_settings(); + // Cocoa application delegate #ifdef QT_MAC_USE_COCOA NSApplication *cocoaApp = [NSApplication sharedApplication]; diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index fab2d8d..fd0e810 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -132,6 +132,10 @@ static const qreal aliasedCoordinateDelta = 0.5 - 0.015625; extern bool qt_cleartype_enabled; #endif +#ifdef Q_WS_MAC +extern bool qt_applefontsmoothing_enabled; +#endif + /******************************************************************************** * Span functions @@ -508,7 +512,7 @@ bool QRasterPaintEngine::begin(QPaintDevice *device) #if defined(Q_WS_WIN) else if (qt_cleartype_enabled) #elif defined (Q_WS_MAC) - else if (true) + else if (qt_applefontsmoothing_enabled) #else else if (false) #endif diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp index 25b6aba..a192e87 100644 --- a/src/gui/painting/qtextureglyphcache.cpp +++ b/src/gui/painting/qtextureglyphcache.cpp @@ -229,8 +229,8 @@ void QImageTextureGlyphCache::createTextureData(int width, int height) int QImageTextureGlyphCache::glyphMargin() const { -#ifdef Q_WS_MAC - return 2; +#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA) + return 0; #else return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0; #endif -- cgit v0.12 From fad27a3b6f018a0bc3cb261c81aaefc540589585 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 21 Oct 2009 21:57:41 +0200 Subject: Rename the .cpp for QNetworkReply benchmark tests --- tests/benchmarks/qnetworkreply/main.cpp | 74 ---------------------- tests/benchmarks/qnetworkreply/qnetworkreply.pro | 2 +- .../benchmarks/qnetworkreply/tst_qnetworkreply.cpp | 74 ++++++++++++++++++++++ 3 files changed, 75 insertions(+), 75 deletions(-) delete mode 100644 tests/benchmarks/qnetworkreply/main.cpp create mode 100644 tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp diff --git a/tests/benchmarks/qnetworkreply/main.cpp b/tests/benchmarks/qnetworkreply/main.cpp deleted file mode 100644 index 666e4f1..0000000 --- a/tests/benchmarks/qnetworkreply/main.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** No Commercial Usage -** This file contains pre-release code and may not be distributed. -** You may use this file in accordance with the terms and conditions -** contained in the Technology Preview License Agreement accompanying -** this package. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** If you have questions regarding the use of this file, please contact -** Nokia at qt-info@nokia.com. -** -** -** -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -// This file contains benchmarks for QNetworkReply functions. - -#include -#include -#include -#include -#include -#include -#include "../../auto/network-settings.h" - -class tst_qnetworkreply : public QObject -{ - Q_OBJECT -private slots: - void httpLatency(); - -}; - -void tst_qnetworkreply::httpLatency() -{ - QNetworkAccessManager manager; - QBENCHMARK{ - QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/")); - QNetworkReply* reply = manager.get(request); - connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); - QTestEventLoop::instance().enterLoop(5); - QVERIFY(!QTestEventLoop::instance().timeout()); - delete reply; - } -} - -QTEST_MAIN(tst_qnetworkreply) - -#include "main.moc" diff --git a/tests/benchmarks/qnetworkreply/qnetworkreply.pro b/tests/benchmarks/qnetworkreply/qnetworkreply.pro index 060acf5..1e67d81 100644 --- a/tests/benchmarks/qnetworkreply/qnetworkreply.pro +++ b/tests/benchmarks/qnetworkreply/qnetworkreply.pro @@ -10,4 +10,4 @@ QT += network CONFIG += release # Input -SOURCES += main.cpp +SOURCES += tst_qnetworkreply.cpp diff --git a/tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp b/tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp new file mode 100644 index 0000000..666e4f1 --- /dev/null +++ b/tests/benchmarks/qnetworkreply/tst_qnetworkreply.cpp @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +// This file contains benchmarks for QNetworkReply functions. + +#include +#include +#include +#include +#include +#include +#include "../../auto/network-settings.h" + +class tst_qnetworkreply : public QObject +{ + Q_OBJECT +private slots: + void httpLatency(); + +}; + +void tst_qnetworkreply::httpLatency() +{ + QNetworkAccessManager manager; + QBENCHMARK{ + QNetworkRequest request(QUrl("http://" + QtNetworkSettings::serverName() + "/qtest/")); + QNetworkReply* reply = manager.get(request); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + delete reply; + } +} + +QTEST_MAIN(tst_qnetworkreply) + +#include "main.moc" -- cgit v0.12 From 493ce4c0aa1c7dc73206917b1a6874e77b7385d9 Mon Sep 17 00:00:00 2001 From: Kurt Korbatits Date: Thu, 22 Oct 2009 10:48:46 +1000 Subject: Fixed clock() function return values in audio class's. clock() function should return microseconds, fixed example, alsa backend and win32 backend. Reviewed-by:Justin McPherson --- examples/multimedia/audioinput/audioinput.cpp | 2 +- examples/multimedia/audiooutput/audiooutput.cpp | 2 +- src/multimedia/audio/qaudioinput_alsa_p.cpp | 2 +- src/multimedia/audio/qaudioinput_win32_p.cpp | 2 +- src/multimedia/audio/qaudiooutput_alsa_p.cpp | 2 +- src/multimedia/audio/qaudiooutput_win32_p.cpp | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/multimedia/audioinput/audioinput.cpp b/examples/multimedia/audioinput/audioinput.cpp index 05723ae..3d537a2 100644 --- a/examples/multimedia/audioinput/audioinput.cpp +++ b/examples/multimedia/audioinput/audioinput.cpp @@ -216,7 +216,7 @@ InputTest::~InputTest() {} void InputTest::status() { - qWarning()<<"bytesReady = "<bytesReady()<<" bytes, clock = "<clock()<<"ms, totalTime = "<totalTime()/1000<<"ms"; + qWarning()<<"bytesReady = "<bytesReady()<<" bytes, clock = "<clock()/1000<<"ms, totalTime = "<totalTime()/1000<<"ms"; } void InputTest::readMore() diff --git a/examples/multimedia/audiooutput/audiooutput.cpp b/examples/multimedia/audiooutput/audiooutput.cpp index 9e532cd..c92bbaf 100644 --- a/examples/multimedia/audiooutput/audiooutput.cpp +++ b/examples/multimedia/audiooutput/audiooutput.cpp @@ -200,7 +200,7 @@ void AudioTest::deviceChanged(int idx) void AudioTest::status() { - qWarning()<<"byteFree = "<bytesFree()<<" bytes, clock = "<clock()<<"ms, totalTime = "<totalTime()/1000<<"ms"; + qWarning()<<"byteFree = "<bytesFree()<<" bytes, clock = "<clock()/1000<<"ms, totalTime = "<totalTime()/1000<<"ms"; } void AudioTest::writeMore() diff --git a/src/multimedia/audio/qaudioinput_alsa_p.cpp b/src/multimedia/audio/qaudioinput_alsa_p.cpp index 6786657..9eb8cfb 100644 --- a/src/multimedia/audio/qaudioinput_alsa_p.cpp +++ b/src/multimedia/audio/qaudioinput_alsa_p.cpp @@ -630,7 +630,7 @@ qint64 QAudioInputPrivate::clock() const l = -l; l %= 1000000; } - return ((t1.tv_sec * 1000)+l/1000); + return ((t1.tv_sec * 1000000)+l); } else return 0; #else diff --git a/src/multimedia/audio/qaudioinput_win32_p.cpp b/src/multimedia/audio/qaudioinput_win32_p.cpp index b6b1efe..a059e76 100644 --- a/src/multimedia/audio/qaudioinput_win32_p.cpp +++ b/src/multimedia/audio/qaudioinput_win32_p.cpp @@ -544,7 +544,7 @@ qint64 QAudioInputPrivate::clock() const if (deviceState == QAudio::StopState) return 0; - return timeStampOpened.elapsed(); + return timeStampOpened.elapsed()*1000; } void QAudioInputPrivate::reset() diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.cpp b/src/multimedia/audio/qaudiooutput_alsa_p.cpp index efa7b27..689da89 100644 --- a/src/multimedia/audio/qaudiooutput_alsa_p.cpp +++ b/src/multimedia/audio/qaudiooutput_alsa_p.cpp @@ -682,7 +682,7 @@ qint64 QAudioOutputPrivate::clock() const l = -l; l %= 1000000; } - return ((t1.tv_sec * 1000)+l/1000); + return ((t1.tv_sec * 1000000)+l); } else return 0; #else diff --git a/src/multimedia/audio/qaudiooutput_win32_p.cpp b/src/multimedia/audio/qaudiooutput_win32_p.cpp index 2c4a1c2..1810ed2 100644 --- a/src/multimedia/audio/qaudiooutput_win32_p.cpp +++ b/src/multimedia/audio/qaudiooutput_win32_p.cpp @@ -496,7 +496,7 @@ qint64 QAudioOutputPrivate::clock() const if (deviceState == QAudio::StopState) return 0; - return timeStampOpened.elapsed(); + return timeStampOpened.elapsed()*1000; } QAudio::Error QAudioOutputPrivate::error() const -- cgit v0.12 From 100afe8da00fdb1661b22e049960ed00a1d3c765 Mon Sep 17 00:00:00 2001 From: Rhys Weatherley Date: Thu, 22 Oct 2009 15:12:40 +1000 Subject: Fix a bug in QGraphicsRotation related to 2D projections The projection to 2D needs to be done when the rotation is applied, not after all transformations have been applied. Reviewed-by: trustme --- src/gui/graphicsview/qgraphicsitem_p.h | 2 +- src/gui/graphicsview/qgraphicstransform.cpp | 4 +++- tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h index 6550362..8696324 100644 --- a/src/gui/graphicsview/qgraphicsitem_p.h +++ b/src/gui/graphicsview/qgraphicsitem_p.h @@ -539,7 +539,7 @@ struct QGraphicsItemPrivate::TransformData QMatrix4x4 m; for (int i = 0; i < graphicsTransforms.size(); ++i) graphicsTransforms.at(i)->applyTo(&m); - x *= m.toTransform(); + x *= m.toTransform(0); } x.translate(xOrigin, yOrigin); x.rotate(rotation); diff --git a/src/gui/graphicsview/qgraphicstransform.cpp b/src/gui/graphicsview/qgraphicstransform.cpp index ec1a2f5..49d8999 100644 --- a/src/gui/graphicsview/qgraphicstransform.cpp +++ b/src/gui/graphicsview/qgraphicstransform.cpp @@ -547,7 +547,9 @@ void QGraphicsRotation::applyTo(QMatrix4x4 *matrix) const return; matrix->translate(d->origin); - matrix->rotate(d->angle, d->axis.x(), d->axis.y(), d->axis.z()); + QMatrix4x4 m; + m.rotate(d->angle, d->axis.x(), d->axis.y(), d->axis.z()); + *matrix *= m.toTransform(); matrix->translate(-d->origin); } diff --git a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp index b407fef..eb5c099 100644 --- a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp +++ b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp @@ -88,7 +88,7 @@ static QTransform transform2D(const QGraphicsTransform& t) { QMatrix4x4 m; t.applyTo(&m); - return m.toTransform(); + return m.toTransform(0); } void tst_QGraphicsTransform::scale() -- cgit v0.12