GetVibrationDeviceHandles used routed haptics availability to decide whether handles existed. Games that cache this answer at startup could retain an empty answer after a controller connected. Return handles for a connected npad style when rumble is enabled and an output sink is installed; check routed outputs when values are sent, keeping the existing permission and lifecycle behavior. Include the PR's rumble diagnostics, count unroutable values individually in mixed batches, and protect aggregate counters across game threads. Correct the code comment to describe Unicorn Overlord's observed empty handles and zero values without claiming restored physical rumble. Add regressions for cached startup handles delivering a nonzero value after routing, diagnostic totals and concurrent sends. Include HID in the existing ThreadSanitizer target and record the mechanism in the service reference. Checked with GAME=010069401ADB8000: full host suite, 73 HID checks, audio and HID ThreadSanitizer checks, docs checks, Mac host build, and iOS compilation (133 files). Physical rumble and iOS runtime remain untested. Broader tool validation is incomplete because Capstone is missing and iconutil failed. Co-authored-by: parsifal295 <130349765+parsifal295@users.noreply.github.com>
139 lines
8.1 KiB
Makefile
139 lines
8.1 KiB
Makefile
# dm/host unit tests in one command: make -C dm/host/tests GAME=<base game title ID> run (takes seconds; build output goes to build/ and is not committed)
|
|
B = build
|
|
PYTHON ?= python3
|
|
# game profile header (dm.h needs game_profile.h, generated by the host Makefile into ../gen/<profile>/)
|
|
# tests that use the game profile need GAME=<base game title ID> (there is no default game); GINC only expands when used, so tests without the profile build as before
|
|
GINC = $(if $(strip $(GAME)),-I../gen/$(GAME) -I../../games/$(GAME),$(error GAME is not set: make GAME=<base game title ID>: $(shell python3 ../../games/game.py list | awk -F'\t' '{printf "%s (%s) ", $$1, $$3}')))
|
|
GAME_H = ../gen/$(GAME)/game_profile.h
|
|
run: $(B)/t_heap_size $(B)/t_touch $(B)/t_gesture $(B)/t_oe $(B)/t_fs $(B)/t_fs_commit_list $(B)/t_thread_leak $(B)/t_fs_case $(B)/t_audio $(B)/t_audio_spsc $(B)/t_swkbd $(B)/t_altstack $(B)/t_condvar $(B)/t_condvar_old $(B)/t_pctl $(B)/t_time $(B)/t_shared_font $(B)/t_vorbis $(B)/t_vorbis_divides $(B)/t_hid $(B)/t_haptics $(B)/t_haptics_apple
|
|
$(B)/t_heap_size
|
|
$(B)/t_touch
|
|
$(B)/t_gesture
|
|
$(B)/t_oe 2>/dev/null
|
|
$(B)/t_fs 2>/dev/null
|
|
TMPDIR="$(abspath $(B))" $(B)/t_fs_commit_list
|
|
$(B)/t_thread_leak
|
|
TMPDIR="$(abspath $(B))" $(B)/t_fs_case 2>/dev/null
|
|
$(B)/t_audio
|
|
$(B)/t_audio_spsc
|
|
$(B)/t_swkbd
|
|
$(B)/t_altstack
|
|
$(B)/t_condvar
|
|
$(B)/t_condvar_old
|
|
$(B)/t_preempt
|
|
$(B)/t_preempt --all-peers
|
|
$(B)/t_pctl
|
|
$(B)/t_time
|
|
$(B)/t_shared_font
|
|
$(B)/t_system_event
|
|
$(B)/t_vorbis
|
|
$(B)/t_vorbis_divides
|
|
$(B)/t_hid
|
|
$(B)/t_haptics
|
|
$(B)/t_haptics_apple
|
|
$(B)/t_nro
|
|
run: $(B)/t_nro
|
|
run: $(B)/t_system_event
|
|
$(B)/t_system_event: t_system_event.c ../hle_thread.c ../hle_sdk16.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wall -Werror -Wno-unused-function -Wno-frame-address -I.. $(GINC) -o $@ t_system_event.c
|
|
.PHONY: system-event
|
|
system-event: $(B)/t_system_event
|
|
$(B)/t_system_event
|
|
$(B)/t_nro: t_nro.c ../loader.c ../hle_ro.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wall -Wno-unused-function -Wno-deprecated-declarations -I.. $(GINC) -o $@ t_nro.c
|
|
.PHONY: nro
|
|
nro: $(B)/t_nro
|
|
$(B)/t_nro
|
|
$(GAME_H):
|
|
$(MAKE) -C .. game_profile GAME=$(GAME)
|
|
$(B)/t_heap_size: t_heap_size.c ../hle_svc.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Werror -Wno-unused-function -fsanitize=undefined -I.. $(GINC) -o $@ t_heap_size.c
|
|
.PHONY: heap_size
|
|
heap_size: $(B)/t_heap_size
|
|
$(B)/t_heap_size
|
|
$(B)/t_touch: t_touch.c ../hle_touch.c ../front.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_touch.c ../hle_touch.c
|
|
$(B)/t_gesture: t_gesture.c ../hle_touch.c ../front.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Wno-unused-function -I.. $(GINC) -o $@ t_gesture.c ../hle_touch.c
|
|
$(B)/t_thread_leak: t_thread_leak.c ../thread.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_thread_leak.c
|
|
$(B)/t_fs: t_fs.c t_fs_stub.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_fs.c t_fs_stub.c ../hle_bigstack.c
|
|
$(B)/t_fs_commit_list: t_fs_commit_list.c t_fs_stub.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Wno-unused-function -I.. $(GINC) -o $@ t_fs_commit_list.c t_fs_stub.c ../hle_bigstack.c
|
|
$(B)/t_fs_case: t_fs_case.c ../hle_fs.c ../hle_bigstack.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_fs_case.c ../hle_bigstack.c
|
|
$(B)/t_audio: t_audio.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_audio.c -framework AudioToolbox
|
|
$(B)/t_audio_spsc: t_audio_spsc.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_audio_spsc.c -framework AudioToolbox
|
|
$(B)/t_audio_spsc_tsan: t_audio_spsc.c ../hle_audio.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -O1 -fsanitize=thread -Wno-unused-function -I.. $(GINC) -o $@ t_audio_spsc.c -framework AudioToolbox
|
|
$(B)/t_swkbd: t_swkbd.c ../hle_swkbd.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_swkbd.c ../hle_swkbd.c
|
|
$(B)/t_altstack: t_altstack.c t_altstack_stub.c ../crash.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_altstack.c t_altstack_stub.c ../crash.c
|
|
$(B)/t_pctl: t_pctl.c ../hle_misc.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_pctl.c
|
|
$(B)/t_shared_font: t_shared_font.c ../hle_sdk16.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Werror -Wno-unused-function -Wno-frame-address -I.. $(GINC) -o $@ t_shared_font.c
|
|
$(B)/t_hid: t_hid.c ../hle_hid.c ../hle_haptics.c ../hle_haptics.h ../pad_slots.h ../dm_input.h ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_hid.c ../hle_haptics.c
|
|
$(B)/t_hid_tsan: t_hid.c ../hle_hid.c ../hle_haptics.c ../hle_haptics.h ../pad_slots.h ../dm_input.h ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -fsanitize=thread -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_hid.c ../hle_haptics.c
|
|
$(B)/t_haptics: t_haptics.c ../hle_haptics.c ../hle_haptics.h ../dm_input.h | $(B)
|
|
clang -O1 -g -Wall -Werror -I.. -o $@ t_haptics.c ../hle_haptics.c
|
|
$(B)/t_haptics_apple: t_haptics_apple.m ../haptics_apple.m ../haptics_apple.h ../hle_haptics.c ../hle_haptics.h | $(B)
|
|
clang -O1 -g -fobjc-arc -Wall -Werror -I.. -o $@ t_haptics_apple.m ../hle_haptics.c -framework Cocoa -framework GameController -framework CoreHaptics
|
|
$(B)/t_time: t_time.c ../hle_time.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_time.c
|
|
$(B)/t_oe: t_oe.c ../hle_oe.c ../hle.h ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -I.. $(GINC) -o $@ t_oe.c
|
|
$(B)/t_condvar: t_condvar.c t_condvar_stub.c ../hle_thread.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -DDM_TEST_HOOKS -I.. $(GINC) -o $@ t_condvar.c t_condvar_stub.c ../hle_thread.c
|
|
$(B)/t_condvar_old: t_condvar.c t_condvar_stub.c ../hle_thread.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -Wno-unused-function -DDM_TEST_HOOKS -DDM_TEST_CV_OLD_ORDER -I.. $(GINC) -o $@ t_condvar.c t_condvar_stub.c ../hle_thread.c
|
|
$(B)/t_preempt: t_preempt.c t_condvar_stub.c ../hle_thread.c ../dm.h $(GAME_H) | $(B)
|
|
clang -O1 -g -Wall -Werror -Wno-unused-function -I.. $(GINC) -o $@ t_preempt.c t_condvar_stub.c
|
|
.PHONY: preempt
|
|
preempt: $(B)/t_preempt
|
|
$(B)/t_preempt
|
|
$(B)/t_preempt --all-peers
|
|
run: $(B)/t_preempt
|
|
# the Vorbis tests build their own packets and need no game profile (they build without GAME)
|
|
$(B)/t_vorbis: t_vorbis.c ../../third_party/stb_vorbis/stb_vorbis.c | $(B)
|
|
clang -O1 -g -Wno-unused-function -Wno-tautological-compare -o $@ t_vorbis.c
|
|
$(B)/t_vorbis_divides: t_vorbis.c ../../third_party/stb_vorbis/stb_vorbis.c | $(B)
|
|
clang -O1 -g -DSTB_VORBIS_DIVIDES_IN_RESIDUE -Wno-unused-function -Wno-tautological-compare -o $@ t_vorbis.c
|
|
$(B):
|
|
mkdir -p $@
|
|
.PHONY: run tsan
|
|
tsan: $(B)/t_audio_spsc_tsan $(B)/t_hid_tsan
|
|
$(B)/t_audio_spsc_tsan
|
|
$(B)/t_hid_tsan
|
|
|
|
MEM_FLAGS = -O1 -Wall -Werror -Wno-unused-function -Imemory_profile -I..
|
|
MEM_DEPS = t_svc_memory.c memory_profile/game_profile.h ../hle_svc.c ../hle_guestthread.c ../hle.h ../dm.h
|
|
$(B)/t_svc_memory: $(MEM_DEPS) | $(B)
|
|
clang $(MEM_FLAGS) -fsanitize=undefined -o $@ t_svc_memory.c
|
|
$(B)/t_svc_memory_unlimited: $(MEM_DEPS) | $(B)
|
|
clang $(MEM_FLAGS) -fsanitize=undefined -DDM_GAME_MEM_MAP_LIMIT=0 -o $@ t_svc_memory.c
|
|
$(B)/t_svc_memory_16k: $(MEM_DEPS) | $(B)
|
|
clang $(MEM_FLAGS) -fsanitize=address,undefined -DTEST_PAGE_16K -o $@ t_svc_memory.c
|
|
$(B)/t_svc_memory_tsan: $(MEM_DEPS) | $(B)
|
|
clang $(MEM_FLAGS) -fsanitize=thread -o $@ t_svc_memory.c
|
|
$(B)/t_svc_memory_dirty: $(MEM_DEPS) ../../gfx/nvn/nvn_dirty.c ../../gfx/nvn/nvn_dirty.h | $(B)
|
|
clang $(MEM_FLAGS) -DTEST_REAL_DIRTY -o $@ t_svc_memory.c ../../gfx/nvn/nvn_dirty.c
|
|
.PHONY: memory memory-tsan memory-dirty memory-profile
|
|
memory: $(B)/t_svc_memory $(B)/t_svc_memory_unlimited $(B)/t_svc_memory_16k
|
|
$(B)/t_svc_memory
|
|
$(B)/t_svc_memory_unlimited
|
|
$(B)/t_svc_memory_16k
|
|
memory-tsan: $(B)/t_svc_memory_tsan
|
|
$(B)/t_svc_memory_tsan
|
|
memory-dirty: $(B)/t_svc_memory_dirty
|
|
$(B)/t_svc_memory_dirty
|
|
memory-profile: $(B)/t_svc_memory
|
|
$(PYTHON) test_memory_profile.py
|
|
run: memory memory-dirty memory-profile
|