Update of FB attached texture is ultra-expensive

Hi All,

I have recently experienced something I want to share with the community…

Well, it is well known that textures attached to a framebuffer object should not be updated using glTexSubImage*(). Simon Green mentioned in his presentation for the GDC 2005: “Try to avoid modifying textures used as rendering destinations using TexImage, CopyTexImage etc.” But how bad is this?

I’ve been developing a terrain engine for years. There is a well defined texture update procedure using glTexSubImage3D(), since texture arrays are used. Everything worked perfectly. But I wanted to add copping form one layer to the other. That involved FBOs usage. After the first successful start of the application (should I mention that nothing works at first start ;)) a tremendous slowdown shocked me. My first guess was frequent texture attachments caused it, but making multiple FBOs (one for each layer) and attaching texture at the initialization time didn’t change anything. Frame rendering time didn’t changed (about 18-20ms, GPU time on my laptop with 8600M), but the application was almost frozen. After moving probes through the code, I finally found the problem. Texture update! Believe it or not, update time increased 5 orders of magnitude. Instead of 0.035ms, update time jumped to 109-192ms.

Maybe I’ll try to update some temporary 2D texture with glTexSubImage2D() and then draw part of it in the FBO for a particular layer, but it will be probably slower than it is now (without FBOs).

In the meantime, could anyone shade some light on the problem of ultra-expensive texture update if it is attached to a FBO?

If you’re copying from one texture to another, could you not use glCopyImageSubData from ARB_copy_image (or the equivalent from NV_copy_image if you don’t have that)?

Regards
elFarto

I agree that copy_image is probably the best solution for direct copying from one texture to another, but my problem also requires rescaling. Textures in different layers have different resolutions so copy_image does not serve the purpose (there is no dstWidth and dstHeight in CopyImageSubData() function). That’s why I need FB and drawing to texture (layer). Maybe this is not a bad proposal for some new extension. :wink:

You could always try NV_draw_texture (if you’ve got it), that allows resizing, but draws to the currently bound framebuffer. Unfortunately it isn’t designed to read from a layered textured, so you’ll need use texture views.

I think a resizing version of glCopyImageSubData would be a good extension too. Currently we have 3 ways to copy texture data around:

glFramebufferBlit: Only works between framebuffer objects and allows resizing, but is bit of a pain to setup
glCopyImageSubData: Works between textures and renderbuffers, but can’t resize
glDrawTextureNV: Only works from 2D textures to the framebuffer, but allows resizing.

Would be nice to have:

void BlitImage(
            uint srcName, enum srcTarget, int srcLevel, int srcX, int srcY, int srcZ,
            uint dstName, enum dstTarget, int dstLevel, int dstX, int dstY, int dstZ,
            sizei srcWidth, sizei srcHeight, sizei srcDepth,
            sizei dstWidth, sizei dstHeight, sizei dstDepth);

But perhaps 18 parameters is a few too many…:stuck_out_tongue:

Regards
elFarto

It doesn’t solve the problem since drawing requires target to be attached to a framebafer, and the problem is in the fact that updating (with glTexSubImage) attached texture is ultra-expensive.

[QUOTE=elFarto;1252270]Currently we have 3 ways to copy texture data around:

glFramebufferBlit: Only works between framebuffer objects and allows resizing, but is bit of a pain to setup
glCopyImageSubData: Works between textures and renderbuffers, but can’t resize
glDrawTextureNV: Only works from 2D textures to the framebuffer, but allows resizing.
[/QUOTE]
Neither of these solves the problem. glFramebufferBlit is a simple solution. What did you mean with “pain to setup”? It doesn’t require shaders and state change for texture update, but the problem of glTexSubImage() stays (everything that involves FB have that problem). glDrawTextureNV is not widely supported and still requires FB. glCopyImageSubData() does not support scaling and filtering. It enables direct memory blocks copying. That’s why scaling and filtering is not supported. I don’t have performance problems with draw-to-texture. It works fine, but subsequent updates of attached textures are very expensive. I just want to know whether it is really necessary to be so.

I just meant that for a ‘simple’ copy, you need to setup 2 FBO and bind them then do a blit, as apposed glCopyImageSubData which accepts all the parameters in one call.

Regards
elFarto