2

I have created a CellGrid class for my cellular automaton, and I want to draw that grid using Cairo. The cell_grid.cpp code snippet below is my implementation of the on_draw() function override. For this example, I have set width_ = height_ = 50 and cell_buffer_ is an std::vector with a size of width_ * height_. The vector containts instances of the Cell enum class, which is defined in the cell_grid.hpp snippet below.

The problem is that for some reason, already when drawing just 50*50 or 2 500 rectangles, I get about 2fps. This Cairo implementation is actually a rewrite of an SFML implementation, on which I got about 150fps when drawing 200*100 or 20 000 rectangles. But as far as I know, SFML isn't a viable option in combination with GTK.

cell_grid.hpp snippet

class CellGrid : public Gtk::DrawingArea
{
public:
    enum class Cell : uint8_t //uchar
    {
        Dead = 0,
        Alive = 1
    };
// ...
};

cell_grid.cpp snippet

// ...
bool CellGrid::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
    const Gtk::Allocation allocation = get_allocation();

    const double cell_w = allocation.get_width() / (double)width_;
    const double cell_h = allocation.get_height() / (double)height_;

    for(size_t y = 0; y < height_; y++)
    {
        for(size_t x = 0; x < width_; x++)
        {
            cr->set_line_width(5.0);
            cr->rectangle(x * cell_w, y * cell_h, cell_w, cell_h);
            cr->set_source_rgb(0.5, 0.5, 0.5);
            cr->stroke_preserve();

            cell_buffer_[y * width_ + x] == Cell::Alive ?
                cr->set_source_rgb(1.0, 1.0, 1.0) :
                cr->set_source_rgb(0.1, 0.1, 0.1);

            cr->fill();
        }
    }

    return true;
}
// ...

Thanks in advance!

BobMorane
  • 3,870
  • 3
  • 20
  • 42
  • if cells are sparse enough, it might be faster to fill with the empty colour first and then rectangle for each cell and finally stroke/fill once at the end (iirc, you can do weird stuff like that). also, you _definitely_ don't need to redundantly set the line width and colour on every iteration... that adds at least some pointless cycles to the loop. also, imho (at least simplistic, pixel-y) stuff like this is probably better done by poking values into an image surface, rather than using Cairo. i did something similar for a cellular automaton a while back but don't have code to hand right now. – underscore_d Jul 27 '20 at 12:06
  • I already removed the redundant Cairo context state changes, but it doesn't really do anything significant in terms of performance. I also thought about maybe using a `Gtk::Image` instead, but as you said, you can only really do "simplistic, pixel-y" stuff. Also, I am still wondering, why SFML's performance was soooo much better. Doesn't Cairo also use OpenGL? I can't imagine the abstraction overhead of Cairo being so massive. – darwin schuppan Jul 27 '20 at 12:12
  • I meant a `Cairo::ImageSurface`, not a `Gtk::Image`. That way you get 'nearly direct' access to the pixels (although you still need to mark-as-dirty and do locking type stuff iirc) and can poke them in considerably faster, which for simplistic stuff like rectangular cells can suffice or at least did for me. I can't be of much more help personally I'm afraid. I suspect this might be better asked on the `gtkmm-list` mailing list but depends who reads – underscore_d Jul 27 '20 at 12:19
  • I guess that might work, but still, there are two things concerning me about this approach, like I already said in the previous comment (regarding possibilities and why SFML's performance is so much better). Anyways, thanks a lot for the help and if nothing else works, your proposal might definitely be something to consider. – darwin schuppan Jul 27 '20 at 12:25

0 Answers0