#!/usr/bin/env python3 # SPDX-License-Identifier: MIT """Independent exact queued-blit wire/CPU-observation oracle; no GPU execution. Failure inventory: docs/ADRENO-BLIT-ENCODING-E2E-20261019.md. """ import argparse,copy,importlib.util,json,struct,sys from pathlib import Path sys.dont_write_bytecode=True ROOT=Path(__file__).resolve().parents[1] spec=importlib.util.spec_from_file_location('mps_wire',ROOT/'tools/decode-mps-encoding.py') m=importlib.util.module_from_spec(spec);spec.loader.exec_module(m) require=m.require;sha=m.sha;enum=m.enum;field=m.field CASES={'buffer-offsets','texture-buffer-rows','buffer-texture-rows','texture-texture-rows','whole-texture','rebound-buffer-chain','fill-copy-buffer','copy-fill-buffer','mps-copy-fill-render'} CONTROLS={'bad-buffer-range','overflow-offset','unaligned-offset','overlap','short-row-pitch','bad-texture-origin','format-mismatch','unsupported-option','unsupported-level','unsupported-slice','missing-copy-abi','mipmap-refusal'} def check(c,directory,overrides=None): overrides=overrides or {} def read(row,key='file',hashkey='sha256'): return overrides[row[key]] if row[key] in overrides else m.filebytes(directory,row,key,hashkey) require(c['status']=='QUEUED_BLIT_ENCODING_CAPTURE_ONLY' and c['gpu_submission'] is False,'blit capture boundary/status') require({x['name'] for x in c['cases']}==CASES and len(c['cases'])==len(CASES),'positive case matrix') require(c['intercepted_commits']==len(CASES)==len(c['streams']),'actual native commit count') require(not c['completion_handlers'],'CPU completion copy replay remains') output=[] for case in c['cases']: name=case['name'];work=case['work'];copies=[r for r in c['copies'] if r['case']==name] require(work['omitted']==0 and not work['encoding_failed'] and not work['trace_incomplete'],'omitted/failed/incomplete blit work') require(all(e['ended'] for e in work['encoders'].values()),'unbalanced encoder') require(case['released_external_owners_before_commit'],'resource lifetime case not exercised') snapshots={r['id']:bytearray(read(r,'initial_file','initial_sha256')) for r in case['memory']} require(all(len(snapshots[r['id']])==r['bytes'] for r in case['memory']),'full allocation snapshot extent') checks=[r for r in c['memory_checks'] if r['case']==name] require(checks and checks[-1]['phase']=='intercepted-native-commit','missing post-encoding CPU observation') initial=[r['initial_sha256'] for r in case['memory']] require(all(r['hashes']==initial[:len(r['hashes'])] for r in checks),'CPU memory changed during encoding') if case['copy_only_model']: if name=='fill-copy-buffer': source=copies[0]['expected_spans'][0]['source'];snapshots[source][16:24]=b'\x5a'*8 for call in copies: require('exception' not in call,'positive copy raised') for span in call['expected_spans']: source=snapshots[span['source']];destination=snapshots[span['destination']] so,do,n=span['source_offset'],span['destination_offset'],span['bytes'] require(0cp[-1]['word']]) events=lambda names:[('event',enum(n)) for n in names] packets=lambda names:[('packet',enum(n)) for n in names] require(before==packets(['CP_THREAD_CONTROL'])+events(['CCU_CLEAN_COLOR','CCU_CLEAN_DEPTH','CACHE_CLEAN','DUMMY_EVENT','SUBPASS_FENCE','DUMMY_EVENT'])+ packets(['CP_WAIT_FOR_IDLE','CP_WAIT_MEM_WRITES']),'copy producer visibility boundary') require(after==packets(['CP_WAIT_MEM_WRITES'])+events(['CCU_CLEAN_COLOR','CCU_CLEAN_DEPTH','CCU_INVALIDATE_COLOR','CCU_INVALIDATE_DEPTH','CACHE_INVALIDATE7','DUMMY_EVENT','SUBPASS_FENCE','DUMMY_EVENT'])+ packets(['CP_WAIT_FOR_IDLE','CP_CCHE_INVALIDATE','CP_WAIT_FOR_IDLE']),'copy consumer visibility boundary') elif 'dispatch' in p: dispatch=next(r for r in c['dispatches'] if r['ordinal']==p['dispatch']) program=next(r['program'] for r in c['pipelines'] if r['entry']==dispatch['pipeline']) m.decode_compute(d,p,dispatch,program,base,base+len(pw));operations.append({'kind':'CP_EXEC_CS','pipeline':dispatch['pipeline']}) else:operations.append({'kind':p['kind']}) base+=len(pw) data.extend(b'\0'*(m.align(len(data))-len(data))) require(base==4*d['header']['ib_dwords'] and d['package'][d['data_offset']:]==data,'unaccounted pass data/words') decoded.append({k:v for k,v in d.items() if k!='package'}|{'file':package['file'],'sha256':sha(raw)}) streamrow=next(r for r in c['streams'] if r['case']==name);stream=read(streamrow);at=0;ib=0;fills=0;layout=[];fill_commands=[] while at=8 and at+size<=len(stream),'native command size');raw=stream[at:at+size] if typ==0x1002: require(ib