PDA

View Full Version : Reading back data from texture. GPU -> CPU



Aliii
10-20-2016, 11:55 AM
I'm rendering stuff into a texture with an FBO every frame and I need to read that data. I mean I need the data on the CPU side. I tried to use glGetTexImage but it's horribly slow. (I tried it with a small texture like 10x10, it's still as slow.)
So what can I do? I don't actually need the whole texture just aggregated data about the pixels / colors. Also I don't need the data immediately after rendering, it's OK if I only get it in the next frame or even 2-3 frames later.

mhagain
10-20-2016, 01:09 PM
The best approach is to evaluate if what you are doing can be done without needing to read back at all. For example, you can calculate the average luminance of a scene for tonemapping by generating mipmaps for your texture; the 1x1 miplevel will contain the average and the end result is an operation that happens entirely on the GPU.

As you've discovered the performance of a read back is largely independent of data size. What actually happens is that normally the CPU and GPU operate asynchronously; doing a read back breaks that and instead the CPU must wait for all pending GPU commands to finish before it can continue processing - it's effectively the equivalent of putting a glFinish at that point in your code.

If you really must read back, the good news is that the fact that you don't need the data immediately means that there is a solution available. Instead of reading back to a system memory pointer, instead create a pixel buffer object (https://www.opengl.org/wiki/Pixel_Buffer_Object) (PBO) and read back to that. Then you can map the PBO and access the data.

Aliii
10-21-2016, 03:00 AM
The best approach is to evaluate if what you are doing can be done without needing to read back at all. For example, you can calculate the average luminance of a scene for tonemapping by generating mipmaps for your texture; the 1x1 miplevel will contain the average and the end result is an operation that happens entirely on the GPU.

As you've discovered the performance of a read back is largely independent of data size. What actually happens is that normally the CPU and GPU operate asynchronously; doing a read back breaks that and instead the CPU must wait for all pending GPU commands to finish before it can continue processing - it's effectively the equivalent of putting a glFinish at that point in your code.

If you really must read back, the good news is that the fact that you don't need the data immediately means that there is a solution available. Instead of reading back to a system memory pointer, instead create a pixel buffer object (https://www.opengl.org/wiki/Pixel_Buffer_Object) (PBO) and read back to that. Then you can map the PBO and access the data.

Thank you! I'm using a PBO now and it works without slowness. If I understand it correctly, the PBO has its data in the normal RAM because of the GL_STREAM_READ hint, and if I only map it after the glGetTexImage finished copying to it then it just returns a pointer without any waiting. Is that correct?

Are the mipmaps that accurate? Can I expect it with (almost) every implementation that a 1x1 miplevel from a large texture will contain the average color accurately?
Thanks!

mhagain
10-21-2016, 05:46 PM
Thank you! I'm using a PBO now and it works without slowness. If I understand it correctly, the PBO has its data in the normal RAM because of the GL_STREAM_READ hint, and if I only map it after the glGetTexImage finished copying to it then it just returns a pointer without any waiting. Is that correct?

Are the mipmaps that accurate? Can I expect it with (almost) every implementation that a 1x1 miplevel from a large texture will contain the average color accurately?
Thanks!

All of this is "it depends", unfortunately - OpenGL specifies functionality, not performance, and even within that there is sometimes some "looseness" so that vendors can do what works best with their hardware.

Having said that, the whole point of PBOs is to allow for asynchronous transfer of texture data between CPU and GPU. OpenGL doesn't specify which menory it's stored in so you need to assume that the driver isn't going to do something stupid. In general, provide the proper usage hints at creation time and you should do OK.

Likewise OpenGL doesn't actually specify the mipmap generation algorithm, nor how accurate they are. You can assume that for a mipmap to be actually usable that it's accurate within a reasonable level of tolerance: 5% or 10%.