Asset - Scripts buffer_getpixel: 10x faster than normal surface_getpixel (GMS1 and GMS2)

Misu

The forum's immigrant

Get buffer_getpixel at the marketplace!
Need a faster surface_getpixel? You come to the right place!​

This asset comes with a small list of scripts that will help you get a pixel color super fast and its totally free.​

How to use each command:

buffer_getpixel_begin(surface) = creates the buffer for checking using a specified surface id
(or surface drawing) and returns you a buffer index.
(NOTE: application_surface only picks the regular Draw events;
not the GUI events.)
If your surface image is static, you can set it to create event,
otherwise, set it in the event that you will get the pixel.

buffer_getpixel(ind,x,y,width,height) = Gets the RGB of a pixel within the specified buffer id (surface).

buffer_getpixel_ext(ind,x,y,width,height) = Gets the RGBA of a pixel within the specified buffer id.

buffer_getpixel_r(ind x,y,width,height) = Gets the Red value of a pixel

buffer_getpixel_g(ind x,y,width,height) = Gets the Green value of a pixel

buffer_getpixel_b(ind x,y,width,height) = Gets the Blue value of a pixel

buffer_getpixel_a(ind x,y,width,height) = Gets the Alpha value of a pixel

//////////////////////////////////////////////////////////////////////////////

The file comes with the scripts and a demonstration of how it works (for dynamic images);

In case your image does not need to update the drawing at all, here's an example on how it works for static images (performance is more noticeable from this):
Code:
//CREATE EVENT
var ss = surface_create(800,450);
surface_set_target(ss);
draw_clear(0)
draw_sprite(spr_0,0,x,y)
surface_reset_target()

WIDE = surface_get_width(ss);
HIGH = surface_get_height(ss);

buff = buffer_getpixel_begin(ss);
/////////////////////////////////////////////////////////////////////////////
//DRAW EVENT (or any other event)
var pixel = buffer_getpixel(buff,16,16,WIDE,HIGH);

draw_text(64,8,string(pixel));
/////////////////////////////////////////////////////////////////////////////
//GAME END EVENT
buffer_getpixel_end(buff)
Try it out if you like and give feedback.
Any problems, doubts, questions, do reply back if you like!
 
Last edited:

Misu

The forum's immigrant
Updated to 1.0.4

- Added two new arguments for each draw_getpixel commands; width and height. This specifies the surface size to use.
- Removed buffer_getpixel_end. The asset is better off using buffer_delete instead.
- Fixed bug that returns incorrect buffer index or mistaken buffer id.
- buffer_getpixel now only relies on one buffer index instead of two.
 

Xer0botXer0

Senpai
Hmm..

What about buffer set pixel ?
I can see this being used to make more realistic dynamic lightning dor sprite art without the use of multiple sprites.

Imagine an area lit by a lamp.. the code is run once and an area around the lamp is prepared so that pixels are lit up according to their color to a lighter shade and a little less lighter the further off from the lamp. That already seems nice to me.

Along comes a player and walks under the lamp.. it would be a little intensive but maybe every 15steps if your game room speed isn't 30 update the pixels so then even your player gets lit. And only updating it when the player is moving.
 

Xer0botXer0

Senpai
What kind of support ? I'm poor lol.
And I might when I get to lighting in my game. Because I have to do it anyway!
 

zbox

Member
GMC Elder
No no - Gamemaker has that functionality of buffer_set_surface already. Just that it doesn't work and YYG should fix it :p
 

GMWolf

aka fel666
How about storing the width and height of the surface at the start of the buffer, that way you don't need to specify it?

Also, how do you manage so many reviews?
 
I'm using the demo and for me it gets 160 real_fps with your buffer_getpixel system.

So I did a test to compare buffer_getpixel vs surface_getpixel with var c = surface_getpixel(application_surface,mouse_x,mouse_y) and again for r, g, b. I get 600 fps_real.

According to the debugger, the buffer_getpixel requires FAR less time, but the buffer_getpixel_begin requires almost 10x slower than surface_getpixel. buffer_getpixel_end requires almost as much as surface_getpixel.

So to summarize...
buffer_getpixel_begin = 8,800
surface_getpixel needs = 847
buffer_getpixel_end = 206
buffer_getpixel = 7

So the catch here as you mentioned, don't update your surfaces, which shouldn't be too tough for things like blocks and maps, otherwise it takes 10x more processing power rather than 10x less.

A more efficient way would be to buffer a surface area of the pixel you're trying to get rather than the entire application_surface as indicated in the demo.

Can someone else confirm this? I might be crazy.



* edit * By default your buffer_getpixel returns a different number than surface_getpixel. Is it because the demo example uses the GUI?
 
Last edited:

sylvain_l

Member
Can someone else confirm this? I might be crazy.
whats crazy is duplicating the whole surface when what you want is just 1 pixel.
do the comparison again, but when you read each pixels of the surface (for example to do some statistics, count how many pixels are a specific color, etc...) that should give a better understanding, when does buffer_get_pixel get handy.
 
I dug into the code more since buffer_getpixel was highly inaccurate to surface_getpixel and it looks like your red and blue are backward where red is blue and blue is red so that gives inaccurate colors in your scripts.

For whatever reason it looks like RGB in buffer data is stored as BGR.

buffer_seek(buff1,buffer_seek_start,px) // is blue rather than red
buffer_seek(buff1,buffer_seek_start,px + 2) // is red rather than blue

