SDL_WaitEvent in 1.3

In the bad old days artists used Macs over windows for one main
reason. On the Mac when you drew with the mouse or a tablet you got
the curve you drew. On Windows you sometimes got what you drew and you
sometimes got long straight segments because Windows coalesced mouse
motion events. In X there was a configuration flag so that it would
either coalesce mouse motion or not, so that X could behave more like
a Mac, or more like WIndows.

From a user point of view, coalesced mouse motion events can be a
serious problem.

I’m not sure about the old school Mac OS, but with X11, you have to
use a separate API that SDL does not use at all (when you get a Motion
event, you call XGetMotionEvents with the events timestamps to get the
detailed history of what happened in between that Motion event and the
one before it), so we’re not losing anything that we had… The X
server always does coalescing for the Motion events themselves, but it
does put one in the queue “once in a while”, it doesn’t do something
like put them in only when there’s nothing else, from what I remember.On Tue, Jan 13, 2009 at 1:23 PM, Bob Pendleton wrote:


http://pphaneuf.livejournal.com/

I have seen a lot of ideas flowing back and forth during this
discussion. I think the problem is that many of the ideas have been
kind of mixed together so it is hard to talk about them and there is a
lot of muddling going on because some people like call backs and some
like a queue and so the real ideas are being confused with those two
nearly equivalent methods of delivering events. I also think there
has been a bit much focus on the details of specific implementations
and not enough focus on the differences between the different possible
implementations. SDL has to work across at least 3 main OSes and a
bunch of others and the differences are what cause many of the design
decisions.

By the way, I’m going with the “get next event” way (AKA “the current
way”) rather than “register callbacks then call a run loop” way.

And you are quite right that they are mostly equivalent (what I call
callback-driven is still synchronous, the callbacks happen one after
the other, and so on).

I’m just going to remove the SDL event queue from the main code path
(leaving it for inter-thread communication, and a few other special
occasions). Even when not using the SDL event queue, I know there will
still be queueing, just not done by us.

Before I go on I want to make sure that people understand why there
are queues anywhere in any system. They are there to buffer the
difference in production and consumption rates between the things at
each end of the queue. Why do we stand in a queue to buy movie tickets
(Ok, the real answer is because we didn’t think to buy them online
:-)? Because the people selling tickets can process each transaction
in about the same amount of time but people show up at a random rate.

Oh, here’s an analogy I can reuse! Using the SDL queue is like
standing in a queue (the OS queue) to get a ticket with a number, then
going in a waiting room (the SDL event queue) until they call your
number (still just one at a time). My point is that events don’t mind
standing up (and in fact, the “sitting down” involves copying data,
which isn’t free), we’d be better off just dealing with them instead
of giving them a ticket. :slight_smile:

  1. The current implementation of the event queue in SDL adds latency.

No. The current implementation of SDL_WaitEvent adds latency. If your
application does not use SDL_WaitEvent, then you’re safe from that
latency (and you’re probably eating all the CPU, which might be okay
if you’re writing a first-person shooter, but less so if you’re
writing a dinky action puzzle game).

  1. The current implementation of the event queue in SDL is based on a
    10+ year old world view. The hardware and the related OS APIs have
    changed since it was originally written.

It’s a bit more subtle and weird than this. The hardware and APIs are
pretty much the same as 10 years ago (NextStep/Cocoa was first
available in 1986, and programs from 1990ish still mostly compile and
run!), but game developers were still programming their games based on
a 10+ years old world view back then (assuming PIO, and asking
things like “how can I wait for the vertical retrace?”), so SDL
catered to them (which is quite the right thing to do).

I was kind of hoping that things (well, mindsets) had changed, and it
seems that it isn’t really the case. So it’s worth making the extra
effort to provide what game developers expect (and I can stack my own
callback dispatch on top if I feel like it).

  1. Using the newer APIs it may be possible to get rid of the SDL queue
    completely and just use the platform APIs.
    I.e. it may be possible to make the current event oriented SDL API
    into a thin layer over existing OS/Platform APIs.

It could be possible to get rid of the SDL queue completely, but I
think it would enforce too many restrictions (basically, the
intersection of what you can put in a “user message” event on all the
supported platforms, and this could potentially shrink when adding
another platform, which would kill backward compatibility), so I’d
still keep one, but it would only used for the SDL_PushEvent messages,
so essentially, messages coming from other threads, most of the time,
or synthetic messages (pretty rare, I’d venture).

To ensure an effect similar to the condition variable that you used in
fastevents, the driver for each platform would have to supply a “wake
up SDL_WaitEvent” method, which could potentially use a "user message"
event specific to the platform that just says “hey, go look at the SDL
queue, there’s stuff for you there!”.

After that it starts getting real confusing to me… :slight_smile: It seems some
of the APIs would are best suited to be used in a callback based event
delivery system and some are best suited to delivering events into a
queue. And, of course it is easy to use callbacks to deliver events to
a queue and equally easy to use a queue to make call backs.

It’s the last bit I disagree with. It’s not equally easy to use
callbacks to deliver events to a queue than to fetch events from a
queue to dispatch callbacks. But it’s not so ridiculously difficult
that I’m not willing to pay the small overhead so that everyone is
much happier and SDL is successful.

