repo: merge the icon pixel probe and the CS table fix set (icon-pixels-next)
The on-device CoreImage pixel test (tools/run-icon-pixels.py, compare-icon-pixels.py, SnapMetal harness/icon-pixels) and SnapMetal 8fe64cb's ADRENO_CS_TABLES=1 build (SP_CS_CONFIG NTEX equal to NSAMP, as Mesa programs every stage), trusted and deployable as metal-stage-iconfix-20261024 (AdrenoMetal ba3a3fd6, CDHash 11d5ff9a; the icon-pixels tool 25f07e86). next1/next1b showed partial System Settings icons with no plug-in or kext refusal.
This commit is contained in:
commit
5e7b890849
10 files changed
+1087
-14
No files matched your search
@@ -273,6 +273,36 @@ in the desktop AdrenoX2 profiles, is off unless the guest boots with
|
||||
adds (`tools/test-adreno-cs-samplers.py`). An AdrenoX2 built without the define
|
||||
ignores the boot-arg.
|
||||
|
||||
## Checking icon pixels on the GPU
|
||||
|
||||
The encoding tests check the plug-in's packets, not what the Adreno GPU makes of
|
||||
them. `icon-pixels` (SnapMetal `harness/icon-pixels*.m`, built and ad-hoc signed
|
||||
by `tools/build-icon-pixels.py`) runs the CoreImage kernels of the Settings
|
||||
icons in the guest on generated inputs (`synth`) and renders a few system icons
|
||||
(`icons`), printing CRC-sealed text lines that `tools/compare-icon-pixels.py`
|
||||
compares with this Mac's, naming what is off: unwritten or partial output,
|
||||
readback or repeat differences, swapped channels, sRGB decode, a missing input
|
||||
of a multi-input kernel. During a `--console` boot, once the multi-user shell
|
||||
answers, as the run's only console client:
|
||||
|
||||
```sh
|
||||
python3 tools/run-icon-pixels.py --device udp://<interface> \
|
||||
--launch-record build/<run-prefix>-early-stop-launch.json --owner <hex> \
|
||||
--tool <build-dir>/icon-pixels --output <new-dir> \
|
||||
--reference-synth tools/icon-pixels-reference-synth.txt --reference-icons <local icons reference>
|
||||
```
|
||||
|
||||
It pushes the tool in checked base64 chunks to `/private/var/tmp/icon-pixels`,
|
||||
runs it as root and, for the NSWorkspace icons, as the console user in that
|
||||
user's bootstrap context, fetches the output three lines per command, collects
|
||||
the plug-in's diagnostics, and compares. `--steps` picks steps; `recache` with
|
||||
`--move-icon-caches TAG` renames the icon caches aside in multi-user and
|
||||
restarts iconservicesd, iconservicesagent, the Dock and System Settings. The
|
||||
synthetic reference is committed; the icons reference summarises Apple's icons
|
||||
and stays local (`icon-pixels icons --host-caps <plug-in bundle>` on this Mac).
|
||||
`tools/test-icon-pixels.py` is the offline test (fault injection and the whole
|
||||
console procedure over the stand-in).
|
||||
|
||||
## Exit codes
|
||||
|
||||
A boot reports why the guest stopped:
|
||||
|
||||
+1
-1
Submodule gpu/adreno-kext/plugin updated: 7bc40ef6cf...8fe64cb859.
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""Build and ad-hoc sign the icon-pixels guest tool (arm64e), without running it in the guest.
|
||||
|
||||
The tool (gpu/adreno-kext/plugin/harness/icon-pixels*.m, SnapMetal) runs the CoreImage kernels
|
||||
of the System Settings pane icons on the default Metal device and prints checksummed lines per case; see its header.
|
||||
Built like the other guest probes (tools/build-adreno-clear-probe.py): xcrun clang -arch arm64e for macOS 27, ad-hoc
|
||||
signature, architecture and signature checked. Writes OUTPUT/icon-pixels and OUTPUT/build.json (size, SHA-256, CDHash,
|
||||
compiler, command lines, source SHA-256s), and prints the record. OUTPUT must not exist.
|
||||
|
||||
python3 tools/build-icon-pixels.py --output build/icon-pixels/tool-YYYYMMDD
|
||||
|
||||
The CDHash is the trust-cache row the guest needs only if its AMFI refuses an ad-hoc arm64e executable
|
||||
(tools/run-icon-pixels.py checks that first and stops with this hint).
|
||||
"""
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import hashlib
|
||||
import json
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
HARNESS = ROOT / 'gpu/adreno-kext/plugin/harness'
|
||||
SOURCES = [HARNESS / 'icon-pixels.m', HARNESS / 'icon-pixels-census.m', HARNESS / 'icon-pixels-icons.m',
|
||||
HARNESS / 'icon-pixels.h']
|
||||
FRAMEWORKS = ['Foundation', 'Metal', 'CoreImage', 'CoreGraphics', 'IOKit', 'AppKit', 'UniformTypeIdentifiers']
|
||||
|
||||
|
||||
def sha(p):
|
||||
return hashlib.sha256(Path(p).read_bytes()).hexdigest()
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument('--output', type=Path, required=True)
|
||||
a = ap.parse_args()
|
||||
out = a.output.resolve()
|
||||
out.mkdir(parents=True, exist_ok=False)
|
||||
binary = out / 'icon-pixels'
|
||||
sources = {str(p.relative_to(ROOT)): sha(p) for p in SOURCES}
|
||||
commands = []
|
||||
|
||||
def run(name, argv):
|
||||
commands.append(argv)
|
||||
r = subprocess.run(argv, cwd=ROOT, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
(out / f'{name}.log').write_text(r.stdout)
|
||||
if r.returncode:
|
||||
raise SystemExit(f'{name} failed ({r.returncode}): {out / (name + ".log")}')
|
||||
return r.stdout
|
||||
compiler = run('compiler', ['xcrun', 'clang', '--version']).splitlines()[0]
|
||||
argv = ['xcrun', 'clang', '-arch', 'arm64e', '-mmacosx-version-min=27.0', '-fobjc-arc', '-fobjc-arc-exceptions', '-O2',
|
||||
'-Wall', '-Wextra', '-Werror', '-Wno-unused-parameter',
|
||||
*[str(p.relative_to(ROOT)) for p in SOURCES if p.suffix == '.m'], '-o', str(binary)]
|
||||
for f in FRAMEWORKS:
|
||||
argv += ['-framework', f]
|
||||
# -x drops local symbols: a smaller binary is fewer console chunks to push.
|
||||
run('build', argv + ['-lz', '-Wl,-dead_strip', '-Wl,-x'])
|
||||
run('sign', ['codesign', '-f', '-s', '-', str(binary)])
|
||||
run('verify-signature', ['codesign', '--verify', '--strict', '--verbose=2', str(binary)])
|
||||
arch = run('architecture', ['lipo', '-archs', str(binary)]).strip()
|
||||
if arch != 'arm64e':
|
||||
raise SystemExit(f'architecture {arch}, not arm64e')
|
||||
signing = run('signature', ['codesign', '-dvvv', str(binary)])
|
||||
cdhash, = re.findall(r'^CDHash=([0-9a-f]+)$', signing, re.M)
|
||||
version = run('version', [str(binary), 'version']).splitlines()[0]
|
||||
if sources != {k: sha(ROOT / k) for k in sources}:
|
||||
raise SystemExit('a source changed during the build')
|
||||
record = dict(status='ICON_PIXELS_BUILT_NOT_RUN_ON_A16', binary=str(binary), bytes=binary.stat().st_size,
|
||||
sha256=sha(binary), cdhash=cdhash, architecture=arch, compiler=compiler, host_version_line=version,
|
||||
sources_sha256=sources, commands=commands,
|
||||
trust_row=dict(name='icon-pixels', cdhash=cdhash, category=2, flags=0))
|
||||
(out / 'build.json').write_text(json.dumps(record, indent=1) + '\n')
|
||||
print(json.dumps({k: record[k] for k in ('status', 'binary', 'bytes', 'sha256', 'cdhash')}, indent=1))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,312 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""Compare icon-pixels output from the guest's GPU with this Mac's reference, case by case.
|
||||
|
||||
icon-pixels (SnapMetal harness/icon-pixels.m, built by tools/build-icon-pixels.py) prints one checksummed line per case.
|
||||
This reads two such outputs (lines whose CRC does not match, such as console noise or a torn line, are dropped and
|
||||
counted) and prints PASS or FAIL per case with what is off:
|
||||
|
||||
python3 tools/compare-icon-pixels.py REFERENCE.txt GUEST.txt [--tolerance 6] [--census-only] [--cases REGEX]
|
||||
[--json OUT.json]
|
||||
|
||||
synth cases (C lines). A case passes when its status is ok, no destination pixel kept the sentinel, both readbacks and
|
||||
all repeats agree, and every sampled value (9 points, 16 middle-row samples, 64 tile means, per-stripe means) is within
|
||||
--tolerance (8-bit units) of the reference in every channel. A failing case names the first matching explanation:
|
||||
ERROR / MISSING the tool raised or never printed the case
|
||||
UNWRITTEN / PARTIAL destination pixels still hold the sentinel: the dispatch never ran, or ran in part
|
||||
READBACK getBytes and a GPU blit of the same texture differ (CPU cache maintenance or coherency)
|
||||
NONDETERMINISTIC repeats from identical inputs differ (synchronisation)
|
||||
BLACK / TRANSPARENT the kernel read zeros (an unbound or null T#, a wrong T# slot, a wrong sampler)
|
||||
SWAP-RB red and blue exchanged (the T# SWAP field: WZYX vs WXYZ)
|
||||
SRGB-EXTRA / SRGB-MISSING colour channels look decoded twice / not decoded (the T# SRGB bit vs CoreImage's own)
|
||||
INPUT-k multi-input cases: the stripe of input k (Metal texture index from the census) is wrong,
|
||||
missing (transparent) or shows input j's content
|
||||
CHANNEL otherwise: which channels are off, by how much, and where (tiles)
|
||||
Icon cases (I lines): coverage, mean colour and the 8x8 alpha/luminance grids against the reference: EMPTY, BLACK,
|
||||
PARTIAL (alpha cells lost), WRONG-COLOUR, SHAPE.
|
||||
K lines (census) are compared too: a different kernel or texture format set is reported as a note, since the pixel
|
||||
comparison is then of different work. --census-only compares only status, census and diagnostics (for an output of
|
||||
the plug-in device with intercepted commits, whose pixels were never computed).
|
||||
Exit status: 0 every case passes, 1 a case fails, 2 unusable input.
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
import zlib
|
||||
|
||||
SENTINEL = '3ca55ac3'
|
||||
|
||||
|
||||
def parse(path):
|
||||
"""{'V': [...], 'C': {name: fields}, 'K': {name: line}, 'I': {...}, 'D': [...], 'E': [...], 'END': ..., 'noise': n}"""
|
||||
out = dict(V=[], C={}, K={}, I={}, D=[], E=[], W=[], END=None, noise=0, lines=0)
|
||||
for raw in Path(path).read_text(errors='replace').splitlines():
|
||||
raw = raw.strip()
|
||||
if not raw:
|
||||
continue
|
||||
body, sep, crc = raw.rpartition(' *')
|
||||
if not sep or not re.fullmatch(r'[0-9a-f]{8}', crc) or f'{zlib.crc32(body.encode()) & 0xffffffff:08x}' != crc:
|
||||
out['noise'] += 1
|
||||
continue
|
||||
out['lines'] += 1
|
||||
kind = body.split(' ', 1)[0]
|
||||
if kind in ('C', 'I'):
|
||||
words = body.split(' ')
|
||||
fields = dict(name=words[1], size=words[2])
|
||||
for w in words[3:]:
|
||||
k, eq, v = w.partition('=')
|
||||
if eq:
|
||||
fields[k] = v
|
||||
out[kind][words[1]] = fields
|
||||
elif kind == 'K':
|
||||
words = body.split(' ', 2)
|
||||
out['K'][words[1]] = words[2] if len(words) > 2 else ''
|
||||
elif kind == 'END':
|
||||
out['END'] = body
|
||||
elif kind in out:
|
||||
out[kind].append(body)
|
||||
return out
|
||||
|
||||
|
||||
def px(h):
|
||||
return [int(h[i:i + 2], 16) for i in (0, 2, 4, 6)]
|
||||
|
||||
|
||||
def values(f):
|
||||
"""Every sampled RGBA value of a C line, labelled by where it came from."""
|
||||
vals = []
|
||||
for i, h in enumerate(f.get('p', '').split(',')):
|
||||
if len(h) == 8:
|
||||
vals.append((f'point{i}', px(h)))
|
||||
for i, h in enumerate(f.get('g', '').split(',')):
|
||||
if len(h) == 8:
|
||||
vals.append((f'row{i}', px(h)))
|
||||
t = f.get('t', '')
|
||||
for i in range(len(t) // 8):
|
||||
vals.append((f'tile{i // 8},{i % 8}', px(t[8 * i:8 * i + 8])))
|
||||
return vals
|
||||
|
||||
|
||||
def stripes(f):
|
||||
s = f.get('s')
|
||||
if not s:
|
||||
return None, None
|
||||
top, _, band = s.partition('/')
|
||||
return [px(h) for h in top.split(',')], [px(h) for h in band.split(',')]
|
||||
|
||||
|
||||
def to_linear(v):
|
||||
c = v / 255.0
|
||||
return 255.0 * (c / 12.92 if c <= 0.04045 else ((c + 0.055) / 1.055) ** 2.4)
|
||||
|
||||
|
||||
def to_srgb(v):
|
||||
c = v / 255.0
|
||||
return 255.0 * (c * 12.92 if c <= 0.0031308 else 1.055 * c ** (1 / 2.4) - 0.055)
|
||||
|
||||
|
||||
def close(a, b, tol, channels=range(4)):
|
||||
return all(abs(a[c] - b[c]) <= tol for c in channels)
|
||||
|
||||
|
||||
def explain_values(ref, got, tol):
|
||||
"""The explanation for sampled values that differ, from the most specific pattern to the generic one."""
|
||||
pairs = [(label, r, g) for (label, r), (_, g) in zip(ref, got)]
|
||||
bad = [(label, r, g) for label, r, g in pairs if not close(r, g, tol)]
|
||||
if not bad:
|
||||
return None
|
||||
if all(g == [0, 0, 0, 0] for _, _, g in bad):
|
||||
return 'TRANSPARENT: the kernel wrote transparent black where the reference has content (null or wrong T#, sampler)'
|
||||
if all(g[:3] == [0, 0, 0] for _, r, g in bad if max(r[:3]) > 24) and any(max(r[:3]) > 24 for _, r, _ in bad):
|
||||
return 'BLACK: colour channels read zero (unbound or null T#, wrong T# slot, or wrong format)'
|
||||
swapped = [(r, g) for _, r, g in pairs if abs(r[0] - r[2]) > 2 * tol]
|
||||
if swapped and all(abs(g[0] - r[2]) <= tol and abs(g[2] - r[0]) <= tol and abs(g[1] - r[1]) <= tol for r, g in swapped):
|
||||
return 'SWAP-RB: red and blue are exchanged (T# SWAP: WZYX for RGBA, WXYZ for BGRA)'
|
||||
mid = [(r, g) for _, r, g in bad if any(40 <= r[c] <= 215 for c in range(3))]
|
||||
|
||||
def frac(fn):
|
||||
hits = [all(abs(g[c] - fn(r[c])) <= tol + 2 for c in range(3) if 40 <= r[c] <= 215) for r, g in mid]
|
||||
return sum(hits) / len(hits) if hits else 0.0
|
||||
if mid and frac(to_linear) >= 0.8:
|
||||
return 'SRGB-EXTRA: colour channels are darker as if sRGB-decoded once more (T# SRGB bit on top of the kernel\'s decode)'
|
||||
if mid and frac(to_srgb) >= 0.8:
|
||||
return 'SRGB-MISSING: colour channels are lighter as if never sRGB-decoded (T# SRGB bit absent)'
|
||||
names = 'RGBA'
|
||||
worst = [max(abs(r[c] - g[c]) for _, r, g in bad) for c in range(4)]
|
||||
off = [names[c] for c in range(4) if worst[c] > tol]
|
||||
zeroed = [names[c] for c in range(4) if all(g[c] == 0 for _, r, g in bad if r[c] > 24)
|
||||
and any(r[c] > 24 for _, r, _ in bad)]
|
||||
tiles = sorted({label for label, _, _ in bad if label.startswith('tile')})
|
||||
where = ''
|
||||
if tiles:
|
||||
rows = sorted({int(t[4:].split(',')[0]) for t in tiles})
|
||||
cols = sorted({int(t.split(',')[1]) for t in tiles})
|
||||
where = f'; {len(tiles)}/64 tiles off (rows {rows[0]}-{rows[-1]}, cols {cols[0]}-{cols[-1]})'
|
||||
first = bad[0]
|
||||
detail = f'channels {"".join(off)} off (max delta ' + ','.join(str(w) for w in worst) + ')'
|
||||
if zeroed:
|
||||
detail += f'; {"".join(zeroed)} reads 0'
|
||||
return f'CHANNEL: {detail}{where}; first at {first[0]}: reference {"".join(f"{x:02x}" for x in first[1])} guest ' \
|
||||
f'{"".join(f"{x:02x}" for x in first[2])}'
|
||||
|
||||
|
||||
def texture_index_of_inputs(census):
|
||||
"""'1=rgba8s:i5,2=rgba8s:i4,...' -> {5: 1, 4: 2, ...} (input k -> Metal texture index)."""
|
||||
out = {}
|
||||
for m in re.finditer(r'(\d+)=[a-z0-9]+:i(\d+)', census or ''):
|
||||
out.setdefault(int(m.group(2)), int(m.group(1)))
|
||||
return out
|
||||
|
||||
|
||||
def compare_synth(name, r, g, rk, gk, tol, census_only):
|
||||
notes = []
|
||||
if gk is not None and rk is not None and gk != rk:
|
||||
notes.append(f'census differs: reference {rk[:160]} | guest {gk[:160]}')
|
||||
if g is None:
|
||||
return 'MISSING: the case printed no line (the tool stopped or the case was filtered)', notes
|
||||
if g.get('st') != 'ok':
|
||||
return f'ERROR: status {g.get("st")}', notes
|
||||
if census_only:
|
||||
if gk != rk:
|
||||
return 'CENSUS: CoreImage dispatched other kernels or bound other texture formats', notes
|
||||
return None, notes
|
||||
w, _, h = g['size'].partition('x')
|
||||
total = int(w) * int(h) if w.isdigit() and h.isdigit() else 0
|
||||
sent = int(g.get('sent', '0'))
|
||||
if total and sent >= total:
|
||||
return 'UNWRITTEN: no destination pixel was written (dispatch dropped or refused, or the GPU never ran it)', notes
|
||||
hashes = g.get('h', '').split(',')
|
||||
if sent:
|
||||
return f'PARTIAL: {sent} of {total} pixels still hold the sentinel (part of the dispatch never wrote)', notes
|
||||
if g.get('hb') not in ('na', hashes[0]):
|
||||
return 'READBACK: getBytes and the GPU blit of the same texture differ (CPU cache maintenance/coherency)', notes
|
||||
if len(set(hashes)) > 1:
|
||||
notes.append('repeats differ')
|
||||
if r is None:
|
||||
return 'MISSING-REFERENCE: the reference has no such case', notes
|
||||
if r['size'] != g['size']:
|
||||
return f'SIZE: {g["size"]} instead of {r["size"]}', notes
|
||||
rt, rb = stripes(r)
|
||||
gt, gb = stripes(g)
|
||||
if rt and gt:
|
||||
index = texture_index_of_inputs(rk)
|
||||
for k, (want, got) in enumerate(zip(rt, gt)):
|
||||
if close(want, got, tol):
|
||||
continue
|
||||
slot = f' (texture({index[k]}))' if k in index else ''
|
||||
if got[3] <= tol:
|
||||
return f'INPUT-{k}: stripe {k} is transparent: input {k}{slot} was not read', notes
|
||||
other = [j for j, o in enumerate(rt) if j != k and close(o, got, tol)]
|
||||
if other:
|
||||
return f'INPUT-{k}: stripe {k} shows input {other[0]}\'s colour: input {k}{slot} reads another texture', notes
|
||||
return f'INPUT-{k}: stripe {k} is {"".join(f"{x:02x}" for x in got)}, reference ' \
|
||||
f'{"".join(f"{x:02x}" for x in want)} (input {k}{slot})', notes
|
||||
for k, (want, got) in enumerate(zip(rb, gb)):
|
||||
if not close(want, got, tol):
|
||||
return f'BLEND: the half-transparent band under stripe {k} is {"".join(f"{x:02x}" for x in got)}, ' \
|
||||
f'reference {"".join(f"{x:02x}" for x in want)} (blend order or premultiplication)', notes
|
||||
why = explain_values(values(r), values(g), tol)
|
||||
if why:
|
||||
return why, notes
|
||||
if len(set(hashes)) > 1:
|
||||
return 'NONDETERMINISTIC: repeats from identical inputs differ (within tolerance of the reference at the samples)', notes
|
||||
return None, notes
|
||||
|
||||
|
||||
def grid(s):
|
||||
return [int(c, 16) for c in s]
|
||||
|
||||
|
||||
def compare_icon(name, r, g, rk, gk, tol):
|
||||
notes = []
|
||||
if g is None:
|
||||
return 'MISSING: the icon printed no line', notes
|
||||
if g.get('st') != 'ok':
|
||||
return f'ERROR: status {g.get("st")}', notes
|
||||
if r is None:
|
||||
return 'MISSING-REFERENCE: the reference has no such icon', notes
|
||||
if r.get('st') != 'ok':
|
||||
return f'REFERENCE-ERROR: the reference status is {r.get("st")}', notes
|
||||
rc, gc = int(r['cov']), int(g['cov'])
|
||||
if gc == 0 and rc > 0:
|
||||
return 'EMPTY: the icon has no visible pixel', notes
|
||||
rrgb, grgb = px(r['rgb'] + 'ff')[:3], px(g['rgb'] + 'ff')[:3]
|
||||
if max(grgb) < 0x10 and max(rrgb) >= 0x30:
|
||||
return f'BLACK: covered pixels are black (mean {g["rgb"]}, reference {r["rgb"]})', notes
|
||||
ra, ga = grid(r['ag']), grid(g['ag'])
|
||||
lost = [i for i, (a, b) in enumerate(zip(ra, ga)) if a >= 3 and b <= a - 3]
|
||||
if lost:
|
||||
return f'PARTIAL: {len(lost)} of 64 alpha cells lost (first row {lost[0] // 8} col {lost[0] % 8}; ' \
|
||||
f'coverage {gc} vs {rc} per mille)', notes
|
||||
if abs(gc - rc) > 30:
|
||||
return f'SHAPE: coverage {gc} vs reference {rc} per mille', notes
|
||||
if any(abs(a - b) > 2 * tol for a, b in zip(rrgb, grgb)):
|
||||
d = ','.join(f'{b - a:+d}' for a, b in zip(rrgb, grgb))
|
||||
return f'WRONG-COLOUR: mean colour {g["rgb"]} vs reference {r["rgb"]} (R,G,B delta {d})', notes
|
||||
rl, gl = grid(r['lg']), grid(g['lg'])
|
||||
off = [i for i, (a, b) in enumerate(zip(rl, gl)) if abs(a - b) > 1]
|
||||
if off or any(abs(a - b) > 1 for a, b in zip(ra, ga)):
|
||||
return f'SHAPE: {len(off)} luminance cells differ by more than one level', notes
|
||||
return None, notes
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument('reference', type=Path)
|
||||
ap.add_argument('guest', type=Path)
|
||||
ap.add_argument('--tolerance', type=int, default=6, help='per-channel tolerance, 8-bit units (default 6)')
|
||||
ap.add_argument('--census-only', action='store_true')
|
||||
ap.add_argument('--cases', help='compare only the cases whose name matches this regular expression')
|
||||
ap.add_argument('--json', type=Path)
|
||||
a = ap.parse_args(argv)
|
||||
ref, got = parse(a.reference), parse(a.guest)
|
||||
if not ref['lines'] or not ref['V']:
|
||||
print(f'unusable reference {a.reference}: {ref["lines"]} valid lines')
|
||||
return 2
|
||||
if a.cases:
|
||||
keep = re.compile(a.cases)
|
||||
for kind in ('C', 'I'):
|
||||
for side in (ref, got):
|
||||
side[kind] = {n: f for n, f in side[kind].items() if keep.search(n)}
|
||||
rows = []
|
||||
for name in list(ref['C']) + [n for n in got['C'] if n not in ref['C']]:
|
||||
why, notes = compare_synth(name, ref['C'].get(name), got['C'].get(name), ref['K'].get(name), got['K'].get(name),
|
||||
a.tolerance, a.census_only)
|
||||
rows.append(dict(case=name, kind='synth', verdict='FAIL' if why else 'PASS', why=why, notes=notes))
|
||||
for name in list(ref['I']) + [n for n in got['I'] if n not in ref['I']]:
|
||||
why, notes = compare_icon(name, ref['I'].get(name), got['I'].get(name), ref['K'].get(name), got['K'].get(name),
|
||||
a.tolerance)
|
||||
rows.append(dict(case=name, kind='icon', verdict='FAIL' if why else 'PASS', why=why, notes=notes))
|
||||
# The plug-in's own record of work it would not encode (dropped: lenient builds, refused: strict ones).
|
||||
for d in got['D']:
|
||||
m = re.search(r' dropped=(\d+) refused=(\d+)', d)
|
||||
if m and (int(m.group(1)) or int(m.group(2))):
|
||||
rows.append(dict(case='plugin-diagnostics', kind='diag', verdict='FAIL', notes=[],
|
||||
why=f'the plug-in dropped {m.group(1)} and refused {m.group(2)} pieces of work in this process '
|
||||
'(the D lines below name them)'))
|
||||
for row in rows:
|
||||
line = f'{row["verdict"]} {row["case"]}' + (f': {row["why"]}' if row['why'] else '')
|
||||
if row['notes']:
|
||||
line += ' [' + '; '.join(row['notes']) + ']'
|
||||
print(line)
|
||||
fails = [r for r in rows if r['verdict'] == 'FAIL']
|
||||
print(f'guest: {got["V"][0] if got["V"] else "no V line"}')
|
||||
print(f'guest lines {got["lines"]}, noise dropped {got["noise"]}, errors {len(got["E"])}, end {got["END"] or "absent"}')
|
||||
for d in got['D'][:7]:
|
||||
print(f'guest {d[:300]}')
|
||||
for w in got['W']:
|
||||
print(f'guest {w[:300]}')
|
||||
print(f'{"PASS" if not fails else "FAIL"}: {len(rows) - len(fails)} of {len(rows)} cases pass'
|
||||
+ (f'; failing: {", ".join(r["case"] for r in fails[:20])}' if fails else ''))
|
||||
if a.json:
|
||||
a.json.write_text(json.dumps(dict(rows=rows, guest_v=got['V'], guest_d=got['D'], guest_end=got['END'],
|
||||
noise=got['noise']), indent=1) + '\n')
|
||||
if not got['V'] or not rows:
|
||||
return 2
|
||||
return 1 if fails else 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -334,10 +334,19 @@ QCC2072_INPUTS = 'qcc2072-inputs' # under the attempt's directory: the th
|
||||
# Settings-icons set (SnapMetal ADRENO_SETTINGS_ICONS): the mirror-slab rows plus the executable c76a4677 (CoreImage
|
||||
# compute kernels sampling sRGB and grey+alpha images; multi-input kernels behind AdrenoIBComputeSamplers), deployed by
|
||||
# tools/deploy-guest-plugin.py; the mirror-slab set remains for rollback as ADDITIONS_MIRRORSLAB.
|
||||
ADDITIONS = 'build/current-assets/metal-stage-settingsicons-20261024/trust-additions.json'
|
||||
ADDITIONS_SHA = 'cdc784df778f7544fac5b2c774c3b6ee49cc70a15670301f3c4515dfed5562ff'
|
||||
TRUST_PAYLOAD = 'build/current-assets/metal-stage-settingsicons-20261024/trustcache.payload'
|
||||
TRUST_SHA = '247598bc2b4b48c31124e6dde3b83a52b41aa59355f697416cec0e8420926636'
|
||||
# Iconfix set (SnapMetal icon-pixels-next, ADRENO_CS_TABLES): the settings-icons rows plus the executable 11d5ff9a
|
||||
# (CoreImage compute kernels get SP_CS_CONFIG NTEX = NSAMP = their T#/S# count, as Mesa programs them;
|
||||
# ADRENO_CS_TABLES=0 in a process's environment keeps the settings-icons counts), deployed by
|
||||
# tools/deploy-guest-plugin.py, and the icon-pixels probe 25f07e86 that tools/run-icon-pixels.py pushes; the
|
||||
# settings-icons set remains for rollback as ADDITIONS_SETTINGSICONS.
|
||||
ADDITIONS = 'build/current-assets/metal-stage-iconfix-20261024/trust-additions.json'
|
||||
ADDITIONS_SHA = '501a90b6e6fe79b346bcb81c1bddee315ae9fbe3d369ff6b5f44b115aeecc4de'
|
||||
TRUST_PAYLOAD = 'build/current-assets/metal-stage-iconfix-20261024/trustcache.payload'
|
||||
TRUST_SHA = '7857aabcda2814974193c24dbc3245312c3ba02d1de46848b8be60a332571af0'
|
||||
ADDITIONS_SETTINGSICONS = 'build/current-assets/metal-stage-settingsicons-20261024/trust-additions.json'
|
||||
ADDITIONS_SETTINGSICONS_SHA = 'cdc784df778f7544fac5b2c774c3b6ee49cc70a15670301f3c4515dfed5562ff'
|
||||
TRUST_PAYLOAD_SETTINGSICONS = 'build/current-assets/metal-stage-settingsicons-20261024/trustcache.payload'
|
||||
TRUST_SHA_SETTINGSICONS = '247598bc2b4b48c31124e6dde3b83a52b41aa59355f697416cec0e8420926636'
|
||||
ADDITIONS_MIRRORSLAB = 'build/current-assets/metal-stage-mirrorslab-20261021/trust-additions.json'
|
||||
ADDITIONS_MIRRORSLAB_SHA = '4802847aef13e6e46ebc50cd03b1e35ebafe929d5ae46f44f4de6a8d4fb64ae7'
|
||||
TRUST_PAYLOAD_MIRRORSLAB = 'build/current-assets/metal-stage-mirrorslab-20261021/trustcache.payload'
|
||||
|
||||
@@ -113,6 +113,10 @@ MIRRORSLAB = ROOT / 'build/current-assets/metal-stage-mirrorslab-20261021'
|
||||
# inside System Settings panes; multi-input kernels only when the kext publishes AdrenoIBComputeSamplers): only the
|
||||
# executable changes, over the mirror-slab 758535d9; runtime v7 and its CodeResources stay installed.
|
||||
SETTINGSICONS = ROOT / 'build/current-assets/metal-stage-settingsicons-20261024'
|
||||
# Iconfix set (SnapMetal icon-pixels-next: ADRENO_SETTINGS_ICONS plus ADRENO_CS_TABLES, built with ADRENO_LENIENT=1
|
||||
# ADRENO_PIPELINE=1 and runtime v7: CoreImage's compute kernels get Mesa's SP_CS_CONFIG texture/sampler/UAV counts):
|
||||
# only the executable changes, over the settings-icons 378ff525; runtime v7 and its CodeResources stay installed.
|
||||
ICONFIX = ROOT / 'build/current-assets/metal-stage-iconfix-20261024'
|
||||
PREVIOUS = ASSETS
|
||||
ORIGINAL = ROOT / 'build/current-assets/metal-stage/AdrenoMetal.bundle/Contents'
|
||||
CONTENTS = 'System/Volumes/Data/Library/GPUBundles/AdrenoMetal.bundle/Contents'
|
||||
@@ -122,9 +126,9 @@ FILES = [ # installed in this order: the executable last
|
||||
patch=WSABORT / 'libAdrenoCompiler-059fcc6e.bsdiff', cdhash='ab4ccbd4806696e30cbe8ca6f8ff271e89cea7cd'),
|
||||
dict(name='CodeResources', path=f'{CONTENTS}/_CodeSignature/CodeResources',
|
||||
base=COMPILESPEED / 'CodeResources', new=WSABORT / 'CodeResources', patch=None, cdhash=None),
|
||||
dict(name='AdrenoMetal', path=f'{CONTENTS}/MacOS/AdrenoMetal', base=MIRRORSLAB / 'AdrenoMetal',
|
||||
new=SETTINGSICONS / 'AdrenoMetal', patch=SETTINGSICONS / 'AdrenoMetal-758535d9.bsdiff',
|
||||
cdhash='c76a4677c74623d78f51f578cc4f2978ea73ff26'),
|
||||
dict(name='AdrenoMetal', path=f'{CONTENTS}/MacOS/AdrenoMetal', base=SETTINGSICONS / 'AdrenoMetal',
|
||||
new=ICONFIX / 'AdrenoMetal', patch=ICONFIX / 'AdrenoMetal-378ff525.bsdiff',
|
||||
cdhash='11d5ff9ae3c796ef3ac5c9fec5853e0f8deaec7b'),
|
||||
]
|
||||
PLUGIN, BASE, NEW, NEW_CDHASH = FILES[-1]['path'], FILES[-1]['base'], FILES[-1]['new'], FILES[-1]['cdhash']
|
||||
WORK = 'System/Volumes/Data/private/var/tmp/snapintosh-plugin'
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
V icon-pixels 1 mode=host-caps device=Apple_M3_Max os=26A428 pid=2871 repeat=2 cs=- plugin=local:AdrenoMetal.bundle@378ff525b00426d1 *57bb7186
|
||||
C tex-rgba8s-lin 128x128 st=ok in=rgba8s h=b42791ae5393cd61,b42791ae5393cd61 hb=b42791ae5393cd61 sent=0 p=00000dff,f80086ff,00f886ff,f8f80dff,36363bff,0d0d3bff,850d3bff,0d853bff,85853bff g=01362bff,02362bff,053668ff,0a3668ff,10362bff,18362bff,233668ff,2f3668ff,3e362bff,4f362bff,633668ff,793668ff,92362bff,ad362bff,cc3668ff,ed3668ff t=010111ff070180ff140113ff280180ff450113ff6c0180ff9e0113ffda0182ff010780ff070714ff14077fff280714ff45077fff6c0714ff9e077fffda0713ff011413ff07147fff141414ff28147fff451414ff6c147fff9e1414ffda1480ff012880ff072814ff14287fff282814ff45287fff6c2814ff9e287fffda2813ff014513ff07457fff144514ff28457fff454514ff6c457fff9e4514ffda4580ff016c80ff076c14ff146c7fff286c14ff456c7fff6c6c14ff9e6c7fffda6c13ff019e13ff079e7fff149e14ff289e7fff459e14ff6c9e7fff9e9e14ffda9e80ff01da82ff07da13ff14da80ff28da13ff45da80ff6cda13ff9eda80ffdada11ff ms=120 *c2f928ab
|
||||
K tex-rgba8s-lin n=2 d=0 ci_affine[0=bgra8:o,1=rgba8s:i0,s0]*2 *b29b244c
|
||||
C tex-rgba8s-near 128x128 st=ok in=rgba8s h=18fd86522e0c0a7d,18fd86522e0c0a7d hb=18fd86522e0c0a7d sent=0 p=00000dff,f80086ff,00f886ff,f8f80dff,37370dff,0d0d0dff,860d0dff,0d860dff,86860dff g=01370dff,02370dff,053786ff,0a3786ff,11370dff,19370dff,233786ff,303786ff,3f370dff,50370dff,643786ff,7a3786ff,93370dff,af370dff,ce3786ff,ef3786ff t=01010dff070186ff14010dff280186ff46010dff6c0186ff9e010dffdb0186ff010786ff07070dff140786ff28070dff460786ff6c070dff9e0786ffdb070dff01140dff071486ff14140dff281486ff46140dff6c1486ff9e140dffdb1486ff012886ff07280dff142886ff28280dff462886ff6c280dff9e2886ffdb280dff01460dff074686ff14460dff284686ff46460dff6c4686ff9e460dffdb4686ff016c86ff076c0dff146c86ff286c0dff466c86ff6c6c0dff9e6c86ffdb6c0dff019e0dff079e86ff149e0dff289e86ff469e0dff6c9e86ff9e9e0dffdb9e86ff01db86ff07db0dff14db86ff28db0dff46db86ff6cdb0dff9edb86ffdbdb0dff ms=3 *c0b0203f
|
||||
K tex-rgba8s-near n=2 d=0 ci_affine_nearest[0=bgra8:o,1=rgba8s:i0,s0]*2 *175e24da
|
||||
C tex-bgra8s-lin 128x128 st=ok in=bgra8s h=b42791ae5393cd61,b42791ae5393cd61 hb=b42791ae5393cd61 sent=0 p=00000dff,f80086ff,00f886ff,f8f80dff,36363bff,0d0d3bff,850d3bff,0d853bff,85853bff g=01362bff,02362bff,053668ff,0a3668ff,10362bff,18362bff,233668ff,2f3668ff,3e362bff,4f362bff,633668ff,793668ff,92362bff,ad362bff,cc3668ff,ed3668ff t=010111ff070180ff140113ff280180ff450113ff6c0180ff9e0113ffda0182ff010780ff070714ff14077fff280714ff45077fff6c0714ff9e077fffda0713ff011413ff07147fff141414ff28147fff451414ff6c147fff9e1414ffda1480ff012880ff072814ff14287fff282814ff45287fff6c2814ff9e287fffda2813ff014513ff07457fff144514ff28457fff454514ff6c457fff9e4514ffda4580ff016c80ff076c14ff146c7fff286c14ff456c7fff6c6c14ff9e6c7fffda6c13ff019e13ff079e7fff149e14ff289e7fff459e14ff6c9e7fff9e9e14ffda9e80ff01da82ff07da13ff14da80ff28da13ff45da80ff6cda13ff9eda80ffdada11ff ms=1 *14caf135
|
||||
K tex-bgra8s-lin n=2 d=0 ci_affine[0=bgra8:o,1=bgra8s:i0,s0]*2 *5a84bd88
|
||||
C tex-bgra8s-near 128x128 st=ok in=bgra8s h=18fd86522e0c0a7d,18fd86522e0c0a7d hb=18fd86522e0c0a7d sent=0 p=00000dff,f80086ff,00f886ff,f8f80dff,37370dff,0d0d0dff,860d0dff,0d860dff,86860dff g=01370dff,02370dff,053786ff,0a3786ff,11370dff,19370dff,233786ff,303786ff,3f370dff,50370dff,643786ff,7a3786ff,93370dff,af370dff,ce3786ff,ef3786ff t=01010dff070186ff14010dff280186ff46010dff6c0186ff9e010dffdb0186ff010786ff07070dff140786ff28070dff460786ff6c070dff9e0786ffdb070dff01140dff071486ff14140dff281486ff46140dff6c1486ff9e140dffdb1486ff012886ff07280dff142886ff28280dff462886ff6c280dff9e2886ffdb280dff01460dff074686ff14460dff284686ff46460dff6c4686ff9e460dffdb4686ff016c86ff076c0dff146c86ff286c0dff466c86ff6c6c0dff9e6c86ffdb6c0dff019e0dff079e86ff149e0dff289e86ff469e0dff6c9e86ff9e9e0dffdb9e86ff01db86ff07db0dff14db86ff28db0dff46db86ff6cdb0dff9edb86ffdbdb0dff ms=2 *7880f28f
|
||||
K tex-bgra8s-near n=2 d=0 ci_affine_nearest[0=bgra8:o,1=bgra8s:i0,s0]*2 *8fc2a065
|
||||
C tex-rgba8-lin 128x128 st=ok in=rgba8 h=c89ba91151c892b9,c89ba91151c892b9 hb=c89ba91151c892b9 sent=0 p=000040ff,fc00c0ff,00fcc0ff,fcfc40ff,7f7f70ff,3f3f70ff,bf3f70ff,3fbf70ff,bfbf70ff g=077f60ff,177f60ff,277fa0ff,377fa0ff,477f60ff,577f60ff,677fa0ff,777fa0ff,877f60ff,977f60ff,a77fa0ff,b77fa0ff,c77f60ff,d77f60ff,e77fa0ff,f77fa0ff t=0e0e44ff2e0ebaff4e0e46ff6e0ebaff8e0e46ffae0ebaffce0e46ffee0ebcff0e2ebaff2e2e48ff4e2eb8ff6e2e48ff8e2eb8ffae2e48ffce2eb8ffee2e46ff0e4e46ff2e4eb8ff4e4e48ff6e4eb8ff8e4e48ffae4eb8ffce4e48ffee4ebaff0e6ebaff2e6e48ff4e6eb8ff6e6e48ff8e6eb8ffae6e48ffce6eb8ffee6e46ff0e8e46ff2e8eb8ff4e8e48ff6e8eb8ff8e8e48ffae8eb8ffce8e48ffee8ebaff0eaebaff2eae48ff4eaeb8ff6eae48ff8eaeb8ffaeae48ffceaeb8ffeeae46ff0ece46ff2eceb8ff4ece48ff6eceb8ff8ece48ffaeceb8ffcece48ffeecebaff0eeebcff2eee46ff4eeebaff6eee46ff8eeebaffaeee46ffceeebaffeeee44ff ms=2 *0db0258a
|
||||
K tex-rgba8-lin n=2 d=0 ci_affine[0=bgra8:o,1=rgba8:i0,s0]*2 *b24b21b5
|
||||
C tex-rgba8-near 128x128 st=ok in=rgba8 h=93f58ae72abcc325,93f58ae72abcc325 hb=93f58ae72abcc325 sent=0 p=000040ff,fc00c0ff,00fcc0ff,fcfc40ff,808040ff,404040ff,c04040ff,40c040ff,c0c040ff g=088040ff,188040ff,2880c0ff,3880c0ff,488040ff,588040ff,6880c0ff,7880c0ff,888040ff,988040ff,a880c0ff,b880c0ff,c88040ff,d88040ff,e880c0ff,f880c0ff t=0e0e40ff2e0ec0ff4e0e40ff6e0ec0ff8e0e40ffae0ec0ffce0e40ffee0ec0ff0e2ec0ff2e2e40ff4e2ec0ff6e2e40ff8e2ec0ffae2e40ffce2ec0ffee2e40ff0e4e40ff2e4ec0ff4e4e40ff6e4ec0ff8e4e40ffae4ec0ffce4e40ffee4ec0ff0e6ec0ff2e6e40ff4e6ec0ff6e6e40ff8e6ec0ffae6e40ffce6ec0ffee6e40ff0e8e40ff2e8ec0ff4e8e40ff6e8ec0ff8e8e40ffae8ec0ffce8e40ffee8ec0ff0eaec0ff2eae40ff4eaec0ff6eae40ff8eaec0ffaeae40ffceaec0ffeeae40ff0ece40ff2ecec0ff4ece40ff6ecec0ff8ece40ffaecec0ffcece40ffeecec0ff0eeec0ff2eee40ff4eeec0ff6eee40ff8eeec0ffaeee40ffceeec0ffeeee40ff ms=2 *8c9b9633
|
||||
K tex-rgba8-near n=2 d=0 ci_affine_nearest[0=bgra8:o,1=rgba8:i0,s0]*2 *1b963012
|
||||
C tex-bgra8-lin 128x128 st=ok in=bgra8 h=c89ba91151c892b9,c89ba91151c892b9 hb=c89ba91151c892b9 sent=0 p=000040ff,fc00c0ff,00fcc0ff,fcfc40ff,7f7f70ff,3f3f70ff,bf3f70ff,3fbf70ff,bfbf70ff g=077f60ff,177f60ff,277fa0ff,377fa0ff,477f60ff,577f60ff,677fa0ff,777fa0ff,877f60ff,977f60ff,a77fa0ff,b77fa0ff,c77f60ff,d77f60ff,e77fa0ff,f77fa0ff t=0e0e44ff2e0ebaff4e0e46ff6e0ebaff8e0e46ffae0ebaffce0e46ffee0ebcff0e2ebaff2e2e48ff4e2eb8ff6e2e48ff8e2eb8ffae2e48ffce2eb8ffee2e46ff0e4e46ff2e4eb8ff4e4e48ff6e4eb8ff8e4e48ffae4eb8ffce4e48ffee4ebaff0e6ebaff2e6e48ff4e6eb8ff6e6e48ff8e6eb8ffae6e48ffce6eb8ffee6e46ff0e8e46ff2e8eb8ff4e8e48ff6e8eb8ff8e8e48ffae8eb8ffce8e48ffee8ebaff0eaebaff2eae48ff4eaeb8ff6eae48ff8eaeb8ffaeae48ffceaeb8ffeeae46ff0ece46ff2eceb8ff4ece48ff6eceb8ff8ece48ffaeceb8ffcece48ffeecebaff0eeebcff2eee46ff4eeebaff6eee46ff8eeebaffaeee46ffceeebaffeeee44ff ms=2 *25d45f8a
|
||||
K tex-bgra8-lin n=2 d=0 ci_affine[0=bgra8:o,1=bgra8:i0,s0]*2 *e8c1b4d0
|
||||
C tex-bgra8-near 128x128 st=ok in=bgra8 h=93f58ae72abcc325,93f58ae72abcc325 hb=93f58ae72abcc325 sent=0 p=000040ff,fc00c0ff,00fcc0ff,fcfc40ff,808040ff,404040ff,c04040ff,40c040ff,c0c040ff g=088040ff,188040ff,2880c0ff,3880c0ff,488040ff,588040ff,6880c0ff,7880c0ff,888040ff,988040ff,a880c0ff,b880c0ff,c88040ff,d88040ff,e880c0ff,f880c0ff t=0e0e40ff2e0ec0ff4e0e40ff6e0ec0ff8e0e40ffae0ec0ffce0e40ffee0ec0ff0e2ec0ff2e2e40ff4e2ec0ff6e2e40ff8e2ec0ffae2e40ffce2ec0ffee2e40ff0e4e40ff2e4ec0ff4e4e40ff6e4ec0ff8e4e40ffae4ec0ffce4e40ffee4ec0ff0e6ec0ff2e6e40ff4e6ec0ff6e6e40ff8e6ec0ffae6e40ffce6ec0ffee6e40ff0e8e40ff2e8ec0ff4e8e40ff6e8ec0ff8e8e40ffae8ec0ffce8e40ffee8ec0ff0eaec0ff2eae40ff4eaec0ff6eae40ff8eaec0ffaeae40ffceaec0ffeeae40ff0ece40ff2ecec0ff4ece40ff6ecec0ff8ece40ffaecec0ffcece40ffeecec0ff0eeec0ff2eee40ff4eeec0ff6eee40ff8eeec0ffaeee40ffceeec0ffeeee40ff ms=2 *13ecd36a
|
||||
K tex-bgra8-near n=2 d=0 ci_affine_nearest[0=bgra8:o,1=bgra8:i0,s0]*2 *cb4d9571
|
||||
C tex-rg8-lin 128x128 st=ok in=rg8 h=b31b3210953ea559,b31b3210953ea559 hb=b31b3210953ea559 sent=0 p=000000ff,fc0000ff,00fc00ff,fcfc00ff,7f7f00ff,3f3f00ff,bf3f00ff,3fbf00ff,bfbf00ff g=077f00ff,177f00ff,277f00ff,377f00ff,477f00ff,577f00ff,677f00ff,777f00ff,877f00ff,977f00ff,a77f00ff,b77f00ff,c77f00ff,d77f00ff,e77f00ff,f77f00ff t=0e0e00ff2e0e00ff4e0e00ff6e0e00ff8e0e00ffae0e00ffce0e00ffee0e00ff0e2e00ff2e2e00ff4e2e00ff6e2e00ff8e2e00ffae2e00ffce2e00ffee2e00ff0e4e00ff2e4e00ff4e4e00ff6e4e00ff8e4e00ffae4e00ffce4e00ffee4e00ff0e6e00ff2e6e00ff4e6e00ff6e6e00ff8e6e00ffae6e00ffce6e00ffee6e00ff0e8e00ff2e8e00ff4e8e00ff6e8e00ff8e8e00ffae8e00ffce8e00ffee8e00ff0eae00ff2eae00ff4eae00ff6eae00ff8eae00ffaeae00ffceae00ffeeae00ff0ece00ff2ece00ff4ece00ff6ece00ff8ece00ffaece00ffcece00ffeece00ff0eee00ff2eee00ff4eee00ff6eee00ff8eee00ffaeee00ffceee00ffeeee00ff ms=2 *21f1215a
|
||||
K tex-rg8-lin n=2 d=0 ci_affine[0=bgra8:o,1=rg8:i0,s0]*2 *715936a4
|
||||
C tex-rg8-near 128x128 st=ok in=rg8 h=ea80530e6ae1d325,ea80530e6ae1d325 hb=ea80530e6ae1d325 sent=0 p=000000ff,fc0000ff,00fc00ff,fcfc00ff,808000ff,404000ff,c04000ff,40c000ff,c0c000ff g=088000ff,188000ff,288000ff,388000ff,488000ff,588000ff,688000ff,788000ff,888000ff,988000ff,a88000ff,b88000ff,c88000ff,d88000ff,e88000ff,f88000ff t=0e0e00ff2e0e00ff4e0e00ff6e0e00ff8e0e00ffae0e00ffce0e00ffee0e00ff0e2e00ff2e2e00ff4e2e00ff6e2e00ff8e2e00ffae2e00ffce2e00ffee2e00ff0e4e00ff2e4e00ff4e4e00ff6e4e00ff8e4e00ffae4e00ffce4e00ffee4e00ff0e6e00ff2e6e00ff4e6e00ff6e6e00ff8e6e00ffae6e00ffce6e00ffee6e00ff0e8e00ff2e8e00ff4e8e00ff6e8e00ff8e8e00ffae8e00ffce8e00ffee8e00ff0eae00ff2eae00ff4eae00ff6eae00ff8eae00ffaeae00ffceae00ffeeae00ff0ece00ff2ece00ff4ece00ff6ece00ff8ece00ffaece00ffcece00ffeece00ff0eee00ff2eee00ff4eee00ff6eee00ff8eee00ffaeee00ffceee00ffeeee00ff ms=2 *0cde3fc2
|
||||
K tex-rg8-near n=2 d=0 ci_affine_nearest[0=bgra8:o,1=rg8:i0,s0]*2 *4102bcce
|
||||
C tex-rg16f-lin 128x128 st=ok in=rg16f h=8d61eb2aececb90d,8d61eb2aececb90d hb=8d61eb2aececb90d sent=0 p=000000ff,fe0000ff,00fe00ff,fefe00ff,bbbb00ff,888800ff,e08800ff,88e000ff,e0e000ff g=2ebb00ff,55bb00ff,6dbb00ff,80bb00ff,90bb00ff,9ebb00ff,aabb00ff,b6bb00ff,c0bb00ff,cabb00ff,d3bb00ff,dcbb00ff,e5bb00ff,edbb00ff,f4bb00ff,fbbb00ff t=3c3c00ff753c00ff963c00ffaf3c00ffc53c00ffd73c00ffe83c00fff73c00ff3c7500ff757500ff967500ffaf7500ffc57500ffd77500ffe87500fff77500ff3c9600ff759600ff969600ffaf9600ffc59600ffd79600ffe89600fff79600ff3caf00ff75af00ff96af00ffafaf00ffc5af00ffd7af00ffe8af00fff7af00ff3cc500ff75c500ff96c500ffafc500ffc5c500ffd7c500ffe8c500fff7c500ff3cd700ff75d700ff96d700ffafd700ffc5d700ffd7d700ffe8d700fff7d700ff3ce800ff75e800ff96e800ffafe800ffc5e800ffd7e800ffe8e800fff7e800ff3cf700ff75f700ff96f700ffaff700ffc5f700ffd7f700ffe8f700fff7f700ff ms=3 *a0d34c03
|
||||
K tex-rg16f-lin n=2 d=0 ci_affine_linear_to_srgb[0=bgra8:o,1=rg16f:i0,s0]*2 *d8fd156b
|
||||
C tex-rg16f-near 128x128 st=ok in=rg16f h=98714485f6035aed,98714485f6035aed hb=98714485f6035aed sent=0 p=000000ff,fe0000ff,00fe00ff,fefe00ff,bcbc00ff,898900ff,e18900ff,89e100ff,e1e100ff g=32bc00ff,56bc00ff,6ebc00ff,81bc00ff,91bc00ff,9fbc00ff,abbc00ff,b7bc00ff,c1bc00ff,cbbc00ff,d4bc00ff,ddbc00ff,e5bc00ff,edbc00ff,f5bc00ff,fcbc00ff t=3b3b00ff753b00ff963b00ffaf3b00ffc53b00ffd83b00ffe83b00fff73b00ff3b7500ff757500ff967500ffaf7500ffc57500ffd87500ffe87500fff77500ff3b9600ff759600ff969600ffaf9600ffc59600ffd89600ffe89600fff79600ff3baf00ff75af00ff96af00ffafaf00ffc5af00ffd8af00ffe8af00fff7af00ff3bc500ff75c500ff96c500ffafc500ffc5c500ffd8c500ffe8c500fff7c500ff3bd800ff75d800ff96d800ffafd800ffc5d800ffd8d800ffe8d800fff7d800ff3be800ff75e800ff96e800ffafe800ffc5e800ffd8e800ffe8e800fff7e800ff3bf700ff75f700ff96f700ffaff700ffc5f700ffd8f700ffe8f700fff7f700ff ms=3 *22f3a87f
|
||||
K tex-rg16f-near n=2 d=0 ci_affine_nearest_linear_to_srgb[0=bgra8:o,1=rg16f:i0,s0]*2 *99d83cef
|
||||
C tex-r8-lin 128x128 st=ok in=r8 h=d830594d4eb56325,d830594d4eb56325 hb=d830594d4eb56325 sent=0 p=000000ff,fc0000ff,000000ff,fc0000ff,7f0000ff,3f0000ff,bf0000ff,3f0000ff,bf0000ff g=070000ff,170000ff,270000ff,370000ff,470000ff,570000ff,670000ff,770000ff,870000ff,970000ff,a70000ff,b70000ff,c70000ff,d70000ff,e70000ff,f70000ff t=0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff ms=2 *9ad3db8f
|
||||
K tex-r8-lin n=2 d=0 ci_affine[0=bgra8:o,1=r8:i0,s0]*2 *62fafdfa
|
||||
C tex-r8-near 128x128 st=ok in=r8 h=a3104ca9de072325,a3104ca9de072325 hb=a3104ca9de072325 sent=0 p=000000ff,fc0000ff,000000ff,fc0000ff,800000ff,400000ff,c00000ff,400000ff,c00000ff g=080000ff,180000ff,280000ff,380000ff,480000ff,580000ff,680000ff,780000ff,880000ff,980000ff,a80000ff,b80000ff,c80000ff,d80000ff,e80000ff,f80000ff t=0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff0e0000ff2e0000ff4e0000ff6e0000ff8e0000ffae0000ffce0000ffee0000ff ms=2 *39ff57e3
|
||||
K tex-r8-near n=2 d=0 ci_affine_nearest[0=bgra8:o,1=r8:i0,s0]*2 *2cd96ce3
|
||||
C tex-r16f-lin 128x128 st=ok in=r16f h=2202a2ffe05b7d25,2202a2ffe05b7d25 hb=2202a2ffe05b7d25 sent=0 p=000000ff,fe0000ff,000000ff,fe0000ff,bb0000ff,880000ff,e00000ff,880000ff,e00000ff g=2e0000ff,550000ff,6d0000ff,800000ff,900000ff,9e0000ff,aa0000ff,b60000ff,c00000ff,ca0000ff,d30000ff,dc0000ff,e50000ff,ed0000ff,f40000ff,fb0000ff t=3c0000ff750000ff960000ffaf0000ffc50000ffd70000ffe80000fff70000ff3c0000ff750000ff960000ffaf0000ffc50000ffd70000ffe80000fff70000ff3c0000ff750000ff960000ffaf0000ffc50000ffd70000ffe80000fff70000ff3c0000ff750000ff960000ffaf0000ffc50000ffd70000ffe80000fff70000ff3c0000ff750000ff960000ffaf0000ffc50000ffd70000ffe80000fff70000ff3c0000ff750000ff960000ffaf0000ffc50000ffd70000ffe80000fff70000ff3c0000ff750000ff960000ffaf0000ffc50000ffd70000ffe80000fff70000ff3c0000ff750000ff960000ffaf0000ffc50000ffd70000ffe80000fff70000ff ms=2 *3a098d33
|
||||
K tex-r16f-lin n=2 d=0 ci_affine_linear_to_srgb[0=bgra8:o,1=r16f:i0,s0]*2 *ae33193c
|
||||
C tex-r16f-near 128x128 st=ok in=r16f h=a49e6124c80b5b25,a49e6124c80b5b25 hb=a49e6124c80b5b25 sent=0 p=000000ff,fe0000ff,000000ff,fe0000ff,bc0000ff,890000ff,e10000ff,890000ff,e10000ff g=320000ff,560000ff,6e0000ff,810000ff,910000ff,9f0000ff,ab0000ff,b70000ff,c10000ff,cb0000ff,d40000ff,dd0000ff,e50000ff,ed0000ff,f50000ff,fc0000ff t=3b0000ff750000ff960000ffaf0000ffc50000ffd80000ffe80000fff70000ff3b0000ff750000ff960000ffaf0000ffc50000ffd80000ffe80000fff70000ff3b0000ff750000ff960000ffaf0000ffc50000ffd80000ffe80000fff70000ff3b0000ff750000ff960000ffaf0000ffc50000ffd80000ffe80000fff70000ff3b0000ff750000ff960000ffaf0000ffc50000ffd80000ffe80000fff70000ff3b0000ff750000ff960000ffaf0000ffc50000ffd80000ffe80000fff70000ff3b0000ff750000ff960000ffaf0000ffc50000ffd80000ffe80000fff70000ff3b0000ff750000ff960000ffaf0000ffc50000ffd80000ffe80000fff70000ff ms=2 *4ca8686b
|
||||
K tex-r16f-near n=2 d=0 ci_affine_nearest_linear_to_srgb[0=bgra8:o,1=r16f:i0,s0]*2 *7df56571
|
||||
C tex-a8-lin 128x128 st=ok in=a8 h=01928e67ca062325,01928e67ca062325 hb=01928e67ca062325 sent=0 p=00000000,000000fc,00000000,000000fc,0000007f,0000003f,000000bf,0000003f,000000bf g=00000007,00000017,00000027,00000037,00000047,00000057,00000067,00000077,00000087,00000097,000000a7,000000b7,000000c7,000000d7,000000e7,000000f7 t=0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee ms=2 *5d340e59
|
||||
K tex-a8-lin n=2 d=0 ci_affine[0=bgra8:o,1=a8:i0,s0]*2 *7ec0ab16
|
||||
C tex-a8-near 128x128 st=ok in=a8 h=e82ccbb286bc2325,e82ccbb286bc2325 hb=e82ccbb286bc2325 sent=0 p=00000000,000000fc,00000000,000000fc,00000080,00000040,000000c0,00000040,000000c0 g=00000008,00000018,00000028,00000038,00000048,00000058,00000068,00000078,00000088,00000098,000000a8,000000b8,000000c8,000000d8,000000e8,000000f8 t=0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee0000000e0000002e0000004e0000006e0000008e000000ae000000ce000000ee ms=2 *49a477d7
|
||||
K tex-a8-near n=2 d=0 ci_affine_nearest[0=bgra8:o,1=a8:i0,s0]*2 *63ee9884
|
||||
C tex-rgba16f-lin 128x128 st=ok in=rgba16f h=bb9f9a7d9949feed,bb9f9a7d9949feed hb=bb9f9a7d9949feed sent=0 p=000089ff,fe00e1ff,00fee1ff,fefe89ff,bbbbb1ff,8888b1ff,e088b1ff,88e0b1ff,e0e0b1ff g=2ebba5ff,55bba5ff,6dbbd0ff,80bbd0ff,90bba5ff,9ebba5ff,aabbd0ff,b6bbd0ff,c0bba5ff,cabba5ff,d3bbd0ff,dcbbd0ff,e5bba5ff,edbba5ff,f4bbd0ff,fbbbd0ff t=3c3c8cff753cdeff963c8effaf3cdeffc53c8effd73cdeffe83c8efff73cdfff3c75deff757590ff9675ddffaf7590ffc575ddffd77590ffe875ddfff7758eff3c968eff7596ddff969690ffaf96ddffc59690ffd796ddffe89690fff796deff3cafdeff75af90ff96afddffafaf90ffc5afddffd7af90ffe8afddfff7af8eff3cc58eff75c5ddff96c590ffafc5ddffc5c590ffd7c5ddffe8c590fff7c5deff3cd7deff75d790ff96d7ddffafd790ffc5d7ddffd7d790ffe8d7ddfff7d78eff3ce88eff75e8ddff96e890ffafe8ddffc5e890ffd7e8ddffe8e890fff7e8deff3cf7dfff75f78eff96f7deffaff78effc5f7deffd7f78effe8f7defff7f78cff ms=2 *885422d6
|
||||
K tex-rgba16f-lin n=2 d=0 ci_affine_premul_linear_to_srgb_unpremul[0=bgra8:o,1=rgba16f:i0,s0]*2 *a3befd7f
|
||||
C tex-rgba16f-near 128x128 st=ok in=rgba16f h=04809933e3a7288d,04809933e3a7288d hb=04809933e3a7288d sent=0 p=000089ff,fe00e1ff,00fee1ff,fefe89ff,bcbc89ff,898989ff,e18989ff,89e189ff,e1e189ff g=32bc89ff,56bc89ff,6ebce1ff,81bce1ff,91bc89ff,9fbc89ff,abbce1ff,b7bce1ff,c1bc89ff,cbbc89ff,d4bce1ff,ddbce1ff,e5bc89ff,edbc89ff,f5bce1ff,fcbce1ff t=3b3b89ff753be1ff963b89ffaf3be1ffc53b89ffd83be1ffe83b89fff73be1ff3b75e1ff757589ff9675e1ffaf7589ffc575e1ffd87589ffe875e1fff77589ff3b9689ff7596e1ff969689ffaf96e1ffc59689ffd896e1ffe89689fff796e1ff3bafe1ff75af89ff96afe1ffafaf89ffc5afe1ffd8af89ffe8afe1fff7af89ff3bc589ff75c5e1ff96c589ffafc5e1ffc5c589ffd8c5e1ffe8c589fff7c5e1ff3bd8e1ff75d889ff96d8e1ffafd889ffc5d8e1ffd8d889ffe8d8e1fff7d889ff3be889ff75e8e1ff96e889ffafe8e1ffc5e889ffd8e8e1ffe8e889fff7e8e1ff3bf7e1ff75f789ff96f7e1ffaff789ffc5f7e1ffd8f789ffe8f7e1fff7f789ff ms=2 *d2fae3b9
|
||||
K tex-rgba16f-near n=2 d=0 ci_affine_nearest_premul_linear_to_srgb_[0=bgra8:o,1=rgba16f:i0,s0]*2 *5e72601b
|
||||
C tex-rgba16u-lin 128x128 st=ok in=rgba16u h=c89ba91151c892b9,c89ba91151c892b9 hb=c89ba91151c892b9 sent=0 p=000040ff,fc00c0ff,00fcc0ff,fcfc40ff,7f7f70ff,3f3f70ff,bf3f70ff,3fbf70ff,bfbf70ff g=077f60ff,177f60ff,277fa0ff,377fa0ff,477f60ff,577f60ff,677fa0ff,777fa0ff,877f60ff,977f60ff,a77fa0ff,b77fa0ff,c77f60ff,d77f60ff,e77fa0ff,f77fa0ff t=0e0e44ff2e0ebaff4e0e46ff6e0ebaff8e0e46ffae0ebaffce0e46ffee0ebcff0e2ebaff2e2e48ff4e2eb8ff6e2e48ff8e2eb8ffae2e48ffce2eb8ffee2e46ff0e4e46ff2e4eb8ff4e4e48ff6e4eb8ff8e4e48ffae4eb8ffce4e48ffee4ebaff0e6ebaff2e6e48ff4e6eb8ff6e6e48ff8e6eb8ffae6e48ffce6eb8ffee6e46ff0e8e46ff2e8eb8ff4e8e48ff6e8eb8ff8e8e48ffae8eb8ffce8e48ffee8ebaff0eaebaff2eae48ff4eaeb8ff6eae48ff8eaeb8ffaeae48ffceaeb8ffeeae46ff0ece46ff2eceb8ff4ece48ff6eceb8ff8ece48ffaeceb8ffcece48ffeecebaff0eeebcff2eee46ff4eeebaff6eee46ff8eeebaffaeee46ffceeebaffeeee44ff ms=2 *4d970514
|
||||
K tex-rgba16u-lin n=2 d=0 ci_affine[0=bgra8:o,1=rgba16u:i0,s0]*2 *7f98cc94
|
||||
C tex-rgba16u-near 128x128 st=ok in=rgba16u h=93f58ae72abcc325,93f58ae72abcc325 hb=93f58ae72abcc325 sent=0 p=000040ff,fc00c0ff,00fcc0ff,fcfc40ff,808040ff,404040ff,c04040ff,40c040ff,c0c040ff g=088040ff,188040ff,2880c0ff,3880c0ff,488040ff,588040ff,6880c0ff,7880c0ff,888040ff,988040ff,a880c0ff,b880c0ff,c88040ff,d88040ff,e880c0ff,f880c0ff t=0e0e40ff2e0ec0ff4e0e40ff6e0ec0ff8e0e40ffae0ec0ffce0e40ffee0ec0ff0e2ec0ff2e2e40ff4e2ec0ff6e2e40ff8e2ec0ffae2e40ffce2ec0ffee2e40ff0e4e40ff2e4ec0ff4e4e40ff6e4ec0ff8e4e40ffae4ec0ffce4e40ffee4ec0ff0e6ec0ff2e6e40ff4e6ec0ff6e6e40ff8e6ec0ffae6e40ffce6ec0ffee6e40ff0e8e40ff2e8ec0ff4e8e40ff6e8ec0ff8e8e40ffae8ec0ffce8e40ffee8ec0ff0eaec0ff2eae40ff4eaec0ff6eae40ff8eaec0ffaeae40ffceaec0ffeeae40ff0ece40ff2ecec0ff4ece40ff6ecec0ff8ece40ffaecec0ffcece40ffeecec0ff0eeec0ff2eee40ff4eeec0ff6eee40ff8eeec0ffaeee40ffceeec0ffeeee40ff ms=2 *0a644c45
|
||||
K tex-rgba16u-near n=2 d=0 ci_affine_nearest[0=bgra8:o,1=rgba16u:i0,s0]*2 *4f64f6c7
|
||||
C tex-rgb10a2-lin 128x128 st=ok in=rgb10a2 h=c89ba91151c892b9,c89ba91151c892b9 hb=c89ba91151c892b9 sent=0 p=000040ff,fc00c0ff,00fcc0ff,fcfc40ff,7f7f70ff,3f3f70ff,bf3f70ff,3fbf70ff,bfbf70ff g=077f60ff,177f60ff,277fa0ff,377fa0ff,477f60ff,577f60ff,677fa0ff,777fa0ff,877f60ff,977f60ff,a77fa0ff,b77fa0ff,c77f60ff,d77f60ff,e77fa0ff,f77fa0ff t=0e0e44ff2e0ebaff4e0e46ff6e0ebaff8e0e46ffae0ebaffce0e46ffee0ebcff0e2ebaff2e2e48ff4e2eb8ff6e2e48ff8e2eb8ffae2e48ffce2eb8ffee2e46ff0e4e46ff2e4eb8ff4e4e48ff6e4eb8ff8e4e48ffae4eb8ffce4e48ffee4ebaff0e6ebaff2e6e48ff4e6eb8ff6e6e48ff8e6eb8ffae6e48ffce6eb8ffee6e46ff0e8e46ff2e8eb8ff4e8e48ff6e8eb8ff8e8e48ffae8eb8ffce8e48ffee8ebaff0eaebaff2eae48ff4eaeb8ff6eae48ff8eaeb8ffaeae48ffceaeb8ffeeae46ff0ece46ff2eceb8ff4ece48ff6eceb8ff8ece48ffaeceb8ffcece48ffeecebaff0eeebcff2eee46ff4eeebaff6eee46ff8eeebaffaeee46ffceeebaffeeee44ff ms=3 *d17e3ca5
|
||||
K tex-rgb10a2-lin n=2 d=0 ci_affine_premul[0=bgra8:o,1=rgb10a2:i0,s0]*2 *c94be537
|
||||
C tex-rgb10a2-near 128x128 st=ok in=rgb10a2 h=93f58ae72abcc325,93f58ae72abcc325 hb=93f58ae72abcc325 sent=0 p=000040ff,fc00c0ff,00fcc0ff,fcfc40ff,808040ff,404040ff,c04040ff,40c040ff,c0c040ff g=088040ff,188040ff,2880c0ff,3880c0ff,488040ff,588040ff,6880c0ff,7880c0ff,888040ff,988040ff,a880c0ff,b880c0ff,c88040ff,d88040ff,e880c0ff,f880c0ff t=0e0e40ff2e0ec0ff4e0e40ff6e0ec0ff8e0e40ffae0ec0ffce0e40ffee0ec0ff0e2ec0ff2e2e40ff4e2ec0ff6e2e40ff8e2ec0ffae2e40ffce2ec0ffee2e40ff0e4e40ff2e4ec0ff4e4e40ff6e4ec0ff8e4e40ffae4ec0ffce4e40ffee4ec0ff0e6ec0ff2e6e40ff4e6ec0ff6e6e40ff8e6ec0ffae6e40ffce6ec0ffee6e40ff0e8e40ff2e8ec0ff4e8e40ff6e8ec0ff8e8e40ffae8ec0ffce8e40ffee8ec0ff0eaec0ff2eae40ff4eaec0ff6eae40ff8eaec0ffaeae40ffceaec0ffeeae40ff0ece40ff2ecec0ff4ece40ff6ecec0ff8ece40ffaecec0ffcece40ffeecec0ff0eeec0ff2eee40ff4eeec0ff6eee40ff8eeec0ffaeee40ffceeec0ffeeee40ff ms=2 *4549d2a9
|
||||
K tex-rgb10a2-near n=2 d=0 ci_affine_nearest_premul[0=bgra8:o,1=rgb10a2:i0,s0]*2 *34f8d0f8
|
||||
C cg-rgba8 128x128 st=ok in=cg-rgba8 h=d6f0f1b08c4ed531,d6f0f1b08c4ed531 hb=d6f0f1b08c4ed531 sent=0 p=00fcc0ff,fcfc40ff,000040ff,fc00c0ff,7f7d90ff,3fbd90ff,bfbd90ff,3f3d90ff,bf3d90ff g=077da0ff,177da0ff,277d60ff,377d60ff,477da0ff,577da0ff,677d60ff,777d60ff,877da0ff,977da0ff,a77d60ff,b77d60ff,c77da0ff,d77da0ff,e77d60ff,f77d60ff t=0eeebcff2eee46ff4eeebaff6eee46ff8eeebaffaeee46ffceeebaffeeee44ff0ece46ff2eceb8ff4ece48ff6eceb8ff8ece48ffaeceb8ffcece48ffeecebaff0eaebaff2eae48ff4eaeb8ff6eae48ff8eaeb8ffaeae48ffceaeb8ffeeae46ff0e8e46ff2e8eb8ff4e8e48ff6e8eb8ff8e8e48ffae8eb8ffce8e48ffee8ebaff0e6ebaff2e6e48ff4e6eb8ff6e6e48ff8e6eb8ffae6e48ffce6eb8ffee6e46ff0e4e46ff2e4eb8ff4e4e48ff6e4eb8ff8e4e48ffae4eb8ffce4e48ffee4ebaff0e2ebaff2e2e48ff4e2eb8ff6e2e48ff8e2eb8ffae2e48ffce2eb8ffee2e46ff0e0e44ff2e0ebaff4e0e46ff6e0ebaff8e0e46ffae0ebaffce0e46ffee0ebcff ms=2 *2dc6981f
|
||||
K cg-rgba8 n=2 d=0 ci_affine_clamp_to_alpha[0=bgra8:o,1=rgba8:x,s0]*2 *beb8dff7
|
||||
C cg-ga8 128x128 st=ok in=cg-ga8 h=5f191369f1d1c7ea,5f191369f1d1c7ea hb=5f191369f1d1c7ea sent=0 p=00000081,7f7f7f81,000000ff,fcfcfcff,606060c0,272727a0,787878a0,373737e0,a8a8a8e0 g=050505c0,111111c0,1d1d1dc0,292929c0,353535c0,424242c0,4e4e4ec0,5a5a5ac0,666666c0,727272c0,7e7e7ec0,8a8a8ac0,969696c0,a2a2a2c0,afafafc0,bbbbbbc0 t=08080888191919882a2a2a883b3b3b884c4c4c885d5d5d886e6e6e887f7f7f88080808981b1b1b982e2e2e984242429855555598686868987b7b7b988e8e8e98090909a81e1e1ea8333333a8494949a85e5e5ea8737373a8888888a89d9d9da80a0a0ab8212121b8383838b84f4f4fb8676767b87d7d7db8959595b8acacacb80b0b0bc8242424c83d3d3dc8565656c86f6f6fc8888888c8a1a1a1c8bbbbbbc80c0c0cd8272727d8424242d85d5d5dd8787878d8939393d8aeaeaed8c9c9c9d80d0d0de82a2a2ae8474747e8646464e8818181e89e9e9ee8bbbbbbe8d8d8d8e80e0e0ef82d2d2df84c4c4cf86b6b6bf88a8a8af8a9a9a9f8c8c8c8f8e7e7e7f8 ms=2 *6be1b569
|
||||
K cg-ga8 n=2 d=0 ci_affine_clamp_to_alpha_premul_linear_t[0=bgra8:o,1=rg8:x,s0]*2 *2f6000dc
|
||||
C cg-ga16f 128x128 st=ok in=cg-ga16f h=b3d788b877ab5d13,b3d788b877ab5d13 hb=b3d788b877ab5d13 sent=0 p=00000081,80808081,000000ff,fefefeff,8d8d8dc0,565656a0,8d8d8da0,787878e0,c6c6c6e0 g=232323c0,404040c0,525252c0,606060c0,6c6c6cc0,777777c0,818181c0,898989c0,919191c0,999999c0,a0a0a0c0,a6a6a6c0,acacacc0,b2b2b2c0,b9b9b9c0,bebebec0 t=202020883e3e3e88505050885e5e5e8869696988737373887c7c7c88848484882323239846464698595959986868689875757598808080988a8a8a9893939398282828a84d4d4da8636363a8737373a8828282a88e8e8ea8999999a8a3a3a3a82b2b2bb8555555b86c6c6cb87f7f7fb88e8e8eb89b9b9bb8a7a7a7b8b3b3b3b82f2f2fc85c5c5cc8767676c88a8a8ac89a9a9ac8a9a9a9c8b6b6b6c8c2c2c2c8333333d8636363d87f7f7fd8959595d8a7a7a7d8b6b6b6d8c5c5c5d8d1d1d1d8373737e86b6b6be8888888e89f9f9fe8b3b3b3e8c4c4c4e8d3d3d3e8e1e1e1e83b3b3bf8727272f8929292f8aaaaaaf8bfbfbff8d1d1d1f8e2e2e2f8f0f0f0f8 ms=3 *423b4430
|
||||
K cg-ga16f n=2 d=0 ci_affine_clamp_to_alpha_premul_linear_t[0=bgra8:o,1=rg16f:x,s0]*2 *6219902b
|
||||
C cg-g8 128x128 st=ok in=cg-g8 h=e8026f5ff62d2f25,e8026f5ff62d2f25 hb=e8026f5ff62d2f25 sent=0 p=000000ff,fcfcfcff,000000ff,fcfcfcff,7f7f7fff,3f3f3fff,bfbfbfff,3f3f3fff,bfbfbfff g=070707ff,171717ff,272727ff,373737ff,474747ff,575757ff,676767ff,777777ff,878787ff,979797ff,a7a7a7ff,b7b7b7ff,c7c7c7ff,d7d7d7ff,e7e7e7ff,f7f7f7ff t=0e0e0eff2e2e2eff4e4e4eff6e6e6eff8e8e8effaeaeaeffcececeffeeeeeeff0e0e0eff2e2e2eff4e4e4eff6e6e6eff8e8e8effaeaeaeffcececeffeeeeeeff0e0e0eff2e2e2eff4e4e4eff6e6e6eff8e8e8effaeaeaeffcececeffeeeeeeff0e0e0eff2e2e2eff4e4e4eff6e6e6eff8e8e8effaeaeaeffcececeffeeeeeeff0e0e0eff2e2e2eff4e4e4eff6e6e6eff8e8e8effaeaeaeffcececeffeeeeeeff0e0e0eff2e2e2eff4e4e4eff6e6e6eff8e8e8effaeaeaeffcececeffeeeeeeff0e0e0eff2e2e2eff4e4e4eff6e6e6eff8e8e8effaeaeaeffcececeffeeeeeeff0e0e0eff2e2e2eff4e4e4eff6e6e6eff8e8e8effaeaeaeffcececeffeeeeeeff ms=2 *629ba8a8
|
||||
K cg-g8 n=2 d=0 ci_affine_swizzle_rrr1[0=bgra8:o,1=r8:x,s0]*2 *d93d598e
|
||||
C lanczos-rgba8s 40x40 st=ok in=rgba8s h=4ba0f959b0d0cc3d,4ba0f959b0d0cc3d hb=4ba0f959b0d0cc3d sent=0 p=00000ce9,e0007be9,00e07be9,e0e00ce9,38382bff,0e0e2bff,880e2bff,0e882bff,88882bff g=013921ff,02381cff,053884ff,093884ff,10381cff,17381cff,233884ff,2d3884ff,3e381cff,4c381cff,633884ff,753884ff,93381cff,a9381cff,cd3884ff,eb3985ff t=010112fb070184fd140114fd280184fd450114fd6c0184fd9d0114fdd70184fb010784fd070717ff140785ff280717ff450785ff6c0717ff9e0785ffd90714fd011414fd071485ff141417ff281485ff451417ff6c1485ff9e1417ffd91484fd012884fd072817ff142885ff282817ff452885ff6c2817ff9e2885ffd92814fd014514fd074585ff144517ff284585ff454517ff6c4585ff9e4517ffd94584fd016c84fd076c17ff146c85ff286c17ff456c85ff6c6c17ff9e6c85ffd96c14fd019d14fd079e85ff149e17ff289e85ff459e17ff6c9e85ff9e9e17ffd99d84fd01d784fb07d914fd14d984fd28d914fd45d984fd6cd914fd9dd984fdd7d712fb ms=4 *3af626a4
|
||||
K lanczos-rgba8s n=6 d=0 ci_premul_srgb_to_linear_unpremul[0=rgba16f:x,1=rgba8s:i0,s0]*2;ci_lanczosDownH[0=rgba16f:x,1=rgba16f:x,s0]*2;ci_clamp_to_alpha_premul_linear_to_srgb_[0=bgra8:o,1=rgba16f:x,s0]*2 *48730eb7
|
||||
C blur-rgba8 128x128 st=ok in=rgba8 h=fb07a0817d8fe8b1,fb07a0817d8fe8b1 hb=fb07a0817d8fe8b1 sent=0 p=010140ff,fb01c0ff,01fbc0ff,fbfb40ff,7f7f88ff,3f3f88ff,bf3f88ff,3fbf88ff,bfbf88ff g=077f82ff,177f82ff,277f97ff,377f96ff,477f82ff,577f82ff,677f97ff,777f96ff,877f82ff,977f82ff,a77f97ff,b77f96ff,c77f82ff,d77f82ff,e77f97ff,f77f98ff t=0e0e51ff2e0eb1ff4e0e59ff6e0eb1ff8e0e59ffae0eb1ffce0e59ffee0eb6ff0e2eb1ff2e2e60ff4e2eadff6e2e60ff8e2eadffae2e60ffce2eadffee2e59ff0e4e59ff2e4eadff4e4e60ff6e4eadff8e4e60ffae4eadffce4e60ffee4eb1ff0e6eb1ff2e6e60ff4e6eadff6e6e60ff8e6eadffae6e60ffce6eadffee6e59ff0e8e59ff2e8eadff4e8e60ff6e8eadff8e8e60ffae8eadffce8e60ffee8eb1ff0eaeb1ff2eae60ff4eaeadff6eae60ff8eaeadffaeae60ffceaeadffeeae59ff0ece59ff2eceadff4ece60ff6eceadff8ece60ffaeceadffcece60ffeeceb1ff0eeeb6ff2eee59ff4eeeb1ff6eee59ff8eeeb1ffaeee59ffceeeb1ffeeee51ff ms=9 *61f773cf
|
||||
K blur-rgba8 n=8 d=0 ci_affine_clampRect_premul_srgb_to_linea[0=rgba16f:x,1=rgba8:i0,s0]*2;F13V[0=rgba16f:x,1=rgba16f:x,s0]*2;F13H[0=rgba16f:x,1=rgba16f:x,s0]*2;ci_affine_clamp_to_alpha_premul_linear_t[0=bgra8:o,1=rgba16f:x,s0]*2 *dc84b1a6
|
||||
C fill 64x64 st=ok in=none h=df48cf684e74c325,df48cf684e74c325 hb=df48cf684e74c325 sent=0 p=4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff g=4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff,4080bfff t=4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff4080bfff ms=2 *55c0282d
|
||||
K fill n=2 d=0 ci_fill[0=bgra8:o]*2 *26dc5965
|
||||
C multi-2 96x96 st=ok in=rgba8s+rgba8s h=68f1e190bbbc8225,68f1e190bbbc8225 hb=68f1e190bbbc8225 sent=0 p=ca0505ff,05930cff,262804c0,262804c0,05930cff,ca0505ff,05930cff,262804c0,262804c0 g=ca0505ff,ca0505ff,ca0505ff,ca0505ff,ca0505ff,ca0505ff,ca0505ff,ca0505ff,05930cff,05930cff,05930cff,05930cff,05930cff,05930cff,05930cff,05930cff t=ca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cffca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cffca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cffca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cffca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cffca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cff262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0 s=ca0505ff,05930cff/262804c0,262804c0 ms=2 *bfd81aa1
|
||||
K multi-2 n=2 d=0 ci_clamp_to_alpha_premul_linear_to_srgb_[0=bgra8:o,1=rgba8s:i1,2=rgba8s:i0,s0,s1]*2 *28cc071a
|
||||
C multi-3 96x96 st=ok in=rgba8s+rgba8s+rgba8s h=10c471ae9b3e1325,10c471ae9b3e1325 hb=10c471ae9b3e1325 sent=0 p=ca0505ff,0814caff,1c1f3adf,1c1f3adf,05930cff,ca0505ff,0814caff,1c1f3adf,1c1f3adf g=ca0505ff,ca0505ff,ca0505ff,ca0505ff,ca0505ff,05930cff,05930cff,05930cff,05930cff,05930cff,05930cff,0814caff,0814caff,0814caff,0814caff,0814caff t=ca0505ffca0505ff883407ff05930cff05930cff073e8bff0814caff0814caffca0505ffca0505ff883407ff05930cff05930cff073e8bff0814caff0814caffca0505ffca0505ff883407ff05930cff05930cff073e8bff0814caff0814caffca0505ffca0505ff883407ff05930cff05930cff073e8bff0814caff0814caffca0505ffca0505ff883407ff05930cff05930cff073e8bff0814caff0814caffca0505ffca0505ff883407ff05930cff05930cff073e8bff0814caff0814caff1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf1c1f3adf s=ca0505ff,05930cff,0814caff/1c1f3adf,1c1f3adf,1c1f3adf ms=2 *1fa05b3d
|
||||
K multi-3 n=2 d=0 ci_clamp_to_alpha_premul_linear_to_srgb_[0=bgra8:o,1=rgba8s:i2,2=rgba8s:i1,3=rgba8s:i0,s0,s1,s2]*2 *56939a93
|
||||
C multi-4 96x96 st=ok in=rgba8s+rgba8s+rgba8s+rgba8s h=45c0c22021566325,45c0c22021566325 hb=45c0c22021566325 sent=0 p=ca0505ff,de9303ff,46322aef,46322aef,0814caff,05930cff,de9303ff,46322aef,46322aef g=ca0505ff,ca0505ff,ca0505ff,ca0505ff,05930cff,05930cff,05930cff,05930cff,0814caff,0814caff,0814caff,0814caff,de9303ff,de9303ff,de9303ff,de9303ff t=ca0505ffca0505ff05930cff05930cff0814caff0814caffde9303ffde9303ffca0505ffca0505ff05930cff05930cff0814caff0814caffde9303ffde9303ffca0505ffca0505ff05930cff05930cff0814caff0814caffde9303ffde9303ffca0505ffca0505ff05930cff05930cff0814caff0814caffde9303ffde9303ffca0505ffca0505ff05930cff05930cff0814caff0814caffde9303ffde9303ffca0505ffca0505ff05930cff05930cff0814caff0814caffde9303ffde9303ff46322aef46322aef46322aef46322aef46322aef46322aef46322aef46322aef46322aef46322aef46322aef46322aef46322aef46322aef46322aef46322aef s=ca0505ff,05930cff,0814caff,de9303ff/46322aef,46322aef,46322aef,46322aef ms=2 *d97e59b2
|
||||
K multi-4 n=2 d=0 ci_clamp_to_alpha_premul_linear_to_srgb_[0=bgra8:o,1=rgba8s:i3,2=rgba8s:i2,3=rgba8s:i1,4=rgba8s:i0,s0,s1,s2,s3]*2 *0717400f
|
||||
C multi-6 96x96 st=ok in=rgba8s+rgba8s+rgba8s+rgba8s+rgba8s+rgba8s h=48a2f683317e9b25,48a2f683317e9b25 hb=48a2f683317e9b25 sent=0 p=ca0505ff,03a4a4ff,2b3940fb,2b3940fb,de9303ff,05930cff,740c93ff,2b3940fb,2b3940fb g=ca0505ff,ca0505ff,ca0505ff,05930cff,05930cff,0814caff,0814caff,0814caff,de9303ff,de9303ff,de9303ff,740c93ff,740c93ff,03a4a4ff,03a4a4ff,03a4a4ff t=ca0505ff47640aff06694bff0814caffde9303ff973963ff4e3f99ff03a4a4ffca0505ff47640aff06694bff0814caffde9303ff973963ff4e3f99ff03a4a4ffca0505ff47640aff06694bff0814caffde9303ff973963ff4e3f99ff03a4a4ffca0505ff47640aff06694bff0814caffde9303ff973963ff4e3f99ff03a4a4ffca0505ff47640aff06694bff0814caffde9303ff973963ff4e3f99ff03a4a4ffca0505ff47640aff06694bff0814caffde9303ff973963ff4e3f99ff03a4a4ff2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb2b3940fb s=ca0505ff,05930cff,0814caff,de9303ff,740c93ff,03a4a4ff/2b3940fb,2b3940fb,2b3940fb,2b3940fb,2b3940fb,2b3940fb ms=4 *597c7046
|
||||
K multi-6 n=2 d=0 ci_clamp_to_alpha_premul_linear_to_srgb_[0=bgra8:o,1=rgba8s:i5,2=rgba8s:i4,3=rgba8s:i3,4=rgba8s:i2,5=rgba8s:i1,6=rgba8s:i0,s0,s1,s2,s3,s4,s5]*2 *f5cc0dfb
|
||||
C multi-6-bgra8 96x96 st=ok in=bgra8+bgra8+bgra8+bgra8+bgra8+bgra8 h=3cf3913f088aa325,3cf3913f088aa325 hb=3cf3913f088aa325 sent=0 p=e62828ff,1ed2d2ff,86adbdfb,86adbdfb,f0c81eff,28c83cff,b43cc8ff,86adbdfb,86adbdfb g=e62828ff,e62828ff,e62828ff,28c83cff,28c83cff,3250e6ff,3250e6ff,3250e6ff,f0c81eff,f0c81eff,f0c81eff,b43cc8ff,b43cc8ff,1ed2d2ff,1ed2d2ff,1ed2d2ff t=e62828ff679335ff2ba075ff3250e6fff0c81effc86b8fff826ecbff1ed2d2ffe62828ff679335ff2ba075ff3250e6fff0c81effc86b8fff826ecbff1ed2d2ffe62828ff679335ff2ba075ff3250e6fff0c81effc86b8fff826ecbff1ed2d2ffe62828ff679335ff2ba075ff3250e6fff0c81effc86b8fff826ecbff1ed2d2ffe62828ff679335ff2ba075ff3250e6fff0c81effc86b8fff826ecbff1ed2d2ffe62828ff679335ff2ba075ff3250e6fff0c81effc86b8fff826ecbff1ed2d2ff86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb86adbdfb s=e62828ff,28c83cff,3250e6ff,f0c81eff,b43cc8ff,1ed2d2ff/86adbdfb,86adbdfb,86adbdfb,86adbdfb,86adbdfb,86adbdfb ms=3 *53eeecc5
|
||||
K multi-6-bgra8 n=2 d=0 ci_clamp_to_alpha_premul_linear_to_srgb_[0=bgra8:o,1=bgra8:i5,2=bgra8:i4,3=bgra8:i3,4=bgra8:i2,5=bgra8:i1,6=bgra8:i0,s0,s1,s2,s3,s4,s5]*2 *271cbc39
|
||||
C filter-srcover-2 96x96 st=ok in=rgba8s+rgba8s h=68f1e190bbbc8225,68f1e190bbbc8225 hb=68f1e190bbbc8225 sent=0 p=ca0505ff,05930cff,262804c0,262804c0,05930cff,ca0505ff,05930cff,262804c0,262804c0 g=ca0505ff,ca0505ff,ca0505ff,ca0505ff,ca0505ff,ca0505ff,ca0505ff,ca0505ff,05930cff,05930cff,05930cff,05930cff,05930cff,05930cff,05930cff,05930cff t=ca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cffca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cffca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cffca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cffca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cffca0505ffca0505ffca0505ffca0505ff05930cff05930cff05930cff05930cff262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0262804c0 s=ca0505ff,05930cff/262804c0,262804c0 ms=2 *d9d8d287
|
||||
K filter-srcover-2 n=2 d=0 ci_clamp_to_alpha_premul_linear_to_srgb_[0=bgra8:o,1=rgba8s:i1,2=rgba8s:i0,s0,s1]*2 *96bcbc95
|
||||
C mixed-3 96x96 st=ok in=cg-ga8+rgba8s+bgra8 h=c895b1e070a11b25,c895b1e070a11b25 hb=c895b1e070a11b25 sent=0 p=30303080,3250e6ff,3c51aeff,1e3890c0,05930cff,616161ff,3250e6ff,3c51aeff,1e3890c0 g=616161ff,616161ff,616161ff,616161ff,616161ff,05930cff,05930cff,05930cff,05930cff,05930cff,05930cff,3250e6ff,3250e6ff,3250e6ff,3250e6ff,3250e6ff t=3030308030303080225124aa05930cff05930cff23669dff3250e6ff3250e6ff3030308030303080225124aa05930cff05930cff23669dff3250e6ff3250e6ff616161ff616161ff427245ff05930cff05930cff23669dff3250e6ff3250e6ff616161ff616161ff427245ff05930cff05930cff23669dff3250e6ff3250e6ff616161ff616161ff427245ff05930cff05930cff23669dff3250e6ff3250e6ff616161ff616161ff427245ff05930cff05930cff23669dff3250e6ff3250e6ff3c51aeff3c51aeff3249a4ea1e3890c01e3890c01e3890c01e3890c01e3890c03c51aeff3c51aeff3249a4ea1e3890c01e3890c01e3890c01e3890c01e3890c0 s=515151d6,05930cff,3250e6ff/3c51aeff,1e3890c0,1e3890c0 ms=2 *fa87a856
|
||||
K mixed-3 n=2 d=0 ci_clamp_to_alpha_premul_linear_to_srgb_[0=bgra8:o,1=bgra8:i2,2=rgba8s:i1,3=rg8:x,s0,s1,s2]*2 *b002e24e
|
||||
D diag=/private/var/tmp/adreno-icon-pixels-2871.log absent *8c0545f2
|
||||
END command=synth cases=38 errors=0 *0510e4e8
|
||||
@@ -0,0 +1,242 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""Run icon-pixels in the A16 guest from its root console shell, fetch its lines and compare them with this Mac's.
|
||||
|
||||
During a --console desktop boot, once the multi-user root shell answers, as the only console client (pass the run's
|
||||
--owner). Writes nothing outside the guest's /private/var/tmp/icon-pixels (and, with --move-icon-caches, renames the
|
||||
icon caches aside). Every console command's output stays under about 4 KB.
|
||||
|
||||
python3 tools/run-icon-pixels.py --device udp://enN --launch-record build/PREFIX-early-stop-launch.json \\
|
||||
--owner HEX --tool build/icon-pixels/TOOL/icon-pixels --output NEW-DIR \\
|
||||
[--reference-synth REF.txt] [--reference-icons REF.txt] [--steps push,version,synth,icons,diag] \\
|
||||
[--move-icon-caches TAG] [--ab-env VAR=VALUE] [--synth-timeout 1200]
|
||||
|
||||
Steps (--steps picks and orders them; each is recorded in OUTPUT/run.json):
|
||||
push the tool as base64 in 512-character printf chunks (tools/deploy-guest-plugin.py's transfer: one numbered file
|
||||
per chunk, a SHA-256 listing finds chunks not held intact and resends them), joined, decoded, its SHA-256
|
||||
checked, then installed as /private/var/tmp/icon-pixels/icon-pixels (mode 755)
|
||||
version `icon-pixels version`: the binary executes (an ad-hoc arm64e executable; if the guest's AMFI kills it, the
|
||||
step stops and names the trust-cache row build-icon-pixels.py recorded) and finds the plug-in device
|
||||
synth `icon-pixels synth --repeat 2` as root: CoreImage kernels on synthetic inputs, on the plug-in device
|
||||
synth-ab the same with --ab-env VAR=VALUE in the tool's environment, into synth-ab.txt (a plug-in built with a
|
||||
per-process switch, such as ADRENO_CS_TABLES=0, then compares both encodings in one boot)
|
||||
icons `icon-pixels icons --source gen` as root (IconServices' generator in-process, on the plug-in device), then,
|
||||
as the console user in that user's bootstrap context (launchctl asuser UID sudo -u #UID),
|
||||
`icon-pixels icons --source ws` (NSWorkspace, through iconservicesagent and its caches)
|
||||
recache with --move-icon-caches TAG: rename the IconServices store, every user's com.apple.iconservices and
|
||||
com.apple.iconservicesagent caches and the Dock's com.apple.dock.iconcache to NAME.TAG (reversible: mv back),
|
||||
restart iconservicesd (launchctl kickstart -k), stop every iconservicesagent, the Dock and System Settings, so
|
||||
the next icons drawn are rendered again with the installed plug-in. Put it before `icons`
|
||||
diag the plug-in's diagnostics: per-process files /private/var/tmp/adreno-*.log (counts, distinct drop/refusal
|
||||
reasons), and the unified log subsystem org.snapintosh.adreno for iconservicesagent and System Settings
|
||||
Each output file is fetched 3 lines per command; every line carries a CRC, so console noise is dropped and a block that
|
||||
came back short is fetched again (up to 4 times). Then tools/compare-icon-pixels.py against the references.
|
||||
Offline (the console stand-in, tools/test-icon-pixels.py): --target 127.0.0.1:PORT --session HEX --guest-root DIR.
|
||||
"""
|
||||
import argparse
|
||||
import base64
|
||||
import hashlib
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import zlib
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
REMOTE = '/private/var/tmp/icon-pixels'
|
||||
BLOCK = 3
|
||||
STEPS = 'push,version,synth,icons,diag'
|
||||
|
||||
|
||||
def load(name, path):
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def valid(line):
|
||||
body, sep, crc = line.strip().rpartition(' *')
|
||||
return bool(sep) and re.fullmatch(r'[0-9a-f]{8}', crc or '') is not None and \
|
||||
f'{zlib.crc32(body.encode()) & 0xffffffff:08x}' == crc
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
where = ap.add_mutually_exclusive_group(required=True)
|
||||
where.add_argument('--device')
|
||||
where.add_argument('--target', help='host:port of the console stand-in (offline test)')
|
||||
ap.add_argument('--launch-record')
|
||||
ap.add_argument('--session')
|
||||
ap.add_argument('--owner', required=True, help='hex console owner of this run (one owner for every console step)')
|
||||
ap.add_argument('--tool', type=Path, required=True)
|
||||
ap.add_argument('--output', type=Path, required=True)
|
||||
ap.add_argument('--steps', default=STEPS)
|
||||
ap.add_argument('--reference-synth', type=Path)
|
||||
ap.add_argument('--reference-icons', type=Path)
|
||||
ap.add_argument('--move-icon-caches', metavar='TAG')
|
||||
ap.add_argument('--ab-env', metavar='VAR=VALUE', help='the environment of the synth-ab step')
|
||||
ap.add_argument('--synth-args', default='--repeat 2')
|
||||
ap.add_argument('--icons-args', default='--size 20 --scale 2')
|
||||
ap.add_argument('--synth-timeout', type=int, default=1200)
|
||||
ap.add_argument('--icons-timeout', type=int, default=600)
|
||||
ap.add_argument('--guest-root', default='/', help='prefix of every guest path (offline test)')
|
||||
ap.add_argument('--console-user', help='uid for the ws icons (default: the owner of /dev/console)')
|
||||
ap.add_argument('--poll-ms', type=int, default=50)
|
||||
ap.add_argument('--wait-ms', type=int, default=150)
|
||||
ap.add_argument('--attempts', type=int, default=30)
|
||||
a = ap.parse_args(argv)
|
||||
steps = [s for s in a.steps.split(',') if s]
|
||||
unknown = set(steps) - {'push', 'version', 'synth', 'synth-ab', 'icons', 'recache', 'diag'}
|
||||
if unknown or ('recache' in steps) != bool(a.move_icon_caches) or ('synth-ab' in steps) != bool(a.ab_env):
|
||||
ap.error(f'unknown steps {sorted(unknown)}, or recache without --move-icon-caches TAG, or synth-ab without '
|
||||
'--ab-env VAR=VALUE (or the reverse)')
|
||||
if a.ab_env and not re.fullmatch(r'[A-Z][A-Z0-9_]{0,63}=[A-Za-z0-9._-]{0,64}', a.ab_env):
|
||||
ap.error('--ab-env is one VAR=VALUE (upper-case name; letters, digits, dot, dash, underscore)')
|
||||
# Offline the "guest" shell is this Mac's: never restart its processes, never ask its sudo for a password.
|
||||
if a.target and 'recache' in steps:
|
||||
ap.error('recache restarts the shell machine\'s icon services, Dock and System Settings: only with --device')
|
||||
if a.target and 'icons' in steps and a.console_user is None:
|
||||
ap.error('offline, pass --console-user (0 skips the NSWorkspace icons)')
|
||||
if a.move_icon_caches and not re.fullmatch(r'[A-Za-z0-9._-]{1,48}', a.move_icon_caches):
|
||||
ap.error('the cache tag is letters, digits, dot, dash and underscore')
|
||||
out = a.output.resolve()
|
||||
out.mkdir(parents=True, exist_ok=False)
|
||||
deploy = load('deploy', ROOT / 'tools/deploy-guest-plugin.py')
|
||||
tool = a.tool.read_bytes()
|
||||
tool_sha = hashlib.sha256(tool).hexdigest()
|
||||
build = a.tool.resolve().parent / 'build.json'
|
||||
trust_row = json.loads(build.read_text()).get('trust_row') if build.is_file() else None
|
||||
args = argparse.Namespace(session=a.session, launch_record=a.launch_record, device=a.device, target=a.target,
|
||||
owner=a.owner, wait_ms=a.wait_ms, poll_ms=a.poll_ms, test_skip_chunk=[])
|
||||
root = a.guest_root.rstrip('/')
|
||||
remote = root + REMOTE
|
||||
exe = f'{remote}/icon-pixels'
|
||||
rec = dict(schema='snapintosh-icon-pixels-run-v1', started=time.time(), tool=str(a.tool), tool_sha256=tool_sha,
|
||||
tool_bytes=len(tool), remote=remote, steps=steps, status='RUNNING')
|
||||
shell = deploy.Shell(args)
|
||||
|
||||
def fetch(name, path):
|
||||
"""The file's lines, BLOCK per command, checksummed; written to OUTPUT/NAME."""
|
||||
count = shell.run(f'{name}-lines', f"awk 'END{{print NR}}' {shlex.quote(path)}", ok=(0, 1))
|
||||
m = re.search(r'^(\d+)\s*$', count, re.M)
|
||||
lines = int(m.group(1)) if m else 0
|
||||
kept, refetched, t0 = [], 0, time.monotonic()
|
||||
for first in range(1, lines + 1, BLOCK):
|
||||
last = min(lines, first + BLOCK - 1)
|
||||
want = last - first + 1
|
||||
good = []
|
||||
for _ in range(5):
|
||||
text = shell.run('fetch', f"sed -n '{first},{last}p' {shlex.quote(path)}", timeout=60, ok=(0, 1))
|
||||
good = [l.strip() for l in text.splitlines() if valid(l)]
|
||||
if len(good) >= want:
|
||||
break
|
||||
refetched += 1
|
||||
kept += good[:want]
|
||||
(out / name).write_text('\n'.join(kept) + ('\n' if kept else ''))
|
||||
rec[name] = dict(lines=lines, fetched=len(kept), refetched_blocks=refetched,
|
||||
seconds=round(time.monotonic() - t0, 1))
|
||||
return kept
|
||||
|
||||
def run_tool(name, command, timeout):
|
||||
t0 = time.monotonic()
|
||||
res = shell.run(name, f'cd {shlex.quote(remote)} && {command} > {name}.txt 2> {name}.err; echo rc=$?; '
|
||||
f"awk 'END{{print NR}}' {name}.txt; tail -c 600 {name}.err", timeout=timeout, ok=(0, 1))
|
||||
m = re.search(r'rc=(\d+)\s+(\d+)', res)
|
||||
rec[f'{name}_rc'] = int(m.group(1)) if m else None
|
||||
rec[f'{name}_seconds'] = round(time.monotonic() - t0, 1)
|
||||
rec[f'{name}_stderr_tail'] = res[res.find('rc='):][-700:] if 'rc=' in res else res[-700:]
|
||||
return fetch(f'{name}.txt', f'{remote}/{name}.txt')
|
||||
|
||||
try:
|
||||
rec['shell_attempts'] = deploy.wait_for_shell(shell, a.attempts, 20)
|
||||
for step in steps:
|
||||
if step == 'push':
|
||||
shell.run('work', f'mkdir -p {shlex.quote(remote)} && rm -rf {shlex.quote(remote)}/push')
|
||||
t0 = time.monotonic()
|
||||
f = dict(name='icon-pixels', text=base64.b64encode(tool).decode(), payload_sha256=tool_sha,
|
||||
new_sha256=tool_sha, patch=False, path=None)
|
||||
rec['push'] = deploy.transfer(shell, args, f'{remote}/push', f)
|
||||
shell.run('install', f'cp {shlex.quote(remote)}/push/icon-pixels.new {shlex.quote(exe)}.new && '
|
||||
f'chmod 755 {shlex.quote(exe)}.new && mv -f {shlex.quote(exe)}.new {shlex.quote(exe)} && '
|
||||
f'rm -rf {shlex.quote(remote)}/push')
|
||||
if shell.digest('installed', exe) != tool_sha:
|
||||
raise deploy.Refused('the installed tool differs from the one pushed')
|
||||
rec['push_seconds'] = round(time.monotonic() - t0, 1)
|
||||
elif step == 'version':
|
||||
res = shell.run('version', f'{shlex.quote(exe)} version 2>&1; echo rc=$?', timeout=120, ok=(0, 1))
|
||||
m = re.search(r'rc=(\d+)', res)
|
||||
rec['version_rc'] = int(m.group(1)) if m else None
|
||||
rec['version'] = [l.strip() for l in res.splitlines() if valid(l)]
|
||||
if rec['version_rc'] != 0 or not any(l.startswith('V ') for l in rec['version']):
|
||||
hint = (f' If it was killed (rc 137, "Killed: 9"), the guest refuses the ad-hoc signature: add the row '
|
||||
f'{json.dumps(trust_row)} to the next run\'s trust additions.' if trust_row else '')
|
||||
raise deploy.Refused(f'icon-pixels does not run: {res[-300:]!r}.{hint}')
|
||||
elif step == 'synth':
|
||||
run_tool('synth', f'./icon-pixels synth {a.synth_args}', a.synth_timeout)
|
||||
elif step == 'synth-ab':
|
||||
run_tool('synth-ab', f'env {a.ab_env} ./icon-pixels synth {a.synth_args}', a.synth_timeout)
|
||||
elif step == 'icons':
|
||||
run_tool('icons-gen', f'./icon-pixels icons --source gen {a.icons_args}', a.icons_timeout)
|
||||
uid = a.console_user or shell.run('console-user', 'stat -f %u /dev/console').strip().splitlines()[-1]
|
||||
rec['console_user'] = uid
|
||||
if uid.isdigit() and uid != '0':
|
||||
run_tool('icons-ws', f'launchctl asuser {uid} sudo -u "#{uid}" ./icon-pixels icons --source ws '
|
||||
f'{a.icons_args}', a.icons_timeout)
|
||||
else:
|
||||
rec['icons_ws'] = f'skipped: /dev/console belongs to {uid!r} (no logged-in user)'
|
||||
elif step == 'recache':
|
||||
tag = a.move_icon_caches
|
||||
paths = (f'{root}/Library/Caches/com.apple.iconservices.store '
|
||||
f'{root}/private/var/folders/*/*/C/com.apple.iconservices '
|
||||
f'{root}/private/var/folders/*/*/C/com.apple.iconservicesagent '
|
||||
f'{root}/private/var/folders/*/*/C/com.apple.dock.iconcache')
|
||||
rec['recache'] = shell.run('recache', (
|
||||
f'for p in {paths}; do if [ -e "$p" ]; then mv "$p" "$p.{tag}" && echo "moved $p" || echo "FAILED $p"; '
|
||||
f'fi; done; launchctl kickstart -k system/com.apple.iconservices.iconservicesd 2>&1 | tail -1; '
|
||||
f'killall iconservicesagent Dock "System Settings" 2>&1 | tail -3; echo recache-done'),
|
||||
timeout=120, ok=(0, 1))[-3000:]
|
||||
elif step == 'diag':
|
||||
rec['diag_files'] = shell.run('diag-files', (
|
||||
f'ls {root}/private/var/tmp/ | grep -c "^adreno-.*\\.log$"; '
|
||||
f'ls -t {root}/private/var/tmp/ | grep "^adreno-.*\\.log$" | head -12'), ok=(0, 1))[-1500:]
|
||||
rec['diag_reasons'] = shell.run('diag-reasons', (
|
||||
f'cat {root}/private/var/tmp/adreno-*.log 2>/dev/null | grep -E "dropped:|refused:|zero texture" | '
|
||||
f'sed -E "s/^.*(dropped:|refused:|zero texture:)/\\1/" | cut -c1-200 | sort | uniq -c | sort -rn | '
|
||||
f'head -15'),
|
||||
timeout=120, ok=(0, 1))[-3500:]
|
||||
rec['diag_unified'] = shell.run('diag-unified', (
|
||||
'log show --last 60m --style compact --predicate \'subsystem == "org.snapintosh.adreno" AND '
|
||||
'(process == "iconservicesagent" OR process == "System Settings")\' 2>/dev/null | '
|
||||
'grep -E "dropped|refused|not built|zero texture|failed" | cut -c1-220 | tail -15'),
|
||||
timeout=600, ok=(0, 1))[-3500:]
|
||||
rec['status'] = 'DONE'
|
||||
except deploy.Refused as error:
|
||||
rec['status'] = 'REFUSED'
|
||||
rec['error'] = str(error)
|
||||
finally:
|
||||
rec['commands'] = [s for s in shell.steps if s['step'] not in ('chunk', 'fetch')]
|
||||
rec['finished'] = time.time()
|
||||
(out / 'run.json').write_text(json.dumps(rec, indent=1) + '\n')
|
||||
compares = {}
|
||||
for name, ref, cases in (('synth.txt', a.reference_synth, '.'), ('synth-ab.txt', a.reference_synth, '.'),
|
||||
('icons-gen.txt', a.reference_icons, '^gen-'),
|
||||
('icons-ws.txt', a.reference_icons, '^ws-')):
|
||||
if ref and (out / name).is_file():
|
||||
r = subprocess.run([sys.executable, str(ROOT / 'tools/compare-icon-pixels.py'), str(ref), str(out / name),
|
||||
'--cases', cases, '--json', str(out / f'{name}.compare.json')], capture_output=True, text=True)
|
||||
(out / f'{name}.compare.txt').write_text(r.stdout + r.stderr)
|
||||
compares[name] = r.stdout.strip().splitlines()[-1] if r.stdout.strip() else f'exit {r.returncode}'
|
||||
print(r.stdout[-2500:])
|
||||
summary = {k: v for k, v in rec.items() if k not in ('commands', 'push')}
|
||||
summary['compare'] = compares
|
||||
print(json.dumps(summary, indent=1)[-4000:])
|
||||
return 0 if rec['status'] == 'DONE' else 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -10,11 +10,12 @@ AdrenoIBComputeSamplers) and standing in for a kext that publishes AdrenoIBCompu
|
||||
- every single-input kernel is encoded, nothing omitted; its package's CS T# for the source texture has the format's
|
||||
FMT6, swap, own channel mapping and sRGB decode (Mesa fd6_format_table; A8 as the fragment sampler encodes it),
|
||||
linear tiling, the texture's size and a 64-byte-multiple pitch; the single shape keeps one sampler unit, a T# table of
|
||||
T#0 (null) + T#1 and SP_CS_CONFIG NTEX 1 / NSAMP 1 / NUAV 2;
|
||||
T#0 (null) + T#1 and SP_CS_CONFIG NTEX 1 / NSAMP 1 / NUAV 2 (with --cs-tables, a plug-in built with ADRENO_CS_TABLES:
|
||||
NTEX 2 / NSAMP 2 / NUAV 1, Mesa's counts);
|
||||
- the two-input kernel: without the property it is omitted, naming AdrenoIBComputeSamplers, and no package carries a
|
||||
CS sampler load of more than one unit; with it, it is encoded with a 3-entry T# table (null, the two inputs, each
|
||||
relocated READ to its own texture with its own format), a 2-unit sampler table of clamping samplers, SP_CS_TSIZE 3
|
||||
and SP_CS_CONFIG NTEX 3 / NSAMP 2;
|
||||
and SP_CS_CONFIG NTEX 3 / NSAMP 2 / NUAV 2 (--cs-tables: NTEX 3 / NSAMP 3 / NUAV 1, a third, zero, sampler entry);
|
||||
- a replaceRegion/getBytes round trip of each format returns the written bytes on the plug-in device and on this
|
||||
Mac's GPU (the CPU layout of the textures CoreImage uploads icons into);
|
||||
- every package replays through the production validator, except the two-input package, which that validator must
|
||||
@@ -23,7 +24,7 @@ AdrenoIBComputeSamplers) and standing in for a kext that publishes AdrenoIBCompu
|
||||
--expect-before: the unchanged plug-in must fail at least one of these.
|
||||
|
||||
python3 tools/test-adreno-settings-ci-encoding.py --bundle BUNDLE --output NEW-DIR [--expect-before]
|
||||
[--cs-samplers-validator]
|
||||
[--cs-samplers-validator] [--cs-tables]
|
||||
"""
|
||||
import argparse
|
||||
import importlib.util
|
||||
@@ -61,6 +62,9 @@ EXPECT = {71: ('FMT6_8_8_8_8_UNORM', 'WZYX', 'XYZW', 1, 4), 81: ('FMT6_8_8_8_8_U
|
||||
90: ('FMT6_10_10_10_2_UNORM', 'WZYX', 'XYZW', 0, 4)}
|
||||
SWZ = {'X': 'X', 'Y': 'Y', 'Z': 'Z', 'W': 'W', '0': 'ZERO', '1': 'ONE'}
|
||||
GATE = '(AdrenoIBComputeSamplers)'
|
||||
# (T# units, sampler units, TSIZE, NTEX, NSAMP, NUAV) of the single and two-input packages; --cs-tables selects Mesa's.
|
||||
SHAPES = {False: ((2, 1, 2, 1, 1, 2), (3, 2, 3, 3, 2, 2)), True: ((2, 1, 2, 2, 2, 1), (3, 2, 3, 3, 3, 1))}
|
||||
CS_TABLES = False
|
||||
checks, failures = 0, []
|
||||
|
||||
|
||||
@@ -174,13 +178,14 @@ def verify(out, report, gated, replays, proposal):
|
||||
check(table is not None, f'{name}: CS T# load without a package table')
|
||||
if table is None:
|
||||
continue
|
||||
single_shape, multi_shape = SHAPES[CS_TABLES]
|
||||
if not multi:
|
||||
check((units, samplers, tsize, ntex, nsamp, nuav) == (2, 1, 2, 1, 1, 2),
|
||||
check((units, samplers, tsize, ntex, nsamp, nuav) == single_shape,
|
||||
f'{name}: single shape T# {units} samplers {samplers} TSIZE {tsize} NTEX {ntex} NSAMP {nsamp} NUAV {nuav}')
|
||||
check(not any(tdesc(pkg, table)['words']) and by_lo.get(table) is None, f'{name}: T#0 is not null')
|
||||
check_texture(name, pkg, by_lo, table, 1, case['sources'][0])
|
||||
else:
|
||||
check((units, samplers, tsize, ntex, nsamp, nuav) == (3, 2, 3, 3, 2, 2),
|
||||
check((units, samplers, tsize, ntex, nsamp, nuav) == multi_shape,
|
||||
f'{name}: two-input shape T# {units} samplers {samplers} TSIZE {tsize} NTEX {ntex} NSAMP {nsamp} NUAV {nuav}')
|
||||
check(not any(tdesc(pkg, table)['words']) and by_lo.get(table) is None, f'{name}: T#0 is not null')
|
||||
kernel = case['kernels'][0]['textures'] if case.get('kernels') else {}
|
||||
@@ -196,6 +201,9 @@ def verify(out, report, gated, replays, proposal):
|
||||
wraps = [T.dfield(w[0], 'A8XX_TEX_SAMP_0', f'WRAP_{a}') for a in 'STR']
|
||||
check(any(w) and all(name_of('a6xx_tex_clamp', x) in ('A6XX_TEX_CLAMP_TO_EDGE', 'A6XX_TEX_CLAMP_TO_BORDER')
|
||||
for x in wraps), f'{name}: sampler {k} words {w} wraps {wraps}')
|
||||
if CS_TABLES:
|
||||
third = [u32(pkg, st + 32 + 4 * i) for i in range(4)]
|
||||
check(not any(third), f'{name}: the third sampler entry (NSAMP 3) is not zero: {third}')
|
||||
for label, exe in replays:
|
||||
rd = out / f'replay-{label}' / d
|
||||
rd.mkdir(parents=True, exist_ok=True)
|
||||
@@ -223,14 +231,16 @@ T_ds = None
|
||||
|
||||
|
||||
def main():
|
||||
global T_ds
|
||||
global T_ds, CS_TABLES
|
||||
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument('--bundle', type=Path, required=True)
|
||||
ap.add_argument('--output', type=Path, required=True)
|
||||
ap.add_argument('--expect-before', action='store_true')
|
||||
ap.add_argument('--cs-tables', action='store_true', help='expect a plug-in built with ADRENO_CS_TABLES (Mesa\'s counts)')
|
||||
ap.add_argument('--cs-samplers-validator', action='store_true',
|
||||
help='also replay through this tree\'s validator built with ADRENO_IB_CS_SAMPLERS and opted in')
|
||||
args = ap.parse_args()
|
||||
CS_TABLES = args.cs_tables
|
||||
out = args.output.resolve()
|
||||
out.mkdir(parents=True, exist_ok=False)
|
||||
exe = out / 'settings-ci-encoding'
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
"""icon-pixels offline: the tool on this Mac's GPU, the comparison's diagnoses, and the console procedure end to end.
|
||||
|
||||
python3 tools/test-icon-pixels.py --output NEW-DIR [--bundle ADRENO-BUNDLE] [--skip-console] [--noise-rate 40]
|
||||
|
||||
1. tools/build-icon-pixels.py builds the tool; it runs `synth` on this Mac's GPU twice (deterministic: identical C
|
||||
lines) and against tools/icon-pixels-reference-synth.txt (the committed synthetic reference, made with --host-caps
|
||||
on the deployed plug-in): every case must PASS, or the reference is stale for this Mac's macOS/CoreImage.
|
||||
2. With --bundle (an ADRENO_SETTINGS_ICONS plug-in bundle with its compiler runtime): `synth --plugin BUNDLE
|
||||
--cs-samplers 8` (the plug-in device, commits intercepted) must dispatch exactly the kernels and texture formats
|
||||
of the reference (compare --census-only PASS) with nothing dropped or refused; without the CS sampler stand-in the
|
||||
multi-input kernels must be dropped (the deployed-kext gate) and the comparison must say so.
|
||||
3. Fault injection: guest outputs derived from the reference, each with one fault the comparison must name: red/blue
|
||||
swapped, an extra or a missing sRGB decode, transparent output, a zeroed channel, an unwritten and a partially
|
||||
written destination, differing readbacks, differing repeats, a missing or foreign input stripe (with its texture
|
||||
index), a broken blend band, an empty/black/partial/recoloured icon, console noise; and a perturbation within
|
||||
tolerance that must still PASS.
|
||||
4. Unless --skip-console: tools/run-icon-pixels.py over the console stand-in (tools/test-console-link.py: q1n1's
|
||||
console handler, the monitor's console link, /bin/sh on a pty, request/reply loss and mid-line console noise)
|
||||
pushes the tool, runs `version`, a few synth cases (also with --ab-env), two generated icons and the diag step,
|
||||
fetches every line and compares them with a direct run of the same cases: identical C and K lines. (recache and
|
||||
the NSWorkspace icons act on the shell's own machine, so the runner refuses them offline.)
|
||||
"""
|
||||
import argparse
|
||||
import importlib.util
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import zlib
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
REFERENCE = ROOT / 'tools/icon-pixels-reference-synth.txt'
|
||||
checks, failures = 0, []
|
||||
|
||||
|
||||
def check(ok, what):
|
||||
global checks
|
||||
checks += 1
|
||||
if not ok:
|
||||
failures.append(what)
|
||||
print('FAIL', what)
|
||||
return ok
|
||||
|
||||
|
||||
def load(name, path):
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def seal(body):
|
||||
return f'{body} *{zlib.crc32(body.encode()) & 0xffffffff:08x}'
|
||||
|
||||
|
||||
def body(line):
|
||||
return line.rpartition(' *')[0]
|
||||
|
||||
|
||||
def kind_lines(text, kinds):
|
||||
return [l for l in text.splitlines() if l[:2] in kinds]
|
||||
|
||||
|
||||
def edit(lines, case, fn, kind='C'):
|
||||
"""A copy of lines with case's line rewritten by fn(fields dict in order) and resealed."""
|
||||
out = []
|
||||
for l in lines:
|
||||
b = body(l)
|
||||
words = b.split(' ')
|
||||
if len(words) > 2 and words[0] == kind and words[1] == case:
|
||||
head, fields = words[:3], {}
|
||||
order = []
|
||||
for w in words[3:]:
|
||||
k, _, v = w.partition('=')
|
||||
fields[k] = v
|
||||
order.append(k)
|
||||
fn(fields)
|
||||
l = seal(' '.join(head + [f'{k}={fields[k]}' for k in order if k in fields]))
|
||||
out.append(l)
|
||||
return out
|
||||
|
||||
|
||||
def map_pixels(fields, fn, keys=('p', 'g', 't', 's')):
|
||||
"""Apply fn([r,g,b,a]) -> [r,g,b,a] to every RRGGBBAA value in the sampled fields."""
|
||||
def one(h):
|
||||
v = fn([int(h[i:i + 2], 16) for i in (0, 2, 4, 6)])
|
||||
return ''.join(f'{max(0, min(255, int(round(x)))):02x}' for x in v)
|
||||
for k in keys:
|
||||
if k not in fields:
|
||||
continue
|
||||
if k == 't':
|
||||
t = fields['t']
|
||||
fields['t'] = ''.join(one(t[i:i + 8]) for i in range(0, len(t), 8))
|
||||
elif k == 's':
|
||||
top, _, band = fields['s'].partition('/')
|
||||
fields['s'] = ','.join(one(h) for h in top.split(',')) + '/' + ','.join(one(h) for h in band.split(','))
|
||||
else:
|
||||
fields[k] = ','.join(one(h) for h in fields[k].split(','))
|
||||
|
||||
|
||||
def run_compare(cmp_, ref_lines, guest_lines, out, name, *extra):
|
||||
ref, guest = out / f'{name}.ref.txt', out / f'{name}.guest.txt'
|
||||
ref.write_text('\n'.join(ref_lines) + '\n')
|
||||
guest.write_text('\n'.join(guest_lines) + '\n')
|
||||
r = subprocess.run([sys.executable, str(ROOT / 'tools/compare-icon-pixels.py'), str(ref), str(guest), *extra],
|
||||
capture_output=True, text=True)
|
||||
(out / f'{name}.compare.txt').write_text(r.stdout + r.stderr)
|
||||
verdicts = {}
|
||||
for l in r.stdout.splitlines():
|
||||
m = re.match(r'(PASS|FAIL) (\S+?)(?:: (.*))?$', l)
|
||||
if m and m.group(2) not in ('of',):
|
||||
verdicts[m.group(2)] = (m.group(1), m.group(3) or '')
|
||||
return r.returncode, verdicts, r.stdout
|
||||
|
||||
|
||||
def fault_injection(out, ref_lines, icon_lines):
|
||||
cmp_ = None
|
||||
lines = ref_lines + icon_lines
|
||||
rc, v, text = run_compare(cmp_, lines, lines, out, 'identical')
|
||||
check(rc == 0 and all(x[0] == 'PASS' for x in v.values()), f'identical output must pass: {text[-300:]}')
|
||||
|
||||
def expect(name, guest, case, verdict_prefix, contains=None):
|
||||
rc, v, text = run_compare(cmp_, lines, guest, out, name)
|
||||
got = v.get(case, ('MISSING', ''))
|
||||
ok = got[0] == 'FAIL' and got[1].startswith(verdict_prefix) and (contains is None or contains in got[1])
|
||||
check(ok and rc == 1, f'{name}: {case} must FAIL with {verdict_prefix}{" ... " + contains if contains else ""}; '
|
||||
f'got {got} rc {rc}')
|
||||
others = [c for c, x in v.items() if c != case and x[0] == 'FAIL']
|
||||
check(not others, f'{name}: only {case} may fail; also {others[:5]}')
|
||||
|
||||
from_srgb = lambda c: 255 * ((c / 255) / 12.92 if c / 255 <= 0.04045 else ((c / 255 + 0.055) / 1.055) ** 2.4)
|
||||
to_srgb = lambda c: 255 * ((c / 255) * 12.92 if c / 255 <= 0.0031308 else 1.055 * (c / 255) ** (1 / 2.4) - 0.055)
|
||||
expect('swap', edit(lines, 'tex-rgba8-lin', lambda f: map_pixels(f, lambda p: [p[2], p[1], p[0], p[3]])),
|
||||
'tex-rgba8-lin', 'SWAP-RB')
|
||||
expect('srgb-extra', edit(lines, 'tex-rgba8-lin', lambda f: map_pixels(f, lambda p: [from_srgb(p[0]), from_srgb(p[1]),
|
||||
from_srgb(p[2]), p[3]])),
|
||||
'tex-rgba8-lin', 'SRGB-EXTRA')
|
||||
expect('srgb-missing', edit(lines, 'tex-rgba8s-lin', lambda f: map_pixels(f, lambda p: [to_srgb(p[0]), to_srgb(p[1]),
|
||||
to_srgb(p[2]), p[3]])),
|
||||
'tex-rgba8s-lin', 'SRGB-MISSING')
|
||||
expect('transparent', edit(lines, 'tex-bgra8-near', lambda f: map_pixels(f, lambda p: [0, 0, 0, 0])),
|
||||
'tex-bgra8-near', 'TRANSPARENT')
|
||||
expect('green-zero', edit(lines, 'tex-rg8-lin', lambda f: map_pixels(f, lambda p: [p[0], 0, p[2], p[3]])),
|
||||
'tex-rg8-lin', 'CHANNEL', 'G reads 0')
|
||||
expect('unwritten', edit(lines, 'tex-rg16f-lin', lambda f: f.update(sent='16384')), 'tex-rg16f-lin', 'UNWRITTEN')
|
||||
expect('partial', edit(lines, 'tex-r8-lin', lambda f: f.update(sent='512')), 'tex-r8-lin', 'PARTIAL')
|
||||
expect('readback', edit(lines, 'tex-a8-lin', lambda f: f.update(hb='0123456789abcdef')), 'tex-a8-lin', 'READBACK')
|
||||
expect('repeats', edit(lines, 'fill', lambda f: f.update(h=f['h'].split(',')[0] + ',0123456789abcdef')),
|
||||
'fill', 'NONDETERMINISTIC')
|
||||
|
||||
def stripe(k, fn):
|
||||
def apply(f):
|
||||
top, _, band = f['s'].partition('/')
|
||||
t = top.split(',')
|
||||
t[k] = fn(t)
|
||||
f['s'] = ','.join(t) + '/' + band
|
||||
return apply
|
||||
expect('input-missing', edit(lines, 'multi-4', stripe(2, lambda t: '00000000')), 'multi-4', 'INPUT-2', 'texture(2)')
|
||||
expect('input-foreign', edit(lines, 'multi-6', stripe(5, lambda t: t[1])), 'multi-6', 'INPUT-5', "input 1's colour")
|
||||
|
||||
def band(f):
|
||||
top, _, b = f['s'].partition('/')
|
||||
f['s'] = top + '/' + ','.join('10203040' for _ in b.split(','))
|
||||
expect('blend', edit(lines, 'mixed-3', band), 'mixed-3', 'BLEND')
|
||||
expect('missing-case', [l for l in lines if not body(l).startswith('C cg-ga8 ')], 'cg-ga8', 'MISSING')
|
||||
expect('error', edit(lines, 'cg-ga16f', lambda f: f.update(st='exception')), 'cg-ga16f', 'ERROR')
|
||||
# Perturbation within tolerance (+-3 on every channel, alternating) must still pass.
|
||||
flip = [1]
|
||||
|
||||
def jitter(p):
|
||||
flip[0] = -flip[0]
|
||||
return [x + 3 * flip[0] for x in p]
|
||||
rc, v, text = run_compare(cmp_, lines, edit(lines, 'tex-rgba16f-lin', lambda f: map_pixels(f, jitter)), out, 'jitter')
|
||||
check(v.get('tex-rgba16f-lin', ('?',))[0] == 'PASS', f'jitter within tolerance must pass: {v.get("tex-rgba16f-lin")}')
|
||||
# Console noise and a torn line are dropped (counted), the rest still compares.
|
||||
noisy = []
|
||||
for i, l in enumerate(lines):
|
||||
noisy.append(l)
|
||||
if i % 5 == 0:
|
||||
noisy.append('AdrenoDisplay: perf pace s=1 pps=59.8 late=0 gpu=1/4357')
|
||||
torn = [l if not body(l).startswith('C fill ') else l[:-3] for l in noisy]
|
||||
rc, v, text = run_compare(cmp_, lines, torn, out, 'noise')
|
||||
check(v.get('fill', ('?',))[0] == 'FAIL' and 'MISSING' in v.get('fill', ('', ''))[1] and
|
||||
sum(1 for x in v.values() if x[0] == 'FAIL') == 1 and 'noise dropped' in text,
|
||||
f'noise: only the torn fill line is lost: {[c for c, x in v.items() if x[0] == "FAIL"]}')
|
||||
if icon_lines:
|
||||
icon = next(body(l).split(' ')[1] for l in icon_lines if body(l).startswith('I gen-folder '))
|
||||
expect('icon-empty', edit(lines, icon, lambda f: f.update(cov='0', rgb='000000', a='00', ag='0' * 64, lg='8' * 64),
|
||||
kind='I'), icon, 'EMPTY')
|
||||
expect('icon-black', edit(lines, icon, lambda f: f.update(rgb='020202'), kind='I'), icon, 'BLACK')
|
||||
expect('icon-partial', edit(lines, icon, lambda f: f.update(ag='0' * 32 + f['ag'][32:]), kind='I'), icon, 'PARTIAL')
|
||||
expect('icon-colour', edit(lines, icon, lambda f: f.update(rgb=f['rgb'][4:6] + f['rgb'][2:4] + f['rgb'][0:2]),
|
||||
kind='I'), icon, 'WRONG-COLOUR')
|
||||
|
||||
|
||||
def console_end_to_end(out, tool, noise_rate):
|
||||
cl = load('consolelink', ROOT / 'tools/test-console-link.py')
|
||||
binary = cl.build(out)
|
||||
cases = 'tex-rgba8s-lin|tex-rg8-near|multi-3|fill'
|
||||
direct = subprocess.run([str(tool), 'synth', '--repeat', '1', '--cases', cases], capture_output=True, text=True,
|
||||
timeout=600)
|
||||
(out / 'console-direct.txt').write_text(direct.stdout)
|
||||
noise = out / 'noise.txt'
|
||||
noise.write_text(''.join(f'AdrenoDisplay: perf pace s={i} pps=59.8 late=0 gpu=1/4357\n' for i in range(200)))
|
||||
guest = out / 'guest'
|
||||
(guest / 'private/var/tmp').mkdir(parents=True)
|
||||
h = cl.Harness(binary, out, 'console', '--duration', 1500, '--shell', "PS1='sh-3.2# ' exec /bin/sh -i",
|
||||
'--loss', 0.03, '--reply-loss', 0.03, '--seed', 47, '--poll-ms', 20,
|
||||
'--noise', noise, '--noise-rate', noise_rate)
|
||||
try:
|
||||
r = subprocess.run([sys.executable, str(ROOT / 'tools/run-icon-pixels.py'), '--target', f'127.0.0.1:{h.port}',
|
||||
'--session', f'{cl.SESSION:x}', '--owner', '5eedc0de51', '--guest-root', str(guest),
|
||||
'--tool', str(tool), '--output', str(out / 'console-run'),
|
||||
'--steps', 'push,version,synth,synth-ab,icons,diag', '--console-user', '0',
|
||||
'--ab-env', 'ADRENO_CS_TABLES=0',
|
||||
'--synth-args', f"--repeat 1 --cases '{cases}'",
|
||||
'--icons-args', "--cases 'gen-(home|folder)'", '--poll-ms', '20', '--wait-ms', '60',
|
||||
'--attempts', '5'],
|
||||
capture_output=True, text=True, timeout=1500, env=dict(os.environ, PYTHONDONTWRITEBYTECODE='1'))
|
||||
(out / 'console-run.log').write_text(r.stdout + r.stderr)
|
||||
finally:
|
||||
h.process.terminate()
|
||||
h.process.wait(timeout=30)
|
||||
check(r.returncode == 0, f'run-icon-pixels exit {r.returncode}: {r.stdout[-300:]} {r.stderr[-300:]}')
|
||||
rec = json.loads((out / 'console-run/run.json').read_text()) if (out / 'console-run/run.json').is_file() else {}
|
||||
check(rec.get('status') == 'DONE' and rec.get('synth_rc') == 0 and rec.get('version_rc') == 0,
|
||||
f'console run: status {rec.get("status")} {rec.get("error")} synth rc {rec.get("synth_rc")}')
|
||||
got = (out / 'console-run/synth.txt').read_text() if (out / 'console-run/synth.txt').is_file() else ''
|
||||
# Identical but for the elapsed-time field.
|
||||
same = lambda text: [re.sub(r' ms=\d+$', '', body(l)) for l in kind_lines(text, ('C ', 'K '))]
|
||||
want = same(direct.stdout)
|
||||
check(same(got) == want and len(want) == 8,
|
||||
f'fetched C/K lines differ from a direct run ({len(same(got))} vs {len(want)} lines)')
|
||||
ab = (out / 'console-run/synth-ab.txt').read_text() if (out / 'console-run/synth-ab.txt').is_file() else ''
|
||||
check(same(ab) == want and rec.get('synth-ab_rc') == 0, f'synth-ab lines differ from a direct run ({len(same(ab))} lines)')
|
||||
icons = (out / 'console-run/icons-gen.txt').read_text() if (out / 'console-run/icons-gen.txt').is_file() else ''
|
||||
check(len(kind_lines(icons, ('I ',))) == 2 and all(' st=ok ' in l for l in kind_lines(icons, ('I ',))),
|
||||
f'icons step: {kind_lines(icons, ("I ",))}')
|
||||
check('skipped' in str(rec.get('icons_ws')) and 'diag_reasons' in rec and 'diag_unified' in rec,
|
||||
f'icons-ws skipped offline and the diag step ran: {rec.get("icons_ws")}')
|
||||
return dict(push_seconds=rec.get('push_seconds'), synth=rec.get('synth.txt'), chunks=(rec.get('push') or {}).get('chunks'))
|
||||
|
||||
|
||||
def main():
|
||||
ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument('--output', type=Path, required=True)
|
||||
ap.add_argument('--bundle', type=Path, help='an ADRENO_SETTINGS_ICONS AdrenoMetal.bundle with its compiler runtime')
|
||||
ap.add_argument('--skip-console', action='store_true')
|
||||
ap.add_argument('--noise-rate', type=int, default=40)
|
||||
a = ap.parse_args()
|
||||
out = a.output.resolve()
|
||||
out.mkdir(parents=True, exist_ok=False)
|
||||
if a.bundle:
|
||||
a.bundle = a.bundle.resolve()
|
||||
r = subprocess.run([sys.executable, str(ROOT / 'tools/build-icon-pixels.py'), '--output', str(out / 'tool')],
|
||||
capture_output=True, text=True)
|
||||
if not check(r.returncode == 0, f'build: {r.stdout[-300:]} {r.stderr[-300:]}'):
|
||||
return 1
|
||||
tool = out / 'tool/icon-pixels'
|
||||
runs = []
|
||||
for n in range(2):
|
||||
r = subprocess.run([str(tool), 'synth'] + (['--host-caps', str(a.bundle)] if a.bundle else []),
|
||||
capture_output=True, text=True, timeout=600)
|
||||
(out / f'host-synth-{n}.txt').write_text(r.stdout)
|
||||
check(r.returncode == 0, f'host synth run {n} exit {r.returncode}: {r.stderr[-300:]}')
|
||||
runs.append(r.stdout)
|
||||
pixels = lambda text: [re.sub(r' ms=\d+$', '', body(l)) for l in kind_lines(text, ('C ',))]
|
||||
check(pixels(runs[0]) and pixels(runs[0]) == pixels(runs[1]), 'two runs on this Mac\'s GPU must print the same pixels')
|
||||
rc = subprocess.run([sys.executable, str(ROOT / 'tools/compare-icon-pixels.py'), str(REFERENCE), str(out / 'host-synth-0.txt'),
|
||||
'--tolerance', '0'], capture_output=True, text=True)
|
||||
(out / 'reference-check.txt').write_text(rc.stdout)
|
||||
check(rc.returncode == 0, f'this Mac no longer reproduces {REFERENCE.name} exactly: {rc.stdout.strip().splitlines()[-1:]}')
|
||||
if a.bundle:
|
||||
for units, label in (('8', 'cs8'), (None, 'cs1')):
|
||||
argv = [str(tool), 'synth', '--plugin', str(a.bundle)] + (['--cs-samplers', units] if units else [])
|
||||
p = subprocess.run(argv, capture_output=True, text=True, timeout=900)
|
||||
(out / f'plugin-{label}.txt').write_text(p.stdout)
|
||||
check(p.returncode == 0, f'plug-in synth ({label}) exit {p.returncode}: {p.stderr[-300:]}')
|
||||
c = subprocess.run([sys.executable, str(ROOT / 'tools/compare-icon-pixels.py'), str(REFERENCE),
|
||||
str(out / f'plugin-{label}.txt'), '--census-only'], capture_output=True, text=True)
|
||||
(out / f'plugin-{label}.compare.txt').write_text(c.stdout)
|
||||
if units:
|
||||
check(c.returncode == 0, f'plug-in census (8 CS sampler units) differs: {c.stdout.strip().splitlines()[-1:]}')
|
||||
else:
|
||||
dropped = re.search(r'dropped=(\d+)', p.stdout)
|
||||
check(c.returncode == 1 and dropped and int(dropped.group(1)) > 0 and 'plugin-diagnostics' in c.stdout,
|
||||
'without AdrenoIBComputeSamplers the multi-input kernels must be dropped and reported')
|
||||
ref_lines = [l for l in REFERENCE.read_text().splitlines() if l.strip()]
|
||||
icons = subprocess.run([str(tool), 'icons', '--size', '20'], capture_output=True, text=True, timeout=600)
|
||||
icon_lines = [l for l in icons.stdout.splitlines() if l.startswith(('I ', 'K gen-', 'K ws-'))]
|
||||
check(icons.returncode == 0 and len([l for l in icon_lines if l.startswith('I ')]) >= 10,
|
||||
f'icons on this Mac: exit {icons.returncode}, {len(icon_lines)} lines')
|
||||
(out / 'faults').mkdir()
|
||||
fault_injection(out / 'faults', ref_lines, icon_lines)
|
||||
console = None
|
||||
if not a.skip_console:
|
||||
console = console_end_to_end(out, tool, a.noise_rate)
|
||||
result = dict(checks=checks, failures=failures, console=console, tool=json.loads((out / 'tool/build.json').read_text()))
|
||||
(out / 'result.json').write_text(json.dumps(result, indent=1) + '\n')
|
||||
print(f'{"PASS" if not failures else "FAIL"}: {checks} checks ({len(failures)} failed); {out / "result.json"}')
|
||||
return 0 if not failures else 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user