Also, not to be a downer here, but after all this talk about event
management, it’s probably worth noting that it’s not really broken, so I’m
not entirely clear on why we’re fixing it.
The parts that I feel are broken are:
- the SDL_Delay in SDL_WaitEvent
- the superfluous queueing (but keeping the necessary queueing, of course!)
- not being possible to wait for events at the same time as something
else (without threads (which is even more queueing), that is)
Note that none of this requires using callbacks, could all be done
with (I think) 100% compatibility with the 1.2 API, only adding new
functions (say, an SDL_WatchFD function similar to XtAppAddInput or
WSAAsyncSelect) which would be pretty much optional (one might expect
some to depend on the platform, say one to watch a Mach port, for
example), and could be added over time.
Having everything go through select() or whatever internally has a benefit
for power management and latency, but the callback thing is getting a little
silly. Can anyone tell me of a case where they ever legitimately lost
events that wasn’t either a bug in SDL (which we should fix) or a bug in
their application (which we should not conceal)?
Note again that whichever event lossage that could be helped does
not need the callbacks to be helped.
Why do I want them, then?
As I said before, it’s easier to make a callback oriented API (such as
Cocoa or BeOS) from an event pump oriented API (such as X11 and
Win32), as it’s pretty obvious. On BeOS, we start the main loop in a
separate thread, then posting back across to the main thread, on Cocoa
we use the hack where we run the whole SDL program from a callback,
since Cocoa also provides separate methods to get events in the style
of XNextEvent/GetMessage. In the worst case where an API wouldn’t
support these tricks, there are still more (increasingly crazier!)
tricks, like queueing down events and asking to exit the main loop
(could be done this way on Mac OS X, might have better integration
with a mixed application), or (brace for it!) using an alternate stack
to call the main loop and swapping the context.
(The “better integration” would allow us to just call
SDL_CreateWindowFrom, have it hook the listeners (on Cocoa), and just
let the main application loop do its normal work, being a “better
citizen”)
When you do the reverse, there’s no trickery, and you’re free to do
things very efficiently, as you’re just calling the callback right
away. If you’ve got an API that is callback oriented, then you don’t
have the potentially expensive trickery (like the queueing events,
then returning from the run loop). Again, it’s my argument that if
there’s something that you layer on, you can’t take it off if you
don’t want it, you have no choice. If you wanted to get an
SDL_PollEvent/SDL_WaitEvent (and I think we pretty much have to, even
though I think it’s generally inferior), you could get it if you
wanted, and accept that there might be an extra overhead.
A callback oriented API also has the efficiency/correctness advantage
that you can keep a minimal XSelectInput (or local equivalent) for
efficiency, without any doubt of having a mismatch or forgetting to
update it (setting the callback means you want it, unsetting it means
you don’t, that’s the end of it). The Xlib API does not work like
that, and check it out, SDL has this very bug in it (the safe “we just
get spurious unknown events”, thankfully):
http://lists.libsdl.org/pipermail/sdl-libsdl.org/2008-May/065066.html
But why I’m not running off with this is that all those trickeries to
make the callback oriented APIs work as an event pump API are kind of
platform-specific, so you wouldn’t necessarily be able to convert the
SDL version of the API back. And if the native SDL 1.3 API becomes
callback driven, paying the overhead to convert back to an event
pump API when the native API might already be an event pump API isn’t
exactly attractive…
What I’m thinking about is whether it could be made so that you can
choose at SDL_Init time which style you want, and SDL would provide
whatever you choosed as efficiently as it can (as I explained, the
callback style would basically be guaranteed to be as efficient as
possible, but the SDL_PollEvent style should be very efficient on X11
and Win32, say). But this is icky, as you might get two code paths in
the driver API for the platforms with the callback style API, and even
then, think of a platform like Mac OS X with a strange set-up (with
the SDLMain.m), etc…
I’m a bit disappointed, but I’m currently leaning toward doing this
with the current style of API, just fixing the three issues I pointed
out at the top.
If you’re not convinced that the latency in SDL_WaitEvent could be
better, try out the small test program attached to the following email
(X11-specific, of course, but does work on Mac OS X):
http://lists.libsdl.org/pipermail/sdl-libsdl.org/2008-May/065067.html
On my Mac, I had to put “#undef main” in front of the main function,
set the SDL_VIDEODRIVER environment variable to “x11”, and I used the
following command line to compile it:
gcc -O2 -F/Users/pphaneuf/Library/Frameworks
-I/Users/pphaneuf/Library/Frameworks/SDL.framework/Headers -framework
SDL -Wall -o sdlwait sdlwait.c
Try uncommenting the three METHOD_xxx (one at a time!), notice the
number at the beginning of the line (number of milliseconds since the
previous event was received) and the CPU usage results at the end (I
forgot the wall time! use “time ./sdlwait” to get the full story).
You’ll see that METHOD_WAIT has low CPU usage, but chunky latency
(multiple of 10 msec, plus a hair), METHOD_POLL has good latency, but
higher CPU usage, and METHOD_SELECT has both good latency and low
CPU usage (a tiny bit lower than METHOD_WAIT, actually!). I think that
if we cut out the event queue (and mutex operations!), it could be
even nicer and smoother, latency-wise (but should be equivalent on the
CPU).
So there is a way to do this better, even if we keep the exact same
external API (it changes), I really think we should at least do that!
But as a bonus, I think it’d be dead easy to get cheaper timers (not
using a thread or pushing events), and shouldn’t be too bad to add
something like WSAAsyncSelect.On Sun, Jan 11, 2009 at 7:43 PM, Ryan C. Gordon wrote:
–
http://pphaneuf.livejournal.com/