Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Image draw speed

i am working on a game, but currently I am running benchmarks.

If anyone can help me on this matter, I would greatly appreciate it.

What I am doing, is I fire the paint event on a panel when I click the start button, with this code:

    private void startToolStripMenuItem_Click(object sender, EventArgs e)
    {
        try
        {
            pnlArea.Invalidate();

        }
        catch (Exception)
        {
            throw;
        }
    }

I then do this in my paint event:

    private void pnlArea_Paint(object sender, PaintEventArgs e)
    {
        try
        {
            stopwatch = new Stopwatch();
            // Begin timing
            stopwatch.Start();

            if (gameStatus == GameStatus.PlaceHead)
            {
                e.Graphics.DrawImage(dictHead["HeadRight"], 100, 100, 15, 15);
            }

            //e.Graphics.Clear(Color.White);

            if (gameStatus == GameStatus.GameTest)
            {
                int x = 0;
                int y = 0;
                for (int i = 0; i < 5000; i++)
                {
                    x += 15;
                    if (x > 1000)
                    {
                        x = 0;
                        y += 15;
                    }

                    e.Graphics.DrawImage(body.Value, x, y, 15, 15);

                }
            }

            toolTimer.Text = Math.Round((stopwatch.Elapsed.TotalMilliseconds / 1000), 2).ToString() + "s";

            // Stop timing
            stopwatch.Stop();
        }
        catch (Exception)
        {

            throw;
        }
    }

This is the body part I am drawing in the code above:

enter image description here

This is the exact size --> 15px x 15px

but this takes up to 1.2 seconds sometimes!!! is there a way I can improve this?

this is a sample of the end result screen: enter image description here

like image 747
Fred Avatar asked Jan 02 '15 16:01

Fred


1 Answers

You need to think about how to minimise the number of drawing calls you make. Currently you draw 5000 small boxes in order to produce a grid. Every time you draw a box you execute several instructions and then call a graphics method to render a scaled image. This is a lot of overhead for each grid square.

So the first thing you could look at would be finding more efficient ways to draw the image - for example, DrawImageUnscaled might work faster than DrawImage and achieve the result you want. But this is optimisation of an inefficient algorithm - what you need to do to get a real performance benefit is see if you can adopt a new, more efficient, algorithm.

If you must render using bitmaps, then look at how the pattern repeats - could you make a bigger bitmap that provides a 4x4 or 16x16 group of cells, and render that? Or a bitmap that represents a whole column or row? Then you might render with 50 calls instead of 5000.

But if you don't need to use bitmap rendering, you may be able to do much better. For example, if you gfx.Clear(backgroundColor) and then draw about 140 black lines down and across, you can create the same display with only 141 calls. Or if you draw about 70 rectangles you can effectively do 2 lines per call This massively reduces the number of method calls you have to make, and allows the graphics system to draw more pixels in a burst, using highly optimised line rendering and rectangle rendering routines (in fact, the rectangle may work out significantly faster than a generalised line due to the system knowing that the lines are always vertical and horizontal).

(If there are bits that do not follow this pattern, then can you still render the background grid and then draw the changes on top?)

Next, if only small areas of the image change from one frame to the next, then your algorithm will draw 5,000 boxes even though 4999 of them are not changing (or 70 rectangles when 1 would suffice). So you can improve matters greatly if you (a) only invalidate the part of the view that needs to change, and (b) write your rendering routine to work out which grid squares are outside the clip bounds and therefore are pointless to draw. This could reduce your updates to drawing 1 rectangle instead of 5000 every frame. (Another way to achieve the same thing would be to keep the image in an offscreen bitmap, and just draw changes onto it. When you render this to the main screen display, the graphics card will clip it for you and achieve the same result - a much faster redraw speed)

It's all about achieving the same display by being "lazy" and thinking laterally to do as little work as possible. (Getting a computer to go faster always boils down to asking it to do less)

like image 75
Jason Williams Avatar answered Oct 29 '22 09:10

Jason Williams