edgefirst-image 0.38.2

High-performance image processing with hardware acceleration for edge AI
Documentation
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
1001
1002
1003
1004
1005
1006
// SPDX-FileCopyrightText: Copyright 2026 Au-Zone Technologies
// SPDX-License-Identifier: Apache-2.0

//! GL shader sources shared across platform backends (macOS ANGLE + Linux).

// ---------------------------------------------------------------------------
// Portable `#version 300 es` fragment shaders shared verbatim by both the
// Linux (PBO/DMA EGLImage) and macOS (IOSurface/ANGLE) render paths, so the
// GLSL bytes are validated identically on every backend.
//
// (YUV→RGB matrix conversion lives in the per-backend NV shaders — Linux
// `shaders::generate_nv_to_rgba_shader_2d` and the macOS `NV_TO_RGBA_FRAGMENT`,
// each carrying the six per-tensor colorimetry uniforms from
// `crate::colorimetry::yuv_to_rgb_coeffs`. Packed YUYV uses the driver Path A
// EGL color-space/range hints. Only the colorimetry-agnostic float packers
// are shared here.)
// ---------------------------------------------------------------------------

/// RGBA8 -> packed planar-float fragment shader (`PlanarRgb` / `PlanarRgba`,
/// F16 or F32).
///
/// The render target is a single `RGBA16F` (F16) or `RGBA32F` (F32) texture
/// sized `(W/4, C*H)` for a `C`-plane destination. Each output texel packs 4
/// float channel samples into its four components, so a linear readout of the
/// rendered texture produces a tightly-packed `[C, H, W]` buffer (CHW order,
/// one plane per row-band). Width `W` must be a multiple of 4.
///
/// The plane index comes from the surface geometry (`floor(oy / H)`), not from
/// a uniform, so a `PlanarRgba` surface of height `4*H` selects plane 3 on its
/// own; the sampler carries a branch for each of the four planes and
/// `pad_color` is a `vec4` so plane 3 pads with the same alpha the CPU
/// reference writes.
///
/// This is the single source of truth consumed by the Linux (PBO/DMA), macOS
/// (IOSurface/ANGLE) and Windows (D3D11 texture) render paths. The GLSL bytes
/// are validated against the CPU converter by the on-target F16 round-trip
/// tests, the macOS IOSurface integration tests and
/// `windows_float_destinations_match_the_cpu_converter_for_every_layout`.
pub(crate) const PLANAR_RGB_F16_PACKED_FRAGMENT: &str = r#"#version 300 es
precision highp float;
precision highp int;
uniform sampler2D src;
uniform vec2 dst_image_size;  // (W, H) — destination plane size
uniform vec4 src_rect_uv;     // (origin_u, origin_v, size_u, size_v)
uniform vec4 src_extent;      // (u_min, v_min, u_max, v_max) a sample may reach
uniform vec4 dst_rect_px;     // (origin_x, origin_y, w, h) within one plane
uniform vec4 pad_color;       // per-channel pad value as written (RGBA)
uniform vec4 norm_scale;      // output = sample * norm_scale + norm_offset
uniform vec4 norm_offset;
out vec4 frag;

// Sample one planar element. Returns the per-channel value at
// (in_plane_x, in_plane_y) for the given plane (0=R, 1=G, 2=B, 3=A).
// Pad value is returned when (in_plane_x, in_plane_y) is outside
// `dst_rect_px`.
float sample_planar_element(float in_plane_x, float in_plane_y, float plane) {
    bool inside_dst = (in_plane_x >= dst_rect_px.x) &&
                      (in_plane_x <  dst_rect_px.x + dst_rect_px.z) &&
                      (in_plane_y >= dst_rect_px.y) &&
                      (in_plane_y <  dst_rect_px.y + dst_rect_px.w);
    if (inside_dst) {
        float u = (in_plane_x - dst_rect_px.x) / dst_rect_px.z;
        float v = (in_plane_y - dst_rect_px.y) / dst_rect_px.w;
        vec2 src_uv = clamp(src_rect_uv.xy + vec2(u, v) * src_rect_uv.zw,
                            src_extent.xy, src_extent.zw);
        vec4 rgba = texture(src, src_uv) * norm_scale + norm_offset;
        if (plane < 0.5) {
            return rgba.r;
        } else if (plane < 1.5) {
            return rgba.g;
        } else if (plane < 2.5) {
            return rgba.b;
        } else {
            return rgba.a;
        }
    } else {
        if (plane < 0.5) {
            return pad_color.r;
        } else if (plane < 1.5) {
            return pad_color.g;
        } else if (plane < 2.5) {
            return pad_color.b;
        } else {
            return pad_color.a;
        }
    }
}

void main() {
    // gl_FragCoord is at pixel center (n+0.5). Floor for the integer
    // index of the output pixel on the (W/4 × 3H) surface.
    int ox = int(floor(gl_FragCoord.x));
    int oy = int(floor(gl_FragCoord.y));

    float plane = floor(float(oy) / dst_image_size.y);
    float in_plane_y = float(oy) - plane * dst_image_size.y + 0.5;

    // Sample 4 consecutive in-plane x positions. Pixel center is
    // (x+0.5) so the first element of pixel `ox` starts at logical
    // tensor column `ox*4` — add 0.5 for the texel center sampled
    // by the bilinear filter.
    float base_x = float(ox * 4) + 0.5;
    float e0 = sample_planar_element(base_x + 0.0, in_plane_y, plane);
    float e1 = sample_planar_element(base_x + 1.0, in_plane_y, plane);
    float e2 = sample_planar_element(base_x + 2.0, in_plane_y, plane);
    float e3 = sample_planar_element(base_x + 3.0, in_plane_y, plane);

    // An RGBA16F attachment narrows each f32 to f16 on write; an RGBA32F
    // one keeps it. Either way the resulting byte layout in the surface is
    // exactly the [C, H, W] planar order the consumer expects.
    frag = vec4(e0, e1, e2, e3);
}
"#;