Basically, there’s two forces: we’d like SDL to be as close to the
metal as possible, while providing an API/behaviour that’s as
consistent as possible from one platform to the other, and we want the
API provided by SDL to be as flexible as possible so that games can be
ported to it and written for it easily. Callbacks favour the former,
and SDL_PollEvent/SDL_WaitEvent favours the latter, and I think the
little bit of “padding” between the metal and the SDL user isn’t
significant enough after all to limit the flexibility of the API so
much (remember that it’s easy to convert a queue API into a callback
API, but the reverse less so, so if we provide a callback interface,
the pain will be for the application rather than us).On Tue, Jan 13, 2009 at 1:14 PM, Bob Pendleton wrote:


http://pphaneuf.livejournal.com/

What exactly do you mean by this? Use no uncertain terms, please. Are
you talking about altering applications? Altering a library? Easier
for the programmer? Easier for the computer?On Tue, Jan 13, 2009 at 4:37 PM, Pierre Phaneuf wrote:

(remember that it’s easy to convert a queue API into a callback
API, but the reverse less so, so if we provide a callback interface,
the pain will be for the application rather than us).


http://codebad.com/

(remember that it’s easy to convert a queue API into a callback
API, but the reverse less so, so if we provide a callback interface,
the pain will be for the application rather than us).

What exactly do you mean by this? Use no uncertain terms, please. Are
you talking about altering applications? Altering a library? Easier
for the programmer? Easier for the computer?

Converting from callback to queue is both harder on the programmer and
on the computer.

If you only have a callback API (Cocoa prefers that, but also has a
queue API, which is what we use now, only BeOS doesn’t have a queue
API at all, from what I can see) and want to convert to a queue API,
you have to register callbacks which will put the information in the
SDL queue, and tell the run loop to exit as soon as possible,
unwinding the stack back to where you started it, where you can then
start returning what you find in the SDL queue. There is a processing
overhead (more copying of events, additional function calls), as well
as the complications of doing this (which differs depending on the
callback API, and so on).

If you have a queue API and you want to convert to a callback API, you
just make a “RunLoop” function that has a “while (1)” loop that gets
one event from the queue, then calls the appropriate callback (no need
to even package things in an SDL_Event, if the callback parameters
happens to be something like “int dx, int dy”, say, for a mouse motion
event). That’s it.

Obviously, if both the platform and SDL had callback APIs, then SDL
would just register callbacks that would just massage the event
information appropriately (more or less the same as is we pulled one
event from the OS queue and returned it from SDL_PollEvent) and pass
it on to the application callbacks, so there’s just about zero
overhead there.

What I meant by my previous comment is that we already do the hard
work of converting those callback APIs to the queue-style API of SDL,
but if we changed SDL to be a callback API, all of this code would
disappear, but would have to appear in the applications that wanted a
queue API (“the pain will be for the application rather than for us”).
Since people already live well with those overheads, and the code is
already written anyway, I figure we should keep this style, rather
than break the API in a very disruptive way.

We’ll have to live with 0.4% less efficiency than we could on some
platforms. ;-)On Tue, Jan 13, 2009 at 6:05 PM, Donny Viszneki <donny.viszneki at gmail.com> wrote:


http://pphaneuf.livejournal.com/

(remember that it’s easy to convert a queue API into a callback
API, but the reverse less so, so if we provide a callback interface,
the pain will be for the application rather than us).

What exactly do you mean by this? Use no uncertain terms, please. Are
you talking about altering applications? Altering a library? Easier
for the programmer? Easier for the computer?

Converting from callback to queue is both harder on the programmer and
on the computer.

If you only have a callback API (Cocoa prefers that, but also has a
queue API, which is what we use now, only BeOS doesn’t have a queue
API at all, from what I can see) and want to convert to a queue API,
you have to register callbacks which will put the information in the
SDL queue, and tell the run loop to exit as soon as possible,
unwinding the stack back to where you started it, where you can then
start returning what you find in the SDL queue. There is a processing
overhead (more copying of events, additional function calls), as well
as the complications of doing this (which differs depending on the
callback API, and so on).

Reading what you’ve said here, I get the impression that the scenario
you describes requires entering some function before any of your
callbacks can be invoked, as opposed to having them entered
asynchronously (as in a signal handler,) is that what you’re saying?

I couldn’t understand what you’ve been saying this whole thread
because I thought you were talking about asynchronous callback
invocation and it didn’t make any sense to me that there was much
programmer difficulty or CPU overhead to just register callbacks that
push data into a queue!

As I think you might have mentioned before, I suppose you could
switch between different stacks and jump the PC around to get the
asynchronous callback behavior from within a synchronous callback.
Neither of these scenarios seems desirable, so now I finally
understand what you were trying to say.

If you have a queue API and you want to convert to a callback API, you
just make a “RunLoop” function that has a “while (1)” loop that gets
one event from the queue, then calls the appropriate callback (no need
to even package things in an SDL_Event, if the callback parameters
happens to be something like “int dx, int dy”, say, for a mouse motion
event). That’s it.

Sounds like GLUT

Obviously, if both the platform and SDL had callback APIs, then SDL
would just register callbacks that would just massage the event
information appropriately (more or less the same as is we pulled one
event from the OS queue and returned it from SDL_PollEvent) and pass
it on to the application callbacks, so there’s just about zero
overhead there.

What I meant by my previous comment is that we already do the hard
work of converting those callback APIs to the queue-style API of SDL,
but if we changed SDL to be a callback API, all of this code would
disappear, but would have to appear in the applications that wanted a
queue API (“the pain will be for the application rather than for us”).
Since people already live well with those overheads, and the code is
already written anyway, I figure we should keep this style, rather
than break the API in a very disruptive way.

We’ll have to live with 0.4% less efficiency than we could on some
platforms. :wink:

Couldn’t we provide an API that invokes user-defined callbacks
asynchronously on platforms which support such a thing (did you
suggest that BeOS does?) but which get called synchronously from
inside some the event pump? The default callback functions could
simply push data into the queue, thus supporting the queue-style API,
a synchronous callback API (which you seem to prefer,) an asynchronous
callback API (which I would really like to see,) and any mix of
callbacks and event queueing?On Tue, Jan 13, 2009 at 7:04 PM, Pierre Phaneuf wrote:

On Tue, Jan 13, 2009 at 6:05 PM, Donny Viszneki <@Donny_Viszneki> wrote:


http://codebad.com/

A bit of a clarification:

Couldn’t we provide an API that invokes user-defined callbacks
asynchronously on platforms which support such a thing (did you
suggest that BeOS does?) but which get called synchronously from
inside some the event pump? The default callback functions could

clarification: inside some the event pump (on platforms that don’t
support asynchronous callback invocation?) The default callback
functions couldOn Tue, Jan 13, 2009 at 8:09 PM, Donny Viszneki <@Donny_Viszneki> wrote:

simply push data into the queue, thus supporting the queue-style API,
a synchronous callback API (which you seem to prefer,) an asynchronous
callback API (which I would really like to see,) and any mix of
callbacks and event queueing?


http://codebad.com/


http://codebad.com/

Reading what you’ve said here, I get the impression that the scenario
you describes requires entering some function before any of your
callbacks can be invoked, as opposed to having them entered
asynchronously (as in a signal handler,) is that what you’re saying?

Yes, such as [NSApplication run], CFRunLoopRun() or
BApplication::Run(). Asynchronous event delivery is rather uncommon.
In fact, I can’t think of a platform where they are even remotely
commonly used, and where I can think of them being used, they’re
basically only used to set a flag for the main thread to notice and do
not do any actual processing (they usually have onerous restrictions
on what they can safely do).

I couldn’t understand what you’ve been saying this whole thread
because I thought you were talking about asynchronous callback
invocation and it didn’t make any sense to me that there was much
programmer difficulty or CPU overhead to just register callbacks that
push data into a queue!

Ah, no, not that! If that was the case, then we’d be done with just
sticking a semaphore on the event queue. :slight_smile:

As I think you might have mentioned before, I suppose you could
switch between different stacks and jump the PC around to get the
asynchronous callback behavior from within a synchronous callback.
Neither of these scenarios seems desirable, so now I finally
understand what you were trying to say.

Yeah, I mean, it’s all theoretically equivalent, but juggling
alternate stacks isn’t exactly in the “easy” category, usually. :wink:

If you have a queue API and you want to convert to a callback API, you
just make a “RunLoop” function that has a “while (1)” loop that gets
one event from the queue, then calls the appropriate callback (no need
to even package things in an SDL_Event, if the callback parameters
happens to be something like “int dx, int dy”, say, for a mouse motion
event). That’s it.

Sounds like GLUT

Yep, pretty much that style, in fact. An API like that is easy to
implement at top efficiency on top of pretty much any conceivable API,
and you can still floor the CPU by putting your "render a frame"
function as the idle callback.

Now, an exercise to the reader: implement an SDL backend on top of GLUT.

Me, I’m a bit of a bondage and discipline kind of guy. I like my C++,
with strict typing (no passing 42 to an enum parameter!), APIs that
guide me naturally toward the right path and that makes whole classes
of bugs inexpressible. Even more so if it is demonstrably more
efficient to implement on most platforms! So me, I long for an API
like GLUT’s (well, maybe not exactly like it, it’s a bit dated in
places).

But I guess that when Doom3 becomes open source, if it doesn’t happen
to be structured just the right way, it’d be a world of pain to port
it to SDL, where the current API can be hammered into any old game in
no time flat. That’s valuable!

We’ll have to live with 0.4% less efficiency than we could on some
platforms. :wink:

Couldn’t we provide an API that invokes user-defined callbacks
asynchronously on platforms which support such a thing (did you
suggest that BeOS does?) but which get called synchronously from
inside some the event pump? The default callback functions could
simply push data into the queue, thus supporting the queue-style API,
a synchronous callback API (which you seem to prefer,) an asynchronous
callback API (which I would really like to see,) and any mix of
callbacks and event queueing?

Nah, BeOS doesn’t do it asynchronously, you call BApplication::Run
from your main, and it never returns, calling the callbacks and so on,
just like GLUT. But BeOS was designed with a “yay threads!” mindset,
so they don’t mind us spinning it on a separate thread (that’s what
SDL does there) and pushing the events to the SDL_Event queue from
there.

Asynchronous callbacks are pretty nutty.

You can make a system where callbacks are dispatched concurrently by
using a thread pool where each thread blocks on a single event queue,
and having the main thread pump the events into it, either by calling
something like SDL_PumpEvents of today, or by hooking up a bunch of
callbacks that puts the events on the queue immediately, so that they
spend basically no time doing processing, just pushing on the queue as
fast as possible. But there’s many platforms (including popular ones
like Win32, if I’m not mistaken?) where many graphic calls are not
thread-safe… Hence the many admonitions in SDL where it says “this
can only be called from the main thread”, including for SDL_PumpEvents
(both SDL_PollEvent and SDL_WaitEvent call that one in their
implementation).

That’s what I was thinking about for a while, whether we could make it
so that with SDL 1.3, you could use which ever one you preferred, but
this proved to be rather complex, with very different codepaths
(meaning a lot of work to maintain the various SDL ports).On Tue, Jan 13, 2009 at 8:09 PM, Donny Viszneki <donny.viszneki at gmail.com> wrote:


http://pphaneuf.livejournal.com/

In the bad old days artists used Macs over windows for one main
reason. On the Mac when you drew with the mouse or a tablet you got
the curve you drew. On Windows you sometimes got what you drew and you
sometimes got long straight segments because Windows coalesced mouse
motion events. In X there was a configuration flag so that it would
either coalesce mouse motion or not, so that X could behave more like
a Mac, or more like WIndows.

From a user point of view, coalesced mouse motion events can be a
serious problem.

I’m not sure about the old school Mac OS, but with X11, you have to
use a separate API that SDL does not use at all (when you get a Motion
event, you call XGetMotionEvents with the events timestamps to get the
detailed history of what happened in between that Motion event and the
one before it), so we’re not losing anything that we had… The X
server always does coalescing for the Motion events themselves, but it
does put one in the queue “once in a while”, it doesn’t do something
like put them in only when there’s nothing else, from what I remember.

Well, from what I remember… I did something like 5 X server ports
but the last one was between '91 and '93… so really, from what I
remember… The servers I worked on always put a motion event on the
queue if the top item on the queue wasn’t already a motion event. If
the top item was a mouse motion event and the mouse buttons hadn’t
changed, then you coalesced the motion and updated the time stamp.
Because the raw mouse motion events were coming out of a device queue
that did not have time stamps, the time stamps were never accurate,
only approximate. In fact, the time stamps were often generated by
just adding 1 to the previous time stamp. The correct time was queried
often enough to make sure there was some correspondence between the
time stamps and real time.

As for XGetMotionEvents, does anyone actually implement that API? I
always implemented the query for the buffer size to return 0 (zero).
The lack of accurate time stamps for motion events made it impossible
to provide correct information and the extra space was a problem back
then. Remember, back in the late '80s technology had just gotten to
where you could get 1 million transistors on a chip. Today, we just
passed the point where we can get 1 billion transistors on a chip so
resource “cost” 1/1000 of what they did back then.

Bob PendletonOn Tue, Jan 13, 2009 at 1:20 PM, Pierre Phaneuf wrote:

On Tue, Jan 13, 2009 at 1:23 PM, Bob Pendleton <@Bob_Pendleton> wrote:


http://pphaneuf.livejournal.com/


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+

I have seen a lot of ideas flowing back and forth during this
discussion. I think the problem is that many of the ideas have been
kind of mixed together so it is hard to talk about them and there is a
lot of muddling going on because some people like call backs and some
like a queue and so the real ideas are being confused with those two
nearly equivalent methods of delivering events. I also think there
has been a bit much focus on the details of specific implementations
and not enough focus on the differences between the different possible
implementations. SDL has to work across at least 3 main OSes and a
bunch of others and the differences are what cause many of the design
decisions.

By the way, I’m going with the “get next event” way (AKA “the current
way”) rather than “register callbacks then call a run loop” way.

And you are quite right that they are mostly equivalent (what I call
callback-driven is still synchronous, the callbacks happen one after
the other, and so on).

Ok, I did not understand that that was what you meant. I was thinking
you meant to use callbacks driven from either the device driver or
from a thread processing something like a loop with a select() in it.
The difference between what you are talking about and what I was
thinking about are enough quite large and seem to be the main source
of misunderstanding, at least on my part.

I’m just going to remove the SDL event queue from the main code path
(leaving it for inter-thread communication, and a few other special
occasions). Even when not using the SDL event queue, I know there will
still be queueing, just not done by us.

Now that I believe I understand what you are talking about I believe I
like where you are going with this.

Before I go on I want to make sure that people understand why there
are queues anywhere in any system. They are there to buffer the
difference in production and consumption rates between the things at
each end of the queue. Why do we stand in a queue to buy movie tickets
(Ok, the real answer is because we didn’t think to buy them online
:-)? Because the people selling tickets can process each transaction
in about the same amount of time but people show up at a random rate.

Oh, here’s an analogy I can reuse! Using the SDL queue is like
standing in a queue (the OS queue) to get a ticket with a number, then
going in a waiting room (the SDL event queue) until they call your
number (still just one at a time). My point is that events don’t mind
standing up (and in fact, the “sitting down” involves copying data,
which isn’t free), we’d be better off just dealing with them instead
of giving them a ticket. :slight_smile:

  1. The current implementation of the event queue in SDL adds latency.

No. The current implementation of SDL_WaitEvent adds latency. If your
application does not use SDL_WaitEvent, then you’re safe from that
latency (and you’re probably eating all the CPU, which might be okay
if you’re writing a first-person shooter, but less so if you’re
writing a dinky action puzzle game).

  1. The current implementation of the event queue in SDL is based on a
    10+ year old world view. The hardware and the related OS APIs have
    changed since it was originally written.

It’s a bit more subtle and weird than this. The hardware and APIs are
pretty much the same as 10 years ago (NextStep/Cocoa was first
available in 1986, and programs from 1990ish still mostly compile and
run!), but game developers were still programming their games based on
a 10+ years old world view back then (assuming PIO, and asking
things like “how can I wait for the vertical retrace?”), so SDL
catered to them (which is quite the right thing to do).

I was kind of hoping that things (well, mindsets) had changed, and it
seems that it isn’t really the case. So it’s worth making the extra
effort to provide what game developers expect (and I can stack my own
callback dispatch on top if I feel like it).

Mindsets are the hardest things in the known Universe.

  1. Using the newer APIs it may be possible to get rid of the SDL queue
    completely and just use the platform APIs.
    I.e. it may be possible to make the current event oriented SDL API
    into a thin layer over existing OS/Platform APIs.

It could be possible to get rid of the SDL queue completely, but I
think it would enforce too many restrictions (basically, the
intersection of what you can put in a “user message” event on all the
supported platforms, and this could potentially shrink when adding
another platform, which would kill backward compatibility), so I’d
still keep one, but it would only used for the SDL_PushEvent messages,
so essentially, messages coming from other threads, most of the time,
or synthetic messages (pretty rare, I’d venture).

Synthetic messages are used in the device code in SDL. In what your
are describing one platform event can become several SDL events.

To ensure an effect similar to the condition variable that you used in
fastevents, the driver for each platform would have to supply a “wake
up SDL_WaitEvent” method, which could potentially use a "user message"
event specific to the platform that just says “hey, go look at the SDL
queue, there’s stuff for you there!”.

After that it starts getting real confusing to me… :slight_smile: It seems some
of the APIs would are best suited to be used in a callback based event
delivery system and some are best suited to delivering events into a
queue. And, of course it is easy to use callbacks to deliver events to
a queue and equally easy to use a queue to make call backs.

It’s the last bit I disagree with. It’s not equally easy to use
callbacks to deliver events to a queue than to fetch events from a
queue to dispatch callbacks. But it’s not so ridiculously difficult
that I’m not willing to pay the small overhead so that everyone is
much happier and SDL is successful.

Two points: 1) in my previous (wrong) understanding of this they are
IMHO equally simple. 2) In this kind of a conversation “equal” is
defined the same way you define “equal” for floating point variables.
That is x == y if abs(x - y) < epsilon. Where epsilon is a matter of
opinion… :slight_smile:

Basically, there’s two forces: we’d like SDL to be as close to the
metal as possible, while providing an API/behaviour that’s as
consistent as possible from one platform to the other, and we want the
API provided by SDL to be as flexible as possible so that games can be
ported to it and written for it easily. Callbacks favour the former,
and SDL_PollEvent/SDL_WaitEvent favours the latter,

You lost me right here. Seems to me that I can just have WaitEvent()
check for pending events in the SDL queue and then return one, or if
that queue is empty, check to see if there is a pending platform event
and if so, return it. Then I need, as I believe you pointed out, a way
to wait for an event to appear in either of the queues. And, of course
this can be extended to as many queues as you like.PollEvent() just
skips the waiting part of the code.

BTW, why is WaitEvent() so important? In any code that does animation
you (or at least I) am going to use PollEvent(), never WaitEvent().

Bob PendletonOn Tue, Jan 13, 2009 at 3:37 PM, Pierre Phaneuf wrote:

On Tue, Jan 13, 2009 at 1:14 PM, Bob Pendleton <@Bob_Pendleton> wrote:

and I think the
little bit of “padding” between the metal and the SDL user isn’t
significant enough after all to limit the flexibility of the API so
much (remember that it’s easy to convert a queue API into a callback
API, but the reverse less so, so if we provide a callback interface,
the pain will be for the application rather than us).


http://pphaneuf.livejournal.com/


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+

Well, from what I remember… I did something like 5 X server ports
but the last one was between '91 and '93… so really, from what I
remember… The servers I worked on always put a motion event on the
queue if the top item on the queue wasn’t already a motion event. If
the top item was a mouse motion event and the mouse buttons hadn’t
changed, then you coalesced the motion and updated the time stamp.
Because the raw mouse motion events were coming out of a device queue
that did not have time stamps, the time stamps were never accurate,
only approximate. In fact, the time stamps were often generated by
just adding 1 to the previous time stamp. The correct time was queried
often enough to make sure there was some correspondence between the
time stamps and real time.

The timestamps don’t have to be strictly accurate (well, it’s always
better!), but the important is that if you keep the timestamp of the
last MotionNotify event you got, you can use it with the timestamp of
the MotionNotify event right after as the start/stop time for
XGetMotionEvents, and you’ll get whatever happened between those two
events in detail.

As for XGetMotionEvents, does anyone actually implement that API? I
always implemented the query for the buffer size to return 0 (zero).
The lack of accurate time stamps for motion events made it impossible
to provide correct information and the extra space was a problem back
then. Remember, back in the late '80s technology had just gotten to
where you could get 1 million transistors on a chip. Today, we just
passed the point where we can get 1 billion transistors on a chip so
resource “cost” 1/1000 of what they did back then.

Here, xdpyinfo tells me that I have a motion buffer size of 256
entries. I never did anything with it, though, so for all I know, you
might never actually get anything. :-)On Wed, Jan 14, 2009 at 6:35 PM, Bob Pendleton wrote:


http://pphaneuf.livejournal.com/

Reading what you’ve said here, I get the impression that the scenario
you describes requires entering some function before any of your
callbacks can be invoked, as opposed to having them entered
asynchronously (as in a signal handler,) is that what you’re saying?

Yes, such as [NSApplication run], CFRunLoopRun() or
BApplication::Run(). Asynchronous event delivery is rather uncommon.
In fact, I can’t think of a platform where they are even remotely
commonly used, and where I can think of them being used, they’re
basically only used to set a flag for the main thread to notice and do
not do any actual processing (they usually have onerous restrictions
on what they can safely do).

I couldn’t understand what you’ve been saying this whole thread
because I thought you were talking about asynchronous callback
invocation and it didn’t make any sense to me that there was much
programmer difficulty or CPU overhead to just register callbacks that
push data into a queue!

Yep, me too.

Ah, no, not that! If that was the case, then we’d be done with just
sticking a semaphore on the event queue. :slight_smile:

As I think you might have mentioned before, I suppose you could
switch between different stacks and jump the PC around to get the
asynchronous callback behavior from within a synchronous callback.
Neither of these scenarios seems desirable, so now I finally
understand what you were trying to say.

Yeah, I mean, it’s all theoretically equivalent, but juggling
alternate stacks isn’t exactly in the “easy” category, usually. :wink:

Depends on who you talk to. :slight_smile:

If you have a queue API and you want to convert to a callback API, you
just make a “RunLoop” function that has a “while (1)” loop that gets
one event from the queue, then calls the appropriate callback (no need
to even package things in an SDL_Event, if the callback parameters
happens to be something like “int dx, int dy”, say, for a mouse motion
event). That’s it.

Sounds like GLUT

It is GLUT

Yep, pretty much that style, in fact. An API like that is easy to
implement at top efficiency on top of pretty much any conceivable API,
and you can still floor the CPU by putting your "render a frame"
function as the idle callback.

Now, an exercise to the reader: implement an SDL backend on top of GLUT.

Been there, done that, then I found SDL. Seriously, my devotion to SDL
is only equaled (with a negative sign) by my dislike of GLUT.

Me, I’m a bit of a bondage and discipline kind of guy. I like my C++,
with strict typing (no passing 42 to an enum parameter!), APIs that
guide me naturally toward the right path and that makes whole classes
of bugs inexpressible. Even more so if it is demonstrably more
efficient to implement on most platforms! So me, I long for an API
like GLUT’s (well, maybe not exactly like it, it’s a bit dated in
places).

GLUT and similar APIs are designed around the GUI and IMHO ignore the
rest of the program. And, frankly, they don’t do that good a job on
the GUI.

But I guess that when Doom3 becomes open source, if it doesn’t happen
to be structured just the right way, it’d be a world of pain to port
it to SDL, where the current API can be hammered into any old game in
no time flat. That’s valuable!

Which is not an argument, it doesn’t even belong in this discussion.

We’ll have to live with 0.4% less efficiency than we could on some
platforms. :wink:

Couldn’t we provide an API that invokes user-defined callbacks
asynchronously on platforms which support such a thing (did you
suggest that BeOS does?) but which get called synchronously from
inside some the event pump? The default callback functions could
simply push data into the queue, thus supporting the queue-style API,
a synchronous callback API (which you seem to prefer,) an asynchronous
callback API (which I would really like to see,) and any mix of
callbacks and event queueing?

Nah, BeOS doesn’t do it asynchronously, you call BApplication::Run
from your main, and it never returns, calling the callbacks and so on,
just like GLUT. But BeOS was designed with a “yay threads!” mindset,
so they don’t mind us spinning it on a separate thread (that’s what
SDL does there) and pushing the events to the SDL_Event queue from
there.

Asynchronous callbacks are pretty nutty.

You can make a system where callbacks are dispatched concurrently by
using a thread pool where each thread blocks on a single event queue,
and having the main thread pump the events into it, either by calling
something like SDL_PumpEvents of today, or by hooking up a bunch of
callbacks that puts the events on the queue immediately, so that they
spend basically no time doing processing, just pushing on the queue as
fast as possible. But there’s many platforms (including popular ones
like Win32, if I’m not mistaken?) where many graphic calls are not
thread-safe… Hence the many admonitions in SDL where it says “this
can only be called from the main thread”, including for SDL_PumpEvents
(both SDL_PollEvent and SDL_WaitEvent call that one in their
implementation).

That’s what I was thinking about for a while, whether we could make it
so that with SDL 1.3, you could use which ever one you preferred, but
this proved to be rather complex, with very different codepaths
(meaning a lot of work to maintain the various SDL ports).


http://pphaneuf.livejournal.com/


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Bob PendletonOn Tue, Jan 13, 2009 at 11:02 PM, Pierre Phaneuf wrote:

On Tue, Jan 13, 2009 at 8:09 PM, Donny Viszneki <donny.viszneki at gmail.com> wrote:

±-------------------------------------+

I nominate that for inclusion in the Top Ten Best Quotes of the Century :slight_smile:

JeffOn Wednesday 14 January 2009 16:11, Bob Pendleton wrote:

Mindsets are the hardest things in the known Universe.

Sure, feel free to post it any where. I would like credit for it, and
if possible include my email address (I have a good spam filter
(gmail)) and mention that I am desperately looking for a job. If you
are looking for great quotations… I’m your man.

Bob PendletonOn Wed, Jan 14, 2009 at 6:41 PM, Jeff Post <j_post at pacbell.net> wrote:

On Wednesday 14 January 2009 16:11, Bob Pendleton wrote:

Mindsets are the hardest things in the known Universe.

I nominate that for inclusion in the Top Ten Best Quotes of the Century :slight_smile:

Jeff


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

±-------------------------------------+

Ok, I did not understand that that was what you meant. I was thinking
you meant to use callbacks driven from either the device driver or
from a thread processing something like a loop with a select() in it.
The difference between what you are talking about and what I was
thinking about are enough quite large and seem to be the main source
of misunderstanding, at least on my part.

Yeah, you were not alone, I didn’t explain this right, it would seem!

Now that I believe I understand what you are talking about I believe I
like where you are going with this.

Note that with the WakeGetEvent, that means that the features of
fastevents could be integrated in SDL itself without even needing the
timer thread that broadcasts to the condition variable! Not that I
want to make fastevents obsolete, but it’d be cool if it’s
functionality was part of the base SDL library, especially if it’s
possible to do it in a very lightweight way (without the extra
thread), so that if you don’t use it, you don’t pay for it.

Mindsets are the hardest things in the known Universe.

No kidding. Even though I’m pretty sure that I (as well as Mark
Kilgard, apparently!) am Right (in my opinion) about callbacks being a
better API to provide, it’s pretty clear to me that if that opinion is
not widely accepted, then poof, it’s all useless, because I’m not
going to change that soon!

It could be possible to get rid of the SDL queue completely, but I
think it would enforce too many restrictions (basically, the
intersection of what you can put in a “user message” event on all the
supported platforms, and this could potentially shrink when adding
another platform, which would kill backward compatibility), so I’d
still keep one, but it would only used for the SDL_PushEvent messages,
so essentially, messages coming from other threads, most of the time,
or synthetic messages (pretty rare, I’d venture).

Synthetic messages are used in the device code in SDL. In what your
are describing one platform event can become several SDL events.

Device code, like joysticks? Hopefully, the common case will be 1:1 as
much as possible. Even if it isn’t, it’ll be at least as good,
anyway…

It’s the last bit I disagree with. It’s not equally easy to use
callbacks to deliver events to a queue than to fetch events from a
queue to dispatch callbacks. But it’s not so ridiculously difficult
that I’m not willing to pay the small overhead so that everyone is
much happier and SDL is successful.

Two points: 1) in my previous (wrong) understanding of this they are
IMHO equally simple. 2) In this kind of a conversation “equal” is
defined the same way you define “equal” for floating point variables.
That is x == y if abs(x - y) < epsilon. Where epsilon is a matter of
opinion… :slight_smile:

See my previous challenge to implement SDL on top of GLUT. I think
you’ll find that epsilon to be not too insignificant after all. :wink:

You’re right about the performance advantage, though: for the vast
majority of cases, it should be only epsilon more efficient with
callbacks than a queue API.

Basically, there’s two forces: we’d like SDL to be as close to the
metal as possible, while providing an API/behaviour that’s as
consistent as possible from one platform to the other, and we want the
API provided by SDL to be as flexible as possible so that games can be
ported to it and written for it easily. Callbacks favour the former,
and SDL_PollEvent/SDL_WaitEvent favours the latter,

You lost me right here. Seems to me that I can just have WaitEvent()
check for pending events in the SDL queue and then return one, or if
that queue is empty, check to see if there is a pending platform event
and if so, return it. Then I need, as I believe you pointed out, a way
to wait for an event to appear in either of the queues. And, of course
this can be extended to as many queues as you like.PollEvent() just
skips the waiting part of the code.

Yep, that’s pretty much what I’m proposing now (with the pseudo-code
in another thread). Since this involves a bit better integration with
the “waiting for the next event”, this gets pushed from the common
code down into the platform-specific driver code, with a cheap
fallback (equivalent to the current code) for drivers that don’t get
immediately updated to be super awesome. :slight_smile:

BTW, why is WaitEvent() so important? In any code that does animation
you (or at least I) am going to use PollEvent(), never WaitEvent().

For two cases.

The first one is, when your animations aren’t necessarily high
framerate, there’s still a lot of sleeping. 30 fps gets you some
decent animations, I don’t want to spin the rest of the time! In
addition, I’d be the type to use the “lightweight timer” feature I
wanted to add to drive those animations, so I want to let it sleep
until the timer expires, and that’s not a reason not to process my
sockets quickly!

The other is that I would like to share as much code as possible when
running dedicated servers (actually, I don’t have a separate dedicated
server binary, I just have a flag for “dedicated mode”), and in that
situation, I really don’t want to use just SDL_PollEvent! I it set up
to do rendering in a 100 Hz timer (like Doom, if I recall!), with some
logic for coping when the framerate is less than that (in which case
it becomes 100% CPU, but that’s rare on current machines). So when I’m
in dedicated mode, I just skip the call to the renderer, sharing a lot
of code. :-)On Wed, Jan 14, 2009 at 7:11 PM, Bob Pendleton wrote:


http://pphaneuf.livejournal.com/

Mindsets are the hardest things in the known Universe.

I nominate that for inclusion in the Top Ten Best Quotes of the Century :slight_smile:

The century is still young, we’ve got time to best it! ;-)On Wed, Jan 14, 2009 at 7:41 PM, Jeff Post <j_post at pacbell.net> wrote:


http://pphaneuf.livejournal.com/

Yeah, I mean, it’s all theoretically equivalent, but juggling
alternate stacks isn’t exactly in the “easy” category, usually. :wink:

Depends on who you talk to. :slight_smile:

Maybe best to not ask the people who come here and ask how to code
their first game using SDL, though. :wink:

Now, an exercise to the reader: implement an SDL backend on top of GLUT.

Been there, done that, then I found SDL. Seriously, my devotion to SDL
is only equaled (with a negative sign) by my dislike of GLUT.

On top of GLUT, I said, not “using GLUT instead of SDL”. Basically,
add a “src/video/glut” directory, and make that work. :slight_smile:

GLUT and similar APIs are designed around the GUI and IMHO ignore the
rest of the program. And, frankly, they don’t do that good a job on
the GUI.

To be fair, GLUT was already close to unmaintained when SDL came out,
and it was mostly designed as an educational tool, not really a
toolkit for serious applications. It’s just an example of a platform
that would be a pain in the ass to put SDL on.

I do not actually recommend touching GLUT even with a 10 foot pole. :-)On Wed, Jan 14, 2009 at 7:24 PM, Bob Pendleton wrote:


http://pphaneuf.livejournal.com/

More or less because SDL_WaitEvent() is as close as SDL gets to select()

Internally select() sleeps your process, waiting for a signal to wake
it up. This saves CPU time, battery power, system load, etc.

(FWIW SDL_PollEvent() is like select() with an immediate return)On Wed, Jan 14, 2009 at 7:11 PM, Bob Pendleton wrote:

BTW, why is WaitEvent() so important? In any code that does animation
you (or at least I) am going to use PollEvent(), never WaitEvent().


http://codebad.com/

Mindsets are the hardest things in the known Universe.

I nominate that for inclusion in the Top Ten Best Quotes of the Century :slight_smile:

Sure, feel free to post it any where. I would like credit for it, and
if possible include my email address (I have a good spam filter
(gmail)) and mention that I am desperately looking for a job. If you
are looking for great quotations… I’m your man.

I hear the great quotation market is tough these days. Good luck!

-CrystalOn Wed, 14 Jan 2009, Bob Pendleton wrote:

On Wed, Jan 14, 2009 at 6:41 PM, Jeff Post <j_post at pacbell.net> wrote:

On Wednesday 14 January 2009 16:11, Bob Pendleton wrote:

How can you measure the length of a programming abstraction?

I think SDL is just over 11 feet, we’re okay!On Wed, Jan 14, 2009 at 8:07 PM, Pierre Phaneuf wrote:

I do not actually recommend touching GLUT even with a 10 foot pole. :slight_smile:


http://codebad.com/

Print out the source code and measure the paper, of course!>----- Original Message ----

From: Donny Viszneki <donny.viszneki at gmail.com>
Subject: Re: [SDL] SDL_WaitEvent in 1.3

On Wed, Jan 14, 2009 at 8:07 PM, Pierre Phaneuf wrote:

I do not actually recommend touching GLUT even with a 10 foot pole. :slight_smile:

How can you measure the length of a programming abstraction?

I think SDL is just over 11 feet, we’re okay!