-
Notifications
You must be signed in to change notification settings - Fork 370
Allow creating mappable buffer with more usages as optional features #5108
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
base: main
Are you sure you want to change the base?
Changes from 4 commits
2b68626
8675390
7765b87
3d39151
cad2e84
44266f8
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 |
|---|---|---|
|
|
@@ -2879,6 +2879,7 @@ enum GPUFeatureName { | |
| "clip-distances", | ||
| "dual-source-blending", | ||
| "subgroups", | ||
| "buffer-map-extended-usages", | ||
| }; | ||
| </script> | ||
|
|
||
|
|
@@ -3037,6 +3038,17 @@ to. | |
| <!-- As needed, compute more allowed usages based on the features enabled on the device. --> | ||
| </div> | ||
|
|
||
| <div algorithm data-timeline=const> | ||
| A {{GPUDevice}}'s <dfn dfn>GPU-writable buffer usages</dfn> are: | ||
|
|
||
| - Always allowed: | ||
| {{GPUBufferUsage/COPY_DST}}, | ||
| {{GPUBufferUsage/STORAGE}}, | ||
| {{GPUBufferUsage/QUERY_RESOLVE}} | ||
|
|
||
| <!-- As needed, compute more allowed usages based on the features enabled on the device. --> | ||
| </div> | ||
|
|
||
| ## Example ## {#initialization-examples} | ||
|
|
||
| <div class=example> | ||
|
|
@@ -3348,14 +3360,16 @@ The {{GPUBufferUsage}} flags determine how a {{GPUBuffer}} may be used after its | |
| The buffer can be mapped for reading. (Example: calling {{GPUBuffer/mapAsync()}} with | ||
| {{GPUMapMode/READ|GPUMapMode.READ}}) | ||
|
|
||
| May only be combined with {{GPUBufferUsage/COPY_DST}}. | ||
| May only be combined with {{GPUBufferUsage/COPY_DST}} when | ||
| {{GPUFeatureName/buffer-map-extended-usages}} is not enabled. | ||
|
|
||
| : <dfn>MAP_WRITE</dfn> | ||
| :: | ||
| The buffer can be mapped for writing. (Example: calling {{GPUBuffer/mapAsync()}} with | ||
| {{GPUMapMode/WRITE|GPUMapMode.WRITE}}) | ||
|
|
||
| May only be combined with {{GPUBufferUsage/COPY_SRC}}. | ||
| May only be combined with {{GPUBufferUsage/COPY_SRC}} when | ||
| {{GPUFeatureName/buffer-map-extended-usages}} is not enabled. | ||
|
Jiawei-Shao marked this conversation as resolved.
Outdated
|
||
|
|
||
| : <dfn>COPY_SRC</dfn> | ||
| :: | ||
|
|
@@ -3448,12 +3462,13 @@ The {{GPUBufferUsage}} flags determine how a {{GPUBuffer}} may be used after its | |
| - |descriptor|.{{GPUBufferDescriptor/usage}} must not be 0. | ||
| - |descriptor|.{{GPUBufferDescriptor/usage}} must be a subset of the | ||
| [=allowed buffer usages=] for |this|. | ||
| - If |descriptor|.{{GPUBufferDescriptor/usage}} contains {{GPUBufferUsage/MAP_READ}}: | ||
| - |descriptor|.{{GPUBufferDescriptor/usage}} must contain no other flags | ||
| except {{GPUBufferUsage/COPY_DST}}. | ||
| - If |descriptor|.{{GPUBufferDescriptor/usage}} contains {{GPUBufferUsage/MAP_WRITE}}: | ||
| - |descriptor|.{{GPUBufferDescriptor/usage}} must contain no other flags | ||
| except {{GPUBufferUsage/COPY_SRC}}. | ||
| - If {{GPUFeatureName/buffer-map-extended-usages}} is not enabled on |this|: | ||
| - If |descriptor|.{{GPUBufferDescriptor/usage}} contains {{GPUBufferUsage/MAP_READ}}: | ||
| - |descriptor|.{{GPUBufferDescriptor/usage}} must contain no other flags | ||
| except {{GPUBufferUsage/COPY_DST}}. | ||
| - If |descriptor|.{{GPUBufferDescriptor/usage}} contains {{GPUBufferUsage/MAP_WRITE}}: | ||
| - |descriptor|.{{GPUBufferDescriptor/usage}} must contain no other flags | ||
| except {{GPUBufferUsage/COPY_SRC}}. | ||
| - If |descriptor|.{{GPUBufferDescriptor/size}} must be ≤ | ||
| |this|.{{GPUObjectBase/[[device]]}}.{{device/[[limits]]}}.{{supported limits/maxBufferSize}}. | ||
| - If |descriptor|.{{GPUBufferDescriptor/mappedAtCreation}} is `true`: | ||
|
|
@@ -3582,21 +3597,40 @@ The {{GPUMapMode}} flags determine how a {{GPUBuffer}} is mapped when calling | |
| Only valid with buffers created with the {{GPUBufferUsage/MAP_READ}} usage. | ||
|
|
||
| Once the buffer is mapped, calls to {{GPUBuffer/getMappedRange()}} will return an | ||
| {{ArrayBuffer}} containing the buffer's current values. Changes to the returned | ||
| {{ArrayBuffer}} will be discarded after {{GPUBuffer/unmap()}} is called. | ||
| {{ArrayBuffer}} containing the buffer's current values. | ||
|
|
||
| Changes to the returned {{ArrayBuffer}} will be discarded after {{GPUBuffer/unmap()}} is | ||
| called. | ||
|
|
||
| : <dfn>WRITE</dfn> | ||
| :: | ||
| Only valid with buffers created with the {{GPUBufferUsage/MAP_WRITE}} usage. | ||
|
|
||
| When the buffer is created without [=GPU-writable buffer usages=]: | ||
| Once the buffer is mapped, calls to {{GPUBuffer/getMappedRange()}} will return an | ||
| {{ArrayBuffer}} containing the buffer’s current values. | ||
|
|
||
| When the buffer is created with [=GPU-writable buffer usages=]: | ||
| Once the buffer is mapped, calls to {{GPUBuffer/getMappedRange()}} will return an | ||
| {{ArrayBuffer}} containing the buffer's current values. Changes to the returned | ||
| {{ArrayBuffer}} will be stored in the {{GPUBuffer}} after {{GPUBuffer/unmap()}} is called. | ||
| {{ArrayBuffer}} containing the default initialized data (zeros) or data written by the | ||
| webpage during a previous mapping. | ||
|
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. Just to be clear, this is allowing either of two behaviors? For better portability we could clear the map region every time. I wonder, would that be too expensive? (How much of the benefit would we lose from avoiding the copyB2B in today's map-write-then-copy pattern?) The region could even be cleared before mapping by the GPU (which might have higher memory bandwidth than the CPU). Maybe if there are really cases where effectively
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.
This comes from a note in the current SPEC. Here I mean for the first time
Obviously clearing the map region every time is expensive and unnecessary. With the mentioned behavior we don't need to either clear or read the data back from the GPU when non-triply mapping is used.
When triply mapping is supported on CPU-cached UMA (e.g. on Intel iGPUs), we can directly get the GPU data through The feature
I feel it strange to use |
||
|
|
||
| Changes to the returned {{ArrayBuffer}} will be stored in the buffer after | ||
| {{GPUBuffer/unmap()}} is called. | ||
|
|
||
| Note: Write-only mapping will never return values produced by the GPU. | ||
|
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. Why is this restriction necessary? Won't it result in an extra copy of the data for write only mappings on UMA systems? I think it would be preferable to state that reading the contents of a write only mappings are undefined (or zero-ed?) in this case.
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 is mainly because currently in Chromium a copy is always needed because we cannot access the mapped pointer from GPU resources directly in the JS side. We can discuss more about this issue in the WG meeting. 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. We have the same restriction in WebKit too, perhaps this is a non-issue.
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.
We couldn't make it fully undefined, at most we could add a third option for what gets returned. Hard to say if the performance would be any better better if we allowed it. It would require cache flushes or something to make sure you don't get unsafe undefined values. And of course for portability reasons we really don't want anyone to rely on data getting read back on write-only mappings. But that's probably not a huge concern. |
||
|
|
||
| : <dfn>READ|WRITE</dfn> | ||
| :: | ||
| Only valid with buffers created with the {{GPUBufferUsage/MAP_READ}} and | ||
| {{GPUBufferUsage/MAP_WRITE}} usage. | ||
|
|
||
| Once the buffer is mapped, calls to {{GPUBuffer/getMappedRange()}} will return an | ||
| {{ArrayBuffer}} containing the buffer's current values. | ||
|
|
||
| Changes to the returned {{ArrayBuffer}} will be stored in the buffer after | ||
| {{GPUBuffer/unmap()}} is called. | ||
|
|
||
| Note: Since the {{GPUBufferUsage/MAP_WRITE}} buffer usage may only be combined with the | ||
| {{GPUBufferUsage/COPY_SRC}} buffer usage, mapping for writing can never return values | ||
| produced by the GPU, and the returned {{ArrayBuffer}} will only ever contain the default | ||
| initialized data (zeros) or data written by the webpage during a previous mapping. | ||
| </dl> | ||
|
|
||
| {{GPUBuffer}} has the following methods: | ||
|
|
@@ -3670,7 +3704,8 @@ The {{GPUMapMode}} flags determine how a {{GPUBuffer}} is mapped when calling | |
| - |rangeSize| is a multiple of 4. | ||
| - |offset| + |rangeSize| ≤ |this|.{{GPUBuffer/size}} | ||
| - |mode| contains only bits defined in {{GPUMapMode}}. | ||
| - |mode| contains exactly one of {{GPUMapMode/READ}} or {{GPUMapMode/WRITE}}. | ||
| - If {{GPUFeatureName/buffer-map-extended-usages}} is not enabled on |this|.device: | ||
| - |mode| contains exactly one of {{GPUMapMode/READ}} or {{GPUMapMode/WRITE}}. | ||
| - If |mode| contains {{GPUMapMode/READ}} then |this|.{{GPUBuffer/usage}} must contain {{GPUBufferUsage/MAP_READ}}. | ||
| - If |mode| contains {{GPUMapMode/WRITE}} then |this|.{{GPUBuffer/usage}} must contain {{GPUBufferUsage/MAP_WRITE}}. | ||
| </div> | ||
|
|
@@ -16660,6 +16695,21 @@ expose real values whenever the feature is available on the adapter: | |
| - New WGSL extensions: | ||
| - [=extension/subgroups=] | ||
|
|
||
| <h3 id=dom-gpufeaturename-buffer-map-extended-usages data-dfn-type=enum-value data-dfn-for=GPUFeatureName>`"buffer-map-extended-usages"` | ||
| </h3> | ||
|
|
||
| Allows the creation of mappable {{GPUBuffer}}s with any other {{GPUBufferUsage}} flags, and allows | ||
| setting both {{GPUMapMode/READ}} and {{GPUMapMode/WRITE}} bits as a valid map mode in | ||
| {{GPUBuffer}}.{{GPUBuffer/mapAsync()}}. | ||
|
|
||
| This feature adds the following [=optional API surfaces=]: | ||
| - Allows the use of {{GPUBufferUsage/MAP_READ}} with any other {{GPUBufferUsage}} flags as | ||
| |descriptor|.{{GPUBufferDescriptor/usage}} in the creation of {{GPUBuffer}}s. | ||
| - Allows the use of {{GPUBufferUsage/MAP_WRITE}} with any other {{GPUBufferUsage}} flags as | ||
| |descriptor|.{{GPUBufferDescriptor/usage}} in the creation of {{GPUBuffer}}s. | ||
| - Allows setting both {{GPUMapMode/READ}} and {{GPUMapMode/WRITE}} bits in the `mode` parameter of | ||
| {{GPUBuffer}}.{{GPUBuffer/mapAsync()}}. | ||
|
Jiawei-Shao marked this conversation as resolved.
Outdated
|
||
|
|
||
| # Appendices # {#appendices} | ||
|
|
||
| ## Texture Format Capabilities ## {#texture-format-caps} | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.