pyglet.graphics.Batch slower than display list

555 views
Skip to first unread message

Adam Griffiths

unread,
Sep 5, 2012, 10:07:57 PM9/5/12
to pyglet...@googlegroups.com
I'm running Pyglet on OS-X (previously 10.7 and now 10.8).
The entire time I've been developing, I've found using Pyglet's Batch objects to be horrendously slow.

I have a demo program (it uses my framework PyGLy and Pyrr) which shows this.

The example renders 121 transparent cubes and allows you to toggle between render methods (Immediate, Batch, DL).
It also disables VSync and runs the render method as fast as possible

I get the following results:

OpenGL immediate mode: 38 fps
pyglet.graphics.Batch: 51 fps
OpenGL Display List: 99 fps

In my other demos (mesh_md2) using Batch made the performance drop to 10 fps.

Is this a known issue?

I see bug #314 was closed due to age. I have a feeling it wasn't really resolved.

Cheers,
Adam

Nathan

unread,
Sep 5, 2012, 11:10:36 PM9/5/12
to pyglet...@googlegroups.com
On Wed, Sep 5, 2012 at 8:07 PM, Adam Griffiths <adam.lw....@gmail.com> wrote:
I'm running Pyglet on OS-X (previously 10.7 and now 10.8).
The entire time I've been developing, I've found using Pyglet's Batch objects to be horrendously slow.


At the risk of hijacking the thread, how did you get it to work on 10.8?

~ Nathan 

Adam Griffiths

unread,
Sep 5, 2012, 11:36:23 PM9/5/12
to pyglet...@googlegroups.com
I wrote a post on installing Pyglet on OS-X on my site.

Essentially, I installed pythonbrew, virtualenv into the system python.

Then install 2.7 with pythonbrew and install Pyglet from the repository.

If I remember correctly, the problem people are having with 10.8 is the system python uses certain libs.
Avoid using it and you shouldn't have any problems.

Cheers,
Adam


--
You received this message because you are subscribed to the Google Groups "pyglet-users" group.
To post to this group, send email to pyglet...@googlegroups.com.
To unsubscribe from this group, send email to pyglet-users...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/pyglet-users?hl=en.

Adam Griffiths

unread,
Sep 9, 2012, 4:07:12 AM9/9/12
to pyglet...@googlegroups.com
No one?

Andreas Schiefer

unread,
Sep 9, 2012, 4:57:56 AM9/9/12
to pyglet...@googlegroups.com
I've quickly skimmed over your code and noticed a few things:

- in setup_scene, it seems that you call initialise_cube for each
position, so you create 121 batches (and display lists) containing one
cube, but only the last one gets stored in the global variable (but
this shouldn't affect the performance, it's just wasted work)

- in your render function, you draw the batch for each cube separately
- this amounts to 121 draw calls, each only drawing a single cube (and
possibly the vertex buffer for the batch gets rebound for each draw
call too, which can be expensive)

The idea of batches is to draw as much geometry as possible in a
single draw call, so I guess you would get much better performance if
you put all your cubes into a single batch and draw them with a single
draw call.
Your current way of rendering might be acceptable if you have some
complex geometry in each batch, but I think the cube is just too
simple to take advantage of batched rendering - the overhead of the
batch is probably bigger than the actual render work.
> --
> You received this message because you are subscribed to the Google Groups
> "pyglet-users" group.
> To view this discussion on the web visit
> https://groups.google.com/d/msg/pyglet-users/-/dtmgnj7yn60J.

Adam Griffiths

unread,
Sep 9, 2012, 5:06:02 AM9/9/12
to pyglet...@googlegroups.com
Thanks for the response Andreas.
The code is just a quick'n'dirty, so excuse the trivial issues such as multiple initialisations.

The point of the example is to demonstrate the speed of various methods.
I'm trying to benchmark the Batch class by doing exactly what you stated, calling it 121 times.

Are you saying that it should be expected for 121 batch calls to be slower than 121 display list calls?

I haven't tried this test with pyglet's vertex_list object, which I'm using in other areas.
I've found using vertex_list is faster than Batch. Is this to be expected?


