Rename QDeclarative symbols to QQuick and QQml
[profile/ivi/qtdeclarative.git] / src / quick / scenegraph / coreapi / qsgdefaultrenderer.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #define GL_GLEXT_PROTOTYPES
44
45 #include "qsgdefaultrenderer_p.h"
46 #include "qsgmaterial.h"
47
48 #include <QtCore/qvarlengtharray.h>
49 #include <QtGui/qguiapplication.h>
50 #include <QtCore/qpair.h>
51 #include <QtCore/QElapsedTimer>
52
53 //#define FORCE_NO_REORDER
54
55 // #define RENDERER_DEBUG
56 #ifdef RENDERER_DEBUG
57 #define DEBUG_THRESHOLD 0
58 QElapsedTimer debugTimer;
59 int materialChanges;
60 int geometryNodesDrawn;
61 #endif
62
63 QT_BEGIN_NAMESPACE
64
65 static bool nodeLessThan(QSGNode *nodeA, QSGNode *nodeB)
66 {
67     if (nodeA->type() != nodeB->type())
68         return nodeA->type() < nodeB->type();
69     if (nodeA->type() != QSGNode::GeometryNodeType)
70         return nodeA < nodeB;
71     QSGGeometryNode *a = static_cast<QSGGeometryNode *>(nodeA);
72     QSGGeometryNode *b = static_cast<QSGGeometryNode *>(nodeA);
73
74     // Sort by clip...
75     if (a->clipList() != b->clipList())
76         return a->clipList() < b->clipList();
77
78     // Sort by material definition
79     QSGMaterialType *aDef = a->material()->type();
80     QSGMaterialType *bDef = b->material()->type();
81
82     if (aDef != bDef)
83         return aDef < bDef;
84
85     // Sort by material state
86     int cmp = a->material()->compare(b->material());
87     if (cmp != 0)
88         return cmp < 0;
89
90     return a->matrix() < b->matrix();
91 }
92
93 static bool nodeLessThanWithRenderOrder(QSGNode *nodeA, QSGNode *nodeB)
94 {
95     if (nodeA->type() != nodeB->type())
96         return nodeA->type() < nodeB->type();
97     if (nodeA->type() != QSGNode::GeometryNodeType)
98         return nodeA < nodeB;
99     QSGGeometryNode *a = static_cast<QSGGeometryNode *>(nodeA);
100     QSGGeometryNode *b = static_cast<QSGGeometryNode *>(nodeA);
101
102     // Sort by clip...
103     if (a->clipList() != b->clipList())
104         return a->clipList() < b->clipList();
105
106     // Sort by material definition
107     QSGMaterialType *aDef = a->material()->type();
108     QSGMaterialType *bDef = b->material()->type();
109
110     if (!(a->material()->flags() & QSGMaterial::Blending)) {
111         int aOrder = a->renderOrder();
112         int bOrder = b->renderOrder();
113         if (aOrder != bOrder)
114             return aOrder > bOrder;
115     }
116
117     if (aDef != bDef)
118         return aDef < bDef;
119
120     // Sort by material state
121     int cmp = a->material()->compare(b->material());
122     if (cmp != 0)
123         return cmp < 0;
124
125     return a->matrix() < b->matrix();
126 }
127
128
129 QSGDefaultRenderer::IndexNodePair::IndexNodePair(int i, QSGNode *node)
130     : QPair<int, QSGNode *>(i, node)
131 {
132 }
133
134 bool QSGDefaultRenderer::IndexNodePair::operator < (const QSGDefaultRenderer::IndexNodePair &other) const
135 {
136     return nodeLessThan(second, other.second);
137 }
138
139
140 QSGDefaultRenderer::IndexNodePairHeap::IndexNodePairHeap()
141     : v(64)
142 {
143 }
144
145 void QSGDefaultRenderer::IndexNodePairHeap::insert(const QSGDefaultRenderer::IndexNodePair &x)
146 {
147     int i = v.size();
148     v.add(x);
149     while (i != 0 && v.at(i) < v.at(parent(i))) {
150         qSwap(v.at(parent(i)), v.at(i));
151         i = parent(i);
152     }
153 }
154
155 QSGDefaultRenderer::IndexNodePair QSGDefaultRenderer::IndexNodePairHeap::pop()
156 {
157     IndexNodePair x = top();
158     if (v.size() > 1)
159         qSwap(v.first(), v.last());
160     v.pop_back();
161     int i = 0;
162     while (left(i) < v.size()) {
163         int low = left(i);
164         if (right(i) < v.size() && v.at(right(i)) < v.at(low))
165             low = right(i);
166         if (!(v.at(low) < v.at(i)))
167             break;
168         qSwap(v.at(i), v.at(low));
169         i = low;
170     }
171     return x;
172 }
173
174
175 QSGDefaultRenderer::QSGDefaultRenderer(QSGContext *context)
176     : QSGRenderer(context)
177     , m_opaqueNodes(64)
178     , m_transparentNodes(64)
179     , m_tempNodes(64)
180     , m_renderGroups(4)
181     , m_rebuild_lists(false)
182     , m_needs_sorting(false)
183     , m_sort_front_to_back(false)
184     , m_render_node_added(false)
185     , m_currentRenderOrder(1)
186 {
187     QStringList args = qApp->arguments();
188 #if defined(QML_RUNTIME_TESTING)
189     m_render_opaque_nodes = !args.contains(QLatin1String("--no-opaque-nodes"));
190     m_render_alpha_nodes = !args.contains(QLatin1String("--no-alpha-nodes"));
191 #endif
192 }
193
194 void QSGDefaultRenderer::nodeChanged(QSGNode *node, QSGNode::DirtyState state)
195 {
196     QSGRenderer::nodeChanged(node, state);
197
198     const quint32 rebuildBits = QSGNode::DirtyNodeAdded | QSGNode::DirtyNodeRemoved
199                                 | QSGNode::DirtyMaterial | QSGNode::DirtyOpacity
200                                 | QSGNode::DirtyForceUpdate | QSGNode::DirtyChildrenDoNotOverlap;
201
202     if (state & rebuildBits)
203         m_rebuild_lists = true;
204
205     if (state & (rebuildBits | QSGNode::DirtyClipList))
206         m_needs_sorting = true;
207 }
208
209 void QSGDefaultRenderer::render()
210 {
211 #if defined (QML_RUNTIME_TESTING)
212     static bool dumpTree = qApp->arguments().contains(QLatin1String("--dump-tree"));
213     if (dumpTree) {
214         printf("\n\n");
215         QSGNodeDumper::dump(rootNode());
216     }
217 #endif
218
219 #ifdef RENDERER_DEBUG
220     debugTimer.invalidate();
221     debugTimer.start();
222     geometryNodesDrawn = 0;
223     materialChanges = 0;
224 #endif
225
226     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
227     glDisable(GL_BLEND);
228
229     glFrontFace(isMirrored() ? GL_CW : GL_CCW);
230     glDisable(GL_CULL_FACE);
231
232     glEnable(GL_DEPTH_TEST);
233     glDepthMask(true);
234     glDepthFunc(GL_GREATER);
235 #if defined(QT_OPENGL_ES)
236     glClearDepthf(0);
237 #else
238     glClearDepth(0);
239 #endif
240
241     glDisable(GL_SCISSOR_TEST);
242     glClearColor(m_clear_color.redF(), m_clear_color.greenF(), m_clear_color.blueF(), m_clear_color.alphaF());
243
244 #ifdef RENDERER_DEBUG
245     int debugtimeSetup = debugTimer.elapsed();
246 #endif
247
248     bindable()->clear(clearMode());
249
250 #ifdef RENDERER_DEBUG
251     int debugtimeClear = debugTimer.elapsed();
252 #endif
253
254     QRect r = viewportRect();
255     glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
256     m_current_projection_matrix = projectionMatrix();
257     m_current_model_view_matrix.setToIdentity();
258
259     m_currentClip = 0;
260     glDisable(GL_STENCIL_TEST);
261
262     m_currentMaterial = 0;
263     m_currentProgram = 0;
264     m_currentMatrix = 0;
265
266     if (m_rebuild_lists) {
267         m_opaqueNodes.reset();
268         m_transparentNodes.reset();
269         m_renderGroups.reset();
270         m_currentRenderOrder = 1;
271         buildLists(rootNode());
272         m_rebuild_lists = false;
273         m_render_node_added = false;
274         RenderGroup group = { m_opaqueNodes.size(), m_transparentNodes.size() };
275         m_renderGroups.add(group);
276     }
277
278 #ifdef RENDERER_DEBUG
279     int debugtimeLists = debugTimer.elapsed();
280 #endif
281
282     if (m_needs_sorting) {
283         if (!m_opaqueNodes.isEmpty()) {
284             bool (*lessThan)(QSGNode *, QSGNode *);
285             lessThan = m_sort_front_to_back ? nodeLessThanWithRenderOrder : nodeLessThan;
286             int start = 0;
287             for (int i = 0; i < m_renderGroups.size(); ++i) {
288                 int end = m_renderGroups.at(i).opaqueEnd;
289                 if (end != start)
290                     qSort(&m_opaqueNodes.first() + start, &m_opaqueNodes.first() + end, lessThan);
291                 start = end;
292             }
293         }
294         m_needs_sorting = false;
295     }
296
297 #ifdef RENDERER_DEBUG
298     int debugtimeSorting = debugTimer.elapsed();
299 #endif
300
301     m_renderOrderMatrix.setToIdentity();
302     m_renderOrderMatrix.scale(1, 1, qreal(1) / m_currentRenderOrder);
303
304     int opaqueStart = 0;
305     int transparentStart = 0;
306     for (int i = 0; i < m_renderGroups.size(); ++i) {
307         int opaqueEnd = m_renderGroups.at(i).opaqueEnd;
308         int transparentEnd = m_renderGroups.at(i).transparentEnd;
309
310         glDisable(GL_BLEND);
311         glDepthMask(true);
312 #ifdef QML_RUNTIME_TESTING
313         if (m_render_opaque_nodes)
314 #endif
315         {
316 #if defined (QML_RUNTIME_TESTING)
317             if (dumpTree)
318                 qDebug() << "Opaque Nodes:";
319 #endif
320             if (opaqueEnd != opaqueStart)
321                 renderNodes(&m_opaqueNodes.first() + opaqueStart, opaqueEnd - opaqueStart);
322         }
323
324         glEnable(GL_BLEND);
325         glDepthMask(false);
326 #ifdef QML_RUNTIME_TESTING
327         if (m_render_alpha_nodes)
328 #endif
329         {
330 #if defined (QML_RUNTIME_TESTING)
331             if (dumpTree)
332                 qDebug() << "Alpha Nodes:";
333 #endif
334             if (transparentEnd != transparentStart)
335                 renderNodes(&m_transparentNodes.first() + transparentStart, transparentEnd - transparentStart);
336         }
337
338         opaqueStart = opaqueEnd;
339         transparentStart = transparentEnd;
340     }
341
342 #ifdef RENDERER_DEBUG
343     int debugtimeRender = debugTimer.elapsed();
344 #endif
345
346     if (m_currentProgram)
347         m_currentProgram->deactivate();
348
349 #ifdef RENDERER_DEBUG
350     if (debugTimer.elapsed() > DEBUG_THRESHOLD) {
351         printf(" --- Renderer breakdown:\n"
352                "     - setup=%d, clear=%d, building=%d, sorting=%d, render=%d\n"
353                "     - material changes: total=%d\n"
354                "     - geometry nodes: total=%d\n",
355                debugtimeSetup,
356                debugtimeClear - debugtimeSetup,
357                debugtimeLists - debugtimeClear,
358                debugtimeSorting - debugtimeLists,
359                debugtimeRender - debugtimeSorting,
360                materialChanges,
361                geometryNodesDrawn);
362     }
363 #endif
364
365 }
366
367 void QSGDefaultRenderer::setSortFrontToBackEnabled(bool sort)
368 {
369     printf("setting sorting to... %d\n", sort);
370     m_sort_front_to_back = sort;
371 }
372
373 bool QSGDefaultRenderer::isSortFrontToBackEnabled() const
374 {
375     return m_sort_front_to_back;
376 }
377
378 void QSGDefaultRenderer::buildLists(QSGNode *node)
379 {
380     if (node->isSubtreeBlocked())
381         return;
382
383     if (node->type() == QSGNode::GeometryNodeType) {
384         QSGGeometryNode *geomNode = static_cast<QSGGeometryNode *>(node);
385         qreal opacity = geomNode->inheritedOpacity();
386         QSGMaterial *m = geomNode->activeMaterial();
387
388 #ifdef FORCE_NO_REORDER
389         if (true) {
390 #else
391         if ((m->flags() & QSGMaterial::Blending) || opacity < 1) {
392 #endif
393             geomNode->setRenderOrder(m_currentRenderOrder - 1);
394             m_transparentNodes.add(geomNode);
395         } else {
396             if (m_render_node_added) {
397                 // Start new group of nodes so that this opaque node is render on top of the
398                 // render node.
399                 RenderGroup group = { m_opaqueNodes.size(), m_transparentNodes.size() };
400                 m_renderGroups.add(group);
401                 m_render_node_added = false;
402             }
403             geomNode->setRenderOrder(m_currentRenderOrder);
404             m_opaqueNodes.add(geomNode);
405             m_currentRenderOrder += 2;
406         }
407     } else if (node->type() == QSGNode::RenderNodeType) {
408         QSGRenderNode *renderNode = static_cast<QSGRenderNode *>(node);
409         m_transparentNodes.add(renderNode);
410         m_render_node_added = true;
411     }
412
413     if (!node->firstChild())
414         return;
415
416 #ifdef FORCE_NO_REORDER
417     static bool reorder = false;
418 #else
419     static bool reorder = qApp->arguments().contains(QLatin1String("--reorder"));
420 #endif
421
422     if (reorder && node->firstChild() != node->lastChild() && (node->flags() & QSGNode::ChildrenDoNotOverlap)) {
423         QVarLengthArray<int, 16> beginIndices;
424         QVarLengthArray<int, 16> endIndices;
425         int baseCount = m_transparentNodes.size();
426         int baseGroupCount = m_renderGroups.size();
427         int count = 0;
428         for (QSGNode *c = node->firstChild(); c; c = c->nextSibling()) {
429             beginIndices.append(m_transparentNodes.size());
430             buildLists(c);
431             endIndices.append(m_transparentNodes.size());
432             ++count;
433         }
434
435         int childNodeCount = m_transparentNodes.size() - baseCount;
436         // Don't reorder if new render groups were added.
437         if (m_renderGroups.size() == baseGroupCount && childNodeCount) {
438             m_tempNodes.reset();
439             m_tempNodes.reserve(childNodeCount);
440             while (childNodeCount) {
441                 for (int i = 0; i < count; ++i) {
442                     if (beginIndices[i] != endIndices[i])
443                         m_heap.insert(IndexNodePair(i, m_transparentNodes.at(beginIndices[i]++)));
444                 }
445                 while (!m_heap.isEmpty()) {
446                     IndexNodePair pair = m_heap.pop();
447                     m_tempNodes.add(pair.second);
448                     --childNodeCount;
449                     int i = pair.first;
450                     if (beginIndices[i] != endIndices[i] && !nodeLessThan(m_transparentNodes.at(beginIndices[i]), pair.second))
451                         m_heap.insert(IndexNodePair(i, m_transparentNodes.at(beginIndices[i]++)));
452                 }
453             }
454             Q_ASSERT(m_tempNodes.size() == m_transparentNodes.size() - baseCount);
455
456             qMemCopy(&m_transparentNodes.at(baseCount), &m_tempNodes.at(0), m_tempNodes.size() * sizeof(QSGGeometryNode *));
457         }
458     } else {
459         for (QSGNode *c = node->firstChild(); c; c = c->nextSibling())
460             buildLists(c);
461     }
462 }
463
464 void QSGDefaultRenderer::renderNodes(QSGNode *const *nodes, int count)
465 {
466     const float scale = 1.0f / m_currentRenderOrder;
467     int currentRenderOrder = 0x80000000;
468     ClipType currentClipType = NoClip;
469     QMatrix4x4 projection = projectionMatrix();
470     m_current_projection_matrix.setColumn(2, scale * projection.column(2));
471
472     //int clipChangeCount = 0;
473     //int programChangeCount = 0;
474     //int materialChangeCount = 0;
475
476     for (int i = 0; i < count; ++i) {
477         if (nodes[i]->type() == QSGNode::RenderNodeType) {
478             QSGRenderNode *renderNode = static_cast<QSGRenderNode *>(nodes[i]);
479
480             if (m_currentProgram)
481                 m_currentProgram->deactivate();
482             m_currentMaterial = 0;
483             m_currentProgram = 0;
484             m_currentMatrix = 0;
485             currentRenderOrder = 0x80000000;
486
487             bool changeClip = renderNode->clipList() != m_currentClip;
488             // The clip function relies on there not being any depth testing..
489             glDisable(GL_DEPTH_TEST);
490             if (changeClip) {
491                 currentClipType = updateStencilClip(renderNode->clipList());
492                 m_currentClip = renderNode->clipList();
493                 //++clipChangeCount;
494             }
495
496             glDepthMask(false);
497             glBindBuffer(GL_ARRAY_BUFFER, 0);
498             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
499
500             QSGRenderNode::RenderState state;
501             state.projectionMatrix = &projection;
502             state.scissorEnabled = currentClipType & ScissorClip;
503             state.stencilEnabled = currentClipType & StencilClip;
504             state.scissorRect = m_current_scissor_rect;
505             state.stencilValue = m_current_stencil_value;
506
507             renderNode->render(state);
508
509             QSGRenderNode::StateFlags changes = renderNode->changedStates();
510             if (changes & QSGRenderNode::ViewportState) {
511                 QRect r = viewportRect();
512                 glViewport(r.x(), deviceRect().bottom() - r.bottom(), r.width(), r.height());
513             }
514             if (changes & QSGRenderNode::StencilState) {
515                 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
516                 glStencilMask(0xff);
517                 glDisable(GL_STENCIL_TEST);
518             }
519             if (changes & (QSGRenderNode::StencilState | QSGRenderNode::ScissorState)) {
520                 glDisable(GL_SCISSOR_TEST);
521                 m_currentClip = 0;
522                 currentClipType = NoClip;
523             }
524             if (changes & QSGRenderNode::DepthState) {
525 #if defined(QT_OPENGL_ES)
526                 glClearDepthf(0);
527 #else
528                 glClearDepth(0);
529 #endif
530                 if (m_clear_mode & QSGRenderer::ClearDepthBuffer) {
531                     glDepthMask(true);
532                     glClear(GL_DEPTH_BUFFER_BIT);
533                 }
534                 glDepthMask(false);
535                 glDepthFunc(GL_GREATER);
536             }
537             if (changes & QSGRenderNode::ColorState)
538                 bindable()->reactivate();
539             if (changes & QSGRenderNode::BlendState) {
540                 glEnable(GL_BLEND);
541                 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
542             }
543             if (changes & QSGRenderNode::CullState) {
544                 glFrontFace(isMirrored() ? GL_CW : GL_CCW);
545                 glDisable(GL_CULL_FACE);
546             }
547
548             glEnable(GL_DEPTH_TEST);
549
550             m_current_model_view_matrix.setToIdentity();
551             m_current_determinant = 1;
552         } else if (nodes[i]->type() == QSGNode::GeometryNodeType) {
553             QSGGeometryNode *geomNode = static_cast<QSGGeometryNode *>(nodes[i]);
554
555             QSGMaterialShader::RenderState::DirtyStates updates;
556
557 #if defined (QML_RUNTIME_TESTING)
558             static bool dumpTree = qApp->arguments().contains(QLatin1String("--dump-tree"));
559             if (dumpTree)
560                 qDebug() << geomNode;
561 #endif
562
563             bool changeMatrix = m_currentMatrix != geomNode->matrix();
564
565             if (changeMatrix) {
566                 m_currentMatrix = geomNode->matrix();
567                 if (m_currentMatrix)
568                     m_current_model_view_matrix = *m_currentMatrix;
569                 else
570                     m_current_model_view_matrix.setToIdentity();
571                 m_current_determinant = m_current_model_view_matrix.determinant();
572                 updates |= QSGMaterialShader::RenderState::DirtyMatrix;
573             }
574
575             bool changeOpacity = m_current_opacity != geomNode->inheritedOpacity();
576             if (changeOpacity) {
577                 updates |= QSGMaterialShader::RenderState::DirtyOpacity;
578                 m_current_opacity = geomNode->inheritedOpacity();
579             }
580
581             Q_ASSERT(geomNode->activeMaterial());
582
583             QSGMaterial *material = geomNode->activeMaterial();
584             QSGMaterialShader *program = m_context->prepareMaterial(material);
585             Q_ASSERT(program->program()->isLinked());
586
587             bool changeClip = geomNode->clipList() != m_currentClip;
588             if (changeClip) {
589                 // The clip function relies on there not being any depth testing..
590                 glDisable(GL_DEPTH_TEST);
591                 currentClipType = updateStencilClip(geomNode->clipList());
592                 glEnable(GL_DEPTH_TEST);
593                 m_currentClip = geomNode->clipList();
594 #ifdef FORCE_NO_REORDER
595                 glDepthMask(false);
596 #else
597                 glDepthMask((material->flags() & QSGMaterial::Blending) == 0 && m_current_opacity == 1);
598 #endif
599                 //++clipChangeCount;
600             }
601
602             bool changeProgram = (changeClip && (currentClipType & StencilClip)) || m_currentProgram != program;
603             if (changeProgram) {
604                 if (m_currentProgram)
605                     m_currentProgram->deactivate();
606                 m_currentProgram = program;
607                 m_currentProgram->activate();
608                 //++programChangeCount;
609                 updates |= (QSGMaterialShader::RenderState::DirtyMatrix | QSGMaterialShader::RenderState::DirtyOpacity);
610
611 #ifdef RENDERER_DEBUG
612                 materialChanges++;
613 #endif
614             }
615
616             bool changeRenderOrder = currentRenderOrder != geomNode->renderOrder();
617             if (changeRenderOrder) {
618                 currentRenderOrder = geomNode->renderOrder();
619                 m_current_projection_matrix.setColumn(3, projection.column(3)
620                                                       + currentRenderOrder
621                                                       * m_current_projection_matrix.column(2));
622                 updates |= QSGMaterialShader::RenderState::DirtyMatrix;
623             }
624
625             if (changeProgram || m_currentMaterial != material) {
626                 program->updateState(state(updates), material, changeProgram ? 0 : m_currentMaterial);
627                 m_currentMaterial = material;
628                 //++materialChangeCount;
629             }
630
631             //glDepthRange((geomNode->renderOrder() + 0.1) * scale, (geomNode->renderOrder() + 0.9) * scale);
632
633             const QSGGeometry *g = geomNode->geometry();
634             draw(program, g);
635
636 #ifdef RENDERER_DEBUG
637             geometryNodesDrawn++;
638 #endif
639         }
640     }
641     //qDebug("Clip: %i, shader program: %i, material: %i times changed while drawing %s items",
642     //    clipChangeCount, programChangeCount, materialChangeCount,
643     //    &list == &m_transparentNodes ? "transparent" : "opaque");
644 }
645
646 QT_END_NAMESPACE