forked from gpuweb/gpuweb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.bs
15967 lines (12832 loc) · 687 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<pre class=metadata>
Title: WebGPU
Shortname: webgpu
Level: None
Status: w3c/ED
Group: webgpu
ED: https://gpuweb.github.io/gpuweb/
TR: https://www.w3.org/TR/webgpu/
Repository: gpuweb/gpuweb
!Participate: <a href="https://github.com/gpuweb/gpuweb/issues/new">File an issue</a> (<a href="https://github.com/gpuweb/gpuweb/issues">open issues</a>)
Editor: Kai Ninomiya, Google https://www.google.com, [email protected], w3cid 99487
Editor: Brandon Jones, Google https://www.google.com, [email protected], w3cid 87824
Editor: Myles C. Maxfield, Apple Inc. https://www.apple.com, [email protected], w3cid 77180
Former Editor: Dzmitry Malyshau, Mozilla https://www.mozilla.org, [email protected], w3cid 96977
Former Editor: Justin Fan, Apple Inc. https://www.apple.com, [email protected], w3cid 115633
Abstract: WebGPU exposes an API for performing operations, such as rendering and computation, on a Graphics Processing Unit.
Markup Shorthands: markdown yes
Markup Shorthands: dfn yes
Markup Shorthands: idl yes
Markup Shorthands: css no
Assume Explicit For: yes
</pre>
<pre class=biblio>
{
"SourceMap": {
"authors": [
"John Lenz",
"Nick Fitzgerald"
],
"href": "https://sourcemaps.info/spec.html",
"title": "Source Map Revision 3 Proposal"
}
}
</pre>
<pre class=link-defaults>
</pre>
<pre class=ignored-specs>
spec:resource-hints;
</pre>
<pre class=anchors>
spec: ECMA-262; urlPrefix: https://tc39.es/ecma262/#
type: dfn
text: agent; url: agent
text: surrounding agent; url: surrounding-agent
text: agent cluster; url: sec-agent-clusters
text: ?; url: sec-returnifabrupt-shorthands
text: !; url: sec-returnifabrupt-shorthands
text: Data Block; url: sec-data-blocks
type: abstract-op
text: DetachArrayBuffer; url: sec-detacharraybuffer
text: AllocateArrayBuffer; url: sec-allocatearraybuffer
text: CreateByteDataBlock; url: sec-createbytedatablock
type: attribute
for: ArrayBuffer
text: [[ArrayBufferDetachKey]]; url: sec-properties-of-the-arraybuffer-instances
spec: HTML; urlPrefix: https://html.spec.whatwg.org/multipage/
type: dfn
text: origin-clean; url: canvas.html#concept-canvas-origin-clean
text: check the usability of the image argument; url: canvas.html#check-the-usability-of-the-image-argument
text: placeholder canvas element; url: canvas.html#offscreencanvas-placeholder
text: event loop processing model; url: webappapis.html#event-loop-processing-model
for: video
text: intrinsic width; url: media.html#concept-video-intrinsic-width
text: intrinsic height; url: media.html#concept-video-intrinsic-height
spec: WebCodecs; urlPrefix: https://www.w3.org/TR/webcodecs/#
type: dfn
text: Close VideoFrame; url: close-videoframe
spec: WEBGL-1; urlPrefix: https://www.khronos.org/registry/webgl/specs/latest/1.0/#
type: interface
text: WebGLRenderingContext; url: WEBGLRENDERINGCONTEXT
type: attribute; for: WebGLRenderingContext
text: drawingBufferColorSpace; url: DOM-WebGLRenderingContext-drawingBufferColorSpace
type: dictionary
text: WebGLContextAttributes; url: WEBGLCONTEXTATTRIBUTES
spec: WGSL; urlPrefix: https://gpuweb.github.io/gpuweb/wgsl/#
type: dfn
text: f16; url: f16
text: location; url: input-output-locations
text: interpolation; url: interpolation
text: pipeline-overridable; url: pipeline-overridable
text: pipeline-overridable constant identifier string; url: pipeline-overridable-constant-identifier-string
text: pipeline-overridable constant default value; url: pipeline-overridable-constant-default-value
text: interface of a shader stage; url: interface-of-a-shader
text: shader execution end; url: shader-execution-end
text: shader stage output; url: shader-stage-output
text: shader stage input; url: shader-stage-input
text: builtin; url: built-in-values
text: channel formats; url: channel-formats
text: invalid memory reference; url: invalid-memory-reference
text: shader module creation; url: shader-module-creation
text: pipeline creation; url: pipeline-creation
text: program error; url: program-error
text: roundUp; url: roundup
text: uncategorized error; url: uncategorized-error
text: shader-creation error; url: shader-creation-error
text: pipeline-creation error; url: pipeline-creation-error
text: store type; url: store-type
text: language extension; url: language-extension
text: runtime-sized; url: runtime-sized
text: WGSL floating point conversion; url: floating-point-conversion
text: WGSL identifier comparison; url: identifier-comparison
text: WGSL scalar type; url: scalar-types
text: @binding; url: attribute-binding
text: @group; url: attribute-group
text: line break; url: line-break
for: address spaces
text: workgroup; url: address-spaces-workgroup
for: builtin
text: sample_mask; url: built-in-values-sample_mask
text: frag_depth; url: built-in-values-frag_depth
for: extension
text: f16; url: extension-f16
type: abstract-op
text: SizeOf; url: sizeof
spec: Internationalization Glossary; urlPrefix: https://www.w3.org/TR/i18n-glossary/#
type: dfn
text: localizable text; url: def-localizable-text
spec: Strings on the Web; urlPrefix: https://w3c.github.io/string-meta/#
type: dfn
text: best practices for language and direction information; url: bp_and-reco
</pre>
<style>
/* Make <dl> blocks more distinct from their surroundings. */
main dl:not(.switch) {
border-left: thin solid #f3e48c;
padding-left: .5em;
}
/* Remove unnecessary extra margin on switch bodies */
dl.switch dd {
margin-left: 0em;
}
/* <p> by default has these margins. Update ul/ol/dl to match,
* since they are also put in places where paragraphs go. */
p, ul, ol, dl {
margin: 1em 0;
}
/* Styling for "editorial" issues */
.note.editorial {
border-color: var(--note-editorial-border);
background: var(--note-editorial-bg);
}
/* Our SVGs aren't responsive to light/dark mode, so they're opaque with a
* white or black background. Rounded corners make them a bit less jarring. */
object[type="image/svg+xml"] {
border-radius: .5em;
}
/* The new spec template doesn't put a box around algorithms anymore. */
/* Add a similar box for Valid Usage requirements. */
div.algorithm, div.validusage {
margin: .5em 0;
padding: .5em;
border-width: thin;
border-style: solid;
border-radius: .5em;
}
div.validusage {
border-color: #88e;
}
div.algorithm {
border-color: #ddd;
}
/*
* If the Valid Usage requirements are the first child of a *-timeline block give it a larger top
* margin to prevent the block labels from overlapping.
*/
.content-timeline>.validusage:first-child,
.device-timeline>.validusage:first-child,
.queue-timeline>.validusage:first-child {
margin-top: 1.5em;
}
/*
* Boxes for steps that occur on a particular timeline.
*/
div.content-timeline, div.device-timeline, div.queue-timeline {
padding: .5em;
border-radius: .5em;
}
.content-timeline {
background: rgba(0, 255, 0, 0.05);
background: var(--tint-green);
}
.device-timeline {
background: rgba(255, 0, 0, 0.05);
background: var(--tint-red);
}
.queue-timeline {
background: rgba(255, 0, 255, 0.05);
background: var(--tint-purple);
}
span[data-timeline],
dfn[data-timeline],
var[data-timeline],
a[data-timeline],
[href="#content-timeline"],
[href="#device-timeline"],
[href="#queue-timeline"] {
border-style: solid;
border-radius: .3em;
border-width: 0 0 .2em 0;
text-decoration: none;
}
dl[data-timeline],
div[data-timeline] {
border-style: solid;
border-radius: 1em 0 0 1em;
padding: .5em;
}
dl[data-timeline] {
border-width: 0 0 0 .25em !important;
}
div[data-timeline] {
border-width: 1px 0 0 .75em;
}
div.algorithm[data-timeline] {
border-width: 1px 1px 1px .75em;
}
div.algorithm > div[data-timeline] {
/* Remove unnecessary padding in this common case. Makes the border of the
* timeline box line up with the border of the surrounding algorithm box. */
margin-left: calc(-.5em - 1px);
margin-right: calc(-.5em - 1px);
}
/*
* Coloring for steps and other stuff on particular timelines.
*/
[data-timeline="content"],
[href="#content-timeline"] {
border-color: #00cc00 !important;
}
[data-timeline="device"],
[href="#device-timeline"] {
border-color: #880000 !important;
}
[data-timeline="queue"],
[href="#queue-timeline"] {
border-color: #c900f1 !important;
}
[data-timeline="const"] {
/* 186 is perceptual 50% gray, so works for both light and dark modes. */
border-color: rgb(186 186 186 / 30%) !important;
}
/*
* Stylistic labels, for clarity of presentation of these blocks.
*
* NOTE: This text is non-accessible and non-selectable; surrounding
* text must also explain the context.
*/
.validusage,
.content-timeline, .device-timeline, .queue-timeline,
[data-timeline] {
position: relative;
}
.validusage::before,
.content-timeline::before,
.device-timeline::before,
.queue-timeline::before {
font-weight: bold;
font-style: italic;
font-size: 1.3rem;
color: rgba(0, 0, 0, 0.15);
color: var(--watermark-text);
position: absolute;
right: .3em;
top: -.1em;
}
.validusage::before {
content: "Valid Usage";
}
.content-timeline::before {
content: "Content Timeline";
}
.device-timeline::before {
content: "Device Timeline";
}
.queue-timeline::before {
content: "Queue Timeline";
}
/*
* Ensure that argumentdef blocks don't overflow algorithm section borders. This is made far harder
* than it needs to be because the top-level W3C stylesheet has several @media + min-width variants
* that mark themselves as !important and then proceed to do the wrong thing.
*/
@media screen and (min-width: 78em) {
body:not(.toc-inline) .algorithm .overlarge {
margin-right: auto !important;
}
}
@media screen and (min-width: 90em) {
body:not(.toc-inline) .algorithm .overlarge {
margin-right: auto !important;
}
}
.algorithm .overlarge {
margin-right: auto !important;
}
/*
* The default argumentdef style has a caption that doesn't suit this spec's
* formatting particularly well. Hide it.
*/
.algorithm .argumentdef {
margin-top: 0;
}
.algorithm .argumentdef > caption {
display: none;
}
/*
* Argumentdef is also too wide given our typenames, so make some tweaks.
*/
/* Move border to tr and reduce padding. */
.algorithm .argumentdef td,
.algorithm .argumentdef th {
padding: .5em;
border: none;
}
.algorithm .argumentdef > tbody > tr {
border-top: thin solid var(--datacell-border);
}
/* Compress "Nullable" and "Optional" and remove horizontal padding. */
.algorithm .argumentdef > thead > tr > :nth-child(3),
.algorithm .argumentdef > thead > tr > :nth-child(4) {
font-family: monospace;
max-width: 4ch;
word-wrap: break-word;
}
.algorithm .argumentdef tr > :nth-child(3),
.algorithm .argumentdef tr > :nth-child(4) {
padding-left: .5em;
padding-right: 0;
}
/* Wrap Parameter and Type onto separate rows. */
.algorithm .argumentdef > thead > tr > th:nth-child(1),
.algorithm .argumentdef > tbody > tr > td:nth-child(1) {
padding-right: .5em;
float: left;
}
.algorithm .argumentdef > thead > tr > th:nth-child(2),
.algorithm .argumentdef > tbody > tr > td:nth-child(2) {
padding-left: .5em;
float: right;
}
.algorithm .argumentdef > thead > tr > th {
vertical-align: top;
}
/*
* Add vertical lines to demarcate multi-column cells.
*/
table.data td,
table.data th {
/* Only one side is needed because there are no outer borders on the tables.
* 186 is perceptual 50% gray, so works for both light and dark modes. */
border-left: 1px solid rgb(186 186 186 / 30%);
}
table.data.no-colspan-center td[colspan],
table.data.no-colspan-center th[colspan] {
text-align: unset;
}
table.data tr.row-continuation td,
table.data tr.row-continuation th {
border-top: none;
}
/*
* Vertical class for table columns. (Can't use th.vertical because of a Safari bug.)
*/
span.vertical {
writing-mode: vertical-rl;
white-space: nowrap;
}
/*
* Sticky table headers.
*/
.overlarge {
/* position: sticky doesn't work inside scrollable elements. */
overflow-x: unset;
}
thead.stickyheader th, th.stickyheader {
position: sticky;
top: 0;
background: #f8f8f8;
background: var(--stickyheader-background);
}
/*
* Light-mode and dark-mode colors
*/
:root {
--watermark-text: rgba(0, 0, 0, 15%);
--stickyheader-background: #f8f8f8;
--tint-red: rgba(255, 0, 0, 6%);
--tint-green: rgba(0, 255, 0, 10%);
--tint-blue: rgba(0, 0, 255, 5%);
--tint-purple: rgba(255, 0, 255, 5%);
--note-editorial-border: #ffa500;
--note-editorial-bg: #ffeedd;
}
@media (prefers-color-scheme:dark) {
:root {
--watermark-text: rgba(255, 255, 255, 25%);
--stickyheader-background: #181818;
--tint-red: rgba(255, 0, 0, 20%);
--tint-green: rgba(0, 255, 0, 18%);
--tint-blue: rgba(0, 130, 255, 24%);
--tint-purple: rgba(255, 0, 255, 22%);
--note-editorial-border: #ffa500;
--note-editorial-bg: var(--borderedblock-bg);
}
}
</style>
# Introduction # {#intro}
*This section is non-normative.*
[Graphics Processing Units](https://en.wikipedia.org/wiki/Graphics_processing_unit), or GPUs for short,
have been essential in enabling rich rendering and computational applications in personal computing.
WebGPU is an API that exposes the capabilities of GPU hardware for the Web.
The API is designed from the ground up to efficiently map to (post-2014) native GPU APIs.
WebGPU is not related to [WebGL](https://www.khronos.org/webgl/) and does not explicitly target OpenGL ES.
WebGPU sees physical GPU hardware as {{GPUAdapter}}s. It provides a connection to an adapter via
{{GPUDevice}}, which manages resources, and the device's {{GPUQueue}}s, which execute commands.
{{GPUDevice}} may have its own memory with high-speed access to the processing units.
{{GPUBuffer}} and {{GPUTexture}} are the <dfn dfn>physical resources</dfn> backed by GPU memory.
{{GPUCommandBuffer}} and {{GPURenderBundle}} are containers for user-recorded commands.
{{GPUShaderModule}} contains [=shader=] code. The other resources,
such as {{GPUSampler}} or {{GPUBindGroup}}, configure the way [=physical resources=] are used by the GPU.
GPUs execute commands encoded in {{GPUCommandBuffer}}s by feeding data through a [=pipeline=],
which is a mix of fixed-function and programmable stages. Programmable stages execute
<dfn dfn>shaders</dfn>, which are special programs designed to run on GPU hardware.
Most of the state of a [=pipeline=] is defined by
a {{GPURenderPipeline}} or a {{GPUComputePipeline}} object. The state not included
in these [=pipeline=] objects is set during encoding with commands,
such as {{GPUCommandEncoder/beginRenderPass()}} or {{GPURenderPassEncoder/setBlendConstant()}}.
# Malicious use considerations # {#malicious-use}
*This section is non-normative.* It describes the risks associated with exposing this API on the Web.
## Security Considerations ## {#security-considerations}
The security requirements for WebGPU are the same as ever for the web, and are likewise non-negotiable.
The general approach is strictly validating all the commands before they reach GPU,
ensuring that a page can only work with its own data.
### CPU-based undefined behavior ### {#security-cpu-ub}
A WebGPU implementation translates the workloads issued by the user into API commands specific
to the target platform. Native APIs specify the valid usage for the commands
(for example, see [vkCreateDescriptorSetLayout](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/vkCreateDescriptorSetLayout.html))
and generally don't guarantee any outcome if the valid usage rules are not followed.
This is called "undefined behavior", and it can be exploited by an attacker to access memory
they don't own, or force the driver to execute arbitrary code.
In order to disallow insecure usage, the range of allowed WebGPU behaviors is defined for any input.
An implementation has to validate all the input from the user and only reach the driver
with the valid workloads. This document specifies all the error conditions and handling semantics.
For example, specifying the same buffer with intersecting ranges in both "source" and "destination"
of {{GPUCommandEncoder/copyBufferToBuffer()}} results in {{GPUCommandEncoder}}
generating an error, and no other operation occurring.
See [[#errors-and-debugging]] for more information about error handling.
### GPU-based undefined behavior ### {#security-gpu-ub}
WebGPU [=shader=]s are executed by the compute units inside GPU hardware. In native APIs,
some of the shader instructions may result in undefined behavior on the GPU.
In order to address that, the shader instruction set and its defined behaviors are
strictly defined by WebGPU. When a shader is provided to {{GPUDevice/createShaderModule()}},
the WebGPU implementation has to validate it
before doing any translation (to platform-specific shaders) or transformation passes.
### Uninitialized data ### {#security-uninitialized}
Generally, allocating new memory may expose the leftover data of other applications running on the system.
In order to address that, WebGPU conceptually initializes all the resources to zero, although in practice
an implementation may skip this step if it sees the developer initializing the contents manually.
This includes variables and shared workgroup memory inside shaders.
The precise mechanism of clearing the workgroup memory can differ between platforms.
If the native API does not provide facilities to clear it, the WebGPU implementation transforms the compute
shader to first do a clear across all invocations, synchronize them, and continue executing developer's code.
<div class=note>
Note:
The initialization status of a resource used in a queue operation can only be known when the
operation is enqueued (not when it is encoded into a command buffer, for example). Therefore,
some implementations will require an unoptimized late-clear at enqueue time (e.g. clearing a
texture, rather than changing {{GPULoadOp}} {{GPULoadOp/"load"}} to {{GPULoadOp/"clear"}}).
As a result, all implementations **should** issue a developer console warning about this
potential performance penalty, even if there is no penalty in that implementation.
</div>
### Out-of-bounds access in shaders ### {#security-shader}
[=Shader=]s can access [=physical resource=]s either directly
(for example, as a {{GPUBufferBindingType/"uniform"}} {{GPUBufferBinding}}), or via <dfn dfn>texture unit</dfn>s,
which are fixed-function hardware blocks that handle texture coordinate conversions.
Validation in the WebGPU API can only guarantee that all the inputs to the shader are provided and
they have the correct usage and types.
The WebGPU API can not guarantee that the data is accessed within bounds
if the [=texture unit=]s are not involved.
In order to prevent the shaders from accessing GPU memory an application doesn't own,
the WebGPU implementation may enable a special mode (called "robust buffer access") in the driver
that guarantees that the access is limited to buffer bounds.
Alternatively, an implementation may transform the shader code by inserting manual bounds checks.
When this path is taken, the out-of-bound checks only apply to array indexing. They aren't needed
for plain field access of shader structures due to the {{GPUBufferBindingLayout/minBindingSize}}
validation on the host side.
If the shader attempts to load data outside of [=physical resource=] bounds,
the implementation is allowed to:
1. return a value at a different location within the resource bounds
1. return a value vector of "(0, 0, 0, X)" with any "X"
1. partially discard the draw or dispatch call
If the shader attempts to write data outside of [=physical resource=] bounds,
the implementation is allowed to:
1. write the value to a different location within the resource bounds
1. discard the write operation
1. partially discard the draw or dispatch call
### Invalid data ### {#security-invalid-data}
When uploading [floating-point](https://en.wikipedia.org/wiki/IEEE_754) data from CPU to GPU,
or generating it on the GPU, we may end up with a binary representation that doesn't correspond
to a valid number, such as infinity or NaN (not-a-number). The GPU behavior in this case is
subject to the accuracy of the GPU hardware implementation of the IEEE-754 standard.
WebGPU guarantees that introducing invalid floating-point numbers would only affect the results
of arithmetic computations and will not have other side effects.
### Driver bugs ### {#security-driver-bugs}
GPU drivers are subject to bugs like any other software. If a bug occurs, an attacker
could possibly exploit the incorrect behavior of the driver to get access to unprivileged data.
In order to reduce the risk, the WebGPU working group will coordinate with GPU vendors
to integrate the WebGPU Conformance Test Suite (CTS) as part of their driver testing process,
like it was done for WebGL.
WebGPU implementations are expected to have workarounds for some of the discovered bugs,
and disable WebGPU on drivers with known bugs that can't be worked around.
### Timing attacks ### {#security-timing}
WebGPU is designed to later support multi-threaded use via Web Workers. As such, it is designed not to open
the users to modern high-precision timing attacks. Some of the objects,
like {{GPUBuffer}} or {{GPUQueue}}, have shared state which can be simultaneously accessed.
This allows race conditions to occur, similar to those of accessing a `SharedArrayBuffer`
from multiple Web Workers, which makes the thread scheduling observable.
WebGPU addresses this by limiting the ability to deserialize (or share) objects only to
the [=agents=] inside the [=agent cluster=], and only if
the [cross-origin isolated](https://web.dev/coop-coep/) policies are in place.
This restriction matches the [mitigations](https://hacks.mozilla.org/2020/07/safely-reviving-shared-memory/)
against the malicious `SharedArrayBuffer` use. Similarly, the user agent may also
serialize the [=agents=] sharing any handles to prevent any concurrency entirely.
In the end, the attack surface for races on shared state in WebGPU will be
a small subset of the `SharedArrayBuffer` attacks.
WebGPU also specifies the {{GPUFeatureName/"timestamp-query"}} feature, which
provides high precision timing of GPU operations. The feature is optional, and a WebGPU
implementation may limit its exposure only to those scenarios that are trusted. Alternatively,
the timing query results could be processed by a compute shader and aligned to a lower precision.
### Row hammer attacks ### {#security-rowhammer}
[Row hammer](https://en.wikipedia.org/wiki/Row_hammer) is a class of attacks that exploit the
leaking of states in DRAM cells. It could be used [on GPU](https://www.vusec.net/projects/glitch/).
WebGPU does not have any specific mitigations in place, and relies on platform-level solutions,
such as reduced memory refresh intervals.
### Denial of service ### {#security-dos}
WebGPU applications have access to GPU memory and compute units. A WebGPU implementation may limit
the available GPU memory to an application, in order to keep other applications responsive.
For GPU processing time, a WebGPU implementation may set up "watchdog" timer that makes sure an
application doesn't cause GPU unresponsiveness for more than a few seconds.
These measures are similar to those used in WebGL.
### Workload identification ### {#security-workload-identification}
WebGPU provides access to constrained global resources shared between different programs
(and web pages) running on the same machine. An application can try to indirectly probe
how constrained these global resources are, in order to reason about workloads performed
by other open web pages, based on the patterns of usage of these shared resources.
These issues are generally analogous to issues with Javascript,
such as system memory and CPU execution throughput. WebGPU does not provide any additional
mitigations for this.
### Memory resources ### {#security-memory-resources}
WebGPU exposes fallible allocations from machine-global memory heaps, such as VRAM.
This allows for probing the size of the system's remaining available memory
(for a given heap type) by attempting to allocate and watching for allocation failures.
GPUs internally have one or more (typically only two) heaps of memory
shared by all running applications. When a heap is depleted, WebGPU would fail to create a resource.
This is observable, which may allow a malicious application to guess what heaps
are used by other applications, and how much they allocate from them.
### Computation resources ### {#security-computation-resources}
If one site uses WebGPU at the same time as another, it may observe the increase
in time it takes to process some work. For example, if a site constantly submits
compute workloads and tracks completion of work on the queue,
it may observe that something else also started using the GPU.
A GPU has many parts that can be tested independently, such as the arithmetic units,
texture sampling units, atomic units, etc. A malicious application may sense when
some of these units are stressed, and attempt to guess the workload of another
application by analyzing the stress patterns. This is analogous to the realities
of CPU execution of Javascript.
### Abuse of capabilities ### {#security-abuse-of-capabilities}
Malicious sites could abuse the capabilities exposed by WebGPU to run
computations that don't benefit the user or their experience and instead only
benefit the site. Examples would be hidden crypto-mining, password cracking
or rainbow tables computations.
It is not possible to guard against these types of uses of the API because the
browser is not able to distinguish between valid workloads and abusive
workloads. This is a general problem with all general-purpose computation
capabilities on the Web: JavaScript, WebAssembly or WebGL. WebGPU only makes
some workloads easier to implement, or slightly more efficient to run than
using WebGL.
To mitigate this form of abuse, browsers can throttle operations on background
tabs, could warn that a tab is using a lot of resource, and restrict which
contexts are allowed to use WebGPU.
User agents can heuristically issue warnings to users about high power use,
especially due to potentially malicious usage.
If a user agent implements such a warning, it should include WebGPU usage in
its heuristics, in addition to JavaScript, WebAssembly, WebGL, and so on.
## Privacy Considerations ## {#privacy-considerations}
<p tracking-vector>
The privacy considerations for WebGPU are similar to those of WebGL. GPU APIs are complex and must
expose various aspects of a device's capabilities out of necessity in order to enable developers to
take advantage of those capabilities effectively. The general mitigation approach involves
normalizing or binning potentially identifying information and enforcing uniform behavior where
possible.
A user agent must not reveal more than 32 distinguishable configurations or buckets.
### Machine-specific features and limits ### {#privacy-machine-limits}
WebGPU can expose a lot of detail on the underlying GPU architecture and the device geometry.
This includes available physical adapters, many limits on the GPU and CPU resources
that could be used (such as the maximum texture size), and any optional hardware-specific
capabilities that are available.
User agents are not obligated to expose the real hardware limits, they are in full control of
how much the machine specifics are exposed. One strategy to reduce fingerprinting is binning
all the target platforms into a few number of bins. In general, the privacy impact of exposing
the hardware limits matches the one of WebGL.
The [=limit/default=] limits are also deliberately high enough
to allow most applications to work without requesting higher limits.
All the usage of the API is validated according to the requested limits,
so the actual hardware capabilities are not exposed to the users by accident.
### Machine-specific artifacts ### {#privacy-machine-artifacts}
There are some machine-specific rasterization/precision artifacts and performance differences
that can be observed roughly in the same way as in WebGL. This applies to rasterization coverage
and patterns, interpolation precision of the varyings between shader stages, compute unit scheduling,
and more aspects of execution.
Generally, rasterization and precision fingerprints are identical across most or all
of the devices of each vendor. Performance differences are relatively intractable,
but also relatively low-signal (as with JS execution performance).
Privacy-critical applications and user agents should utilize software implementations to eliminate
such artifacts.
### Machine-specific performance ### {#privacy-machine-performance}
Another factor for differentiating users is measuring the performance of specific
operations on the GPU. Even with low precision timing, repeated execution of an operation
can show if the user's machine is fast at specific workloads.
This is a fairly common vector (present in both WebGL and Javascript),
but it's also low-signal and relatively intractable to truly normalize.
WebGPU compute pipelines expose access to GPU unobstructed by the fixed-function hardware.
This poses an additional risk for unique device fingerprinting. User agents can take steps
to dissociate logical GPU invocations with actual compute units to reduce this risk.
### User Agent State ### {#privacy-user-agent-state}
This specification doesn't define any additional user-agent state for an origin.
However it is expected that user agents will have compilation caches for the result of expensive
compilation like {{GPUShaderModule}}, {{GPURenderPipeline}} and {{GPUComputePipeline}}.
These caches are important to improve the loading time of WebGPU applications after the first
visit.
For the specification, these caches are indifferentiable from incredibly fast compilation, but
for applications it would be easy to measure how long {{GPUDevice/createComputePipelineAsync()}}
takes to resolve. This can leak information across origins (like "did the user access a site with
this specific shader") so user agents should follow the best practices in
[storage partitioning](https://github.com/privacycg/storage-partitioning).
The system's GPU driver may also have its own cache of compiled shaders and pipelines. User agents
may want to disable these when at all possible, or add per-partition data to shaders in ways that
will make the GPU driver consider them different.
### Driver bugs ### {#privacy-driver-bugs}
In addition to the concerns outlined in [[#security-driver-bugs|Security Considerations]], driver
bugs may introduce differences in behavior that can be observed as a method of differentiating
users. The mitigations mentioned in Security Considerations apply here as well, including
coordinating with GPU vendors and implementing workarounds for known issues in the user agent.
### Adapter Identifiers ### {#privacy-adapter-identifiers}
Past experience with WebGL has demonstrated that developers have a legitimate need to be able to
identify the GPU their code is running on in order to create and maintain robust GPU-based content.
For example, to identify adapters with known driver bugs in order to work around them or to avoid
features that perform more poorly than expected on a given class of hardware.
But exposing adapter identifiers also naturally expands the amount of fingerprinting information
available, so there's a desire to limit the precision with which we identify the adapter.
There are several mitigations that can be applied to strike a balance between enabling robust
content and preserving privacy. First is that user agents can reduce the burden on developers by
identifying and working around known driver issues, as they have since browsers began making use of
GPUs.
When adapter identifiers are exposed by default they should be as broad as possible while still
being useful. Possibly identifying, for example, the adapter's vendor and general architecture
without identifying the specific adapter in use. Similarly, in some cases identifiers for an adapter
that is considered a reasonable proxy for the actual adapter may be reported.
In cases where full and detailed information about the adapter is useful (for example: when filing
bug reports) the user can be asked for consent to reveal additional information about their hardware
to the page.
Finally, the user agent will always have the discretion to not report adapter identifiers at all if
it considers it appropriate, such as in enhanced privacy modes.
# Fundamentals # {#fundamentals}
## Conventions ## {#api-conventions}
### Syntactic Shorthands ### {#shorthands}
In this specification, the following syntactic shorthands are used:
: The `.` ("dot") syntax, common in programming languages.
::
The phrasing "`Foo.Bar`" means "the `Bar` member of the value (or interface) `Foo`."
If `Foo` is an [=ordered map=], [=asserts=] that the key `Bar` exists.
<p class="note editorial">Editorial:
Some phrasing in this spec may currently assume this resolves to `undefined` if `Bar` doesn't exist.
The phrasing "`Foo.Bar` is [=map/exist|provided=]" means
"the `Bar` member [=map/exists=] in the [=map=] value `Foo`"
: The `?.` ("optional chaining") syntax, adopted from JavaScript.
::
The phrasing "`Foo?.Bar`" means
"if `Foo` is `null` or `undefined` or `Bar` does not [=map/exist=] in `Foo`, `undefined`; otherwise, `Foo.Bar`".
For example, where `buffer` is a {{GPUBuffer}}, `buffer?.\[[device]].\[[adapter]]` means
"if `buffer` is `null` or `undefined`, then `undefined`; otherwise,
the `\[[adapter]]` internal slot of the `\[[device]]` internal slot of `buffer`.
: The `??` ("nullish coalescing") syntax, adopted from JavaScript.
::
The phrasing "`x` ?? `y`" means "`x`, if `x` is not null/undefined, and `y` otherwise".
: <dfn dfn>slot-backed attribute</dfn>
::
A WebIDL attribute which is backed by an internal slot of the same name.
It may or may not be mutable.
### WebGPU Interfaces ### {#webgpu-interfaces}
A <dfn dfn>WebGPU interface</dfn> defines a WebGPU object. It can be used:
- On the [=content timeline=] where it was created, where it is a JavaScript-exposed WebIDL interface.
- On all other timelines, where only [=immutable properties=] can be accessed.
The following special property types can be defined on [=WebGPU interfaces=]:
: <dfn dfn data-timeline=const>immutable property</dfn>
::
A read-only slot set during initialization of the object. It can be accessed from any timeline.
Note: Since the slot is immutable, implementations may have a copy on multiple timelines, as needed.
[=Immutable properties=] are defined in this way to avoid describing multiple copies in this spec.
If named `[[with brackets]]`, it is an internal slot.
If named `withoutBrackets`, it is a `readonly` [=slot-backed attribute=].
: <dfn dfn data-timeline=content>content timeline property</dfn>
::
A property which is only accessible from the [=content timeline=]
where the object was created.
If named `[[with brackets]]`, it is an internal slot.
If named `withoutBrackets`, it is a [=slot-backed attribute=].
Any interface which includes <dfn interface>GPUObjectBase</dfn> is a [=WebGPU interface=].
<script type=idl>
interface mixin GPUObjectBase {
attribute USVString label;
};
</script>
<div algorithm>
<div data-timeline=content>
To <dfn abstract-op>create a new WebGPU object</dfn>({{GPUObjectBase}} |parent|,
interface |T|, {{GPUObjectDescriptorBase}} |descriptor|)
(where |T| extends {{GPUObjectBase}}):
1. Let |device| be |parent|.{{GPUObjectBase/[[device]]}}.
1. Let |object| be a new instance of |T|.
1. Let |internals| be a new (uninitialized) instance of the type of
|T|.`\[[internals]]` (which may override {{GPUObjectBase}}.{{GPUObjectBase/[[internals]]}})
that is accessible only from the [=device timeline=] of |device|.
1. Set |object|.{{GPUObjectBase/[[device]]}} to |device|.
1. Set |object|.{{GPUObjectBase/[[internals]]}} to |internals|.
1. Set |object|.{{GPUObjectBase/label}} to |descriptor|.{{GPUObjectDescriptorBase/label}}.
1. Return [|object|, |internals|].
</div>
</div>
{{GPUObjectBase}} has the following [=immutable properties=]:
<dl dfn-type=attribute dfn-for=GPUObjectBase data-timeline=const>
: <dfn>\[[internals]]</dfn>, of type [=internal object=], readonly, overridable
::
The [=internal object=].
Operations on the contents of this object [=assert=] they are running on the
[=device timeline=], and that the device is [=valid=].
For each interface that subtypes {{GPUObjectBase}}, this may be overridden with a subtype
of [=internal object=]. This slot is initially set to an uninitialized object of that type.
: <dfn>\[[device]]</dfn>, of type [=device=], readonly
::
The [=device=] that owns the [=internal object=].
Operations on the contents of this object [=assert=] they are running on the
[=device timeline=], and that the device is [=valid=].
</dl>
{{GPUObjectBase}} has the following [=content timeline properties=]:
<dl dfn-type=attribute dfn-for=GPUObjectBase data-timeline=content>
: <dfn>label</dfn>
::
A developer-provided label which is used in an implementation-defined way.
It can be used by the browser, OS, or other tools to help
identify the underlying [=internal object=] to the developer.
Examples include displaying the label in {{GPUError}} messages, console warnings,
browser developer tools, and platform debugging utilities.
<div class=note>
Implementations **should** use labels to enhance error messages by using them to
identify WebGPU objects.
However, this need not be the only way of identifying objects:
implementations **should** also use other available information,
especially when no label is available. For example:
- The label of the parent {{GPUTexture}} when printing a {{GPUTextureView}}.
- The label of the parent {{GPUCommandEncoder}} when printing a
{{GPURenderPassEncoder}} or {{GPUComputePassEncoder}}.
- The label of the source {{GPUCommandEncoder}} when printing a {{GPUCommandBuffer}}.
- The label of the source {{GPURenderBundleEncoder}} when printing a {{GPURenderBundle}}.
</div>
<div class=note>
Note:
The {{GPUObjectBase/label}} is a property of the {{GPUObjectBase}}.
Two {{GPUObjectBase}} "wrapper" objects have completely separate label states,
even if they refer to the same underlying object
(for example returned by {{GPUPipelineBase/getBindGroupLayout()}}).
The {{GPUObjectBase/label}} property will not change except by being set from JavaScript.
This means one underlying object could be associated with multiple labels.
This specification does not define how the label is propagated to the [=device timeline=].
How labels are used is completely implementation-defined: error messages could
show the most recently set label, all known labels, or no labels at all.
It is defined as a {{USVString}} because some user agents may
supply it to the debug facilities of the underlying native APIs.
</div>
</dl>
<div class=note>
Note:
Ideally [=WebGPU interfaces=] should not prevent their parent objects, such as the
{{GPUObjectBase/[[device]]}} that owns them, from being garbage collected. This cannot be
guaranteed, however, as holding a strong reference to a parent object may be required in some
implementations.
As a result, developers should assume that a [=WebGPU interface=] may not be garbage collected
until all child objects of that interface have also been garbage collected. This may cause some
resources to remain allocated longer than anticipated.
Calling the `destroy` method on a [=WebGPU interface=] (such as
{{GPUDevice}}.{{GPUDevice/destroy()}} or {{GPUBuffer}}.{{GPUBuffer/destroy()}}) should be
favored over relying on garbage collection if predictable release of allocated resources is
needed.
</div>
### Internal Objects ### {#webgpu-internal-objects}
An <dfn dfn>internal object</dfn> tracks state of WebGPU objects that may only be used on
the [=device timeline=], in [=device timeline slots=], which may be mutable.
: <dfn dfn data-timeline=device>device timeline slot</dfn>
::
An internal slot which is only accessible from the [=device timeline=].
All reads/writes to the mutable state of an [=internal object=] occur from steps executing on a
single well-ordered [=device timeline=]. These steps may have been issued from a
[=content timeline=] algorithm on any of multiple [=agents=].
Note: An "[=agent=]" refers to a JavaScript "thread" (i.e. main thread, or Web Worker).
### Object Descriptors ### {#object-descriptors}
An <dfn dfn>object descriptor</dfn> holds the information needed to create an object,
which is typically done via one of the `create*` methods of {{GPUDevice}}.
<script type=idl>
dictionary GPUObjectDescriptorBase {
USVString label;
};
</script>
{{GPUObjectDescriptorBase}} has the following members:
<dl dfn-type=dict-member dfn-for=GPUObjectDescriptorBase>
: <dfn>label</dfn>
::
The initial value of {{GPUObjectBase/label|GPUObjectBase.label}}.
</dl>
## Asynchrony ## {#asynchrony}
### Invalid Internal Objects & Contagious Invalidity ### {#invalidity}
Object creation operations in WebGPU don't return promises, but nonetheless are internally
asynchronous. Returned objects refer to [=internal objects=] which are manipulated on a
[=device timeline=]. Rather than fail with exceptions or rejections, most errors that occur on a
[=device timeline=] are communicated through {{GPUError}}s generated on the associated [=device=].
[=Internal objects=] are either <dfn dfn>valid</dfn> or <dfn dfn>invalid</dfn>.
An [=invalid=] object will never become [=valid=] at a later time,
but some [=valid=] objects may become [=invalid=].
Objects are [=invalid=] from creation if it wasn't possible to create them.
This can happen, for example, if the [=object descriptor=] doesn't describe a valid
object, or if there is not enough memory to allocate a resource.
[=Internal objects=] of *most* types cannot become [=invalid=] after they are created, but still
may become unusable, e.g. if the owning device is [=lose the device|lost=] or
{{GPUDevice/destroy()|destroyed}}, or the object has a special internal state,
like buffer state "[=buffer internals/state/destroyed=]".
[=Internal objects=] of some types *can* become [=invalid=] after they are created; specifically,
[=devices=], [=adapters=], {{GPUCommandBuffer}}s, and command/pass/bundle encoders.