Cheers,
Adam

Andreas Schiefer

unread,
Sep 9, 2012, 6:02:04 AM9/9/12
to pyglet...@googlegroups.com
For simple, static geometries, yes, display lists will probably be
faster. But they cannot be changed and have some size limitations.
Also, as far as I know, some OpenGL drivers even emulate display lists
using their vertex buffer code.

On the other hand, vertex buffers as used by batches have some
overhead because the buffers have to be bound for the draw call etc.
(and you additionally store and restore some GL state, which you don't
do in the display list render path).
The advantage of vertex buffers is that you can change the data
dynamically (and their size is not really limited).

In an ideal case, you put all your geometry into one vertex buffer,
bind it once during setup and draw everything with a single draw call
in the render loop.
Switching between different buffers and storing and restoring GL state
are relatively expensive operations.


On Sun, Sep 9, 2012 at 11:06 AM, Adam Griffiths

Adam Griffiths

unread,
Sep 9, 2012, 7:21:58 AM9/9/12
to pyglet...@googlegroups.com
Thanks for the explanation.
I had assumed a Batch and vertex buffer would be roughly equivalent in terms of draw calls / overhead.
When I get time I'll try a Batch with more complex geometry.

So vertex buffers would be the way to go, and then merging those into a Batch when needed for larger geometries.

Because it's a 'glDrawBuffers' call (or equivalent), Batch can only have a single fragment, vertex and geometry shader bound before the draw call.
This would also be true for vertex buffers too.
Hence, some sorting by rendering by material.

Thanks for the help =)

Cheers,
Adam

Andreas Schiefer

unread,
Sep 9, 2012, 8:48:56 AM9/9/12
to pyglet...@googlegroups.com
I may have created some confusion by mixing terms without explaining.
I was mostly talking about OpenGL vertex buffers, not necessarily
pylget's classes.
A pyglet Batch is implemented in terms of an OpenGL vertex buffer, so
they should be roughly equivalent in terms of overhead and rendercalls
needed (though the Batch class does a few additional things).
Pyglet's Batch class allows to manage several separate (to the
programmer) list of vertices inside of a single OpenGL vertex buffer
object. This allows for more efficient rendering than using a seperate
vertex buffer for each list of vertices (because switching vertex
buffers is somewhat expensive). You can use pyglet's Group classes to
use e.g. different shaders while drawing one batch. Of course this
results in multiple draw calls internally, but keeps the advantage of
not switching vertex buffers. So basically, a Batch in pyglet is a
convenience class to manage multiple objects within a single OpenGL
vertex buffer.

If you want to render a single object multiple times, the best
OpenGL-way would be to use instanced rendering, but there is no pyglet
class which exposes this, you have to use the according OpenGL
functions directly.

In your example you have one Batch containing one object and you're
drawing this Batch multiple times. This does not exploit any of the
advantages of the Batch class, because for each draw call, the
underlying OpenGL vertex buffer is first bound, then rendered and
finally unbound again.
To take advantage of the Batch class, you can add the object multiple
times to the batch (at different positions), and render them using one
batch.draw() call. This way, the OpenGL vertex buffer is only bound
and unbound once (and everything is rendered in one draw call, except
if you use Groups for different shaders etc.).

If you only have one object and don't want to add it multiple times to
a Batch, then the Batch class is probably too much overhead because it
is designed to manage multiple objects in one OpenGL vertex buffer.

I hope that clears up any misconceptions I may have created. :-)



On Sun, Sep 9, 2012 at 1:21 PM, Adam Griffiths

Adam Griffiths

unread,
Sep 9, 2012, 9:52:50 AM9/9/12
to pyglet...@googlegroups.com
When I mentioned vertex list / buffers, I was actually referring to Pyglet's own classes.
So this actually confuses me more, as there appears to be a performance difference between Pyglet's vertex list and Batch, which according to your statements shouldn't be the case.

Let me update my example code and I'll get back to you.

Cheers,
Adam
Reply all
Reply to author
Forward
0 new messages