/// RGBA8 -> packed interleaved-float fragment shader (`Rgb`, F16 or F32).
///
/// The render target is a single `RGBA16F` (F16) or `RGBA32F` (F32) texture
/// sized `(W*3/4, H)`. Each output texel packs 4 consecutive elements of the
/// destination's `[H, W, 3]` stream into its four components, so a linear
/// readout produces a tightly-packed NHWC buffer. `W*3` must divide into whole
/// texels, which for a 3-channel row means `W % 4 == 0`.
///
/// Same crop and pad contract as the planar packer: the destination element
/// index gives the pixel and channel, `dst_rect_px` decides whether that pixel
/// is content or pad, and `src_rect_uv` maps content onto the source. Sampling
/// the source once per element rather than packing an already-rendered u8
/// intermediate keeps the result identical to the F32 NHWC PBO path, which
/// samples the same way.
pub(crate) const FLOAT_NHWC_PACKED_FRAGMENT: &str = r#"#version 300 es
precision highp float;
precision highp int;
uniform sampler2D src;
uniform vec4 src_rect_uv;     // (origin_u, origin_v, size_u, size_v)
uniform vec4 src_extent;      // (u_min, v_min, u_max, v_max) a sample may reach
uniform vec4 dst_rect_px;     // (origin_x, origin_y, w, h) in pixel space
uniform vec4 pad_color;       // per-channel pad value as written (RGBA)
uniform vec4 norm_scale;      // output = sample * norm_scale + norm_offset
uniform vec4 norm_offset;
out vec4 frag;

// Sample one element of the interleaved [H, W, 3] stream. `element` is the
// element's index within its row, `oy` the destination row; the pad value is
// returned when the element's pixel lies outside `dst_rect_px`.
float sample_interleaved_element(int element, int oy) {
    int px = element / 3;
    int channel = element - px * 3;
    float fx = float(px);
    float fy = float(oy);
    bool inside_dst = (fx >= dst_rect_px.x) &&
                      (fx <  dst_rect_px.x + dst_rect_px.z) &&
                      (fy >= dst_rect_px.y) &&
                      (fy <  dst_rect_px.y + dst_rect_px.w);
    if (!inside_dst) {
        return (channel == 0) ? pad_color.r
             : (channel == 1) ? pad_color.g : pad_color.b;
    }
    // Pixel center (+0.5) so LINEAR filtering resamples about the right
    // point, matching the F32 NHWC PBO shader.
    float u = (fx + 0.5 - dst_rect_px.x) / dst_rect_px.z;
    float v = (fy + 0.5 - dst_rect_px.y) / dst_rect_px.w;
    vec2 src_uv = clamp(src_rect_uv.xy + vec2(u, v) * src_rect_uv.zw,
                        src_extent.xy, src_extent.zw);
    vec4 rgba = texture(src, src_uv) * norm_scale + norm_offset;
    return (channel == 0) ? rgba.r
         : (channel == 1) ? rgba.g : rgba.b;
}

void main() {
    // gl_FragCoord is at pixel center (n+0.5). Floor for the integer index
    // of the output texel on the (W*3/4 x H) surface.
    int ox = int(floor(gl_FragCoord.x));
    int oy = int(floor(gl_FragCoord.y));
    int base = ox * 4;
    frag = vec4(sample_interleaved_element(base + 0, oy),
                sample_interleaved_element(base + 1, oy),
                sample_interleaved_element(base + 2, oy),
                sample_interleaved_element(base + 3, oy));
}
"#;

/// RGBA8 -> float `Rgba` fragment shader: the float paths' crop and pad
/// contract at one texel per pixel.
///
/// The render target is an `RGBA16F` (F16) or `RGBA32F` (F32) texture sized
/// `(W, H)` — an `Rgba` float destination needs no packing, so the whole
/// fetched texel is the output, alpha included.
///
/// Addressing comes from `gl_FragCoord`, not the interpolated texcoord: the
/// other float shaders read the destination row straight off `gl_FragCoord.y`
/// (framebuffer row 0 is the surface's first row of memory) and the quad's
/// texcoords run the other way down the viewport.
pub(crate) const FLOAT_RGBA_FRAGMENT: &str = r#"#version 300 es
precision highp float;
precision highp int;
uniform sampler2D src;
uniform vec4 src_rect_uv;     // (origin_u, origin_v, size_u, size_v)
uniform vec4 src_extent;      // (u_min, v_min, u_max, v_max) a sample may reach
uniform vec4 dst_rect_px;     // (origin_x, origin_y, w, h) in pixel space
uniform vec4 pad_color;       // per-channel pad value as written (RGBA)
uniform vec4 norm_scale;      // output = sample * norm_scale + norm_offset
uniform vec4 norm_offset;
out vec4 color;

