aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@nokia.com>2011-11-11 16:49:41 +0100
committerQt by Nokia <qt-info@nokia.com>2011-11-14 15:28:43 +0100
commitace4b5881c6074b6e525281e0daa3a4740203b15 (patch)
treea9f51f4b1c423764e74fcaa4791d08d0747ccb63
parentfd58c5fc9fa5dc1aa975cf40a5a58945671e22ee (diff)
Distance field glyph cache refactoring.
The distance field glyph cache is now an abstract class part of the adaptation layer. It can be implemented to define the way the glyphs are stored in graphics memory on a specific platform. The typical use case is for having a cross-process glyph cache. To implement a custom glyph cache, one has to override three pure virtual functions: requestGlyphs(), storeGlyphs() and releaseGlyphs(). The default implementation works the same way as before the refactoring (no cross-process cache). Change-Id: I6e231a119abbffbe36f5f0d690f0b8be0664ff4f Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
-rw-r--r--src/declarative/items/qquicktext.cpp1
-rw-r--r--src/declarative/items/qquicktextedit.cpp1
-rw-r--r--src/declarative/items/qquicktextinput.cpp1
-rw-r--r--src/declarative/items/qquicktextnode.cpp1
-rw-r--r--src/declarative/scenegraph/qsgadaptationlayer.cpp273
-rw-r--r--src/declarative/scenegraph/qsgadaptationlayer_p.h125
-rw-r--r--src/declarative/scenegraph/qsgcontext.cpp14
-rw-r--r--src/declarative/scenegraph/qsgcontext_p.h5
-rw-r--r--src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache.cpp389
-rw-r--r--src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache_p.h108
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h210
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp199
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp25
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h13
-rw-r--r--src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h11
-rw-r--r--src/declarative/scenegraph/scenegraph.pri16
-rw-r--r--src/declarative/scenegraph/util/qsgdistancefieldutil.cpp (renamed from src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp)501
-rw-r--r--src/declarative/scenegraph/util/qsgdistancefieldutil_p.h111
-rw-r--r--tests/auto/declarative/qquicktext/tst_qquicktext.cpp1
-rw-r--r--tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp1
-rw-r--r--tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp1
21 files changed, 1199 insertions, 808 deletions
diff --git a/src/declarative/items/qquicktext.cpp b/src/declarative/items/qquicktext.cpp
index 4a3308626a..e11e4be089 100644
--- a/src/declarative/items/qquicktext.cpp
+++ b/src/declarative/items/qquicktext.cpp
@@ -42,7 +42,6 @@
#include "qquicktext_p.h"
#include "qquicktext_p_p.h"
-#include <private/qsgdistancefieldglyphcache_p.h>
#include <private/qsgcontext_p.h>
#include <private/qsgadaptationlayer_p.h>
#include "qquicktextnode_p.h"
diff --git a/src/declarative/items/qquicktextedit.cpp b/src/declarative/items/qquicktextedit.cpp
index 18d2cb8ede..c5b2f5750b 100644
--- a/src/declarative/items/qquicktextedit.cpp
+++ b/src/declarative/items/qquicktextedit.cpp
@@ -56,7 +56,6 @@
#include <private/qdeclarativeglobal_p.h>
#include <private/qtextcontrol_p.h>
#include <private/qtextengine_p.h>
-#include <private/qsgdistancefieldglyphcache_p.h>
#include <private/qsgtexture_p.h>
#include <private/qsgadaptationlayer_p.h>
diff --git a/src/declarative/items/qquicktextinput.cpp b/src/declarative/items/qquicktextinput.cpp
index 69f699446a..218a313a17 100644
--- a/src/declarative/items/qquicktextinput.cpp
+++ b/src/declarative/items/qquicktextinput.cpp
@@ -44,7 +44,6 @@
#include "qquickcanvas.h"
#include <private/qdeclarativeglobal_p.h>
-#include <private/qsgdistancefieldglyphcache_p.h>
#include <QtDeclarative/qdeclarativeinfo.h>
#include <QtGui/qevent.h>
diff --git a/src/declarative/items/qquicktextnode.cpp b/src/declarative/items/qquicktextnode.cpp
index 5cc372f9e1..56c3b54cd7 100644
--- a/src/declarative/items/qquicktextnode.cpp
+++ b/src/declarative/items/qquicktextnode.cpp
@@ -42,7 +42,6 @@
#include "qquicktextnode_p.h"
#include "qsgsimplerectnode.h"
#include <private/qsgadaptationlayer_p.h>
-#include <private/qsgdistancefieldglyphcache_p.h>
#include <private/qsgdistancefieldglyphnode_p.h>
#include <private/qsgcontext_p.h>
diff --git a/src/declarative/scenegraph/qsgadaptationlayer.cpp b/src/declarative/scenegraph/qsgadaptationlayer.cpp
index e573e5f344..966a24acd3 100644
--- a/src/declarative/scenegraph/qsgadaptationlayer.cpp
+++ b/src/declarative/scenegraph/qsgadaptationlayer.cpp
@@ -40,3 +40,276 @@
****************************************************************************/
#include "qsgadaptationlayer_p.h"
+
+#include <qmath.h>
+#include <private/qsgdistancefieldutil_p.h>
+#include <private/qsgdistancefieldglyphnode_p.h>
+#include <private/qrawfont_p.h>
+#include <QtGui/qguiapplication.h>
+#include <qdir.h>
+
+QT_BEGIN_NAMESPACE
+
+
+QHash<QString, QOpenGLMultiGroupSharedResource> QSGDistanceFieldGlyphCache::m_caches_data;
+
+QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
+ : ctx(c)
+ , m_manager(man)
+{
+ Q_ASSERT(font.isValid());
+ m_font = font;
+
+ m_cacheData = cacheData();
+
+ QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
+ m_glyphCount = fontD->fontEngine->glyphCount();
+
+ m_cacheData->doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
+
+ m_referenceFont = m_font;
+ m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(m_cacheData->doubleGlyphResolution));
+ Q_ASSERT(m_referenceFont.isValid());
+}
+
+QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
+{
+}
+
+QSGDistanceFieldGlyphCache::GlyphCacheData *QSGDistanceFieldGlyphCache::cacheData()
+{
+ QString key = QString::fromLatin1("%1_%2_%3_%4")
+ .arg(m_font.familyName())
+ .arg(m_font.styleName())
+ .arg(m_font.weight())
+ .arg(m_font.style());
+ return m_caches_data[key].value<QSGDistanceFieldGlyphCache::GlyphCacheData>(ctx);
+}
+
+qreal QSGDistanceFieldGlyphCache::fontScale() const
+{
+ return qreal(m_font.pixelSize()) / QT_DISTANCEFIELD_BASEFONTSIZE(m_cacheData->doubleGlyphResolution);
+}
+
+int QSGDistanceFieldGlyphCache::distanceFieldRadius() const
+{
+ return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution);
+}
+
+QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph)
+{
+ QHash<glyph_t, Metrics>::iterator metric = m_metrics.find(glyph);
+ if (metric == m_metrics.end()) {
+ QPainterPath path = m_font.pathForGlyph(glyph);
+ QRectF br = path.boundingRect();
+
+ Metrics m;
+ m.width = br.width();
+ m.height = br.height();
+ m.baselineX = br.x();
+ m.baselineY = -br.y();
+
+ metric = m_metrics.insert(glyph, m);
+ }
+
+ return metric.value();
+}
+
+QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph) const
+{
+ return m_cacheData->texCoords.value(glyph);
+}
+
+static QSGDistanceFieldGlyphCache::Texture g_emptyTexture;
+
+const QSGDistanceFieldGlyphCache::Texture *QSGDistanceFieldGlyphCache::glyphTexture(glyph_t glyph) const
+{
+ QHash<glyph_t, Texture*>::const_iterator it = m_cacheData->glyphTextures.find(glyph);
+ if (it == m_cacheData->glyphTextures.constEnd())
+ return &g_emptyTexture;
+ return it.value();
+}
+
+void QSGDistanceFieldGlyphCache::populate(const QVector<glyph_t> &glyphs)
+{
+ QSet<glyph_t> newGlyphs;
+ int count = glyphs.count();
+ for (int i = 0; i < count; ++i) {
+ glyph_t glyphIndex = glyphs.at(i);
+ if ((int) glyphIndex >= glyphCount()) {
+ qWarning("Warning: distance-field glyph is not available with index %d", glyphIndex);
+ continue;
+ }
+
+ if (m_cacheData->texCoords.contains(glyphIndex) || newGlyphs.contains(glyphIndex))
+ continue;
+
+ QPainterPath path = m_referenceFont.pathForGlyph(glyphIndex);
+ m_cacheData->glyphPaths.insert(glyphIndex, path);
+ if (path.isEmpty()) {
+ TexCoord c;
+ c.width = 0;
+ c.height = 0;
+ m_cacheData->texCoords.insert(glyphIndex, c);
+ continue;
+ }
+
+ newGlyphs.insert(glyphIndex);
+ }
+
+ if (newGlyphs.isEmpty())
+ return;
+
+ QVector<glyph_t> glyphsVec;
+ QSet<glyph_t>::const_iterator it = newGlyphs.constBegin();
+ while (it != newGlyphs.constEnd()) {
+ glyphsVec.append(*it);
+ ++it;
+ }
+ requestGlyphs(glyphsVec);
+}
+
+void QSGDistanceFieldGlyphCache::release(const QVector<glyph_t> &glyphs)
+{
+ releaseGlyphs(glyphs);
+}
+
+void QSGDistanceFieldGlyphCache::update()
+{
+ if (m_cacheData->pendingGlyphs.isEmpty())
+ return;
+
+ QHash<glyph_t, QImage> distanceFields;
+
+ // ### Remove before final release
+ static bool cacheDistanceFields = QGuiApplication::arguments().contains(QLatin1String("--cache-distance-fields"));
+
+ QString tmpPath = QString::fromLatin1("%1/.qt/").arg(QDir::tempPath());
+ QString keyBase = QString::fromLatin1("%1%2%3_%4_%5_%6.fontblob")
+ .arg(tmpPath)
+ .arg(m_font.familyName())
+ .arg(m_font.styleName())
+ .arg(m_font.weight())
+ .arg(m_font.style());
+
+ if (cacheDistanceFields && !QFile::exists(tmpPath))
+ QDir(tmpPath).mkpath(tmpPath);
+
+ for (int i = 0; i < m_cacheData->pendingGlyphs.size(); ++i) {
+ glyph_t glyphIndex = m_cacheData->pendingGlyphs.at(i);
+
+ if (cacheDistanceFields) {
+ QString key = keyBase.arg(glyphIndex);
+ QFile file(key);
+ if (file.open(QFile::ReadOnly)) {
+ int fileSize = file.size();
+ int dim = sqrt(float(fileSize));
+ QByteArray blob = file.readAll();
+ QImage df(dim, dim, QImage::Format_Indexed8);
+ memcpy(df.bits(), blob.constData(), fileSize);
+ distanceFields.insert(glyphIndex, df);
+ continue;
+ }
+ }
+
+ QImage distanceField = qt_renderDistanceFieldGlyph(m_font, glyphIndex, m_cacheData->doubleGlyphResolution);
+ distanceFields.insert(glyphIndex, distanceField);
+
+ if (cacheDistanceFields) {
+ QString key = keyBase.arg(glyphIndex);
+ QFile file(key);
+ file.open(QFile::WriteOnly);
+ file.write((const char *) distanceField.constBits(), distanceField.width() * distanceField.height());
+ }
+ }
+
+ m_cacheData->pendingGlyphs.reset();
+
+ storeGlyphs(distanceFields);
+}
+
+void QSGDistanceFieldGlyphCache::addGlyphPositions(const QList<GlyphPosition> &glyphs)
+{
+ int count = glyphs.count();
+ for (int i = 0; i < count; ++i) {
+ GlyphPosition glyph = glyphs.at(i);
+
+ QPainterPath path = m_cacheData->glyphPaths.value(glyph.glyph);
+ QRectF br = path.boundingRect();
+ TexCoord c;
+ c.xMargin = QT_DISTANCEFIELD_RADIUS(m_cacheData->doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution));
+ c.yMargin = QT_DISTANCEFIELD_RADIUS(m_cacheData->doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution));
+ c.x = glyph.position.x();
+ c.y = glyph.position.y();
+ c.width = br.width();
+ c.height = br.height();
+
+ m_cacheData->texCoords.insert(glyph.glyph, c);
+ }
+}
+
+void QSGDistanceFieldGlyphCache::addGlyphTextures(const QVector<glyph_t> &glyphs, const Texture &tex)
+{
+ int i = m_cacheData->textures.indexOf(tex);
+ if (i == -1) {
+ m_cacheData->textures.append(tex);
+ i = m_cacheData->textures.size() - 1;
+ } else {
+ m_cacheData->textures[i].size = tex.size;
+ }
+ Texture *texture = &(m_cacheData->textures[i]);
+
+ int count = glyphs.count();
+ for (int j = 0; j < count; ++j)
+ m_cacheData->glyphTextures.insert(glyphs.at(j), texture);
+
+ QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_cacheData->m_registeredNodes.begin();
+ while (it != m_cacheData->m_registeredNodes.end()) {
+ (*it)->updateGeometry();
+ ++it;
+ }
+}
+
+void QSGDistanceFieldGlyphCache::markGlyphsToRender(const QVector<glyph_t> &glyphs)
+{
+ int count = glyphs.count();
+ for (int i = 0; i < count; ++i)
+ m_cacheData->pendingGlyphs.add(glyphs.at(i));
+}
+
+void QSGDistanceFieldGlyphCache::removeGlyph(glyph_t glyph)
+{
+ m_cacheData->texCoords.remove(glyph);
+ m_cacheData->glyphTextures.remove(glyph);
+}
+
+void QSGDistanceFieldGlyphCache::updateTexture(GLuint oldTex, GLuint newTex, const QSize &newTexSize)
+{
+ int count = m_cacheData->textures.count();
+ for (int i = 0; i < count; ++i) {
+ Texture &tex = m_cacheData->textures[i];
+ if (tex.textureId == oldTex) {
+ tex.textureId = newTex;
+ tex.size = newTexSize;
+ return;
+ }
+ }
+}
+
+bool QSGDistanceFieldGlyphCache::containsGlyph(glyph_t glyph) const
+{
+ return m_cacheData->texCoords.contains(glyph);
+}
+
+void QSGDistanceFieldGlyphCache::registerGlyphNode(QSGDistanceFieldGlyphNode *node)
+{
+ m_cacheData->m_registeredNodes.append(node);
+}
+
+void QSGDistanceFieldGlyphCache::unregisterGlyphNode(QSGDistanceFieldGlyphNode *node)
+{
+ m_cacheData->m_registeredNodes.removeOne(node);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgadaptationlayer_p.h b/src/declarative/scenegraph/qsgadaptationlayer_p.h
index 0ad60913b3..82e0c7cf42 100644
--- a/src/declarative/scenegraph/qsgadaptationlayer_p.h
+++ b/src/declarative/scenegraph/qsgadaptationlayer_p.h
@@ -51,6 +51,9 @@
#include <QtCore/qsharedpointer.h>
#include <QtGui/qglyphrun.h>
#include <QtCore/qurl.h>
+#include <private/qfontengine_p.h>
+#include <QtGui/private/qdatabuffer_p.h>
+#include <private/qopenglcontext_p.h>
// ### remove
#include <private/qquicktext_p.h>
@@ -64,6 +67,8 @@ QT_MODULE(Declarative)
class QSGNode;
class QImage;
class TextureReference;
+class QSGDistanceFieldGlyphCacheManager;
+class QSGDistanceFieldGlyphNode;
// TODO: Rename from XInterface to AbstractX.
class Q_DECLARATIVE_EXPORT QSGRectangleNode : public QSGGeometryNode
@@ -124,6 +129,126 @@ protected:
QRectF m_bounding_rect;
};
+class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCache
+{
+public:
+ QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font);
+ virtual ~QSGDistanceFieldGlyphCache();
+
+ struct Metrics {
+ qreal width;
+ qreal height;
+ qreal baselineX;
+ qreal baselineY;
+
+ bool isNull() const { return width == 0 || height == 0; }
+ };
+
+ struct TexCoord {
+ qreal x;
+ qreal y;
+ qreal width;
+ qreal height;
+ qreal xMargin;
+ qreal yMargin;
+
+ TexCoord() : x(0), y(0), width(-1), height(-1), xMargin(0), yMargin(0) { }
+
+ bool isNull() const { return width <= 0 || height <= 0; }
+ bool isValid() const { return width >= 0 && height >= 0; }
+ };
+
+ struct Texture {
+ GLuint textureId;
+ QSize size;
+
+ Texture() : textureId(0), size(QSize()) { }
+ bool operator == (const Texture &other) const { return textureId == other.textureId; }
+ };
+
+ const QSGDistanceFieldGlyphCacheManager *manager() const { return m_manager; }
+
+ const QRawFont &font() const { return m_font; }
+
+ qreal fontScale() const;
+ int distanceFieldRadius() const;
+ int glyphCount() const { return m_glyphCount; }
+ bool doubleGlyphResolution() const { return m_cacheData->doubleGlyphResolution; }
+
+ Metrics glyphMetrics(glyph_t glyph);
+ TexCoord glyphTexCoord(glyph_t glyph) const;
+ const Texture *glyphTexture(glyph_t glyph) const;
+
+ void populate(const QVector<glyph_t> &glyphs);
+ void release(const QVector<glyph_t> &glyphs);
+
+ void update();
+
+ void registerGlyphNode(QSGDistanceFieldGlyphNode *node);
+ void unregisterGlyphNode(QSGDistanceFieldGlyphNode *node);
+
+protected:
+ struct GlyphPosition {
+ glyph_t glyph;
+ QPointF position;
+ };
+
+ virtual void requestGlyphs(const QVector<glyph_t> &glyphs) = 0;
+ virtual void storeGlyphs(const QHash<glyph_t, QImage> &glyphs) = 0;
+ virtual void releaseGlyphs(const QVector<glyph_t> &glyphs) = 0;
+
+ void addGlyphPositions(const QList<GlyphPosition> &glyphs);
+ void addGlyphTextures(const QVector<glyph_t> &glyphs, const Texture &tex);
+ void markGlyphsToRender(const QVector<glyph_t> &glyphs);
+ void removeGlyph(glyph_t glyph);
+
+ void updateTexture(GLuint oldTex, GLuint newTex, const QSize &newTexSize);
+
+ bool containsGlyph(glyph_t glyph) const;
+
+ QOpenGLContext *ctx;
+
+private:
+ struct GlyphCacheData : public QOpenGLSharedResource {
+ QList<Texture> textures;
+ QHash<glyph_t, Texture*> glyphTextures;
+ QHash<glyph_t, TexCoord> texCoords;
+ QDataBuffer<glyph_t> pendingGlyphs;
+ QHash<glyph_t, QPainterPath> glyphPaths;
+ bool doubleGlyphResolution;
+ QLinkedList<QSGDistanceFieldGlyphNode*> m_registeredNodes;
+
+ GlyphCacheData(QOpenGLContext *ctx)
+ : QOpenGLSharedResource(ctx->shareGroup())
+ , pendingGlyphs(64)
+ , doubleGlyphResolution(false)
+ {}
+
+ void invalidateResource()
+ {
+ textures.clear();
+ glyphTextures.clear();
+ texCoords.clear();
+ }
+
+ void freeResource(QOpenGLContext *)
+ {
+ }
+ };
+
+ QSGDistanceFieldGlyphCacheManager *m_manager;
+
+ QRawFont m_font;
+ QRawFont m_referenceFont;
+
+ int m_glyphCount;
+ QHash<glyph_t, Metrics> m_metrics;
+
+ GlyphCacheData *cacheData();
+ GlyphCacheData *m_cacheData;
+ static QHash<QString, QOpenGLMultiGroupSharedResource> m_caches_data;
+};
+
QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgcontext.cpp b/src/declarative/scenegraph/qsgcontext.cpp
index f995f9e76e..87beb72b5b 100644
--- a/src/declarative/scenegraph/qsgcontext.cpp
+++ b/src/declarative/scenegraph/qsgcontext.cpp
@@ -45,11 +45,12 @@
#include <private/qsgdefaultrenderer_p.h>
+#include <private/qsgdistancefieldutil_p.h>
+#include <private/qsgdefaultdistancefieldglyphcache_p.h>
#include <private/qsgdefaultrectanglenode_p.h>
#include <private/qsgdefaultimagenode_p.h>
#include <private/qsgdefaultglyphnode_p.h>
#include <private/qsgdistancefieldglyphnode_p.h>
-#include <private/qsgdistancefieldglyphcache_p.h>
#include <private/qsgtexture_p.h>
#include <qsgengine.h>
@@ -289,6 +290,15 @@ QSGImageNode *QSGContext::createImageNode()
}
/*!
+ Factory function for scene graph backends of the distance-field glyph cache.
+ */
+QSGDistanceFieldGlyphCache *QSGContext::createDistanceFieldGlyphCache(const QRawFont &font)
+{
+ Q_D(QSGContext);
+ return new QSGDefaultDistanceFieldGlyphCache(d->distanceFieldCacheManager, glContext(), font);
+}
+
+/*!
Factory function for scene graph backends of the Text elements;
*/
QSGGlyphNode *QSGContext::createGlyphNode()
@@ -304,7 +314,7 @@ QSGGlyphNode *QSGContext::createGlyphNode()
return new QSGDefaultGlyphNode;
} else {
if (!d->distanceFieldCacheManager) {
- d->distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager(d->gl);
+ d->distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager(this);
if (doSubpixel)
d->distanceFieldCacheManager->setDefaultAntialiasingMode(QSGGlyphNode::HighQualitySubPixelAntialiasing);
else if (doLowQualSubpixel)
diff --git a/src/declarative/scenegraph/qsgcontext_p.h b/src/declarative/scenegraph/qsgcontext_p.h
index 6fdd4aed37..328b85eb2b 100644
--- a/src/declarative/scenegraph/qsgcontext_p.h
+++ b/src/declarative/scenegraph/qsgcontext_p.h
@@ -48,6 +48,8 @@
#include <QtGui/QImage>
#include <QtGui/QSurfaceFormat>
+#include <private/qrawfont_p.h>
+
#include "qsgnode.h"
QT_BEGIN_HEADER
@@ -61,6 +63,7 @@ class QSGRectangleNode;
class QSGImageNode;
class QSGGlyphNode;
class QSGRenderer;
+class QSGDistanceFieldGlyphCache;
class QSGTexture;
class QSGMaterial;
@@ -95,6 +98,8 @@ public:
virtual void renderNextFrame(QOpenGLFramebufferObject *fbo = 0);
+ virtual QSGDistanceFieldGlyphCache *createDistanceFieldGlyphCache(const QRawFont &font);
+
virtual QSGRectangleNode *createRectangleNode();
virtual QSGImageNode *createImageNode();
virtual QSGGlyphNode *createGlyphNode();
diff --git a/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
new file mode 100644
index 0000000000..7a03cde026
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -0,0 +1,389 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgdefaultdistancefieldglyphcache_p.h"
+
+#include <private/qsgdistancefieldutil_p.h>
+#include <qopenglshaderprogram.h>
+#include <QtGui/private/qopenglengineshadersource_p.h>
+#include <qopenglfunctions.h>
+
+
+class TextureBlitHelper
+{
+public:
+ TextureBlitHelper()
+ {
+ m_vertexCoordinateArray[0] = -1.0f;
+ m_vertexCoordinateArray[1] = -1.0f;
+ m_vertexCoordinateArray[2] = 1.0f;
+ m_vertexCoordinateArray[3] = -1.0f;
+ m_vertexCoordinateArray[4] = 1.0f;
+ m_vertexCoordinateArray[5] = 1.0f;
+ m_vertexCoordinateArray[6] = -1.0f;
+ m_vertexCoordinateArray[7] = 1.0f;
+
+ m_textureCoordinateArray[0] = 0.0f;
+ m_textureCoordinateArray[1] = 0.0f;
+ m_textureCoordinateArray[2] = 1.0f;
+ m_textureCoordinateArray[3] = 0.0f;
+ m_textureCoordinateArray[4] = 1.0f;
+ m_textureCoordinateArray[5] = 1.0f;
+ m_textureCoordinateArray[6] = 0.0f;
+ m_textureCoordinateArray[7] = 1.0f;
+
+ m_blitProgram = new QOpenGLShaderProgram;
+ {
+ QString source;
+ source.append(QLatin1String(qopenglslMainWithTexCoordsVertexShader));
+ source.append(QLatin1String(qopenglslUntransformedPositionVertexShader));
+
+ QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram);
+ vertexShader->compileSourceCode(source);
+
+ m_blitProgram->addShader(vertexShader);
+ }
+ {
+ QString source;
+ source.append(QLatin1String(qopenglslMainFragmentShader));
+ source.append(QLatin1String(qopenglslImageSrcFragmentShader));
+
+ QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram);
+ fragmentShader->compileSourceCode(source);
+
+ m_blitProgram->addShader(fragmentShader);
+ }
+ m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
+ m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
+ m_blitProgram->link();
+ }
+
+ ~TextureBlitHelper()
+ {
+ delete m_blitProgram;
+ }
+
+ QOpenGLShaderProgram *blitProgram() { return m_blitProgram; }
+ const GLfloat *blitVertexArray() const { return &m_vertexCoordinateArray[0]; }
+ const GLfloat *blitTextureArray() const { return &m_textureCoordinateArray[0]; }
+
+private:
+ QOpenGLShaderProgram *m_blitProgram;
+ GLfloat m_vertexCoordinateArray[8];
+ GLfloat m_textureCoordinateArray[8];
+};
+
+static TextureBlitHelper *g_textureBlitHelper = 0;
+
+QHash<QString, QOpenGLMultiGroupSharedResource> QSGDefaultDistanceFieldGlyphCache::m_textures_data;
+
+QSGDefaultDistanceFieldGlyphCache::DistanceFieldTextureData *QSGDefaultDistanceFieldGlyphCache::textureData()
+{
+ QString key = QString::fromLatin1("%1_%2_%3_%4")
+ .arg(font().familyName())
+ .arg(font().styleName())
+ .arg(font().weight())
+ .arg(font().style());
+ return m_textures_data[key].value<QSGDefaultDistanceFieldGlyphCache::DistanceFieldTextureData>(QOpenGLContext::currentContext());
+}
+
+QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
+ : QSGDistanceFieldGlyphCache(man, c, font)
+ , m_maxTextureSize(0)
+{
+ m_textureData = textureData();
+}
+
+void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QVector<glyph_t> &glyphs)
+{
+ int count = glyphs.count();
+
+ // Avoid useless and costly glyph re-generation
+ if (cacheIsFull() && !m_textureData->unusedGlyphs.isEmpty()) {
+ for (int i = 0; i < count; ++i) {
+ glyph_t glyphIndex = glyphs.at(i);
+ if (containsGlyph(glyphIndex) && m_textureData->unusedGlyphs.contains(glyphIndex))
+ m_textureData->unusedGlyphs.remove(glyphIndex);
+ }
+ }
+
+ QList<GlyphPosition> glyphPositions;
+ QVector<glyph_t> glyphsToRender;
+
+ for (int i = 0; i < count; ++i) {
+ glyph_t glyphIndex = glyphs.at(i);
+
+ if (++m_textureData->glyphRefCount[glyphIndex] == 1)
+ m_textureData->unusedGlyphs.remove(glyphIndex);
+
+ if (cacheIsFull() && m_textureData->unusedGlyphs.isEmpty())
+ continue;
+
+ GlyphPosition p;
+ p.glyph = glyphIndex;
+ p.position = QPointF(m_textureData->currX, m_textureData->currY);
+
+ if (!cacheIsFull()) {
+ m_textureData->currX += QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution());
+ if (m_textureData->currX >= maxTextureSize()) {
+ m_textureData->currX = 0;
+ m_textureData->currY += QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution());
+ }
+ } else {
+ // Recycle glyphs
+ if (!m_textureData->unusedGlyphs.isEmpty()) {
+ glyph_t unusedGlyph = *m_textureData->unusedGlyphs.constBegin();
+ TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
+ p.position = QPointF(unusedCoord.x, unusedCoord.y);
+ m_textureData->unusedGlyphs.remove(unusedGlyph);
+ removeGlyph(unusedGlyph);
+ }
+ }
+
+ if (p.position.y() < maxTextureSize()) {
+ glyphPositions.append(p);
+ glyphsToRender.append(glyphIndex);
+ }
+ }
+
+ addGlyphPositions(glyphPositions);
+ markGlyphsToRender(glyphsToRender);
+}
+
+void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage> &glyphs)
+{
+ int requiredWidth = maxTextureSize();
+ int rows = 128 / (requiredWidth / QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution())); // Enough rows to fill the latin1 set by default..
+ int requiredHeight = qMin(maxTextureSize(),
+ qMax(m_textureData->currY + QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()),
+ QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()) * rows));
+
+ resizeTexture((requiredWidth), (requiredHeight));
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ QVector<glyph_t> glyphTextures;
+
+ QHash<glyph_t, QImage>::const_iterator it;
+ for (it = glyphs.constBegin(); it != glyphs.constEnd(); ++it) {
+ glyph_t glyphIndex = it.key();
+ TexCoord c = glyphTexCoord(glyphIndex);
+
+ glyphTextures.append(glyphIndex);
+
+ QImage glyph = it.value();
+
+ if (useWorkaroundBrokenFBOReadback()) {
+ uchar *inBits = glyph.scanLine(0);
+ uchar *outBits = m_textureData->image.scanLine(int(c.y)) + int(c.x);
+ for (int y = 0; y < glyph.height(); ++y) {
+ qMemCopy(outBits, inBits, glyph.width());
+ inBits += glyph.bytesPerLine();
+ outBits += m_textureData->image.bytesPerLine();
+ }
+ }
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
+ }
+
+ Texture t;
+ t.textureId = m_textureData->texture;
+ t.size = m_textureData->size;
+ addGlyphTextures(glyphTextures, t);
+}
+
+void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QVector<glyph_t> &glyphs)
+{
+ int count = glyphs.count();
+ for (int i = 0; i < count; ++i) {
+ glyph_t glyphIndex = glyphs.at(i);
+ if (--m_textureData->glyphRefCount[glyphIndex] == 0 && !glyphTexCoord(glyphIndex).isNull())
+ m_textureData->unusedGlyphs.insert(glyphIndex);
+ }
+}
+
+void QSGDefaultDistanceFieldGlyphCache::createTexture(int width, int height)
+{
+ if (useWorkaroundBrokenFBOReadback() && m_textureData->image.isNull())
+ m_textureData->image = QImage(width, height, QImage::Format_Indexed8);
+
+ while (glGetError() != GL_NO_ERROR) { }
+
+ glGenTextures(1, &m_textureData->texture);
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ m_textureData->size = QSize(width, height);
+
+ GLuint error = glGetError();
+ if (error != GL_NO_ERROR) {
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glDeleteTextures(1, &m_textureData->texture);
+ m_textureData->texture = 0;
+ }
+
+}
+
+void QSGDefaultDistanceFieldGlyphCache::resizeTexture(int width, int height)
+{
+ int oldWidth = m_textureData->size.width();
+ int oldHeight = m_textureData->size.height();
+ if (width == oldWidth && height == oldHeight)
+ return;
+
+ GLuint oldTexture = m_textureData->texture;
+ createTexture(width, height);
+
+ if (!oldTexture)
+ return;
+
+ updateTexture(oldTexture, m_textureData->texture, m_textureData->size);
+
+ if (useWorkaroundBrokenFBOReadback()) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, m_textureData->image.constBits());
+ m_textureData->image = m_textureData->image.copy(0, 0, width, height);
+ glDeleteTextures(1, &oldTexture);
+ return;
+ }
+
+ if (!g_textureBlitHelper)
+ g_textureBlitHelper = new TextureBlitHelper;
+
+ if (!m_textureData->fbo)
+ ctx->functions()->glGenFramebuffers(1, &m_textureData->fbo);
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_textureData->fbo);
+
+ GLuint tmp_texture;
+ glGenTextures(1, &tmp_texture);
+ glBindTexture(GL_TEXTURE_2D, tmp_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, tmp_texture, 0);
+
+ ctx->functions()->glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, oldTexture);
+
+ // save current render states
+ GLboolean stencilTestEnabled;
+ GLboolean depthTestEnabled;
+ GLboolean scissorTestEnabled;
+ GLboolean blendEnabled;
+ GLint viewport[4];
+ GLint oldProgram;
+ glGetBooleanv(GL_STENCIL_TEST, &stencilTestEnabled);
+ glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled);
+ glGetBooleanv(GL_SCISSOR_TEST, &scissorTestEnabled);
+ glGetBooleanv(GL_BLEND, &blendEnabled);
+ glGetIntegerv(GL_VIEWPORT, &viewport[0]);
+ glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgram);
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_SCISSOR_TEST);
+ glDisable(GL_BLEND);
+
+ glViewport(0, 0, oldWidth, oldHeight);
+
+ ctx->functions()->glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, g_textureBlitHelper->blitVertexArray());
+ ctx->functions()->glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, g_textureBlitHelper->blitTextureArray());
+
+ g_textureBlitHelper->blitProgram()->bind();
+ g_textureBlitHelper->blitProgram()->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
+ g_textureBlitHelper->blitProgram()->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
+ g_textureBlitHelper->blitProgram()->disableAttributeArray(int(QT_OPACITY_ATTR));
+ g_textureBlitHelper->blitProgram()->setUniformValue("imageTexture", GLuint(0));
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
+
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+
+ ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_RENDERBUFFER, 0);
+ glDeleteTextures(1, &tmp_texture);
+ glDeleteTextures(1, &oldTexture);
+
+ ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // restore render states
+ if (stencilTestEnabled)
+ glEnable(GL_STENCIL_TEST);
+ if (depthTestEnabled)
+ glEnable(GL_DEPTH_TEST);
+ if (scissorTestEnabled)
+ glEnable(GL_SCISSOR_TEST);
+ if (blendEnabled)
+ glEnable(GL_BLEND);
+ glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+ ctx->functions()->glUseProgram(oldProgram);
+}
+
+bool QSGDefaultDistanceFieldGlyphCache::useWorkaroundBrokenFBOReadback() const
+{
+ static bool set = false;
+ static bool useWorkaround = false;
+ if (!set) {
+ QOpenGLContextPrivate *ctx_p = static_cast<QOpenGLContextPrivate *>(QOpenGLContextPrivate::get(ctx));
+ useWorkaround = ctx_p->workaround_brokenFBOReadBack;
+ set = true;
+ }
+ return useWorkaround;
+}
+
+int QSGDefaultDistanceFieldGlyphCache::maxTextureSize() const
+{
+ if (!m_maxTextureSize)
+ glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
+ return m_maxTextureSize;
+}
+
+QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
new file mode 100644
index 0000000000..aed8d72174
--- /dev/null
+++ b/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGDEFAULTDISTANCEFIELDGLYPHCACHE_H
+#define QSGDEFAULTDISTANCEFIELDGLYPHCACHE_H
+
+#include <QtGui/qopenglfunctions.h>
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_DECLARATIVE_EXPORT QSGDefaultDistanceFieldGlyphCache : public QSGDistanceFieldGlyphCache
+{
+public:
+ QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font);
+
+ void requestGlyphs(const QVector<glyph_t> &glyphs);
+ void storeGlyphs(const QHash<glyph_t, QImage> &glyphs);
+ void releaseGlyphs(const QVector<glyph_t> &glyphs);
+
+ bool cacheIsFull() const { return m_textureData->currY >= maxTextureSize(); }
+ bool useWorkaroundBrokenFBOReadback() const;
+ int maxTextureSize() const;
+
+private:
+ void createTexture(int width, int height);
+ void resizeTexture(int width, int height);
+
+ mutable int m_maxTextureSize;
+
+ struct DistanceFieldTextureData : public QOpenGLSharedResource {
+ GLuint texture;
+ GLuint fbo;
+ QSize size;
+ QHash<glyph_t, quint32> glyphRefCount;
+ QSet<glyph_t> unusedGlyphs;
+ int currX;
+ int currY;
+ QImage image;
+
+ DistanceFieldTextureData(QOpenGLContext *ctx)
+ : QOpenGLSharedResource(ctx->shareGroup())
+ , texture(0)
+ , fbo(0)
+ , currX(0)
+ , currY(0)
+ {}
+
+ void invalidateResource()
+ {
+ texture = 0;
+ fbo = 0;
+ size = QSize();
+ }
+
+ void freeResource(QOpenGLContext *ctx)
+ {
+ glDeleteTextures(1, &texture);
+ ctx->functions()->glDeleteFramebuffers(1, &fbo);
+ }
+ };
+
+ DistanceFieldTextureData *textureData();
+ DistanceFieldTextureData *m_textureData;
+ static QHash<QString, QOpenGLMultiGroupSharedResource> m_textures_data;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGDEFAULTDISTANCEFIELDGLYPHCACHE_H
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h
deleted file mode 100644
index aea7c5952f..0000000000
--- a/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
-**
-** This file is part of the QtDeclarative module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** 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.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef DISTANCEFIELDGLYPHCACHE_H
-#define DISTANCEFIELDGLYPHCACHE_H
-
-#include <qopengl.h>
-#include <qrawfont.h>
-#include <private/qopenglcontext_p.h>
-#include <QtGui/qopenglfunctions.h>
-#include <private/qfont_p.h>
-#include <private/qfontengine_p.h>
-#include <QtGui/private/qdatabuffer_p.h>
-#include <private/qsgadaptationlayer_p.h>
-
-QT_BEGIN_NAMESPACE
-
-typedef float (*ThresholdFunc)(float glyphScale);
-typedef float (*AntialiasingSpreadFunc)(float glyphScale);
-
-class QOpenGLShaderProgram;
-class QSGDistanceFieldGlyphCache;
-
-class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCacheManager
-{
-public:
- QSGDistanceFieldGlyphCacheManager(QOpenGLContext *c);
- ~QSGDistanceFieldGlyphCacheManager();
-
- QSGDistanceFieldGlyphCache *cache(const QRawFont &font);
-
- QSGGlyphNode::AntialiasingMode defaultAntialiasingMode() const { return m_defaultAntialiasingMode; }
- void setDefaultAntialiasingMode(QSGGlyphNode::AntialiasingMode mode) { m_defaultAntialiasingMode = mode; }
-
- ThresholdFunc thresholdFunc() const { return m_threshold_func; }
- void setThresholdFunc(ThresholdFunc func) { m_threshold_func = func; }
-
- AntialiasingSpreadFunc antialiasingSpreadFunc() const { return m_antialiasingSpread_func; }
- void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; }
-
- QOpenGLShaderProgram *blitProgram() { return m_blitProgram; }
- const GLfloat *blitVertexArray() const { return &m_vertexCoordinateArray[0]; }
- const GLfloat *blitTextureArray() const { return &m_textureCoordinateArray[0]; }
-
- int maxTextureSize() const;
-
-private:
- QHash<QFontEngine *, QSGDistanceFieldGlyphCache *> m_caches;
-
- QOpenGLContext *ctx;
-
- QSGGlyphNode::AntialiasingMode m_defaultAntialiasingMode;
- ThresholdFunc m_threshold_func;
- AntialiasingSpreadFunc m_antialiasingSpread_func;
-
- mutable int m_maxTextureSize;
-
- QOpenGLShaderProgram *m_blitProgram;
- GLfloat m_vertexCoordinateArray[8];
- GLfloat m_textureCoordinateArray[8];
-};
-
-class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCache
-{
-public:
- ~QSGDistanceFieldGlyphCache();
-
- struct Metrics {
- qreal width;
- qreal height;
- qreal baselineX;
- qreal baselineY;
-
- bool isNull() const { return width == 0 || height == 0; }
- };
- Metrics glyphMetrics(glyph_t glyph);
-
- struct TexCoord {
- qreal x;
- qreal y;
- qreal width;
- qreal height;
- qreal xMargin;
- qreal yMargin;
-
- TexCoord() : x(0), y(0), width(0), height(0), xMargin(0), yMargin(0) { }
-
- bool isNull() const { return width == 0 || height == 0; }
- };
- TexCoord glyphTexCoord(glyph_t glyph);
-
- const QSGDistanceFieldGlyphCacheManager *manager() const { return m_manager; }
-
- GLuint texture();
- QSize textureSize() const;
- qreal fontScale() const;
- int distanceFieldRadius() const;
- QImage renderDistanceFieldGlyph(glyph_t glyph) const;
-
- int glyphCount() const;
-
- void populate(int count, const glyph_t *glyphs);
- void derefGlyphs(int count, const glyph_t *glyphs);
- void updateCache();
-
- bool cacheIsFull() const { return m_textureData->currY >= m_manager->maxTextureSize(); }
-
- bool useWorkaroundBrokenFBOReadback() const;
-
-private:
- QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font);
-
- void createTexture(int width, int height);
- void resizeTexture(int width, int height);
-
- QSGDistanceFieldGlyphCacheManager *m_manager;
-
- QOpenGLContext *ctx;
-
- QRawFont m_font;
- QRawFont m_referenceFont;
-
- int m_glyphCount;
- QHash<glyph_t, Metrics> m_metrics;
-
- struct DistanceFieldTextureData : public QOpenGLSharedResource {
- GLuint texture;
- GLuint fbo;
- QSize size;
- QHash<glyph_t, TexCoord> texCoords;
- QDataBuffer<glyph_t> pendingGlyphs;
- QHash<glyph_t, quint32> glyphRefCount;
- QSet<glyph_t> unusedGlyphs;
- int currX;
- int currY;
- QImage image;
- bool doubleGlyphResolution;
-
- DistanceFieldTextureData(QOpenGLContext *ctx)
- : QOpenGLSharedResource(ctx->shareGroup())
- , texture(0)
- , fbo(0)
- , pendingGlyphs(64)
- , currX(0)
- , currY(0)
- , doubleGlyphResolution(false)
- {}
-
- void invalidateResource()
- {
- texture = 0;
- fbo = 0;
- size = QSize();
- }
-
- void freeResource(QOpenGLContext *ctx)
- {
- glDeleteTextures(1, &texture);
- ctx->functions()->glDeleteFramebuffers(1, &fbo);
- }
- };
-
- DistanceFieldTextureData *textureData();
- DistanceFieldTextureData *m_textureData;
- static QHash<QString, QOpenGLMultiGroupSharedResource> m_textures_data;
-
- friend class QSGDistanceFieldGlyphCacheManager;
-};
-
-QT_END_NAMESPACE
-
-#endif // DISTANCEFIELDGLYPHCACHE_H
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp
index e25b1520a1..e4a39e484b 100644
--- a/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp
@@ -41,7 +41,7 @@
#include "qsgdistancefieldglyphnode_p.h"
#include "qsgdistancefieldglyphnode_p_p.h"
-#include "qsgdistancefieldglyphcache_p.h"
+#include <private/qsgdistancefieldutil_p.h>
#include <private/qsgcontext_p.h>
QT_BEGIN_NAMESPACE
@@ -53,7 +53,6 @@ QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGDistanceFieldGlyphCacheM
, m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0)
, m_style(QQuickText::Normal)
, m_antialiasingMode(GrayAntialiasing)
- , m_dirtyFont(false)
, m_dirtyGeometry(false)
, m_dirtyMaterial(false)
{
@@ -69,8 +68,8 @@ QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode()
{
delete m_material;
if (m_glyph_cache) {
- const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
- m_glyph_cache->derefGlyphs(glyphIndexes.count(), glyphIndexes.constData());
+ m_glyph_cache->release(m_glyphs.glyphIndexes());
+ m_glyph_cache->unregisterGlyphNode(this);
}
}
@@ -97,7 +96,24 @@ void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphR
m_position = QPointF(position.x(), position.y() - font.ascent());
m_glyphs = glyphs;
- m_dirtyFont = true;
+ QSGDistanceFieldGlyphCache *oldCache = m_glyph_cache;
+ m_glyph_cache = m_glyph_cacheManager->cache(m_glyphs.rawFont());
+ if (m_glyph_cache != oldCache) {
+ if (oldCache)
+ oldCache->unregisterGlyphNode(this);
+ m_glyph_cache->registerGlyphNode(this);
+ }
+ m_glyph_cache->populate(glyphs.glyphIndexes());
+
+ const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
+ const QVector<QPointF> &glyphPositions = m_glyphs.positions();
+ for (int i = 0; i < glyphIndexes.size(); ++i) {
+ GlyphInfo g;
+ g.glyphIndex = glyphIndexes.at(i);
+ g.position = glyphPositions.at(i);
+ m_glyphsToAdd.append(g);
+ }
+
m_dirtyGeometry = true;
m_dirtyMaterial = true;
}
@@ -120,78 +136,74 @@ void QSGDistanceFieldGlyphNode::setStyleColor(const QColor &color)
void QSGDistanceFieldGlyphNode::update()
{
- if (m_dirtyFont)
- updateFont();
- if (m_dirtyGeometry)
- updateGeometry();
if (m_dirtyMaterial)
updateMaterial();
+ if (m_dirtyGeometry)
+ updateGeometry();
}
void QSGDistanceFieldGlyphNode::updateGeometry()
{
Q_ASSERT(m_glyph_cache);
- QSGGeometry *g = geometry();
- QRectF boundingRect;
-
- const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes();
+ if (m_glyphsToAdd.isEmpty())
+ return;
- m_glyph_cache->populate(glyphIndexes.count(), glyphIndexes.constData());
+ QSGGeometry *g = geometry();
Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT);
int oldVertexCount = g->vertexCount();
int oldIndexCount = g->indexCount();
- // We could potentially move the realloc part into the QSGGeometry object as a
- // grow() function...
+ QVector<QSGGeometry::TexturedPoint2D> vp;
+ vp.reserve(m_glyphsToAdd.size() * 4);
+ QVector<ushort> ip;
+ ip.reserve(m_glyphsToAdd.size() * 6);
- void *data = 0;
- if (oldVertexCount && oldIndexCount) {
- int byteSize = oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D)
- + oldIndexCount * sizeof(quint16);
- data = qMalloc(byteSize);
- memcpy(data, g->vertexData(), byteSize);
- }
+ QPointF margins(2, 2);
+ QPointF texMargins = margins / m_glyph_cache->fontScale();
- g->allocate(oldVertexCount + glyphIndexes.size() * 4, oldIndexCount + glyphIndexes.size() * 6);
+ const QSGDistanceFieldGlyphCache::Texture *textureToUse = 0;
- if (data) {
- memcpy(g->vertexData(), data, oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D));
- memcpy(g->indexData(), ((char *) data) + oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D),
- oldIndexCount * sizeof(quint16));
- qFree(data);
- }
+ QLinkedList<GlyphInfo>::iterator it = m_glyphsToAdd.begin();
+ while (it != m_glyphsToAdd.end()) {
+ quint32 glyphIndex = it->glyphIndex;
+ QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex);
- QSGGeometry::TexturedPoint2D *vp = g->vertexDataAsTexturedPoint2D() + oldVertexCount;
- ushort *ip = g->indexDataAsUShort() + oldIndexCount;
+ if (c.isNull()) {
+ if (!c.isValid())
+ ++it;
+ else
+ it = m_glyphsToAdd.erase(it);
+ continue;
+ }
- QPointF margins(2, 2);
- QPointF texMargins = margins / m_glyph_cache->fontScale();
+ const QSGDistanceFieldGlyphCache::Texture *texture = m_glyph_cache->glyphTexture(glyphIndex);
+ if (!texture->textureId) {
+ ++it;
+ continue;
+ }
- QVector<QPointF> glyphPositions = m_glyphs.positions();
- for (int i = 0; i < glyphIndexes.size(); ++i) {
- quint32 glyphIndex = glyphIndexes.at(i);
QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex);
- QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex);
- if (!metrics.isNull() && !c.isNull()) {
- metrics.width += margins.x() * 2;
- metrics.height += margins.y() * 2;
- metrics.baselineX -= margins.x();
- metrics.baselineY += margins.y();
- c.xMargin -= texMargins.x();
- c.yMargin -= texMargins.y();
- c.width += texMargins.x() * 2;
- c.height += texMargins.y() * 2;
- }
+ if (!textureToUse)
+ textureToUse = texture;
- const QPointF &glyphPosition = glyphPositions.at(i);
+ metrics.width += margins.x() * 2;
+ metrics.height += margins.y() * 2;
+ metrics.baselineX -= margins.x();
+ metrics.baselineY += margins.y();
+ c.xMargin -= texMargins.x();
+ c.yMargin -= texMargins.y();
+ c.width += texMargins.x() * 2;
+ c.height += texMargins.y() * 2;
+
+ const QPointF &glyphPosition = it->position;
qreal x = glyphPosition.x() + metrics.baselineX + m_position.x();
qreal y = glyphPosition.y() - metrics.baselineY + m_position.y();
- boundingRect |= QRectF(x, y, metrics.width, metrics.height);
+ m_boundingRect |= QRectF(x, y, metrics.width, metrics.height);
float cx1 = x;
float cx2 = x + metrics.width;
@@ -206,49 +218,60 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
if (m_baseLine.isNull())
m_baseLine = glyphPosition;
- int vi = i & 1 ? (glyphIndexes.size() + 1) / 2 + i / 2 : i / 2;
- vp[4 * vi + 0].set(cx1, cy1, tx1, ty1);
- vp[4 * vi + 1].set(cx2, cy1, tx2, ty1);
- vp[4 * vi + 2].set(cx1, cy2, tx1, ty2);
- vp[4 * vi + 3].set(cx2, cy2, tx2, ty2);
-
- int o = i * 4 + oldVertexCount;
- ip[6 * i + 0] = o + 0;
- ip[6 * i + 1] = o + 2;
- ip[6 * i + 2] = o + 3;
- ip[6 * i + 3] = o + 3;
- ip[6 * i + 4] = o + 1;
- ip[6 * i + 5] = o + 0;
+ int i = vp.size();
+
+ QSGGeometry::TexturedPoint2D v1;
+ v1.set(cx1, cy1, tx1, ty1);
+ QSGGeometry::TexturedPoint2D v2;
+ v2.set(cx2, cy1, tx2, ty1);
+ QSGGeometry::TexturedPoint2D v3;
+ v3.set(cx1, cy2, tx1, ty2);
+ QSGGeometry::TexturedPoint2D v4;
+ v4.set(cx2, cy2, tx2, ty2);
+ vp.append(v1);
+ vp.append(v2);
+ vp.append(v3);
+ vp.append(v4);
+
+ int o = i + oldVertexCount;
+ ip.append(o + 0);
+ ip.append(o + 2);
+ ip.append(o + 3);
+ ip.append(o + 3);
+ ip.append(o + 1);
+ ip.append(o + 0);
+
+ it = m_glyphsToAdd.erase(it);
}
-// printf("Vertices:\n");
-// for (int v=0; v<g->vertexCount(); ++v) {
-// QSGGeometry::TexturedPoint2D *t = g->vertexDataAsTexturedPoint2D() + v;
-// printf(" - %d -- %f %f -- %.3f %.3f\n", v, t->x, t->y, t->tx, t->ty);
-// }
-
-// printf("Indices:\n");
-// for (int i=0; i<g->indexCount();) {
-
-// printf(" - %[ ", i);
-// printf("%d, ", g->indexDataAsUShort()[i++]);
-// printf("%d, ", g->indexDataAsUShort()[i++]);
-// printf("%d, ", g->indexDataAsUShort()[i++]);
-// printf("%d, ", g->indexDataAsUShort()[i++]);
-// printf("%d, ", g->indexDataAsUShort()[i++]);
-// printf("%d", g->indexDataAsUShort()[i++]);
-// printf(" ]\n");
-// }
-
- setBoundingRect(boundingRect);
+ if (vp.isEmpty())
+ return;
+
+ void *data = 0;
+ if (oldVertexCount && oldIndexCount) {
+ int byteSize = oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D)
+ + oldIndexCount * sizeof(quint16);
+ data = qMalloc(byteSize);
+ memcpy(data, g->vertexData(), byteSize);
+ }
+
+ g->allocate(oldVertexCount + vp.size(), oldIndexCount + ip.size());
+
+ if (data) {
+ memcpy(g->vertexData(), data, oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D));
+ memcpy(g->indexData(), ((char *) data) + oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D),
+ oldIndexCount * sizeof(quint16));
+ qFree(data);
+ }
+
+ memcpy(g->vertexDataAsTexturedPoint2D() + oldVertexCount, vp.constData(), vp.size() * sizeof(QSGGeometry::TexturedPoint2D));
+ memcpy(g->indexDataAsUShort() + oldIndexCount, ip.constData(), ip.size() * sizeof(quint16));
+
+ setBoundingRect(m_boundingRect);
markDirty(DirtyGeometry);
m_dirtyGeometry = false;
-}
-void QSGDistanceFieldGlyphNode::updateFont()
-{
- m_glyph_cache = m_glyph_cacheManager->cache(m_glyphs.rawFont());
- m_dirtyFont = false;
+ m_material->setTexture(textureToUse);
}
void QSGDistanceFieldGlyphNode::updateMaterial()
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp
index a7dbb3b7f6..a506e23cc1 100644
--- a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -40,7 +40,7 @@
****************************************************************************/
#include "qsgdistancefieldglyphnode_p_p.h"
-#include "qsgdistancefieldglyphcache_p.h"
+#include <private/qsgdistancefieldutil_p.h>
#include <private/qsgtexture_p.h>
#include <QtGui/qopenglfunctions.h>
#include <qmath.h>
@@ -138,9 +138,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q
QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect);
QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect);
- bool updated = material->updateTexture();
- if (updated && !material->glyphCache()->useWorkaroundBrokenFBOReadback())
- activate();
+ bool updated = material->updateCache();
if (oldMaterial == 0
|| material->color() != oldMaterial->color()
@@ -171,10 +169,10 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q
if (updated
|| oldMaterial == 0
- || oldMaterial->glyphCache()->texture() != material->glyphCache()->texture()) {
- program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->glyphCache()->textureSize().width(),
- 1.0 / material->glyphCache()->textureSize().height()));
- glBindTexture(GL_TEXTURE_2D, material->glyphCache()->texture());
+ || oldMaterial->texture()->textureId != material->texture()->textureId) {
+ program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->textureSize().width(),
+ 1.0 / material->textureSize().height()));
+ glBindTexture(GL_TEXTURE_2D, material->texture()->textureId);
if (updated) {
// Set the mag/min filters to be linear. We only need to do this when the texture
@@ -189,6 +187,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q
QSGDistanceFieldTextMaterial::QSGDistanceFieldTextMaterial()
: m_glyph_cache(0)
+ , m_texture(0)
{
setFlag(Blending, true);
}
@@ -208,10 +207,12 @@ QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader() const
return new QSGDistanceFieldTextMaterialShader;
}
-bool QSGDistanceFieldTextMaterial::updateTexture()
+bool QSGDistanceFieldTextMaterial::updateCache()
{
- m_glyph_cache->updateCache();
- QSize glyphCacheSize = m_glyph_cache->textureSize();
+ m_glyph_cache->update();
+ if (!m_texture)
+ m_texture = m_glyph_cache->glyphTexture(-1); // invalid texture
+ QSize glyphCacheSize = m_texture->size;
if (glyphCacheSize != m_size) {
m_size = glyphCacheSize;
@@ -433,7 +434,7 @@ void DistanceFieldShiftedStyleTextMaterialShader::updateState(const RenderState
if (oldMaterial == 0
|| oldMaterial->glyphCache()->fontScale() != material->glyphCache()->fontScale()
|| oldMaterial->shift() != material->shift()
- || oldMaterial->glyphCache()->textureSize() != material->glyphCache()->textureSize()) {
+ || oldMaterial->textureSize() != material->textureSize()) {
updateShift(material->glyphCache(), material->shift());
}
}
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h
index 1d8bcea868..f4877b0a1d 100644
--- a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -53,7 +53,6 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Declarative)
-class QSGDistanceFieldGlyphCache;
class QSGDistanceFieldGlyphCacheManager;
class QSGDistanceFieldTextMaterial;
class QSGDistanceFieldGlyphNode: public QSGGlyphNode
@@ -73,9 +72,9 @@ public:
virtual void update();
-private:
void updateGeometry();
- void updateFont();
+
+private:
void updateMaterial();
QColor m_color;
@@ -89,8 +88,14 @@ private:
QQuickText::TextStyle m_style;
QColor m_styleColor;
AntialiasingMode m_antialiasingMode;
+ QRectF m_boundingRect;
+
+ struct GlyphInfo {
+ quint32 glyphIndex;
+ QPointF position;
+ };
+ QLinkedList<GlyphInfo> m_glyphsToAdd;
- uint m_dirtyFont: 1;
uint m_dirtyGeometry: 1;
uint m_dirtyMaterial: 1;
};
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h
index 8733edf203..c8c73bfac0 100644
--- a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h
+++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h
@@ -44,11 +44,10 @@
#include <qsgmaterial.h>
#include "qsgdistancefieldglyphnode_p.h"
+#include "qsgadaptationlayer_p.h"
QT_BEGIN_NAMESPACE
-class QSGDistanceFieldGlyphCache;
-
class QSGDistanceFieldTextMaterial: public QSGMaterial
{
public:
@@ -65,12 +64,18 @@ public:
void setGlyphCache(QSGDistanceFieldGlyphCache *a) { m_glyph_cache = a; }
QSGDistanceFieldGlyphCache *glyphCache() const { return m_glyph_cache; }
- bool updateTexture();
+ void setTexture(const QSGDistanceFieldGlyphCache::Texture * tex) { m_texture = tex; }
+ const QSGDistanceFieldGlyphCache::Texture * texture() const { return m_texture; }
+
+ QSize textureSize() const { return m_size; }
+
+ bool updateCache();
protected:
QSize m_size;
QColor m_color;
QSGDistanceFieldGlyphCache *m_glyph_cache;
+ const QSGDistanceFieldGlyphCache::Texture *m_texture;
};
class QSGDistanceFieldStyledTextMaterial : public QSGDistanceFieldTextMaterial
diff --git a/src/declarative/scenegraph/scenegraph.pri b/src/declarative/scenegraph/scenegraph.pri
index d4e0707ba3..0adc20502d 100644
--- a/src/declarative/scenegraph/scenegraph.pri
+++ b/src/declarative/scenegraph/scenegraph.pri
@@ -33,7 +33,8 @@ HEADERS += \
$$PWD/util/qsgtexture.h \
$$PWD/util/qsgtexture_p.h \
$$PWD/util/qsgtextureprovider_p.h \
- $$PWD/util/qsgpainternode_p.h
+ $$PWD/util/qsgpainternode_p.h \
+ $$PWD/util/qsgdistancefieldutil_p.h
SOURCES += \
$$PWD/util/qsgareaallocator.cpp \
@@ -45,7 +46,8 @@ SOURCES += \
$$PWD/util/qsgvertexcolormaterial.cpp \
$$PWD/util/qsgtexture.cpp \
$$PWD/util/qsgtextureprovider.cpp \
- $$PWD/util/qsgpainternode.cpp
+ $$PWD/util/qsgpainternode.cpp \
+ $$PWD/util/qsgdistancefieldutil.cpp
# QML / Adaptations API
@@ -54,7 +56,7 @@ HEADERS += \
$$PWD/qsgcontext_p.h \
$$PWD/qsgcontextplugin_p.h \
$$PWD/qsgdefaultglyphnode_p.h \
- $$PWD/qsgdistancefieldglyphcache_p.h \
+ $$PWD/qsgdefaultdistancefieldglyphcache_p.h \
$$PWD/qsgdistancefieldglyphnode_p.h \
$$PWD/qsgdistancefieldglyphnode_p_p.h \
$$PWD/qsgdefaultglyphnode_p_p.h \
@@ -69,10 +71,16 @@ SOURCES += \
$$PWD/qsgcontextplugin.cpp \
$$PWD/qsgdefaultglyphnode.cpp \
$$PWD/qsgdefaultglyphnode_p.cpp \
- $$PWD/qsgdistancefieldglyphcache.cpp \
+ $$PWD/qsgdefaultdistancefieldglyphcache.cpp \
$$PWD/qsgdistancefieldglyphnode.cpp \
$$PWD/qsgdistancefieldglyphnode_p.cpp \
$$PWD/qsgdefaultimagenode.cpp \
$$PWD/qsgdefaultrectanglenode.cpp \
$$PWD/qsgflashnode.cpp \
$$PWD/qsgpathsimplifier.cpp
+
+
+
+
+
+
diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp b/src/declarative/scenegraph/util/qsgdistancefieldutil.cpp
index 60e5bb7727..a74c96b808 100644
--- a/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp
+++ b/src/declarative/scenegraph/util/qsgdistancefieldutil.cpp
@@ -39,53 +39,14 @@
**
****************************************************************************/
-#include "qsgdistancefieldglyphcache_p.h"
+#include "qsgdistancefieldutil_p.h"
#include <qmath.h>
#include <private/qsgpathsimplifier_p.h>
-#include <private/qdeclarativeglobal_p.h>
-#include <qopenglshaderprogram.h>
+#include <private/qsgadaptationlayer_p.h>
#include <QtGui/private/qopenglengineshadersource_p.h>
#include <private/qsgcontext_p.h>
-#include <private/qrawfont_p.h>
-#include <qopenglfunctions.h>
-#include <qglyphrun.h>
-#include <qrawfont.h>
-#include <qdir.h>
-#include <QtGui/qguiapplication.h>
-
-QT_BEGIN_NAMESPACE
-
-#define QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE 54
-#define QT_DISTANCEFIELD_DEFAULT_TILESIZE 64
-#define QT_DISTANCEFIELD_DEFAULT_SCALE 16
-#define QT_DISTANCEFIELD_DEFAULT_RADIUS 80
-#define QT_DISTANCEFIELD_HIGHGLYPHCOUNT 2000
-
-#define QT_DISTANCEFIELD_BASEFONTSIZE \
- (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE * 2 : \
- QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE)
-#define QT_DISTANCEFIELD_TILESIZE \
- (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_TILESIZE * 2 : \
- QT_DISTANCEFIELD_DEFAULT_TILESIZE)
-#define QT_DISTANCEFIELD_SCALE \
- (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_SCALE / 2 : \
- QT_DISTANCEFIELD_DEFAULT_SCALE)
-#define QT_DISTANCEFIELD_RADIUS \
- (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_RADIUS / 2 : \
- QT_DISTANCEFIELD_DEFAULT_RADIUS)
-
-static inline int qt_next_power_of_two(int v)
-{
- v--;
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- ++v;
- return v;
-}
+
static float defaultThresholdFunc(float glyphScale)
{
@@ -748,7 +709,7 @@ static QImage makeDistanceField(int imgSize, const QPainterPath &path, int dfSca
return image;
}
-static bool fontHasNarrowOutlines(const QRawFont &f)
+bool qt_fontHasNarrowOutlines(const QRawFont &f)
{
QRawFont font = f;
font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE);
@@ -798,65 +759,36 @@ static bool fontHasNarrowOutlines(const QRawFont &f)
return minHThick == 1 || minVThick == 1;
}
-QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager(QOpenGLContext *c)
- : ctx(c)
+QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution)
+{
+ QRawFont renderFont = font;
+ renderFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(doubleResolution) * QT_DISTANCEFIELD_SCALE(doubleResolution));
+
+ QPainterPath path = renderFont.pathForGlyph(glyph);
+ path.translate(-path.boundingRect().topLeft());
+ path.setFillRule(Qt::WindingFill);
+
+ QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE(doubleResolution),
+ path,
+ QT_DISTANCEFIELD_SCALE(doubleResolution),
+ QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution));
+ return im;
+}
+
+QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager(QSGContext *c)
+ : sgCtx(c)
, m_threshold_func(defaultThresholdFunc)
, m_antialiasingSpread_func(defaultAntialiasingSpreadFunc)
- , m_maxTextureSize(0)
{
#ifndef QT_OPENGL_ES
m_defaultAntialiasingMode = QSGGlyphNode::HighQualitySubPixelAntialiasing;
#else
m_defaultAntialiasingMode = QSGGlyphNode::GrayAntialiasing;
#endif
-
- m_vertexCoordinateArray[0] = -1.0f;
- m_vertexCoordinateArray[1] = -1.0f;
- m_vertexCoordinateArray[2] = 1.0f;
- m_vertexCoordinateArray[3] = -1.0f;
- m_vertexCoordinateArray[4] = 1.0f;
- m_vertexCoordinateArray[5] = 1.0f;
- m_vertexCoordinateArray[6] = -1.0f;
- m_vertexCoordinateArray[7] = 1.0f;
-
- m_textureCoordinateArray[0] = 0.0f;
- m_textureCoordinateArray[1] = 0.0f;
- m_textureCoordinateArray[2] = 1.0f;
- m_textureCoordinateArray[3] = 0.0f;
- m_textureCoordinateArray[4] = 1.0f;
- m_textureCoordinateArray[5] = 1.0f;
- m_textureCoordinateArray[6] = 0.0f;
- m_textureCoordinateArray[7] = 1.0f;
-
- m_blitProgram = new QOpenGLShaderProgram;
- {
- QString source;
- source.append(QLatin1String(qopenglslMainWithTexCoordsVertexShader));
- source.append(QLatin1String(qopenglslUntransformedPositionVertexShader));
-
- QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram);
- vertexShader->compileSourceCode(source);
-
- m_blitProgram->addShader(vertexShader);
- }
- {
- QString source;
- source.append(QLatin1String(qopenglslMainFragmentShader));
- source.append(QLatin1String(qopenglslImageSrcFragmentShader));
-
- QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram);
- fragmentShader->compileSourceCode(source);
-
- m_blitProgram->addShader(fragmentShader);
- }
- m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
- m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
- m_blitProgram->link();
}
QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager()
{
- delete m_blitProgram;
qDeleteAll(m_caches.values());
}
@@ -865,393 +797,6 @@ QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCacheManager::cache(const QRawF
QRawFontPrivate *fontD = QRawFontPrivate::get(font);
QHash<QFontEngine *, QSGDistanceFieldGlyphCache *>::iterator cache = m_caches.find(fontD->fontEngine);
if (cache == m_caches.end())
- cache = m_caches.insert(fontD->fontEngine, new QSGDistanceFieldGlyphCache(this, ctx, font));
+ cache = m_caches.insert(fontD->fontEngine, sgCtx->createDistanceFieldGlyphCache(font));
return cache.value();
}
-
-int QSGDistanceFieldGlyphCacheManager::maxTextureSize() const
-{
- if (!m_maxTextureSize)
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
- return m_maxTextureSize;
-}
-
-
-QHash<QString, QOpenGLMultiGroupSharedResource> QSGDistanceFieldGlyphCache::m_textures_data;
-
-QSGDistanceFieldGlyphCache::DistanceFieldTextureData *QSGDistanceFieldGlyphCache::textureData()
-{
- QString key = QString::fromLatin1("%1_%2_%3_%4")
- .arg(m_font.familyName())
- .arg(m_font.styleName())
- .arg(m_font.weight())
- .arg(m_font.style());
- return m_textures_data[key].value<QSGDistanceFieldGlyphCache::DistanceFieldTextureData>(QOpenGLContext::currentContext());
-}
-
-QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
- : m_manager(man)
- , ctx(c)
-{
- Q_ASSERT(font.isValid());
- m_font = font;
-
- m_textureData = textureData();
-
- QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
- m_glyphCount = fontD->fontEngine->glyphCount();
-
- m_textureData->doubleGlyphResolution = fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
-
- m_referenceFont = m_font;
- m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE);
- Q_ASSERT(m_referenceFont.isValid());
-}
-
-QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
-{
-}
-
-GLuint QSGDistanceFieldGlyphCache::texture()
-{
- return m_textureData->texture;
-}
-
-QSize QSGDistanceFieldGlyphCache::textureSize() const
-{
- return m_textureData->size;
-}
-
-QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph)
-{
- QHash<glyph_t, Metrics>::iterator metric = m_metrics.find(glyph);
- if (metric == m_metrics.end()) {
- QPainterPath path = m_font.pathForGlyph(glyph);
- QRectF br = path.boundingRect();
-
- Metrics m;
- m.width = br.width();
- m.height = br.height();
- m.baselineX = br.x();
- m.baselineY = -br.y();
-
- metric = m_metrics.insert(glyph, m);
- }
-
- return metric.value();
-}
-
-QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph)
-{
- return m_textureData->texCoords.value(glyph);
-}
-
-QImage QSGDistanceFieldGlyphCache::renderDistanceFieldGlyph(glyph_t glyph) const
-{
- QRawFont renderFont = m_font;
- renderFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE * QT_DISTANCEFIELD_SCALE);
-
- QPainterPath path = renderFont.pathForGlyph(glyph);
- path.translate(-path.boundingRect().topLeft());
- path.setFillRule(Qt::WindingFill);
-
- QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE,
- path,
- QT_DISTANCEFIELD_SCALE,
- QT_DISTANCEFIELD_RADIUS / QT_DISTANCEFIELD_SCALE);
- return im;
-}
-
-qreal QSGDistanceFieldGlyphCache::fontScale() const
-{
- return qreal(m_font.pixelSize()) / QT_DISTANCEFIELD_BASEFONTSIZE;
-}
-
-int QSGDistanceFieldGlyphCache::distanceFieldRadius() const
-{
- return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE;
-}
-
-void QSGDistanceFieldGlyphCache::populate(int count, const glyph_t *glyphs)
-{
- // Avoid useless and costly glyph re-generation
- if (cacheIsFull() && !m_textureData->unusedGlyphs.isEmpty()) {
- for (int i = 0; i < count; ++i) {
- glyph_t glyphIndex = glyphs[i];
- if (m_textureData->texCoords.contains(glyphIndex) && m_textureData->unusedGlyphs.contains(glyphIndex))
- m_textureData->unusedGlyphs.remove(glyphIndex);
- }
- }
-
- for (int i = 0; i < count; ++i) {
- glyph_t glyphIndex = glyphs[i];
- if ((int) glyphIndex >= glyphCount()) {
- qWarning("Warning: distance-field glyph is not available with index %d", glyphIndex);
- continue;
- }
-
- if (++m_textureData->glyphRefCount[glyphIndex] == 1)
- m_textureData->unusedGlyphs.remove(glyphIndex);
-
- if (m_textureData->texCoords.contains(glyphIndex)
- || (cacheIsFull() && m_textureData->unusedGlyphs.isEmpty()))
- continue;
-
- QPainterPath path = m_referenceFont.pathForGlyph(glyphIndex);
- if (path.isEmpty()) {
- m_textureData->texCoords.insert(glyphIndex, TexCoord());
- continue;
- }
- QRectF br = path.boundingRect();
-
- TexCoord c;
- c.xMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE);
- c.yMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE);
- c.x = m_textureData->currX;
- c.y = m_textureData->currY;
- c.width = br.width();
- c.height = br.height();
-
- if (!cacheIsFull()) {
- m_textureData->currX += QT_DISTANCEFIELD_TILESIZE;
- if (m_textureData->currX >= m_manager->maxTextureSize()) {
- m_textureData->currX = 0;
- m_textureData->currY += QT_DISTANCEFIELD_TILESIZE;
- }
- } else {
- // Recycle glyphs
- if (!m_textureData->unusedGlyphs.isEmpty()) {
- glyph_t unusedGlyph = *m_textureData->unusedGlyphs.constBegin();
- TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
- c.x = unusedCoord.x;
- c.y = unusedCoord.y;
- m_textureData->unusedGlyphs.remove(unusedGlyph);
- m_textureData->texCoords.remove(unusedGlyph);
- }
- }
-
- if (c.y < m_manager->maxTextureSize()) {
- m_textureData->texCoords.insert(glyphIndex, c);
- m_textureData->pendingGlyphs.add(glyphIndex);
- }
- }
-}
-
-void QSGDistanceFieldGlyphCache::derefGlyphs(int count, const glyph_t *glyphs)
-{
- for (int i = 0; i < count; ++i)
- if (--m_textureData->glyphRefCount[glyphs[i]] == 0 && !glyphTexCoord(glyphs[i]).isNull())
- m_textureData->unusedGlyphs.insert(glyphs[i]);
-}
-
-void QSGDistanceFieldGlyphCache::createTexture(int width, int height)
-{
- if (ctx->d_func()->workaround_brokenFBOReadBack && m_textureData->image.isNull())
- m_textureData->image = QImage(width, height, QImage::Format_Indexed8);
-
- while (glGetError() != GL_NO_ERROR) { }
-
- glGenTextures(1, &m_textureData->texture);
- glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
-
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- m_textureData->size = QSize(width, height);
-
- GLuint error = glGetError();
- if (error != GL_NO_ERROR) {
- glBindTexture(GL_TEXTURE_2D, 0);
- glDeleteTextures(1, &m_textureData->texture);
- m_textureData->texture = 0;
- }
-
-}
-
-void QSGDistanceFieldGlyphCache::resizeTexture(int width, int height)
-{
- int oldWidth = m_textureData->size.width();
- int oldHeight = m_textureData->size.height();
- if (width == oldWidth && height == oldHeight)
- return;
-
- GLuint oldTexture = m_textureData->texture;
- createTexture(width, height);
-
- if (!oldTexture)
- return;
-
- if (ctx->d_func()->workaround_brokenFBOReadBack) {
- m_textureData->image = m_textureData->image.copy(0, 0, width, height);
- QImage copy = m_textureData->image.copy(0, 0, oldWidth, oldHeight);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, copy.constBits());
- glDeleteTextures(1, &oldTexture);
- return;
- }
-
- if (!m_textureData->fbo)
- ctx->functions()->glGenFramebuffers(1, &m_textureData->fbo);
- ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_textureData->fbo);
-
- GLuint tmp_texture;
- glGenTextures(1, &tmp_texture);
- glBindTexture(GL_TEXTURE_2D, tmp_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glBindTexture(GL_TEXTURE_2D, 0);
- ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, tmp_texture, 0);
-
- ctx->functions()->glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, oldTexture);
-
- // save current render states
- GLboolean stencilTestEnabled;
- GLboolean depthTestEnabled;
- GLboolean scissorTestEnabled;
- GLboolean blendEnabled;
- GLint viewport[4];
- glGetBooleanv(GL_STENCIL_TEST, &stencilTestEnabled);
- glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled);
- glGetBooleanv(GL_SCISSOR_TEST, &scissorTestEnabled);
- glGetBooleanv(GL_BLEND, &blendEnabled);
- glGetIntegerv(GL_VIEWPORT, &viewport[0]);
-
- glDisable(GL_STENCIL_TEST);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_SCISSOR_TEST);
- glDisable(GL_BLEND);
-
- glViewport(0, 0, oldWidth, oldHeight);
-
- ctx->functions()->glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_manager->blitVertexArray());
- ctx->functions()->glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_manager->blitTextureArray());
-
- m_manager->blitProgram()->bind();
- m_manager->blitProgram()->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
- m_manager->blitProgram()->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
- m_manager->blitProgram()->disableAttributeArray(int(QT_OPACITY_ATTR));
- m_manager->blitProgram()->setUniformValue("imageTexture", GLuint(0));
-
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
- glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
-
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
-
- ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_RENDERBUFFER, 0);
- glDeleteTextures(1, &tmp_texture);
- glDeleteTextures(1, &oldTexture);
-
- ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, 0);
-
- // restore render states
- if (stencilTestEnabled)
- glEnable(GL_STENCIL_TEST);
- if (depthTestEnabled)
- glEnable(GL_DEPTH_TEST);
- if (scissorTestEnabled)
- glEnable(GL_SCISSOR_TEST);
- if (blendEnabled)
- glEnable(GL_BLEND);
- glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
-}
-
-void QSGDistanceFieldGlyphCache::updateCache()
-{
- if (m_textureData->pendingGlyphs.isEmpty())
- return;
-
- int requiredWidth = m_manager->maxTextureSize();
- int rows = 128 / (requiredWidth / QT_DISTANCEFIELD_TILESIZE); // Enough rows to fill the latin1 set by default..
- int requiredHeight = qMin(m_manager->maxTextureSize(), qMax(m_textureData->currY + QT_DISTANCEFIELD_TILESIZE, QT_DISTANCEFIELD_TILESIZE * rows));
-
- resizeTexture((requiredWidth), (requiredHeight));
- glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
-
- // ### Remove before final release
- static bool cacheDistanceFields = QGuiApplication::arguments().contains(QLatin1String("--cache-distance-fields"));
-
-// #define QSGDISTANCEFIELDS_TIME_CREATION
-#ifdef QSGDISTANCEFIELDS_TIME_CREATION
- QTime time;
- time.start();
-#endif
-
- QString tmpPath = QString::fromLatin1("%1/.qt/").arg(QDir::tempPath());
- QString keyBase = QString::fromLatin1("%1%2%3_%4_%5_%6.fontblob")
- .arg(tmpPath)
- .arg(m_font.familyName())
- .arg(m_font.styleName())
- .arg(m_font.weight())
- .arg(m_font.style());
-
- if (cacheDistanceFields && !QFile::exists(tmpPath))
- QDir(tmpPath).mkpath(tmpPath);
-
- for (int i = 0; i < m_textureData->pendingGlyphs.size(); ++i) {
- glyph_t glyphIndex = m_textureData->pendingGlyphs.at(i);
- TexCoord c = m_textureData->texCoords.value(glyphIndex);
-
- if (cacheDistanceFields) {
- QString key = keyBase.arg(glyphIndex);
- QFile file(key);
- if (file.open(QFile::ReadOnly)) {
- int fileSize = file.size();
- int dim = sqrt(float(fileSize));
- QByteArray blob = file.readAll();
- glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, dim, dim, GL_ALPHA, GL_UNSIGNED_BYTE, blob.constData());
- continue;
- }
- }
-
- QImage glyph = renderDistanceFieldGlyph(glyphIndex);
-
- if (ctx->d_func()->workaround_brokenFBOReadBack) {
- uchar *inBits = glyph.scanLine(0);
- uchar *outBits = m_textureData->image.scanLine(int(c.y)) + int(c.x);
- for (int y = 0; y < glyph.height(); ++y) {
- qMemCopy(outBits, inBits, glyph.width());
- inBits += glyph.bytesPerLine();
- outBits += m_textureData->image.bytesPerLine();
- }
- }
-
- glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
-
- if (cacheDistanceFields) {
- QString key = keyBase.arg(glyphIndex);
- QFile file(key);
- file.open(QFile::WriteOnly);
- file.write((const char *) glyph.constBits(), glyph.width() * glyph.height());
- }
- }
-
-#ifdef QSGDISTANCEFIELDS_TIME_CREATION
- static int totalTime;
- totalTime += time.elapsed();
- printf("time: %d\n", totalTime);
-#endif
-
- m_textureData->pendingGlyphs.reset();
-}
-
-bool QSGDistanceFieldGlyphCache::useWorkaroundBrokenFBOReadback() const
-{
- return ctx->d_func()->workaround_brokenFBOReadBack;
-}
-
-int QSGDistanceFieldGlyphCache::glyphCount() const
-{
- return m_glyphCount;
-}
-
-QT_END_NAMESPACE
diff --git a/src/declarative/scenegraph/util/qsgdistancefieldutil_p.h b/src/declarative/scenegraph/util/qsgdistancefieldutil_p.h
new file mode 100644
index 0000000000..93dffab76e
--- /dev/null
+++ b/src/declarative/scenegraph/util/qsgdistancefieldutil_p.h
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** 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.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QSGDISTANCEFIELDUTIL_H
+#define QSGDISTANCEFIELDUTIL_H
+
+#include <qrawfont.h>
+#include <private/qfontengine_p.h>
+#include <private/qsgadaptationlayer_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE 54
+#define QT_DISTANCEFIELD_DEFAULT_TILESIZE 64
+#define QT_DISTANCEFIELD_DEFAULT_SCALE 16
+#define QT_DISTANCEFIELD_DEFAULT_RADIUS 80
+#define QT_DISTANCEFIELD_HIGHGLYPHCOUNT 2000
+
+#define QT_DISTANCEFIELD_BASEFONTSIZE(NarrowOutlineFont) \
+ (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE * 2 : \
+ QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE)
+#define QT_DISTANCEFIELD_TILESIZE(NarrowOutlineFont) \
+ (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_TILESIZE * 2 : \
+ QT_DISTANCEFIELD_DEFAULT_TILESIZE)
+#define QT_DISTANCEFIELD_SCALE(NarrowOutlineFont) \
+ (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_SCALE / 2 : \
+ QT_DISTANCEFIELD_DEFAULT_SCALE)
+#define QT_DISTANCEFIELD_RADIUS(NarrowOutlineFont) \
+ (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_RADIUS / 2 : \
+ QT_DISTANCEFIELD_DEFAULT_RADIUS)
+
+
+typedef float (*ThresholdFunc)(float glyphScale);
+typedef float (*AntialiasingSpreadFunc)(float glyphScale);
+
+bool qt_fontHasNarrowOutlines(const QRawFont &f);
+QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution);
+
+
+class QOpenGLShaderProgram;
+class QSGDistanceFieldGlyphCache;
+class QSGContext;
+
+class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCacheManager
+{
+public:
+ QSGDistanceFieldGlyphCacheManager(QSGContext *c);
+ ~QSGDistanceFieldGlyphCacheManager();
+
+ QSGDistanceFieldGlyphCache *cache(const QRawFont &font);
+
+ QSGGlyphNode::AntialiasingMode defaultAntialiasingMode() const { return m_defaultAntialiasingMode; }
+ void setDefaultAntialiasingMode(QSGGlyphNode::AntialiasingMode mode) { m_defaultAntialiasingMode = mode; }
+
+ ThresholdFunc thresholdFunc() const { return m_threshold_func; }
+ void setThresholdFunc(ThresholdFunc func) { m_threshold_func = func; }
+
+ AntialiasingSpreadFunc antialiasingSpreadFunc() const { return m_antialiasingSpread_func; }
+ void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; }
+
+private:
+ QHash<QFontEngine *, QSGDistanceFieldGlyphCache *> m_caches;
+
+ QSGContext *sgCtx;
+
+ QSGGlyphNode::AntialiasingMode m_defaultAntialiasingMode;
+ ThresholdFunc m_threshold_func;
+ AntialiasingSpreadFunc m_antialiasingSpread_func;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSGDISTANCEFIELDUTIL_H
diff --git a/tests/auto/declarative/qquicktext/tst_qquicktext.cpp b/tests/auto/declarative/qquicktext/tst_qquicktext.cpp
index 8ac3a078bc..a8852fbc9f 100644
--- a/tests/auto/declarative/qquicktext/tst_qquicktext.cpp
+++ b/tests/auto/declarative/qquicktext/tst_qquicktext.cpp
@@ -45,7 +45,6 @@
#include <private/qquicktext_p.h>
#include <private/qquicktext_p_p.h>
#include <private/qdeclarativevaluetype_p.h>
-#include <private/qsgdistancefieldglyphcache_p.h>
#include <QFontMetrics>
#include <QGraphicsSceneMouseEvent>
#include <qmath.h>
diff --git a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp
index 693619f638..116d6307fe 100644
--- a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp
+++ b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp
@@ -51,7 +51,6 @@
#include <QtGui/qguiapplication.h>
#include <private/qquicktextedit_p.h>
#include <private/qquicktextedit_p_p.h>
-#include <private/qsgdistancefieldglyphcache_p.h>
#include <QFontMetrics>
#include <QQuickView>
#include <QDir>
diff --git a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp
index bf29f88ff1..210099c2a4 100644
--- a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp
+++ b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp
@@ -52,7 +52,6 @@
#include <QDir>
#include <QStyle>
#include <QInputContext>
-#include <private/qsgdistancefieldglyphcache_p.h>
#include <QtOpenGL/QGLShaderProgram>
#include <math.h>