Changing these gives accurate results as surface_getpixel would. This inaccuracy is in the following scripts:
- buffer_getpixel
- buffer_getpixel_r,
- buffer_getpixel_b
- buffer_getpixel_ext

If someone wants to confirm this please do, but its like this on both the non Steam and Steam version of GMS 1.

Maybe this was changed in the latest patch, because those eight 5 star reviews have been content with using something that gave inaccurate results.
 
Last edited:

Misu

The forum's immigrant
Sorry for not following this, I have been focusing on other things lately. Just today decided to follow this thread and realize all the comments I havent seen yet.

To start off, @sitebender I am glad you pointed that out for that I wasnt aware about that prob with the inverted colour format. Its due to that Game Maker "used to" rely on a Delphi compiler and suppose Delphi can only read colour formats in order of BGRA. I was using the traditional RGBA format like any other language. Dont know why GMS2 still uses the delphi format when the compiler is changed to C++ . At least I got the scripts fixed now although I'll update the asset tonight once I revise everything first to ensure nothing else is running improperly.

Also I decided to replace buffer_seek with buffer_peek instead so it would be much simpler.

Be aware, that the performance is only noticeable for heavy-duty processing (iteration). Buffers tend to be way more stable on frame rate but there is a tiny chance of it to run a tad slower. If you were to compare it with surface_getpixel, youll need to compare it by doing a massive iteration process like so:
Code:
repeat(400) // < ------ iterate 400 times
{
 var c = buffer_getpixel(buff,mouse_x,mouse_y,W,H);//get pixel RGB from mouse coordinates
 var r = buffer_getpixel_r(buff,mouse_x,mouse_y,W,H);//get red value
 var g = buffer_getpixel_g(buff,mouse_x,mouse_y,W,H);//get green value
 var b = buffer_getpixel_b(buff,mouse_x,mouse_y,W,H);//get blue value
}
With that type of repetition on executing with surfaces, surface_getpixel causes to drop the fps to 8 - 10 on my pc while the buffer scripts maintain a bit stable from 20 - 35 fps. So these scripts help out for the most complicated techniques in game making like editing pre-made heightmaps or bake effects for example.

I have told a few people to test this out before releasing it and people have confirmed to me that the performance is greatly noticeable.
Not sure why your computer shows it badly. I do know the performance is not noticeable for the simple tasks but dropping that bad is something I never seen before. Perhaps it different with your hardware.

Of course when doing realtime changes, it runs slower because:

1. Its copying the entire image into the buffer index instead of 1 pixel.
2. its removing the entire image from the buffer index as well.

I had been aware of that before actually. I even posted a suggestion for a feature to copy only a specified fragment of a texture:



I tried poking, Im assuming YYG didnt seem that interested in adding such idea to the program. It would gradually improve the performance imho. If you are tempt for a new buffer function for specifying only a fragment of a texture, feel free to poke YYG. Perhaps the more people seeking for this the higher probability of them to consider doing so.

Also for those who actually need buffer_set_texture fixed, Ive seen people tried so hard on insisting YYG to fix that. Many filed reports, suggestions, even PMing. I dunno how YYG tend to listen to their users; they havent done anything about these small stuff yet since GMS 1.4 was a thing. I am very tempt to using that. It appears it is only function for very limited amount of hardware and could use a new scratch on making it work for any hardware.

Anyway thanks for all the comments and everything. Ill be updating this asset shortly.

Btw @sitebender you seem very focused on my asset functionality. What are you using it for anyway? Care to tell about it?
 
D

Deleted member 467

Guest
ooh - a cool asset that should help performance for some of my things and is free. Noice.
 

Misu

The forum's immigrant
Hold on because I just updated the asset now to version 1.0.6

Changelog:

- Notice that the colour formats were returning incorrectly since GMS follows an inverted pattern. The colour formats are now fixed with BGRA.

- buffer_seek has been replaced with buffer_peek instead.

- Minor fixes

I like to thank everyone for contributing with feedbacks and pointing out problems. I am always opened to hear from anyone, just give me a poke for anything and Ill revise with care. :)
 
I'm a little pressed for time, so I can't explain why.

What I can explain is to test your buffer_getpixel system I did make a random color palette swapper that takes the color palette of a sprite, then makes a random palette to switch out the original colors. You can also swap it out with pre existing color palettes too. The surface_getpixel method takes a noticeable amount of time longer.

Sure there are shaders that swap colors instantly, but this one doesn't require shaders. My 10+ year old PC crashes when any shader is used.

Here's a video of the random color palette generator I made. I like it because I like the pretty colors. Oh ahd uh there might need to be a seizure warning as it is random colors.

 

Misu

The forum's immigrant
Very interesting. I like how you tend to test beyond the boundaries. If anything you need me to know, always be sure to ask, thanks again.

I also like to mention that Im very intrigued on having an improved version of this with another function that can control the amount of pixels to copy. It would benefit much for those kind of cases. And like how @Xer0botXer0 mentioned in his earlier post, it would benefit a lot for making an exceptional side for effects.

Im actually tempted to do a petition to see how many people consider for a new upgrade on the buffer functions, including fixing that buffer_set_texture. If anyone interested and think its a good idea, Ill do one.
 
it is a good asset but it would be nice if there was a quick version of buffer_getpixel_begin()
something that would take a sprite and create a surface for you.
 
Top