I'm currently working on an algorithm which creates a texture within a render buffer. The operations are pretty complex, but for the GPU this is a simple task, done very quickly.
The problem is that, after creating the texture, i would like to save it. This requires to extract it from GPU memory.
For this operation, i'm using glGetTexImage(). It works, but the performance is sluggish. No, i mean even slower than that. For example, an 8MB texture (uncompressed) requires 3 seconds (yes, seconds) to be extracted. That's mind puzzling. I'm almost wondering if my graphic card is connected by a serial link...
Anyway, i've looked around, and found some people complaining about the same, but no working solution so far. The most promising advise was to "extract data in the native format of the GPU". Which i've tried and tried, but failed so far.
Edit : by moving the call to glGetTexImage() in a different place, the speed has been a bit improved for the most dramatic samples : looking again at the 8MB texture, it knows requires 500ms, instead of 3sec. It's better, but still much too slow. Smaller texture sizes were not affected by the change (typical timing remained into the 60-80ms range).
Using glFinish() didn't help either. Note that, if i call glFinish() (without glGetTexImage), i'm getting a fixed 16ms result, whatever the texture size or complexity. It really looks like the timing for a frame at 60fps.
The timing is measured for the full rendering + saving sequence. The call to glGetTexImage() alone does not really matter. That being said, it is this call which changes the performance.
And yes, of course, as stated at the beginning, the texture is "created into the GPU", hence the need to save it.
Edit 2 : I've also tried to use glReadPixels(), instead of glGetTexImage(). But it's worse unfortunately. Approximately twice slower.
Edit 3 : Here is the code. Note that it uses a "framework" that i've not developed. So some of the function calls here are not OpenGL standard. But they are nonetheless quite self-expressive.
glDisable(GL_BLEND); // Simple construction, for test : the resulting texture is output into render buffer renderbufx1.bind(); clear(0,0,0,0); simpleDiffShader.bind(); simpleDiffShader.setTexture("TextureRef",img.tex,0); simpleDiffShader.setTexture("TextureDown",renderbufx2.getTexture(),1); img.tex->drawPart(-1,-1,2,2,0,0,1,1); simpleDiffShader.unbind(); renderbufx1.unbind(); // Not really useful, but just in case, the result is copied into another render buffer. // renderbufx1 is going to be displayed, and i want to avoid any access conflict savebufx1.bind(); clear(0,0,0,0); renderbufx1.getTexture()->bind(); renderbufx1.getTexture()->drawPart(-1,-1,2,2,0,0,1,1); renderbufx1.getTexture()->unbind(); savebufx1.unbind(); savebufx1.getTexture()->bind(); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_BYTE, t.data); // <-- This is the line savebufx1.getTexture()->unbind(); glEnable (GL_BLEND); renderbufx1.getTexture()->bind(); renderbufx1.getTexture()->drawPart(tex2x,-1,w,h,texSpan,texSpan,fact,fact); renderbufx1.getTexture()->unbind();
Timing measured encompasses all this (and a few other things, which do not really contribute to the total).
Edit 4 : (on course for the most edited question of the week)
The native texture format of the GPU is supposed to be retrieved through the function glGetTexLevelParameter. More precisely, i've used this line of code :
glGetTexLevelParameteriv ( GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &iTexFormat);
The result of the function (within iTexFormat) is 32856. 32856, decimal, is 0x8058, and within gl.h there is :
#define GL_RGBA8 0x8058