|
| 1 | +# Features that add new limits |
| 2 | + |
| 3 | +Some new features add associated limits. This document records a design policy for such features. |
| 4 | + |
| 5 | +## Common behaviors |
| 6 | + |
| 7 | +- `{ newLimit: undefined }` is allowed even if `newLimit` is unknown. (It has no effect.) |
| 8 | +- Limits entries associated with features have these Adapter Capability Guarantees: |
| 9 | + - If the feature is available, its limits are `better` than or equal to the default. |
| 10 | + - If not, its limits are `undefined`. |
| 11 | + - They are `undefined` if the feature is unavailable on the adapter. |
| 12 | +- It is allowed to request a limit that's available on the adapter (that is, |
| 13 | + not `undefined` in `adapter.limits`), even without also requesting the corresponding feature. |
| 14 | + It won't have any effect, but the limit request will still be validated against the adapter. |
| 15 | +- It is allowed to request a feature that's available on the adapter, even without also |
| 16 | + requesting the corresponding limit(s). (They will get their default values.) |
| 17 | + |
| 18 | +## Policies for new features |
| 19 | + |
| 20 | +- There should be a feature name for each such feature - don't just add a new limit |
| 21 | + (defaulting to 0) on its own. |
| 22 | + - Allows us to clearly guarantee a default value for the limit when the feature is available. |
| 23 | + (You only have to request the feature, not figure out what limit you need to request.) |
| 24 | + - Is consistent with features that add 0 limits or more than 1 limit. |
| 25 | +- Each new limit should define its "default" value as the default non-trivial value |
| 26 | + (that is, ignoring whether the feature is available/requested). |
| 27 | + |
| 28 | +## Example |
| 29 | + |
| 30 | +The new feature is `"foo"`. |
| 31 | +The new limit is `maxFoo`, and it has a default value of `5`. |
| 32 | + |
| 33 | +### Case Studies |
| 34 | + |
| 35 | +For each case study we'll look at how a piece of code behaves in several cases given an adapter `a`: |
| 36 | + |
| 37 | +- *Available (5)*: a browser which implements `"foo"`, on a device with support with `maxFoo: 5`. |
| 38 | + - `a.features.has("foo")` is `true` |
| 39 | + - `'maxFoo' in a.requiredLimits` is `true` |
| 40 | + - `a.requiredLimits.maxFoo` is `7` |
| 41 | +- *Available (7)*: a browser which implements `"foo"`, on a device with support with `maxFoo: 7`. |
| 42 | + - `a.features.has("foo")` is `true` |
| 43 | + - `'maxFoo' in a.requiredLimits` is `true` |
| 44 | + - `a.requiredLimits.maxFoo` is `7` |
| 45 | +- *Unavailable*: a browser which implements `"foo"`, on a device without support. |
| 46 | + - `a.features.has("foo")` is `false` |
| 47 | + - `'maxFoo' in a.requiredLimits` is `true` |
| 48 | + - `a.requiredLimits.maxFoo` is `undefined` |
| 49 | +- *Unimplemented*: a browser which hasn't implemented `"foo"` **but does implement the new rules allowing unknown limits set to `undefined`** |
| 50 | + - `a.features.has("foo")` is `false` |
| 51 | + - `'maxFoo' in a.requiredLimits` is `false` |
| 52 | + - `a.requiredLimits.maxFoo` is `undefined` |
| 53 | + |
| 54 | +In all cases `requiredFeatures: []` is the same as not specifying it, |
| 55 | +`requiredLimits: {}` is the same as not specifying it, and |
| 56 | +`maxFoo: undefined` is the same as not specifying it. |
| 57 | +We'll ignore the `requiredLimits: a.limits` case, as it should be equivalent to one of the other cases |
| 58 | +(which one depends on the resolution of [#4277](https://github.com/gpuweb/gpuweb/issues/4277)). |
| 59 | + |
| 60 | +- `a.requestDevice({ requiredFeatures: [], requiredLimits: { maxFoo: undefined } })` |
| 61 | + - *Available (7)*: OK, request ignored, device limit is `undefined` |
| 62 | + - *Available (5)*: OK, request ignored, device limit is `undefined` |
| 63 | + - *Unavailable*: OK, request ignored, device limit is `undefined` |
| 64 | + - *Unimplemented*: OK, request ignored, device limit is `undefined` |
| 65 | +- `a.requestDevice({ requiredFeatures: [], requiredLimits: { maxFoo: a.limits.maxFoo } })` |
| 66 | + - *Available (7)*: OK, device limit is `undefined` (request has no effect) |
| 67 | + - *Available (5)*: OK, device limit is `undefined` (request has no effect) |
| 68 | + - *Unavailable*: OK (limit request ignored because undefined) |
| 69 | + - *Unimplemented*: OK (limit request ignored because undefined) |
| 70 | +- `a.requestDevice({ requiredFeatures: [], requiredLimits: { maxFoo: 5 } })` |
| 71 | + - *Available (7)*: OK, device limit is `undefined` (request has no effect) |
| 72 | + - *Available (5)*: OK, device limit is `undefined` (request has no effect) |
| 73 | + - *Unavailable*: error, limit key not available |
| 74 | + - *Unimplemented*: error, limit key not available |
| 75 | +- `a.requestDevice({ requiredFeatures: [], requiredLimits: { maxFoo: 7 } })` |
| 76 | + - *Available (7)*: OK, device limit is `undefined` (request has no effect) |
| 77 | + - *Available (5)*: error, limit value not available (even though request would have no effect) |
| 78 | + - *Unavailable*: error, limit key not available |
| 79 | + - *Unimplemented*: error, limit key not available |
| 80 | +- `a.requestDevice({ requiredFeatures: ["foo"], requiredLimits: { maxFoo: undefined } })` |
| 81 | + - *Available (7)*: OK, enabled with limit set to default (5) |
| 82 | + - *Available (5)*: OK, enabled with limit set to default (5) |
| 83 | + - *Unavailable*: error, feature not available |
| 84 | + - *Unimplemented*: error, feature not available |
| 85 | +- `a.requestDevice({ requiredFeatures: ["foo"], requiredLimits: { maxFoo: a.limits.maxFoo } })` |
| 86 | + - *Available (7)*: OK, enabled with limit set to 7 |
| 87 | + - *Available (5)*: OK, enabled with limit set to 5 |
| 88 | + - *Unavailable*: error, feature not available |
| 89 | + - *Unimplemented*: error, feature not available |
| 90 | +- `a.requestDevice({ requiredFeatures: ["foo"], requiredLimits: { maxFoo: 5 } })` |
| 91 | + - *Available (7)*: OK, enabled with limit set to 5 |
| 92 | + - *Available (5)*: OK, enabled with limit set to 5 |
| 93 | + - *Unavailable*: error, feature not available, limit key not available |
| 94 | + - *Unimplemented*: error, feature not available, limit key not available |
| 95 | +- `a.requestDevice({ requiredFeatures: ["foo"], requiredLimits: { maxFoo: 7 } })` |
| 96 | + - *Available (7)*: OK, enabled with limit set to 7 |
| 97 | + - *Available (5)*: error, limit value not available |
| 98 | + - *Unavailable*: error, feature not available, limit key not available |
| 99 | + - *Unimplemented*: error, feature not available, limit key not available |
| 100 | +- `a.requestDevice({ requiredFeatures: a.features, requiredLimits: { maxFoo: undefined } })` |
| 101 | + - *Available (7)*: OK, enabled with limit set to default (5) |
| 102 | + - *Available (5)*: OK, enabled with limit set to default (5) |
| 103 | + - *Unavailable*: OK, neither limit nor feature is requested |
| 104 | + - *Unimplemented*: OK, neither limit nor feature is requested |
| 105 | +- `a.requestDevice({ requiredFeatures: a.features, requiredLimits: { maxFoo: a.limits.maxFoo } })` |
| 106 | + - *Available (7)*: OK, enabled with limit set to 7 |
| 107 | + - *Available (5)*: OK, enabled with limit set to 5 |
| 108 | + - *Unavailable*: OK, neither limit nor feature is requested |
| 109 | + - *Unimplemented*: OK, neither limit nor feature is requested |
| 110 | +- `a.requestDevice({ requiredFeatures: a.features, requiredLimits: { maxFoo: 5 } })` |
| 111 | + - *Available (7)*: OK, enabled with limit set to 5 |
| 112 | + - *Available (5)*: OK, enabled with limit set to 5 |
| 113 | + - *Unavailable*: error, limit key not available |
| 114 | + - *Unimplemented*: error, limit key not available |
| 115 | +- `a.requestDevice({ requiredFeatures: a.features, requiredLimits: { maxFoo: 7 } })` |
| 116 | + - *Available (7)*: OK, enabled with limit set to 7 |
| 117 | + - *Available (5)*: error, limit value not available |
| 118 | + - *Unavailable*: error, limit key not available |
| 119 | + - *Unimplemented*: error, limit key not available |
0 commit comments