void main() {
    float px = float(int(floor(gl_FragCoord.x)));
    float py = float(int(floor(gl_FragCoord.y)));
    bool inside_dst = (px >= dst_rect_px.x) &&
                      (px <  dst_rect_px.x + dst_rect_px.z) &&
                      (py >= dst_rect_px.y) &&
                      (py <  dst_rect_px.y + dst_rect_px.w);
    if (!inside_dst) {
        color = pad_color;
        return;
    }
    // Pixel center (+0.5), as in the packed float shaders.
    float u = (px + 0.5 - dst_rect_px.x) / dst_rect_px.z;
    float v = (py + 0.5 - dst_rect_px.y) / dst_rect_px.w;
    vec2 src_uv = clamp(src_rect_uv.xy + vec2(u, v) * src_rect_uv.zw,
                        src_extent.xy, src_extent.zw);
    color = texture(src, src_uv) * norm_scale + norm_offset;
}
"#;

/// Fullscreen-quad vertex shader shared by both backends. Position is a `vec3`
/// (NDC, `z` unused for the 2D quad but carried so the same shader serves the
/// segmentation passes); passes `fragPos`/`tc` to the fragment stage. The VBO
/// feeds `pos` (location 0) and `texCoord` (location 1).
pub(crate) const VERTEX_SHADER: &str = "\
#version 300 es
precision mediump float;
layout(location = 0) in vec3 pos;
layout(location = 1) in vec2 texCoord;

out vec3 fragPos;
out vec2 tc;

void main() {
    fragPos = pos;
    tc = texCoord;

    gl_Position = vec4(pos, 1.0);
}
";

// ---------------------------------------------------------------------------
// NV12/NV16/NV24 (semi-planar YUV, single R8 plane) -> RGBA, shared across
// backends. Both the Linux (DMA-BUF EGLImage) and macOS (IOSurface/ANGLE) paths
// decode the SAME combined-plane byte layout (`PixelFormat::chroma_layout` +
// `combined_plane_height`) using the **divide-free** addressing form: direct 2D
// `texelFetch` + a branchless `carry` for NV24's wrapping 2W-byte chroma row.
// No per-pixel integer divide/modulo — that is pathologically slow on Vivante
// GC7000UL / V3D and is also the software-emulated slow path on Apple GPUs
// (variable divisor), so the divide-free form is the right default everywhere.
//
// Both backends use the same `VERTEX_SHADER` (above), so the fragment shader is
// byte-identical on both — ONE source string. The bytes are validated on-target
// (Linux) and frozen by `nv_fragment_byte_identical` below.

/// Declarations shared by the NV->RGBA program and its int8 twin, ending with
/// `nv_rgb(x, y)`: the exact YUV->RGB conversion of the luma texel at (x, y)
/// and its co-sited chroma. References the `chroma_shift`/`chroma_lines`/
/// `tex_width` layout uniforms and the six colorimetry uniforms.
/// The colorimetry uniforms every NV program reads (see `nv_yuv_to_rgb_fn`).
macro_rules! nv_colorimetry {
    () => {
        "// Per-tensor colorimetry (YUV→RGB matrix + range), set by draw_nv_texture_2d
// from the source tensor's resolved colorimetry. Path B applies the matrix in
// the shader, so it is correct regardless of driver EGL color-hint support.
uniform float y_offset;
uniform float y_scale;
uniform float c_vr;
uniform float c_ug;
uniform float c_vg;
uniform float c_ub;
"
    };
}

/// `nv_yuv_to_rgb`: the exact YUV->RGB matrix every NV program applies.
macro_rules! nv_yuv_to_rgb_fn {
    () => {
        "// Floor expanded luma at 0 to match the CPU `yuv` crate's saturating (Y-16)
// term (limited footroom Y<16 → 0). The top is left uncapped — the crate lets
// headroom exceed 1.0 and relies on the final RGB clamp, so the GL path must
// too. No-op for full range (y_offset=0, y_scale=1).
vec3 nv_yuv_to_rgb(float yv, float u, float v) {
    float yp = max((yv - y_offset) * y_scale, 0.0);
    float up = u - 128.0 / 255.0;
    float vp = v - 128.0 / 255.0;
    return clamp(vec3(yp + c_vr * vp, yp - c_ug * up - c_vg * vp, yp + c_ub * up), 0.0, 1.0);
}

"
    };
}

macro_rules! nv_rgba_header {
    () => {
        concat!(
            "#version 300 es
precision highp float;
precision highp int;
uniform highp sampler2D src;
uniform ivec2 img_size;
uniform int tex_width;
uniform ivec2 chroma_shift;
uniform int chroma_lines;
// Inclusive texel bounds (x0, y0, x1, y1) of the source crop: every tap is
// clamped to them, so a crop never reads pixels from outside itself.
uniform ivec4 src_rect;
// Hardware-filtered program only: the chroma plane as (U, V) texels on unit 1,
// the image's share of each texture (`*_scale`), and the crop's half-texel-
// inset rectangle on each (`*_clamp`), which keeps the LINEAR kernel inside
// the crop and the luma rows.
uniform highp sampler2D uv_tex;
uniform vec2 luma_scale;
uniform vec4 luma_clamp;
uniform vec2 chroma_scale;
uniform vec4 chroma_clamp;
",
            nv_colorimetry!(),
            "in vec3 fragPos;
in vec2 tc;
out vec4 color;

",
            nv_yuv_to_rgb_fn!(),
            "vec3 nv_rgb(int x, int y) {
    // Luma: direct 2D texel — no per-pixel integer divide/modulo (very slow on
    // some embedded GPUs, e.g. Vivante GC7000UL).
    float yv = texelFetch(src, ivec2(x, y), 0).r;

    // Interleaved CbCr plane begins at buffer row `h`. Each image-chroma-row
    // spans `chroma_lines` R8 rows: NV24's 2W-byte row wraps once at tex_width
    // (carry); NV12/NV16 fit one row. `cx` is even so `cx+1` stays in-row.
    int ccol = x >> chroma_shift.x;
    int crow = y >> chroma_shift.y;
    int ccol2 = ccol * 2;
    int carry = ccol2 >= tex_width ? 1 : 0;
    int cy = img_size.y + crow * chroma_lines + carry;
    int cx = ccol2 - carry * tex_width;
    float u = texelFetch(src, ivec2(cx, cy), 0).r;
    float v = texelFetch(src, ivec2(cx + 1, cy), 0).r;
    return nv_yuv_to_rgb(yv, u, v);
}

"
        )
    };
}

/// `main()` statements of the single-tap NV programs, for draws that map the
/// crop 1:1: reads the texel under the fragment and leaves it in `rgb`. `tc`
/// spans the crop's outer edges, so `tc * size` is the source position.
macro_rules! nv_rgb_nearest_body {
    () => {
        "    ivec2 i = clamp(ivec2(tc * vec2(img_size)), src_rect.xy, src_rect.zw);
    vec3 rgb = nv_rgb(i.x, i.y);
"
    };
}

/// `main()` statements of the bilinear NV programs, for draws that rescale
/// the crop: half-pixel-centred bilinear, the GL_LINEAR / OpenCV INTER_LINEAR
/// convention, with every tap clamped to the crop. Blending the four texels'
/// converted RGB equals converting at native resolution and then resizing, as
/// the CPU backend does.
macro_rules! nv_rgb_bilinear_body {
    () => {
        "    vec2 p = tc * vec2(img_size) - 0.5;
    vec2 p0 = floor(p);
    vec2 f = p - p0;
    ivec2 i0 = clamp(ivec2(p0), src_rect.xy, src_rect.zw);
    ivec2 i1 = clamp(ivec2(p0) + 1, src_rect.xy, src_rect.zw);
    vec3 rgb = mix(mix(nv_rgb(i0.x, i0.y), nv_rgb(i1.x, i0.y), f.x),
                   mix(nv_rgb(i0.x, i1.y), nv_rgb(i1.x, i1.y), f.x), f.y);
"
    };
}

/// `main()` statements of the hardware-filtered bilinear NV programs: luma
/// from the combined plane and chroma from its (U, V) view, each through the
/// texture unit's LINEAR filter, then the exact YUV->RGB matrix. Filtering
/// chroma on its own grid centres each chroma sample on the luma pixels it
/// covers, as JPEG sites it.
macro_rules! nv_rgb_hw_bilinear_body {
    () => {
        "    vec2 luv = clamp(tc * luma_scale, luma_clamp.xy, luma_clamp.zw);
    vec2 cuv = clamp(tc * chroma_scale, chroma_clamp.xy, chroma_clamp.zw);
    vec2 c = texture(uv_tex, cuv).rg;
    vec3 rgb = nv_yuv_to_rgb(texture(src, luv).r, c.r, c.g);
"
    };
}

/// The integer output mapping every int8 program applies to its RGB output.
/// Built with `QUANT_MAPPED`, normalization and quantization are uniforms and
/// the result is stored as the low byte; without it, the plain `x ^ 0x80` bias.
macro_rules! int_quantize {
    () => {
        "#ifdef QUANT_MAPPED
uniform highp vec3 q_scale;   // q = clamp(floor(v * q_scale + q_offset), q_lo, q_hi)
uniform highp vec3 q_offset;
uniform highp vec3 q_lo;
uniform highp vec3 q_hi;
uniform highp vec3 q_zero;    // zero point / 255; q_wrap marks a negative stored value
uniform highp vec3 q_wrap;
highp vec3 quantize(highp vec3 v) {
    highp vec3 q = clamp(floor(v * q_scale + q_offset), q_lo, q_hi);
    return q * (1.0 / 255.0) + q_zero + step(q, q_wrap) * (256.0 / 255.0);
}
#else
// The plain XOR 0x80 bias, `(q + 128) mod 256`, as the CPU `byte ^ 0x80`.
highp vec3 quantize(highp vec3 v) {
    highp vec3 q = floor(v * 255.0 + 0.5);
    return mod(q + 128.0, 256.0) / 255.0;
}
#endif

"
    };
}

/// YUYV (sampled as a GL_RG texture: R=Y, G=alternating U/V) → RGBA.
/// Each output pixel samples its own texel and the horizontal partner to
/// recover both chroma components; the YUV→RGB matrix + range come from
/// the per-tensor colorimetry uniforms (same names as the NV program).
/// `src_size` is the texture's texel grid and `src_extent` the logical
/// image's rectangle on it (`render::sample_clamp_rect`), which differ when
/// the import covers more of the texture than the logical image.
/// Portable `sampler2D` — shared by the IOSurface zero-copy source path
/// and any future heap-YUYV upload path.
/// Declarations shared by the YUYV->RGBA program and its int8 twin.
macro_rules! yuyv_rgba_2d_header {
    () => {
        r#"#version 300 es
precision highp float;
uniform highp sampler2D tex;
uniform vec2 src_size;
uniform vec4 src_extent;
uniform float y_offset;
uniform float y_scale;
uniform float c_vr;
uniform float c_ug;
uniform float c_vg;
uniform float c_ub;
in vec3 fragPos;
in vec2 tc;
out vec4 color;

"#
    };
}

