diff --git a/.gitignore b/.gitignore index 2a6b1e1..e69de29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +0,0 @@ -# Ignore files generated by citra or the VNC client -citra/out -driver/out diff --git a/README.md b/README.md index 1901e4b..d987acc 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,19 @@ A set of tools for running automated Rust tests against Citra (3DS emulator). 1. Build a test executable (type tbd) 1. `citra-emu` container: bind-mount test executable and choose it 1. `driver` container perform input / output as needed for test, via VNC - * possible extension: `3dslink -s` to get actual stdout/stderr (return code?) - * acceptance testing of images, hopefully via screenshot + +## To do work + +* [ ] Reorganize docker build files vs runtime files a bit +* [ ] Make this repo useable as a github action +* [ ] Run itself as part of CI? I guess? +* [ ] Simpler user-run workflow: + * Ideally, a single command to spin everything up, build + load a 3dsx and run a vdo script. + * Maybe cargo args passed in as environment variable or something? +* [ ] Clearly defined dependencies + use cases: + * Should this be usable without Rust? + * Is docker the only real dependency? + * Does this need a separate binary, or can we just use native cargo test + capabilities? diff --git a/citra/qt-config.ini b/citra/qt-config.ini deleted file mode 100644 index 1ad0544..0000000 --- a/citra/qt-config.ini +++ /dev/null @@ -1,496 +0,0 @@ -[Audio] -enable_audio_stretching=true -enable_audio_stretching\default=true -enable_dsp_lle=false -enable_dsp_lle\default=true -enable_dsp_lle_multithread=false -enable_dsp_lle_multithread\default=true -mic_input_device=Default -mic_input_device\default=true -mic_input_type=0 -mic_input_type\default=true -output_device=auto -output_device\default=true -output_engine=auto -output_engine\default=true -volume=@Variant(\0\0\0\x87?\x80\0\0) -volume\default=true - -[Camera] -camera_inner_config= -camera_inner_config\default=true -camera_inner_flip=0 -camera_inner_flip\default=true -camera_inner_name=blank -camera_inner_name\default=true -camera_outer_left_config= -camera_outer_left_config\default=true -camera_outer_left_flip=0 -camera_outer_left_flip\default=true -camera_outer_left_name=blank -camera_outer_left_name\default=true -camera_outer_right_config= -camera_outer_right_config\default=true -camera_outer_right_flip=0 -camera_outer_right_flip\default=true -camera_outer_right_name=blank -camera_outer_right_name\default=true - -[Controls] -profile=0 -profile\default=true -profiles\1\button_a="code:65,engine:keyboard" -profiles\1\button_a\default=true -profiles\1\button_b="code:83,engine:keyboard" -profiles\1\button_b\default=true -profiles\1\button_debug="code:79,engine:keyboard" -profiles\1\button_debug\default=true -profiles\1\button_down="code:71,engine:keyboard" -profiles\1\button_down\default=true -profiles\1\button_gpio14="code:80,engine:keyboard" -profiles\1\button_gpio14\default=true -profiles\1\button_home="code:66,engine:keyboard" -profiles\1\button_home\default=true -profiles\1\button_l="code:81,engine:keyboard" -profiles\1\button_l\default=true -profiles\1\button_left="code:70,engine:keyboard" -profiles\1\button_left\default=true -profiles\1\button_r="code:87,engine:keyboard" -profiles\1\button_r\default=true -profiles\1\button_right="code:72,engine:keyboard" -profiles\1\button_right\default=true -profiles\1\button_select="code:78,engine:keyboard" -profiles\1\button_select\default=true -profiles\1\button_start="code:77,engine:keyboard" -profiles\1\button_start\default=true -profiles\1\button_up="code:84,engine:keyboard" -profiles\1\button_up\default=true -profiles\1\button_x="code:90,engine:keyboard" -profiles\1\button_x\default=true -profiles\1\button_y="code:88,engine:keyboard" -profiles\1\button_y\default=true -profiles\1\button_zl="code:49,engine:keyboard" -profiles\1\button_zl\default=true -profiles\1\button_zr="code:50,engine:keyboard" -profiles\1\button_zr\default=true -profiles\1\c_stick="down:code$075$1engine$0keyboard,engine:analog_from_button,left:code$074$1engine$0keyboard,modifier:code$068$1engine$0keyboard,modifier_scale:0.500000,right:code$076$1engine$0keyboard,up:code$073$1engine$0keyboard" -profiles\1\c_stick\default=true -profiles\1\circle_pad="down:code$016777237$1engine$0keyboard,engine:analog_from_button,left:code$016777234$1engine$0keyboard,modifier:code$068$1engine$0keyboard,modifier_scale:0.500000,right:code$016777236$1engine$0keyboard,up:code$016777235$1engine$0keyboard" -profiles\1\circle_pad\default=true -profiles\1\motion_device="engine:motion_emu,update_period:100,sensitivity:0.01,tilt_clamp:90.0" -profiles\1\motion_device\default=true -profiles\1\name=default -profiles\1\name\default=true -profiles\1\touch_device=engine:emu_window -profiles\1\touch_device\default=true -profiles\1\touch_from_button_map=0 -profiles\1\touch_from_button_map\default=true -profiles\1\udp_input_address=127.0.0.1 -profiles\1\udp_input_address\default=true -profiles\1\udp_input_port=26760 -profiles\1\udp_input_port\default=true -profiles\1\udp_pad_index=0 -profiles\1\udp_pad_index\default=true -profiles\1\use_touch_from_button=false -profiles\1\use_touch_from_button\default=true -profiles\size=1 -touch_from_button_maps\1\entries\size=0 -touch_from_button_maps\1\name=default -touch_from_button_maps\1\name\default=true -touch_from_button_maps\size=1 - -[Core] -cpu_clock_percentage=100 -cpu_clock_percentage\default=true -use_cpu_jit=true -use_cpu_jit\default=true - -[Data%20Storage] -nand_directory=/root/.local/share/citra-emu/nand/ -nand_directory\default=true -sdmc_directory=/root/.local/share/citra-emu/sdmc/ -sdmc_directory\default=true -use_virtual_sd=true -use_virtual_sd\default=true - -[Debugging] -LLE\AC=false -LLE\AC\default=true -LLE\ACT=false -LLE\ACT\default=true -LLE\AM=false -LLE\AM\default=true -LLE\BOSS=false -LLE\BOSS\default=true -LLE\CAM=false -LLE\CAM\default=true -LLE\CDC=false -LLE\CDC\default=true -LLE\CECD=false -LLE\CECD\default=true -LLE\CFG=false -LLE\CFG\default=true -LLE\CSND=false -LLE\CSND\default=true -LLE\DLP=false -LLE\DLP\default=true -LLE\DSP=false -LLE\DSP\default=true -LLE\ERR=false -LLE\ERR\default=true -LLE\FRD=false -LLE\FRD\default=true -LLE\FS=false -LLE\FS\default=true -LLE\GPIO=false -LLE\GPIO\default=true -LLE\GSP=false -LLE\GSP\default=true -LLE\HID=false -LLE\HID\default=true -LLE\HTTP=false -LLE\HTTP\default=true -LLE\I2C=false -LLE\I2C\default=true -LLE\IR=false -LLE\IR\default=true -LLE\LDR=false -LLE\LDR\default=true -LLE\MCU=false -LLE\MCU\default=true -LLE\MIC=false -LLE\MIC\default=true -LLE\MP=false -LLE\MP\default=true -LLE\MVD=false -LLE\MVD\default=true -LLE\NDM=false -LLE\NDM\default=true -LLE\NEWS=false -LLE\NEWS\default=true -LLE\NFC=false -LLE\NFC\default=true -LLE\NIM=false -LLE\NIM\default=true -LLE\NS=false -LLE\NS\default=true -LLE\NWM=false -LLE\NWM\default=true -LLE\PDN=false -LLE\PDN\default=true -LLE\PM=false -LLE\PM\default=true -LLE\PS=false -LLE\PS\default=true -LLE\PTM=false -LLE\PTM\default=true -LLE\PXI=false -LLE\PXI\default=true -LLE\QTM=false -LLE\QTM\default=true -LLE\SOC=false -LLE\SOC\default=true -LLE\SPI=false -LLE\SPI\default=true -LLE\SSL=false -LLE\SSL\default=true -gdbstub_port=24689 -gdbstub_port\default=true -record_frame_times=false -use_gdbstub=false -use_gdbstub\default=true - -[Layout] -custom_bottom_bottom=480 -custom_bottom_bottom\default=true -custom_bottom_left=40 -custom_bottom_left\default=true -custom_bottom_right=360 -custom_bottom_right\default=true -custom_bottom_top=240 -custom_bottom_top\default=true -custom_layout=false -custom_layout\default=true -custom_top_bottom=240 -custom_top_bottom\default=true -custom_top_left=0 -custom_top_left\default=true -custom_top_right=400 -custom_top_right\default=true -custom_top_top=0 -custom_top_top\default=true -factor_3d=0 -factor_3d\default=true -filter_mode=true -filter_mode\default=true -layout_option=0 -pp_shader_name=none (builtin) -pp_shader_name\default=true -render_3d=0 -render_3d\default=true -swap_screen=false -swap_screen\default=true -upright_screen=false -upright_screen\default=true - -[Miscellaneous] -log_filter=*:Info -log_filter\default=true - -[Renderer] -bg_blue=0.545098066329956 -bg_blue\default=false -bg_green=0.545098066329956 -bg_green\default=false -bg_red=0.545098066329956 -bg_red\default=false -frame_limit=100 -frame_limit\default=true -frame_limit_alternate=200 -frame_limit_alternate\default=true -resolution_factor=1 -resolution_factor\default=true -shaders_accurate_mul=true -shaders_accurate_mul\default=true -texture_filter_name=none -texture_filter_name\default=true -use_disk_shader_cache=true -use_disk_shader_cache\default=true -use_frame_limit_alternate=false -use_frame_limit_alternate\default=true -use_hw_renderer=true -use_hw_renderer\default=true -use_hw_shader=true -use_hw_shader\default=true -use_shader_jit=true -use_shader_jit\default=true -use_vsync_new=true -use_vsync_new\default=true - -[System] -init_clock=0 -init_clock\default=true -init_time=946681277 -init_time\default=true -is_new_3ds=true -is_new_3ds\default=true -region_value=-1 -region_value\default=true - -[UI] -GameList\hideNoIcon=false -GameList\hideNoIcon\default=true -GameList\iconSize=2 -GameList\iconSize\default=true -GameList\row1=2 -GameList\row1\default=true -GameList\row2=0 -GameList\row2\default=true -GameList\singleLineMode=false -GameList\singleLineMode\default=true -Multiplayer\game_id=0 -Multiplayer\game_id\default=true -Multiplayer\host_type=0 -Multiplayer\host_type\default=true -Multiplayer\ip= -Multiplayer\ip\default=true -Multiplayer\ip_ban_list\size=0 -Multiplayer\max_player=8 -Multiplayer\max_player\default=true -Multiplayer\nickname= -Multiplayer\nickname\default=true -Multiplayer\port=24872 -Multiplayer\port\default=true -Multiplayer\room_description= -Multiplayer\room_description\default=true -Multiplayer\room_name= -Multiplayer\room_name\default=true -Multiplayer\room_nickname= -Multiplayer\room_nickname\default=true -Multiplayer\room_port=24872 -Multiplayer\room_port\default=true -Multiplayer\username_ban_list\size=0 -Paths\gamedirs\1\deep_scan=false -Paths\gamedirs\1\deep_scan\default=true -Paths\gamedirs\1\expanded=true -Paths\gamedirs\1\expanded\default=true -Paths\gamedirs\1\path=INSTALLED -Paths\gamedirs\2\deep_scan=false -Paths\gamedirs\2\deep_scan\default=true -Paths\gamedirs\2\expanded=true -Paths\gamedirs\2\expanded\default=true -Paths\gamedirs\2\path=SYSTEM -Paths\gamedirs\size=2 -Paths\language=en -Paths\language\default=false -Paths\moviePlaybackPath= -Paths\movieRecordPath= -Paths\recentFiles=@Invalid() -Paths\romsPath= -Paths\screenshotPath= -Paths\symbolsPath= -Paths\videoDumpingPath= -Shortcuts\Main%20Window\Advance%20Frame\Context=2 -Shortcuts\Main%20Window\Advance%20Frame\Context\default=true -Shortcuts\Main%20Window\Advance%20Frame\KeySeq=\\ -Shortcuts\Main%20Window\Advance%20Frame\KeySeq\default=true -Shortcuts\Main%20Window\Capture%20Screenshot\Context=2 -Shortcuts\Main%20Window\Capture%20Screenshot\Context\default=true -Shortcuts\Main%20Window\Capture%20Screenshot\KeySeq=Ctrl+P -Shortcuts\Main%20Window\Capture%20Screenshot\KeySeq\default=true -Shortcuts\Main%20Window\Continue\Pause%20Emulation\Context=1 -Shortcuts\Main%20Window\Continue\Pause%20Emulation\Context\default=true -Shortcuts\Main%20Window\Continue\Pause%20Emulation\KeySeq=F4 -Shortcuts\Main%20Window\Continue\Pause%20Emulation\KeySeq\default=true -Shortcuts\Main%20Window\Decrease%20Speed%20Limit\Context=2 -Shortcuts\Main%20Window\Decrease%20Speed%20Limit\Context\default=true -Shortcuts\Main%20Window\Decrease%20Speed%20Limit\KeySeq=- -Shortcuts\Main%20Window\Decrease%20Speed%20Limit\KeySeq\default=true -Shortcuts\Main%20Window\Exit%20Citra\Context=1 -Shortcuts\Main%20Window\Exit%20Citra\Context\default=true -Shortcuts\Main%20Window\Exit%20Citra\KeySeq=Ctrl+Q -Shortcuts\Main%20Window\Exit%20Citra\KeySeq\default=true -Shortcuts\Main%20Window\Exit%20Fullscreen\Context=1 -Shortcuts\Main%20Window\Exit%20Fullscreen\Context\default=true -Shortcuts\Main%20Window\Exit%20Fullscreen\KeySeq=Esc -Shortcuts\Main%20Window\Exit%20Fullscreen\KeySeq\default=true -Shortcuts\Main%20Window\Fullscreen\Context=1 -Shortcuts\Main%20Window\Fullscreen\Context\default=true -Shortcuts\Main%20Window\Fullscreen\KeySeq=F11 -Shortcuts\Main%20Window\Fullscreen\KeySeq\default=true -Shortcuts\Main%20Window\Increase%20Speed%20Limit\Context=2 -Shortcuts\Main%20Window\Increase%20Speed%20Limit\Context\default=true -Shortcuts\Main%20Window\Increase%20Speed%20Limit\KeySeq=+ -Shortcuts\Main%20Window\Increase%20Speed%20Limit\KeySeq\default=true -Shortcuts\Main%20Window\Load%20Amiibo\Context=2 -Shortcuts\Main%20Window\Load%20Amiibo\Context\default=true -Shortcuts\Main%20Window\Load%20Amiibo\KeySeq=F2 -Shortcuts\Main%20Window\Load%20Amiibo\KeySeq\default=true -Shortcuts\Main%20Window\Load%20File\Context=1 -Shortcuts\Main%20Window\Load%20File\Context\default=true -Shortcuts\Main%20Window\Load%20File\KeySeq=Ctrl+O -Shortcuts\Main%20Window\Load%20File\KeySeq\default=true -Shortcuts\Main%20Window\Load%20from%20Newest%20Slot\Context=1 -Shortcuts\Main%20Window\Load%20from%20Newest%20Slot\Context\default=true -Shortcuts\Main%20Window\Load%20from%20Newest%20Slot\KeySeq=Ctrl+V -Shortcuts\Main%20Window\Load%20from%20Newest%20Slot\KeySeq\default=true -Shortcuts\Main%20Window\Remove%20Amiibo\Context=2 -Shortcuts\Main%20Window\Remove%20Amiibo\Context\default=true -Shortcuts\Main%20Window\Remove%20Amiibo\KeySeq=F3 -Shortcuts\Main%20Window\Remove%20Amiibo\KeySeq\default=true -Shortcuts\Main%20Window\Restart%20Emulation\Context=1 -Shortcuts\Main%20Window\Restart%20Emulation\Context\default=true -Shortcuts\Main%20Window\Restart%20Emulation\KeySeq=F6 -Shortcuts\Main%20Window\Restart%20Emulation\KeySeq\default=true -Shortcuts\Main%20Window\Rotate%20Screens%20Upright\Context=1 -Shortcuts\Main%20Window\Rotate%20Screens%20Upright\Context\default=true -Shortcuts\Main%20Window\Rotate%20Screens%20Upright\KeySeq=F8 -Shortcuts\Main%20Window\Rotate%20Screens%20Upright\KeySeq\default=true -Shortcuts\Main%20Window\Save%20to%20Oldest%20Slot\Context=1 -Shortcuts\Main%20Window\Save%20to%20Oldest%20Slot\Context\default=true -Shortcuts\Main%20Window\Save%20to%20Oldest%20Slot\KeySeq=Ctrl+C -Shortcuts\Main%20Window\Save%20to%20Oldest%20Slot\KeySeq\default=true -Shortcuts\Main%20Window\Stop%20Emulation\Context=1 -Shortcuts\Main%20Window\Stop%20Emulation\Context\default=true -Shortcuts\Main%20Window\Stop%20Emulation\KeySeq=F5 -Shortcuts\Main%20Window\Stop%20Emulation\KeySeq\default=true -Shortcuts\Main%20Window\Swap%20Screens\Context=1 -Shortcuts\Main%20Window\Swap%20Screens\Context\default=true -Shortcuts\Main%20Window\Swap%20Screens\KeySeq=F9 -Shortcuts\Main%20Window\Swap%20Screens\KeySeq\default=true -Shortcuts\Main%20Window\Toggle%20Alternate%20Speed\Context=2 -Shortcuts\Main%20Window\Toggle%20Alternate%20Speed\Context\default=true -Shortcuts\Main%20Window\Toggle%20Alternate%20Speed\KeySeq=Ctrl+Z -Shortcuts\Main%20Window\Toggle%20Alternate%20Speed\KeySeq\default=true -Shortcuts\Main%20Window\Toggle%20Filter%20Bar\Context=1 -Shortcuts\Main%20Window\Toggle%20Filter%20Bar\Context\default=true -Shortcuts\Main%20Window\Toggle%20Filter%20Bar\KeySeq=Ctrl+F -Shortcuts\Main%20Window\Toggle%20Filter%20Bar\KeySeq\default=true -Shortcuts\Main%20Window\Toggle%20Frame%20Advancing\Context=2 -Shortcuts\Main%20Window\Toggle%20Frame%20Advancing\Context\default=true -Shortcuts\Main%20Window\Toggle%20Frame%20Advancing\KeySeq=Ctrl+A -Shortcuts\Main%20Window\Toggle%20Frame%20Advancing\KeySeq\default=true -Shortcuts\Main%20Window\Toggle%20Screen%20Layout\Context=1 -Shortcuts\Main%20Window\Toggle%20Screen%20Layout\Context\default=true -Shortcuts\Main%20Window\Toggle%20Screen%20Layout\KeySeq=F10 -Shortcuts\Main%20Window\Toggle%20Screen%20Layout\KeySeq\default=true -Shortcuts\Main%20Window\Toggle%20Status%20Bar\Context=1 -Shortcuts\Main%20Window\Toggle%20Status%20Bar\Context\default=true -Shortcuts\Main%20Window\Toggle%20Status%20Bar\KeySeq=Ctrl+S -Shortcuts\Main%20Window\Toggle%20Status%20Bar\KeySeq\default=true -Shortcuts\Main%20Window\Toggle%20Texture%20Dumping\Context=2 -Shortcuts\Main%20Window\Toggle%20Texture%20Dumping\Context\default=true -Shortcuts\Main%20Window\Toggle%20Texture%20Dumping\KeySeq=Ctrl+D -Shortcuts\Main%20Window\Toggle%20Texture%20Dumping\KeySeq\default=true -UILayout\gameListHeaderState=@ByteArray(\0\0\0\xff\0\0\0\0\0\0\0\x1\0\0\0\x1\0\0\0\x5\x1\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x4\x98\0\0\0\x5\x1\x1\0\x1\0\0\0\0\0\0\0\0\0\0\0\0h\xff\xff\xff\xff\0\0\0\x81\0\0\0\0\0\0\0\x5\0\0\x2\x80\0\0\0\x1\0\0\0\0\0\0\0h\0\0\0\x1\0\0\0\0\0\0\0h\0\0\0\x1\0\0\0\0\0\0\0h\0\0\0\x1\0\0\0\0\0\0\0\xe0\0\0\0\x1\0\0\0\0\0\0\x3\xe8\0\0\0\0h) -UILayout\geometry="@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\xe3\0\0\0\x99\0\0\x4r\0\0\x2\x31\0\0\0\xe4\0\0\0\xad\0\0\x4q\0\0\x2,\0\0\0\0\0\0\0\0\x5V\0\0\0\xe4\0\0\0\xad\0\0\x4q\0\0\x2,)" -UILayout\geometryRenderWindow=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\x14\0\0\0\x63\0\0\0\x31\0\0\0\0\0\0\0\x14\0\0\0\x63\0\0\0\x31\0\0\0\0\0\0\0\0\x5V\0\0\0\0\0\0\0\x14\0\0\0\x63\0\0\0\x31) -UILayout\microProfileDialogGeometry=@ByteArray(\x1\xd9\xd0\xcb\0\x3\0\0\0\0\0\0\0\0\0\x14\0\0\x3\xe7\0\0\x2k\0\0\0\0\0\0\0\x14\0\0\x3\xe7\0\0\x2k\0\0\0\0\0\0\0\0\x5V\0\0\0\0\0\0\0\x14\0\0\x3\xe7\0\0\x2k) -UILayout\microProfileDialogVisible=false -UILayout\microProfileDialogVisible\default=true -UILayout\state=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x2\0\0\0\0\0\0\0\0\0\0\0\0\xfc\x2\0\0\0\x1\xfb\0\0\0\x1c\0W\0\x61\0i\0t\0T\0r\0\x65\0\x65\0W\0i\0\x64\0g\0\x65\0t\0\0\0\0\0\xff\xff\xff\xff\0\0\0V\0\xff\xff\xff\0\0\0\x1\0\0\0\0\0\0\0\0\xfc\x2\0\0\0\b\xfb\0\0\0\x18\0\x41\0R\0M\0R\0\x65\0g\0i\0s\0t\0\x65\0r\0s\0\0\0\0\0\xff\xff\xff\xff\0\0\0h\0\xff\xff\xff\xfb\0\0\0 \0G\0r\0\x61\0p\0h\0i\0\x63\0s\0\x44\0\x65\0\x62\0u\0g\0g\0\x65\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0V\0\xff\xff\xff\xfb\0\0\0\"\0P\0i\0\x63\0\x61\0 \0\x43\0o\0m\0m\0\x61\0n\0\x64\0 \0L\0i\0s\0t\0\0\0\0\0\xff\xff\xff\xff\0\0\0\x8d\0\xff\xff\xff\xfb\0\0\0*\0P\0i\0\x63\0\x61\0\x42\0r\0\x65\0\x61\0k\0P\0o\0i\0n\0t\0s\0W\0i\0\x64\0g\0\x65\0t\0\0\0\0\0\xff\xff\xff\xff\0\0\0\x8d\0\xff\xff\xff\xfb\0\0\0 \0P\0i\0\x63\0\x61\0V\0\x65\0r\0t\0\x65\0x\0S\0h\0\x61\0\x64\0\x65\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\x1\xb8\0\xff\xff\xff\xfb\0\0\0\x12\0\x43\0i\0T\0r\0\x61\0\x63\0i\0n\0g\0\0\0\0\0\xff\xff\xff\xff\0\0\0G\0\xff\xff\xff\xfb\0\0\0.\0L\0L\0\x45\0S\0\x65\0r\0v\0i\0\x63\0\x65\0M\0o\0\x64\0u\0l\0\x65\0s\0W\0i\0\x64\0g\0\x65\0t\0\0\0\0\0\xff\xff\xff\xff\0\0\0V\0\xff\xff\xff\xfb\0\0\0\x16\0I\0P\0\x43\0R\0\x65\0\x63\0o\0r\0\x64\0\x65\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0\xcb\0\xff\xff\xff\0\0\x3\x8e\0\0\x1J\0\0\0\x4\0\0\0\x4\0\0\0\b\0\0\0\b\xfc\0\0\0\0) -Updater\check_for_update_on_start=true -Updater\check_for_update_on_start\default=true -Updater\update_on_close=false -Updater\update_on_close\default=true -calloutFlags=1 -calloutFlags\default=false -confirmClose=true -confirmClose\default=true -displayTitleBars=true -displayTitleBars\default=true -enable_discord_presence=false -enable_discord_presence\default=false -firstStart=false -firstStart\default=false -fullscreen=false -fullscreen\default=true -hideInactiveMouse=false -hideInactiveMouse\default=true -pauseWhenInBackground=false -pauseWhenInBackground\default=true -screenshot_resolution_factor=0 -screenshot_resolution_factor\default=true -showConsole=false -showConsole\default=true -showFilterBar=true -showFilterBar\default=true -showStatusBar=true -showStatusBar\default=true -singleWindowMode=true -singleWindowMode\default=true -theme=colorful_dark -theme\default=false - -[Utility] -custom_textures=false -custom_textures\default=true -dump_textures=false -dump_textures\default=true -preload_textures=false -preload_textures\default=true - -[VideoDumping] -audio_bitrate=64000 -audio_bitrate\default=true -audio_encoder=libvorbis -audio_encoder\default=true -audio_encoder_options= -audio_encoder_options\default=true -format_options= -output_format=webm -output_format\default=true -video_bitrate=2500000 -video_bitrate\default=true -video_encoder=libvpx-vp9 -video_encoder\default=true -video_encoder_options="quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1" -video_encoder_options\default=true - -[WebService] -citra_token= -citra_username= -enable_telemetry=false -enable_telemetry\default=false -web_api_url=https://api.citra-emu.org -web_api_url\default=true diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 8600c14..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,26 +0,0 @@ -version: '2' -services: - citra: - build: - context: . - dockerfile: docker/citra.dockerfile - shm_size: 2G - environment: - OPENBOX_ARGS: '--startup "citra-qt ${TEST_FILE:?}"' - RESOLUTION: 1366x768 - ports: - - "6080:80" - - "5900:5900" - volumes: - - "./citra:/tmp/citra" - - "${TEST_FILE:?}:${TEST_FILE:?}:ro" - - driver: - build: - context: . - dockerfile: docker/driver.dockerfile - volumes: - - "./driver:/tmp/driver" - working_dir: /tmp/driver/out - command: ["/usr/libexec/vncdo.sh", "/tmp/driver/main.vdo"] - diff --git a/docker/citra.dockerfile b/docker/citra.dockerfile index 6597747..18cb7a4 100644 --- a/docker/citra.dockerfile +++ b/docker/citra.dockerfile @@ -1,20 +1,29 @@ -FROM dorowu/ubuntu-desktop-lxde-vnc +FROM buildpack-deps:latest as builder -RUN apt-get update -y && \ - apt-get install -y \ - libqt5gui5 \ - libqt5multimedia5 +# ARG CITRA_RELEASE=nightly-1783 +# ARG CITRA_RELEASE_FILE=citra-linux-20220902-746609f.tar.xz - -ARG CITRA_RELEASE=nightly-1763 -ARG CITRA_RELEASE_FILE=citra-linux-20220503-856b3d6.tar.xz +ARG CITRA_CHANNEL=nightly +ARG CITRA_RELEASE=1816 WORKDIR /tmp -RUN wget https://github.com/citra-emu/citra-nightly/releases/download/${CITRA_RELEASE}/${CITRA_RELEASE_FILE} -RUN mkdir -p citra && \ - tar --strip-components 1 -C citra -xvf ${CITRA_RELEASE_FILE} && \ - cp citra/citra-qt citra/citra /usr/local/bin +COPY ./citra/download_citra.sh /usr/local/bin/download_citra +RUN apt-get update -y && apt-get install -y jq +RUN download_citra ${CITRA_CHANNEL} ${CITRA_RELEASE} + +FROM ubuntu:latest + +RUN apt-get update -y && \ + apt-get install -y \ + libswscale5 \ + libsdl2-2.0-0 \ + libavformat58 \ + libavfilter7 \ + xvfb + +COPY --from=builder /tmp/citra /usr/local/bin +COPY ./citra/sdl2-config.ini /root/.config/citra-emu/ -COPY citra/qt-config.ini /root/.config/citra-emu/ +WORKDIR /app -ENV OPENBOX_ARGS='--startup "citra-qt /root/hello-world.3dsx"' +CMD [ "citra", "--version" ] diff --git a/docker/citra/download_citra.sh b/docker/citra/download_citra.sh new file mode 100755 index 0000000..bacb06a --- /dev/null +++ b/docker/citra/download_citra.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +set -euxo pipefail + +CITRA_CHANNEL=$1 +CITRA_RELEASE=$2 + +RELEASE_API="https://api.github.com/repos/citra-emu/citra-${CITRA_CHANNEL}/releases/tags/${CITRA_CHANNEL}-${CITRA_RELEASE}" + +curl "${RELEASE_API}" | + jq --raw-output '.assets[].browser_download_url' | + grep -E 'citra-linux-.*.tar.xz' | + xargs wget -O citra-linux.tar.xz + +tar --strip-components 1 -xvf citra-linux.tar.xz diff --git a/docker/citra/sdl2-config.ini b/docker/citra/sdl2-config.ini new file mode 100644 index 0000000..2abb7bb --- /dev/null +++ b/docker/citra/sdl2-config.ini @@ -0,0 +1,342 @@ + +[Controls] +# The input devices and parameters for each 3DS native input +# It should be in the format of "engine:[engine_name],[param1]:[value1],[param2]:[value2]..." +# Escape characters $0 (for ':'), $1 (for ',') and $2 (for '$') can be used in values + +# for button input, the following devices are available: +# - "keyboard" (default) for keyboard input. Required parameters: +# - "code": the code of the key to bind +# - "sdl" for joystick input using SDL. Required parameters: +# - "joystick": the index of the joystick to bind +# - "button"(optional): the index of the button to bind +# - "hat"(optional): the index of the hat to bind as direction buttons +# - "axis"(optional): the index of the axis to bind +# - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", "down", "left" or "right" +# - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is +# triggered if the axis value crosses +# - "direction"(only used for axis): "+" means the button is triggered when the axis value +# is greater than the threshold; "-" means the button is triggered when the axis value +# is smaller than the threshold +button_a= +button_b= +button_x= +button_y= +button_up= +button_down= +button_left= +button_right= +button_l= +button_r= +button_start= +button_select= +button_debug= +button_gpio14= +button_zl= +button_zr= +button_home= + +# for analog input, the following devices are available: +# - "analog_from_button" (default) for emulating analog input from direction buttons. Required parameters: +# - "up", "down", "left", "right": sub-devices for each direction. +# Should be in the format as a button input devices using escape characters, for example, "engine$0keyboard$1code$00" +# - "modifier": sub-devices as a modifier. +# - "modifier_scale": a float number representing the applied modifier scale to the analog input. +# Must be in range of 0.0-1.0. Defaults to 0.5 +# - "sdl" for joystick input using SDL. Required parameters: +# - "joystick": the index of the joystick to bind +# - "axis_x": the index of the axis to bind as x-axis (default to 0) +# - "axis_y": the index of the axis to bind as y-axis (default to 1) +circle_pad= +c_stick= + +# for motion input, the following devices are available: +# - "motion_emu" (default) for emulating motion input from mouse input. Required parameters: +# - "update_period": update period in milliseconds (default to 100) +# - "sensitivity": the coefficient converting mouse movement to tilting angle (default to 0.01) +# - "tilt_clamp": the max value of the tilt angle in degrees (default to 90) +# - "cemuhookudp" reads motion input from a udp server that uses cemuhook's udp protocol +motion_device= + +# for touch input, the following devices are available: +# - "emu_window" (default) for emulating touch input from mouse input to the emulation window. No parameters required +# - "cemuhookudp" reads touch input from a udp server that uses cemuhook's udp protocol +# - "min_x", "min_y", "max_x", "max_y": defines the udp device's touch screen coordinate system +touch_device= + +# Most desktop operating systems do not expose a way to poll the motion state of the controllers +# so as a way around it, cemuhook created a udp client/server protocol to broadcast the data directly +# from a controller device to the client program. Citra has a client that can connect and read +# from any cemuhook compatible motion program. + +# IPv4 address of the udp input server (Default "127.0.0.1") +udp_input_address= + +# Port of the udp input server. (Default 26760) +udp_input_port= + +# The pad to request data on. Should be between 0 (Pad 1) and 3 (Pad 4). (Default 0) +udp_pad_index= + +[Core] +# Whether to use the Just-In-Time (JIT) compiler for CPU emulation +# 0: Interpreter (slow), 1 (default): JIT (fast) +use_cpu_jit = + +# Change the Clock Frequency of the emulated 3DS CPU. +# Underclocking can increase the performance of the game at the risk of freezing. +# Overclocking may fix lag that happens on console, but also comes with the risk of freezing. +# Range is any positive integer (but we suspect 25 - 400 is a good idea) Default is 100 +cpu_clock_percentage = + +[Renderer] +# Whether to render using GLES or OpenGL +# 0 (default): OpenGL, 1: GLES +use_gles = + +# Whether to use software or hardware rendering. +# 0: Software, 1 (default): Hardware +use_hw_renderer = + +# Whether to use hardware shaders to emulate 3DS shaders +# 0: Software, 1 (default): Hardware +use_hw_shader = + +# Whether to use separable shaders to emulate 3DS shaders (macOS only) +# 0: Off (Default), 1 : On +separable_shader = + +# Whether to use accurate multiplication in hardware shaders +# 0: Off (Faster, but causes issues in some games) 1: On (Default. Slower, but correct) +shaders_accurate_mul = + +# Whether to use the Just-In-Time (JIT) compiler for shader emulation +# 0: Interpreter (slow), 1 (default): JIT (fast) +use_shader_jit = + +# Forces VSync on the display thread. Usually doesn't impact performance, but on some drivers it can +# so only turn this off if you notice a speed difference. +# 0: Off, 1 (default): On +use_vsync_new = + +# Reduce stuttering by storing and loading generated shaders to disk +# 0: Off, 1 (default. On) +use_disk_shader_cache = + +# Resolution scale factor +# 0: Auto (scales resolution to window size), 1: Native 3DS screen resolution, Otherwise a scale +# factor for the 3DS resolution +resolution_factor = + +# Texture filter name +texture_filter_name = + +# Limits the speed of the game to run no faster than this value as a percentage of target speed. +# Will not have an effect if unthrottled is enabled. +# 5 - 995: Speed limit as a percentage of target game speed. 0 for unthrottled. 100 (default) +frame_limit = + +# Overrides the frame limiter to use frame_limit_alternate instead of frame_limit. +# 0: Off (default), 1: On +use_frame_limit_alternate = + +# Alternate speed limit to be used instead of frame_limit if use_frame_limit_alternate is enabled +# 5 - 995: Speed limit as a percentage of target game speed. 0 for unthrottled. 200 (default) +frame_limit_alternate = + +# The clear color for the renderer. What shows up on the sides of the bottom screen. +# Must be in range of 0.0-1.0. Defaults to 0.0 for all. +bg_red = 0.5 +bg_blue = 0.5 +bg_green = 0.5 + +# Whether and how Stereoscopic 3D should be rendered +# 0 (default): Off, 1: Side by Side, 2: Anaglyph, 3: Interlaced, 4: Reverse Interlaced +render_3d = + +# Change 3D Intensity +# 0 - 100: Intensity. 0 (default) +factor_3d = + +# The name of the post processing shader to apply. +# Loaded from shaders if render_3d is off or side by side. +# Loaded from shaders/anaglyph if render_3d is anaglyph +pp_shader_name = + +# Whether to enable linear filtering or not +# This is required for some shaders to work correctly +# 0: Nearest, 1 (default): Linear +filter_mode = + +[Layout] +# Layout for the screen inside the render window. +# 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen, 3: Side by Side +layout_option = + +# Toggle custom layout (using the settings below) on or off. +# 0 (default): Off, 1: On +custom_layout = + +# Screen placement when using Custom layout option +# 0x, 0y is the top left corner of the render window. +custom_top_left = +custom_top_top = +custom_top_right = +custom_top_bottom = +custom_bottom_left = +custom_bottom_top = +custom_bottom_right = +custom_bottom_bottom = + +# Swaps the prominent screen with the other screen. +# For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen. +# 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent +swap_screen = + +# Toggle upright orientation, for book style games. +# 0 (default): Off, 1: On +upright_screen = + +# Dumps textures as PNG to dump/textures/[Title ID]/. +# 0 (default): Off, 1: On +dump_textures = + +# Reads PNG files from load/textures/[Title ID]/ and replaces textures. +# 0 (default): Off, 1: On +custom_textures = + +# Loads all custom textures into memory before booting. +# 0 (default): Off, 1: On +preload_textures = + +[Audio] +# Whether or not to enable DSP LLE +# 0 (default): No, 1: Yes +enable_dsp_lle = + +# Whether or not to run DSP LLE on a different thread +# 0 (default): No, 1: Yes +enable_dsp_lle_thread = + + +# Which audio output engine to use. +# auto (default): Auto-select, null: No audio output, sdl2: SDL2 (if available) +output_engine = + +# Whether or not to enable the audio-stretching post-processing effect. +# This effect adjusts audio speed to match emulation speed and helps prevent audio stutter, +# at the cost of increasing audio latency. +# 0: No, 1 (default): Yes +enable_audio_stretching = + +# Which audio device to use. +# auto (default): Auto-select +output_device = + +# Output volume. +# 1.0 (default): 100%, 0.0; mute +volume = + +[Data Storage] +# Whether to create a virtual SD card. +# 1 (default): Yes, 0: No +use_virtual_sd = + +# The path of the virtual SD card directory. +# empty (default) will use the user_path +sdmc_directory = + +# The path of NAND directory. +# empty (default) will use the user_path +nand_directory = + +[System] +# The system model that Citra will try to emulate +# 0: Old 3DS, 1: New 3DS (default) +is_new_3ds = + +# The system region that Citra will use during emulation +# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan +region_value = + +# The clock to use when citra starts +# 0: System clock (default), 1: fixed time +init_clock = + +# Time used when init_clock is set to fixed_time in the format %Y-%m-%d %H:%M:%S +# set to fixed time. Default 2000-01-01 00:00:01 +# Note: 3DS can only handle times later then Jan 1 2000 +init_time = + +[Camera] +# Which camera engine to use for the right outer camera +# blank (default): a dummy camera that always returns black image +camera_outer_right_name = + +# A config string for the right outer camera. Its meaning is defined by the camera engine +camera_outer_right_config = + +# The image flip to apply +# 0: None (default), 1: Horizontal, 2: Vertical, 3: Reverse +camera_outer_right_flip = + +# ... for the left outer camera +camera_outer_left_name = +camera_outer_left_config = +camera_outer_left_flip = + +# ... for the inner camera +camera_inner_name = +camera_inner_config = +camera_inner_flip = + +[Miscellaneous] +# A filter which removes logs below a certain logging level. +# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical +log_filter = *:Info Debug.Emulated:Debug +# Kernel:Debug Service.APT:Trace + +[Debugging] +# Record frame time data, can be found in the log directory. Boolean value +record_frame_times = +# Port for listening to GDB connections. +use_gdbstub=false +gdbstub_port=24689 +# To LLE a service module add "LLE\=true" + +[WebService] +# Whether or not to enable telemetry +# 0: No, 1 (default): Yes +enable_telemetry = 1 +# URL for Web API +web_api_url = https://api.citra-emu.org +# Username and token for Citra Web Service +# See https://profile.citra-emu.org/ for more info +citra_username = +citra_token = + +[Video Dumping] +# Format of the video to output, default: webm +output_format = + +# Options passed to the muxer (optional) +# This is a param package, format: [key1]:[value1],[key2]:[value2],... +format_options = + +# Video encoder used, default: libvpx-vp9 +video_encoder = libvpx-vp9 + +# Options passed to the video codec (optional) +video_encoder_options = quality:realtime,speed:6,tile-columns:4,frame-parallel:1,threads:8,row-mt:1 + +# Video bitrate, default: 2500000 +video_bitrate = + +# Audio encoder used, default: libvorbis +audio_encoder = libvorbis + +# Options passed to the audio codec (optional) +audio_encoder_options = + +# Audio bitrate, default: 64000 +audio_bitrate = diff --git a/docker/driver.dockerfile b/docker/driver.dockerfile deleted file mode 100644 index a993ace..0000000 --- a/docker/driver.dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ghcr.io/ian-h-chamberlain/rust-devkitarm - -RUN apt-get update -y && \ - apt-get install -y python3 python3-pip python3-pil - -RUN pip3 install vncdotool - -COPY driver/vncdo.sh /usr/libexec/ - -CMD [ "vncdo", "--version" ] diff --git a/driver/citra-controls.png b/driver/citra-controls.png deleted file mode 100644 index 13cf6d9..0000000 Binary files a/driver/citra-controls.png and /dev/null differ diff --git a/driver/citra-hotkeys.png b/driver/citra-hotkeys.png deleted file mode 100644 index 3bc5574..0000000 Binary files a/driver/citra-hotkeys.png and /dev/null differ diff --git a/driver/main.vdo b/driver/main.vdo deleted file mode 100644 index 40060d7..0000000 --- a/driver/main.vdo +++ /dev/null @@ -1,16 +0,0 @@ -# Wait for citra to finish startup -sleep 3 - -# Main test logic -key ctrl-p type "/tmp/citra/out/screenshot0.png" key enter -keydown a keyup a -keydown s keyup s -keydown z keyup z -keydown q - keydown a keyup a - keydown s keyup s - keydown z keyup z -keyup q -key ctrl-p type "/tmp/citra/out/screenshot1.png" key enter - -capture final.png diff --git a/driver/vncdo.sh b/driver/vncdo.sh deleted file mode 100755 index b02c161..0000000 --- a/driver/vncdo.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -while ! vncdo -s citra pause 0 &>/dev/null; do - echo "waiting for VNC server..." - sleep 1 -done - -exec vncdo -s citra --nocursor --delay 400 "$@" diff --git a/run.sh b/run.sh deleted file mode 100755 index 712eabc..0000000 --- a/run.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -set -eux -o pipefail - -if [[ $# -lt 1 ]]; then - echo "Usage: run.sh 3DSX_FILE" - exit 1 -fi - -trap 'docker-compose down' EXIT - -rm -rf citra/out driver/out -mkdir -p citra/out driver/out - -TEST_FILE=$(realpath "$1") -export TEST_FILE - -docker-compose build -docker-compose up -d citra -docker-compose run driver diff --git a/test-crate/.gitignore b/test-crate/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/test-crate/.gitignore @@ -0,0 +1 @@ +/target diff --git a/test-crate/Cargo.lock b/test-crate/Cargo.lock new file mode 100644 index 0000000..edd7621 --- /dev/null +++ b/test-crate/Cargo.lock @@ -0,0 +1,119 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "const-zero" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d3d68618a1f2c2d86e0bd2adec82e31960ca11aaeb5f353ff01746a4e08f36" + +[[package]] +name = "ctru-rs" +version = "0.7.1" +source = "git+https://github.com/Meziu/ctru-rs.git#ac6c81e7819185be46576af3441f5260d39a2320" +dependencies = [ + "bitflags", + "cfg-if", + "const-zero", + "ctru-sys", + "libc", + "linker-fix-3ds", + "once_cell", + "pthread-3ds", + "toml", + "widestring", +] + +[[package]] +name = "ctru-sys" +version = "0.4.1" +source = "git+https://github.com/Meziu/ctru-rs.git#ac6c81e7819185be46576af3441f5260d39a2320" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.132" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8371e4e5341c3a96db127eb2465ac681ced4c433e01dd0e938adbef26ba93ba5" + +[[package]] +name = "linker-fix-3ds" +version = "0.1.0" +source = "git+https://github.com/Meziu/rust-linker-fix-3ds.git#d5d3be4a0da876df6d6ac55cc8b48488713e149a" +dependencies = [ + "ctru-sys", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" + +[[package]] +name = "pthread-3ds" +version = "0.1.0" +source = "git+https://github.com/Meziu/pthread-3ds.git#42a80c0e816251138df535648258671d93e047a6" +dependencies = [ + "ctru-sys", + "libc", + "spin", + "static_assertions", +] + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" + +[[package]] +name = "spin" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c530c2b0d0bf8b69304b39fe2001993e267461948b890cd037d8ad4293fa1a0d" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "test-crate" +version = "0.1.0" +dependencies = [ + "ctru-rs", + "ctru-sys", +] + +[[package]] +name = "toml" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +dependencies = [ + "serde", +] + +[[package]] +name = "widestring" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7157704c2e12e3d2189c507b7482c52820a16dfa4465ba91add92f266667cadb" diff --git a/test-crate/Cargo.toml b/test-crate/Cargo.toml new file mode 100644 index 0000000..b5dd4a7 --- /dev/null +++ b/test-crate/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "test-crate" +version = "0.1.0" +edition = "2021" +authors = [""] + +[dependencies] +ctru-rs = { git = "https://github.com/Meziu/ctru-rs.git" } +ctru-sys = { git = "https://github.com/Meziu/ctru-rs.git" } diff --git a/test-crate/src/main.rs b/test-crate/src/main.rs new file mode 100644 index 0000000..c8957bf --- /dev/null +++ b/test-crate/src/main.rs @@ -0,0 +1,53 @@ +use std::time::Duration; + +use ctru::console::Console; +use ctru::gfx::Gfx; +use ctru::services::apt::Apt; +use ctru::services::hid::{Hid, KeyPad}; + +fn main() { + ctru::init(); + let gfx = Gfx::init().expect("Couldn't obtain GFX controller"); + let hid = Hid::init().expect("Couldn't obtain HID controller"); + let apt = Apt::init().expect("Couldn't obtain APT controller"); + // let _console = Console::init(gfx.top_screen.borrow_mut()); + + let _ = unsafe { ctru_sys::consoleDebugInit(ctru_sys::debugDevice_SVC) }; + + std::env::set_var("RUST_BACKTRACE", "full"); + + let res = unsafe { ctru_sys::gdbHioDevInit() }; + if res != 0 { + eprintln!("failed to init gdbHIO: {res}"); + } else { + eprintln!("init gdb hio"); + } + + // let res = unsafe { ctru_sys::gdbHioDevRedirectStdStreams(false, true, true) }; + // if res != 0 { + // eprintln!("failed to redirect gdbHIO: {res}"); + // } else { + // eprintln!("redirected gdb hio"); + // } + + println!("hey stdout"); + eprintln!("hey stderr"); + + // Main loop + while apt.main_loop() { + //Scan all the inputs. This should be done once for each frame + hid.scan_input(); + + if hid.keys_down().contains(KeyPad::KEY_START) { + break; + } + // Flush and swap framebuffers + gfx.flush_buffers(); + gfx.swap_buffers(); + + //Wait for VBlank + gfx.wait_for_vblank(); + } + + unsafe { ctru_sys::gdbHioDevExit() }; +}