aboutsummaryrefslogtreecommitdiffstats
path: root/src/declarative/scenegraph/coreapi/qsgrenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/declarative/scenegraph/coreapi/qsgrenderer.cpp')
-rw-r--r--src/declarative/scenegraph/coreapi/qsgrenderer.cpp201
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