1
\$\begingroup\$

I'm trying to improve the draw performance on my c++, OpenGL, SDL game.

Back in school we mostly learned immediate mode, so that's how my drawing was originally implemented. When I started reading up online about improving performance, I read about VBOs and how they are 'so much better' and use the graphics card memory, etc.

So I took a couple of nights and converted to them. When I tested the game, it actually ran slower (draw method went from ~7 to ~10 ticks).

Did I do something wrong or are VBOs only more efficient in certain situations?

Here's my class for tessellated polygons after adding VBOs (my game draws a lot of flat 2D shapes in a 3D world, sort of papermario-style)

#include "Tesselator.h" Tesselator::Tesselator(std::vector<b2Vec2> vertices, Gradient* gradient) { this->vertices = vertices; this->gradient = gradient; tesselator = gluNewTess(); gluTessCallback(tesselator, GLU_TESS_BEGIN_DATA, (void(CALLBACK*)())beginCallback); gluTessCallback(tesselator, GLU_TESS_VERTEX_DATA, (void(CALLBACK*)())vertexCallback); gluTessCallback(tesselator, GLU_TESS_END, (void(CALLBACK*)())endCallback); int vertcount = (int)vertices.size(); GLdouble vertarray[vertcount][3]; for (int i = 0; i < vertices.size(); i++) { vertarray[i][0] = vertices[i].x; vertarray[i][1] = vertices[i].y; vertarray[i][2] = 0; } gluTessBeginPolygon(tesselator, this); gluTessBeginContour(tesselator); for (int i = 0; i < vertices.size(); i++) { gluTessVertex(tesselator, vertarray[i], vertarray[i]); } gluTessEndContour(tesselator); gluTessEndPolygon(tesselator); gluDeleteTess(tesselator); for (int i = 0; i < triangles.size(); i++) { triangleVBOs.push_back(new VertexBufferObject(triangles[i])); } for (int i = 0; i < trianglefans.size(); i++) { triangleFanVBOs.push_back(new VertexBufferObject(trianglefans[i])); } for (int i = 0; i < trianglestrips.size(); i++) { triangleStripVBOs.push_back(new VertexBufferObject(trianglestrips[i])); } } Tesselator::~Tesselator() { for (int i = 0; i < triangleVBOs.size(); i++) { delete triangleVBOs[i]; } for (int i = 0; i < triangleFanVBOs.size(); i++) { delete triangleFanVBOs[i]; } for (int i = 0; i < triangleStripVBOs.size(); i++) { delete triangleStripVBOs[i]; } triangleVBOs.clear(); triangleFanVBOs.clear(); triangleStripVBOs.clear(); } void Tesselator::draw(float z) { Drawing::applyZTranslation(z); for (int i = 0; i < triangleVBOs.size(); i++) { triangleVBOs[i]->draw(GL_TRIANGLES); } for (int i = 0; i < triangleFanVBOs.size(); i++) { triangleFanVBOs[i]->draw(GL_TRIANGLE_FAN); } for (int i = 0; i < triangleStripVBOs.size(); i++) { triangleStripVBOs[i]->draw(GL_TRIANGLE_STRIP); } Drawing::applyZTranslation(-z); } void Tesselator::addTriangle() { std::vector<b2Vec2> triangleVertices; triangles.push_back(triangleVertices); } void Tesselator::addTriangleFan() { std::vector<b2Vec2> triangleFanVertices; trianglefans.push_back(triangleFanVertices); } void Tesselator::addTriangleStrip() { std::vector<b2Vec2> triangleStripVertices; trianglestrips.push_back(triangleStripVertices); } void Tesselator::addVertex(b2Vec2 vertex) { if (currentType == GL_TRIANGLES) { triangles.back().push_back(b2Vec2(vertex.x, vertex.y)); } else if (currentType == GL_TRIANGLE_FAN) { trianglefans.back().push_back(b2Vec2(vertex.x, vertex.y)); } else if (currentType == GL_TRIANGLE_STRIP) { trianglestrips.back().push_back(b2Vec2(vertex.x, vertex.y)); } } void CALLBACK Tesselator::beginCallback(GLenum type, GLvoid * tessdata) { Tesselator* tess = (Tesselator*) tessdata; tess->currentType = type; if (type == GL_TRIANGLES) { tess->addTriangle(); } else if (type == GL_TRIANGLE_FAN) { tess->addTriangleFan(); } else if (type == GL_TRIANGLE_STRIP) { tess->addTriangleStrip(); } } void CALLBACK Tesselator::vertexCallback(GLdouble* vertex, GLvoid* tessdata) { Tesselator* tess = (Tesselator*) tessdata; tess->addVertex(b2Vec2(*(vertex), *(vertex + 1))); } void CALLBACK Tesselator::endCallback() { } 

and here is my vertex buffer object class