/// `main()` statements shared by the YUYV->RGBA program and its int8 twin:
/// reads `tc` and the uniforms above, leaves the pixel in `r`, `g`, `b`.
macro_rules! yuyv_rgb_body {
    () => {
        r#"    vec2 texel = vec2(1.0) / src_size;
    // `src_extent` keeps the texel index inside the logical image when the
    // texture is larger than it; `src_size` is the texture's own grid.
    vec2 col = floor(clamp(tc, src_extent.xy, src_extent.zw) * src_size);
    bool even = mod(col.x, 2.0) < 0.5;
    vec2 self_uv = (col + vec2(0.5)) * texel;
    // The clamp bounds `col`, not the partner. On an odd logical width the
    // last column is even, so its partner is one texel past the logical
    // image: stale pool content on a narrowed import, and the column itself
    // under CLAMP_TO_EDGE otherwise. Out of scope, and unchanged by the
    // clamp: a YUYV chroma pair spans two columns, so an odd width has no
    // partner to read in any layout (the allocation is `width` texels wide,
    // not rounded up), and the engine's YUYV coverage is even widths only.
    vec2 pair_uv = (col + vec2(even ? 1.5 : -0.5, 0.5)) * texel;

    vec4 self_rg = texture(tex, self_uv);
    vec4 pair_rg = texture(tex, pair_uv);
    float y = self_rg.r;
    float u, v;
    if (even) { u = self_rg.g; v = pair_rg.g; }
    else      { v = self_rg.g; u = pair_rg.g; }

    // Identical matrix/range math to the NV program: floor the expanded
    // luma at 0 (limited-range footroom folds to 0; full range is a no-op
    // with y_offset=0/y_scale=1), top end left to the per-channel clamp.
    float yp = max((y - y_offset) * y_scale, 0.0);
    float up = u - 128.0 / 255.0;
    float vp = v - 128.0 / 255.0;
    float r = clamp(yp + c_vr * vp, 0.0, 1.0);
    float g = clamp(yp - c_ug * up - c_vg * vp, 0.0, 1.0);
    float b = clamp(yp + c_ub * up, 0.0, 1.0);
"#
    };
}

pub(crate) const YUYV_RGBA_2D_FRAGMENT: &str = concat!(
    yuyv_rgba_2d_header!(),
    "void main() {\n",
    yuyv_rgb_body!(),
    "    color = vec4(r, g, b, 1.0);\n}\n"
);

/// Int8 variant of [`YUYV_RGBA_2D_FRAGMENT`]: the same pixel, with the XOR
/// 0x80 bias every int8 program applies (`(q + 128) mod 256`, matching the
/// CPU `byte ^ 0x80`).
pub(crate) const YUYV_RGBA_2D_INT8_FRAGMENT: &str = concat!(
    yuyv_rgba_2d_header!(),
    int_quantize!(),
    "void main() {\n",
    yuyv_rgb_body!(),
    "    color = vec4(quantize(vec3(r, g, b)), 1.0);\n}\n"
);

/// NV->RGBA fragment shader (Path B) for draws that do not rescale. Vertex
/// stage ([`VERTEX_SHADER`]) provides `fragPos`/`tc`; output is `color`. The
/// bytes are validated on-target (Linux) and frozen by the golden test below.
pub(crate) const NV_RGBA_FRAGMENT: &str = concat!(
    nv_rgba_header!(),
    "void main() {\n",
    nv_rgb_nearest_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// Int8 variant of [`NV_RGBA_FRAGMENT`].
pub(crate) const NV_RGBA_INT8_FRAGMENT: &str = concat!(
    nv_rgba_header!(),
    int_quantize!(),
    "void main() {\n",
    nv_rgb_nearest_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

/// NV->RGBA fragment shader (Path B) for draws that rescale: bilinear. A
/// separate program rather than a uniform branch in [`NV_RGBA_FRAGMENT`]:
/// Vivante GC7000UL does not reliably honour that branch, and on V3D and
/// Adreno the untaken half still slows 1:1 draws.
pub(crate) const NV_RGBA_BILINEAR_FRAGMENT: &str = concat!(
    nv_rgba_header!(),
    "void main() {\n",
    nv_rgb_bilinear_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// NV->RGBA fragment shader (Path B) for draws that rescale, where the chroma
/// plane can be bound as its own texture: bilinear through the texture unit,
/// two filtered fetches per pixel instead of the twelve of
/// [`NV_RGBA_BILINEAR_FRAGMENT`], which remains the fallback.
pub(crate) const NV_RGBA_HW_BILINEAR_FRAGMENT: &str = concat!(
    nv_rgba_header!(),
    "void main() {\n",
    nv_rgb_hw_bilinear_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// Int8 variant of [`NV_RGBA_HW_BILINEAR_FRAGMENT`].
pub(crate) const NV_RGBA_HW_BILINEAR_INT8_FRAGMENT: &str = concat!(
    nv_rgba_header!(),
    int_quantize!(),
    "void main() {\n",
    nv_rgb_hw_bilinear_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

/// Header of the Y2Y NV programs: `GL_EXT_YUV_target` samples an NV12
/// import as raw (Y, U, V), filtered by the texture unit but not converted by
/// the driver, so the exact matrix still applies. `src_extent` is the
/// rectangle a sample may reach, as in the external-sampler programs.
macro_rules! nv_y2y_header {
    () => {
        concat!(
            "#version 300 es
#extension GL_EXT_YUV_target : require
precision highp float;
uniform __samplerExternal2DY2YEXT src;
uniform highp vec4 src_extent;
",
            nv_colorimetry!(),
            "in vec3 fragPos;
in highp vec2 tc;
out vec4 color;

",
            nv_yuv_to_rgb_fn!()
        )
    };
}

/// `main()` statements of the Y2Y NV programs: one filtered fetch.
macro_rules! nv_rgb_y2y_body {
    () => {
        "    vec3 yuv = texture(src, clamp(tc, src_extent.xy, src_extent.zw)).rgb;
    vec3 rgb = nv_yuv_to_rgb(yuv.r, yuv.g, yuv.b);
"
    };
}

/// NV->RGBA fragment shader for draws that rescale, on GPUs with
/// `GL_EXT_YUV_target` that cannot bind the chroma plane as its own texture
/// (Mali lists no two-channel 8-bit import format): bilinear through the
/// texture unit from a single NV12 import, one fetch per pixel.
pub(crate) const NV_RGBA_Y2Y_FRAGMENT: &str = concat!(
    nv_y2y_header!(),
    "void main() {\n",
    nv_rgb_y2y_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// Int8 variant of [`NV_RGBA_Y2Y_FRAGMENT`].
pub(crate) const NV_RGBA_Y2Y_INT8_FRAGMENT: &str = concat!(
    nv_y2y_header!(),
    int_quantize!(),
    "void main() {\n",
    nv_rgb_y2y_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

/// Int8 variant of [`NV_RGBA_BILINEAR_FRAGMENT`].
pub(crate) const NV_RGBA_BILINEAR_INT8_FRAGMENT: &str = concat!(
    nv_rgba_header!(),
    int_quantize!(),
    "void main() {\n",
    nv_rgb_bilinear_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

// ---------------------------------------------------------------------------
// Packed sources from an R8 view of the buffer. No GPU texel format holds a
// packed 24-bit pixel, so the buffer is presented as one R8 texture
// `row_stride` texels wide and `height` rows tall, and each pixel is assembled
// from its bytes. Taps go through `texture()` at texel centres rather than
// `texelFetch`: same bytes under NEAREST, and Vivante GC7000UL runs it about
// 1.8x faster. A header supplies `src_px(x, y)`, the exact pixel, and
// `src_col(x, v)`, the pixel's bytes blended between rows by a LINEAR sampler;
// the sampling bodies below are shared by every header.

/// Declarations every packed R8-view program shares: the layout uniforms.
macro_rules! packed_r8_uniforms {
    () => {
        "#version 300 es
precision highp float;
precision highp int;
uniform highp sampler2D src;
uniform ivec2 img_size;
// Reciprocal of the R8 texture's size: (row stride in bytes, rows).
uniform vec2 inv_tex;
// Inclusive texel bounds (x0, y0, x1, y1) of the source crop: every tap is
// clamped to them, so a crop never reads pixels from outside itself.
uniform ivec4 src_rect;
"
    };
}

/// Packed RGB, three bytes per pixel.
macro_rules! rgb_r8_header {
    () => {
        concat!(
            packed_r8_uniforms!(),
            "in vec3 fragPos;
in vec2 tc;
out vec4 color;

vec3 src_px(int x, int y) {
    float b = float(x * 3) + 0.5;
    float v = (float(y) + 0.5) * inv_tex.y;
    return vec3(texture(src, vec2(b * inv_tex.x, v)).r,
                texture(src, vec2((b + 1.0) * inv_tex.x, v)).r,
                texture(src, vec2((b + 2.0) * inv_tex.x, v)).r);
}

// Under LINEAR filtering, at texture row coordinate `v`. Each tap sits 1/1024
// texel right of its byte's centre so the horizontal weight quantizes to zero:
// a tap computed exactly at the centre can land a hair left of it and blend
// in a fraction of the previous byte, which belongs to another channel.
vec3 src_col(int x, float v) {
    float b = float(x * 3) + 0.5 + 1.0 / 1024.0;
    return vec3(texture(src, vec2(b * inv_tex.x, v)).r,
                texture(src, vec2((b + 1.0) * inv_tex.x, v)).r,
                texture(src, vec2((b + 2.0) * inv_tex.x, v)).r);
}

"
        )
    };
}

/// YUYV luma only, for a Grey destination: each pixel's Y byte (byte `2x`),
/// range-expanded as the CPU's luma copy does, in every channel.
macro_rules! yuyv_luma_r8_header {
    () => {
        concat!(
            packed_r8_uniforms!(),
            "// Luma range expansion from the source's colorimetry, as in the NV
// programs: limited range maps 16..235 onto 0..1, full range is unchanged.
uniform float y_offset;
uniform float y_scale;
in vec3 fragPos;
in vec2 tc;
out vec4 color;

vec3 luma(float y) {
    return vec3(clamp((y - y_offset) * y_scale, 0.0, 1.0));
}

vec3 src_px(int x, int y) {
    float b = float(x * 2) + 0.5;
    return luma(texture(src, vec2(b * inv_tex.x, (float(y) + 0.5) * inv_tex.y)).r);
}

// Under LINEAR filtering, at texture row coordinate `v`, nudged off the byte
// centre as in the packed-RGB header so no chroma byte blends in.
vec3 src_col(int x, float v) {
    float b = float(x * 2) + 0.5 + 1.0 / 1024.0;
    return luma(texture(src, vec2(b * inv_tex.x, v)).r);
}

"
        )
    };
}

/// `main()` statements of the single-tap packed programs (a draw that maps
/// the crop 1:1, or nearest interpolation): the pixel under `tc`.
macro_rules! packed_r8_nearest_body {
    () => {
        "    ivec2 i = clamp(ivec2(tc * vec2(img_size)), src_rect.xy, src_rect.zw);
    vec3 rgb = src_px(i.x, i.y);
"
    };
}

/// `main()` statements of the shader-filtered bilinear packed programs:
/// half-pixel-centred bilinear from four exact pixels, every tap clamped to
/// the crop — the convention of the NV bilinear programs.
macro_rules! packed_r8_bilinear_body {
    () => {
        "    vec2 p = tc * vec2(img_size) - 0.5;
    vec2 p0 = floor(p);
    vec2 f = p - p0;
    ivec2 i0 = clamp(ivec2(p0), src_rect.xy, src_rect.zw);
    ivec2 i1 = clamp(ivec2(p0) + 1, src_rect.xy, src_rect.zw);
    vec3 rgb = mix(mix(src_px(i0.x, i0.y), src_px(i1.x, i0.y), f.x),
                   mix(src_px(i0.x, i1.y), src_px(i1.x, i1.y), f.x), f.y);
"
    };
}

/// `main()` statements of the hardware-assisted bilinear packed programs:
/// the texture unit's LINEAR filter blends rows within each byte column, the
/// shader blends the two columns, half the fetches of the shader-filtered
/// program. The row coordinate is clamped to the crop's row centres so the
/// filter never reaches a row outside it.
macro_rules! packed_r8_hw_bilinear_body {
    () => {
        "    vec2 p = tc * vec2(img_size) - 0.5;
    float x0 = floor(p.x);
    float fx = p.x - x0;
    int xa = clamp(int(x0), src_rect.x, src_rect.z);
    int xb = clamp(int(x0) + 1, src_rect.x, src_rect.z);
    float v = (clamp(p.y, float(src_rect.y), float(src_rect.w)) + 0.5) * inv_tex.y;
    vec3 rgb = mix(src_col(xa, v), src_col(xb, v), fx);
"
    };
}

/// Packed-RGB->RGBA fragment shader for draws that do not rescale.
pub(crate) const RGB_R8_RGBA_FRAGMENT: &str = concat!(
    rgb_r8_header!(),
    "void main() {\n",
    packed_r8_nearest_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// Int8 variant of [`RGB_R8_RGBA_FRAGMENT`].
pub(crate) const RGB_R8_RGBA_INT8_FRAGMENT: &str = concat!(
    rgb_r8_header!(),
    int_quantize!(),
    "void main() {\n",
    packed_r8_nearest_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

/// Packed-RGB->RGBA fragment shader for draws that rescale, filtered in the
/// shader: the exact program, and the fallback when the texture units may
/// not filter.
pub(crate) const RGB_R8_RGBA_BILINEAR_FRAGMENT: &str = concat!(
    rgb_r8_header!(),
    "void main() {\n",
    packed_r8_bilinear_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// Int8 variant of [`RGB_R8_RGBA_BILINEAR_FRAGMENT`].
pub(crate) const RGB_R8_RGBA_BILINEAR_INT8_FRAGMENT: &str = concat!(
    rgb_r8_header!(),
    int_quantize!(),
    "void main() {\n",
    packed_r8_bilinear_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

/// Packed-RGB->RGBA fragment shader for draws that rescale, with the rows
/// blended by the texture unit.
pub(crate) const RGB_R8_RGBA_HW_BILINEAR_FRAGMENT: &str = concat!(
    rgb_r8_header!(),
    "void main() {\n",
    packed_r8_hw_bilinear_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// Int8 variant of [`RGB_R8_RGBA_HW_BILINEAR_FRAGMENT`].
pub(crate) const RGB_R8_RGBA_HW_BILINEAR_INT8_FRAGMENT: &str = concat!(
    rgb_r8_header!(),
    int_quantize!(),
    "void main() {\n",
    packed_r8_hw_bilinear_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

/// YUYV->Grey fragment shader for draws that do not rescale.
pub(crate) const YUYV_LUMA_R8_FRAGMENT: &str = concat!(
    yuyv_luma_r8_header!(),
    "void main() {\n",
    packed_r8_nearest_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// Int8 variant of [`YUYV_LUMA_R8_FRAGMENT`].
pub(crate) const YUYV_LUMA_R8_INT8_FRAGMENT: &str = concat!(
    yuyv_luma_r8_header!(),
    int_quantize!(),
    "void main() {\n",
    packed_r8_nearest_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

/// YUYV->Grey fragment shader for draws that rescale, filtered in the shader.
pub(crate) const YUYV_LUMA_R8_BILINEAR_FRAGMENT: &str = concat!(
    yuyv_luma_r8_header!(),
    "void main() {\n",
    packed_r8_bilinear_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// Int8 variant of [`YUYV_LUMA_R8_BILINEAR_FRAGMENT`].
pub(crate) const YUYV_LUMA_R8_BILINEAR_INT8_FRAGMENT: &str = concat!(
    yuyv_luma_r8_header!(),
    int_quantize!(),
    "void main() {\n",
    packed_r8_bilinear_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

/// YUYV->Grey fragment shader for draws that rescale, with the rows blended
/// by the texture unit.
pub(crate) const YUYV_LUMA_R8_HW_BILINEAR_FRAGMENT: &str = concat!(
    yuyv_luma_r8_header!(),
    "void main() {\n",
    packed_r8_hw_bilinear_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// Int8 variant of [`YUYV_LUMA_R8_HW_BILINEAR_FRAGMENT`].
pub(crate) const YUYV_LUMA_R8_HW_BILINEAR_INT8_FRAGMENT: &str = concat!(
    yuyv_luma_r8_header!(),
    int_quantize!(),
    "void main() {\n",
    packed_r8_hw_bilinear_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

// ---------------------------------------------------------------------------
// RGBA -> Grey: the second pass of a colour source into a Grey destination.
// The first pass rendered the converted image into an RGBA texture at the
// destination's size; this one samples it 1:1 (NEAREST) and writes BT.601
// full-range luma, the weights the CPU's RGB -> Grey conversion uses.

macro_rules! luma_2d_header {
    () => {
        "#version 300 es
precision highp float;
uniform highp sampler2D tex;
in vec3 fragPos;
in highp vec2 tc;
out vec4 color;

"
    };
}

macro_rules! luma_2d_body {
    () => {
        "    vec3 rgb = vec3(dot(texture(tex, tc).rgb, vec3(0.299, 0.587, 0.114)));
"
    };
}

/// RGBA->Grey fragment shader (BT.601 luma in every channel).
pub(crate) const LUMA_2D_FRAGMENT: &str = concat!(
    luma_2d_header!(),
    "void main() {\n",
    luma_2d_body!(),
    "    color = vec4(rgb, 1.0);\n}\n"
);

/// Int8 variant of [`LUMA_2D_FRAGMENT`].
pub(crate) const LUMA_2D_INT8_FRAGMENT: &str = concat!(
    luma_2d_header!(),
    int_quantize!(),
    "void main() {\n",
    luma_2d_body!(),
    "    color = vec4(quantize(rgb), 1.0);\n}\n"
);

#[cfg(test)]
mod nv_shader_golden {
    /// The golden with CRLF normalized to LF. A checkout made with
    /// `core.autocrlf=true` (the Git for Windows default) gives
    /// `include_str!` CRLF line endings while rustc normalizes the string
    /// literal to LF. `.gitattributes` pins `*.glsl` to LF; this covers
    /// checkouts made before that attribute existed.
    fn golden(src: &str) -> String {
        src.replace("\r\n", "\n")
    }

    /// The NV->RGBA shader source is validated on-target (V3D/Mali/Vivante/Tegra);
    /// its bytes must not drift. `golden/nv_rgba_linux.glsl` is the frozen
    /// reference. This test runs on every platform (the module is uncfg'd), so
    /// byte-identity is enforced on the macOS and Windows hosts too, not just
    /// the Linux lane.
    #[test]
    fn nv_fragment_byte_identical() {
        assert_eq!(
            super::NV_RGBA_FRAGMENT,
            golden(include_str!("golden/nv_rgba_linux.glsl")).as_str(),
            "NV->RGBA shader bytes drifted from the on-target-validated golden"
        );
        assert_eq!(
            super::NV_RGBA_BILINEAR_FRAGMENT,
            golden(include_str!("golden/nv_rgba_bilinear_linux.glsl")).as_str(),
            "bilinear NV->RGBA shader bytes drifted from the on-target-validated golden"
        );
        assert_eq!(
            super::NV_RGBA_Y2Y_FRAGMENT,
            golden(include_str!("golden/nv_rgba_y2y_linux.glsl")).as_str(),
            "Y2Y NV->RGBA shader bytes drifted from the on-target-validated golden"
        );
        assert_eq!(
            super::NV_RGBA_HW_BILINEAR_FRAGMENT,
            golden(include_str!("golden/nv_rgba_hw_bilinear_linux.glsl")).as_str(),
            "hardware-bilinear NV->RGBA shader bytes drifted from the on-target-validated golden"
        );
    }

    /// The packed-RGB R8 shader sources, validated on-target (Vivante,
    /// Mali, V3D, Adreno), frozen like the NV ones.
    #[test]
    fn rgb_r8_fragment_byte_identical() {
        assert_eq!(
            super::RGB_R8_RGBA_FRAGMENT,
            golden(include_str!("golden/rgb_r8_rgba_linux.glsl")).as_str(),
            "packed-RGB shader bytes drifted from the on-target-validated golden"
        );
        assert_eq!(
            super::RGB_R8_RGBA_BILINEAR_FRAGMENT,
            golden(include_str!("golden/rgb_r8_rgba_bilinear_linux.glsl")).as_str(),
            "bilinear packed-RGB shader bytes drifted from the on-target-validated golden"
        );
        assert_eq!(
            super::RGB_R8_RGBA_HW_BILINEAR_FRAGMENT,
            golden(include_str!("golden/rgb_r8_rgba_hw_bilinear_linux.glsl")).as_str(),
            "hardware-bilinear packed-RGB shader bytes drifted from the on-target-validated golden"
        );
    }

    /// The YUYV luma and RGBA->Grey shader sources, frozen like the others.
    #[test]
    fn grey_fragment_byte_identical() {
        assert_eq!(
            super::YUYV_LUMA_R8_FRAGMENT,
            golden(include_str!("golden/yuyv_luma_r8_linux.glsl")).as_str(),
            "YUYV luma shader bytes drifted from the on-target-validated golden"
        );
        assert_eq!(
            super::YUYV_LUMA_R8_BILINEAR_FRAGMENT,
            golden(include_str!("golden/yuyv_luma_r8_bilinear_linux.glsl")).as_str(),
            "bilinear YUYV luma shader bytes drifted from the on-target-validated golden"
        );
        assert_eq!(
            super::YUYV_LUMA_R8_HW_BILINEAR_FRAGMENT,
            golden(include_str!("golden/yuyv_luma_r8_hw_bilinear_linux.glsl")).as_str(),
            "hardware-bilinear YUYV luma shader bytes drifted from the on-target-validated golden"
        );
        assert_eq!(
            super::LUMA_2D_FRAGMENT,
            golden(include_str!("golden/luma_2d_linux.glsl")).as_str(),
            "RGBA->Grey shader bytes drifted from the on-target-validated golden"
        );
    }

    #[test]
    fn vertex_byte_identical() {
        assert_eq!(
            super::VERTEX_SHADER,
            golden(include_str!("golden/vertex.glsl")).as_str(),
            "vertex shader bytes drifted from the on-target-validated golden"
        );
    }
}