Drawing large numbers of primitives
R S

Essentially I want to draw a matrix to the screen, and quickly.

The image will always be composed of squares at some resolution. I have been using primitives to draw them up to now, and this has performed well for my test cases of a 600x600px display and drawing a 100x100 matrix (ie each square is 6x6 px). Now that I'm moving to trying to draw larger examples, it seems that it isn't running nearly as well. The 100x100 matrix is able to be drawn at hundreds of fps easily, but trying to draw a 600x600 matrix to the same 600x600 px display as before has the framerate tank to about 0.5fps.

I'm confused as to why the same quantity of drawing takes much more resources when done in more steps. It seems that it is not possible to lock a bitmap and then draw with primitives, is this actually the case or have I made a mistake there? (I assume that there isn't the issue of loading/unloading the bitmap from the video card repeatedly by default using primitives, so locking would at best be redundant)

I could go to drawing pixel by pixel manually with locking, but I'm not sure if that would actually be faster and I don't want to charge in and implement it if there is something obvious I'm missing. What is the best way to handle this?

weapon_S

In my calculations you do 36 times as much drawing, not the same amount :P The only things that cause a slowdown I can think of are: you're using a weird way of calculating the the rectangle coordinates; or the so-called 'matrix' is actually coupled with a large data-structure that forces memory paging when allocating 360,000.
I am so smart.
The only other ways I can think of to draw a grid of squares are:
- Use a transformation on a single square. (Read the manual)
- Use the primitives low-level drawing routines. (Read the manual)
- Use putpixel on a bitmap and scale it up.
I'd go with the third, because that's the only one I understand =_=

james_lohr

Nowadays I never know whether questions are referring to old-school Allegro (memory/video bitmaps), or the latest version of Allegro built on OpenGL, but I'm going to assume the latter...

By "primitives" do you mean that you're using the some Allegro primitives library? If so then the issue is probably that you're introducing all sorts of unnecessary overhead. Drawing 360,000 quads using a plain OpenGL quadstrip should be lightning fast on any vaguely decent machine even if you're doing it straight from immediate mode. However, calling some crappy primitives library method call 360,000 times (which at the very least is going to include a GL.Begin / GL.End, and may even include modelview transformations) is not going to be fast.

Basically, if you want to do things properly learn OpenGL instead of relying on libraries built on top of it. :P

R S

I meant the same amount of drawing as in the same number of pixels get drawn, just in more parts. In both cases a 600x600 pixel display was completely redrawn, one in 6x6 squares, the other in 1x1 squares.

The actual accessing of the data from the matrix isn't the slow part here, as I can read it all to a standard array in preparation to dump that to a text file in vastly less time than this is now taking.

By "Use the primitives low-level drawing routines" thats what I'm already doing as far as I know, using al_draw_filled_rectangle(...).

I've tried using the primitives drawing both directly onto the display backbuffer and also onto an intermediary bitmap and both gave the same speed results.

I'll have a go on doing putpixel on a locked bitmap and scaling up. This may well be the most efficient solution if there isn't a way to do it directly with the primitives.

EDIT: James, if there isn't a way to solve this issue within allegro, is it possible to incorporate some OpenGL directly into an allegro project for something as simple as drawing a shedload of squares to an existing allegro display? If so, how?

james_lohr
R S said:

is it possible to incorporate some OpenGL directly into an allegro project for something as simple as drawing a shedload of squares to an existing allegro display? If so, how?

There's probably nothing stopping you calling OpenGL directly; however, if you want to maintain compatibility with other rendering backends (i.e. software and DirectX), it's going to be a bit more work.

Either way, what you are doing sounds very basic and should be trivial in whatever.

[edit]

Just had a look at the primitives code, and yeah: looooads of overhead. You certainly don't want to be using it if you're drawing more than a few thousand primitives.

SiegeLord
R S said:

By "Use the primitives low-level drawing routines" thats what I'm already doing as far as I know, using al_draw_filled_rectangle(...).

No, low level routines are al_draw_prim and al_draw_indexed_prim. The others are high level routines. In your case you'd use al_draw_prim with a ALLEGRO_PRIM_TRIANGLE_LIST primitive type. See ex_prim for usage.

Trent Gamblin

Just had a look at the primitives code, and yeah: looooads of overhead. You certainly don't want to be using it if you're drawing more than a few thousand primitives.

What do you mean? What part of the primitives addon? You can use al_draw_prim with ALLEGRO_PRIM_POINT_LIST and it boils down to a single glDrawArrays call...

james_lohr

You can use al_draw_prim with ALLEGRO_PRIM_POINT_LIST and it boils down to a single glDrawArrays call..

You said it. ;)

The point is that not all of the setup (texture binding, glEnables/Disables and transformations) is always necessary. I'm not saying that there is anything wrong with the primitives addon by the way. This is more of a case of it being misused, but for drawing a large number of very small primitives, it is going to be very inefficient, even using the "low-level" routines like al_draw_prim.

Elias

The performance advantage may be negligible though. Basically something like:

lots of al_draw_bitmap calls << al_draw_prim <= glDrawArrays

Of course if with OpenGL you would try to keep all the vertices on the GPU in a VBO or things like that, using it directly will be an advantage.

Trent Gamblin

The point is that not all of the setup (texture binding, glEnables/Disables and transformations) is always necessary.

It's done once per call. You seem to be saying that for larger numbers of primitives it's less efficient, but it gets more efficient the more primitives you draw. The only thing better is a vbo like Elias said, but you can't always use vbos.

james_lohr

I'm saying that calling al_draw_prim repeatedly is much slowing that calling the OpenGL directly for the particular problem at hand.

For example, assuming what the OP is trying to do is to draw a matrix of solid squares, then this could be done with a single call to GL_QUADS, setting the colour every 4th vertex. This is going to be much much faster than calling al_draw_prim individually for every quad.

Elias said:

The performance advantage may be negligible though.

It's not though, hence this thread.

Trent Gamblin

Ok, but you're comparing apples and oranges... drawing a bunch of GL_QUADS directly with gl calls is going to be negligibly different from al_draw_prim with ALLEGRO_PRIM_TRIANGLE_LIST.

james_lohr

Sure, drawing it all using a vertex array, an ALLEGRO_PRIM_TRIANGLE_LIST and a single call to al_draw_prim is going to do the job: it would appear that al_draw_prim is a little more flexible than I gave it credit.

I had glanced at the code and in the absence of GL_QUADS, I had made a few unfair assumptions of what was there.

Trent Gamblin

Well we don't support GL_QUADS simply because not all of the platforms we target (OpenGL ES) support quads.

Thread #609524. Printed from Allegro.cc