Search code examples
c#optimizationxnadrawxna-4.0

How can I optimize this bottleneck Draw call?


I profiled my application (a game), and I noticed that this function is a (the!) bottleneck. In particular, this function is called a lot due to it's meaning: it draws windows of my game's skyscraper. The game is flowing horizontally so, everytime new skyscraper are generated and windows has to be drawn.

The method is simple: I load just one image of a window and then I use it like a "stencil" to draw every window, while I calculate its position on the skyscraper.

  • position_ is the starting position, based on top-left corner where I want to begin drawing
  • n_horizontal_windows_ and n_vertical_windows_ is self-explanatory and it is generated in constructor
  • skipped_lights_ is a matrix of bool that says if that particular light is on or off (off means don't draw the window)
  • delta_x is like the padding, the distance between a window and another.
  • w_window is the width of the window (every window has the same)

    public override void Draw(SpriteBatch spriteBatch)
    {
        Vector2 tmp_pos = position_;
        float default_pos_y = tmp_pos.Y;
    
        for (int r = 0; r < n_horizontal_windows_; ++r)
        {
            for (int c = 0; c < n_vertical_windows; ++c)
            {
                if (skipped_lights_[r, c])
                {
                    spriteBatch.Draw(
                        window_texture_,
                        tmp_pos,
                        overlay_color_);
                }
    
                tmp_pos.Y += delta_y_;
            }
            tmp_pos.X += delta_x_ + w_window_;
            tmp_pos.Y = default_pos_y;
        }
    
    }
    

As you can see the position is calculated inside the loop.

Just an example of the result (as you can see I create three layers of skyscrapers):

An example of the result

How can I optimize this function?


Solution

  • You could always render each building to a texture and cache it while it's on screen. That way you only draw the windows once for each building. you will draw the entire building in one call after it's been cached, saving you from building it piece by piece every frame. It should prevent a lot of over-draw that you were getting each frame too. It will have a slight memory cost though.