-
Notifications
You must be signed in to change notification settings - Fork 370
Add adapter.[[current]] #1523
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add adapter.[[current]] #1523
Changes from 5 commits
b57b277
10b6c00
bf17473
fe76118
4804c35
29a35fd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -883,6 +883,22 @@ An [=adapter=] has the following internal slots: | |
|
|
||
| Each adapter limit must be the same or [=limit/better=] than its default value | ||
| in [=supported limits=]. | ||
|
|
||
| : <dfn>\[[current]]</dfn>, of type boolean | ||
| :: | ||
| Indicates whether the adapter is allowed to vend new devices at this time. | ||
| Its value may change at any time. | ||
|
|
||
| It is initially set to `true` inside {{GPU/requestAdapter()}}. | ||
| It becomes `false` inside "[=lose the device=]" and "[=mark adapters stale=]". | ||
| Once set to `false`, it cannot become `true` again. | ||
|
|
||
| Note: | ||
| This mechanism ensures that various adapter-creation scenarios look similar to applications, | ||
| so they can easily be robust to more scenarios with less testing: first initialization, | ||
| reinitialization due to an unplugged adapter, reinitialization due to a test | ||
| {{GPUDevice/destroy()|GPUDevice.destroy()}} call, etc. It also ensures applications use | ||
| the latest system state to make decisions about which adapter to use. | ||
| </dl> | ||
|
|
||
| [=Adapters=] are exposed via {{GPUAdapter}}. | ||
|
|
@@ -894,7 +910,7 @@ through which [=internal objects=] are created. | |
| It can be shared across multiple [=agents=] (e.g. dedicated workers). | ||
|
|
||
| A [=device=] is the exclusive owner of all [=internal objects=] created from it: | ||
| when the [=device=] is lost, it and all objects created on it (directly, e.g. | ||
| when the [=device=] is [=lose the device|lost=], it and all objects created on it (directly, e.g. | ||
| {{GPUDevice/createTexture()}}, or indirectly, e.g. {{GPUTexture/createView()}}) become | ||
| [=invalid=]. | ||
|
|
||
|
|
@@ -935,6 +951,22 @@ and adds extra `[[`/`]]` in spec text. Consider removing the brackets. | |
| member corresponding to |key| in |device|.{{device/[[limits]]}} to the value |value|. | ||
| </div> | ||
|
|
||
| Any time the user agent needs to revoke access to a device, it calls | ||
| [=lose the device=](device, `undefined`). | ||
|
|
||
| <div algorithm> | ||
| To <dfn dfn>lose the device</dfn>(|device|, |reason|): | ||
|
|
||
| 1. Set |device|.{{device/[[adapter]]}}.{{adapter/[[current]]}} to `false`. | ||
| 1. Issue: explain how to get from |device| to its "primary" {{GPUDevice}}. | ||
| 1. Resolve {{GPUDevice/lost|GPUDevice.lost}} with a new {{GPUDeviceLostInfo}} with | ||
| {{GPUDeviceLostInfo/reason}} set to |reason| and | ||
|
kainino0x marked this conversation as resolved.
|
||
| {{GPUDeviceLostInfo/message}} set to an implementation-defined value. | ||
|
|
||
| Note: {{GPUDeviceLostInfo/message}} should not disclose unnecessary user/system | ||
| information and should never be parsed by applications. | ||
| </div> | ||
|
|
||
| [=Devices=] are exposed via {{GPUDevice}}. | ||
|
|
||
| ## Optional Capabilities ## {#optional-capabilities} | ||
|
|
@@ -1225,12 +1257,13 @@ interface GPU { | |
| 1. Let |promise| be [=a new promise=]. | ||
| 1. Issue the following steps on the [=Device timeline=] of |this|: | ||
| <div class=device-timeline> | ||
| 1. If the user agent chooses to return an adapter: | ||
| 1. If the user agent chooses to return an adapter, it should: | ||
|
|
||
| 1. The user agent chooses an [=adapter=] |adapter| according to the rules in | ||
| 1. Create an [=adapter=] |adapter| with {{adapter/[[current]]}} set to `true`, | ||
| chosen according to the rules in | ||
| [[#adapter-selection]] and the criteria in |options|. | ||
|
|
||
| 1. |promise| [=resolves=] with a new {{GPUAdapter}} encapsulating |adapter|. | ||
| 1. [=Resolve=] |promise| with a new {{GPUAdapter}} encapsulating |adapter|. | ||
|
|
||
| 1. Otherwise, |promise| [=resolves=] with `null`. | ||
| </div> | ||
|
|
@@ -1241,6 +1274,37 @@ interface GPU { | |
| </div> | ||
| </dl> | ||
|
|
||
| {{GPU}} has the following internal slots: | ||
|
|
||
| <dl dfn-type=attribute dfn-for=GPU> | ||
| : <dfn>\[[previously_returned_adapters]]</dfn>, of type [=ordered set=]<[=adapter=]> | ||
| :: | ||
| The set of [=adapters=] that have been returned via {{GPU/requestAdapter()}}. | ||
| It is used, then cleared, in [=mark adapters stale=]. | ||
| </dl> | ||
|
|
||
| Upon any change in the system's state that could affect the result of any {{GPU/requestAdapter()}} | ||
| call, the user agent *should* [=mark adapters stale=]. For example: | ||
|
|
||
| - A physical adapter is added/removed (via plug, driver update, TDR, etc.) | ||
| - The system's power configuration has changed (laptop unplugged, power settings changed, etc.) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not think the scenarios under "system's power configuration has changed" should always trigger WebGPU context lost unless the browser specifically wants content to be moved from the high power adapter to the low power adapter. If the WebGPU content is on a low power adapter, it should remain "current" regardless of the laptop being unplugged or power settings changing. Perhaps change the wording from "should" to "could" here.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It doesn't trigger device loss, it just puts the adapter into a state where it cannot vend new devices.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Earlier in the PR, it says:
The PR doesn't go into detail about when "invalidation" is different than "revoking access" so I thought (incorrectly) that those were the same thing. This could use more clarification. However, unless I am misunderstanding the proposed wording, there's still more information disclosure happening than necessary. If the system's power configuration has changed and an adapter that used to be on the old list is also on the new list, we shouldn't set its "current" flag to false. Right?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No GPUAdapter object will ever be returned more than once. Every time you call requestAdapters you get new GPUAdapter objects even if they refer to the same underlying hardware.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK. Then by the same token, if the system's power configuration has changed and an OS adapter that used to be on the old list is also on the new list, then I think all of the WebGPU adapter instances corresponding to the OS adapter should continue to handle out devices. Do you agree?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Because those adapters are still perfectly fine to use. If I unplug my hybrid laptop and WebGPU is running perfectly fine on the battery saving adapter, the web developer should be none-the-wiser to my actions. With your PR, the web developer can detect what I've done by noticing that the WebGPU adapter object for the low power adapter no longer gives out WebGPU devices. Giving this information to WebGPU developers does not help them write better WebGPU programs so we shouldn't give it out. Now if I unplug my hybrid laptop and WebGPU is running on the power consuming adapter, I'm more comfortable having the power consuming WebGPU adapter object stop giving out WebGPU devices. Here, there's a user benefit to giving developers this information, so it's worth doing.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I want to resolve that by marking adapters stale more often, not less. I used to have that written into the spec but it didn't make it into this revision of the PR, something like:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added to the spec
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think having the browser randomly mark adapters stale for no use benefit seems overkill. If we're going to have a "current" flag, I think it's sufficient for the spec to simply say: "Similar to context-lost, developers should be prepared to encounter adapters where the current flag has becomes false during the course of the WebGPU program. Examples of cases where the current flag could becomes false include: power state changes, and physical adapters becoming added/removed." Taking a step back, when will it be the case that an adapter becomes non-current but does NOT become lost? If a developer discovers the adapter they're currently using is non-current but is happily accepting draw commands, should they take that as a hint to move their operation somewhere else? Is it an omen of possible calamity ahead?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There is a benefit though: it makes it much harder to accidentally write applications which fail in rarer situations like system setting changes or eGPU usage. We can't rely on people to read every piece of documentation thoroughly.
(Added bracketed part just to make sure I am understanding correctly.) |
||
|
|
||
| Additionally, [=mark adapters stale=] may by scheduled at any time. User agents may choose to do | ||
| this often even when there has been no system state change (e.g. several seconds after the last | ||
| call to {{GPU/requestDevice()}}. This has no effect on well-formed applications, obfuscates real | ||
| system state changes, and makes developers more aware that calling {{GPU/requestAdapters()}} | ||
| again is always necessary before calling {{GPUAdapter/requestDevice()}}. | ||
|
|
||
| <div algorithm> | ||
| To <dfn dfn>mark adapters stale</dfn>: | ||
|
|
||
| 1. For each |adapter| in `navigator.gpu.`{{GPU/[[previously_returned_adapters]]}}: | ||
| 1. Set |adapter|.{{GPUAdapter/[[adapter]]}}.{{adapter/[[current]]}} to `false`. | ||
| 1. [=list/Empty=] `navigator.gpu.`{{GPU/[[previously_returned_adapters]]}}. | ||
|
|
||
| Issue: Update here if an `adaptersadded`/`adapterschanged` event is introduced. | ||
| </div> | ||
|
|
||
| <div class="example"> | ||
| Request a {{GPUAdapter}}: | ||
| <pre highlight="js"> | ||
|
|
@@ -1408,16 +1472,22 @@ interface GPUAdapter { | |
| |adapter|.{{adapter/[[limits]]}}. | ||
| </div> | ||
|
|
||
| 1. If the user agent cannot fulfill the request: | ||
| 1. If |adapter|.{{adapter/[[current]]}} is `false`, | ||
| or the user agent otherwise cannot fulfill the request: | ||
|
|
||
| 1. Let |device| be a new [=device=]. | ||
| 1. [=Lose the device=](|device|, `undefined`). | ||
|
|
||
| 1. Let |device| be a new {{GPUDevice}} object which has | ||
| {{GPUDevice/lost|GPUDevice.lost}} resolved with a {{GPUDeviceLostInfo}} | ||
| with {{GPUDeviceLostInfo/reason}} `undefined` and an | ||
| implementation-defined {{GPUDeviceLostInfo/message}}. | ||
| Note: | ||
| This makes |adapter|.{{adapter/[[current]]}} `false`, if it wasn't already. | ||
|
|
||
| Issue: Probably centralize this better with other device loss triggering, once added. | ||
| Note: | ||
| User agents should consider issuing developer-visible warnings in | ||
| most or all cases when this occurs. Applications should perform | ||
| reinitialization logic starting with {{GPU/requestAdapter()}}. | ||
|
|
||
| 1. [=Resolve=] |promise| with |device| and stop. | ||
| 1. [=Resolve=] |promise| with a new {{GPUDevice}} encapsulating |device|, | ||
| and stop. | ||
|
|
||
| 1. [=Resolve=] |promise| with a new {{GPUDevice}} object encapsulating | ||
| [=a new device=] with the capabilities described by |descriptor|. | ||
|
|
@@ -1548,24 +1618,19 @@ Those not defined here are defined elsewhere in this document. | |
| <dl dfn-type=method dfn-for=GPUDevice> | ||
| : <dfn>destroy()</dfn> | ||
| :: | ||
| Destroys the [=device=]. | ||
| Destroys the [=device=], preventing further operations on it. | ||
| Outstanding asynchronous operations will fail. | ||
|
|
||
| <div algorithm=GPUDevice.destroy()> | ||
| **Called on:** {{GPUDevice}} |this|. | ||
|
|
||
| 1. Make |this|.{{GPUDevice/[[device]]}} [=invalid=]. | ||
| 1. Resolve {{GPUDevice/lost}}, on every {{GPUDevice}} associated with | ||
| |this|.{{GPUDevice/[[device]]}}, with a {{GPUDeviceLostInfo}} with | ||
| {{GPUDeviceLostInfo/reason}} {{GPUDeviceLostReason/"destroyed"}} | ||
| and an implementation-defined {{GPUDeviceLostInfo/message}}. | ||
|
|
||
| Issue: Probably centralize this better with other device loss triggering, once added. | ||
| 1. [=Lose the device=](|this|.{{GPUDevice/[[device]]}}, | ||
| {{GPUDeviceLostReason/"destroyed"}}). | ||
| </div> | ||
|
|
||
| Note: | ||
| This prevents any further operations on the device. | ||
| Implementations can free resource allocations immediately. | ||
| Outstanding asynchronous operations will fail, so implementations can abort them early. | ||
| Since no further operations can occur on this device, implementations can free resource | ||
| allocations and abort outstanding asynchronous operations immediately. | ||
| </dl> | ||
|
|
||
| {{GPUDevice}} objects are [=serializable objects=]. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I changed this from "only outside of user tasks" to "at any time" because this state is not part of the content process, so changing it between user tasks doesn't make sense.