Alex Rivera | Logout

glTexSubImage2D extremely slow on Intel video card

Asked 2011-10-18T13:40:03.087
11

My video card is Mobile Intel 4 Series. I'm updating a texture with changing data every frame, here's my main loop:

for(;;) {
    Timer timer;

    glBindTexture(GL_TEXTURE2D, tex);
    glBegin(GL_QUADS); ... /* draw textured quad */ ... glEnd();
    glTexSubImage2D(GL_TEXTURE2D, 0, 0, 0, 512, 512,
        GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, data);
    swapBuffers();

    cout << timer.Elapsed();
}

Every iteration takes 120ms. However, inserting glFlush before glTexSubImage2D brings the iteration time to 2ms.

The issue is not in the pixel format. I've tried the pixel formats BGRA, RGBA and ABGR_EXT together with the pixel types UNSIGNED_BYTE, BYTE, UNSIGNED_INT_8_8_8_8 and UNSIGNED_INT_8_8_8_8_EXT. The texture's internal pixel format is RGBA.

The order of calls matters. Moving the texture upload before the quad drawing, for example, fixes the slowness.

I also tried this on an GeForce GT 420M card, and it works fast there. My real app does have performance problems on non-Intel cards that are fixed by glFlush calls, but I haven't distilled those to a test case yet.

Any ideas on how to debug this?

Edit
Report

2 Answers

3

I assume you're actually using that texture for one or more of your quads?

Uploading textures is one of the most expensive operations possible. Since your texture data changes every frame, the upload is unavoidable, but you should try to do it when the texture isn't in use by shaders. Remember that glBegin(GL_QUADS); ... glEnd(); doesn't actually draw quads, it requests that the GPU render the quads. Until the rendering completes, the texture will be locked. Depending on the implementation, this might cause the texture upload to wait (ala glFlush), but it could also cause the upload to fail, in which case you've wasted megabytes of PCIe bandwidth and the driver has to retry.

It sounds like you already have a solution: upload all new textures at the beginning of the frame. So what's your question?

NOTE: Intel integrated graphics are horribly slow anyway.

answered 2011-10-18T14:24:02.230
1

When you make a Draw Call ( glDrawElements, other ), the driver simply add this call in a buffer, and let the GPU consume these commands when it can.

If this buffer had to be consumed entirely at glSwapBuffers, this would mean that the GPU would be idle after that, waiting for you to send new commands.

Drivers solve this by letting the GPU lag one frame behind. This is the first reason why glTexSubImage2D blocks : the driver waits for the GPU not to use it anymore (in the previous frame) to begin the transfer, so that you never get half-updated data.

The other reason is that glTexSubImage2D is synchronous. Il will also block during the whole transfer.

  • You can solve the first issue by keeping 2 textures : one for the current frame, one for the previous frame. Upload the texture in the former, but draw with the latter.
  • You can solve the second issue by using a GL_TEXTURE_BUFFER Buffer Object, which allows asynchronous transfers.

In your case, I suspect that calling glTexSubImage2D just before glSwapBuffer adds an extra synchronization in the driver, whereas drawing the quad just before glSwapBuffer simply appends the command in the buffer. 120ms is probably a driver bug, though : even an Intel GMA doesn't need 120ms to upload a 512x512 texture.

answered 2011-10-18T17:44:48.360

Your Answer