PDA

View Full Version : Updating pixels



lampcord
05-28-2015, 03:10 PM
Hi all, struggling with a problem in a game I'm working on.

I need to find the most efficient way to update individual pixels on the screen.

Assume on any given frame I'll be updating about 20% of the pixels and the rest of the screen stays the same.

Here's what I've tried:
1) getting a pixel buffer from the screen's gc. When I try to update it I get an access violation.
2) Creating a pixel buffer the size of the screen, updating it, creating an image from it and rendering it to the screen. This works but is extremely slow.

One of the problems I've had is I can see how to make an image from a pixel buffer but I can't figure out how to go the other way around. Is there a member function on an Image to get the pixel_buffer? If so, I can't seem to find it. I can create an Image from a pixel_buffer but how about the other way around?

Also, I can't figure out how to update an image with a new pixel_buffer, just create one. So I have to create a whole new image each time which seems inefficient as hell.

Any help would be greatly appreciated.

rombust
05-28-2015, 03:40 PM
I have just committed to GIT - Image::set_subimage().

I have had that function on my personal version of ClanLib for a while, but forgot about it.
Although, strictly speaking, you could do a similar thing by building a clan::Image using a clan::Texture2D, and uploading to the texture2d, but that's messy (imho)

Anyway "update individual pixels on the screen". This depends on exactly what you are doing.

The general rule of thumb is don't read the pixels back from the texture or the screen. It will be slow. The graphics card has to wait to complete all drawing, then copy data to the CPU RAM for you to update, then copy it back.


"getting a pixel buffer from the screen's gc. When I try to update it I get an access violation"
I can't remember the details. It is probably because the memory is read only. You might have to clone it (ouch!). Maybe different using Direct3D or OpenGL, I cannot remember.

But you shouldn't need to do that anyway.

Have a look at the canvas example, would that method help you?

Judas
05-29-2015, 12:44 AM
I need to find the most efficient way to update individual pixels on the screen.

Assume on any given frame I'll be updating about 20% of the pixels and the rest of the screen stays the same.

This really depends on what exactly this update is doing. Your choices roughly are:

1) Output the screen stuff to a texture. Then run a fullscreen pixel shader program that reads from the texture and outputs the final result (ShaderEffect is the high level class doing this). Typical examples for this kind of effect is: bloom, distance blur, linear-to-sRGB, some lensflare effects, distortion effects, old CRT monitor effect, etc. All data stays on the GPU.

2) Output the screen stuff to a texture. Then run one or more compute shader programs. This allows you to do far more complicated stuff where the pixel shader might be too simplistic an approach. All data stays on the GPU. ShaderEffect also supports this method.

3) Apply the effect to a CPU image and upload it to the GPU each frame (this is what the function rombust added does). GPU command pipelining is still intact as the GPU can render things while the CPU works on that image and transfers it. Catch is that sending too much data like this will mean the GPU will be stalled waiting for the CPU.

4) Download the resulting screen texture, update the pixels, then re-upload and render it. This is a very bad idea as CPU and GPU now constantly have to wait for each other - your frame rate will be terrible.


One of the problems I've had is I can see how to make an image from a pixel buffer but I can't figure out how to go the other way around. Is there a member function on an Image to get the pixel_buffer? If so, I can't seem to find it. I can create an Image from a pixel_buffer but how about the other way around?

The functions you are looking for are on Texture2D. The steps roughly are to create a Texture2D, then create a Canvas that outputs to it, then render and finally call get_pixeldata on the texture. However, this is method 4 above, which I only really recommend if there is no other way of getting what you want.