diff options
Diffstat (limited to 'src/declarative/scenegraph/coreapi/qsgrenderer.cpp')
-rw-r--r-- | src/declarative/scenegraph/coreapi/qsgrenderer.cpp | 201 |
1 files changed, 164 insertions, 37 deletions
diff --git a/src/declarative/scenegraph/coreapi/qsgrenderer.cpp b/src/declarative/scenegraph/coreapi/qsgrenderer.cpp index 67575597ff..607c5b5b1f 100644 --- a/src/declarative/scenegraph/coreapi/qsgrenderer.cpp +++ b/src/declarative/scenegraph/coreapi/qsgrenderer.cpp @@ -43,12 +43,13 @@ #include "qsgnode.h" #include "qsgmaterial.h" #include "qsgnodeupdater_p.h" +#include "qsggeometry_p.h" #include "private/qsgadaptationlayer_p.h" -#include <QGLShaderProgram> -#include <qglframebufferobject.h> -#include <QtGui/qapplication.h> +#include <QOpenGLShaderProgram> +#include <qopenglframebufferobject.h> +#include <QtWidgets/qapplication.h> #include <qdatetime.h> @@ -80,7 +81,7 @@ void QSGBindable::reactivate() const glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } -QSGBindableFbo::QSGBindableFbo(QGLFramebufferObject *fbo) : m_fbo(fbo) +QSGBindableFbo::QSGBindableFbo(QOpenGLFramebufferObject *fbo) : m_fbo(fbo) { } @@ -130,6 +131,8 @@ QSGRenderer::QSGRenderer(QSGContext *context) , m_changed_emitted(false) , m_mirrored(false) , m_is_rendering(false) + , m_vertex_buffer_bound(false) + , m_index_buffer_bound(false) { initializeGLFunctions(); } @@ -206,7 +209,7 @@ void QSGRenderer::renderScene() class B : public QSGBindable { public: - void bind() const { QGLFramebufferObject::bindDefault(); } + void bind() const { QOpenGLFramebufferObject::bindDefault(); } } b; renderScene(b); } @@ -254,6 +257,16 @@ void QSGRenderer::renderScene(const QSGBindable &bindable) m_changed_emitted = false; m_bindable = 0; + if (m_vertex_buffer_bound) { + glBindBuffer(GL_ARRAY_BUFFER, 0); + m_vertex_buffer_bound = false; + } + + if (m_index_buffer_bound) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + m_index_buffer_bound = false; + } + #ifdef QSG_RENDERER_TIMING printf(" - Breakdown of frametime: preprocess=%d, updates=%d, binding=%d, render=%d, total=%d\n", preprocessTime, @@ -441,13 +454,13 @@ QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip) } else { if (!stencilEnabled) { if (!m_clip_program.isLinked()) { - m_clip_program.addShaderFromSourceCode(QGLShader::Vertex, + 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(QGLShader::Fragment, + m_clip_program.addShaderFromSourceCode(QOpenGLShader::Fragment, "void main() { \n" " gl_FragColor = vec4(0.81, 0.83, 0.12, 1.0); \n" // Trolltech green ftw! "}"); @@ -473,14 +486,17 @@ QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip) glStencilFunc(GL_EQUAL, clipDepth, 0xff); // stencil test, ref, test mask glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); // stencil fail, z fail, z pass - const QSGGeometry *geometry = clip->geometry(); - Q_ASSERT(geometry->attributeCount() > 0); - const QSGGeometry::Attribute *a = geometry->attributes(); - - glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, geometry->stride(), geometry->vertexData()); + const QSGGeometry *g = clip->geometry(); + Q_ASSERT(g->attributeCount() > 0); + const QSGGeometry::Attribute *a = g->attributes(); + glVertexAttribPointer(0, a->tupleSize, a->type, GL_FALSE, g->stride(), g->vertexData()); m_clip_program.setUniformValue(m_clip_matrix_id, m); - draw(clip); + if (g->indexCount()) { + glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData()); + } else { + glDrawArrays(g->drawingMode(), 0, g->vertexCount()); + } ++clipDepth; } @@ -507,25 +523,6 @@ QSGRenderer::ClipType QSGRenderer::updateStencilClip(const QSGClipNode *clip) } -/*! - Issues the GL draw call for \a geometryNode. - - The function assumes that attributes have been bound and set up prior - to making this call. - - \internal - */ - -void QSGRenderer::draw(const QSGBasicGeometryNode *node) -{ - const QSGGeometry *g = node->geometry(); - if (g->indexCount()) { - glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), g->indexData()); - } else { - glDrawArrays(g->drawingMode(), 0, g->vertexCount()); - } -} - static inline int size_of_type(GLenum type) { @@ -542,19 +539,102 @@ static inline int size_of_type(GLenum type) 4, sizeof(double) }; + Q_ASSERT(type >= GL_BYTE && type <= 0x140A); // the value of GL_DOUBLE return sizes[type - GL_BYTE]; } + +class QSGRendererVBOGeometryData : public QSGGeometryData +{ +public: + QSGRendererVBOGeometryData() + : vertexBuffer(0) + , indexBuffer(0) + { + } + + ~QSGRendererVBOGeometryData() + { + QOpenGLFunctions *func = QOpenGLContext::currentContext()->functions(); + if (vertexBuffer) + func->glDeleteBuffers(1, &vertexBuffer); + if (indexBuffer) + func->glDeleteBuffers(1, &indexBuffer); + } + + GLuint vertexBuffer; + GLuint indexBuffer; + + static QSGRendererVBOGeometryData *get(const QSGGeometry *g) { + QSGRendererVBOGeometryData *gd = static_cast<QSGRendererVBOGeometryData *>(QSGGeometryData::data(g)); + if (!gd) { + gd = new QSGRendererVBOGeometryData; + QSGGeometryData::install(g, gd); + } + return gd; + } + +}; + +static inline GLenum qt_drawTypeForPattern(QSGGeometry::DataPattern p) +{ + Q_ASSERT(p > 0 && p <= 3); + static GLenum drawTypes[] = { 0, + GL_STREAM_DRAW, + GL_DYNAMIC_DRAW, + GL_STATIC_DRAW + }; + return drawTypes[p]; +} + + /*! - Convenience function to set up and bind the vertex data in \a g to the - required attribute positions defined in \a material. + Issues the GL draw call for the geometry \a g using the material \a shader. + + The function assumes that attributes have been bound and set up prior + to making this call. \internal */ -void QSGRenderer::bindGeometry(QSGMaterialShader *material, const QSGGeometry *g) +void QSGRenderer::draw(const QSGMaterialShader *shader, const QSGGeometry *g) { - char const *const *attrNames = material->attributeNames(); + // ### remove before final release... + static bool use_vbo = !QApplication::arguments().contains("--no-vbo"); + + const void *vertexData; + int vertexByteSize = g->vertexCount() * g->stride(); + if (use_vbo && g->vertexDataPattern() != QSGGeometry::AlwaysUploadPattern && vertexByteSize > 1024) { + + // The base pointer for a VBO is 0 + vertexData = 0; + + bool updateData = QSGGeometryData::hasDirtyVertexData(g); + QSGRendererVBOGeometryData *gd = QSGRendererVBOGeometryData::get(g); + if (!gd->vertexBuffer) { + glGenBuffers(1, &gd->vertexBuffer); + updateData = true; + } + + glBindBuffer(GL_ARRAY_BUFFER, gd->vertexBuffer); + m_vertex_buffer_bound = true; + + if (updateData) { + glBufferData(GL_ARRAY_BUFFER, vertexByteSize, g->vertexData(), + qt_drawTypeForPattern(g->vertexDataPattern())); + QSGGeometryData::clearDirtyVertexData(g); + } + + } else { + if (m_vertex_buffer_bound) { + glBindBuffer(GL_ARRAY_BUFFER, 0); + m_vertex_buffer_bound = false; + } + vertexData = g->vertexData(); + } + + // Bind the vertices to attributes... + char const *const *attrNames = shader->attributeNames(); int offset = 0; for (int j = 0; attrNames[j]; ++j) { if (!*attrNames[j]) @@ -562,15 +642,62 @@ void QSGRenderer::bindGeometry(QSGMaterialShader *material, const QSGGeometry *g Q_ASSERT_X(j < g->attributeCount(), "QSGRenderer::bindGeometry()", "Geometry lacks attribute required by material"); const QSGGeometry::Attribute &a = g->attributes()[j]; Q_ASSERT_X(j == a.position, "QSGRenderer::bindGeometry()", "Geometry does not have continuous attribute positions"); + #if defined(QT_OPENGL_ES_2) GLboolean normalize = a.type != GL_FLOAT; #else GLboolean normalize = a.type != GL_FLOAT && a.type != GL_DOUBLE; #endif - glVertexAttribPointer(a.position, a.tupleSize, a.type, normalize, g->stride(), (char *) g->vertexData() + offset); + glVertexAttribPointer(a.position, a.tupleSize, a.type, normalize, g->stride(), (char *) vertexData + offset); offset += a.tupleSize * size_of_type(a.type); } + + // Set up the indices... + const void *indexData; + if (use_vbo && g->indexDataPattern() != QSGGeometry::AlwaysUploadPattern && g->indexCount() > 512) { + + // Base pointer for a VBO is 0 + indexData = 0; + + bool updateData = QSGGeometryData::hasDirtyIndexData(g); + QSGRendererVBOGeometryData *gd = QSGRendererVBOGeometryData::get(g); + if (!gd->indexBuffer) { + glGenBuffers(1, &gd->indexBuffer); + updateData = true; + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gd->indexBuffer); + m_index_buffer_bound = true; + + if (updateData) { + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + g->indexCount() * (g->indexType() == GL_UNSIGNED_SHORT ? 2 : 4), + g->indexData(), + qt_drawTypeForPattern(g->indexDataPattern())); + QSGGeometryData::clearDirtyIndexData(g); + } + + } else { + if (m_index_buffer_bound) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + m_index_buffer_bound = false; + } + indexData = g->indexData(); + } + + + // draw the stuff... + if (g->indexCount()) { + glDrawElements(g->drawingMode(), g->indexCount(), g->indexType(), indexData); + } else { + glDrawArrays(g->drawingMode(), 0, g->vertexCount()); + } + + // We leave buffers bound for now... They will be reset by bind on next draw() or + // set back to 0 if next draw is not using VBOs + } + QT_END_NAMESPACE |