macite / swingame

2D game library accessible from multiple languages
swingame.com
27 stars 9 forks source link

Pixel drawing is slow #36

Open Aloz1 opened 8 years ago

Aloz1 commented 8 years ago

Currently pixel drawing is very slow in Swingame, to the point where drawing each pixel once on a 800x600 window results in a desperate of approximately 1-10 frames per second (dependant on the computer).

Having explored ideas, it seems that drawing all pixel changes to an SDL_Surface then moving those changes to a texture once per frame will dramatically increase the speed.

Aloz1 commented 8 years ago

I've tested this so far by adding a new data type named sg_pixbuf_be and have compared it's speed to the current method of drawing pixels directly to a window of size 800x600 pixels.

Drawing directly to the window yields a speed of 134ms per frame on my laptop, whilst drawing to a pixbuf which is then drawn to the screen is approximately 42ms per frame.

Whilst creating a new datatype called pixbuf proves that it would be advantageous to draw in this way, I'm thinking modifying bitmap such that it can act similar to a pixbuf would be a better approach. Bitmap already has both a surface and a texture, bitmap can already have shapes drawn to it, and modifying bitmap would be less intrusive and would continue to work with already existing games/programs.

@macite, any additional comments or thoughts before I go ahead?

macite commented 8 years ago

Yeah, this is interesting. If you changed the bitmap then all drawing operations would need to be changed to use that approach -- draw changes to the surface then render to each texture on its draw. There was a reason we didn't do it this way... I remember. Drawing rotated and scaled bitmaps onto other bitmaps.

It may be better to have the pixel buffer and only support something like put pixel.... what else did you want to support for this?

Aloz1 commented 8 years ago

I was thinking about having an enum in the bitmap which determines if the last drawing operation was to a SDL_Surface or to a SDL_Texture and syncs one with the other periodically if the next operation was to the opposite data type. For example, if the last drawing operation was a Texture operation and the next one was a Surface operation, then the surface would be synced with the texture.

This would allow multiple pixels to be drawn to a surface relatively quickly, then for the surface to only be transferred to textures once a texture based operation occurs. You'll still get slow cases, like when you draw a pixel, then a shape, then another pixel and another shape. But this seems like a rather odd thing to do anyway and should end up being the same speed as what we've already got.

jgardner8 commented 8 years ago

May I suggest a DrawPixelBatch() function that takes an array of pixels and does the surface/texture handling internally? That would mean that the feature is entirely insulated from the rest of the codebase, and it will be clearer that you have to draw all your pixels at once for efficiency.


From: Aloz1 notifications@github.com Sent: Thursday, 12 May 2016 2:44:49 PM To: macite/swingame Subject: Re: [macite/swingame] Pixel drawing is slow (#36)

I was thinking about having an enum in the bitmap which determines if the last drawing operation was to a SDL_Surface or to a SDL_Texture and syncs one with the other periodically if the next operation was to the opposite data type. For example, if the last drawing operation was a Texture operation and the next one was a Surface operation, then the surface would be synced with the texture.

This would allow multiple pixels to be drawn to a surface relatively quickly, then for the surface to only be transferred to textures once a texture based operation occurs. You'll still get slow cases, like when you draw a pixel, then a shape, then another pixel and another shape. But this seems like a rather odd thing to do anyway and should end up being the same speed as what we've already got.

You are receiving this because you are subscribed to this thread. Reply to this email directly or view it on GitHubhttps://github.com/macite/swingame/issues/36#issuecomment-218659129

macite commented 8 years ago

Draw Pixel Batch sounds like a good idea in this case. Parameters? May need a PixelBatch type, to avoid issues mapping this between languages.

jgardner8 commented 8 years ago

I envisioned it as multiple sets of whatever DrawPixel takes. Then it would be akin to calling DrawPixel in a loop but with efficiency gains. I've not looked at it too closely to be honest, so there may be details to work out -- a PixelBatch type sounds like one of them.


From: Andrew Cain notifications@github.com Sent: Thursday, 12 May 2016 4:10:06 PM To: macite/swingame Cc: James Gardner; Comment Subject: Re: [macite/swingame] Pixel drawing is slow (#36)

Draw Pixel Batch sounds like a good idea in this case. Parameters? May need a PixelBatch type, to avoid issues mapping this between languages.

You are receiving this because you commented. Reply to this email directly or view it on GitHubhttps://github.com/macite/swingame/issues/36#issuecomment-218668625

Aloz1 commented 8 years ago

That's essentially what I've done by creating sg_pixbuf_be. But after thinking about it, I figured it would be quicker to only update pixels in the texture when they're needed, and only those that have changed...not once every frame (what I've implemented), or by individually transferring pixels across (which is what is currently in swingame).

The way you'd do this is by introducing a SDL_Texture into each pixbuf, then calling either SDL_UpdateTexture or SDL_LockTexture once you've finished drawing pixels to transfer the changes across to the GPU.

Once you've done this however, there is very little difference between sg_pixbuf_bg and sg_bitmap_be...just that one is way faster with pixels...and the other has shape drawing functionality. Hence why my train of thought led to merging sg_pixbuf_be and sg_bitmap_be.

We could keep the two separate, but I felt it would be more convenient and more beneficial to merge the functionality together.

I'll experiment some more and let you know what the numbers are like for speed regarding SDL_UpdateTexture and SDL_LockTexture. I'm currently creating a new texture each frame from the surface data, so there is definitely room for improvement.

macite commented 8 years ago

Also make sure you are on the quality/splash-kit-prep branch... branches need to be sorted before we move but this is the current develop branch.

macite commented 8 years ago

Branches are tidied up now... work off develop.

Aloz1 commented 8 years ago

Finally finished both versions. Sorry it took so long, I've been busy with work and had to rebase everything (as well as fix up some small bugs) as I'd unfortunately been developing under the old v4_backend branch. I'll create pull requests for both methods so you can comment on them and see what you think.

As an aside, the way I've implemented this under the bitmap_be version means that bitmap_be always has a surface as well as textures, and remembers where it last drew to so it can keep things in sync. This also ties in quite nicely with how swingame currently keeps bitmaps open without a window.