diff --git a/docs/RUNNING.md b/docs/RUNNING.md index 87f392e..f3d2274 100644 --- a/docs/RUNNING.md +++ b/docs/RUNNING.md @@ -142,7 +142,7 @@ The flags fall into these groups: | Console and early stop | `--console`, `--single-user`, `--early-stop-delay`, `--let-panic`, `--panic-serve` | | Input | `--input`, `--input-touchpad`, `--input-ptp`, `--input-active-us` | | Present path | `--present-dartpool`, `--present-resident`, `--present-beam`, `--present-va-reclaim`, `--present-maint`, `--present-latch`, `--present-pipeline` | -| GPU | `--ib-async`, `--gpu-recover`, `--gpu-va-wide`, `--gpu-coherent`, `--resident-mib`, `--adreno-fill-br`, `--adreno-fence-br`, `--gpu-x290-survey` | +| GPU | `--ib-async`, `--gpu-recover`, `--gpu-va-wide`, `--gpu-coherent`, `--resident-mib`, `--adreno-fill-br`, `--adreno-fence-br`, `--adreno-cs-samplers`, `--gpu-x290-survey` | | Panel brightness | `--edp-backlight`, `--edp-backlight-mode` | | Clocks and bandwidth | `--thermal-guard`, `--gpu-dvfs`, `--gpu-dvfs-ceiling`, `--cpu-dvfs`, `--ddr-vote`, `--llcc`, `--bw-probe` | | Storage | `--nvme-async`, `--nvme-converted` | @@ -229,8 +229,9 @@ installed and only continues the boot). The kext side of the icons inside System Settings panes, `ADRENO_IB_CS_SAMPLERS` in the desktop AdrenoX2 profiles, is off unless the guest boots with -`adreno_cs_samplers=1`. `tools/cycle.py` has no option that adds that boot-arg -yet. +`adreno_cs_samplers=1`, which `tools/cycle.py installed-fresh --adreno-cs-samplers` +adds (`tools/test-adreno-cs-samplers.py`). An AdrenoX2 built without the define +ignores the boot-arg. ## Exit codes diff --git a/tools/cycle.py b/tools/cycle.py index 491e721..b4e914d 100755 --- a/tools/cycle.py +++ b/tools/cycle.py @@ -491,6 +491,12 @@ def parse(argv=None): help='guest boot-arg adreno_present_maint=1: AdrenoDisplay keeps its layer-0 clean+invalidate pass ' 'even while the beam is LOCKED (tear-free fix2 skips it then); for b12v8\'s stale bands; ' 'give it to every mode of the attempt') + p.add_argument('--adreno-cs-samplers', action='store_true', + help='guest boot-arg adreno_cs_samplers=1: an AdrenoX2 built with ADRENO_IB_CS_SAMPLERS (the desktop ' + 'profiles since agents/settings-icons; others ignore it) lets the IB validator admit CS sampler ' + 'loads of up to 8 units and publishes AdrenoIBComputeSamplers, so an ADRENO_SETTINGS_ICONS ' + 'plug-in encodes CoreImage\'s multi-input kernels (folder, document and Safari icons in System ' + 'Settings panes); give it to every mode of the attempt') p.add_argument('--spmi-scratch', action='store_true', help='SNAP_SPMI_SCRATCH: the emulated SPMI controller also serves the PMU scratch-pad registers ' '(f700-f7ff, 8f80-8fff) from RAM, so AppleDialogSPMIPMU::_readRegs stops failing with e00002bc ' diff --git a/tools/cycle_lib/installed_fresh.py b/tools/cycle_lib/installed_fresh.py index baa9e12..83a05e3 100644 --- a/tools/cycle_lib/installed_fresh.py +++ b/tools/cycle_lib/installed_fresh.py @@ -1158,6 +1158,8 @@ def boot_addition(args): extra = [] if getattr(args, 'present_maint', False): extra.append('adreno_present_maint=1') + if getattr(args, 'adreno_cs_samplers', False): + extra.append('adreno_cs_samplers=1') # read only by an ADRENO_IB_CS_SAMPLERS AdrenoX2 (configureDevice) if getattr(args, 'gpu_coherent', False): extra.append('adreno_coherent=1') # the kext still skips only after the monitor's self-test said ON if getattr(args, 'gpu_coherent_force', False): diff --git a/tools/test-adreno-cs-samplers.py b/tools/test-adreno-cs-samplers.py new file mode 100755 index 0000000..2b6b6fd --- /dev/null +++ b/tools/test-adreno-cs-samplers.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: MIT +"""Host test for cycle.py installed-fresh --adreno-cs-samplers. No A16 access. + +Without the option the boot-argument addition is exactly what earlier attempts qualified; with it, it appends +adreno_cs_samplers=1 once. The other half of the contract is SnapAdreno's: the boot-arg name is the one AdrenoX2's +configureDevice reads, that read sits under ADRENO_IB_CS_SAMPLERS, and the desktop profiles build AdrenoX2 and +adreno-ib-command with that define (a kext without it ignores the boot-arg). +""" +import argparse +import importlib.util +import os +import re +import subprocess +import sys +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +sys.path.insert(0, str(ROOT / 'tools')) +from cycle_lib import installed_fresh as fresh # noqa: E402 + +spec = importlib.util.spec_from_file_location('cycle_cli', ROOT / 'tools/cycle.py') +cli = importlib.util.module_from_spec(spec) +spec.loader.exec_module(cli) + +BASE = ' '.join([fresh.TIMESYNC_FLAG, fresh.COMPRESSOR_SW_FLAG]) +KEXT = ROOT / 'gpu/adreno-kext/kext' +BOOT_ARG = 'adreno_cs_samplers' +DEFINE = 'ADRENO_IB_CS_SAMPLERS' + + +def ns(**kw): + return argparse.Namespace(**kw) + + +def profile_units(name): + """{unit: defines} of a SnapAdreno profile, as build.sh sources it.""" + script = f'. "$D/profiles/{name}.sh"; set | grep "^U_"' + out = subprocess.run(['sh', '-c', script], env=dict(os.environ, D=str(KEXT)), capture_output=True, text=True, + check=True).stdout + units = {} + for line in out.splitlines(): + unit, _, value = line.partition('=') + units[unit[2:]] = value.strip('\'"').split() + return units + + +class AdrenoCsSamplers(unittest.TestCase): + def test_default_unchanged(self): + self.assertEqual(fresh.boot_addition(ns()), BASE) + self.assertEqual(fresh.boot_addition(ns(adreno_cs_samplers=False)), BASE) + + def test_flag_adds_the_boot_arg_once(self): + self.assertEqual(fresh.boot_addition(ns(adreno_cs_samplers=True)), f'{BASE} {BOOT_ARG}=1') + line = fresh.boot_addition(ns(console=True, single_user=True, adreno_cs_samplers=True, edp_backlight=True, + input=True, input_fnkeys=3, resident_mib=1536)) + words = line.split() + self.assertEqual(words.count(f'{BOOT_ARG}=1'), 1, line) + for word in ('adreno_backlight=1', 'snap_i2c_fnkeys=3', 'adreno_resident_mib=1536', fresh.SINGLE_USER_FLAG): + self.assertIn(word, words, line) + + def test_cli_reaches_args(self): + base = ['installed-fresh', '--prefix', 'x', '--variant', 'fast', '--check'] + self.assertFalse(cli.parse(base).adreno_cs_samplers) + self.assertTrue(cli.parse(base + ['--adreno-cs-samplers']).adreno_cs_samplers) + + def test_kext_reads_this_boot_arg_under_its_define(self): + src = (KEXT / 'src/AdrenoX2/device.cpp').read_text() + reads = re.findall(r'PE_parse_boot_argn\("(adreno_cs_samplers)"', src) + self.assertEqual(reads, [BOOT_ARG]) + depth, guarded = [], None + for line in src.splitlines(): + s = line.strip() + if s.startswith('#if'): + depth.append(DEFINE in s) + elif s.startswith('#endif'): + depth.pop() + elif f'"{BOOT_ARG}"' in s and 'PE_parse_boot_argn' in s: + guarded = any(depth) + self.assertTrue(guarded, 'the boot-arg read is not under ADRENO_IB_CS_SAMPLERS') + + def test_desktop_profiles_build_the_opt_in(self): + for name in ('desktop-nocoherent', 'desktop', 'desktop-backlight', 'desktop-next'): + units = profile_units(name) + for unit in ('AdrenoX2', 'adreno_ib_command'): + self.assertIn(f'-D{DEFINE}=1', units.get(unit, []), f'{name} {unit}') + + +if __name__ == '__main__': + unittest.main()