#include "VertexBufferObject.h" VertexBufferObject::VertexBufferObject(std::vector<b2Vec2> shapeVertices) { numberOfCoordinateValues = 0; for (int i = 0; i < shapeVertices.size(); i++) { numberOfCoordinateValues = numberOfCoordinateValues + 2; } float coordinateValues[numberOfCoordinateValues]; int coordinateValueArrayIndex = 0; for (int i = 0; i < shapeVertices.size(); i++) { coordinateValues[coordinateValueArrayIndex] = shapeVertices[i].x; coordinateValueArrayIndex++; coordinateValues[coordinateValueArrayIndex] = shapeVertices[i].y; coordinateValueArrayIndex++; } glGenBuffers(1, &id); glBindBuffer(GL_ARRAY_BUFFER, id); glBufferData(GL_ARRAY_BUFFER, sizeof(coordinateValues), coordinateValues, GL_STATIC_DRAW); } VertexBufferObject::~VertexBufferObject() { glDeleteBuffers(1, &id); } void VertexBufferObject::draw(GLenum mode) { glBindBuffer(GL_ARRAY_BUFFER, id); glVertexPointer(2, GL_FLOAT, 0, NULL); glEnableClientState(GL_VERTEX_ARRAY); glDrawArrays(mode, 0, numberOfCoordinateValues/2); glDisableClientState(GL_VERTEX_ARRAY); glBindBuffer(GL_ARRAY_BUFFER, 0); } 

and heres what the draw method for Tesselator used to look like before adding VBOs

void Tesselator::draw(float z) { for (int i = 0; i < triangles.size(); i++) { Drawing::drawTriangles(triangles[i], z, gradient); } for (int i = 0; i < trianglefans.size(); i++) { Drawing::drawTriangleFan(trianglefans[i], z, gradient); } for (int i = 0; i < trianglestrips.size(); i++) { Drawing::drawTriangleStrip(trianglestrips[i], z, gradient); } } 

and in Drawing.cpp:

void Drawing::drawTriangles(std::vector<b2Vec2> vertices, float z, Gradient* gradient) { glBegin(GL_TRIANGLES); for (int i = 0; i < vertices.size(); i++) { addVertex(vertices[i].x, vertices[i].y, z, gradient); } glEnd(); } void Drawing::drawTriangleFan(std::vector<b2Vec2> vertices, float z, Gradient* gradient) { glBegin(GL_TRIANGLE_FAN); for (int i = 0; i < vertices.size(); i++) { addVertex(vertices[i].x, vertices[i].y, z, gradient); } glEnd(); } void Drawing::drawTriangleStrip(std::vector<b2Vec2> vertices, float z, Gradient* gradient) { glBegin(GL_TRIANGLE_STRIP); for (int i = 0; i < vertices.size(); i++) { addVertex(vertices[i].x, vertices[i].y, z, gradient); } glEnd(); } 
\$\endgroup\$
0

2 Answers 2

-1
\$\begingroup\$

glBegin(GL_TRIANGLES);

You ar still using old school glBegin/glEnd for drawing, this is not going to be faster.

You need to bind the buffer, push data to the VBO after changing it, and then draw with said buffer. This will most likely decrease your drawtime. Also, try and find geometry that does not change and create a static VBO for all that data, push it to the gpu. Now you only need to bind the buffer and draw it.

[1] - https://en.wikipedia.org/wiki/Vertex_Buffer_Object

\$\endgroup\$
10
  • 1
    \$\begingroup\$ I think you misread the post. You are reading from the part of my code that was replaced \$\endgroup\$ Commented Feb 21, 2016 at 20:39
  • \$\begingroup\$ I only posted the old code before implementing VBOs for comparison "and heres what the draw method for Tesselator used to look like before adding VBOs... and in Drawing.cpp:" \$\endgroup\$ Commented Feb 21, 2016 at 20:44
  • 2
    \$\begingroup\$ That is correct, I totally missed the text in between explaning before and after - sorry! Going from glBegin/glEnd to glBindBuffer et al and not decreasing the time it takes to render is wierd. It is really hard to say what might cause this. \$\endgroup\$ Commented Feb 21, 2016 at 22:03
  • 1
    \$\begingroup\$ Those functions are all deprecated since 3+ core as can be read in the Wikipedia article about OpenGL. I guess adding an color to your vertices could help, or just for debugging - change clear color to non-black; this should give you black lines when rendering. \$\endgroup\$ Commented Feb 22, 2016 at 6:55
  • 1
    \$\begingroup\$ I recommend downloading a OpenGL debugger such as CodeXL by AMD. It's hard to give any further advice without knowing more about the code of your program in general. There might be something that is slowing things down that is not directly related to VBOs. \$\endgroup\$ Commented Feb 22, 2016 at 7:51
-1
\$\begingroup\$

A lot of people think, that every aspect of the VBOs are fast, that's not really true. Binding a VBO is very slow. Always make sure, you bind VBOs one time, then render the same model multiple times with different position, rotation, etc.

\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.