effective offscreen texture copy

I have an offscreen buffer associate with a texture. I would like to save this specific texture for later use, but I need to do it every frame.

I have the following code running but it is very very slow. I create a PNMImage to store the content and move it to another texture.

base.graphicsEngine.extractTextureData(self.tex1, base.win.getGsg())
self.tex1.store(self.screenImage)
self.savetex.load(self.screenImage)

Are there more effective ways to do this ?

I don’t know how extractTextureData works exactly but you might get better results by setting the render texture mode to RTMCopyRam and calling getTexture on the buffer (getTexture(n) for multiple render textures) to retrieve a pointer to the texture. Panda will automatically copy the render texture to ram every frame.

But really, you should try to keep the texture on the GPU (although I can imagine there are a few cases when you want it in RAM.)

I tried, but the result is still not fast enough.

I would like to keep things in GPU side also. Is there a way to copy content of an offscreen buffer to another offscreen buffer in the GPU side ?

It doesn’t surprise me that it’s slow - copying a texture from GPU to CPU is a relatively slow operation.

Certainly, you could just set the mode to RTMBindOrCopy and call getTexture on one buffer (in case of the FilterManager, just specify a colortex), this texture will be on GPU and not in RAM (if you attempt to do something with it’s contents, you will get an error) and you can just assign this texture either to a shader input or a card, using setTexture.

I believe this is what you were doing in the other thread as well.

Yes, I was doing it in other demos.

But this time I want to save this texture to somewhere, and use it a few frames later. In my previous works, I usually use it immediately in a shader, so no need to save it in CPU side.

If I save it to a texture in CPU, the performance is bad. What are the available ways to save it efficiently for this case ?

Just keep the texture on the GPU. Use RTMCopyTexture (instead of RTMBindOrCopy or RTMCopyRam), and use a different texture object for each copy you want to keep. Of course texture memory is limited, so you can’t go crazy with this; but with a modern graphics card you can store quite a few screenshots.

David

Hi David,

Can you give a few lines of sample code ? I am a bit confused by the various APIs to perform this task.

May be I shall explain a bit more what I want to do.

I have a scene, which render as normal.
I have a FilterManager, which as a chain of quad, attached with a chain of shader.

In the output of the middle of the chain, I want to save the content of that buffer. The buffer will be used in one or several frames later as the input of a shader.

So I would need an effective API to store this buffer to an other buffer. Can you show me how to do it with RTMCopyTexture ?

I just mean that when you bind the buffer to a texture, use RTMCopyTexture instead of any other binding. The texture will persist until it is copied over with another frame, so if you unbind the texture after the first frame has been rendered, you will have saved the image.

David

FilterManager uses RTMBindOrCopy to bind the textures. If you don’t want that, I guess you can create a class that inherits from FilterManager and override the createBuffer class.
David, what’s exactly the difference between RTMBindOrCopy and RTMCopyTexture?

RTMBindOrCopy will attempt to bind the texture directly to the framebuffer if the driver supports that, and fail back to RTMCopyTexture if it doesn’t.

Binding the texture to the framebuffer means the texture shares the same graphics memory as the framebuffer. When you render the frame, you are directly rendering to the texture, and no copy operation is required. It’s a tiny bit faster because you avoid the need for the copy.

The only downside is that the texture is permanently associated with the buffer; if you disassociate the texture from the buffer, you lose the texture data too. In RTMCopyTexture, the texture has its own memory that it keeps whether it is attached to a buffer or not.

Another option, instead of using RTMCopyTexture, is to go ahead and use RTMBindOrCopy, but take the texture and the buffer out of the chain when you want to keep it around. Create a new texture and buffer to replace it in the chain. You’ll have to keep the buffer around for as long as you need the texture, potentially wasting even more graphics memory (especially if Panda ended up failing over to the copy operation anyway), but you don’t have to monkey with the internals of the FilterManager.

David

Thanks a lot. I believe I made some working code from your suggestions.