diff options
Diffstat (limited to 'src/quick/items/context2d')
-rw-r--r-- | src/quick/items/context2d/qquickcanvascontext_p.h | 5 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcanvasitem.cpp | 77 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcanvasitem_p.h | 4 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2d.cpp | 159 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2d_p.h | 9 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp | 6 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h | 26 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2dtexture.cpp | 17 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2dtexture_p.h | 22 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2dtile.cpp | 13 | ||||
-rw-r--r-- | src/quick/items/context2d/qquickcontext2dtile_p.h | 13 |
11 files changed, 217 insertions, 134 deletions
diff --git a/src/quick/items/context2d/qquickcanvascontext_p.h b/src/quick/items/context2d/qquickcanvascontext_p.h index 4f71770e1a..0746b7dcd3 100644 --- a/src/quick/items/context2d/qquickcanvascontext_p.h +++ b/src/quick/items/context2d/qquickcanvascontext_p.h @@ -51,10 +51,13 @@ // We mean it. // +#include <private/qtquickglobal_p.h> + +QT_REQUIRE_CONFIG(quick_canvas); + #include <QtQuick/qquickitem.h> #include <private/qv8engine_p.h> - QT_BEGIN_NAMESPACE class QQuickCanvasItem; diff --git a/src/quick/items/context2d/qquickcanvasitem.cpp b/src/quick/items/context2d/qquickcanvasitem.cpp index 89a68e4f33..3b2b125c63 100644 --- a/src/quick/items/context2d/qquickcanvasitem.cpp +++ b/src/quick/items/context2d/qquickcanvasitem.cpp @@ -43,7 +43,7 @@ #include <private/qquickcanvascontext_p.h> #include <private/qquickcontext2d_p.h> #include <private/qquickcontext2dtexture_p.h> -#include <qsgsimpletexturenode.h> +#include <private/qsgadaptationlayer_p.h> #include <QtQuick/private/qquickpixmapcache_p.h> #include <QtGui/QGuiApplication> @@ -59,24 +59,11 @@ QT_BEGIN_NAMESPACE -class QQuickCanvasNode : public QSGSimpleTextureNode -{ -public: - QQuickCanvasNode() { - qsgnode_set_description(this, QStringLiteral("canvasnode")); - setOwnsTexture(false); - } - - ~QQuickCanvasNode() { - delete texture(); - } -}; - class QQuickCanvasTextureProvider : public QSGTextureProvider { public: - QQuickCanvasNode *node; - QSGTexture *texture() const Q_DECL_OVERRIDE { return node ? node->texture() : 0; } + QSGTexture *tex; + QSGTexture *texture() const Q_DECL_OVERRIDE { return tex; } void fireTextureChanged() { emit textureChanged(); } }; @@ -187,7 +174,8 @@ public: QUrl baseUrl; QMap<int, QV4::PersistentValue> animationCallbacks; mutable QQuickCanvasTextureProvider *textureProvider; - QQuickCanvasNode *node; + QSGInternalImageNode *node; + QSGTexture *nodeTexture; }; QQuickCanvasItemPrivate::QQuickCanvasItemPrivate() @@ -203,6 +191,7 @@ QQuickCanvasItemPrivate::QQuickCanvasItemPrivate() , renderStrategy(QQuickCanvasItem::Immediate) , textureProvider(0) , node(0) + , nodeTexture(0) { implicitAntialiasing = true; } @@ -256,17 +245,18 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate() The Canvas item supports two render targets: \c Canvas.Image and \c Canvas.FramebufferObject. - The \c Canvas.Image render target is a \a QImage object. This render - target supports background thread rendering, allowing complex or long - running painting to be executed without blocking the UI. + The \c Canvas.Image render target is a \a QImage object. This render target + supports background thread rendering, allowing complex or long running + painting to be executed without blocking the UI. This is the only render + target that is supported by all Qt Quick backends. The Canvas.FramebufferObject render target utilizes OpenGL hardware acceleration rather than rendering into system memory, which in many cases - results in faster rendering. Canvas.FramebufferObject relies on the - OpenGL extensions \c GL_EXT_framebuffer_multisample and - \c GL_EXT_framebuffer_blit for antialiasing. It will also use more - graphics memory when rendering strategy is anything other than - Canvas.Cooperative. + results in faster rendering. Canvas.FramebufferObject relies on the OpenGL + extensions \c GL_EXT_framebuffer_multisample and \c GL_EXT_framebuffer_blit + for antialiasing. It will also use more graphics memory when rendering + strategy is anything other than Canvas.Cooperative. Framebuffer objects may + not be available with Qt Quick backends other than OpenGL. The default render target is Canvas.Image and the default renderStrategy is Canvas.Immediate. @@ -301,7 +291,14 @@ QQuickCanvasItemPrivate::~QQuickCanvasItemPrivate() and can be used directly in \l {ShaderEffect}{ShaderEffects} and other classes that consume texture providers. - \sa Context2D + \note In general large canvases, frequent updates, and animation should be + avoided with the Canvas.Image render target. This is because with + accelerated graphics APIs each update will lead to a texture upload. Also, + if possible, prefer QQuickPaintedItem and implement drawing in C++ via + QPainter instead of the more expensive and likely less performing + JavaScript and Context2D approach. + + \sa Context2D QQuickPaintedItem */ QQuickCanvasItem::QQuickCanvasItem(QQuickItem *parent) @@ -712,7 +709,7 @@ void QQuickCanvasItem::updatePolish() for (auto it = animationCallbacks.cbegin(), end = animationCallbacks.cend(); it != end; ++it) { QV4::ScopedFunctionObject f(scope, it.value().value()); callData->args[0] = QV4::Primitive::fromUInt32(QDateTime::currentMSecsSinceEpoch() / 1000); - f->call(callData); + f->call(scope, callData); } } else { @@ -739,16 +736,16 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData if (!d->context || d->canvasWindow.size().isEmpty()) { if (d->textureProvider) { - d->textureProvider->node = 0; + d->textureProvider->tex = 0; d->textureProvider->fireTextureChanged(); } delete oldNode; return 0; } - QQuickCanvasNode *node = static_cast<QQuickCanvasNode*>(oldNode); + QSGInternalImageNode *node = static_cast<QSGInternalImageNode *>(oldNode); if (!node) { - node = new QQuickCanvasNode(); + node = QQuickWindowPrivate::get(window())->context->sceneGraphContext()->createInternalImageNode(); d->node = node; } @@ -765,22 +762,27 @@ QSGNode *QQuickCanvasItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData QQuickContext2D *ctx = qobject_cast<QQuickContext2D *>(d->context); QQuickContext2DTexture *factory = ctx->texture(); - QSGTexture *texture = factory->textureForNextFrame(node->texture(), window()); + QSGTexture *texture = factory->textureForNextFrame(d->nodeTexture, window()); if (!texture) { delete node; d->node = 0; + delete d->nodeTexture; + d->nodeTexture = 0; if (d->textureProvider) { - d->textureProvider->node = 0; + d->textureProvider->tex = 0; d->textureProvider->fireTextureChanged(); } return 0; } + d->nodeTexture = texture; node->setTexture(texture); - node->setRect(QRectF(QPoint(0, 0), d->canvasWindow.size())); + node->setTargetRect(QRectF(QPoint(0, 0), d->canvasWindow.size())); + node->setInnerTargetRect(QRectF(QPoint(0, 0), d->canvasWindow.size())); + node->update(); if (d->textureProvider) { - d->textureProvider->node = node; + d->textureProvider->tex = d->nodeTexture; d->textureProvider->fireTextureChanged(); } return node; @@ -800,14 +802,17 @@ QSGTextureProvider *QQuickCanvasItem::textureProvider() const return QQuickItem::textureProvider(); Q_D(const QQuickCanvasItem); +#ifndef QT_NO_OPENGL QQuickWindow *w = window(); - if (!w || !w->openglContext() || QThread::currentThread() != w->openglContext()->thread()) { + if (!w || !w->isSceneGraphInitialized() + || QThread::currentThread() != QQuickWindowPrivate::get(w)->context->thread()) { qWarning("QQuickCanvasItem::textureProvider: can only be queried on the rendering thread of an exposed window"); return 0; } +#endif if (!d->textureProvider) d->textureProvider = new QQuickCanvasTextureProvider; - d->textureProvider->node = d->node; + d->textureProvider->tex = d->nodeTexture; return d->textureProvider; } diff --git a/src/quick/items/context2d/qquickcanvasitem_p.h b/src/quick/items/context2d/qquickcanvasitem_p.h index 4f94393a45..8196debef1 100644 --- a/src/quick/items/context2d/qquickcanvasitem_p.h +++ b/src/quick/items/context2d/qquickcanvasitem_p.h @@ -51,6 +51,10 @@ // We mean it. // +#include <private/qtquickglobal_p.h> + +QT_REQUIRE_CONFIG(quick_canvas); + #include <QtQuick/qquickitem.h> #include <private/qv8engine_p.h> #include <private/qqmlrefcount_p.h> diff --git a/src/quick/items/context2d/qquickcontext2d.cpp b/src/quick/items/context2d/qquickcontext2d.cpp index b2117d3eb9..2483a8eadb 100644 --- a/src/quick/items/context2d/qquickcontext2d.cpp +++ b/src/quick/items/context2d/qquickcontext2d.cpp @@ -43,6 +43,7 @@ #include <private/qquickcontext2dtexture_p.h> #include <private/qquickitem_p.h> #include <QtQuick/private/qquickshadereffectsource_p.h> +#include <qsgrendererinterface.h> #include <QtQuick/private/qsgcontext_p.h> #include <private/qquicksvgparser_p.h> @@ -74,6 +75,10 @@ #include <private/qguiapplication_p.h> #include <qpa/qplatformintegration.h> +#ifndef QT_NO_OPENGL +# include <private/qsgdefaultrendercontext_p.h> +#endif + #include <cmath> #if defined(Q_OS_QNX) || defined(Q_OS_ANDROID) #include <ctype.h> @@ -484,34 +489,43 @@ namespace QV4 { namespace Heap { struct QQuickJSContext2D : Object { - QQuickJSContext2D() {} + void init() { Object::init(); } QQuickContext2D* context; }; struct QQuickJSContext2DPrototype : Object { - QQuickJSContext2DPrototype() {} + void init() { Object::init(); } }; struct QQuickContext2DStyle : Object { - QQuickContext2DStyle() + void init() { + brush = new QBrush; patternRepeatX = false; patternRepeatY = false; } + void destroy() { + delete brush; + Object::destroy(); + } - QBrush brush; + QBrush *brush; bool patternRepeatX:1; bool patternRepeatY:1; }; struct QQuickJSContext2DPixelData : Object { - QQuickJSContext2DPixelData(); + void init(); + void destroy() { + delete image; + Object::destroy(); + } - QImage image; + QImage *image; }; struct QQuickJSContext2DImageData : Object { - QQuickJSContext2DImageData(); + void init(); QV4::Value pixelData; }; @@ -789,7 +803,7 @@ static QPainter::CompositionMode qt_composite_mode_from_string(const QString &co } else if (compositeOperator == QLatin1String("destination-over")) { return QPainter::CompositionMode_DestinationOver; } else if (compositeOperator == QLatin1String("lighter")) { - return QPainter::CompositionMode_Lighten; + return QPainter::CompositionMode_Plus; } else if (compositeOperator == QLatin1String("copy")) { return QPainter::CompositionMode_Source; } else if (compositeOperator == QLatin1String("xor")) { @@ -852,7 +866,7 @@ static QString qt_composite_mode_to_string(QPainter::CompositionMode op) case QPainter::CompositionMode_Xor: return QStringLiteral("xor"); case QPainter::CompositionMode_Plus: - return QStringLiteral("plus"); + return QStringLiteral("lighter"); case QPainter::CompositionMode_Multiply: return QStringLiteral("qt-multiply"); case QPainter::CompositionMode_Screen: @@ -892,8 +906,10 @@ struct QQuickJSContext2DPixelData : public QV4::Object static QV4::ReturnedValue proto_get_length(QV4::CallContext *ctx); }; -QV4::Heap::QQuickJSContext2DPixelData::QQuickJSContext2DPixelData() +void QV4::Heap::QQuickJSContext2DPixelData::init() { + Object::init(); + image = new QImage; QV4::Scope scope(internalClass->engine); QV4::ScopedObject o(scope, this); o->setArrayType(QV4::Heap::ArrayData::Custom); @@ -915,8 +931,9 @@ struct QQuickJSContext2DImageData : public QV4::Object } }; -QV4::Heap::QQuickJSContext2DImageData::QQuickJSContext2DImageData() +void QV4::Heap::QQuickJSContext2DImageData::init() { + Object::init(); pixelData = QV4::Primitive::undefinedValue(); QV4::Scope scope(internalClass->engine); @@ -938,11 +955,11 @@ static QV4::ReturnedValue qt_create_image_data(qreal w, qreal h, QV4::ExecutionE pixelData->setPrototype(p); if (image.isNull()) { - pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32); - pixelData->d()->image.fill(0x00000000); + *pixelData->d()->image = QImage(w, h, QImage::Format_ARGB32); + pixelData->d()->image->fill(0x00000000); } else { Q_ASSERT(image.width() == qRound(w) && image.height() == qRound(h)); - pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32); + *pixelData->d()->image = image.format() == QImage::Format_ARGB32 ? image : image.convertToFormat(QImage::Format_ARGB32); } QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, scope.engine->memoryManager->allocObject<QQuickJSContext2DImageData>()); @@ -1387,9 +1404,9 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_fillStyle(QV4::CallContext *ctx r->d()->context->m_fillStyle.set(scope.engine, value); } else { QV4::Scoped<QQuickContext2DStyle> style(scope, value->as<QQuickContext2DStyle>()); - if (style && style->d()->brush != r->d()->context->state.fillStyle) { - r->d()->context->state.fillStyle = style->d()->brush; - r->d()->context->buffer()->setFillStyle(style->d()->brush, style->d()->patternRepeatX, style->d()->patternRepeatY); + if (style && *style->d()->brush != r->d()->context->state.fillStyle) { + r->d()->context->state.fillStyle = *style->d()->brush; + r->d()->context->buffer()->setFillStyle(*style->d()->brush, style->d()->patternRepeatX, style->d()->patternRepeatY); r->d()->context->m_fillStyle.set(scope.engine, value); r->d()->context->state.fillPatternRepeatX = style->d()->patternRepeatX; r->d()->context->state.fillPatternRepeatY = style->d()->patternRepeatY; @@ -1496,9 +1513,9 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_strokeStyle(QV4::CallContext *c r->d()->context->m_strokeStyle.set(scope.engine, value); } else { QV4::Scoped<QQuickContext2DStyle> style(scope, value->as<QQuickContext2DStyle>()); - if (style && style->d()->brush != r->d()->context->state.strokeStyle) { - r->d()->context->state.strokeStyle = style->d()->brush; - r->d()->context->buffer()->setStrokeStyle(style->d()->brush, style->d()->patternRepeatX, style->d()->patternRepeatY); + if (style && *style->d()->brush != r->d()->context->state.strokeStyle) { + r->d()->context->state.strokeStyle = *style->d()->brush; + r->d()->context->buffer()->setStrokeStyle(*style->d()->brush, style->d()->patternRepeatX, style->d()->patternRepeatY); r->d()->context->m_strokeStyle.set(scope.engine, value); r->d()->context->state.strokePatternRepeatX = style->d()->patternRepeatX; r->d()->context->state.strokePatternRepeatY = style->d()->patternRepeatY; @@ -1556,7 +1573,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createLinearGradient(QV4:: QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>()); QV4::ScopedObject p(scope, ed->gradientProto.value()); gradient->setPrototype(p); - gradient->d()->brush = QLinearGradient(x0, y0, x1, y1); + *gradient->d()->brush = QLinearGradient(x0, y0, x1, y1); return gradient.asReturnedValue(); } @@ -1607,7 +1624,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createRadialGradient(QV4:: QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>()); QV4::ScopedObject p(scope, ed->gradientProto.value()); gradient->setPrototype(p); - gradient->d()->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0)); + *gradient->d()->brush = QRadialGradient(QPointF(x1, y1), r0+r1, QPointF(x0, y0)); return gradient.asReturnedValue(); } @@ -1650,7 +1667,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createConicalGradient(QV4: QV4::Scoped<QQuickContext2DStyle> gradient(scope, scope.engine->memoryManager->allocObject<QQuickContext2DStyle>()); QV4::ScopedObject p(scope, ed->gradientProto.value()); gradient->setPrototype(p); - gradient->d()->brush = QConicalGradient(x, y, angle); + *gradient->d()->brush = QConicalGradient(x, y, angle); return gradient.asReturnedValue(); } @@ -1715,7 +1732,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallCon if (patternMode >= 0 && patternMode < Qt::LinearGradientPattern) { style = static_cast<Qt::BrushStyle>(patternMode); } - pattern->d()->brush = QBrush(color, style); + *pattern->d()->brush = QBrush(color, style); } else { QImage patternTexture; @@ -1723,14 +1740,14 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createPattern(QV4::CallCon QV4::ScopedString s(scope, scope.engine->newString(QStringLiteral("data"))); QV4::Scoped<QQuickJSContext2DPixelData> pixelData(scope, o->get(s)); if (!!pixelData) { - patternTexture = pixelData->d()->image; + patternTexture = *pixelData->d()->image; } } else { patternTexture = r->d()->context->createPixmap(QUrl(ctx->args()[0].toQStringNoThrow()))->image(); } if (!patternTexture.isNull()) { - pattern->d()->brush.setTextureImage(patternTexture); + pattern->d()->brush->setTextureImage(patternTexture); QString repetition = ctx->args()[1].toQStringNoThrow(); if (repetition == QLatin1String("repeat") || repetition.isEmpty()) { @@ -2669,15 +2686,15 @@ QV4::ReturnedValue QQuickJSContext2D::method_set_textAlign(QV4::CallContext *ctx QString textAlign = s->toQString(); QQuickContext2D::TextAlignType ta; - if (textAlign == QStringLiteral("start")) + if (textAlign == QLatin1String("start")) ta = QQuickContext2D::Start; - else if (textAlign == QStringLiteral("end")) + else if (textAlign == QLatin1String("end")) ta = QQuickContext2D::End; - else if (textAlign == QStringLiteral("left")) + else if (textAlign == QLatin1String("left")) ta = QQuickContext2D::Left; - else if (textAlign == QStringLiteral("right")) + else if (textAlign == QLatin1String("right")) ta = QQuickContext2D::Right; - else if (textAlign == QStringLiteral("center")) + else if (textAlign == QLatin1String("center")) ta = QQuickContext2D::Center; else return QV4::Encode::undefined(); @@ -2920,8 +2937,8 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_drawImage(QV4::CallContext QV4::Scoped<QQuickJSContext2DImageData> imageData(scope, arg); if (!!imageData) { QV4::Scoped<QQuickJSContext2DPixelData> pix(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>()); - if (pix && !pix->d()->image.isNull()) { - pixmap.adopt(new QQuickCanvasPixmap(pix->d()->image)); + if (pix && !pix->d()->image->isNull()) { + pixmap.adopt(new QQuickCanvasPixmap(*pix->d()->image)); } else { V4THROW_DOM(DOMEXCEPTION_TYPE_MISMATCH_ERR, "drawImage(), type mismatch"); } @@ -3029,7 +3046,7 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_width(QV4::CallContext QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>()); if (!r) return QV4::Encode(0); - return QV4::Encode(r->d()->image.width()); + return QV4::Encode(r->d()->image->width()); } /*! @@ -3045,7 +3062,7 @@ QV4::ReturnedValue QQuickJSContext2DImageData::method_get_height(QV4::CallContex QV4::Scoped<QQuickJSContext2DPixelData> r(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>()); if (!r) return QV4::Encode(0); - return QV4::Encode(r->d()->image.height()); + return QV4::Encode(r->d()->image->height()); } /*! @@ -3083,10 +3100,10 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::proto_get_length(QV4::CallContext { QV4::Scope scope(ctx); QV4::Scoped<QQuickJSContext2DPixelData> r(scope, ctx->thisObject().as<QQuickJSContext2DPixelData>()); - if (!r || r->d()->image.isNull()) + if (!r || r->d()->image->isNull()) return QV4::Encode::undefined(); - return QV4::Encode(r->d()->image.width() * r->d()->image.height() * 4); + return QV4::Encode(r->d()->image->width() * r->d()->image->height() * 4); } QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, uint index, bool *hasProperty) @@ -3096,13 +3113,13 @@ QV4::ReturnedValue QQuickJSContext2DPixelData::getIndexed(const QV4::Managed *m, QV4::Scope scope(v4); QV4::Scoped<QQuickJSContext2DPixelData> r(scope, static_cast<const QQuickJSContext2DPixelData *>(m)); - if (index < static_cast<quint32>(r->d()->image.width() * r->d()->image.height() * 4)) { + if (index < static_cast<quint32>(r->d()->image->width() * r->d()->image->height() * 4)) { if (hasProperty) *hasProperty = true; - const quint32 w = r->d()->image.width(); + const quint32 w = r->d()->image->width(); const quint32 row = (index / 4) / w; const quint32 col = (index / 4) % w; - const QRgb* pixel = reinterpret_cast<const QRgb*>(r->d()->image.constScanLine(row)); + const QRgb* pixel = reinterpret_cast<const QRgb*>(r->d()->image->constScanLine(row)); pixel += col; switch (index % 4) { case 0: @@ -3131,12 +3148,12 @@ void QQuickJSContext2DPixelData::putIndexed(QV4::Managed *m, uint index, const Q QV4::Scoped<QQuickJSContext2DPixelData> r(scope, static_cast<QQuickJSContext2DPixelData *>(m)); const int v = value.toInt32(); - if (r && index < static_cast<quint32>(r->d()->image.width() * r->d()->image.height() * 4) && v >= 0 && v <= 255) { - const quint32 w = r->d()->image.width(); + if (r && index < static_cast<quint32>(r->d()->image->width() * r->d()->image->height() * 4) && v >= 0 && v <= 255) { + const quint32 w = r->d()->image->width(); const quint32 row = (index / 4) / w; const quint32 col = (index / 4) % w; - QRgb* pixel = reinterpret_cast<QRgb*>(r->d()->image.scanLine(row)); + QRgb* pixel = reinterpret_cast<QRgb*>(r->d()->image->scanLine(row)); pixel += col; switch (index % 4) { case 0: @@ -3187,8 +3204,8 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_createImageData(QV4::CallC if (!!imgData) { QV4::Scoped<QQuickJSContext2DPixelData> pa(scope, imgData->d()->pixelData.as<QQuickJSContext2DPixelData>()); if (pa) { - qreal w = pa->d()->image.width(); - qreal h = pa->d()->image.height(); + qreal w = pa->d()->image->width(); + qreal h = pa->d()->image->height(); return qt_create_image_data(w, h, scope.engine, QImage()); } } else if (arg0->isString()) { @@ -3266,8 +3283,8 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont QV4::Scoped<QQuickJSContext2DPixelData> pixelArray(scope, imageData->d()->pixelData.as<QQuickJSContext2DPixelData>()); if (pixelArray) { - w = pixelArray->d()->image.width(); - h = pixelArray->d()->image.height(); + w = pixelArray->d()->image->width(); + h = pixelArray->d()->image->height(); if (ctx->argc() == 7) { dirtyX = ctx->args()[3].toNumber(); @@ -3316,7 +3333,7 @@ QV4::ReturnedValue QQuickJSContext2DPrototype::method_putImageData(QV4::CallCont dirtyHeight = h; } - QImage image = pixelArray->d()->image.copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight); + QImage image = pixelArray->d()->image->copy(dirtyX, dirtyY, dirtyWidth, dirtyHeight); r->d()->context->buffer()->drawImage(image, QRectF(dirtyX, dirtyY, dirtyWidth, dirtyHeight), QRectF(dx, dy, dirtyWidth, dirtyHeight)); } return ctx->thisObject().asReturnedValue(); @@ -3351,9 +3368,9 @@ QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::CallCo if (ctx->argc() == 2) { - if (!style->d()->brush.gradient()) + if (!style->d()->brush->gradient()) V4THROW_ERROR("Not a valid CanvasGradient object, can't get the gradient information"); - QGradient gradient = *(style->d()->brush.gradient()); + QGradient gradient = *(style->d()->brush->gradient()); qreal pos = ctx->args()[0].toNumber(); QColor color; @@ -3371,7 +3388,7 @@ QV4::ReturnedValue QQuickContext2DStyle::gradient_proto_addColorStop(QV4::CallCo } else { V4THROW_DOM(DOMEXCEPTION_SYNTAX_ERR, "CanvasGradient: parameter color is not a valid color string"); } - style->d()->brush = gradient; + *style->d()->brush = gradient; } return ctx->thisObject().asReturnedValue(); @@ -3980,10 +3997,12 @@ public: ~QQuickContext2DThreadCleanup() { +#ifndef QT_NO_OPENGL context->makeCurrent(surface); delete texture; context->doneCurrent(); delete context; +#endif surface->deleteLater(); } @@ -4019,6 +4038,7 @@ QQuickContext2D::~QQuickContext2D() delete m_buffer; if (m_renderTarget == QQuickCanvasItem::FramebufferObject) { +#ifndef QT_NO_OPENGL if (m_renderStrategy == QQuickCanvasItem::Immediate && m_glContext) { Q_ASSERT(QThread::currentThread() == m_glContext->thread()); m_glContext->makeCurrent(m_surface.data()); @@ -4039,6 +4059,7 @@ QQuickContext2D::~QQuickContext2D() m_texture->deleteLater(); } } +#endif } else { // Image based does not have GL resources, but must still be deleted // on its designated thread after it has completed whatever it might @@ -4064,8 +4085,6 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args m_canvas = canvasItem; m_renderTarget = canvasItem->renderTarget(); - - QQuickWindow *window = canvasItem->window(); m_renderStrategy = canvasItem->renderStrategy(); #ifdef Q_OS_WIN @@ -4084,12 +4103,24 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args m_renderTarget = QQuickCanvasItem::Image; } + // Disable Framebuffer Object based rendering when not running with OpenGL + if (m_renderTarget == QQuickCanvasItem::FramebufferObject) { + QSGRendererInterface *rif = canvasItem->window()->rendererInterface(); + if (rif && rif->graphicsApi() != QSGRendererInterface::OpenGL) + m_renderTarget = QQuickCanvasItem::Image; + } + switch (m_renderTarget) { case QQuickCanvasItem::Image: m_texture = new QQuickContext2DImageTexture; break; case QQuickCanvasItem::FramebufferObject: +#ifndef QT_NO_OPENGL m_texture = new QQuickContext2DFBOTexture; +#else + // It shouldn't be possible to use a FramebufferObject without OpenGL + m_texture = nullptr; +#endif break; } @@ -4103,18 +4134,27 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args m_thread = QThread::currentThread(); QThread *renderThread = m_thread; - QThread *sceneGraphThread = window->openglContext() ? window->openglContext()->thread() : 0; +#ifndef QT_NO_OPENGL + QQuickWindow *window = canvasItem->window(); + QQuickWindowPrivate *wd = QQuickWindowPrivate::get(window); + QThread *sceneGraphThread = wd->context->thread(); if (m_renderStrategy == QQuickCanvasItem::Threaded) renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem)); else if (m_renderStrategy == QQuickCanvasItem::Cooperative) renderThread = sceneGraphThread; +#else + if (m_renderStrategy == QQuickCanvasItem::Threaded) + renderThread = QQuickContext2DRenderThread::instance(qmlEngine(canvasItem)); +#endif + if (renderThread && renderThread != QThread::currentThread()) m_texture->moveToThread(renderThread); - +#ifndef QT_NO_OPENGL if (m_renderTarget == QQuickCanvasItem::FramebufferObject && renderThread != sceneGraphThread) { - QOpenGLContext *cc = QQuickWindowPrivate::get(window)->context->openglContext(); + auto openglRenderContext = static_cast<const QSGDefaultRenderContext *>(QQuickWindowPrivate::get(window)->context); + QOpenGLContext *cc = openglRenderContext->openglContext(); m_surface.reset(new QOffscreenSurface); m_surface->setFormat(window->format()); m_surface->create(); @@ -4125,7 +4165,7 @@ void QQuickContext2D::init(QQuickCanvasItem *canvasItem, const QVariantMap &args m_glContext->moveToThread(renderThread); m_texture->initializeOpenGL(m_glContext, m_surface.data()); } - +#endif connect(m_texture, SIGNAL(textureChanged()), SIGNAL(textureChanged())); reset(); @@ -4172,6 +4212,7 @@ QImage QQuickContext2D::toImage(const QRectF& bounds) flush(); m_texture->grabImage(bounds); } else { +#ifndef QT_NO_OPENGL QQuickWindow *window = m_canvas->window(); QOpenGLContext *ctx = window ? window->openglContext() : 0; if (ctx && ctx->isValid()) { @@ -4187,6 +4228,10 @@ QImage QQuickContext2D::toImage(const QRectF& bounds) qWarning() << "Cannot read pixels from canvas before opengl context is valid"; return QImage(); } +#else + flush(); + m_texture->grabImage(bounds); +#endif } } else if (m_renderStrategy == QQuickCanvasItem::Cooperative) { qWarning() << "Pixel readback is not supported in Cooperative mode, please try Threaded or Immediate mode"; diff --git a/src/quick/items/context2d/qquickcontext2d_p.h b/src/quick/items/context2d/qquickcontext2d_p.h index cfb62ee052..e897263b6f 100644 --- a/src/quick/items/context2d/qquickcontext2d_p.h +++ b/src/quick/items/context2d/qquickcontext2d_p.h @@ -51,7 +51,10 @@ // We mean it. // -#include <QtQuick/qtquickglobal.h> +#include <private/qtquickglobal_p.h> + +QT_REQUIRE_CONFIG(quick_canvas); + #include <QtQml/qqml.h> #include <QtQml/qqmlcomponent.h> #include <private/qquickcanvascontext_p.h> @@ -126,8 +129,8 @@ public: struct State { State() - : strokeStyle(QColor("#000000")) - , fillStyle(QColor("#000000")) + : strokeStyle(QColor(Qt::black)) + , fillStyle(QColor(Qt::black)) , fillPatternRepeatX(false) , fillPatternRepeatY(false) , strokePatternRepeatX(false) diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp index 58b374e696..8d659040b3 100644 --- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp +++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp @@ -42,9 +42,11 @@ #include <qqml.h> #include <QtCore/QMutex> #include <QtQuick/qsgtexture.h> -#include <QtGui/QOpenGLContext> #include <QtGui/QPaintEngine> -#include <QtGui/private/qopenglpaintengine_p.h> +#ifndef QT_NO_OPENGL +# include <QtGui/QOpenGLContext> +# include <QtGui/private/qopenglpaintengine_p.h> +#endif #define HAS_SHADOW(offsetX, offsetY, blur, color) (color.isValid() && color.alpha() && (blur || offsetX || offsetY)) diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h index a82b88f36f..3663e49f10 100644 --- a/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h +++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer_p.h @@ -51,6 +51,10 @@ // We mean it. // +#include <private/qtquickglobal_p.h> + +QT_REQUIRE_CONFIG(quick_canvas); + #include <QtCore/qmutex.h> #include "qquickcontext2d_p.h" @@ -70,7 +74,7 @@ public: inline int size() {return commands.size();} inline bool isEmpty() const {return commands.isEmpty(); } inline bool hasNext() const {return cmdIdx < commands.size(); } - inline QQuickContext2D::PaintCommand takeNextCommand() { return commands[cmdIdx++]; } + inline QQuickContext2D::PaintCommand takeNextCommand() { return commands.at(cmdIdx++); } inline qreal takeGlobalAlpha() { return takeReal(); } inline QPainter::CompositionMode takeGlobalCompositeOperation(){ return static_cast<QPainter::CompositionMode>(takeInt()); } @@ -227,20 +231,20 @@ public: colors << color; } - inline QTransform takeMatrix() { return matrixes[matrixIdx++]; } + inline QTransform takeMatrix() { return matrixes.at(matrixIdx++); } - inline QRectF takeRect() { return rects[rectIdx++]; } + inline QRectF takeRect() { return rects.at(rectIdx++); } - inline QPainterPath takePath() { return pathes[pathIdx++]; } + inline QPainterPath takePath() { return pathes.at(pathIdx++); } - inline const QImage& takeImage() { return images[imageIdx++]; } - inline QQmlRefPointer<QQuickCanvasPixmap> takePixmap() { return pixmaps[pixmapIdx++]; } + inline const QImage& takeImage() { return images.at(imageIdx++); } + inline QQmlRefPointer<QQuickCanvasPixmap> takePixmap() { return pixmaps.at(pixmapIdx++); } - inline int takeInt() { return ints[intIdx++]; } - inline bool takeBool() {return bools[boolIdx++]; } - inline qreal takeReal() { return reals[realIdx++]; } - inline QColor takeColor() { return colors[colorIdx++]; } - inline QBrush takeBrush() { return brushes[brushIdx++]; } + inline int takeInt() { return ints.at(intIdx++); } + inline bool takeBool() {return bools.at(boolIdx++); } + inline qreal takeReal() { return reals.at(realIdx++); } + inline QColor takeColor() { return colors.at(colorIdx++); } + inline QBrush takeBrush() { return brushes.at(brushIdx++); } void replay(QPainter* painter, QQuickContext2D::State& state, const QVector2D &scaleFactor); diff --git a/src/quick/items/context2d/qquickcontext2dtexture.cpp b/src/quick/items/context2d/qquickcontext2dtexture.cpp index 375f537b9b..4435c0c37b 100644 --- a/src/quick/items/context2d/qquickcontext2dtexture.cpp +++ b/src/quick/items/context2d/qquickcontext2dtexture.cpp @@ -44,14 +44,16 @@ #include <QtQuick/private/qsgtexture_p.h> #include "qquickcontext2dcommandbuffer_p.h" #include <QOpenGLPaintDevice> - +#ifndef QT_NO_OPENGL #include <QOpenGLFramebufferObject> #include <QOpenGLFramebufferObjectFormat> +#include <QOpenGLFunctions> +#endif #include <QtCore/QThread> #include <QtGui/QGuiApplication> QT_BEGIN_NAMESPACE - +#ifndef QT_NO_OPENGL #define QT_MINIMUM_FBO_SIZE 64 static inline int qt_next_power_of_two(int v) @@ -85,10 +87,12 @@ struct GLAcquireContext { } QOpenGLContext *ctx; }; - +#endif QQuickContext2DTexture::QQuickContext2DTexture() : m_context(0) +#ifndef QT_NO_OPENGL , m_gl(0) +#endif , m_surface(0) , m_item(0) , m_canvasWindowChanged(false) @@ -250,9 +254,9 @@ void QQuickContext2DTexture::paint(QQuickContext2DCommandBuffer *ccb) return; } QQuickContext2D::mutex.unlock(); - +#ifndef QT_NO_OPENGL GLAcquireContext currentContext(m_gl, m_surface); - +#endif if (!m_tiledCanvas) { paintWithoutTiles(ccb); delete ccb; @@ -379,7 +383,7 @@ bool QQuickContext2DTexture::event(QEvent *e) } return QObject::event(e); } - +#ifndef QT_NO_OPENGL static inline QSize npotAdjustedSize(const QSize &size) { static bool checked = false; @@ -650,6 +654,7 @@ void QQuickContext2DFBOTexture::endPainting() m_fbo->bindDefault(); } +#endif QQuickContext2DImageTexture::QQuickContext2DImageTexture() : QQuickContext2DTexture() diff --git a/src/quick/items/context2d/qquickcontext2dtexture_p.h b/src/quick/items/context2d/qquickcontext2dtexture_p.h index edc7283283..6a5d4e8b09 100644 --- a/src/quick/items/context2d/qquickcontext2dtexture_p.h +++ b/src/quick/items/context2d/qquickcontext2dtexture_p.h @@ -51,13 +51,17 @@ // We mean it. // +#include <private/qtquickglobal_p.h> + +QT_REQUIRE_CONFIG(quick_canvas); + #include <QtQuick/qsgtexture.h> #include "qquickcanvasitem_p.h" #include "qquickcontext2d_p.h" - -#include <QOpenGLContext> -#include <QOpenGLFramebufferObject> - +#ifndef QT_NO_OPENGL +# include <QOpenGLContext> +# include <QOpenGLFramebufferObject> +#endif #include <QtCore/QMutex> #include <QtCore/QWaitCondition> #include <QtCore/QThread> @@ -121,11 +125,12 @@ public: // Called during sync() on the scene graph thread while GUI is blocked. virtual QSGTexture *textureForNextFrame(QSGTexture *lastFrame, QQuickWindow *window) = 0; bool event(QEvent *e); - +#ifndef QT_NO_OPENGL void initializeOpenGL(QOpenGLContext *gl, QOffscreenSurface *s) { m_gl = gl; m_surface = s; } +#endif Q_SIGNALS: void textureChanged(); @@ -152,8 +157,9 @@ protected: QList<QQuickContext2DTile*> m_tiles; QQuickContext2D *m_context; - +#ifndef QT_NO_OPENGL QOpenGLContext *m_gl; +#endif QSurface *m_surface; QQuickContext2D::State m_state; @@ -174,7 +180,7 @@ protected: uint m_painting : 1; uint m_onCustomThread : 1; // Not GUI and not SGRender }; - +#ifndef QT_NO_OPENGL class QQuickContext2DFBOTexture : public QQuickContext2DTexture { Q_OBJECT @@ -209,7 +215,7 @@ private: GLuint m_displayTextures[2]; int m_displayTexture; }; - +#endif class QSGPlainTexture; class QQuickContext2DImageTexture : public QQuickContext2DTexture { diff --git a/src/quick/items/context2d/qquickcontext2dtile.cpp b/src/quick/items/context2d/qquickcontext2dtile.cpp index a1503762de..95b6c9d961 100644 --- a/src/quick/items/context2d/qquickcontext2dtile.cpp +++ b/src/quick/items/context2d/qquickcontext2dtile.cpp @@ -38,10 +38,11 @@ ****************************************************************************/ #include "qquickcontext2dtile_p.h" - -#include <QOpenGLFramebufferObject> -#include <QOpenGLFramebufferObjectFormat> -#include <QOpenGLPaintDevice> +#ifndef QT_NO_OPENGL +# include <QOpenGLFramebufferObject> +# include <QOpenGLFramebufferObjectFormat> +# include <QOpenGLPaintDevice> +#endif QT_BEGIN_NAMESPACE @@ -96,7 +97,7 @@ QPainter* QQuickContext2DTile::createPainter(bool smooth, bool antialiasing) return 0; } - +#ifndef QT_NO_OPENGL QQuickContext2DFBOTile::QQuickContext2DFBOTile() : QQuickContext2DTile() , m_fbo(0) @@ -146,7 +147,7 @@ void QQuickContext2DFBOTile::setRect(const QRect& r) m_fbo = new QOpenGLFramebufferObject(r.size(), format); } } - +#endif QQuickContext2DImageTile::QQuickContext2DImageTile() : QQuickContext2DTile() diff --git a/src/quick/items/context2d/qquickcontext2dtile_p.h b/src/quick/items/context2d/qquickcontext2dtile_p.h index d9be2023c4..2f3fdeb54f 100644 --- a/src/quick/items/context2d/qquickcontext2dtile_p.h +++ b/src/quick/items/context2d/qquickcontext2dtile_p.h @@ -51,9 +51,14 @@ // We mean it. // -#include "qquickcontext2d_p.h" -#include <QOpenGLFramebufferObject> +#include <private/qtquickglobal_p.h> + +QT_REQUIRE_CONFIG(quick_canvas); +#include "qquickcontext2d_p.h" +#ifndef QT_NO_OPENGL +# include <QOpenGLFramebufferObject> +#endif QT_BEGIN_NAMESPACE class QQuickContext2DTexture; @@ -82,7 +87,7 @@ protected: QPainter m_painter; }; - +#ifndef QT_NO_OPENGL class QQuickContext2DFBOTile : public QQuickContext2DTile { public: @@ -99,7 +104,7 @@ private: QOpenGLFramebufferObject *m_fbo; }; - +#endif class QQuickContext2DImageTile : public QQuickContext2DTile { public: |