aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph
diff options
context:
space:
mode:
authorSergio Ahumada <sergio.ahumada@digia.com>2013-11-27 10:58:56 +0100
committerSergio Ahumada <sergio.ahumada@digia.com>2013-11-27 10:58:56 +0100
commit9df70b0304fa44d2f1b1504d7e58d718eab4343a (patch)
tree95a7b207a39c2b44bd4e80bcc1ea3d36bedd9a99 /src/quick/scenegraph
parent648d4ae6a3591e916f175e32c12a2ea4f8edb6a9 (diff)
parent900e3d4ad5f2bc4994ddf164c15c641f85630b81 (diff)
Merge branch 'stable' into dev
Conflicts: .qmake.conf Change-Id: I10d4f9e993d23750a6e8ddc1291b79e47fc83c64
Diffstat (limited to 'src/quick/scenegraph')
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp175
-rw-r--r--src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h31
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.cpp63
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterial.h15
-rw-r--r--src/quick/scenegraph/coreapi/qsgmaterialshader_p.h (renamed from src/quick/scenegraph/qsgflashnode_p.h)22
-rw-r--r--src/quick/scenegraph/coreapi/qsgnodeupdater.cpp9
-rw-r--r--src/quick/scenegraph/coreapi/qsgnodeupdater_p.h5
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer.cpp32
-rw-r--r--src/quick/scenegraph/coreapi/qsgrenderer_p.h8
-rw-r--r--src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp29
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer.cpp5
-rw-r--r--src/quick/scenegraph/qsgadaptationlayer_p.h4
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp591
-rw-r--r--src/quick/scenegraph/qsgcontext_p.h107
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp142
-rw-r--r--src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h10
-rw-r--r--src/quick/scenegraph/qsgdefaultglyphnode_p.cpp168
-rw-r--r--src/quick/scenegraph/qsgdefaultimagenode.cpp76
-rw-r--r--src/quick/scenegraph/qsgdefaultrectanglenode.cpp66
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode.cpp9
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp250
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p.h6
-rw-r--r--src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h1
-rw-r--r--src/quick/scenegraph/qsgrenderloop.cpp32
-rw-r--r--src/quick/scenegraph/qsgrenderloop_p.h3
-rw-r--r--src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp1
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop.cpp681
-rw-r--r--src/quick/scenegraph/qsgthreadedrenderloop_p.h30
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop.cpp29
-rw-r--r--src/quick/scenegraph/qsgwindowsrenderloop_p.h7
-rw-r--r--src/quick/scenegraph/scenegraph.pri85
-rw-r--r--src/quick/scenegraph/scenegraph.qrc68
-rw-r--r--src/quick/scenegraph/shaders/24bittextmask.frag10
-rw-r--r--src/quick/scenegraph/shaders/24bittextmask_core.frag14
-rw-r--r--src/quick/scenegraph/shaders/8bittextmask.frag9
-rw-r--r--src/quick/scenegraph/shaders/8bittextmask_core.frag13
-rw-r--r--src/quick/scenegraph/shaders/distancefieldoutlinetext.frag16
-rw-r--r--src/quick/scenegraph/shaders/distancefieldoutlinetext_core.frag20
-rw-r--r--src/quick/scenegraph/shaders/distancefieldshiftedtext.frag17
-rw-r--r--src/quick/scenegraph/shaders/distancefieldshiftedtext.vert17
-rw-r--r--src/quick/scenegraph/shaders/distancefieldshiftedtext_core.frag20
-rw-r--r--src/quick/scenegraph/shaders/distancefieldshiftedtext_core.vert18
-rw-r--r--src/quick/scenegraph/shaders/distancefieldtext.frag13
-rw-r--r--src/quick/scenegraph/shaders/distancefieldtext.vert13
-rw-r--r--src/quick/scenegraph/shaders/distancefieldtext_core.frag16
-rw-r--r--src/quick/scenegraph/shaders/distancefieldtext_core.vert15
-rw-r--r--src/quick/scenegraph/shaders/flatcolor.frag6
-rw-r--r--src/quick/scenegraph/shaders/flatcolor.vert7
-rw-r--r--src/quick/scenegraph/shaders/flatcolor_core.frag10
-rw-r--r--src/quick/scenegraph/shaders/flatcolor_core.vert10
-rw-r--r--src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag58
-rw-r--r--src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert34
-rw-r--r--src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.frag32
-rw-r--r--src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.vert36
-rw-r--r--src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.frag17
-rw-r--r--src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.vert27
-rw-r--r--src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.frag21
-rw-r--r--src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.vert29
-rw-r--r--src/quick/scenegraph/shaders/opaquetexture.frag8
-rw-r--r--src/quick/scenegraph/shaders/opaquetexture.vert12
-rw-r--r--src/quick/scenegraph/shaders/opaquetexture_core.frag12
-rw-r--r--src/quick/scenegraph/shaders/opaquetexture_core.vert14
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext.frag21
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext.vert22
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext_core.frag25
-rw-r--r--src/quick/scenegraph/shaders/outlinedtext_core.vert24
-rw-r--r--src/quick/scenegraph/shaders/rendernode.frag8
-rw-r--r--src/quick/scenegraph/shaders/rendernode.vert10
-rw-r--r--src/quick/scenegraph/shaders/rendernode_core.frag12
-rw-r--r--src/quick/scenegraph/shaders/rendernode_core.vert12
-rw-r--r--src/quick/scenegraph/shaders/smoothcolor.frag6
-rw-r--r--src/quick/scenegraph/shaders/smoothcolor.vert45
-rw-r--r--src/quick/scenegraph/shaders/smoothcolor_core.frag10
-rw-r--r--src/quick/scenegraph/shaders/smoothcolor_core.vert47
-rw-r--r--src/quick/scenegraph/shaders/smoothtexture.frag9
-rw-r--r--src/quick/scenegraph/shaders/smoothtexture.vert52
-rw-r--r--src/quick/scenegraph/shaders/smoothtexture_core.frag13
-rw-r--r--src/quick/scenegraph/shaders/smoothtexture_core.vert54
-rw-r--r--src/quick/scenegraph/shaders/stencilclip.frag4
-rw-r--r--src/quick/scenegraph/shaders/stencilclip.vert8
-rw-r--r--src/quick/scenegraph/shaders/stencilclip_core.frag8
-rw-r--r--src/quick/scenegraph/shaders/stencilclip_core.vert10
-rw-r--r--src/quick/scenegraph/shaders/styledtext.frag14
-rw-r--r--src/quick/scenegraph/shaders/styledtext.vert16
-rw-r--r--src/quick/scenegraph/shaders/styledtext_core.frag18
-rw-r--r--src/quick/scenegraph/shaders/styledtext_core.vert18
-rw-r--r--src/quick/scenegraph/shaders/textmask.frag10
-rw-r--r--src/quick/scenegraph/shaders/textmask.vert13
-rw-r--r--src/quick/scenegraph/shaders/textmask_core.frag14
-rw-r--r--src/quick/scenegraph/shaders/textmask_core.vert15
-rw-r--r--src/quick/scenegraph/shaders/texture.frag9
-rw-r--r--src/quick/scenegraph/shaders/texture_core.frag13
-rw-r--r--src/quick/scenegraph/shaders/vertexcolor.frag6
-rw-r--r--src/quick/scenegraph/shaders/vertexcolor.vert13
-rw-r--r--src/quick/scenegraph/shaders/vertexcolor_core.frag10
-rw-r--r--src/quick/scenegraph/shaders/vertexcolor_core.vert15
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture.cpp51
-rw-r--r--src/quick/scenegraph/util/qsgatlastexture_p.h10
-rw-r--r--src/quick/scenegraph/util/qsgflatcolormaterial.cpp29
-rw-r--r--src/quick/scenegraph/util/qsgpainternode.cpp6
-rw-r--r--src/quick/scenegraph/util/qsgpainternode_p.h2
-rw-r--r--src/quick/scenegraph/util/qsgshadersourcebuilder.cpp403
-rw-r--r--src/quick/scenegraph/util/qsgshadersourcebuilder_p.h (renamed from src/quick/scenegraph/qsgflashnode.cpp)50
-rw-r--r--src/quick/scenegraph/util/qsgtexture.cpp16
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial.cpp50
-rw-r--r--src/quick/scenegraph/util/qsgtexturematerial_p.h8
-rw-r--r--src/quick/scenegraph/util/qsgvertexcolormaterial.cpp33
107 files changed, 3147 insertions, 1399 deletions
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
index f25e144674..79b5de72c0 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp
@@ -40,11 +40,13 @@
****************************************************************************/
#include "qsgbatchrenderer_p.h"
+#include <private/qsgshadersourcebuilder_p.h>
#include <QtCore/QElapsedTimer>
#include <QtGui/QGuiApplication>
#include <QtGui/QOpenGLFramebufferObject>
+#include <QtGui/QOpenGLVertexArrayObject>
#include <private/qqmlprofilerservice_p.h>
@@ -56,7 +58,7 @@
QT_BEGIN_NAMESPACE
-extern QByteArray qsgShaderRewriter_insertZAttributes(const char *input);
+extern QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfaceFormat::OpenGLContextProfile profile);
namespace QSGBatchRenderer
{
@@ -112,6 +114,7 @@ struct QMatrix4x4_Accessor
int flagBits;
static bool isTranslate(const QMatrix4x4 &m) { return ((const QMatrix4x4_Accessor &) m).flagBits <= 0x1; }
+ static bool isScale(const QMatrix4x4 &m) { return ((const QMatrix4x4_Accessor &) m).flagBits <= 0x2; }
static bool is2DSafe(const QMatrix4x4 &m) { return ((const QMatrix4x4_Accessor &) m).flagBits < 0x8; }
};
@@ -130,10 +133,12 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material)
#endif
QSGMaterialShader *s = material->createShader();
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ QSurfaceFormat::OpenGLContextProfile profile = ctx->format().profile();
QOpenGLShaderProgram *p = s->program();
p->addShaderFromSourceCode(QOpenGLShader::Vertex,
- qsgShaderRewriter_insertZAttributes(s->vertexShader()));
+ qsgShaderRewriter_insertZAttributes(s->vertexShader(), profile));
p->addShaderFromSourceCode(QOpenGLShader::Fragment,
s->fragmentShader());
@@ -283,7 +288,6 @@ Updater::Updater(Renderer *r)
void Updater::updateStates(QSGNode *n)
{
- m_toplevel_alpha = 1;
m_current_clip = 0;
m_added = 0;
@@ -389,6 +393,9 @@ void Updater::visitOpacityNode(Node *n)
if (was != is) {
renderer->m_rebuild = Renderer::FullRebuild;
n->isOpaque = is;
+ } else if (!is) {
+ renderer->invalidateAlphaBatchesForRoot(m_roots.last());
+ renderer->m_rebuild |= Renderer::BuildBatches;
}
++m_force_update;
SHADOWNODE_TRAVERSE(n) visitNode(*child);
@@ -530,6 +537,38 @@ int qsg_positionAttribute(QSGGeometry *g) {
return -1;
}
+
+void Rect::map(const QMatrix4x4 &matrix)
+{
+ const float *m = matrix.constData();
+ if (QMatrix4x4_Accessor::isScale(matrix)) {
+ tl.x = tl.x * m[0] + m[12];
+ tl.y = tl.y * m[5] + m[13];
+ br.x = br.x * m[0] + m[12];
+ br.y = br.y * m[5] + m[13];
+ if (tl.x > br.x)
+ qSwap(tl.x, br.x);
+ if (tl.y > br.y)
+ qSwap(tl.y, br.y);
+ } else {
+ Pt mtl = tl;
+ Pt mtr = { br.x, tl.y };
+ Pt mbl = { tl.x, br.y };
+ Pt mbr = br;
+
+ mtl.map(matrix);
+ mtr.map(matrix);
+ mbl.map(matrix);
+ mbr.map(matrix);
+
+ set(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
+ (*this) |= mtl;
+ (*this) |= mtr;
+ (*this) |= mbl;
+ (*this) |= mbr;
+ }
+}
+
void Element::computeBounds()
{
Q_ASSERT(!boundsComputed);
@@ -550,6 +589,17 @@ void Element::computeBounds()
vd += g->sizeOfVertex();
}
bounds.map(*node->matrix());
+
+ if (!qIsFinite(bounds.tl.x))
+ bounds.tl.x = -FLT_MAX;
+ if (!qIsFinite(bounds.tl.y))
+ bounds.tl.y = -FLT_MAX;
+ if (!qIsFinite(bounds.br.x))
+ bounds.br.x = FLT_MAX;
+ if (!qIsFinite(bounds.br.y))
+ bounds.br.y = FLT_MAX;
+
+ boundsOutsideFloatRange = bounds.isOutsideFloatRange();
}
RenderNodeElement::~RenderNodeElement()
@@ -650,12 +700,26 @@ bool Batch::isTranslateOnlyToRoot() const {
/*
* Iterates through all the nodes in the batch and returns true if the
- * nodes are all "2D safe" meaning that they can be merged and that
- * the value in the z coordinate is of no consequence.
+ * nodes are all safe to batch. There are two separate criteria:
+ *
+ * - The matrix is such that the z component of the result is of no
+ * consequence.
+ *
+ * - The bounds are inside the stable floating point range. This applies
+ * to desktop only where we in this case can trigger a fallback to
+ * unmerged in which case we pass the geometry straight through and
+ * just apply the matrix.
+ *
+ * NOTE: This also means a slight performance impact for geometries which
+ * are defined to be outside the stable floating point range and still
+ * use single precision float, but given that this implicitly fixes
+ * huge lists and tables, it is worth it.
*/
-bool Batch::allMatricesAre2DSafe() const {
+bool Batch::isSafeToBatch() const {
Element *e = first;
while (e) {
+ if (e->boundsOutsideFloatRange)
+ return false;
if (!QMatrix4x4_Accessor::is2DSafe(*e->node->matrix()))
return false;
e = e->nextInBatch;
@@ -683,7 +747,7 @@ static int qsg_countNodesInBatches(const QDataBuffer<Batch *> &batches)
return sum;
}
-Renderer::Renderer(QSGContext *ctx)
+Renderer::Renderer(QSGRenderContext *ctx)
: QSGRenderer(ctx)
, m_opaqueRenderList(64)
, m_alphaRenderList(64)
@@ -700,6 +764,7 @@ Renderer::Renderer(QSGContext *ctx)
, m_zRange(0)
, m_currentMaterial(0)
, m_currentShader(0)
+ , m_vao(0)
{
setNodeUpdater(new Updater(this));
@@ -740,6 +805,13 @@ Renderer::Renderer(QSGContext *ctx)
qDebug() << "Batch thresholds: nodes:" << m_batchNodeThreshold << " vertices:" << m_batchVertexThreshold;
qDebug() << "Using buffer strategy:" << (m_bufferStrategy == GL_STATIC_DRAW ? "static" : (m_bufferStrategy == GL_DYNAMIC_DRAW ? "dynamic" : "stream"));
}
+
+ // If rendering with an OpenGL Core profile context, we need to create a VAO
+ // to hold our vertex specification state.
+ if (context()->openglContext()->format().profile() == QSurfaceFormat::CoreProfile) {
+ m_vao = new QOpenGLVertexArrayObject(this);
+ m_vao->create();
+ }
}
static void qsg_wipeBuffer(Buffer *buffer, QOpenGLFunctions *funcs)
@@ -1344,6 +1416,15 @@ void Renderer::buildRenderListsFromScratch()
buildRenderLists(rootNode());
}
+void Renderer::invalidateAlphaBatchesForRoot(Node *root)
+{
+ for (int i=0; i<m_alphaBatches.size(); ++i) {
+ Batch *b = m_alphaBatches.at(i);
+ if (b->root == root || root == 0)
+ b->invalidate();
+ }
+}
+
/* Clean up batches by making it a consecutive list of "valid"
* batches and moving all invalidated batches to the batches pool.
*/
@@ -1491,6 +1572,13 @@ void Renderer::prepareAlphaBatches()
ej->batch = batch;
next->nextInBatch = ej;
next = ej;
+ } else {
+ /* When we come across a compatible element which hits an overlap, we
+ * need to stop the batch right away. We cannot add more elements
+ * to the current batch as they will be rendered before the batch that the
+ * current 'ej' will be added to.
+ */
+ break;
}
} else {
overlapBounds |= ej->bounds;
@@ -1616,7 +1704,7 @@ void Renderer::uploadBatch(Batch *b)
&& (((gn->activeMaterial()->flags() & QSGMaterial::RequiresDeterminant) == 0)
|| (((gn->activeMaterial()->flags() & QSGMaterial_RequiresFullMatrixBit) == 0) && b->isTranslateOnlyToRoot())
)
- && b->allMatricesAre2DSafe();
+ && b->isSafeToBatch();
b->merged = canMerge;
@@ -1890,7 +1978,14 @@ void Renderer::renderMergedBatch(const Batch *batch)
updateClip(gn->clipList(), batch);
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id);
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vbo.id);
+
+ char *indexBase = 0;
+ if (m_context->hasBrokenIndexBufferObjects()) {
+ indexBase = batch->vbo.data;
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ } else {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vbo.id);
+ }
QSGMaterial *material = gn->activeMaterial();
@@ -1925,7 +2020,7 @@ void Renderer::renderMergedBatch(const Batch *batch)
}
glVertexAttribPointer(sms->pos_order, 1, GL_FLOAT, false, 0, (void *) (qintptr) (draw.zorders));
- glDrawElements(g->drawingMode(), draw.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (draw.indices));
+ glDrawElements(g->drawingMode(), draw.indexCount, GL_UNSIGNED_SHORT, (void *) (qintptr) (indexBase + draw.indices));
}
}
@@ -1958,8 +2053,15 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
updateClip(gn->clipList(), batch);
glBindBuffer(GL_ARRAY_BUFFER, batch->vbo.id);
- if (batch->indexCount)
- glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vbo.id);
+ char *indexBase = 0;
+ if (batch->indexCount) {
+ if (m_context->hasBrokenIndexBufferObjects()) {
+ indexBase = batch->vbo.data;
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ } else {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batch->vbo.id);
+ }
+ }
// We always have dirty matrix as all batches are at a unique z range.
QSGMaterialShader::RenderState::DirtyStates dirty = QSGMaterialShader::RenderState::DirtyMatrix;
@@ -1978,7 +2080,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
}
int vOffset = 0;
- int iOffset = batch->vertexCount * gn->geometry()->sizeOfVertex();
+ char *iOffset = indexBase + batch->vertexCount * gn->geometry()->sizeOfVertex();
QMatrix4x4 rootMatrix = batch->root ? matrixForRoot(batch->root) : QMatrix4x4();
@@ -1994,7 +2096,9 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
program->updateState(state(dirty), material, m_currentMaterial);
- m_currentMaterial = gn->activeMaterial();
+ // We don't need to bother with asking each node for its material as they
+ // are all identical (compare==0) since they are in the same batch.
+ m_currentMaterial = material;
QSGGeometry* g = gn->geometry();
char const *const *attrNames = program->attributeNames();
@@ -2009,7 +2113,7 @@ void Renderer::renderUnmergedBatch(const Batch *batch)
}
if (g->indexCount())
- glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), (void *) (qintptr) iOffset);
+ glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), iOffset);
else
glDrawArrays(g->drawingMode(), 0, g->vertexCount());
@@ -2031,14 +2135,13 @@ void Renderer::renderBatches()
<< " -> Alpha: " << qsg_countNodesInBatches(m_alphaBatches) << " nodes in " << m_alphaBatches.size() << " batches...";
}
- QRect r = viewportRect();
- glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
-
for (QHash<QSGRenderNode *, RenderNodeElement *>::const_iterator it = m_renderNodeElements.constBegin();
it != m_renderNodeElements.constEnd(); ++it) {
prepareRenderNode(it.value());
}
+ QRect r = viewportRect();
+ glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
glClearColor(clearColor().redF(), clearColor().greenF(), clearColor().blueF(), clearColor().alphaF());
#if defined(QT_OPENGL_ES)
glClearDepthf(1);
@@ -2126,6 +2229,17 @@ void Renderer::deleteRemovedElements()
m_elementsToDelete.reset();
}
+void Renderer::preprocess()
+{
+ // Bind our VAO. It's important that we do this here as the
+ // QSGRenderer::preprocess() call may well do work that requires
+ // a bound VAO.
+ if (m_vao)
+ m_vao->bind();
+
+ QSGRenderer::preprocess();
+}
+
void Renderer::render()
{
if (Q_UNLIKELY(debug_dump)) {
@@ -2233,6 +2347,9 @@ void Renderer::render()
renderBatches();
m_rebuild = 0;
+
+ if (m_vao)
+ m_vao->release();
}
void Renderer::prepareRenderNode(RenderNodeElement *e)
@@ -2310,23 +2427,11 @@ void Renderer::renderRenderNode(Batch *batch)
if (!m_shaderManager->blitProgram) {
m_shaderManager->blitProgram = new QOpenGLShaderProgram();
- const char *vs =
- "attribute highp vec4 av; "
- "attribute highp vec2 at; "
- "varying highp vec2 t; "
- "void main() { "
- " gl_Position = av; "
- " t = at; "
- "} ";
- const char *fs =
- "uniform lowp sampler2D tex; "
- "varying highp vec2 t; "
- "void main() { "
- " gl_FragColor = texture2D(tex, t); "
- "} ";
-
- m_shaderManager->blitProgram->addShaderFromSourceCode(QOpenGLShader::Vertex, vs);
- m_shaderManager->blitProgram->addShaderFromSourceCode(QOpenGLShader::Fragment, fs);
+
+ QSGShaderSourceBuilder::initializeProgramFromFiles(
+ m_shaderManager->blitProgram,
+ QStringLiteral(":/scenegraph/shaders/rendernode.vert"),
+ QStringLiteral(":/scenegraph/shaders/rendernode.frag"));
m_shaderManager->blitProgram->bindAttributeLocation("av", 0);
m_shaderManager->blitProgram->bindAttributeLocation("at", 1);
m_shaderManager->blitProgram->link();
diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
index 94e8ba5d96..95e111552d 100644
--- a/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer_p.h
@@ -50,9 +50,13 @@
QT_BEGIN_NAMESPACE
+class QOpenGLVertexArrayObject;
+
namespace QSGBatchRenderer
{
+#define QSG_RENDERER_COORD_LIMIT 1000000.0f
+
struct Vec;
struct Rect;
struct Buffer;
@@ -117,14 +121,7 @@ struct Rect {
Q_ASSERT(tl.y <= br.y);
}
- void map(const QMatrix4x4 &m) {
- tl.map(m);
- br.map(m);
- if (br.x < tl.x)
- qSwap(br.x, tl.x);
- if (br.y < tl.y)
- qSwap(br.y, tl.y);
- }
+ void map(const QMatrix4x4 &m);
void set(float left, float top, float right, float bottom) {
tl.set(left, top);
@@ -136,6 +133,13 @@ struct Rect {
bool yOverlap = r.tl.y < br.y && r.br.y > tl.y;
return xOverlap && yOverlap;
}
+
+ bool isOutsideFloatRange() const {
+ return tl.x < -QSG_RENDERER_COORD_LIMIT
+ || tl.y < -QSG_RENDERER_COORD_LIMIT
+ || br.x > QSG_RENDERER_COORD_LIMIT
+ || br.y > QSG_RENDERER_COORD_LIMIT;
+ }
};
inline QDebug operator << (QDebug d, const Rect &r) {
@@ -158,6 +162,7 @@ struct Element {
, root(0)
, order(0)
, boundsComputed(false)
+ , boundsOutsideFloatRange(false)
, translateOnlyToRoot(false)
, removed(false)
, orphaned(false)
@@ -181,6 +186,7 @@ struct Element {
int order;
uint boundsComputed : 1;
+ uint boundsOutsideFloatRange : 1;
uint translateOnlyToRoot : 1;
uint removed : 1;
uint orphaned : 1;
@@ -242,7 +248,7 @@ struct Batch
void cleanupRemovedElements();
bool isTranslateOnlyToRoot() const;
- bool allMatricesAre2DSafe() const;
+ bool isSafeToBatch() const;
// pseudo-constructor...
void init() {
@@ -389,11 +395,12 @@ public:
class Q_QUICK_PRIVATE_EXPORT Renderer : public QSGRenderer
{
public:
- Renderer(QSGContext *);
+ Renderer(QSGRenderContext *);
~Renderer();
protected:
void nodeChanged(QSGNode *node, QSGNode::DirtyState state);
+ void preprocess() Q_DECL_OVERRIDE;
void render();
private:
@@ -420,6 +427,7 @@ private:
void prepareOpaqueBatches();
bool checkOverlap(int first, int last, const Rect &bounds);
void prepareAlphaBatches();
+ void invalidateAlphaBatchesForRoot(Node *root);
void uploadBatch(Batch *b);
void uploadMergedElement(Element *e, int vaOffset, char **vertexData, char **zData, char **indexData, quint16 *iBase, int *indexCount);
@@ -476,6 +484,9 @@ private:
QSGMaterialShader *m_currentProgram;
ShaderManager::Shader *m_currentShader;
const QSGClipNode *m_currentClip;
+
+ // For minimal OpenGL core profile support
+ QOpenGLVertexArrayObject *m_vao;
};
Batch *Renderer::newBatch()
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.cpp b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
index 25d256158e..686d1438b4 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.cpp
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.cpp
@@ -41,9 +41,21 @@
#include "qsgmaterial.h"
#include "qsgrenderer_p.h"
+#include "qsgmaterialshader_p.h"
+#include <private/qsgshadersourcebuilder_p.h>
QT_BEGIN_NAMESPACE
+const char *QSGMaterialShaderPrivate::loadShaderSource(QOpenGLShader::ShaderType type) const
+{
+ QStringList files = m_sourceFiles[type];
+ QSGShaderSourceBuilder builder;
+ Q_FOREACH (const QString &file, files)
+ builder.appendSourceFile(file);
+ m_sources[type] = builder.source();
+ return m_sources[type].constData();
+}
+
#ifndef QT_NO_DEBUG
static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty();
#endif
@@ -165,14 +177,21 @@ static bool qsg_leak_check = !qgetenv("QML_LEAK_CHECK").isEmpty();
Creates a new QSGMaterialShader.
*/
QSGMaterialShader::QSGMaterialShader()
+ : d_ptr(new QSGMaterialShaderPrivate)
+{
+}
+
+QSGMaterialShader::QSGMaterialShader(QSGMaterialShaderPrivate &dd)
+ : d_ptr(&dd)
{
- Q_UNUSED(m_reserved);
}
/*!
- \fn QSGMaterialShader::~QSGMaterialShader()
\internal
*/
+QSGMaterialShader::~QSGMaterialShader()
+{
+}
/*!
\fn char const *const *QSGMaterialShader::attributeNames() const
@@ -194,6 +213,11 @@ QSGMaterialShader::QSGMaterialShader()
The contents returned from this function should never change.
*/
+const char *QSGMaterialShader::vertexShader() const
+{
+ Q_D(const QSGMaterialShader);
+ return d->loadShaderSource(QOpenGLShader::Vertex);
+}
/*!
@@ -204,6 +228,11 @@ QSGMaterialShader::QSGMaterialShader()
The contents returned from this function should never change.
*/
+const char *QSGMaterialShader::fragmentShader() const
+{
+ Q_D(const QSGMaterialShader);
+ return d->loadShaderSource(QOpenGLShader::Fragment);
+}
/*!
@@ -274,7 +303,35 @@ void QSGMaterialShader::updateState(const RenderState & /* state */, QSGMaterial
{
}
+/*!
+ Sets the GLSL source file for the shader stage \a type to \a sourceFile. The
+ default implementation of the vertexShader() and fragmentShader() functions
+ will load the source files set by this function.
+
+ This function is useful when you have a single source file for a given shader
+ stage. If your shader consists of multiple source files then use
+ setShaderSourceFiles()
+
+ \sa setShaderSourceFiles(), vertexShader(), fragmentShader()
+ */
+void QSGMaterialShader::setShaderSourceFile(QOpenGLShader::ShaderType type, const QString &sourceFile)
+{
+ Q_D(QSGMaterialShader);
+ d->m_sourceFiles[type] = (QStringList() << sourceFile);
+}
+
+/*!
+ Sets the GLSL source files for the shader stage \a type to \a sourceFiles. The
+ default implementation of the vertexShader() and fragmentShader() functions
+ will load the source files set by this function in the order given.
+ \sa setShaderSourceFile(), vertexShader(), fragmentShader()
+ */
+void QSGMaterialShader::setShaderSourceFiles(QOpenGLShader::ShaderType type, const QStringList &sourceFiles)
+{
+ Q_D(QSGMaterialShader);
+ d->m_sourceFiles[type] = sourceFiles;
+}
/*!
This function is called when the shader is initialized to compile the
@@ -478,7 +535,7 @@ QRect QSGMaterialShader::RenderState::deviceRect() const
QOpenGLContext *QSGMaterialShader::RenderState::context() const
{
- return static_cast<const QSGRenderer *>(m_data)->glContext();
+ return static_cast<const QSGRenderer *>(m_data)->context()->openglContext();
}
diff --git a/src/quick/scenegraph/coreapi/qsgmaterial.h b/src/quick/scenegraph/coreapi/qsgmaterial.h
index f3ef62d3e5..bfe570ca02 100644
--- a/src/quick/scenegraph/coreapi/qsgmaterial.h
+++ b/src/quick/scenegraph/coreapi/qsgmaterial.h
@@ -48,6 +48,7 @@
QT_BEGIN_NAMESPACE
class QSGMaterial;
+class QSGMaterialShaderPrivate;
namespace QSGBatchRenderer {
class ShaderManager;
@@ -88,7 +89,7 @@ public:
};
QSGMaterialShader();
- virtual ~QSGMaterialShader() {};
+ virtual ~QSGMaterialShader();
virtual void activate();
virtual void deactivate();
@@ -99,18 +100,24 @@ public:
inline QOpenGLShaderProgram *program() { return &m_program; }
protected:
+ Q_DECLARE_PRIVATE(QSGMaterialShader)
+ QSGMaterialShader(QSGMaterialShaderPrivate &dd);
+
friend class QSGContext;
friend class QSGBatchRenderer::ShaderManager;
+ void setShaderSourceFile(QOpenGLShader::ShaderType type, const QString &sourceFile);
+ void setShaderSourceFiles(QOpenGLShader::ShaderType type, const QStringList &sourceFiles);
+
virtual void compile();
virtual void initialize() { }
- virtual const char *vertexShader() const = 0;
- virtual const char *fragmentShader() const = 0;
+ virtual const char *vertexShader() const;
+ virtual const char *fragmentShader() const;
private:
QOpenGLShaderProgram m_program;
- void *m_reserved;
+ QScopedPointer<QSGMaterialShaderPrivate> d_ptr;
};
struct QSGMaterialType { };
diff --git a/src/quick/scenegraph/qsgflashnode_p.h b/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h
index 96496158ae..fc8a35c41d 100644
--- a/src/quick/scenegraph/qsgflashnode_p.h
+++ b/src/quick/scenegraph/coreapi/qsgmaterialshader_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -39,25 +39,23 @@
**
****************************************************************************/
-#ifndef QSGFLASHNODE_H
-#define QSGFLASHNODE_H
+#ifndef QSGMATERIALSHADER_P_H
+#define QSGMATERIALSHADER_P_H
-#include <QtQuick/QSGSimpleRectNode>
+#include <private/qtquickglobal_p.h>
+#include <QOpenGLShader>
QT_BEGIN_NAMESPACE
-class QSGFlashNode : public QSGSimpleRectNode
+class Q_QUICK_PRIVATE_EXPORT QSGMaterialShaderPrivate
{
public:
- QSGFlashNode();
+ const char *loadShaderSource(QOpenGLShader::ShaderType type) const;
- void preprocess();
-
-private:
- int m_counter;
+ QHash<QOpenGLShader::ShaderType, QStringList> m_sourceFiles;
+ mutable QHash<QOpenGLShader::ShaderType, QByteArray> m_sources;
};
QT_END_NAMESPACE
-#endif // QSGFLASHNODE_H
-
+#endif // QSGMATERIALSHADER_P_H
diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
index d5e83bb452..51cc844612 100644
--- a/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
+++ b/src/quick/scenegraph/coreapi/qsgnodeupdater.cpp
@@ -102,16 +102,11 @@ void QSGNodeUpdater::updateStates(QSGNode *n)
bool QSGNodeUpdater::isNodeBlocked(QSGNode *node, QSGNode *root) const
{
- qreal opacity = 1;
while (node != root && node != 0) {
- if (node->type() == QSGNode::OpacityNodeType) {
- opacity *= static_cast<QSGOpacityNode *>(node)->opacity();
- if (opacity < 0.001)
- return true;
- }
+ if (node->isSubtreeBlocked())
+ return true;
node = node->parent();
}
-
return false;
}
diff --git a/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h b/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h
index d0adbc5dd2..4c3be61a76 100644
--- a/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h
+++ b/src/quick/scenegraph/coreapi/qsgnodeupdater_p.h
@@ -64,9 +64,6 @@ public:
virtual void updateStates(QSGNode *n);
virtual bool isNodeBlocked(QSGNode *n, QSGNode *root) const;
- void setToplevelOpacity(qreal alpha) { m_opacity_stack.last() = alpha; }
- qreal toplevelOpacity() const { return m_opacity_stack.last(); }
-
protected:
virtual void enterTransformNode(QSGTransformNode *);
virtual void leaveTransformNode(QSGTransformNode *);
@@ -88,8 +85,6 @@ protected:
const QSGClipNode *m_current_clip;
int m_force_update;
-
- qreal m_toplevel_alpha;
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer.cpp b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
index 216c32f027..3c9c353bd8 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrenderer.cpp
@@ -46,6 +46,7 @@
#include "qsggeometry_p.h"
#include <private/qsgadaptationlayer_p.h>
+#include <private/qsgshadersourcebuilder_p.h>
#include <QOpenGLShaderProgram>
#include <qopenglframebufferobject.h>
@@ -133,7 +134,7 @@ void QSGBindableFboId::bind() const
*/
-QSGRenderer::QSGRenderer(QSGContext *context)
+QSGRenderer::QSGRenderer(QSGRenderContext *context)
: QObject()
, m_clear_color(Qt::transparent)
, m_clear_mode(ClearColorBuffer | ClearDepthBuffer)
@@ -162,20 +163,6 @@ QSGRenderer::~QSGRenderer()
}
/*!
- Returns the scene graph context for this renderer.
-
- \internal
- */
-
-QSGContext *QSGRenderer::context()
-{
- return m_context;
-}
-
-
-
-
-/*!
Returns the node updater that this renderer uses to update states in the
scene graph.
@@ -398,7 +385,6 @@ void QSGRenderer::preprocess()
preprocessTime = frameTimer.nsecsElapsed();
#endif
- nodeUpdater()->setToplevelOpacity(context()->renderAlpha());
nodeUpdater()->updateStates(m_root_node);
#ifndef QSG_NO_RENDER_TIMING
@@ -496,16 +482,10 @@ QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip)
} else {
if (!(clipType & StencilClip)) {
if (!m_clip_program.isLinked()) {
- m_clip_program.addShaderFromSourceCode(QOpenGLShader::Vertex,
- "attribute highp vec4 vCoord; \n"
- "uniform highp mat4 matrix; \n"
- "void main() { \n"
- " gl_Position = matrix * vCoord; \n"
- "}");
- m_clip_program.addShaderFromSourceCode(QOpenGLShader::Fragment,
- "void main() { \n"
- " gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); \n" // Trolltech green ftw!
- "}");
+ QSGShaderSourceBuilder::initializeProgramFromFiles(
+ &m_clip_program,
+ QStringLiteral(":/scenegraph/shaders/stencilclip.vert"),
+ QStringLiteral(":/scenegraph/shaders/stencilclip.frag"));
m_clip_program.bindAttributeLocation("vCoord", 0);
m_clip_program.link();
m_clip_matrix_id = m_clip_program.uniformLocation("matrix");
diff --git a/src/quick/scenegraph/coreapi/qsgrenderer_p.h b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
index a1ebfa0946..43811e6d5e 100644
--- a/src/quick/scenegraph/coreapi/qsgrenderer_p.h
+++ b/src/quick/scenegraph/coreapi/qsgrenderer_p.h
@@ -84,7 +84,7 @@ public:
};
Q_DECLARE_FLAGS(ClearMode, ClearModeBit)
- QSGRenderer(QSGContext *context);
+ QSGRenderer(QSGRenderContext *context);
virtual ~QSGRenderer();
void setRootNode(QSGRootNode *node);
@@ -117,9 +117,7 @@ public:
void setClearColor(const QColor &color);
QColor clearColor() const { return m_clear_color; }
- QOpenGLContext *glContext() const { Q_ASSERT(m_context); return m_context->glContext(); }
-
- QSGContext *context();
+ QSGRenderContext *context() const { return m_context; }
void renderScene();
void renderScene(const QSGBindable &bindable);
@@ -161,7 +159,7 @@ protected:
QRect m_current_scissor_rect;
int m_current_stencil_value;
- QSGContext *m_context;
+ QSGRenderContext *m_context;
private:
QSGRootNode *m_root_node;
diff --git a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
index eade198cd0..2849eff304 100644
--- a/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
+++ b/src/quick/scenegraph/coreapi/qsgshaderrewriter.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include <QtCore>
+#include <QtGui/QSurfaceFormat>
// Duct Tape tokenizer for the purpose of parsing and rewriting
// shader source code
@@ -173,7 +174,7 @@ Tokenizer::Token Tokenizer::next()
using namespace QSGShaderRewriter;
-QByteArray qsgShaderRewriter_insertZAttributes(const char *input)
+QByteArray qsgShaderRewriter_insertZAttributes(const char *input, QSurfaceFormat::OpenGLContextProfile profile)
{
Tokenizer tok;
tok.initialize(input);
@@ -182,15 +183,33 @@ QByteArray qsgShaderRewriter_insertZAttributes(const char *input)
Tokenizer::Token t = tok.next();
// First find "void main() { ... "
+ const char* voidPos = input;
while (t != Tokenizer::Token_EOF) {
if (lt == Tokenizer::Token_Void && t == Tokenizer::Token_Identifier) {
if (qstrncmp("main", tok.identifier, 4) == 0)
break;
}
+ voidPos = tok.pos - 4;
lt = t;
t = tok.next();
}
+ QByteArray result;
+ result.reserve(1024);
+ result += QByteArray::fromRawData(input, voidPos - input);
+ switch (profile) {
+ case QSurfaceFormat::NoProfile:
+ case QSurfaceFormat::CompatibilityProfile:
+ result += QByteArrayLiteral("attribute highp float _qt_order;\n");
+ result += QByteArrayLiteral("uniform highp float _qt_zRange;\n");
+ break;
+
+ case QSurfaceFormat::CoreProfile:
+ result += QByteArrayLiteral("in float _qt_order;\n");
+ result += QByteArrayLiteral("uniform float _qt_zRange;\n");
+ break;
+ }
+
// Find first brace '{'
while (t != Tokenizer::Token_EOF && t != Tokenizer::Token_OpenBrace) t = tok.next();
int braceDepth = 1;
@@ -202,12 +221,8 @@ QByteArray qsgShaderRewriter_insertZAttributes(const char *input)
case Tokenizer::Token_CloseBrace:
braceDepth--;
if (braceDepth == 0) {
- QByteArray result;
- result.reserve(1024);
- result += "attribute highp float _qt_order;\n";
- result += "uniform highp float _qt_zRange;\n";
- result += QByteArray::fromRawData(input, tok.pos - 1 - input);
- result += " gl_Position.z = gl_Position.z * _qt_zRange + _qt_order;\n";
+ result += QByteArray::fromRawData(voidPos, tok.pos - 1 - voidPos);
+ result += QByteArrayLiteral(" gl_Position.z = (gl_Position.z * _qt_zRange + _qt_order) * gl_Position.w;\n");
result += QByteArray(tok.pos - 1);
return result;
}
diff --git a/src/quick/scenegraph/qsgadaptationlayer.cpp b/src/quick/scenegraph/qsgadaptationlayer.cpp
index cdf63be5f2..58c843a286 100644
--- a/src/quick/scenegraph/qsgadaptationlayer.cpp
+++ b/src/quick/scenegraph/qsgadaptationlayer.cpp
@@ -61,8 +61,7 @@ static QElapsedTimer qsg_render_timer;
QSGDistanceFieldGlyphCache::Texture QSGDistanceFieldGlyphCache::s_emptyTexture;
QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font)
- : ctx(c)
- , m_manager(man)
+ : m_manager(man)
, m_pendingGlyphs(64)
{
Q_ASSERT(font.isValid());
@@ -75,6 +74,8 @@ QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCach
m_referenceFont = font;
m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(m_doubleGlyphResolution));
Q_ASSERT(m_referenceFont.isValid());
+
+ m_coreProfile = (c->format().profile() == QSurfaceFormat::CoreProfile);
}
QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
diff --git a/src/quick/scenegraph/qsgadaptationlayer_p.h b/src/quick/scenegraph/qsgadaptationlayer_p.h
index ebeb449be5..f2d7dc07ca 100644
--- a/src/quick/scenegraph/qsgadaptationlayer_p.h
+++ b/src/quick/scenegraph/qsgadaptationlayer_p.h
@@ -66,6 +66,7 @@ class QImage;
class TextureReference;
class QSGDistanceFieldGlyphCacheManager;
class QSGDistanceFieldGlyphNode;
+class QOpenGLContext;
class Q_QUICK_PRIVATE_EXPORT QSGRectangleNode : public QSGGeometryNode
{
@@ -246,7 +247,7 @@ protected:
GlyphData &glyphData(glyph_t glyph);
- QOpenGLContext *ctx;
+ inline bool isCoreProfile() const { return m_coreProfile; }
private:
QSGDistanceFieldGlyphCacheManager *m_manager;
@@ -255,6 +256,7 @@ private:
int m_glyphCount;
bool m_doubleGlyphResolution;
+ bool m_coreProfile;
QList<Texture> m_textures;
QHash<glyph_t, GlyphData> m_glyphsData;
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index bb8e3c4b36..afde7939f2 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -72,11 +72,8 @@
#include <private/qqmlprofilerservice_p.h>
-DEFINE_BOOL_CONFIG_OPTION(qmlFlashMode, QML_FLASH_MODE)
-DEFINE_BOOL_CONFIG_OPTION(qmlTranslucentMode, QML_TRANSLUCENT_MODE)
DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
-
/*
Comments about this class from Gunnar:
@@ -94,51 +91,38 @@ DEFINE_BOOL_CONFIG_OPTION(qmlDisableDistanceField, QML_DISABLE_DISTANCEFIELD)
to defining plugin interfaces..
*/
-
QT_BEGIN_NAMESPACE
class QSGContextPrivate : public QObjectPrivate
{
public:
QSGContextPrivate()
- : gl(0)
- , depthStencilBufferManager(0)
- , distanceFieldCacheManager(0)
- #if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2_ANGLE)
- , distanceFieldAntialiasing(QSGGlyphNode::HighQualitySubPixelAntialiasing)
- #else
- , distanceFieldAntialiasing(QSGGlyphNode::GrayAntialiasing)
- #endif
- , atlasManager(0)
- , flashMode(qmlFlashMode())
+ : antialiasingMethod(QSGContext::UndecidedAntialiasing)
, distanceFieldDisabled(qmlDisableDistanceField())
- , msaa(false)
+ , distanceFieldAntialiasing(
+#if !defined(QT_OPENGL_ES) || defined(QT_OPENGL_ES_2_ANGLE)
+ QSGGlyphNode::HighQualitySubPixelAntialiasing
+#else
+ QSGGlyphNode::GrayAntialiasing
+#endif
+ )
{
- renderAlpha = qmlTranslucentMode() ? 0.5 : 1;
}
~QSGContextPrivate()
{
}
- QOpenGLContext *gl;
-
- QMutex textureMutex;
- QHash<QQuickTextureFactory *, QSGTexture *> textures;
- QSGDepthStencilBufferManager *depthStencilBufferManager;
- QSGDistanceFieldGlyphCacheManager *distanceFieldCacheManager;
-
- QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing;
-
- QSGAtlasTexture::Manager *atlasManager;
-
- bool flashMode;
- float renderAlpha;
+ QMutex mutex;
+ QSGContext::AntialiasingMethod antialiasingMethod;
bool distanceFieldDisabled;
+ QSGDistanceFieldGlyphNode::AntialiasingMode distanceFieldAntialiasing;
- bool msaa;
+ static QOpenGLContext *sharedOpenGLContext;
};
+QOpenGLContext *QSGContextPrivate::sharedOpenGLContext = 0;
+
class QSGTextureCleanupEvent : public QEvent
{
public:
@@ -188,144 +172,190 @@ QSGContext::QSGContext(QObject *parent) :
QSGContext::~QSGContext()
{
- invalidate();
}
+/*!
+ * This function is used by the Qt WebEngine to set up context sharing
+ * across multiple windows. Do not use it for any other purpose.
+ */
+void QSGContext::setSharedOpenGLContext(QOpenGLContext *context)
+{
+ QSGContextPrivate::sharedOpenGLContext = context;
+}
+QOpenGLContext *QSGContext::sharedOpenGLContext()
+{
+ return QSGContextPrivate::sharedOpenGLContext;
+}
-void QSGContext::invalidate()
+void QSGContext::renderContextInitialized(QSGRenderContext *renderContext)
{
Q_D(QSGContext);
- d->textureMutex.lock();
- qDeleteAll(d->textures.values());
- d->textures.clear();
- d->textureMutex.unlock();
- delete d->depthStencilBufferManager;
- d->depthStencilBufferManager = 0;
- delete d->distanceFieldCacheManager;
- d->distanceFieldCacheManager = 0;
- d->gl = 0;
-
- emit invalidated();
-
- /* The cleanup of the atlas textures is a bit intruiging.
- As part of the cleanup in the threaded render loop, we
- do:
- 1. call this function
- 2. call QCoreApp::sendPostedEvents() to immediately process
- any pending deferred deletes.
- 3. delete the GL context.
- As textures need the atlas manager while cleaning up, the
- manager needs to be cleaned up after the textures, so
- we post a deleteLater here at the very bottom so it gets
- deferred deleted last.
-
- Another alternative would be to use a QPointer in
- QSGAtlasTexture::Texture, but this seemed simpler.
- */
+ d->mutex.lock();
+ if (d->antialiasingMethod == UndecidedAntialiasing) {
+ QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD");
+ if (aaType == "msaa") {
+ d->antialiasingMethod = MsaaAntialiasing;
+ } else if (aaType == "vertex") {
+ d->antialiasingMethod = VertexAntialiasing;
+ } else {
+ if (renderContext->openglContext()->format().samples() > 0)
+ d->antialiasingMethod = MsaaAntialiasing;
+ else
+ d->antialiasingMethod = VertexAntialiasing;
+ }
+ }
- if (d->atlasManager) {
- d->atlasManager->deleteLater();
- d->atlasManager = 0;
+ static bool dumped = false;
+ if (!dumped && qEnvironmentVariableIsSet("QSG_INFO")) {
+ dumped = true;
+ qDebug() << "GL_VENDOR: " << (const char *) glGetString(GL_VENDOR);
+ qDebug() << "GL_RENDERER: " << (const char *) glGetString(GL_RENDERER);
+ qDebug() << "GL_VERSION: " << (const char *) glGetString(GL_VERSION);
+ qDebug() << "GL_EXTENSIONS:\n " << QByteArray((const char *) glGetString(GL_EXTENSIONS)).replace(" ", "\n ").constData();
}
+
+ d->mutex.unlock();
}
+void QSGContext::renderContextInvalidated(QSGRenderContext *)
+{
+}
-QSGTexture *QSGContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window)
+/*!
+ Factory function for scene graph backends of the Rectangle element.
+ */
+QSGRectangleNode *QSGContext::createRectangleNode()
{
Q_D(QSGContext);
- if (!factory)
- return 0;
-
- d->textureMutex.lock();
- QSGTexture *texture = d->textures.value(factory);
- if (!texture) {
- if (QQuickDefaultTextureFactory *dtf = qobject_cast<QQuickDefaultTextureFactory *>(factory))
- texture = createTexture(dtf->image());
- else
- texture = factory->createTexture(window);
- d->textures.insert(factory, texture);
- connect(factory, SIGNAL(destroyed(QObject *)), this, SLOT(textureFactoryDestroyed(QObject *)), Qt::DirectConnection);
- }
- d->textureMutex.unlock();
- return texture;
+ return d->antialiasingMethod == MsaaAntialiasing
+ ? new QSGMultisampleAntialiasing::RectangleNode
+ : new QSGDefaultRectangleNode;
}
+/*!
+ Factory function for scene graph backends of the Image element.
+ */
+QSGImageNode *QSGContext::createImageNode()
+{
+ Q_D(QSGContext);
+ return d->antialiasingMethod == MsaaAntialiasing
+ ? new QSGMultisampleAntialiasing::ImageNode
+ : new QSGDefaultImageNode;
+}
-void QSGContext::textureFactoryDestroyed(QObject *o)
+/*!
+ Factory function for scene graph backends of the Text elements which supports native
+ text rendering. Used in special cases where native look and feel is a main objective.
+*/
+QSGGlyphNode *QSGContext::createNativeGlyphNode(QSGRenderContext *rc)
{
+#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_ES_2_ANGLE)
Q_D(QSGContext);
- QQuickTextureFactory *f = static_cast<QQuickTextureFactory *>(o);
+ if (d->distanceFieldDisabled)
+ return new QSGDefaultGlyphNode;
+ else
+ return createGlyphNode(rc);
+#else
+ Q_UNUSED(rc);
+ return new QSGDefaultGlyphNode;
+#endif
+}
- d->textureMutex.lock();
- QSGTexture *t = d->textures.take(f);
- d->textureMutex.unlock();
+/*!
+ Factory function for scene graph backends of the Text elements;
+ */
+QSGGlyphNode *QSGContext::createGlyphNode(QSGRenderContext *rc)
+{
+ Q_D(QSGContext);
- if (t) {
- if (t->thread() == thread())
- t->deleteLater();
- else
- QCoreApplication::postEvent(this, new QSGTextureCleanupEvent(t));
+ if (d->distanceFieldDisabled) {
+ return createNativeGlyphNode(rc);
+ } else {
+ QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(rc);
+ node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing);
+ return node;
}
}
-
-QOpenGLContext *QSGContext::glContext() const
+QSurfaceFormat QSGContext::defaultSurfaceFormat() const
{
- Q_D(const QSGContext);
- return d->gl;
+ QSurfaceFormat format;
+ format.setDepthBufferSize(24);
+ format.setStencilBufferSize(8);
+ if (QQuickWindow::hasDefaultAlphaBuffer())
+ format.setAlphaBufferSize(8);
+ format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
+ return format;
}
/*!
- Initializes the scene graph context with the GL context \a context. This also
- emits the ready() signal so that the QML graph can start building scene graph nodes.
+ Returns the minimum supported framebuffer object size.
*/
-void QSGContext::initialize(QOpenGLContext *context)
+
+QSize QSGContext::minimumFBOSize() const
{
- Q_D(QSGContext);
+#ifdef Q_OS_MAC
+ return QSize(33, 33);
+#else
+ return QSize(1, 1);
+#endif
+}
- QByteArray aaType = qgetenv("QSG_ANTIALIASING_METHOD");
- if (aaType == "msaa") {
- d->msaa = true;
- } else if (aaType == "vertex") {
- d->msaa = false;
- } else {
- if (context->format().samples() > 0)
- d->msaa = true;
- else
- d->msaa = false;
- }
- // Sanity check the surface format, in case it was overridden by the application
- QSurfaceFormat requested = defaultSurfaceFormat();
- QSurfaceFormat actual = context->format();
- if (requested.depthBufferSize() > 0 && actual.depthBufferSize() <= 0)
- qWarning("QSGContext::initialize: depth buffer support missing, expect rendering errors");
- if (requested.stencilBufferSize() > 0 && actual.stencilBufferSize() <= 0)
- qWarning("QSGContext::initialize: stencil buffer support missing, expect rendering errors");
- d->atlasManager = new QSGAtlasTexture::Manager();
+/*!
+ Sets whether or not the scene graph should use the distance field technique to render text
+ */
+void QSGContext::setDistanceFieldEnabled(bool enabled)
+{
+ d_func()->distanceFieldDisabled = !enabled;
+}
- Q_ASSERT(!d->gl);
- d->gl = context;
- emit initialized();
+/*!
+ Returns true if the scene graph uses the distance field technique to render text
+ */
+bool QSGContext::isDistanceFieldEnabled() const
+{
+ return !d_func()->distanceFieldDisabled;
}
+
+
/*!
- Returns if the scene graph context is ready or not, meaning that it has a valid
- GL context.
+ Creates a new animation driver.
*/
-bool QSGContext::isReady() const
+
+QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
{
- Q_D(const QSGContext);
- return d->gl;
+ return new QAnimationDriver(parent);
}
+QSGRenderContext::QSGRenderContext(QSGContext *context)
+ : m_gl(0)
+ , m_sg(context)
+ , m_atlasManager(0)
+ , m_depthStencilManager(0)
+ , m_distanceFieldCacheManager(0)
+ , m_brokenIBOs(false)
+ , m_serializedRender(false)
+{
+}
-void QSGContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId)
+QSGRenderContext::~QSGRenderContext()
{
+ invalidate();
+}
+
+static QBasicMutex qsg_framerender_mutex;
+
+void QSGRenderContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId)
+{
+ if (m_serializedRender)
+ qsg_framerender_mutex.lock();
+
if (fboId) {
QSGBindableFboId bindable(fboId);
renderer->renderScene(bindable);
@@ -333,39 +363,20 @@ void QSGContext::renderNextFrame(QSGRenderer *renderer, GLuint fboId)
renderer->renderScene();
}
-}
+ if (m_serializedRender)
+ qsg_framerender_mutex.unlock();
-/*!
- Factory function for scene graph backends of the Rectangle element.
- */
-QSGRectangleNode *QSGContext::createRectangleNode()
-{
- Q_D(QSGContext);
- return d->msaa ? new QSGMultisampleAntialiasing::RectangleNode
- : new QSGDefaultRectangleNode;
-}
-
-/*!
- Factory function for scene graph backends of the Image element.
- */
-QSGImageNode *QSGContext::createImageNode()
-{
- Q_D(QSGContext);
- return d->msaa ? new QSGMultisampleAntialiasing::ImageNode
- : new QSGDefaultImageNode;
}
/*!
Factory function for scene graph backends of the distance-field glyph cache.
*/
-QSGDistanceFieldGlyphCache *QSGContext::distanceFieldGlyphCache(const QRawFont &font)
+QSGDistanceFieldGlyphCache *QSGRenderContext::distanceFieldGlyphCache(const QRawFont &font)
{
- Q_D(QSGContext);
-
- if (!d->distanceFieldCacheManager)
- d->distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager;
+ if (!m_distanceFieldCacheManager)
+ m_distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager;
- QSGDistanceFieldGlyphCache *cache = d->distanceFieldCacheManager->cache(font);
+ QSGDistanceFieldGlyphCache *cache = m_distanceFieldCacheManager->cache(font);
if (!cache) {
QPlatformIntegration *platformIntegration = QGuiApplicationPrivate::platformIntegration();
if (platformIntegration != 0
@@ -387,125 +398,125 @@ QSGDistanceFieldGlyphCache *QSGContext::distanceFieldGlyphCache(const QRawFont &
QPlatformSharedGraphicsCache::Alpha8);
cache = new QSGSharedDistanceFieldGlyphCache(keyName,
- sharedGraphicsCache,
- d->distanceFieldCacheManager,
- glContext(),
- font);
+ sharedGraphicsCache,
+ m_distanceFieldCacheManager,
+ openglContext(),
+ font);
}
}
}
if (!cache)
- cache = new QSGDefaultDistanceFieldGlyphCache(d->distanceFieldCacheManager, glContext(), font);
- d->distanceFieldCacheManager->insertCache(font, cache);
+ cache = new QSGDefaultDistanceFieldGlyphCache(m_distanceFieldCacheManager, openglContext(), font);
+ m_distanceFieldCacheManager->insertCache(font, cache);
}
+
return cache;
}
-/*!
- Factory function for scene graph backends of the Text elements which supports native
- text rendering. Used in special cases where native look and feel is a main objective.
-*/
-QSGGlyphNode *QSGContext::createNativeGlyphNode()
+#define QSG_RENDERCONTEXT_PROPERTY "_q_sgrendercontext"
+
+QSGRenderContext *QSGRenderContext::from(QOpenGLContext *context)
{
-#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_ES_2_ANGLE)
- Q_D(QSGContext);
- if (d->distanceFieldDisabled)
- return new QSGDefaultGlyphNode;
- else
- return createGlyphNode();
-#else
- return new QSGDefaultGlyphNode;
-#endif
+ return qobject_cast<QSGRenderContext *>(context->property(QSG_RENDERCONTEXT_PROPERTY).value<QObject *>());
}
-/*!
- Factory function for scene graph backends of the Text elements;
- */
-QSGGlyphNode *QSGContext::createGlyphNode()
+void QSGRenderContext::registerFontengineForCleanup(QFontEngine *engine)
{
- Q_D(QSGContext);
-
- if (d->distanceFieldDisabled) {
- return createNativeGlyphNode();
- } else {
- QSGDistanceFieldGlyphNode *node = new QSGDistanceFieldGlyphNode(this);
- node->setPreferredAntialiasingMode(d->distanceFieldAntialiasing);
- return node;
- }
+ m_fontEnginesToClean << engine;
}
/*!
- Factory function for the scene graph renderers.
-
- The renderers are used for the toplevel renderer and once for every
- QQuickShaderEffectSource used in the QML scene.
+ Initializes the scene graph render context with the GL context \a context. This also
+ emits the ready() signal so that the QML graph can start building scene graph nodes.
*/
-QSGRenderer *QSGContext::createRenderer()
+void QSGRenderContext::initialize(QOpenGLContext *context)
{
- return new QSGBatchRenderer::Renderer(this);
-}
-
-
+ // Sanity check the surface format, in case it was overridden by the application
+ QSurfaceFormat requested = m_sg->defaultSurfaceFormat();
+ QSurfaceFormat actual = context->format();
+ if (requested.depthBufferSize() > 0 && actual.depthBufferSize() <= 0)
+ qWarning("QSGContext::initialize: depth buffer support missing, expect rendering errors");
+ if (requested.stencilBufferSize() > 0 && actual.stencilBufferSize() <= 0)
+ qWarning("QSGContext::initialize: stencil buffer support missing, expect rendering errors");
+ if (!m_atlasManager)
+ m_atlasManager = new QSGAtlasTexture::Manager();
+
+ Q_ASSERT_X(!m_gl, "QSGRenderContext::initialize", "already initialized!");
+ m_gl = context;
+ m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant::fromValue(this));
+ m_sg->renderContextInitialized(this);
+
+#ifdef Q_OS_LINUX
+ const char *vendor = (const char *) glGetString(GL_VENDOR);
+ if (strstr(vendor, "nouveau"))
+ m_brokenIBOs = true;
+ const char *renderer = (const char *) glGetString(GL_RENDERER);
+ if (strstr(renderer, "llvmpipe"))
+ m_serializedRender = true;
+#endif
-QSurfaceFormat QSGContext::defaultSurfaceFormat() const
-{
- QSurfaceFormat format;
- format.setDepthBufferSize(24);
- format.setStencilBufferSize(8);
- if (QQuickWindow::hasDefaultAlphaBuffer())
- format.setAlphaBufferSize(8);
- format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
- return format;
+ emit initialized();
}
-
-/*!
- Factory function for texture objects.
-
- If \a image is a valid image, the QSGTexture::setImage function
- will be called with \a image as argument.
- */
-
-QSGTexture *QSGContext::createTexture(const QImage &image) const
+void QSGRenderContext::invalidate()
{
- Q_D(const QSGContext);
- QSGTexture *at = d->atlasManager->create(image);
- if (at)
- return at;
- return createTextureNoAtlas(image);
-}
+ if (!m_gl)
+ return;
+
+ qDeleteAll(m_textures.values());
+ m_textures.clear();
+
+ /* The cleanup of the atlas textures is a bit intriguing.
+ As part of the cleanup in the threaded render loop, we
+ do:
+ 1. call this function
+ 2. call QCoreApp::sendPostedEvents() to immediately process
+ any pending deferred deletes.
+ 3. delete the GL context.
+
+ As textures need the atlas manager while cleaning up, the
+ manager needs to be cleaned up after the textures, so
+ we post a deleteLater here at the very bottom so it gets
+ deferred deleted last.
+
+ Another alternative would be to use a QPointer in
+ QSGAtlasTexture::Texture, but this seemed simpler.
+ */
+ m_atlasManager->invalidate();
+ m_atlasManager->deleteLater();
+ m_atlasManager = 0;
+
+ // The following piece of code will read/write to the font engine's caches,
+ // potentially from different threads. However, this is safe because this
+ // code is only called from QQuickWindow's shutdown which is called
+ // only when the GUI is blocked, and multiple threads will call it in
+ // sequence. (see qsgdefaultglyphnode_p.cpp's init())
+ for (QSet<QFontEngine *>::const_iterator it = m_fontEnginesToClean.constBegin(),
+ end = m_fontEnginesToClean.constEnd(); it != end; ++it) {
+ (*it)->clearGlyphCache(m_gl);
+ }
+ m_fontEnginesToClean.clear();
-QSGTexture *QSGContext::createTextureNoAtlas(const QImage &image) const
-{
- QSGPlainTexture *t = new QSGPlainTexture();
- if (!image.isNull())
- t->setImage(image);
- return t;
-}
+ delete m_depthStencilManager;
+ m_depthStencilManager = 0;
-/*!
- Returns the minimum supported framebuffer object size.
- */
-
-QSize QSGContext::minimumFBOSize() const
-{
-#ifdef Q_OS_MAC
- return QSize(33, 33);
-#else
- return QSize(1, 1);
-#endif
-}
+ delete m_distanceFieldCacheManager;
+ m_distanceFieldCacheManager = 0;
+ m_gl->setProperty(QSG_RENDERCONTEXT_PROPERTY, QVariant());
+ m_gl = 0;
+ m_sg->renderContextInvalidated(this);
+ emit invalidated();
+}
/*!
Returns a shared pointer to a depth stencil buffer that can be used with \a fbo.
*/
-QSharedPointer<QSGDepthStencilBuffer> QSGContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo)
+QSharedPointer<QSGDepthStencilBuffer> QSGRenderContext::depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo)
{
- Q_D(QSGContext);
- if (!d->gl)
+ if (!m_gl)
return QSharedPointer<QSGDepthStencilBuffer>();
QSGDepthStencilBufferManager *manager = depthStencilBufferManager();
QSGDepthStencilBuffer::Format format;
@@ -514,7 +525,7 @@ QSharedPointer<QSGDepthStencilBuffer> QSGContext::depthStencilBufferForFbo(QOpen
format.attachments = QSGDepthStencilBuffer::DepthAttachment | QSGDepthStencilBuffer::StencilAttachment;
QSharedPointer<QSGDepthStencilBuffer> buffer = manager->bufferForFormat(format);
if (buffer.isNull()) {
- buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(d->gl, format));
+ buffer = QSharedPointer<QSGDepthStencilBuffer>(new QSGDefaultDepthStencilBuffer(m_gl, format));
manager->insertBuffer(buffer);
}
return buffer;
@@ -524,89 +535,81 @@ QSharedPointer<QSGDepthStencilBuffer> QSGContext::depthStencilBufferForFbo(QOpen
Returns a pointer to the context's depth/stencil buffer manager. This is useful for custom
implementations of \l depthStencilBufferForFbo().
*/
-QSGDepthStencilBufferManager *QSGContext::depthStencilBufferManager()
+QSGDepthStencilBufferManager *QSGRenderContext::depthStencilBufferManager()
{
- Q_D(QSGContext);
- if (!d->gl)
+ if (!m_gl)
return 0;
- if (!d->depthStencilBufferManager)
- d->depthStencilBufferManager = new QSGDepthStencilBufferManager(d->gl);
- return d->depthStencilBufferManager;
+ if (!m_depthStencilManager)
+ m_depthStencilManager = new QSGDepthStencilBufferManager(m_gl);
+ return m_depthStencilManager;
}
/*!
- Sets whether the scene graph should render with flashing update rectangles or not
- */
-
-void QSGContext::setFlashModeEnabled(bool enabled)
-{
- d_func()->flashMode = enabled;
-}
-
+ Factory function for texture objects.
-/*!
- Returns true if the scene graph should be rendered with flashing update rectangles
+ If \a image is a valid image, the QSGTexture::setImage function
+ will be called with \a image as argument.
*/
-bool QSGContext::isFlashModeEnabled() const
+
+QSGTexture *QSGRenderContext::createTexture(const QImage &image) const
{
- return d_func()->flashMode;
+ QSGTexture *t = m_atlasManager->create(image);
+ if (t)
+ return t;
+ return createTextureNoAtlas(image);
}
-
-/*!
- Sets the toplevel opacity for rendering. This value will be multiplied into all
- drawing calls where possible.
-
- The default value is 1. Any other value will cause artifacts and is primarily
- useful for debugging.
- */
-void QSGContext::setRenderAlpha(qreal renderAlpha)
+QSGTexture *QSGRenderContext::createTextureNoAtlas(const QImage &image) const
{
- d_func()->renderAlpha = renderAlpha;
+ QSGPlainTexture *t = new QSGPlainTexture();
+ if (!image.isNull())
+ t->setImage(image);
+ return t;
}
-
/*!
- Returns the toplevel opacity used for rendering.
-
- The default value is 1.
+ Factory function for the scene graph renderers.
- \sa setRenderAlpha()
+ The renderers are used for the toplevel renderer and once for every
+ QQuickShaderEffectSource used in the QML scene.
*/
-qreal QSGContext::renderAlpha() const
+QSGRenderer *QSGRenderContext::createRenderer()
{
- return d_func()->renderAlpha;
+ return new QSGBatchRenderer::Renderer(this);
}
-
-/*!
- Sets whether or not the scene graph should use the distance field technique to render text
- */
-void QSGContext::setDistanceFieldEnabled(bool enabled)
+QSGTexture *QSGRenderContext::textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window)
{
- d_func()->distanceFieldDisabled = !enabled;
-}
+ if (!factory)
+ return 0;
+ m_mutex.lock();
+ QSGTexture *texture = m_textures.value(factory);
+ m_mutex.unlock();
-/*!
- Returns true if the scene graph uses the distance field technique to render text
- */
-bool QSGContext::isDistanceFieldEnabled() const
-{
- return !d_func()->distanceFieldDisabled;
-}
-
+ if (!texture) {
+ if (QQuickDefaultTextureFactory *dtf = qobject_cast<QQuickDefaultTextureFactory *>(factory))
+ texture = createTexture(dtf->image());
+ else
+ texture = factory->createTexture(window);
+ m_mutex.lock();
+ m_textures.insert(factory, texture);
+ m_mutex.unlock();
-/*!
- Creates a new animation driver.
- */
+ connect(factory, SIGNAL(destroyed(QObject *)), this, SLOT(textureFactoryDestroyed(QObject *)), Qt::DirectConnection);
+ }
+ return texture;
+}
-QAnimationDriver *QSGContext::createAnimationDriver(QObject *parent)
+void QSGRenderContext::textureFactoryDestroyed(QObject *o)
{
- return new QAnimationDriver(parent);
+ m_mutex.lock();
+ QSGTexture *t = m_textures.take(static_cast<QQuickTextureFactory *>(o));
+ m_mutex.unlock();
+ if (t)
+ t->deleteLater();
}
-
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgcontext_p.h b/src/quick/scenegraph/qsgcontext_p.h
index 2057c0031d..c562a909c5 100644
--- a/src/quick/scenegraph/qsgcontext_p.h
+++ b/src/quick/scenegraph/qsgcontext_p.h
@@ -56,6 +56,9 @@
QT_BEGIN_NAMESPACE
+namespace QSGAtlasTexture {
+ class Manager;
+}
class QSGContextPrivate;
class QSGRectangleNode;
@@ -73,66 +76,102 @@ class QOpenGLContext;
class QOpenGLFramebufferObject;
class QQuickTextureFactory;
+class QSGDistanceFieldGlyphCacheManager;
+class QSGContext;
-class Q_QUICK_PRIVATE_EXPORT QSGContext : public QObject
+
+class Q_QUICK_PRIVATE_EXPORT QSGRenderContext : public QObject
{
Q_OBJECT
- Q_DECLARE_PRIVATE(QSGContext)
-
public:
- explicit QSGContext(QObject *parent = 0);
- ~QSGContext();
+ QSGRenderContext(QSGContext *context);
+ ~QSGRenderContext();
+
+ QOpenGLContext *openglContext() const { return m_gl; }
+ QSGContext *sceneGraphContext() const { return m_sg; }
virtual void initialize(QOpenGLContext *context);
virtual void invalidate();
- QOpenGLContext *glContext() const;
-
- bool isReady() const;
-
virtual void renderNextFrame(QSGRenderer *renderer, GLuint fboId);
- virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font);
+ virtual QSharedPointer<QSGDepthStencilBuffer> depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo);
+ QSGDepthStencilBufferManager *depthStencilBufferManager();
- virtual QSGRectangleNode *createRectangleNode();
- virtual QSGImageNode *createImageNode();
- virtual QSGGlyphNode *createGlyphNode();
- virtual QSGGlyphNode *createNativeGlyphNode();
- virtual QSGRenderer *createRenderer();
+ virtual QSGDistanceFieldGlyphCache *distanceFieldGlyphCache(const QRawFont &font);
+ QSGTexture *textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window);
virtual QSGTexture *createTexture(const QImage &image) const;
virtual QSGTexture *createTextureNoAtlas(const QImage &image) const;
- virtual QSize minimumFBOSize() const;
- virtual QSharedPointer<QSGDepthStencilBuffer> depthStencilBufferForFbo(QOpenGLFramebufferObject *fbo);
- QSGDepthStencilBufferManager *depthStencilBufferManager();
+ virtual QSGRenderer *createRenderer();
- virtual QSurfaceFormat defaultSurfaceFormat() const;
+ void registerFontengineForCleanup(QFontEngine *engine);
- QSGTexture *textureForFactory(QQuickTextureFactory *factory, QQuickWindow *window);
+ static QSGRenderContext *from(QOpenGLContext *context);
- static QSGContext *createDefaultContext();
+ bool hasBrokenIndexBufferObjects() const { return m_brokenIBOs; }
- void setFlashModeEnabled(bool enabled);
- bool isFlashModeEnabled() const;
+Q_SIGNALS:
+ void initialized();
+ void invalidated();
+
+public Q_SLOTS:
+ void textureFactoryDestroyed(QObject *o);
- void setRenderAlpha(qreal renderAlpha);
- qreal renderAlpha() const;
+protected:
+ QOpenGLContext *m_gl;
+ QSGContext *m_sg;
- void setDistanceFieldEnabled(bool enabled);
- bool isDistanceFieldEnabled() const;
+ QMutex m_mutex;
+ QHash<QQuickTextureFactory *, QSGTexture *> m_textures;
+ QSGAtlasTexture::Manager *m_atlasManager;
+ QSGDepthStencilBufferManager *m_depthStencilManager;
+ QSGDistanceFieldGlyphCacheManager *m_distanceFieldCacheManager;
+
+ QSet<QFontEngine *> m_fontEnginesToClean;
+
+ bool m_brokenIBOs;
+ bool m_serializedRender;
+};
+
+
+class Q_QUICK_PRIVATE_EXPORT QSGContext : public QObject
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSGContext)
+
+public:
+ enum AntialiasingMethod {
+ UndecidedAntialiasing,
+ VertexAntialiasing,
+ MsaaAntialiasing
+ };
+
+ explicit QSGContext(QObject *parent = 0);
+ ~QSGContext();
+
+ virtual void renderContextInitialized(QSGRenderContext *renderContext);
+ virtual void renderContextInvalidated(QSGRenderContext *renderContext);
+
+ virtual QSGRectangleNode *createRectangleNode();
+ virtual QSGImageNode *createImageNode();
+ virtual QSGGlyphNode *createGlyphNode(QSGRenderContext *rc);
+ virtual QSGGlyphNode *createNativeGlyphNode(QSGRenderContext *rc);
virtual QAnimationDriver *createAnimationDriver(QObject *parent);
- static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
- static QSGRenderLoop *createWindowManager();
+ virtual QSize minimumFBOSize() const;
+ virtual QSurfaceFormat defaultSurfaceFormat() const;
+ static void setSharedOpenGLContext(QOpenGLContext *context);
+ static QOpenGLContext *sharedOpenGLContext();
-public Q_SLOTS:
- void textureFactoryDestroyed(QObject *o);
+ void setDistanceFieldEnabled(bool enabled);
+ bool isDistanceFieldEnabled() const;
-Q_SIGNALS:
- void initialized();
- void invalidated();
+ static QSGContext *createDefaultContext();
+ static QQuickTextureFactory *createTextureFactoryFromImage(const QImage &image);
+ static QSGRenderLoop *createWindowManager();
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
index 8a1a87cdc0..c5c4e18e37 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache.cpp
@@ -48,6 +48,10 @@
#include <qopenglfunctions.h>
#include <qmath.h>
+#if !defined(QT_OPENGL_ES_2)
+#include <QtGui/qopenglfunctions_3_2_core.h>
+#endif
+
QT_BEGIN_NAMESPACE
DEFINE_BOOL_CONFIG_OPTION(qmlUseGlyphCacheWorkaround, QML_USE_GLYPHCACHE_WORKAROUND)
@@ -58,6 +62,9 @@ QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistance
, m_maxTextureCount(3)
, m_blitProgram(0)
, m_fboGuard(0)
+#if !defined(QT_OPENGL_ES_2)
+ , m_funcs(0)
+#endif
{
m_blitVertexCoordinateArray[0] = -1.0f;
m_blitVertexCoordinateArray[1] = -1.0f;
@@ -167,7 +174,7 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField>
if (glyph.width() != expectedWidth)
glyph = glyph.copy(0, 0, expectedWidth, glyph.height());
- if (useWorkaround()) {
+ if (useTextureResizeWorkaround()) {
uchar *inBits = glyph.scanLine(0);
uchar *outBits = texInfo->image.scanLine(int(c.y)) + int(c.x);
for (int y = 0; y < glyph.height(); ++y) {
@@ -177,7 +184,24 @@ void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QList<QDistanceField>
}
}
- glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
+#if !defined(QT_OPENGL_ES_2)
+ const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
+#else
+ const GLenum format = GL_ALPHA;
+#endif
+ if (useTextureUploadWorkaround()) {
+ for (int i = 0; i < glyph.height(); ++i) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ c.x, c.y + i, glyph.width(),1,
+ format, GL_UNSIGNED_BYTE,
+ glyph.scanLine(i));
+ }
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ c.x, c.y, glyph.width(), glyph.height(),
+ format, GL_UNSIGNED_BYTE,
+ glyph.constBits());
+ }
}
// restore to previous alignment
@@ -204,7 +228,7 @@ void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyph
void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int width, int height)
{
- if (useWorkaround() && texInfo->image.isNull())
+ if (useTextureResizeWorkaround() && texInfo->image.isNull())
texInfo->image = QDistanceField(width, height);
while (glGetError() != GL_NO_ERROR) { }
@@ -212,11 +236,20 @@ void QSGDefaultDistanceFieldGlyphCache::createTexture(TextureInfo *texInfo, int
glGenTextures(1, &texInfo->texture);
glBindTexture(GL_TEXTURE_2D, texInfo->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);
+#if !defined(QT_OPENGL_ES_2)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ const GLint internalFormat = isCoreProfile() ? GL_R8 : GL_ALPHA;
+ const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
+#else
+ const GLint internalFormat = GL_ALPHA;
+ const GLenum format = GL_ALPHA;
+#endif
+
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, 0);
texInfo->size = QSize(width, height);
@@ -236,6 +269,9 @@ static void freeFramebufferFunc(QOpenGLFunctions *funcs, GLuint id)
void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int width, int height)
{
+ QOpenGLContext *ctx = QOpenGLContext::currentContext();
+ Q_ASSERT(ctx);
+
int oldWidth = texInfo->size.width();
int oldHeight = texInfo->size.height();
if (width == oldWidth && height == oldHeight)
@@ -249,12 +285,76 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
updateTexture(oldTexture, texInfo->texture, texInfo->size);
- if (useWorkaround()) {
+#if !defined(QT_OPENGL_ES_2)
+ if (isCoreProfile() && !useTextureResizeWorkaround()) {
+ // For an OpenGL Core Profile we can use http://www.opengl.org/wiki/Framebuffer#Blitting
+ // to efficiently copy the contents of the old texture to the new texture
+ // TODO: Use ARB_copy_image if available of if we have >=4.3 context
+ if (!m_funcs) {
+ m_funcs = ctx->versionFunctions<QOpenGLFunctions_3_2_Core>();
+ Q_ASSERT(m_funcs);
+ m_funcs->initializeOpenGLFunctions();
+ }
+
+ // Create a framebuffer object to which we can attach our old and new textures (to
+ // the first two color buffer attachment points)
+ if (!m_fboGuard) {
+ GLuint fbo;
+ m_funcs->glGenFramebuffers(1, &fbo);
+ m_fboGuard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
+ }
+
+ // Bind the FBO to both the GL_READ_FRAMEBUFFER? and GL_DRAW_FRAMEBUFFER targets
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_fboGuard->id());
+
+ // Bind the old texture to GL_COLOR_ATTACHMENT0
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, oldTexture, 0);
+
+ // Bind the new texture to GL_COLOR_ATTACHMENT1
+ m_funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1,
+ GL_TEXTURE_2D, texInfo->texture, 0);
+
+ // Set the source and destination buffers
+ m_funcs->glReadBuffer(GL_COLOR_ATTACHMENT0);
+ m_funcs->glDrawBuffer(GL_COLOR_ATTACHMENT1);
+
+ // Do the blit
+ m_funcs->glBlitFramebuffer(0, 0, oldWidth, oldHeight,
+ 0, 0, oldWidth, oldHeight,
+ GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ // Reset the default framebuffer
+ m_funcs->glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ return;
+ } else if (useTextureResizeWorkaround()) {
+#else
+ if (useTextureResizeWorkaround()) {
+#endif
GLint alignment = 4; // default value
glGetIntegerv(GL_UNPACK_ALIGNMENT, &alignment);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, texInfo->image.constBits());
+#if !defined(QT_OPENGL_ES_2)
+ const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA;
+#else
+ const GLenum format = GL_ALPHA;
+#endif
+
+ if (useTextureUploadWorkaround()) {
+ for (int i = 0; i < texInfo->image.height(); ++i) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, i, oldWidth, 1,
+ format, GL_UNSIGNED_BYTE,
+ texInfo->image.scanLine(i));
+ }
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, 0, oldWidth, oldHeight,
+ format, GL_UNSIGNED_BYTE,
+ texInfo->image.constBits());
+ }
glPixelStorei(GL_UNPACK_ALIGNMENT, alignment); // restore to previous value
@@ -278,12 +378,15 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
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);
+#if !defined(QT_OPENGL_ES_2)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+#endif
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, tmp_texture, 0);
@@ -325,7 +428,12 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
glBindTexture(GL_TEXTURE_2D, texInfo->texture);
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+ if (useTextureUploadWorkaround()) {
+ for (int i = 0; i < oldHeight; ++i)
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, i, 0, i, oldWidth, 1);
+ } else {
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
+ }
ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER, 0);
@@ -350,12 +458,12 @@ void QSGDefaultDistanceFieldGlyphCache::resizeTexture(TextureInfo *texInfo, int
m_blitProgram->disableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
}
-bool QSGDefaultDistanceFieldGlyphCache::useWorkaround() const
+bool QSGDefaultDistanceFieldGlyphCache::useTextureResizeWorkaround() const
{
static bool set = false;
static bool useWorkaround = false;
if (!set) {
- QOpenGLContextPrivate *ctx_p = static_cast<QOpenGLContextPrivate *>(QOpenGLContextPrivate::get(ctx));
+ QOpenGLContextPrivate *ctx_p = static_cast<QOpenGLContextPrivate *>(QOpenGLContextPrivate::get(QOpenGLContext::currentContext()));
useWorkaround = ctx_p->workaround_brokenFBOReadBack
|| qmlUseGlyphCacheWorkaround(); // on some hardware the workaround is faster (see QTBUG-29264)
set = true;
@@ -363,6 +471,18 @@ bool QSGDefaultDistanceFieldGlyphCache::useWorkaround() const
return useWorkaround;
}
+bool QSGDefaultDistanceFieldGlyphCache::useTextureUploadWorkaround() const
+{
+ static bool set = false;
+ static bool useWorkaround = false;
+ if (!set) {
+ useWorkaround = qstrcmp(reinterpret_cast<const char*>(glGetString(GL_RENDERER)),
+ "Mali-400 MP") == 0;
+ set = true;
+ }
+ return useWorkaround;
+}
+
int QSGDefaultDistanceFieldGlyphCache::maxTextureSize() const
{
if (!m_maxTextureSize)
diff --git a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
index cd6fa00852..a5833af5fb 100644
--- a/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
+++ b/src/quick/scenegraph/qsgdefaultdistancefieldglyphcache_p.h
@@ -51,6 +51,10 @@
QT_BEGIN_NAMESPACE
class QOpenGLSharedResourceGuard;
+#if !defined(QT_OPENGL_ES_2)
+class QOpenGLFunctions_3_2_Core;
+#endif
+
class Q_QUICK_PRIVATE_EXPORT QSGDefaultDistanceFieldGlyphCache : public QSGDistanceFieldGlyphCache
{
public:
@@ -62,7 +66,8 @@ public:
void referenceGlyphs(const QSet<glyph_t> &glyphs);
void releaseGlyphs(const QSet<glyph_t> &glyphs);
- bool useWorkaround() const;
+ bool useTextureResizeWorkaround() const;
+ bool useTextureUploadWorkaround() const;
int maxTextureSize() const;
void setMaxTextureCount(int max) { m_maxTextureCount = max; }
@@ -132,6 +137,9 @@ private:
GLfloat m_blitTextureCoordinateArray[8];
QOpenGLSharedResourceGuard *m_fboGuard;
+#if !defined(QT_OPENGL_ES_2)
+ QOpenGLFunctions_3_2_Core *m_funcs;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
index 39d9832f58..35c4d1c506 100644
--- a/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdefaultglyphnode_p.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qsgdefaultglyphnode_p_p.h"
+#include <private/qsgmaterialshader_p.h>
#include <qopenglshaderprogram.h>
@@ -75,8 +76,6 @@ public:
protected:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_matrix_id;
int m_color_id;
@@ -85,30 +84,6 @@ protected:
QFontEngineGlyphCache::Type m_cacheType;
};
-const char *QSGTextMaskShader::vertexShader() const {
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec2 sampleCoord; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *QSGTextMaskShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "void main() { \n"
- " lowp vec4 glyph = texture2D(_qt_texture, sampleCoord); \n"
- " gl_FragColor = vec4(glyph.rgb * color.a, glyph.a); \n"
- "}";
-}
-
char const *const *QSGTextMaskShader::attributeNames() const
{
static char const *const attr[] = { "vCoord", "tCoord", 0 };
@@ -116,8 +91,11 @@ char const *const *QSGTextMaskShader::attributeNames() const
}
QSGTextMaskShader::QSGTextMaskShader(QFontEngineGlyphCache::Type cacheType)
- : m_cacheType(cacheType)
+ : QSGMaterialShader(*new QSGMaterialShaderPrivate),
+ m_cacheType(cacheType)
{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/textmask.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/textmask.frag"));
}
static inline qreal fontSmoothingGamma()
@@ -186,22 +164,13 @@ class QSG8BitTextMaskShader : public QSGTextMaskShader
public:
QSG8BitTextMaskShader(QFontEngineGlyphCache::Type cacheType)
: QSGTextMaskShader(cacheType)
- {}
+ {
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/8bittextmask.frag"));
+ }
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
- virtual const char *fragmentShader() const;
};
-const char *QSG8BitTextMaskShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "uniform lowp sampler2D texture; \n"
- "uniform lowp vec4 color; \n"
- "void main() { \n"
- " gl_FragColor = color * texture2D(texture, sampleCoord).a; \n"
- "}";
-}
-
void QSG8BitTextMaskShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
QSGTextMaskShader::updateState(state, newEffect, oldEffect);
@@ -220,28 +189,18 @@ public:
QSG24BitTextMaskShader(QFontEngineGlyphCache::Type cacheType)
: QSGTextMaskShader(cacheType)
, m_useSRGB(false)
- {}
+ {
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/24bittextmask.frag"));
+ }
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual void initialize();
void activate();
void deactivate();
- virtual const char *fragmentShader() const;
uint m_useSRGB : 1;
};
-const char *QSG24BitTextMaskShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "uniform lowp sampler2D texture; \n"
- "uniform lowp float color; // just the alpha, really... \n"
- "void main() { \n"
- " lowp vec4 glyph = texture2D(texture, sampleCoord); \n"
- " gl_FragColor = vec4(glyph.rgb * color, glyph.a); \n"
- "}";
-}
-
void QSG24BitTextMaskShader::initialize()
{
QSGTextMaskShader::initialize();
@@ -302,14 +261,15 @@ class QSGStyledTextShader : public QSG8BitTextMaskShader
public:
QSGStyledTextShader(QFontEngineGlyphCache::Type cacheType)
: QSG8BitTextMaskShader(cacheType)
- { }
+ {
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/styledtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/styledtext.frag"));
+ }
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
private:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_shift_id;
int m_styleColor_id;
@@ -367,98 +327,17 @@ void QSGStyledTextShader::updateState(const RenderState &state,
program()->setUniformValue(m_matrix_id, state.combinedMatrix());
}
-const char *QSGStyledTextShader::vertexShader() const
-{
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "uniform highp vec2 shift; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 shiftedSampleCoord; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " shiftedSampleCoord = (tCoord - shift) * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *QSGStyledTextShader::fragmentShader() const
-{
- return
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 shiftedSampleCoord; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform lowp vec4 styleColor; \n"
- "void main() { \n"
- " lowp float glyph = texture2D(_qt_texture, sampleCoord).a; \n"
- " lowp float style = clamp(texture2D(_qt_texture, shiftedSampleCoord).a - glyph, \n"
- " 0.0, 1.0); \n"
- " gl_FragColor = style * styleColor + glyph * color; \n"
- "}";
-}
-
-
class QSGOutlinedTextShader : public QSGStyledTextShader
{
public:
QSGOutlinedTextShader(QFontEngineGlyphCache::Type cacheType)
: QSGStyledTextShader(cacheType)
- { }
-
-private:
- const char *vertexShader() const;
- const char *fragmentShader() const;
+ {
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/outlinedtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/outlinedtext.frag"));
+ }
};
-const char *QSGOutlinedTextShader::vertexShader() const
-{
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "uniform highp vec2 shift; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 sCoordUp; \n"
- "varying highp vec2 sCoordDown; \n"
- "varying highp vec2 sCoordLeft; \n"
- "varying highp vec2 sCoordRight; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " sCoordUp = (tCoord - vec2(0.0, -1.0)) * textureScale; \n"
- " sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale; \n"
- " sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale; \n"
- " sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *QSGOutlinedTextShader::fragmentShader() const
-{
- return
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 sCoordUp; \n"
- "varying highp vec2 sCoordDown; \n"
- "varying highp vec2 sCoordLeft; \n"
- "varying highp vec2 sCoordRight; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform lowp vec4 styleColor; \n"
- "void main() { \n"
- "lowp float glyph = texture2D(_qt_texture, sampleCoord).a; \n"
- " lowp float outline = clamp(clamp(texture2D(_qt_texture, sCoordUp).a + \n"
- " texture2D(_qt_texture, sCoordDown).a + \n"
- " texture2D(_qt_texture, sCoordLeft).a + \n"
- " texture2D(_qt_texture, sCoordRight).a, \n"
- " 0.0, 1.0) - glyph, \n"
- " 0.0, 1.0); \n"
- " gl_FragColor = outline * styleColor + glyph * color; \n"
- "}";
-}
-
QSGTextMaskMaterial::QSGTextMaskMaterial(const QRawFont &font, int cacheType)
: m_texture(0)
, m_glyphCache(0)
@@ -480,6 +359,12 @@ void QSGTextMaskMaterial::init(int cacheType)
QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext());
Q_ASSERT(ctx != 0);
+ // The following piece of code will read/write to the font engine's caches,
+ // potentially from different threads. However, this is safe because this
+ // code is only called from QQuickItem::updatePaintNode() which is called
+ // only when the GUI is blocked, and multiple threads will call it in
+ // sequence. See also QSGRenderContext::invalidate
+
QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
if (fontD->fontEngine != 0) {
if (cacheType < 0) {
@@ -494,6 +379,9 @@ void QSGTextMaskMaterial::init(int cacheType)
m_glyphCache = new QOpenGLTextureGlyphCache(QFontEngineGlyphCache::Type(cacheType),
QTransform());
fontD->fontEngine->setGlyphCache(ctx, m_glyphCache.data());
+ QSGRenderContext *sg = QSGRenderContext::from(ctx);
+ Q_ASSERT(sg);
+ sg->registerFontengineForCleanup(fontD->fontEngine);
}
}
}
diff --git a/src/quick/scenegraph/qsgdefaultimagenode.cpp b/src/quick/scenegraph/qsgdefaultimagenode.cpp
index 11d0e5dbeb..926c0c1f4a 100644
--- a/src/quick/scenegraph/qsgdefaultimagenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultimagenode.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qsgdefaultimagenode_p.h"
+#include <private/qsgmaterialshader_p.h>
#include <QtCore/qvarlengtharray.h>
#include <QtCore/qmath.h>
@@ -75,13 +76,13 @@ namespace
class SmoothTextureMaterialShader : public QSGTextureMaterialShader
{
public:
+ SmoothTextureMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
protected:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_pixelSizeLoc;
};
@@ -109,6 +110,13 @@ QSGMaterialShader *QSGSmoothTextureMaterial::createShader() const
return new SmoothTextureMaterialShader;
}
+SmoothTextureMaterialShader::SmoothTextureMaterialShader()
+ : QSGTextureMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/smoothtexture.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/smoothtexture.frag"));
+}
+
void SmoothTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
if (oldEffect == 0) {
@@ -137,70 +145,6 @@ void SmoothTextureMaterialShader::initialize()
QSGTextureMaterialShader::initialize();
}
-const char *SmoothTextureMaterialShader::vertexShader() const
-{
- return
- "uniform highp vec2 pixelSize; \n"
- "uniform highp mat4 qt_Matrix; \n"
- "uniform lowp float opacity; \n"
- "attribute highp vec4 vertex; \n"
- "attribute highp vec2 multiTexCoord; \n"
- "attribute highp vec2 vertexOffset; \n"
- "attribute highp vec2 texCoordOffset; \n"
- "varying highp vec2 texCoord; \n"
- "varying lowp float vertexOpacity; \n"
- "void main() { \n"
- " highp vec4 pos = qt_Matrix * vertex; \n"
- " gl_Position = pos; \n"
- " texCoord = multiTexCoord; \n"
-
- " if (vertexOffset.x != 0.) { \n"
- " highp vec4 delta = qt_Matrix[0] * vertexOffset.x; \n"
- " highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w; \n"
- " highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize); \n"
- " dir -= ndir * delta.w * pos.w; \n"
- " highp float numerator = dot(dir, ndir * pos.w * pos.w); \n"
- " highp float scale = 0.0; \n"
- " if (numerator < 0.0) \n"
- " scale = 1.0; \n"
- " else \n"
- " scale = min(1.0, numerator / dot(dir, dir)); \n"
- " gl_Position += scale * delta; \n"
- " texCoord.x += scale * texCoordOffset.x; \n"
- " } \n"
-
- " if (vertexOffset.y != 0.) { \n"
- " highp vec4 delta = qt_Matrix[1] * vertexOffset.y; \n"
- " highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w; \n"
- " highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize); \n"
- " dir -= ndir * delta.w * pos.w; \n"
- " highp float numerator = dot(dir, ndir * pos.w * pos.w); \n"
- " highp float scale = 0.0; \n"
- " if (numerator < 0.0) \n"
- " scale = 1.0; \n"
- " else \n"
- " scale = min(1.0, numerator / dot(dir, dir)); \n"
- " gl_Position += scale * delta; \n"
- " texCoord.y += scale * texCoordOffset.y; \n"
- " } \n"
-
- " bool onEdge = any(notEqual(vertexOffset, vec2(0.))); \n"
- " bool outerEdge = all(equal(texCoordOffset, vec2(0.))); \n"
- " vertexOpacity = onEdge && outerEdge ? 0. : opacity; \n"
- "}";
-}
-
-const char *SmoothTextureMaterialShader::fragmentShader() const
-{
- return
- "uniform sampler2D qt_Texture; \n"
- "varying highp vec2 texCoord; \n"
- "varying lowp float vertexOpacity; \n"
- "void main() { \n"
- " gl_FragColor = texture2D(qt_Texture, texCoord) * vertexOpacity; \n"
- "}";
-}
-
QSGDefaultImageNode::QSGDefaultImageNode()
: m_innerSourceRect(0, 0, 1, 1)
, m_subSourceRect(0, 0, 1, 1)
diff --git a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
index 14c61bae79..fb989fd6fb 100644
--- a/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
+++ b/src/quick/scenegraph/qsgdefaultrectanglenode.cpp
@@ -110,19 +110,26 @@ namespace
class SmoothColorMaterialShader : public QSGMaterialShader
{
public:
+ SmoothColorMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
private:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_matrixLoc;
int m_opacityLoc;
int m_pixelSizeLoc;
};
+SmoothColorMaterialShader::SmoothColorMaterialShader()
+ : QSGMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/smoothcolor.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/smoothcolor.frag"));
+}
+
void SmoothColorMaterialShader::updateState(const RenderState &state, QSGMaterial *, QSGMaterial *oldEffect)
{
if (state.isOpacityDirty())
@@ -156,61 +163,6 @@ void SmoothColorMaterialShader::initialize()
m_pixelSizeLoc = program()->uniformLocation("pixelSize");
}
-const char *SmoothColorMaterialShader::vertexShader() const
-{
- return
- "uniform highp vec2 pixelSize; \n"
- "uniform highp mat4 matrix; \n"
- "uniform lowp float opacity; \n"
- "attribute highp vec4 vertex; \n"
- "attribute lowp vec4 vertexColor; \n"
- "attribute highp vec2 vertexOffset; \n"
- "varying lowp vec4 color; \n"
- "void main() { \n"
- " highp vec4 pos = matrix * vertex; \n"
- " gl_Position = pos; \n"
-
- " if (vertexOffset.x != 0.) { \n"
- " highp vec4 delta = matrix[0] * vertexOffset.x; \n"
- " highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w; \n"
- " highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize); \n"
- " dir -= ndir * delta.w * pos.w; \n"
- " highp float numerator = dot(dir, ndir * pos.w * pos.w); \n"
- " highp float scale = 0.0; \n"
- " if (numerator < 0.0) \n"
- " scale = 1.0; \n"
- " else \n"
- " scale = min(1.0, numerator / dot(dir, dir)); \n"
- " gl_Position += scale * delta; \n"
- " } \n"
-
- " if (vertexOffset.y != 0.) { \n"
- " highp vec4 delta = matrix[1] * vertexOffset.y; \n"
- " highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w; \n"
- " highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize); \n"
- " dir -= ndir * delta.w * pos.w; \n"
- " highp float numerator = dot(dir, ndir * pos.w * pos.w); \n"
- " highp float scale = 0.0; \n"
- " if (numerator < 0.0) \n"
- " scale = 1.0; \n"
- " else \n"
- " scale = min(1.0, numerator / dot(dir, dir)); \n"
- " gl_Position += scale * delta; \n"
- " } \n"
-
- " color = vertexColor * opacity; \n"
- "}";
-}
-
-const char *SmoothColorMaterialShader::fragmentShader() const
-{
- return
- "varying lowp vec4 color; \n"
- "void main() { \n"
- " gl_FragColor = color; \n"
- "}";
-}
-
QSGSmoothColorMaterial::QSGSmoothColorMaterial()
{
setFlag(RequiresFullMatrixExceptTranslate, true);
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
index 876a9ea9ad..a9faf12096 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode.cpp
@@ -46,7 +46,7 @@
QT_BEGIN_NAMESPACE
-QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGContext *context)
+QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGRenderContext *context)
: m_glyphNodeType(RootGlyphNode)
, m_context(context)
, m_material(0)
@@ -235,7 +235,12 @@ void QSGDistanceFieldGlyphNode::updateGeometry()
if (texture->textureId && !m_texture)
m_texture = texture;
- if (m_texture != texture) {
+ // As we use UNSIGNED_SHORT indexing in the geometry, we overload the
+ // "glyphsInOtherTextures" concept as overflow for if there are more than
+ // 65536 vertices to render which would otherwise exceed the maximum index
+ // size. This will cause sub-nodes to be recursively created to handle any
+ // number of glyphs.
+ if (m_texture != texture || vp.size() >= 65536) {
if (texture->textureId) {
GlyphInfo &glyphInfo = glyphsInOtherTextures[texture];
glyphInfo.indexes.append(glyphIndex);
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
index 125243847a..12a431246c 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.cpp
@@ -59,8 +59,6 @@ public:
protected:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
void updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc);
void updateColor(const QVector4D &c);
@@ -81,44 +79,20 @@ protected:
float m_lastAlphaMax;
};
-const char *QSGDistanceFieldTextMaterialShader::vertexShader() const {
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec2 sampleCoord; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *QSGDistanceFieldTextMaterialShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "uniform mediump sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "void main() { \n"
- " gl_FragColor = color * smoothstep(alphaMin, \n"
- " alphaMax, \n"
- " texture2D(_qt_texture, sampleCoord).a); \n"
- "}";
-}
-
char const *const *QSGDistanceFieldTextMaterialShader::attributeNames() const {
static char const *const attr[] = { "vCoord", "tCoord", 0 };
return attr;
}
QSGDistanceFieldTextMaterialShader::QSGDistanceFieldTextMaterialShader()
- : m_fontScale(1.0)
+ : QSGMaterialShader(),
+ m_fontScale(1.0)
, m_matrixScale(1.0)
, m_lastAlphaMin(-1)
, m_lastAlphaMax(-1)
{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/distancefieldtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldtext.frag"));
}
void QSGDistanceFieldTextMaterialShader::updateAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc)
@@ -287,7 +261,6 @@ public:
protected:
virtual void initialize();
- virtual const char *fragmentShader() const = 0;
int m_styleColor_id;
};
@@ -355,7 +328,6 @@ public:
protected:
virtual void initialize();
- virtual const char *fragmentShader() const;
void updateOutlineAlphaRange(ThresholdFunc thresholdFunc, AntialiasingSpreadFunc spreadFunc, int dfRadius);
@@ -363,26 +335,10 @@ protected:
int m_outlineAlphaMax1_id;
};
-const char *DistanceFieldOutlineTextMaterialShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform lowp vec4 styleColor; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "uniform mediump float outlineAlphaMax0; \n"
- "uniform mediump float outlineAlphaMax1; \n"
- "void main() { \n"
- " mediump float d = texture2D(_qt_texture, sampleCoord).a; \n"
- " gl_FragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d)) \n"
- " * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d); \n"
- "}";
-}
-
DistanceFieldOutlineTextMaterialShader::DistanceFieldOutlineTextMaterialShader()
: DistanceFieldStyledTextMaterialShader()
{
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldoutlinetext.frag"));
}
void DistanceFieldOutlineTextMaterialShader::initialize()
@@ -454,8 +410,6 @@ public:
protected:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
void updateShift(qreal fontScale, const QPointF& shift);
@@ -465,6 +419,8 @@ protected:
DistanceFieldShiftedStyleTextMaterialShader::DistanceFieldShiftedStyleTextMaterialShader()
: DistanceFieldStyledTextMaterialShader()
{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/distancefieldshiftedtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/distancefieldshiftedtext.frag"));
}
void DistanceFieldShiftedStyleTextMaterialShader::initialize()
@@ -495,41 +451,6 @@ void DistanceFieldShiftedStyleTextMaterialShader::updateShift(qreal fontScale, c
program()->setUniformValue(m_shift_id, texel);
}
-const char *DistanceFieldShiftedStyleTextMaterialShader::vertexShader() const
-{
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "uniform highp vec2 shift; \n"
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 shiftedSampleCoord; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " shiftedSampleCoord = (tCoord - shift) * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *DistanceFieldShiftedStyleTextMaterialShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec2 shiftedSampleCoord; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform lowp vec4 styleColor; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "void main() { \n"
- " highp float a = smoothstep(alphaMin, alphaMax, texture2D(_qt_texture, sampleCoord).a); \n"
- " highp vec4 shifted = styleColor * smoothstep(alphaMin, \n"
- " alphaMax, \n"
- " texture2D(_qt_texture, shiftedSampleCoord).a); \n"
- " gl_FragColor = mix(shifted, color, a); \n"
- "}";
-}
-
QSGDistanceFieldShiftedStyleTextMaterial::QSGDistanceFieldShiftedStyleTextMaterial()
: QSGDistanceFieldStyledTextMaterial()
{
@@ -550,111 +471,35 @@ QSGMaterialShader *QSGDistanceFieldShiftedStyleTextMaterial::createShader() cons
return new DistanceFieldShiftedStyleTextMaterialShader;
}
+int QSGDistanceFieldShiftedStyleTextMaterial::compare(const QSGMaterial *o) const
+{
+ const QSGDistanceFieldShiftedStyleTextMaterial *other = static_cast<const QSGDistanceFieldShiftedStyleTextMaterial *>(o);
+ if (m_shift != other->m_shift)
+ return &m_shift < &other->m_shift ? -1 : 1;
+ return QSGDistanceFieldStyledTextMaterial::compare(o);
+}
class QSGHiQSubPixelDistanceFieldTextMaterialShader : public QSGDistanceFieldTextMaterialShader
{
public:
+ QSGHiQSubPixelDistanceFieldTextMaterialShader();
+
virtual void initialize();
virtual void activate();
virtual void deactivate();
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
-protected:
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
-
private:
int m_fontScale_id;
int m_vecDelta_id;
};
-const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::vertexShader() const {
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "uniform highp float fontScale; \n"
- "uniform highp vec4 vecDelta; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec3 sampleFarLeft; \n"
- "varying highp vec3 sampleNearLeft; \n"
- "varying highp vec3 sampleNearRight; \n"
- "varying highp vec3 sampleFarRight; \n"
- "void main() { \n"
- " sampleCoord = tCoord * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- // Calculate neighbour pixel position in item space.
- " highp vec3 wDelta = gl_Position.w * vecDelta.xyw; \n"
- " highp vec3 farLeft = vCoord.xyw - 0.667 * wDelta; \n"
- " highp vec3 nearLeft = vCoord.xyw - 0.333 * wDelta; \n"
- " highp vec3 nearRight = vCoord.xyw + 0.333 * wDelta; \n"
- " highp vec3 farRight = vCoord.xyw + 0.667 * wDelta; \n"
- // Calculate neighbour texture coordinate.
- " highp vec2 scale = textureScale / fontScale; \n"
- " highp vec2 base = sampleCoord - scale * vCoord.xy; \n"
- " sampleFarLeft = vec3(base * farLeft.z + scale * farLeft.xy, farLeft.z); \n"
- " sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z); \n"
- " sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z); \n"
- " sampleFarRight = vec3(base * farRight.z + scale * farRight.xy, farRight.z); \n"
- "}";
-}
-
-const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
- return
- "varying highp vec2 sampleCoord; \n"
- "varying highp vec3 sampleFarLeft; \n"
- "varying highp vec3 sampleNearLeft; \n"
- "varying highp vec3 sampleNearRight; \n"
- "varying highp vec3 sampleFarRight; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "void main() { \n"
- " highp vec4 n; \n"
- " n.x = texture2DProj(_qt_texture, sampleFarLeft).a; \n"
- " n.y = texture2DProj(_qt_texture, sampleNearLeft).a; \n"
- " highp float c = texture2D(_qt_texture, sampleCoord).a; \n"
- " n.z = texture2DProj(_qt_texture, sampleNearRight).a; \n"
- " n.w = texture2DProj(_qt_texture, sampleFarRight).a; \n"
-#if 0
- // Blurrier, faster.
- " n = smoothstep(alphaMin, alphaMax, n); \n"
- " c = smoothstep(alphaMin, alphaMax, c); \n"
-#else
- // Sharper, slower.
- " highp vec2 d = min(abs(n.yw - n.xz) * 2., 0.67); \n"
- " highp vec2 lo = mix(vec2(alphaMin), vec2(0.5), d); \n"
- " highp vec2 hi = mix(vec2(alphaMax), vec2(0.5), d); \n"
- " n = smoothstep(lo.xxyy, hi.xxyy, n); \n"
- " c = smoothstep(lo.x + lo.y, hi.x + hi.y, 2. * c); \n"
-#endif
- " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
- "}";
-}
-
-//const char *QSGHiQSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
-// return
-// "#extension GL_OES_standard_derivatives: enable \n"
-// "varying highp vec2 sampleCoord; \n"
-// "uniform sampler2D _qt_texture; \n"
-// "uniform lowp vec4 color; \n"
-// "uniform highp float alphaMin; \n"
-// "uniform highp float alphaMax; \n"
-// "void main() { \n"
-// " highp vec2 delta = dFdx(sampleCoord); \n"
-// " highp vec4 n; \n"
-// " n.x = texture2D(_qt_texture, sampleCoord - 0.667 * delta).a; \n"
-// " n.y = texture2D(_qt_texture, sampleCoord - 0.333 * delta).a; \n"
-// " highp float c = texture2D(_qt_texture, sampleCoord).a; \n"
-// " n.z = texture2D(_qt_texture, sampleCoord + 0.333 * delta).a; \n"
-// " n.w = texture2D(_qt_texture, sampleCoord + 0.667 * delta).a; \n"
-// " n = smoothstep(alphaMin, alphaMax, n); \n"
-// " c = smoothstep(alphaMin, alphaMax, c); \n"
-// " gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w; \n"
-// "}";
-//}
+QSGHiQSubPixelDistanceFieldTextMaterialShader::QSGHiQSubPixelDistanceFieldTextMaterialShader()
+ : QSGDistanceFieldTextMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag"));
+}
void QSGHiQSubPixelDistanceFieldTextMaterialShader::initialize()
{
@@ -712,52 +557,15 @@ QSGMaterialShader *QSGHiQSubPixelDistanceFieldTextMaterial::createShader() const
class QSGLoQSubPixelDistanceFieldTextMaterialShader : public QSGHiQSubPixelDistanceFieldTextMaterialShader
{
-protected:
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
+public:
+ QSGLoQSubPixelDistanceFieldTextMaterialShader();
};
-const char *QSGLoQSubPixelDistanceFieldTextMaterialShader::vertexShader() const {
- return
- "uniform highp mat4 matrix; \n"
- "uniform highp vec2 textureScale; \n"
- "uniform highp float fontScale; \n"
- "uniform highp vec4 vecDelta; \n"
- "attribute highp vec4 vCoord; \n"
- "attribute highp vec2 tCoord; \n"
- "varying highp vec3 sampleNearLeft; \n"
- "varying highp vec3 sampleNearRight; \n"
- "void main() { \n"
- " highp vec2 sampleCoord = tCoord * textureScale; \n"
- " gl_Position = matrix * vCoord; \n"
- // Calculate neighbour pixel position in item space.
- " highp vec3 wDelta = gl_Position.w * vecDelta.xyw; \n"
- " highp vec3 nearLeft = vCoord.xyw - 0.25 * wDelta; \n"
- " highp vec3 nearRight = vCoord.xyw + 0.25 * wDelta; \n"
- // Calculate neighbour texture coordinate.
- " highp vec2 scale = textureScale / fontScale; \n"
- " highp vec2 base = sampleCoord - scale * vCoord.xy; \n"
- " sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z); \n"
- " sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z); \n"
- "}";
-}
-
-const char *QSGLoQSubPixelDistanceFieldTextMaterialShader::fragmentShader() const {
- return
- "varying highp vec3 sampleNearLeft; \n"
- "varying highp vec3 sampleNearRight; \n"
- "uniform sampler2D _qt_texture; \n"
- "uniform lowp vec4 color; \n"
- "uniform mediump float alphaMin; \n"
- "uniform mediump float alphaMax; \n"
- "void main() { \n"
- " highp vec2 n; \n"
- " n.x = texture2DProj(_qt_texture, sampleNearLeft).a; \n"
- " n.y = texture2DProj(_qt_texture, sampleNearRight).a; \n"
- " n = smoothstep(alphaMin, alphaMax, n); \n"
- " highp float c = 0.5 * (n.x + n.y); \n"
- " gl_FragColor = vec4(n.x, c, n.y, c) * color.w; \n"
- "}";
+QSGLoQSubPixelDistanceFieldTextMaterialShader::QSGLoQSubPixelDistanceFieldTextMaterialShader()
+ : QSGHiQSubPixelDistanceFieldTextMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/loqsubpixeldistancefieldtext.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/loqsubpixeldistancefieldtext.frag"));
}
QSGMaterialType *QSGLoQSubPixelDistanceFieldTextMaterial::type() const
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
index 2558413675..98a65d7347 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p.h
@@ -49,13 +49,13 @@
QT_BEGIN_NAMESPACE
-class QSGContext;
+class QSGRenderContext;
class QSGDistanceFieldGlyphCacheManager;
class QSGDistanceFieldTextMaterial;
class QSGDistanceFieldGlyphNode: public QSGGlyphNode, public QSGDistanceFieldGlyphConsumer
{
public:
- QSGDistanceFieldGlyphNode(QSGContext *context);
+ QSGDistanceFieldGlyphNode(QSGRenderContext *context);
~QSGDistanceFieldGlyphNode();
virtual QPointF baseLine() const { return m_baseLine; }
@@ -86,7 +86,7 @@ private:
DistanceFieldGlyphNodeType m_glyphNodeType;
QColor m_color;
QPointF m_baseLine;
- QSGContext *m_context;
+ QSGRenderContext *m_context;
QSGDistanceFieldTextMaterial *m_material;
QPointF m_originalPosition;
QPointF m_position;
diff --git a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
index cf0d2d525e..d56fd01d3e 100644
--- a/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
+++ b/src/quick/scenegraph/qsgdistancefieldglyphnode_p_p.h
@@ -117,6 +117,7 @@ public:
virtual QSGMaterialType *type() const;
virtual QSGMaterialShader *createShader() const;
+ virtual int compare(const QSGMaterial *other) const;
void setShift(const QPointF &shift) { m_shift = shift; }
const QPointF &shift() const { return m_shift; }
diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp
index 163d1d35c5..aa0d7b5a6c 100644
--- a/src/quick/scenegraph/qsgrenderloop.cpp
+++ b/src/quick/scenegraph/qsgrenderloop.cpp
@@ -87,13 +87,13 @@ class QSGGuiThreadRenderLoop : public QSGRenderLoop
Q_OBJECT
public:
QSGGuiThreadRenderLoop();
+ ~QSGGuiThreadRenderLoop();
void show(QQuickWindow *window);
void hide(QQuickWindow *window);
void windowDestroyed(QQuickWindow *window);
- void initializeGL();
void renderWindow(QQuickWindow *window);
void exposureChanged(QQuickWindow *window);
QImage grab(QQuickWindow *window);
@@ -106,6 +106,7 @@ public:
QAnimationDriver *animationDriver() const { return 0; }
QSGContext *sceneGraphContext() const;
+ QSGRenderContext *createRenderContext(QSGContext *) const { return rc; }
bool event(QEvent *);
@@ -118,6 +119,7 @@ public:
QOpenGLContext *gl;
QSGContext *sg;
+ QSGRenderContext *rc;
QImage grabContent;
@@ -140,11 +142,15 @@ bool QSGRenderLoop::useConsistentTiming()
QSGRenderLoop *QSGRenderLoop::instance()
{
if (!s_instance) {
-
s_instance = QSGContext::createWindowManager();
- if (useConsistentTiming())
+ bool info = qEnvironmentVariableIsSet("QSG_INFO");
+
+ if (useConsistentTiming()) {
QUnifiedTimer::instance(true)->setConsistentTiming(true);
+ if (info)
+ qDebug() << "QSG: using fixed animation steps";
+ }
if (!s_instance) {
@@ -177,12 +183,15 @@ QSGRenderLoop *QSGRenderLoop::instance()
switch (loopType) {
case ThreadedRenderLoop:
+ if (info) qDebug() << "QSG: threaded render loop";
s_instance = new QSGThreadedRenderLoop();
break;
case WindowsRenderLoop:
+ if (info) qDebug() << "QSG: windows render loop";
s_instance = new QSGWindowsRenderLoop();
break;
default:
+ if (info) qDebug() << "QSG: basic render loop";
s_instance = new QSGGuiThreadRenderLoop();
break;
}
@@ -202,8 +211,14 @@ QSGGuiThreadRenderLoop::QSGGuiThreadRenderLoop()
, eventPending(false)
{
sg = QSGContext::createDefaultContext();
+ rc = new QSGRenderContext(sg);
}
+QSGGuiThreadRenderLoop::~QSGGuiThreadRenderLoop()
+{
+ delete rc;
+ delete sg;
+}
void QSGGuiThreadRenderLoop::show(QQuickWindow *window)
{
@@ -226,7 +241,8 @@ void QSGGuiThreadRenderLoop::hide(QQuickWindow *window)
if (m_windows.size() == 0) {
if (!cd->persistentSceneGraph) {
- sg->invalidate();
+ rc->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
if (!cd->persistentGLContext) {
delete gl;
gl = 0;
@@ -239,7 +255,8 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window)
{
hide(window);
if (m_windows.size() == 0) {
- sg->invalidate();
+ rc->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete gl;
gl = 0;
}
@@ -257,14 +274,17 @@ void QSGGuiThreadRenderLoop::renderWindow(QQuickWindow *window)
if (!gl) {
gl = new QOpenGLContext();
gl->setFormat(window->requestedFormat());
+ if (QSGContext::sharedOpenGLContext())
+ gl->setShareContext(QSGContext::sharedOpenGLContext());
if (!gl->create()) {
+ qWarning("QtQuick: failed to create OpenGL context");
delete gl;
gl = 0;
} else {
current = gl->makeCurrent(window);
}
if (current)
- sg->initialize(gl);
+ QQuickWindowPrivate::get(window)->context->initialize(gl);
} else {
current = gl->makeCurrent(window);
}
diff --git a/src/quick/scenegraph/qsgrenderloop_p.h b/src/quick/scenegraph/qsgrenderloop_p.h
index 933a8428f1..72bad16c63 100644
--- a/src/quick/scenegraph/qsgrenderloop_p.h
+++ b/src/quick/scenegraph/qsgrenderloop_p.h
@@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE
class QQuickWindow;
class QSGContext;
+class QSGRenderContext;
class QAnimationDriver;
class Q_QUICK_PRIVATE_EXPORT QSGRenderLoop : public QObject
@@ -60,6 +61,7 @@ public:
virtual void show(QQuickWindow *window) = 0;
virtual void hide(QQuickWindow *window) = 0;
+ virtual void resize(QQuickWindow *) {};
virtual void windowDestroyed(QQuickWindow *window) = 0;
@@ -72,6 +74,7 @@ public:
virtual QAnimationDriver *animationDriver() const = 0;
virtual QSGContext *sceneGraphContext() const = 0;
+ virtual QSGRenderContext *createRenderContext(QSGContext *) const = 0;
virtual void releaseResources(QQuickWindow *window) = 0;
diff --git a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
index 34a884348d..cc0218aefd 100644
--- a/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
+++ b/src/quick/scenegraph/qsgshareddistancefieldglyphcache.cpp
@@ -228,6 +228,7 @@ QSGSharedDistanceFieldGlyphCache::QSGSharedDistanceFieldGlyphCache(const QByteAr
this, SLOT(reportItemsInvalidated(QByteArray,QVector<quint32>)),
Qt::DirectConnection);
+ Q_ASSERT(c);
QQuickWindow *window = static_cast<QQuickWindow *>(c->surface());
Q_ASSERT(window != 0);
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
index 7421db1db1..850a463c3e 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp
+++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp
@@ -84,6 +84,17 @@
---
+ There is one thread per window and one opengl context per thread.
+
+ ---
+
+ The render thread has affinity to the GUI thread until a window
+ is shown. From that moment and until the window is destroyed, it
+ will have affinity to the render thread. (moved back at the end
+ of run for cleanup).
+
+ ---
+
The render loop is active while any window is exposed. All visible
windows are tracked, but only exposed windows are actually added to
the render thread and rendered. That means that if all windows are
@@ -97,26 +108,14 @@ QT_BEGIN_NAMESPACE
// #define QSG_RENDER_LOOP_DEBUG
-// #define QSG_RENDER_LOOP_DEBUG_FULL
-#ifdef QSG_RENDER_LOOP_DEBUG
-#define QSG_RENDER_LOOP_DEBUG_BASIC
-#endif
-
-#ifdef QSG_RENDER_LOOP_DEBUG_FULL
-#define QSG_RENDER_LOOP_DEBUG_BASIC
-#endif
-#if defined (QSG_RENDER_LOOP_DEBUG_FULL)
+#if defined (QSG_RENDER_LOOP_DEBUG)
QElapsedTimer qsgrl_timer;
-# define RLDEBUG1(x) qDebug("(%6d) %s : %4d - %s", (int) qsgrl_timer.elapsed(), __FILE__, __LINE__, x);
-# define RLDEBUG(x) qDebug("(%6d) %s : %4d - %s", (int) qsgrl_timer.elapsed(), __FILE__, __LINE__, x);
-#elif defined (QSG_RENDER_LOOP_DEBUG_BASIC)
-QElapsedTimer qsgrl_timer;
-# define RLDEBUG1(x) qDebug("(%6d) %s : %4d - %s", (int) qsgrl_timer.elapsed(), __FILE__, __LINE__, x);
-# define RLDEBUG(x)
+# define QSG_RT_DEBUG(MSG) qDebug("(%6d) line=%4d - win=%10p): Render: %s", (int) qsgrl_timer.elapsed(), __LINE__, window, MSG);
+# define QSG_GUI_DEBUG(WIN, MSG) qDebug("(%6d) line=%4d - win=%10p): Gui: %s", (int) qsgrl_timer.elapsed(), __LINE__, WIN, MSG);
#else
-# define RLDEBUG1(x)
-# define RLDEBUG(x)
+# define QSG_RT_DEBUG(MSG)
+# define QSG_GUI_DEBUG(WIN,MSG)
#endif
@@ -276,23 +275,25 @@ class QSGRenderThread : public QThread
{
Q_OBJECT
public:
-
- QSGRenderThread(QSGThreadedRenderLoop *w)
+ QSGRenderThread(QSGThreadedRenderLoop *w, QSGRenderContext *renderContext)
: wm(w)
, gl(0)
- , sg(QSGContext::createDefaultContext())
+ , sgrc(renderContext)
, animatorDriver(0)
, pendingUpdate(0)
, sleeping(false)
, syncResultedInChanges(false)
- , guiIsLocked(false)
- , shouldExit(false)
+ , active(false)
+ , window(0)
, stopEventProcessing(false)
{
- sg->moveToThread(this);
vsyncDelta = qsgrl_animation_interval();
}
+ ~QSGRenderThread()
+ {
+ delete sgrc;
+ }
void invalidateOpenGL(QQuickWindow *window, bool inDestructor);
void initializeOpenGL();
@@ -307,7 +308,7 @@ public:
{
if (sleeping)
stopEventProcessing = true;
- if (m_windows.size() > 0)
+ if (window)
pendingUpdate |= RepaintRequest;
}
@@ -317,7 +318,7 @@ public:
public slots:
void sceneGraphChanged() {
- RLDEBUG(" Render: sceneGraphChanged()");
+ QSG_RT_DEBUG("sceneGraphChanged()");
syncResultedInChanges = true;
}
@@ -329,16 +330,15 @@ public:
QSGThreadedRenderLoop *wm;
QOpenGLContext *gl;
- QSGContext *sg;
+ QSGRenderContext *sgrc;
QAnimationDriver *animatorDriver;
uint pendingUpdate;
- uint sleeping;
- uint syncResultedInChanges;
+ bool sleeping;
+ bool syncResultedInChanges;
- volatile bool guiIsLocked;
- volatile bool shouldExit;
+ volatile bool active;
float vsyncDelta;
@@ -347,11 +347,8 @@ public:
QElapsedTimer m_timer;
- struct Window {
- QQuickWindow *window;
- QSize size;
- };
- QList<Window> m_windows;
+ QQuickWindow *window; // Will be 0 when window is not exposed
+ QSize windowSize;
// Local event queue stuff...
bool stopEventProcessing;
@@ -363,64 +360,57 @@ bool QSGRenderThread::event(QEvent *e)
switch ((int) e->type()) {
case WM_Expose: {
- RLDEBUG1(" Render: WM_Expose");
+ QSG_RT_DEBUG("WM_Expose");
WMExposeEvent *se = static_cast<WMExposeEvent *>(e);
pendingUpdate |= RepaintRequest;
- if (Window *w = windowFor(m_windows, se->window)) {
- w->size = se->size;
- RLDEBUG1(" Render: - window already added...");
+ Q_ASSERT(!window || window == se->window);
+
+ windowSize = se->size;
+ if (window) {
+ QSG_RT_DEBUG(" - window already added...");
return true;
}
- Window window;
- window.window = se->window;
- window.size = se->size;
- m_windows << window;
- connect(animatorDriver, SIGNAL(started()), QQuickWindowPrivate::get(se->window)->animationController, SLOT(animationsStarted()));
+ window = se->window;
return true; }
case WM_Obscure: {
- RLDEBUG1(" Render: WM_Obscure");
- WMWindowEvent *ce = static_cast<WMWindowEvent *>(e);
- for (int i=0; i<m_windows.size(); ++i) {
- if (m_windows.at(i).window == ce->window) {
- RLDEBUG1(" Render: - removed one...");
- m_windows.removeAt(i);
- disconnect(animatorDriver, SIGNAL(started()), QQuickWindowPrivate::get(ce->window)->animationController, SLOT(animationsStarted()));
- break;
- }
- }
+ QSG_RT_DEBUG("WM_Obscure");
- if (sleeping && m_windows.size())
- stopEventProcessing = true;
+ Q_ASSERT(!window || window == static_cast<WMWindowEvent *>(e)->window);
+
+ mutex.lock();
+ if (window) {
+ QSG_RT_DEBUG(" - removed one...");
+ window = 0;
+ }
+ waitCondition.wakeOne();
+ mutex.unlock();
return true; }
case WM_RequestSync:
- RLDEBUG(" Render: WM_RequestSync");
+ QSG_RT_DEBUG("WM_RequestSync");
if (sleeping)
stopEventProcessing = true;
- if (m_windows.size() > 0)
+ if (window)
pendingUpdate |= SyncRequest;
return true;
case WM_TryRelease: {
- RLDEBUG1(" Render: WM_TryRelease");
+ QSG_RT_DEBUG("WM_TryRelease");
mutex.lock();
WMTryReleaseEvent *wme = static_cast<WMTryReleaseEvent *>(e);
- if (m_windows.size() == 0) {
- RLDEBUG1(" Render: - setting exit flag and invalidating GL");
+ if (!window || wme->inDestructor) {
+ QSG_RT_DEBUG(" - setting exit flag and invalidating GL");
invalidateOpenGL(wme->window, wme->inDestructor);
- shouldExit = !gl;
+ active = gl;
if (sleeping)
stopEventProcessing = true;
- } else if (wme->window == gl->surface()) {
- RLDEBUG1(" Render: - destroying the current window. Calling doneCurrent()...");
- gl->doneCurrent();
} else {
- RLDEBUG1(" Render: - not releasing anything because we have active windows...");
+ QSG_RT_DEBUG(" - not releasing anything because we have active windows...");
}
waitCondition.wakeOne();
mutex.unlock();
@@ -428,24 +418,24 @@ bool QSGRenderThread::event(QEvent *e)
}
case WM_Grab: {
- RLDEBUG1(" Render: WM_Grab");
+ QSG_RT_DEBUG("WM_Grab");
WMGrabEvent *ce = static_cast<WMGrabEvent *>(e);
- Window *w = windowFor(m_windows, ce->window);
+ Q_ASSERT(ce->window == window);
mutex.lock();
- if (w) {
- gl->makeCurrent(ce->window);
+ if (window) {
+ gl->makeCurrent(window);
- RLDEBUG1(" Render: - syncing scene graph");
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(w->window);
+ QSG_RT_DEBUG(" - syncing scene graph");
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
d->syncSceneGraph();
- RLDEBUG1(" Render: - rendering scene graph");
- QQuickWindowPrivate::get(ce->window)->renderSceneGraph(w->size);
+ QSG_RT_DEBUG(" - rendering scene graph");
+ QQuickWindowPrivate::get(window)->renderSceneGraph(windowSize);
- RLDEBUG1(" Render: - grabbing result...");
- *ce->image = qt_gl_read_framebuffer(w->size, false, false);
+ QSG_RT_DEBUG(" - grabbing result...");
+ *ce->image = qt_gl_read_framebuffer(windowSize, false, false);
}
- RLDEBUG1(" Render: - waking gui to handle grab result");
+ QSG_RT_DEBUG(" - waking gui to handle grab result");
waitCondition.wakeOne();
mutex.unlock();
return true;
@@ -465,7 +455,7 @@ bool QSGRenderThread::event(QEvent *e)
void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
{
- RLDEBUG1(" Render: invalidateOpenGL()");
+ QSG_RT_DEBUG("invalidateOpenGL()");
if (!gl)
return;
@@ -476,43 +466,32 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
}
- bool persistentGL = false;
- bool persistentSG = false;
-
- // GUI is locked so accessing the wm and window here is safe
- for (int i=0; i<wm->m_windows.size(); ++i) {
- const QSGThreadedRenderLoop::Window &w = wm->m_windows.at(i);
- if (!inDestructor || w.window != window) {
- persistentSG |= w.window->isPersistentSceneGraph();
- persistentGL |= w.window->isPersistentOpenGLContext();
- }
- }
+ bool wipeSG = inDestructor || !window->isPersistentSceneGraph();
+ bool wipeGL = inDestructor || (wipeSG && !window->isPersistentOpenGLContext());
gl->makeCurrent(window);
- // The canvas nodes must be cleanded up regardless if we are in the destructor..
- if (!persistentSG || inDestructor) {
+ // The canvas nodes must be cleaned up regardless if we are in the destructor..
+ if (wipeSG) {
QQuickWindowPrivate *dd = QQuickWindowPrivate::get(window);
dd->cleanupNodesOnShutdown();
- }
-
- // We're not doing any cleanup in this case...
- if (persistentSG) {
- RLDEBUG1(" Render: - persistent SG, avoiding cleanup");
+ } else {
+ QSG_RT_DEBUG(" - persistent SG, avoiding cleanup");
return;
}
- sg->invalidate();
+ sgrc->invalidate();
+ QCoreApplication::processEvents();
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
gl->doneCurrent();
- RLDEBUG1(" Render: - invalidated scenegraph..");
+ QSG_RT_DEBUG(" - invalidated scenegraph..");
- if (!persistentGL) {
+ if (wipeGL) {
delete gl;
gl = 0;
- RLDEBUG1(" Render: - invalidated OpenGL");
+ QSG_RT_DEBUG(" - invalidated OpenGL");
} else {
- RLDEBUG1(" Render: - persistent GL, avoiding cleanup");
+ QSG_RT_DEBUG(" - persistent GL, avoiding cleanup");
}
}
@@ -522,32 +501,34 @@ void QSGRenderThread::invalidateOpenGL(QQuickWindow *window, bool inDestructor)
*/
void QSGRenderThread::sync()
{
- RLDEBUG(" Render: sync()");
+ QSG_RT_DEBUG("sync()");
mutex.lock();
- Q_ASSERT_X(guiIsLocked, "QSGRenderThread::sync()", "sync triggered on bad terms as gui is not already locked...");
+ Q_ASSERT_X(wm->m_locked, "QSGRenderThread::sync()", "sync triggered on bad terms as gui is not already locked...");
- for (int i=0; i<m_windows.size(); ++i) {
- Window &w = const_cast<Window &>(m_windows.at(i));
- if (w.size.width() == 0 || w.size.height() == 0) {
- RLDEBUG(" Render: - window has bad size, waiting...");
- continue;
- }
- gl->makeCurrent(w.window);
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(w.window);
+ bool current = false;
+ if (windowSize.width() > 0 && windowSize.height() > 0)
+ current = gl->makeCurrent(window);
+ if (current) {
+ gl->makeCurrent(window);
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
bool hadRenderer = d->renderer != 0;
d->syncSceneGraph();
if (!hadRenderer && d->renderer) {
- RLDEBUG(" Render: - renderer was created, hooking up changed signal");
+ QSG_RT_DEBUG(" - renderer was created, hooking up changed signal");
syncResultedInChanges = true;
connect(d->renderer, SIGNAL(sceneGraphChanged()), this, SLOT(sceneGraphChanged()), Qt::DirectConnection);
}
- }
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
-
- RLDEBUG(" Render: - unlocking after sync");
+ // Process deferred deletes now, directly after the sync as
+ // deleteLater on the GUI must now also have resulted in SG changes
+ // and the delete is a safe operation.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ } else {
+ QSG_RT_DEBUG(" - window has bad size, waiting...");
+ }
+ QSG_RT_DEBUG(" - window has bad size, waiting...");
waitCondition.wakeOne();
mutex.unlock();
}
@@ -565,7 +546,7 @@ void QSGRenderThread::syncAndRender()
QElapsedTimer waitTimer;
waitTimer.start();
- RLDEBUG(" Render: syncAndRender()");
+ QSG_RT_DEBUG("syncAndRender()");
syncResultedInChanges = false;
@@ -574,16 +555,15 @@ void QSGRenderThread::syncAndRender()
pendingUpdate = 0;
if (syncRequested) {
- RLDEBUG(" Render: - update pending, doing sync");
+ QSG_RT_DEBUG(" - update pending, doing sync");
sync();
}
if (!syncResultedInChanges && !(repaintRequested)) {
- RLDEBUG(" Render: - no changes, rendering aborted");
+ QSG_RT_DEBUG(" - no changes, rendering aborted");
int waitTime = vsyncDelta - (int) waitTimer.elapsed();
if (waitTime > 0)
msleep(waitTime);
- emit wm->timeToIncubate();
return;
}
@@ -591,33 +571,37 @@ void QSGRenderThread::syncAndRender()
if (profileFrames)
syncTime = threadTimer.nsecsElapsed();
#endif
- RLDEBUG(" Render: - rendering starting");
+ QSG_RT_DEBUG(" - rendering starting");
+
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
- if (animatorDriver->isRunning())
+ if (animatorDriver->isRunning()) {
+ d->animationController->lock();
animatorDriver->advance();
+ d->animationController->unlock();
+ }
- for (int i=0; i<m_windows.size(); ++i) {
- Window &w = const_cast<Window &>(m_windows.at(i));
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(w.window);
- if (!d->renderer || w.size.width() == 0 || w.size.height() == 0) {
- RLDEBUG(" Render: - Window not yet ready, skipping render...");
- continue;
- }
- gl->makeCurrent(w.window);
- d->renderSceneGraph(w.size);
+ bool current = false;
+ if (d->renderer && windowSize.width() > 0 && windowSize.height() > 0)
+ current = gl->makeCurrent(window);
+ if (current) {
+ d->renderSceneGraph(windowSize);
#ifndef QSG_NO_RENDER_TIMING
- if (profileFrames && i == 0)
+ if (profileFrames)
renderTime = threadTimer.nsecsElapsed();
#endif
- gl->swapBuffers(w.window);
+ gl->swapBuffers(window);
d->fireFrameSwapped();
+ } else {
+ QSG_RT_DEBUG(" - Window not yet ready, skipping render...");
}
- RLDEBUG(" Render: - rendering done");
- emit wm->timeToIncubate();
+
+ QSG_RT_DEBUG(" - rendering done");
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing)
- qDebug("Render Thread: framedelta=%d, sync=%d, first render=%d, after final swap=%d",
+ qDebug("Render Thread: window=%p, framedelta=%d, sync=%d, first render=%d, after final swap=%d",
+ window,
int(sinceLastTime/1000000),
int(syncTime/1000000),
int((renderTime - syncTime)/1000000),
@@ -644,78 +628,73 @@ void QSGRenderThread::postEvent(QEvent *e)
void QSGRenderThread::processEvents()
{
- RLDEBUG(" Render: processEvents()");
+ QSG_RT_DEBUG("processEvents()");
while (eventQueue.hasMoreEvents()) {
QEvent *e = eventQueue.takeEvent(false);
event(e);
delete e;
}
- RLDEBUG(" Render: - done with processEvents()");
+ QSG_RT_DEBUG(" - done with processEvents()");
}
void QSGRenderThread::processEventsAndWaitForMore()
{
- RLDEBUG(" Render: processEventsAndWaitForMore()");
+ QSG_RT_DEBUG("processEventsAndWaitForMore()");
stopEventProcessing = false;
while (!stopEventProcessing) {
QEvent *e = eventQueue.takeEvent(true);
event(e);
delete e;
}
- RLDEBUG(" Render: - done with processEventsAndWaitForMore()");
+ QSG_RT_DEBUG(" - done with processEventsAndWaitForMore()");
}
void QSGRenderThread::run()
{
- RLDEBUG1(" Render: run()");
- animatorDriver = sg->createAnimationDriver(0);
+ QSG_RT_DEBUG("run()");
+ animatorDriver = sgrc->sceneGraphContext()->createAnimationDriver(0);
animatorDriver->install();
QUnifiedTimer::instance(true)->setConsistentTiming(QSGRenderLoop::useConsistentTiming());
- while (!shouldExit) {
+ while (active) {
- if (m_windows.size() > 0) {
- if (!sg->isReady()) {
- gl->makeCurrent(m_windows.at(0).window);
- sg->initialize(gl);
- }
+ if (window) {
+ if (!sgrc->openglContext() && windowSize.width() > 0 && windowSize.height() > 0 && gl->makeCurrent(window))
+ sgrc->initialize(gl);
syncAndRender();
}
processEvents();
QCoreApplication::processEvents();
- if (!shouldExit
- && (pendingUpdate == 0 || m_windows.size() == 0)) {
- RLDEBUG(" Render: enter event loop (going to sleep)");
+ if (active && (pendingUpdate == 0 || !window)) {
+ QSG_RT_DEBUG("enter event loop (going to sleep)");
sleeping = true;
processEventsAndWaitForMore();
sleeping = false;
}
-
}
Q_ASSERT_X(!gl, "QSGRenderThread::run()", "The OpenGL context should be cleaned up before exiting the render thread...");
- RLDEBUG1(" Render: run() completed...");
+ QSG_RT_DEBUG("run() completed...");
delete animatorDriver;
animatorDriver = 0;
+
+ sgrc->moveToThread(wm->thread());
+ moveToThread(wm->thread());
}
QSGThreadedRenderLoop::QSGThreadedRenderLoop()
- : m_animation_timer(0)
- , m_update_timer(0)
- , m_sync_triggered_update(false)
+ : sg(QSGContext::createDefaultContext())
+ , m_animation_timer(0)
{
#if defined(QSG_RENDER_LOOP_DEBUG_BASIC) || defined (QSG_RENDER_LOOP_DEBUG_FULL)
qsgrl_timer.start();
#endif
- m_thread = new QSGRenderThread(this);
- m_thread->moveToThread(m_thread);
-
- m_animation_driver = m_thread->sg->createAnimationDriver(this);
+ m_animation_driver = sg->createAnimationDriver(this);
m_exhaust_delay = get_env_int("QML_EXHAUST_DELAY", 5);
@@ -723,14 +702,19 @@ QSGThreadedRenderLoop::QSGThreadedRenderLoop()
connect(m_animation_driver, SIGNAL(stopped()), this, SLOT(animationStopped()));
m_animation_driver->install();
- RLDEBUG1("GUI: QSGThreadedRenderLoop() created");
+ QSG_GUI_DEBUG((void *) 0, "QSGThreadedRenderLoop() created");
+}
+
+QSGRenderContext *QSGThreadedRenderLoop::createRenderContext(QSGContext *sg) const
+{
+ return new QSGRenderContext(sg);
}
-void QSGThreadedRenderLoop::maybePostPolishRequest()
+void QSGThreadedRenderLoop::maybePostPolishRequest(Window *w)
{
- if (m_update_timer == 0) {
- RLDEBUG("GUI: - posting update");
- m_update_timer = startTimer(m_exhaust_delay, Qt::PreciseTimer);
+ if (w->timerId == 0) {
+ QSG_GUI_DEBUG(w->window, " - posting update");
+ w->timerId = startTimer(m_exhaust_delay, Qt::PreciseTimer);
}
}
@@ -741,7 +725,7 @@ QAnimationDriver *QSGThreadedRenderLoop::animationDriver() const
QSGContext *QSGThreadedRenderLoop::sceneGraphContext() const
{
- return m_thread->sg;
+ return sg;
}
bool QSGThreadedRenderLoop::anyoneShowing() const
@@ -761,35 +745,79 @@ bool QSGThreadedRenderLoop::interleaveIncubation() const
void QSGThreadedRenderLoop::animationStarted()
{
- RLDEBUG("GUI: animationStarted()");
- if (!anyoneShowing() && m_animation_timer == 0)
- m_animation_timer = startTimer(qsgrl_animation_interval());
- maybePostPolishRequest();
+ QSG_GUI_DEBUG((void *) 0, "animationStarted()");
+ startOrStopAnimationTimer();
+
+ for (int i=0; i<m_windows.size(); ++i)
+ maybePostPolishRequest(const_cast<Window *>(&m_windows.at(i)));
}
void QSGThreadedRenderLoop::animationStopped()
{
- RLDEBUG("GUI: animationStopped()");
- if (!anyoneShowing()) {
+ QSG_GUI_DEBUG((void *) 0, "animationStopped()");
+ startOrStopAnimationTimer();
+}
+
+
+void QSGThreadedRenderLoop::startOrStopAnimationTimer()
+{
+ int exposedWindows = 0;
+ Window *theOne = 0;
+ for (int i=0; i<m_windows.size(); ++i) {
+ Window &w = m_windows[i];
+ if (w.window->isVisible() && w.window->isExposed()) {
+ ++exposedWindows;
+ theOne = &w;
+ }
+ }
+
+ if (m_animation_timer != 0 && (exposedWindows == 1 || !m_animation_driver->isRunning())) {
killTimer(m_animation_timer);
m_animation_timer = 0;
+ // If animations are running, make sure we keep on animating
+ if (m_animation_driver->isRunning())
+ maybePostPolishRequest(theOne);
+
+ } else if (m_animation_timer == 0 && exposedWindows != 1 && m_animation_driver->isRunning()) {
+ m_animation_timer = startTimer(qsgrl_animation_interval());
}
}
-
-
/*
- Adds this window to the list of tracked windowes in this window
+ Adds this window to the list of tracked windows in this window
manager. show() does not trigger rendering to start, that happens
in expose.
*/
void QSGThreadedRenderLoop::show(QQuickWindow *window)
{
- RLDEBUG1("GUI: show()");
+ QSG_GUI_DEBUG(window, "show()");
+
+ if (Window *w = windowFor(m_windows, window)) {
+ /* Safeguard ourselves against misbehaving platform plugins.
+ *
+ * When being shown, the window should not be exposed as the
+ * platform plugin is only told to show after we send the show
+ * event. If we are already shown at this time and we don't have
+ * an active rendering thread we don't trust the plugin to send
+ * us another expose event, so make this explicit call to
+ * handleExposure.
+ *
+ * REF: QTCREATORBUG-10699
+ */
+ if (window->isExposed() && (!w->thread || !w->thread->window))
+ handleExposure(w);
+ return;
+ }
+
+ QSG_GUI_DEBUG(window, " - now tracking new window");
Window win;
win.window = window;
+ win.thread = new QSGRenderThread(this, QQuickWindowPrivate::get(window)->context);
+ win.timerId = 0;
+ win.updateDuringSync = false;
+ win.gotBrokenExposeFromPlatformPlugin = false;
m_windows << win;
}
@@ -803,19 +831,12 @@ void QSGThreadedRenderLoop::show(QQuickWindow *window)
void QSGThreadedRenderLoop::hide(QQuickWindow *window)
{
- RLDEBUG1("GUI: hide()");
+ QSG_GUI_DEBUG(window, "hide()");
if (window->isExposed())
- handleObscurity(window);
+ handleObscurity(windowFor(m_windows, window));
releaseResources(window);
-
- for (int i=0; i<m_windows.size(); ++i) {
- if (m_windows.at(i).window == window) {
- m_windows.removeAt(i);
- break;
- }
- }
}
@@ -826,26 +847,51 @@ void QSGThreadedRenderLoop::hide(QQuickWindow *window)
*/
void QSGThreadedRenderLoop::windowDestroyed(QQuickWindow *window)
{
- RLDEBUG1("GUI: windowDestroyed()");
+ QSG_GUI_DEBUG(window, "windowDestroyed()");
if (window->isVisible())
hide(window);
releaseResources(window, true);
- RLDEBUG1("GUI: - done with windowDestroyed()");
+ for (int i=0; i<m_windows.size(); ++i) {
+ if (m_windows.at(i).window == window) {
+ QSGRenderThread *thread = m_windows.at(i).thread;
+ while (thread->isRunning())
+ QThread::yieldCurrentThread();
+ Q_ASSERT(thread->thread() == QThread::currentThread());
+ delete thread;
+ m_windows.removeAt(i);
+ break;
+ }
+ }
+
+ QSG_GUI_DEBUG(window, " - done with windowDestroyed()");
}
void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window)
{
- RLDEBUG1("GUI: exposureChanged()");
- if (windowFor(m_windows, window) == 0)
+ QSG_GUI_DEBUG(window, "exposureChanged()");
+ Window *w = windowFor(m_windows, window);
+ if (!w)
return;
if (window->isExposed()) {
- handleExposure(window);
+ handleExposure(w);
} else {
- handleObscurity(window);
+ handleObscurity(w);
+ }
+}
+
+void QSGThreadedRenderLoop::resize(QQuickWindow *window)
+{
+ Window *w = windowFor(m_windows, window);
+ if (w
+ && w->gotBrokenExposeFromPlatformPlugin
+ && window->width() > 0 && window->height() > 0
+ && w->window->geometry().intersects(w->window->screen()->availableGeometry())) {
+ w->gotBrokenExposeFromPlatformPlugin = false;
+ handleExposure(w);
}
}
@@ -854,49 +900,64 @@ void QSGThreadedRenderLoop::exposureChanged(QQuickWindow *window)
Will post an event to the render thread that this window should
start to render.
*/
-void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
+void QSGThreadedRenderLoop::handleExposure(Window *w)
{
- RLDEBUG1("GUI: handleExposure");
+ QSG_GUI_DEBUG(w->window, "handleExposure");
+
+ if (w->window->width() <= 0 || w->window->height() <= 0
+ || !w->window->geometry().intersects(w->window->screen()->availableGeometry())) {
+#ifndef QT_NO_DEBUG
+ qWarning("QSGThreadedRenderLoop: expose event received for window with invalid geometry.");
+#endif
+ w->gotBrokenExposeFromPlatformPlugin = true;
+ return;
+ }
// Because we are going to bind a GL context to it, make sure it
// is created.
- if (!window->handle())
- window->create();
-
- m_thread->postEvent(new WMExposeEvent(window));
+ if (!w->window->handle())
+ w->window->create();
// Start render thread if it is not running
- if (!m_thread->isRunning()) {
- m_thread->shouldExit = false;
-
- RLDEBUG1("GUI: - starting render thread...");
+ if (!w->thread->isRunning()) {
+
+ QSG_GUI_DEBUG(w->window, " - starting render thread...");
+
+ if (!w->thread->gl) {
+ w->thread->gl = new QOpenGLContext();
+ if (QSGContext::sharedOpenGLContext())
+ w->thread->gl->setShareContext(QSGContext::sharedOpenGLContext());
+ w->thread->gl->setFormat(w->window->requestedFormat());
+ if (!w->thread->gl->create()) {
+ delete w->thread->gl;
+ w->thread->gl = 0;
+ qWarning("QtQuick: failed to create OpenGL context");
+ return;
+ }
- if (!m_thread->gl) {
- QOpenGLContext *ctx = new QOpenGLContext();
- ctx->setFormat(window->requestedFormat());
- ctx->create();
- ctx->moveToThread(m_thread);
- m_thread->gl = ctx;
+ w->thread->gl->moveToThread(w->thread);
+ QSG_GUI_DEBUG(w->window, " - OpenGL context created...");
}
- QQuickAnimatorController *controller = QQuickWindowPrivate::get(window)->animationController;
- if (controller->thread() != m_thread)
- controller->moveToThread(m_thread);
+ QQuickAnimatorController *controller = QQuickWindowPrivate::get(w->window)->animationController;
+ if (controller->thread() != w->thread)
+ controller->moveToThread(w->thread);
- m_thread->start();
+ w->thread->active = true;
+ if (w->thread->thread() == QThread::currentThread()) {
+ w->thread->sgrc->moveToThread(w->thread);
+ w->thread->moveToThread(w->thread);
+ }
+ w->thread->start();
} else {
- RLDEBUG1("GUI: - render thread already running");
+ QSG_GUI_DEBUG(w->window, " - render thread already running");
}
- polishAndSync();
-
- // Kill non-visual animation timer if it is running
- if (m_animation_timer) {
- killTimer(m_animation_timer);
- m_animation_timer = 0;
- }
+ w->thread->postEvent(new WMExposeEvent(w->window));
+ polishAndSync(w);
+ startOrStopAnimationTimer();
}
/*!
@@ -906,43 +967,51 @@ void QSGThreadedRenderLoop::handleExposure(QQuickWindow *window)
It also starts up the non-vsync animation tick if no more windows
are showing.
*/
-void QSGThreadedRenderLoop::handleObscurity(QQuickWindow *window)
+void QSGThreadedRenderLoop::handleObscurity(Window *w)
{
- RLDEBUG1("GUI: handleObscurity");
- if (m_thread->isRunning())
- m_thread->postEvent(new WMWindowEvent(window, WM_Obscure));
-
- if (!anyoneShowing() && m_animation_driver->isRunning() && m_animation_timer == 0) {
- m_animation_timer = startTimer(qsgrl_animation_interval());
+ QSG_GUI_DEBUG(w->window, "handleObscurity");
+ if (w->thread->isRunning()) {
+ w->thread->mutex.lock();
+ w->thread->postEvent(new WMWindowEvent(w->window, WM_Obscure));
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ w->thread->mutex.unlock();
}
+
+ startOrStopAnimationTimer();
}
+void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
+{
+ Window *w = windowFor(m_windows, window);
+ if (w)
+ maybeUpdate(w);
+}
+
/*!
Called whenever the QML scene has changed. Will post an event to
ourselves that a sync is needed.
*/
-void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
+void QSGThreadedRenderLoop::maybeUpdate(Window *w)
{
- Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || m_thread->guiIsLocked,
+ Q_ASSERT_X(QThread::currentThread() == QCoreApplication::instance()->thread() || m_locked,
"QQuickItem::update()",
"Function can only be called from GUI thread or during QQuickItem::updatePaintNode()");
- RLDEBUG("GUI: maybeUpdate...");
- Window *w = windowFor(m_windows, window);
- if (!w || !m_thread->isRunning()) {
+ QSG_GUI_DEBUG(w->window, "maybeUpdate...");
+ if (!w || !w->thread->isRunning()) {
return;
}
// Call this function from the Gui thread later as startTimer cannot be
// called from the render thread.
- if (QThread::currentThread() == m_thread) {
- RLDEBUG("GUI: - on render thread, will update later..");
- m_sync_triggered_update = true;
+ if (QThread::currentThread() == w->thread) {
+ QSG_GUI_DEBUG(w->window, " - on render thread, will update later..");
+ w->updateDuringSync = true;
return;
}
- maybePostPolishRequest();
+ maybePostPolishRequest(w);
}
/*!
@@ -952,15 +1021,19 @@ void QSGThreadedRenderLoop::maybeUpdate(QQuickWindow *window)
*/
void QSGThreadedRenderLoop::update(QQuickWindow *window)
{
- if (QThread::currentThread() == m_thread) {
- RLDEBUG("Gui: update called on render thread");
- m_thread->requestRepaint();
+ Window *w = windowFor(m_windows, window);
+ if (!w)
+ return;
+
+ if (w->thread == QThread::currentThread()) {
+ QSG_RT_DEBUG("QQuickWindow::update called on render thread");
+ w->thread->requestRepaint();
return;
}
- RLDEBUG("Gui: update called");
- m_thread->postEvent(new QEvent(WM_RequestRepaint));
- maybeUpdate(window);
+ QSG_GUI_DEBUG(w->window, "update called");
+ w->thread->postEvent(new QEvent(WM_RequestRepaint));
+ maybeUpdate(w);
}
@@ -971,28 +1044,34 @@ void QSGThreadedRenderLoop::update(QQuickWindow *window)
*/
void QSGThreadedRenderLoop::releaseResources(QQuickWindow *window, bool inDestructor)
{
- RLDEBUG1("GUI: releaseResources requested...");
+ QSG_GUI_DEBUG(window, "releaseResources requested...");
+
+ Window *w = windowFor(m_windows, window);
+ if (!w)
+ return;
- m_thread->mutex.lock();
- if (m_thread->isRunning() && !m_thread->shouldExit) {
- RLDEBUG1("GUI: - posting release request to render thread");
- m_thread->postEvent(new WMTryReleaseEvent(window, inDestructor));
- m_thread->waitCondition.wait(&m_thread->mutex);
+ w->thread->mutex.lock();
+ if (w->thread->isRunning() && w->thread->active) {
+ QSG_GUI_DEBUG(w->window, " - posting release request to render thread");
+ w->thread->postEvent(new WMTryReleaseEvent(window, inDestructor));
+ w->thread->waitCondition.wait(&w->thread->mutex);
}
- m_thread->mutex.unlock();
+ w->thread->mutex.unlock();
}
-void QSGThreadedRenderLoop::polishAndSync()
+void QSGThreadedRenderLoop::polishAndSync(Window *w)
{
- if (!anyoneShowing()) {
- killTimer(m_update_timer);
- m_update_timer = 0;
+ QSG_GUI_DEBUG(w->window, "polishAndSync()");
+
+ if (!w->window->isExposed() || !w->window->isVisible() || w->window->size().isEmpty()) {
+ QSG_GUI_DEBUG(w->window, " - not exposed, aborting...");
+ killTimer(w->timerId);
+ w->timerId = 0;
return;
}
- RLDEBUG("GUI: polishAndSync()");
#ifndef QSG_NO_RENDER_TIMING
QElapsedTimer timer;
@@ -1004,52 +1083,51 @@ void QSGThreadedRenderLoop::polishAndSync()
timer.start();
#endif
- // Polish as the last thing we do before we allow the sync to take place
- for (int i=0; i<m_windows.size(); ++i) {
- const Window &w = m_windows.at(i);
- QQuickWindowPrivate *d = QQuickWindowPrivate::get(w.window);
- d->polishItems();
- }
+ QQuickWindowPrivate *d = QQuickWindowPrivate::get(w->window);
+ d->polishItems();
+
#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
polishTime = timer.nsecsElapsed();
#endif
- m_sync_triggered_update = false;
+ w->updateDuringSync = false;
- RLDEBUG("GUI: - lock for sync...");
- m_thread->mutex.lock();
- m_thread->guiIsLocked = true;
- m_thread->postEvent(new QEvent(WM_RequestSync));
+ QSG_GUI_DEBUG(w->window, " - lock for sync...");
+ w->thread->mutex.lock();
+ m_locked = true;
+ w->thread->postEvent(new QEvent(WM_RequestSync));
- RLDEBUG("GUI: - wait for sync...");
+ QSG_GUI_DEBUG(w->window, " - wait for sync...");
#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
waitTime = timer.nsecsElapsed();
#endif
- m_thread->waitCondition.wait(&m_thread->mutex);
- m_thread->guiIsLocked = false;
- m_thread->mutex.unlock();
- RLDEBUG("GUI: - unlocked after sync...");
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ m_locked = false;
+ w->thread->mutex.unlock();
+ QSG_GUI_DEBUG(w->window, " - unlocked after sync...");
#ifndef QSG_NO_RENDER_TIMING
if (profileFrames)
syncTime = timer.nsecsElapsed();
#endif
- killTimer(m_update_timer);
- m_update_timer = 0;
+ killTimer(w->timerId);
+ w->timerId = 0;
- if (m_animation_driver->isRunning()) {
- RLDEBUG("GUI: - animations advancing");
+ if (m_animation_timer == 0 && m_animation_driver->isRunning()) {
+ QSG_GUI_DEBUG(w->window, " - animations advancing");
m_animation_driver->advance();
- RLDEBUG("GUI: - animations done");
+ QSG_GUI_DEBUG(w->window, " - animations done");
// We need to trigger another sync to keep animations running...
- maybePostPolishRequest();
- } else if (m_sync_triggered_update) {
- maybePostPolishRequest();
+ maybePostPolishRequest(w);
+ emit timeToIncubate();
+ } else if (w->updateDuringSync) {
+ maybePostPolishRequest(w);
}
+
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing)
qDebug(" - on GUI: polish=%d, lock=%d, block/sync=%d -- animations=%d",
@@ -1073,15 +1151,26 @@ bool QSGThreadedRenderLoop::event(QEvent *e)
{
switch ((int) e->type()) {
- case QEvent::Timer:
- if (static_cast<QTimerEvent *>(e)->timerId() == m_animation_timer) {
- RLDEBUG("GUI: QEvent::Timer -> non-visual animation");
+ case QEvent::Timer: {
+ QTimerEvent *te = static_cast<QTimerEvent *>(e);
+ if (te->timerId() == m_animation_timer) {
+ QSG_GUI_DEBUG((void *) 0, "QEvent::Timer -> non-visual animation");
m_animation_driver->advance();
- } else if (static_cast<QTimerEvent *>(e)->timerId() == m_update_timer) {
- RLDEBUG("GUI: QEvent::Timer -> Polish & Sync");
- polishAndSync();
+ emit timeToIncubate();
+ } else {
+ QSG_GUI_DEBUG((void *) 0, "QEvent::Timer -> Polish & Sync");
+ Window *w = 0;
+ for (int i=0; i<m_windows.size(); ++i) {
+ if (m_windows.at(i).timerId == te->timerId()) {
+ w = const_cast<Window *>(&m_windows.at(i));
+ break;
+ }
+ }
+ if (w)
+ polishAndSync(w);
}
return true;
+ }
default:
break;
@@ -1104,26 +1193,30 @@ bool QSGThreadedRenderLoop::event(QEvent *e)
QImage QSGThreadedRenderLoop::grab(QQuickWindow *window)
{
- RLDEBUG("GUI: grab");
- if (!m_thread->isRunning())
+ QSG_GUI_DEBUG(window, "grab");
+
+ Window *w = windowFor(m_windows, window);
+ Q_ASSERT(w);
+
+ if (!w->thread->isRunning())
return QImage();
if (!window->handle())
window->create();
- RLDEBUG1("GUI: - polishing items...");
+ QSG_GUI_DEBUG(w->window, " - polishing items...");
QQuickWindowPrivate *d = QQuickWindowPrivate::get(window);
d->polishItems();
QImage result;
- m_thread->mutex.lock();
- RLDEBUG1("GUI: - locking, posting grab event");
- m_thread->postEvent(new WMGrabEvent(window, &result));
- m_thread->waitCondition.wait(&m_thread->mutex);
- RLDEBUG1("GUI: - locking, grab done, unlocking");
- m_thread->mutex.unlock();
-
- RLDEBUG1("Gui: - grab complete");
+ w->thread->mutex.lock();
+ QSG_GUI_DEBUG(w->window, " - locking, posting grab event");
+ w->thread->postEvent(new WMGrabEvent(window, &result));
+ w->thread->waitCondition.wait(&w->thread->mutex);
+ QSG_GUI_DEBUG(w->window, " - locking, grab done, unlocking");
+ w->thread->mutex.unlock();
+
+ QSG_GUI_DEBUG(w->window, " - grab complete");
return result;
}
diff --git a/src/quick/scenegraph/qsgthreadedrenderloop_p.h b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
index b943739a0d..844d180788 100644
--- a/src/quick/scenegraph/qsgthreadedrenderloop_p.h
+++ b/src/quick/scenegraph/qsgthreadedrenderloop_p.h
@@ -60,18 +60,17 @@ public:
void show(QQuickWindow *window);
void hide(QQuickWindow *window);
+ void resize(QQuickWindow *window);
void windowDestroyed(QQuickWindow *window);
void exposureChanged(QQuickWindow *window);
- void handleExposure(QQuickWindow *window);
- void handleObscurity(QQuickWindow *window);
-
QImage grab(QQuickWindow *);
void update(QQuickWindow *window);
void maybeUpdate(QQuickWindow *window);
QSGContext *sceneGraphContext() const;
+ QSGRenderContext *createRenderContext(QSGContext *) const;
QAnimationDriver *animationDriver() const;
@@ -86,6 +85,14 @@ public Q_SLOTS:
void animationStopped();
private:
+ struct Window {
+ QQuickWindow *window;
+ QSGRenderThread *thread;
+ int timerId;
+ uint updateDuringSync : 1;
+ uint gotBrokenExposeFromPlatformPlugin : 1;
+ };
+
friend class QSGRenderThread;
void releaseResources(QQuickWindow *window, bool inDestructor);
@@ -94,25 +101,24 @@ private:
bool anyoneShowing() const;
void initialize();
- void maybePostPolishRequest();
-
+ void startOrStopAnimationTimer();
+ void maybePostPolishRequest(Window *w);
void waitForReleaseComplete();
+ void polishAndSync(Window *w);
+ void maybeUpdate(Window *window);
- void polishAndSync();
+ void handleExposure(Window *w);
+ void handleObscurity(Window *w);
- struct Window {
- QQuickWindow *window;
- };
- QSGRenderThread *m_thread;
+ QSGContext *sg;
QAnimationDriver *m_animation_driver;
QList<Window> m_windows;
int m_animation_timer;
- int m_update_timer;
int m_exhaust_delay;
- bool m_sync_triggered_update;
+ bool m_locked;
};
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
index 95584d0f5d..0c128d5cae 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp
+++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp
@@ -85,6 +85,8 @@ QSGWindowsRenderLoop::QSGWindowsRenderLoop()
qsg_debug_timer.start();
#endif
+ m_rc = new QSGRenderContext(m_sg);
+
m_animationDriver = m_sg->createAnimationDriver(m_sg);
m_animationDriver->install();
@@ -102,6 +104,12 @@ QSGWindowsRenderLoop::QSGWindowsRenderLoop()
#endif
}
+QSGWindowsRenderLoop::~QSGWindowsRenderLoop()
+{
+ delete m_rc;
+ delete m_sg;
+}
+
bool QSGWindowsRenderLoop::interleaveIncubation() const
{
return m_animationDriver->isRunning() && anyoneShowing();
@@ -170,13 +178,22 @@ void QSGWindowsRenderLoop::show(QQuickWindow *window)
RLDEBUG(" - creating GL context");
m_gl = new QOpenGLContext();
m_gl->setFormat(window->requestedFormat());
- m_gl->create();
+ if (QSGContext::sharedOpenGLContext())
+ m_gl->setShareContext(QSGContext::sharedOpenGLContext());
+ bool created = m_gl->create();
+ if (!created) {
+ qWarning("QtQuick: failed to create OpenGL context");
+ delete m_gl;
+ m_gl = 0;
+ return;
+ }
QSG_RENDER_TIMING_SAMPLE(time_created);
RLDEBUG(" - making current");
- m_gl->makeCurrent(window);
+ bool current = m_gl->makeCurrent(window);
RLDEBUG(" - initializing SG");
QSG_RENDER_TIMING_SAMPLE(time_current);
- m_sg->initialize(m_gl);
+ if (current)
+ m_rc->initialize(m_gl);
#ifndef QSG_NO_RENDER_TIMING
if (qsg_render_timing) {
@@ -230,7 +247,8 @@ void QSGWindowsRenderLoop::hide(QQuickWindow *window)
// potentially clean up.
if (m_windows.size() == 0) {
if (!cd->persistentSceneGraph) {
- m_sg->invalidate();
+ QQuickWindowPrivate::get(window)->context->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
if (!cd->persistentGLContext) {
delete m_gl;
m_gl = 0;
@@ -246,7 +264,8 @@ void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window)
// If this is the last tracked window, clean up SG and GL.
if (m_windows.size() == 0) {
- m_sg->invalidate();
+ QQuickWindowPrivate::get(window)->context->invalidate();
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
delete m_gl;
m_gl = 0;
}
diff --git a/src/quick/scenegraph/qsgwindowsrenderloop_p.h b/src/quick/scenegraph/qsgwindowsrenderloop_p.h
index cb01e1e04b..e4ee688c9f 100644
--- a/src/quick/scenegraph/qsgwindowsrenderloop_p.h
+++ b/src/quick/scenegraph/qsgwindowsrenderloop_p.h
@@ -51,11 +51,14 @@
QT_BEGIN_NAMESPACE
+class QSGRenderContext;
+
class QSGWindowsRenderLoop : public QSGRenderLoop
{
Q_OBJECT
public:
explicit QSGWindowsRenderLoop();
+ ~QSGWindowsRenderLoop();
void show(QQuickWindow *window);
void hide(QQuickWindow *window);
@@ -71,14 +74,13 @@ public:
QAnimationDriver *animationDriver() const { return m_animationDriver; }
QSGContext *sceneGraphContext() const { return m_sg; }
+ QSGRenderContext *createRenderContext(QSGContext *) const { return m_rc; }
void releaseResources(QQuickWindow *) { }
void render();
void renderWindow(QQuickWindow *window);
- void resize(QQuickWindow *, const QSize &) { }
-
bool event(QEvent *event);
bool anyoneShowing() const;
@@ -102,6 +104,7 @@ private:
QOpenGLContext *m_gl;
QSGContext *m_sg;
+ QSGRenderContext *m_rc;
QAnimationDriver *m_animationDriver;
diff --git a/src/quick/scenegraph/scenegraph.pri b/src/quick/scenegraph/scenegraph.pri
index 3b8221264b..6f64c881a8 100644
--- a/src/quick/scenegraph/scenegraph.pri
+++ b/src/quick/scenegraph/scenegraph.pri
@@ -10,7 +10,8 @@ HEADERS += \
$$PWD/coreapi/qsgnodeupdater_p.h \
$$PWD/coreapi/qsgrenderer_p.h \
$$PWD/coreapi/qsgrendernode_p.h \
- $$PWD/coreapi/qsggeometry_p.h
+ $$PWD/coreapi/qsggeometry_p.h \
+ $$PWD/coreapi/qsgmaterialshader_p.h
SOURCES += \
$$PWD/coreapi/qsgbatchrenderer.cpp \
@@ -20,8 +21,7 @@ SOURCES += \
$$PWD/coreapi/qsgnodeupdater.cpp \
$$PWD/coreapi/qsgrenderer.cpp \
$$PWD/coreapi/qsgrendernode.cpp \
- $$PWD/coreapi/qsgshaderrewriter.cpp \
- scenegraph/util/qsgsimplematerial.cpp
+ $$PWD/coreapi/qsgshaderrewriter.cpp
# Util API
HEADERS += \
@@ -39,7 +39,8 @@ HEADERS += \
$$PWD/util/qsgtexture_p.h \
$$PWD/util/qsgtextureprovider.h \
$$PWD/util/qsgpainternode_p.h \
- $$PWD/util/qsgdistancefieldutil_p.h
+ $$PWD/util/qsgdistancefieldutil_p.h \
+ $$PWD/util/qsgshadersourcebuilder_p.h
SOURCES += \
$$PWD/util/qsgareaallocator.cpp \
@@ -53,7 +54,9 @@ SOURCES += \
$$PWD/util/qsgtexture.cpp \
$$PWD/util/qsgtextureprovider.cpp \
$$PWD/util/qsgpainternode.cpp \
- $$PWD/util/qsgdistancefieldutil.cpp
+ $$PWD/util/qsgdistancefieldutil.cpp \
+ $$PWD/util/qsgsimplematerial.cpp \
+ $$PWD/util/qsgshadersourcebuilder.cpp
# QML / Adaptations API
HEADERS += \
@@ -67,7 +70,6 @@ HEADERS += \
$$PWD/qsgdefaultglyphnode_p_p.h \
$$PWD/qsgdefaultimagenode_p.h \
$$PWD/qsgdefaultrectanglenode_p.h \
- $$PWD/qsgflashnode_p.h \
$$PWD/qsgshareddistancefieldglyphcache_p.h \
$$PWD/qsgrenderloop_p.h \
$$PWD/qsgthreadedrenderloop_p.h \
@@ -84,8 +86,77 @@ SOURCES += \
$$PWD/qsgdistancefieldglyphnode_p.cpp \
$$PWD/qsgdefaultimagenode.cpp \
$$PWD/qsgdefaultrectanglenode.cpp \
- $$PWD/qsgflashnode.cpp \
$$PWD/qsgshareddistancefieldglyphcache.cpp \
$$PWD/qsgrenderloop.cpp \
$$PWD/qsgthreadedrenderloop.cpp \
$$PWD/qsgwindowsrenderloop.cpp
+
+RESOURCES += \
+ $$PWD/scenegraph.qrc
+
+OTHER_FILES += \
+ $$PWD/shaders/24bittextmask.frag \
+ $$PWD/shaders/8bittextmask.frag \
+ $$PWD/shaders/distancefieldoutlinetext.frag \
+ $$PWD/shaders/distancefieldshiftedtext.frag \
+ $$PWD/shaders/distancefieldshiftedtext.vert \
+ $$PWD/shaders/distancefieldtext.frag \
+ $$PWD/shaders/distancefieldtext.vert \
+ $$PWD/shaders/flatcolor.frag \
+ $$PWD/shaders/flatcolor.vert \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext.frag \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext.vert \
+ $$PWD/shaders/loqsubpixeldistancefieldtext.frag \
+ $$PWD/shaders/loqsubpixeldistancefieldtext.vert \
+ $$PWD/shaders/opaquetexture.frag \
+ $$PWD/shaders/opaquetexture.vert \
+ $$PWD/shaders/outlinedtext.frag \
+ $$PWD/shaders/outlinedtext.vert \
+ $$PWD/shaders/rendernode.frag \
+ $$PWD/shaders/rendernode.vert \
+ $$PWD/shaders/smoothcolor.frag \
+ $$PWD/shaders/smoothcolor.vert \
+ $$PWD/shaders/smoothtexture.frag \
+ $$PWD/shaders/smoothtexture.vert \
+ $$PWD/shaders/stencilclip.frag \
+ $$PWD/shaders/stencilclip.vert \
+ $$PWD/shaders/styledtext.frag \
+ $$PWD/shaders/styledtext.vert \
+ $$PWD/shaders/textmask.frag \
+ $$PWD/shaders/textmask.vert \
+ $$PWD/shaders/texture.frag \
+ $$PWD/shaders/vertexcolor.frag \
+ $$PWD/shaders/vertexcolor.vert \
+ $$PWD/shaders/24bittextmask_core.frag \
+ $$PWD/shaders/8bittextmask_core.frag \
+ $$PWD/shaders/distancefieldoutlinetext_core.frag \
+ $$PWD/shaders/distancefieldshiftedtext_core.frag \
+ $$PWD/shaders/distancefieldshiftedtext_core.vert \
+ $$PWD/shaders/distancefieldtext_core.frag \
+ $$PWD/shaders/distancefieldtext_core.vert \
+ $$PWD/shaders/flatcolor_core.frag \
+ $$PWD/shaders/flatcolor_core.vert \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext_core.frag \
+ $$PWD/shaders/hiqsubpixeldistancefieldtext_core.vert \
+ $$PWD/shaders/loqsubpixeldistancefieldtext_core.frag \
+ $$PWD/shaders/loqsubpixeldistancefieldtext_core.vert \
+ $$PWD/shaders/opaquetexture_core.frag \
+ $$PWD/shaders/opaquetexture_core.vert \
+ $$PWD/shaders/outlinedtext_core.frag \
+ $$PWD/shaders/outlinedtext_core.vert \
+ $$PWD/shaders/rendernode_core.frag \
+ $$PWD/shaders/rendernode_core.vert \
+ $$PWD/shaders/smoothcolor_core.frag \
+ $$PWD/shaders/smoothcolor_core.vert \
+ $$PWD/shaders/smoothtexture_core.frag \
+ $$PWD/shaders/smoothtexture_core.vert \
+ $$PWD/shaders/stencilclip_core.frag \
+ $$PWD/shaders/stencilclip_core.vert \
+ $$PWD/shaders/styledtext_core.frag \
+ $$PWD/shaders/styledtext_core.vert \
+ $$PWD/shaders/textmask_core.frag \
+ $$PWD/shaders/textmask_core.vert \
+ $$PWD/shaders/texture_core.frag \
+ $$PWD/shaders/vertexcolor_core.frag \
+ $$PWD/shaders/vertexcolor_core.vert
+
diff --git a/src/quick/scenegraph/scenegraph.qrc b/src/quick/scenegraph/scenegraph.qrc
new file mode 100644
index 0000000000..2be8b246d3
--- /dev/null
+++ b/src/quick/scenegraph/scenegraph.qrc
@@ -0,0 +1,68 @@
+<RCC>
+ <qresource prefix="/scenegraph">
+ <file>shaders/flatcolor.frag</file>
+ <file>shaders/flatcolor.vert</file>
+ <file>shaders/8bittextmask.frag</file>
+ <file>shaders/24bittextmask.frag</file>
+ <file>shaders/opaquetexture.frag</file>
+ <file>shaders/opaquetexture.vert</file>
+ <file>shaders/outlinedtext.frag</file>
+ <file>shaders/outlinedtext.vert</file>
+ <file>shaders/smoothcolor.frag</file>
+ <file>shaders/smoothcolor.vert</file>
+ <file>shaders/smoothtexture.frag</file>
+ <file>shaders/smoothtexture.vert</file>
+ <file>shaders/styledtext.frag</file>
+ <file>shaders/styledtext.vert</file>
+ <file>shaders/textmask.frag</file>
+ <file>shaders/textmask.vert</file>
+ <file>shaders/texture.frag</file>
+ <file>shaders/distancefieldoutlinetext.frag</file>
+ <file>shaders/distancefieldshiftedtext.frag</file>
+ <file>shaders/distancefieldshiftedtext.vert</file>
+ <file>shaders/distancefieldtext.frag</file>
+ <file>shaders/distancefieldtext.vert</file>
+ <file>shaders/hiqsubpixeldistancefieldtext.frag</file>
+ <file>shaders/hiqsubpixeldistancefieldtext.vert</file>
+ <file>shaders/loqsubpixeldistancefieldtext.frag</file>
+ <file>shaders/loqsubpixeldistancefieldtext.vert</file>
+ <file>shaders/vertexcolor.frag</file>
+ <file>shaders/vertexcolor.vert</file>
+ <file>shaders/rendernode.vert</file>
+ <file>shaders/rendernode.frag</file>
+ <file>shaders/stencilclip.frag</file>
+ <file>shaders/stencilclip.vert</file>
+ <file>shaders/8bittextmask_core.frag</file>
+ <file>shaders/24bittextmask_core.frag</file>
+ <file>shaders/distancefieldoutlinetext_core.frag</file>
+ <file>shaders/distancefieldshiftedtext_core.frag</file>
+ <file>shaders/distancefieldshiftedtext_core.vert</file>
+ <file>shaders/distancefieldtext_core.frag</file>
+ <file>shaders/distancefieldtext_core.vert</file>
+ <file>shaders/flatcolor_core.frag</file>
+ <file>shaders/flatcolor_core.vert</file>
+ <file>shaders/hiqsubpixeldistancefieldtext_core.frag</file>
+ <file>shaders/hiqsubpixeldistancefieldtext_core.vert</file>
+ <file>shaders/loqsubpixeldistancefieldtext_core.frag</file>
+ <file>shaders/loqsubpixeldistancefieldtext_core.vert</file>
+ <file>shaders/opaquetexture_core.frag</file>
+ <file>shaders/opaquetexture_core.vert</file>
+ <file>shaders/outlinedtext_core.frag</file>
+ <file>shaders/outlinedtext_core.vert</file>
+ <file>shaders/rendernode_core.frag</file>
+ <file>shaders/rendernode_core.vert</file>
+ <file>shaders/smoothcolor_core.frag</file>
+ <file>shaders/smoothcolor_core.vert</file>
+ <file>shaders/smoothtexture_core.frag</file>
+ <file>shaders/smoothtexture_core.vert</file>
+ <file>shaders/stencilclip_core.frag</file>
+ <file>shaders/stencilclip_core.vert</file>
+ <file>shaders/styledtext_core.frag</file>
+ <file>shaders/styledtext_core.vert</file>
+ <file>shaders/textmask_core.frag</file>
+ <file>shaders/textmask_core.vert</file>
+ <file>shaders/texture_core.frag</file>
+ <file>shaders/vertexcolor_core.frag</file>
+ <file>shaders/vertexcolor_core.vert</file>
+ </qresource>
+</RCC>
diff --git a/src/quick/scenegraph/shaders/24bittextmask.frag b/src/quick/scenegraph/shaders/24bittextmask.frag
new file mode 100644
index 0000000000..5c21e202f9
--- /dev/null
+++ b/src/quick/scenegraph/shaders/24bittextmask.frag
@@ -0,0 +1,10 @@
+varying highp vec2 sampleCoord;
+
+uniform lowp sampler2D _qt_texture;
+uniform lowp float color; // just the alpha, really...
+
+void main()
+{
+ lowp vec4 glyph = texture2D(_qt_texture, sampleCoord);
+ gl_FragColor = vec4(glyph.rgb * color, glyph.a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/24bittextmask_core.frag b/src/quick/scenegraph/shaders/24bittextmask_core.frag
new file mode 100644
index 0000000000..29d1f23017
--- /dev/null
+++ b/src/quick/scenegraph/shaders/24bittextmask_core.frag
@@ -0,0 +1,14 @@
+#version 150 core
+
+in vec2 sampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform float color; // just the alpha, really...
+
+void main()
+{
+ vec4 glyph = texture(_qt_texture, sampleCoord);
+ fragColor = vec4(glyph.rgb * color, glyph.a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/8bittextmask.frag b/src/quick/scenegraph/shaders/8bittextmask.frag
new file mode 100644
index 0000000000..44ffb279cb
--- /dev/null
+++ b/src/quick/scenegraph/shaders/8bittextmask.frag
@@ -0,0 +1,9 @@
+varying highp vec2 sampleCoord;
+
+uniform lowp sampler2D _qt_texture;
+uniform lowp vec4 color;
+
+void main()
+{
+ gl_FragColor = color * texture2D(_qt_texture, sampleCoord).a;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/8bittextmask_core.frag b/src/quick/scenegraph/shaders/8bittextmask_core.frag
new file mode 100644
index 0000000000..2d67a4676a
--- /dev/null
+++ b/src/quick/scenegraph/shaders/8bittextmask_core.frag
@@ -0,0 +1,13 @@
+#version 150 core
+
+in vec2 sampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+
+void main()
+{
+ fragColor = color * texture(_qt_texture, sampleCoord).r;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldoutlinetext.frag b/src/quick/scenegraph/shaders/distancefieldoutlinetext.frag
new file mode 100644
index 0000000000..250ed322a1
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldoutlinetext.frag
@@ -0,0 +1,16 @@
+varying highp vec2 sampleCoord;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform lowp vec4 styleColor;
+uniform mediump float alphaMin;
+uniform mediump float alphaMax;
+uniform mediump float outlineAlphaMax0;
+uniform mediump float outlineAlphaMax1;
+
+void main()
+{
+ mediump float d = texture2D(_qt_texture, sampleCoord).a;
+ gl_FragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d))
+ * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldoutlinetext_core.frag b/src/quick/scenegraph/shaders/distancefieldoutlinetext_core.frag
new file mode 100644
index 0000000000..80fa05ca3c
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldoutlinetext_core.frag
@@ -0,0 +1,20 @@
+#version 150 core
+
+in vec2 sampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform vec4 styleColor;
+uniform float alphaMin;
+uniform float alphaMax;
+uniform float outlineAlphaMax0;
+uniform float outlineAlphaMax1;
+
+void main()
+{
+ float d = texture(_qt_texture, sampleCoord).r;
+ fragColor = mix(styleColor, color, smoothstep(alphaMin, alphaMax, d))
+ * smoothstep(outlineAlphaMax0, outlineAlphaMax1, d);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag b/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag
new file mode 100644
index 0000000000..60c1c7468b
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldshiftedtext.frag
@@ -0,0 +1,17 @@
+varying highp vec2 sampleCoord;
+varying highp vec2 shiftedSampleCoord;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform lowp vec4 styleColor;
+uniform mediump float alphaMin;
+uniform mediump float alphaMax;
+
+void main()
+{
+ highp float a = smoothstep(alphaMin, alphaMax, texture2D(_qt_texture, sampleCoord).a);
+ highp vec4 shifted = styleColor * smoothstep(alphaMin,
+ alphaMax,
+ texture2D(_qt_texture, shiftedSampleCoord).a);
+ gl_FragColor = mix(shifted, color, a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldshiftedtext.vert b/src/quick/scenegraph/shaders/distancefieldshiftedtext.vert
new file mode 100644
index 0000000000..800eadc4f1
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldshiftedtext.vert
@@ -0,0 +1,17 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+uniform highp vec2 shift;
+
+varying highp vec2 sampleCoord;
+varying highp vec2 shiftedSampleCoord;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ shiftedSampleCoord = (tCoord - shift) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.frag b/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.frag
new file mode 100644
index 0000000000..3f66965e78
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.frag
@@ -0,0 +1,20 @@
+#version 150 core
+
+in vec2 sampleCoord;
+in vec2 shiftedSampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform vec4 styleColor;
+uniform float alphaMin;
+uniform float alphaMax;
+
+void main()
+{
+ float a = smoothstep(alphaMin, alphaMax, texture(_qt_texture, sampleCoord).r);
+ vec4 shifted = styleColor * smoothstep(alphaMin, alphaMax,
+ texture(_qt_texture, shiftedSampleCoord).r);
+ fragColor = mix(shifted, color, a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.vert b/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.vert
new file mode 100644
index 0000000000..b7a3ecc667
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldshiftedtext_core.vert
@@ -0,0 +1,18 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+out vec2 shiftedSampleCoord;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+uniform vec2 shift;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ shiftedSampleCoord = (tCoord - shift) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldtext.frag b/src/quick/scenegraph/shaders/distancefieldtext.frag
new file mode 100644
index 0000000000..951fb2a825
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldtext.frag
@@ -0,0 +1,13 @@
+varying highp vec2 sampleCoord;
+
+uniform mediump sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform mediump float alphaMin;
+uniform mediump float alphaMax;
+
+void main()
+{
+ gl_FragColor = color * smoothstep(alphaMin,
+ alphaMax,
+ texture2D(_qt_texture, sampleCoord).a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldtext.vert b/src/quick/scenegraph/shaders/distancefieldtext.vert
new file mode 100644
index 0000000000..c4963977a5
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldtext.vert
@@ -0,0 +1,13 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec2 sampleCoord;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldtext_core.frag b/src/quick/scenegraph/shaders/distancefieldtext_core.frag
new file mode 100644
index 0000000000..9c64a60d3d
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldtext_core.frag
@@ -0,0 +1,16 @@
+#version 150 core
+
+in vec2 sampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform float alphaMin;
+uniform float alphaMax;
+
+void main()
+{
+ fragColor = color * smoothstep(alphaMin, alphaMax,
+ texture(_qt_texture, sampleCoord).r);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/distancefieldtext_core.vert b/src/quick/scenegraph/shaders/distancefieldtext_core.vert
new file mode 100644
index 0000000000..7fc693d139
--- /dev/null
+++ b/src/quick/scenegraph/shaders/distancefieldtext_core.vert
@@ -0,0 +1,15 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/flatcolor.frag b/src/quick/scenegraph/shaders/flatcolor.frag
new file mode 100644
index 0000000000..8c225bf5a4
--- /dev/null
+++ b/src/quick/scenegraph/shaders/flatcolor.frag
@@ -0,0 +1,6 @@
+uniform lowp vec4 color;
+
+void main()
+{
+ gl_FragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/flatcolor.vert b/src/quick/scenegraph/shaders/flatcolor.vert
new file mode 100644
index 0000000000..a61de97f85
--- /dev/null
+++ b/src/quick/scenegraph/shaders/flatcolor.vert
@@ -0,0 +1,7 @@
+attribute highp vec4 vCoord;
+uniform highp mat4 matrix;
+
+void main()
+{
+ gl_Position = matrix * vCoord;
+}
diff --git a/src/quick/scenegraph/shaders/flatcolor_core.frag b/src/quick/scenegraph/shaders/flatcolor_core.frag
new file mode 100644
index 0000000000..23a957ad7b
--- /dev/null
+++ b/src/quick/scenegraph/shaders/flatcolor_core.frag
@@ -0,0 +1,10 @@
+#version 150 core
+
+out vec4 fragColor;
+
+uniform vec4 color;
+
+void main()
+{
+ fragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/flatcolor_core.vert b/src/quick/scenegraph/shaders/flatcolor_core.vert
new file mode 100644
index 0000000000..e33c591b95
--- /dev/null
+++ b/src/quick/scenegraph/shaders/flatcolor_core.vert
@@ -0,0 +1,10 @@
+#version 150 core
+
+in vec4 vCoord;
+
+uniform mat4 matrix;
+
+void main()
+{
+ gl_Position = matrix * vCoord;
+}
diff --git a/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag
new file mode 100644
index 0000000000..9b65e5f79b
--- /dev/null
+++ b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.frag
@@ -0,0 +1,58 @@
+varying highp vec2 sampleCoord;
+varying highp vec3 sampleFarLeft;
+varying highp vec3 sampleNearLeft;
+varying highp vec3 sampleNearRight;
+varying highp vec3 sampleFarRight;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform mediump float alphaMin;
+uniform mediump float alphaMax;
+
+void main()
+{
+ highp vec4 n;
+ n.x = texture2DProj(_qt_texture, sampleFarLeft).a;
+ n.y = texture2DProj(_qt_texture, sampleNearLeft).a;
+ highp float c = texture2D(_qt_texture, sampleCoord).a;
+ n.z = texture2DProj(_qt_texture, sampleNearRight).a;
+ n.w = texture2DProj(_qt_texture, sampleFarRight).a;
+#if 0
+ // Blurrier, faster.
+ n = smoothstep(alphaMin, alphaMax, n);
+ c = smoothstep(alphaMin, alphaMax, c);
+#else
+ // Sharper, slower.
+ highp vec2 d = min(abs(n.yw - n.xz) * 2., 0.67);
+ highp vec2 lo = mix(vec2(alphaMin), vec2(0.5), d);
+ highp vec2 hi = mix(vec2(alphaMax), vec2(0.5), d);
+ n = smoothstep(lo.xxyy, hi.xxyy, n);
+ c = smoothstep(lo.x + lo.y, hi.x + hi.y, 2. * c);
+#endif
+ gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w;
+}
+
+/*
+#extension GL_OES_standard_derivatives: enable
+
+varying highp vec2 sampleCoord;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform highp float alphaMin;
+uniform highp float alphaMax;
+
+void main()
+{
+ highp vec2 delta = dFdx(sampleCoord);
+ highp vec4 n;
+ n.x = texture2D(_qt_texture, sampleCoord - 0.667 * delta).a;
+ n.y = texture2D(_qt_texture, sampleCoord - 0.333 * delta).a;
+ highp float c = texture2D(_qt_texture, sampleCoord).a;
+ n.z = texture2D(_qt_texture, sampleCoord + 0.333 * delta).a;
+ n.w = texture2D(_qt_texture, sampleCoord + 0.667 * delta).a;
+ n = smoothstep(alphaMin, alphaMax, n);
+ c = smoothstep(alphaMin, alphaMax, c);
+ gl_FragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w;
+};
+*/ \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert
new file mode 100644
index 0000000000..62768e88e1
--- /dev/null
+++ b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext.vert
@@ -0,0 +1,34 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+uniform highp float fontScale;
+uniform highp vec4 vecDelta;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec2 sampleCoord;
+varying highp vec3 sampleFarLeft;
+varying highp vec3 sampleNearLeft;
+varying highp vec3 sampleNearRight;
+varying highp vec3 sampleFarRight;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+
+ // Calculate neighbor pixel position in item space.
+ highp vec3 wDelta = gl_Position.w * vecDelta.xyw;
+ highp vec3 farLeft = vCoord.xyw - 0.667 * wDelta;
+ highp vec3 nearLeft = vCoord.xyw - 0.333 * wDelta;
+ highp vec3 nearRight = vCoord.xyw + 0.333 * wDelta;
+ highp vec3 farRight = vCoord.xyw + 0.667 * wDelta;
+
+ // Calculate neighbor texture coordinate.
+ highp vec2 scale = textureScale / fontScale;
+ highp vec2 base = sampleCoord - scale * vCoord.xy;
+ sampleFarLeft = vec3(base * farLeft.z + scale * farLeft.xy, farLeft.z);
+ sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z);
+ sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z);
+ sampleFarRight = vec3(base * farRight.z + scale * farRight.xy, farRight.z);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.frag b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.frag
new file mode 100644
index 0000000000..cf6ba2b8d9
--- /dev/null
+++ b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.frag
@@ -0,0 +1,32 @@
+#version 150 core
+
+in vec2 sampleCoord;
+in vec3 sampleFarLeft;
+in vec3 sampleNearLeft;
+in vec3 sampleNearRight;
+in vec3 sampleFarRight;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform float alphaMin;
+uniform float alphaMax;
+
+void main()
+{
+ vec4 n;
+ n.x = textureProj(_qt_texture, sampleFarLeft).r;
+ n.y = textureProj(_qt_texture, sampleNearLeft).r;
+ float c = texture(_qt_texture, sampleCoord).r;
+ n.z = textureProj(_qt_texture, sampleNearRight).r;
+ n.w = textureProj(_qt_texture, sampleFarRight).r;
+
+ vec2 d = min(abs(n.yw - n.xz) * 2., 0.67);
+ vec2 lo = mix(vec2(alphaMin), vec2(0.5), d);
+ vec2 hi = mix(vec2(alphaMax), vec2(0.5), d);
+ n = smoothstep(lo.xxyy, hi.xxyy, n);
+ c = smoothstep(lo.x + lo.y, hi.x + hi.y, 2. * c);
+
+ fragColor = vec4(0.333 * (n.xyz + n.yzw + c), c) * color.w;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.vert b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.vert
new file mode 100644
index 0000000000..936f74725b
--- /dev/null
+++ b/src/quick/scenegraph/shaders/hiqsubpixeldistancefieldtext_core.vert
@@ -0,0 +1,36 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+out vec3 sampleFarLeft;
+out vec3 sampleNearLeft;
+out vec3 sampleNearRight;
+out vec3 sampleFarRight;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+uniform float fontScale;
+uniform vec4 vecDelta;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+
+ // Calculate neighbor pixel position in item space.
+ vec3 wDelta = gl_Position.w * vecDelta.xyw;
+ vec3 farLeft = vCoord.xyw - 0.667 * wDelta;
+ vec3 nearLeft = vCoord.xyw - 0.333 * wDelta;
+ vec3 nearRight = vCoord.xyw + 0.333 * wDelta;
+ vec3 farRight = vCoord.xyw + 0.667 * wDelta;
+
+ // Calculate neighbor texture coordinate.
+ vec2 scale = textureScale / fontScale;
+ vec2 base = sampleCoord - scale * vCoord.xy;
+ sampleFarLeft = vec3(base * farLeft.z + scale * farLeft.xy, farLeft.z);
+ sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z);
+ sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z);
+ sampleFarRight = vec3(base * farRight.z + scale * farRight.xy, farRight.z);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.frag b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.frag
new file mode 100644
index 0000000000..61b6c8dd9a
--- /dev/null
+++ b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.frag
@@ -0,0 +1,17 @@
+varying highp vec3 sampleNearLeft;
+varying highp vec3 sampleNearRight;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform mediump float alphaMin;
+uniform mediump float alphaMax;
+
+void main()
+{
+ highp vec2 n;
+ n.x = texture2DProj(_qt_texture, sampleNearLeft).a;
+ n.y = texture2DProj(_qt_texture, sampleNearRight).a;
+ n = smoothstep(alphaMin, alphaMax, n);
+ highp float c = 0.5 * (n.x + n.y);
+ gl_FragColor = vec4(n.x, c, n.y, c) * color.w;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.vert b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.vert
new file mode 100644
index 0000000000..33cb7efb19
--- /dev/null
+++ b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext.vert
@@ -0,0 +1,27 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+uniform highp float fontScale;
+uniform highp vec4 vecDelta;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec3 sampleNearLeft;
+varying highp vec3 sampleNearRight;
+
+void main()
+{
+ highp vec2 sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+
+ // Calculate neighbor pixel position in item space.
+ highp vec3 wDelta = gl_Position.w * vecDelta.xyw;
+ highp vec3 nearLeft = vCoord.xyw - 0.25 * wDelta;
+ highp vec3 nearRight = vCoord.xyw + 0.25 * wDelta;
+
+ // Calculate neighbor texture coordinate.
+ highp vec2 scale = textureScale / fontScale;
+ highp vec2 base = sampleCoord - scale * vCoord.xy;
+ sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z);
+ sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.frag b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.frag
new file mode 100644
index 0000000000..2dd588d307
--- /dev/null
+++ b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.frag
@@ -0,0 +1,21 @@
+#version 150 core
+
+in vec3 sampleNearLeft;
+in vec3 sampleNearRight;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform float alphaMin;
+uniform float alphaMax;
+
+void main()
+{
+ vec2 n;
+ n.x = textureProj(_qt_texture, sampleNearLeft).r;
+ n.y = textureProj(_qt_texture, sampleNearRight).r;
+ n = smoothstep(alphaMin, alphaMax, n);
+ float c = 0.5 * (n.x + n.y);
+ fragColor = vec4(n.x, c, n.y, c) * color.w;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.vert b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.vert
new file mode 100644
index 0000000000..b887a70001
--- /dev/null
+++ b/src/quick/scenegraph/shaders/loqsubpixeldistancefieldtext_core.vert
@@ -0,0 +1,29 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec3 sampleNearLeft;
+out vec3 sampleNearRight;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+uniform float fontScale;
+uniform vec4 vecDelta;
+
+void main()
+{
+ vec2 sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+
+ // Calculate neighbor pixel position in item space.
+ vec3 wDelta = gl_Position.w * vecDelta.xyw;
+ vec3 nearLeft = vCoord.xyw - 0.25 * wDelta;
+ vec3 nearRight = vCoord.xyw + 0.25 * wDelta;
+
+ // Calculate neighbor texture coordinate.
+ vec2 scale = textureScale / fontScale;
+ vec2 base = sampleCoord - scale * vCoord.xy;
+ sampleNearLeft = vec3(base * nearLeft.z + scale * nearLeft.xy, nearLeft.z);
+ sampleNearRight = vec3(base * nearRight.z + scale * nearRight.xy, nearRight.z);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/opaquetexture.frag b/src/quick/scenegraph/shaders/opaquetexture.frag
new file mode 100644
index 0000000000..b7e07de385
--- /dev/null
+++ b/src/quick/scenegraph/shaders/opaquetexture.frag
@@ -0,0 +1,8 @@
+varying highp vec2 qt_TexCoord;
+
+uniform sampler2D qt_Texture;
+
+void main()
+{
+ gl_FragColor = texture2D(qt_Texture, qt_TexCoord);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/opaquetexture.vert b/src/quick/scenegraph/shaders/opaquetexture.vert
new file mode 100644
index 0000000000..32cf02df25
--- /dev/null
+++ b/src/quick/scenegraph/shaders/opaquetexture.vert
@@ -0,0 +1,12 @@
+uniform highp mat4 qt_Matrix;
+
+attribute highp vec4 qt_VertexPosition;
+attribute highp vec2 qt_VertexTexCoord;
+
+varying highp vec2 qt_TexCoord;
+
+void main()
+{
+ qt_TexCoord = qt_VertexTexCoord;
+ gl_Position = qt_Matrix * qt_VertexPosition;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/opaquetexture_core.frag b/src/quick/scenegraph/shaders/opaquetexture_core.frag
new file mode 100644
index 0000000000..5f30e68677
--- /dev/null
+++ b/src/quick/scenegraph/shaders/opaquetexture_core.frag
@@ -0,0 +1,12 @@
+#version 150 core
+
+in vec2 qt_TexCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D qt_Texture;
+
+void main()
+{
+ fragColor = texture(qt_Texture, qt_TexCoord);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/opaquetexture_core.vert b/src/quick/scenegraph/shaders/opaquetexture_core.vert
new file mode 100644
index 0000000000..419b1a825c
--- /dev/null
+++ b/src/quick/scenegraph/shaders/opaquetexture_core.vert
@@ -0,0 +1,14 @@
+#version 150 core
+
+uniform mat4 qt_Matrix;
+
+in vec4 qt_VertexPosition;
+in vec2 qt_VertexTexCoord;
+
+out vec2 qt_TexCoord;
+
+void main()
+{
+ qt_TexCoord = qt_VertexTexCoord;
+ gl_Position = qt_Matrix * qt_VertexPosition;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/outlinedtext.frag b/src/quick/scenegraph/shaders/outlinedtext.frag
new file mode 100644
index 0000000000..b3e5475d5d
--- /dev/null
+++ b/src/quick/scenegraph/shaders/outlinedtext.frag
@@ -0,0 +1,21 @@
+varying highp vec2 sampleCoord;
+varying highp vec2 sCoordUp;
+varying highp vec2 sCoordDown;
+varying highp vec2 sCoordLeft;
+varying highp vec2 sCoordRight;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform lowp vec4 styleColor;
+
+void main()
+{
+ lowp float glyph = texture2D(_qt_texture, sampleCoord).a;
+ lowp float outline = clamp(clamp(texture2D(_qt_texture, sCoordUp).a +
+ texture2D(_qt_texture, sCoordDown).a +
+ texture2D(_qt_texture, sCoordLeft).a +
+ texture2D(_qt_texture, sCoordRight).a,
+ 0.0, 1.0) - glyph,
+ 0.0, 1.0);
+ gl_FragColor = outline * styleColor + glyph * color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/outlinedtext.vert b/src/quick/scenegraph/shaders/outlinedtext.vert
new file mode 100644
index 0000000000..ced8afd034
--- /dev/null
+++ b/src/quick/scenegraph/shaders/outlinedtext.vert
@@ -0,0 +1,22 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+uniform highp vec2 shift;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec2 sampleCoord;
+varying highp vec2 sCoordUp;
+varying highp vec2 sCoordDown;
+varying highp vec2 sCoordLeft;
+varying highp vec2 sCoordRight;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ sCoordUp = (tCoord - vec2(0.0, -1.0)) * textureScale;
+ sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale;
+ sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale;
+ sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/outlinedtext_core.frag b/src/quick/scenegraph/shaders/outlinedtext_core.frag
new file mode 100644
index 0000000000..e19c8937f9
--- /dev/null
+++ b/src/quick/scenegraph/shaders/outlinedtext_core.frag
@@ -0,0 +1,25 @@
+#version 150 core
+
+in vec2 sampleCoord;
+in vec2 sCoordUp;
+in vec2 sCoordDown;
+in vec2 sCoordLeft;
+in vec2 sCoordRight;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform vec4 styleColor;
+
+void main()
+{
+ float glyph = texture(_qt_texture, sampleCoord).r;
+ float outline = clamp(clamp(texture(_qt_texture, sCoordUp).r +
+ texture(_qt_texture, sCoordDown).r +
+ texture(_qt_texture, sCoordLeft).r +
+ texture(_qt_texture, sCoordRight).r,
+ 0.0, 1.0) - glyph,
+ 0.0, 1.0);
+ fragColor = outline * styleColor + glyph * color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/outlinedtext_core.vert b/src/quick/scenegraph/shaders/outlinedtext_core.vert
new file mode 100644
index 0000000000..4aa13101fd
--- /dev/null
+++ b/src/quick/scenegraph/shaders/outlinedtext_core.vert
@@ -0,0 +1,24 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+out vec2 sCoordUp;
+out vec2 sCoordDown;
+out vec2 sCoordLeft;
+out vec2 sCoordRight;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+uniform vec2 shift;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ sCoordUp = (tCoord - vec2(0.0, -1.0)) * textureScale;
+ sCoordDown = (tCoord - vec2(0.0, 1.0)) * textureScale;
+ sCoordLeft = (tCoord - vec2(-1.0, 0.0)) * textureScale;
+ sCoordRight = (tCoord - vec2(1.0, 0.0)) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/rendernode.frag b/src/quick/scenegraph/shaders/rendernode.frag
new file mode 100644
index 0000000000..b4e9b0209c
--- /dev/null
+++ b/src/quick/scenegraph/shaders/rendernode.frag
@@ -0,0 +1,8 @@
+uniform lowp sampler2D tex;
+
+varying highp vec2 t;
+
+void main()
+{
+ gl_FragColor = texture2D(tex, t);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/rendernode.vert b/src/quick/scenegraph/shaders/rendernode.vert
new file mode 100644
index 0000000000..fbfe9ef8ae
--- /dev/null
+++ b/src/quick/scenegraph/shaders/rendernode.vert
@@ -0,0 +1,10 @@
+attribute highp vec4 av;
+attribute highp vec2 at;
+
+varying highp vec2 t;
+
+void main()
+{
+ gl_Position = av;
+ t = at;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/rendernode_core.frag b/src/quick/scenegraph/shaders/rendernode_core.frag
new file mode 100644
index 0000000000..7c187265df
--- /dev/null
+++ b/src/quick/scenegraph/shaders/rendernode_core.frag
@@ -0,0 +1,12 @@
+#version 150 core
+
+uniform sampler2D tex;
+
+in vec2 t;
+
+out vec4 color;
+
+void main()
+{
+ fragColor = texture(tex, t);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/rendernode_core.vert b/src/quick/scenegraph/shaders/rendernode_core.vert
new file mode 100644
index 0000000000..a76d519a5a
--- /dev/null
+++ b/src/quick/scenegraph/shaders/rendernode_core.vert
@@ -0,0 +1,12 @@
+#version 150 core
+
+in vec4 av;
+in vec2 at;
+
+out vec2 t;
+
+void main()
+{
+ gl_Position = av;
+ t = at;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothcolor.frag b/src/quick/scenegraph/shaders/smoothcolor.frag
new file mode 100644
index 0000000000..71de9dbfc2
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothcolor.frag
@@ -0,0 +1,6 @@
+varying lowp vec4 color;
+
+void main()
+{
+ gl_FragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothcolor.vert b/src/quick/scenegraph/shaders/smoothcolor.vert
new file mode 100644
index 0000000000..df70fea92a
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothcolor.vert
@@ -0,0 +1,45 @@
+uniform highp vec2 pixelSize;
+uniform highp mat4 matrix;
+uniform lowp float opacity;
+
+attribute highp vec4 vertex;
+attribute lowp vec4 vertexColor;
+attribute highp vec2 vertexOffset;
+
+varying lowp vec4 color;
+
+void main()
+{
+ highp vec4 pos = matrix * vertex;
+ gl_Position = pos;
+
+ if (vertexOffset.x != 0.) {
+ highp vec4 delta = matrix[0] * vertexOffset.x;
+ highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ highp float numerator = dot(dir, ndir * pos.w * pos.w);
+ highp float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ }
+
+ if (vertexOffset.y != 0.) {
+ highp vec4 delta = matrix[1] * vertexOffset.y;
+ highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ highp float numerator = dot(dir, ndir * pos.w * pos.w);
+ highp float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ }
+
+ color = vertexColor * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothcolor_core.frag b/src/quick/scenegraph/shaders/smoothcolor_core.frag
new file mode 100644
index 0000000000..84533c2b40
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothcolor_core.frag
@@ -0,0 +1,10 @@
+#version 150 core
+
+in vec4 color;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothcolor_core.vert b/src/quick/scenegraph/shaders/smoothcolor_core.vert
new file mode 100644
index 0000000000..1eed751ccd
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothcolor_core.vert
@@ -0,0 +1,47 @@
+#version 150 core
+
+in vec4 vertex;
+in vec4 vertexColor;
+in vec2 vertexOffset;
+
+out vec4 color;
+
+uniform vec2 pixelSize;
+uniform mat4 matrix;
+uniform float opacity;
+
+void main()
+{
+ vec4 pos = matrix * vertex;
+ gl_Position = pos;
+
+ if (vertexOffset.x != 0.) {
+ vec4 delta = matrix[0] * vertexOffset.x;
+ vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ float numerator = dot(dir, ndir * pos.w * pos.w);
+ float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ }
+
+ if (vertexOffset.y != 0.) {
+ vec4 delta = matrix[1] * vertexOffset.y;
+ vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ float numerator = dot(dir, ndir * pos.w * pos.w);
+ float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ }
+
+ color = vertexColor * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothtexture.frag b/src/quick/scenegraph/shaders/smoothtexture.frag
new file mode 100644
index 0000000000..e4f6359f3d
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothtexture.frag
@@ -0,0 +1,9 @@
+uniform sampler2D qt_Texture;
+
+varying highp vec2 texCoord;
+varying lowp float vertexOpacity;
+
+void main()
+{
+ gl_FragColor = texture2D(qt_Texture, texCoord) * vertexOpacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothtexture.vert b/src/quick/scenegraph/shaders/smoothtexture.vert
new file mode 100644
index 0000000000..1ce824a68f
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothtexture.vert
@@ -0,0 +1,52 @@
+uniform highp vec2 pixelSize;
+uniform highp mat4 qt_Matrix;
+uniform lowp float opacity;
+
+attribute highp vec4 vertex;
+attribute highp vec2 multiTexCoord;
+attribute highp vec2 vertexOffset;
+attribute highp vec2 texCoordOffset;
+
+varying highp vec2 texCoord;
+varying lowp float vertexOpacity;
+
+void main()
+{
+ highp vec4 pos = qt_Matrix * vertex;
+ gl_Position = pos;
+ texCoord = multiTexCoord;
+
+ if (vertexOffset.x != 0.) {
+ highp vec4 delta = qt_Matrix[0] * vertexOffset.x;
+ highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ highp float numerator = dot(dir, ndir * pos.w * pos.w);
+ highp float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ texCoord.x += scale * texCoordOffset.x;
+ }
+
+ if (vertexOffset.y != 0.) {
+ highp vec4 delta = qt_Matrix[1] * vertexOffset.y;
+ highp vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ highp vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ highp float numerator = dot(dir, ndir * pos.w * pos.w);
+ highp float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ texCoord.y += scale * texCoordOffset.y;
+ }
+
+ bool onEdge = any(notEqual(vertexOffset, vec2(0.)));
+ bool outerEdge = all(equal(texCoordOffset, vec2(0.)));
+ vertexOpacity = onEdge && outerEdge ? 0. : opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothtexture_core.frag b/src/quick/scenegraph/shaders/smoothtexture_core.frag
new file mode 100644
index 0000000000..8a9aefd4c8
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothtexture_core.frag
@@ -0,0 +1,13 @@
+#version 150 core
+
+in vec2 texCoord;
+in float vertexOpacity;
+
+out vec4 fragColor;
+
+uniform sampler2D qt_Texture;
+
+void main()
+{
+ fragColor = texture(qt_Texture, texCoord) * vertexOpacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/smoothtexture_core.vert b/src/quick/scenegraph/shaders/smoothtexture_core.vert
new file mode 100644
index 0000000000..a2489a39c5
--- /dev/null
+++ b/src/quick/scenegraph/shaders/smoothtexture_core.vert
@@ -0,0 +1,54 @@
+#version 150 core
+
+in vec4 vertex;
+in vec2 multiTexCoord;
+in vec2 vertexOffset;
+in vec2 texCoordOffset;
+
+out vec2 texCoord;
+out float vertexOpacity;
+
+uniform vec2 pixelSize;
+uniform mat4 qt_Matrix;
+uniform float opacity;
+
+void main()
+{
+ vec4 pos = qt_Matrix * vertex;
+ gl_Position = pos;
+ texCoord = multiTexCoord;
+
+ if (vertexOffset.x != 0.) {
+ vec4 delta = qt_Matrix[0] * vertexOffset.x;
+ vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ float numerator = dot(dir, ndir * pos.w * pos.w);
+ float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ texCoord.x += scale * texCoordOffset.x;
+ }
+
+ if (vertexOffset.y != 0.) {
+ vec4 delta = qt_Matrix[1] * vertexOffset.y;
+ vec2 dir = delta.xy * pos.w - pos.xy * delta.w;
+ vec2 ndir = .5 * pixelSize * normalize(dir / pixelSize);
+ dir -= ndir * delta.w * pos.w;
+ float numerator = dot(dir, ndir * pos.w * pos.w);
+ float scale = 0.0;
+ if (numerator < 0.0)
+ scale = 1.0;
+ else
+ scale = min(1.0, numerator / dot(dir, dir));
+ gl_Position += scale * delta;
+ texCoord.y += scale * texCoordOffset.y;
+ }
+
+ bool onEdge = any(notEqual(vertexOffset, vec2(0.)));
+ bool outerEdge = all(equal(texCoordOffset, vec2(0.)));
+ vertexOpacity = onEdge && outerEdge ? 0. : opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/stencilclip.frag b/src/quick/scenegraph/shaders/stencilclip.frag
new file mode 100644
index 0000000000..70b7717977
--- /dev/null
+++ b/src/quick/scenegraph/shaders/stencilclip.frag
@@ -0,0 +1,4 @@
+void main()
+{
+ gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); // Trolltech green ftw!
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/stencilclip.vert b/src/quick/scenegraph/shaders/stencilclip.vert
new file mode 100644
index 0000000000..0e546c8112
--- /dev/null
+++ b/src/quick/scenegraph/shaders/stencilclip.vert
@@ -0,0 +1,8 @@
+attribute highp vec4 vCoord;
+
+uniform highp mat4 matrix;
+
+void main()
+{
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/stencilclip_core.frag b/src/quick/scenegraph/shaders/stencilclip_core.frag
new file mode 100644
index 0000000000..4d05de4ca9
--- /dev/null
+++ b/src/quick/scenegraph/shaders/stencilclip_core.frag
@@ -0,0 +1,8 @@
+#version 150 core
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = vec4(0.81, 0.83, 0.12, 1.0); // Trolltech green ftw!
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/stencilclip_core.vert b/src/quick/scenegraph/shaders/stencilclip_core.vert
new file mode 100644
index 0000000000..37e240c735
--- /dev/null
+++ b/src/quick/scenegraph/shaders/stencilclip_core.vert
@@ -0,0 +1,10 @@
+#version 150 core
+
+in vec4 vCoord;
+
+uniform mat4 matrix;
+
+void main()
+{
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/styledtext.frag b/src/quick/scenegraph/shaders/styledtext.frag
new file mode 100644
index 0000000000..662dbef2fc
--- /dev/null
+++ b/src/quick/scenegraph/shaders/styledtext.frag
@@ -0,0 +1,14 @@
+varying highp vec2 sampleCoord;
+varying highp vec2 shiftedSampleCoord;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+uniform lowp vec4 styleColor;
+
+void main()
+{
+ lowp float glyph = texture2D(_qt_texture, sampleCoord).a;
+ lowp float style = clamp(texture2D(_qt_texture, shiftedSampleCoord).a - glyph,
+ 0.0, 1.0);
+ gl_FragColor = style * styleColor + glyph * color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/styledtext.vert b/src/quick/scenegraph/shaders/styledtext.vert
new file mode 100644
index 0000000000..3ad9497b65
--- /dev/null
+++ b/src/quick/scenegraph/shaders/styledtext.vert
@@ -0,0 +1,16 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+uniform highp vec2 shift;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec2 sampleCoord;
+varying highp vec2 shiftedSampleCoord;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ shiftedSampleCoord = (tCoord - shift) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/styledtext_core.frag b/src/quick/scenegraph/shaders/styledtext_core.frag
new file mode 100644
index 0000000000..50f64c64a2
--- /dev/null
+++ b/src/quick/scenegraph/shaders/styledtext_core.frag
@@ -0,0 +1,18 @@
+#version 150 core
+
+in vec2 sampleCoord;
+in vec2 shiftedSampleCoord;
+
+out vec4 color;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+uniform vec4 styleColor;
+
+void main()
+{
+ float glyph = texture(_qt_texture, sampleCoord).a;
+ float style = clamp(texture(_qt_texture, shiftedSampleCoord).r - glyph,
+ 0.0, 1.0);
+ fragColor = style * styleColor + glyph * color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/styledtext_core.vert b/src/quick/scenegraph/shaders/styledtext_core.vert
new file mode 100644
index 0000000000..b7a3ecc667
--- /dev/null
+++ b/src/quick/scenegraph/shaders/styledtext_core.vert
@@ -0,0 +1,18 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+out vec2 shiftedSampleCoord;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+uniform vec2 shift;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ shiftedSampleCoord = (tCoord - shift) * textureScale;
+ gl_Position = matrix * vCoord;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/textmask.frag b/src/quick/scenegraph/shaders/textmask.frag
new file mode 100644
index 0000000000..7715688ecc
--- /dev/null
+++ b/src/quick/scenegraph/shaders/textmask.frag
@@ -0,0 +1,10 @@
+varying highp vec2 sampleCoord;
+
+uniform sampler2D _qt_texture;
+uniform lowp vec4 color;
+
+void main()
+{
+ lowp vec4 glyph = texture2D(_qt_texture, sampleCoord);
+ gl_FragColor = vec4(glyph.rgb * color.a, glyph.a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/textmask.vert b/src/quick/scenegraph/shaders/textmask.vert
new file mode 100644
index 0000000000..1f45e9cf71
--- /dev/null
+++ b/src/quick/scenegraph/shaders/textmask.vert
@@ -0,0 +1,13 @@
+uniform highp mat4 matrix;
+uniform highp vec2 textureScale;
+
+attribute highp vec4 vCoord;
+attribute highp vec2 tCoord;
+
+varying highp vec2 sampleCoord;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+}
diff --git a/src/quick/scenegraph/shaders/textmask_core.frag b/src/quick/scenegraph/shaders/textmask_core.frag
new file mode 100644
index 0000000000..17dda53c97
--- /dev/null
+++ b/src/quick/scenegraph/shaders/textmask_core.frag
@@ -0,0 +1,14 @@
+#version 150 core
+
+in vec2 sampleCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D _qt_texture;
+uniform vec4 color;
+
+void main()
+{
+ vec4 glyph = texture(_qt_texture, sampleCoord);
+ fragColor = vec4(glyph.rgb * color.a, glyph.a);
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/textmask_core.vert b/src/quick/scenegraph/shaders/textmask_core.vert
new file mode 100644
index 0000000000..619248dccb
--- /dev/null
+++ b/src/quick/scenegraph/shaders/textmask_core.vert
@@ -0,0 +1,15 @@
+#version 150 core
+
+in vec4 vCoord;
+in vec2 tCoord;
+
+out vec2 sampleCoord;
+
+uniform mat4 matrix;
+uniform vec2 textureScale;
+
+void main()
+{
+ sampleCoord = tCoord * textureScale;
+ gl_Position = matrix * vCoord;
+}
diff --git a/src/quick/scenegraph/shaders/texture.frag b/src/quick/scenegraph/shaders/texture.frag
new file mode 100644
index 0000000000..2d97f2e66a
--- /dev/null
+++ b/src/quick/scenegraph/shaders/texture.frag
@@ -0,0 +1,9 @@
+varying highp vec2 qt_TexCoord;
+
+uniform sampler2D qt_Texture;
+uniform lowp float opacity;
+
+void main()
+{
+ gl_FragColor = texture2D(qt_Texture, qt_TexCoord) * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/texture_core.frag b/src/quick/scenegraph/shaders/texture_core.frag
new file mode 100644
index 0000000000..d9bdf6a238
--- /dev/null
+++ b/src/quick/scenegraph/shaders/texture_core.frag
@@ -0,0 +1,13 @@
+#version 150 core
+
+in vec2 qt_TexCoord;
+
+out vec4 fragColor;
+
+uniform sampler2D qt_Texture;
+uniform float opacity;
+
+void main()
+{
+ fragColor = texture(qt_Texture, qt_TexCoord) * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/vertexcolor.frag b/src/quick/scenegraph/shaders/vertexcolor.frag
new file mode 100644
index 0000000000..71de9dbfc2
--- /dev/null
+++ b/src/quick/scenegraph/shaders/vertexcolor.frag
@@ -0,0 +1,6 @@
+varying lowp vec4 color;
+
+void main()
+{
+ gl_FragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/vertexcolor.vert b/src/quick/scenegraph/shaders/vertexcolor.vert
new file mode 100644
index 0000000000..750d520114
--- /dev/null
+++ b/src/quick/scenegraph/shaders/vertexcolor.vert
@@ -0,0 +1,13 @@
+attribute highp vec4 vertexCoord;
+attribute highp vec4 vertexColor;
+
+uniform highp mat4 matrix;
+uniform highp float opacity;
+
+varying lowp vec4 color;
+
+void main()
+{
+ gl_Position = matrix * vertexCoord;
+ color = vertexColor * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/vertexcolor_core.frag b/src/quick/scenegraph/shaders/vertexcolor_core.frag
new file mode 100644
index 0000000000..84533c2b40
--- /dev/null
+++ b/src/quick/scenegraph/shaders/vertexcolor_core.frag
@@ -0,0 +1,10 @@
+#version 150 core
+
+in vec4 color;
+
+out vec4 fragColor;
+
+void main()
+{
+ fragColor = color;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/shaders/vertexcolor_core.vert b/src/quick/scenegraph/shaders/vertexcolor_core.vert
new file mode 100644
index 0000000000..219b840913
--- /dev/null
+++ b/src/quick/scenegraph/shaders/vertexcolor_core.vert
@@ -0,0 +1,15 @@
+#version 150 core
+
+in vec4 vertexCoord;
+in vec4 vertexColor;
+
+out vec4 color;
+
+uniform mat4 matrix;
+uniform float opacity;
+
+void main()
+{
+ gl_Position = matrix * vertexCoord;
+ color = vertexColor * opacity;
+} \ No newline at end of file
diff --git a/src/quick/scenegraph/util/qsgatlastexture.cpp b/src/quick/scenegraph/util/qsgatlastexture.cpp
index 3710f05b9a..8678d106ff 100644
--- a/src/quick/scenegraph/util/qsgatlastexture.cpp
+++ b/src/quick/scenegraph/util/qsgatlastexture.cpp
@@ -47,11 +47,14 @@
#include <QtGui/QOpenGLContext>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
+#include <QtGui/QSurface>
#include <private/qsgtexture_p.h>
#include <private/qqmlprofilerservice_p.h>
+QT_BEGIN_NAMESPACE
+
#ifndef GL_BGRA
#define GL_BGRA 0x80E1
#endif
@@ -89,26 +92,36 @@ static int qsg_envInt(const char *name, int defaultValue)
Manager::Manager()
: m_atlas(0)
{
- QSize screenSize = QGuiApplication::primaryScreen()->geometry().size();
+ QOpenGLContext *gl = QOpenGLContext::currentContext();
+ Q_ASSERT(gl);
+ QSurface *surface = gl->surface();
+ QSize surfaceSize = surface->size();
int max;
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
- int w = qMin(max, qsg_envInt("QSG_ATLAS_WIDTH", qsg_powerOfTwo(screenSize.width())));
- int h = qMin(max, qsg_envInt("QSG_ATLAS_HEIGHT", qsg_powerOfTwo(screenSize.height())));
+
+ int w = qMin(max, qsg_envInt("QSG_ATLAS_WIDTH", qMax(512, qsg_powerOfTwo(surfaceSize.width()))));
+ int h = qMin(max, qsg_envInt("QSG_ATLAS_HEIGHT", qMax(512, qsg_powerOfTwo(surfaceSize.height()))));
m_atlas_size_limit = qsg_envInt("QSG_ATLAS_SIZE_LIMIT", qMax(w, h) / 2);
m_atlas_size = QSize(w, h);
+
+ if (qEnvironmentVariableIsSet("QSG_INFO"))
+ qDebug() << "QSG: texture atlas dimensions:" << w << "x" << h;
}
Manager::~Manager()
{
- invalidate();
+ Q_ASSERT(m_atlas == 0);
}
void Manager::invalidate()
{
- delete m_atlas;
- m_atlas = 0;
+ if (m_atlas) {
+ m_atlas->invalidate();
+ m_atlas->deleteLater();
+ m_atlas = 0;
+ }
}
QSGTexture *Manager::create(const QImage &image)
@@ -118,10 +131,7 @@ QSGTexture *Manager::create(const QImage &image)
if (!m_atlas)
m_atlas = new Atlas(m_atlas_size);
t = m_atlas->create(image);
- if (t)
- return t;
}
-
return t;
}
@@ -139,6 +149,11 @@ Atlas::Atlas(const QSize &size)
|| strstr(ext, "GL_EXT_texture_format_BGRA8888")
|| strstr(ext, "GL_IMG_texture_format_BGRA8888")) {
m_internalFormat = m_externalFormat = GL_BGRA;
+#ifdef Q_OS_IOS
+ } else if (strstr(ext, "GL_APPLE_texture_format_BGRA8888")) {
+ m_internalFormat = GL_RGBA;
+ m_externalFormat = GL_BGRA;
+#endif
} else {
m_internalFormat = m_externalFormat = GL_RGBA;
}
@@ -153,13 +168,21 @@ Atlas::Atlas(const QSize &size)
Atlas::~Atlas()
{
- if (m_texture_id)
- glDeleteTextures(1, &m_texture_id);
+ Q_ASSERT(!m_texture_id);
}
+void Atlas::invalidate()
+{
+ Q_ASSERT(QOpenGLContext::currentContext());
+ if (m_texture_id) {
+ glDeleteTextures(1, &m_texture_id);
+ m_texture_id = 0;
+ }
+}
Texture *Atlas::create(const QImage &image)
{
+ // No need to lock, as manager already locked it.
QRect rect = m_allocator.allocate(QSize(image.width() + 2, image.height() + 2));
if (rect.width() > 0 && rect.height() > 0) {
Texture *t = new Texture(this, rect, image);
@@ -293,6 +316,9 @@ bool Atlas::bind(QSGTexture::Filtering filtering)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+#if !defined(QT_OPENGL_ES_2)
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+#endif
glTexImage2D(GL_TEXTURE_2D, 0, m_internalFormat, m_size.width(), m_size.height(), 0, m_externalFormat, GL_UNSIGNED_BYTE, 0);
#if 0
@@ -383,7 +409,6 @@ void Atlas::remove(Texture *t)
{
QRect atlasRect = t->atlasSubRect();
m_allocator.deallocate(atlasRect);
-
m_pending_uploads.removeOne(t);
}
@@ -428,3 +453,5 @@ QSGTexture *Texture::removedFromAtlas() const
}
}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgatlastexture_p.h b/src/quick/scenegraph/util/qsgatlastexture_p.h
index f8edd96f47..ade7b8f00e 100644
--- a/src/quick/scenegraph/util/qsgatlastexture_p.h
+++ b/src/quick/scenegraph/util/qsgatlastexture_p.h
@@ -50,6 +50,8 @@
#include <QtQuick/private/qsgtexture_p.h>
#include <QtQuick/private/qsgareaallocator_p.h>
+QT_BEGIN_NAMESPACE
+
namespace QSGAtlasTexture
{
@@ -69,19 +71,18 @@ public:
private:
Atlas *m_atlas;
- Atlas *m_secondary_atlas;
QSize m_atlas_size;
int m_atlas_size_limit;
};
-class Atlas
+class Atlas : public QObject
{
public:
Atlas(const QSize &size);
~Atlas();
- void initialize();
+ void invalidate();
int textureId() const;
bool bind(QSGTexture::Filtering filteing);
@@ -95,7 +96,6 @@ public:
QSize size() const { return m_size; }
private:
-
QSGAreaAllocator m_allocator;
GLuint m_texture_id;
QSize m_size;
@@ -153,4 +153,6 @@ private:
}
+QT_END_NAMESPACE
+
#endif
diff --git a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
index 83264e2930..c603c62a20 100644
--- a/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgflatcolormaterial.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qsgflatcolormaterial.h"
+#include <private/qsgmaterialshader_p.h>
#include <qopenglshaderprogram.h>
@@ -48,6 +49,8 @@ QT_BEGIN_NAMESPACE
class FlatColorMaterialShader : public QSGMaterialShader
{
public:
+ FlatColorMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
@@ -55,8 +58,6 @@ public:
private:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_matrix_id;
int m_color_id;
@@ -64,6 +65,13 @@ private:
QSGMaterialType FlatColorMaterialShader::type;
+FlatColorMaterialShader::FlatColorMaterialShader()
+ : QSGMaterialShader(*new QSGMaterialShaderPrivate)
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/flatcolor.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/flatcolor.frag"));
+}
+
void FlatColorMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
@@ -98,23 +106,6 @@ void FlatColorMaterialShader::initialize()
m_color_id = program()->uniformLocation("color");
}
-const char *FlatColorMaterialShader::vertexShader() const {
- return
- "attribute highp vec4 vCoord; \n"
- "uniform highp mat4 matrix; \n"
- "void main() { \n"
- " gl_Position = matrix * vCoord; \n"
- "}";
-}
-
-const char *FlatColorMaterialShader::fragmentShader() const {
- return
- "uniform lowp vec4 color; \n"
- "void main() { \n"
- " gl_FragColor = color; \n"
- "}";
-}
-
/*!
diff --git a/src/quick/scenegraph/util/qsgpainternode.cpp b/src/quick/scenegraph/util/qsgpainternode.cpp
index d6bec550d3..797fc4d145 100644
--- a/src/quick/scenegraph/util/qsgpainternode.cpp
+++ b/src/quick/scenegraph/util/qsgpainternode.cpp
@@ -111,7 +111,7 @@ QSGPainterNode::QSGPainterNode(QQuickPaintedItem *item)
, m_dirtyRenderTarget(false)
, m_dirtyTexture(false)
{
- m_context = static_cast<QQuickPaintedItemPrivate *>(QObjectPrivate::get(item))->sceneGraphContext();
+ m_context = static_cast<QQuickPaintedItemPrivate *>(QObjectPrivate::get(item))->sceneGraphRenderContext();
setMaterial(&m_materialO);
setOpaqueMaterial(&m_material);
@@ -260,7 +260,7 @@ void QSGPainterNode::updateRenderTarget()
if (m_actualRenderTarget == QQuickPaintedItem::FramebufferObject ||
m_actualRenderTarget == QQuickPaintedItem::InvertedYFramebufferObject) {
- const QOpenGLContext *ctx = m_context->glContext();
+ const QOpenGLContext *ctx = m_context->openglContext();
if (m_fbo && !m_dirtyGeometry && (!ctx->format().samples() || !m_multisamplingSupported))
return;
@@ -323,7 +323,7 @@ void QSGPainterNode::updateFBOSize()
fboWidth = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qt_next_power_of_two(m_size.width()));
fboHeight = qMax(QT_MINIMUM_DYNAMIC_FBO_SIZE, qt_next_power_of_two(m_size.height()));
} else {
- QSize minimumFBOSize = m_context->minimumFBOSize();
+ QSize minimumFBOSize = m_context->sceneGraphContext()->minimumFBOSize();
fboWidth = qMax(minimumFBOSize.width(), m_size.width());
fboHeight = qMax(minimumFBOSize.height(), m_size.height());
}
diff --git a/src/quick/scenegraph/util/qsgpainternode_p.h b/src/quick/scenegraph/util/qsgpainternode_p.h
index bc1556672c..df0943d38e 100644
--- a/src/quick/scenegraph/util/qsgpainternode_p.h
+++ b/src/quick/scenegraph/util/qsgpainternode_p.h
@@ -113,7 +113,7 @@ private:
void updateRenderTarget();
void updateFBOSize();
- QSGContext *m_context;
+ QSGRenderContext *m_context;
QQuickPaintedItem::RenderTarget m_preferredRenderTarget;
QQuickPaintedItem::RenderTarget m_actualRenderTarget;
diff --git a/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp
new file mode 100644
index 0000000000..1a1963dbca
--- /dev/null
+++ b/src/quick/scenegraph/util/qsgshadersourcebuilder.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia 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.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsgshadersourcebuilder_p.h"
+
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qopenglshaderprogram.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qfile.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QSGShaderParser {
+
+struct Tokenizer {
+
+ enum Token {
+ Token_Invalid,
+ Token_Void,
+ Token_OpenBrace,
+ Token_CloseBrace,
+ Token_SemiColon,
+ Token_Identifier,
+ Token_Macro,
+ Token_Version,
+ Token_Extension,
+ Token_SingleLineComment,
+ Token_MultiLineCommentStart,
+ Token_MultiLineCommentEnd,
+ Token_NewLine,
+ Token_Unspecified,
+ Token_EOF
+ };
+
+ static const char *NAMES[];
+
+ void initialize(const char *input);
+ Token next();
+
+ const char *stream;
+ const char *pos;
+ const char *identifier;
+};
+
+const char *Tokenizer::NAMES[] = {
+ "Invalid",
+ "Void",
+ "OpenBrace",
+ "CloseBrace",
+ "SemiColon",
+ "Identifier",
+ "Macro",
+ "Version",
+ "Extension",
+ "SingleLineComment",
+ "MultiLineCommentStart",
+ "MultiLineCommentEnd",
+ "NewLine",
+ "Unspecified",
+ "EOF"
+};
+
+void Tokenizer::initialize(const char *input)
+{
+ stream = input;
+ pos = input;
+ identifier = input;
+}
+
+Tokenizer::Token Tokenizer::next()
+{
+ while (*pos != 0) {
+ char c = *pos++;
+ switch (c) {
+ case '/':
+ if (*pos == '/') {
+ // '//' comment
+ return Token_SingleLineComment;
+ } else if (*pos == '*') {
+ // /* */ comment
+ return Token_MultiLineCommentStart;
+ }
+ break;
+
+ case '*':
+ if (*pos == '/')
+ return Token_MultiLineCommentEnd;
+
+ case '\n':
+ return Token_NewLine;
+
+ case '\r':
+ if (*pos == '\n')
+ return Token_NewLine;
+
+ case '#': {
+ if (*pos == 'v' && pos[1] == 'e' && pos[2] == 'r' && pos[3] == 's'
+ && pos[4] == 'i' && pos[5] == 'o' && pos[6] == 'n') {
+ return Token_Version;
+ } else if (*pos == 'e' && pos[1] == 'x' && pos[2] == 't' && pos[3] == 'e'
+ && pos[4] == 'n' && pos[5] == 's' && pos[6] == 'i'&& pos[7] == 'o'
+ && pos[8] == 'n') {
+ return Token_Extension;
+ } else {
+ while (*pos != 0) {
+ if (*pos == '\n') {
+ ++pos;
+ break;
+ } else if (*pos == '\\') {
+ ++pos;
+ while (*pos != 0 && (*pos == ' ' || *pos == '\t'))
+ ++pos;
+ if (*pos != 0 && (*pos == '\n' || (*pos == '\r' && pos[1] == '\n')))
+ pos+=2;
+ } else {
+ ++pos;
+ }
+ }
+ }
+ break;
+ }
+
+ case ';':
+ return Token_SemiColon;
+
+ case 0:
+ return Token_EOF;
+
+ case '{':
+ return Token_OpenBrace;
+
+ case '}':
+ return Token_CloseBrace;
+
+ case ' ':
+ break;
+
+ case 'v': {
+ if (*pos == 'o' && pos[1] == 'i' && pos[2] == 'd') {
+ pos += 3;
+ return Token_Void;
+ }
+ // Fall-thru
+ }
+ default:
+ // Identifier...
+ if ((c >= 'a' && c <= 'z' ) || (c >= 'A' && c <= 'Z' ) || c == '_') {
+ identifier = pos - 1;
+ while (*pos != 0 && ((*pos >= 'a' && *pos <= 'z')
+ || (*pos >= 'A' && *pos <= 'Z')
+ || *pos == '_'
+ || (*pos >= '0' && *pos <= '9'))) {
+ ++pos;
+ }
+ return Token_Identifier;
+ } else {
+ return Token_Unspecified;
+ }
+ }
+ }
+
+ return Token_Invalid;
+}
+
+} // namespace QSGShaderParser
+
+using namespace QSGShaderParser;
+
+QSGShaderSourceBuilder::QSGShaderSourceBuilder()
+{
+}
+
+void QSGShaderSourceBuilder::initializeProgramFromFiles(QOpenGLShaderProgram *program,
+ const QString &vertexShader,
+ const QString &fragmentShader)
+{
+ Q_ASSERT(program);
+ program->removeAllShaders();
+
+ QSGShaderSourceBuilder builder;
+
+ builder.appendSourceFile(vertexShader);
+ program->addShaderFromSourceCode(QOpenGLShader::Vertex, builder.source());
+ builder.clear();
+
+ builder.appendSourceFile(fragmentShader);
+ program->addShaderFromSourceCode(QOpenGLShader::Fragment, builder.source());
+}
+
+QByteArray QSGShaderSourceBuilder::source() const
+{
+ return m_source;
+}
+
+void QSGShaderSourceBuilder::clear()
+{
+ m_source.clear();
+}
+
+void QSGShaderSourceBuilder::appendSource(const QByteArray &source)
+{
+ m_source += source;
+}
+
+void QSGShaderSourceBuilder::appendSourceFile(const QString &fileName)
+{
+ const QString resolvedFileName = resolveShaderPath(fileName);
+ QFile f(resolvedFileName);
+ if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ qWarning() << "Failed to find shader" << resolvedFileName;
+ return;
+ }
+ m_source += f.readAll();
+}
+
+void QSGShaderSourceBuilder::addDefinition(const QByteArray &definition)
+{
+ if (definition.isEmpty())
+ return;
+
+ Tokenizer tok;
+ const char *input = m_source.constData();
+ tok.initialize(input);
+
+ // First find #version, #extension's and "void main() { ... "
+ const char *versionPos = 0;
+ const char *extensionPos = 0;
+ bool inSingleLineComment = false;
+ bool inMultiLineComment = false;
+ bool foundVersionStart = false;
+ bool foundExtensionStart = false;
+
+ Tokenizer::Token lt = Tokenizer::Token_Unspecified;
+ Tokenizer::Token t = tok.next();
+ while (t != Tokenizer::Token_EOF) {
+ // Handle comment blocks
+ if (t == Tokenizer::Token_MultiLineCommentStart )
+ inMultiLineComment = true;
+ if (t == Tokenizer::Token_MultiLineCommentEnd)
+ inMultiLineComment = false;
+ if (t == Tokenizer::Token_SingleLineComment)
+ inSingleLineComment = true;
+ if (t == Tokenizer::Token_NewLine && inSingleLineComment && !inMultiLineComment)
+ inSingleLineComment = false;
+
+ // Have we found #version, #extension or void main()?
+ if (t == Tokenizer::Token_Version && !inSingleLineComment && !inMultiLineComment)
+ foundVersionStart = true;
+
+ if (t == Tokenizer::Token_Extension && !inSingleLineComment && !inMultiLineComment)
+ foundExtensionStart = true;
+
+ if (foundVersionStart && t == Tokenizer::Token_NewLine) {
+ versionPos = tok.pos;
+ foundVersionStart = false;
+ } else if (foundExtensionStart && t == Tokenizer::Token_NewLine) {
+ extensionPos = tok.pos;
+ foundExtensionStart = false;
+ } else if (lt == Tokenizer::Token_Void && t == Tokenizer::Token_Identifier) {
+ if (qstrncmp("main", tok.identifier, 4) == 0)
+ break;
+ }
+
+ // Scan to next token
+ lt = t;
+ t = tok.next();
+ }
+
+ // Determine where to insert the definition.
+ // If we found #extension directives, insert after last one,
+ // else, if we found #version insert after #version
+ // otherwise, insert at beginning.
+ const char *insertionPos = extensionPos ? extensionPos : (versionPos ? versionPos : input);
+
+ // Construct a new shader string, inserting the definition
+ QByteArray newSource;
+ newSource.reserve(m_source.size() + definition.size() + 9);
+ newSource += QByteArray::fromRawData(input, insertionPos - input);
+ newSource += QByteArrayLiteral("#define ") + definition + QByteArrayLiteral("\n");
+ newSource += QByteArray::fromRawData(insertionPos, m_source.size() - (insertionPos - input));
+
+ m_source = newSource;
+}
+
+void QSGShaderSourceBuilder::removeVersion()
+{
+ Tokenizer tok;
+ const char *input = m_source.constData();
+ tok.initialize(input);
+
+ // First find #version beginning and end (if present)
+ const char *versionStartPos = 0;
+ const char *versionEndPos = 0;
+ bool inSingleLineComment = false;
+ bool inMultiLineComment = false;
+ bool foundVersionStart = false;
+
+ Tokenizer::Token lt = Tokenizer::Token_Unspecified;
+ Tokenizer::Token t = tok.next();
+ while (t != Tokenizer::Token_EOF) {
+ // Handle comment blocks
+ if (t == Tokenizer::Token_MultiLineCommentStart )
+ inMultiLineComment = true;
+ if (t == Tokenizer::Token_MultiLineCommentEnd)
+ inMultiLineComment = false;
+ if (t == Tokenizer::Token_SingleLineComment)
+ inSingleLineComment = true;
+ if (t == Tokenizer::Token_NewLine && inSingleLineComment && !inMultiLineComment)
+ inSingleLineComment = false;
+
+ // Have we found #version, #extension or void main()?
+ if (t == Tokenizer::Token_Version && !inSingleLineComment && !inMultiLineComment) {
+ versionStartPos = tok.pos - 1;
+ foundVersionStart = true;
+ } else if (foundVersionStart && t == Tokenizer::Token_NewLine) {
+ versionEndPos = tok.pos;
+ break;
+ } else if (lt == Tokenizer::Token_Void && t == Tokenizer::Token_Identifier) {
+ if (qstrncmp("main", tok.identifier, 4) == 0)
+ break;
+ }
+
+ // Scan to next token
+ lt = t;
+ t = tok.next();
+ }
+
+ if (versionStartPos == 0)
+ return;
+
+ // Construct a new shader string, inserting the definition
+ QByteArray newSource;
+ newSource.reserve(m_source.size() - (versionEndPos - versionStartPos));
+ newSource += QByteArray::fromRawData(input, versionStartPos - input);
+ newSource += QByteArray::fromRawData(versionEndPos, m_source.size() - (versionEndPos - versionStartPos));
+
+ m_source = newSource;
+}
+
+QString QSGShaderSourceBuilder::resolveShaderPath(const QString &path) const
+{
+ if (contextProfile() != QSurfaceFormat::CoreProfile) {
+ return path;
+ } else {
+ int idx = path.lastIndexOf(QStringLiteral("."));
+ QString resolvedPath;
+ if (idx != -1)
+ resolvedPath = path.left(idx)
+ + QStringLiteral("_core")
+ + path.right(path.length() - idx);
+ return resolvedPath;
+ }
+}
+
+QSurfaceFormat::OpenGLContextProfile QSGShaderSourceBuilder::contextProfile() const
+{
+ QOpenGLContext *context = QOpenGLContext::currentContext();
+ QSurfaceFormat::OpenGLContextProfile profile = QSurfaceFormat::NoProfile;
+ Q_ASSERT(context);
+ profile = context->format().profile();
+ return profile;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/qsgflashnode.cpp b/src/quick/scenegraph/util/qsgshadersourcebuilder_p.h
index 7fbe673e15..63f2d78767 100644
--- a/src/quick/scenegraph/qsgflashnode.cpp
+++ b/src/quick/scenegraph/util/qsgshadersourcebuilder_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQuick module of the Qt Toolkit.
@@ -39,24 +39,44 @@
**
****************************************************************************/
-#include "qsgflashnode_p.h"
+#ifndef QSGSHADERSOURCEBUILDER_P_H
+#define QSGSHADERSOURCEBUILDER_P_H
+
+#include <private/qtquickglobal_p.h>
+
+#include <QtGui/qsurfaceformat.h>
+#include <QtCore/qbytearray.h>
QT_BEGIN_NAMESPACE
-QSGFlashNode::QSGFlashNode()
- : m_counter(1)
-{
- setFlag(UsePreprocess);
- setColor(QColor(rand()%56 + 200, rand()%56 + 200, rand()%156 + 100)); // A random, mostly yellow, color
-}
+class QOpenGLShaderProgram;
-void QSGFlashNode::preprocess()
+class Q_QUICK_PRIVATE_EXPORT QSGShaderSourceBuilder
{
- if (m_counter) {
- --m_counter;
- } else {
- delete this;
- }
-}
+public:
+ QSGShaderSourceBuilder();
+
+ static void initializeProgramFromFiles(QOpenGLShaderProgram *program,
+ const QString &vertexShader,
+ const QString &fragmentShader);
+
+ QByteArray source() const;
+ void clear();
+
+ void appendSource(const QByteArray &source);
+ void appendSourceFile(const QString &fileName);
+ void addDefinition(const QByteArray &definition);
+ void removeVersion();
+
+protected:
+ virtual QString resolveShaderPath(const QString &path) const;
+
+private:
+ QSurfaceFormat::OpenGLContextProfile contextProfile() const;
+
+ QByteArray m_source;
+};
QT_END_NAMESPACE
+
+#endif // QSGSHADERSOURCEBUILDER_P_H
diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp
index b079100a37..51b3bafaf7 100644
--- a/src/quick/scenegraph/util/qsgtexture.cpp
+++ b/src/quick/scenegraph/util/qsgtexture.cpp
@@ -682,16 +682,21 @@ void QSGPlainTexture::bind()
GLenum externalFormat = GL_RGBA;
GLenum internalFormat = GL_RGBA;
- const char *extensions = (const char *) glGetString(GL_EXTENSIONS);
- if (strstr(extensions, "GL_EXT_bgra")) {
+ QOpenGLContext *context = QOpenGLContext::currentContext();
+ if (context->hasExtension(QByteArrayLiteral("GL_EXT_bgra"))) {
externalFormat = GL_BGRA;
#ifdef QT_OPENGL_ES
internalFormat = GL_BGRA;
#endif
- } else if (strstr(extensions, "GL_EXT_texture_format_BGRA8888")
- || strstr(extensions, "GL_IMG_texture_format_BGRA8888")) {
+ } else if (context->hasExtension(QByteArrayLiteral("GL_EXT_texture_format_BGRA8888"))
+ || context->hasExtension(QByteArrayLiteral("GL_IMG_texture_format_BGRA8888"))) {
externalFormat = GL_BGRA;
internalFormat = GL_BGRA;
+#ifdef Q_OS_IOS
+ } else if (context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) {
+ externalFormat = GL_BGRA;
+ internalFormat = GL_RGBA;
+#endif
} else {
qsg_swizzleBGRAToRGBA(&tmp);
}
@@ -711,8 +716,7 @@ void QSGPlainTexture::bind()
if (m_has_mipmaps) {
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
- ctx->functions()->glGenerateMipmap(GL_TEXTURE_2D);
+ context->functions()->glGenerateMipmap(GL_TEXTURE_2D);
m_mipmaps_generated = true;
}
diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp
index ba98c83682..df55404504 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial.cpp
+++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp
@@ -54,36 +54,15 @@ inline static bool isPowerOfTwo(int x)
}
#endif
-const char qt_scenegraph_texture_material_vertex_code[] =
- "uniform highp mat4 qt_Matrix; \n"
- "attribute highp vec4 qt_VertexPosition; \n"
- "attribute highp vec2 qt_VertexTexCoord; \n"
- "varying highp vec2 qt_TexCoord; \n"
- "void main() { \n"
- " qt_TexCoord = qt_VertexTexCoord; \n"
- " gl_Position = qt_Matrix * qt_VertexPosition; \n"
- "}";
-
-const char qt_scenegraph_texture_material_fragment[] =
- "varying highp vec2 qt_TexCoord; \n"
- "uniform sampler2D qt_Texture; \n"
- "void main() { \n"
- " gl_FragColor = texture2D(qt_Texture, qt_TexCoord);\n"
- "}";
-
-
-const char *QSGOpaqueTextureMaterialShader::vertexShader() const
-{
- return qt_scenegraph_texture_material_vertex_code;
-}
+QSGMaterialType QSGOpaqueTextureMaterialShader::type;
-const char *QSGOpaqueTextureMaterialShader::fragmentShader() const
+QSGOpaqueTextureMaterialShader::QSGOpaqueTextureMaterialShader()
+ : QSGMaterialShader()
{
- return qt_scenegraph_texture_material_fragment;
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/opaquetexture.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/opaquetexture.frag"));
}
-QSGMaterialType QSGOpaqueTextureMaterialShader::type;
-
char const *const *QSGOpaqueTextureMaterialShader::attributeNames() const
{
static char const *const attr[] = { "qt_VertexPosition", "qt_VertexTexCoord", 0 };
@@ -353,14 +332,6 @@ int QSGOpaqueTextureMaterial::compare(const QSGMaterial *o) const
a material in the scene graph.
*/
-static const char qt_scenegraph_texture_material_opacity_fragment[] =
- "varying highp vec2 qt_TexCoord; \n"
- "uniform sampler2D qt_Texture; \n"
- "uniform lowp float opacity; \n"
- "void main() { \n"
- " gl_FragColor = texture2D(qt_Texture, qt_TexCoord) * opacity; \n"
- "}";
-
QSGMaterialType QSGTextureMaterialShader::type;
@@ -385,6 +356,12 @@ QSGMaterialShader *QSGTextureMaterial::createShader() const
return new QSGTextureMaterialShader;
}
+QSGTextureMaterialShader::QSGTextureMaterialShader()
+ : QSGOpaqueTextureMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/texture.frag"));
+}
+
void QSGTextureMaterialShader::updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
{
Q_ASSERT(oldEffect == 0 || newEffect->type() == oldEffect->type());
@@ -400,9 +377,4 @@ void QSGTextureMaterialShader::initialize()
m_opacity_id = program()->uniformLocation("opacity");
}
-const char *QSGTextureMaterialShader::fragmentShader() const
-{
- return qt_scenegraph_texture_material_opacity_fragment;
-}
-
QT_END_NAMESPACE
diff --git a/src/quick/scenegraph/util/qsgtexturematerial_p.h b/src/quick/scenegraph/util/qsgtexturematerial_p.h
index 077337d211..db65d85738 100644
--- a/src/quick/scenegraph/util/qsgtexturematerial_p.h
+++ b/src/quick/scenegraph/util/qsgtexturematerial_p.h
@@ -50,6 +50,8 @@ QT_BEGIN_NAMESPACE
class Q_QUICK_PRIVATE_EXPORT QSGOpaqueTextureMaterialShader : public QSGMaterialShader
{
public:
+ QSGOpaqueTextureMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
@@ -57,8 +59,6 @@ public:
protected:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_matrix_id;
};
@@ -66,14 +66,14 @@ protected:
class QSGTextureMaterialShader : public QSGOpaqueTextureMaterialShader
{
public:
+ QSGTextureMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual void initialize();
static QSGMaterialType type;
protected:
- virtual const char *fragmentShader() const;
-
int m_opacity_id;
};
diff --git a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
index f205f34ce4..ef2455f702 100644
--- a/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
+++ b/src/quick/scenegraph/util/qsgvertexcolormaterial.cpp
@@ -48,6 +48,8 @@ QT_BEGIN_NAMESPACE
class QSGVertexColorMaterialShader : public QSGMaterialShader
{
public:
+ QSGVertexColorMaterialShader();
+
virtual void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect);
virtual char const *const *attributeNames() const;
@@ -55,8 +57,6 @@ public:
private:
virtual void initialize();
- virtual const char *vertexShader() const;
- virtual const char *fragmentShader() const;
int m_matrix_id;
int m_opacity_id;
@@ -64,6 +64,13 @@ private:
QSGMaterialType QSGVertexColorMaterialShader::type;
+QSGVertexColorMaterialShader::QSGVertexColorMaterialShader()
+ : QSGMaterialShader()
+{
+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/scenegraph/shaders/vertexcolor.vert"));
+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/scenegraph/shaders/vertexcolor.frag"));
+}
+
void QSGVertexColorMaterialShader::updateState(const RenderState &state, QSGMaterial * /*newEffect*/, QSGMaterial *)
{
if (state.isOpacityDirty())
@@ -85,28 +92,6 @@ void QSGVertexColorMaterialShader::initialize()
m_opacity_id = program()->uniformLocation("opacity");
}
-const char *QSGVertexColorMaterialShader::vertexShader() const {
- return
- "attribute highp vec4 vertexCoord; \n"
- "attribute highp vec4 vertexColor; \n"
- "uniform highp mat4 matrix; \n"
- "uniform highp float opacity; \n"
- "varying lowp vec4 color; \n"
- "void main() { \n"
- " gl_Position = matrix * vertexCoord; \n"
- " color = vertexColor * opacity; \n"
- "}";
-}
-
-const char *QSGVertexColorMaterialShader::fragmentShader() const {
- return
- "varying lowp vec4 color; \n"
- "void main() { \n"
- " gl_FragColor = color; \n"
- "}";
-}
-
-
/*!
\class QSGVertexColorMaterial