Jump to content
  • Advertisement
Sign in to follow this  

OpenGL GPU brush strokes and "undo"

This topic is 1152 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm attempting to write a simple painting application, and I'm looking for strategies for using the GPU to handle most of the blending and rendering.

Rendering several brush "stamps" onto a render target and make it look like a brush stroke is simple.
But in order to enable the user to "undo" the previous strokes, each stroke needs to be stored in memory as a separate state of the canvas (in the form of tiles, for example).
When the user finishes a brush stroke by releasing the mouse etc., I grab the part of the render target that was modified and store it into a buffer.

With a high resolution canvas (8192 x 8192 ARGB pixels for example), in order to have a lot of undo levels you need a lot of memory (video memory won't be enough). Not only that, reading data from the render target onto system memory is very very slow. One test I did with such a large canvas took 200ms to complete.
I would like for the user to be able to undo several levels in sequence: imagine pressing Crtl+Z, Ctrl+Z, Ctrl+Z fast.

I'm using Direct3D 9 and the GetRenderTargetData function. I can also use OpenGL 2.1.
Am I missing something? Is there a clever solution to this?

Share this post

Link to post
Share on other sites

Hello. Great post, thank you.

Undo principle C sounds interesting. A brush stamp is just a quad mesh, so whenever a stamp is rendered its geometry can be stored in buffers.


These buffers would contain the meshes for every stroke, described by ranges in those buffers. Since the geometry is always rendered in the same order as it is described in the buffer, reproducing a series of strokes would mean rendering from the start of the buffers with the desired primitive count. This would preserve the depth order of the strokes, and should be faster than storing several tiles of pixel data.

After a lot of strokes have been done and reproducing all of them by redrawing becomes expensive, then the current framebuffer(s) can be downloaded to system memory.


I will look into this. I think OpenGL should handle this better since it has asynchronous reading with that PBO extension, and Direct3D 9 doesn't seem to have anything of the kind.

Share this post

Link to post
Share on other sites
Memory back-up as a method may become more feasible if you only back up the region that was changed.
Then make special cases for clear operations or anything else that effects the whole screen.

And you can flush to disk to store these back-ups, using a limited number of undo operations (even Adobe Photoshop has to do this) to limit the footprint of all these copies.

L. Spiro

Share this post

Link to post
Share on other sites

There are (at least) 3 undo principles:


a) Inverting the effect of the last action;

b) restoring the memorized state that was valid before the last action (as you do ATM);

c) replaying the history of actions exclusive the last one.


No one of them is per se suitable for pixel painting programs:


a) is not possible because information may be lost due to the former application of the action;

b) costs masses of memory (and bandwidth in your case);

c) costs much performance if the painting has progressed too far.


A way that is suggested now and then is to combine the above possibilities with the goal to lower the average costs. For example, a memento is made only after N actions, and for then at most N-2 remaining actions a replay is done. The drawing area can be tiled for the purpose of storing a memento, so that just the tiles effected during the last N-1 actions need to be memorized. Older mementos can be externalized by a background job.


Tiles also don't necessarily have to be on the grid if you want to support cheap move operations.

Edited by l0calh05t

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!