Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Page 1 of 2 12 LastLast
Results 1 to 10 of 11

Thread: Optimizing rendering of rectangles

  1. #1
    Junior Member Newbie
    Join Date
    Sep 2015
    Posts
    6

    Optimizing rendering of rectangles

    I need to draw couple of millions of rectangles, and I would like to get some advice on optimization, because currently it gets very slow (can notice lag when starting, zooming or dragging). The code is as follows:

    Code :
        const GLfloat vertexes[] =
        {
            x,              y,              0.0,
            x + x_delta,    y,              0.0,
            x,              y + y_delta,    0.0,
            x + x_delta,    y + y_delta,    0.0,
        };
     
        int vertexLocation = m_program.attributeLocation("aVertex");
        m_program.enableAttributeArray(vertexLocation);
        m_program.setAttributeArray(vertexLocation, GL_FLOAT, vertexes, 3);
     
        const GLfloat colors[] =
        {
            0.2, 0.6, 1.0, 0.3,
            0.2, 0.6, 1.0, 0.3,
            0.2, 0.6, 1.0, 0.3,
            0.2, 0.6, 1.0, 0.3,
        };
        int colorLocation = m_program.attributeLocation("aColor");
        m_program.enableAttributeArray(colorLocation);
        m_program.setAttributeArray(colorLocation, GL_FLOAT, colors, 4);
     
        const GLushort indices[] =
        {
            0, 1, 2, // first triangle
            3, 3, 2, // second triangle
        };
     
        glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(indices[0]), GL_UNSIGNED_SHORT, indices);
     
        m_program.disableAttributeArray( vertexLocation );
        m_program.disableAttributeArray( colorLocation );

    These rectangles are actually very small and they appear as lines (code for drawing lines is almost the same), so to certain zoom level I draw only lines, still is very slow. I am not sure if such performance is ok when drawing so many of rectangles. Maybe I am expecting too much, or there is a mistake in code. Anyway, I would like to hear some hints on performance optimization.

    Already using glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE);, drawing only in 2D. All rectangles are of unique dimensions.

    Thanks you in advance.
    Last edited by Kozersky; 10-07-2015 at 08:00 AM.

  2. #2
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    3,008
    Calling glDrawElements() once per rectangle or line is very inefficient.

    Store the data for all of the rectangles (or lines) in one set of arrays and draw them all with a single glDrawElements() call.

  3. #3
    Junior Member Newbie
    Join Date
    Sep 2015
    Posts
    6
    Ok, code has been changed to (called only once):

    Code :
        int vertexLocation = m_program.attributeLocation("aVertex");
        m_program.enableAttributeArray(vertexLocation);
        m_program.setAttributeArray(vertexLocation, m_Vertexes.data());
     
        int colorLocation = m_program.attributeLocation("aColor");
        m_program.enableAttributeArray(colorLocation);
        m_program.setAttributeArray(colorLocation, m_Colors.data());
     
        glDrawElements(GL_TRIANGLES, m_Indices.size(), GL_UNSIGNED_SHORT, m_Indices.data());
     
        m_program.disableAttributeArray( vertexLocation );
        m_program.disableAttributeArray( colorLocation );

    And m_Vertextes, m_Colors, m_Indices are as follows (called every time data should be populated):

    Code :
        m_Vertexes[m_VertexesCounter++] = (QVector3D(static_cast<float>(x), static_cast<float>(y), 0.0));
        ...
        m_Colors[m_ColorsCounter++] = (QVector4D(0.5f, 0.5f, 0.5f, 1.0f));
        ...
        m_Indices[m_IndicesCounter++] = 0;
        ...

    It works faster, though I don"t see rectangles now. What can I be missing?
    Last edited by Kozersky; 10-07-2015 at 02:32 PM.

  4. #4
    Intern Newbie
    Join Date
    May 2015
    Posts
    37
    Just a side note.
    Quote Originally Posted by Kozersky View Post
    Code :
        const GLushort indices[] =
        {
            0, 1, 2, // first triangle
            3, 3, 2, // second triangle
        };
    Is this really what you want from the second triangle? 3, 3, 2 looks like a degenerate triangle which may or may not look like a line, depending on renderer.

  5. #5
    Junior Member Newbie
    Join Date
    Sep 2015
    Posts
    6
    Ah, sorry, that was a typo, code in fact looks like this:

    Code :
        const GLushort indices[] =
        {
            0, 1, 2, // first triangle
            1, 3, 2, // second triangle
        };

    But thanks for noticing.

  6. #6
    Intern Newbie
    Join Date
    May 2015
    Posts
    37
    If I understand correctly, your task is quite similar to mine, and the technique you may need is per-polygon (per-rect in your case) attributes.
    What version of OpenGL do you intend to use? The ease of use of what I`m going to describe largely depends on whether GL 3.0++ is available.

    [UPD:] However, in case your geometry doesn`t change each frame, a much simpler and 3.0-independent approach is possible.

  7. #7
    Junior Member Newbie
    Join Date
    Sep 2015
    Posts
    6
    I intend to use latest OpenGL version, this is a new project.

    PS: there is still a problem:
    It works faster, though I don"t see rectangles now. What can I be missing?
    I have also found some information regarding optimization, posting it here, hopefully someone can comment/find it useful:

    * don't store colors in array, calculate them in vertex shader;
    * use *_STRIP versions;
    * place vertices and indices in VBO.
    Last edited by Kozersky; 10-09-2015 at 10:27 AM.

  8. #8
    Intern Newbie
    Join Date
    May 2015
    Posts
    37
    Quote Originally Posted by Kozersky View Post
    * don't store colors in array, calculate them in vertex shader
    According to what I`ve seen in the code above, the color doesn`t need calculation since it`s static, and that gives you many options: you may pass it via uniform, you may use glDrawElementsInstanced (more on that below), and of course you may just hardcode the color into your shader.

    Quote Originally Posted by Kozersky View Post
    * use *_STRIP versions
    Not sure if this is relevant to your task.

    Quote Originally Posted by Kozersky View Post
    * place vertices and indices in VBO
    Certainly the most useful advice.
    If your scene has static geometry, you may upload it to the VRAM during initialization and then just tell the GPU to use it over and over each frame. If not, there are still many other approaches.
    One of these is to use a buffer texture to store dimensions for rectangles, one pixel for one rectangle: R = horizontal pos, G = vertical pos, B = width, A = height. Then, a single-rect VBO is created, with unit square dimensions and the desired color, and finally, glDrawElementsInstanced is called, with the number of copies equalling the number of rectangles desired.
    Inside the vertex shader, gl_InstanceID-th element of the buffer texture is read and proper dimensions are computed for a given rectangle.

  9. #9
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    3,008
    Quote Originally Posted by hidefromkgb View Post
    One of these is to use a buffer texture to store dimensions for rectangles, one pixel for one rectangle: R = horizontal pos, G = vertical pos, B = width, A = height. Then, a single-rect VBO is created, with unit square dimensions and the desired color, and finally, glDrawElementsInstanced is called, with the number of copies equalling the number of rectangles desired.
    Inside the vertex shader, gl_InstanceID-th element of the buffer texture is read and proper dimensions are computed for a given rectangle.
    There's no reason to use a buffer texture if you're using instancing. You can just use an instanced vertex attribute, which will be more efficient than a texture lookup.

    Buffer textures can be used to achieve the same effect as instancing without actually using instancing, e.g. because you need to support OpenGL versions which lack instancing, or because the overhead of using instancing turns out to be worse than the overhead of a texture lookup (which may be the case here; you'd have to test and compare).

  10. #10
    Intern Newbie
    Join Date
    May 2015
    Posts
    37
    GClements, granted, I forgot that part about IVAs =(
    By the way, does the GPU really issue a «true» lookup when dealing with a buffer texture?
    Last edited by hidefromkgb; 10-09-2015 at 02:52 PM.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •