Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Primitive drawing - Allegro 4 vs 5

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Primitive drawing - Allegro 4 vs 5
Andrew Gillett
Member #15,868
January 2015

I am doing some experiments with Allegro 5, having previously been using Allegro 4. I'm porting a program which draws 2000 unfilled circles. I'm finding that it runs slower in Allegro 5 (latest stable version) - about 4ms for drawing vs 1ms in Allegro 4.

In Allegro 4 I was drawing to a memory bitmap and blitting to the screen. In Allegro 5 I am writing to the default display and calling al_flip_display.

I remember reading in the docs somewhere that the primitive functions are not well-optimised. Is there any way to speed this up? I tried drawing to an intermediate memory bitmap like in the old days and drawing that to the screen but it was incredibly slow. Should I have been locking it?

I am running on Windows 7.

beoran
Member #12,636
March 2011

What frame rate are you getting? It could be that the vertical retrace is seemingly slowing you down. How does it scale to 4000, 8000, ... circles?

Andrew Gillett
Member #15,868
January 2015

With no circles the render time is 0.3ms, with 4000 it is 10ms. The vsync is not included in the render timings.

Polybios
Member #12,293
October 2010

Well, you're comparing apples and oranges in a way.
A5 and A4 are completely different in their inner workings, as A5 is using the GPU to do most drawing. The GPU, as exposed through OpenGL and Direct3D, doesn't provide rendering of 'high level' primitives directly (such as circles), at least not in a standard way. It basically only knows how to draw triangles (and line segments). But it can do this very fast.

So what A5's primitives functions do is basically to calculate vertices (using the CPU) which are then passed to the GPU to do the rendering by "connecting" the vertices using either triangles or line segments.

That means that, internaly, al_draw_filled_circle / al_draw_circle just calls al_calculate_arc and pass the resulting vertices to al_draw_prim.

I think that having too many calls to al_draw_prim is not going to be terribly fast, since it probably involves some state changes. Generally, the GPU likes to be in one state (i. e. all parameters (textures, matrices, ...) set, only receiving vertex data (position, color, texture coordinates)). You could therefore maybe speed up the process by minimizing your al_draw_prim calls (remember that these happen behind the scenes anyway).
You could do that by putting more/many/all your vertices in a big buffer via al_calculate_arc and drawing this in not so many/fewer/one al_draw_prim calls. Depending on your geometry, you could also use a vertex buffer to store your vertex data directly on the GPU side of things. This is only supported by A 5.1 though.

SiegeLord
Member #7,827
October 2006
avatar

One optimization would be to create something akin to al_hold_bitmap_drawing, but for primitives... this would minimize the number of al_draw_prim calls. Without doing something akin to that, there's not much you can do currently.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Polybios
Member #12,293
October 2010

That would be a good thing to have... I've already run into similar issues.

Edit: It would only make sense if texture and vertex declaration would remain the same, wouldn't it? Maybe "splitting" al_draw_prim and friends into three functions (setup state, send (more) data, revert state) would also be an option? I can see that setup_state in prim_opengl.c already passes the vertex-array-pointer to OpenGL, though. So the pointer is actually part of the state... Hmm... You can already use the indexed versions... So maybe an optimization just for the high_primitives? All of the high_primitives.c drawing functions seem to use local vertex caches on the stack, so this would probably need to change. Maybe they could be made to send their vertices into an internal buffer that is drawn when full? But circles would need do draw triangle fans whereas... Well, whatever.

Other possible approaches to the OP's problem depend on what kind of circles he wants to draw.
If they're all the same size or if there are only a few different sizes, another possible solution would be to draw them to bitmaps (edit: one bitmap) first and then draw the bitmaps in one go with al_hold_bitmap_drawing. They could be white and drawn tinted if different colors are needed. That should be quite fast.
Or if their relative position doesn't change (which I doubt), they could be calculated into a big vertex array before, which is drawn in one al_draw_prim call with transformations enabled to move all of them around.
I doubt these are applicable though.

Chris Katko
Member #1,881
January 2002
avatar

Drawing circles is not an appropriate benchmark of what a GPU can do. If all you need is circles, buy a circle drawing card.

I'm joking, but you get the point. Synthetic benchmarks are not automatically valid predictors of real-world performance. There's some great books full of exceptions that can make a benchmark useless.

There are a few use cases where Allegro 4 can be faster (lots of per-pixel manipulation). But I've recently run an Allegro 5 program where I drew thousands of 1x1 blended rectangles to draw single pixel rain and it still ran at maximum FPS; so, I'm not even sure that's the case anymore unless you're doing something wrong.

Usually, people coming from Allegro 4 still have the "allegro 4 mindset" and don't understand that modern graphics are done much differently, and that your game should be structured to reflect that.

For example:

The vsync is not included in the render timings.

Just because you didn't ask for it, doesn't mean it's not on. Drivers can both assume a default if you didn't ask, and override it if you did ask.

Secondly, your drawing routines may be slower initially, but do they linearly grow in time? It's entirely possible your modern graphics have a higher initial overhead, but scale much better. Try higher numbers of circles. What happens to both the A4 and A5 versions?

Let's be clear: It's entirely possible you're spot on and there's something wrong or broken in A5 making it slower. But in most cases, it's a user doing things wrong.

So:
- Please list your hardware
- Please post the minimal amount of code that replicates the issue, formatted in < code> tags

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs

SiegeLord
Member #7,827
October 2006
avatar

Polybios said:

So maybe an optimization just for the high_primitives? All of the high_primitives.c drawing functions seem to use local vertex caches on the stack, so this would probably need to change. Maybe they could be made to send their vertices into an internal buffer that is drawn when full? But circles would need do draw triangle fans whereas... Well, whatever.

Yes, it's for high primitives only. There'd be a new thread-local or perhaps display-local vertex buffer just like with bitmaps. Everything would be drawn using indexed triangle lists.

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Thomas Fjellstrom
Member #476
June 2000
avatar

SiegeLord said:

Everything would be drawn using indexed triangle lists.

I could really use some code like that, but for 3D shapes :o take a line, and make some triangles out of it to make a line you can see from all sides, and store it in the same vbo as other shapes...

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Chris Katko
Member #1,881
January 2002
avatar

and make some triangles out of it to make a line you can see from all sides, and store it in the same vbo as other shapes...

Wouldn't that be fairly easy with bill-boarded sprites / triangles? (Always facing the screen.)

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs

Thomas Fjellstrom
Member #476
June 2000
avatar

Wouldn't that be fairly easy with bill-boarded sprites / triangles? (Always facing the screen.)

Yeah, I suppose. I'd have to regenerate them every frame to do that though.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Edgar Reynaldo
Member #8,592
May 2007
avatar

In my model viewer I didn't have any problem with lines being obscured. They respected the z buffer afaics. Of course they're ultra thin though.

And as far as A4 vs A5 goes, you have to understand the fundamental differences between them in order to make full use of their capabilities.

If you're making 50,000 circles with each calling al_draw_prim, that will take much longer than batching up all your geometry into a vertex buffer of some sort and drawing it with a single al_draw_prim. It should be much faster. So try precalculating all your vertices and adding them into a vector or something and then draw them all at once.

Thomas Fjellstrom
Member #476
June 2000
avatar

In my model viewer I didn't have any problem with lines being obscured. They respected the z buffer afaics. Of course they're ultra thin though.

If you have culling turned on properly, if you go behind a poly, it will disappear completely. So you either need to regen it to face the camera, or make four, so it shows up from the four cardinal directions. could do a cross shape or a box. One use for it is to show the "block" or object you're looking at by drawing a wire frame around it. or draw chunk boundaries, or other debugging aids. And I'd like to share a single VBO for all of the different primitive shapes I'd like to draw (cubes, wire frames, lines, etc).

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Edgar Reynaldo
Member #8,592
May 2007
avatar

Chris Katko
Member #1,881
January 2002
avatar

So you either need to regen it to face the camera, or make four, so it shows up from the four cardinal directions

I wonder how distance comes into play. You want distance so that a line has depth (think parallax effect looking down a very long spring), but you don't want the volume of the line to change, do you? Because at a distance, it'll disappear.

I guess it depends what you mean when you say you want "a line" in 3-D.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs

Thomas Fjellstrom
Member #476
June 2000
avatar

I thought hairlines didn't have any kind of facing?

How do you draw hairlines with triangles? :o

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Edgar Reynaldo
Member #8,592
May 2007
avatar

I was using al_draw_prim with ALLEGRO_PRIM_LINE_LIST. I wasn't drawing triangles, but I guess that's what we are talking about here. It might work for you though, to draw lines instead of triangles. But you want an actual poly shape though, right? You could draw a triangular prism - that's only 5 faces, or a rectangular prism, with 6 faces.

Edit - we can discuss this on IRC if you like, instead of spamming this thread with OT stuff.

beoran
Member #12,636
March 2011

I've been doing 3D drawing with al_draw_indexed_prim and it works nicely, but even better performance would be nice. Something like al_hold_prim_drawing and a per-destination bitmap vbo buffer would be great... :) But yes, we're going off topic.

For the circle problem al_draw_indexed_prim() is a good solution, if you regenerate the point lists every time. You'll have to calculate the circle points yourself but you can easily color and texture the result.

Andrew Gillett
Member #15,868
January 2015

Quote:

Chris Katko

Let me be more clear about my question. I am working on a game in Allegro 4, whose graphics are drawn purely using primitives. I'm aware that the world has moved on from pixel-based drawing but I'm curious to find out if the performance of my game in Allegro 5 will be better, worse or the same. I never said there was anything wrong or broken about AL5, although the docs admit that primitive drawing is not well-optimised. I could carry on using Allegro 4 but there is an issue with it which on my machine causes the mouse to become ultra-laggy in the debugger, making debugging almost impossible (discussed on this forum earlier this year).

When I said the vsync is not included in the render timings, I meant that I am using QueryPerformanceCounter in Windows to measure the time taken to make all the draw calls. The call to al_flip_display is outside this timed section.

For my current project, small filled rectangles are more important than circles, so I have updated my test program to draw those instead. The performance is comparable to how it was before.

AL5:
5,000: 14.3ms
10,000: 25.9ms
20,000: 47ms

AL4:
5,000: 3ms
10,000: 3.7ms
20,000: 4.8ms

I will look into the suggestions that people have made on this thread.

My hardware is Intel Core i3-3220, with Intel HD onboard graphics.

beoran
Member #12,636
March 2011

If it's rectangles, why not try to cheat and stretch/blit a bitmap with a border in it? Blitting of bitmaps is well optimized in Allegro5 :)

Andrew Gillett
Member #15,868
January 2015

Just tried drawing rectangles with a single call to al_draw_prim, draw time for 20,000 is 10ms.

EDIT: After some optimisation, got it down to 6.5ms.

Thomas Fjellstrom
Member #476
June 2000
avatar

A blit is likely to be even faster :)

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Andrew Gillett
Member #15,868
January 2015

Do you mean with al_draw_bitmap? Draw time was 25ms for 20,000.

Thomas Fjellstrom
Member #476
June 2000
avatar

Do you mean with al_draw_bitmap? Draw time was 25ms for 20,000.

Now turn on held drawing via al_hold_bitmap_drawing :) and batch drawing that use the same textures together. either sort by texture, or use atlasing to put all images in the same larger texture.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Andrew Gillett
Member #15,868
January 2015

With al_hold_bitmap_drawing, draw is 6.5ms - same as using a single al_draw_prim call.

 1   2 


Go to: