2
\$\begingroup\$

I have an atomic counter in my fragment shader that my application reads after each drawcall. I am currently using glMapBufferRange with GL_MAP_READ_BIT set. This absolutely destroys my applications performance. To give you an idea of how often the atomic counter gets read, each drawcall consists of a million vertices.

\$\endgroup\$
4
  • \$\begingroup\$ Is it the atomic increment, or the buffer read, which seems to impact performance? You can determine this by removing one, then the other. \$\endgroup\$ Commented Feb 9, 2015 at 2:04
  • \$\begingroup\$ it`s the buffer read which affects the performance. The atomic increment has neglible impact. \$\endgroup\$
    – Andreas
    Commented Feb 9, 2015 at 10:15
  • \$\begingroup\$ I'm not posting this as an answer, because I'm just learning this part of OpenGL also, and kind-of making stuff up. That said -- two things to try might be: 1) would it be ok to read it only every, say 200 frames, and average? 2) maybe "ping-ponging" two or more buffers would help, since reading and drawing wouldn't necessarily block each other. Not sure what the change-and-read sequence recipe exactly should be... \$\endgroup\$ Commented Feb 9, 2015 at 19:16
  • 1
    \$\begingroup\$ I am going to try something similar to buffer ping-ponging to solve this. It seems that the problem is that each time I do this the CPU and GPU spend ages syncing. I am not sure I have the corrrect solution, but I will post it as soon as I get any positive results. \$\endgroup\$
    – Andreas
    Commented Feb 9, 2015 at 21:19

2 Answers 2

3
\$\begingroup\$

I solved the problem by binding the atomic counter to the GL_COPY_READ_BUFFER and using glCopyBufferSubData to copy the counter to a buffer bound to the GL_COPY_WRITE_BUFFER. Then I mapped the buffer with glMapBufferRange and set Gl_MAP_READ_BIT. This seemed to sync much better and for now it is sufficient for my use. I did not test glGetBufferSubdata, but that might work as well.

\$\endgroup\$
1
\$\begingroup\$

The reason it destroys your performance is that OpenGL commands are asynchronous, so when you try to read the atomic counter, the CPU freezes and waits until all the GPU's atomic-counter-buffer-related operations have completed.

It's basically like sending out an HTTP request and freezing the program until it returns.

There are 2 solutions:

  1. Read the data back asynchronously, as explained here. (That article doesn't cover reading back from the framebuffer. If that's something you want to do, then you can use Pixel Buffer Objects and Asynchronous Readbacks.)

  2. Don't read the data back. Instead, use OpenGL commands to modify the data however you like, and prepare it for its next draw call. Some useful techniques/commands are:

    • You can copy data between buffers with glCopyBufferSubData.
    • You can modify data however you like with compute shaders.
    • You can tell OpenGL to store various data from the rendering pipeline (e.g. fragment shader output) using Transform Feedback.
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .