Bug 21434 - Need to spec liveness of Gamepad objects
Need to spec liveness of Gamepad objects
Status: RESOLVED MOVED
Product: WebAppsWG
Classification: Unclassified
Component: HISTORICAL - Gamepad
unspecified
All All
: P2 normal
: ---
Assigned To: Ted Mielczarek [:ted]
public-webapps-bugzilla
:
Depends on:
Blocks: 17309
  Show dependency treegraph
 
Reported: 2013-03-29 13:34 UTC by Ted Mielczarek [:ted]
Modified: 2015-04-24 10:51 UTC (History)
6 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Ted Mielczarek [:ted] 2013-03-29 13:34:49 UTC
The discussion in bug 17309 made it clear that Scott and I have implemented two different things in regards to the "liveness" of Gamepad objects. Scott's Chrome implementation returns a static snapshot of each Gamepad when you getGamepads(), whereas the Gamepad object attached to the "ongamepadconnected" event in my Firefox implementation is live: you can get the latest device state out of it at any time.

We need to decide what the correct behavior here is and spec it.

Obviously I'm biased in favor of my implementation, but I think it does have one large benefit: we're expecting users to poll Gamepad status in a requestAnimationFrame loop, so if you're generating new Gamepad objects for every call to getGamepads() you're going to be generating a lot of garbage.
Comment 1 Scott Graham 2013-03-29 17:26:04 UTC
(In reply to comment #0)
> The discussion in bug 17309 made it clear that Scott and I have implemented
> two different things in regards to the "liveness" of Gamepad objects.
> Scott's Chrome implementation returns a static snapshot of each Gamepad when
> you getGamepads(), whereas the Gamepad object attached to the
> "ongamepadconnected" event in my Firefox implementation is live: you can get
> the latest device state out of it at any time.
> 
> We need to decide what the correct behavior here is and spec it.
> 
> Obviously I'm biased in favor of my implementation, but I think it does have
> one large benefit: we're expecting users to poll Gamepad status in a
> requestAnimationFrame loop, so if you're generating new Gamepad objects for
> every call to getGamepads() you're going to be generating a lot of garbage.

(I'm honestly not sure precisely what I implemented.)

I agree on the reducing garbage concern, and so returning/modifying the same objects sounds right to me.

The part I don't like as much is that the data unexpectedly changes, and it's unclear when, and with what frequency it's updated. That's why I used getGamepads() as the sync point for "Please update the data in my gamepad objects to the most recent state".
Comment 2 Ted Mielczarek [:ted] 2013-04-17 13:14:21 UTC
The HTML WebApp spec has concepts we can use to define this in a straightforward way:
http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#concept-task

It basically specs thread event queues, so that you can say that the Gamepad state will be updated after the current script has finished executing.
Comment 3 Ted Mielczarek [:ted] 2014-06-23 18:41:43 UTC
I chatted with another implementer and they were curious as to whether (assuming that Gamepad objects are snapshots):

navigator.getGamepads()[0] == navigator.getGamepads()[0]

ought to be true. It looks like it currently is in Chrome, but not in the IE developer preview.

We agreed that sensible spec language would allow that to be true, and in fact the spec should allow implementations to return the same snapshot for a Gamepad until the data changes (the gamepad has been interacted with in some way).
Comment 4 Philip Jägenstedt 2014-12-18 15:25:35 UTC
Live Array-like objects like NodeList are more work to implement and test, we should avoid making more of them.

That navigator.getGamepads()[0] === navigator.getGamepads()[0] should always hold true seems like a given, otherwise you'll necessarily have multiple Gamepad objects representing the same underlying hardware, and the mess of updating all of them. Unless the idea is that a Gamepad object is a snapshot and you have to call getGamepads() every time you want to check for changes? Easy to implement, but a bit odd...

Finally, navigator.getGamepads() === navigator.getGamepads()? Returning a new array every time seems easier bindings-wise at least in Blink. It does require having a separate array internally to keep track of the Gamepad objects so that you don't create new one. Spec'ing and testing how the return value of getGamepads() is reused seems like an unnecessary burden to me.
Comment 5 Ted Mielczarek [:ted] 2014-12-18 15:50:16 UTC
(In reply to Philip Jägenstedt from comment #4)
> Live Array-like objects like NodeList are more work to implement and test,
> we should avoid making more of them.

Yeah, I don't think anyone is arguing for that, thankfully.

> That navigator.getGamepads()[0] === navigator.getGamepads()[0] should always
> hold true seems like a given, otherwise you'll necessarily have multiple
> Gamepad objects representing the same underlying hardware, and the mess of
> Unless the idea is that a Gamepad object is a snapshot
> and you have to call getGamepads() every time you want to check for changes?
> Easy to implement, but a bit odd...

This is the entire crux of this bug: currently the Gamepad objects in Firefox always represent the most-recent-available state of the controller, whereas in Chrome and IE they represent a snapshot of the state as of the time you called navigator.getGamepads().

There was a long thread about this on public-webapps earlier this year:
http://lists.w3.org/Archives/Public/public-webapps/2014AprJun/0238.html

It didn't really reach any strong conclusions, there are good arguments to be made both ways. One compelling argument that was made is that if we do spec some sort of data change events in the future we will want snapshots for that:
http://lists.w3.org/Archives/Public/public-webapps/2014AprJun/0257.html

There's also a pretty good argument (that didn't come up on-list) that having snapshots makes it easier to compare gamepad state in the polling model, since you can hang on to the previous snapshot and compare vs. the next snapshot (using .timestamp, for one, and checking whether button states match etc).
Comment 6 Philip Jägenstedt 2015-02-09 11:29:14 UTC
I'm trying to implement the Navigator.getGamepads() change in https://codereview.chromium.org/808643005/ but quickly realized that "Retrieve a snapshot of the data for the the currently connected and interacted-with gamepads." isn't a certainly until this spec bug is resolved.

Having getGamepads() return a new array of completly new Gamepad object every time is simple enough to implement, but it seems to make the GamepadEvent nonsensical, as the GamepadEvent.gamepad member will necessarily be a Gamepad object constructed only for that event and that will never appear in any array returned by Navigator.getGamepads().

What does Firefox do?
Comment 7 Philip Jägenstedt 2015-02-09 13:32:22 UTC
(In reply to Philip Jägenstedt from comment #6)
> What does Firefox do?

I don't have a gamepad to test with here, but judging by the code in gecko-dev and minor testing, it looks like Firefox always returns a new array, but the internal Gamepad objects are just allocated once. One point of doubt is |Gamepad::Clone|, is that called as part of getGamepads() so that a new object is seen by script every time?
Comment 8 Ted Mielczarek [:ted] 2015-04-24 10:51:03 UTC
Moved to https://github.com/w3c/gamepad/issues/8