sync 6fdf6301e2bb
Browse files- README.md +4 -2
- build/webgpu/bench.json +56 -3
- build/webgpu/grid-sample.wgsl.jinja +13 -49
- build/webgpu/grid-sample3d.wgsl.jinja +51 -54
- build/webgpu/manifest.json +12 -23
- build/webgpu/metadata.json +8 -8
- build/webgpu/test.json +309 -2
README.md
CHANGED
|
@@ -49,6 +49,8 @@ Default values (overridable per request):
|
|
| 49 |
|
| 50 |
One implementation is selected per call from the device capabilities, the request shapes and the dtypes; these notes say what each one covers.
|
| 51 |
|
|
|
|
|
|
|
| 52 |
- `ncdhw_rank5_channel_vector` — Shares volumetric coordinates, padding and interpolation across a vector of channels; uses two lanes for two channels and four lanes otherwise, with masked tails and device-capped workgroups.
|
| 53 |
- `ncdhw_rank5` — Portable scalar volumetric sampling for all interpolation and padding modes.
|
| 54 |
|
|
@@ -57,14 +59,14 @@ One implementation is selected per call from the device capabilities, the reques
|
|
| 57 |
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
|
| 58 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 59 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 60 |
-
- [`bench.json`](build/webgpu/bench.json) — benchmark
|
| 61 |
- [`grid-sample.wgsl.jinja`](build/webgpu/grid-sample.wgsl.jinja)
|
| 62 |
- [`grid-sample3d.wgsl.jinja`](build/webgpu/grid-sample3d.wgsl.jinja)
|
| 63 |
|
| 64 |
## Use with `@huggingface/kernels`
|
| 65 |
|
| 66 |
```sh
|
| 67 |
-
npm install --save-exact @huggingface/kernels@0.0.1-preview.
|
| 68 |
```
|
| 69 |
|
| 70 |
Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
|
|
|
|
| 49 |
|
| 50 |
One implementation is selected per call from the device capabilities, the request shapes and the dtypes; these notes say what each one covers.
|
| 51 |
|
| 52 |
+
- `nchw_rank4_channel_vector` — Resolves the sampling coordinate once per pixel and reuses it across four channels, so one thread gathers from four channel planes instead of reading one coalesced. This amortizes the coordinate math across channels, trading a coalesced read for a scattered gather; adapters where scattered gathers are slow use the coalesced variant instead.
|
| 53 |
+
- `nchw_rank4` — Portable scalar spatial sampling: one thread per output element, so reads stay coalesced within one channel plane. The route for every adapter whose gather throughput the channel vector would spend.
|
| 54 |
- `ncdhw_rank5_channel_vector` — Shares volumetric coordinates, padding and interpolation across a vector of channels; uses two lanes for two channels and four lanes otherwise, with masked tails and device-capped workgroups.
|
| 55 |
- `ncdhw_rank5` — Portable scalar volumetric sampling for all interpolation and padding modes.
|
| 56 |
|
|
|
|
| 59 |
- [`metadata.json`](build/webgpu/metadata.json) — kernel metadata (id, digests, per-variant templates, provenance)
|
| 60 |
- [`manifest.json`](build/webgpu/manifest.json) — the op contract (source of truth)
|
| 61 |
- [`test.json`](build/webgpu/test.json) — correctness cases
|
| 62 |
+
- [`bench.json`](build/webgpu/bench.json) — benchmark cases
|
| 63 |
- [`grid-sample.wgsl.jinja`](build/webgpu/grid-sample.wgsl.jinja)
|
| 64 |
- [`grid-sample3d.wgsl.jinja`](build/webgpu/grid-sample3d.wgsl.jinja)
|
| 65 |
|
| 66 |
## Use with `@huggingface/kernels`
|
| 67 |
|
| 68 |
```sh
|
| 69 |
+
npm install --save-exact @huggingface/kernels@0.0.1-preview.3
|
| 70 |
```
|
| 71 |
|
| 72 |
Required output shapes and logical data types are inferred from the supplied inputs and attributes; result tensors are allocated automatically.
|
build/webgpu/bench.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
| 10 |
"outputs": { "y": { "dtype": "float32", "shape": [1, 3, 256, 256] } }
|
| 11 |
},
|
| 12 |
{
|
| 13 |
-
"name": "
|
| 14 |
"preset": "smoke",
|
| 15 |
"attrs": { "mode": "linear", "padding_mode": "zeros", "align_corners": 0 },
|
| 16 |
"inputs": {
|
|
@@ -63,7 +63,7 @@
|
|
| 63 |
}
|
| 64 |
},
|
| 65 |
{
|
| 66 |
-
"name": "
|
| 67 |
"preset": "smoke",
|
| 68 |
"attrs": { "mode": "linear", "padding_mode": "zeros", "align_corners": 0 },
|
| 69 |
"inputs": {
|
|
@@ -412,6 +412,59 @@
|
|
| 412 |
"bench": {
|
| 413 |
"metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.grid) + numel(shapes.y)) * 4" }]
|
| 414 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 415 |
}
|
| 416 |
-
]
|
|
|
|
| 417 |
}
|
|
|
|
| 10 |
"outputs": { "y": { "dtype": "float32", "shape": [1, 3, 256, 256] } }
|
| 11 |
},
|
| 12 |
{
|
| 13 |
+
"name": "nchw_1x32x256x256_linear_zeros_f32_control",
|
| 14 |
"preset": "smoke",
|
| 15 |
"attrs": { "mode": "linear", "padding_mode": "zeros", "align_corners": 0 },
|
| 16 |
"inputs": {
|
|
|
|
| 63 |
}
|
| 64 |
},
|
| 65 |
{
|
| 66 |
+
"name": "ncdhw_1x4x16x32x32_linear_zeros_f32_volumetric",
|
| 67 |
"preset": "smoke",
|
| 68 |
"attrs": { "mode": "linear", "padding_mode": "zeros", "align_corners": 0 },
|
| 69 |
"inputs": {
|
|
|
|
| 412 |
"bench": {
|
| 413 |
"metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.grid) + numel(shapes.y)) * 4" }]
|
| 414 |
}
|
| 415 |
+
},
|
| 416 |
+
{
|
| 417 |
+
"name": "volume_scalar_linear_reflection_float32_c1",
|
| 418 |
+
"preset": "stress",
|
| 419 |
+
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 0 },
|
| 420 |
+
"inputs": {
|
| 421 |
+
"x": { "dtype": "float32", "shape": [1, 1, 12, 16, 16], "dist": "normal", "scale": 0.3, "seed": 16304 },
|
| 422 |
+
"grid": { "dtype": "float32", "shape": [1, 24, 32, 32, 3], "dist": "normal", "scale": 1.5, "seed": 16404 }
|
| 423 |
+
},
|
| 424 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 24, 32, 32] } },
|
| 425 |
+
"bench": {
|
| 426 |
+
"metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.grid) + numel(shapes.y)) * 4" }]
|
| 427 |
+
}
|
| 428 |
+
},
|
| 429 |
+
{
|
| 430 |
+
"name": "volume_scalar_linear_reflection_float16_c1",
|
| 431 |
+
"preset": "stress",
|
| 432 |
+
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 1 },
|
| 433 |
+
"inputs": {
|
| 434 |
+
"x": { "dtype": "float16", "shape": [1, 1, 12, 16, 16], "dist": "normal", "scale": 0.3, "seed": 16305 },
|
| 435 |
+
"grid": { "dtype": "float16", "shape": [1, 24, 32, 32, 3], "dist": "normal", "scale": 1.5, "seed": 16405 }
|
| 436 |
+
},
|
| 437 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 1, 24, 32, 32] } },
|
| 438 |
+
"bench": {
|
| 439 |
+
"metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.grid) + numel(shapes.y)) * 2" }]
|
| 440 |
+
}
|
| 441 |
+
},
|
| 442 |
+
{
|
| 443 |
+
"name": "volume_scalar_cubic_reflection_float32_c1",
|
| 444 |
+
"preset": "stress",
|
| 445 |
+
"attrs": { "mode": "cubic", "padding_mode": "reflection", "align_corners": 0 },
|
| 446 |
+
"inputs": {
|
| 447 |
+
"x": { "dtype": "float32", "shape": [1, 1, 12, 16, 16], "dist": "normal", "scale": 0.3, "seed": 16316 },
|
| 448 |
+
"grid": { "dtype": "float32", "shape": [1, 24, 32, 32, 3], "dist": "normal", "scale": 1.5, "seed": 16416 }
|
| 449 |
+
},
|
| 450 |
+
"outputs": { "y": { "dtype": "float32", "shape": [1, 1, 24, 32, 32] } },
|
| 451 |
+
"bench": {
|
| 452 |
+
"metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.grid) + numel(shapes.y)) * 4" }]
|
| 453 |
+
}
|
| 454 |
+
},
|
| 455 |
+
{
|
| 456 |
+
"name": "volume_scalar_cubic_reflection_float16_c1",
|
| 457 |
+
"preset": "stress",
|
| 458 |
+
"attrs": { "mode": "cubic", "padding_mode": "reflection", "align_corners": 1 },
|
| 459 |
+
"inputs": {
|
| 460 |
+
"x": { "dtype": "float16", "shape": [1, 1, 12, 16, 16], "dist": "normal", "scale": 0.3, "seed": 16317 },
|
| 461 |
+
"grid": { "dtype": "float16", "shape": [1, 24, 32, 32, 3], "dist": "normal", "scale": 1.5, "seed": 16417 }
|
| 462 |
+
},
|
| 463 |
+
"outputs": { "y": { "dtype": "float16", "shape": [1, 1, 24, 32, 32] } },
|
| 464 |
+
"bench": {
|
| 465 |
+
"metrics": [{ "type": "bandwidth", "value": "(numel(shapes.x) + numel(shapes.grid) + numel(shapes.y)) * 2" }]
|
| 466 |
+
}
|
| 467 |
}
|
| 468 |
+
],
|
| 469 |
+
"tunableSpace": { "RESOLVE_REFLECTION_TAPS": [0, 1] }
|
| 470 |
}
|
build/webgpu/grid-sample.wgsl.jinja
CHANGED
|
@@ -1,36 +1,8 @@
|
|
| 1 |
-
{% macro flat_index_2d(name="i", bound="params.count", guardInline=false
|
| 2 |
-
{%
|
| 3 |
-
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 4 |
-
// per-axis workgroup fold width (outputs > 16.7M elements).
|
| 5 |
-
{% elif note == "limit" %}
|
| 6 |
-
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 7 |
-
// per-axis workgroup fold width.
|
| 8 |
-
{% elif note == "device-axis" %}
|
| 9 |
-
// The flat dispatch is folded across x/y at a fixed per-axis workgroup
|
| 10 |
-
// width; gid.y carries the high portion of the output index.
|
| 11 |
-
{% elif note == "vec4-limit" %}
|
| 12 |
-
// 2D-folded flat vec4 index: gid.y carries the high bits past the dispatch's
|
| 13 |
-
// per-axis workgroup fold width (the dispatch caps x and spills into y).
|
| 14 |
-
{% elif note == "element-limit" %}
|
| 15 |
-
// 2D-folded flat element index: gid.y carries the high bits past the
|
| 16 |
-
// dispatch's per-axis workgroup fold width.
|
| 17 |
-
{% elif note == "dispatch" %}
|
| 18 |
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 19 |
// per-axis workgroup fold width.
|
| 20 |
-
{%
|
| 21 |
-
{% if bound == "" %}
|
| 22 |
-
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ tunables.WORKGROUP_SIZE }}u;
|
| 23 |
-
{%- elif guardInline %}
|
| 24 |
-
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ tunables.WORKGROUP_SIZE }}u;
|
| 25 |
-
if ({{ name }} >= {{ bound }}) { return; }
|
| 26 |
-
{%- else %}
|
| 27 |
-
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ tunables.WORKGROUP_SIZE }}u;
|
| 28 |
-
if ({{ name }} >= {{ bound }}) {
|
| 29 |
-
return;
|
| 30 |
-
}
|
| 31 |
-
{%- endif %}
|
| 32 |
-
{% endmacro %}
|
| 33 |
-
|
| 34 |
{{ env.wgsl.resourceDeclarations }}
|
| 35 |
|
| 36 |
fn denormalize(n: f32, length: u32) -> f32 {
|
|
@@ -72,8 +44,8 @@ fn reflect_coord(v: f32, lo: f32, hi: f32) -> f32 {
|
|
| 72 |
}
|
| 73 |
return x0;
|
| 74 |
}
|
| 75 |
-
|
| 76 |
{% endif %}
|
|
|
|
| 77 |
{% if modeSpec != "nearest" %}
|
| 78 |
fn sample_floor(v: f32) -> i32 {
|
| 79 |
if (v > 2147483000.0) {
|
|
@@ -92,7 +64,7 @@ fn sample_floor(v: f32) -> i32 {
|
|
| 92 |
}
|
| 93 |
return i32(floor(v));
|
| 94 |
}
|
| 95 |
-
{%
|
| 96 |
fn sample_round(v: f32) -> i32 {
|
| 97 |
if (v > 2147483000.0) {
|
| 98 |
{% if paddingMode == "reflection" %}
|
|
@@ -110,10 +82,9 @@ fn sample_round(v: f32) -> i32 {
|
|
| 110 |
}
|
| 111 |
return i32(round(v));
|
| 112 |
}
|
| 113 |
-
{%
|
| 114 |
-
|
| 115 |
-
|
| 116 |
{% if modeSpec == "cubic" %}
|
|
|
|
| 117 |
fn cubic_coeffs(t: f32) -> vec4<f32> {
|
| 118 |
let a = -0.75;
|
| 119 |
let x0 = abs(t + 1.0);
|
|
@@ -128,9 +99,9 @@ fn cubic_one(x0: f32, a: f32) -> f32 {
|
|
| 128 |
if (x0 < 2.0) { return a * x0 * x0 * x0 - 5.0 * a * x0 * x0 + 8.0 * a * x0 - 4.0 * a; }
|
| 129 |
return 0.0;
|
| 130 |
}
|
| 131 |
-
|
| 132 |
-
{% endif -%}
|
| 133 |
{% if channelWidthSpec is not defined %}
|
|
|
|
| 134 |
fn pixel(base: u32, h: i32, w: i32) -> f32 {
|
| 135 |
{% if paddingMode == "zeros" %}
|
| 136 |
if (h < 0 || h >= i32(params.inH) || w < 0 || w >= i32(params.inW)) { return 0.0; }
|
|
@@ -152,12 +123,11 @@ fn pixel(base: u32, h: i32, w: i32) -> f32 {
|
|
| 152 |
{% endif %}
|
| 153 |
return f32(x[base + hh * params.inW + ww]);
|
| 154 |
}
|
| 155 |
-
|
| 156 |
-
|
| 157 |
{% endif %}
|
| 158 |
{% if channelWidthSpec is defined %}
|
| 159 |
{% set channelVec = "vec" ~ channelWidthSpec ~ "<f32>" %}
|
| 160 |
{% set components = ["x", "y", "z", "w"] %}
|
|
|
|
| 161 |
// A block of NCHW channels shares one grid coordinate. Tail lanes alias the
|
| 162 |
// final channel safely because main suppresses their stores.
|
| 163 |
{% if paddingMode != "reflection" or modeSpec == "nearest" %}
|
|
@@ -188,12 +158,9 @@ fn pixel_channels(n: u32, c0: u32, h: i32, w: i32) -> {{ channelVec }} {
|
|
| 188 |
f32(x[(nb + {% if channelTail %}min(c0 + {{ lane }}u, params.C - 1u){% else %}c0 + {{ lane }}u{% endif %}) * plane + offset]){% if not loop.last %},{% else %});{% endif %}
|
| 189 |
{% endfor %}
|
| 190 |
}
|
| 191 |
-
|
| 192 |
-
{% endif %}
|
| 193 |
-
{% if paddingMode == "reflection" %}
|
| 194 |
// Reflection gives every tap in one row or column the same resolved coordinate.
|
| 195 |
// Resolve each row and column once in main and reuse it for all channel loads.
|
| 196 |
-
{% if modeSpec != "nearest" %}
|
| 197 |
fn pixel_channels_resolved(n: u32, c0: u32, h: u32, w: u32) -> {{ channelVec }} {
|
| 198 |
let plane = params.inH * params.inW;
|
| 199 |
let offset = h * params.inW + w;
|
|
@@ -203,15 +170,12 @@ fn pixel_channels_resolved(n: u32, c0: u32, h: u32, w: u32) -> {{ channelVec }}
|
|
| 203 |
f32(x[(nb + {% if channelTail %}min(c0 + {{ lane }}u, params.C - 1u){% else %}c0 + {{ lane }}u{% endif %}) * plane + offset]){% if not loop.last %},{% else %});{% endif %}
|
| 204 |
{% endfor %}
|
| 205 |
}
|
| 206 |
-
|
| 207 |
{% endif %}
|
| 208 |
-
{% else %}
|
| 209 |
-
|
| 210 |
{% endif %}
|
| 211 |
-
|
| 212 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 213 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 214 |
-
{{ flat_index_2d("i", "") }}
|
| 215 |
{% if channelWidthSpec is defined %}
|
| 216 |
let out_plane = params.outH * params.outW;
|
| 217 |
let channel_blocks = (params.C + {{ channelWidthSpec - 1 }}u) / {{ channelWidthSpec }}u;
|
|
|
|
| 1 |
+
{% macro flat_index_2d(workgroupSize, name="i", bound="params.count", guardInline=false) %}
|
| 2 |
+
{% set wgTerm = workgroupSize ~ "u" if workgroupSize is number else workgroupSize %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 4 |
// per-axis workgroup fold width.
|
| 5 |
+
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ wgTerm }};{% endmacro %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
{{ env.wgsl.resourceDeclarations }}
|
| 7 |
|
| 8 |
fn denormalize(n: f32, length: u32) -> f32 {
|
|
|
|
| 44 |
}
|
| 45 |
return x0;
|
| 46 |
}
|
|
|
|
| 47 |
{% endif %}
|
| 48 |
+
|
| 49 |
{% if modeSpec != "nearest" %}
|
| 50 |
fn sample_floor(v: f32) -> i32 {
|
| 51 |
if (v > 2147483000.0) {
|
|
|
|
| 64 |
}
|
| 65 |
return i32(floor(v));
|
| 66 |
}
|
| 67 |
+
{% else %}
|
| 68 |
fn sample_round(v: f32) -> i32 {
|
| 69 |
if (v > 2147483000.0) {
|
| 70 |
{% if paddingMode == "reflection" %}
|
|
|
|
| 82 |
}
|
| 83 |
return i32(round(v));
|
| 84 |
}
|
| 85 |
+
{% endif %}
|
|
|
|
|
|
|
| 86 |
{% if modeSpec == "cubic" %}
|
| 87 |
+
|
| 88 |
fn cubic_coeffs(t: f32) -> vec4<f32> {
|
| 89 |
let a = -0.75;
|
| 90 |
let x0 = abs(t + 1.0);
|
|
|
|
| 99 |
if (x0 < 2.0) { return a * x0 * x0 * x0 - 5.0 * a * x0 * x0 + 8.0 * a * x0 - 4.0 * a; }
|
| 100 |
return 0.0;
|
| 101 |
}
|
| 102 |
+
{% endif %}
|
|
|
|
| 103 |
{% if channelWidthSpec is not defined %}
|
| 104 |
+
|
| 105 |
fn pixel(base: u32, h: i32, w: i32) -> f32 {
|
| 106 |
{% if paddingMode == "zeros" %}
|
| 107 |
if (h < 0 || h >= i32(params.inH) || w < 0 || w >= i32(params.inW)) { return 0.0; }
|
|
|
|
| 123 |
{% endif %}
|
| 124 |
return f32(x[base + hh * params.inW + ww]);
|
| 125 |
}
|
|
|
|
|
|
|
| 126 |
{% endif %}
|
| 127 |
{% if channelWidthSpec is defined %}
|
| 128 |
{% set channelVec = "vec" ~ channelWidthSpec ~ "<f32>" %}
|
| 129 |
{% set components = ["x", "y", "z", "w"] %}
|
| 130 |
+
|
| 131 |
// A block of NCHW channels shares one grid coordinate. Tail lanes alias the
|
| 132 |
// final channel safely because main suppresses their stores.
|
| 133 |
{% if paddingMode != "reflection" or modeSpec == "nearest" %}
|
|
|
|
| 158 |
f32(x[(nb + {% if channelTail %}min(c0 + {{ lane }}u, params.C - 1u){% else %}c0 + {{ lane }}u{% endif %}) * plane + offset]){% if not loop.last %},{% else %});{% endif %}
|
| 159 |
{% endfor %}
|
| 160 |
}
|
| 161 |
+
{% else %}
|
|
|
|
|
|
|
| 162 |
// Reflection gives every tap in one row or column the same resolved coordinate.
|
| 163 |
// Resolve each row and column once in main and reuse it for all channel loads.
|
|
|
|
| 164 |
fn pixel_channels_resolved(n: u32, c0: u32, h: u32, w: u32) -> {{ channelVec }} {
|
| 165 |
let plane = params.inH * params.inW;
|
| 166 |
let offset = h * params.inW + w;
|
|
|
|
| 170 |
f32(x[(nb + {% if channelTail %}min(c0 + {{ lane }}u, params.C - 1u){% else %}c0 + {{ lane }}u{% endif %}) * plane + offset]){% if not loop.last %},{% else %});{% endif %}
|
| 171 |
{% endfor %}
|
| 172 |
}
|
|
|
|
| 173 |
{% endif %}
|
|
|
|
|
|
|
| 174 |
{% endif %}
|
| 175 |
+
|
| 176 |
@compute @workgroup_size({{ tunables.WORKGROUP_SIZE }})
|
| 177 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 178 |
+
{{ flat_index_2d(tunables.WORKGROUP_SIZE, "i", "") }}
|
| 179 |
{% if channelWidthSpec is defined %}
|
| 180 |
let out_plane = params.outH * params.outW;
|
| 181 |
let channel_blocks = (params.C + {{ channelWidthSpec - 1 }}u) / {{ channelWidthSpec }}u;
|
build/webgpu/grid-sample3d.wgsl.jinja
CHANGED
|
@@ -1,36 +1,9 @@
|
|
| 1 |
-
{% macro flat_index_2d(name="i", bound="params.count", guardInline=false
|
| 2 |
-
{%
|
| 3 |
-
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 4 |
-
// per-axis workgroup fold width (outputs > 16.7M elements).
|
| 5 |
-
{% elif note == "limit" %}
|
| 6 |
-
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 7 |
-
// per-axis workgroup fold width.
|
| 8 |
-
{% elif note == "device-axis" %}
|
| 9 |
-
// The flat dispatch is folded across x/y at a fixed per-axis workgroup
|
| 10 |
-
// width; gid.y carries the high portion of the output index.
|
| 11 |
-
{% elif note == "vec4-limit" %}
|
| 12 |
-
// 2D-folded flat vec4 index: gid.y carries the high bits past the dispatch's
|
| 13 |
-
// per-axis workgroup fold width (the dispatch caps x and spills into y).
|
| 14 |
-
{% elif note == "element-limit" %}
|
| 15 |
-
// 2D-folded flat element index: gid.y carries the high bits past the
|
| 16 |
-
// dispatch's per-axis workgroup fold width.
|
| 17 |
-
{% elif note == "dispatch" %}
|
| 18 |
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 19 |
// per-axis workgroup fold width.
|
| 20 |
-
{
|
| 21 |
-
{
|
| 22 |
-
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ tunables.WORKGROUP_SIZE }}u;
|
| 23 |
-
{%- elif guardInline %}
|
| 24 |
-
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ tunables.WORKGROUP_SIZE }}u;
|
| 25 |
-
if ({{ name }} >= {{ bound }}) { return; }
|
| 26 |
-
{%- else %}
|
| 27 |
-
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ tunables.WORKGROUP_SIZE }}u;
|
| 28 |
-
if ({{ name }} >= {{ bound }}) {
|
| 29 |
-
return;
|
| 30 |
-
}
|
| 31 |
-
{%- endif %}
|
| 32 |
-
{% endmacro %}
|
| 33 |
-
|
| 34 |
{{ env.wgsl.resourceDeclarations }}
|
| 35 |
|
| 36 |
fn denormalize(n: f32, length: u32) -> f32 {
|
|
@@ -72,8 +45,8 @@ fn reflect_coord(v: f32, lo: f32, hi: f32) -> f32 {
|
|
| 72 |
}
|
| 73 |
return x0;
|
| 74 |
}
|
| 75 |
-
|
| 76 |
{% endif %}
|
|
|
|
| 77 |
{% if modeSpec != "nearest" %}
|
| 78 |
fn sample_floor(v: f32) -> i32 {
|
| 79 |
if (v > 2147483000.0) {
|
|
@@ -92,7 +65,7 @@ fn sample_floor(v: f32) -> i32 {
|
|
| 92 |
}
|
| 93 |
return i32(floor(v));
|
| 94 |
}
|
| 95 |
-
{%
|
| 96 |
fn sample_round(v: f32) -> i32 {
|
| 97 |
if (v > 2147483000.0) {
|
| 98 |
{% if paddingMode == "reflection" %}
|
|
@@ -110,10 +83,9 @@ fn sample_round(v: f32) -> i32 {
|
|
| 110 |
}
|
| 111 |
return i32(round(v));
|
| 112 |
}
|
| 113 |
-
{%
|
| 114 |
-
|
| 115 |
-
|
| 116 |
{% if modeSpec == "cubic" %}
|
|
|
|
| 117 |
fn cubic_coeffs(t: f32) -> vec4<f32> {
|
| 118 |
let a = -0.75;
|
| 119 |
let x0 = abs(t + 1.0);
|
|
@@ -128,12 +100,34 @@ fn cubic_one(x0: f32, a: f32) -> f32 {
|
|
| 128 |
if (x0 < 2.0) { return a * x0 * x0 * x0 - 5.0 * a * x0 * x0 + 8.0 * a * x0 - 4.0 * a; }
|
| 129 |
return 0.0;
|
| 130 |
}
|
| 131 |
-
|
| 132 |
-
{% endif -%}
|
| 133 |
{% set volumeVector = channelWidthSpec is defined %}
|
| 134 |
{% set volumeT = "vec" ~ channelWidthSpec ~ "<f32>" if volumeVector else "f32" %}
|
| 135 |
{% set voxelArgs = "img_base, c, " if volumeVector and channelTail else "img_base, " %}
|
| 136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 137 |
{% if paddingMode == "zeros" %}
|
| 138 |
if (d < 0 || d >= i32(params.inD) || h < 0 || h >= i32(params.inH) || w < 0 || w >= i32(params.inW)) {
|
| 139 |
return {% if volumeVector %}{{ volumeT }}(0.0){% else %}0.0{% endif %};
|
|
@@ -159,6 +153,7 @@ fn voxel(base: u32,{% if volumeVector and channelTail %} c0: u32,{% endif %} d:
|
|
| 159 |
let hh = u32(clamp(rh, 0, i32(params.inH) - 1));
|
| 160 |
let ww = u32(clamp(rw, 0, i32(params.inW) - 1));
|
| 161 |
{% endif %}
|
|
|
|
| 162 |
{% if volumeVector %}
|
| 163 |
// All channels share the resolved voxel coordinates. Incomplete vectors
|
| 164 |
// alias the final channel on loads; main masks their output stores.
|
|
@@ -173,7 +168,7 @@ fn voxel(base: u32,{% if volumeVector and channelTail %} c0: u32,{% endif %} d:
|
|
| 173 |
|
| 174 |
@compute @workgroup_size({{ volumeWorkgroup if volumeVector else tunables.WORKGROUP_SIZE }})
|
| 175 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 176 |
-
{{ flat_index_2d(guardInline=true) }}
|
| 177 |
|
| 178 |
let ow = i % params.outW;
|
| 179 |
var t = i / params.outW;
|
|
@@ -200,22 +195,23 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
| 200 |
let result = voxel({{ voxelArgs }}sample_round(sz), sample_round(sy), sample_round(sx));
|
| 201 |
{% elif modeSpec == "cubic" %}
|
| 202 |
// Tricubic applies separable four-tap Keys interpolation along each spatial
|
| 203 |
-
// axis
|
| 204 |
-
//
|
| 205 |
let x0 = sample_floor(sx) - 1;
|
| 206 |
let y0 = sample_floor(sy) - 1;
|
| 207 |
let z0 = sample_floor(sz) - 1;
|
| 208 |
let cx = cubic_coeffs(sx - f32(x0 + 1));
|
| 209 |
let cy = cubic_coeffs(sy - f32(y0 + 1));
|
| 210 |
let cz = cubic_coeffs(sz - f32(z0 + 1));
|
|
|
|
| 211 |
var result = {% if volumeVector %}{{ volumeT }}(0.0){% else %}0.0{% endif %};
|
| 212 |
for (var kz = 0i; kz < 4i; kz = kz + 1i) {
|
| 213 |
var plane = {% if volumeVector %}{{ volumeT }}(0.0){% else %}0.0{% endif %};
|
| 214 |
for (var ky = 0i; ky < 4i; ky = ky + 1i) {
|
| 215 |
-
let row = cx.x * voxel({{ voxelArgs }}z0 + kz, y0 + ky, x0)
|
| 216 |
-
+ cx.y * voxel({{ voxelArgs }}z0 + kz, y0 + ky, x0 + 1)
|
| 217 |
-
+ cx.z * voxel({{ voxelArgs }}z0 + kz, y0 + ky, x0 + 2)
|
| 218 |
-
+ cx.w * voxel({{ voxelArgs }}z0 + kz, y0 + ky, x0 + 3);
|
| 219 |
plane = plane + cy[u32(ky)] * row;
|
| 220 |
}
|
| 221 |
result = result + cz[u32(kz)] * plane;
|
|
@@ -227,14 +223,15 @@ fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
|
| 227 |
let wx = sx - f32(x0);
|
| 228 |
let wy = sy - f32(y0);
|
| 229 |
let wz = sz - f32(z0);
|
| 230 |
-
|
| 231 |
-
let
|
| 232 |
-
let
|
| 233 |
-
let
|
| 234 |
-
let
|
| 235 |
-
let
|
| 236 |
-
let
|
| 237 |
-
let
|
|
|
|
| 238 |
let front = (1.0 - wy) * ((1.0 - wx) * v000 + wx * v001) + wy * ((1.0 - wx) * v010 + wx * v011);
|
| 239 |
let back = (1.0 - wy) * ((1.0 - wx) * v100 + wx * v101) + wy * ((1.0 - wx) * v110 + wx * v111);
|
| 240 |
let result = (1.0 - wz) * front + wz * back;
|
|
|
|
| 1 |
+
{% macro flat_index_2d(workgroupSize, name="i", bound="params.count", guardInline=false) %}
|
| 2 |
+
{% set wgTerm = workgroupSize ~ "u" if workgroupSize is number else workgroupSize %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
// 2D-folded flat index: gid.y carries the high bits past the dispatch's
|
| 4 |
// per-axis workgroup fold width.
|
| 5 |
+
let {{ name }} = gid.x + gid.y * {{ DISPATCH_FOLD_WIDTH }}u * {{ wgTerm }};
|
| 6 |
+
if ({{ name }} >= {{ bound }}) { return; }{% endmacro %}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
{{ env.wgsl.resourceDeclarations }}
|
| 8 |
|
| 9 |
fn denormalize(n: f32, length: u32) -> f32 {
|
|
|
|
| 45 |
}
|
| 46 |
return x0;
|
| 47 |
}
|
|
|
|
| 48 |
{% endif %}
|
| 49 |
+
|
| 50 |
{% if modeSpec != "nearest" %}
|
| 51 |
fn sample_floor(v: f32) -> i32 {
|
| 52 |
if (v > 2147483000.0) {
|
|
|
|
| 65 |
}
|
| 66 |
return i32(floor(v));
|
| 67 |
}
|
| 68 |
+
{% else %}
|
| 69 |
fn sample_round(v: f32) -> i32 {
|
| 70 |
if (v > 2147483000.0) {
|
| 71 |
{% if paddingMode == "reflection" %}
|
|
|
|
| 83 |
}
|
| 84 |
return i32(round(v));
|
| 85 |
}
|
| 86 |
+
{% endif %}
|
|
|
|
|
|
|
| 87 |
{% if modeSpec == "cubic" %}
|
| 88 |
+
|
| 89 |
fn cubic_coeffs(t: f32) -> vec4<f32> {
|
| 90 |
let a = -0.75;
|
| 91 |
let x0 = abs(t + 1.0);
|
|
|
|
| 100 |
if (x0 < 2.0) { return a * x0 * x0 * x0 - 5.0 * a * x0 * x0 + 8.0 * a * x0 - 4.0 * a; }
|
| 101 |
return 0.0;
|
| 102 |
}
|
| 103 |
+
{% endif %}
|
|
|
|
| 104 |
{% set volumeVector = channelWidthSpec is defined %}
|
| 105 |
{% set volumeT = "vec" ~ channelWidthSpec ~ "<f32>" if volumeVector else "f32" %}
|
| 106 |
{% set voxelArgs = "img_base, c, " if volumeVector and channelTail else "img_base, " %}
|
| 107 |
+
{% if resolveReflectionTaps %}
|
| 108 |
+
|
| 109 |
+
fn reflected_index(index: i32, length: u32) -> u32 {
|
| 110 |
+
{% if alignCorners %}
|
| 111 |
+
let reflected = i32(reflect_coord(f32(index), 0.0, f32(length) - 1.0));
|
| 112 |
+
{% else %}
|
| 113 |
+
let reflected = i32(reflect_coord(f32(index), -0.5, f32(length) - 0.5));
|
| 114 |
+
{% endif %}
|
| 115 |
+
return u32(clamp(reflected, 0, i32(length) - 1));
|
| 116 |
+
}
|
| 117 |
+
{% endif %}
|
| 118 |
+
{% macro reflected_axis_taps() %}
|
| 119 |
+
{% if resolveReflectionTaps %}
|
| 120 |
+
{% for axis, length in [["x", "inW"], ["y", "inH"], ["z", "inD"]] %}
|
| 121 |
+
let i{{ axis }} = vec{{ 4 if modeSpec == "cubic" else 2 }}<u32>(
|
| 122 |
+
{% for tap in range(4 if modeSpec == "cubic" else 2) %}
|
| 123 |
+
reflected_index({{ axis }}0{% if tap %} + {{ tap }}{% endif %}, params.{{ length }}){% if loop.last %});{% else %},{% endif %}
|
| 124 |
+
{% endfor %}
|
| 125 |
+
{% endfor %}
|
| 126 |
+
{% endif %}
|
| 127 |
+
{% endmacro %}
|
| 128 |
+
|
| 129 |
+
fn voxel(base: u32,{% if volumeVector and channelTail %} c0: u32,{% endif %} {% if resolveReflectionTaps %}dd: u32, hh: u32, ww: u32{% else %}d: i32, h: i32, w: i32{% endif %}) -> {{ volumeT }} {
|
| 130 |
+
{% if not resolveReflectionTaps %}
|
| 131 |
{% if paddingMode == "zeros" %}
|
| 132 |
if (d < 0 || d >= i32(params.inD) || h < 0 || h >= i32(params.inH) || w < 0 || w >= i32(params.inW)) {
|
| 133 |
return {% if volumeVector %}{{ volumeT }}(0.0){% else %}0.0{% endif %};
|
|
|
|
| 153 |
let hh = u32(clamp(rh, 0, i32(params.inH) - 1));
|
| 154 |
let ww = u32(clamp(rw, 0, i32(params.inW) - 1));
|
| 155 |
{% endif %}
|
| 156 |
+
{% endif %}
|
| 157 |
{% if volumeVector %}
|
| 158 |
// All channels share the resolved voxel coordinates. Incomplete vectors
|
| 159 |
// alias the final channel on loads; main masks their output stores.
|
|
|
|
| 168 |
|
| 169 |
@compute @workgroup_size({{ volumeWorkgroup if volumeVector else tunables.WORKGROUP_SIZE }})
|
| 170 |
fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
|
| 171 |
+
{{ flat_index_2d(volumeWorkgroup if volumeVector else tunables.WORKGROUP_SIZE, guardInline=true) }}
|
| 172 |
|
| 173 |
let ow = i % params.outW;
|
| 174 |
var t = i / params.outW;
|
|
|
|
| 195 |
let result = voxel({{ voxelArgs }}sample_round(sz), sample_round(sy), sample_round(sx));
|
| 196 |
{% elif modeSpec == "cubic" %}
|
| 197 |
// Tricubic applies separable four-tap Keys interpolation along each spatial
|
| 198 |
+
// axis. Reflection taps are resolved once per axis when enabled; other
|
| 199 |
+
// padding modes are handled by voxel().
|
| 200 |
let x0 = sample_floor(sx) - 1;
|
| 201 |
let y0 = sample_floor(sy) - 1;
|
| 202 |
let z0 = sample_floor(sz) - 1;
|
| 203 |
let cx = cubic_coeffs(sx - f32(x0 + 1));
|
| 204 |
let cy = cubic_coeffs(sy - f32(y0 + 1));
|
| 205 |
let cz = cubic_coeffs(sz - f32(z0 + 1));
|
| 206 |
+
{{ reflected_axis_taps() }}
|
| 207 |
var result = {% if volumeVector %}{{ volumeT }}(0.0){% else %}0.0{% endif %};
|
| 208 |
for (var kz = 0i; kz < 4i; kz = kz + 1i) {
|
| 209 |
var plane = {% if volumeVector %}{{ volumeT }}(0.0){% else %}0.0{% endif %};
|
| 210 |
for (var ky = 0i; ky < 4i; ky = ky + 1i) {
|
| 211 |
+
let row = cx.x * voxel({{ voxelArgs }}{{ "iz[u32(kz)], iy[u32(ky)], ix.x" if resolveReflectionTaps else "z0 + kz, y0 + ky, x0" }})
|
| 212 |
+
+ cx.y * voxel({{ voxelArgs }}{{ "iz[u32(kz)], iy[u32(ky)], ix.y" if resolveReflectionTaps else "z0 + kz, y0 + ky, x0 + 1" }})
|
| 213 |
+
+ cx.z * voxel({{ voxelArgs }}{{ "iz[u32(kz)], iy[u32(ky)], ix.z" if resolveReflectionTaps else "z0 + kz, y0 + ky, x0 + 2" }})
|
| 214 |
+
+ cx.w * voxel({{ voxelArgs }}{{ "iz[u32(kz)], iy[u32(ky)], ix.w" if resolveReflectionTaps else "z0 + kz, y0 + ky, x0 + 3" }});
|
| 215 |
plane = plane + cy[u32(ky)] * row;
|
| 216 |
}
|
| 217 |
result = result + cz[u32(kz)] * plane;
|
|
|
|
| 223 |
let wx = sx - f32(x0);
|
| 224 |
let wy = sy - f32(y0);
|
| 225 |
let wz = sz - f32(z0);
|
| 226 |
+
{{ reflected_axis_taps() }}
|
| 227 |
+
let v000 = voxel({{ voxelArgs }}{{ "iz.x, iy.x, ix.x" if resolveReflectionTaps else "z0, y0, x0" }});
|
| 228 |
+
let v001 = voxel({{ voxelArgs }}{{ "iz.x, iy.x, ix.y" if resolveReflectionTaps else "z0, y0, x0 + 1" }});
|
| 229 |
+
let v010 = voxel({{ voxelArgs }}{{ "iz.x, iy.y, ix.x" if resolveReflectionTaps else "z0, y0 + 1, x0" }});
|
| 230 |
+
let v011 = voxel({{ voxelArgs }}{{ "iz.x, iy.y, ix.y" if resolveReflectionTaps else "z0, y0 + 1, x0 + 1" }});
|
| 231 |
+
let v100 = voxel({{ voxelArgs }}{{ "iz.y, iy.x, ix.x" if resolveReflectionTaps else "z0 + 1, y0, x0" }});
|
| 232 |
+
let v101 = voxel({{ voxelArgs }}{{ "iz.y, iy.x, ix.y" if resolveReflectionTaps else "z0 + 1, y0, x0 + 1" }});
|
| 233 |
+
let v110 = voxel({{ voxelArgs }}{{ "iz.y, iy.y, ix.x" if resolveReflectionTaps else "z0 + 1, y0 + 1, x0" }});
|
| 234 |
+
let v111 = voxel({{ voxelArgs }}{{ "iz.y, iy.y, ix.y" if resolveReflectionTaps else "z0 + 1, y0 + 1, x0 + 1" }});
|
| 235 |
let front = (1.0 - wy) * ((1.0 - wx) * v000 + wx * v001) + wy * ((1.0 - wx) * v010 + wx * v011);
|
| 236 |
let back = (1.0 - wy) * ((1.0 - wx) * v100 + wx * v101) + wy * ((1.0 - wx) * v110 + wx * v111);
|
| 237 |
let result = (1.0 - wz) * front + wz * back;
|
build/webgpu/manifest.json
CHANGED
|
@@ -22,8 +22,9 @@
|
|
| 22 |
"align_corners": { "values": [0, 1] }
|
| 23 |
},
|
| 24 |
"typeConstraints": { "T": ["float32", "float16"] },
|
| 25 |
-
"tunables": { "WORKGROUP_SIZE": { "default": 256 } },
|
| 26 |
"derive": {
|
|
|
|
| 27 |
"wave32Adapter": "has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize == 32 and device.adapterInfo.subgroupMaxSize == 32",
|
| 28 |
"reportedNonWave32Adapter": "not wave32Adapter and (has(device.adapterInfo, \"subgroupMinSize\") or has(device.adapterInfo, \"subgroupMaxSize\"))",
|
| 29 |
"deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
|
|
@@ -31,11 +32,13 @@
|
|
| 31 |
"channelWidth": 4,
|
| 32 |
"scalar": "dtypes.T",
|
| 33 |
"volumeWidth": "min(channelWidth, pow(2, log2ceil(max(1, dim(shapes.x, 1)))))",
|
| 34 |
-
"volumeWorkgroup": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)"
|
|
|
|
|
|
|
|
|
|
| 35 |
},
|
| 36 |
"bindings": {
|
| 37 |
"params": {
|
| 38 |
-
"buffer": "uniform",
|
| 39 |
"struct": [
|
| 40 |
{ "name": "count", "type": "u32", "value": "numel(shapes.y)" },
|
| 41 |
{ "name": "C", "type": "u32", "value": "dim(shapes.x, 1)" },
|
|
@@ -50,19 +53,14 @@
|
|
| 50 |
{
|
| 51 |
"id": "nchw_rank4_channel_vector",
|
| 52 |
"priority": 5,
|
| 53 |
-
"when": ["rank4Ok", "
|
|
|
|
| 54 |
"passes": [
|
| 55 |
{
|
| 56 |
"id": "main",
|
| 57 |
"name": "GridSample.ChannelX4",
|
| 58 |
"shader": "grid-sample.wgsl.jinja",
|
| 59 |
-
"derive": {
|
| 60 |
-
"modeSpec": "attrs.mode",
|
| 61 |
-
"paddingMode": "attrs.padding_mode",
|
| 62 |
-
"alignCorners": "attrs.align_corners != 0",
|
| 63 |
-
"channelWidthSpec": "channelWidth",
|
| 64 |
-
"channelTail": "dim(shapes.x, 1) % channelWidth != 0"
|
| 65 |
-
},
|
| 66 |
"bindings": ["x", "grid", "y", "params"],
|
| 67 |
"dispatch": {
|
| 68 |
"x": "min(ceilDiv((dim(shapes.y, 0) * ceilDiv(dim(shapes.y, 1), channelWidth) * dim(shapes.y, 2) * dim(shapes.y, 3)), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
@@ -80,11 +78,6 @@
|
|
| 80 |
"id": "main",
|
| 81 |
"name": "GridSample",
|
| 82 |
"shader": "grid-sample.wgsl.jinja",
|
| 83 |
-
"derive": {
|
| 84 |
-
"modeSpec": "attrs.mode",
|
| 85 |
-
"paddingMode": "attrs.padding_mode",
|
| 86 |
-
"alignCorners": "attrs.align_corners != 0"
|
| 87 |
-
},
|
| 88 |
"bindings": ["x", "grid", "y", "params"],
|
| 89 |
"dispatch": {
|
| 90 |
"x": "min(ceilDiv((numel(shapes.y)), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
@@ -104,11 +97,9 @@
|
|
| 104 |
"name": "GridSample.VolumetricChannels",
|
| 105 |
"shader": "grid-sample3d.wgsl.jinja",
|
| 106 |
"derive": {
|
| 107 |
-
"modeSpec": "attrs.mode",
|
| 108 |
-
"paddingMode": "attrs.padding_mode",
|
| 109 |
-
"alignCorners": "attrs.align_corners != 0",
|
| 110 |
"channelWidthSpec": "volumeWidth",
|
| 111 |
-
"channelTail": "dim(shapes.x, 1) % volumeWidth != 0"
|
|
|
|
| 112 |
},
|
| 113 |
"bindings": [
|
| 114 |
"x",
|
|
@@ -150,9 +141,7 @@
|
|
| 150 |
"name": "GridSample.Volumetric",
|
| 151 |
"shader": "grid-sample3d.wgsl.jinja",
|
| 152 |
"derive": {
|
| 153 |
-
"
|
| 154 |
-
"paddingMode": "attrs.padding_mode",
|
| 155 |
-
"alignCorners": "attrs.align_corners != 0"
|
| 156 |
},
|
| 157 |
"bindings": [
|
| 158 |
"x",
|
|
|
|
| 22 |
"align_corners": { "values": [0, 1] }
|
| 23 |
},
|
| 24 |
"typeConstraints": { "T": ["float32", "float16"] },
|
| 25 |
+
"tunables": { "WORKGROUP_SIZE": { "default": 256 }, "RESOLVE_REFLECTION_TAPS": { "default": 1 } },
|
| 26 |
"derive": {
|
| 27 |
+
"appleAdapter": "has(device.adapterInfo, \"vendor\") and device.adapterInfo.vendor == \"apple\"",
|
| 28 |
"wave32Adapter": "has(device.adapterInfo, \"subgroupMinSize\") and has(device.adapterInfo, \"subgroupMaxSize\") and device.adapterInfo.subgroupMinSize == 32 and device.adapterInfo.subgroupMaxSize == 32",
|
| 29 |
"reportedNonWave32Adapter": "not wave32Adapter and (has(device.adapterInfo, \"subgroupMinSize\") or has(device.adapterInfo, \"subgroupMaxSize\"))",
|
| 30 |
"deviceWorkgroupCap": "min(device.limits.maxComputeInvocationsPerWorkgroup, device.limits.maxComputeWorkgroupSizeX)",
|
|
|
|
| 32 |
"channelWidth": 4,
|
| 33 |
"scalar": "dtypes.T",
|
| 34 |
"volumeWidth": "min(channelWidth, pow(2, log2ceil(max(1, dim(shapes.x, 1)))))",
|
| 35 |
+
"volumeWorkgroup": "min(tunables.WORKGROUP_SIZE, deviceWorkgroupCap)",
|
| 36 |
+
"alignCorners": "attrs.align_corners != 0",
|
| 37 |
+
"modeSpec": "attrs.mode",
|
| 38 |
+
"paddingMode": "attrs.padding_mode"
|
| 39 |
},
|
| 40 |
"bindings": {
|
| 41 |
"params": {
|
|
|
|
| 42 |
"struct": [
|
| 43 |
{ "name": "count", "type": "u32", "value": "numel(shapes.y)" },
|
| 44 |
{ "name": "C", "type": "u32", "value": "dim(shapes.x, 1)" },
|
|
|
|
| 53 |
{
|
| 54 |
"id": "nchw_rank4_channel_vector",
|
| 55 |
"priority": 5,
|
| 56 |
+
"when": ["rank4Ok", "dim(shapes.x, 1) >= 2"],
|
| 57 |
+
"demoteWhen": ["not appleAdapter"],
|
| 58 |
"passes": [
|
| 59 |
{
|
| 60 |
"id": "main",
|
| 61 |
"name": "GridSample.ChannelX4",
|
| 62 |
"shader": "grid-sample.wgsl.jinja",
|
| 63 |
+
"derive": { "channelWidthSpec": "channelWidth", "channelTail": "dim(shapes.x, 1) % channelWidth != 0" },
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
"bindings": ["x", "grid", "y", "params"],
|
| 65 |
"dispatch": {
|
| 66 |
"x": "min(ceilDiv((dim(shapes.y, 0) * ceilDiv(dim(shapes.y, 1), channelWidth) * dim(shapes.y, 2) * dim(shapes.y, 3)), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
|
|
| 78 |
"id": "main",
|
| 79 |
"name": "GridSample",
|
| 80 |
"shader": "grid-sample.wgsl.jinja",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
"bindings": ["x", "grid", "y", "params"],
|
| 82 |
"dispatch": {
|
| 83 |
"x": "min(ceilDiv((numel(shapes.y)), (tunables.WORKGROUP_SIZE)), 65535)",
|
|
|
|
| 97 |
"name": "GridSample.VolumetricChannels",
|
| 98 |
"shader": "grid-sample3d.wgsl.jinja",
|
| 99 |
"derive": {
|
|
|
|
|
|
|
|
|
|
| 100 |
"channelWidthSpec": "volumeWidth",
|
| 101 |
+
"channelTail": "dim(shapes.x, 1) % volumeWidth != 0",
|
| 102 |
+
"resolveReflectionTaps": "attrs.padding_mode == \"reflection\" and attrs.mode != \"nearest\" and tunables.RESOLVE_REFLECTION_TAPS != 0"
|
| 103 |
},
|
| 104 |
"bindings": [
|
| 105 |
"x",
|
|
|
|
| 141 |
"name": "GridSample.Volumetric",
|
| 142 |
"shader": "grid-sample3d.wgsl.jinja",
|
| 143 |
"derive": {
|
| 144 |
+
"resolveReflectionTaps": "attrs.padding_mode == \"reflection\" and attrs.mode != \"nearest\" and tunables.RESOLVE_REFLECTION_TAPS != 0"
|
|
|
|
|
|
|
| 145 |
},
|
| 146 |
"bindings": [
|
| 147 |
"x",
|
build/webgpu/metadata.json
CHANGED
|
@@ -1,22 +1,22 @@
|
|
| 1 |
{
|
| 2 |
"name": "ai.onnx.GridSample",
|
| 3 |
-
"id": "
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
| 7 |
"digest": {
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
-
"bench.json": "
|
| 11 |
-
"grid-sample.wgsl.jinja": "
|
| 12 |
-
"grid-sample3d.wgsl.jinja": "
|
| 13 |
-
"manifest.json": "
|
| 14 |
-
"test.json": "
|
| 15 |
}
|
| 16 |
},
|
| 17 |
-
"provenance": { "kernel": { "sha": "
|
| 18 |
"webgpu": {
|
| 19 |
-
"manifestSpec": "2.
|
| 20 |
"variants": {
|
| 21 |
"nchw_rank4_channel_vector": ["grid-sample.wgsl.jinja"],
|
| 22 |
"nchw_rank4": ["grid-sample.wgsl.jinja"],
|
|
|
|
| 1 |
{
|
| 2 |
"name": "ai.onnx.GridSample",
|
| 3 |
+
"id": "_ai_onnx_gridsample_webgpu_11c7e55",
|
| 4 |
"version": 1,
|
| 5 |
"license": "Apache-2.0",
|
| 6 |
"backend": { "type": "webgpu" },
|
| 7 |
"digest": {
|
| 8 |
"algorithm": "sha256",
|
| 9 |
"files": {
|
| 10 |
+
"bench.json": "zRyVJ7WL0vHjv1U48z8EM9u2l5FufDQYPq5VfWYxVyw=",
|
| 11 |
+
"grid-sample.wgsl.jinja": "+smIQHwp1GEltoAVpbIKI0oJbsjAXGVGPy2ZhVHvF8Y=",
|
| 12 |
+
"grid-sample3d.wgsl.jinja": "e638b7ZNv0/EmEXA5+M4PlzQ81vHXpRlj3t5iVieohY=",
|
| 13 |
+
"manifest.json": "UyKUdbD0viJTcRHht1BWQpHNviVreaI5JZjLthQDKM0=",
|
| 14 |
+
"test.json": "5SMIjxyMjqQYJ+GGIjZ6md6MjqRGQwkKIbZn5NAIGRw="
|
| 15 |
}
|
| 16 |
},
|
| 17 |
+
"provenance": { "kernel": { "sha": "6fdf6301e2bbcc2f03bf1eaf493b7ad55ef33afc", "dirty": false } },
|
| 18 |
"webgpu": {
|
| 19 |
+
"manifestSpec": "2.1",
|
| 20 |
"variants": {
|
| 21 |
"nchw_rank4_channel_vector": ["grid-sample.wgsl.jinja"],
|
| 22 |
"nchw_rank4": ["grid-sample.wgsl.jinja"],
|
build/webgpu/test.json
CHANGED
|
@@ -5,7 +5,8 @@
|
|
| 5 |
"onnx_backend_far_coords_zeros_padding_input_grid": [-10, -10, -5, -5, -0.2, -0.2, 10, 10, 10, 10, -0.2, -0.2, 5, 5, 10, 10],
|
| 6 |
"onnx_backend_gridsample_input_x": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
| 7 |
"onnx_backend_gridsample_aligncorners_true_input_grid": [-1, -1, -0.5, -0.5, -0.20000000298023224, -0.20000000298023224, 0, 0, 0, 0, -0.20000000298023224, -0.20000000298023224, 0.5, 0.5, 1, 1],
|
| 8 |
-
"onnx_backend_gridsample_border_padding_input_grid": [-10, -10, -5, -5, -0.20000000298023224, -0.20000000298023224, 10, 10, 10, 10, -0.20000000298023224, -0.20000000298023224, 5, 5, 10, 10]
|
|
|
|
| 9 |
},
|
| 10 |
"cases": [
|
| 11 |
{
|
|
@@ -227,7 +228,7 @@
|
|
| 227 |
"provenance": {
|
| 228 |
"source": "onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc",
|
| 229 |
"test": "GridSampleCustomTest.test_grid_sample_20_4D_bilinear_reflection_extreme_coords",
|
| 230 |
-
"notes": "
|
| 231 |
},
|
| 232 |
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 0 },
|
| 233 |
"inputs": {
|
|
@@ -2739,6 +2740,312 @@
|
|
| 2739 |
}
|
| 2740 |
},
|
| 2741 |
"outputs": { "y": { "dtype": "float32", "shape": [2, 5, 5, 7, 9], "tolerance": 0.0001, "relTolerance": 0.0001 } }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2742 |
}
|
| 2743 |
]
|
| 2744 |
}
|
|
|
|
| 5 |
"onnx_backend_far_coords_zeros_padding_input_grid": [-10, -10, -5, -5, -0.2, -0.2, 10, 10, 10, 10, -0.2, -0.2, 5, 5, 10, 10],
|
| 6 |
"onnx_backend_gridsample_input_x": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
| 7 |
"onnx_backend_gridsample_aligncorners_true_input_grid": [-1, -1, -0.5, -0.5, -0.20000000298023224, -0.20000000298023224, 0, 0, 0, 0, -0.20000000298023224, -0.20000000298023224, 0.5, 0.5, 1, 1],
|
| 8 |
+
"onnx_backend_gridsample_border_padding_input_grid": [-10, -10, -5, -5, -0.20000000298023224, -0.20000000298023224, 10, 10, 10, 10, -0.20000000298023224, -0.20000000298023224, 5, 5, 10, 10],
|
| 9 |
+
"reflection_coordinate_f32_rounding_rank4_input_x": [1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1]
|
| 10 |
},
|
| 11 |
"cases": [
|
| 12 |
{
|
|
|
|
| 228 |
"provenance": {
|
| 229 |
"source": "onnxruntime/test/providers/cpu/tensor/grid_sample_test_custom.cc",
|
| 230 |
"test": "GridSampleCustomTest.test_grid_sample_20_4D_bilinear_reflection_extreme_coords",
|
| 231 |
+
"notes": "Grid coordinates of +/-5, well outside the normalized [-1,1] range but smaller than ONNX Runtime's extreme-coordinate test values, check reflection padding at finite far-out-of-bounds coordinates with bilinear sampling."
|
| 232 |
},
|
| 233 |
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 0 },
|
| 234 |
"inputs": {
|
|
|
|
| 2740 |
}
|
| 2741 |
},
|
| 2742 |
"outputs": { "y": { "dtype": "float32", "shape": [2, 5, 5, 7, 9], "tolerance": 0.0001, "relTolerance": 0.0001 } }
|
| 2743 |
+
},
|
| 2744 |
+
{
|
| 2745 |
+
"name": "volume_scalar_linear_reflection_ac0_float32",
|
| 2746 |
+
"provenance": {
|
| 2747 |
+
"notes": "Scalar volumetric reflection with out-of-range taps; aligned cases include a dimension-one input to exercise the zero-width reflection interval."
|
| 2748 |
+
},
|
| 2749 |
+
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 0 },
|
| 2750 |
+
"inputs": {
|
| 2751 |
+
"x": {
|
| 2752 |
+
"dtype": "float32",
|
| 2753 |
+
"shape": [2, 1, 3, 5, 7],
|
| 2754 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2755 |
+
},
|
| 2756 |
+
"grid": {
|
| 2757 |
+
"dtype": "float32",
|
| 2758 |
+
"shape": [2, 3, 4, 7, 3],
|
| 2759 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2760 |
+
}
|
| 2761 |
+
},
|
| 2762 |
+
"outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3, 4, 7], "tolerance": 0.0001, "relTolerance": 0.0001 } }
|
| 2763 |
+
},
|
| 2764 |
+
{
|
| 2765 |
+
"name": "volume_scalar_linear_reflection_ac1_float32",
|
| 2766 |
+
"provenance": {
|
| 2767 |
+
"notes": "Scalar volumetric reflection with out-of-range taps; aligned cases include a dimension-one input to exercise the zero-width reflection interval."
|
| 2768 |
+
},
|
| 2769 |
+
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 1 },
|
| 2770 |
+
"inputs": {
|
| 2771 |
+
"x": {
|
| 2772 |
+
"dtype": "float32",
|
| 2773 |
+
"shape": [2, 1, 1, 5, 7],
|
| 2774 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2775 |
+
},
|
| 2776 |
+
"grid": {
|
| 2777 |
+
"dtype": "float32",
|
| 2778 |
+
"shape": [2, 3, 4, 7, 3],
|
| 2779 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2780 |
+
}
|
| 2781 |
+
},
|
| 2782 |
+
"outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3, 4, 7], "tolerance": 0.0001, "relTolerance": 0.0001 } }
|
| 2783 |
+
},
|
| 2784 |
+
{
|
| 2785 |
+
"name": "volume_tail_linear_reflection_float32_per_voxel",
|
| 2786 |
+
"provenance": {
|
| 2787 |
+
"notes": "Explicit per-voxel comparison path retains the reflection behavior on incomplete channel vectors."
|
| 2788 |
+
},
|
| 2789 |
+
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 0 },
|
| 2790 |
+
"inputs": {
|
| 2791 |
+
"x": {
|
| 2792 |
+
"dtype": "float32",
|
| 2793 |
+
"shape": [2, 3, 5, 7, 9],
|
| 2794 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2795 |
+
},
|
| 2796 |
+
"grid": {
|
| 2797 |
+
"dtype": "float32",
|
| 2798 |
+
"shape": [2, 7, 9, 11, 3],
|
| 2799 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2800 |
+
}
|
| 2801 |
+
},
|
| 2802 |
+
"outputs": { "y": { "dtype": "float32", "shape": [2, 3, 7, 9, 11], "tolerance": 0.0001, "relTolerance": 0.0001 } },
|
| 2803 |
+
"tunables": { "RESOLVE_REFLECTION_TAPS": 0 }
|
| 2804 |
+
},
|
| 2805 |
+
{
|
| 2806 |
+
"name": "volume_scalar_linear_reflection_ac0_float16",
|
| 2807 |
+
"provenance": {
|
| 2808 |
+
"notes": "Scalar volumetric reflection with out-of-range taps; aligned cases include a dimension-one input to exercise the zero-width reflection interval."
|
| 2809 |
+
},
|
| 2810 |
+
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 0 },
|
| 2811 |
+
"inputs": {
|
| 2812 |
+
"x": {
|
| 2813 |
+
"dtype": "float16",
|
| 2814 |
+
"shape": [2, 1, 3, 5, 7],
|
| 2815 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2816 |
+
},
|
| 2817 |
+
"grid": {
|
| 2818 |
+
"dtype": "float16",
|
| 2819 |
+
"shape": [2, 3, 4, 7, 3],
|
| 2820 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2821 |
+
}
|
| 2822 |
+
},
|
| 2823 |
+
"outputs": { "y": { "dtype": "float16", "shape": [2, 1, 3, 4, 7], "tolerance": 0.001, "relTolerance": 0.001 } }
|
| 2824 |
+
},
|
| 2825 |
+
{
|
| 2826 |
+
"name": "volume_scalar_linear_reflection_ac1_float16",
|
| 2827 |
+
"provenance": {
|
| 2828 |
+
"notes": "Scalar volumetric reflection with out-of-range taps; aligned cases include a dimension-one input to exercise the zero-width reflection interval."
|
| 2829 |
+
},
|
| 2830 |
+
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 1 },
|
| 2831 |
+
"inputs": {
|
| 2832 |
+
"x": {
|
| 2833 |
+
"dtype": "float16",
|
| 2834 |
+
"shape": [2, 1, 1, 5, 7],
|
| 2835 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2836 |
+
},
|
| 2837 |
+
"grid": {
|
| 2838 |
+
"dtype": "float16",
|
| 2839 |
+
"shape": [2, 3, 4, 7, 3],
|
| 2840 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2841 |
+
}
|
| 2842 |
+
},
|
| 2843 |
+
"outputs": { "y": { "dtype": "float16", "shape": [2, 1, 3, 4, 7], "tolerance": 0.001, "relTolerance": 0.001 } }
|
| 2844 |
+
},
|
| 2845 |
+
{
|
| 2846 |
+
"name": "volume_tail_linear_reflection_float16_per_voxel",
|
| 2847 |
+
"provenance": {
|
| 2848 |
+
"notes": "Explicit per-voxel comparison path retains the reflection behavior on incomplete channel vectors."
|
| 2849 |
+
},
|
| 2850 |
+
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 0 },
|
| 2851 |
+
"inputs": {
|
| 2852 |
+
"x": {
|
| 2853 |
+
"dtype": "float16",
|
| 2854 |
+
"shape": [2, 3, 5, 7, 9],
|
| 2855 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2856 |
+
},
|
| 2857 |
+
"grid": {
|
| 2858 |
+
"dtype": "float16",
|
| 2859 |
+
"shape": [2, 7, 9, 11, 3],
|
| 2860 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2861 |
+
}
|
| 2862 |
+
},
|
| 2863 |
+
"outputs": { "y": { "dtype": "float16", "shape": [2, 3, 7, 9, 11], "tolerance": 0.001, "relTolerance": 0.001 } },
|
| 2864 |
+
"tunables": { "RESOLVE_REFLECTION_TAPS": 0 }
|
| 2865 |
+
},
|
| 2866 |
+
{
|
| 2867 |
+
"name": "volume_scalar_cubic_reflection_ac0_float32",
|
| 2868 |
+
"provenance": {
|
| 2869 |
+
"notes": "Scalar volumetric reflection with out-of-range taps; aligned cases include a dimension-one input to exercise the zero-width reflection interval."
|
| 2870 |
+
},
|
| 2871 |
+
"attrs": { "mode": "cubic", "padding_mode": "reflection", "align_corners": 0 },
|
| 2872 |
+
"inputs": {
|
| 2873 |
+
"x": {
|
| 2874 |
+
"dtype": "float32",
|
| 2875 |
+
"shape": [2, 1, 3, 5, 7],
|
| 2876 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2877 |
+
},
|
| 2878 |
+
"grid": {
|
| 2879 |
+
"dtype": "float32",
|
| 2880 |
+
"shape": [2, 3, 4, 7, 3],
|
| 2881 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2882 |
+
}
|
| 2883 |
+
},
|
| 2884 |
+
"outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3, 4, 7], "tolerance": 0.0001, "relTolerance": 0.0001 } }
|
| 2885 |
+
},
|
| 2886 |
+
{
|
| 2887 |
+
"name": "volume_scalar_cubic_reflection_ac1_float32",
|
| 2888 |
+
"provenance": {
|
| 2889 |
+
"notes": "Scalar volumetric reflection with out-of-range taps; aligned cases include a dimension-one input to exercise the zero-width reflection interval."
|
| 2890 |
+
},
|
| 2891 |
+
"attrs": { "mode": "cubic", "padding_mode": "reflection", "align_corners": 1 },
|
| 2892 |
+
"inputs": {
|
| 2893 |
+
"x": {
|
| 2894 |
+
"dtype": "float32",
|
| 2895 |
+
"shape": [2, 1, 1, 5, 7],
|
| 2896 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2897 |
+
},
|
| 2898 |
+
"grid": {
|
| 2899 |
+
"dtype": "float32",
|
| 2900 |
+
"shape": [2, 3, 4, 7, 3],
|
| 2901 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2902 |
+
}
|
| 2903 |
+
},
|
| 2904 |
+
"outputs": { "y": { "dtype": "float32", "shape": [2, 1, 3, 4, 7], "tolerance": 0.0001, "relTolerance": 0.0001 } }
|
| 2905 |
+
},
|
| 2906 |
+
{
|
| 2907 |
+
"name": "volume_tail_cubic_reflection_float32_per_voxel",
|
| 2908 |
+
"provenance": {
|
| 2909 |
+
"notes": "Explicit per-voxel comparison path retains the reflection behavior on incomplete channel vectors."
|
| 2910 |
+
},
|
| 2911 |
+
"attrs": { "mode": "cubic", "padding_mode": "reflection", "align_corners": 0 },
|
| 2912 |
+
"inputs": {
|
| 2913 |
+
"x": {
|
| 2914 |
+
"dtype": "float32",
|
| 2915 |
+
"shape": [2, 3, 5, 7, 9],
|
| 2916 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2917 |
+
},
|
| 2918 |
+
"grid": {
|
| 2919 |
+
"dtype": "float32",
|
| 2920 |
+
"shape": [2, 7, 9, 11, 3],
|
| 2921 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2922 |
+
}
|
| 2923 |
+
},
|
| 2924 |
+
"outputs": { "y": { "dtype": "float32", "shape": [2, 3, 7, 9, 11], "tolerance": 0.0001, "relTolerance": 0.0001 } },
|
| 2925 |
+
"tunables": { "RESOLVE_REFLECTION_TAPS": 0 }
|
| 2926 |
+
},
|
| 2927 |
+
{
|
| 2928 |
+
"name": "volume_scalar_cubic_reflection_ac0_float16",
|
| 2929 |
+
"provenance": {
|
| 2930 |
+
"notes": "Scalar volumetric reflection with out-of-range taps; aligned cases include a dimension-one input to exercise the zero-width reflection interval."
|
| 2931 |
+
},
|
| 2932 |
+
"attrs": { "mode": "cubic", "padding_mode": "reflection", "align_corners": 0 },
|
| 2933 |
+
"inputs": {
|
| 2934 |
+
"x": {
|
| 2935 |
+
"dtype": "float16",
|
| 2936 |
+
"shape": [2, 1, 3, 5, 7],
|
| 2937 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2938 |
+
},
|
| 2939 |
+
"grid": {
|
| 2940 |
+
"dtype": "float16",
|
| 2941 |
+
"shape": [2, 3, 4, 7, 3],
|
| 2942 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2943 |
+
}
|
| 2944 |
+
},
|
| 2945 |
+
"outputs": { "y": { "dtype": "float16", "shape": [2, 1, 3, 4, 7], "tolerance": 0.001, "relTolerance": 0.001 } }
|
| 2946 |
+
},
|
| 2947 |
+
{
|
| 2948 |
+
"name": "volume_scalar_cubic_reflection_ac1_float16",
|
| 2949 |
+
"provenance": {
|
| 2950 |
+
"notes": "Scalar volumetric reflection with out-of-range taps; aligned cases include a dimension-one input to exercise the zero-width reflection interval."
|
| 2951 |
+
},
|
| 2952 |
+
"attrs": { "mode": "cubic", "padding_mode": "reflection", "align_corners": 1 },
|
| 2953 |
+
"inputs": {
|
| 2954 |
+
"x": {
|
| 2955 |
+
"dtype": "float16",
|
| 2956 |
+
"shape": [2, 1, 1, 5, 7],
|
| 2957 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2958 |
+
},
|
| 2959 |
+
"grid": {
|
| 2960 |
+
"dtype": "float16",
|
| 2961 |
+
"shape": [2, 3, 4, 7, 3],
|
| 2962 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2963 |
+
}
|
| 2964 |
+
},
|
| 2965 |
+
"outputs": { "y": { "dtype": "float16", "shape": [2, 1, 3, 4, 7], "tolerance": 0.001, "relTolerance": 0.001 } }
|
| 2966 |
+
},
|
| 2967 |
+
{
|
| 2968 |
+
"name": "volume_tail_cubic_reflection_float16_per_voxel",
|
| 2969 |
+
"provenance": {
|
| 2970 |
+
"notes": "Explicit per-voxel comparison path retains the reflection behavior on incomplete channel vectors."
|
| 2971 |
+
},
|
| 2972 |
+
"attrs": { "mode": "cubic", "padding_mode": "reflection", "align_corners": 0 },
|
| 2973 |
+
"inputs": {
|
| 2974 |
+
"x": {
|
| 2975 |
+
"dtype": "float16",
|
| 2976 |
+
"shape": [2, 3, 5, 7, 9],
|
| 2977 |
+
"data": { "kind": "fillFloat32", "scale": 0.3, "sinStep": 0.17, "cosStep": 0.09 }
|
| 2978 |
+
},
|
| 2979 |
+
"grid": {
|
| 2980 |
+
"dtype": "float16",
|
| 2981 |
+
"shape": [2, 7, 9, 11, 3],
|
| 2982 |
+
"data": { "kind": "linspace", "start": -3.5, "end": 3.5 }
|
| 2983 |
+
}
|
| 2984 |
+
},
|
| 2985 |
+
"outputs": { "y": { "dtype": "float16", "shape": [2, 3, 7, 9, 11], "tolerance": 0.001, "relTolerance": 0.001 } },
|
| 2986 |
+
"tunables": { "RESOLVE_REFLECTION_TAPS": 0 }
|
| 2987 |
+
},
|
| 2988 |
+
{
|
| 2989 |
+
"name": "reflection_coordinate_f32_rounding_rank4",
|
| 2990 |
+
"provenance": {
|
| 2991 |
+
"notes": "Float32 coordinate normalization outside the image must round before interpolation. Alternating pixels amplify the f32 versus f64 coordinate difference; expected value independently checked with ONNX Runtime's CPU provider."
|
| 2992 |
+
},
|
| 2993 |
+
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 1 },
|
| 2994 |
+
"inputs": {
|
| 2995 |
+
"x": {
|
| 2996 |
+
"dtype": "float32",
|
| 2997 |
+
"shape": [1, 1, 256, 1],
|
| 2998 |
+
"data": {
|
| 2999 |
+
"kind": "values",
|
| 3000 |
+
"values": { "$ref": "#/fixtureArrays/reflection_coordinate_f32_rounding_rank4_input_x" }
|
| 3001 |
+
}
|
| 3002 |
+
},
|
| 3003 |
+
"grid": {
|
| 3004 |
+
"dtype": "float32",
|
| 3005 |
+
"shape": [1, 1, 1, 2],
|
| 3006 |
+
"data": { "kind": "values", "values": [0.0, 3.7643392086029053] }
|
| 3007 |
+
}
|
| 3008 |
+
},
|
| 3009 |
+
"outputs": {
|
| 3010 |
+
"y": {
|
| 3011 |
+
"dtype": "float32",
|
| 3012 |
+
"shape": [1, 1, 1, 1],
|
| 3013 |
+
"data": { "kind": "values", "values": [-0.0933837890625] },
|
| 3014 |
+
"tolerance": 0.0001,
|
| 3015 |
+
"relTolerance": 0.0001
|
| 3016 |
+
}
|
| 3017 |
+
}
|
| 3018 |
+
},
|
| 3019 |
+
{
|
| 3020 |
+
"name": "reflection_coordinate_f32_rounding_rank5",
|
| 3021 |
+
"provenance": {
|
| 3022 |
+
"notes": "Float32 coordinate normalization outside the image must round before interpolation. Alternating pixels amplify the f32 versus f64 coordinate difference; expected value independently checked with ONNX Runtime's CPU provider."
|
| 3023 |
+
},
|
| 3024 |
+
"attrs": { "mode": "linear", "padding_mode": "reflection", "align_corners": 1 },
|
| 3025 |
+
"inputs": {
|
| 3026 |
+
"x": {
|
| 3027 |
+
"dtype": "float32",
|
| 3028 |
+
"shape": [1, 1, 1, 256, 1],
|
| 3029 |
+
"data": {
|
| 3030 |
+
"kind": "values",
|
| 3031 |
+
"values": { "$ref": "#/fixtureArrays/reflection_coordinate_f32_rounding_rank4_input_x" }
|
| 3032 |
+
}
|
| 3033 |
+
},
|
| 3034 |
+
"grid": {
|
| 3035 |
+
"dtype": "float32",
|
| 3036 |
+
"shape": [1, 1, 1, 1, 3],
|
| 3037 |
+
"data": { "kind": "values", "values": [0.0, 3.7643392086029053, 0.0] }
|
| 3038 |
+
}
|
| 3039 |
+
},
|
| 3040 |
+
"outputs": {
|
| 3041 |
+
"y": {
|
| 3042 |
+
"dtype": "float32",
|
| 3043 |
+
"shape": [1, 1, 1, 1, 1],
|
| 3044 |
+
"data": { "kind": "values", "values": [-0.0933837890625] },
|
| 3045 |
+
"tolerance": 0.0001,
|
| 3046 |
+
"relTolerance": 0.0001
|
| 3047 |
+
}
|
| 3048 |
+
}
|
| 3049 |
}
|
| 3050 |
]
|
| 3051 |
}
|