OpenGL glDrawArrays比glBegin慢

时间:2018-04-04 16:31:50

标签: c++ opengl

我一直在玩我的函数中的glDrawArrays。

由于某些原因,当使用glDrawArrays进行绘制时,我会下降大约400fps。

我打电话给我的打印功能2000次进行测试。

不确定为什么,因为我认为glDrawArrays可以做到这一点?

这是打印功能:

void Font::Print(const char* Text, int x, int y)
{
    int sLen, Loop;
    int Row, Col;
    float U, V, U1, V1;

    CurX = x;
    CurY = y;

    sLen = (int)strnlen(Text, BFG_MAXSTRING);


#ifdef ARRAYDRAW
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
#else
    glBegin(GL_QUADS);
#endif

    for (Loop = 0; Loop != sLen; ++Loop)
    {
        Row = (Text[Loop] - Base) / RowPitch;
        Col = (Text[Loop] - Base) - Row * RowPitch;

        U = Col * ColFactor;
        V = Row * RowFactor;
        U1 = U + ColFactor;
        V1 = V + RowFactor;

#ifdef ARRAYDRAW
        Vertex vert[] = {
            CurX, CurY,
            U, V1,

            CurX + CellX, CurY,
            U1, V1,

            CurX + CellX, CurY + CellY,
            U1, V,

            CurX, CurY + CellY,
            U, V
        };

        glVertexPointer(2, GL_INT, sizeof(Vertex), &vert[0].x);
        glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &vert[0].u);
        glDrawArrays(GL_QUADS, 0, 4);
#else
        glTexCoord2f(U, V1);  glVertex2i(CurX, CurY);
        glTexCoord2f(U1, V1);  glVertex2i(CurX + CellX, CurY);
        glTexCoord2f(U1, V); glVertex2i(CurX + CellX, CurY + CellY);
        glTexCoord2f(U, V); glVertex2i(CurX, CurY + CellY);
#endif


        CurX += Width[Text[Loop]];
    }

#ifdef ARRAYDRAW
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
#else
    glEnd();
#endi

2 个答案:

答案 0 :(得分:4)

使用OpenGL的主要性能问题之一是OpenGL调用的数量。这就是glDrawArrays变得方便的地方:如果你渲染一百万个三角形,那么大约有一百万个glVertex和类似的调用,但仍然只有几个使用glDrawArrays的调用

现在,在你的情况下,在循环中你只渲染一个四元组,并且两种方法的OpenGL调用数大致相同。这就是为什么你没有看到性能提升。

似乎你可以在没有任何循环的情况下做到这一点:

glVertexPointer(2, GL_INT, sizeof(Vertex), &vert[0].x);
glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), &vert[0].u);
glDrawArrays(GL_QUADS, 0, 4 * sLen); // <-- note

因此一次渲染所有四边形。我希望这会更高效。

更好的方法(在实践中实际使用的方法)是使用VBO's,因此只在GPU上复制顶点数据一次然后使用它。

答案 1 :(得分:1)

@lisyarus是对的。您的问题是您正在使用旨在使用缓冲区对象的接口,但您正在使用立即模式方法。

我在你对@lisyarus的评论中看到你说你不能使用缓冲区对象,因为你事先并不知道你的字符串。但是,这并非完全正确。我将在下面做出一些假设,这可能是也可能不正确,但它们应该指向正确的方向。

在您当前的示例中,您将为每个四边形发送一个绘图,表示字符串中的字符。基于此,我们至少知道这个字符串有多长。相反,让我们构建一个内存表示,然后批量绘制命令来处理字符串中的所有字符。

所以在开始时创建你的内存表示

Vertex* v = (Vertex*)malloc(sizeof(Vertex) * numOfVertexForString);

然后在你的循环中不发出任何GL函数调用。而是构建上面的内存缓冲区。然后在你的循环之后创建一个VBO并在一次调用中绘制所有的四边形。

GLuint vbo;
GLGenBuffers(1, &vbo);
GLBindBuffer(GL_VERTEX_ARRAY, vbo);
GLBufferData(GL_VERTEX_ARRAY, sizeof(Vertex) * numOfVertexInString, v, GL_STATIC_DRAW);

然后,最后绘制缓冲区对象的内容。

glDrawArray(GL_QUADS, 0, 4 * sLen);

使用任何图形库时,重点是减少您拨打的电话数量。因为这些呼叫通过驱动程序路由它们很慢。更糟糕的是,如果您的数据不是图形库需要驱动程序的格式,如果被迫翻译它。你无法避免驱动程序中发生的事情,但你可以避免你发送的电话数量。