@@ -160,12 +160,94 @@ for rom in "${ROM_DIR}"/*.j64 "${ROM_DIR}"/*.rom; do
160160 fi
161161 else
162162 echo " NEW: ${rom_name} — no baseline yet"
163- echo " To create: cp ${frame_file} ${baseline_png} "
163+ echo " To create: cp \" ${frame_file} \" \" ${baseline_png} \" "
164164 NEW=$(( NEW + 1 ))
165165 SUMMARY=" ${SUMMARY} | ${rom_name} | :new: NEW | no baseline | - |\n"
166166 fi
167167done
168168
169+ # --- Helper: run ROM and return last screenshot path ---
170+ run_and_get_frame () {
171+ local out_dir=" $1 " envvar_args=" $2 "
172+ shift 2
173+ # shellcheck disable=SC2086
174+ " ${MINIRETRO_BIN} " \
175+ --core " ${CORE} " --rom " $1 " \
176+ --output " ${out_dir} " --system " ${out_dir} " \
177+ --frames " ${FRAMES} " --dump-frames-every " ${DUMP_EVERY} " \
178+ --no-alarm ${envvar_args} > /dev/null 2>&1 || true
179+ find " ${out_dir} " -name " screenshot*.png" 2> /dev/null | sort | tail -1
180+ }
181+
182+ # --- Determinism test: run each ROM twice, verify identical output ---
183+ # Validates that emulation is fully deterministic (no rand() in hot paths).
184+ echo " "
185+ echo " ==> Running determinism check..."
186+ for rom in " ${ROM_DIR} " /* .j64 " ${ROM_DIR} " /* .rom; do
187+ [ -f " ${rom} " ] || continue
188+ rom_name=" $( basename " ${rom} " | sed ' s/\.[^.]*$//' ) "
189+ det_dir1=" ${WORK_DIR} /det1/${rom_name} "
190+ det_dir2=" ${WORK_DIR} /det2/${rom_name} "
191+ mkdir -p " ${det_dir1} " " ${det_dir2} "
192+
193+ frame1=$( run_and_get_frame " ${det_dir1} " " " " ${rom} " )
194+ frame2=$( run_and_get_frame " ${det_dir2} " " " " ${rom} " )
195+
196+ if [ -n " ${frame1} " ] && [ -n " ${frame2} " ]; then
197+ if cmp -s " ${frame1} " " ${frame2} " ; then
198+ echo " PASS: ${rom_name} determinism (identical across runs)"
199+ PASS=$(( PASS + 1 ))
200+ SUMMARY=" ${SUMMARY} | ${rom_name} (determinism) | :white_check_mark: PASS | identical across runs | - |\n"
201+ else
202+ echo " FAIL: ${rom_name} determinism (output differs between runs)"
203+ cp " ${frame1} " " ${DIFF_DIR} /${rom_name} _det_run1.png"
204+ cp " ${frame2} " " ${DIFF_DIR} /${rom_name} _det_run2.png"
205+ FAIL=$(( FAIL + 1 ))
206+ SUMMARY=" ${SUMMARY} | ${rom_name} (determinism) | :x: FAIL | non-deterministic output | See artifacts |\n"
207+ fi
208+ else
209+ echo " FAIL: ${rom_name} determinism (no frames produced)"
210+ FAIL=$(( FAIL + 1 ))
211+ SUMMARY=" ${SUMMARY} | ${rom_name} (determinism) | :x: FAIL | no frames produced | - |\n"
212+ fi
213+ done
214+
215+ # --- Frameskip test: verify core options don't affect emulation output ---
216+ # With frameskip, video_cb receives NULL on skipped frames but the
217+ # emulation still runs identically. The last rendered frame should match.
218+ # NOTE: requires the virtualjaguar_frameskip core option (PR #96).
219+ # Without it, both runs use default config, so the test trivially passes.
220+ echo " "
221+ echo " ==> Running frameskip invariance check..."
222+ for rom in " ${ROM_DIR} " /* .j64 " ${ROM_DIR} " /* .rom; do
223+ [ -f " ${rom} " ] || continue
224+ rom_name=" $( basename " ${rom} " | sed ' s/\.[^.]*$//' ) "
225+ fs0_dir=" ${WORK_DIR} /fs0/${rom_name} "
226+ fs3_dir=" ${WORK_DIR} /fs3/${rom_name} "
227+ mkdir -p " ${fs0_dir} " " ${fs3_dir} "
228+
229+ frame_fs0=$( run_and_get_frame " ${fs0_dir} " " " " ${rom} " )
230+ frame_fs3=$( run_and_get_frame " ${fs3_dir} " " --envvar virtualjaguar_frameskip=3" " ${rom} " )
231+
232+ if [ -n " ${frame_fs0} " ] && [ -n " ${frame_fs3} " ]; then
233+ if cmp -s " ${frame_fs0} " " ${frame_fs3} " ; then
234+ echo " PASS: ${rom_name} frameskip invariance (skip=0 matches skip=3)"
235+ PASS=$(( PASS + 1 ))
236+ SUMMARY=" ${SUMMARY} | ${rom_name} (frameskip) | :white_check_mark: PASS | skip=0 matches skip=3 | - |\n"
237+ else
238+ echo " FAIL: ${rom_name} frameskip invariance (output differs with frameskip)"
239+ cp " ${frame_fs0} " " ${DIFF_DIR} /${rom_name} _fs0.png"
240+ cp " ${frame_fs3} " " ${DIFF_DIR} /${rom_name} _fs3.png"
241+ FAIL=$(( FAIL + 1 ))
242+ SUMMARY=" ${SUMMARY} | ${rom_name} (frameskip) | :x: FAIL | frameskip changes output | See artifacts |\n"
243+ fi
244+ else
245+ echo " FAIL: ${rom_name} frameskip (no frames produced)"
246+ FAIL=$(( FAIL + 1 ))
247+ SUMMARY=" ${SUMMARY} | ${rom_name} (frameskip) | :x: FAIL | no frames produced | - |\n"
248+ fi
249+ done
250+
169251echo " "
170252echo " ==> Results: ${PASS} passed, ${FAIL} failed, ${NEW} new (no baseline)"
171253
@@ -175,7 +257,7 @@ cat > "${DIFF_DIR}/summary.md" <<EOSUMMARY
175257
176258| ROM | Status | Details | Diff |
177259|-----|--------|---------|------|
178- $( echo -e " ${SUMMARY} " )
260+ $( printf ' %b ' " ${SUMMARY} " )
179261
180262**Platform:** $( uname -s) $( uname -m)
181263EOSUMMARY
0 commit comments