summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt8
-rw-r--r--dist/qt_themes/colorful_midnight_blue/icons/16x16/lock.pngbin0 -> 401 bytes
-rw-r--r--dist/qt_themes/colorful_midnight_blue/icons/index.theme8
-rw-r--r--dist/qt_themes/colorful_midnight_blue/style.qrc57
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_checked.pngbin492 -> 1935 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.pngbin491 -> 1960 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.pngbin252 -> 1813 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.pngbin493 -> 492 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.pngbin492 -> 491 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.pngbin249 -> 252 bytes
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss8
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/LICENSE.rst405
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.pngbin0 -> 304 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.pngbin0 -> 3438 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.pngbin0 -> 1098 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.pngbin0 -> 15120 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.pngbin0 -> 542 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.pngbin0 -> 339 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.pngbin0 -> 676 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme14
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/Hmovetoolbar.pngbin0 -> 220 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/Hsepartoolbar.pngbin0 -> 172 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/Vmovetoolbar.pngbin0 -> 228 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/Vsepartoolbar.pngbin0 -> 187 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down.pngbin0 -> 525 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down@2x.pngbin0 -> 977 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled.pngbin0 -> 547 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled@2x.pngbin0 -> 1040 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus.pngbin0 -> 530 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus@2x.pngbin0 -> 1025 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed.pngbin0 -> 518 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed@2x.pngbin0 -> 1007 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left.pngbin0 -> 546 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left@2x.pngbin0 -> 1072 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled.pngbin0 -> 569 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled@2x.pngbin0 -> 1126 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus.pngbin0 -> 565 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus@2x.pngbin0 -> 1143 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed.pngbin0 -> 541 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed@2x.pngbin0 -> 1120 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right.pngbin0 -> 518 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right@2x.pngbin0 -> 1062 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled.pngbin0 -> 553 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled@2x.pngbin0 -> 1143 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus.pngbin0 -> 543 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus@2x.pngbin0 -> 1139 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed.pngbin0 -> 544 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed@2x.pngbin0 -> 1121 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up.pngbin0 -> 512 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up@2x.pngbin0 -> 969 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled.pngbin0 -> 538 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled@2x.pngbin0 -> 1046 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus.pngbin0 -> 530 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus@2x.pngbin0 -> 1017 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed.pngbin0 -> 518 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed@2x.pngbin0 -> 998 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon.pngbin0 -> 1256 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon@2x.pngbin0 -> 3286 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled.pngbin0 -> 1256 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled@2x.pngbin0 -> 3286 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus.pngbin0 -> 1256 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus@2x.pngbin0 -> 3286 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed.pngbin0 -> 1256 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed@2x.pngbin0 -> 3286 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed-on.pngbin0 -> 147 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed.pngbin0 -> 350 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed@2x.pngbin0 -> 704 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled.pngbin0 -> 373 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled@2x.pngbin0 -> 729 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus.pngbin0 -> 380 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus@2x.pngbin0 -> 717 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed.pngbin0 -> 372 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed@2x.pngbin0 -> 725 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end.pngbin0 -> 142 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end@2x.pngbin0 -> 220 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled.pngbin0 -> 146 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled@2x.pngbin0 -> 225 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus.pngbin0 -> 146 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus@2x.pngbin0 -> 226 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed.pngbin0 -> 146 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed@2x.pngbin0 -> 225 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line.pngbin0 -> 130 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line@2x.pngbin0 -> 242 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled.pngbin0 -> 134 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled@2x.pngbin0 -> 248 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus.pngbin0 -> 134 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus@2x.pngbin0 -> 249 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed.pngbin0 -> 134 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed@2x.pngbin0 -> 248 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more.pngbin0 -> 155 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more@2x.pngbin0 -> 257 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled.pngbin0 -> 162 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled@2x.pngbin0 -> 265 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus.pngbin0 -> 162 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus@2x.pngbin0 -> 266 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed.pngbin0 -> 162 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed@2x.pngbin0 -> 265 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open-on.pngbin0 -> 150 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open.pngbin0 -> 354 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open@2x.pngbin0 -> 657 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled.pngbin0 -> 375 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled@2x.pngbin0 -> 682 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus.pngbin0 -> 367 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus@2x.pngbin0 -> 665 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed.pngbin0 -> 369 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed@2x.pngbin0 -> 661 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked.pngbin0 -> 452 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked@2x.pngbin0 -> 825 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled.pngbin0 -> 467 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled@2x.pngbin0 -> 845 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus.pngbin0 -> 441 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus@2x.pngbin0 -> 823 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed.pngbin0 -> 418 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed@2x.pngbin0 -> 829 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate.pngbin0 -> 581 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate@2x.pngbin0 -> 1081 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled.pngbin0 -> 614 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled@2x.pngbin0 -> 1105 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus.pngbin0 -> 576 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus@2x.pngbin0 -> 1066 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed.pngbin0 -> 563 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed@2x.pngbin0 -> 1087 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked.pngbin0 -> 397 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked@2x.pngbin0 -> 828 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled.pngbin0 -> 386 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled@2x.pngbin0 -> 875 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus.pngbin0 -> 394 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus@2x.pngbin0 -> 866 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed.pngbin0 -> 403 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed@2x.pngbin0 -> 861 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/close-hover.pngbin0 -> 598 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/close-pressed.pngbin0 -> 598 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/close.pngbin0 -> 586 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow.pngbin0 -> 165 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow_disabled.pngbin0 -> 166 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow.pngbin0 -> 166 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow_disabled.pngbin0 -> 166 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal.pngbin0 -> 117 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal@2x.pngbin0 -> 135 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled.pngbin0 -> 121 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled@2x.pngbin0 -> 139 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus.pngbin0 -> 120 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus@2x.pngbin0 -> 138 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed.pngbin0 -> 120 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed@2x.pngbin0 -> 138 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical.pngbin0 -> 130 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical@2x.pngbin0 -> 242 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled.pngbin0 -> 134 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled@2x.pngbin0 -> 248 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus.pngbin0 -> 134 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus@2x.pngbin0 -> 249 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed.pngbin0 -> 134 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed@2x.pngbin0 -> 248 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked.pngbin0 -> 1224 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked@2x.pngbin0 -> 2714 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled.pngbin0 -> 1325 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled@2x.pngbin0 -> 2893 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus.pngbin0 -> 1293 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus@2x.pngbin0 -> 2736 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed.pngbin0 -> 1276 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed@2x.pngbin0 -> 2765 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked.pngbin0 -> 963 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked@2x.pngbin0 -> 2195 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled.pngbin0 -> 1040 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled@2x.pngbin0 -> 2294 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus.pngbin0 -> 1032 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus@2x.pngbin0 -> 2186 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed.pngbin0 -> 1022 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed@2x.pngbin0 -> 2197 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow.pngbin0 -> 160 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow_disabled.pngbin0 -> 160 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/sizegrip.pngbin0 -> 129 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-end.pngbin0 -> 224 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-more.pngbin0 -> 182 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-vline.pngbin0 -> 239 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal.pngbin0 -> 150 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal@2x.pngbin0 -> 304 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled.pngbin0 -> 155 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled@2x.pngbin0 -> 308 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus.pngbin0 -> 154 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus@2x.pngbin0 -> 311 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed.pngbin0 -> 154 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed@2x.pngbin0 -> 307 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical.pngbin0 -> 137 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical@2x.pngbin0 -> 201 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled.pngbin0 -> 140 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled@2x.pngbin0 -> 212 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus.pngbin0 -> 144 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus@2x.pngbin0 -> 211 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed.pngbin0 -> 143 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed@2x.pngbin0 -> 204 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal.pngbin0 -> 145 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal@2x.pngbin0 -> 286 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled.pngbin0 -> 151 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled@2x.pngbin0 -> 292 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus.pngbin0 -> 149 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus@2x.pngbin0 -> 294 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed.pngbin0 -> 149 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed@2x.pngbin0 -> 289 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical.pngbin0 -> 133 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical@2x.pngbin0 -> 191 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled.pngbin0 -> 135 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled@2x.pngbin0 -> 199 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus.pngbin0 -> 139 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus@2x.pngbin0 -> 196 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed.pngbin0 -> 138 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed@2x.pngbin0 -> 193 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent.pngbin0 -> 104 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent@2x.pngbin0 -> 117 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled.pngbin0 -> 104 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled@2x.pngbin0 -> 117 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus.pngbin0 -> 104 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus@2x.pngbin0 -> 117 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed.pngbin0 -> 104 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed@2x.pngbin0 -> 117 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/undock.pngbin0 -> 578 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow.pngbin0 -> 158 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow_disabled.pngbin0 -> 159 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close.pngbin0 -> 766 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close@2x.pngbin0 -> 1690 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled.pngbin0 -> 838 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled@2x.pngbin0 -> 1724 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus.pngbin0 -> 756 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus@2x.pngbin0 -> 1704 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed.pngbin0 -> 745 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed@2x.pngbin0 -> 1679 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip.pngbin0 -> 426 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip@2x.pngbin0 -> 735 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled.pngbin0 -> 447 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled@2x.pngbin0 -> 768 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus.pngbin0 -> 435 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus@2x.pngbin0 -> 738 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed.pngbin0 -> 444 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed@2x.pngbin0 -> 729 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize.pngbin0 -> 193 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize@2x.pngbin0 -> 316 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled.pngbin0 -> 206 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled@2x.pngbin0 -> 332 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus.pngbin0 -> 208 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus@2x.pngbin0 -> 339 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed.pngbin0 -> 202 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed@2x.pngbin0 -> 336 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock.pngbin0 -> 510 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock@2x.pngbin0 -> 875 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled.pngbin0 -> 541 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled@2x.pngbin0 -> 910 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus.pngbin0 -> 519 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus@2x.pngbin0 -> 877 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed.pngbin0 -> 523 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed@2x.pngbin0 -> 880 bytes
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/style.qrc225
-rw-r--r--dist/qt_themes/qdarkstyle_midnight_blue/style.qss2174
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/audio_core/stream.cpp7
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/common_paths.h1
-rw-r--r--src/common/concepts.h32
-rw-r--r--src/common/file_util.cpp1
-rw-r--r--src/common/file_util.h1
-rw-r--r--src/common/string_util.h12
-rw-r--r--src/common/virtual_buffer.cpp2
-rw-r--r--src/core/core.cpp2
-rw-r--r--src/core/core_timing.cpp16
-rw-r--r--src/core/core_timing.h7
-rw-r--r--src/core/cpu_manager.cpp6
-rw-r--r--src/core/device_memory.cpp5
-rw-r--r--src/core/device_memory.h8
-rw-r--r--src/core/file_sys/mode.h9
-rw-r--r--src/core/file_sys/patch_manager.cpp4
-rw-r--r--src/core/file_sys/registered_cache.cpp126
-rw-r--r--src/core/file_sys/registered_cache.h6
-rw-r--r--src/core/file_sys/savedata_factory.cpp33
-rw-r--r--src/core/file_sys/savedata_factory.h47
-rw-r--r--src/core/file_sys/vfs_real.cpp30
-rw-r--r--src/core/file_sys/xts_archive.cpp14
-rw-r--r--src/core/hardware_interrupt_manager.cpp4
-rw-r--r--src/core/hle/kernel/hle_ipc.h30
-rw-r--r--src/core/hle/kernel/kernel.cpp2
-rw-r--r--src/core/hle/kernel/server_session.cpp6
-rw-r--r--src/core/hle/kernel/time_manager.cpp10
-rw-r--r--src/core/hle/service/acc/acc.cpp6
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp43
-rw-r--r--src/core/hle/service/am/am.cpp11
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.cpp61
-rw-r--r--src/core/hle/service/am/applets/software_keyboard.h1
-rw-r--r--src/core/hle/service/audio/audout_u.cpp2
-rw-r--r--src/core/hle/service/audio/hwopus.cpp2
-rw-r--r--src/core/hle/service/bcat/module.cpp2
-rw-r--r--src/core/hle/service/es/es.cpp2
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp8
-rw-r--r--src/core/hle/service/filesystem/filesystem.h6
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp73
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h6
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp53
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp17
-rw-r--r--src/core/hle/service/hid/hid.cpp8
-rw-r--r--src/core/hle/service/hid/hid.h2
-rw-r--r--src/core/hle/service/ldr/ldr.cpp5
-rw-r--r--src/core/hle/service/nfp/nfp.cpp8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp202
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h79
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp33
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h6
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp36
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.cpp4
-rw-r--r--src/core/hle/service/nvflinger/nvflinger.h30
-rw-r--r--src/core/hle/service/set/set.cpp2
-rw-r--r--src/core/hle/service/sm/sm.h5
-rw-r--r--src/core/hle/service/time/time.cpp4
-rw-r--r--src/core/hle/service/time/time_zone_service.cpp4
-rw-r--r--src/core/hle/service/vi/vi.cpp8
-rw-r--r--src/core/memory/cheat_engine.cpp12
-rw-r--r--src/core/memory/cheat_engine.h2
-rw-r--r--src/core/memory/dmnt_cheat_vm.cpp226
-rw-r--r--src/core/network/network.cpp2
-rw-r--r--src/core/perf_stats.cpp20
-rw-r--r--src/core/perf_stats.h11
-rw-r--r--src/core/settings.cpp1
-rw-r--r--src/core/settings.h1
-rw-r--r--src/core/tools/freezer.cpp11
-rw-r--r--src/core/tools/freezer.h2
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp191
-rw-r--r--src/input_common/gcadapter/gc_adapter.h44
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp6
-rw-r--r--src/input_common/udp/client.cpp1
-rw-r--r--src/tests/core/core_timing.cpp18
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h9
-rw-r--r--src/video_core/compatible_formats.h2
-rw-r--r--src/video_core/gpu.cpp2
-rw-r--r--src/video_core/gpu.h4
-rw-r--r--src/video_core/gpu_thread.cpp4
-rw-r--r--src/video_core/macro/macro_jit_x64.cpp1
-rw-r--r--src/video_core/memory_manager.cpp532
-rw-r--r--src/video_core/memory_manager.h172
-rw-r--r--src/video_core/renderer_opengl/gl_arb_decompiler.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp5
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp15
-rw-r--r--src/video_core/renderer_vulkan/fixed_pipeline_state.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_blit_screen.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_device.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_rasterizer.cpp13
-rw-r--r--src/video_core/renderer_vulkan/vk_sampler_cache.cpp1
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp5
-rw-r--r--src/video_core/renderer_vulkan/vk_swapchain.cpp2
-rw-r--r--src/video_core/renderer_vulkan/vk_texture_cache.cpp4
-rw-r--r--src/video_core/shader/decode/arithmetic_integer.cpp6
-rw-r--r--src/video_core/shader/decode/video.cpp19
-rw-r--r--src/video_core/shader/decode/xmad.cpp15
-rw-r--r--src/video_core/shader/shader_ir.cpp4
-rw-r--r--src/video_core/texture_cache/format_lookup_table.cpp2
-rw-r--r--src/video_core/texture_cache/surface_params.cpp97
-rw-r--r--src/yuzu/bootmanager.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp36
-rw-r--r--src/yuzu/configuration/config.h2
-rw-r--r--src/yuzu/configuration/configuration_shared.cpp74
-rw-r--r--src/yuzu/configuration/configuration_shared.h20
-rw-r--r--src/yuzu/configuration/configure_audio.cpp23
-rw-r--r--src/yuzu/configuration/configure_audio.h6
-rw-r--r--src/yuzu/configuration/configure_audio.ui151
-rw-r--r--src/yuzu/configuration/configure_debug.ui22
-rw-r--r--src/yuzu/configuration/configure_general.cpp37
-rw-r--r--src/yuzu/configuration/configure_general.h7
-rw-r--r--src/yuzu/configuration/configure_graphics.cpp54
-rw-r--r--src/yuzu/configuration/configure_graphics.h7
-rw-r--r--src/yuzu/configuration/configure_graphics.ui282
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.cpp68
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.h9
-rw-r--r--src/yuzu/configuration/configure_graphics_advanced.ui161
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp76
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.cpp39
-rw-r--r--src/yuzu/configuration/configure_system.cpp115
-rw-r--r--src/yuzu/configuration/configure_system.h7
-rw-r--r--src/yuzu/configuration/configure_system.ui972
-rw-r--r--src/yuzu/configuration/configure_ui.cpp26
-rw-r--r--src/yuzu/configuration/configure_ui.ui45
-rw-r--r--src/yuzu/debugger/wait_tree.cpp5
-rw-r--r--src/yuzu/game_list.cpp34
-rw-r--r--src/yuzu/game_list.h15
-rw-r--r--src/yuzu/game_list_worker.cpp4
-rw-r--r--src/yuzu/main.cpp226
-rw-r--r--src/yuzu/main.h9
-rw-r--r--src/yuzu/uisettings.cpp2
-rw-r--r--src/yuzu/uisettings.h4
385 files changed, 5676 insertions, 2413 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7a49318aa..3282ae9d4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -159,15 +159,15 @@ macro(yuzu_find_packages)
159 # Capitalization matters here. We need the naming to match the generated paths from Conan 159 # Capitalization matters here. We need the naming to match the generated paths from Conan
160 set(REQUIRED_LIBS 160 set(REQUIRED_LIBS
161 # Cmake Pkg Prefix Version Conan Pkg 161 # Cmake Pkg Prefix Version Conan Pkg
162 "Boost 1.71 boost/1.72.0" 162 "Boost 1.73 boost/1.73.0"
163 "Catch2 2.11 catch2/2.11.0" 163 "Catch2 2.13 catch2/2.13.0"
164 "fmt 7.0 fmt/7.0.1" 164 "fmt 7.0 fmt/7.0.1"
165 # can't use until https://github.com/bincrafters/community/issues/1173 165 # can't use until https://github.com/bincrafters/community/issues/1173
166 #"libzip 1.5 libzip/1.5.2@bincrafters/stable" 166 #"libzip 1.5 libzip/1.5.2@bincrafters/stable"
167 "lz4 1.8 lz4/1.9.2" 167 "lz4 1.8 lz4/1.9.2"
168 "nlohmann_json 3.7 nlohmann_json/3.7.3" 168 "nlohmann_json 3.8 nlohmann_json/3.8.0"
169 "ZLIB 1.2 zlib/1.2.11" 169 "ZLIB 1.2 zlib/1.2.11"
170 "zstd 1.4 zstd/1.4.4" 170 "zstd 1.4 zstd/1.4.5"
171 ) 171 )
172 172
173 foreach(PACKAGE ${REQUIRED_LIBS}) 173 foreach(PACKAGE ${REQUIRED_LIBS})
diff --git a/dist/qt_themes/colorful_midnight_blue/icons/16x16/lock.png b/dist/qt_themes/colorful_midnight_blue/icons/16x16/lock.png
new file mode 100644
index 000000000..32c505848
--- /dev/null
+++ b/dist/qt_themes/colorful_midnight_blue/icons/16x16/lock.png
Binary files differ
diff --git a/dist/qt_themes/colorful_midnight_blue/icons/index.theme b/dist/qt_themes/colorful_midnight_blue/icons/index.theme
new file mode 100644
index 000000000..e23bfe6f9
--- /dev/null
+++ b/dist/qt_themes/colorful_midnight_blue/icons/index.theme
@@ -0,0 +1,8 @@
1[Icon Theme]
2Name=colorful_midnight_blue
3Comment=Colorful theme (Midnight Blue style)
4Inherits=default
5Directories=16x16
6
7[16x16]
8Size=16
diff --git a/dist/qt_themes/colorful_midnight_blue/style.qrc b/dist/qt_themes/colorful_midnight_blue/style.qrc
new file mode 100644
index 000000000..fd33bc850
--- /dev/null
+++ b/dist/qt_themes/colorful_midnight_blue/style.qrc
@@ -0,0 +1,57 @@
1<RCC>
2 <qresource prefix="icons/colorful_midnight_blue">
3 <file alias="index.theme">icons/index.theme</file>
4 <file alias="16x16/lock.png">icons/16x16/lock.png</file>
5 <file alias="48x48/bad_folder.png">../colorful/icons/48x48/bad_folder.png</file>
6 <file alias="48x48/chip.png">../colorful/icons/48x48/chip.png</file>
7 <file alias="48x48/folder.png">../colorful/icons/48x48/folder.png</file>
8 <file alias="48x48/plus.png">../colorful/icons/48x48/plus.png</file>
9 <file alias="48x48/sd_card.png">../colorful/icons/48x48/sd_card.png</file>
10 <file alias="256x256/plus_folder.png">../colorful/icons/256x256/plus_folder.png</file>
11 </qresource>
12
13 <qresource prefix="qss_icons">
14 <file alias="rc/up_arrow_disabled.png">../qdarkstyle_midnight_blue/rc/up_arrow_disabled.png</file>
15 <file alias="rc/Hmovetoolbar.png">../qdarkstyle_midnight_blue/rc/Hmovetoolbar.png</file>
16 <file alias="rc/stylesheet-branch-end.png">../qdarkstyle_midnight_blue/rc/stylesheet-branch-end.png</file>
17 <file alias="rc/branch_closed-on.png">../qdarkstyle_midnight_blue/rc/branch_closed-on.png</file>
18 <file alias="rc/stylesheet-vline.png">../qdarkstyle_midnight_blue/rc/stylesheet-vline.png</file>
19 <file alias="rc/branch_closed.png">../qdarkstyle_midnight_blue/rc/branch_closed.png</file>
20 <file alias="rc/branch_open-on.png">../qdarkstyle_midnight_blue/rc/branch_open-on.png</file>
21 <file alias="rc/transparent.png">../qdarkstyle_midnight_blue/rc/transparent.png</file>
22 <file alias="rc/right_arrow_disabled.png">../qdarkstyle_midnight_blue/rc/right_arrow_disabled.png</file>
23 <file alias="rc/sizegrip.png">../qdarkstyle_midnight_blue/rc/sizegrip.png</file>
24 <file alias="rc/close.png">../qdarkstyle_midnight_blue/rc/close.png</file>
25 <file alias="rc/close-hover.png">../qdarkstyle_midnight_blue/rc/close-hover.png</file>
26 <file alias="rc/close-pressed.png">../qdarkstyle_midnight_blue/rc/close-pressed.png</file>
27 <file alias="rc/down_arrow.png">../qdarkstyle_midnight_blue/rc/down_arrow.png</file>
28 <file alias="rc/Vmovetoolbar.png">../qdarkstyle_midnight_blue/rc/Vmovetoolbar.png</file>
29 <file alias="rc/left_arrow.png">../qdarkstyle_midnight_blue/rc/left_arrow.png</file>
30 <file alias="rc/stylesheet-branch-more.png">../qdarkstyle_midnight_blue/rc/stylesheet-branch-more.png</file>
31 <file alias="rc/up_arrow.png">../qdarkstyle_midnight_blue/rc/up_arrow.png</file>
32 <file alias="rc/right_arrow.png">../qdarkstyle_midnight_blue/rc/right_arrow.png</file>
33 <file alias="rc/left_arrow_disabled.png">../qdarkstyle_midnight_blue/rc/left_arrow_disabled.png</file>
34 <file alias="rc/Hsepartoolbar.png">../qdarkstyle_midnight_blue/rc/Hsepartoolbar.png</file>
35 <file alias="rc/branch_open.png">../qdarkstyle_midnight_blue/rc/branch_open.png</file>
36 <file alias="rc/Vsepartoolbar.png">../qdarkstyle_midnight_blue/rc/Vsepartoolbar.png</file>
37 <file alias="rc/down_arrow_disabled.png">../qdarkstyle_midnight_blue/rc/down_arrow_disabled.png</file>
38 <file alias="rc/undock.png">../qdarkstyle_midnight_blue/rc/undock.png</file>
39 <file alias="rc/checkbox_checked_disabled.png">../qdarkstyle_midnight_blue/rc/checkbox_checked_disabled.png</file>
40 <file alias="rc/checkbox_checked_focus.png">../qdarkstyle_midnight_blue/rc/checkbox_checked_focus.png</file>
41 <file alias="rc/checkbox_checked.png">../qdarkstyle_midnight_blue/rc/checkbox_checked.png</file>
42 <file alias="rc/checkbox_indeterminate.png">../qdarkstyle_midnight_blue/rc/checkbox_indeterminate.png</file>
43 <file alias="rc/checkbox_indeterminate_focus.png">../qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus.png</file>
44 <file alias="rc/checkbox_unchecked_disabled.png">../qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled.png</file>
45 <file alias="rc/checkbox_unchecked_focus.png">../qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus.png</file>
46 <file alias="rc/checkbox_unchecked.png">../qdarkstyle_midnight_blue/rc/checkbox_unchecked.png</file>
47 <file alias="rc/radio_checked_disabled.png">../qdarkstyle_midnight_blue/rc/radio_checked_disabled.png</file>
48 <file alias="rc/radio_checked_focus.png">../qdarkstyle_midnight_blue/rc/radio_checked_focus.png</file>
49 <file alias="rc/radio_checked.png">../qdarkstyle_midnight_blue/rc/radio_checked.png</file>
50 <file alias="rc/radio_unchecked_disabled.png">../qdarkstyle_midnight_blue/rc/radio_unchecked_disabled.png</file>
51 <file alias="rc/radio_unchecked_focus.png">../qdarkstyle_midnight_blue/rc/radio_unchecked_focus.png</file>
52 <file alias="rc/radio_unchecked.png">../qdarkstyle_midnight_blue/rc/radio_unchecked.png</file>
53 </qresource>
54 <qresource prefix="colorful_midnight_blue">
55 <file alias="style.qss">../qdarkstyle_midnight_blue/style.qss</file>
56 </qresource>
57</RCC>
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png b/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png
index 830cfee65..dd891298f 100644
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png
+++ b/dist/qt_themes/qdarkstyle/rc/checkbox_checked.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png b/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png
index cb63cc2fa..44bf145f8 100644
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png
+++ b/dist/qt_themes/qdarkstyle/rc/checkbox_checked_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png b/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png
index 671be273b..60238b21d 100644
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png
+++ b/dist/qt_themes/qdarkstyle/rc/checkbox_checked_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png
index 41024f768..830cfee65 100644
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png
+++ b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png
index abdc01d90..cb63cc2fa 100644
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png
+++ b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png
index 415f9b6e1..671be273b 100644
--- a/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png
+++ b/dist/qt_themes/qdarkstyle/rc/checkbox_indeterminate_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss
index 2d5c9761f..2926a05fa 100644
--- a/dist/qt_themes/qdarkstyle/style.qss
+++ b/dist/qt_themes/qdarkstyle/style.qss
@@ -654,7 +654,11 @@ QAbstractSpinBox::down-arrow:hover {
654 image: url(:/qss_icons/rc/down_arrow.png); 654 image: url(:/qss_icons/rc/down_arrow.png);
655} 655}
656 656
657QLabel, 657QLabel {
658 border: 0;
659 background: transparent;
660}
661
658QTabWidget { 662QTabWidget {
659 border: 0; 663 border: 0;
660} 664}
@@ -1269,4 +1273,4 @@ QPushButton#RendererStatusBarButton:checked {
1269 1273
1270QPushButton#RendererStatusBarButton:!checked{ 1274QPushButton#RendererStatusBarButton:!checked{
1271 color: #00ccdd; 1275 color: #00ccdd;
1272} \ No newline at end of file 1276}
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/LICENSE.rst b/dist/qt_themes/qdarkstyle_midnight_blue/LICENSE.rst
new file mode 100644
index 000000000..e22b68735
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/LICENSE.rst
@@ -0,0 +1,405 @@
1License
2=======
3
4The MIT License (MIT) - Code
5----------------------------
6
7Copyright (c) 2013-2019 Colin Duquesnoy
8
9Permission is hereby granted, free of charge, to any person obtaining a
10copy of this software and associated documentation files (the
11"Software"), to deal in the Software without restriction, including
12without limitation the rights to use, copy, modify, merge, publish,
13distribute, sublicense, and/or sell copies of the Software, and to
14permit persons to whom the Software is furnished to do so, subject to
15the following conditions:
16
17The above copyright notice and this permission notice shall be included
18in all copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27
28
29Creative Commons Attribution International 4.0 - Images
30-------------------------------------------------------
31
32QDarkStyle (c) 2013-2019 Colin Duquesnoy
33QDarkStyle (c) 2019-2019 Daniel Cosmo Pizetta
34
35Creative Commons Corporation (“Creative Commons”) is not a law firm and
36does not provide legal services or legal advice. Distribution of
37Creative Commons public licenses does not create a lawyer-client or
38other relationship. Creative Commons makes its licenses and related
39information available on an “as-is” basis. Creative Commons gives no
40warranties regarding its licenses, any material licensed under their
41terms and conditions, or any related information. Creative Commons
42disclaims all liability for damages resulting from their use to the
43fullest extent possible.
44
45Using Creative Commons Public Licenses
46~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
47
48Creative Commons public licenses provide a standard set of terms and
49conditions that creators and other rights holders may use to share
50original works of authorship and other material subject to copyright and
51certain other rights specified in the public license below. The
52following considerations are for informational purposes only, are not
53exhaustive, and do not form part of our licenses.
54
55- **Considerations for licensors:** Our public licenses are intended
56 for use by those authorized to give the public permission to use
57 material in ways otherwise restricted by copyright and certain other
58 rights. Our licenses are irrevocable. Licensors should read and
59 understand the terms and conditions of the license they choose before
60 applying it. Licensors should also secure all rights necessary before
61 applying our licenses so that the public can reuse the material as
62 expected. Licensors should clearly mark any material not subject to
63 the license. This includes other CC-licensed material, or material
64 used under an exception or limitation to copyright. `More
65 considerations for
66 licensors <http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensors>`__.
67
68- **Considerations for the public:** By using one of our public
69 licenses, a licensor grants the public permission to use the licensed
70 material under specified terms and conditions. If the licensor’s
71 permission is not necessary for any reason–for example, because of
72 any applicable exception or limitation to copyright–then that use is
73 not regulated by the license. Our licenses grant only permissions
74 under copyright and certain other rights that a licensor has
75 authority to grant. Use of the licensed material may still be
76 restricted for other reasons, including because others have copyright
77 or other rights in the material. A licensor may make special
78 requests, such as asking that all changes be marked or described.
79 Although not required by our licenses, you are encouraged to respect
80 those requests where reasonable. `More considerations for the
81 public <http://wiki.creativecommons.org/Considerations_for_licensors_and_licensees#Considerations_for_licensees>`__.
82
83
84Creative Commons Attribution 4.0 International Public License
85-------------------------------------------------------------
86
87By exercising the Licensed Rights (defined below), You accept and agree
88to be bound by the terms and conditions of this Creative Commons
89Attribution 4.0 International Public License ("Public License"). To the
90extent this Public License may be interpreted as a contract, You are
91granted the Licensed Rights in consideration of Your acceptance of these
92terms and conditions, and the Licensor grants You such rights in
93consideration of benefits the Licensor receives from making the Licensed
94Material available under these terms and conditions.
95
96Section 1 – Definitions
97~~~~~~~~~~~~~~~~~~~~~~~
98
99a. **Adapted Material** means material subject to Copyright and Similar
100 Rights that is derived from or based upon the Licensed Material and
101 in which the Licensed Material is translated, altered, arranged,
102 transformed, or otherwise modified in a manner requiring permission
103 under the Copyright and Similar Rights held by the Licensor. For
104 purposes of this Public License, where the Licensed Material is a
105 musical work, performance, or sound recording, Adapted Material is
106 always produced where the Licensed Material is synched in timed
107 relation with a moving image.
108
109b. **Adapter's License** means the license You apply to Your Copyright
110 and Similar Rights in Your contributions to Adapted Material in
111 accordance with the terms and conditions of this Public License.
112
113c. **Copyright and Similar Rights** means copyright and/or similar
114 rights closely related to copyright including, without limitation,
115 performance, broadcast, sound recording, and Sui Generis Database
116 Rights, without regard to how the rights are labeled or categorized.
117 For purposes of this Public License, the rights specified in Section
118 2(b)(1)-(2) are not Copyright and Similar Rights.
119
120d. **Effective Technological Measures** means those measures that, in
121 the absence of proper authority, may not be circumvented under laws
122 fulfilling obligations under Article 11 of the WIPO Copyright Treaty
123 adopted on December 20, 1996, and/or similar international
124 agreements.
125
126e. **Exceptions and Limitations** means fair use, fair dealing, and/or
127 any other exception or limitation to Copyright and Similar Rights
128 that applies to Your use of the Licensed Material.
129
130f. **Licensed Material** means the artistic or literary work, database,
131 or other material to which the Licensor applied this Public License.
132
133g. **Licensed Rights** means the rights granted to You subject to the
134 terms and conditions of this Public License, which are limited to all
135 Copyright and Similar Rights that apply to Your use of the Licensed
136 Material and that the Licensor has authority to license.
137
138h. **Licensor** means the individual(s) or entity(ies) granting rights
139 under this Public License.
140
141i. **Share** means to provide material to the public by any means or
142 process that requires permission under the Licensed Rights, such as
143 reproduction, public display, public performance, distribution,
144 dissemination, communication, or importation, and to make material
145 available to the public including in ways that members of the public
146 may access the material from a place and at a time individually
147 chosen by them.
148
149j. **Sui Generis Database Rights** means rights other than copyright
150 resulting from Directive 96/9/EC of the European Parliament and of
151 the Council of 11 March 1996 on the legal protection of databases, as
152 amended and/or succeeded, as well as other essentially equivalent
153 rights anywhere in the world.
154
155k. **You** means the individual or entity exercising the Licensed Rights
156 under this Public License. Your has a corresponding meaning.
157
158Section 2 – Scope
159~~~~~~~~~~~~~~~~~
160
161a. **License grant.**
162
1631. Subject to the terms and conditions of this Public License, the
164 Licensor hereby grants You a worldwide, royalty-free,
165 non-sublicensable, non-exclusive, irrevocable license to exercise the
166 Licensed Rights in the Licensed Material to:
167
168 A. reproduce and Share the Licensed Material, in whole or in part;
169 and
170
171 B. produce, reproduce, and Share Adapted Material.
172
1732. **Exceptions and Limitations.** For the avoidance of doubt, where
174 Exceptions and Limitations apply to Your use, this Public License
175 does not apply, and You do not need to comply with its terms and
176 conditions.
177
1783. **Term.** The term of this Public License is specified in Section
179 6(a).
180
1814. **Media and formats; technical modifications allowed.** The Licensor
182 authorizes You to exercise the Licensed Rights in all media and
183 formats whether now known or hereafter created, and to make technical
184 modifications necessary to do so. The Licensor waives and/or agrees
185 not to assert any right or authority to forbid You from making
186 technical modifications necessary to exercise the Licensed Rights,
187 including technical modifications necessary to circumvent Effective
188 Technological Measures. For purposes of this Public License, simply
189 making modifications authorized by this Section 2(a)(4) never
190 produces Adapted Material.
191
1925. **Downstream recipients.**
193
194 A. **Offer from the Licensor – Licensed Material.** Every recipient
195 of the Licensed Material automatically receives an offer from the
196 Licensor to exercise the Licensed Rights under the terms and
197 conditions of this Public License.
198
199 B. **No downstream restrictions.** You may not offer or impose any
200 additional or different terms or conditions on, or apply any
201 Effective Technological Measures to, the Licensed Material if doing
202 so restricts exercise of the Licensed Rights by any recipient of the
203 Licensed Material.
204
2056. **No endorsement.** Nothing in this Public License constitutes or may
206 be construed as permission to assert or imply that You are, or that
207 Your use of the Licensed Material is, connected with, or sponsored,
208 endorsed, or granted official status by, the Licensor or others
209 designated to receive attribution as provided in Section
210 3(a)(1)(A)(i).
211
212b. **Other rights.**
213
2141. Moral rights, such as the right of integrity, are not licensed under
215 this Public License, nor are publicity, privacy, and/or other similar
216 personality rights; however, to the extent possible, the Licensor
217 waives and/or agrees not to assert any such rights held by the
218 Licensor to the limited extent necessary to allow You to exercise the
219 Licensed Rights, but not otherwise.
220
2212. Patent and trademark rights are not licensed under this Public
222 License.
223
2243. To the extent possible, the Licensor waives any right to collect
225 royalties from You for the exercise of the Licensed Rights, whether
226 directly or through a collecting society under any voluntary or
227 waivable statutory or compulsory licensing scheme. In all other cases
228 the Licensor expressly reserves any right to collect such royalties.
229
230Section 3 – License Conditions
231~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
232
233Your exercise of the Licensed Rights is expressly made subject to the
234following conditions.
235
236a. **Attribution.**
237
2381. If You Share the Licensed Material (including in modified form), You
239 must:
240
241 A. retain the following if it is supplied by the Licensor with the
242 Licensed Material:
243
244 i. identification of the creator(s) of the Licensed Material and any
245 others designated to receive attribution, in any reasonable manner
246 requested by the Licensor (including by pseudonym if designated);
247
248 ii. a copyright notice;
249
250 iii. a notice that refers to this Public License;
251
252 iv. a notice that refers to the disclaimer of warranties;
253
254 v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable;
255
256 B. indicate if You modified the Licensed Material and retain an
257 indication of any previous modifications; and
258
259 C. indicate the Licensed Material is licensed under this Public
260 License, and include the text of, or the URI or hyperlink to, this
261 Public License.
262
2632. You may satisfy the conditions in Section 3(a)(1) in any reasonable
264 manner based on the medium, means, and context in which You Share the
265 Licensed Material. For example, it may be reasonable to satisfy the
266 conditions by providing a URI or hyperlink to a resource that
267 includes the required information.
268
2693. If requested by the Licensor, You must remove any of the information
270 required by Section 3(a)(1)(A) to the extent reasonably practicable.
271
2724. If You Share Adapted Material You produce, the Adapter's License You
273 apply must not prevent recipients of the Adapted Material from
274 complying with this Public License.
275
276Section 4 – Sui Generis Database Rights
277~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
278
279Where the Licensed Rights include Sui Generis Database Rights that apply
280to Your use of the Licensed Material:
281
282a. for the avoidance of doubt, Section 2(a)(1) grants You the right to
283 extract, reuse, reproduce, and Share all or a substantial portion of
284 the contents of the database;
285
286b. if You include all or a substantial portion of the database contents
287 in a database in which You have Sui Generis Database Rights, then the
288 database in which You have Sui Generis Database Rights (but not its
289 individual contents) is Adapted Material; and
290
291c. You must comply with the conditions in Section 3(a) if You Share all
292 or a substantial portion of the contents of the database.
293
294For the avoidance of doubt, this Section 4 supplements and does not
295replace Your obligations under this Public License where the Licensed
296Rights include other Copyright and Similar Rights.
297
298Section 5 – Disclaimer of Warranties and Limitation of Liability
299~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
300
301a. Unless otherwise separately undertaken by the Licensor, to the
302 extent possible, the Licensor offers the Licensed Material as-is and
303 as-available, and makes no representations or warranties of any kind
304 concerning the Licensed Material, whether express, implied,
305 statutory, or other. This includes, without limitation, warranties of
306 title, merchantability, fitness for a particular purpose,
307 non-infringement, absence of latent or other defects, accuracy, or
308 the presence or absence of errors, whether or not known or
309 discoverable. Where disclaimers of warranties are not allowed in full
310 or in part, this disclaimer may not apply to You.
311
312b. To the extent possible, in no event will the Licensor be liable to
313 You on any legal theory (including, without limitation, negligence)
314 or otherwise for any direct, special, indirect, incidental,
315 consequential, punitive, exemplary, or other losses, costs, expenses,
316 or damages arising out of this Public License or use of the Licensed
317 Material, even if the Licensor has been advised of the possibility of
318 such losses, costs, expenses, or damages. Where a limitation of
319 liability is not allowed in full or in part, this limitation may not
320 apply to You.
321
322c. The disclaimer of warranties and limitation of liability provided
323 above shall be interpreted in a manner that, to the extent possible,
324 most closely approximates an absolute disclaimer and waiver of all
325 liability.
326
327Section 6 – Term and Termination
328~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
329
330a. This Public License applies for the term of the Copyright and Similar
331 Rights licensed here. However, if You fail to comply with this Public
332 License, then Your rights under this Public License terminate
333 automatically.
334
335b. Where Your right to use the Licensed Material has terminated under
336 Section 6(a), it reinstates:
337
3381. automatically as of the date the violation is cured, provided it is
339 cured within 30 days of Your discovery of the violation; or
340
3412. upon express reinstatement by the Licensor.
342
343For the avoidance of doubt, this Section 6(b) does not affect any right
344the Licensor may have to seek remedies for Your violations of this
345Public License.
346
347c. For the avoidance of doubt, the Licensor may also offer the Licensed
348 Material under separate terms or conditions or stop distributing the
349 Licensed Material at any time; however, doing so will not terminate
350 this Public License.
351
352d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
353 License.
354
355Section 7 – Other Terms and Conditions
356~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
357
358a. The Licensor shall not be bound by any additional or different terms
359 or conditions communicated by You unless expressly agreed.
360
361b. Any arrangements, understandings, or agreements regarding the
362 Licensed Material not stated herein are separate from and independent
363 of the terms and conditions of this Public License.
364
365Section 8 – Interpretation
366~~~~~~~~~~~~~~~~~~~~~~~~~~
367
368a. For the avoidance of doubt, this Public License does not, and shall
369 not be interpreted to, reduce, limit, restrict, or impose conditions
370 on any use of the Licensed Material that could lawfully be made
371 without permission under this Public License.
372
373b. To the extent possible, if any provision of this Public License is
374 deemed unenforceable, it shall be automatically reformed to the
375 minimum extent necessary to make it enforceable. If the provision
376 cannot be reformed, it shall be severed from this Public License
377 without affecting the enforceability of the remaining terms and
378 conditions.
379
380c. No term or condition of this Public License will be waived and no
381 failure to comply consented to unless expressly agreed to by the
382 Licensor.
383
384d. Nothing in this Public License constitutes or may be interpreted as a
385 limitation upon, or waiver of, any privileges and immunities that
386 apply to the Licensor or You, including from the legal processes of
387 any jurisdiction or authority.
388
389 Creative Commons is not a party to its public licenses.
390 Notwithstanding, Creative Commons may elect to apply one of its
391 public licenses to material it publishes and in those instances will
392 be considered the “Licensor.” Except for the limited purpose of
393 indicating that material is shared under a Creative Commons public
394 license or as otherwise permitted by the Creative Commons policies
395 published at
396 `creativecommons.org/policies <http://creativecommons.org/policies>`__,
397 Creative Commons does not authorize the use of the trademark
398 “Creative Commons” or any other trademark or logo of Creative
399 Commons without its prior written consent including, without
400 limitation, in connection with any unauthorized modifications to any
401 of its public licenses or any other arrangements, understandings, or
402 agreements concerning use of licensed material. For the avoidance of
403 doubt, this paragraph does not form part of the public licenses.
404
405 Creative Commons may be contacted at creativecommons.org
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.png
new file mode 100644
index 000000000..c750a39e8
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/16x16/lock.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.png
new file mode 100644
index 000000000..303f9a321
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/256x256/plus_folder.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.png
new file mode 100644
index 000000000..4a9709623
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/bad_folder.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.png
new file mode 100644
index 000000000..973fabd05
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/chip.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.png
new file mode 100644
index 000000000..0f1e987d6
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/folder.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.png
new file mode 100644
index 000000000..16cc8b4f4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/plus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.png b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.png
new file mode 100644
index 000000000..0291c6542
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/48x48/sd_card.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme b/dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme
new file mode 100644
index 000000000..447a6c8be
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/icons/index.theme
@@ -0,0 +1,14 @@
1[Icon Theme]
2Name=qdarkstyle_midnight_blue
3Comment=dark theme
4Inherits=default
5Directories=16x16,48x48,256x256
6
7[16x16]
8Size=16
9
10[48x48]
11Size=48
12
13[256x256]
14Size=256
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hmovetoolbar.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hmovetoolbar.png
new file mode 100644
index 000000000..cead99ed1
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hmovetoolbar.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hsepartoolbar.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hsepartoolbar.png
new file mode 100644
index 000000000..7f183c8b3
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Hsepartoolbar.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vmovetoolbar.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vmovetoolbar.png
new file mode 100644
index 000000000..512edcecd
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vmovetoolbar.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vsepartoolbar.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vsepartoolbar.png
new file mode 100644
index 000000000..d9dc1561b
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/Vsepartoolbar.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down.png
new file mode 100644
index 000000000..c4e6894ba
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down@2x.png
new file mode 100644
index 000000000..bb8cbed0d
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled.png
new file mode 100644
index 000000000..aa1d06c08
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled@2x.png
new file mode 100644
index 000000000..86bf434b8
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus.png
new file mode 100644
index 000000000..1c42ee8f6
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus@2x.png
new file mode 100644
index 000000000..7374637c5
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed.png
new file mode 100644
index 000000000..8139ee3e8
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed@2x.png
new file mode 100644
index 000000000..5e9d225ff
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_down_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left.png
new file mode 100644
index 000000000..ef929fdf0
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left@2x.png
new file mode 100644
index 000000000..c8923d6f4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled.png
new file mode 100644
index 000000000..9c69561a7
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled@2x.png
new file mode 100644
index 000000000..e52114312
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus.png
new file mode 100644
index 000000000..a1f070455
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus@2x.png
new file mode 100644
index 000000000..c4267e856
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed.png
new file mode 100644
index 000000000..bd706cbdd
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed@2x.png
new file mode 100644
index 000000000..341b2e541
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_left_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right.png
new file mode 100644
index 000000000..4f3388505
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right@2x.png
new file mode 100644
index 000000000..94b260965
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled.png
new file mode 100644
index 000000000..0fbc6b04c
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled@2x.png
new file mode 100644
index 000000000..8e9272a5b
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus.png
new file mode 100644
index 000000000..764940945
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus@2x.png
new file mode 100644
index 000000000..6d52b5fa3
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed.png
new file mode 100644
index 000000000..a5f04522a
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed@2x.png
new file mode 100644
index 000000000..6f6a8130c
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_right_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up.png
new file mode 100644
index 000000000..61d7574a4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up@2x.png
new file mode 100644
index 000000000..d711fae16
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled.png
new file mode 100644
index 000000000..18e8ecd8d
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled@2x.png
new file mode 100644
index 000000000..fb4defb52
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus.png
new file mode 100644
index 000000000..a7acd9b66
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus@2x.png
new file mode 100644
index 000000000..9cd982a1d
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed.png
new file mode 100644
index 000000000..390a80e21
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed@2x.png
new file mode 100644
index 000000000..dd352cff3
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/arrow_up_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon.png
new file mode 100644
index 000000000..37a6158cc
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon@2x.png
new file mode 100644
index 000000000..e6e5cb916
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled.png
new file mode 100644
index 000000000..37a6158cc
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled@2x.png
new file mode 100644
index 000000000..e6e5cb916
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus.png
new file mode 100644
index 000000000..37a6158cc
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus@2x.png
new file mode 100644
index 000000000..e6e5cb916
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed.png
new file mode 100644
index 000000000..37a6158cc
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed@2x.png
new file mode 100644
index 000000000..e6e5cb916
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/base_icon_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed-on.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed-on.png
new file mode 100644
index 000000000..d081e9b3b
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed-on.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed.png
new file mode 100644
index 000000000..53e2c51f5
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed@2x.png
new file mode 100644
index 000000000..06cdefa5f
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled.png
new file mode 100644
index 000000000..5106a1438
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled@2x.png
new file mode 100644
index 000000000..180bae9e6
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus.png
new file mode 100644
index 000000000..c227f9f71
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus@2x.png
new file mode 100644
index 000000000..ad23d0d33
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed.png
new file mode 100644
index 000000000..90845a81f
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed@2x.png
new file mode 100644
index 000000000..60aaeb7fb
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_closed_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end.png
new file mode 100644
index 000000000..08b5559b2
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end@2x.png
new file mode 100644
index 000000000..ae6dbe991
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled.png
new file mode 100644
index 000000000..027a8894a
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled@2x.png
new file mode 100644
index 000000000..43c1b0c76
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus.png
new file mode 100644
index 000000000..fdb3160bb
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus@2x.png
new file mode 100644
index 000000000..3ca890449
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed.png
new file mode 100644
index 000000000..1c2432dd4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed@2x.png
new file mode 100644
index 000000000..af0f8fa5a
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_end_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line.png
new file mode 100644
index 000000000..a3a564e44
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line@2x.png
new file mode 100644
index 000000000..1dbf71fc7
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled.png
new file mode 100644
index 000000000..ecc7e6d93
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled@2x.png
new file mode 100644
index 000000000..adc6446c9
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus.png
new file mode 100644
index 000000000..0037f175a
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus@2x.png
new file mode 100644
index 000000000..cb257a914
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed.png
new file mode 100644
index 000000000..2d0856527
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed@2x.png
new file mode 100644
index 000000000..803708fb4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_line_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more.png
new file mode 100644
index 000000000..31b6cee87
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more@2x.png
new file mode 100644
index 000000000..f1f7a67f1
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled.png
new file mode 100644
index 000000000..d4b604905
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled@2x.png
new file mode 100644
index 000000000..3ef752108
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus.png
new file mode 100644
index 000000000..943c13d0b
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus@2x.png
new file mode 100644
index 000000000..9f53ef1fa
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed.png
new file mode 100644
index 000000000..9037ed3b3
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed@2x.png
new file mode 100644
index 000000000..675d52c76
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_more_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open-on.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open-on.png
new file mode 100644
index 000000000..ec372b27d
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open-on.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open.png
new file mode 100644
index 000000000..0861d0bc7
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open@2x.png
new file mode 100644
index 000000000..8850f7367
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled.png
new file mode 100644
index 000000000..b6c80243b
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled@2x.png
new file mode 100644
index 000000000..15ce9f265
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus.png
new file mode 100644
index 000000000..eadb0962a
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus@2x.png
new file mode 100644
index 000000000..7dfcbbe8a
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed.png
new file mode 100644
index 000000000..2b22e8d08
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed@2x.png
new file mode 100644
index 000000000..269a0cbee
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/branch_open_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked.png
new file mode 100644
index 000000000..e7ed08081
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked@2x.png
new file mode 100644
index 000000000..35f2ade58
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled.png
new file mode 100644
index 000000000..512b0a3e4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled@2x.png
new file mode 100644
index 000000000..557383ec8
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus.png
new file mode 100644
index 000000000..0b90412f2
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus@2x.png
new file mode 100644
index 000000000..7aee03cbb
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed.png
new file mode 100644
index 000000000..3d4c869b7
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed@2x.png
new file mode 100644
index 000000000..bfbc14b94
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_checked_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate.png
new file mode 100644
index 000000000..c21ab99bf
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate@2x.png
new file mode 100644
index 000000000..2fc29cee6
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled.png
new file mode 100644
index 000000000..1d3c21492
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled@2x.png
new file mode 100644
index 000000000..bb8e7a747
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus.png
new file mode 100644
index 000000000..13ca4a7a4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus@2x.png
new file mode 100644
index 000000000..3907eb8d4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed.png
new file mode 100644
index 000000000..12f83ceba
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed@2x.png
new file mode 100644
index 000000000..5ff4f6629
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_indeterminate_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked.png
new file mode 100644
index 000000000..e2da452fa
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked@2x.png
new file mode 100644
index 000000000..3732d5406
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled.png
new file mode 100644
index 000000000..c2e30c690
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled@2x.png
new file mode 100644
index 000000000..c4bddb6eb
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus.png
new file mode 100644
index 000000000..c57f04d9f
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus@2x.png
new file mode 100644
index 000000000..1776ad048
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed.png
new file mode 100644
index 000000000..be41236e1
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed@2x.png
new file mode 100644
index 000000000..b1ad7c72f
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/checkbox_unchecked_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-hover.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-hover.png
new file mode 100644
index 000000000..657943a66
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-hover.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-pressed.png
new file mode 100644
index 000000000..937d00598
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close-pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/close.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close.png
new file mode 100644
index 000000000..bc0f57610
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/close.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow.png
new file mode 100644
index 000000000..e271f7f90
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow_disabled.png
new file mode 100644
index 000000000..5805d9842
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/down_arrow_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow.png
new file mode 100644
index 000000000..f808d2d72
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow_disabled.png
new file mode 100644
index 000000000..f5b9af8a3
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/left_arrow_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal.png
new file mode 100644
index 000000000..11bc5c003
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal@2x.png
new file mode 100644
index 000000000..c229ac963
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled.png
new file mode 100644
index 000000000..204df8058
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled@2x.png
new file mode 100644
index 000000000..a4713c565
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus.png
new file mode 100644
index 000000000..ecda0c10b
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus@2x.png
new file mode 100644
index 000000000..84397efdb
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed.png
new file mode 100644
index 000000000..fd5d864ca
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed@2x.png
new file mode 100644
index 000000000..140552e4f
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_horizontal_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical.png
new file mode 100644
index 000000000..a3a564e44
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical@2x.png
new file mode 100644
index 000000000..1dbf71fc7
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled.png
new file mode 100644
index 000000000..ecc7e6d93
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled@2x.png
new file mode 100644
index 000000000..adc6446c9
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus.png
new file mode 100644
index 000000000..0037f175a
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus@2x.png
new file mode 100644
index 000000000..cb257a914
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed.png
new file mode 100644
index 000000000..2d0856527
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed@2x.png
new file mode 100644
index 000000000..803708fb4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/line_vertical_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked.png
new file mode 100644
index 000000000..6f1fd6ca6
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked@2x.png
new file mode 100644
index 000000000..228ffdbf2
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled.png
new file mode 100644
index 000000000..27788530d
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled@2x.png
new file mode 100644
index 000000000..930bfaf70
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus.png
new file mode 100644
index 000000000..ca8e8bc9a
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus@2x.png
new file mode 100644
index 000000000..aa0f1152b
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed.png
new file mode 100644
index 000000000..6e391a0ff
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed@2x.png
new file mode 100644
index 000000000..0512731ae
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_checked_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked.png
new file mode 100644
index 000000000..763306bdc
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked@2x.png
new file mode 100644
index 000000000..28b6a0784
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled.png
new file mode 100644
index 000000000..fc0b12f78
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled@2x.png
new file mode 100644
index 000000000..d31f2b4b9
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus.png
new file mode 100644
index 000000000..9c87b01e4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus@2x.png
new file mode 100644
index 000000000..4b4c7321d
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed.png
new file mode 100644
index 000000000..709e31633
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed@2x.png
new file mode 100644
index 000000000..b014de5f0
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/radio_unchecked_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow.png
new file mode 100644
index 000000000..9b0a4e6a7
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow_disabled.png
new file mode 100644
index 000000000..5c0bee402
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/right_arrow_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/sizegrip.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/sizegrip.png
new file mode 100644
index 000000000..350583aaa
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/sizegrip.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-end.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-end.png
new file mode 100644
index 000000000..cb5d3b51f
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-end.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-more.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-more.png
new file mode 100644
index 000000000..62711409d
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-branch-more.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-vline.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-vline.png
new file mode 100644
index 000000000..87536cce1
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/stylesheet-vline.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal.png
new file mode 100644
index 000000000..012ea2dfb
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal@2x.png
new file mode 100644
index 000000000..520c34f98
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled.png
new file mode 100644
index 000000000..1f91df98f
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled@2x.png
new file mode 100644
index 000000000..738008f92
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus.png
new file mode 100644
index 000000000..999b3c7d8
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus@2x.png
new file mode 100644
index 000000000..f8e40b7d1
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed.png
new file mode 100644
index 000000000..c31b69deb
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed@2x.png
new file mode 100644
index 000000000..2f4cb41c7
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_horizontal_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical.png
new file mode 100644
index 000000000..16473bfd8
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical@2x.png
new file mode 100644
index 000000000..90a5caee3
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled.png
new file mode 100644
index 000000000..2d240edb5
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled@2x.png
new file mode 100644
index 000000000..fd1df30f1
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus.png
new file mode 100644
index 000000000..58cda1f80
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus@2x.png
new file mode 100644
index 000000000..9222b4fd8
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed.png
new file mode 100644
index 000000000..e7d641926
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed@2x.png
new file mode 100644
index 000000000..9c438faf4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_move_vertical_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal.png
new file mode 100644
index 000000000..3c0acbdcc
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal@2x.png
new file mode 100644
index 000000000..fb4e24c88
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled.png
new file mode 100644
index 000000000..32f7e8ca6
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled@2x.png
new file mode 100644
index 000000000..f7bec188b
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus.png
new file mode 100644
index 000000000..91c19d65c
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus@2x.png
new file mode 100644
index 000000000..c4829918d
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed.png
new file mode 100644
index 000000000..7a7f91737
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed@2x.png
new file mode 100644
index 000000000..d65773b48
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_horizontal_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical.png
new file mode 100644
index 000000000..4dde3f37f
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical@2x.png
new file mode 100644
index 000000000..fe97c0de3
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled.png
new file mode 100644
index 000000000..7426ae2de
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled@2x.png
new file mode 100644
index 000000000..7acc6d33e
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus.png
new file mode 100644
index 000000000..6e3c12143
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus@2x.png
new file mode 100644
index 000000000..cac3a56c2
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed.png
new file mode 100644
index 000000000..b777784b8
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed@2x.png
new file mode 100644
index 000000000..7ed878fd3
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/toolbar_separator_vertical_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent.png
new file mode 100644
index 000000000..8b241c4a4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent@2x.png
new file mode 100644
index 000000000..2c3df7a5e
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled.png
new file mode 100644
index 000000000..8b241c4a4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled@2x.png
new file mode 100644
index 000000000..2c3df7a5e
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus.png
new file mode 100644
index 000000000..8b241c4a4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus@2x.png
new file mode 100644
index 000000000..2c3df7a5e
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed.png
new file mode 100644
index 000000000..8b241c4a4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed@2x.png
new file mode 100644
index 000000000..2c3df7a5e
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/transparent_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/undock.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/undock.png
new file mode 100644
index 000000000..88691d779
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/undock.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow.png
new file mode 100644
index 000000000..abcc72452
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow_disabled.png
new file mode 100644
index 000000000..b9c8e3b53
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/up_arrow_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close.png
new file mode 100644
index 000000000..6f55c3ae7
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close@2x.png
new file mode 100644
index 000000000..ff644f2e8
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled.png
new file mode 100644
index 000000000..22694e31d
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled@2x.png
new file mode 100644
index 000000000..ebc97db70
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus.png
new file mode 100644
index 000000000..f017eda31
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus@2x.png
new file mode 100644
index 000000000..5a354d796
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed.png
new file mode 100644
index 000000000..04b922dd0
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed@2x.png
new file mode 100644
index 000000000..58c0bf592
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_close_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip.png
new file mode 100644
index 000000000..0528049bb
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip@2x.png
new file mode 100644
index 000000000..1ca1b073c
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled.png
new file mode 100644
index 000000000..15f55c056
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled@2x.png
new file mode 100644
index 000000000..33a4588e8
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus.png
new file mode 100644
index 000000000..06e76c31f
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus@2x.png
new file mode 100644
index 000000000..58c2d06e4
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed.png
new file mode 100644
index 000000000..b3a566cdb
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed@2x.png
new file mode 100644
index 000000000..e9da94049
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_grip_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize.png
new file mode 100644
index 000000000..f60981615
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize@2x.png
new file mode 100644
index 000000000..30f728f02
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled.png
new file mode 100644
index 000000000..29db1c9b1
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled@2x.png
new file mode 100644
index 000000000..1572ca2fe
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus.png
new file mode 100644
index 000000000..cb592f598
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus@2x.png
new file mode 100644
index 000000000..6f6465169
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed.png
new file mode 100644
index 000000000..6962440ac
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed@2x.png
new file mode 100644
index 000000000..cb028272b
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_minimize_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock.png
new file mode 100644
index 000000000..616da991a
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock@2x.png
new file mode 100644
index 000000000..511036bf2
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled.png
new file mode 100644
index 000000000..a2b3d25b2
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled@2x.png
new file mode 100644
index 000000000..638ec8104
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_disabled@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus.png
new file mode 100644
index 000000000..ae6dc4a60
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus@2x.png
new file mode 100644
index 000000000..d06dd1eac
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_focus@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed.png
new file mode 100644
index 000000000..e9142ded2
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed@2x.png b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed@2x.png
new file mode 100644
index 000000000..a597420f3
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/rc/window_undock_pressed@2x.png
Binary files differ
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc
new file mode 100644
index 000000000..1b7686f15
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qrc
@@ -0,0 +1,225 @@
1<RCC>
2 <qresource prefix="icons/qdarkstyle_midnight_blue">
3 <file alias="index.theme">icons/index.theme</file>
4 <file alias="16x16/lock.png">icons/16x16/lock.png</file>
5 <file alias="48x48/bad_folder.png">icons/48x48/bad_folder.png</file>
6 <file alias="48x48/chip.png">icons/48x48/chip.png</file>
7 <file alias="48x48/folder.png">icons/48x48/folder.png</file>
8 <file alias="48x48/plus.png">icons/48x48/plus.png</file>
9 <file alias="48x48/sd_card.png">icons/48x48/sd_card.png</file>
10 <file alias="256x256/plus_folder.png">icons/256x256/plus_folder.png</file>
11 </qresource>
12 <qresource prefix="qss_icons">
13 <file>rc/arrow_down.png</file>
14 <file>rc/arrow_down@2x.png</file>
15 <file>rc/arrow_down_disabled.png</file>
16 <file>rc/arrow_down_disabled@2x.png</file>
17 <file>rc/arrow_down_focus.png</file>
18 <file>rc/arrow_down_focus@2x.png</file>
19 <file>rc/arrow_down_pressed.png</file>
20 <file>rc/arrow_down_pressed@2x.png</file>
21 <file>rc/arrow_left.png</file>
22 <file>rc/arrow_left@2x.png</file>
23 <file>rc/arrow_left_disabled.png</file>
24 <file>rc/arrow_left_disabled@2x.png</file>
25 <file>rc/arrow_left_focus.png</file>
26 <file>rc/arrow_left_focus@2x.png</file>
27 <file>rc/arrow_left_pressed.png</file>
28 <file>rc/arrow_left_pressed@2x.png</file>
29 <file>rc/arrow_right.png</file>
30 <file>rc/arrow_right@2x.png</file>
31 <file>rc/arrow_right_disabled.png</file>
32 <file>rc/arrow_right_disabled@2x.png</file>
33 <file>rc/arrow_right_focus.png</file>
34 <file>rc/arrow_right_focus@2x.png</file>
35 <file>rc/arrow_right_pressed.png</file>
36 <file>rc/arrow_right_pressed@2x.png</file>
37 <file>rc/arrow_up.png</file>
38 <file>rc/arrow_up@2x.png</file>
39 <file>rc/arrow_up_disabled.png</file>
40 <file>rc/arrow_up_disabled@2x.png</file>
41 <file>rc/arrow_up_focus.png</file>
42 <file>rc/arrow_up_focus@2x.png</file>
43 <file>rc/arrow_up_pressed.png</file>
44 <file>rc/arrow_up_pressed@2x.png</file>
45 <file>rc/base_icon.png</file>
46 <file>rc/base_icon@2x.png</file>
47 <file>rc/base_icon_disabled.png</file>
48 <file>rc/base_icon_disabled@2x.png</file>
49 <file>rc/base_icon_focus.png</file>
50 <file>rc/base_icon_focus@2x.png</file>
51 <file>rc/base_icon_pressed.png</file>
52 <file>rc/base_icon_pressed@2x.png</file>
53 <file>rc/branch_closed.png</file>
54 <file>rc/branch_closed@2x.png</file>
55 <file>rc/branch_closed_disabled.png</file>
56 <file>rc/branch_closed_disabled@2x.png</file>
57 <file>rc/branch_closed_focus.png</file>
58 <file>rc/branch_closed_focus@2x.png</file>
59 <file>rc/branch_closed_pressed.png</file>
60 <file>rc/branch_closed_pressed@2x.png</file>
61 <file>rc/branch_end.png</file>
62 <file>rc/branch_end@2x.png</file>
63 <file>rc/branch_end_disabled.png</file>
64 <file>rc/branch_end_disabled@2x.png</file>
65 <file>rc/branch_end_focus.png</file>
66 <file>rc/branch_end_focus@2x.png</file>
67 <file>rc/branch_end_pressed.png</file>
68 <file>rc/branch_end_pressed@2x.png</file>
69 <file>rc/branch_line.png</file>
70 <file>rc/branch_line@2x.png</file>
71 <file>rc/branch_line_disabled.png</file>
72 <file>rc/branch_line_disabled@2x.png</file>
73 <file>rc/branch_line_focus.png</file>
74 <file>rc/branch_line_focus@2x.png</file>
75 <file>rc/branch_line_pressed.png</file>
76 <file>rc/branch_line_pressed@2x.png</file>
77 <file>rc/branch_more.png</file>
78 <file>rc/branch_more@2x.png</file>
79 <file>rc/branch_more_disabled.png</file>
80 <file>rc/branch_more_disabled@2x.png</file>
81 <file>rc/branch_more_focus.png</file>
82 <file>rc/branch_more_focus@2x.png</file>
83 <file>rc/branch_more_pressed.png</file>
84 <file>rc/branch_more_pressed@2x.png</file>
85 <file>rc/branch_open.png</file>
86 <file>rc/branch_open@2x.png</file>
87 <file>rc/branch_open_disabled.png</file>
88 <file>rc/branch_open_disabled@2x.png</file>
89 <file>rc/branch_open_focus.png</file>
90 <file>rc/branch_open_focus@2x.png</file>
91 <file>rc/branch_open_pressed.png</file>
92 <file>rc/branch_open_pressed@2x.png</file>
93 <file>rc/checkbox_checked.png</file>
94 <file>rc/checkbox_checked@2x.png</file>
95 <file>rc/checkbox_checked_disabled.png</file>
96 <file>rc/checkbox_checked_disabled@2x.png</file>
97 <file>rc/checkbox_checked_focus.png</file>
98 <file>rc/checkbox_checked_focus@2x.png</file>
99 <file>rc/checkbox_checked_pressed.png</file>
100 <file>rc/checkbox_checked_pressed@2x.png</file>
101 <file>rc/checkbox_indeterminate.png</file>
102 <file>rc/checkbox_indeterminate@2x.png</file>
103 <file>rc/checkbox_indeterminate_disabled.png</file>
104 <file>rc/checkbox_indeterminate_disabled@2x.png</file>
105 <file>rc/checkbox_indeterminate_focus.png</file>
106 <file>rc/checkbox_indeterminate_focus@2x.png</file>
107 <file>rc/checkbox_indeterminate_pressed.png</file>
108 <file>rc/checkbox_indeterminate_pressed@2x.png</file>
109 <file>rc/checkbox_unchecked.png</file>
110 <file>rc/checkbox_unchecked@2x.png</file>
111 <file>rc/checkbox_unchecked_disabled.png</file>
112 <file>rc/checkbox_unchecked_disabled@2x.png</file>
113 <file>rc/checkbox_unchecked_focus.png</file>
114 <file>rc/checkbox_unchecked_focus@2x.png</file>
115 <file>rc/checkbox_unchecked_pressed.png</file>
116 <file>rc/checkbox_unchecked_pressed@2x.png</file>
117 <file>rc/line_horizontal.png</file>
118 <file>rc/line_horizontal@2x.png</file>
119 <file>rc/line_horizontal_disabled.png</file>
120 <file>rc/line_horizontal_disabled@2x.png</file>
121 <file>rc/line_horizontal_focus.png</file>
122 <file>rc/line_horizontal_focus@2x.png</file>
123 <file>rc/line_horizontal_pressed.png</file>
124 <file>rc/line_horizontal_pressed@2x.png</file>
125 <file>rc/line_vertical.png</file>
126 <file>rc/line_vertical@2x.png</file>
127 <file>rc/line_vertical_disabled.png</file>
128 <file>rc/line_vertical_disabled@2x.png</file>
129 <file>rc/line_vertical_focus.png</file>
130 <file>rc/line_vertical_focus@2x.png</file>
131 <file>rc/line_vertical_pressed.png</file>
132 <file>rc/line_vertical_pressed@2x.png</file>
133 <file>rc/radio_checked.png</file>
134 <file>rc/radio_checked@2x.png</file>
135 <file>rc/radio_checked_disabled.png</file>
136 <file>rc/radio_checked_disabled@2x.png</file>
137 <file>rc/radio_checked_focus.png</file>
138 <file>rc/radio_checked_focus@2x.png</file>
139 <file>rc/radio_checked_pressed.png</file>
140 <file>rc/radio_checked_pressed@2x.png</file>
141 <file>rc/radio_unchecked.png</file>
142 <file>rc/radio_unchecked@2x.png</file>
143 <file>rc/radio_unchecked_disabled.png</file>
144 <file>rc/radio_unchecked_disabled@2x.png</file>
145 <file>rc/radio_unchecked_focus.png</file>
146 <file>rc/radio_unchecked_focus@2x.png</file>
147 <file>rc/radio_unchecked_pressed.png</file>
148 <file>rc/radio_unchecked_pressed@2x.png</file>
149 <file>rc/toolbar_move_horizontal.png</file>
150 <file>rc/toolbar_move_horizontal@2x.png</file>
151 <file>rc/toolbar_move_horizontal_disabled.png</file>
152 <file>rc/toolbar_move_horizontal_disabled@2x.png</file>
153 <file>rc/toolbar_move_horizontal_focus.png</file>
154 <file>rc/toolbar_move_horizontal_focus@2x.png</file>
155 <file>rc/toolbar_move_horizontal_pressed.png</file>
156 <file>rc/toolbar_move_horizontal_pressed@2x.png</file>
157 <file>rc/toolbar_move_vertical.png</file>
158 <file>rc/toolbar_move_vertical@2x.png</file>
159 <file>rc/toolbar_move_vertical_disabled.png</file>
160 <file>rc/toolbar_move_vertical_disabled@2x.png</file>
161 <file>rc/toolbar_move_vertical_focus.png</file>
162 <file>rc/toolbar_move_vertical_focus@2x.png</file>
163 <file>rc/toolbar_move_vertical_pressed.png</file>
164 <file>rc/toolbar_move_vertical_pressed@2x.png</file>
165 <file>rc/toolbar_separator_horizontal.png</file>
166 <file>rc/toolbar_separator_horizontal@2x.png</file>
167 <file>rc/toolbar_separator_horizontal_disabled.png</file>
168 <file>rc/toolbar_separator_horizontal_disabled@2x.png</file>
169 <file>rc/toolbar_separator_horizontal_focus.png</file>
170 <file>rc/toolbar_separator_horizontal_focus@2x.png</file>
171 <file>rc/toolbar_separator_horizontal_pressed.png</file>
172 <file>rc/toolbar_separator_horizontal_pressed@2x.png</file>
173 <file>rc/toolbar_separator_vertical.png</file>
174 <file>rc/toolbar_separator_vertical@2x.png</file>
175 <file>rc/toolbar_separator_vertical_disabled.png</file>
176 <file>rc/toolbar_separator_vertical_disabled@2x.png</file>
177 <file>rc/toolbar_separator_vertical_focus.png</file>
178 <file>rc/toolbar_separator_vertical_focus@2x.png</file>
179 <file>rc/toolbar_separator_vertical_pressed.png</file>
180 <file>rc/toolbar_separator_vertical_pressed@2x.png</file>
181 <file>rc/transparent.png</file>
182 <file>rc/transparent@2x.png</file>
183 <file>rc/transparent_disabled.png</file>
184 <file>rc/transparent_disabled@2x.png</file>
185 <file>rc/transparent_focus.png</file>
186 <file>rc/transparent_focus@2x.png</file>
187 <file>rc/transparent_pressed.png</file>
188 <file>rc/transparent_pressed@2x.png</file>
189 <file>rc/window_close.png</file>
190 <file>rc/window_close@2x.png</file>
191 <file>rc/window_close_disabled.png</file>
192 <file>rc/window_close_disabled@2x.png</file>
193 <file>rc/window_close_focus.png</file>
194 <file>rc/window_close_focus@2x.png</file>
195 <file>rc/window_close_pressed.png</file>
196 <file>rc/window_close_pressed@2x.png</file>
197 <file>rc/window_grip.png</file>
198 <file>rc/window_grip@2x.png</file>
199 <file>rc/window_grip_disabled.png</file>
200 <file>rc/window_grip_disabled@2x.png</file>
201 <file>rc/window_grip_focus.png</file>
202 <file>rc/window_grip_focus@2x.png</file>
203 <file>rc/window_grip_pressed.png</file>
204 <file>rc/window_grip_pressed@2x.png</file>
205 <file>rc/window_minimize.png</file>
206 <file>rc/window_minimize@2x.png</file>
207 <file>rc/window_minimize_disabled.png</file>
208 <file>rc/window_minimize_disabled@2x.png</file>
209 <file>rc/window_minimize_focus.png</file>
210 <file>rc/window_minimize_focus@2x.png</file>
211 <file>rc/window_minimize_pressed.png</file>
212 <file>rc/window_minimize_pressed@2x.png</file>
213 <file>rc/window_undock.png</file>
214 <file>rc/window_undock@2x.png</file>
215 <file>rc/window_undock_disabled.png</file>
216 <file>rc/window_undock_disabled@2x.png</file>
217 <file>rc/window_undock_focus.png</file>
218 <file>rc/window_undock_focus@2x.png</file>
219 <file>rc/window_undock_pressed.png</file>
220 <file>rc/window_undock_pressed@2x.png</file>
221 </qresource>
222 <qresource prefix="qdarkstyle_midnight_blue">
223 <file>style.qss</file>
224 </qresource>
225</RCC>
diff --git a/dist/qt_themes/qdarkstyle_midnight_blue/style.qss b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
new file mode 100644
index 000000000..9c24b0d07
--- /dev/null
+++ b/dist/qt_themes/qdarkstyle_midnight_blue/style.qss
@@ -0,0 +1,2174 @@
1/* ---------------------------------------------------------------------------
2
3 Created by the qtsass compiler v0.1.1
4
5 The definitions are in the "qdarkstyle.qss._styles.scss" module
6
7 WARNING! All changes made in this file will be lost!
8
9--------------------------------------------------------------------------- */
10/* QDarkStyleSheet -----------------------------------------------------------
11
12This is the main style sheet, the palette has nine colors.
13
14It is based on three selecting colors, three greyish (background) colors
15plus three whitish (foreground) colors. Each set of widgets of the same
16type have a header like this:
17
18 ------------------
19 GroupName --------
20 ------------------
21
22And each widget is separated with a header like this:
23
24 QWidgetName ------
25
26This makes more easy to find and change some css field. The basic
27configuration is described bellow.
28
29 BACKGROUND -----------
30
31 Light (unpressed)
32 Normal (border, disabled, pressed, checked, toolbars, menus)
33 Dark (background)
34
35 FOREGROUND -----------
36
37 Light (texts/labels)
38 Normal (not used yet)
39 Dark (disabled texts)
40
41 SELECTION ------------
42
43 Light (selection/hover/active)
44 Normal (selected)
45 Dark (selected disabled)
46
47If a stranger configuration is required because of a bugfix or anything
48else, keep the comment on the line above so nobody changes it, including the
49issue number.
50
51*/
52/*
53
54See Qt documentation:
55
56 - https://doc.qt.io/qt-5/stylesheet.html
57 - https://doc.qt.io/qt-5/stylesheet-reference.html
58 - https://doc.qt.io/qt-5/stylesheet-examples.html
59
60--------------------------------------------------------------------------- */
61/* QWidget ----------------------------------------------------------------
62
63--------------------------------------------------------------------------- */
64QWidget {
65 background-color: #19232D;
66 border: 0px solid #32414B;
67 padding: 0px;
68 color: #F0F0F0;
69 selection-background-color: #1464A0;
70 selection-color: #F0F0F0;
71}
72
73QWidget:disabled {
74 background-color: #19232D;
75 color: #787878;
76 selection-background-color: #14506E;
77 selection-color: #787878;
78}
79
80QWidget::item:selected {
81 background-color: #1464A0;
82}
83
84QWidget::item:hover {
85 background-color: #148CD2;
86 color: #32414B;
87}
88
89/* QMainWindow ------------------------------------------------------------
90
91This adjusts the splitter in the dock widget, not qsplitter
92https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmainwindow
93
94--------------------------------------------------------------------------- */
95QMainWindow::separator {
96 background-color: #32414B;
97 border: 0px solid #19232D;
98 spacing: 0px;
99 padding: 2px;
100}
101
102QMainWindow::separator:hover {
103 background-color: #505F69;
104 border: 0px solid #148CD2;
105}
106
107QMainWindow::separator:horizontal {
108 width: 5px;
109 margin-top: 2px;
110 margin-bottom: 2px;
111 image: url(":/qss_icons/rc/toolbar_separator_vertical.png");
112}
113
114QMainWindow::separator:vertical {
115 height: 5px;
116 margin-left: 2px;
117 margin-right: 2px;
118 image: url(":/qss_icons/rc/toolbar_separator_horizontal.png");
119}
120
121/* QToolTip ---------------------------------------------------------------
122
123https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtooltip
124
125--------------------------------------------------------------------------- */
126QToolTip {
127 background-color: #148CD2;
128 border: 1px solid #19232D;
129 color: #19232D;
130 /* Remove padding, for fix combo box tooltip */
131 padding: 0px;
132 /* Remove opacity, fix #174 - may need to use RGBA */
133}
134
135/* QStatusBar -------------------------------------------------------------
136
137https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qstatusbar
138
139--------------------------------------------------------------------------- */
140QStatusBar {
141 border: 1px solid #32414B;
142 /* Fixes Spyder #9120, #9121 */
143 background: #32414B;
144 /* Fixes #205, white vertical borders separating items */
145}
146
147QStatusBar::item {
148 border: none;
149}
150
151QStatusBar QToolTip {
152 background-color: #148CD2;
153 border: 1px solid #19232D;
154 color: #19232D;
155 /* Remove padding, for fix combo box tooltip */
156 padding: 0px;
157 /* Reducing transparency to read better */
158 opacity: 230;
159}
160
161QStatusBar QLabel {
162 /* Fixes Spyder #9120, #9121 */
163 background: transparent;
164}
165
166/* QCheckBox --------------------------------------------------------------
167
168https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcheckbox
169
170--------------------------------------------------------------------------- */
171QCheckBox {
172 background-color: #19232D;
173 color: #F0F0F0;
174 spacing: 4px;
175 outline: none;
176 padding-top: 4px;
177 padding-bottom: 4px;
178}
179
180QCheckBox:focus {
181 border: none;
182}
183
184QCheckBox QWidget:disabled {
185 background-color: #19232D;
186 color: #787878;
187}
188
189QCheckBox::indicator {
190 margin-left: 4px;
191 height: 16px;
192 width: 16px;
193}
194
195QCheckBox::indicator:unchecked {
196 image: url(":/qss_icons/rc/checkbox_unchecked.png");
197}
198
199QCheckBox::indicator:unchecked:hover, QCheckBox::indicator:unchecked:focus, QCheckBox::indicator:unchecked:pressed {
200 border: none;
201 image: url(":/qss_icons/rc/checkbox_unchecked_focus.png");
202}
203
204QCheckBox::indicator:unchecked:disabled {
205 image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png");
206}
207
208QCheckBox::indicator:checked {
209 image: url(":/qss_icons/rc/checkbox_checked.png");
210}
211
212QCheckBox::indicator:checked:hover, QCheckBox::indicator:checked:focus, QCheckBox::indicator:checked:pressed {
213 border: none;
214 image: url(":/qss_icons/rc/checkbox_checked_focus.png");
215}
216
217QCheckBox::indicator:checked:disabled {
218 image: url(":/qss_icons/rc/checkbox_checked_disabled.png");
219}
220
221QCheckBox::indicator:indeterminate {
222 image: url(":/qss_icons/rc/checkbox_indeterminate.png");
223}
224
225QCheckBox::indicator:indeterminate:disabled {
226 image: url(":/qss_icons/rc/checkbox_indeterminate_disabled.png");
227}
228
229QCheckBox::indicator:indeterminate:focus, QCheckBox::indicator:indeterminate:hover, QCheckBox::indicator:indeterminate:pressed {
230 image: url(":/qss_icons/rc/checkbox_indeterminate_focus.png");
231}
232
233/* QGroupBox --------------------------------------------------------------
234
235https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qgroupbox
236
237--------------------------------------------------------------------------- */
238QGroupBox {
239 font-weight: bold;
240 border: 1px solid #32414B;
241 border-radius: 4px;
242 padding: 4px;
243 margin-top: 16px;
244}
245
246QGroupBox::title {
247 subcontrol-origin: margin;
248 subcontrol-position: top left;
249 left: 3px;
250 padding-left: 3px;
251 padding-right: 5px;
252 padding-top: 8px;
253 padding-bottom: 16px;
254}
255
256QGroupBox::indicator {
257 margin-left: 2px;
258 height: 16px;
259 width: 16px;
260}
261
262QGroupBox::indicator:unchecked {
263 border: none;
264 image: url(":/qss_icons/rc/checkbox_unchecked.png");
265}
266
267QGroupBox::indicator:unchecked:hover, QGroupBox::indicator:unchecked:focus, QGroupBox::indicator:unchecked:pressed {
268 border: none;
269 image: url(":/qss_icons/rc/checkbox_unchecked_focus.png");
270}
271
272QGroupBox::indicator:unchecked:disabled {
273 image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png");
274}
275
276QGroupBox::indicator:checked {
277 border: none;
278 image: url(":/qss_icons/rc/checkbox_checked.png");
279}
280
281QGroupBox::indicator:checked:hover, QGroupBox::indicator:checked:focus, QGroupBox::indicator:checked:pressed {
282 border: none;
283 image: url(":/qss_icons/rc/checkbox_checked_focus.png");
284}
285
286QGroupBox::indicator:checked:disabled {
287 image: url(":/qss_icons/rc/checkbox_checked_disabled.png");
288}
289
290/* QRadioButton -----------------------------------------------------------
291
292https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qradiobutton
293
294--------------------------------------------------------------------------- */
295QRadioButton {
296 background-color: #19232D;
297 color: #F0F0F0;
298 spacing: 4px;
299 padding: 0px;
300 border: none;
301 outline: none;
302}
303
304QRadioButton:focus {
305 border: none;
306}
307
308QRadioButton:disabled {
309 background-color: #19232D;
310 color: #787878;
311 border: none;
312 outline: none;
313}
314
315QRadioButton QWidget {
316 background-color: #19232D;
317 color: #F0F0F0;
318 spacing: 0px;
319 padding: 0px;
320 outline: none;
321 border: none;
322}
323
324QRadioButton::indicator {
325 border: none;
326 outline: none;
327 margin-left: 4px;
328 height: 16px;
329 width: 16px;
330}
331
332QRadioButton::indicator:unchecked {
333 image: url(":/qss_icons/rc/radio_unchecked.png");
334}
335
336QRadioButton::indicator:unchecked:hover, QRadioButton::indicator:unchecked:focus, QRadioButton::indicator:unchecked:pressed {
337 border: none;
338 outline: none;
339 image: url(":/qss_icons/rc/radio_unchecked_focus.png");
340}
341
342QRadioButton::indicator:unchecked:disabled {
343 image: url(":/qss_icons/rc/radio_unchecked_disabled.png");
344}
345
346QRadioButton::indicator:checked {
347 border: none;
348 outline: none;
349 image: url(":/qss_icons/rc/radio_checked.png");
350}
351
352QRadioButton::indicator:checked:hover, QRadioButton::indicator:checked:focus, QRadioButton::indicator:checked:pressed {
353 border: none;
354 outline: none;
355 image: url(":/qss_icons/rc/radio_checked_focus.png");
356}
357
358QRadioButton::indicator:checked:disabled {
359 outline: none;
360 image: url(":/qss_icons/rc/radio_checked_disabled.png");
361}
362
363/* QMenuBar ---------------------------------------------------------------
364
365https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenubar
366
367--------------------------------------------------------------------------- */
368QMenuBar {
369 background-color: #32414B;
370 padding: 2px;
371 border: 1px solid #19232D;
372 color: #F0F0F0;
373}
374
375QMenuBar:focus {
376 border: 1px solid #148CD2;
377}
378
379QMenuBar::item {
380 background: transparent;
381 padding: 4px;
382}
383
384QMenuBar::item:selected {
385 padding: 4px;
386 background: transparent;
387 border: 0px solid #32414B;
388}
389
390QMenuBar::item:pressed {
391 padding: 4px;
392 border: 0px solid #32414B;
393 background-color: #148CD2;
394 color: #F0F0F0;
395 margin-bottom: 0px;
396 padding-bottom: 0px;
397}
398
399/* QMenu ------------------------------------------------------------------
400
401https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qmenu
402
403--------------------------------------------------------------------------- */
404QMenu {
405 border: 0px solid #32414B;
406 color: #F0F0F0;
407 margin: 0px;
408}
409
410QMenu::separator {
411 height: 1px;
412 background-color: #505F69;
413 color: #F0F0F0;
414}
415
416QMenu::icon {
417 margin: 0px;
418 padding-left: 8px;
419}
420
421QMenu::item {
422 background-color: #32414B;
423 padding: 4px 24px 4px 24px;
424 /* Reserve space for selection border */
425 border: 1px transparent #32414B;
426}
427
428QMenu::item:selected {
429 color: #F0F0F0;
430}
431
432QMenu::indicator {
433 width: 12px;
434 height: 12px;
435 padding-left: 6px;
436 /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */
437 /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */
438}
439
440QMenu::indicator:non-exclusive:unchecked {
441 image: url(":/qss_icons/rc/checkbox_unchecked.png");
442}
443
444QMenu::indicator:non-exclusive:unchecked:selected {
445 image: url(":/qss_icons/rc/checkbox_unchecked_disabled.png");
446}
447
448QMenu::indicator:non-exclusive:checked {
449 image: url(":/qss_icons/rc/checkbox_checked.png");
450}
451
452QMenu::indicator:non-exclusive:checked:selected {
453 image: url(":/qss_icons/rc/checkbox_checked_disabled.png");
454}
455
456QMenu::indicator:exclusive:unchecked {
457 image: url(":/qss_icons/rc/radio_unchecked.png");
458}
459
460QMenu::indicator:exclusive:unchecked:selected {
461 image: url(":/qss_icons/rc/radio_unchecked_disabled.png");
462}
463
464QMenu::indicator:exclusive:checked {
465 image: url(":/qss_icons/rc/radio_checked.png");
466}
467
468QMenu::indicator:exclusive:checked:selected {
469 image: url(":/qss_icons/rc/radio_checked_disabled.png");
470}
471
472QMenu::right-arrow {
473 margin: 5px;
474 image: url(":/qss_icons/rc/arrow_right.png");
475 height: 12px;
476 width: 12px;
477}
478
479/* QAbstractItemView ------------------------------------------------------
480
481https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox
482
483--------------------------------------------------------------------------- */
484QAbstractItemView {
485 alternate-background-color: #19232D;
486 color: #F0F0F0;
487 border: 1px solid #32414B;
488 border-radius: 4px;
489}
490
491QAbstractItemView QLineEdit {
492 padding: 2px;
493}
494
495/* QAbstractScrollArea ----------------------------------------------------
496
497https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea
498
499--------------------------------------------------------------------------- */
500QAbstractScrollArea {
501 background-color: #19232D;
502 border: 1px solid #32414B;
503 border-radius: 4px;
504 padding: 2px;
505 /* fix #159 */
506 min-height: 1.25em;
507 /* fix #159 */
508 color: #F0F0F0;
509}
510
511QAbstractScrollArea:disabled {
512 color: #787878;
513}
514
515/* QScrollArea ------------------------------------------------------------
516
517--------------------------------------------------------------------------- */
518QScrollArea QWidget QWidget:disabled {
519 background-color: #19232D;
520}
521
522/* QScrollBar -------------------------------------------------------------
523
524https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qscrollbar
525
526--------------------------------------------------------------------------- */
527QScrollBar:horizontal {
528 height: 16px;
529 margin: 2px 16px 2px 16px;
530 border: 1px solid #32414B;
531 border-radius: 4px;
532 background-color: #19232D;
533}
534
535QScrollBar:vertical {
536 background-color: #19232D;
537 width: 16px;
538 margin: 16px 2px 16px 2px;
539 border: 1px solid #32414B;
540 border-radius: 4px;
541}
542
543QScrollBar::handle:horizontal {
544 background-color: #787878;
545 border: 1px solid #32414B;
546 border-radius: 4px;
547 min-width: 8px;
548}
549
550QScrollBar::handle:horizontal:hover {
551 background-color: #148CD2;
552 border: 1px solid #148CD2;
553 border-radius: 4px;
554 min-width: 8px;
555}
556
557QScrollBar::handle:horizontal:focus {
558 border: 1px solid #1464A0;
559}
560
561QScrollBar::handle:vertical {
562 background-color: #787878;
563 border: 1px solid #32414B;
564 min-height: 8px;
565 border-radius: 4px;
566}
567
568QScrollBar::handle:vertical:hover {
569 background-color: #148CD2;
570 border: 1px solid #148CD2;
571 border-radius: 4px;
572 min-height: 8px;
573}
574
575QScrollBar::handle:vertical:focus {
576 border: 1px solid #1464A0;
577}
578
579QScrollBar::add-line:horizontal {
580 margin: 0px 0px 0px 0px;
581 border-image: url(":/qss_icons/rc/arrow_right_disabled.png");
582 height: 12px;
583 width: 12px;
584 subcontrol-position: right;
585 subcontrol-origin: margin;
586}
587
588QScrollBar::add-line:horizontal:hover, QScrollBar::add-line:horizontal:on {
589 border-image: url(":/qss_icons/rc/arrow_right.png");
590 height: 12px;
591 width: 12px;
592 subcontrol-position: right;
593 subcontrol-origin: margin;
594}
595
596QScrollBar::add-line:vertical {
597 margin: 3px 0px 3px 0px;
598 border-image: url(":/qss_icons/rc/arrow_down_disabled.png");
599 height: 12px;
600 width: 12px;
601 subcontrol-position: bottom;
602 subcontrol-origin: margin;
603}
604
605QScrollBar::add-line:vertical:hover, QScrollBar::add-line:vertical:on {
606 border-image: url(":/qss_icons/rc/arrow_down.png");
607 height: 12px;
608 width: 12px;
609 subcontrol-position: bottom;
610 subcontrol-origin: margin;
611}
612
613QScrollBar::sub-line:horizontal {
614 margin: 0px 3px 0px 3px;
615 border-image: url(":/qss_icons/rc/arrow_left_disabled.png");
616 height: 12px;
617 width: 12px;
618 subcontrol-position: left;
619 subcontrol-origin: margin;
620}
621
622QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on {
623 border-image: url(":/qss_icons/rc/arrow_left.png");
624 height: 12px;
625 width: 12px;
626 subcontrol-position: left;
627 subcontrol-origin: margin;
628}
629
630QScrollBar::sub-line:vertical {
631 margin: 3px 0px 3px 0px;
632 border-image: url(":/qss_icons/rc/arrow_up_disabled.png");
633 height: 12px;
634 width: 12px;
635 subcontrol-position: top;
636 subcontrol-origin: margin;
637}
638
639QScrollBar::sub-line:vertical:hover, QScrollBar::sub-line:vertical:on {
640 border-image: url(":/qss_icons/rc/arrow_up.png");
641 height: 12px;
642 width: 12px;
643 subcontrol-position: top;
644 subcontrol-origin: margin;
645}
646
647QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal {
648 background: none;
649}
650
651QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {
652 background: none;
653}
654
655QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
656 background: none;
657}
658
659QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
660 background: none;
661}
662
663/* QTextEdit --------------------------------------------------------------
664
665https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-specific-widgets
666
667--------------------------------------------------------------------------- */
668QTextEdit {
669 background-color: #19232D;
670 color: #F0F0F0;
671 border-radius: 4px;
672 border: 1px solid #32414B;
673}
674
675QTextEdit:hover {
676 border: 1px solid #148CD2;
677 color: #F0F0F0;
678}
679
680QTextEdit:focus {
681 border: 1px solid #1464A0;
682}
683
684QTextEdit:selected {
685 background: #1464A0;
686 color: #32414B;
687}
688
689/* QPlainTextEdit ---------------------------------------------------------
690
691--------------------------------------------------------------------------- */
692QPlainTextEdit {
693 background-color: #19232D;
694 color: #F0F0F0;
695 border-radius: 4px;
696 border: 1px solid #32414B;
697}
698
699QPlainTextEdit:hover {
700 border: 1px solid #148CD2;
701 color: #F0F0F0;
702}
703
704QPlainTextEdit:focus {
705 border: 1px solid #1464A0;
706}
707
708QPlainTextEdit:selected {
709 background: #1464A0;
710 color: #32414B;
711}
712
713/* QSizeGrip --------------------------------------------------------------
714
715https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsizegrip
716
717--------------------------------------------------------------------------- */
718QSizeGrip {
719 background: transparent;
720 width: 12px;
721 height: 12px;
722 image: url(":/qss_icons/rc/window_grip.png");
723}
724
725/* QStackedWidget ---------------------------------------------------------
726
727--------------------------------------------------------------------------- */
728QStackedWidget {
729 padding: 2px;
730 border: 1px solid #32414B;
731 border: 1px solid #19232D;
732}
733
734/* QToolBar ---------------------------------------------------------------
735
736https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbar
737
738--------------------------------------------------------------------------- */
739QToolBar {
740 background-color: #32414B;
741 border-bottom: 1px solid #19232D;
742 padding: 2px;
743 font-weight: bold;
744 spacing: 2px;
745}
746
747QToolBar QToolButton {
748 background-color: #32414B;
749 border: 1px solid #32414B;
750}
751
752QToolBar QToolButton:hover {
753 border: 1px solid #148CD2;
754}
755
756QToolBar QToolButton:checked {
757 border: 1px solid #19232D;
758 background-color: #19232D;
759}
760
761QToolBar QToolButton:checked:hover {
762 border: 1px solid #148CD2;
763}
764
765QToolBar::handle:horizontal {
766 width: 16px;
767 image: url(":/qss_icons/rc/toolbar_move_horizontal.png");
768}
769
770QToolBar::handle:vertical {
771 height: 16px;
772 image: url(":/qss_icons/rc/toolbar_move_vertical.png");
773}
774
775QToolBar::separator:horizontal {
776 width: 16px;
777 image: url(":/qss_icons/rc/toolbar_separator_horizontal.png");
778}
779
780QToolBar::separator:vertical {
781 height: 16px;
782 image: url(":/qss_icons/rc/toolbar_separator_vertical.png");
783}
784
785QToolButton#qt_toolbar_ext_button {
786 background: #32414B;
787 border: 0px;
788 color: #F0F0F0;
789 image: url(":/qss_icons/rc/arrow_right.png");
790}
791
792/* QAbstractSpinBox -------------------------------------------------------
793
794--------------------------------------------------------------------------- */
795QAbstractSpinBox {
796 background-color: #19232D;
797 border: 1px solid #32414B;
798 color: #F0F0F0;
799 /* This fixes 103, 111 */
800 padding-top: 2px;
801 /* This fixes 103, 111 */
802 padding-bottom: 2px;
803 padding-left: 4px;
804 padding-right: 4px;
805 border-radius: 4px;
806 /* min-width: 5px; removed to fix 109 */
807}
808
809QAbstractSpinBox:up-button {
810 background-color: transparent #19232D;
811 subcontrol-origin: border;
812 subcontrol-position: top right;
813 border-left: 1px solid #32414B;
814 border-bottom: 1px solid #32414B;
815 border-top-left-radius: 0;
816 border-bottom-left-radius: 0;
817 margin: 1px;
818 width: 12px;
819 margin-bottom: -1px;
820}
821
822QAbstractSpinBox::up-arrow, QAbstractSpinBox::up-arrow:disabled, QAbstractSpinBox::up-arrow:off {
823 image: url(":/qss_icons/rc/arrow_up_disabled.png");
824 height: 8px;
825 width: 8px;
826}
827
828QAbstractSpinBox::up-arrow:hover {
829 image: url(":/qss_icons/rc/arrow_up.png");
830}
831
832QAbstractSpinBox:down-button {
833 background-color: transparent #19232D;
834 subcontrol-origin: border;
835 subcontrol-position: bottom right;
836 border-left: 1px solid #32414B;
837 border-top: 1px solid #32414B;
838 border-top-left-radius: 0;
839 border-bottom-left-radius: 0;
840 margin: 1px;
841 width: 12px;
842 margin-top: -1px;
843}
844
845QAbstractSpinBox::down-arrow, QAbstractSpinBox::down-arrow:disabled, QAbstractSpinBox::down-arrow:off {
846 image: url(":/qss_icons/rc/arrow_down_disabled.png");
847 height: 8px;
848 width: 8px;
849}
850
851QAbstractSpinBox::down-arrow:hover {
852 image: url(":/qss_icons/rc/arrow_down.png");
853}
854
855QAbstractSpinBox:hover {
856 border: 1px solid #148CD2;
857 color: #F0F0F0;
858}
859
860QAbstractSpinBox:focus {
861 border: 1px solid #1464A0;
862}
863
864QAbstractSpinBox:selected {
865 background: #1464A0;
866 color: #32414B;
867}
868
869/* ------------------------------------------------------------------------ */
870/* DISPLAYS --------------------------------------------------------------- */
871/* ------------------------------------------------------------------------ */
872/* QLabel -----------------------------------------------------------------
873
874https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe
875
876--------------------------------------------------------------------------- */
877QLabel {
878 background: transparent;
879 border: 0px solid #32414B;
880 padding: 2px;
881 margin: 0px;
882 color: #F0F0F0;
883}
884
885QLabel:disabled {
886 border: 0px solid #32414B;
887 color: #787878;
888}
889
890/* QTextBrowser -----------------------------------------------------------
891
892https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qabstractscrollarea
893
894--------------------------------------------------------------------------- */
895QTextBrowser {
896 background-color: #19232D;
897 border: 1px solid #32414B;
898 color: #F0F0F0;
899 border-radius: 4px;
900}
901
902QTextBrowser:disabled {
903 background-color: #19232D;
904 border: 1px solid #32414B;
905 color: #787878;
906 border-radius: 4px;
907}
908
909QTextBrowser:hover, QTextBrowser:!hover, QTextBrowser:selected, QTextBrowser:pressed {
910 border: 1px solid #32414B;
911}
912
913/* QGraphicsView ----------------------------------------------------------
914
915--------------------------------------------------------------------------- */
916QGraphicsView {
917 background-color: #19232D;
918 border: 1px solid #32414B;
919 color: #F0F0F0;
920 border-radius: 4px;
921}
922
923QGraphicsView:disabled {
924 background-color: #19232D;
925 border: 1px solid #32414B;
926 color: #787878;
927 border-radius: 4px;
928}
929
930QGraphicsView:hover, QGraphicsView:!hover, QGraphicsView:selected, QGraphicsView:pressed {
931 border: 1px solid #32414B;
932}
933
934/* QCalendarWidget --------------------------------------------------------
935
936--------------------------------------------------------------------------- */
937QCalendarWidget {
938 border: 1px solid #32414B;
939 border-radius: 4px;
940}
941
942QCalendarWidget:disabled {
943 background-color: #19232D;
944 color: #787878;
945}
946
947/* QLCDNumber -------------------------------------------------------------
948
949--------------------------------------------------------------------------- */
950QLCDNumber {
951 background-color: #19232D;
952 color: #F0F0F0;
953}
954
955QLCDNumber:disabled {
956 background-color: #19232D;
957 color: #787878;
958}
959
960/* QProgressBar -----------------------------------------------------------
961
962https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qprogressbar
963
964--------------------------------------------------------------------------- */
965QProgressBar {
966 background-color: #19232D;
967 border: 1px solid #32414B;
968 color: #F0F0F0;
969 border-radius: 4px;
970 text-align: center;
971}
972
973QProgressBar:disabled {
974 background-color: #19232D;
975 border: 1px solid #32414B;
976 color: #787878;
977 border-radius: 4px;
978 text-align: center;
979}
980
981QProgressBar::chunk {
982 background-color: #1464A0;
983 color: #19232D;
984 border-radius: 4px;
985}
986
987QProgressBar::chunk:disabled {
988 background-color: #14506E;
989 color: #787878;
990 border-radius: 4px;
991}
992
993/* ------------------------------------------------------------------------ */
994/* BUTTONS ---------------------------------------------------------------- */
995/* ------------------------------------------------------------------------ */
996/* QPushButton ------------------------------------------------------------
997
998https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qpushbutton
999
1000--------------------------------------------------------------------------- */
1001QPushButton {
1002 background-color: #505F69;
1003 border: 1px solid #32414B;
1004 color: #F0F0F0;
1005 border-radius: 4px;
1006 padding: 3px;
1007 outline: none;
1008 /* Issue #194 - Special case of QPushButton inside dialogs, for better UI */
1009 min-width: 80px;
1010}
1011
1012QPushButton:disabled {
1013 background-color: #32414B;
1014 border: 1px solid #32414B;
1015 color: #787878;
1016 border-radius: 4px;
1017 padding: 3px;
1018}
1019
1020QPushButton:checked {
1021 background-color: #32414B;
1022 border: 1px solid #32414B;
1023 border-radius: 4px;
1024 padding: 3px;
1025 outline: none;
1026}
1027
1028QPushButton:checked:disabled {
1029 background-color: #19232D;
1030 border: 1px solid #32414B;
1031 color: #787878;
1032 border-radius: 4px;
1033 padding: 3px;
1034 outline: none;
1035}
1036
1037QPushButton:checked:selected {
1038 background: #1464A0;
1039 color: #32414B;
1040}
1041
1042QPushButton::menu-indicator {
1043 subcontrol-origin: padding;
1044 subcontrol-position: bottom right;
1045 bottom: 4px;
1046}
1047
1048QPushButton:pressed {
1049 background-color: #19232D;
1050 border: 1px solid #19232D;
1051}
1052
1053QPushButton:pressed:hover {
1054 border: 1px solid #148CD2;
1055}
1056
1057QPushButton:hover {
1058 border: 1px solid #148CD2;
1059 color: #F0F0F0;
1060}
1061
1062QPushButton:selected {
1063 background: #1464A0;
1064 color: #32414B;
1065}
1066
1067QPushButton:hover {
1068 border: 1px solid #148CD2;
1069 color: #F0F0F0;
1070}
1071
1072QPushButton:focus {
1073 border: 1px solid #1464A0;
1074}
1075
1076/* QToolButton ------------------------------------------------------------
1077
1078https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbutton
1079
1080--------------------------------------------------------------------------- */
1081QToolButton {
1082 background-color: transparent;
1083 border: 1px solid transparent;
1084 border-radius: 4px;
1085 margin: 0px;
1086 padding: 2px;
1087 /* The subcontrols below are used only in the DelayedPopup mode */
1088 /* The subcontrols below are used only in the MenuButtonPopup mode */
1089 /* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */
1090}
1091
1092QToolButton:checked {
1093 background-color: transparent;
1094 border: 1px solid #1464A0;
1095}
1096
1097QToolButton:checked:disabled {
1098 border: 1px solid #14506E;
1099}
1100
1101QToolButton:pressed {
1102 margin: 1px;
1103 background-color: transparent;
1104 border: 1px solid #1464A0;
1105}
1106
1107QToolButton:disabled {
1108 border: none;
1109}
1110
1111QToolButton:hover {
1112 border: 1px solid #148CD2;
1113}
1114
1115QToolButton[popupMode="0"] {
1116 /* Only for DelayedPopup */
1117 padding-right: 2px;
1118}
1119
1120QToolButton[popupMode="1"] {
1121 /* Only for MenuButtonPopup */
1122 padding-right: 20px;
1123}
1124
1125QToolButton[popupMode="1"]::menu-button {
1126 border: none;
1127}
1128
1129QToolButton[popupMode="1"]::menu-button:hover {
1130 border: none;
1131 border-left: 1px solid #148CD2;
1132 border-radius: 0;
1133}
1134
1135QToolButton[popupMode="2"] {
1136 /* Only for InstantPopup */
1137 padding-right: 2px;
1138}
1139
1140QToolButton::menu-button {
1141 padding: 2px;
1142 border-radius: 4px;
1143 border: 1px solid #32414B;
1144 width: 12px;
1145 outline: none;
1146}
1147
1148QToolButton::menu-button:hover {
1149 border: 1px solid #148CD2;
1150}
1151
1152QToolButton::menu-button:checked:hover {
1153 border: 1px solid #148CD2;
1154}
1155
1156QToolButton::menu-indicator {
1157 image: url(":/qss_icons/rc/arrow_down.png");
1158 height: 8px;
1159 width: 8px;
1160 top: 0;
1161 /* Exclude a shift for better image */
1162 left: -2px;
1163 /* Shift it a bit */
1164}
1165
1166QToolButton::menu-arrow {
1167 image: url(":/qss_icons/rc/arrow_down.png");
1168 height: 8px;
1169 width: 8px;
1170}
1171
1172QToolButton::menu-arrow:hover {
1173 image: url(":/qss_icons/rc/arrow_down_focus.png");
1174}
1175
1176/* QCommandLinkButton -----------------------------------------------------
1177
1178--------------------------------------------------------------------------- */
1179QCommandLinkButton {
1180 background-color: transparent;
1181 border: 1px solid #32414B;
1182 color: #F0F0F0;
1183 border-radius: 4px;
1184 padding: 0px;
1185 margin: 0px;
1186}
1187
1188QCommandLinkButton:disabled {
1189 background-color: transparent;
1190 color: #787878;
1191}
1192
1193/* ------------------------------------------------------------------------ */
1194/* INPUTS - NO FIELDS ----------------------------------------------------- */
1195/* ------------------------------------------------------------------------ */
1196/* QComboBox --------------------------------------------------------------
1197
1198https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qcombobox
1199
1200--------------------------------------------------------------------------- */
1201QComboBox {
1202 border: 1px solid #32414B;
1203 border-radius: 4px;
1204 selection-background-color: #1464A0;
1205 padding-left: 4px;
1206 padding-right: 36px;
1207 /* 4 + 16*2 See scrollbar size */
1208 /* Fixes #103, #111 */
1209 min-height: 1.5em;
1210 /* padding-top: 2px; removed to fix #132 */
1211 /* padding-bottom: 2px; removed to fix #132 */
1212 /* min-width: 75px; removed to fix #109 */
1213 /* Needed to remove indicator - fix #132 */
1214}
1215
1216QComboBox QAbstractItemView {
1217 border: 1px solid #32414B;
1218 border-radius: 0;
1219 background-color: #19232D;
1220 selection-background-color: #1464A0;
1221}
1222
1223QComboBox QAbstractItemView:hover {
1224 background-color: #19232D;
1225 color: #F0F0F0;
1226}
1227
1228QComboBox QAbstractItemView:selected {
1229 background: #1464A0;
1230 color: #32414B;
1231}
1232
1233QComboBox QAbstractItemView:alternate {
1234 background: #19232D;
1235}
1236
1237QComboBox:disabled {
1238 background-color: #19232D;
1239 color: #787878;
1240}
1241
1242QComboBox:hover {
1243 border: 1px solid #148CD2;
1244}
1245
1246QComboBox:focus {
1247 border: 1px solid #1464A0;
1248}
1249
1250QComboBox:on {
1251 selection-background-color: #1464A0;
1252}
1253
1254QComboBox::indicator {
1255 border: none;
1256 border-radius: 0;
1257 background-color: transparent;
1258 selection-background-color: transparent;
1259 color: transparent;
1260 selection-color: transparent;
1261 /* Needed to remove indicator - fix #132 */
1262}
1263
1264QComboBox::indicator:alternate {
1265 background: #19232D;
1266}
1267
1268QComboBox::item:alternate {
1269 background: #19232D;
1270}
1271
1272QComboBox::item:checked {
1273 font-weight: bold;
1274}
1275
1276QComboBox::item:selected {
1277 border: 0px solid transparent;
1278}
1279
1280QComboBox::drop-down {
1281 subcontrol-origin: padding;
1282 subcontrol-position: top right;
1283 width: 12px;
1284 border-left: 1px solid #32414B;
1285}
1286
1287QComboBox::down-arrow {
1288 image: url(":/qss_icons/rc/arrow_down_disabled.png");
1289 height: 8px;
1290 width: 8px;
1291}
1292
1293QComboBox::down-arrow:on, QComboBox::down-arrow:hover, QComboBox::down-arrow:focus {
1294 image: url(":/qss_icons/rc/arrow_down.png");
1295}
1296
1297/* QSlider ----------------------------------------------------------------
1298
1299https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qslider
1300
1301--------------------------------------------------------------------------- */
1302QSlider:disabled {
1303 background: #19232D;
1304}
1305
1306QSlider:focus {
1307 border: none;
1308}
1309
1310QSlider::groove:horizontal {
1311 background: #32414B;
1312 border: 1px solid #32414B;
1313 height: 4px;
1314 margin: 0px;
1315 border-radius: 4px;
1316}
1317
1318QSlider::groove:vertical {
1319 background: #32414B;
1320 border: 1px solid #32414B;
1321 width: 4px;
1322 margin: 0px;
1323 border-radius: 4px;
1324}
1325
1326QSlider::add-page:vertical {
1327 background: #1464A0;
1328 border: 1px solid #32414B;
1329 width: 4px;
1330 margin: 0px;
1331 border-radius: 4px;
1332}
1333
1334QSlider::add-page:vertical :disabled {
1335 background: #14506E;
1336}
1337
1338QSlider::sub-page:horizontal {
1339 background: #1464A0;
1340 border: 1px solid #32414B;
1341 height: 4px;
1342 margin: 0px;
1343 border-radius: 4px;
1344}
1345
1346QSlider::sub-page:horizontal:disabled {
1347 background: #14506E;
1348}
1349
1350QSlider::handle:horizontal {
1351 background: #787878;
1352 border: 1px solid #32414B;
1353 width: 8px;
1354 height: 8px;
1355 margin: -8px 0px;
1356 border-radius: 4px;
1357}
1358
1359QSlider::handle:horizontal:hover {
1360 background: #148CD2;
1361 border: 1px solid #148CD2;
1362}
1363
1364QSlider::handle:horizontal:focus {
1365 border: 1px solid #1464A0;
1366}
1367
1368QSlider::handle:vertical {
1369 background: #787878;
1370 border: 1px solid #32414B;
1371 width: 8px;
1372 height: 8px;
1373 margin: 0 -8px;
1374 border-radius: 4px;
1375}
1376
1377QSlider::handle:vertical:hover {
1378 background: #148CD2;
1379 border: 1px solid #148CD2;
1380}
1381
1382QSlider::handle:vertical:focus {
1383 border: 1px solid #1464A0;
1384}
1385
1386/* QLineEdit --------------------------------------------------------------
1387
1388https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlineedit
1389
1390--------------------------------------------------------------------------- */
1391QLineEdit {
1392 background-color: #19232D;
1393 padding-top: 2px;
1394 /* This QLineEdit fix 103, 111 */
1395 padding-bottom: 2px;
1396 /* This QLineEdit fix 103, 111 */
1397 padding-left: 4px;
1398 padding-right: 4px;
1399 border-style: solid;
1400 border: 1px solid #32414B;
1401 border-radius: 4px;
1402 color: #F0F0F0;
1403}
1404
1405QLineEdit:disabled {
1406 background-color: #19232D;
1407 color: #787878;
1408}
1409
1410QLineEdit:hover {
1411 border: 1px solid #148CD2;
1412 color: #F0F0F0;
1413}
1414
1415QLineEdit:focus {
1416 border: 1px solid #1464A0;
1417}
1418
1419QLineEdit:selected {
1420 background-color: #1464A0;
1421 color: #32414B;
1422}
1423
1424/* QTabWiget --------------------------------------------------------------
1425
1426https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar
1427
1428--------------------------------------------------------------------------- */
1429QTabWidget {
1430 padding: 2px;
1431 selection-background-color: #32414B;
1432}
1433
1434QTabWidget QWidget {
1435 /* Fixes #189 */
1436 border-radius: 4px;
1437}
1438
1439QTabWidget::pane {
1440 border: 1px solid #32414B;
1441 border-radius: 4px;
1442 margin: 0px;
1443 /* Fixes double border inside pane with pyqt5 */
1444 padding: 0px;
1445}
1446
1447QTabWidget::pane:selected {
1448 background-color: #32414B;
1449 border: 1px solid #1464A0;
1450}
1451
1452/* QTabBar ----------------------------------------------------------------
1453
1454https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar
1455
1456--------------------------------------------------------------------------- */
1457QTabBar {
1458 qproperty-drawBase: 0;
1459 border-radius: 4px;
1460 margin: 0px;
1461 padding: 2px;
1462 border: 0;
1463 /* left: 5px; move to the right by 5px - removed for fix */
1464}
1465
1466QTabBar::close-button {
1467 border: 0;
1468 margin: 2px;
1469 padding: 2px;
1470 image: url(":/qss_icons/rc/window_close.png");
1471}
1472
1473QTabBar::close-button:hover {
1474 image: url(":/qss_icons/rc/window_close_focus.png");
1475}
1476
1477QTabBar::close-button:pressed {
1478 image: url(":/qss_icons/rc/window_close_pressed.png");
1479}
1480
1481/* QTabBar::tab - selected ------------------------------------------------
1482
1483https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtabwidget-and-qtabbar
1484
1485--------------------------------------------------------------------------- */
1486QTabBar::tab {
1487 /* !selected and disabled ----------------------------------------- */
1488 /* selected ------------------------------------------------------- */
1489}
1490
1491QTabBar::tab:top:selected:disabled {
1492 border-bottom: 3px solid #14506E;
1493 color: #787878;
1494 background-color: #32414B;
1495}
1496
1497QTabBar::tab:bottom:selected:disabled {
1498 border-top: 3px solid #14506E;
1499 color: #787878;
1500 background-color: #32414B;
1501}
1502
1503QTabBar::tab:left:selected:disabled {
1504 border-right: 3px solid #14506E;
1505 color: #787878;
1506 background-color: #32414B;
1507}
1508
1509QTabBar::tab:right:selected:disabled {
1510 border-left: 3px solid #14506E;
1511 color: #787878;
1512 background-color: #32414B;
1513}
1514
1515QTabBar::tab:top:!selected:disabled {
1516 border-bottom: 3px solid #19232D;
1517 color: #787878;
1518 background-color: #19232D;
1519}
1520
1521QTabBar::tab:bottom:!selected:disabled {
1522 border-top: 3px solid #19232D;
1523 color: #787878;
1524 background-color: #19232D;
1525}
1526
1527QTabBar::tab:left:!selected:disabled {
1528 border-right: 3px solid #19232D;
1529 color: #787878;
1530 background-color: #19232D;
1531}
1532
1533QTabBar::tab:right:!selected:disabled {
1534 border-left: 3px solid #19232D;
1535 color: #787878;
1536 background-color: #19232D;
1537}
1538
1539QTabBar::tab:top:!selected {
1540 border-bottom: 2px solid #19232D;
1541 margin-top: 2px;
1542}
1543
1544QTabBar::tab:bottom:!selected {
1545 border-top: 2px solid #19232D;
1546 margin-bottom: 3px;
1547}
1548
1549QTabBar::tab:left:!selected {
1550 border-left: 2px solid #19232D;
1551 margin-right: 2px;
1552}
1553
1554QTabBar::tab:right:!selected {
1555 border-right: 2px solid #19232D;
1556 margin-left: 2px;
1557}
1558
1559QTabBar::tab:top {
1560 background-color: #32414B;
1561 color: #F0F0F0;
1562 margin-left: 2px;
1563 padding-left: 4px;
1564 padding-right: 4px;
1565 padding-top: 2px;
1566 padding-bottom: 2px;
1567 min-width: 5px;
1568 border-bottom: 3px solid #32414B;
1569 border-top-left-radius: 3px;
1570 border-top-right-radius: 3px;
1571}
1572
1573QTabBar::tab:top:selected {
1574 background-color: #505F69;
1575 color: #F0F0F0;
1576 border-bottom: 3px solid #1464A0;
1577 border-top-left-radius: 3px;
1578 border-top-right-radius: 3px;
1579}
1580
1581QTabBar::tab:top:!selected:hover {
1582 border: 1px solid #148CD2;
1583 border-bottom: 3px solid #148CD2;
1584 /* Fixes spyder-ide/spyder#9766 */
1585 padding-left: 4px;
1586 padding-right: 4px;
1587}
1588
1589QTabBar::tab:bottom {
1590 color: #F0F0F0;
1591 border-top: 3px solid #32414B;
1592 background-color: #32414B;
1593 margin-left: 2px;
1594 padding-left: 4px;
1595 padding-right: 4px;
1596 padding-top: 2px;
1597 padding-bottom: 2px;
1598 border-bottom-left-radius: 3px;
1599 border-bottom-right-radius: 3px;
1600 min-width: 5px;
1601}
1602
1603QTabBar::tab:bottom:selected {
1604 color: #F0F0F0;
1605 background-color: #505F69;
1606 border-top: 3px solid #1464A0;
1607 border-bottom-left-radius: 3px;
1608 border-bottom-right-radius: 3px;
1609}
1610
1611QTabBar::tab:bottom:!selected:hover {
1612 border: 1px solid #148CD2;
1613 border-top: 3px solid #148CD2;
1614 /* Fixes spyder-ide/spyder#9766 */
1615 padding-left: 4px;
1616 padding-right: 4px;
1617}
1618
1619QTabBar::tab:left {
1620 color: #F0F0F0;
1621 background-color: #32414B;
1622 margin-top: 2px;
1623 padding-left: 2px;
1624 padding-right: 2px;
1625 padding-top: 4px;
1626 padding-bottom: 4px;
1627 border-top-left-radius: 3px;
1628 border-bottom-left-radius: 3px;
1629 min-height: 5px;
1630}
1631
1632QTabBar::tab:left:selected {
1633 color: #F0F0F0;
1634 background-color: #505F69;
1635 border-right: 3px solid #1464A0;
1636}
1637
1638QTabBar::tab:left:!selected:hover {
1639 border: 1px solid #148CD2;
1640 border-right: 3px solid #148CD2;
1641 padding: 0px;
1642}
1643
1644QTabBar::tab:right {
1645 color: #F0F0F0;
1646 background-color: #32414B;
1647 margin-top: 2px;
1648 padding-left: 2px;
1649 padding-right: 2px;
1650 padding-top: 4px;
1651 padding-bottom: 4px;
1652 border-top-right-radius: 3px;
1653 border-bottom-right-radius: 3px;
1654 min-height: 5px;
1655}
1656
1657QTabBar::tab:right:selected {
1658 color: #F0F0F0;
1659 background-color: #505F69;
1660 border-left: 3px solid #1464A0;
1661}
1662
1663QTabBar::tab:right:!selected:hover {
1664 border: 1px solid #148CD2;
1665 border-left: 3px solid #148CD2;
1666 padding: 0px;
1667}
1668
1669QTabBar QToolButton {
1670 /* Fixes #136 */
1671 background-color: #32414B;
1672 height: 12px;
1673 width: 12px;
1674}
1675
1676QTabBar QToolButton:pressed {
1677 background-color: #32414B;
1678}
1679
1680QTabBar QToolButton:pressed:hover {
1681 border: 1px solid #148CD2;
1682}
1683
1684QTabBar QToolButton::left-arrow:enabled {
1685 image: url(":/qss_icons/rc/arrow_left.png");
1686}
1687
1688QTabBar QToolButton::left-arrow:disabled {
1689 image: url(":/qss_icons/rc/arrow_left_disabled.png");
1690}
1691
1692QTabBar QToolButton::right-arrow:enabled {
1693 image: url(":/qss_icons/rc/arrow_right.png");
1694}
1695
1696QTabBar QToolButton::right-arrow:disabled {
1697 image: url(":/qss_icons/rc/arrow_right_disabled.png");
1698}
1699
1700/* QDockWiget -------------------------------------------------------------
1701
1702--------------------------------------------------------------------------- */
1703QDockWidget {
1704 outline: 1px solid #32414B;
1705 background-color: #19232D;
1706 border: 1px solid #32414B;
1707 border-radius: 4px;
1708 titlebar-close-icon: url(":/qss_icons/rc/window_close.png");
1709 titlebar-normal-icon: url(":/qss_icons/rc/window_undock.png");
1710}
1711
1712QDockWidget::title {
1713 /* Better size for title bar */
1714 padding: 6px;
1715 spacing: 4px;
1716 border: none;
1717 background-color: #32414B;
1718}
1719
1720QDockWidget::close-button {
1721 background-color: #32414B;
1722 border-radius: 4px;
1723 border: none;
1724}
1725
1726QDockWidget::close-button:hover {
1727 image: url(":/qss_icons/rc/window_close_focus.png");
1728}
1729
1730QDockWidget::close-button:pressed {
1731 image: url(":/qss_icons/rc/window_close_pressed.png");
1732}
1733
1734QDockWidget::float-button {
1735 background-color: #32414B;
1736 border-radius: 4px;
1737 border: none;
1738}
1739
1740QDockWidget::float-button:hover {
1741 image: url(":/qss_icons/rc/window_undock_focus.png");
1742}
1743
1744QDockWidget::float-button:pressed {
1745 image: url(":/qss_icons/rc/window_undock_pressed.png");
1746}
1747
1748/* QTreeView QListView QTableView -----------------------------------------
1749
1750https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtreeview
1751https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qlistview
1752https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtableview
1753
1754--------------------------------------------------------------------------- */
1755QTreeView:branch:selected, QTreeView:branch:hover {
1756 background: url(":/qss_icons/rc/transparent.png");
1757}
1758
1759QTreeView:branch:has-siblings:!adjoins-item {
1760 border-image: url(":/qss_icons/rc/branch_line.png") 0;
1761}
1762
1763QTreeView:branch:has-siblings:adjoins-item {
1764 border-image: url(":/qss_icons/rc/branch_more.png") 0;
1765}
1766
1767QTreeView:branch:!has-children:!has-siblings:adjoins-item {
1768 border-image: url(":/qss_icons/rc/branch_end.png") 0;
1769}
1770
1771QTreeView:branch:has-children:!has-siblings:closed, QTreeView:branch:closed:has-children:has-siblings {
1772 border-image: none;
1773 image: url(":/qss_icons/rc/branch_closed.png");
1774}
1775
1776QTreeView:branch:open:has-children:!has-siblings, QTreeView:branch:open:has-children:has-siblings {
1777 border-image: none;
1778 image: url(":/qss_icons/rc/branch_open.png");
1779}
1780
1781QTreeView:branch:has-children:!has-siblings:closed:hover, QTreeView:branch:closed:has-children:has-siblings:hover {
1782 image: url(":/qss_icons/rc/branch_closed_focus.png");
1783}
1784
1785QTreeView:branch:open:has-children:!has-siblings:hover, QTreeView:branch:open:has-children:has-siblings:hover {
1786 image: url(":/qss_icons/rc/branch_open_focus.png");
1787}
1788
1789QTreeView::indicator:checked,
1790QListView::indicator:checked {
1791 image: url(":/qss_icons/rc/checkbox_checked.png");
1792}
1793
1794QTreeView::indicator:checked:hover, QTreeView::indicator:checked:focus, QTreeView::indicator:checked:pressed,
1795QListView::indicator:checked:hover,
1796QListView::indicator:checked:focus,
1797QListView::indicator:checked:pressed {
1798 image: url(":/qss_icons/rc/checkbox_checked_focus.png");
1799}
1800
1801QTreeView::indicator:unchecked,
1802QListView::indicator:unchecked {
1803 image: url(":/qss_icons/rc/checkbox_unchecked.png");
1804}
1805
1806QTreeView::indicator:unchecked:hover, QTreeView::indicator:unchecked:focus, QTreeView::indicator:unchecked:pressed,
1807QListView::indicator:unchecked:hover,
1808QListView::indicator:unchecked:focus,
1809QListView::indicator:unchecked:pressed {
1810 image: url(":/qss_icons/rc/checkbox_unchecked_focus.png");
1811}
1812
1813QTreeView::indicator:indeterminate,
1814QListView::indicator:indeterminate {
1815 image: url(":/qss_icons/rc/checkbox_indeterminate.png");
1816}
1817
1818QTreeView::indicator:indeterminate:hover, QTreeView::indicator:indeterminate:focus, QTreeView::indicator:indeterminate:pressed,
1819QListView::indicator:indeterminate:hover,
1820QListView::indicator:indeterminate:focus,
1821QListView::indicator:indeterminate:pressed {
1822 image: url(":/qss_icons/rc/checkbox_indeterminate_focus.png");
1823}
1824
1825QTreeView,
1826QListView,
1827QTableView,
1828QColumnView {
1829 background-color: #19232D;
1830 border: 1px solid #32414B;
1831 color: #F0F0F0;
1832 gridline-color: #32414B;
1833 border-radius: 4px;
1834}
1835
1836QTreeView:disabled,
1837QListView:disabled,
1838QTableView:disabled,
1839QColumnView:disabled {
1840 background-color: #19232D;
1841 color: #787878;
1842}
1843
1844QTreeView:selected,
1845QListView:selected,
1846QTableView:selected,
1847QColumnView:selected {
1848 background-color: #1464A0;
1849 color: #32414B;
1850}
1851
1852QTreeView:hover,
1853QListView:hover,
1854QTableView:hover,
1855QColumnView:hover {
1856 background-color: #19232D;
1857 border: 1px solid #148CD2;
1858}
1859
1860QTreeView::item:pressed,
1861QListView::item:pressed,
1862QTableView::item:pressed,
1863QColumnView::item:pressed {
1864 background-color: #1464A0;
1865}
1866
1867QTreeView::item:selected:hover,
1868QListView::item:selected:hover,
1869QTableView::item:selected:hover,
1870QColumnView::item:selected:hover {
1871 background: #1464A0;
1872 color: #19232D;
1873}
1874
1875QTreeView::item:selected:active,
1876QListView::item:selected:active,
1877QTableView::item:selected:active,
1878QColumnView::item:selected:active {
1879 background-color: #1464A0;
1880}
1881
1882QTreeView::item:!selected:hover,
1883QListView::item:!selected:hover,
1884QTableView::item:!selected:hover,
1885QColumnView::item:!selected:hover {
1886 outline: 0;
1887 color: #148CD2;
1888 background-color: #32414B;
1889}
1890
1891QTableCornerButton::section {
1892 background-color: #19232D;
1893 border: 1px transparent #32414B;
1894 border-radius: 0px;
1895}
1896
1897/* QHeaderView ------------------------------------------------------------
1898
1899https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qheaderview
1900
1901--------------------------------------------------------------------------- */
1902QHeaderView {
1903 background-color: #32414B;
1904 border: 0px transparent #32414B;
1905 padding: 0px;
1906 margin: 0px;
1907 border-radius: 0px;
1908}
1909
1910QHeaderView:disabled {
1911 background-color: #32414B;
1912 border: 1px transparent #32414B;
1913 padding: 2px;
1914}
1915
1916QHeaderView::section {
1917 background-color: #32414B;
1918 color: #F0F0F0;
1919 padding: 2px;
1920 border-radius: 0px;
1921 text-align: left;
1922}
1923
1924QHeaderView::section:checked {
1925 color: #F0F0F0;
1926 background-color: #1464A0;
1927}
1928
1929QHeaderView::section:checked:disabled {
1930 color: #787878;
1931 background-color: #14506E;
1932}
1933
1934QHeaderView::section::horizontal {
1935 padding-left: 4px;
1936 padding-right: 4px;
1937 border-left: 1px solid #19232D;
1938}
1939
1940QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one {
1941 border-left: 1px solid #32414B;
1942}
1943
1944QHeaderView::section::horizontal:disabled {
1945 color: #787878;
1946}
1947
1948QHeaderView::section::vertical {
1949 padding-left: 4px;
1950 padding-right: 4px;
1951 border-top: 1px solid #19232D;
1952}
1953
1954QHeaderView::section::vertical::first, QHeaderView::section::vertical::only-one {
1955 border-top: 1px solid #32414B;
1956}
1957
1958QHeaderView::section::vertical:disabled {
1959 color: #787878;
1960}
1961
1962QHeaderView::down-arrow {
1963 /* Those settings (border/width/height/background-color) solve bug */
1964 /* transparent arrow background and size */
1965 background-color: #32414B;
1966 border: none;
1967 height: 12px;
1968 width: 12px;
1969 padding-left: 2px;
1970 padding-right: 2px;
1971 image: url(":/qss_icons/rc/arrow_down.png");
1972}
1973
1974QHeaderView::up-arrow {
1975 background-color: #32414B;
1976 border: none;
1977 height: 12px;
1978 width: 12px;
1979 padding-left: 2px;
1980 padding-right: 2px;
1981 image: url(":/qss_icons/rc/arrow_up.png");
1982}
1983
1984/* QToolBox --------------------------------------------------------------
1985
1986https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qtoolbox
1987
1988--------------------------------------------------------------------------- */
1989QToolBox {
1990 padding: 0px;
1991 border: 0px;
1992 border: 1px solid #32414B;
1993}
1994
1995QToolBox:selected {
1996 padding: 0px;
1997 border: 2px solid #1464A0;
1998}
1999
2000QToolBox::tab {
2001 background-color: #19232D;
2002 border: 1px solid #32414B;
2003 color: #F0F0F0;
2004 border-top-left-radius: 4px;
2005 border-top-right-radius: 4px;
2006}
2007
2008QToolBox::tab:disabled {
2009 color: #787878;
2010}
2011
2012QToolBox::tab:selected {
2013 background-color: #505F69;
2014 border-bottom: 2px solid #1464A0;
2015}
2016
2017QToolBox::tab:selected:disabled {
2018 background-color: #32414B;
2019 border-bottom: 2px solid #14506E;
2020}
2021
2022QToolBox::tab:!selected {
2023 background-color: #32414B;
2024 border-bottom: 2px solid #32414B;
2025}
2026
2027QToolBox::tab:!selected:disabled {
2028 background-color: #19232D;
2029}
2030
2031QToolBox::tab:hover {
2032 border-color: #148CD2;
2033 border-bottom: 2px solid #148CD2;
2034}
2035
2036QToolBox QScrollArea QWidget QWidget {
2037 padding: 0px;
2038 border: 0px;
2039 background-color: #19232D;
2040}
2041
2042/* QFrame -----------------------------------------------------------------
2043
2044https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qframe
2045https://doc.qt.io/qt-5/qframe.html#-prop
2046https://doc.qt.io/qt-5/qframe.html#details
2047https://stackoverflow.com/questions/14581498/qt-stylesheet-for-hline-vline-color
2048
2049--------------------------------------------------------------------------- */
2050/* (dot) .QFrame fix #141, #126, #123 */
2051.QFrame {
2052 border-radius: 4px;
2053 border: 1px solid #32414B;
2054 /* No frame */
2055 /* HLine */
2056 /* HLine */
2057}
2058
2059.QFrame[frameShape="0"] {
2060 border-radius: 4px;
2061 border: 1px transparent #32414B;
2062}
2063
2064.QFrame[frameShape="4"] {
2065 max-height: 2px;
2066 border: none;
2067 background-color: #32414B;
2068}
2069
2070.QFrame[frameShape="5"] {
2071 max-width: 2px;
2072 border: none;
2073 background-color: #32414B;
2074}
2075
2076/* QSplitter --------------------------------------------------------------
2077
2078https://doc.qt.io/qt-5/stylesheet-examples.html#customizing-qsplitter
2079
2080--------------------------------------------------------------------------- */
2081QSplitter {
2082 background-color: #32414B;
2083 spacing: 0px;
2084 padding: 0px;
2085 margin: 0px;
2086}
2087
2088QSplitter::handle {
2089 background-color: #32414B;
2090 border: 0px solid #19232D;
2091 spacing: 0px;
2092 padding: 1px;
2093 margin: 0px;
2094}
2095
2096QSplitter::handle:hover {
2097 background-color: #787878;
2098}
2099
2100QSplitter::handle:horizontal {
2101 width: 5px;
2102 image: url(":/qss_icons/rc/line_vertical.png");
2103}
2104
2105QSplitter::handle:vertical {
2106 height: 5px;
2107 image: url(":/qss_icons/rc/line_horizontal.png");
2108}
2109
2110/* QDateEdit, QDateTimeEdit -----------------------------------------------
2111
2112--------------------------------------------------------------------------- */
2113QDateEdit, QDateTimeEdit {
2114 selection-background-color: #1464A0;
2115 border-style: solid;
2116 border: 1px solid #32414B;
2117 border-radius: 4px;
2118 /* This fixes 103, 111 */
2119 padding-top: 2px;
2120 /* This fixes 103, 111 */
2121 padding-bottom: 2px;
2122 padding-left: 4px;
2123 padding-right: 4px;
2124 min-width: 10px;
2125}
2126
2127QDateEdit:on, QDateTimeEdit:on {
2128 selection-background-color: #1464A0;
2129}
2130
2131QDateEdit::drop-down, QDateTimeEdit::drop-down {
2132 subcontrol-origin: padding;
2133 subcontrol-position: top right;
2134 width: 12px;
2135 border-left: 1px solid #32414B;
2136}
2137
2138QDateEdit::down-arrow, QDateTimeEdit::down-arrow {
2139 image: url(":/qss_icons/rc/arrow_down_disabled.png");
2140 height: 8px;
2141 width: 8px;
2142}
2143
2144QDateEdit::down-arrow:on, QDateEdit::down-arrow:hover, QDateEdit::down-arrow:focus, QDateTimeEdit::down-arrow:on, QDateTimeEdit::down-arrow:hover, QDateTimeEdit::down-arrow:focus {
2145 image: url(":/qss_icons/rc/arrow_down.png");
2146}
2147
2148QDateEdit QAbstractItemView, QDateTimeEdit QAbstractItemView {
2149 background-color: #19232D;
2150 border-radius: 4px;
2151 border: 1px solid #32414B;
2152 selection-background-color: #1464A0;
2153}
2154
2155/* QAbstractView ----------------------------------------------------------
2156
2157--------------------------------------------------------------------------- */
2158QAbstractView:hover {
2159 border: 1px solid #148CD2;
2160 color: #F0F0F0;
2161}
2162
2163QAbstractView:selected {
2164 background: #1464A0;
2165 color: #32414B;
2166}
2167
2168/* PlotWidget -------------------------------------------------------------
2169
2170--------------------------------------------------------------------------- */
2171PlotWidget {
2172 /* Fix cut labels in plots #134 */
2173 padding: 0px;
2174}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1e977e8a8..54dca3302 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -60,6 +60,7 @@ else()
60 -Wmissing-declarations 60 -Wmissing-declarations
61 -Wno-attributes 61 -Wno-attributes
62 -Wno-unused-parameter 62 -Wno-unused-parameter
63 -fconcepts
63 ) 64 )
64 65
65 if (ARCHITECTURE_x86_64) 66 if (ARCHITECTURE_x86_64)
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index f80ab92e4..7be5d5087 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -36,9 +36,10 @@ Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format fo
36 ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_) 36 ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_)
37 : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)}, 37 : sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)},
38 sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} { 38 sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} {
39 39 release_event =
40 release_event = Core::Timing::CreateEvent( 40 Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
41 name, [this](u64, std::chrono::nanoseconds ns_late) { ReleaseActiveBuffer(ns_late); }); 41 ReleaseActiveBuffer(ns_late);
42 });
42} 43}
43 44
44void Stream::Play() { 45void Stream::Play() {
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index d120c8d3d..78c3bfb3b 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -110,6 +110,7 @@ add_library(common STATIC
110 common_funcs.h 110 common_funcs.h
111 common_paths.h 111 common_paths.h
112 common_types.h 112 common_types.h
113 concepts.h
113 dynamic_library.cpp 114 dynamic_library.cpp
114 dynamic_library.h 115 dynamic_library.h
115 fiber.cpp 116 fiber.cpp
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index 076752d3b..3c593d5f6 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -35,6 +35,7 @@
35#define KEYS_DIR "keys" 35#define KEYS_DIR "keys"
36#define LOAD_DIR "load" 36#define LOAD_DIR "load"
37#define DUMP_DIR "dump" 37#define DUMP_DIR "dump"
38#define SCREENSHOTS_DIR "screenshots"
38#define SHADER_DIR "shader" 39#define SHADER_DIR "shader"
39#define LOG_DIR "log" 40#define LOG_DIR "log"
40 41
diff --git a/src/common/concepts.h b/src/common/concepts.h
new file mode 100644
index 000000000..db5fb373d
--- /dev/null
+++ b/src/common/concepts.h
@@ -0,0 +1,32 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace Common {
8
9#include <type_traits>
10
11// Check if type is like an STL container
12template <typename T>
13concept IsSTLContainer = requires(T t) {
14 typename T::value_type;
15 typename T::iterator;
16 typename T::const_iterator;
17 // TODO(ogniK): Replace below is std::same_as<void> when MSVC supports it.
18 t.begin();
19 t.end();
20 t.cbegin();
21 t.cend();
22 t.data();
23 t.size();
24};
25
26// Check if type T is derived from T2
27template <typename T, typename T2>
28concept IsBaseOf = requires {
29 std::is_base_of_v<T, T2>;
30};
31
32} // namespace Common
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 45b750e1e..4ede9f72c 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -695,6 +695,7 @@ const std::string& GetUserPath(UserPath path, const std::string& new_path) {
695 paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP); 695 paths.emplace(UserPath::NANDDir, user_path + NAND_DIR DIR_SEP);
696 paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP); 696 paths.emplace(UserPath::LoadDir, user_path + LOAD_DIR DIR_SEP);
697 paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP); 697 paths.emplace(UserPath::DumpDir, user_path + DUMP_DIR DIR_SEP);
698 paths.emplace(UserPath::ScreenshotsDir, user_path + SCREENSHOTS_DIR DIR_SEP);
698 paths.emplace(UserPath::ShaderDir, user_path + SHADER_DIR DIR_SEP); 699 paths.emplace(UserPath::ShaderDir, user_path + SHADER_DIR DIR_SEP);
699 paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP); 700 paths.emplace(UserPath::SysDataDir, user_path + SYSDATA_DIR DIR_SEP);
700 paths.emplace(UserPath::KeysDir, user_path + KEYS_DIR DIR_SEP); 701 paths.emplace(UserPath::KeysDir, user_path + KEYS_DIR DIR_SEP);
diff --git a/src/common/file_util.h b/src/common/file_util.h
index f7a0c33fa..187b93161 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -32,6 +32,7 @@ enum class UserPath {
32 SDMCDir, 32 SDMCDir,
33 LoadDir, 33 LoadDir,
34 DumpDir, 34 DumpDir,
35 ScreenshotsDir,
35 ShaderDir, 36 ShaderDir,
36 SysDataDir, 37 SysDataDir,
37 UserDir, 38 UserDir,
diff --git a/src/common/string_util.h b/src/common/string_util.h
index 583fd05e6..023dff5dc 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -74,16 +74,4 @@ std::string StringFromFixedZeroTerminatedBuffer(const char* buffer, std::size_t
74std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer, 74std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buffer,
75 std::size_t max_len); 75 std::size_t max_len);
76 76
77/**
78 * Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
79 * intended to be used to strip a system-specific build directory from the `__FILE__` macro,
80 * leaving only the path relative to the sources root.
81 *
82 * @param path The input file path as a null-terminated string
83 * @param root The name of the root source directory as a null-terminated string. Path up to and
84 * including the last occurrence of this name will be stripped
85 * @return A pointer to the same string passed as `path`, but starting at the trimmed portion
86 */
87const char* TrimSourcePath(const char* path, const char* root = "src");
88
89} // namespace Common 77} // namespace Common
diff --git a/src/common/virtual_buffer.cpp b/src/common/virtual_buffer.cpp
index b426f4747..be5b67752 100644
--- a/src/common/virtual_buffer.cpp
+++ b/src/common/virtual_buffer.cpp
@@ -38,7 +38,7 @@ void* AllocateMemoryPages(std::size_t size) {
38 return base; 38 return base;
39} 39}
40 40
41void FreeMemoryPages(void* base, std::size_t size) { 41void FreeMemoryPages(void* base, [[maybe_unused]] std::size_t size) {
42 if (!base) { 42 if (!base) {
43 return; 43 return;
44 } 44 }
diff --git a/src/core/core.cpp b/src/core/core.cpp
index e598c0e2b..42277e2cd 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -146,7 +146,7 @@ struct System::Impl {
146 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { 146 ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
147 LOG_DEBUG(HW_Memory, "initialized OK"); 147 LOG_DEBUG(HW_Memory, "initialized OK");
148 148
149 device_memory = std::make_unique<Core::DeviceMemory>(system); 149 device_memory = std::make_unique<Core::DeviceMemory>();
150 150
151 is_multicore = Settings::values.use_multi_core.GetValue(); 151 is_multicore = Settings::values.use_multi_core.GetValue();
152 is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation.GetValue(); 152 is_async_gpu = is_multicore || Settings::values.use_asynchronous_gpu_emulation.GetValue();
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index b5feb3f24..71af26ec5 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -23,7 +23,7 @@ std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callbac
23struct CoreTiming::Event { 23struct CoreTiming::Event {
24 u64 time; 24 u64 time;
25 u64 fifo_order; 25 u64 fifo_order;
26 u64 userdata; 26 std::uintptr_t user_data;
27 std::weak_ptr<EventType> type; 27 std::weak_ptr<EventType> type;
28 28
29 // Sort by time, unless the times are the same, in which case sort by 29 // Sort by time, unless the times are the same, in which case sort by
@@ -58,7 +58,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) {
58 event_fifo_id = 0; 58 event_fifo_id = 0;
59 shutting_down = false; 59 shutting_down = false;
60 ticks = 0; 60 ticks = 0;
61 const auto empty_timed_callback = [](u64, std::chrono::nanoseconds) {}; 61 const auto empty_timed_callback = [](std::uintptr_t, std::chrono::nanoseconds) {};
62 ev_lost = CreateEvent("_lost_event", empty_timed_callback); 62 ev_lost = CreateEvent("_lost_event", empty_timed_callback);
63 if (is_multicore) { 63 if (is_multicore) {
64 timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this)); 64 timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this));
@@ -107,22 +107,24 @@ bool CoreTiming::HasPendingEvents() const {
107} 107}
108 108
109void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future, 109void CoreTiming::ScheduleEvent(std::chrono::nanoseconds ns_into_future,
110 const std::shared_ptr<EventType>& event_type, u64 userdata) { 110 const std::shared_ptr<EventType>& event_type,
111 std::uintptr_t user_data) {
111 { 112 {
112 std::scoped_lock scope{basic_lock}; 113 std::scoped_lock scope{basic_lock};
113 const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count()); 114 const u64 timeout = static_cast<u64>((GetGlobalTimeNs() + ns_into_future).count());
114 115
115 event_queue.emplace_back(Event{timeout, event_fifo_id++, userdata, event_type}); 116 event_queue.emplace_back(Event{timeout, event_fifo_id++, user_data, event_type});
116 117
117 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>()); 118 std::push_heap(event_queue.begin(), event_queue.end(), std::greater<>());
118 } 119 }
119 event.Set(); 120 event.Set();
120} 121}
121 122
122void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata) { 123void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
124 std::uintptr_t user_data) {
123 std::scoped_lock scope{basic_lock}; 125 std::scoped_lock scope{basic_lock};
124 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) { 126 const auto itr = std::remove_if(event_queue.begin(), event_queue.end(), [&](const Event& e) {
125 return e.type.lock().get() == event_type.get() && e.userdata == userdata; 127 return e.type.lock().get() == event_type.get() && e.user_data == user_data;
126 }); 128 });
127 129
128 // Removing random items breaks the invariant so we have to re-establish it. 130 // Removing random items breaks the invariant so we have to re-establish it.
@@ -197,7 +199,7 @@ std::optional<s64> CoreTiming::Advance() {
197 199
198 if (const auto event_type{evt.type.lock()}) { 200 if (const auto event_type{evt.type.lock()}) {
199 event_type->callback( 201 event_type->callback(
200 evt.userdata, std::chrono::nanoseconds{static_cast<s64>(global_timer - evt.time)}); 202 evt.user_data, std::chrono::nanoseconds{static_cast<s64>(global_timer - evt.time)});
201 } 203 }
202 204
203 basic_lock.lock(); 205 basic_lock.lock();
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 120c74e46..b0b6036e4 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -22,7 +22,8 @@
22namespace Core::Timing { 22namespace Core::Timing {
23 23
24/// A callback that may be scheduled for a particular core timing event. 24/// A callback that may be scheduled for a particular core timing event.
25using TimedCallback = std::function<void(u64 userdata, std::chrono::nanoseconds ns_late)>; 25using TimedCallback =
26 std::function<void(std::uintptr_t user_data, std::chrono::nanoseconds ns_late)>;
26 27
27/// Contains the characteristics of a particular event. 28/// Contains the characteristics of a particular event.
28struct EventType { 29struct EventType {
@@ -94,9 +95,9 @@ public:
94 95
95 /// Schedules an event in core timing 96 /// Schedules an event in core timing
96 void ScheduleEvent(std::chrono::nanoseconds ns_into_future, 97 void ScheduleEvent(std::chrono::nanoseconds ns_into_future,
97 const std::shared_ptr<EventType>& event_type, u64 userdata = 0); 98 const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data = 0);
98 99
99 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, u64 userdata); 100 void UnscheduleEvent(const std::shared_ptr<EventType>& event_type, std::uintptr_t user_data);
100 101
101 /// We only permit one event of each type in the queue at a time. 102 /// We only permit one event of each type in the queue at a time.
102 void RemoveEvent(const std::shared_ptr<EventType>& event_type); 103 void RemoveEvent(const std::shared_ptr<EventType>& event_type);
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 32afcf3ae..358943429 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -52,15 +52,15 @@ void CpuManager::Shutdown() {
52} 52}
53 53
54std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() { 54std::function<void(void*)> CpuManager::GetGuestThreadStartFunc() {
55 return std::function<void(void*)>(GuestThreadFunction); 55 return GuestThreadFunction;
56} 56}
57 57
58std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() { 58std::function<void(void*)> CpuManager::GetIdleThreadStartFunc() {
59 return std::function<void(void*)>(IdleThreadFunction); 59 return IdleThreadFunction;
60} 60}
61 61
62std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() { 62std::function<void(void*)> CpuManager::GetSuspendThreadStartFunc() {
63 return std::function<void(void*)>(SuspendThreadFunction); 63 return SuspendThreadFunction;
64} 64}
65 65
66void CpuManager::GuestThreadFunction(void* cpu_manager_) { 66void CpuManager::GuestThreadFunction(void* cpu_manager_) {
diff --git a/src/core/device_memory.cpp b/src/core/device_memory.cpp
index 51097ced3..0c4b440ed 100644
--- a/src/core/device_memory.cpp
+++ b/src/core/device_memory.cpp
@@ -2,14 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h"
6#include "core/device_memory.h" 5#include "core/device_memory.h"
7#include "core/memory.h"
8 6
9namespace Core { 7namespace Core {
10 8
11DeviceMemory::DeviceMemory(System& system) : buffer{DramMemoryMap::Size}, system{system} {} 9DeviceMemory::DeviceMemory() : buffer{DramMemoryMap::Size} {}
12
13DeviceMemory::~DeviceMemory() = default; 10DeviceMemory::~DeviceMemory() = default;
14 11
15} // namespace Core 12} // namespace Core
diff --git a/src/core/device_memory.h b/src/core/device_memory.h
index 9efa088d0..5b1ae28f3 100644
--- a/src/core/device_memory.h
+++ b/src/core/device_memory.h
@@ -4,14 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/assert.h" 7#include "common/common_types.h"
8#include "common/common_funcs.h"
9#include "common/virtual_buffer.h" 8#include "common/virtual_buffer.h"
10 9
11namespace Core { 10namespace Core {
12 11
13class System;
14
15namespace DramMemoryMap { 12namespace DramMemoryMap {
16enum : u64 { 13enum : u64 {
17 Base = 0x80000000ULL, 14 Base = 0x80000000ULL,
@@ -26,7 +23,7 @@ enum : u64 {
26 23
27class DeviceMemory : NonCopyable { 24class DeviceMemory : NonCopyable {
28public: 25public:
29 explicit DeviceMemory(Core::System& system); 26 explicit DeviceMemory();
30 ~DeviceMemory(); 27 ~DeviceMemory();
31 28
32 template <typename T> 29 template <typename T>
@@ -45,7 +42,6 @@ public:
45 42
46private: 43private:
47 Common::VirtualBuffer<u8> buffer; 44 Common::VirtualBuffer<u8> buffer;
48 Core::System& system;
49}; 45};
50 46
51} // namespace Core 47} // namespace Core
diff --git a/src/core/file_sys/mode.h b/src/core/file_sys/mode.h
index c95205668..2b4f21073 100644
--- a/src/core/file_sys/mode.h
+++ b/src/core/file_sys/mode.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_funcs.h"
7#include "common/common_types.h" 8#include "common/common_types.h"
8 9
9namespace FileSys { 10namespace FileSys {
@@ -11,13 +12,11 @@ namespace FileSys {
11enum class Mode : u32 { 12enum class Mode : u32 {
12 Read = 1, 13 Read = 1,
13 Write = 2, 14 Write = 2,
14 ReadWrite = 3, 15 ReadWrite = Read | Write,
15 Append = 4, 16 Append = 4,
16 WriteAppend = 6, 17 WriteAppend = Write | Append,
17}; 18};
18 19
19inline u32 operator&(Mode lhs, Mode rhs) { 20DECLARE_ENUM_FLAG_OPERATORS(Mode)
20 return static_cast<u32>(lhs) & static_cast<u32>(rhs);
21}
22 21
23} // namespace FileSys 22} // namespace FileSys
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index c47ff863e..729dbb5f4 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -288,8 +288,8 @@ std::optional<std::vector<Core::Memory::CheatEntry>> ReadCheatFileFromFolder(
288 } 288 }
289 289
290 Core::Memory::TextCheatParser parser; 290 Core::Memory::TextCheatParser parser;
291 return parser.Parse( 291 return parser.Parse(system,
292 system, std::string_view(reinterpret_cast<const char* const>(data.data()), data.size())); 292 std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
293} 293}
294 294
295} // Anonymous namespace 295} // Anonymous namespace
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 37351c561..f831487dd 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -344,15 +344,18 @@ VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
344 344
345static std::optional<NcaID> CheckMapForContentRecord(const std::map<u64, CNMT>& map, u64 title_id, 345static std::optional<NcaID> CheckMapForContentRecord(const std::map<u64, CNMT>& map, u64 title_id,
346 ContentRecordType type) { 346 ContentRecordType type) {
347 if (map.find(title_id) == map.end()) 347 const auto cmnt_iter = map.find(title_id);
348 return {}; 348 if (cmnt_iter == map.cend()) {
349 349 return std::nullopt;
350 const auto& cnmt = map.at(title_id); 350 }
351 351
352 const auto iter = std::find_if(cnmt.GetContentRecords().begin(), cnmt.GetContentRecords().end(), 352 const auto& cnmt = cmnt_iter->second;
353 const auto& content_records = cnmt.GetContentRecords();
354 const auto iter = std::find_if(content_records.cbegin(), content_records.cend(),
353 [type](const ContentRecord& rec) { return rec.type == type; }); 355 [type](const ContentRecord& rec) { return rec.type == type; });
354 if (iter == cnmt.GetContentRecords().end()) 356 if (iter == content_records.cend()) {
355 return {}; 357 return std::nullopt;
358 }
356 359
357 return std::make_optional(iter->nca_id); 360 return std::make_optional(iter->nca_id);
358} 361}
@@ -467,14 +470,16 @@ VirtualFile RegisteredCache::GetEntryUnparsed(u64 title_id, ContentRecordType ty
467 470
468std::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const { 471std::optional<u32> RegisteredCache::GetEntryVersion(u64 title_id) const {
469 const auto meta_iter = meta.find(title_id); 472 const auto meta_iter = meta.find(title_id);
470 if (meta_iter != meta.end()) 473 if (meta_iter != meta.cend()) {
471 return meta_iter->second.GetTitleVersion(); 474 return meta_iter->second.GetTitleVersion();
475 }
472 476
473 const auto yuzu_meta_iter = yuzu_meta.find(title_id); 477 const auto yuzu_meta_iter = yuzu_meta.find(title_id);
474 if (yuzu_meta_iter != yuzu_meta.end()) 478 if (yuzu_meta_iter != yuzu_meta.cend()) {
475 return yuzu_meta_iter->second.GetTitleVersion(); 479 return yuzu_meta_iter->second.GetTitleVersion();
480 }
476 481
477 return {}; 482 return std::nullopt;
478} 483}
479 484
480VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) const { 485VirtualFile RegisteredCache::GetEntryRaw(u64 title_id, ContentRecordType type) const {
@@ -547,56 +552,6 @@ InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_ex
547 return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy); 552 return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy);
548} 553}
549 554
550bool RegisteredCache::RemoveExistingEntry(u64 title_id) {
551 const auto delete_nca = [this](const NcaID& id) {
552 const auto path = GetRelativePathFromNcaID(id, false, true, false);
553
554 if (dir->GetFileRelative(path) == nullptr) {
555 return false;
556 }
557
558 Core::Crypto::SHA256Hash hash{};
559 mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
560 const auto dirname = fmt::format("000000{:02X}", hash[0]);
561
562 const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
563
564 const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false)));
565
566 return res;
567 };
568
569 // If an entry exists in the registered cache, remove it
570 if (HasEntry(title_id, ContentRecordType::Meta)) {
571 LOG_INFO(Loader,
572 "Previously installed entry (v{}) for title_id={:016X} detected! "
573 "Attempting to remove...",
574 GetEntryVersion(title_id).value_or(0), title_id);
575 // Get all the ncas associated with the current CNMT and delete them
576 const auto meta_old_id =
577 GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{});
578 const auto program_id =
579 GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{});
580 const auto data_id =
581 GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{});
582 const auto control_id =
583 GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{});
584 const auto html_id =
585 GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{});
586 const auto legal_id =
587 GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{});
588
589 delete_nca(meta_old_id);
590 delete_nca(program_id);
591 delete_nca(data_id);
592 delete_nca(control_id);
593 delete_nca(html_id);
594 delete_nca(legal_id);
595 return true;
596 }
597 return false;
598}
599
600InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists, 555InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists,
601 const VfsCopyFunction& copy) { 556 const VfsCopyFunction& copy) {
602 const auto ncas = nsp.GetNCAsCollapsed(); 557 const auto ncas = nsp.GetNCAsCollapsed();
@@ -692,6 +647,57 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
692 return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); 647 return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
693} 648}
694 649
650bool RegisteredCache::RemoveExistingEntry(u64 title_id) const {
651 const auto delete_nca = [this](const NcaID& id) {
652 const auto path = GetRelativePathFromNcaID(id, false, true, false);
653
654 const bool isFile = dir->GetFileRelative(path) != nullptr;
655 const bool isDir = dir->GetDirectoryRelative(path) != nullptr;
656
657 if (isFile) {
658 return dir->DeleteFile(path);
659 } else if (isDir) {
660 return dir->DeleteSubdirectoryRecursive(path);
661 }
662
663 return false;
664 };
665
666 // If an entry exists in the registered cache, remove it
667 if (HasEntry(title_id, ContentRecordType::Meta)) {
668 LOG_INFO(Loader,
669 "Previously installed entry (v{}) for title_id={:016X} detected! "
670 "Attempting to remove...",
671 GetEntryVersion(title_id).value_or(0), title_id);
672
673 // Get all the ncas associated with the current CNMT and delete them
674 const auto meta_old_id =
675 GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{});
676 const auto program_id =
677 GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{});
678 const auto data_id =
679 GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{});
680 const auto control_id =
681 GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{});
682 const auto html_id =
683 GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{});
684 const auto legal_id =
685 GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{});
686
687 const auto deleted_meta = delete_nca(meta_old_id);
688 const auto deleted_program = delete_nca(program_id);
689 const auto deleted_data = delete_nca(data_id);
690 const auto deleted_control = delete_nca(control_id);
691 const auto deleted_html = delete_nca(html_id);
692 const auto deleted_legal = delete_nca(legal_id);
693
694 return deleted_meta && (deleted_meta || deleted_program || deleted_data ||
695 deleted_control || deleted_html || deleted_legal);
696 }
697
698 return false;
699}
700
695InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy, 701InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
696 bool overwrite_if_exists, 702 bool overwrite_if_exists,
697 std::optional<NcaID> override_id) { 703 std::optional<NcaID> override_id) {
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 29cf0d40c..ec1d54f27 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -155,9 +155,6 @@ public:
155 std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {}, 155 std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
156 std::optional<u64> title_id = {}) const override; 156 std::optional<u64> title_id = {}) const override;
157 157
158 // Removes an existing entry based on title id
159 bool RemoveExistingEntry(u64 title_id);
160
161 // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure 158 // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
162 // there is a meta NCA and all of them are accessible. 159 // there is a meta NCA and all of them are accessible.
163 InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false, 160 InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
@@ -172,6 +169,9 @@ public:
172 InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false, 169 InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false,
173 const VfsCopyFunction& copy = &VfsRawCopy); 170 const VfsCopyFunction& copy = &VfsRawCopy);
174 171
172 // Removes an existing entry based on title id
173 bool RemoveExistingEntry(u64 title_id) const;
174
175private: 175private:
176 template <typename T> 176 template <typename T>
177 void IterateAllMetadata(std::vector<T>& out, 177 void IterateAllMetadata(std::vector<T>& out,
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index adfd2c1a4..ba4efee3a 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -17,23 +17,23 @@ constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
17 17
18namespace { 18namespace {
19 19
20void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) { 20void PrintSaveDataAttributeWarnings(SaveDataAttribute meta) {
21 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) { 21 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
22 if (meta.zero_1 != 0) { 22 if (meta.zero_1 != 0) {
23 LOG_WARNING(Service_FS, 23 LOG_WARNING(Service_FS,
24 "Possibly incorrect SaveDataDescriptor, type is " 24 "Possibly incorrect SaveDataAttribute, type is "
25 "SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).", 25 "SystemSaveData||SaveData but offset 0x28 is non-zero ({:016X}).",
26 meta.zero_1); 26 meta.zero_1);
27 } 27 }
28 if (meta.zero_2 != 0) { 28 if (meta.zero_2 != 0) {
29 LOG_WARNING(Service_FS, 29 LOG_WARNING(Service_FS,
30 "Possibly incorrect SaveDataDescriptor, type is " 30 "Possibly incorrect SaveDataAttribute, type is "
31 "SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).", 31 "SystemSaveData||SaveData but offset 0x30 is non-zero ({:016X}).",
32 meta.zero_2); 32 meta.zero_2);
33 } 33 }
34 if (meta.zero_3 != 0) { 34 if (meta.zero_3 != 0) {
35 LOG_WARNING(Service_FS, 35 LOG_WARNING(Service_FS,
36 "Possibly incorrect SaveDataDescriptor, type is " 36 "Possibly incorrect SaveDataAttribute, type is "
37 "SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).", 37 "SystemSaveData||SaveData but offset 0x38 is non-zero ({:016X}).",
38 meta.zero_3); 38 meta.zero_3);
39 } 39 }
@@ -41,33 +41,32 @@ void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) {
41 41
42 if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) { 42 if (meta.type == SaveDataType::SystemSaveData && meta.title_id != 0) {
43 LOG_WARNING(Service_FS, 43 LOG_WARNING(Service_FS,
44 "Possibly incorrect SaveDataDescriptor, type is SystemSaveData but title_id is " 44 "Possibly incorrect SaveDataAttribute, type is SystemSaveData but title_id is "
45 "non-zero ({:016X}).", 45 "non-zero ({:016X}).",
46 meta.title_id); 46 meta.title_id);
47 } 47 }
48 48
49 if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) { 49 if (meta.type == SaveDataType::DeviceSaveData && meta.user_id != u128{0, 0}) {
50 LOG_WARNING(Service_FS, 50 LOG_WARNING(Service_FS,
51 "Possibly incorrect SaveDataDescriptor, type is DeviceSaveData but user_id is " 51 "Possibly incorrect SaveDataAttribute, type is DeviceSaveData but user_id is "
52 "non-zero ({:016X}{:016X})", 52 "non-zero ({:016X}{:016X})",
53 meta.user_id[1], meta.user_id[0]); 53 meta.user_id[1], meta.user_id[0]);
54 } 54 }
55} 55}
56 56
57bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataDescriptor& desc) { 57bool ShouldSaveDataBeAutomaticallyCreated(SaveDataSpaceId space, const SaveDataAttribute& attr) {
58 return desc.type == SaveDataType::CacheStorage || desc.type == SaveDataType::TemporaryStorage || 58 return attr.type == SaveDataType::CacheStorage || attr.type == SaveDataType::TemporaryStorage ||
59 (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User 59 (space == SaveDataSpaceId::NandUser && ///< Normal Save Data -- Current Title & User
60 (desc.type == SaveDataType::SaveData || desc.type == SaveDataType::DeviceSaveData) && 60 (attr.type == SaveDataType::SaveData || attr.type == SaveDataType::DeviceSaveData) &&
61 desc.title_id == 0 && desc.save_id == 0); 61 attr.title_id == 0 && attr.save_id == 0);
62} 62}
63 63
64} // Anonymous namespace 64} // Anonymous namespace
65 65
66std::string SaveDataDescriptor::DebugInfo() const { 66std::string SaveDataAttribute::DebugInfo() const {
67 return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, " 67 return fmt::format("[title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, type={:02X}, "
68 "save_id={:016X}, "
69 "rank={}, index={}]", 68 "rank={}, index={}]",
70 static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id, 69 title_id, user_id[1], user_id[0], save_id, static_cast<u8>(type),
71 static_cast<u8>(rank), index); 70 static_cast<u8>(rank), index);
72} 71}
73 72
@@ -80,8 +79,8 @@ SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save
80SaveDataFactory::~SaveDataFactory() = default; 79SaveDataFactory::~SaveDataFactory() = default;
81 80
82ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space, 81ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
83 const SaveDataDescriptor& meta) const { 82 const SaveDataAttribute& meta) const {
84 PrintSaveDataDescriptorWarnings(meta); 83 PrintSaveDataAttributeWarnings(meta);
85 84
86 const auto save_directory = 85 const auto save_directory =
87 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id); 86 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
@@ -98,7 +97,7 @@ ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
98} 97}
99 98
100ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, 99ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
101 const SaveDataDescriptor& meta) const { 100 const SaveDataAttribute& meta) const {
102 101
103 const auto save_directory = 102 const auto save_directory =
104 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id); 103 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index 991e57aa1..6625bbbd8 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -21,6 +21,7 @@ enum class SaveDataSpaceId : u8 {
21 TemporaryStorage = 3, 21 TemporaryStorage = 3,
22 SdCardUser = 4, 22 SdCardUser = 4,
23 ProperSystem = 100, 23 ProperSystem = 100,
24 SafeMode = 101,
24}; 25};
25 26
26enum class SaveDataType : u8 { 27enum class SaveDataType : u8 {
@@ -30,28 +31,50 @@ enum class SaveDataType : u8 {
30 DeviceSaveData = 3, 31 DeviceSaveData = 3,
31 TemporaryStorage = 4, 32 TemporaryStorage = 4,
32 CacheStorage = 5, 33 CacheStorage = 5,
34 SystemBcat = 6,
33}; 35};
34 36
35enum class SaveDataRank : u8 { 37enum class SaveDataRank : u8 {
36 Primary, 38 Primary = 0,
37 Secondary, 39 Secondary = 1,
38}; 40};
39 41
40struct SaveDataDescriptor { 42enum class SaveDataFlags : u32 {
41 u64_le title_id; 43 None = (0 << 0),
44 KeepAfterResettingSystemSaveData = (1 << 0),
45 KeepAfterRefurbishment = (1 << 1),
46 KeepAfterResettingSystemSaveDataWithoutUserSaveData = (1 << 2),
47 NeedsSecureDelete = (1 << 3),
48};
49
50struct SaveDataAttribute {
51 u64 title_id;
42 u128 user_id; 52 u128 user_id;
43 u64_le save_id; 53 u64 save_id;
44 SaveDataType type; 54 SaveDataType type;
45 SaveDataRank rank; 55 SaveDataRank rank;
46 u16_le index; 56 u16 index;
47 INSERT_PADDING_BYTES(4); 57 INSERT_PADDING_BYTES(4);
48 u64_le zero_1; 58 u64 zero_1;
49 u64_le zero_2; 59 u64 zero_2;
50 u64_le zero_3; 60 u64 zero_3;
51 61
52 std::string DebugInfo() const; 62 std::string DebugInfo() const;
53}; 63};
54static_assert(sizeof(SaveDataDescriptor) == 0x40, "SaveDataDescriptor has incorrect size."); 64static_assert(sizeof(SaveDataAttribute) == 0x40, "SaveDataAttribute has incorrect size.");
65
66struct SaveDataExtraData {
67 SaveDataAttribute attr;
68 u64 owner_id;
69 s64 timestamp;
70 SaveDataFlags flags;
71 INSERT_PADDING_BYTES(4);
72 s64 available_size;
73 s64 journal_size;
74 s64 commit_id;
75 std::array<u8, 0x190> unused;
76};
77static_assert(sizeof(SaveDataExtraData) == 0x200, "SaveDataExtraData has incorrect size.");
55 78
56struct SaveDataSize { 79struct SaveDataSize {
57 u64 normal; 80 u64 normal;
@@ -64,8 +87,8 @@ public:
64 explicit SaveDataFactory(VirtualDir dir); 87 explicit SaveDataFactory(VirtualDir dir);
65 ~SaveDataFactory(); 88 ~SaveDataFactory();
66 89
67 ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataDescriptor& meta) const; 90 ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
68 ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) const; 91 ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
69 92
70 VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; 93 VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
71 94
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 96ce5957c..0db0091f6 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -18,20 +18,22 @@ static std::string ModeFlagsToString(Mode mode) {
18 std::string mode_str; 18 std::string mode_str;
19 19
20 // Calculate the correct open mode for the file. 20 // Calculate the correct open mode for the file.
21 if (mode & Mode::Read && mode & Mode::Write) { 21 if (True(mode & Mode::Read) && True(mode & Mode::Write)) {
22 if (mode & Mode::Append) 22 if (True(mode & Mode::Append)) {
23 mode_str = "a+"; 23 mode_str = "a+";
24 else 24 } else {
25 mode_str = "r+"; 25 mode_str = "r+";
26 }
26 } else { 27 } else {
27 if (mode & Mode::Read) 28 if (True(mode & Mode::Read)) {
28 mode_str = "r"; 29 mode_str = "r";
29 else if (mode & Mode::Append) 30 } else if (True(mode & Mode::Append)) {
30 mode_str = "a"; 31 mode_str = "a";
31 else if (mode & Mode::Write) 32 } else if (True(mode & Mode::Write)) {
32 mode_str = "w"; 33 mode_str = "w";
33 else 34 } else {
34 UNREACHABLE_MSG("Invalid file open mode: {:02X}", static_cast<u8>(mode)); 35 UNREACHABLE_MSG("Invalid file open mode: {:02X}", static_cast<u8>(mode));
36 }
35 } 37 }
36 38
37 mode_str += "b"; 39 mode_str += "b";
@@ -73,8 +75,9 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
73 } 75 }
74 } 76 }
75 77
76 if (!FileUtil::Exists(path) && (perms & Mode::WriteAppend) != 0) 78 if (!FileUtil::Exists(path) && True(perms & Mode::WriteAppend)) {
77 FileUtil::CreateEmptyFile(path); 79 FileUtil::CreateEmptyFile(path);
80 }
78 81
79 auto backing = std::make_shared<FileUtil::IOFile>(path, ModeFlagsToString(perms).c_str()); 82 auto backing = std::make_shared<FileUtil::IOFile>(path, ModeFlagsToString(perms).c_str());
80 cache[path] = backing; 83 cache[path] = backing;
@@ -247,11 +250,11 @@ std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const {
247} 250}
248 251
249bool RealVfsFile::IsWritable() const { 252bool RealVfsFile::IsWritable() const {
250 return (perms & Mode::WriteAppend) != 0; 253 return True(perms & Mode::WriteAppend);
251} 254}
252 255
253bool RealVfsFile::IsReadable() const { 256bool RealVfsFile::IsReadable() const {
254 return (perms & Mode::ReadWrite) != 0; 257 return True(perms & Mode::ReadWrite);
255} 258}
256 259
257std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { 260std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
@@ -319,8 +322,9 @@ RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string&
319 path_components(FileUtil::SplitPathComponents(path)), 322 path_components(FileUtil::SplitPathComponents(path)),
320 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), 323 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
321 perms(perms_) { 324 perms(perms_) {
322 if (!FileUtil::Exists(path) && perms & Mode::WriteAppend) 325 if (!FileUtil::Exists(path) && True(perms & Mode::WriteAppend)) {
323 FileUtil::CreateDir(path); 326 FileUtil::CreateDir(path);
327 }
324} 328}
325 329
326RealVfsDirectory::~RealVfsDirectory() = default; 330RealVfsDirectory::~RealVfsDirectory() = default;
@@ -371,11 +375,11 @@ std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories()
371} 375}
372 376
373bool RealVfsDirectory::IsWritable() const { 377bool RealVfsDirectory::IsWritable() const {
374 return (perms & Mode::WriteAppend) != 0; 378 return True(perms & Mode::WriteAppend);
375} 379}
376 380
377bool RealVfsDirectory::IsReadable() const { 381bool RealVfsDirectory::IsReadable() const {
378 return (perms & Mode::ReadWrite) != 0; 382 return True(perms & Mode::ReadWrite);
379} 383}
380 384
381std::string RealVfsDirectory::GetName() const { 385std::string RealVfsDirectory::GetName() const {
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index 86e06ccb9..81413c684 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -70,14 +70,18 @@ NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
70NAX::~NAX() = default; 70NAX::~NAX() = default;
71 71
72Loader::ResultStatus NAX::Parse(std::string_view path) { 72Loader::ResultStatus NAX::Parse(std::string_view path) {
73 if (file->ReadObject(header.get()) != sizeof(NAXHeader)) 73 if (file == nullptr) {
74 return Loader::ResultStatus::ErrorNullFile;
75 }
76 if (file->ReadObject(header.get()) != sizeof(NAXHeader)) {
74 return Loader::ResultStatus::ErrorBadNAXHeader; 77 return Loader::ResultStatus::ErrorBadNAXHeader;
75 78 }
76 if (header->magic != Common::MakeMagic('N', 'A', 'X', '0')) 79 if (header->magic != Common::MakeMagic('N', 'A', 'X', '0')) {
77 return Loader::ResultStatus::ErrorBadNAXHeader; 80 return Loader::ResultStatus::ErrorBadNAXHeader;
78 81 }
79 if (file->GetSize() < NAX_HEADER_PADDING_SIZE + header->file_size) 82 if (file->GetSize() < NAX_HEADER_PADDING_SIZE + header->file_size) {
80 return Loader::ResultStatus::ErrorIncorrectNAXFileSize; 83 return Loader::ResultStatus::ErrorIncorrectNAXFileSize;
84 }
81 85
82 keys.DeriveSDSeedLazy(); 86 keys.DeriveSDSeedLazy();
83 std::array<Core::Crypto::Key256, 2> sd_keys{}; 87 std::array<Core::Crypto::Key256, 2> sd_keys{};
diff --git a/src/core/hardware_interrupt_manager.cpp b/src/core/hardware_interrupt_manager.cpp
index efc1030c1..645f26e91 100644
--- a/src/core/hardware_interrupt_manager.cpp
+++ b/src/core/hardware_interrupt_manager.cpp
@@ -11,8 +11,8 @@
11namespace Core::Hardware { 11namespace Core::Hardware {
12 12
13InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) { 13InterruptManager::InterruptManager(Core::System& system_in) : system(system_in) {
14 gpu_interrupt_event = 14 gpu_interrupt_event = Core::Timing::CreateEvent(
15 Core::Timing::CreateEvent("GPUInterrupt", [this](u64 message, std::chrono::nanoseconds) { 15 "GPUInterrupt", [this](std::uintptr_t message, std::chrono::nanoseconds) {
16 auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv"); 16 auto nvdrv = system.ServiceManager().GetService<Service::Nvidia::NVDRV>("nvdrv");
17 const u32 syncpt = static_cast<u32>(message >> 32); 17 const u32 syncpt = static_cast<u32>(message >> 32);
18 const u32 value = static_cast<u32>(message); 18 const u32 value = static_cast<u32>(message);
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index b31673928..f3277b766 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -13,6 +13,7 @@
13#include <vector> 13#include <vector>
14#include <boost/container/small_vector.hpp> 14#include <boost/container/small_vector.hpp>
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "common/concepts.h"
16#include "common/swap.h" 17#include "common/swap.h"
17#include "core/hle/ipc.h" 18#include "core/hle/ipc.h"
18#include "core/hle/kernel/object.h" 19#include "core/hle/kernel/object.h"
@@ -193,23 +194,24 @@ public:
193 194
194 /* Helper function to write a buffer using the appropriate buffer descriptor 195 /* Helper function to write a buffer using the appropriate buffer descriptor
195 * 196 *
196 * @tparam ContiguousContainer an arbitrary container that satisfies the 197 * @tparam T an arbitrary container that satisfies the
197 * ContiguousContainer concept in the C++ standard library. 198 * ContiguousContainer concept in the C++ standard library or a trivially copyable type.
198 * 199 *
199 * @param container The container to write the data of into a buffer. 200 * @param data The container/data to write into a buffer.
200 * @param buffer_index The buffer in particular to write to. 201 * @param buffer_index The buffer in particular to write to.
201 */ 202 */
202 template <typename ContiguousContainer, 203 template <typename T, typename = std::enable_if_t<!std::is_pointer_v<T>>>
203 typename = std::enable_if_t<!std::is_pointer_v<ContiguousContainer>>> 204 std::size_t WriteBuffer(const T& data, std::size_t buffer_index = 0) const {
204 std::size_t WriteBuffer(const ContiguousContainer& container, 205 if constexpr (Common::IsSTLContainer<T>) {
205 std::size_t buffer_index = 0) const { 206 using ContiguousType = typename T::value_type;
206 using ContiguousType = typename ContiguousContainer::value_type; 207 static_assert(std::is_trivially_copyable_v<ContiguousType>,
207 208 "Container to WriteBuffer must contain trivially copyable objects");
208 static_assert(std::is_trivially_copyable_v<ContiguousType>, 209 return WriteBuffer(std::data(data), std::size(data) * sizeof(ContiguousType),
209 "Container to WriteBuffer must contain trivially copyable objects"); 210 buffer_index);
210 211 } else {
211 return WriteBuffer(std::data(container), std::size(container) * sizeof(ContiguousType), 212 static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
212 buffer_index); 213 return WriteBuffer(&data, sizeof(T), buffer_index);
214 }
213 } 215 }
214 216
215 /// Helper function to get the size of the input buffer 217 /// Helper function to get the size of the input buffer
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 8dd4a2637..cabe8d418 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -145,7 +145,7 @@ struct KernelCore::Impl {
145 145
146 void InitializePreemption(KernelCore& kernel) { 146 void InitializePreemption(KernelCore& kernel) {
147 preemption_event = Core::Timing::CreateEvent( 147 preemption_event = Core::Timing::CreateEvent(
148 "PreemptionCallback", [this, &kernel](u64, std::chrono::nanoseconds) { 148 "PreemptionCallback", [this, &kernel](std::uintptr_t, std::chrono::nanoseconds) {
149 { 149 {
150 SchedulerLock lock(kernel); 150 SchedulerLock lock(kernel);
151 global_scheduler.PreemptThreads(); 151 global_scheduler.PreemptThreads();
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index af22f4c33..7e6391c6c 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -33,8 +33,10 @@ ResultVal<std::shared_ptr<ServerSession>> ServerSession::Create(KernelCore& kern
33 std::string name) { 33 std::string name) {
34 std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)}; 34 std::shared_ptr<ServerSession> session{std::make_shared<ServerSession>(kernel)};
35 35
36 session->request_event = Core::Timing::CreateEvent( 36 session->request_event =
37 name, [session](u64, std::chrono::nanoseconds) { session->CompleteSyncRequest(); }); 37 Core::Timing::CreateEvent(name, [session](std::uintptr_t, std::chrono::nanoseconds) {
38 session->CompleteSyncRequest();
39 });
38 session->name = std::move(name); 40 session->name = std::move(name);
39 session->parent = std::move(parent); 41 session->parent = std::move(parent);
40 42
diff --git a/src/core/hle/kernel/time_manager.cpp b/src/core/hle/kernel/time_manager.cpp
index 88b01b751..95f2446c9 100644
--- a/src/core/hle/kernel/time_manager.cpp
+++ b/src/core/hle/kernel/time_manager.cpp
@@ -16,14 +16,14 @@ namespace Kernel {
16 16
17TimeManager::TimeManager(Core::System& system_) : system{system_} { 17TimeManager::TimeManager(Core::System& system_) : system{system_} {
18 time_manager_event_type = Core::Timing::CreateEvent( 18 time_manager_event_type = Core::Timing::CreateEvent(
19 "Kernel::TimeManagerCallback", [this](u64 thread_handle, std::chrono::nanoseconds) { 19 "Kernel::TimeManagerCallback",
20 SchedulerLock lock(system.Kernel()); 20 [this](std::uintptr_t thread_handle, std::chrono::nanoseconds) {
21 Handle proper_handle = static_cast<Handle>(thread_handle); 21 const SchedulerLock lock(system.Kernel());
22 const auto proper_handle = static_cast<Handle>(thread_handle);
22 if (cancelled_events[proper_handle]) { 23 if (cancelled_events[proper_handle]) {
23 return; 24 return;
24 } 25 }
25 std::shared_ptr<Thread> thread = 26 auto thread = this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
26 this->system.Kernel().RetrieveThreadFromGlobalHandleTable(proper_handle);
27 thread->OnWakeUp(); 27 thread->OnWakeUp();
28 }); 28 });
29} 29}
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 8ac856ec3..63e4aeca0 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -286,9 +286,7 @@ protected:
286 ProfileBase profile_base{}; 286 ProfileBase profile_base{};
287 ProfileData data{}; 287 ProfileData data{};
288 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { 288 if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) {
289 std::array<u8, sizeof(ProfileData)> raw_data; 289 ctx.WriteBuffer(data);
290 std::memcpy(raw_data.data(), &data, sizeof(ProfileData));
291 ctx.WriteBuffer(raw_data);
292 IPC::ResponseBuilder rb{ctx, 16}; 290 IPC::ResponseBuilder rb{ctx, 16};
293 rb.Push(RESULT_SUCCESS); 291 rb.Push(RESULT_SUCCESS);
294 rb.PushRaw(profile_base); 292 rb.PushRaw(profile_base);
@@ -333,7 +331,7 @@ protected:
333 std::vector<u8> buffer(size); 331 std::vector<u8> buffer(size);
334 image.ReadBytes(buffer.data(), buffer.size()); 332 image.ReadBytes(buffer.data(), buffer.size());
335 333
336 ctx.WriteBuffer(buffer.data(), buffer.size()); 334 ctx.WriteBuffer(buffer);
337 rb.Push<u32>(size); 335 rb.Push<u32>(size);
338 } 336 }
339 337
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index eb8c81645..a98d57b5c 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -58,7 +58,7 @@ ProfileManager::~ProfileManager() {
58/// internal management of the users profiles 58/// internal management of the users profiles
59std::optional<std::size_t> ProfileManager::AddToProfiles(const ProfileInfo& profile) { 59std::optional<std::size_t> ProfileManager::AddToProfiles(const ProfileInfo& profile) {
60 if (user_count >= MAX_USERS) { 60 if (user_count >= MAX_USERS) {
61 return {}; 61 return std::nullopt;
62 } 62 }
63 profiles[user_count] = profile; 63 profiles[user_count] = profile;
64 return user_count++; 64 return user_count++;
@@ -101,13 +101,14 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& usern
101 [&uuid](const ProfileInfo& profile) { return uuid == profile.user_uuid; })) { 101 [&uuid](const ProfileInfo& profile) { return uuid == profile.user_uuid; })) {
102 return ERROR_USER_ALREADY_EXISTS; 102 return ERROR_USER_ALREADY_EXISTS;
103 } 103 }
104 ProfileInfo profile; 104
105 profile.user_uuid = uuid; 105 return AddUser({
106 profile.username = username; 106 .user_uuid = uuid,
107 profile.data = {}; 107 .username = username,
108 profile.creation_time = 0x0; 108 .creation_time = 0,
109 profile.is_open = false; 109 .data = {},
110 return AddUser(profile); 110 .is_open = false,
111 });
111} 112}
112 113
113/// Creates a new user on the system. This function allows a much simpler method of registration 114/// Creates a new user on the system. This function allows a much simpler method of registration
@@ -126,7 +127,7 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const std::string& username)
126 127
127std::optional<UUID> ProfileManager::GetUser(std::size_t index) const { 128std::optional<UUID> ProfileManager::GetUser(std::size_t index) const {
128 if (index >= MAX_USERS) { 129 if (index >= MAX_USERS) {
129 return {}; 130 return std::nullopt;
130 } 131 }
131 132
132 return profiles[index].user_uuid; 133 return profiles[index].user_uuid;
@@ -135,13 +136,13 @@ std::optional<UUID> ProfileManager::GetUser(std::size_t index) const {
135/// Returns a users profile index based on their user id. 136/// Returns a users profile index based on their user id.
136std::optional<std::size_t> ProfileManager::GetUserIndex(const UUID& uuid) const { 137std::optional<std::size_t> ProfileManager::GetUserIndex(const UUID& uuid) const {
137 if (!uuid) { 138 if (!uuid) {
138 return {}; 139 return std::nullopt;
139 } 140 }
140 141
141 const auto iter = std::find_if(profiles.begin(), profiles.end(), 142 const auto iter = std::find_if(profiles.begin(), profiles.end(),
142 [&uuid](const ProfileInfo& p) { return p.user_uuid == uuid; }); 143 [&uuid](const ProfileInfo& p) { return p.user_uuid == uuid; });
143 if (iter == profiles.end()) { 144 if (iter == profiles.end()) {
144 return {}; 145 return std::nullopt;
145 } 146 }
146 147
147 return static_cast<std::size_t>(std::distance(profiles.begin(), iter)); 148 return static_cast<std::size_t>(std::distance(profiles.begin(), iter));
@@ -339,7 +340,13 @@ void ProfileManager::ParseUserSaveFile() {
339 continue; 340 continue;
340 } 341 }
341 342
342 AddUser({user.uuid, user.username, user.timestamp, user.extra_data, false}); 343 AddUser({
344 .user_uuid = user.uuid,
345 .username = user.username,
346 .creation_time = user.timestamp,
347 .data = user.extra_data,
348 .is_open = false,
349 });
343 } 350 }
344 351
345 std::stable_partition(profiles.begin(), profiles.end(), 352 std::stable_partition(profiles.begin(), profiles.end(),
@@ -350,11 +357,13 @@ void ProfileManager::WriteUserSaveFile() {
350 ProfileDataRaw raw{}; 357 ProfileDataRaw raw{};
351 358
352 for (std::size_t i = 0; i < MAX_USERS; ++i) { 359 for (std::size_t i = 0; i < MAX_USERS; ++i) {
353 raw.users[i].username = profiles[i].username; 360 raw.users[i] = {
354 raw.users[i].uuid2 = profiles[i].user_uuid; 361 .uuid = profiles[i].user_uuid,
355 raw.users[i].uuid = profiles[i].user_uuid; 362 .uuid2 = profiles[i].user_uuid,
356 raw.users[i].timestamp = profiles[i].creation_time; 363 .timestamp = profiles[i].creation_time,
357 raw.users[i].extra_data = profiles[i].data; 364 .username = profiles[i].username,
365 .extra_data = profiles[i].data,
366 };
358 } 367 }
359 368
360 const auto raw_path = 369 const auto raw_path =
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 4e7a0bec9..55a1edf1a 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1342,12 +1342,12 @@ void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
1342 1342
1343 LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]); 1343 LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
1344 1344
1345 FileSys::SaveDataDescriptor descriptor{}; 1345 FileSys::SaveDataAttribute attribute{};
1346 descriptor.title_id = system.CurrentProcess()->GetTitleID(); 1346 attribute.title_id = system.CurrentProcess()->GetTitleID();
1347 descriptor.user_id = user_id; 1347 attribute.user_id = user_id;
1348 descriptor.type = FileSys::SaveDataType::SaveData; 1348 attribute.type = FileSys::SaveDataType::SaveData;
1349 const auto res = system.GetFileSystemController().CreateSaveData( 1349 const auto res = system.GetFileSystemController().CreateSaveData(
1350 FileSys::SaveDataSpaceId::NandUser, descriptor); 1350 FileSys::SaveDataSpaceId::NandUser, attribute);
1351 1351
1352 IPC::ResponseBuilder rb{ctx, 4}; 1352 IPC::ResponseBuilder rb{ctx, 4};
1353 rb.Push(res.Code()); 1353 rb.Push(res.Code());
@@ -1405,7 +1405,6 @@ void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) {
1405 // Get supported languages from NACP, if possible 1405 // Get supported languages from NACP, if possible
1406 // Default to 0 (all languages supported) 1406 // Default to 0 (all languages supported)
1407 u32 supported_languages = 0; 1407 u32 supported_languages = 0;
1408 FileSys::PatchManager pm{system.CurrentProcess()->GetTitleID()};
1409 1408
1410 const auto res = [this] { 1409 const auto res = [this] {
1411 const auto title_id = system.CurrentProcess()->GetTitleID(); 1410 const auto title_id = system.CurrentProcess()->GetTitleID();
diff --git a/src/core/hle/service/am/applets/software_keyboard.cpp b/src/core/hle/service/am/applets/software_keyboard.cpp
index fbe3686ae..289da2619 100644
--- a/src/core/hle/service/am/applets/software_keyboard.cpp
+++ b/src/core/hle/service/am/applets/software_keyboard.cpp
@@ -13,11 +13,23 @@
13 13
14namespace Service::AM::Applets { 14namespace Service::AM::Applets {
15 15
16namespace {
17enum class Request : u32 {
18 Finalize = 0x4,
19 SetUserWordInfo = 0x6,
20 SetCustomizeDic = 0x7,
21 Calc = 0xa,
22 SetCustomizedDictionaries = 0xb,
23 UnsetCustomizedDictionaries = 0xc,
24 UnknownD = 0xd,
25 UnknownE = 0xe,
26};
27constexpr std::size_t SWKBD_INLINE_INIT_SIZE = 0x8;
16constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8; 28constexpr std::size_t SWKBD_OUTPUT_BUFFER_SIZE = 0x7D8;
17constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4; 29constexpr std::size_t SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE = 0x7D4;
18constexpr std::size_t DEFAULT_MAX_LENGTH = 500; 30constexpr std::size_t DEFAULT_MAX_LENGTH = 500;
19constexpr bool INTERACTIVE_STATUS_OK = false; 31constexpr bool INTERACTIVE_STATUS_OK = false;
20 32} // Anonymous namespace
21static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters( 33static Core::Frontend::SoftwareKeyboardParameters ConvertToFrontendParameters(
22 KeyboardConfig config, std::u16string initial_text) { 34 KeyboardConfig config, std::u16string initial_text) {
23 Core::Frontend::SoftwareKeyboardParameters params{}; 35 Core::Frontend::SoftwareKeyboardParameters params{};
@@ -47,6 +59,7 @@ SoftwareKeyboard::~SoftwareKeyboard() = default;
47 59
48void SoftwareKeyboard::Initialize() { 60void SoftwareKeyboard::Initialize() {
49 complete = false; 61 complete = false;
62 is_inline = false;
50 initial_text.clear(); 63 initial_text.clear();
51 final_data.clear(); 64 final_data.clear();
52 65
@@ -56,6 +69,11 @@ void SoftwareKeyboard::Initialize() {
56 ASSERT(keyboard_config_storage != nullptr); 69 ASSERT(keyboard_config_storage != nullptr);
57 const auto& keyboard_config = keyboard_config_storage->GetData(); 70 const auto& keyboard_config = keyboard_config_storage->GetData();
58 71
72 if (keyboard_config.size() == SWKBD_INLINE_INIT_SIZE) {
73 is_inline = true;
74 return;
75 }
76
59 ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig)); 77 ASSERT(keyboard_config.size() >= sizeof(KeyboardConfig));
60 std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig)); 78 std::memcpy(&config, keyboard_config.data(), sizeof(KeyboardConfig));
61 79
@@ -87,16 +105,32 @@ void SoftwareKeyboard::ExecuteInteractive() {
87 const auto storage = broker.PopInteractiveDataToApplet(); 105 const auto storage = broker.PopInteractiveDataToApplet();
88 ASSERT(storage != nullptr); 106 ASSERT(storage != nullptr);
89 const auto data = storage->GetData(); 107 const auto data = storage->GetData();
90 const auto status = static_cast<bool>(data[0]); 108 if (!is_inline) {
91 109 const auto status = static_cast<bool>(data[0]);
92 if (status == INTERACTIVE_STATUS_OK) { 110 if (status == INTERACTIVE_STATUS_OK) {
93 complete = true; 111 complete = true;
112 } else {
113 std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
114 std::memcpy(string.data(), data.data() + 4, string.size() * 2);
115 frontend.SendTextCheckDialog(
116 Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()),
117 [this] { broker.SignalStateChanged(); });
118 }
94 } else { 119 } else {
95 std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string; 120 Request request{};
96 std::memcpy(string.data(), data.data() + 4, string.size() * 2); 121 std::memcpy(&request, data.data(), sizeof(Request));
97 frontend.SendTextCheckDialog( 122
98 Common::UTF16StringFromFixedZeroTerminatedBuffer(string.data(), string.size()), 123 switch (request) {
99 [this] { broker.SignalStateChanged(); }); 124 case Request::Calc: {
125 broker.PushNormalDataFromApplet(
126 std::make_shared<IStorage>(std::move(std::vector<u8>{1})));
127 broker.SignalStateChanged();
128 break;
129 }
130 default:
131 UNIMPLEMENTED_MSG("Request {:X} is not implemented", request);
132 break;
133 }
100 } 134 }
101} 135}
102 136
@@ -108,9 +142,10 @@ void SoftwareKeyboard::Execute() {
108 } 142 }
109 143
110 const auto parameters = ConvertToFrontendParameters(config, initial_text); 144 const auto parameters = ConvertToFrontendParameters(config, initial_text);
111 145 if (!is_inline) {
112 frontend.RequestText([this](std::optional<std::u16string> text) { WriteText(std::move(text)); }, 146 frontend.RequestText(
113 parameters); 147 [this](std::optional<std::u16string> text) { WriteText(std::move(text)); }, parameters);
148 }
114} 149}
115 150
116void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) { 151void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
diff --git a/src/core/hle/service/am/applets/software_keyboard.h b/src/core/hle/service/am/applets/software_keyboard.h
index ef4801fc6..5a3824b5a 100644
--- a/src/core/hle/service/am/applets/software_keyboard.h
+++ b/src/core/hle/service/am/applets/software_keyboard.h
@@ -78,6 +78,7 @@ private:
78 KeyboardConfig config; 78 KeyboardConfig config;
79 std::u16string initial_text; 79 std::u16string initial_text;
80 bool complete = false; 80 bool complete = false;
81 bool is_inline = false;
81 std::vector<u8> final_data; 82 std::vector<u8> final_data;
82}; 83};
83 84
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp
index 106e89743..dd80dd1dc 100644
--- a/src/core/hle/service/audio/audout_u.cpp
+++ b/src/core/hle/service/audio/audout_u.cpp
@@ -71,7 +71,7 @@ public:
71 71
72 stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate, 72 stream = audio_core.OpenStream(system.CoreTiming(), audio_params.sample_rate,
73 audio_params.channel_count, std::move(unique_name), 73 audio_params.channel_count, std::move(unique_name),
74 [=]() { buffer_event.writable->Signal(); }); 74 [this] { buffer_event.writable->Signal(); });
75 } 75 }
76 76
77private: 77private:
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp
index d19513cbb..f1d81602c 100644
--- a/src/core/hle/service/audio/hwopus.cpp
+++ b/src/core/hle/service/audio/hwopus.cpp
@@ -92,7 +92,7 @@ private:
92 if (performance) { 92 if (performance) {
93 rb.Push<u64>(*performance); 93 rb.Push<u64>(*performance);
94 } 94 }
95 ctx.WriteBuffer(samples.data(), samples.size() * sizeof(s16)); 95 ctx.WriteBuffer(samples);
96 } 96 }
97 97
98 bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input, 98 bool DecodeOpusData(u32& consumed, u32& sample_count, const std::vector<u8>& input,
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp
index 603b64d4f..db0e06ca1 100644
--- a/src/core/hle/service/bcat/module.cpp
+++ b/src/core/hle/service/bcat/module.cpp
@@ -112,7 +112,7 @@ private:
112 void GetImpl(Kernel::HLERequestContext& ctx) { 112 void GetImpl(Kernel::HLERequestContext& ctx) {
113 LOG_DEBUG(Service_BCAT, "called"); 113 LOG_DEBUG(Service_BCAT, "called");
114 114
115 ctx.WriteBuffer(&impl, sizeof(DeliveryCacheProgressImpl)); 115 ctx.WriteBuffer(impl);
116 116
117 IPC::ResponseBuilder rb{ctx, 2}; 117 IPC::ResponseBuilder rb{ctx, 2};
118 rb.Push(RESULT_SUCCESS); 118 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp
index a41c73c48..c2737a365 100644
--- a/src/core/hle/service/es/es.cpp
+++ b/src/core/hle/service/es/es.cpp
@@ -160,7 +160,7 @@ private:
160 return; 160 return;
161 } 161 }
162 162
163 ctx.WriteBuffer(key.data(), key.size()); 163 ctx.WriteBuffer(key);
164 164
165 IPC::ResponseBuilder rb{ctx, 2}; 165 IPC::ResponseBuilder rb{ctx, 2};
166 rb.Push(RESULT_SUCCESS); 166 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index c66124998..4490f8e4c 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -311,7 +311,7 @@ ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
311} 311}
312 312
313ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData( 313ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
314 FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const { 314 FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const {
315 LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", 315 LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}",
316 static_cast<u8>(space), save_struct.DebugInfo()); 316 static_cast<u8>(space), save_struct.DebugInfo());
317 317
@@ -323,15 +323,15 @@ ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
323} 323}
324 324
325ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData( 325ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
326 FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& descriptor) const { 326 FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& attribute) const {
327 LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", 327 LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
328 static_cast<u8>(space), descriptor.DebugInfo()); 328 static_cast<u8>(space), attribute.DebugInfo());
329 329
330 if (save_data_factory == nullptr) { 330 if (save_data_factory == nullptr) {
331 return FileSys::ERROR_ENTITY_NOT_FOUND; 331 return FileSys::ERROR_ENTITY_NOT_FOUND;
332 } 332 }
333 333
334 return save_data_factory->Open(space, descriptor); 334 return save_data_factory->Open(space, attribute);
335} 335}
336 336
337ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace( 337ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 1b0a6a949..6dbbf0b2b 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -31,7 +31,7 @@ enum class SaveDataSpaceId : u8;
31enum class SaveDataType : u8; 31enum class SaveDataType : u8;
32enum class StorageId : u8; 32enum class StorageId : u8;
33 33
34struct SaveDataDescriptor; 34struct SaveDataAttribute;
35struct SaveDataSize; 35struct SaveDataSize;
36} // namespace FileSys 36} // namespace FileSys
37 37
@@ -69,9 +69,9 @@ public:
69 ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id, 69 ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
70 FileSys::ContentRecordType type) const; 70 FileSys::ContentRecordType type) const;
71 ResultVal<FileSys::VirtualDir> CreateSaveData( 71 ResultVal<FileSys::VirtualDir> CreateSaveData(
72 FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const; 72 FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const;
73 ResultVal<FileSys::VirtualDir> OpenSaveData( 73 ResultVal<FileSys::VirtualDir> OpenSaveData(
74 FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const; 74 FileSys::SaveDataSpaceId space, const FileSys::SaveDataAttribute& save_struct) const;
75 ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) const; 75 ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) const;
76 ResultVal<FileSys::VirtualDir> OpenSDMC() const; 76 ResultVal<FileSys::VirtualDir> OpenSDMC() const;
77 ResultVal<FileSys::VirtualDir> OpenBISPartition(FileSys::BisPartitionId id) const; 77 ResultVal<FileSys::VirtualDir> OpenBISPartition(FileSys::BisPartitionId id) const;
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 20c331b77..26fd87f58 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -696,8 +696,8 @@ FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
696 {67, nullptr, "FindSaveDataWithFilter"}, 696 {67, nullptr, "FindSaveDataWithFilter"},
697 {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"}, 697 {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
698 {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"}, 698 {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
699 {70, nullptr, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"}, 699 {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
700 {71, nullptr, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"}, 700 {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
701 {80, nullptr, "OpenSaveDataMetaFile"}, 701 {80, nullptr, "OpenSaveDataMetaFile"},
702 {81, nullptr, "OpenSaveDataTransferManager"}, 702 {81, nullptr, "OpenSaveDataTransferManager"},
703 {82, nullptr, "OpenSaveDataTransferManagerVersion2"}, 703 {82, nullptr, "OpenSaveDataTransferManagerVersion2"},
@@ -812,7 +812,7 @@ void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
812void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) { 812void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
813 IPC::RequestParser rp{ctx}; 813 IPC::RequestParser rp{ctx};
814 814
815 auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); 815 auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
816 [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); 816 [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
817 u128 uid = rp.PopRaw<u128>(); 817 u128 uid = rp.PopRaw<u128>();
818 818
@@ -826,17 +826,18 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
826} 826}
827 827
828void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) { 828void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
829 LOG_INFO(Service_FS, "called."); 829 IPC::RequestParser rp{ctx};
830 830
831 struct Parameters { 831 struct Parameters {
832 FileSys::SaveDataSpaceId save_data_space_id; 832 FileSys::SaveDataSpaceId space_id;
833 FileSys::SaveDataDescriptor descriptor; 833 FileSys::SaveDataAttribute attribute;
834 }; 834 };
835 835
836 IPC::RequestParser rp{ctx};
837 const auto parameters = rp.PopRaw<Parameters>(); 836 const auto parameters = rp.PopRaw<Parameters>();
838 837
839 auto dir = fsc.OpenSaveData(parameters.save_data_space_id, parameters.descriptor); 838 LOG_INFO(Service_FS, "called.");
839
840 auto dir = fsc.OpenSaveData(parameters.space_id, parameters.attribute);
840 if (dir.Failed()) { 841 if (dir.Failed()) {
841 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 842 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
842 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); 843 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
@@ -844,13 +845,18 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
844 } 845 }
845 846
846 FileSys::StorageId id; 847 FileSys::StorageId id;
847 if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::NandUser) { 848
849 switch (parameters.space_id) {
850 case FileSys::SaveDataSpaceId::NandUser:
848 id = FileSys::StorageId::NandUser; 851 id = FileSys::StorageId::NandUser;
849 } else if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardSystem || 852 break;
850 parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardUser) { 853 case FileSys::SaveDataSpaceId::SdCardSystem:
854 case FileSys::SaveDataSpaceId::SdCardUser:
851 id = FileSys::StorageId::SdCard; 855 id = FileSys::StorageId::SdCard;
852 } else { 856 break;
857 case FileSys::SaveDataSpaceId::NandSystem:
853 id = FileSys::StorageId::NandSystem; 858 id = FileSys::StorageId::NandSystem;
859 break;
854 } 860 }
855 861
856 auto filesystem = 862 auto filesystem =
@@ -876,22 +882,31 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
876 rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space, fsc)); 882 rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space, fsc));
877} 883}
878 884
879void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { 885void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(Kernel::HLERequestContext& ctx) {
880 IPC::RequestParser rp{ctx}; 886 LOG_WARNING(Service_FS, "(STUBBED) called.");
881 log_mode = rp.PopEnum<LogMode>();
882
883 LOG_DEBUG(Service_FS, "called, log_mode={:08X}", static_cast<u32>(log_mode));
884 887
885 IPC::ResponseBuilder rb{ctx, 2}; 888 IPC::ResponseBuilder rb{ctx, 2};
886 rb.Push(RESULT_SUCCESS); 889 rb.Push(RESULT_SUCCESS);
887} 890}
888 891
889void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { 892void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
890 LOG_DEBUG(Service_FS, "called"); 893 Kernel::HLERequestContext& ctx) {
894 IPC::RequestParser rp{ctx};
895
896 struct Parameters {
897 FileSys::SaveDataSpaceId space_id;
898 FileSys::SaveDataAttribute attribute;
899 };
900
901 const auto parameters = rp.PopRaw<Parameters>();
902 // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
903 constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
904
905 LOG_WARNING(Service_FS, "(STUBBED) called, flags={}", flags);
891 906
892 IPC::ResponseBuilder rb{ctx, 3}; 907 IPC::ResponseBuilder rb{ctx, 3};
893 rb.Push(RESULT_SUCCESS); 908 rb.Push(RESULT_SUCCESS);
894 rb.PushEnum(log_mode); 909 rb.Push(flags);
895} 910}
896 911
897void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { 912void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
@@ -966,6 +981,24 @@ void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ct
966 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); 981 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
967} 982}
968 983
984void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
985 IPC::RequestParser rp{ctx};
986 log_mode = rp.PopEnum<LogMode>();
987
988 LOG_DEBUG(Service_FS, "called, log_mode={:08X}", static_cast<u32>(log_mode));
989
990 IPC::ResponseBuilder rb{ctx, 2};
991 rb.Push(RESULT_SUCCESS);
992}
993
994void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
995 LOG_DEBUG(Service_FS, "called");
996
997 IPC::ResponseBuilder rb{ctx, 3};
998 rb.Push(RESULT_SUCCESS);
999 rb.PushEnum(log_mode);
1000}
1001
969void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) { 1002void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
970 const auto raw = ctx.ReadBuffer(); 1003 const auto raw = ctx.ReadBuffer();
971 auto log = Common::StringFromFixedZeroTerminatedBuffer( 1004 auto log = Common::StringFromFixedZeroTerminatedBuffer(
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index dfb3e395b..4964e874e 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -43,11 +43,13 @@ private:
43 void OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx); 43 void OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx);
44 void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx); 44 void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
45 void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx); 45 void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
46 void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 46 void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(Kernel::HLERequestContext& ctx);
47 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); 47 void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(Kernel::HLERequestContext& ctx);
48 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); 48 void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
49 void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); 49 void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
50 void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); 50 void OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
51 void SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
52 void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
51 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); 53 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
52 void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx); 54 void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
53 void OpenMultiCommitManager(Kernel::HLERequestContext& ctx); 55 void OpenMultiCommitManager(Kernel::HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index cb35919e9..ad251ed4a 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -39,33 +39,36 @@ void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing,
39 39
40 cur_entry.sampling_number = last_entry.sampling_number + 1; 40 cur_entry.sampling_number = last_entry.sampling_number + 1;
41 cur_entry.sampling_number2 = cur_entry.sampling_number; 41 cur_entry.sampling_number2 = cur_entry.sampling_number;
42 cur_entry.attribute.connected.Assign(1);
43 auto& pad = cur_entry.pad_state;
44 42
45 using namespace Settings::NativeButton; 43 if (Settings::values.debug_pad_enabled) {
46 pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); 44 cur_entry.attribute.connected.Assign(1);
47 pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); 45 auto& pad = cur_entry.pad_state;
48 pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
49 pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
50 pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
51 pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
52 pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
53 pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
54 pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
55 pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
56 pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
57 pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
58 pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
59 pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
60 46
61 const auto [stick_l_x_f, stick_l_y_f] = 47 using namespace Settings::NativeButton;
62 analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); 48 pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus());
63 const auto [stick_r_x_f, stick_r_y_f] = 49 pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
64 analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); 50 pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
65 cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); 51 pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
66 cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); 52 pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
67 cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); 53 pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
68 cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); 54 pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
55 pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
56 pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
57 pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
58 pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
59 pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
60 pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
61 pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
62
63 const auto [stick_l_x_f, stick_l_y_f] =
64 analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
65 const auto [stick_r_x_f, stick_r_y_f] =
66 analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
67 cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
68 cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
69 cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
70 cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
71 }
69 72
70 std::memcpy(data, &shared_memory, sizeof(SharedMemory)); 73 std::memcpy(data, &shared_memory, sizeof(SharedMemory));
71} 74}
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index feae89525..0b896d5ad 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -40,15 +40,16 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing,
40 40
41 cur_entry.key.fill(0); 41 cur_entry.key.fill(0);
42 cur_entry.modifier = 0; 42 cur_entry.modifier = 0;
43 43 if (Settings::values.keyboard_enabled) {
44 for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { 44 for (std::size_t i = 0; i < keyboard_keys.size(); ++i) {
45 cur_entry.key[i / KEYS_PER_BYTE] |= (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)); 45 cur_entry.key[i / KEYS_PER_BYTE] |=
46 } 46 (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE));
47 47 }
48 for (std::size_t i = 0; i < keyboard_mods.size(); ++i) { 48
49 cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i); 49 for (std::size_t i = 0; i < keyboard_mods.size(); ++i) {
50 cur_entry.modifier |= (keyboard_mods[i]->GetStatus() << i);
51 }
50 } 52 }
51
52 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); 53 std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
53} 54}
54 55
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 680290cbd..1e95b7580 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -77,8 +77,9 @@ IAppletResource::IAppletResource(Core::System& system)
77 77
78 // Register update callbacks 78 // Register update callbacks
79 pad_update_event = Core::Timing::CreateEvent( 79 pad_update_event = Core::Timing::CreateEvent(
80 "HID::UpdatePadCallback", [this](u64 userdata, std::chrono::nanoseconds ns_late) { 80 "HID::UpdatePadCallback",
81 UpdateControllers(userdata, ns_late); 81 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
82 UpdateControllers(user_data, ns_late);
82 }); 83 });
83 84
84 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?) 85 // TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
@@ -108,7 +109,8 @@ void IAppletResource::GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) {
108 rb.PushCopyObjects(shared_mem); 109 rb.PushCopyObjects(shared_mem);
109} 110}
110 111
111void IAppletResource::UpdateControllers(u64 userdata, std::chrono::nanoseconds ns_late) { 112void IAppletResource::UpdateControllers(std::uintptr_t user_data,
113 std::chrono::nanoseconds ns_late) {
112 auto& core_timing = system.CoreTiming(); 114 auto& core_timing = system.CoreTiming();
113 115
114 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); 116 const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index c6f0a2584..efb07547f 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -64,7 +64,7 @@ private:
64 } 64 }
65 65
66 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); 66 void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
67 void UpdateControllers(u64 userdata, std::chrono::nanoseconds ns_late); 67 void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
68 68
69 std::shared_ptr<Kernel::SharedMemory> shared_mem; 69 std::shared_ptr<Kernel::SharedMemory> shared_mem;
70 70
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 64a526b9e..d8cd10e31 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -310,7 +310,7 @@ public:
310 310
311 ResultVal<VAddr> MapProcessCodeMemory(Kernel::Process* process, VAddr baseAddress, 311 ResultVal<VAddr> MapProcessCodeMemory(Kernel::Process* process, VAddr baseAddress,
312 u64 size) const { 312 u64 size) const {
313 for (int retry{}; retry < MAXIMUM_MAP_RETRIES; retry++) { 313 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
314 auto& page_table{process->PageTable()}; 314 auto& page_table{process->PageTable()};
315 const VAddr addr{GetRandomMapRegion(page_table, size)}; 315 const VAddr addr{GetRandomMapRegion(page_table, size)};
316 const ResultCode result{page_table.MapProcessCodeMemory(addr, baseAddress, size)}; 316 const ResultCode result{page_table.MapProcessCodeMemory(addr, baseAddress, size)};
@@ -331,8 +331,7 @@ public:
331 331
332 ResultVal<VAddr> MapNro(Kernel::Process* process, VAddr nro_addr, std::size_t nro_size, 332 ResultVal<VAddr> MapNro(Kernel::Process* process, VAddr nro_addr, std::size_t nro_size,
333 VAddr bss_addr, std::size_t bss_size, std::size_t size) const { 333 VAddr bss_addr, std::size_t bss_size, std::size_t size) const {
334 334 for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
335 for (int retry{}; retry < MAXIMUM_MAP_RETRIES; retry++) {
336 auto& page_table{process->PageTable()}; 335 auto& page_table{process->PageTable()};
337 VAddr addr{}; 336 VAddr addr{};
338 337
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp
index 4b79eb81d..5e2d769a4 100644
--- a/src/core/hle/service/nfp/nfp.cpp
+++ b/src/core/hle/service/nfp/nfp.cpp
@@ -127,7 +127,7 @@ private:
127 const u32 array_size = rp.Pop<u32>(); 127 const u32 array_size = rp.Pop<u32>();
128 LOG_DEBUG(Service_NFP, "called, array_size={}", array_size); 128 LOG_DEBUG(Service_NFP, "called, array_size={}", array_size);
129 129
130 ctx.WriteBuffer(&device_handle, sizeof(device_handle)); 130 ctx.WriteBuffer(device_handle);
131 131
132 IPC::ResponseBuilder rb{ctx, 3}; 132 IPC::ResponseBuilder rb{ctx, 3};
133 rb.Push(RESULT_SUCCESS); 133 rb.Push(RESULT_SUCCESS);
@@ -220,7 +220,7 @@ private:
220 220
221 tag_info.protocol = 1; // TODO(ogniK): Figure out actual values 221 tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
222 tag_info.tag_type = 2; 222 tag_info.tag_type = 2;
223 ctx.WriteBuffer(&tag_info, sizeof(TagInfo)); 223 ctx.WriteBuffer(tag_info);
224 rb.Push(RESULT_SUCCESS); 224 rb.Push(RESULT_SUCCESS);
225 } 225 }
226 226
@@ -237,7 +237,7 @@ private:
237 237
238 IPC::ResponseBuilder rb{ctx, 2}; 238 IPC::ResponseBuilder rb{ctx, 2};
239 auto amiibo = nfp_interface.GetAmiiboBuffer(); 239 auto amiibo = nfp_interface.GetAmiiboBuffer();
240 ctx.WriteBuffer(&amiibo.model_info, sizeof(amiibo.model_info)); 240 ctx.WriteBuffer(amiibo.model_info);
241 rb.Push(RESULT_SUCCESS); 241 rb.Push(RESULT_SUCCESS);
242 } 242 }
243 243
@@ -283,7 +283,7 @@ private:
283 283
284 CommonInfo common_info{}; 284 CommonInfo common_info{};
285 common_info.application_area_size = 0; 285 common_info.application_area_size = 0;
286 ctx.WriteBuffer(&common_info, sizeof(CommonInfo)); 286 ctx.WriteBuffer(common_info);
287 287
288 IPC::ResponseBuilder rb{ctx, 2}; 288 IPC::ResponseBuilder rb{ctx, 2};
289 rb.Push(RESULT_SUCCESS); 289 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 195421cc0..d4ba88147 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -16,11 +16,12 @@
16#include "video_core/renderer_base.h" 16#include "video_core/renderer_base.h"
17 17
18namespace Service::Nvidia::Devices { 18namespace Service::Nvidia::Devices {
19
19namespace NvErrCodes { 20namespace NvErrCodes {
20enum { 21constexpr u32 Success{};
21 InvalidNmapHandle = -22, 22constexpr u32 OutOfMemory{static_cast<u32>(-12)};
22}; 23constexpr u32 InvalidInput{static_cast<u32>(-22)};
23} 24} // namespace NvErrCodes
24 25
25nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) 26nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
26 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 27 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
@@ -49,8 +50,9 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std:
49 break; 50 break;
50 } 51 }
51 52
52 if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) 53 if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) {
53 return Remap(input, output); 54 return Remap(input, output);
55 }
54 56
55 UNIMPLEMENTED_MSG("Unimplemented ioctl command"); 57 UNIMPLEMENTED_MSG("Unimplemented ioctl command");
56 return 0; 58 return 0;
@@ -59,6 +61,7 @@ u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std:
59u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { 61u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
60 IoctlInitalizeEx params{}; 62 IoctlInitalizeEx params{};
61 std::memcpy(&params, input.data(), input.size()); 63 std::memcpy(&params, input.data(), input.size());
64
62 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); 65 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
63 66
64 return 0; 67 return 0;
@@ -67,53 +70,61 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou
67u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { 70u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
68 IoctlAllocSpace params{}; 71 IoctlAllocSpace params{};
69 std::memcpy(&params, input.data(), input.size()); 72 std::memcpy(&params, input.data(), input.size());
73
70 LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages, 74 LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages,
71 params.page_size, params.flags); 75 params.page_size, params.flags);
72 76
73 auto& gpu = system.GPU(); 77 const auto size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)};
74 const u64 size{static_cast<u64>(params.pages) * static_cast<u64>(params.page_size)}; 78 if ((params.flags & AddressSpaceFlags::FixedOffset) != AddressSpaceFlags::None) {
75 if (params.flags & 1) { 79 params.offset = *system.GPU().MemoryManager().AllocateFixed(params.offset, size);
76 params.offset = gpu.MemoryManager().AllocateSpace(params.offset, size, 1);
77 } else { 80 } else {
78 params.offset = gpu.MemoryManager().AllocateSpace(size, params.align); 81 params.offset = system.GPU().MemoryManager().Allocate(size, params.align);
82 }
83
84 auto result{NvErrCodes::Success};
85 if (!params.offset) {
86 LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size);
87 result = NvErrCodes::OutOfMemory;
79 } 88 }
80 89
81 std::memcpy(output.data(), &params, output.size()); 90 std::memcpy(output.data(), &params, output.size());
82 return 0; 91 return result;
83} 92}
84 93
85u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { 94u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
86 std::size_t num_entries = input.size() / sizeof(IoctlRemapEntry); 95 const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
87 96
88 LOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries=0x{:X}", num_entries); 97 LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
89 98
99 auto result{NvErrCodes::Success};
90 std::vector<IoctlRemapEntry> entries(num_entries); 100 std::vector<IoctlRemapEntry> entries(num_entries);
91 std::memcpy(entries.data(), input.data(), input.size()); 101 std::memcpy(entries.data(), input.data(), input.size());
92 102
93 auto& gpu = system.GPU();
94 for (const auto& entry : entries) { 103 for (const auto& entry : entries) {
95 LOG_WARNING(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}", 104 LOG_DEBUG(Service_NVDRV, "remap entry, offset=0x{:X} handle=0x{:X} pages=0x{:X}",
96 entry.offset, entry.nvmap_handle, entry.pages); 105 entry.offset, entry.nvmap_handle, entry.pages);
97 GPUVAddr offset = static_cast<GPUVAddr>(entry.offset) << 0x10; 106
98 auto object = nvmap_dev->GetObject(entry.nvmap_handle); 107 const auto object{nvmap_dev->GetObject(entry.nvmap_handle)};
99 if (!object) { 108 if (!object) {
100 LOG_CRITICAL(Service_NVDRV, "nvmap {} is an invalid handle!", entry.nvmap_handle); 109 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle);
101 std::memcpy(output.data(), entries.data(), output.size()); 110 result = NvErrCodes::InvalidInput;
102 return static_cast<u32>(NvErrCodes::InvalidNmapHandle); 111 break;
103 } 112 }
104 113
105 ASSERT(object->status == nvmap::Object::Status::Allocated); 114 const auto offset{static_cast<GPUVAddr>(entry.offset) << 0x10};
115 const auto size{static_cast<u64>(entry.pages) << 0x10};
116 const auto map_offset{static_cast<u64>(entry.map_offset) << 0x10};
117 const auto addr{system.GPU().MemoryManager().Map(object->addr + map_offset, offset, size)};
106 118
107 const u64 size = static_cast<u64>(entry.pages) << 0x10; 119 if (!addr) {
108 ASSERT(size <= object->size); 120 LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!");
109 const u64 map_offset = static_cast<u64>(entry.map_offset) << 0x10; 121 result = NvErrCodes::InvalidInput;
110 122 break;
111 const GPUVAddr returned = 123 }
112 gpu.MemoryManager().MapBufferEx(object->addr + map_offset, offset, size);
113 ASSERT(returned == offset);
114 } 124 }
125
115 std::memcpy(output.data(), entries.data(), output.size()); 126 std::memcpy(output.data(), entries.data(), output.size());
116 return 0; 127 return result;
117} 128}
118 129
119u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { 130u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
@@ -126,44 +137,76 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
126 params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size, 137 params.flags, params.nvmap_handle, params.buffer_offset, params.mapping_size,
127 params.offset); 138 params.offset);
128 139
129 if (!params.nvmap_handle) { 140 const auto object{nvmap_dev->GetObject(params.nvmap_handle)};
130 return 0; 141 if (!object) {
142 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);
143 std::memcpy(output.data(), &params, output.size());
144 return NvErrCodes::InvalidInput;
131 } 145 }
132 146
133 auto object = nvmap_dev->GetObject(params.nvmap_handle);
134 ASSERT(object);
135
136 // We can only map objects that have already been assigned a CPU address.
137 ASSERT(object->status == nvmap::Object::Status::Allocated);
138
139 ASSERT(params.buffer_offset == 0);
140
141 // The real nvservices doesn't make a distinction between handles and ids, and 147 // The real nvservices doesn't make a distinction between handles and ids, and
142 // object can only have one handle and it will be the same as its id. Assert that this is the 148 // object can only have one handle and it will be the same as its id. Assert that this is the
143 // case to prevent unexpected behavior. 149 // case to prevent unexpected behavior.
144 ASSERT(object->id == params.nvmap_handle); 150 ASSERT(object->id == params.nvmap_handle);
145
146 auto& gpu = system.GPU(); 151 auto& gpu = system.GPU();
147 152
148 if (params.flags & 1) { 153 u64 page_size{params.page_size};
149 params.offset = gpu.MemoryManager().MapBufferEx(object->addr, params.offset, object->size); 154 if (!page_size) {
150 } else { 155 page_size = object->align;
151 params.offset = gpu.MemoryManager().MapBufferEx(object->addr, object->size); 156 }
157
158 if ((params.flags & AddressSpaceFlags::Remap) != AddressSpaceFlags::None) {
159 if (const auto buffer_map{FindBufferMap(params.offset)}; buffer_map) {
160 const auto cpu_addr{static_cast<VAddr>(buffer_map->CpuAddr() + params.buffer_offset)};
161 const auto gpu_addr{static_cast<GPUVAddr>(params.offset + params.buffer_offset)};
162
163 if (!gpu.MemoryManager().Map(cpu_addr, gpu_addr, params.mapping_size)) {
164 LOG_CRITICAL(Service_NVDRV,
165 "remap failed, flags={:X}, nvmap_handle={:X}, buffer_offset={}, "
166 "mapping_size = {}, offset={}",
167 params.flags, params.nvmap_handle, params.buffer_offset,
168 params.mapping_size, params.offset);
169
170 std::memcpy(output.data(), &params, output.size());
171 return NvErrCodes::InvalidInput;
172 }
173
174 std::memcpy(output.data(), &params, output.size());
175 return NvErrCodes::Success;
176 } else {
177 LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset);
178
179 std::memcpy(output.data(), &params, output.size());
180 return NvErrCodes::InvalidInput;
181 }
152 } 182 }
153 183
154 // Create a new mapping entry for this operation. 184 // We can only map objects that have already been assigned a CPU address.
155 ASSERT_MSG(buffer_mappings.find(params.offset) == buffer_mappings.end(), 185 ASSERT(object->status == nvmap::Object::Status::Allocated);
156 "Offset is already mapped"); 186
187 const auto physical_address{object->addr + params.buffer_offset};
188 u64 size{params.mapping_size};
189 if (!size) {
190 size = object->size;
191 }
157 192
158 BufferMapping mapping{}; 193 const bool is_alloc{(params.flags & AddressSpaceFlags::FixedOffset) == AddressSpaceFlags::None};
159 mapping.nvmap_handle = params.nvmap_handle; 194 if (is_alloc) {
160 mapping.offset = params.offset; 195 params.offset = gpu.MemoryManager().MapAllocate(physical_address, size, page_size);
161 mapping.size = object->size; 196 } else {
197 params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size);
198 }
162 199
163 buffer_mappings[params.offset] = mapping; 200 auto result{NvErrCodes::Success};
201 if (!params.offset) {
202 LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size);
203 result = NvErrCodes::InvalidInput;
204 } else {
205 AddBufferMap(params.offset, size, physical_address, is_alloc);
206 }
164 207
165 std::memcpy(output.data(), &params, output.size()); 208 std::memcpy(output.data(), &params, output.size());
166 return 0; 209 return result;
167} 210}
168 211
169u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { 212u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
@@ -172,24 +215,20 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
172 215
173 LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); 216 LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset);
174 217
175 const auto itr = buffer_mappings.find(params.offset); 218 if (const auto size{RemoveBufferMap(params.offset)}; size) {
176 if (itr == buffer_mappings.end()) { 219 system.GPU().MemoryManager().Unmap(params.offset, *size);
177 LOG_WARNING(Service_NVDRV, "Tried to unmap an invalid offset 0x{:X}", params.offset); 220 } else {
178 // Hardware tests shows that unmapping an already unmapped buffer always returns successful 221 LOG_ERROR(Service_NVDRV, "invalid offset=0x{:X}", params.offset);
179 // and doesn't fail.
180 return 0;
181 } 222 }
182 223
183 params.offset = system.GPU().MemoryManager().UnmapBuffer(params.offset, itr->second.size);
184 buffer_mappings.erase(itr->second.offset);
185
186 std::memcpy(output.data(), &params, output.size()); 224 std::memcpy(output.data(), &params, output.size());
187 return 0; 225 return NvErrCodes::Success;
188} 226}
189 227
190u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { 228u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {
191 IoctlBindChannel params{}; 229 IoctlBindChannel params{};
192 std::memcpy(&params, input.data(), input.size()); 230 std::memcpy(&params, input.data(), input.size());
231
193 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); 232 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
194 233
195 channel = params.fd; 234 channel = params.fd;
@@ -199,6 +238,7 @@ u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& ou
199u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { 238u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) {
200 IoctlGetVaRegions params{}; 239 IoctlGetVaRegions params{};
201 std::memcpy(&params, input.data(), input.size()); 240 std::memcpy(&params, input.data(), input.size());
241
202 LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr, 242 LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
203 params.buf_size); 243 params.buf_size);
204 244
@@ -210,9 +250,43 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o
210 params.regions[1].offset = 0x04000000; 250 params.regions[1].offset = 0x04000000;
211 params.regions[1].page_size = 0x10000; 251 params.regions[1].page_size = 0x10000;
212 params.regions[1].pages = 0x1bffff; 252 params.regions[1].pages = 0x1bffff;
253
213 // TODO(ogniK): This probably can stay stubbed but should add support way way later 254 // TODO(ogniK): This probably can stay stubbed but should add support way way later
255
214 std::memcpy(output.data(), &params, output.size()); 256 std::memcpy(output.data(), &params, output.size());
215 return 0; 257 return 0;
216} 258}
217 259
260std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const {
261 const auto end{buffer_mappings.upper_bound(gpu_addr)};
262 for (auto iter{buffer_mappings.begin()}; iter != end; ++iter) {
263 if (gpu_addr >= iter->second.StartAddr() && gpu_addr < iter->second.EndAddr()) {
264 return iter->second;
265 }
266 }
267
268 return {};
269}
270
271void nvhost_as_gpu::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr,
272 bool is_allocated) {
273 buffer_mappings[gpu_addr] = {gpu_addr, size, cpu_addr, is_allocated};
274}
275
276std::optional<std::size_t> nvhost_as_gpu::RemoveBufferMap(GPUVAddr gpu_addr) {
277 if (const auto iter{buffer_mappings.find(gpu_addr)}; iter != buffer_mappings.end()) {
278 std::size_t size{};
279
280 if (iter->second.IsAllocated()) {
281 size = iter->second.Size();
282 }
283
284 buffer_mappings.erase(iter);
285
286 return size;
287 }
288
289 return {};
290}
291
218} // namespace Service::Nvidia::Devices 292} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index f79fcc065..9a0cdff0c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -4,9 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <map>
7#include <memory> 8#include <memory>
8#include <unordered_map> 9#include <optional>
9#include <vector> 10#include <vector>
11
12#include "common/common_funcs.h"
10#include "common/common_types.h" 13#include "common/common_types.h"
11#include "common/swap.h" 14#include "common/swap.h"
12#include "core/hle/service/nvdrv/devices/nvdevice.h" 15#include "core/hle/service/nvdrv/devices/nvdevice.h"
@@ -15,6 +18,13 @@ namespace Service::Nvidia::Devices {
15 18
16class nvmap; 19class nvmap;
17 20
21enum class AddressSpaceFlags : u32 {
22 None = 0x0,
23 FixedOffset = 0x1,
24 Remap = 0x100,
25};
26DECLARE_ENUM_FLAG_OPERATORS(AddressSpaceFlags);
27
18class nvhost_as_gpu final : public nvdevice { 28class nvhost_as_gpu final : public nvdevice {
19public: 29public:
20 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 30 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
@@ -25,6 +35,45 @@ public:
25 IoctlVersion version) override; 35 IoctlVersion version) override;
26 36
27private: 37private:
38 class BufferMap final {
39 public:
40 constexpr BufferMap() = default;
41
42 constexpr BufferMap(GPUVAddr start_addr, std::size_t size)
43 : start_addr{start_addr}, end_addr{start_addr + size} {}
44
45 constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr,
46 bool is_allocated)
47 : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr},
48 is_allocated{is_allocated} {}
49
50 constexpr VAddr StartAddr() const {
51 return start_addr;
52 }
53
54 constexpr VAddr EndAddr() const {
55 return end_addr;
56 }
57
58 constexpr std::size_t Size() const {
59 return end_addr - start_addr;
60 }
61
62 constexpr VAddr CpuAddr() const {
63 return cpu_addr;
64 }
65
66 constexpr bool IsAllocated() const {
67 return is_allocated;
68 }
69
70 private:
71 GPUVAddr start_addr{};
72 GPUVAddr end_addr{};
73 VAddr cpu_addr{};
74 bool is_allocated{};
75 };
76
28 enum class IoctlCommand : u32_le { 77 enum class IoctlCommand : u32_le {
29 IocInitalizeExCommand = 0x40284109, 78 IocInitalizeExCommand = 0x40284109,
30 IocAllocateSpaceCommand = 0xC0184102, 79 IocAllocateSpaceCommand = 0xC0184102,
@@ -49,7 +98,7 @@ private:
49 struct IoctlAllocSpace { 98 struct IoctlAllocSpace {
50 u32_le pages; 99 u32_le pages;
51 u32_le page_size; 100 u32_le page_size;
52 u32_le flags; 101 AddressSpaceFlags flags;
53 INSERT_PADDING_WORDS(1); 102 INSERT_PADDING_WORDS(1);
54 union { 103 union {
55 u64_le offset; 104 u64_le offset;
@@ -69,18 +118,18 @@ private:
69 static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); 118 static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
70 119
71 struct IoctlMapBufferEx { 120 struct IoctlMapBufferEx {
72 u32_le flags; // bit0: fixed_offset, bit2: cacheable 121 AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable
73 u32_le kind; // -1 is default 122 u32_le kind; // -1 is default
74 u32_le nvmap_handle; 123 u32_le nvmap_handle;
75 u32_le page_size; // 0 means don't care 124 u32_le page_size; // 0 means don't care
76 u64_le buffer_offset; 125 s64_le buffer_offset;
77 u64_le mapping_size; 126 u64_le mapping_size;
78 u64_le offset; 127 s64_le offset;
79 }; 128 };
80 static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); 129 static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");
81 130
82 struct IoctlUnmapBuffer { 131 struct IoctlUnmapBuffer {
83 u64_le offset; 132 s64_le offset;
84 }; 133 };
85 static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); 134 static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size");
86 135
@@ -106,15 +155,6 @@ private:
106 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, 155 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
107 "IoctlGetVaRegions is incorrect size"); 156 "IoctlGetVaRegions is incorrect size");
108 157
109 struct BufferMapping {
110 u64 offset;
111 u64 size;
112 u32 nvmap_handle;
113 };
114
115 /// Map containing the nvmap object mappings in GPU memory.
116 std::unordered_map<u64, BufferMapping> buffer_mappings;
117
118 u32 channel{}; 158 u32 channel{};
119 159
120 u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); 160 u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
@@ -125,7 +165,14 @@ private:
125 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output); 165 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
126 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output); 166 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
127 167
168 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
169 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
170 std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
171
128 std::shared_ptr<nvmap> nvmap_dev; 172 std::shared_ptr<nvmap> nvmap_dev;
173
174 // This is expected to be ordered, therefore we must use a map, not unordered_map
175 std::map<GPUVAddr, BufferMap> buffer_mappings;
129}; 176};
130 177
131} // namespace Service::Nvidia::Devices 178} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 8c742316c..9436e16ad 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -18,7 +18,12 @@ enum {
18}; 18};
19} 19}
20 20
21nvmap::nvmap(Core::System& system) : nvdevice(system) {} 21nvmap::nvmap(Core::System& system) : nvdevice(system) {
22 // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
23 // represent this.
24 CreateObject(0);
25}
26
22nvmap::~nvmap() = default; 27nvmap::~nvmap() = default;
23 28
24VAddr nvmap::GetObjectAddress(u32 handle) const { 29VAddr nvmap::GetObjectAddress(u32 handle) const {
@@ -50,6 +55,21 @@ u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<
50 return 0; 55 return 0;
51} 56}
52 57
58u32 nvmap::CreateObject(u32 size) {
59 // Create a new nvmap object and obtain a handle to it.
60 auto object = std::make_shared<Object>();
61 object->id = next_id++;
62 object->size = size;
63 object->status = Object::Status::Created;
64 object->refcount = 1;
65
66 const u32 handle = next_handle++;
67
68 handles.insert_or_assign(handle, std::move(object));
69
70 return handle;
71}
72
53u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { 73u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
54 IocCreateParams params; 74 IocCreateParams params;
55 std::memcpy(&params, input.data(), sizeof(params)); 75 std::memcpy(&params, input.data(), sizeof(params));
@@ -59,17 +79,8 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
59 LOG_ERROR(Service_NVDRV, "Size is 0"); 79 LOG_ERROR(Service_NVDRV, "Size is 0");
60 return static_cast<u32>(NvErrCodes::InvalidValue); 80 return static_cast<u32>(NvErrCodes::InvalidValue);
61 } 81 }
62 // Create a new nvmap object and obtain a handle to it.
63 auto object = std::make_shared<Object>();
64 object->id = next_id++;
65 object->size = params.size;
66 object->status = Object::Status::Created;
67 object->refcount = 1;
68
69 u32 handle = next_handle++;
70 handles[handle] = std::move(object);
71 82
72 params.handle = handle; 83 params.handle = CreateObject(params.size);
73 84
74 std::memcpy(output.data(), &params, sizeof(params)); 85 std::memcpy(output.data(), &params, sizeof(params));
75 return 0; 86 return 0;
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 73c2e8809..84624be00 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -49,10 +49,10 @@ public:
49 49
50private: 50private:
51 /// Id to use for the next handle that is created. 51 /// Id to use for the next handle that is created.
52 u32 next_handle = 1; 52 u32 next_handle = 0;
53 53
54 /// Id to use for the next object that is created. 54 /// Id to use for the next object that is created.
55 u32 next_id = 1; 55 u32 next_id = 0;
56 56
57 /// Mapping of currently allocated handles to the objects they represent. 57 /// Mapping of currently allocated handles to the objects they represent.
58 std::unordered_map<u32, std::shared_ptr<Object>> handles; 58 std::unordered_map<u32, std::shared_ptr<Object>> handles;
@@ -119,6 +119,8 @@ private:
119 }; 119 };
120 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); 120 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
121 121
122 u32 CreateObject(u32 size);
123
122 u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); 124 u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
123 u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); 125 u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
124 u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); 126 u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index deaf0808b..88fbfa9b0 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -60,24 +60,24 @@ void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) {
60 60
61 if (ctrl.must_delay) { 61 if (ctrl.must_delay) {
62 ctrl.fresh_call = false; 62 ctrl.fresh_call = false;
63 ctx.SleepClientThread("NVServices::DelayedResponse", ctrl.timeout, 63 ctx.SleepClientThread(
64 [=](std::shared_ptr<Kernel::Thread> thread, 64 "NVServices::DelayedResponse", ctrl.timeout,
65 Kernel::HLERequestContext& ctx, 65 [=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
66 Kernel::ThreadWakeupReason reason) { 66 Kernel::ThreadWakeupReason reason) {
67 IoctlCtrl ctrl2{ctrl}; 67 IoctlCtrl ctrl2{ctrl};
68 std::vector<u8> tmp_output = output; 68 std::vector<u8> tmp_output = output;
69 std::vector<u8> tmp_output2 = output2; 69 std::vector<u8> tmp_output2 = output2;
70 u32 result = nvdrv->Ioctl(fd, command, input, input2, tmp_output, 70 const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output,
71 tmp_output2, ctrl2, version); 71 tmp_output2, ctrl2, version);
72 ctx.WriteBuffer(tmp_output, 0); 72 ctx_.WriteBuffer(tmp_output, 0);
73 if (version == IoctlVersion::Version3) { 73 if (version == IoctlVersion::Version3) {
74 ctx.WriteBuffer(tmp_output2, 1); 74 ctx_.WriteBuffer(tmp_output2, 1);
75 } 75 }
76 IPC::ResponseBuilder rb{ctx, 3}; 76 IPC::ResponseBuilder rb{ctx_, 3};
77 rb.Push(RESULT_SUCCESS); 77 rb.Push(RESULT_SUCCESS);
78 rb.Push(result); 78 rb.Push(ioctl_result);
79 }, 79 },
80 nvdrv->GetEventWriteable(ctrl.event_id)); 80 nvdrv->GetEventWriteable(ctrl.event_id));
81 } else { 81 } else {
82 ctx.WriteBuffer(output); 82 ctx.WriteBuffer(output);
83 if (version == IoctlVersion::Version3) { 83 if (version == IoctlVersion::Version3) {
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp
index 789856118..f644a460d 100644
--- a/src/core/hle/service/nvflinger/nvflinger.cpp
+++ b/src/core/hle/service/nvflinger/nvflinger.cpp
@@ -67,8 +67,8 @@ NVFlinger::NVFlinger(Core::System& system) : system(system) {
67 67
68 // Schedule the screen composition events 68 // Schedule the screen composition events
69 composition_event = Core::Timing::CreateEvent( 69 composition_event = Core::Timing::CreateEvent(
70 "ScreenComposition", [this](u64, std::chrono::nanoseconds ns_late) { 70 "ScreenComposition", [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
71 Lock(); 71 const auto guard = Lock();
72 Compose(); 72 Compose();
73 73
74 const auto ticks = std::chrono::nanoseconds{GetNextTicks()}; 74 const auto ticks = std::chrono::nanoseconds{GetNextTicks()};
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h
index e4959a9af..ff85cbba6 100644
--- a/src/core/hle/service/nvflinger/nvflinger.h
+++ b/src/core/hle/service/nvflinger/nvflinger.h
@@ -54,12 +54,12 @@ public:
54 /// Opens the specified display and returns the ID. 54 /// Opens the specified display and returns the ID.
55 /// 55 ///
56 /// If an invalid display name is provided, then an empty optional is returned. 56 /// If an invalid display name is provided, then an empty optional is returned.
57 std::optional<u64> OpenDisplay(std::string_view name); 57 [[nodiscard]] std::optional<u64> OpenDisplay(std::string_view name);
58 58
59 /// Creates a layer on the specified display and returns the layer ID. 59 /// Creates a layer on the specified display and returns the layer ID.
60 /// 60 ///
61 /// If an invalid display ID is specified, then an empty optional is returned. 61 /// If an invalid display ID is specified, then an empty optional is returned.
62 std::optional<u64> CreateLayer(u64 display_id); 62 [[nodiscard]] std::optional<u64> CreateLayer(u64 display_id);
63 63
64 /// Closes a layer on all displays for the given layer ID. 64 /// Closes a layer on all displays for the given layer ID.
65 void CloseLayer(u64 layer_id); 65 void CloseLayer(u64 layer_id);
@@ -67,41 +67,39 @@ public:
67 /// Finds the buffer queue ID of the specified layer in the specified display. 67 /// Finds the buffer queue ID of the specified layer in the specified display.
68 /// 68 ///
69 /// If an invalid display ID or layer ID is provided, then an empty optional is returned. 69 /// If an invalid display ID or layer ID is provided, then an empty optional is returned.
70 std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id) const; 70 [[nodiscard]] std::optional<u32> FindBufferQueueId(u64 display_id, u64 layer_id) const;
71 71
72 /// Gets the vsync event for the specified display. 72 /// Gets the vsync event for the specified display.
73 /// 73 ///
74 /// If an invalid display ID is provided, then nullptr is returned. 74 /// If an invalid display ID is provided, then nullptr is returned.
75 std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const; 75 [[nodiscard]] std::shared_ptr<Kernel::ReadableEvent> FindVsyncEvent(u64 display_id) const;
76 76
77 /// Obtains a buffer queue identified by the ID. 77 /// Obtains a buffer queue identified by the ID.
78 BufferQueue& FindBufferQueue(u32 id); 78 [[nodiscard]] BufferQueue& FindBufferQueue(u32 id);
79 79
80 /// Obtains a buffer queue identified by the ID. 80 /// Obtains a buffer queue identified by the ID.
81 const BufferQueue& FindBufferQueue(u32 id) const; 81 [[nodiscard]] const BufferQueue& FindBufferQueue(u32 id) const;
82 82
83 /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when 83 /// Performs a composition request to the emulated nvidia GPU and triggers the vsync events when
84 /// finished. 84 /// finished.
85 void Compose(); 85 void Compose();
86 86
87 s64 GetNextTicks() const; 87 [[nodiscard]] s64 GetNextTicks() const;
88 88
89 std::unique_lock<std::mutex> Lock() { 89 [[nodiscard]] std::unique_lock<std::mutex> Lock() const { return std::unique_lock{*guard}; }
90 return std::unique_lock{*guard};
91 }
92 90
93private: 91 private :
94 /// Finds the display identified by the specified ID. 92 /// Finds the display identified by the specified ID.
95 VI::Display* FindDisplay(u64 display_id); 93 [[nodiscard]] VI::Display* FindDisplay(u64 display_id);
96 94
97 /// Finds the display identified by the specified ID. 95 /// Finds the display identified by the specified ID.
98 const VI::Display* FindDisplay(u64 display_id) const; 96 [[nodiscard]] const VI::Display* FindDisplay(u64 display_id) const;
99 97
100 /// Finds the layer identified by the specified ID in the desired display. 98 /// Finds the layer identified by the specified ID in the desired display.
101 VI::Layer* FindLayer(u64 display_id, u64 layer_id); 99 [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id);
102 100
103 /// Finds the layer identified by the specified ID in the desired display. 101 /// Finds the layer identified by the specified ID in the desired display.
104 const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const; 102 [[nodiscard]] const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const;
105 103
106 static void VSyncThread(NVFlinger& nv_flinger); 104 static void VSyncThread(NVFlinger& nv_flinger);
107 105
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp
index 34fe2fd82..e64777668 100644
--- a/src/core/hle/service/set/set.cpp
+++ b/src/core/hle/service/set/set.cpp
@@ -106,7 +106,7 @@ void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) {
106 106
107 IPC::ResponseBuilder rb{ctx, 2}; 107 IPC::ResponseBuilder rb{ctx, 2};
108 rb.Push(RESULT_SUCCESS); 108 rb.Push(RESULT_SUCCESS);
109 ctx.WriteBuffer(&layout, sizeof(KeyboardLayout)); 109 ctx.WriteBuffer(layout);
110} 110}
111} // Anonymous namespace 111} // Anonymous namespace
112 112
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index b06d2f103..b526a94fe 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -9,6 +9,7 @@
9#include <type_traits> 9#include <type_traits>
10#include <unordered_map> 10#include <unordered_map>
11 11
12#include "common/concepts.h"
12#include "core/hle/kernel/client_port.h" 13#include "core/hle/kernel/client_port.h"
13#include "core/hle/kernel/object.h" 14#include "core/hle/kernel/object.h"
14#include "core/hle/kernel/server_port.h" 15#include "core/hle/kernel/server_port.h"
@@ -56,10 +57,8 @@ public:
56 ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name); 57 ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name);
57 ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name); 58 ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name);
58 59
59 template <typename T> 60 template <Common::IsBaseOf<Kernel::SessionRequestHandler> T>
60 std::shared_ptr<T> GetService(const std::string& service_name) const { 61 std::shared_ptr<T> GetService(const std::string& service_name) const {
61 static_assert(std::is_base_of_v<Kernel::SessionRequestHandler, T>,
62 "Not a base of ServiceFrameworkBase");
63 auto service = registered_services.find(service_name); 62 auto service = registered_services.find(service_name);
64 if (service == registered_services.end()) { 63 if (service == registered_services.end()) {
65 LOG_DEBUG(Service, "Can't find service: {}", service_name); 64 LOG_DEBUG(Service, "Can't find service: {}", service_name);
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 13e4b3818..ee4fa4b48 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -290,7 +290,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
290 290
291 IPC::ResponseBuilder rb{ctx, 2}; 291 IPC::ResponseBuilder rb{ctx, 2};
292 rb.Push(RESULT_SUCCESS); 292 rb.Push(RESULT_SUCCESS);
293 ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot)); 293 ctx.WriteBuffer(clock_snapshot);
294} 294}
295 295
296void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) { 296void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) {
@@ -313,7 +313,7 @@ void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLEReques
313 313
314 IPC::ResponseBuilder rb{ctx, 2}; 314 IPC::ResponseBuilder rb{ctx, 2};
315 rb.Push(RESULT_SUCCESS); 315 rb.Push(RESULT_SUCCESS);
316 ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot)); 316 ctx.WriteBuffer(clock_snapshot);
317} 317}
318 318
319void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser( 319void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp
index db57ae069..ff3a10b3e 100644
--- a/src/core/hle/service/time/time_zone_service.cpp
+++ b/src/core/hle/service/time/time_zone_service.cpp
@@ -142,7 +142,7 @@ void ITimeZoneService::ToPosixTime(Kernel::HLERequestContext& ctx) {
142 IPC::ResponseBuilder rb{ctx, 3}; 142 IPC::ResponseBuilder rb{ctx, 3};
143 rb.Push(RESULT_SUCCESS); 143 rb.Push(RESULT_SUCCESS);
144 rb.PushRaw<u32>(1); // Number of times we're returning 144 rb.PushRaw<u32>(1); // Number of times we're returning
145 ctx.WriteBuffer(&posix_time, sizeof(s64)); 145 ctx.WriteBuffer(posix_time);
146} 146}
147 147
148void ITimeZoneService::ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) { 148void ITimeZoneService::ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
@@ -164,7 +164,7 @@ void ITimeZoneService::ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
164 IPC::ResponseBuilder rb{ctx, 3}; 164 IPC::ResponseBuilder rb{ctx, 3};
165 rb.Push(RESULT_SUCCESS); 165 rb.Push(RESULT_SUCCESS);
166 rb.PushRaw<u32>(1); // Number of times we're returning 166 rb.PushRaw<u32>(1); // Number of times we're returning
167 ctx.WriteBuffer(&posix_time, sizeof(s64)); 167 ctx.WriteBuffer(posix_time);
168} 168}
169 169
170} // namespace Service::Time 170} // namespace Service::Time
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp
index b9dcd38e7..480d34725 100644
--- a/src/core/hle/service/vi/vi.cpp
+++ b/src/core/hle/service/vi/vi.cpp
@@ -511,7 +511,7 @@ private:
511 LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id, 511 LOG_DEBUG(Service_VI, "called. id=0x{:08X} transaction={:X}, flags=0x{:08X}", id,
512 static_cast<u32>(transaction), flags); 512 static_cast<u32>(transaction), flags);
513 513
514 nv_flinger->Lock(); 514 const auto guard = nv_flinger->Lock();
515 auto& buffer_queue = nv_flinger->FindBufferQueue(id); 515 auto& buffer_queue = nv_flinger->FindBufferQueue(id);
516 516
517 switch (transaction) { 517 switch (transaction) {
@@ -548,10 +548,10 @@ private:
548 // Wait the current thread until a buffer becomes available 548 // Wait the current thread until a buffer becomes available
549 ctx.SleepClientThread( 549 ctx.SleepClientThread(
550 "IHOSBinderDriver::DequeueBuffer", UINT64_MAX, 550 "IHOSBinderDriver::DequeueBuffer", UINT64_MAX,
551 [=](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx, 551 [=, this](std::shared_ptr<Kernel::Thread> thread,
552 Kernel::ThreadWakeupReason reason) { 552 Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) {
553 // Repeat TransactParcel DequeueBuffer when a buffer is available 553 // Repeat TransactParcel DequeueBuffer when a buffer is available
554 nv_flinger->Lock(); 554 const auto guard = nv_flinger->Lock();
555 auto& buffer_queue = nv_flinger->FindBufferQueue(id); 555 auto& buffer_queue = nv_flinger->FindBufferQueue(id);
556 auto result = buffer_queue.DequeueBuffer(width, height); 556 auto result = buffer_queue.DequeueBuffer(width, height);
557 ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer."); 557 ASSERT_MSG(result != std::nullopt, "Could not dequeue buffer.");
diff --git a/src/core/memory/cheat_engine.cpp b/src/core/memory/cheat_engine.cpp
index ced41b1fe..eeebdf02e 100644
--- a/src/core/memory/cheat_engine.cpp
+++ b/src/core/memory/cheat_engine.cpp
@@ -188,11 +188,11 @@ CheatEngine::~CheatEngine() {
188} 188}
189 189
190void CheatEngine::Initialize() { 190void CheatEngine::Initialize() {
191 event = Core::Timing::CreateEvent("CheatEngine::FrameCallback::" + 191 event = Core::Timing::CreateEvent(
192 Common::HexToString(metadata.main_nso_build_id), 192 "CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
193 [this](u64 userdata, std::chrono::nanoseconds ns_late) { 193 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
194 FrameCallback(userdata, ns_late); 194 FrameCallback(user_data, ns_late);
195 }); 195 });
196 core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event); 196 core_timing.ScheduleEvent(CHEAT_ENGINE_NS, event);
197 197
198 metadata.process_id = system.CurrentProcess()->GetProcessID(); 198 metadata.process_id = system.CurrentProcess()->GetProcessID();
@@ -219,7 +219,7 @@ void CheatEngine::Reload(std::vector<CheatEntry> cheats) {
219 219
220MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70)); 220MICROPROFILE_DEFINE(Cheat_Engine, "Add-Ons", "Cheat Engine", MP_RGB(70, 200, 70));
221 221
222void CheatEngine::FrameCallback(u64, std::chrono::nanoseconds ns_late) { 222void CheatEngine::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
223 if (is_pending_reload.exchange(false)) { 223 if (is_pending_reload.exchange(false)) {
224 vm.LoadProgram(cheats); 224 vm.LoadProgram(cheats);
225 } 225 }
diff --git a/src/core/memory/cheat_engine.h b/src/core/memory/cheat_engine.h
index d4068cf84..fa039a831 100644
--- a/src/core/memory/cheat_engine.h
+++ b/src/core/memory/cheat_engine.h
@@ -72,7 +72,7 @@ public:
72 void Reload(std::vector<CheatEntry> cheats); 72 void Reload(std::vector<CheatEntry> cheats);
73 73
74private: 74private:
75 void FrameCallback(u64 userdata, std::chrono::nanoseconds ns_late); 75 void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
76 76
77 DmntCheatVm vm; 77 DmntCheatVm vm;
78 CheatProcessMetadata metadata; 78 CheatProcessMetadata metadata;
diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp
index 2e7da23fe..48be80c12 100644
--- a/src/core/memory/dmnt_cheat_vm.cpp
+++ b/src/core/memory/dmnt_cheat_vm.cpp
@@ -313,30 +313,32 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
313 313
314 switch (opcode_type) { 314 switch (opcode_type) {
315 case CheatVmOpcodeType::StoreStatic: { 315 case CheatVmOpcodeType::StoreStatic: {
316 StoreStaticOpcode store_static{};
317 // 0TMR00AA AAAAAAAA YYYYYYYY (YYYYYYYY) 316 // 0TMR00AA AAAAAAAA YYYYYYYY (YYYYYYYY)
318 // Read additional words. 317 // Read additional words.
319 const u32 second_dword = GetNextDword(); 318 const u32 second_dword = GetNextDword();
320 store_static.bit_width = (first_dword >> 24) & 0xF; 319 const u32 bit_width = (first_dword >> 24) & 0xF;
321 store_static.mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF); 320
322 store_static.offset_register = ((first_dword >> 16) & 0xF); 321 opcode.opcode = StoreStaticOpcode{
323 store_static.rel_address = 322 .bit_width = bit_width,
324 (static_cast<u64>(first_dword & 0xFF) << 32ul) | static_cast<u64>(second_dword); 323 .mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF),
325 store_static.value = GetNextVmInt(store_static.bit_width); 324 .offset_register = (first_dword >> 16) & 0xF,
326 opcode.opcode = store_static; 325 .rel_address = (static_cast<u64>(first_dword & 0xFF) << 32) | second_dword,
326 .value = GetNextVmInt(bit_width),
327 };
327 } break; 328 } break;
328 case CheatVmOpcodeType::BeginConditionalBlock: { 329 case CheatVmOpcodeType::BeginConditionalBlock: {
329 BeginConditionalOpcode begin_cond{};
330 // 1TMC00AA AAAAAAAA YYYYYYYY (YYYYYYYY) 330 // 1TMC00AA AAAAAAAA YYYYYYYY (YYYYYYYY)
331 // Read additional words. 331 // Read additional words.
332 const u32 second_dword = GetNextDword(); 332 const u32 second_dword = GetNextDword();
333 begin_cond.bit_width = (first_dword >> 24) & 0xF; 333 const u32 bit_width = (first_dword >> 24) & 0xF;
334 begin_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF); 334
335 begin_cond.cond_type = static_cast<ConditionalComparisonType>((first_dword >> 16) & 0xF); 335 opcode.opcode = BeginConditionalOpcode{
336 begin_cond.rel_address = 336 .bit_width = bit_width,
337 (static_cast<u64>(first_dword & 0xFF) << 32ul) | static_cast<u64>(second_dword); 337 .mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF),
338 begin_cond.value = GetNextVmInt(begin_cond.bit_width); 338 .cond_type = static_cast<ConditionalComparisonType>((first_dword >> 16) & 0xF),
339 opcode.opcode = begin_cond; 339 .rel_address = (static_cast<u64>(first_dword & 0xFF) << 32) | second_dword,
340 .value = GetNextVmInt(bit_width),
341 };
340 } break; 342 } break;
341 case CheatVmOpcodeType::EndConditionalBlock: { 343 case CheatVmOpcodeType::EndConditionalBlock: {
342 // 20000000 344 // 20000000
@@ -344,12 +346,14 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
344 opcode.opcode = EndConditionalOpcode{}; 346 opcode.opcode = EndConditionalOpcode{};
345 } break; 347 } break;
346 case CheatVmOpcodeType::ControlLoop: { 348 case CheatVmOpcodeType::ControlLoop: {
347 ControlLoopOpcode ctrl_loop{};
348 // 300R0000 VVVVVVVV 349 // 300R0000 VVVVVVVV
349 // 310R0000 350 // 310R0000
350 // Parse register, whether loop start or loop end. 351 // Parse register, whether loop start or loop end.
351 ctrl_loop.start_loop = ((first_dword >> 24) & 0xF) == 0; 352 ControlLoopOpcode ctrl_loop{
352 ctrl_loop.reg_index = ((first_dword >> 20) & 0xF); 353 .start_loop = ((first_dword >> 24) & 0xF) == 0,
354 .reg_index = (first_dword >> 20) & 0xF,
355 .num_iters = 0,
356 };
353 357
354 // Read number of iters if loop start. 358 // Read number of iters if loop start.
355 if (ctrl_loop.start_loop) { 359 if (ctrl_loop.start_loop) {
@@ -358,66 +362,65 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
358 opcode.opcode = ctrl_loop; 362 opcode.opcode = ctrl_loop;
359 } break; 363 } break;
360 case CheatVmOpcodeType::LoadRegisterStatic: { 364 case CheatVmOpcodeType::LoadRegisterStatic: {
361 LoadRegisterStaticOpcode ldr_static{};
362 // 400R0000 VVVVVVVV VVVVVVVV 365 // 400R0000 VVVVVVVV VVVVVVVV
363 // Read additional words. 366 // Read additional words.
364 ldr_static.reg_index = ((first_dword >> 16) & 0xF); 367 opcode.opcode = LoadRegisterStaticOpcode{
365 ldr_static.value = 368 .reg_index = (first_dword >> 16) & 0xF,
366 (static_cast<u64>(GetNextDword()) << 32ul) | static_cast<u64>(GetNextDword()); 369 .value = (static_cast<u64>(GetNextDword()) << 32) | GetNextDword(),
367 opcode.opcode = ldr_static; 370 };
368 } break; 371 } break;
369 case CheatVmOpcodeType::LoadRegisterMemory: { 372 case CheatVmOpcodeType::LoadRegisterMemory: {
370 LoadRegisterMemoryOpcode ldr_memory{};
371 // 5TMRI0AA AAAAAAAA 373 // 5TMRI0AA AAAAAAAA
372 // Read additional words. 374 // Read additional words.
373 const u32 second_dword = GetNextDword(); 375 const u32 second_dword = GetNextDword();
374 ldr_memory.bit_width = (first_dword >> 24) & 0xF; 376 opcode.opcode = LoadRegisterMemoryOpcode{
375 ldr_memory.mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF); 377 .bit_width = (first_dword >> 24) & 0xF,
376 ldr_memory.reg_index = ((first_dword >> 16) & 0xF); 378 .mem_type = static_cast<MemoryAccessType>((first_dword >> 20) & 0xF),
377 ldr_memory.load_from_reg = ((first_dword >> 12) & 0xF) != 0; 379 .reg_index = ((first_dword >> 16) & 0xF),
378 ldr_memory.rel_address = 380 .load_from_reg = ((first_dword >> 12) & 0xF) != 0,
379 (static_cast<u64>(first_dword & 0xFF) << 32ul) | static_cast<u64>(second_dword); 381 .rel_address = (static_cast<u64>(first_dword & 0xFF) << 32) | second_dword,
380 opcode.opcode = ldr_memory; 382 };
381 } break; 383 } break;
382 case CheatVmOpcodeType::StoreStaticToAddress: { 384 case CheatVmOpcodeType::StoreStaticToAddress: {
383 StoreStaticToAddressOpcode str_static{};
384 // 6T0RIor0 VVVVVVVV VVVVVVVV 385 // 6T0RIor0 VVVVVVVV VVVVVVVV
385 // Read additional words. 386 // Read additional words.
386 str_static.bit_width = (first_dword >> 24) & 0xF; 387 opcode.opcode = StoreStaticToAddressOpcode{
387 str_static.reg_index = ((first_dword >> 16) & 0xF); 388 .bit_width = (first_dword >> 24) & 0xF,
388 str_static.increment_reg = ((first_dword >> 12) & 0xF) != 0; 389 .reg_index = (first_dword >> 16) & 0xF,
389 str_static.add_offset_reg = ((first_dword >> 8) & 0xF) != 0; 390 .increment_reg = ((first_dword >> 12) & 0xF) != 0,
390 str_static.offset_reg_index = ((first_dword >> 4) & 0xF); 391 .add_offset_reg = ((first_dword >> 8) & 0xF) != 0,
391 str_static.value = 392 .offset_reg_index = (first_dword >> 4) & 0xF,
392 (static_cast<u64>(GetNextDword()) << 32ul) | static_cast<u64>(GetNextDword()); 393 .value = (static_cast<u64>(GetNextDword()) << 32) | GetNextDword(),
393 opcode.opcode = str_static; 394 };
394 } break; 395 } break;
395 case CheatVmOpcodeType::PerformArithmeticStatic: { 396 case CheatVmOpcodeType::PerformArithmeticStatic: {
396 PerformArithmeticStaticOpcode perform_math_static{};
397 // 7T0RC000 VVVVVVVV 397 // 7T0RC000 VVVVVVVV
398 // Read additional words. 398 // Read additional words.
399 perform_math_static.bit_width = (first_dword >> 24) & 0xF; 399 opcode.opcode = PerformArithmeticStaticOpcode{
400 perform_math_static.reg_index = ((first_dword >> 16) & 0xF); 400 .bit_width = (first_dword >> 24) & 0xF,
401 perform_math_static.math_type = 401 .reg_index = ((first_dword >> 16) & 0xF),
402 static_cast<RegisterArithmeticType>((first_dword >> 12) & 0xF); 402 .math_type = static_cast<RegisterArithmeticType>((first_dword >> 12) & 0xF),
403 perform_math_static.value = GetNextDword(); 403 .value = GetNextDword(),
404 opcode.opcode = perform_math_static; 404 };
405 } break; 405 } break;
406 case CheatVmOpcodeType::BeginKeypressConditionalBlock: { 406 case CheatVmOpcodeType::BeginKeypressConditionalBlock: {
407 BeginKeypressConditionalOpcode begin_keypress_cond{};
408 // 8kkkkkkk 407 // 8kkkkkkk
409 // Just parse the mask. 408 // Just parse the mask.
410 begin_keypress_cond.key_mask = first_dword & 0x0FFFFFFF; 409 opcode.opcode = BeginKeypressConditionalOpcode{
411 opcode.opcode = begin_keypress_cond; 410 .key_mask = first_dword & 0x0FFFFFFF,
411 };
412 } break; 412 } break;
413 case CheatVmOpcodeType::PerformArithmeticRegister: { 413 case CheatVmOpcodeType::PerformArithmeticRegister: {
414 PerformArithmeticRegisterOpcode perform_math_reg{};
415 // 9TCRSIs0 (VVVVVVVV (VVVVVVVV)) 414 // 9TCRSIs0 (VVVVVVVV (VVVVVVVV))
416 perform_math_reg.bit_width = (first_dword >> 24) & 0xF; 415 PerformArithmeticRegisterOpcode perform_math_reg{
417 perform_math_reg.math_type = static_cast<RegisterArithmeticType>((first_dword >> 20) & 0xF); 416 .bit_width = (first_dword >> 24) & 0xF,
418 perform_math_reg.dst_reg_index = ((first_dword >> 16) & 0xF); 417 .math_type = static_cast<RegisterArithmeticType>((first_dword >> 20) & 0xF),
419 perform_math_reg.src_reg_1_index = ((first_dword >> 12) & 0xF); 418 .dst_reg_index = (first_dword >> 16) & 0xF,
420 perform_math_reg.has_immediate = ((first_dword >> 8) & 0xF) != 0; 419 .src_reg_1_index = (first_dword >> 12) & 0xF,
420 .src_reg_2_index = 0,
421 .has_immediate = ((first_dword >> 8) & 0xF) != 0,
422 .value = {},
423 };
421 if (perform_math_reg.has_immediate) { 424 if (perform_math_reg.has_immediate) {
422 perform_math_reg.src_reg_2_index = 0; 425 perform_math_reg.src_reg_2_index = 0;
423 perform_math_reg.value = GetNextVmInt(perform_math_reg.bit_width); 426 perform_math_reg.value = GetNextVmInt(perform_math_reg.bit_width);
@@ -427,7 +430,6 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
427 opcode.opcode = perform_math_reg; 430 opcode.opcode = perform_math_reg;
428 } break; 431 } break;
429 case CheatVmOpcodeType::StoreRegisterToAddress: { 432 case CheatVmOpcodeType::StoreRegisterToAddress: {
430 StoreRegisterToAddressOpcode str_register{};
431 // ATSRIOxa (aaaaaaaa) 433 // ATSRIOxa (aaaaaaaa)
432 // A = opcode 10 434 // A = opcode 10
433 // T = bit width 435 // T = bit width
@@ -439,20 +441,23 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
439 // Relative Address 441 // Relative Address
440 // x = offset register (for offset type 1), memory type (for offset type 3) 442 // x = offset register (for offset type 1), memory type (for offset type 3)
441 // a = relative address (for offset type 2+3) 443 // a = relative address (for offset type 2+3)
442 str_register.bit_width = (first_dword >> 24) & 0xF; 444 StoreRegisterToAddressOpcode str_register{
443 str_register.str_reg_index = ((first_dword >> 20) & 0xF); 445 .bit_width = (first_dword >> 24) & 0xF,
444 str_register.addr_reg_index = ((first_dword >> 16) & 0xF); 446 .str_reg_index = (first_dword >> 20) & 0xF,
445 str_register.increment_reg = ((first_dword >> 12) & 0xF) != 0; 447 .addr_reg_index = (first_dword >> 16) & 0xF,
446 str_register.ofs_type = static_cast<StoreRegisterOffsetType>(((first_dword >> 8) & 0xF)); 448 .increment_reg = ((first_dword >> 12) & 0xF) != 0,
447 str_register.ofs_reg_index = ((first_dword >> 4) & 0xF); 449 .ofs_type = static_cast<StoreRegisterOffsetType>(((first_dword >> 8) & 0xF)),
450 .mem_type = MemoryAccessType::MainNso,
451 .ofs_reg_index = (first_dword >> 4) & 0xF,
452 .rel_address = 0,
453 };
448 switch (str_register.ofs_type) { 454 switch (str_register.ofs_type) {
449 case StoreRegisterOffsetType::None: 455 case StoreRegisterOffsetType::None:
450 case StoreRegisterOffsetType::Reg: 456 case StoreRegisterOffsetType::Reg:
451 // Nothing more to do 457 // Nothing more to do
452 break; 458 break;
453 case StoreRegisterOffsetType::Imm: 459 case StoreRegisterOffsetType::Imm:
454 str_register.rel_address = 460 str_register.rel_address = (static_cast<u64>(first_dword & 0xF) << 32) | GetNextDword();
455 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
456 break; 461 break;
457 case StoreRegisterOffsetType::MemReg: 462 case StoreRegisterOffsetType::MemReg:
458 str_register.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF); 463 str_register.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
@@ -460,8 +465,7 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
460 case StoreRegisterOffsetType::MemImm: 465 case StoreRegisterOffsetType::MemImm:
461 case StoreRegisterOffsetType::MemImmReg: 466 case StoreRegisterOffsetType::MemImmReg:
462 str_register.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF); 467 str_register.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
463 str_register.rel_address = 468 str_register.rel_address = (static_cast<u64>(first_dword & 0xF) << 32) | GetNextDword();
464 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
465 break; 469 break;
466 default: 470 default:
467 str_register.ofs_type = StoreRegisterOffsetType::None; 471 str_register.ofs_type = StoreRegisterOffsetType::None;
@@ -470,7 +474,6 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
470 opcode.opcode = str_register; 474 opcode.opcode = str_register;
471 } break; 475 } break;
472 case CheatVmOpcodeType::BeginRegisterConditionalBlock: { 476 case CheatVmOpcodeType::BeginRegisterConditionalBlock: {
473 BeginRegisterConditionalOpcode begin_reg_cond{};
474 // C0TcSX## 477 // C0TcSX##
475 // C0TcS0Ma aaaaaaaa 478 // C0TcS0Ma aaaaaaaa
476 // C0TcS1Mr 479 // C0TcS1Mr
@@ -492,11 +495,19 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
492 // r = offset register. 495 // r = offset register.
493 // X = other register. 496 // X = other register.
494 // V = value. 497 // V = value.
495 begin_reg_cond.bit_width = (first_dword >> 20) & 0xF; 498
496 begin_reg_cond.cond_type = 499 BeginRegisterConditionalOpcode begin_reg_cond{
497 static_cast<ConditionalComparisonType>((first_dword >> 16) & 0xF); 500 .bit_width = (first_dword >> 20) & 0xF,
498 begin_reg_cond.val_reg_index = ((first_dword >> 12) & 0xF); 501 .cond_type = static_cast<ConditionalComparisonType>((first_dword >> 16) & 0xF),
499 begin_reg_cond.comp_type = static_cast<CompareRegisterValueType>((first_dword >> 8) & 0xF); 502 .val_reg_index = (first_dword >> 12) & 0xF,
503 .comp_type = static_cast<CompareRegisterValueType>((first_dword >> 8) & 0xF),
504 .mem_type = MemoryAccessType::MainNso,
505 .addr_reg_index = 0,
506 .other_reg_index = 0,
507 .ofs_reg_index = 0,
508 .rel_address = 0,
509 .value = {},
510 };
500 511
501 switch (begin_reg_cond.comp_type) { 512 switch (begin_reg_cond.comp_type) {
502 case CompareRegisterValueType::StaticValue: 513 case CompareRegisterValueType::StaticValue:
@@ -508,26 +519,25 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
508 case CompareRegisterValueType::MemoryRelAddr: 519 case CompareRegisterValueType::MemoryRelAddr:
509 begin_reg_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF); 520 begin_reg_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
510 begin_reg_cond.rel_address = 521 begin_reg_cond.rel_address =
511 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword())); 522 (static_cast<u64>(first_dword & 0xF) << 32) | GetNextDword();
512 break; 523 break;
513 case CompareRegisterValueType::MemoryOfsReg: 524 case CompareRegisterValueType::MemoryOfsReg:
514 begin_reg_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF); 525 begin_reg_cond.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
515 begin_reg_cond.ofs_reg_index = (first_dword & 0xF); 526 begin_reg_cond.ofs_reg_index = (first_dword & 0xF);
516 break; 527 break;
517 case CompareRegisterValueType::RegisterRelAddr: 528 case CompareRegisterValueType::RegisterRelAddr:
518 begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF); 529 begin_reg_cond.addr_reg_index = (first_dword >> 4) & 0xF;
519 begin_reg_cond.rel_address = 530 begin_reg_cond.rel_address =
520 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword())); 531 (static_cast<u64>(first_dword & 0xF) << 32) | GetNextDword();
521 break; 532 break;
522 case CompareRegisterValueType::RegisterOfsReg: 533 case CompareRegisterValueType::RegisterOfsReg:
523 begin_reg_cond.addr_reg_index = ((first_dword >> 4) & 0xF); 534 begin_reg_cond.addr_reg_index = (first_dword >> 4) & 0xF;
524 begin_reg_cond.ofs_reg_index = (first_dword & 0xF); 535 begin_reg_cond.ofs_reg_index = first_dword & 0xF;
525 break; 536 break;
526 } 537 }
527 opcode.opcode = begin_reg_cond; 538 opcode.opcode = begin_reg_cond;
528 } break; 539 } break;
529 case CheatVmOpcodeType::SaveRestoreRegister: { 540 case CheatVmOpcodeType::SaveRestoreRegister: {
530 SaveRestoreRegisterOpcode save_restore_reg{};
531 // C10D0Sx0 541 // C10D0Sx0
532 // C1 = opcode 0xC1 542 // C1 = opcode 0xC1
533 // D = destination index. 543 // D = destination index.
@@ -535,36 +545,37 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
535 // x = 3 if clearing reg, 2 if clearing saved value, 1 if saving a register, 0 if restoring 545 // x = 3 if clearing reg, 2 if clearing saved value, 1 if saving a register, 0 if restoring
536 // a register. 546 // a register.
537 // NOTE: If we add more save slots later, current encoding is backwards compatible. 547 // NOTE: If we add more save slots later, current encoding is backwards compatible.
538 save_restore_reg.dst_index = (first_dword >> 16) & 0xF; 548 opcode.opcode = SaveRestoreRegisterOpcode{
539 save_restore_reg.src_index = (first_dword >> 8) & 0xF; 549 .dst_index = (first_dword >> 16) & 0xF,
540 save_restore_reg.op_type = static_cast<SaveRestoreRegisterOpType>((first_dword >> 4) & 0xF); 550 .src_index = (first_dword >> 8) & 0xF,
541 opcode.opcode = save_restore_reg; 551 .op_type = static_cast<SaveRestoreRegisterOpType>((first_dword >> 4) & 0xF),
552 };
542 } break; 553 } break;
543 case CheatVmOpcodeType::SaveRestoreRegisterMask: { 554 case CheatVmOpcodeType::SaveRestoreRegisterMask: {
544 SaveRestoreRegisterMaskOpcode save_restore_regmask{};
545 // C2x0XXXX 555 // C2x0XXXX
546 // C2 = opcode 0xC2 556 // C2 = opcode 0xC2
547 // x = 3 if clearing reg, 2 if clearing saved value, 1 if saving, 0 if restoring. 557 // x = 3 if clearing reg, 2 if clearing saved value, 1 if saving, 0 if restoring.
548 // X = 16-bit bitmask, bit i --> save or restore register i. 558 // X = 16-bit bitmask, bit i --> save or restore register i.
549 save_restore_regmask.op_type = 559 SaveRestoreRegisterMaskOpcode save_restore_regmask{
550 static_cast<SaveRestoreRegisterOpType>((first_dword >> 20) & 0xF); 560 .op_type = static_cast<SaveRestoreRegisterOpType>((first_dword >> 20) & 0xF),
561 .should_operate = {},
562 };
551 for (std::size_t i = 0; i < NumRegisters; i++) { 563 for (std::size_t i = 0; i < NumRegisters; i++) {
552 save_restore_regmask.should_operate[i] = (first_dword & (1u << i)) != 0; 564 save_restore_regmask.should_operate[i] = (first_dword & (1U << i)) != 0;
553 } 565 }
554 opcode.opcode = save_restore_regmask; 566 opcode.opcode = save_restore_regmask;
555 } break; 567 } break;
556 case CheatVmOpcodeType::ReadWriteStaticRegister: { 568 case CheatVmOpcodeType::ReadWriteStaticRegister: {
557 ReadWriteStaticRegisterOpcode rw_static_reg{};
558 // C3000XXx 569 // C3000XXx
559 // C3 = opcode 0xC3. 570 // C3 = opcode 0xC3.
560 // XX = static register index. 571 // XX = static register index.
561 // x = register index. 572 // x = register index.
562 rw_static_reg.static_idx = ((first_dword >> 4) & 0xFF); 573 opcode.opcode = ReadWriteStaticRegisterOpcode{
563 rw_static_reg.idx = (first_dword & 0xF); 574 .static_idx = (first_dword >> 4) & 0xFF,
564 opcode.opcode = rw_static_reg; 575 .idx = first_dword & 0xF,
576 };
565 } break; 577 } break;
566 case CheatVmOpcodeType::DebugLog: { 578 case CheatVmOpcodeType::DebugLog: {
567 DebugLogOpcode debug_log{};
568 // FFFTIX## 579 // FFFTIX##
569 // FFFTI0Ma aaaaaaaa 580 // FFFTI0Ma aaaaaaaa
570 // FFFTI1Mr 581 // FFFTI1Mr
@@ -583,31 +594,36 @@ bool DmntCheatVm::DecodeNextOpcode(CheatVmOpcode& out) {
583 // a = relative address. 594 // a = relative address.
584 // r = offset register. 595 // r = offset register.
585 // X = value register. 596 // X = value register.
586 debug_log.bit_width = (first_dword >> 16) & 0xF; 597 DebugLogOpcode debug_log{
587 debug_log.log_id = ((first_dword >> 12) & 0xF); 598 .bit_width = (first_dword >> 16) & 0xF,
588 debug_log.val_type = static_cast<DebugLogValueType>((first_dword >> 8) & 0xF); 599 .log_id = (first_dword >> 12) & 0xF,
600 .val_type = static_cast<DebugLogValueType>((first_dword >> 8) & 0xF),
601 .mem_type = MemoryAccessType::MainNso,
602 .addr_reg_index = 0,
603 .val_reg_index = 0,
604 .ofs_reg_index = 0,
605 .rel_address = 0,
606 };
589 607
590 switch (debug_log.val_type) { 608 switch (debug_log.val_type) {
591 case DebugLogValueType::RegisterValue: 609 case DebugLogValueType::RegisterValue:
592 debug_log.val_reg_index = ((first_dword >> 4) & 0xF); 610 debug_log.val_reg_index = (first_dword >> 4) & 0xF;
593 break; 611 break;
594 case DebugLogValueType::MemoryRelAddr: 612 case DebugLogValueType::MemoryRelAddr:
595 debug_log.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF); 613 debug_log.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
596 debug_log.rel_address = 614 debug_log.rel_address = (static_cast<u64>(first_dword & 0xF) << 32) | GetNextDword();
597 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
598 break; 615 break;
599 case DebugLogValueType::MemoryOfsReg: 616 case DebugLogValueType::MemoryOfsReg:
600 debug_log.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF); 617 debug_log.mem_type = static_cast<MemoryAccessType>((first_dword >> 4) & 0xF);
601 debug_log.ofs_reg_index = (first_dword & 0xF); 618 debug_log.ofs_reg_index = first_dword & 0xF;
602 break; 619 break;
603 case DebugLogValueType::RegisterRelAddr: 620 case DebugLogValueType::RegisterRelAddr:
604 debug_log.addr_reg_index = ((first_dword >> 4) & 0xF); 621 debug_log.addr_reg_index = (first_dword >> 4) & 0xF;
605 debug_log.rel_address = 622 debug_log.rel_address = (static_cast<u64>(first_dword & 0xF) << 32) | GetNextDword();
606 ((static_cast<u64>(first_dword & 0xF) << 32ul) | static_cast<u64>(GetNextDword()));
607 break; 623 break;
608 case DebugLogValueType::RegisterOfsReg: 624 case DebugLogValueType::RegisterOfsReg:
609 debug_log.addr_reg_index = ((first_dword >> 4) & 0xF); 625 debug_log.addr_reg_index = (first_dword >> 4) & 0xF;
610 debug_log.ofs_reg_index = (first_dword & 0xF); 626 debug_log.ofs_reg_index = first_dword & 0xF;
611 break; 627 break;
612 } 628 }
613 opcode.opcode = debug_log; 629 opcode.opcode = debug_log;
diff --git a/src/core/network/network.cpp b/src/core/network/network.cpp
index fb21b0a47..56d173b5e 100644
--- a/src/core/network/network.cpp
+++ b/src/core/network/network.cpp
@@ -15,7 +15,9 @@
15#include <errno.h> 15#include <errno.h>
16#include <fcntl.h> 16#include <fcntl.h>
17#include <netdb.h> 17#include <netdb.h>
18#include <netinet/in.h>
18#include <poll.h> 19#include <poll.h>
20#include <sys/socket.h>
19#include <unistd.h> 21#include <unistd.h>
20#else 22#else
21#error "Unimplemented platform" 23#error "Unimplemented platform"
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index 29339ead7..b899ac884 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -74,15 +74,16 @@ void PerfStats::EndGameFrame() {
74 game_frames += 1; 74 game_frames += 1;
75} 75}
76 76
77double PerfStats::GetMeanFrametime() { 77double PerfStats::GetMeanFrametime() const {
78 std::lock_guard lock{object_mutex}; 78 std::lock_guard lock{object_mutex};
79 79
80 if (current_index <= IgnoreFrames) { 80 if (current_index <= IgnoreFrames) {
81 return 0; 81 return 0;
82 } 82 }
83
83 const double sum = std::accumulate(perf_history.begin() + IgnoreFrames, 84 const double sum = std::accumulate(perf_history.begin() + IgnoreFrames,
84 perf_history.begin() + current_index, 0.0); 85 perf_history.begin() + current_index, 0.0);
85 return sum / (current_index - IgnoreFrames); 86 return sum / static_cast<double>(current_index - IgnoreFrames);
86} 87}
87 88
88PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us) { 89PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us) {
@@ -94,12 +95,13 @@ PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us
94 95
95 const auto system_us_per_second = (current_system_time_us - reset_point_system_us) / interval; 96 const auto system_us_per_second = (current_system_time_us - reset_point_system_us) / interval;
96 97
97 PerfStatsResults results{}; 98 const PerfStatsResults results{
98 results.system_fps = static_cast<double>(system_frames) / interval; 99 .system_fps = static_cast<double>(system_frames) / interval,
99 results.game_fps = static_cast<double>(game_frames) / interval; 100 .game_fps = static_cast<double>(game_frames) / interval,
100 results.frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() / 101 .frametime = duration_cast<DoubleSecs>(accumulated_frametime).count() /
101 static_cast<double>(system_frames); 102 static_cast<double>(system_frames),
102 results.emulation_speed = system_us_per_second.count() / 1'000'000.0; 103 .emulation_speed = system_us_per_second.count() / 1'000'000.0,
104 };
103 105
104 // Reset counters 106 // Reset counters
105 reset_point = now; 107 reset_point = now;
@@ -111,7 +113,7 @@ PerfStatsResults PerfStats::GetAndResetStats(microseconds current_system_time_us
111 return results; 113 return results;
112} 114}
113 115
114double PerfStats::GetLastFrameTimeScale() { 116double PerfStats::GetLastFrameTimeScale() const {
115 std::lock_guard lock{object_mutex}; 117 std::lock_guard lock{object_mutex};
116 118
117 constexpr double FRAME_LENGTH = 1.0 / 60; 119 constexpr double FRAME_LENGTH = 1.0 / 60;
diff --git a/src/core/perf_stats.h b/src/core/perf_stats.h
index d9a64f072..69256b960 100644
--- a/src/core/perf_stats.h
+++ b/src/core/perf_stats.h
@@ -30,7 +30,6 @@ struct PerfStatsResults {
30class PerfStats { 30class PerfStats {
31public: 31public:
32 explicit PerfStats(u64 title_id); 32 explicit PerfStats(u64 title_id);
33
34 ~PerfStats(); 33 ~PerfStats();
35 34
36 using Clock = std::chrono::high_resolution_clock; 35 using Clock = std::chrono::high_resolution_clock;
@@ -42,18 +41,18 @@ public:
42 PerfStatsResults GetAndResetStats(std::chrono::microseconds current_system_time_us); 41 PerfStatsResults GetAndResetStats(std::chrono::microseconds current_system_time_us);
43 42
44 /** 43 /**
45 * Returns the Arthimetic Mean of all frametime values stored in the performance history. 44 * Returns the arithmetic mean of all frametime values stored in the performance history.
46 */ 45 */
47 double GetMeanFrametime(); 46 double GetMeanFrametime() const;
48 47
49 /** 48 /**
50 * Gets the ratio between walltime and the emulated time of the previous system frame. This is 49 * Gets the ratio between walltime and the emulated time of the previous system frame. This is
51 * useful for scaling inputs or outputs moving between the two time domains. 50 * useful for scaling inputs or outputs moving between the two time domains.
52 */ 51 */
53 double GetLastFrameTimeScale(); 52 double GetLastFrameTimeScale() const;
54 53
55private: 54private:
56 std::mutex object_mutex{}; 55 mutable std::mutex object_mutex;
57 56
58 /// Title ID for the game that is running. 0 if there is no game running yet 57 /// Title ID for the game that is running. 0 if there is no game running yet
59 u64 title_id{0}; 58 u64 title_id{0};
@@ -61,7 +60,7 @@ private:
61 std::size_t current_index{0}; 60 std::size_t current_index{0};
62 /// Stores an hour of historical frametime data useful for processing and tracking performance 61 /// Stores an hour of historical frametime data useful for processing and tracking performance
63 /// regressions with code changes. 62 /// regressions with code changes.
64 std::array<double, 216000> perf_history = {}; 63 std::array<double, 216000> perf_history{};
65 64
66 /// Point when the cumulative counters were reset 65 /// Point when the cumulative counters were reset
67 Clock::time_point reset_point = Clock::now(); 66 Clock::time_point reset_point = Clock::now();
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 44252dd81..416b2d866 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -173,7 +173,6 @@ void RestoreGlobalState() {
173 values.use_assembly_shaders.SetGlobal(true); 173 values.use_assembly_shaders.SetGlobal(true);
174 values.use_asynchronous_shaders.SetGlobal(true); 174 values.use_asynchronous_shaders.SetGlobal(true);
175 values.use_fast_gpu_time.SetGlobal(true); 175 values.use_fast_gpu_time.SetGlobal(true);
176 values.force_30fps_mode.SetGlobal(true);
177 values.bg_red.SetGlobal(true); 176 values.bg_red.SetGlobal(true);
178 values.bg_green.SetGlobal(true); 177 values.bg_green.SetGlobal(true);
179 values.bg_blue.SetGlobal(true); 178 values.bg_blue.SetGlobal(true);
diff --git a/src/core/settings.h b/src/core/settings.h
index 386233fdf..bb145f193 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -435,7 +435,6 @@ struct Values {
435 Setting<bool> use_vsync; 435 Setting<bool> use_vsync;
436 Setting<bool> use_assembly_shaders; 436 Setting<bool> use_assembly_shaders;
437 Setting<bool> use_asynchronous_shaders; 437 Setting<bool> use_asynchronous_shaders;
438 Setting<bool> force_30fps_mode;
439 Setting<bool> use_fast_gpu_time; 438 Setting<bool> use_fast_gpu_time;
440 439
441 Setting<float> bg_red; 440 Setting<float> bg_red;
diff --git a/src/core/tools/freezer.cpp b/src/core/tools/freezer.cpp
index 27b894b51..2003e096f 100644
--- a/src/core/tools/freezer.cpp
+++ b/src/core/tools/freezer.cpp
@@ -55,10 +55,11 @@ void MemoryWriteWidth(Core::Memory::Memory& memory, u32 width, VAddr addr, u64 v
55 55
56Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_) 56Freezer::Freezer(Core::Timing::CoreTiming& core_timing_, Core::Memory::Memory& memory_)
57 : core_timing{core_timing_}, memory{memory_} { 57 : core_timing{core_timing_}, memory{memory_} {
58 event = Core::Timing::CreateEvent("MemoryFreezer::FrameCallback", 58 event = Core::Timing::CreateEvent(
59 [this](u64 userdata, std::chrono::nanoseconds ns_late) { 59 "MemoryFreezer::FrameCallback",
60 FrameCallback(userdata, ns_late); 60 [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
61 }); 61 FrameCallback(user_data, ns_late);
62 });
62 core_timing.ScheduleEvent(memory_freezer_ns, event); 63 core_timing.ScheduleEvent(memory_freezer_ns, event);
63} 64}
64 65
@@ -159,7 +160,7 @@ std::vector<Freezer::Entry> Freezer::GetEntries() const {
159 return entries; 160 return entries;
160} 161}
161 162
162void Freezer::FrameCallback(u64, std::chrono::nanoseconds ns_late) { 163void Freezer::FrameCallback(std::uintptr_t, std::chrono::nanoseconds ns_late) {
163 if (!IsActive()) { 164 if (!IsActive()) {
164 LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events."); 165 LOG_DEBUG(Common_Memory, "Memory freezer has been deactivated, ending callback events.");
165 return; 166 return;
diff --git a/src/core/tools/freezer.h b/src/core/tools/freezer.h
index 8438783d5..2b2326bc4 100644
--- a/src/core/tools/freezer.h
+++ b/src/core/tools/freezer.h
@@ -73,7 +73,7 @@ public:
73 std::vector<Entry> GetEntries() const; 73 std::vector<Entry> GetEntries() const;
74 74
75private: 75private:
76 void FrameCallback(u64 userdata, std::chrono::nanoseconds ns_late); 76 void FrameCallback(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
77 void FillEntryReads(); 77 void FillEntryReads();
78 78
79 std::atomic_bool active{false}; 79 std::atomic_bool active{false};
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp
index 898a278a9..74759ea7d 100644
--- a/src/input_common/gcadapter/gc_adapter.cpp
+++ b/src/input_common/gcadapter/gc_adapter.cpp
@@ -24,12 +24,9 @@ Adapter::Adapter() {
24 } 24 }
25 LOG_INFO(Input, "GC Adapter Initialization started"); 25 LOG_INFO(Input, "GC Adapter Initialization started");
26 26
27 current_status = NO_ADAPTER_DETECTED;
28 get_origin.fill(true);
29
30 const int init_res = libusb_init(&libusb_ctx); 27 const int init_res = libusb_init(&libusb_ctx);
31 if (init_res == LIBUSB_SUCCESS) { 28 if (init_res == LIBUSB_SUCCESS) {
32 StartScanThread(); 29 Setup();
33 } else { 30 } else {
34 LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res); 31 LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res);
35 } 32 }
@@ -37,9 +34,9 @@ Adapter::Adapter() {
37 34
38GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) { 35GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& adapter_payload) {
39 GCPadStatus pad = {}; 36 GCPadStatus pad = {};
37 const std::size_t offset = 1 + (9 * port);
40 38
41 ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4); 39 adapter_controllers_status[port] = static_cast<ControllerTypes>(adapter_payload[offset] >> 4);
42 adapter_controllers_status[port] = type;
43 40
44 static constexpr std::array<PadButton, 8> b1_buttons{ 41 static constexpr std::array<PadButton, 8> b1_buttons{
45 PadButton::PAD_BUTTON_A, PadButton::PAD_BUTTON_B, PadButton::PAD_BUTTON_X, 42 PadButton::PAD_BUTTON_A, PadButton::PAD_BUTTON_B, PadButton::PAD_BUTTON_X,
@@ -54,14 +51,19 @@ GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& ad
54 PadButton::PAD_TRIGGER_L, 51 PadButton::PAD_TRIGGER_L,
55 }; 52 };
56 53
54 static constexpr std::array<PadAxes, 6> axes{
55 PadAxes::StickX, PadAxes::StickY, PadAxes::SubstickX,
56 PadAxes::SubstickY, PadAxes::TriggerLeft, PadAxes::TriggerRight,
57 };
58
57 if (adapter_controllers_status[port] == ControllerTypes::None && !get_origin[port]) { 59 if (adapter_controllers_status[port] == ControllerTypes::None && !get_origin[port]) {
58 // Controller may have been disconnected, recalibrate if reconnected. 60 // Controller may have been disconnected, recalibrate if reconnected.
59 get_origin[port] = true; 61 get_origin[port] = true;
60 } 62 }
61 63
62 if (adapter_controllers_status[port] != ControllerTypes::None) { 64 if (adapter_controllers_status[port] != ControllerTypes::None) {
63 const u8 b1 = adapter_payload[1 + (9 * port) + 1]; 65 const u8 b1 = adapter_payload[offset + 1];
64 const u8 b2 = adapter_payload[1 + (9 * port) + 2]; 66 const u8 b2 = adapter_payload[offset + 2];
65 67
66 for (std::size_t i = 0; i < b1_buttons.size(); ++i) { 68 for (std::size_t i = 0; i < b1_buttons.size(); ++i) {
67 if ((b1 & (1U << i)) != 0) { 69 if ((b1 & (1U << i)) != 0) {
@@ -74,21 +76,13 @@ GCPadStatus Adapter::GetPadStatus(std::size_t port, const std::array<u8, 37>& ad
74 pad.button |= static_cast<u16>(b2_buttons[j]); 76 pad.button |= static_cast<u16>(b2_buttons[j]);
75 } 77 }
76 } 78 }
77 79 for (PadAxes axis : axes) {
78 pad.stick_x = adapter_payload[1 + (9 * port) + 3]; 80 const std::size_t index = static_cast<std::size_t>(axis);
79 pad.stick_y = adapter_payload[1 + (9 * port) + 4]; 81 pad.axis_values[index] = adapter_payload[offset + 3 + index];
80 pad.substick_x = adapter_payload[1 + (9 * port) + 5]; 82 }
81 pad.substick_y = adapter_payload[1 + (9 * port) + 6];
82 pad.trigger_left = adapter_payload[1 + (9 * port) + 7];
83 pad.trigger_right = adapter_payload[1 + (9 * port) + 8];
84 83
85 if (get_origin[port]) { 84 if (get_origin[port]) {
86 origin_status[port].stick_x = pad.stick_x; 85 origin_status[port].axis_values = pad.axis_values;
87 origin_status[port].stick_y = pad.stick_y;
88 origin_status[port].substick_x = pad.substick_x;
89 origin_status[port].substick_y = pad.substick_y;
90 origin_status[port].trigger_left = pad.trigger_left;
91 origin_status[port].trigger_right = pad.trigger_right;
92 get_origin[port] = false; 86 get_origin[port] = false;
93 } 87 }
94 } 88 }
@@ -101,82 +95,47 @@ void Adapter::PadToState(const GCPadStatus& pad, GCState& state) {
101 state.buttons.insert_or_assign(button_value, pad.button & button_value); 95 state.buttons.insert_or_assign(button_value, pad.button & button_value);
102 } 96 }
103 97
104 state.axes.insert_or_assign(static_cast<u8>(PadAxes::StickX), pad.stick_x); 98 for (size_t i = 0; i < pad.axis_values.size(); ++i) {
105 state.axes.insert_or_assign(static_cast<u8>(PadAxes::StickY), pad.stick_y); 99 state.axes.insert_or_assign(static_cast<u8>(i), pad.axis_values[i]);
106 state.axes.insert_or_assign(static_cast<u8>(PadAxes::SubstickX), pad.substick_x); 100 }
107 state.axes.insert_or_assign(static_cast<u8>(PadAxes::SubstickY), pad.substick_y);
108 state.axes.insert_or_assign(static_cast<u8>(PadAxes::TriggerLeft), pad.trigger_left);
109 state.axes.insert_or_assign(static_cast<u8>(PadAxes::TriggerRight), pad.trigger_right);
110} 101}
111 102
112void Adapter::Read() { 103void Adapter::Read() {
113 LOG_DEBUG(Input, "GC Adapter Read() thread started"); 104 LOG_DEBUG(Input, "GC Adapter Read() thread started");
114 105
115 int payload_size_in, payload_size_copy; 106 int payload_size;
116 std::array<u8, 37> adapter_payload; 107 std::array<u8, 37> adapter_payload;
117 std::array<u8, 37> adapter_payload_copy;
118 std::array<GCPadStatus, 4> pads; 108 std::array<GCPadStatus, 4> pads;
119 109
120 while (adapter_thread_running) { 110 while (adapter_thread_running) {
121 libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(), 111 libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(),
122 sizeof(adapter_payload), &payload_size_in, 16); 112 sizeof(adapter_payload), &payload_size, 16);
123 payload_size_copy = 0;
124 // this mutex might be redundant?
125 {
126 std::lock_guard<std::mutex> lk(s_mutex);
127 std::copy(std::begin(adapter_payload), std::end(adapter_payload),
128 std::begin(adapter_payload_copy));
129 payload_size_copy = payload_size_in;
130 }
131 113
132 if (payload_size_copy != sizeof(adapter_payload_copy) || 114 if (payload_size != sizeof(adapter_payload) || adapter_payload[0] != LIBUSB_DT_HID) {
133 adapter_payload_copy[0] != LIBUSB_DT_HID) { 115 LOG_ERROR(Input,
134 LOG_ERROR(Input, "error reading payload (size: {}, type: {:02x})", payload_size_copy, 116 "Error reading payload (size: {}, type: {:02x}) Is the adapter connected?",
135 adapter_payload_copy[0]); 117 payload_size, adapter_payload[0]);
136 adapter_thread_running = false; // error reading from adapter, stop reading. 118 adapter_thread_running = false; // error reading from adapter, stop reading.
137 break; 119 break;
138 } 120 }
139 for (std::size_t port = 0; port < pads.size(); ++port) { 121 for (std::size_t port = 0; port < pads.size(); ++port) {
140 pads[port] = GetPadStatus(port, adapter_payload_copy); 122 pads[port] = GetPadStatus(port, adapter_payload);
141 if (DeviceConnected(port) && configuring) { 123 if (DeviceConnected(port) && configuring) {
142 if (pads[port].button != 0) { 124 if (pads[port].button != 0) {
143 pad_queue[port].Push(pads[port]); 125 pad_queue[port].Push(pads[port]);
144 } 126 }
145 127
146 // Accounting for a threshold here because of some controller variance 128 // Accounting for a threshold here to ensure an intentional press
147 if (pads[port].stick_x > origin_status[port].stick_x + pads[port].THRESHOLD || 129 for (size_t i = 0; i < pads[port].axis_values.size(); ++i) {
148 pads[port].stick_x < origin_status[port].stick_x - pads[port].THRESHOLD) { 130 const u8 value = pads[port].axis_values[i];
149 pads[port].axis = GCAdapter::PadAxes::StickX; 131 const u8 origin = origin_status[port].axis_values[i];
150 pads[port].axis_value = pads[port].stick_x; 132
151 pad_queue[port].Push(pads[port]); 133 if (value > origin + pads[port].THRESHOLD ||
152 } 134 value < origin - pads[port].THRESHOLD) {
153 if (pads[port].stick_y > origin_status[port].stick_y + pads[port].THRESHOLD || 135 pads[port].axis = static_cast<PadAxes>(i);
154 pads[port].stick_y < origin_status[port].stick_y - pads[port].THRESHOLD) { 136 pads[port].axis_value = pads[port].axis_values[i];
155 pads[port].axis = GCAdapter::PadAxes::StickY; 137 pad_queue[port].Push(pads[port]);
156 pads[port].axis_value = pads[port].stick_y; 138 }
157 pad_queue[port].Push(pads[port]);
158 }
159 if (pads[port].substick_x > origin_status[port].substick_x + pads[port].THRESHOLD ||
160 pads[port].substick_x < origin_status[port].substick_x - pads[port].THRESHOLD) {
161 pads[port].axis = GCAdapter::PadAxes::SubstickX;
162 pads[port].axis_value = pads[port].substick_x;
163 pad_queue[port].Push(pads[port]);
164 }
165 if (pads[port].substick_y > origin_status[port].substick_y + pads[port].THRESHOLD ||
166 pads[port].substick_y < origin_status[port].substick_y - pads[port].THRESHOLD) {
167 pads[port].axis = GCAdapter::PadAxes::SubstickY;
168 pads[port].axis_value = pads[port].substick_y;
169 pad_queue[port].Push(pads[port]);
170 }
171 if (pads[port].trigger_left > pads[port].TRIGGER_THRESHOLD) {
172 pads[port].axis = GCAdapter::PadAxes::TriggerLeft;
173 pads[port].axis_value = pads[port].trigger_left;
174 pad_queue[port].Push(pads[port]);
175 }
176 if (pads[port].trigger_right > pads[port].TRIGGER_THRESHOLD) {
177 pads[port].axis = GCAdapter::PadAxes::TriggerRight;
178 pads[port].axis_value = pads[port].trigger_right;
179 pad_queue[port].Push(pads[port]);
180 } 139 }
181 } 140 }
182 PadToState(pads[port], state[port]); 141 PadToState(pads[port], state[port]);
@@ -185,42 +144,11 @@ void Adapter::Read() {
185 } 144 }
186} 145}
187 146
188void Adapter::ScanThreadFunc() {
189 LOG_INFO(Input, "GC Adapter scanning thread started");
190
191 while (detect_thread_running) {
192 if (usb_adapter_handle == nullptr) {
193 std::lock_guard<std::mutex> lk(initialization_mutex);
194 Setup();
195 }
196 std::this_thread::sleep_for(std::chrono::milliseconds(500));
197 }
198}
199
200void Adapter::StartScanThread() {
201 if (detect_thread_running) {
202 return;
203 }
204 if (!libusb_ctx) {
205 return;
206 }
207
208 detect_thread_running = true;
209 detect_thread = std::thread(&Adapter::ScanThreadFunc, this);
210}
211
212void Adapter::StopScanThread() {
213 detect_thread_running = false;
214 detect_thread.join();
215}
216
217void Adapter::Setup() { 147void Adapter::Setup() {
218 // Reset the error status in case the adapter gets unplugged 148 // Initialize all controllers as unplugged
219 if (current_status < 0) {
220 current_status = NO_ADAPTER_DETECTED;
221 }
222
223 adapter_controllers_status.fill(ControllerTypes::None); 149 adapter_controllers_status.fill(ControllerTypes::None);
150 // Initialize all ports to store axis origin values
151 get_origin.fill(true);
224 152
225 // pointer to list of connected usb devices 153 // pointer to list of connected usb devices
226 libusb_device** devices{}; 154 libusb_device** devices{};
@@ -229,8 +157,6 @@ void Adapter::Setup() {
229 const ssize_t device_count = libusb_get_device_list(libusb_ctx, &devices); 157 const ssize_t device_count = libusb_get_device_list(libusb_ctx, &devices);
230 if (device_count < 0) { 158 if (device_count < 0) {
231 LOG_ERROR(Input, "libusb_get_device_list failed with error: {}", device_count); 159 LOG_ERROR(Input, "libusb_get_device_list failed with error: {}", device_count);
232 detect_thread_running = false; // Stop the loop constantly checking for gc adapter
233 // TODO: For hotplug+gc adapter checkbox implementation, revert this.
234 return; 160 return;
235 } 161 }
236 162
@@ -244,9 +170,6 @@ void Adapter::Setup() {
244 } 170 }
245 libusb_free_device_list(devices, 1); 171 libusb_free_device_list(devices, 1);
246 } 172 }
247 // Break out of the ScanThreadFunc() loop that is constantly looking for the device
248 // Assumes user has GC adapter plugged in before launch to use the adapter
249 detect_thread_running = false;
250} 173}
251 174
252bool Adapter::CheckDeviceAccess(libusb_device* device) { 175bool Adapter::CheckDeviceAccess(libusb_device* device) {
@@ -331,32 +254,23 @@ void Adapter::GetGCEndpoint(libusb_device* device) {
331 sizeof(clear_payload), nullptr, 16); 254 sizeof(clear_payload), nullptr, 16);
332 255
333 adapter_thread_running = true; 256 adapter_thread_running = true;
334 current_status = ADAPTER_DETECTED; 257 adapter_input_thread = std::thread(&Adapter::Read, this);
335 adapter_input_thread = std::thread([=] { Read(); }); // Read input
336} 258}
337 259
338Adapter::~Adapter() { 260Adapter::~Adapter() {
339 StopScanThread();
340 Reset(); 261 Reset();
341} 262}
342 263
343void Adapter::Reset() { 264void Adapter::Reset() {
344 std::unique_lock<std::mutex> lock(initialization_mutex, std::defer_lock);
345 if (!lock.try_lock()) {
346 return;
347 }
348 if (current_status != ADAPTER_DETECTED) {
349 return;
350 }
351
352 if (adapter_thread_running) { 265 if (adapter_thread_running) {
353 adapter_thread_running = false; 266 adapter_thread_running = false;
354 } 267 }
355 adapter_input_thread.join(); 268 if (adapter_input_thread.joinable()) {
269 adapter_input_thread.join();
270 }
356 271
357 adapter_controllers_status.fill(ControllerTypes::None); 272 adapter_controllers_status.fill(ControllerTypes::None);
358 get_origin.fill(true); 273 get_origin.fill(true);
359 current_status = NO_ADAPTER_DETECTED;
360 274
361 if (usb_adapter_handle) { 275 if (usb_adapter_handle) {
362 libusb_release_interface(usb_adapter_handle, 1); 276 libusb_release_interface(usb_adapter_handle, 1);
@@ -409,24 +323,7 @@ const std::array<GCState, 4>& Adapter::GetPadState() const {
409} 323}
410 324
411int Adapter::GetOriginValue(int port, int axis) const { 325int Adapter::GetOriginValue(int port, int axis) const {
412 const auto& status = origin_status[port]; 326 return origin_status[port].axis_values[axis];
413
414 switch (static_cast<PadAxes>(axis)) {
415 case PadAxes::StickX:
416 return status.stick_x;
417 case PadAxes::StickY:
418 return status.stick_y;
419 case PadAxes::SubstickX:
420 return status.substick_x;
421 case PadAxes::SubstickY:
422 return status.substick_y;
423 case PadAxes::TriggerLeft:
424 return status.trigger_left;
425 case PadAxes::TriggerRight:
426 return status.trigger_right;
427 default:
428 return 0;
429 }
430} 327}
431 328
432} // namespace GCAdapter 329} // namespace GCAdapter
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h
index 3586c8bda..bed81915c 100644
--- a/src/input_common/gcadapter/gc_adapter.h
+++ b/src/input_common/gcadapter/gc_adapter.h
@@ -47,24 +47,10 @@ enum class PadAxes : u8 {
47}; 47};
48 48
49struct GCPadStatus { 49struct GCPadStatus {
50 u16 button{}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits 50 u16 button{}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits
51 u8 stick_x{}; // 0 <= stick_x <= 255 51
52 u8 stick_y{}; // 0 <= stick_y <= 255 52 std::array<u8, 6> axis_values{}; // Triggers and sticks, following indices defined in PadAxes
53 u8 substick_x{}; // 0 <= substick_x <= 255 53 static constexpr u8 THRESHOLD = 50; // Threshold for axis press for polling
54 u8 substick_y{}; // 0 <= substick_y <= 255
55 u8 trigger_left{}; // 0 <= trigger_left <= 255
56 u8 trigger_right{}; // 0 <= trigger_right <= 255
57
58 static constexpr u8 MAIN_STICK_CENTER_X = 0x80;
59 static constexpr u8 MAIN_STICK_CENTER_Y = 0x80;
60 static constexpr u8 MAIN_STICK_RADIUS = 0x7f;
61 static constexpr u8 C_STICK_CENTER_X = 0x80;
62 static constexpr u8 C_STICK_CENTER_Y = 0x80;
63 static constexpr u8 C_STICK_RADIUS = 0x7f;
64 static constexpr u8 THRESHOLD = 10;
65
66 // 256/4, at least a quarter press to count as a press. For polling mostly
67 static constexpr u8 TRIGGER_THRESHOLD = 64;
68 54
69 u8 port{}; 55 u8 port{};
70 PadAxes axis{PadAxes::Undefined}; 56 PadAxes axis{PadAxes::Undefined};
@@ -78,11 +64,6 @@ struct GCState {
78 64
79enum class ControllerTypes { None, Wired, Wireless }; 65enum class ControllerTypes { None, Wired, Wireless };
80 66
81enum {
82 NO_ADAPTER_DETECTED = 0,
83 ADAPTER_DETECTED = 1,
84};
85
86class Adapter { 67class Adapter {
87public: 68public:
88 /// Initialize the GC Adapter capture and read sequence 69 /// Initialize the GC Adapter capture and read sequence
@@ -111,12 +92,6 @@ private:
111 void PadToState(const GCPadStatus& pad, GCState& state); 92 void PadToState(const GCPadStatus& pad, GCState& state);
112 93
113 void Read(); 94 void Read();
114 void ScanThreadFunc();
115 /// Begin scanning for the GC Adapter.
116 void StartScanThread();
117
118 /// Stop scanning for the adapter
119 void StopScanThread();
120 95
121 /// Resets status of device connected to port 96 /// Resets status of device connected to port
122 void ResetDeviceType(std::size_t port); 97 void ResetDeviceType(std::size_t port);
@@ -133,19 +108,11 @@ private:
133 /// For use in initialization, querying devices to find the adapter 108 /// For use in initialization, querying devices to find the adapter
134 void Setup(); 109 void Setup();
135 110
136 int current_status = NO_ADAPTER_DETECTED;
137 libusb_device_handle* usb_adapter_handle = nullptr; 111 libusb_device_handle* usb_adapter_handle = nullptr;
138 std::array<ControllerTypes, 4> adapter_controllers_status{};
139
140 std::mutex s_mutex;
141 112
142 std::thread adapter_input_thread; 113 std::thread adapter_input_thread;
143 bool adapter_thread_running; 114 bool adapter_thread_running;
144 115
145 std::mutex initialization_mutex;
146 std::thread detect_thread;
147 bool detect_thread_running = false;
148
149 libusb_context* libusb_ctx; 116 libusb_context* libusb_ctx;
150 117
151 u8 input_endpoint = 0; 118 u8 input_endpoint = 0;
@@ -153,10 +120,11 @@ private:
153 120
154 bool configuring = false; 121 bool configuring = false;
155 122
156 std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue;
157 std::array<GCState, 4> state; 123 std::array<GCState, 4> state;
158 std::array<bool, 4> get_origin; 124 std::array<bool, 4> get_origin;
159 std::array<GCPadStatus, 4> origin_status; 125 std::array<GCPadStatus, 4> origin_status;
126 std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue;
127 std::array<ControllerTypes, 4> adapter_controllers_status{};
160}; 128};
161 129
162} // namespace GCAdapter 130} // namespace GCAdapter
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index 96e22d3ad..f45983f3f 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -76,8 +76,7 @@ std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::Param
76 76
77 // button is not an axis/stick button 77 // button is not an axis/stick button
78 if (button_id != PAD_STICK_ID) { 78 if (button_id != PAD_STICK_ID) {
79 auto button = std::make_unique<GCButton>(port, button_id, adapter.get()); 79 return std::make_unique<GCButton>(port, button_id, adapter.get());
80 return std::move(button);
81 } 80 }
82 81
83 // For Axis buttons, used by the binary sticks. 82 // For Axis buttons, used by the binary sticks.
@@ -264,7 +263,8 @@ Common::ParamPackage GCAnalogFactory::GetNextInput() {
264 if (analog_x_axis == -1) { 263 if (analog_x_axis == -1) {
265 analog_x_axis = axis; 264 analog_x_axis = axis;
266 controller_number = static_cast<int>(port); 265 controller_number = static_cast<int>(port);
267 } else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) { 266 } else if (analog_y_axis == -1 && analog_x_axis != axis &&
267 controller_number == static_cast<int>(port)) {
268 analog_y_axis = axis; 268 analog_y_axis = axis;
269 } 269 }
270 } 270 }
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp
index e63c73c4f..6c95a8b42 100644
--- a/src/input_common/udp/client.cpp
+++ b/src/input_common/udp/client.cpp
@@ -9,7 +9,6 @@
9#include <functional> 9#include <functional>
10#include <thread> 10#include <thread>
11#include <boost/asio.hpp> 11#include <boost/asio.hpp>
12#include <boost/bind.hpp>
13#include "common/logging/log.h" 12#include "common/logging/log.h"
14#include "input_common/udp/client.h" 13#include "input_common/udp/client.h"
15#include "input_common/udp/protocol.h" 14#include "input_common/udp/protocol.h"
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp
index 244463a47..b35459152 100644
--- a/src/tests/core/core_timing.cpp
+++ b/src/tests/core/core_timing.cpp
@@ -25,10 +25,10 @@ std::bitset<CB_IDS.size()> callbacks_ran_flags;
25u64 expected_callback = 0; 25u64 expected_callback = 0;
26 26
27template <unsigned int IDX> 27template <unsigned int IDX>
28void HostCallbackTemplate(u64 userdata, std::chrono::nanoseconds ns_late) { 28void HostCallbackTemplate(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
29 static_assert(IDX < CB_IDS.size(), "IDX out of range"); 29 static_assert(IDX < CB_IDS.size(), "IDX out of range");
30 callbacks_ran_flags.set(IDX); 30 callbacks_ran_flags.set(IDX);
31 REQUIRE(CB_IDS[IDX] == userdata); 31 REQUIRE(CB_IDS[IDX] == user_data);
32 REQUIRE(CB_IDS[IDX] == CB_IDS[calls_order[expected_callback]]); 32 REQUIRE(CB_IDS[IDX] == CB_IDS[calls_order[expected_callback]]);
33 delays[IDX] = ns_late.count(); 33 delays[IDX] = ns_late.count();
34 ++expected_callback; 34 ++expected_callback;
@@ -46,20 +46,16 @@ struct ScopeInit final {
46 Core::Timing::CoreTiming core_timing; 46 Core::Timing::CoreTiming core_timing;
47}; 47};
48 48
49#pragma optimize("", off)
50
51u64 TestTimerSpeed(Core::Timing::CoreTiming& core_timing) { 49u64 TestTimerSpeed(Core::Timing::CoreTiming& core_timing) {
52 u64 start = core_timing.GetGlobalTimeNs().count(); 50 const u64 start = core_timing.GetGlobalTimeNs().count();
53 u64 placebo = 0; 51 volatile u64 placebo = 0;
54 for (std::size_t i = 0; i < 1000; i++) { 52 for (std::size_t i = 0; i < 1000; i++) {
55 placebo += core_timing.GetGlobalTimeNs().count(); 53 placebo = placebo + core_timing.GetGlobalTimeNs().count();
56 } 54 }
57 u64 end = core_timing.GetGlobalTimeNs().count(); 55 const u64 end = core_timing.GetGlobalTimeNs().count();
58 return (end - start); 56 return end - start;
59} 57}
60 58
61#pragma optimize("", on)
62
63} // Anonymous namespace 59} // Anonymous namespace
64 60
65TEST_CASE("CoreTiming[BasicOrder]", "[core]") { 61TEST_CASE("CoreTiming[BasicOrder]", "[core]") {
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index dd7ce8c99..b5dc68902 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -524,11 +524,8 @@ private:
524 void MarkRegionAsWritten(VAddr start, VAddr end) { 524 void MarkRegionAsWritten(VAddr start, VAddr end) {
525 const u64 page_end = end >> WRITE_PAGE_BIT; 525 const u64 page_end = end >> WRITE_PAGE_BIT;
526 for (u64 page_start = start >> WRITE_PAGE_BIT; page_start <= page_end; ++page_start) { 526 for (u64 page_start = start >> WRITE_PAGE_BIT; page_start <= page_end; ++page_start) {
527 auto it = written_pages.find(page_start); 527 if (const auto [it, inserted] = written_pages.emplace(page_start, 1); !inserted) {
528 if (it != written_pages.end()) { 528 ++it->second;
529 it->second = it->second + 1;
530 } else {
531 written_pages.insert_or_assign(page_start, 1);
532 } 529 }
533 } 530 }
534 } 531 }
@@ -539,7 +536,7 @@ private:
539 auto it = written_pages.find(page_start); 536 auto it = written_pages.find(page_start);
540 if (it != written_pages.end()) { 537 if (it != written_pages.end()) {
541 if (it->second > 1) { 538 if (it->second > 1) {
542 it->second = it->second - 1; 539 --it->second;
543 } else { 540 } else {
544 written_pages.erase(it); 541 written_pages.erase(it);
545 } 542 }
diff --git a/src/video_core/compatible_formats.h b/src/video_core/compatible_formats.h
index d1082566d..51766349b 100644
--- a/src/video_core/compatible_formats.h
+++ b/src/video_core/compatible_formats.h
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#pragma once
6
5#include <array> 7#include <array>
6#include <bitset> 8#include <bitset>
7#include <cstddef> 9#include <cstddef>
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp
index 8e19c3373..512578c8b 100644
--- a/src/video_core/gpu.cpp
+++ b/src/video_core/gpu.cpp
@@ -81,7 +81,7 @@ void GPU::WaitFence(u32 syncpoint_id, u32 value) {
81 } 81 }
82 MICROPROFILE_SCOPE(GPU_wait); 82 MICROPROFILE_SCOPE(GPU_wait);
83 std::unique_lock lock{sync_mutex}; 83 std::unique_lock lock{sync_mutex};
84 sync_cv.wait(lock, [=]() { return syncpoints[syncpoint_id].load() >= value; }); 84 sync_cv.wait(lock, [=, this] { return syncpoints[syncpoint_id].load() >= value; });
85} 85}
86 86
87void GPU::IncrementSyncPoint(const u32 syncpoint_id) { 87void GPU::IncrementSyncPoint(const u32 syncpoint_id) {
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h
index 19a34c402..ebfc7b0c7 100644
--- a/src/video_core/gpu.h
+++ b/src/video_core/gpu.h
@@ -252,7 +252,7 @@ public:
252 const Tegra::DmaPusher& DmaPusher() const; 252 const Tegra::DmaPusher& DmaPusher() const;
253 253
254 struct Regs { 254 struct Regs {
255 static constexpr size_t NUM_REGS = 0x100; 255 static constexpr size_t NUM_REGS = 0x40;
256 256
257 union { 257 union {
258 struct { 258 struct {
@@ -271,7 +271,7 @@ public:
271 u32 semaphore_trigger; 271 u32 semaphore_trigger;
272 INSERT_UNION_PADDING_WORDS(0xC); 272 INSERT_UNION_PADDING_WORDS(0xC);
273 273
274 // The puser and the puller share the reference counter, the pusher only has read 274 // The pusher and the puller share the reference counter, the pusher only has read
275 // access 275 // access
276 u32 reference_count; 276 u32 reference_count;
277 INSERT_UNION_PADDING_WORDS(0x5); 277 INSERT_UNION_PADDING_WORDS(0x5);
diff --git a/src/video_core/gpu_thread.cpp b/src/video_core/gpu_thread.cpp
index 738c6f0c1..bf761abf2 100644
--- a/src/video_core/gpu_thread.cpp
+++ b/src/video_core/gpu_thread.cpp
@@ -44,9 +44,9 @@ static void RunThread(Core::System& system, VideoCore::RendererBase& renderer,
44 dma_pusher.DispatchCalls(); 44 dma_pusher.DispatchCalls();
45 } else if (const auto data = std::get_if<SwapBuffersCommand>(&next.data)) { 45 } else if (const auto data = std::get_if<SwapBuffersCommand>(&next.data)) {
46 renderer.SwapBuffers(data->framebuffer ? &*data->framebuffer : nullptr); 46 renderer.SwapBuffers(data->framebuffer ? &*data->framebuffer : nullptr);
47 } else if (const auto data = std::get_if<OnCommandListEndCommand>(&next.data)) { 47 } else if (std::holds_alternative<OnCommandListEndCommand>(next.data)) {
48 renderer.Rasterizer().ReleaseFences(); 48 renderer.Rasterizer().ReleaseFences();
49 } else if (const auto data = std::get_if<GPUTickCommand>(&next.data)) { 49 } else if (std::holds_alternative<GPUTickCommand>(next.data)) {
50 system.GPU().TickWork(); 50 system.GPU().TickWork();
51 } else if (const auto data = std::get_if<FlushRegionCommand>(&next.data)) { 51 } else if (const auto data = std::get_if<FlushRegionCommand>(&next.data)) {
52 renderer.Rasterizer().FlushRegion(data->addr, data->size); 52 renderer.Rasterizer().FlushRegion(data->addr, data->size);
diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp
index 07292702f..c1b9e4ad9 100644
--- a/src/video_core/macro/macro_jit_x64.cpp
+++ b/src/video_core/macro/macro_jit_x64.cpp
@@ -419,7 +419,6 @@ void Tegra::MacroJITx64Impl::Optimizer_ScanFlags() {
419 419
420void MacroJITx64Impl::Compile() { 420void MacroJITx64Impl::Compile() {
421 MICROPROFILE_SCOPE(MacroJitCompile); 421 MICROPROFILE_SCOPE(MacroJitCompile);
422 bool keep_executing = true;
423 labels.fill(Xbyak::Label()); 422 labels.fill(Xbyak::Label());
424 423
425 Common::X64::ABI_PushRegistersAndAdjustStack(*this, Common::X64::ABI_ALL_CALLEE_SAVED, 8); 424 Common::X64::ABI_PushRegistersAndAdjustStack(*this, Common::X64::ABI_ALL_CALLEE_SAVED, 8);
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp
index ff5505d12..844164645 100644
--- a/src/video_core/memory_manager.cpp
+++ b/src/video_core/memory_manager.cpp
@@ -4,7 +4,6 @@
4 4
5#include "common/alignment.h" 5#include "common/alignment.h"
6#include "common/assert.h" 6#include "common/assert.h"
7#include "common/logging/log.h"
8#include "core/core.h" 7#include "core/core.h"
9#include "core/hle/kernel/memory/page_table.h" 8#include "core/hle/kernel/memory/page_table.h"
10#include "core/hle/kernel/process.h" 9#include "core/hle/kernel/process.h"
@@ -16,121 +15,137 @@
16namespace Tegra { 15namespace Tegra {
17 16
18MemoryManager::MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer) 17MemoryManager::MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer)
19 : rasterizer{rasterizer}, system{system} { 18 : system{system}, rasterizer{rasterizer}, page_table(page_table_size) {}
20 page_table.Resize(address_space_width, page_bits, false);
21
22 // Initialize the map with a single free region covering the entire managed space.
23 VirtualMemoryArea initial_vma;
24 initial_vma.size = address_space_end;
25 vma_map.emplace(initial_vma.base, initial_vma);
26
27 UpdatePageTableForVMA(initial_vma);
28}
29 19
30MemoryManager::~MemoryManager() = default; 20MemoryManager::~MemoryManager() = default;
31 21
32GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { 22GPUVAddr MemoryManager::UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size) {
33 const u64 aligned_size{Common::AlignUp(size, page_size)}; 23 u64 remaining_size{size};
34 const GPUVAddr gpu_addr{FindFreeRegion(address_space_base, aligned_size)}; 24 for (u64 offset{}; offset < size; offset += page_size) {
35 25 if (remaining_size < page_size) {
36 AllocateMemory(gpu_addr, 0, aligned_size); 26 SetPageEntry(gpu_addr + offset, page_entry + offset, remaining_size);
37 27 } else {
28 SetPageEntry(gpu_addr + offset, page_entry + offset);
29 }
30 remaining_size -= page_size;
31 }
38 return gpu_addr; 32 return gpu_addr;
39} 33}
40 34
41GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) { 35GPUVAddr MemoryManager::Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size) {
42 const u64 aligned_size{Common::AlignUp(size, page_size)}; 36 return UpdateRange(gpu_addr, cpu_addr, size);
43 37}
44 AllocateMemory(gpu_addr, 0, aligned_size);
45 38
46 return gpu_addr; 39GPUVAddr MemoryManager::MapAllocate(VAddr cpu_addr, std::size_t size, std::size_t align) {
40 return Map(cpu_addr, *FindFreeRange(size, align), size);
47} 41}
48 42
49GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) { 43void MemoryManager::Unmap(GPUVAddr gpu_addr, std::size_t size) {
50 const u64 aligned_size{Common::AlignUp(size, page_size)}; 44 if (!size) {
51 const GPUVAddr gpu_addr{FindFreeRegion(address_space_base, aligned_size)}; 45 return;
46 }
52 47
53 MapBackingMemory(gpu_addr, system.Memory().GetPointer(cpu_addr), aligned_size, cpu_addr); 48 // Flush and invalidate through the GPU interface, to be asynchronous if possible.
54 ASSERT( 49 system.GPU().FlushAndInvalidateRegion(*GpuToCpuAddress(gpu_addr), size);
55 system.CurrentProcess()->PageTable().LockForDeviceAddressSpace(cpu_addr, size).IsSuccess());
56 50
57 return gpu_addr; 51 UpdateRange(gpu_addr, PageEntry::State::Unmapped, size);
58} 52}
59 53
60GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) { 54std::optional<GPUVAddr> MemoryManager::AllocateFixed(GPUVAddr gpu_addr, std::size_t size) {
61 ASSERT((gpu_addr & page_mask) == 0); 55 for (u64 offset{}; offset < size; offset += page_size) {
56 if (!GetPageEntry(gpu_addr + offset).IsUnmapped()) {
57 return {};
58 }
59 }
62 60
63 const u64 aligned_size{Common::AlignUp(size, page_size)}; 61 return UpdateRange(gpu_addr, PageEntry::State::Allocated, size);
62}
64 63
65 MapBackingMemory(gpu_addr, system.Memory().GetPointer(cpu_addr), aligned_size, cpu_addr); 64GPUVAddr MemoryManager::Allocate(std::size_t size, std::size_t align) {
66 ASSERT( 65 return *AllocateFixed(*FindFreeRange(size, align), size);
67 system.CurrentProcess()->PageTable().LockForDeviceAddressSpace(cpu_addr, size).IsSuccess());
68 return gpu_addr;
69} 66}
70 67
71GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) { 68void MemoryManager::TryLockPage(PageEntry page_entry, std::size_t size) {
72 ASSERT((gpu_addr & page_mask) == 0); 69 if (!page_entry.IsValid()) {
70 return;
71 }
73 72
74 const u64 aligned_size{Common::AlignUp(size, page_size)}; 73 ASSERT(system.CurrentProcess()
75 const auto cpu_addr = GpuToCpuAddress(gpu_addr); 74 ->PageTable()
76 ASSERT(cpu_addr); 75 .LockForDeviceAddressSpace(page_entry.ToAddress(), size)
76 .IsSuccess());
77}
77 78
78 // Flush and invalidate through the GPU interface, to be asynchronous if possible. 79void MemoryManager::TryUnlockPage(PageEntry page_entry, std::size_t size) {
79 system.GPU().FlushAndInvalidateRegion(*cpu_addr, aligned_size); 80 if (!page_entry.IsValid()) {
81 return;
82 }
80 83
81 UnmapRange(gpu_addr, aligned_size);
82 ASSERT(system.CurrentProcess() 84 ASSERT(system.CurrentProcess()
83 ->PageTable() 85 ->PageTable()
84 .UnlockForDeviceAddressSpace(cpu_addr.value(), size) 86 .UnlockForDeviceAddressSpace(page_entry.ToAddress(), size)
85 .IsSuccess()); 87 .IsSuccess());
86
87 return gpu_addr;
88} 88}
89 89
90GPUVAddr MemoryManager::FindFreeRegion(GPUVAddr region_start, u64 size) const { 90PageEntry MemoryManager::GetPageEntry(GPUVAddr gpu_addr) const {
91 // Find the first Free VMA. 91 return page_table[PageEntryIndex(gpu_addr)];
92 const VMAHandle vma_handle{ 92}
93 std::find_if(vma_map.begin(), vma_map.end(), [region_start, size](const auto& vma) {
94 if (vma.second.type != VirtualMemoryArea::Type::Unmapped) {
95 return false;
96 }
97 93
98 const VAddr vma_end{vma.second.base + vma.second.size}; 94void MemoryManager::SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size) {
99 return vma_end > region_start && vma_end >= region_start + size; 95 // TODO(bunnei): We should lock/unlock device regions. This currently causes issues due to
100 })}; 96 // improper tracking, but should be fixed in the future.
101 97
102 if (vma_handle == vma_map.end()) { 98 //// Unlock the old page
103 return {}; 99 // TryUnlockPage(page_table[PageEntryIndex(gpu_addr)], size);
104 }
105 100
106 return std::max(region_start, vma_handle->second.base); 101 //// Lock the new page
107} 102 // TryLockPage(page_entry, size);
108 103
109bool MemoryManager::IsAddressValid(GPUVAddr addr) const { 104 page_table[PageEntryIndex(gpu_addr)] = page_entry;
110 return (addr >> page_bits) < page_table.pointers.size();
111} 105}
112 106
113std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr addr) const { 107std::optional<GPUVAddr> MemoryManager::FindFreeRange(std::size_t size, std::size_t align) const {
114 if (!IsAddressValid(addr)) { 108 if (!align) {
115 return {}; 109 align = page_size;
110 } else {
111 align = Common::AlignUp(align, page_size);
116 } 112 }
117 113
118 const VAddr cpu_addr{page_table.backing_addr[addr >> page_bits]}; 114 u64 available_size{};
119 if (cpu_addr) { 115 GPUVAddr gpu_addr{address_space_start};
120 return cpu_addr + (addr & page_mask); 116 while (gpu_addr + available_size < address_space_size) {
117 if (GetPageEntry(gpu_addr + available_size).IsUnmapped()) {
118 available_size += page_size;
119
120 if (available_size >= size) {
121 return gpu_addr;
122 }
123 } else {
124 gpu_addr += available_size + page_size;
125 available_size = 0;
126
127 const auto remainder{gpu_addr % align};
128 if (remainder) {
129 gpu_addr = (gpu_addr - remainder) + align;
130 }
131 }
121 } 132 }
122 133
123 return {}; 134 return {};
124} 135}
125 136
126template <typename T> 137std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) const {
127T MemoryManager::Read(GPUVAddr addr) const { 138 const auto page_entry{GetPageEntry(gpu_addr)};
128 if (!IsAddressValid(addr)) { 139 if (!page_entry.IsValid()) {
129 return {}; 140 return {};
130 } 141 }
131 142
132 const u8* page_pointer{GetPointer(addr)}; 143 return page_entry.ToAddress() + (gpu_addr & page_mask);
133 if (page_pointer) { 144}
145
146template <typename T>
147T MemoryManager::Read(GPUVAddr addr) const {
148 if (auto page_pointer{GetPointer(addr)}; page_pointer) {
134 // NOTE: Avoid adding any extra logic to this fast-path block 149 // NOTE: Avoid adding any extra logic to this fast-path block
135 T value; 150 T value;
136 std::memcpy(&value, page_pointer, sizeof(T)); 151 std::memcpy(&value, page_pointer, sizeof(T));
@@ -144,12 +159,7 @@ T MemoryManager::Read(GPUVAddr addr) const {
144 159
145template <typename T> 160template <typename T>
146void MemoryManager::Write(GPUVAddr addr, T data) { 161void MemoryManager::Write(GPUVAddr addr, T data) {
147 if (!IsAddressValid(addr)) { 162 if (auto page_pointer{GetPointer(addr)}; page_pointer) {
148 return;
149 }
150
151 u8* page_pointer{GetPointer(addr)};
152 if (page_pointer) {
153 // NOTE: Avoid adding any extra logic to this fast-path block 163 // NOTE: Avoid adding any extra logic to this fast-path block
154 std::memcpy(page_pointer, &data, sizeof(T)); 164 std::memcpy(page_pointer, &data, sizeof(T));
155 return; 165 return;
@@ -167,66 +177,49 @@ template void MemoryManager::Write<u16>(GPUVAddr addr, u16 data);
167template void MemoryManager::Write<u32>(GPUVAddr addr, u32 data); 177template void MemoryManager::Write<u32>(GPUVAddr addr, u32 data);
168template void MemoryManager::Write<u64>(GPUVAddr addr, u64 data); 178template void MemoryManager::Write<u64>(GPUVAddr addr, u64 data);
169 179
170u8* MemoryManager::GetPointer(GPUVAddr addr) { 180u8* MemoryManager::GetPointer(GPUVAddr gpu_addr) {
171 if (!IsAddressValid(addr)) { 181 if (!GetPageEntry(gpu_addr).IsValid()) {
172 return {}; 182 return {};
173 } 183 }
174 184
175 auto& memory = system.Memory(); 185 const auto address{GpuToCpuAddress(gpu_addr)};
176 186 if (!address) {
177 const VAddr page_addr{page_table.backing_addr[addr >> page_bits]}; 187 return {};
178
179 if (page_addr != 0) {
180 return memory.GetPointer(page_addr + (addr & page_mask));
181 } 188 }
182 189
183 LOG_ERROR(HW_GPU, "Unknown GetPointer @ 0x{:016X}", addr); 190 return system.Memory().GetPointer(*address);
184 return {};
185} 191}
186 192
187const u8* MemoryManager::GetPointer(GPUVAddr addr) const { 193const u8* MemoryManager::GetPointer(GPUVAddr gpu_addr) const {
188 if (!IsAddressValid(addr)) { 194 if (!GetPageEntry(gpu_addr).IsValid()) {
189 return {}; 195 return {};
190 } 196 }
191 197
192 const auto& memory = system.Memory(); 198 const auto address{GpuToCpuAddress(gpu_addr)};
193 199 if (!address) {
194 const VAddr page_addr{page_table.backing_addr[addr >> page_bits]}; 200 return {};
195
196 if (page_addr != 0) {
197 return memory.GetPointer(page_addr + (addr & page_mask));
198 } 201 }
199 202
200 LOG_ERROR(HW_GPU, "Unknown GetPointer @ 0x{:016X}", addr); 203 return system.Memory().GetPointer(*address);
201 return {};
202}
203
204bool MemoryManager::IsBlockContinuous(const GPUVAddr start, const std::size_t size) const {
205 const std::size_t inner_size = size - 1;
206 const GPUVAddr end = start + inner_size;
207 const auto host_ptr_start = reinterpret_cast<std::uintptr_t>(GetPointer(start));
208 const auto host_ptr_end = reinterpret_cast<std::uintptr_t>(GetPointer(end));
209 const auto range = static_cast<std::size_t>(host_ptr_end - host_ptr_start);
210 return range == inner_size;
211} 204}
212 205
213void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, 206void MemoryManager::ReadBlock(GPUVAddr gpu_src_addr, void* dest_buffer, std::size_t size) const {
214 const std::size_t size) const {
215 std::size_t remaining_size{size}; 207 std::size_t remaining_size{size};
216 std::size_t page_index{gpu_src_addr >> page_bits}; 208 std::size_t page_index{gpu_src_addr >> page_bits};
217 std::size_t page_offset{gpu_src_addr & page_mask}; 209 std::size_t page_offset{gpu_src_addr & page_mask};
218 210
219 auto& memory = system.Memory();
220
221 while (remaining_size > 0) { 211 while (remaining_size > 0) {
222 const std::size_t copy_amount{ 212 const std::size_t copy_amount{
223 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)}; 213 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
224 214
225 const VAddr src_addr{page_table.backing_addr[page_index] + page_offset}; 215 if (const auto page_addr{GpuToCpuAddress(page_index << page_bits)}; page_addr) {
226 // Flush must happen on the rasterizer interface, such that memory is always synchronous 216 const auto src_addr{*page_addr + page_offset};
227 // when it is read (even when in asynchronous GPU mode). Fixes Dead Cells title menu. 217
228 rasterizer.FlushRegion(src_addr, copy_amount); 218 // Flush must happen on the rasterizer interface, such that memory is always synchronous
229 memory.ReadBlockUnsafe(src_addr, dest_buffer, copy_amount); 219 // when it is read (even when in asynchronous GPU mode). Fixes Dead Cells title menu.
220 rasterizer.FlushRegion(src_addr, copy_amount);
221 system.Memory().ReadBlockUnsafe(src_addr, dest_buffer, copy_amount);
222 }
230 223
231 page_index++; 224 page_index++;
232 page_offset = 0; 225 page_offset = 0;
@@ -241,18 +234,17 @@ void MemoryManager::ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer,
241 std::size_t page_index{gpu_src_addr >> page_bits}; 234 std::size_t page_index{gpu_src_addr >> page_bits};
242 std::size_t page_offset{gpu_src_addr & page_mask}; 235 std::size_t page_offset{gpu_src_addr & page_mask};
243 236
244 auto& memory = system.Memory();
245
246 while (remaining_size > 0) { 237 while (remaining_size > 0) {
247 const std::size_t copy_amount{ 238 const std::size_t copy_amount{
248 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)}; 239 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
249 const u8* page_pointer = page_table.pointers[page_index]; 240
250 if (page_pointer) { 241 if (const auto page_addr{GpuToCpuAddress(page_index << page_bits)}; page_addr) {
251 const VAddr src_addr{page_table.backing_addr[page_index] + page_offset}; 242 const auto src_addr{*page_addr + page_offset};
252 memory.ReadBlockUnsafe(src_addr, dest_buffer, copy_amount); 243 system.Memory().ReadBlockUnsafe(src_addr, dest_buffer, copy_amount);
253 } else { 244 } else {
254 std::memset(dest_buffer, 0, copy_amount); 245 std::memset(dest_buffer, 0, copy_amount);
255 } 246 }
247
256 page_index++; 248 page_index++;
257 page_offset = 0; 249 page_offset = 0;
258 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount; 250 dest_buffer = static_cast<u8*>(dest_buffer) + copy_amount;
@@ -260,23 +252,23 @@ void MemoryManager::ReadBlockUnsafe(GPUVAddr gpu_src_addr, void* dest_buffer,
260 } 252 }
261} 253}
262 254
263void MemoryManager::WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, 255void MemoryManager::WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer, std::size_t size) {
264 const std::size_t size) {
265 std::size_t remaining_size{size}; 256 std::size_t remaining_size{size};
266 std::size_t page_index{gpu_dest_addr >> page_bits}; 257 std::size_t page_index{gpu_dest_addr >> page_bits};
267 std::size_t page_offset{gpu_dest_addr & page_mask}; 258 std::size_t page_offset{gpu_dest_addr & page_mask};
268 259
269 auto& memory = system.Memory();
270
271 while (remaining_size > 0) { 260 while (remaining_size > 0) {
272 const std::size_t copy_amount{ 261 const std::size_t copy_amount{
273 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)}; 262 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
274 263
275 const VAddr dest_addr{page_table.backing_addr[page_index] + page_offset}; 264 if (const auto page_addr{GpuToCpuAddress(page_index << page_bits)}; page_addr) {
276 // Invalidate must happen on the rasterizer interface, such that memory is always 265 const auto dest_addr{*page_addr + page_offset};
277 // synchronous when it is written (even when in asynchronous GPU mode). 266
278 rasterizer.InvalidateRegion(dest_addr, copy_amount); 267 // Invalidate must happen on the rasterizer interface, such that memory is always
279 memory.WriteBlockUnsafe(dest_addr, src_buffer, copy_amount); 268 // synchronous when it is written (even when in asynchronous GPU mode).
269 rasterizer.InvalidateRegion(dest_addr, copy_amount);
270 system.Memory().WriteBlockUnsafe(dest_addr, src_buffer, copy_amount);
271 }
280 272
281 page_index++; 273 page_index++;
282 page_offset = 0; 274 page_offset = 0;
@@ -286,21 +278,20 @@ void MemoryManager::WriteBlock(GPUVAddr gpu_dest_addr, const void* src_buffer,
286} 278}
287 279
288void MemoryManager::WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer, 280void MemoryManager::WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buffer,
289 const std::size_t size) { 281 std::size_t size) {
290 std::size_t remaining_size{size}; 282 std::size_t remaining_size{size};
291 std::size_t page_index{gpu_dest_addr >> page_bits}; 283 std::size_t page_index{gpu_dest_addr >> page_bits};
292 std::size_t page_offset{gpu_dest_addr & page_mask}; 284 std::size_t page_offset{gpu_dest_addr & page_mask};
293 285
294 auto& memory = system.Memory();
295
296 while (remaining_size > 0) { 286 while (remaining_size > 0) {
297 const std::size_t copy_amount{ 287 const std::size_t copy_amount{
298 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)}; 288 std::min(static_cast<std::size_t>(page_size) - page_offset, remaining_size)};
299 u8* page_pointer = page_table.pointers[page_index]; 289
300 if (page_pointer) { 290 if (const auto page_addr{GpuToCpuAddress(page_index << page_bits)}; page_addr) {
301 const VAddr dest_addr{page_table.backing_addr[page_index] + page_offset}; 291 const auto dest_addr{*page_addr + page_offset};
302 memory.WriteBlockUnsafe(dest_addr, src_buffer, copy_amount); 292 system.Memory().WriteBlockUnsafe(dest_addr, src_buffer, copy_amount);
303 } 293 }
294
304 page_index++; 295 page_index++;
305 page_offset = 0; 296 page_offset = 0;
306 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount; 297 src_buffer = static_cast<const u8*>(src_buffer) + copy_amount;
@@ -308,273 +299,26 @@ void MemoryManager::WriteBlockUnsafe(GPUVAddr gpu_dest_addr, const void* src_buf
308 } 299 }
309} 300}
310 301
311void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, 302void MemoryManager::CopyBlock(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size) {
312 const std::size_t size) {
313 std::vector<u8> tmp_buffer(size); 303 std::vector<u8> tmp_buffer(size);
314 ReadBlock(gpu_src_addr, tmp_buffer.data(), size); 304 ReadBlock(gpu_src_addr, tmp_buffer.data(), size);
315 WriteBlock(gpu_dest_addr, tmp_buffer.data(), size); 305 WriteBlock(gpu_dest_addr, tmp_buffer.data(), size);
316} 306}
317 307
318void MemoryManager::CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, 308void MemoryManager::CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr,
319 const std::size_t size) { 309 std::size_t size) {
320 std::vector<u8> tmp_buffer(size); 310 std::vector<u8> tmp_buffer(size);
321 ReadBlockUnsafe(gpu_src_addr, tmp_buffer.data(), size); 311 ReadBlockUnsafe(gpu_src_addr, tmp_buffer.data(), size);
322 WriteBlockUnsafe(gpu_dest_addr, tmp_buffer.data(), size); 312 WriteBlockUnsafe(gpu_dest_addr, tmp_buffer.data(), size);
323} 313}
324 314
325bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) { 315bool MemoryManager::IsGranularRange(GPUVAddr gpu_addr, std::size_t size) {
326 const VAddr addr = page_table.backing_addr[gpu_addr >> page_bits]; 316 const auto cpu_addr{GpuToCpuAddress(gpu_addr)};
327 const std::size_t page = (addr & Core::Memory::PAGE_MASK) + size; 317 if (!cpu_addr) {
328 return page <= Core::Memory::PAGE_SIZE;
329}
330
331void MemoryManager::MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type,
332 VAddr backing_addr) {
333 LOG_DEBUG(HW_GPU, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * page_size,
334 (base + size) * page_size);
335
336 const VAddr end{base + size};
337 ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}",
338 base + page_table.pointers.size());
339
340 if (memory == nullptr) {
341 while (base != end) {
342 page_table.pointers[base] = nullptr;
343 page_table.backing_addr[base] = 0;
344
345 base += 1;
346 }
347 } else {
348 while (base != end) {
349 page_table.pointers[base] = memory;
350 page_table.backing_addr[base] = backing_addr;
351
352 base += 1;
353 memory += page_size;
354 backing_addr += page_size;
355 }
356 }
357}
358
359void MemoryManager::MapMemoryRegion(GPUVAddr base, u64 size, u8* target, VAddr backing_addr) {
360 ASSERT_MSG((size & page_mask) == 0, "non-page aligned size: {:016X}", size);
361 ASSERT_MSG((base & page_mask) == 0, "non-page aligned base: {:016X}", base);
362 MapPages(base / page_size, size / page_size, target, Common::PageType::Memory, backing_addr);
363}
364
365void MemoryManager::UnmapRegion(GPUVAddr base, u64 size) {
366 ASSERT_MSG((size & page_mask) == 0, "non-page aligned size: {:016X}", size);
367 ASSERT_MSG((base & page_mask) == 0, "non-page aligned base: {:016X}", base);
368 MapPages(base / page_size, size / page_size, nullptr, Common::PageType::Unmapped);
369}
370
371bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
372 ASSERT(base + size == next.base);
373 if (type != next.type) {
374 return {};
375 }
376 if (type == VirtualMemoryArea::Type::Allocated && (offset + size != next.offset)) {
377 return {};
378 }
379 if (type == VirtualMemoryArea::Type::Mapped && backing_memory + size != next.backing_memory) {
380 return {};
381 }
382 return true;
383}
384
385MemoryManager::VMAHandle MemoryManager::FindVMA(GPUVAddr target) const {
386 if (target >= address_space_end) {
387 return vma_map.end();
388 } else {
389 return std::prev(vma_map.upper_bound(target));
390 }
391}
392
393MemoryManager::VMAIter MemoryManager::Allocate(VMAIter vma_handle) {
394 VirtualMemoryArea& vma{vma_handle->second};
395
396 vma.type = VirtualMemoryArea::Type::Allocated;
397 vma.backing_addr = 0;
398 vma.backing_memory = {};
399 UpdatePageTableForVMA(vma);
400
401 return MergeAdjacent(vma_handle);
402}
403
404MemoryManager::VMAHandle MemoryManager::AllocateMemory(GPUVAddr target, std::size_t offset,
405 u64 size) {
406
407 // This is the appropriately sized VMA that will turn into our allocation.
408 VMAIter vma_handle{CarveVMA(target, size)};
409 VirtualMemoryArea& vma{vma_handle->second};
410
411 ASSERT(vma.size == size);
412
413 vma.offset = offset;
414
415 return Allocate(vma_handle);
416}
417
418MemoryManager::VMAHandle MemoryManager::MapBackingMemory(GPUVAddr target, u8* memory, u64 size,
419 VAddr backing_addr) {
420 // This is the appropriately sized VMA that will turn into our allocation.
421 VMAIter vma_handle{CarveVMA(target, size)};
422 VirtualMemoryArea& vma{vma_handle->second};
423
424 ASSERT(vma.size == size);
425
426 vma.type = VirtualMemoryArea::Type::Mapped;
427 vma.backing_memory = memory;
428 vma.backing_addr = backing_addr;
429 UpdatePageTableForVMA(vma);
430
431 return MergeAdjacent(vma_handle);
432}
433
434void MemoryManager::UnmapRange(GPUVAddr target, u64 size) {
435 VMAIter vma{CarveVMARange(target, size)};
436 const VAddr target_end{target + size};
437 const VMAIter end{vma_map.end()};
438
439 // The comparison against the end of the range must be done using addresses since VMAs can be
440 // merged during this process, causing invalidation of the iterators.
441 while (vma != end && vma->second.base < target_end) {
442 // Unmapped ranges return to allocated state and can be reused
443 // This behavior is used by Super Mario Odyssey, Sonic Forces, and likely other games
444 vma = std::next(Allocate(vma));
445 }
446
447 ASSERT(FindVMA(target)->second.size >= size);
448}
449
450MemoryManager::VMAIter MemoryManager::StripIterConstness(const VMAHandle& iter) {
451 // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given
452 // non-const access to its container.
453 return vma_map.erase(iter, iter); // Erases an empty range of elements
454}
455
456MemoryManager::VMAIter MemoryManager::CarveVMA(GPUVAddr base, u64 size) {
457 ASSERT_MSG((size & page_mask) == 0, "non-page aligned size: 0x{:016X}", size);
458 ASSERT_MSG((base & page_mask) == 0, "non-page aligned base: 0x{:016X}", base);
459
460 VMAIter vma_handle{StripIterConstness(FindVMA(base))};
461 if (vma_handle == vma_map.end()) {
462 // Target address is outside the managed range
463 return {};
464 }
465
466 const VirtualMemoryArea& vma{vma_handle->second};
467 if (vma.type == VirtualMemoryArea::Type::Mapped) {
468 // Region is already allocated
469 return vma_handle;
470 }
471
472 const VAddr start_in_vma{base - vma.base};
473 const VAddr end_in_vma{start_in_vma + size};
474
475 ASSERT_MSG(end_in_vma <= vma.size, "region size 0x{:016X} is less than required size 0x{:016X}",
476 vma.size, end_in_vma);
477
478 if (end_in_vma < vma.size) {
479 // Split VMA at the end of the allocated region
480 SplitVMA(vma_handle, end_in_vma);
481 }
482 if (start_in_vma != 0) {
483 // Split VMA at the start of the allocated region
484 vma_handle = SplitVMA(vma_handle, start_in_vma);
485 }
486
487 return vma_handle;
488}
489
490MemoryManager::VMAIter MemoryManager::CarveVMARange(GPUVAddr target, u64 size) {
491 ASSERT_MSG((size & page_mask) == 0, "non-page aligned size: 0x{:016X}", size);
492 ASSERT_MSG((target & page_mask) == 0, "non-page aligned base: 0x{:016X}", target);
493
494 const VAddr target_end{target + size};
495 ASSERT(target_end >= target);
496 ASSERT(size > 0);
497
498 VMAIter begin_vma{StripIterConstness(FindVMA(target))};
499 const VMAIter i_end{vma_map.lower_bound(target_end)};
500 if (std::any_of(begin_vma, i_end, [](const auto& entry) {
501 return entry.second.type == VirtualMemoryArea::Type::Unmapped;
502 })) {
503 return {}; 318 return {};
504 } 319 }
505 320 const std::size_t page{(*cpu_addr & Core::Memory::PAGE_MASK) + size};
506 if (target != begin_vma->second.base) { 321 return page <= Core::Memory::PAGE_SIZE;
507 begin_vma = SplitVMA(begin_vma, target - begin_vma->second.base);
508 }
509
510 VMAIter end_vma{StripIterConstness(FindVMA(target_end))};
511 if (end_vma != vma_map.end() && target_end != end_vma->second.base) {
512 end_vma = SplitVMA(end_vma, target_end - end_vma->second.base);
513 }
514
515 return begin_vma;
516}
517
518MemoryManager::VMAIter MemoryManager::SplitVMA(VMAIter vma_handle, u64 offset_in_vma) {
519 VirtualMemoryArea& old_vma{vma_handle->second};
520 VirtualMemoryArea new_vma{old_vma}; // Make a copy of the VMA
521
522 // For now, don't allow no-op VMA splits (trying to split at a boundary) because it's probably
523 // a bug. This restriction might be removed later.
524 ASSERT(offset_in_vma < old_vma.size);
525 ASSERT(offset_in_vma > 0);
526
527 old_vma.size = offset_in_vma;
528 new_vma.base += offset_in_vma;
529 new_vma.size -= offset_in_vma;
530
531 switch (new_vma.type) {
532 case VirtualMemoryArea::Type::Unmapped:
533 break;
534 case VirtualMemoryArea::Type::Allocated:
535 new_vma.offset += offset_in_vma;
536 break;
537 case VirtualMemoryArea::Type::Mapped:
538 new_vma.backing_memory += offset_in_vma;
539 break;
540 }
541
542 ASSERT(old_vma.CanBeMergedWith(new_vma));
543
544 return vma_map.emplace_hint(std::next(vma_handle), new_vma.base, new_vma);
545}
546
547MemoryManager::VMAIter MemoryManager::MergeAdjacent(VMAIter iter) {
548 const VMAIter next_vma{std::next(iter)};
549 if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) {
550 iter->second.size += next_vma->second.size;
551 vma_map.erase(next_vma);
552 }
553
554 if (iter != vma_map.begin()) {
555 VMAIter prev_vma{std::prev(iter)};
556 if (prev_vma->second.CanBeMergedWith(iter->second)) {
557 prev_vma->second.size += iter->second.size;
558 vma_map.erase(iter);
559 iter = prev_vma;
560 }
561 }
562
563 return iter;
564}
565
566void MemoryManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
567 switch (vma.type) {
568 case VirtualMemoryArea::Type::Unmapped:
569 UnmapRegion(vma.base, vma.size);
570 break;
571 case VirtualMemoryArea::Type::Allocated:
572 MapMemoryRegion(vma.base, vma.size, nullptr, vma.backing_addr);
573 break;
574 case VirtualMemoryArea::Type::Mapped:
575 MapMemoryRegion(vma.base, vma.size, vma.backing_memory, vma.backing_addr);
576 break;
577 }
578} 322}
579 323
580} // namespace Tegra 324} // namespace Tegra
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h
index 87658e87a..681bd9588 100644
--- a/src/video_core/memory_manager.h
+++ b/src/video_core/memory_manager.h
@@ -6,9 +6,9 @@
6 6
7#include <map> 7#include <map>
8#include <optional> 8#include <optional>
9#include <vector>
9 10
10#include "common/common_types.h" 11#include "common/common_types.h"
11#include "common/page_table.h"
12 12
13namespace VideoCore { 13namespace VideoCore {
14class RasterizerInterface; 14class RasterizerInterface;
@@ -20,45 +20,57 @@ class System;
20 20
21namespace Tegra { 21namespace Tegra {
22 22
23/** 23class PageEntry final {
24 * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space 24public:
25 * with homogeneous attributes across its extents. In this particular implementation each VMA is 25 enum class State : u32 {
26 * also backed by a single host memory allocation. 26 Unmapped = static_cast<u32>(-1),
27 */ 27 Allocated = static_cast<u32>(-2),
28struct VirtualMemoryArea {
29 enum class Type : u8 {
30 Unmapped,
31 Allocated,
32 Mapped,
33 }; 28 };
34 29
35 /// Virtual base address of the region. 30 constexpr PageEntry() = default;
36 GPUVAddr base{}; 31 constexpr PageEntry(State state) : state{state} {}
37 /// Size of the region. 32 constexpr PageEntry(VAddr addr) : state{static_cast<State>(addr >> ShiftBits)} {}
38 u64 size{}; 33
39 /// Memory area mapping type. 34 constexpr bool IsUnmapped() const {
40 Type type{Type::Unmapped}; 35 return state == State::Unmapped;
41 /// CPU memory mapped address corresponding to this memory area. 36 }
42 VAddr backing_addr{}; 37
43 /// Offset into the backing_memory the mapping starts from. 38 constexpr bool IsAllocated() const {
44 std::size_t offset{}; 39 return state == State::Allocated;
45 /// Pointer backing this VMA. 40 }
46 u8* backing_memory{}; 41
47 42 constexpr bool IsValid() const {
48 /// Tests if this area can be merged to the right with `next`. 43 return !IsUnmapped() && !IsAllocated();
49 bool CanBeMergedWith(const VirtualMemoryArea& next) const; 44 }
45
46 constexpr VAddr ToAddress() const {
47 if (!IsValid()) {
48 return {};
49 }
50
51 return static_cast<VAddr>(state) << ShiftBits;
52 }
53
54 constexpr PageEntry operator+(u64 offset) {
55 // If this is a reserved value, offsets do not apply
56 if (!IsValid()) {
57 return *this;
58 }
59 return PageEntry{(static_cast<VAddr>(state) << ShiftBits) + offset};
60 }
61
62private:
63 static constexpr std::size_t ShiftBits{12};
64
65 State state{State::Unmapped};
50}; 66};
67static_assert(sizeof(PageEntry) == 4, "PageEntry is too large");
51 68
52class MemoryManager final { 69class MemoryManager final {
53public: 70public:
54 explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer); 71 explicit MemoryManager(Core::System& system, VideoCore::RasterizerInterface& rasterizer);
55 ~MemoryManager(); 72 ~MemoryManager();
56 73
57 GPUVAddr AllocateSpace(u64 size, u64 align);
58 GPUVAddr AllocateSpace(GPUVAddr addr, u64 size, u64 align);
59 GPUVAddr MapBufferEx(VAddr cpu_addr, u64 size);
60 GPUVAddr MapBufferEx(VAddr cpu_addr, GPUVAddr addr, u64 size);
61 GPUVAddr UnmapBuffer(GPUVAddr addr, u64 size);
62 std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const; 74 std::optional<VAddr> GpuToCpuAddress(GPUVAddr addr) const;
63 75
64 template <typename T> 76 template <typename T>
@@ -70,9 +82,6 @@ public:
70 u8* GetPointer(GPUVAddr addr); 82 u8* GetPointer(GPUVAddr addr);
71 const u8* GetPointer(GPUVAddr addr) const; 83 const u8* GetPointer(GPUVAddr addr) const;
72 84
73 /// Returns true if the block is continuous in host memory, false otherwise
74 bool IsBlockContinuous(GPUVAddr start, std::size_t size) const;
75
76 /** 85 /**
77 * ReadBlock and WriteBlock are full read and write operations over virtual 86 * ReadBlock and WriteBlock are full read and write operations over virtual
78 * GPU Memory. It's important to use these when GPU memory may not be continuous 87 * GPU Memory. It's important to use these when GPU memory may not be continuous
@@ -98,92 +107,43 @@ public:
98 void CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size); 107 void CopyBlockUnsafe(GPUVAddr gpu_dest_addr, GPUVAddr gpu_src_addr, std::size_t size);
99 108
100 /** 109 /**
101 * IsGranularRange checks if a gpu region can be simply read with a pointer 110 * IsGranularRange checks if a gpu region can be simply read with a pointer.
102 */ 111 */
103 bool IsGranularRange(GPUVAddr gpu_addr, std::size_t size); 112 bool IsGranularRange(GPUVAddr gpu_addr, std::size_t size);
104 113
105private: 114 GPUVAddr Map(VAddr cpu_addr, GPUVAddr gpu_addr, std::size_t size);
106 using VMAMap = std::map<GPUVAddr, VirtualMemoryArea>; 115 GPUVAddr MapAllocate(VAddr cpu_addr, std::size_t size, std::size_t align);
107 using VMAHandle = VMAMap::const_iterator; 116 std::optional<GPUVAddr> AllocateFixed(GPUVAddr gpu_addr, std::size_t size);
108 using VMAIter = VMAMap::iterator; 117 GPUVAddr Allocate(std::size_t size, std::size_t align);
109 118 void Unmap(GPUVAddr gpu_addr, std::size_t size);
110 bool IsAddressValid(GPUVAddr addr) const;
111 void MapPages(GPUVAddr base, u64 size, u8* memory, Common::PageType type,
112 VAddr backing_addr = 0);
113 void MapMemoryRegion(GPUVAddr base, u64 size, u8* target, VAddr backing_addr);
114 void UnmapRegion(GPUVAddr base, u64 size);
115
116 /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
117 VMAHandle FindVMA(GPUVAddr target) const;
118
119 VMAHandle AllocateMemory(GPUVAddr target, std::size_t offset, u64 size);
120
121 /**
122 * Maps an unmanaged host memory pointer at a given address.
123 *
124 * @param target The guest address to start the mapping at.
125 * @param memory The memory to be mapped.
126 * @param size Size of the mapping in bytes.
127 * @param backing_addr The base address of the range to back this mapping.
128 */
129 VMAHandle MapBackingMemory(GPUVAddr target, u8* memory, u64 size, VAddr backing_addr);
130
131 /// Unmaps a range of addresses, splitting VMAs as necessary.
132 void UnmapRange(GPUVAddr target, u64 size);
133
134 /// Converts a VMAHandle to a mutable VMAIter.
135 VMAIter StripIterConstness(const VMAHandle& iter);
136
137 /// Marks as the specified VMA as allocated.
138 VMAIter Allocate(VMAIter vma);
139
140 /**
141 * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
142 * the appropriate error checking.
143 */
144 VMAIter CarveVMA(GPUVAddr base, u64 size);
145
146 /**
147 * Splits the edges of the given range of non-Free VMAs so that there is a VMA split at each
148 * end of the range.
149 */
150 VMAIter CarveVMARange(GPUVAddr base, u64 size);
151
152 /**
153 * Splits a VMA in two, at the specified offset.
154 * @returns the right side of the split, with the original iterator becoming the left side.
155 */
156 VMAIter SplitVMA(VMAIter vma, u64 offset_in_vma);
157 119
158 /** 120private:
159 * Checks for and merges the specified VMA with adjacent ones if possible. 121 PageEntry GetPageEntry(GPUVAddr gpu_addr) const;
160 * @returns the merged VMA or the original if no merging was possible. 122 void SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size = page_size);
161 */ 123 GPUVAddr UpdateRange(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size);
162 VMAIter MergeAdjacent(VMAIter vma); 124 std::optional<GPUVAddr> FindFreeRange(std::size_t size, std::size_t align) const;
163 125
164 /// Updates the pages corresponding to this VMA so they match the VMA's attributes. 126 void TryLockPage(PageEntry page_entry, std::size_t size);
165 void UpdatePageTableForVMA(const VirtualMemoryArea& vma); 127 void TryUnlockPage(PageEntry page_entry, std::size_t size);
166 128
167 /// Finds a free (unmapped region) of the specified size starting at the specified address. 129 static constexpr std::size_t PageEntryIndex(GPUVAddr gpu_addr) {
168 GPUVAddr FindFreeRegion(GPUVAddr region_start, u64 size) const; 130 return (gpu_addr >> page_bits) & page_table_mask;
131 }
169 132
170private: 133 static constexpr u64 address_space_size = 1ULL << 40;
134 static constexpr u64 address_space_start = 1ULL << 32;
171 static constexpr u64 page_bits{16}; 135 static constexpr u64 page_bits{16};
172 static constexpr u64 page_size{1 << page_bits}; 136 static constexpr u64 page_size{1 << page_bits};
173 static constexpr u64 page_mask{page_size - 1}; 137 static constexpr u64 page_mask{page_size - 1};
138 static constexpr u64 page_table_bits{24};
139 static constexpr u64 page_table_size{1 << page_table_bits};
140 static constexpr u64 page_table_mask{page_table_size - 1};
174 141
175 /// Address space in bits, according to Tegra X1 TRM 142 Core::System& system;
176 static constexpr u32 address_space_width{40};
177 /// Start address for mapping, this is fairly arbitrary but must be non-zero.
178 static constexpr GPUVAddr address_space_base{0x100000};
179 /// End of address space, based on address space in bits.
180 static constexpr GPUVAddr address_space_end{1ULL << address_space_width};
181 143
182 Common::PageTable page_table;
183 VMAMap vma_map;
184 VideoCore::RasterizerInterface& rasterizer; 144 VideoCore::RasterizerInterface& rasterizer;
185 145
186 Core::System& system; 146 std::vector<PageEntry> page_table;
187}; 147};
188 148
189} // namespace Tegra 149} // namespace Tegra
diff --git a/src/video_core/renderer_opengl/gl_arb_decompiler.cpp b/src/video_core/renderer_opengl/gl_arb_decompiler.cpp
index 3b61c9e21..b7e9ed2e9 100644
--- a/src/video_core/renderer_opengl/gl_arb_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_arb_decompiler.cpp
@@ -1291,13 +1291,6 @@ std::string ARBDecompiler::Visit(const Node& node) {
1291 return "{0, 0, 0, 0}.x"; 1291 return "{0, 0, 0, 0}.x";
1292 } 1292 }
1293 1293
1294 const auto buffer_index = [this, &abuf]() -> std::string {
1295 if (stage != ShaderType::Geometry) {
1296 return "";
1297 }
1298 return fmt::format("[{}]", Visit(abuf->GetBuffer()));
1299 };
1300
1301 const Attribute::Index index = abuf->GetIndex(); 1294 const Attribute::Index index = abuf->GetIndex();
1302 const u32 element = abuf->GetElement(); 1295 const u32 element = abuf->GetElement();
1303 const char swizzle = Swizzle(element); 1296 const char swizzle = Swizzle(element);
@@ -1403,7 +1396,7 @@ std::string ARBDecompiler::Visit(const Node& node) {
1403 return {}; 1396 return {};
1404 } 1397 }
1405 1398
1406 if (const auto cmt = std::get_if<CommentNode>(&*node)) { 1399 if ([[maybe_unused]] const auto cmt = std::get_if<CommentNode>(&*node)) {
1407 // Uncommenting this will generate invalid code. GLASM lacks comments. 1400 // Uncommenting this will generate invalid code. GLASM lacks comments.
1408 // AddLine("// {}", cmt->GetText()); 1401 // AddLine("// {}", cmt->GetText());
1409 return {}; 1402 return {};
@@ -1711,7 +1704,7 @@ std::string ARBDecompiler::HCastFloat(Operation operation) {
1711} 1704}
1712 1705
1713std::string ARBDecompiler::HUnpack(Operation operation) { 1706std::string ARBDecompiler::HUnpack(Operation operation) {
1714 const std::string operand = Visit(operation[0]); 1707 std::string operand = Visit(operation[0]);
1715 switch (std::get<Tegra::Shader::HalfType>(operation.GetMeta())) { 1708 switch (std::get<Tegra::Shader::HalfType>(operation.GetMeta())) {
1716 case Tegra::Shader::HalfType::H0_H1: 1709 case Tegra::Shader::HalfType::H0_H1:
1717 return operand; 1710 return operand;
@@ -2061,7 +2054,7 @@ std::string ARBDecompiler::InvocationId(Operation) {
2061 2054
2062std::string ARBDecompiler::YNegate(Operation) { 2055std::string ARBDecompiler::YNegate(Operation) {
2063 LOG_WARNING(Render_OpenGL, "(STUBBED)"); 2056 LOG_WARNING(Render_OpenGL, "(STUBBED)");
2064 const std::string temporary = AllocTemporary(); 2057 std::string temporary = AllocTemporary();
2065 AddLine("MOV.F {}, 1;", temporary); 2058 AddLine("MOV.F {}, 1;", temporary);
2066 return temporary; 2059 return temporary;
2067} 2060}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 03e82c599..cb284db77 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -178,16 +178,11 @@ RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWind
178 178
179 if (device.UseAsynchronousShaders()) { 179 if (device.UseAsynchronousShaders()) {
180 // Max worker threads we should allow 180 // Max worker threads we should allow
181 constexpr auto MAX_THREADS = 2u; 181 constexpr u32 MAX_THREADS = 4;
182 // Amount of threads we should reserve for other parts of yuzu 182 // Deduce how many threads we can use
183 constexpr auto RESERVED_THREADS = 6u; 183 const u32 threads_used = std::thread::hardware_concurrency() / 4;
184 // Get the amount of threads we can use(this can return zero)
185 const auto cpu_thread_count =
186 std::max(RESERVED_THREADS, std::thread::hardware_concurrency());
187 // Deduce how many "extra" threads we have to use.
188 const auto max_threads_unused = cpu_thread_count - RESERVED_THREADS;
189 // Always allow at least 1 thread regardless of our settings 184 // Always allow at least 1 thread regardless of our settings
190 const auto max_worker_count = std::max(1u, max_threads_unused); 185 const auto max_worker_count = std::max(1U, threads_used);
191 // Don't use more than MAX_THREADS 186 // Don't use more than MAX_THREADS
192 const auto worker_count = std::min(max_worker_count, MAX_THREADS); 187 const auto worker_count = std::min(max_worker_count, MAX_THREADS);
193 async_shaders.AllocateWorkers(worker_count); 188 async_shaders.AllocateWorkers(worker_count);
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index f469ed656..be71e1733 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -126,7 +126,7 @@ std::shared_ptr<Registry> MakeRegistry(const ShaderDiskCacheEntry& entry) {
126 const VideoCore::GuestDriverProfile guest_profile{entry.texture_handler_size}; 126 const VideoCore::GuestDriverProfile guest_profile{entry.texture_handler_size};
127 const VideoCommon::Shader::SerializedRegistryInfo info{guest_profile, entry.bound_buffer, 127 const VideoCommon::Shader::SerializedRegistryInfo info{guest_profile, entry.bound_buffer,
128 entry.graphics_info, entry.compute_info}; 128 entry.graphics_info, entry.compute_info};
129 const auto registry = std::make_shared<Registry>(entry.type, info); 129 auto registry = std::make_shared<Registry>(entry.type, info);
130 for (const auto& [address, value] : entry.keys) { 130 for (const auto& [address, value] : entry.keys) {
131 const auto [buffer, offset] = address; 131 const auto [buffer, offset] = address;
132 registry->InsertKey(buffer, offset, value); 132 registry->InsertKey(buffer, offset, value);
@@ -237,7 +237,6 @@ std::unique_ptr<Shader> Shader::CreateStageFromMemory(
237 const ShaderParameters& params, Maxwell::ShaderProgram program_type, ProgramCode code, 237 const ShaderParameters& params, Maxwell::ShaderProgram program_type, ProgramCode code,
238 ProgramCode code_b, VideoCommon::Shader::AsyncShaders& async_shaders, VAddr cpu_addr) { 238 ProgramCode code_b, VideoCommon::Shader::AsyncShaders& async_shaders, VAddr cpu_addr) {
239 const auto shader_type = GetShaderType(program_type); 239 const auto shader_type = GetShaderType(program_type);
240 const std::size_t size_in_bytes = code.size() * sizeof(u64);
241 240
242 auto& gpu = params.system.GPU(); 241 auto& gpu = params.system.GPU();
243 gpu.ShaderNotify().MarkSharderBuilding(); 242 gpu.ShaderNotify().MarkSharderBuilding();
@@ -287,8 +286,6 @@ std::unique_ptr<Shader> Shader::CreateStageFromMemory(
287 286
288std::unique_ptr<Shader> Shader::CreateKernelFromMemory(const ShaderParameters& params, 287std::unique_ptr<Shader> Shader::CreateKernelFromMemory(const ShaderParameters& params,
289 ProgramCode code) { 288 ProgramCode code) {
290 const std::size_t size_in_bytes = code.size() * sizeof(u64);
291
292 auto& gpu = params.system.GPU(); 289 auto& gpu = params.system.GPU();
293 gpu.ShaderNotify().MarkSharderBuilding(); 290 gpu.ShaderNotify().MarkSharderBuilding();
294 291
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 6a9602ff8..3f75fcd2b 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -1919,7 +1919,7 @@ private:
1919 Expression Comparison(Operation operation) { 1919 Expression Comparison(Operation operation) {
1920 static_assert(!unordered || type == Type::Float); 1920 static_assert(!unordered || type == Type::Float);
1921 1921
1922 const Expression expr = GenerateBinaryInfix(operation, op, Type::Bool, type, type); 1922 Expression expr = GenerateBinaryInfix(operation, op, Type::Bool, type, type);
1923 1923
1924 if constexpr (op.compare("!=") == 0 && type == Type::Float && !unordered) { 1924 if constexpr (op.compare("!=") == 0 && type == Type::Float && !unordered) {
1925 // GLSL's operator!=(float, float) doesn't seem be ordered. This happens on both AMD's 1925 // GLSL's operator!=(float, float) doesn't seem be ordered. This happens on both AMD's
@@ -1959,10 +1959,6 @@ private:
1959 return {fmt::format("({} != 0)", carry), Type::Bool}; 1959 return {fmt::format("({} != 0)", carry), Type::Bool};
1960 } 1960 }
1961 1961
1962 Expression LogicalFIsNan(Operation operation) {
1963 return GenerateUnary(operation, "isnan", Type::Bool, Type::Float);
1964 }
1965
1966 Expression LogicalAssign(Operation operation) { 1962 Expression LogicalAssign(Operation operation) {
1967 const Node& dest = operation[0]; 1963 const Node& dest = operation[0];
1968 const Node& src = operation[1]; 1964 const Node& src = operation[1];
@@ -2778,15 +2774,6 @@ private:
2778 return std::min<u32>(device.GetMaxVaryings(), Maxwell::NumVaryings); 2774 return std::min<u32>(device.GetMaxVaryings(), Maxwell::NumVaryings);
2779 } 2775 }
2780 2776
2781 bool IsRenderTargetEnabled(u32 render_target) const {
2782 for (u32 component = 0; component < 4; ++component) {
2783 if (header.ps.IsColorComponentOutputEnabled(render_target, component)) {
2784 return true;
2785 }
2786 }
2787 return false;
2788 }
2789
2790 const Device& device; 2777 const Device& device;
2791 const ShaderIR& ir; 2778 const ShaderIR& ir;
2792 const Registry& registry; 2779 const Registry& registry;
diff --git a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
index d1f0ea932..81a39a3b8 100644
--- a/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
+++ b/src/video_core/renderer_vulkan/fixed_pipeline_state.cpp
@@ -40,7 +40,6 @@ constexpr std::array POLYGON_OFFSET_ENABLE_LUT = {
40} // Anonymous namespace 40} // Anonymous namespace
41 41
42void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_state) { 42void FixedPipelineState::Fill(const Maxwell& regs, bool has_extended_dynamic_state) {
43 const auto& clip = regs.view_volume_clip_control;
44 const std::array enabled_lut = {regs.polygon_offset_point_enable, 43 const std::array enabled_lut = {regs.polygon_offset_point_enable,
45 regs.polygon_offset_line_enable, 44 regs.polygon_offset_line_enable,
46 regs.polygon_offset_fill_enable}; 45 regs.polygon_offset_fill_enable};
diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
index ce53e5a6b..a551e3de8 100644
--- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp
+++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp
@@ -696,6 +696,7 @@ void VKBlitScreen::CreateFramebuffers() {
696 .flags = 0, 696 .flags = 0,
697 .renderPass = *renderpass, 697 .renderPass = *renderpass,
698 .attachmentCount = 1, 698 .attachmentCount = 1,
699 .pAttachments = nullptr,
699 .width = size.width, 700 .width = size.width,
700 .height = size.height, 701 .height = size.height,
701 .layers = 1, 702 .layers = 1,
diff --git a/src/video_core/renderer_vulkan/vk_device.cpp b/src/video_core/renderer_vulkan/vk_device.cpp
index 6245e0d78..0c03e4d83 100644
--- a/src/video_core/renderer_vulkan/vk_device.cpp
+++ b/src/video_core/renderer_vulkan/vk_device.cpp
@@ -771,8 +771,9 @@ std::vector<VkDeviceQueueCreateInfo> VKDevice::GetDeviceQueueCreateInfos() const
771 .pNext = nullptr, 771 .pNext = nullptr,
772 .flags = 0, 772 .flags = 0,
773 .queueFamilyIndex = queue_family, 773 .queueFamilyIndex = queue_family,
774 .queueCount = 1,
775 .pQueuePriorities = nullptr,
774 }); 776 });
775 ci.queueCount = 1;
776 ci.pQueuePriorities = &QUEUE_PRIORITY; 777 ci.pQueuePriorities = &QUEUE_PRIORITY;
777 } 778 }
778 779
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
index 42b3a744c..418c62bc4 100644
--- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp
@@ -261,8 +261,13 @@ VKComputePipeline& VKPipelineCache::GetComputePipeline(const ComputePipelineCach
261 } 261 }
262 262
263 const Specialization specialization{ 263 const Specialization specialization{
264 .base_binding = 0,
264 .workgroup_size = key.workgroup_size, 265 .workgroup_size = key.workgroup_size,
265 .shared_memory_size = key.shared_memory_size, 266 .shared_memory_size = key.shared_memory_size,
267 .point_size = std::nullopt,
268 .enabled_attributes = {},
269 .attribute_types = {},
270 .ndc_minus_one_to_one = false,
266 }; 271 };
267 const SPIRVShader spirv_shader{Decompile(device, shader->GetIR(), ShaderType::Compute, 272 const SPIRVShader spirv_shader{Decompile(device, shader->GetIR(), ShaderType::Compute,
268 shader->GetRegistry(), specialization), 273 shader->GetRegistry(), specialization),
diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
index 31e44aa2b..7500e8244 100644
--- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp
+++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp
@@ -532,10 +532,6 @@ void RasterizerVulkan::Clear() {
532 532
533 scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil, 533 scheduler.Record([clear_depth = regs.clear_depth, clear_stencil = regs.clear_stencil,
534 clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) { 534 clear_rect, aspect_flags](vk::CommandBuffer cmdbuf) {
535 VkClearValue clear_value;
536 clear_value.depthStencil.depth = clear_depth;
537 clear_value.depthStencil.stencil = clear_stencil;
538
539 VkClearAttachment attachment; 535 VkClearAttachment attachment;
540 attachment.aspectMask = aspect_flags; 536 attachment.aspectMask = aspect_flags;
541 attachment.colorAttachment = 0; 537 attachment.colorAttachment = 0;
@@ -819,8 +815,13 @@ bool RasterizerVulkan::WalkAttachmentOverlaps(const CachedSurfaceView& attachmen
819 815
820std::tuple<VkFramebuffer, VkExtent2D> RasterizerVulkan::ConfigureFramebuffers( 816std::tuple<VkFramebuffer, VkExtent2D> RasterizerVulkan::ConfigureFramebuffers(
821 VkRenderPass renderpass) { 817 VkRenderPass renderpass) {
822 FramebufferCacheKey key{renderpass, std::numeric_limits<u32>::max(), 818 FramebufferCacheKey key{
823 std::numeric_limits<u32>::max(), std::numeric_limits<u32>::max()}; 819 .renderpass = renderpass,
820 .width = std::numeric_limits<u32>::max(),
821 .height = std::numeric_limits<u32>::max(),
822 .layers = std::numeric_limits<u32>::max(),
823 .views = {},
824 };
824 825
825 const auto try_push = [&key](const View& view) { 826 const auto try_push = [&key](const View& view) {
826 if (!view) { 827 if (!view) {
diff --git a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp b/src/video_core/renderer_vulkan/vk_sampler_cache.cpp
index 2d5460776..b068888f9 100644
--- a/src/video_core/renderer_vulkan/vk_sampler_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_sampler_cache.cpp
@@ -47,6 +47,7 @@ vk::Sampler VKSamplerCache::CreateSampler(const Tegra::Texture::TSCEntry& tsc) c
47 VkSamplerCustomBorderColorCreateInfoEXT border{ 47 VkSamplerCustomBorderColorCreateInfoEXT border{
48 .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT, 48 .sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
49 .pNext = nullptr, 49 .pNext = nullptr,
50 .customBorderColor = {},
50 .format = VK_FORMAT_UNDEFINED, 51 .format = VK_FORMAT_UNDEFINED,
51 }; 52 };
52 std::memcpy(&border.customBorderColor, color.data(), sizeof(color)); 53 std::memcpy(&border.customBorderColor, color.data(), sizeof(color));
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
index 694452fd8..cd7d7a4e4 100644
--- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
+++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp
@@ -706,9 +706,9 @@ private:
706 } 706 }
707 707
708 void DeclareInternalFlags() { 708 void DeclareInternalFlags() {
709 constexpr std::array names = {"zero", "sign", "carry", "overflow"}; 709 static constexpr std::array names{"zero", "sign", "carry", "overflow"};
710
710 for (std::size_t flag = 0; flag < INTERNAL_FLAGS_COUNT; ++flag) { 711 for (std::size_t flag = 0; flag < INTERNAL_FLAGS_COUNT; ++flag) {
711 const auto flag_code = static_cast<InternalFlag>(flag);
712 const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); 712 const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
713 internal_flags[flag] = AddGlobalVariable(Name(id, names[flag])); 713 internal_flags[flag] = AddGlobalVariable(Name(id, names[flag]));
714 } 714 }
@@ -2804,7 +2804,6 @@ private:
2804 std::map<GlobalMemoryBase, Id> global_buffers; 2804 std::map<GlobalMemoryBase, Id> global_buffers;
2805 std::map<u32, TexelBuffer> uniform_texels; 2805 std::map<u32, TexelBuffer> uniform_texels;
2806 std::map<u32, SampledImage> sampled_images; 2806 std::map<u32, SampledImage> sampled_images;
2807 std::map<u32, TexelBuffer> storage_texels;
2808 std::map<u32, StorageImage> images; 2807 std::map<u32, StorageImage> images;
2809 2808
2810 std::array<Id, Maxwell::NumRenderTargets> frag_colors{}; 2809 std::array<Id, Maxwell::NumRenderTargets> frag_colors{};
diff --git a/src/video_core/renderer_vulkan/vk_swapchain.cpp b/src/video_core/renderer_vulkan/vk_swapchain.cpp
index c25e312b6..6bfd2abae 100644
--- a/src/video_core/renderer_vulkan/vk_swapchain.cpp
+++ b/src/video_core/renderer_vulkan/vk_swapchain.cpp
@@ -156,6 +156,7 @@ void VKSwapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities,
156 .minImageCount = requested_image_count, 156 .minImageCount = requested_image_count,
157 .imageFormat = surface_format.format, 157 .imageFormat = surface_format.format,
158 .imageColorSpace = surface_format.colorSpace, 158 .imageColorSpace = surface_format.colorSpace,
159 .imageExtent = {},
159 .imageArrayLayers = 1, 160 .imageArrayLayers = 1,
160 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, 161 .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
161 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE, 162 .imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
@@ -204,6 +205,7 @@ void VKSwapchain::CreateImageViews() {
204 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, 205 .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
205 .pNext = nullptr, 206 .pNext = nullptr,
206 .flags = 0, 207 .flags = 0,
208 .image = {},
207 .viewType = VK_IMAGE_VIEW_TYPE_2D, 209 .viewType = VK_IMAGE_VIEW_TYPE_2D,
208 .format = image_format, 210 .format = image_format,
209 .components = 211 .components =
diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
index d102e6d27..2c6f54101 100644
--- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp
+++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp
@@ -138,6 +138,7 @@ VkImageCreateInfo GenerateImageCreateInfo(const VKDevice& device, const SurfaceP
138 .flags = 0, 138 .flags = 0,
139 .imageType = SurfaceTargetToImage(params.target), 139 .imageType = SurfaceTargetToImage(params.target),
140 .format = format, 140 .format = format,
141 .extent = {},
141 .mipLevels = params.num_levels, 142 .mipLevels = params.num_levels,
142 .arrayLayers = static_cast<u32>(params.GetNumLayers()), 143 .arrayLayers = static_cast<u32>(params.GetNumLayers()),
143 .samples = VK_SAMPLE_COUNT_1_BIT, 144 .samples = VK_SAMPLE_COUNT_1_BIT,
@@ -458,6 +459,7 @@ VkImageView CachedSurfaceView::GetAttachment() {
458 .pNext = nullptr, 459 .pNext = nullptr,
459 .flags = 0, 460 .flags = 0,
460 .image = surface.GetImageHandle(), 461 .image = surface.GetImageHandle(),
462 .viewType = VK_IMAGE_VIEW_TYPE_1D,
461 .format = surface.GetImage().GetFormat(), 463 .format = surface.GetImage().GetFormat(),
462 .components = 464 .components =
463 { 465 {
@@ -471,6 +473,8 @@ VkImageView CachedSurfaceView::GetAttachment() {
471 .aspectMask = aspect_mask, 473 .aspectMask = aspect_mask,
472 .baseMipLevel = base_level, 474 .baseMipLevel = base_level,
473 .levelCount = num_levels, 475 .levelCount = num_levels,
476 .baseArrayLayer = 0,
477 .layerCount = 0,
474 }, 478 },
475 }; 479 };
476 if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) { 480 if (image_view_type == VK_IMAGE_VIEW_TYPE_3D) {
diff --git a/src/video_core/shader/decode/arithmetic_integer.cpp b/src/video_core/shader/decode/arithmetic_integer.cpp
index a041519b7..73155966f 100644
--- a/src/video_core/shader/decode/arithmetic_integer.cpp
+++ b/src/video_core/shader/decode/arithmetic_integer.cpp
@@ -98,12 +98,12 @@ u32 ShaderIR::DecodeArithmeticInteger(NodeBlock& bb, u32 pc) {
98 op_b = GetOperandAbsNegInteger(op_b, false, instr.iadd3.neg_b, true); 98 op_b = GetOperandAbsNegInteger(op_b, false, instr.iadd3.neg_b, true);
99 op_c = GetOperandAbsNegInteger(op_c, false, instr.iadd3.neg_c, true); 99 op_c = GetOperandAbsNegInteger(op_c, false, instr.iadd3.neg_c, true);
100 100
101 const Node value = [&]() { 101 const Node value = [&] {
102 const Node add_ab = Operation(OperationCode::IAdd, NO_PRECISE, op_a, op_b); 102 Node add_ab = Operation(OperationCode::IAdd, NO_PRECISE, op_a, op_b);
103 if (opcode->get().GetId() != OpCode::Id::IADD3_R) { 103 if (opcode->get().GetId() != OpCode::Id::IADD3_R) {
104 return Operation(OperationCode::IAdd, NO_PRECISE, add_ab, op_c); 104 return Operation(OperationCode::IAdd, NO_PRECISE, add_ab, op_c);
105 } 105 }
106 const Node shifted = [&]() { 106 const Node shifted = [&] {
107 switch (instr.iadd3.mode) { 107 switch (instr.iadd3.mode) {
108 case Tegra::Shader::IAdd3Mode::RightShift: 108 case Tegra::Shader::IAdd3Mode::RightShift:
109 // TODO(tech4me): According to 109 // TODO(tech4me): According to
diff --git a/src/video_core/shader/decode/video.cpp b/src/video_core/shader/decode/video.cpp
index 64ba60ea2..1c0957277 100644
--- a/src/video_core/shader/decode/video.cpp
+++ b/src/video_core/shader/decode/video.cpp
@@ -91,29 +91,28 @@ u32 ShaderIR::DecodeVideo(NodeBlock& bb, u32 pc) {
91 return pc; 91 return pc;
92} 92}
93 93
94Node ShaderIR::GetVideoOperand(Node op, bool is_chunk, bool is_signed, 94Node ShaderIR::GetVideoOperand(Node op, bool is_chunk, bool is_signed, VideoType type,
95 Tegra::Shader::VideoType type, u64 byte_height) { 95 u64 byte_height) {
96 if (!is_chunk) { 96 if (!is_chunk) {
97 return BitfieldExtract(op, static_cast<u32>(byte_height * 8), 8); 97 return BitfieldExtract(op, static_cast<u32>(byte_height * 8), 8);
98 } 98 }
99 const Node zero = Immediate(0);
100 99
101 switch (type) { 100 switch (type) {
102 case Tegra::Shader::VideoType::Size16_Low: 101 case VideoType::Size16_Low:
103 return BitfieldExtract(op, 0, 16); 102 return BitfieldExtract(op, 0, 16);
104 case Tegra::Shader::VideoType::Size16_High: 103 case VideoType::Size16_High:
105 return BitfieldExtract(op, 16, 16); 104 return BitfieldExtract(op, 16, 16);
106 case Tegra::Shader::VideoType::Size32: 105 case VideoType::Size32:
107 // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when this type is used 106 // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when this type is used
108 // (1 * 1 + 0 == 0x5b800000). Until a better explanation is found: abort. 107 // (1 * 1 + 0 == 0x5b800000). Until a better explanation is found: abort.
109 UNIMPLEMENTED(); 108 UNIMPLEMENTED();
110 return zero; 109 return Immediate(0);
111 case Tegra::Shader::VideoType::Invalid: 110 case VideoType::Invalid:
112 UNREACHABLE_MSG("Invalid instruction encoding"); 111 UNREACHABLE_MSG("Invalid instruction encoding");
113 return zero; 112 return Immediate(0);
114 default: 113 default:
115 UNREACHABLE(); 114 UNREACHABLE();
116 return zero; 115 return Immediate(0);
117 } 116 }
118} 117}
119 118
diff --git a/src/video_core/shader/decode/xmad.cpp b/src/video_core/shader/decode/xmad.cpp
index c83dc6615..233b8fa42 100644
--- a/src/video_core/shader/decode/xmad.cpp
+++ b/src/video_core/shader/decode/xmad.cpp
@@ -81,20 +81,21 @@ u32 ShaderIR::DecodeXmad(NodeBlock& bb, u32 pc) {
81 SetTemporary(bb, 0, product); 81 SetTemporary(bb, 0, product);
82 product = GetTemporary(0); 82 product = GetTemporary(0);
83 83
84 const Node original_c = op_c; 84 Node original_c = op_c;
85 const Tegra::Shader::XmadMode set_mode = mode; // Workaround to clang compile error 85 const Tegra::Shader::XmadMode set_mode = mode; // Workaround to clang compile error
86 op_c = [&]() { 86 op_c = [&] {
87 switch (set_mode) { 87 switch (set_mode) {
88 case Tegra::Shader::XmadMode::None: 88 case Tegra::Shader::XmadMode::None:
89 return original_c; 89 return original_c;
90 case Tegra::Shader::XmadMode::CLo: 90 case Tegra::Shader::XmadMode::CLo:
91 return BitfieldExtract(original_c, 0, 16); 91 return BitfieldExtract(std::move(original_c), 0, 16);
92 case Tegra::Shader::XmadMode::CHi: 92 case Tegra::Shader::XmadMode::CHi:
93 return BitfieldExtract(original_c, 16, 16); 93 return BitfieldExtract(std::move(original_c), 16, 16);
94 case Tegra::Shader::XmadMode::CBcc: { 94 case Tegra::Shader::XmadMode::CBcc: {
95 const Node shifted_b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b, 95 Node shifted_b = SignedOperation(OperationCode::ILogicalShiftLeft, is_signed_b,
96 original_b, Immediate(16)); 96 original_b, Immediate(16));
97 return SignedOperation(OperationCode::IAdd, is_signed_c, original_c, shifted_b); 97 return SignedOperation(OperationCode::IAdd, is_signed_c, std::move(original_c),
98 std::move(shifted_b));
98 } 99 }
99 case Tegra::Shader::XmadMode::CSfu: { 100 case Tegra::Shader::XmadMode::CSfu: {
100 const Node comp_a = 101 const Node comp_a =
diff --git a/src/video_core/shader/shader_ir.cpp b/src/video_core/shader/shader_ir.cpp
index e322c3402..29d794b34 100644
--- a/src/video_core/shader/shader_ir.cpp
+++ b/src/video_core/shader/shader_ir.cpp
@@ -112,9 +112,9 @@ Node ShaderIR::GetOutputAttribute(Attribute::Index index, u64 element, Node buff
112} 112}
113 113
114Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) const { 114Node ShaderIR::GetInternalFlag(InternalFlag flag, bool negated) const {
115 const Node node = MakeNode<InternalFlagNode>(flag); 115 Node node = MakeNode<InternalFlagNode>(flag);
116 if (negated) { 116 if (negated) {
117 return Operation(OperationCode::LogicalNegate, node); 117 return Operation(OperationCode::LogicalNegate, std::move(node));
118 } 118 }
119 return node; 119 return node;
120} 120}
diff --git a/src/video_core/texture_cache/format_lookup_table.cpp b/src/video_core/texture_cache/format_lookup_table.cpp
index a1cc4756d..7d5a75648 100644
--- a/src/video_core/texture_cache/format_lookup_table.cpp
+++ b/src/video_core/texture_cache/format_lookup_table.cpp
@@ -19,8 +19,6 @@ constexpr auto SNORM = ComponentType::SNORM;
19constexpr auto UNORM = ComponentType::UNORM; 19constexpr auto UNORM = ComponentType::UNORM;
20constexpr auto SINT = ComponentType::SINT; 20constexpr auto SINT = ComponentType::SINT;
21constexpr auto UINT = ComponentType::UINT; 21constexpr auto UINT = ComponentType::UINT;
22constexpr auto SNORM_FORCE_FP16 = ComponentType::SNORM_FORCE_FP16;
23constexpr auto UNORM_FORCE_FP16 = ComponentType::UNORM_FORCE_FP16;
24constexpr auto FLOAT = ComponentType::FLOAT; 22constexpr auto FLOAT = ComponentType::FLOAT;
25constexpr bool C = false; // Normal color 23constexpr bool C = false; // Normal color
26constexpr bool S = true; // Srgb 24constexpr bool S = true; // Srgb
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index 9e5fe2374..9a98f0e98 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -74,9 +74,9 @@ SurfaceParams SurfaceParams::CreateForTexture(const FormatLookupTable& lookup_ta
74 SurfaceParams params; 74 SurfaceParams params;
75 params.is_tiled = tic.IsTiled(); 75 params.is_tiled = tic.IsTiled();
76 params.srgb_conversion = tic.IsSrgbConversionEnabled(); 76 params.srgb_conversion = tic.IsSrgbConversionEnabled();
77 params.block_width = params.is_tiled ? tic.BlockWidth() : 0, 77 params.block_width = params.is_tiled ? tic.BlockWidth() : 0;
78 params.block_height = params.is_tiled ? tic.BlockHeight() : 0, 78 params.block_height = params.is_tiled ? tic.BlockHeight() : 0;
79 params.block_depth = params.is_tiled ? tic.BlockDepth() : 0, 79 params.block_depth = params.is_tiled ? tic.BlockDepth() : 0;
80 params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1; 80 params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1;
81 params.pixel_format = lookup_table.GetPixelFormat( 81 params.pixel_format = lookup_table.GetPixelFormat(
82 tic.format, params.srgb_conversion, tic.r_type, tic.g_type, tic.b_type, tic.a_type); 82 tic.format, params.srgb_conversion, tic.r_type, tic.g_type, tic.b_type, tic.a_type);
@@ -130,14 +130,13 @@ SurfaceParams SurfaceParams::CreateForImage(const FormatLookupTable& lookup_tabl
130 SurfaceParams params; 130 SurfaceParams params;
131 params.is_tiled = tic.IsTiled(); 131 params.is_tiled = tic.IsTiled();
132 params.srgb_conversion = tic.IsSrgbConversionEnabled(); 132 params.srgb_conversion = tic.IsSrgbConversionEnabled();
133 params.block_width = params.is_tiled ? tic.BlockWidth() : 0, 133 params.block_width = params.is_tiled ? tic.BlockWidth() : 0;
134 params.block_height = params.is_tiled ? tic.BlockHeight() : 0, 134 params.block_height = params.is_tiled ? tic.BlockHeight() : 0;
135 params.block_depth = params.is_tiled ? tic.BlockDepth() : 0, 135 params.block_depth = params.is_tiled ? tic.BlockDepth() : 0;
136 params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1; 136 params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1;
137 params.pixel_format = lookup_table.GetPixelFormat( 137 params.pixel_format = lookup_table.GetPixelFormat(
138 tic.format, params.srgb_conversion, tic.r_type, tic.g_type, tic.b_type, tic.a_type); 138 tic.format, params.srgb_conversion, tic.r_type, tic.g_type, tic.b_type, tic.a_type);
139 params.type = GetFormatType(params.pixel_format); 139 params.type = GetFormatType(params.pixel_format);
140 params.type = GetFormatType(params.pixel_format);
141 params.target = ImageTypeToSurfaceTarget(entry.type); 140 params.target = ImageTypeToSurfaceTarget(entry.type);
142 // TODO: on 1DBuffer we should use the tic info. 141 // TODO: on 1DBuffer we should use the tic info.
143 if (tic.IsBuffer()) { 142 if (tic.IsBuffer()) {
@@ -167,27 +166,30 @@ SurfaceParams SurfaceParams::CreateForImage(const FormatLookupTable& lookup_tabl
167 166
168SurfaceParams SurfaceParams::CreateForDepthBuffer(Core::System& system) { 167SurfaceParams SurfaceParams::CreateForDepthBuffer(Core::System& system) {
169 const auto& regs = system.GPU().Maxwell3D().regs; 168 const auto& regs = system.GPU().Maxwell3D().regs;
170 SurfaceParams params;
171 params.is_tiled = regs.zeta.memory_layout.type ==
172 Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear;
173 params.srgb_conversion = false;
174 params.block_width = std::min(regs.zeta.memory_layout.block_width.Value(), 5U);
175 params.block_height = std::min(regs.zeta.memory_layout.block_height.Value(), 5U);
176 params.block_depth = std::min(regs.zeta.memory_layout.block_depth.Value(), 5U);
177 params.tile_width_spacing = 1;
178 params.pixel_format = PixelFormatFromDepthFormat(regs.zeta.format);
179 params.type = GetFormatType(params.pixel_format);
180 params.width = regs.zeta_width;
181 params.height = regs.zeta_height;
182 params.pitch = 0;
183 params.num_levels = 1;
184 params.emulated_levels = 1;
185 169
186 const bool is_layered = regs.zeta_layers > 1 && params.block_depth == 0; 170 const auto block_depth = std::min(regs.zeta.memory_layout.block_depth.Value(), 5U);
187 params.is_layered = is_layered; 171 const bool is_layered = regs.zeta_layers > 1 && block_depth == 0;
188 params.target = is_layered ? SurfaceTarget::Texture2DArray : SurfaceTarget::Texture2D; 172 const auto pixel_format = PixelFormatFromDepthFormat(regs.zeta.format);
189 params.depth = is_layered ? regs.zeta_layers.Value() : 1U; 173
190 return params; 174 return {
175 .is_tiled = regs.zeta.memory_layout.type ==
176 Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear,
177 .srgb_conversion = false,
178 .is_layered = is_layered,
179 .block_width = std::min(regs.zeta.memory_layout.block_width.Value(), 5U),
180 .block_height = std::min(regs.zeta.memory_layout.block_height.Value(), 5U),
181 .block_depth = block_depth,
182 .tile_width_spacing = 1,
183 .width = regs.zeta_width,
184 .height = regs.zeta_height,
185 .depth = is_layered ? regs.zeta_layers.Value() : 1U,
186 .pitch = 0,
187 .num_levels = 1,
188 .emulated_levels = 1,
189 .pixel_format = pixel_format,
190 .type = GetFormatType(pixel_format),
191 .target = is_layered ? SurfaceTarget::Texture2DArray : SurfaceTarget::Texture2D,
192 };
191} 193}
192 194
193SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::size_t index) { 195SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::size_t index) {
@@ -233,24 +235,29 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz
233 235
234SurfaceParams SurfaceParams::CreateForFermiCopySurface( 236SurfaceParams SurfaceParams::CreateForFermiCopySurface(
235 const Tegra::Engines::Fermi2D::Regs::Surface& config) { 237 const Tegra::Engines::Fermi2D::Regs::Surface& config) {
236 SurfaceParams params{}; 238 const bool is_tiled = !config.linear;
237 params.is_tiled = !config.linear; 239 const auto pixel_format = PixelFormatFromRenderTargetFormat(config.format);
238 params.srgb_conversion = config.format == Tegra::RenderTargetFormat::B8G8R8A8_SRGB || 240
239 config.format == Tegra::RenderTargetFormat::A8B8G8R8_SRGB; 241 SurfaceParams params{
240 params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 5U) : 0, 242 .is_tiled = is_tiled,
241 params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 5U) : 0, 243 .srgb_conversion = config.format == Tegra::RenderTargetFormat::B8G8R8A8_SRGB ||
242 params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 5U) : 0, 244 config.format == Tegra::RenderTargetFormat::A8B8G8R8_SRGB,
243 params.tile_width_spacing = 1; 245 .block_width = is_tiled ? std::min(config.BlockWidth(), 5U) : 0U,
244 params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); 246 .block_height = is_tiled ? std::min(config.BlockHeight(), 5U) : 0U,
245 params.type = GetFormatType(params.pixel_format); 247 .block_depth = is_tiled ? std::min(config.BlockDepth(), 5U) : 0U,
246 params.width = config.width; 248 .tile_width_spacing = 1,
247 params.height = config.height; 249 .width = config.width,
248 params.pitch = config.pitch; 250 .height = config.height,
249 // TODO(Rodrigo): Try to guess texture arrays from parameters 251 .depth = 1,
250 params.target = SurfaceTarget::Texture2D; 252 .pitch = config.pitch,
251 params.depth = 1; 253 .num_levels = 1,
252 params.num_levels = 1; 254 .emulated_levels = 1,
253 params.emulated_levels = 1; 255 .pixel_format = pixel_format,
256 .type = GetFormatType(pixel_format),
257 // TODO(Rodrigo): Try to guess texture arrays from parameters
258 .target = SurfaceTarget::Texture2D,
259 };
260
254 params.is_layered = params.IsLayered(); 261 params.is_layered = params.IsLayered();
255 return params; 262 return params;
256} 263}
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp
index 5738787ac..8fc322b30 100644
--- a/src/yuzu/bootmanager.cpp
+++ b/src/yuzu/bootmanager.cpp
@@ -567,7 +567,7 @@ void GRenderWindow::CaptureScreenshot(u32 res_scale, const QString& screenshot_p
567 screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32); 567 screenshot_image = QImage(QSize(layout.width, layout.height), QImage::Format_RGB32);
568 renderer.RequestScreenshot( 568 renderer.RequestScreenshot(
569 screenshot_image.bits(), 569 screenshot_image.bits(),
570 [=] { 570 [=, this] {
571 const std::string std_screenshot_path = screenshot_path.toStdString(); 571 const std::string std_screenshot_path = screenshot_path.toStdString();
572 if (screenshot_image.mirrored(false, true).save(screenshot_path)) { 572 if (screenshot_image.mirrored(false, true).save(screenshot_path)) {
573 LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path); 573 LOG_INFO(Frontend, "Screenshot saved to \"{}\"", std_screenshot_path);
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp
index 59a193edd..cb71b8d11 100644
--- a/src/yuzu/configuration/config.cpp
+++ b/src/yuzu/configuration/config.cpp
@@ -578,7 +578,6 @@ void Config::ReadPathValues() {
578 578
579 UISettings::values.roms_path = ReadSetting(QStringLiteral("romsPath")).toString(); 579 UISettings::values.roms_path = ReadSetting(QStringLiteral("romsPath")).toString();
580 UISettings::values.symbols_path = ReadSetting(QStringLiteral("symbolsPath")).toString(); 580 UISettings::values.symbols_path = ReadSetting(QStringLiteral("symbolsPath")).toString();
581 UISettings::values.screenshot_path = ReadSetting(QStringLiteral("screenshotPath")).toString();
582 UISettings::values.game_dir_deprecated = 581 UISettings::values.game_dir_deprecated =
583 ReadSetting(QStringLiteral("gameListRootDir"), QStringLiteral(".")).toString(); 582 ReadSetting(QStringLiteral("gameListRootDir"), QStringLiteral(".")).toString();
584 UISettings::values.game_dir_deprecated_deepscan = 583 UISettings::values.game_dir_deprecated_deepscan =
@@ -666,8 +665,6 @@ void Config::ReadRendererValues() {
666 QStringLiteral("use_asynchronous_shaders"), false); 665 QStringLiteral("use_asynchronous_shaders"), false);
667 ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"), 666 ReadSettingGlobal(Settings::values.use_fast_gpu_time, QStringLiteral("use_fast_gpu_time"),
668 true); 667 true);
669 ReadSettingGlobal(Settings::values.force_30fps_mode, QStringLiteral("force_30fps_mode"), false);
670
671 ReadSettingGlobal(Settings::values.bg_red, QStringLiteral("bg_red"), 0.0); 668 ReadSettingGlobal(Settings::values.bg_red, QStringLiteral("bg_red"), 0.0);
672 ReadSettingGlobal(Settings::values.bg_green, QStringLiteral("bg_green"), 0.0); 669 ReadSettingGlobal(Settings::values.bg_green, QStringLiteral("bg_green"), 0.0);
673 ReadSettingGlobal(Settings::values.bg_blue, QStringLiteral("bg_blue"), 0.0); 670 ReadSettingGlobal(Settings::values.bg_blue, QStringLiteral("bg_blue"), 0.0);
@@ -675,6 +672,22 @@ void Config::ReadRendererValues() {
675 qt_config->endGroup(); 672 qt_config->endGroup();
676} 673}
677 674
675void Config::ReadScreenshotValues() {
676 qt_config->beginGroup(QStringLiteral("Screenshots"));
677
678 UISettings::values.enable_screenshot_save_as =
679 ReadSetting(QStringLiteral("enable_screenshot_save_as"), true).toBool();
680 FileUtil::GetUserPath(
681 FileUtil::UserPath::ScreenshotsDir,
682 qt_config
683 ->value(QStringLiteral("screenshot_path"), QString::fromStdString(FileUtil::GetUserPath(
684 FileUtil::UserPath::ScreenshotsDir)))
685 .toString()
686 .toStdString());
687
688 qt_config->endGroup();
689}
690
678void Config::ReadShortcutValues() { 691void Config::ReadShortcutValues() {
679 qt_config->beginGroup(QStringLiteral("Shortcuts")); 692 qt_config->beginGroup(QStringLiteral("Shortcuts"));
680 693
@@ -756,6 +769,7 @@ void Config::ReadUIValues() {
756 ReadUIGamelistValues(); 769 ReadUIGamelistValues();
757 ReadUILayoutValues(); 770 ReadUILayoutValues();
758 ReadPathValues(); 771 ReadPathValues();
772 ReadScreenshotValues();
759 ReadShortcutValues(); 773 ReadShortcutValues();
760 774
761 UISettings::values.single_window_mode = 775 UISettings::values.single_window_mode =
@@ -1085,7 +1099,6 @@ void Config::SavePathValues() {
1085 1099
1086 WriteSetting(QStringLiteral("romsPath"), UISettings::values.roms_path); 1100 WriteSetting(QStringLiteral("romsPath"), UISettings::values.roms_path);
1087 WriteSetting(QStringLiteral("symbolsPath"), UISettings::values.symbols_path); 1101 WriteSetting(QStringLiteral("symbolsPath"), UISettings::values.symbols_path);
1088 WriteSetting(QStringLiteral("screenshotPath"), UISettings::values.screenshot_path);
1089 qt_config->beginWriteArray(QStringLiteral("gamedirs")); 1102 qt_config->beginWriteArray(QStringLiteral("gamedirs"));
1090 for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) { 1103 for (int i = 0; i < UISettings::values.game_dirs.size(); ++i) {
1091 qt_config->setArrayIndex(i); 1104 qt_config->setArrayIndex(i);
@@ -1153,9 +1166,6 @@ void Config::SaveRendererValues() {
1153 Settings::values.use_asynchronous_shaders, false); 1166 Settings::values.use_asynchronous_shaders, false);
1154 WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time, 1167 WriteSettingGlobal(QStringLiteral("use_fast_gpu_time"), Settings::values.use_fast_gpu_time,
1155 true); 1168 true);
1156 WriteSettingGlobal(QStringLiteral("force_30fps_mode"), Settings::values.force_30fps_mode,
1157 false);
1158
1159 // Cast to double because Qt's written float values are not human-readable 1169 // Cast to double because Qt's written float values are not human-readable
1160 WriteSettingGlobal(QStringLiteral("bg_red"), Settings::values.bg_red, 0.0); 1170 WriteSettingGlobal(QStringLiteral("bg_red"), Settings::values.bg_red, 0.0);
1161 WriteSettingGlobal(QStringLiteral("bg_green"), Settings::values.bg_green, 0.0); 1171 WriteSettingGlobal(QStringLiteral("bg_green"), Settings::values.bg_green, 0.0);
@@ -1164,6 +1174,17 @@ void Config::SaveRendererValues() {
1164 qt_config->endGroup(); 1174 qt_config->endGroup();
1165} 1175}
1166 1176
1177void Config::SaveScreenshotValues() {
1178 qt_config->beginGroup(QStringLiteral("Screenshots"));
1179
1180 WriteSetting(QStringLiteral("enable_screenshot_save_as"),
1181 UISettings::values.enable_screenshot_save_as);
1182 WriteSetting(QStringLiteral("screenshot_path"),
1183 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ScreenshotsDir)));
1184
1185 qt_config->endGroup();
1186}
1187
1167void Config::SaveShortcutValues() { 1188void Config::SaveShortcutValues() {
1168 qt_config->beginGroup(QStringLiteral("Shortcuts")); 1189 qt_config->beginGroup(QStringLiteral("Shortcuts"));
1169 1190
@@ -1226,6 +1247,7 @@ void Config::SaveUIValues() {
1226 SaveUIGamelistValues(); 1247 SaveUIGamelistValues();
1227 SaveUILayoutValues(); 1248 SaveUILayoutValues();
1228 SavePathValues(); 1249 SavePathValues();
1250 SaveScreenshotValues();
1229 SaveShortcutValues(); 1251 SaveShortcutValues();
1230 1252
1231 WriteSetting(QStringLiteral("singleWindowMode"), UISettings::values.single_window_mode, true); 1253 WriteSetting(QStringLiteral("singleWindowMode"), UISettings::values.single_window_mode, true);
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h
index 8e815f829..e5f39b040 100644
--- a/src/yuzu/configuration/config.h
+++ b/src/yuzu/configuration/config.h
@@ -51,6 +51,7 @@ private:
51 void ReadPathValues(); 51 void ReadPathValues();
52 void ReadCpuValues(); 52 void ReadCpuValues();
53 void ReadRendererValues(); 53 void ReadRendererValues();
54 void ReadScreenshotValues();
54 void ReadShortcutValues(); 55 void ReadShortcutValues();
55 void ReadSystemValues(); 56 void ReadSystemValues();
56 void ReadUIValues(); 57 void ReadUIValues();
@@ -76,6 +77,7 @@ private:
76 void SavePathValues(); 77 void SavePathValues();
77 void SaveCpuValues(); 78 void SaveCpuValues();
78 void SaveRendererValues(); 79 void SaveRendererValues();
80 void SaveScreenshotValues();
79 void SaveShortcutValues(); 81 void SaveShortcutValues();
80 void SaveSystemValues(); 82 void SaveSystemValues();
81 void SaveUIValues(); 83 void SaveUIValues();
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp
index bb47c3933..f9becab6e 100644
--- a/src/yuzu/configuration/configuration_shared.cpp
+++ b/src/yuzu/configuration/configuration_shared.cpp
@@ -4,17 +4,20 @@
4 4
5#include <QCheckBox> 5#include <QCheckBox>
6#include <QComboBox> 6#include <QComboBox>
7#include <QObject>
8#include <QString>
7#include "core/settings.h" 9#include "core/settings.h"
8#include "yuzu/configuration/configuration_shared.h" 10#include "yuzu/configuration/configuration_shared.h"
9#include "yuzu/configuration/configure_per_game.h" 11#include "yuzu/configuration/configure_per_game.h"
10 12
11void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting, 13void ConfigurationShared::ApplyPerGameSetting(Settings::Setting<bool>* setting,
12 const QCheckBox* checkbox) { 14 const QCheckBox* checkbox,
13 if (checkbox->checkState() == Qt::PartiallyChecked) { 15 const CheckState& tracker) {
16 if (tracker == CheckState::Global) {
14 setting->SetGlobal(true); 17 setting->SetGlobal(true);
15 } else { 18 } else {
16 setting->SetGlobal(false); 19 setting->SetGlobal(false);
17 setting->SetValue(checkbox->checkState() == Qt::Checked); 20 setting->SetValue(checkbox->checkState());
18 } 21 }
19} 22}
20 23
@@ -69,8 +72,69 @@ void ConfigurationShared::SetPerGameSetting(
69 ConfigurationShared::USE_GLOBAL_OFFSET); 72 ConfigurationShared::USE_GLOBAL_OFFSET);
70} 73}
71 74
72void ConfigurationShared::InsertGlobalItem(QComboBox* combobox) { 75void ConfigurationShared::SetHighlight(QWidget* widget, const std::string& name, bool highlighted) {
73 const QString use_global_text = ConfigurePerGame::tr("Use global configuration"); 76 if (highlighted) {
77 widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,203,255,0.5) }")
78 .arg(QString::fromStdString(name)));
79 } else {
80 widget->setStyleSheet(QStringLiteral("QWidget#%1 { background-color:rgba(0,0,0,0) }")
81 .arg(QString::fromStdString(name)));
82 }
83 widget->show();
84}
85
86void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox, const std::string& name,
87 const Settings::Setting<bool>& setting,
88 CheckState& tracker) {
89 if (setting.UsingGlobal()) {
90 tracker = CheckState::Global;
91 } else {
92 tracker = (setting.GetValue() == setting.GetValue(true)) ? CheckState::On : CheckState::Off;
93 }
94 SetHighlight(checkbox, name, tracker != CheckState::Global);
95 QObject::connect(checkbox, &QCheckBox::clicked, checkbox,
96 [checkbox, name, setting, &tracker]() {
97 tracker = static_cast<CheckState>((static_cast<int>(tracker) + 1) %
98 static_cast<int>(CheckState::Count));
99 if (tracker == CheckState::Global) {
100 checkbox->setChecked(setting.GetValue(true));
101 }
102 SetHighlight(checkbox, name, tracker != CheckState::Global);
103 });
104}
105
106void ConfigurationShared::SetColoredTristate(QCheckBox* checkbox, const std::string& name,
107 bool global, bool state, bool global_state,
108 CheckState& tracker) {
109 if (global) {
110 tracker = CheckState::Global;
111 } else {
112 tracker = (state == global_state) ? CheckState::On : CheckState::Off;
113 }
114 SetHighlight(checkbox, name, tracker != CheckState::Global);
115 QObject::connect(checkbox, &QCheckBox::clicked, checkbox,
116 [checkbox, name, global_state, &tracker]() {
117 tracker = static_cast<CheckState>((static_cast<int>(tracker) + 1) %
118 static_cast<int>(CheckState::Count));
119 if (tracker == CheckState::Global) {
120 checkbox->setChecked(global_state);
121 }
122 SetHighlight(checkbox, name, tracker != CheckState::Global);
123 });
124}
125
126void ConfigurationShared::SetColoredComboBox(QComboBox* combobox, QWidget* target,
127 const std::string& target_name, int global) {
128 InsertGlobalItem(combobox, global);
129 QObject::connect(combobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), target,
130 [target, target_name](int index) {
131 ConfigurationShared::SetHighlight(target, target_name, index != 0);
132 });
133}
134
135void ConfigurationShared::InsertGlobalItem(QComboBox* combobox, int global_index) {
136 const QString use_global_text =
137 ConfigurePerGame::tr("Use global configuration (%1)").arg(combobox->itemText(global_index));
74 combobox->insertItem(ConfigurationShared::USE_GLOBAL_INDEX, use_global_text); 138 combobox->insertItem(ConfigurationShared::USE_GLOBAL_INDEX, use_global_text);
75 combobox->insertSeparator(ConfigurationShared::USE_GLOBAL_SEPARATOR_INDEX); 139 combobox->insertSeparator(ConfigurationShared::USE_GLOBAL_SEPARATOR_INDEX);
76} 140}
diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h
index b11b1b950..003148c68 100644
--- a/src/yuzu/configuration/configuration_shared.h
+++ b/src/yuzu/configuration/configuration_shared.h
@@ -15,9 +15,17 @@ constexpr int USE_GLOBAL_INDEX = 0;
15constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1; 15constexpr int USE_GLOBAL_SEPARATOR_INDEX = 1;
16constexpr int USE_GLOBAL_OFFSET = 2; 16constexpr int USE_GLOBAL_OFFSET = 2;
17 17
18enum class CheckState {
19 Off,
20 On,
21 Global,
22 Count,
23};
24
18// Global-aware apply and set functions 25// Global-aware apply and set functions
19 26
20void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox); 27void ApplyPerGameSetting(Settings::Setting<bool>* setting, const QCheckBox* checkbox,
28 const CheckState& tracker);
21void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox); 29void ApplyPerGameSetting(Settings::Setting<int>* setting, const QComboBox* combobox);
22void ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting, 30void ApplyPerGameSetting(Settings::Setting<Settings::RendererBackend>* setting,
23 const QComboBox* combobox); 31 const QComboBox* combobox);
@@ -31,6 +39,14 @@ void SetPerGameSetting(QComboBox* combobox,
31void SetPerGameSetting(QComboBox* combobox, 39void SetPerGameSetting(QComboBox* combobox,
32 const Settings::Setting<Settings::GPUAccuracy>* setting); 40 const Settings::Setting<Settings::GPUAccuracy>* setting);
33 41
34void InsertGlobalItem(QComboBox* combobox); 42void SetHighlight(QWidget* widget, const std::string& name, bool highlighted);
43void SetColoredTristate(QCheckBox* checkbox, const std::string& name,
44 const Settings::Setting<bool>& setting, CheckState& tracker);
45void SetColoredTristate(QCheckBox* checkbox, const std::string& name, bool global, bool state,
46 bool global_state, CheckState& tracker);
47void SetColoredComboBox(QComboBox* combobox, QWidget* target, const std::string& target_name,
48 int global);
49
50void InsertGlobalItem(QComboBox* combobox, int global_index);
35 51
36} // namespace ConfigurationShared 52} // namespace ConfigurationShared
diff --git a/src/yuzu/configuration/configure_audio.cpp b/src/yuzu/configuration/configure_audio.cpp
index cc021beec..fea632531 100644
--- a/src/yuzu/configuration/configure_audio.cpp
+++ b/src/yuzu/configuration/configure_audio.cpp
@@ -49,12 +49,9 @@ void ConfigureAudio::SetConfiguration() {
49 49
50 ui->volume_slider->setValue(Settings::values.volume.GetValue() * ui->volume_slider->maximum()); 50 ui->volume_slider->setValue(Settings::values.volume.GetValue() * ui->volume_slider->maximum());
51 51
52 if (Settings::configuring_global) { 52 ui->toggle_audio_stretching->setChecked(Settings::values.enable_audio_stretching.GetValue());
53 ui->toggle_audio_stretching->setChecked( 53
54 Settings::values.enable_audio_stretching.GetValue()); 54 if (!Settings::configuring_global) {
55 } else {
56 ConfigurationShared::SetPerGameSetting(ui->toggle_audio_stretching,
57 &Settings::values.enable_audio_stretching);
58 if (Settings::values.volume.UsingGlobal()) { 55 if (Settings::values.volume.UsingGlobal()) {
59 ui->volume_combo_box->setCurrentIndex(0); 56 ui->volume_combo_box->setCurrentIndex(0);
60 ui->volume_slider->setEnabled(false); 57 ui->volume_slider->setEnabled(false);
@@ -62,6 +59,8 @@ void ConfigureAudio::SetConfiguration() {
62 ui->volume_combo_box->setCurrentIndex(1); 59 ui->volume_combo_box->setCurrentIndex(1);
63 ui->volume_slider->setEnabled(true); 60 ui->volume_slider->setEnabled(true);
64 } 61 }
62 ConfigurationShared::SetHighlight(ui->volume_layout, "volume_layout",
63 !Settings::values.volume.UsingGlobal());
65 } 64 }
66 SetVolumeIndicatorText(ui->volume_slider->sliderPosition()); 65 SetVolumeIndicatorText(ui->volume_slider->sliderPosition());
67} 66}
@@ -120,7 +119,8 @@ void ConfigureAudio::ApplyConfiguration() {
120 } 119 }
121 } else { 120 } else {
122 ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching, 121 ConfigurationShared::ApplyPerGameSetting(&Settings::values.enable_audio_stretching,
123 ui->toggle_audio_stretching); 122 ui->toggle_audio_stretching,
123 enable_audio_stretching);
124 if (ui->volume_combo_box->currentIndex() == 0) { 124 if (ui->volume_combo_box->currentIndex() == 0) {
125 Settings::values.volume.SetGlobal(true); 125 Settings::values.volume.SetGlobal(true);
126 } else { 126 } else {
@@ -173,9 +173,14 @@ void ConfigureAudio::SetupPerGameUI() {
173 return; 173 return;
174 } 174 }
175 175
176 ui->toggle_audio_stretching->setTristate(true); 176 ConfigurationShared::SetColoredTristate(ui->toggle_audio_stretching, "toggle_audio_stretching",
177 Settings::values.enable_audio_stretching,
178 enable_audio_stretching);
177 connect(ui->volume_combo_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), 179 connect(ui->volume_combo_box, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated),
178 this, [this](int index) { ui->volume_slider->setEnabled(index == 1); }); 180 this, [this](int index) {
181 ui->volume_slider->setEnabled(index == 1);
182 ConfigurationShared::SetHighlight(ui->volume_layout, "volume_layout", index == 1);
183 });
179 184
180 ui->output_sink_combo_box->setVisible(false); 185 ui->output_sink_combo_box->setVisible(false);
181 ui->output_sink_label->setVisible(false); 186 ui->output_sink_label->setVisible(false);
diff --git a/src/yuzu/configuration/configure_audio.h b/src/yuzu/configuration/configure_audio.h
index d84f4a682..9dbd3d93e 100644
--- a/src/yuzu/configuration/configure_audio.h
+++ b/src/yuzu/configuration/configure_audio.h
@@ -7,6 +7,10 @@
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9 9
10namespace ConfigurationShared {
11enum class CheckState;
12}
13
10namespace Ui { 14namespace Ui {
11class ConfigureAudio; 15class ConfigureAudio;
12} 16}
@@ -37,4 +41,6 @@ private:
37 void SetupPerGameUI(); 41 void SetupPerGameUI();
38 42
39 std::unique_ptr<Ui::ConfigureAudio> ui; 43 std::unique_ptr<Ui::ConfigureAudio> ui;
44
45 ConfigurationShared::CheckState enable_audio_stretching;
40}; 46};
diff --git a/src/yuzu/configuration/configure_audio.ui b/src/yuzu/configuration/configure_audio.ui
index 862ccb988..9bd0cca96 100644
--- a/src/yuzu/configuration/configure_audio.ui
+++ b/src/yuzu/configuration/configure_audio.ui
@@ -56,80 +56,91 @@
56 </layout> 56 </layout>
57 </item> 57 </item>
58 <item> 58 <item>
59 <layout class="QHBoxLayout" name="horizontalLayout_2"> 59 <widget class="QWidget" name="volume_layout" native="true">
60 <property name="topMargin"> 60 <layout class="QHBoxLayout" name="horizontalLayout_2">
61 <number>0</number> 61 <property name="leftMargin">
62 </property> 62 <number>0</number>
63 <item> 63 </property>
64 <widget class="QComboBox" name="volume_combo_box"> 64 <property name="topMargin">
65 <item> 65 <number>0</number>
66 </property>
67 <property name="rightMargin">
68 <number>0</number>
69 </property>
70 <property name="bottomMargin">
71 <number>0</number>
72 </property>
73 <item>
74 <widget class="QComboBox" name="volume_combo_box">
75 <item>
76 <property name="text">
77 <string>Use global volume</string>
78 </property>
79 </item>
80 <item>
81 <property name="text">
82 <string>Set volume:</string>
83 </property>
84 </item>
85 </widget>
86 </item>
87 <item>
88 <widget class="QLabel" name="volume_label">
66 <property name="text"> 89 <property name="text">
67 <string>Use global volume</string> 90 <string>Volume:</string>
91 </property>
92 </widget>
93 </item>
94 <item>
95 <spacer name="horizontalSpacer">
96 <property name="orientation">
97 <enum>Qt::Horizontal</enum>
98 </property>
99 <property name="sizeHint" stdset="0">
100 <size>
101 <width>30</width>
102 <height>20</height>
103 </size>
104 </property>
105 </spacer>
106 </item>
107 <item>
108 <widget class="QSlider" name="volume_slider">
109 <property name="sizePolicy">
110 <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
111 <horstretch>0</horstretch>
112 <verstretch>0</verstretch>
113 </sizepolicy>
114 </property>
115 <property name="maximum">
116 <number>100</number>
117 </property>
118 <property name="pageStep">
119 <number>10</number>
120 </property>
121 <property name="orientation">
122 <enum>Qt::Horizontal</enum>
123 </property>
124 </widget>
125 </item>
126 <item>
127 <widget class="QLabel" name="volume_indicator">
128 <property name="minimumSize">
129 <size>
130 <width>32</width>
131 <height>0</height>
132 </size>
68 </property> 133 </property>
69 </item>
70 <item>
71 <property name="text"> 134 <property name="text">
72 <string>Set volume:</string> 135 <string>0 %</string>
73 </property> 136 </property>
74 </item> 137 <property name="alignment">
75 </widget> 138 <set>Qt::AlignCenter</set>
76 </item> 139 </property>
77 <item> 140 </widget>
78 <widget class="QLabel" name="volume_label"> 141 </item>
79 <property name="text"> 142 </layout>
80 <string>Volume:</string> 143 </widget>
81 </property>
82 </widget>
83 </item>
84 <item>
85 <spacer name="horizontalSpacer">
86 <property name="orientation">
87 <enum>Qt::Horizontal</enum>
88 </property>
89 <property name="sizeHint" stdset="0">
90 <size>
91 <width>30</width>
92 <height>20</height>
93 </size>
94 </property>
95 </spacer>
96 </item>
97 <item>
98 <widget class="QSlider" name="volume_slider">
99 <property name="sizePolicy">
100 <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
101 <horstretch>0</horstretch>
102 <verstretch>0</verstretch>
103 </sizepolicy>
104 </property>
105 <property name="maximum">
106 <number>100</number>
107 </property>
108 <property name="pageStep">
109 <number>10</number>
110 </property>
111 <property name="orientation">
112 <enum>Qt::Horizontal</enum>
113 </property>
114 </widget>
115 </item>
116 <item>
117 <widget class="QLabel" name="volume_indicator">
118 <property name="minimumSize">
119 <size>
120 <width>32</width>
121 <height>0</height>
122 </size>
123 </property>
124 <property name="text">
125 <string>0 %</string>
126 </property>
127 <property name="alignment">
128 <set>Qt::AlignCenter</set>
129 </property>
130 </widget>
131 </item>
132 </layout>
133 </item> 144 </item>
134 </layout> 145 </layout>
135 </widget> 146 </widget>
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui
index 272bdd6b8..9d6feb9f7 100644
--- a/src/yuzu/configuration/configure_debug.ui
+++ b/src/yuzu/configuration/configure_debug.ui
@@ -171,26 +171,6 @@
171 </property> 171 </property>
172 <layout class="QVBoxLayout" name="verticalLayout_6"> 172 <layout class="QVBoxLayout" name="verticalLayout_6">
173 <item> 173 <item>
174 <widget class="QCheckBox" name="dump_decompressed_nso">
175 <property name="whatsThis">
176 <string>When checked, any NSO yuzu tries to load or patch will be copied decompressed to the yuzu/dump directory.</string>
177 </property>
178 <property name="text">
179 <string>Dump Decompressed NSOs</string>
180 </property>
181 </widget>
182 </item>
183 <item>
184 <widget class="QCheckBox" name="dump_exefs">
185 <property name="whatsThis">
186 <string>When checked, any game that yuzu loads will have its ExeFS dumped to the yuzu/dump directory.</string>
187 </property>
188 <property name="text">
189 <string>Dump ExeFS</string>
190 </property>
191 </widget>
192 </item>
193 <item>
194 <widget class="QCheckBox" name="reporting_services"> 174 <widget class="QCheckBox" name="reporting_services">
195 <property name="text"> 175 <property name="text">
196 <string>Enable Verbose Reporting Services</string> 176 <string>Enable Verbose Reporting Services</string>
@@ -257,8 +237,6 @@
257 <tabstop>open_log_button</tabstop> 237 <tabstop>open_log_button</tabstop>
258 <tabstop>homebrew_args_edit</tabstop> 238 <tabstop>homebrew_args_edit</tabstop>
259 <tabstop>enable_graphics_debugging</tabstop> 239 <tabstop>enable_graphics_debugging</tabstop>
260 <tabstop>dump_decompressed_nso</tabstop>
261 <tabstop>dump_exefs</tabstop>
262 <tabstop>reporting_services</tabstop> 240 <tabstop>reporting_services</tabstop>
263 <tabstop>quest_flag</tabstop> 241 <tabstop>quest_flag</tabstop>
264 </tabstops> 242 </tabstops>
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp
index 20316c9cc..c0dbd9855 100644
--- a/src/yuzu/configuration/configure_general.cpp
+++ b/src/yuzu/configuration/configure_general.cpp
@@ -19,9 +19,10 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
19 19
20 SetConfiguration(); 20 SetConfiguration();
21 21
22 connect(ui->toggle_frame_limit, &QCheckBox::stateChanged, ui->frame_limit, [this]() { 22 if (Settings::configuring_global) {
23 ui->frame_limit->setEnabled(ui->toggle_frame_limit->checkState() == Qt::Checked); 23 connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit,
24 }); 24 [this]() { ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked()); });
25 }
25} 26}
26 27
27ConfigureGeneral::~ConfigureGeneral() = default; 28ConfigureGeneral::~ConfigureGeneral() = default;
@@ -40,17 +41,12 @@ void ConfigureGeneral::SetConfiguration() {
40 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue()); 41 ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit.GetValue());
41 ui->frame_limit->setValue(Settings::values.frame_limit.GetValue()); 42 ui->frame_limit->setValue(Settings::values.frame_limit.GetValue());
42 43
43 if (!Settings::configuring_global) { 44 if (Settings::configuring_global) {
44 if (Settings::values.use_multi_core.UsingGlobal()) { 45 ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue());
45 ui->use_multi_core->setCheckState(Qt::PartiallyChecked); 46 } else {
46 } 47 ui->frame_limit->setEnabled(Settings::values.use_frame_limit.GetValue() &&
47 if (Settings::values.use_frame_limit.UsingGlobal()) { 48 use_frame_limit != ConfigurationShared::CheckState::Global);
48 ui->toggle_frame_limit->setCheckState(Qt::PartiallyChecked);
49 }
50 } 49 }
51
52 ui->frame_limit->setEnabled(ui->toggle_frame_limit->checkState() == Qt::Checked &&
53 ui->toggle_frame_limit->isEnabled());
54} 50}
55 51
56void ConfigureGeneral::ApplyConfiguration() { 52void ConfigureGeneral::ApplyConfiguration() {
@@ -71,9 +67,9 @@ void ConfigureGeneral::ApplyConfiguration() {
71 } 67 }
72 } else { 68 } else {
73 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core, 69 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_multi_core,
74 ui->use_multi_core); 70 ui->use_multi_core, use_multi_core);
75 71
76 bool global_frame_limit = ui->toggle_frame_limit->checkState() == Qt::PartiallyChecked; 72 bool global_frame_limit = use_frame_limit == ConfigurationShared::CheckState::Global;
77 Settings::values.use_frame_limit.SetGlobal(global_frame_limit); 73 Settings::values.use_frame_limit.SetGlobal(global_frame_limit);
78 Settings::values.frame_limit.SetGlobal(global_frame_limit); 74 Settings::values.frame_limit.SetGlobal(global_frame_limit);
79 if (!global_frame_limit) { 75 if (!global_frame_limit) {
@@ -109,6 +105,13 @@ void ConfigureGeneral::SetupPerGameUI() {
109 ui->toggle_background_pause->setVisible(false); 105 ui->toggle_background_pause->setVisible(false);
110 ui->toggle_hide_mouse->setVisible(false); 106 ui->toggle_hide_mouse->setVisible(false);
111 107
112 ui->toggle_frame_limit->setTristate(true); 108 ConfigurationShared::SetColoredTristate(ui->toggle_frame_limit, "toggle_frame_limit",
113 ui->use_multi_core->setTristate(true); 109 Settings::values.use_frame_limit, use_frame_limit);
110 ConfigurationShared::SetColoredTristate(ui->use_multi_core, "use_multi_core",
111 Settings::values.use_multi_core, use_multi_core);
112
113 connect(ui->toggle_frame_limit, &QCheckBox::clicked, ui->frame_limit, [this]() {
114 ui->frame_limit->setEnabled(ui->toggle_frame_limit->isChecked() &&
115 (use_frame_limit != ConfigurationShared::CheckState::Global));
116 });
114} 117}
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h
index 9c785c22e..323ffbd8f 100644
--- a/src/yuzu/configuration/configure_general.h
+++ b/src/yuzu/configuration/configure_general.h
@@ -7,6 +7,10 @@
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9 9
10namespace ConfigurationShared {
11enum class CheckState;
12}
13
10class HotkeyRegistry; 14class HotkeyRegistry;
11 15
12namespace Ui { 16namespace Ui {
@@ -31,4 +35,7 @@ private:
31 void SetupPerGameUI(); 35 void SetupPerGameUI();
32 36
33 std::unique_ptr<Ui::ConfigureGeneral> ui; 37 std::unique_ptr<Ui::ConfigureGeneral> ui;
38
39 ConfigurationShared::CheckState use_frame_limit;
40 ConfigurationShared::CheckState use_multi_core;
34}; 41};
diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp
index cb4706bd6..3e42531c3 100644
--- a/src/yuzu/configuration/configure_graphics.cpp
+++ b/src/yuzu/configuration/configure_graphics.cpp
@@ -31,8 +31,14 @@ ConfigureGraphics::ConfigureGraphics(QWidget* parent)
31 31
32 SetConfiguration(); 32 SetConfiguration();
33 33
34 connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, 34 connect(ui->api, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] {
35 [this] { UpdateDeviceComboBox(); }); 35 UpdateDeviceComboBox();
36 if (!Settings::configuring_global) {
37 ConfigurationShared::SetHighlight(ui->api_layout, "api_layout",
38 ui->api->currentIndex() !=
39 ConfigurationShared::USE_GLOBAL_INDEX);
40 }
41 });
36 connect(ui->device, qOverload<int>(&QComboBox::activated), this, 42 connect(ui->device, qOverload<int>(&QComboBox::activated), this,
37 [this](int device) { UpdateDeviceSelection(device); }); 43 [this](int device) { UpdateDeviceSelection(device); });
38 44
@@ -65,25 +71,26 @@ void ConfigureGraphics::SetConfiguration() {
65 ui->api->setEnabled(runtime_lock); 71 ui->api->setEnabled(runtime_lock);
66 ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock); 72 ui->use_asynchronous_gpu_emulation->setEnabled(runtime_lock);
67 ui->use_disk_shader_cache->setEnabled(runtime_lock); 73 ui->use_disk_shader_cache->setEnabled(runtime_lock);
74 ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
75 ui->use_asynchronous_gpu_emulation->setChecked(
76 Settings::values.use_asynchronous_gpu_emulation.GetValue());
68 77
69 if (Settings::configuring_global) { 78 if (Settings::configuring_global) {
70 ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); 79 ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
71 ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); 80 ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
72 ui->use_disk_shader_cache->setChecked(Settings::values.use_disk_shader_cache.GetValue());
73 ui->use_asynchronous_gpu_emulation->setChecked(
74 Settings::values.use_asynchronous_gpu_emulation.GetValue());
75 } else { 81 } else {
76 ConfigurationShared::SetPerGameSetting(ui->use_disk_shader_cache,
77 &Settings::values.use_disk_shader_cache);
78 ConfigurationShared::SetPerGameSetting(ui->use_asynchronous_gpu_emulation,
79 &Settings::values.use_asynchronous_gpu_emulation);
80
81 ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); 82 ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
83 ConfigurationShared::SetHighlight(ui->api_layout, "api_layout",
84 !Settings::values.renderer_backend.UsingGlobal());
82 ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox, 85 ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
83 &Settings::values.aspect_ratio); 86 &Settings::values.aspect_ratio);
84 87
85 ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1); 88 ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
86 ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal()); 89 ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
90 ConfigurationShared::SetHighlight(ui->ar_label, "ar_label",
91 !Settings::values.aspect_ratio.UsingGlobal());
92 ConfigurationShared::SetHighlight(ui->bg_layout, "bg_layout",
93 !Settings::values.bg_red.UsingGlobal());
87 } 94 }
88 95
89 UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red.GetValue(), 96 UpdateBackgroundColorButton(QColor::fromRgbF(Settings::values.bg_red.GetValue(),
@@ -135,9 +142,10 @@ void ConfigureGraphics::ApplyConfiguration() {
135 ui->aspect_ratio_combobox); 142 ui->aspect_ratio_combobox);
136 143
137 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache, 144 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_disk_shader_cache,
138 ui->use_disk_shader_cache); 145 ui->use_disk_shader_cache, use_disk_shader_cache);
139 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation, 146 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_gpu_emulation,
140 ui->use_asynchronous_gpu_emulation); 147 ui->use_asynchronous_gpu_emulation,
148 use_asynchronous_gpu_emulation);
141 149
142 if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { 150 if (ui->bg_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) {
143 Settings::values.bg_red.SetGlobal(true); 151 Settings::values.bg_red.SetGlobal(true);
@@ -241,10 +249,20 @@ void ConfigureGraphics::SetupPerGameUI() {
241 } 249 }
242 250
243 connect(ui->bg_combobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this, 251 connect(ui->bg_combobox, static_cast<void (QComboBox::*)(int)>(&QComboBox::activated), this,
244 [this](int index) { ui->bg_button->setEnabled(index == 1); }); 252 [this](int index) {
245 253 ui->bg_button->setEnabled(index == 1);
246 ui->use_disk_shader_cache->setTristate(true); 254 ConfigurationShared::SetHighlight(ui->bg_layout, "bg_layout", index == 1);
247 ui->use_asynchronous_gpu_emulation->setTristate(true); 255 });
248 ConfigurationShared::InsertGlobalItem(ui->aspect_ratio_combobox); 256
249 ConfigurationShared::InsertGlobalItem(ui->api); 257 ConfigurationShared::SetColoredTristate(ui->use_disk_shader_cache, "use_disk_shader_cache",
258 Settings::values.use_disk_shader_cache,
259 use_disk_shader_cache);
260 ConfigurationShared::SetColoredTristate(
261 ui->use_asynchronous_gpu_emulation, "use_asynchronous_gpu_emulation",
262 Settings::values.use_asynchronous_gpu_emulation, use_asynchronous_gpu_emulation);
263
264 ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label, "ar_label",
265 Settings::values.aspect_ratio.GetValue(true));
266 ConfigurationShared::InsertGlobalItem(
267 ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
250} 268}
diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h
index 24f01c739..b4961f719 100644
--- a/src/yuzu/configuration/configure_graphics.h
+++ b/src/yuzu/configuration/configure_graphics.h
@@ -10,6 +10,10 @@
10#include <QWidget> 10#include <QWidget>
11#include "core/settings.h" 11#include "core/settings.h"
12 12
13namespace ConfigurationShared {
14enum class CheckState;
15}
16
13namespace Ui { 17namespace Ui {
14class ConfigureGraphics; 18class ConfigureGraphics;
15} 19}
@@ -42,6 +46,9 @@ private:
42 std::unique_ptr<Ui::ConfigureGraphics> ui; 46 std::unique_ptr<Ui::ConfigureGraphics> ui;
43 QColor bg_color; 47 QColor bg_color;
44 48
49 ConfigurationShared::CheckState use_disk_shader_cache;
50 ConfigurationShared::CheckState use_asynchronous_gpu_emulation;
51
45 std::vector<QString> vulkan_devices; 52 std::vector<QString> vulkan_devices;
46 u32 vulkan_device{}; 53 u32 vulkan_device{};
47}; 54};
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui
index 62418fc14..62aa337e7 100644
--- a/src/yuzu/configuration/configure_graphics.ui
+++ b/src/yuzu/configuration/configure_graphics.ui
@@ -6,7 +6,7 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>400</width> 9 <width>437</width>
10 <height>321</height> 10 <height>321</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
@@ -23,43 +23,56 @@
23 </property> 23 </property>
24 <layout class="QVBoxLayout" name="verticalLayout_3"> 24 <layout class="QVBoxLayout" name="verticalLayout_3">
25 <item> 25 <item>
26 <layout class="QHBoxLayout" name="horizontalLayout_4"> 26 <widget class="QWidget" name="api_layout" native="true">
27 <item> 27 <layout class="QGridLayout" name="gridLayout">
28 <widget class="QLabel" name="label_2"> 28 <property name="leftMargin">
29 <property name="text"> 29 <number>0</number>
30 <string>API:</string> 30 </property>
31 </property> 31 <property name="topMargin">
32 </widget> 32 <number>0</number>
33 </item> 33 </property>
34 <item> 34 <property name="rightMargin">
35 <widget class="QComboBox" name="api"> 35 <number>0</number>
36 <item> 36 </property>
37 <property name="bottomMargin">
38 <number>0</number>
39 </property>
40 <property name="horizontalSpacing">
41 <number>6</number>
42 </property>
43 <item row="0" column="0">
44 <widget class="QLabel" name="api_label">
37 <property name="text"> 45 <property name="text">
38 <string notr="true">OpenGL</string> 46 <string>API:</string>
39 </property> 47 </property>
40 </item> 48 </widget>
41 <item> 49 </item>
50 <item row="0" column="1">
51 <widget class="QComboBox" name="api">
52 <item>
53 <property name="text">
54 <string notr="true">OpenGL</string>
55 </property>
56 </item>
57 <item>
58 <property name="text">
59 <string notr="true">Vulkan</string>
60 </property>
61 </item>
62 </widget>
63 </item>
64 <item row="1" column="0">
65 <widget class="QLabel" name="device_label">
42 <property name="text"> 66 <property name="text">
43 <string notr="true">Vulkan</string> 67 <string>Device:</string>
44 </property> 68 </property>
45 </item> 69 </widget>
46 </widget> 70 </item>
47 </item> 71 <item row="1" column="1">
48 </layout> 72 <widget class="QComboBox" name="device"/>
49 </item> 73 </item>
50 <item> 74 </layout>
51 <layout class="QHBoxLayout" name="horizontalLayout_5"> 75 </widget>
52 <item>
53 <widget class="QLabel" name="label_3">
54 <property name="text">
55 <string>Device:</string>
56 </property>
57 </widget>
58 </item>
59 <item>
60 <widget class="QComboBox" name="device"/>
61 </item>
62 </layout>
63 </item> 76 </item>
64 </layout> 77 </layout>
65 </widget> 78 </widget>
@@ -85,96 +98,133 @@
85 </widget> 98 </widget>
86 </item> 99 </item>
87 <item> 100 <item>
88 <layout class="QHBoxLayout" name="horizontalLayout_6"> 101 <widget class="QWidget" name="aspect_ratio_layout" native="true">
89 <item> 102 <layout class="QHBoxLayout" name="horizontalLayout_6">
90 <widget class="QLabel" name="ar_label"> 103 <property name="leftMargin">
91 <property name="text"> 104 <number>0</number>
92 <string>Aspect Ratio:</string> 105 </property>
93 </property> 106 <property name="topMargin">
94 </widget> 107 <number>0</number>
95 </item> 108 </property>
96 <item> 109 <property name="rightMargin">
97 <widget class="QComboBox" name="aspect_ratio_combobox"> 110 <number>0</number>
98 <item> 111 </property>
99 <property name="text"> 112 <property name="bottomMargin">
100 <string>Default (16:9)</string> 113 <number>0</number>
101 </property> 114 </property>
102 </item> 115 <item>
103 <item> 116 <widget class="QLabel" name="ar_label">
104 <property name="text">
105 <string>Force 4:3</string>
106 </property>
107 </item>
108 <item>
109 <property name="text">
110 <string>Force 21:9</string>
111 </property>
112 </item>
113 <item>
114 <property name="text"> 117 <property name="text">
115 <string>Stretch to Window</string> 118 <string>Aspect Ratio:</string>
116 </property> 119 </property>
117 </item> 120 </widget>
118 </widget> 121 </item>
119 </item> 122 <item>
120 </layout> 123 <widget class="QComboBox" name="aspect_ratio_combobox">
124 <item>
125 <property name="text">
126 <string>Default (16:9)</string>
127 </property>
128 </item>
129 <item>
130 <property name="text">
131 <string>Force 4:3</string>
132 </property>
133 </item>
134 <item>
135 <property name="text">
136 <string>Force 21:9</string>
137 </property>
138 </item>
139 <item>
140 <property name="text">
141 <string>Stretch to Window</string>
142 </property>
143 </item>
144 </widget>
145 </item>
146 </layout>
147 </widget>
121 </item> 148 </item>
122 <item> 149 <item>
123 <layout class="QHBoxLayout" name="horizontalLayout_3"> 150 <widget class="QWidget" name="bg_layout" native="true">
124 <item> 151 <property name="sizePolicy">
125 <widget class="QComboBox" name="bg_combobox"> 152 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
126 <property name="currentText"> 153 <horstretch>0</horstretch>
127 <string>Use global background color</string> 154 <verstretch>0</verstretch>
128 </property> 155 </sizepolicy>
129 <property name="currentIndex"> 156 </property>
130 <number>0</number> 157 <layout class="QHBoxLayout" name="horizontalLayout_3">
131 </property> 158 <property name="spacing">
132 <property name="maxVisibleItems"> 159 <number>6</number>
133 <number>10</number> 160 </property>
134 </property> 161 <property name="leftMargin">
135 <item> 162 <number>0</number>
136 <property name="text"> 163 </property>
164 <property name="topMargin">
165 <number>0</number>
166 </property>
167 <property name="rightMargin">
168 <number>0</number>
169 </property>
170 <property name="bottomMargin">
171 <number>0</number>
172 </property>
173 <item>
174 <widget class="QComboBox" name="bg_combobox">
175 <property name="currentText">
137 <string>Use global background color</string> 176 <string>Use global background color</string>
138 </property> 177 </property>
139 </item> 178 <property name="currentIndex">
140 <item> 179 <number>0</number>
180 </property>
181 <property name="maxVisibleItems">
182 <number>10</number>
183 </property>
184 <item>
185 <property name="text">
186 <string>Use global background color</string>
187 </property>
188 </item>
189 <item>
190 <property name="text">
191 <string>Set background color:</string>
192 </property>
193 </item>
194 </widget>
195 </item>
196 <item>
197 <widget class="QLabel" name="bg_label">
141 <property name="text"> 198 <property name="text">
142 <string>Set background color:</string> 199 <string>Background Color:</string>
143 </property> 200 </property>
144 </item> 201 </widget>
145 </widget> 202 </item>
146 </item> 203 <item>
147 <item> 204 <spacer name="horizontalSpacer">
148 <widget class="QLabel" name="bg_label"> 205 <property name="orientation">
149 <property name="text"> 206 <enum>Qt::Horizontal</enum>
150 <string>Background Color:</string> 207 </property>
151 </property> 208 <property name="sizeHint" stdset="0">
152 </widget> 209 <size>
153 </item> 210 <width>40</width>
154 <item> 211 <height>20</height>
155 <spacer name="horizontalSpacer"> 212 </size>
156 <property name="orientation"> 213 </property>
157 <enum>Qt::Horizontal</enum> 214 </spacer>
158 </property> 215 </item>
159 <property name="sizeHint" stdset="0"> 216 <item>
160 <size> 217 <widget class="QPushButton" name="bg_button">
161 <width>40</width> 218 <property name="maximumSize">
162 <height>20</height> 219 <size>
163 </size> 220 <width>40</width>
164 </property> 221 <height>16777215</height>
165 </spacer> 222 </size>
166 </item> 223 </property>
167 <item> 224 </widget>
168 <widget class="QPushButton" name="bg_button"> 225 </item>
169 <property name="maximumSize"> 226 </layout>
170 <size> 227 </widget>
171 <width>40</width>
172 <height>16777215</height>
173 </size>
174 </property>
175 </widget>
176 </item>
177 </layout>
178 </item> 228 </item>
179 </layout> 229 </layout>
180 </widget> 230 </widget>
diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp
index ce30188cd..c5d1a778c 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.cpp
+++ b/src/yuzu/configuration/configure_graphics_advanced.cpp
@@ -25,35 +25,26 @@ void ConfigureGraphicsAdvanced::SetConfiguration() {
25 ui->use_vsync->setEnabled(runtime_lock); 25 ui->use_vsync->setEnabled(runtime_lock);
26 ui->use_assembly_shaders->setEnabled(runtime_lock); 26 ui->use_assembly_shaders->setEnabled(runtime_lock);
27 ui->use_asynchronous_shaders->setEnabled(runtime_lock); 27 ui->use_asynchronous_shaders->setEnabled(runtime_lock);
28 ui->force_30fps_mode->setEnabled(runtime_lock);
29 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock); 28 ui->anisotropic_filtering_combobox->setEnabled(runtime_lock);
30 29
30 ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
31 ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue());
32 ui->use_asynchronous_shaders->setChecked(Settings::values.use_asynchronous_shaders.GetValue());
33 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
34
31 if (Settings::configuring_global) { 35 if (Settings::configuring_global) {
32 ui->gpu_accuracy->setCurrentIndex( 36 ui->gpu_accuracy->setCurrentIndex(
33 static_cast<int>(Settings::values.gpu_accuracy.GetValue())); 37 static_cast<int>(Settings::values.gpu_accuracy.GetValue()));
34 ui->use_vsync->setChecked(Settings::values.use_vsync.GetValue());
35 ui->use_assembly_shaders->setChecked(Settings::values.use_assembly_shaders.GetValue());
36 ui->use_asynchronous_shaders->setChecked(
37 Settings::values.use_asynchronous_shaders.GetValue());
38 ui->use_fast_gpu_time->setChecked(Settings::values.use_fast_gpu_time.GetValue());
39 ui->force_30fps_mode->setChecked(Settings::values.force_30fps_mode.GetValue());
40 ui->anisotropic_filtering_combobox->setCurrentIndex( 38 ui->anisotropic_filtering_combobox->setCurrentIndex(
41 Settings::values.max_anisotropy.GetValue()); 39 Settings::values.max_anisotropy.GetValue());
42 } else { 40 } else {
43 ConfigurationShared::SetPerGameSetting(ui->gpu_accuracy, &Settings::values.gpu_accuracy); 41 ConfigurationShared::SetPerGameSetting(ui->gpu_accuracy, &Settings::values.gpu_accuracy);
44 ConfigurationShared::SetPerGameSetting(ui->use_vsync, &Settings::values.use_vsync);
45 ConfigurationShared::SetPerGameSetting(ui->use_assembly_shaders,
46 &Settings::values.use_assembly_shaders);
47 ConfigurationShared::SetPerGameSetting(ui->use_asynchronous_shaders,
48 &Settings::values.use_asynchronous_shaders);
49 ConfigurationShared::SetPerGameSetting(ui->use_asynchronous_shaders,
50 &Settings::values.use_asynchronous_shaders);
51 ConfigurationShared::SetPerGameSetting(ui->use_fast_gpu_time,
52 &Settings::values.use_fast_gpu_time);
53 ConfigurationShared::SetPerGameSetting(ui->force_30fps_mode,
54 &Settings::values.force_30fps_mode);
55 ConfigurationShared::SetPerGameSetting(ui->anisotropic_filtering_combobox, 42 ConfigurationShared::SetPerGameSetting(ui->anisotropic_filtering_combobox,
56 &Settings::values.max_anisotropy); 43 &Settings::values.max_anisotropy);
44 ConfigurationShared::SetHighlight(ui->label_gpu_accuracy, "label_gpu_accuracy",
45 !Settings::values.gpu_accuracy.UsingGlobal());
46 ConfigurationShared::SetHighlight(ui->af_label, "af_label",
47 !Settings::values.max_anisotropy.UsingGlobal());
57 } 48 }
58} 49}
59 50
@@ -85,9 +76,6 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
85 if (Settings::values.use_fast_gpu_time.UsingGlobal()) { 76 if (Settings::values.use_fast_gpu_time.UsingGlobal()) {
86 Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked()); 77 Settings::values.use_fast_gpu_time.SetValue(ui->use_fast_gpu_time->isChecked());
87 } 78 }
88 if (Settings::values.force_30fps_mode.UsingGlobal()) {
89 Settings::values.force_30fps_mode.SetValue(ui->force_30fps_mode->isChecked());
90 }
91 if (Settings::values.max_anisotropy.UsingGlobal()) { 79 if (Settings::values.max_anisotropy.UsingGlobal()) {
92 Settings::values.max_anisotropy.SetValue( 80 Settings::values.max_anisotropy.SetValue(
93 ui->anisotropic_filtering_combobox->currentIndex()); 81 ui->anisotropic_filtering_combobox->currentIndex());
@@ -95,17 +83,15 @@ void ConfigureGraphicsAdvanced::ApplyConfiguration() {
95 } else { 83 } else {
96 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, 84 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
97 ui->anisotropic_filtering_combobox); 85 ui->anisotropic_filtering_combobox);
98 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync); 86 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_vsync, ui->use_vsync,
87 use_vsync);
99 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders, 88 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_assembly_shaders,
100 ui->use_assembly_shaders); 89 ui->use_assembly_shaders, use_assembly_shaders);
101 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
102 ui->use_asynchronous_shaders);
103 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders, 90 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_asynchronous_shaders,
104 ui->use_asynchronous_shaders); 91 ui->use_asynchronous_shaders,
92 use_asynchronous_shaders);
105 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time, 93 ConfigurationShared::ApplyPerGameSetting(&Settings::values.use_fast_gpu_time,
106 ui->use_fast_gpu_time); 94 ui->use_fast_gpu_time, use_fast_gpu_time);
107 ConfigurationShared::ApplyPerGameSetting(&Settings::values.force_30fps_mode,
108 ui->force_30fps_mode);
109 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy, 95 ConfigurationShared::ApplyPerGameSetting(&Settings::values.max_anisotropy,
110 ui->anisotropic_filtering_combobox); 96 ui->anisotropic_filtering_combobox);
111 97
@@ -139,18 +125,26 @@ void ConfigureGraphicsAdvanced::SetupPerGameUI() {
139 ui->use_asynchronous_shaders->setEnabled( 125 ui->use_asynchronous_shaders->setEnabled(
140 Settings::values.use_asynchronous_shaders.UsingGlobal()); 126 Settings::values.use_asynchronous_shaders.UsingGlobal());
141 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal()); 127 ui->use_fast_gpu_time->setEnabled(Settings::values.use_fast_gpu_time.UsingGlobal());
142 ui->force_30fps_mode->setEnabled(Settings::values.force_30fps_mode.UsingGlobal());
143 ui->anisotropic_filtering_combobox->setEnabled( 128 ui->anisotropic_filtering_combobox->setEnabled(
144 Settings::values.max_anisotropy.UsingGlobal()); 129 Settings::values.max_anisotropy.UsingGlobal());
145 130
146 return; 131 return;
147 } 132 }
148 133
149 ConfigurationShared::InsertGlobalItem(ui->gpu_accuracy); 134 ConfigurationShared::SetColoredTristate(ui->use_vsync, "use_vsync", Settings::values.use_vsync,
150 ui->use_vsync->setTristate(true); 135 use_vsync);
151 ui->use_assembly_shaders->setTristate(true); 136 ConfigurationShared::SetColoredTristate(ui->use_assembly_shaders, "use_assembly_shaders",
152 ui->use_asynchronous_shaders->setTristate(true); 137 Settings::values.use_assembly_shaders,
153 ui->use_fast_gpu_time->setTristate(true); 138 use_assembly_shaders);
154 ui->force_30fps_mode->setTristate(true); 139 ConfigurationShared::SetColoredTristate(
155 ConfigurationShared::InsertGlobalItem(ui->anisotropic_filtering_combobox); 140 ui->use_asynchronous_shaders, "use_asynchronous_shaders",
141 Settings::values.use_asynchronous_shaders, use_asynchronous_shaders);
142 ConfigurationShared::SetColoredTristate(ui->use_fast_gpu_time, "use_fast_gpu_time",
143 Settings::values.use_fast_gpu_time, use_fast_gpu_time);
144 ConfigurationShared::SetColoredComboBox(
145 ui->gpu_accuracy, ui->label_gpu_accuracy, "label_gpu_accuracy",
146 static_cast<int>(Settings::values.gpu_accuracy.GetValue(true)));
147 ConfigurationShared::SetColoredComboBox(
148 ui->anisotropic_filtering_combobox, ui->af_label, "af_label",
149 static_cast<int>(Settings::values.max_anisotropy.GetValue(true)));
156} 150}
diff --git a/src/yuzu/configuration/configure_graphics_advanced.h b/src/yuzu/configuration/configure_graphics_advanced.h
index c043588ff..e61b571c7 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.h
+++ b/src/yuzu/configuration/configure_graphics_advanced.h
@@ -7,6 +7,10 @@
7#include <memory> 7#include <memory>
8#include <QWidget> 8#include <QWidget>
9 9
10namespace ConfigurationShared {
11enum class CheckState;
12}
13
10namespace Ui { 14namespace Ui {
11class ConfigureGraphicsAdvanced; 15class ConfigureGraphicsAdvanced;
12} 16}
@@ -29,4 +33,9 @@ private:
29 void SetupPerGameUI(); 33 void SetupPerGameUI();
30 34
31 std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui; 35 std::unique_ptr<Ui::ConfigureGraphicsAdvanced> ui;
36
37 ConfigurationShared::CheckState use_vsync;
38 ConfigurationShared::CheckState use_assembly_shaders;
39 ConfigurationShared::CheckState use_asynchronous_shaders;
40 ConfigurationShared::CheckState use_fast_gpu_time;
32}; 41};
diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui
index 71e7dfe5e..a793c803d 100644
--- a/src/yuzu/configuration/configure_graphics_advanced.ui
+++ b/src/yuzu/configuration/configure_graphics_advanced.ui
@@ -6,7 +6,7 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>400</width> 9 <width>404</width>
10 <height>321</height> 10 <height>321</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
@@ -23,34 +23,48 @@
23 </property> 23 </property>
24 <layout class="QVBoxLayout" name="verticalLayout_3"> 24 <layout class="QVBoxLayout" name="verticalLayout_3">
25 <item> 25 <item>
26 <layout class="QHBoxLayout" name="horizontalLayout_2"> 26 <widget class="QWidget" name="gpu_accuracy_layout" native="true">
27 <item> 27 <layout class="QHBoxLayout" name="horizontalLayout_2">
28 <widget class="QLabel" name="label_gpu_accuracy"> 28 <property name="leftMargin">
29 <property name="text"> 29 <number>0</number>
30 <string>Accuracy Level:</string> 30 </property>
31 </property> 31 <property name="topMargin">
32 </widget> 32 <number>0</number>
33 </item> 33 </property>
34 <item> 34 <property name="rightMargin">
35 <widget class="QComboBox" name="gpu_accuracy"> 35 <number>0</number>
36 <item> 36 </property>
37 <property name="bottomMargin">
38 <number>0</number>
39 </property>
40 <item>
41 <widget class="QLabel" name="label_gpu_accuracy">
37 <property name="text"> 42 <property name="text">
38 <string notr="true">Normal</string> 43 <string>Accuracy Level:</string>
39 </property> 44 </property>
40 </item> 45 </widget>
41 <item> 46 </item>
42 <property name="text"> 47 <item>
43 <string notr="true">High</string> 48 <widget class="QComboBox" name="gpu_accuracy">
44 </property> 49 <item>
45 </item> 50 <property name="text">
46 <item> 51 <string notr="true">Normal</string>
47 <property name="text"> 52 </property>
48 <string notr="true">Extreme(very slow)</string> 53 </item>
49 </property> 54 <item>
50 </item> 55 <property name="text">
51 </widget> 56 <string notr="true">High</string>
52 </item> 57 </property>
53 </layout> 58 </item>
59 <item>
60 <property name="text">
61 <string notr="true">Extreme(very slow)</string>
62 </property>
63 </item>
64 </widget>
65 </item>
66 </layout>
67 </widget>
54 </item> 68 </item>
55 <item> 69 <item>
56 <widget class="QCheckBox" name="use_vsync"> 70 <widget class="QCheckBox" name="use_vsync">
@@ -83,13 +97,6 @@
83 </widget> 97 </widget>
84 </item> 98 </item>
85 <item> 99 <item>
86 <widget class="QCheckBox" name="force_30fps_mode">
87 <property name="text">
88 <string>Force 30 FPS mode</string>
89 </property>
90 </widget>
91 </item>
92 <item>
93 <widget class="QCheckBox" name="use_fast_gpu_time"> 100 <widget class="QCheckBox" name="use_fast_gpu_time">
94 <property name="text"> 101 <property name="text">
95 <string>Use Fast GPU Time</string> 102 <string>Use Fast GPU Time</string>
@@ -97,44 +104,58 @@
97 </widget> 104 </widget>
98 </item> 105 </item>
99 <item> 106 <item>
100 <layout class="QHBoxLayout" name="horizontalLayout_1"> 107 <widget class="QWidget" name="af_layout" native="true">
101 <item> 108 <layout class="QHBoxLayout" name="horizontalLayout_1">
102 <widget class="QLabel" name="af_label"> 109 <property name="leftMargin">
103 <property name="text"> 110 <number>0</number>
104 <string>Anisotropic Filtering:</string> 111 </property>
105 </property> 112 <property name="topMargin">
106 </widget> 113 <number>0</number>
107 </item> 114 </property>
108 <item> 115 <property name="rightMargin">
109 <widget class="QComboBox" name="anisotropic_filtering_combobox"> 116 <number>0</number>
110 <item> 117 </property>
118 <property name="bottomMargin">
119 <number>0</number>
120 </property>
121 <item>
122 <widget class="QLabel" name="af_label">
111 <property name="text"> 123 <property name="text">
112 <string>Default</string> 124 <string>Anisotropic Filtering:</string>
113 </property> 125 </property>
114 </item> 126 </widget>
115 <item> 127 </item>
116 <property name="text"> 128 <item>
117 <string>2x</string> 129 <widget class="QComboBox" name="anisotropic_filtering_combobox">
118 </property> 130 <item>
119 </item> 131 <property name="text">
120 <item> 132 <string>Default</string>
121 <property name="text"> 133 </property>
122 <string>4x</string> 134 </item>
123 </property> 135 <item>
124 </item> 136 <property name="text">
125 <item> 137 <string>2x</string>
126 <property name="text"> 138 </property>
127 <string>8x</string> 139 </item>
128 </property> 140 <item>
129 </item> 141 <property name="text">
130 <item> 142 <string>4x</string>
131 <property name="text"> 143 </property>
132 <string>16x</string> 144 </item>
133 </property> 145 <item>
134 </item> 146 <property name="text">
135 </widget> 147 <string>8x</string>
136 </item> 148 </property>
137 </layout> 149 </item>
150 <item>
151 <property name="text">
152 <string>16x</string>
153 </property>
154 </item>
155 </widget>
156 </item>
157 </layout>
158 </widget>
138 </item> 159 </item>
139 </layout> 160 </layout>
140 </widget> 161 </widget>
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 00433926d..b1850bc95 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -280,9 +280,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
280 } 280 }
281 281
282 button->setContextMenuPolicy(Qt::CustomContextMenu); 282 button->setContextMenuPolicy(Qt::CustomContextMenu);
283 connect(button, &QPushButton::clicked, [=] { 283 connect(button, &QPushButton::clicked, [=, this] {
284 HandleClick(button_map[button_id], 284 HandleClick(button_map[button_id],
285 [=](Common::ParamPackage params) { 285 [=, this](Common::ParamPackage params) {
286 // Workaround for ZL & ZR for analog triggers like on XBOX controllors. 286 // Workaround for ZL & ZR for analog triggers like on XBOX controllors.
287 // Analog triggers (from controllers like the XBOX controller) would not 287 // Analog triggers (from controllers like the XBOX controller) would not
288 // work due to a different range of their signals (from 0 to 255 on 288 // work due to a different range of their signals (from 0 to 255 on
@@ -300,19 +300,20 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
300 }, 300 },
301 InputCommon::Polling::DeviceType::Button); 301 InputCommon::Polling::DeviceType::Button);
302 }); 302 });
303 connect(button, &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) { 303 connect(button, &QPushButton::customContextMenuRequested,
304 QMenu context_menu; 304 [=, this](const QPoint& menu_location) {
305 context_menu.addAction(tr("Clear"), [&] { 305 QMenu context_menu;
306 buttons_param[button_id].Clear(); 306 context_menu.addAction(tr("Clear"), [&] {
307 button_map[button_id]->setText(tr("[not set]")); 307 buttons_param[button_id].Clear();
308 }); 308 button_map[button_id]->setText(tr("[not set]"));
309 context_menu.addAction(tr("Restore Default"), [&] { 309 });
310 buttons_param[button_id] = Common::ParamPackage{ 310 context_menu.addAction(tr("Restore Default"), [&] {
311 InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; 311 buttons_param[button_id] = Common::ParamPackage{
312 button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); 312 InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
313 }); 313 button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
314 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); 314 });
315 }); 315 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
316 });
316 } 317 }
317 318
318 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) { 319 for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; analog_id++) {
@@ -323,16 +324,16 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
323 } 324 }
324 325
325 analog_button->setContextMenuPolicy(Qt::CustomContextMenu); 326 analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
326 connect(analog_button, &QPushButton::clicked, [=]() { 327 connect(analog_button, &QPushButton::clicked, [=, this] {
327 HandleClick(analog_map_buttons[analog_id][sub_button_id], 328 HandleClick(analog_map_buttons[analog_id][sub_button_id],
328 [=](const Common::ParamPackage& params) { 329 [=, this](const Common::ParamPackage& params) {
329 SetAnalogButton(params, analogs_param[analog_id], 330 SetAnalogButton(params, analogs_param[analog_id],
330 analog_sub_buttons[sub_button_id]); 331 analog_sub_buttons[sub_button_id]);
331 }, 332 },
332 InputCommon::Polling::DeviceType::Button); 333 InputCommon::Polling::DeviceType::Button);
333 }); 334 });
334 connect(analog_button, &QPushButton::customContextMenuRequested, 335 connect(analog_button, &QPushButton::customContextMenuRequested,
335 [=](const QPoint& menu_location) { 336 [=, this](const QPoint& menu_location) {
336 QMenu context_menu; 337 QMenu context_menu;
337 context_menu.addAction(tr("Clear"), [&] { 338 context_menu.addAction(tr("Clear"), [&] {
338 analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); 339 analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
@@ -350,32 +351,35 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
350 menu_location)); 351 menu_location));
351 }); 352 });
352 } 353 }
353 connect(analog_map_stick[analog_id], &QPushButton::clicked, [=] { 354 connect(analog_map_stick[analog_id], &QPushButton::clicked, [=, this] {
354 if (QMessageBox::information( 355 if (QMessageBox::information(
355 this, tr("Information"), 356 this, tr("Information"),
356 tr("After pressing OK, first move your joystick horizontally, " 357 tr("After pressing OK, first move your joystick horizontally, "
357 "and then vertically."), 358 "and then vertically."),
358 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { 359 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
359 HandleClick( 360 HandleClick(analog_map_stick[analog_id],
360 analog_map_stick[analog_id], 361 [=, this](const Common::ParamPackage& params) {
361 [=](const Common::ParamPackage& params) { analogs_param[analog_id] = params; }, 362 analogs_param[analog_id] = params;
362 InputCommon::Polling::DeviceType::Analog); 363 },
364 InputCommon::Polling::DeviceType::Analog);
363 } 365 }
364 }); 366 });
365 367
366 connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, [=] { 368 connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged,
367 const float slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value(); 369 [=, this] {
368 if (analogs_param[analog_id].Get("engine", "") == "sdl" || 370 const float slider_value =
369 analogs_param[analog_id].Get("engine", "") == "gcpad") { 371 analog_map_deadzone_and_modifier_slider[analog_id]->value();
370 analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( 372 if (analogs_param[analog_id].Get("engine", "") == "sdl" ||
371 tr("Deadzone: %1%").arg(slider_value)); 373 analogs_param[analog_id].Get("engine", "") == "gcpad") {
372 analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); 374 analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
373 } else { 375 tr("Deadzone: %1%").arg(slider_value));
374 analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( 376 analogs_param[analog_id].Set("deadzone", slider_value / 100.0f);
375 tr("Modifier Scale: %1%").arg(slider_value)); 377 } else {
376 analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f); 378 analog_map_deadzone_and_modifier_slider_label[analog_id]->setText(
377 } 379 tr("Modifier Scale: %1%").arg(slider_value));
378 }); 380 analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f);
381 }
382 });
379 } 383 }
380 384
381 connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); 385 connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp
index e0647ea5b..ea2549363 100644
--- a/src/yuzu/configuration/configure_mouse_advanced.cpp
+++ b/src/yuzu/configuration/configure_mouse_advanced.cpp
@@ -83,25 +83,28 @@ ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent)
83 } 83 }
84 84
85 button->setContextMenuPolicy(Qt::CustomContextMenu); 85 button->setContextMenuPolicy(Qt::CustomContextMenu);
86 connect(button, &QPushButton::clicked, [=] { 86 connect(button, &QPushButton::clicked, [=, this] {
87 HandleClick( 87 HandleClick(button_map[button_id],
88 button_map[button_id], 88 [=, this](const Common::ParamPackage& params) {
89 [=](const Common::ParamPackage& params) { buttons_param[button_id] = params; }, 89 buttons_param[button_id] = params;
90 InputCommon::Polling::DeviceType::Button); 90 },
91 }); 91 InputCommon::Polling::DeviceType::Button);
92 connect(button, &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) {
93 QMenu context_menu;
94 context_menu.addAction(tr("Clear"), [&] {
95 buttons_param[button_id].Clear();
96 button_map[button_id]->setText(tr("[not set]"));
97 });
98 context_menu.addAction(tr("Restore Default"), [&] {
99 buttons_param[button_id] = Common::ParamPackage{
100 InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])};
101 button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
102 });
103 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
104 }); 92 });
93 connect(button, &QPushButton::customContextMenuRequested,
94 [=, this](const QPoint& menu_location) {
95 QMenu context_menu;
96 context_menu.addAction(tr("Clear"), [&] {
97 buttons_param[button_id].Clear();
98 button_map[button_id]->setText(tr("[not set]"));
99 });
100 context_menu.addAction(tr("Restore Default"), [&] {
101 buttons_param[button_id] =
102 Common::ParamPackage{InputCommon::GenerateKeyboardParam(
103 Config::default_mouse_buttons[button_id])};
104 button_map[button_id]->setText(ButtonToText(buttons_param[button_id]));
105 });
106 context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
107 });
105 } 108 }
106 109
107 connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); 110 connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp
index 68e02738b..0c4daf147 100644
--- a/src/yuzu/configuration/configure_system.cpp
+++ b/src/yuzu/configuration/configure_system.cpp
@@ -67,21 +67,21 @@ void ConfigureSystem::SetConfiguration() {
67 const auto rtc_time = Settings::values.custom_rtc.GetValue().value_or( 67 const auto rtc_time = Settings::values.custom_rtc.GetValue().value_or(
68 std::chrono::seconds(QDateTime::currentSecsSinceEpoch())); 68 std::chrono::seconds(QDateTime::currentSecsSinceEpoch()));
69 69
70 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
71 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() &&
72 Settings::values.rng_seed.UsingGlobal());
73 ui->rng_seed_edit->setText(rng_seed);
74
75 ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value());
76 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() &&
77 Settings::values.rng_seed.UsingGlobal());
78 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
79
70 if (Settings::configuring_global) { 80 if (Settings::configuring_global) {
71 ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); 81 ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue());
72 ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue()); 82 ui->combo_region->setCurrentIndex(Settings::values.region_index.GetValue());
73 ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue()); 83 ui->combo_time_zone->setCurrentIndex(Settings::values.time_zone_index.GetValue());
74 ui->combo_sound->setCurrentIndex(Settings::values.sound_index.GetValue()); 84 ui->combo_sound->setCurrentIndex(Settings::values.sound_index.GetValue());
75
76 ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value());
77 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() &&
78 Settings::values.rng_seed.UsingGlobal());
79 ui->rng_seed_edit->setText(rng_seed);
80
81 ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.GetValue().has_value());
82 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value() &&
83 Settings::values.rng_seed.UsingGlobal());
84 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
85 } else { 85 } else {
86 ConfigurationShared::SetPerGameSetting(ui->combo_language, 86 ConfigurationShared::SetPerGameSetting(ui->combo_language,
87 &Settings::values.language_index); 87 &Settings::values.language_index);
@@ -90,27 +90,14 @@ void ConfigureSystem::SetConfiguration() {
90 &Settings::values.time_zone_index); 90 &Settings::values.time_zone_index);
91 ConfigurationShared::SetPerGameSetting(ui->combo_sound, &Settings::values.sound_index); 91 ConfigurationShared::SetPerGameSetting(ui->combo_sound, &Settings::values.sound_index);
92 92
93 if (Settings::values.rng_seed.UsingGlobal()) { 93 ConfigurationShared::SetHighlight(ui->label_language, "label_language",
94 ui->rng_seed_checkbox->setCheckState(Qt::PartiallyChecked); 94 !Settings::values.language_index.UsingGlobal());
95 } else { 95 ConfigurationShared::SetHighlight(ui->label_region, "label_region",
96 ui->rng_seed_checkbox->setCheckState( 96 !Settings::values.region_index.UsingGlobal());
97 Settings::values.rng_seed.GetValue().has_value() ? Qt::Checked : Qt::Unchecked); 97 ConfigurationShared::SetHighlight(ui->label_timezone, "label_timezone",
98 ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value()); 98 !Settings::values.time_zone_index.UsingGlobal());
99 if (Settings::values.rng_seed.GetValue().has_value()) { 99 ConfigurationShared::SetHighlight(ui->label_sound, "label_sound",
100 ui->rng_seed_edit->setText(rng_seed); 100 !Settings::values.sound_index.UsingGlobal());
101 }
102 }
103
104 if (Settings::values.custom_rtc.UsingGlobal()) {
105 ui->custom_rtc_checkbox->setCheckState(Qt::PartiallyChecked);
106 } else {
107 ui->custom_rtc_checkbox->setCheckState(
108 Settings::values.custom_rtc.GetValue().has_value() ? Qt::Checked : Qt::Unchecked);
109 ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.GetValue().has_value());
110 if (Settings::values.custom_rtc.GetValue().has_value()) {
111 ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count()));
112 }
113 }
114 } 101 }
115} 102}
116 103
@@ -161,37 +148,44 @@ void ConfigureSystem::ApplyConfiguration() {
161 ui->combo_time_zone); 148 ui->combo_time_zone);
162 ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound); 149 ConfigurationShared::ApplyPerGameSetting(&Settings::values.sound_index, ui->combo_sound);
163 150
164 switch (ui->rng_seed_checkbox->checkState()) { 151 switch (use_rng_seed) {
165 case Qt::Checked: 152 case ConfigurationShared::CheckState::On:
166 Settings::values.rng_seed.SetGlobal(false); 153 case ConfigurationShared::CheckState::Off:
167 Settings::values.rng_seed.SetValue(ui->rng_seed_edit->text().toULongLong(nullptr, 16));
168 break;
169 case Qt::Unchecked:
170 Settings::values.rng_seed.SetGlobal(false); 154 Settings::values.rng_seed.SetGlobal(false);
171 Settings::values.rng_seed.SetValue(std::nullopt); 155 if (ui->rng_seed_checkbox->isChecked()) {
156 Settings::values.rng_seed.SetValue(
157 ui->rng_seed_edit->text().toULongLong(nullptr, 16));
158 } else {
159 Settings::values.rng_seed.SetValue(std::nullopt);
160 }
172 break; 161 break;
173 case Qt::PartiallyChecked: 162 case ConfigurationShared::CheckState::Global:
174 Settings::values.rng_seed.SetGlobal(false); 163 Settings::values.rng_seed.SetGlobal(false);
175 Settings::values.rng_seed.SetValue(std::nullopt); 164 Settings::values.rng_seed.SetValue(std::nullopt);
176 Settings::values.rng_seed.SetGlobal(true); 165 Settings::values.rng_seed.SetGlobal(true);
177 break; 166 break;
167 case ConfigurationShared::CheckState::Count:
168 break;
178 } 169 }
179 170
180 switch (ui->custom_rtc_checkbox->checkState()) { 171 switch (use_custom_rtc) {
181 case Qt::Checked: 172 case ConfigurationShared::CheckState::On:
182 Settings::values.custom_rtc.SetGlobal(false); 173 case ConfigurationShared::CheckState::Off:
183 Settings::values.custom_rtc.SetValue(
184 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
185 break;
186 case Qt::Unchecked:
187 Settings::values.custom_rtc.SetGlobal(false); 174 Settings::values.custom_rtc.SetGlobal(false);
188 Settings::values.custom_rtc.SetValue(std::nullopt); 175 if (ui->custom_rtc_checkbox->isChecked()) {
176 Settings::values.custom_rtc.SetValue(
177 std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()));
178 } else {
179 Settings::values.custom_rtc.SetValue(std::nullopt);
180 }
189 break; 181 break;
190 case Qt::PartiallyChecked: 182 case ConfigurationShared::CheckState::Global:
191 Settings::values.custom_rtc.SetGlobal(false); 183 Settings::values.custom_rtc.SetGlobal(false);
192 Settings::values.custom_rtc.SetValue(std::nullopt); 184 Settings::values.custom_rtc.SetValue(std::nullopt);
193 Settings::values.custom_rtc.SetGlobal(true); 185 Settings::values.custom_rtc.SetGlobal(true);
194 break; 186 break;
187 case ConfigurationShared::CheckState::Count:
188 break;
195 } 189 }
196 } 190 }
197 191
@@ -229,10 +223,23 @@ void ConfigureSystem::SetupPerGameUI() {
229 return; 223 return;
230 } 224 }
231 225
232 ConfigurationShared::InsertGlobalItem(ui->combo_language); 226 ConfigurationShared::SetColoredComboBox(ui->combo_language, ui->label_language,
233 ConfigurationShared::InsertGlobalItem(ui->combo_region); 227 "label_language",
234 ConfigurationShared::InsertGlobalItem(ui->combo_time_zone); 228 Settings::values.language_index.GetValue(true));
235 ConfigurationShared::InsertGlobalItem(ui->combo_sound); 229 ConfigurationShared::SetColoredComboBox(ui->combo_region, ui->label_region, "label_region",
236 ui->rng_seed_checkbox->setTristate(true); 230 Settings::values.region_index.GetValue(true));
237 ui->custom_rtc_checkbox->setTristate(true); 231 ConfigurationShared::SetColoredComboBox(ui->combo_time_zone, ui->label_timezone,
232 "label_timezone",
233 Settings::values.time_zone_index.GetValue(true));
234 ConfigurationShared::SetColoredComboBox(ui->combo_sound, ui->label_sound, "label_sound",
235 Settings::values.sound_index.GetValue(true));
236
237 ConfigurationShared::SetColoredTristate(
238 ui->rng_seed_checkbox, "rng_seed_checkbox", Settings::values.rng_seed.UsingGlobal(),
239 Settings::values.rng_seed.GetValue().has_value(),
240 Settings::values.rng_seed.GetValue(true).has_value(), use_rng_seed);
241 ConfigurationShared::SetColoredTristate(
242 ui->custom_rtc_checkbox, "custom_rtc_checkbox", Settings::values.custom_rtc.UsingGlobal(),
243 Settings::values.custom_rtc.GetValue().has_value(),
244 Settings::values.custom_rtc.GetValue(true).has_value(), use_custom_rtc);
238} 245}
diff --git a/src/yuzu/configuration/configure_system.h b/src/yuzu/configuration/configure_system.h
index f317ef8b5..fc5cd2945 100644
--- a/src/yuzu/configuration/configure_system.h
+++ b/src/yuzu/configuration/configure_system.h
@@ -9,6 +9,10 @@
9#include <QList> 9#include <QList>
10#include <QWidget> 10#include <QWidget>
11 11
12namespace ConfigurationShared {
13enum class CheckState;
14}
15
12namespace Ui { 16namespace Ui {
13class ConfigureSystem; 17class ConfigureSystem;
14} 18}
@@ -41,4 +45,7 @@ private:
41 int region_index = 0; 45 int region_index = 0;
42 int time_zone_index = 0; 46 int time_zone_index = 0;
43 int sound_index = 0; 47 int sound_index = 0;
48
49 ConfigurationShared::CheckState use_rng_seed;
50 ConfigurationShared::CheckState use_custom_rtc;
44}; 51};
diff --git a/src/yuzu/configuration/configure_system.ui b/src/yuzu/configuration/configure_system.ui
index 9c8cca6dc..53b95658b 100644
--- a/src/yuzu/configuration/configure_system.ui
+++ b/src/yuzu/configuration/configure_system.ui
@@ -21,490 +21,494 @@
21 <property name="title"> 21 <property name="title">
22 <string>System Settings</string> 22 <string>System Settings</string>
23 </property> 23 </property>
24 <layout class="QGridLayout" name="gridLayout"> 24 <layout class="QVBoxLayout" name="verticalLayout_2">
25 <item row="3" column="0"> 25 <item>
26 <widget class="QLabel" name="label_sound"> 26 <layout class="QGridLayout" name="gridLayout_2">
27 <property name="text"> 27 <item row="1" column="0">
28 <string>Sound output mode</string> 28 <widget class="QLabel" name="label_region">
29 </property> 29 <property name="text">
30 </widget> 30 <string>Region:</string>
31 </item> 31 </property>
32 <item row="4" column="0"> 32 </widget>
33 <widget class="QLabel" name="label_console_id"> 33 </item>
34 <property name="text"> 34 <item row="2" column="1">
35 <string>Console ID:</string> 35 <widget class="QComboBox" name="combo_time_zone">
36 </property> 36 <item>
37 </widget> 37 <property name="text">
38 </item> 38 <string>Auto</string>
39 <item row="0" column="1"> 39 </property>
40 <widget class="QComboBox" name="combo_language"> 40 </item>
41 <property name="toolTip"> 41 <item>
42 <string>Note: this can be overridden when region setting is auto-select</string> 42 <property name="text">
43 </property> 43 <string>Default</string>
44 <item> 44 </property>
45 <property name="text"> 45 </item>
46 <string>Japanese (日本語)</string> 46 <item>
47 </property> 47 <property name="text">
48 </item> 48 <string>CET</string>
49 <item> 49 </property>
50 <property name="text"> 50 </item>
51 <string>English</string> 51 <item>
52 </property> 52 <property name="text">
53 </item> 53 <string>CST6CDT</string>
54 <item> 54 </property>
55 <property name="text"> 55 </item>
56 <string>French (français)</string> 56 <item>
57 </property> 57 <property name="text">
58 </item> 58 <string>Cuba</string>
59 <item> 59 </property>
60 <property name="text"> 60 </item>
61 <string>German (Deutsch)</string> 61 <item>
62 </property> 62 <property name="text">
63 </item> 63 <string>EET</string>
64 <item> 64 </property>
65 <property name="text"> 65 </item>
66 <string>Italian (italiano)</string> 66 <item>
67 </property> 67 <property name="text">
68 </item> 68 <string>Egypt</string>
69 <item> 69 </property>
70 <property name="text"> 70 </item>
71 <string>Spanish (español)</string> 71 <item>
72 </property> 72 <property name="text">
73 </item> 73 <string>Eire</string>
74 <item> 74 </property>
75 <property name="text"> 75 </item>
76 <string>Chinese</string> 76 <item>
77 </property> 77 <property name="text">
78 </item> 78 <string>EST</string>
79 <item> 79 </property>
80 <property name="text"> 80 </item>
81 <string>Korean (한국어)</string> 81 <item>
82 </property> 82 <property name="text">
83 </item> 83 <string>EST5EDT</string>
84 <item> 84 </property>
85 <property name="text"> 85 </item>
86 <string>Dutch (Nederlands)</string> 86 <item>
87 </property> 87 <property name="text">
88 </item> 88 <string>GB</string>
89 <item> 89 </property>
90 <property name="text"> 90 </item>
91 <string>Portuguese (português)</string> 91 <item>
92 </property> 92 <property name="text">
93 </item> 93 <string>GB-Eire</string>
94 <item> 94 </property>
95 <property name="text"> 95 </item>
96 <string>Russian (Русский)</string> 96 <item>
97 </property> 97 <property name="text">
98 </item> 98 <string>GMT</string>
99 <item> 99 </property>
100 <property name="text"> 100 </item>
101 <string>Taiwanese</string> 101 <item>
102 </property> 102 <property name="text">
103 </item> 103 <string>GMT+0</string>
104 <item> 104 </property>
105 <property name="text"> 105 </item>
106 <string>British English</string> 106 <item>
107 </property> 107 <property name="text">
108 </item> 108 <string>GMT-0</string>
109 <item> 109 </property>
110 <property name="text"> 110 </item>
111 <string>Canadian French</string> 111 <item>
112 </property> 112 <property name="text">
113 </item> 113 <string>GMT0</string>
114 <item> 114 </property>
115 <property name="text"> 115 </item>
116 <string>Latin American Spanish</string> 116 <item>
117 </property> 117 <property name="text">
118 </item> 118 <string>Greenwich</string>
119 <item> 119 </property>
120 <property name="text"> 120 </item>
121 <string>Simplified Chinese</string> 121 <item>
122 </property> 122 <property name="text">
123 </item> 123 <string>Hongkong</string>
124 <item> 124 </property>
125 <property name="text"> 125 </item>
126 <string>Traditional Chinese (正體中文)</string> 126 <item>
127 </property> 127 <property name="text">
128 </item> 128 <string>HST</string>
129 </widget> 129 </property>
130 </item> 130 </item>
131 <item row="1" column="0"> 131 <item>
132 <widget class="QLabel" name="label_region"> 132 <property name="text">
133 <property name="text"> 133 <string>Iceland</string>
134 <string>Region:</string> 134 </property>
135 </property> 135 </item>
136 </widget> 136 <item>
137 </item> 137 <property name="text">
138 <item row="1" column="1"> 138 <string>Iran</string>
139 <widget class="QComboBox" name="combo_region"> 139 </property>
140 <item> 140 </item>
141 <property name="text"> 141 <item>
142 <string>Japan</string> 142 <property name="text">
143 </property> 143 <string>Israel</string>
144 </item> 144 </property>
145 <item> 145 </item>
146 <property name="text"> 146 <item>
147 <string>USA</string> 147 <property name="text">
148 </property> 148 <string>Jamaica</string>
149 </item> 149 </property>
150 <item> 150 </item>
151 <property name="text"> 151 <item>
152 <string>Europe</string> 152 <property name="text">
153 </property> 153 <string>Japan</string>
154 </item> 154 </property>
155 <item> 155 </item>
156 <property name="text"> 156 <item>
157 <string>Australia</string> 157 <property name="text">
158 </property> 158 <string>Kwajalein</string>
159 </item> 159 </property>
160 <item> 160 </item>
161 <property name="text"> 161 <item>
162 <string>China</string> 162 <property name="text">
163 </property> 163 <string>Libya</string>
164 </item> 164 </property>
165 <item> 165 </item>
166 <property name="text"> 166 <item>
167 <string>Korea</string> 167 <property name="text">
168 </property> 168 <string>MET</string>
169 </item> 169 </property>
170 <item> 170 </item>
171 <property name="text"> 171 <item>
172 <string>Taiwan</string> 172 <property name="text">
173 </property> 173 <string>MST</string>
174 </item> 174 </property>
175 </widget> 175 </item>
176 </item> 176 <item>
177 <item row="2" column="0"> 177 <property name="text">
178 <widget class="QLabel" name="label_timezone"> 178 <string>MST7MDT</string>
179 <property name="text"> 179 </property>
180 <string>Time Zone:</string> 180 </item>
181 </property> 181 <item>
182 </widget> 182 <property name="text">
183 </item> 183 <string>Navajo</string>
184 <item row="2" column="1"> 184 </property>
185 <widget class="QComboBox" name="combo_time_zone"> 185 </item>
186 <item> 186 <item>
187 <property name="text"> 187 <property name="text">
188 <string>Auto</string> 188 <string>NZ</string>
189 </property> 189 </property>
190 </item> 190 </item>
191 <item> 191 <item>
192 <property name="text"> 192 <property name="text">
193 <string>Default</string> 193 <string>NZ-CHAT</string>
194 </property> 194 </property>
195 </item> 195 </item>
196 <item> 196 <item>
197 <property name="text"> 197 <property name="text">
198 <string>CET</string> 198 <string>Poland</string>
199 </property> 199 </property>
200 </item> 200 </item>
201 <item> 201 <item>
202 <property name="text"> 202 <property name="text">
203 <string>CST6CDT</string> 203 <string>Portugal</string>
204 </property> 204 </property>
205 </item> 205 </item>
206 <item> 206 <item>
207 <property name="text"> 207 <property name="text">
208 <string>Cuba</string> 208 <string>PRC</string>
209 </property> 209 </property>
210 </item> 210 </item>
211 <item> 211 <item>
212 <property name="text"> 212 <property name="text">
213 <string>EET</string> 213 <string>PST8PDT</string>
214 </property> 214 </property>
215 </item> 215 </item>
216 <item> 216 <item>
217 <property name="text"> 217 <property name="text">
218 <string>Egypt</string> 218 <string>ROC</string>
219 </property> 219 </property>
220 </item> 220 </item>
221 <item> 221 <item>
222 <property name="text"> 222 <property name="text">
223 <string>Eire</string> 223 <string>ROK</string>
224 </property> 224 </property>
225 </item> 225 </item>
226 <item> 226 <item>
227 <property name="text"> 227 <property name="text">
228 <string>EST</string> 228 <string>Singapore</string>
229 </property> 229 </property>
230 </item> 230 </item>
231 <item> 231 <item>
232 <property name="text"> 232 <property name="text">
233 <string>EST5EDT</string> 233 <string>Turkey</string>
234 </property> 234 </property>
235 </item> 235 </item>
236 <item> 236 <item>
237 <property name="text"> 237 <property name="text">
238 <string>GB</string> 238 <string>UCT</string>
239 </property> 239 </property>
240 </item> 240 </item>
241 <item> 241 <item>
242 <property name="text"> 242 <property name="text">
243 <string>GB-Eire</string> 243 <string>Universal</string>
244 </property> 244 </property>
245 </item> 245 </item>
246 <item> 246 <item>
247 <property name="text"> 247 <property name="text">
248 <string>GMT</string> 248 <string>UTC</string>
249 </property> 249 </property>
250 </item> 250 </item>
251 <item> 251 <item>
252 <property name="text"> 252 <property name="text">
253 <string>GMT+0</string> 253 <string>W-SU</string>
254 </property> 254 </property>
255 </item> 255 </item>
256 <item> 256 <item>
257 <property name="text"> 257 <property name="text">
258 <string>GMT-0</string> 258 <string>WET</string>
259 </property> 259 </property>
260 </item> 260 </item>
261 <item> 261 <item>
262 <property name="text"> 262 <property name="text">
263 <string>GMT0</string> 263 <string>Zulu</string>
264 </property> 264 </property>
265 </item> 265 </item>
266 <item> 266 </widget>
267 <property name="text"> 267 </item>
268 <string>Greenwich</string> 268 <item row="1" column="1">
269 </property> 269 <widget class="QComboBox" name="combo_region">
270 </item> 270 <item>
271 <item> 271 <property name="text">
272 <property name="text"> 272 <string>Japan</string>
273 <string>Hongkong</string> 273 </property>
274 </property> 274 </item>
275 </item> 275 <item>
276 <item> 276 <property name="text">
277 <property name="text"> 277 <string>USA</string>
278 <string>HST</string> 278 </property>
279 </property> 279 </item>
280 </item> 280 <item>
281 <item> 281 <property name="text">
282 <property name="text"> 282 <string>Europe</string>
283 <string>Iceland</string> 283 </property>
284 </property> 284 </item>
285 </item> 285 <item>
286 <item> 286 <property name="text">
287 <property name="text"> 287 <string>Australia</string>
288 <string>Iran</string> 288 </property>
289 </property> 289 </item>
290 </item> 290 <item>
291 <item> 291 <property name="text">
292 <property name="text"> 292 <string>China</string>
293 <string>Israel</string> 293 </property>
294 </property> 294 </item>
295 </item> 295 <item>
296 <item> 296 <property name="text">
297 <property name="text"> 297 <string>Korea</string>
298 <string>Jamaica</string> 298 </property>
299 </property> 299 </item>
300 </item> 300 <item>
301 <item> 301 <property name="text">
302 <property name="text"> 302 <string>Taiwan</string>
303 <string>Japan</string> 303 </property>
304 </property> 304 </item>
305 </item> 305 </widget>
306 <item> 306 </item>
307 <property name="text"> 307 <item row="2" column="0">
308 <string>Kwajalein</string> 308 <widget class="QLabel" name="label_timezone">
309 </property> 309 <property name="text">
310 </item> 310 <string>Time Zone:</string>
311 <item> 311 </property>
312 <property name="text"> 312 </widget>
313 <string>Libya</string> 313 </item>
314 </property> 314 <item row="0" column="1">
315 </item> 315 <widget class="QComboBox" name="combo_language">
316 <item> 316 <property name="toolTip">
317 <property name="text"> 317 <string>Note: this can be overridden when region setting is auto-select</string>
318 <string>MET</string> 318 </property>
319 </property> 319 <item>
320 </item> 320 <property name="text">
321 <item> 321 <string>Japanese (日本語)</string>
322 <property name="text"> 322 </property>
323 <string>MST</string> 323 </item>
324 </property> 324 <item>
325 </item> 325 <property name="text">
326 <item> 326 <string>English</string>
327 <property name="text"> 327 </property>
328 <string>MST7MDT</string> 328 </item>
329 </property> 329 <item>
330 </item> 330 <property name="text">
331 <item> 331 <string>French (français)</string>
332 <property name="text"> 332 </property>
333 <string>Navajo</string> 333 </item>
334 </property> 334 <item>
335 </item> 335 <property name="text">
336 <item> 336 <string>German (Deutsch)</string>
337 <property name="text"> 337 </property>
338 <string>NZ</string> 338 </item>
339 </property> 339 <item>
340 </item> 340 <property name="text">
341 <item> 341 <string>Italian (italiano)</string>
342 <property name="text"> 342 </property>
343 <string>NZ-CHAT</string> 343 </item>
344 </property> 344 <item>
345 </item> 345 <property name="text">
346 <item> 346 <string>Spanish (español)</string>
347 <property name="text"> 347 </property>
348 <string>Poland</string> 348 </item>
349 </property> 349 <item>
350 </item> 350 <property name="text">
351 <item> 351 <string>Chinese</string>
352 <property name="text"> 352 </property>
353 <string>Portugal</string> 353 </item>
354 </property> 354 <item>
355 </item> 355 <property name="text">
356 <item> 356 <string>Korean (한국어)</string>
357 <property name="text"> 357 </property>
358 <string>PRC</string> 358 </item>
359 </property> 359 <item>
360 </item> 360 <property name="text">
361 <item> 361 <string>Dutch (Nederlands)</string>
362 <property name="text"> 362 </property>
363 <string>PST8PDT</string> 363 </item>
364 </property> 364 <item>
365 </item> 365 <property name="text">
366 <item> 366 <string>Portuguese (português)</string>
367 <property name="text"> 367 </property>
368 <string>ROC</string> 368 </item>
369 </property> 369 <item>
370 </item> 370 <property name="text">
371 <item> 371 <string>Russian (Русский)</string>
372 <property name="text"> 372 </property>
373 <string>ROK</string> 373 </item>
374 </property> 374 <item>
375 </item> 375 <property name="text">
376 <item> 376 <string>Taiwanese</string>
377 <property name="text"> 377 </property>
378 <string>Singapore</string> 378 </item>
379 </property> 379 <item>
380 </item> 380 <property name="text">
381 <item> 381 <string>British English</string>
382 <property name="text"> 382 </property>
383 <string>Turkey</string> 383 </item>
384 </property> 384 <item>
385 </item> 385 <property name="text">
386 <item> 386 <string>Canadian French</string>
387 <property name="text"> 387 </property>
388 <string>UCT</string> 388 </item>
389 </property> 389 <item>
390 </item> 390 <property name="text">
391 <item> 391 <string>Latin American Spanish</string>
392 <property name="text"> 392 </property>
393 <string>Universal</string> 393 </item>
394 </property> 394 <item>
395 </item> 395 <property name="text">
396 <item> 396 <string>Simplified Chinese</string>
397 <property name="text"> 397 </property>
398 <string>UTC</string> 398 </item>
399 </property> 399 <item>
400 </item> 400 <property name="text">
401 <item> 401 <string>Traditional Chinese (正體中文)</string>
402 <property name="text"> 402 </property>
403 <string>W-SU</string> 403 </item>
404 </property> 404 </widget>
405 </item> 405 </item>
406 <item> 406 <item row="5" column="0">
407 <property name="text"> 407 <widget class="QCheckBox" name="custom_rtc_checkbox">
408 <string>WET</string> 408 <property name="text">
409 </property> 409 <string>Custom RTC</string>
410 </item> 410 </property>
411 <item> 411 </widget>
412 <property name="text"> 412 </item>
413 <string>Zulu</string> 413 <item row="0" column="0">
414 </property> 414 <widget class="QLabel" name="label_language">
415 </item> 415 <property name="text">
416 </widget> 416 <string>Language</string>
417 </item> 417 </property>
418 <item row="6" column="0"> 418 </widget>
419 <widget class="QCheckBox" name="rng_seed_checkbox"> 419 </item>
420 <property name="text"> 420 <item row="6" column="0">
421 <string>RNG Seed</string> 421 <widget class="QCheckBox" name="rng_seed_checkbox">
422 </property> 422 <property name="text">
423 </widget> 423 <string>RNG Seed</string>
424 </item> 424 </property>
425 <item row="3" column="1"> 425 </widget>
426 <widget class="QComboBox" name="combo_sound"> 426 </item>
427 <item> 427 <item row="3" column="1">
428 <property name="text"> 428 <widget class="QComboBox" name="combo_sound">
429 <string>Mono</string> 429 <item>
430 </property> 430 <property name="text">
431 </item> 431 <string>Mono</string>
432 <item> 432 </property>
433 <property name="text"> 433 </item>
434 <string>Stereo</string> 434 <item>
435 </property> 435 <property name="text">
436 </item> 436 <string>Stereo</string>
437 <item> 437 </property>
438 <property name="text"> 438 </item>
439 <string>Surround</string> 439 <item>
440 </property> 440 <property name="text">
441 </item> 441 <string>Surround</string>
442 </widget> 442 </property>
443 </item> 443 </item>
444 <item row="0" column="0"> 444 </widget>
445 <widget class="QLabel" name="label_language"> 445 </item>
446 <property name="text"> 446 <item row="4" column="0">
447 <string>Language</string> 447 <widget class="QLabel" name="label_console_id">
448 </property> 448 <property name="text">
449 </widget> 449 <string>Console ID:</string>
450 </item> 450 </property>
451 <item row="4" column="1"> 451 </widget>
452 <widget class="QPushButton" name="button_regenerate_console_id"> 452 </item>
453 <property name="sizePolicy"> 453 <item row="3" column="0">
454 <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> 454 <widget class="QLabel" name="label_sound">
455 <horstretch>0</horstretch> 455 <property name="text">
456 <verstretch>0</verstretch> 456 <string>Sound output mode</string>
457 </sizepolicy> 457 </property>
458 </property> 458 </widget>
459 <property name="layoutDirection"> 459 </item>
460 <enum>Qt::RightToLeft</enum> 460 <item row="5" column="1">
461 </property> 461 <widget class="QDateTimeEdit" name="custom_rtc_edit">
462 <property name="text"> 462 <property name="minimumDate">
463 <string>Regenerate</string> 463 <date>
464 </property> 464 <year>1970</year>
465 </widget> 465 <month>1</month>
466 </item> 466 <day>1</day>
467 <item row="5" column="0"> 467 </date>
468 <widget class="QCheckBox" name="custom_rtc_checkbox"> 468 </property>
469 <property name="text"> 469 <property name="displayFormat">
470 <string>Custom RTC</string> 470 <string>d MMM yyyy h:mm:ss AP</string>
471 </property> 471 </property>
472 </widget> 472 </widget>
473 </item> 473 </item>
474 <item row="5" column="1"> 474 <item row="6" column="1">
475 <widget class="QDateTimeEdit" name="custom_rtc_edit"> 475 <widget class="QLineEdit" name="rng_seed_edit">
476 <property name="minimumDate"> 476 <property name="sizePolicy">
477 <date> 477 <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
478 <year>1970</year> 478 <horstretch>0</horstretch>
479 <month>1</month> 479 <verstretch>0</verstretch>
480 <day>1</day> 480 </sizepolicy>
481 </date> 481 </property>
482 </property> 482 <property name="font">
483 <property name="displayFormat"> 483 <font>
484 <string>d MMM yyyy h:mm:ss AP</string> 484 <family>Lucida Console</family>
485 </property> 485 </font>
486 </widget> 486 </property>
487 </item> 487 <property name="inputMask">
488 <item row="6" column="1"> 488 <string notr="true">HHHHHHHH</string>
489 <widget class="QLineEdit" name="rng_seed_edit"> 489 </property>
490 <property name="sizePolicy"> 490 <property name="maxLength">
491 <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> 491 <number>8</number>
492 <horstretch>0</horstretch> 492 </property>
493 <verstretch>0</verstretch> 493 </widget>
494 </sizepolicy> 494 </item>
495 </property> 495 <item row="4" column="1">
496 <property name="font"> 496 <widget class="QPushButton" name="button_regenerate_console_id">
497 <font> 497 <property name="sizePolicy">
498 <family>Lucida Console</family> 498 <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
499 </font> 499 <horstretch>0</horstretch>
500 </property> 500 <verstretch>0</verstretch>
501 <property name="inputMask"> 501 </sizepolicy>
502 <string notr="true">HHHHHHHH</string> 502 </property>
503 </property> 503 <property name="layoutDirection">
504 <property name="maxLength"> 504 <enum>Qt::RightToLeft</enum>
505 <number>8</number> 505 </property>
506 </property> 506 <property name="text">
507 </widget> 507 <string>Regenerate</string>
508 </property>
509 </widget>
510 </item>
511 </layout>
508 </item> 512 </item>
509 </layout> 513 </layout>
510 </widget> 514 </widget>
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp
index 24b6c5b72..2c20b68d0 100644
--- a/src/yuzu/configuration/configure_ui.cpp
+++ b/src/yuzu/configuration/configure_ui.cpp
@@ -4,9 +4,11 @@
4 4
5#include <array> 5#include <array>
6#include <utility> 6#include <utility>
7#include <QFileDialog>
7 8
8#include <QDirIterator> 9#include <QDirIterator>
9#include "common/common_types.h" 10#include "common/common_types.h"
11#include "common/file_util.h"
10#include "core/settings.h" 12#include "core/settings.h"
11#include "ui_configure_ui.h" 13#include "ui_configure_ui.h"
12#include "yuzu/configuration/configure_ui.h" 14#include "yuzu/configuration/configure_ui.h"
@@ -52,9 +54,21 @@ ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::Configur
52 54
53 // Update text ComboBoxes after user interaction. 55 // Update text ComboBoxes after user interaction.
54 connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::activated), 56 connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::activated),
55 [=]() { ConfigureUi::UpdateSecondRowComboBox(); }); 57 [this] { ConfigureUi::UpdateSecondRowComboBox(); });
56 connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::activated), 58 connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::activated),
57 [=]() { ConfigureUi::UpdateFirstRowComboBox(); }); 59 [this] { ConfigureUi::UpdateFirstRowComboBox(); });
60
61 // Set screenshot path to user specification.
62 connect(ui->screenshot_path_button, &QToolButton::pressed, this, [this] {
63 const QString& filename =
64 QFileDialog::getExistingDirectory(
65 this, tr("Select Screenshots Path..."),
66 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ScreenshotsDir))) +
67 QDir::separator();
68 if (!filename.isEmpty()) {
69 ui->screenshot_path_edit->setText(filename);
70 }
71 });
58} 72}
59 73
60ConfigureUi::~ConfigureUi() = default; 74ConfigureUi::~ConfigureUi() = default;
@@ -66,6 +80,10 @@ void ConfigureUi::ApplyConfiguration() {
66 UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); 80 UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
67 UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); 81 UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
68 UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt(); 82 UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt();
83
84 UISettings::values.enable_screenshot_save_as = ui->enable_screenshot_save_as->isChecked();
85 FileUtil::GetUserPath(FileUtil::UserPath::ScreenshotsDir,
86 ui->screenshot_path_edit->text().toStdString());
69 Settings::Apply(); 87 Settings::Apply();
70} 88}
71 89
@@ -80,6 +98,10 @@ void ConfigureUi::SetConfiguration() {
80 ui->show_add_ons->setChecked(UISettings::values.show_add_ons); 98 ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
81 ui->icon_size_combobox->setCurrentIndex( 99 ui->icon_size_combobox->setCurrentIndex(
82 ui->icon_size_combobox->findData(UISettings::values.icon_size)); 100 ui->icon_size_combobox->findData(UISettings::values.icon_size));
101
102 ui->enable_screenshot_save_as->setChecked(UISettings::values.enable_screenshot_save_as);
103 ui->screenshot_path_edit->setText(
104 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ScreenshotsDir)));
83} 105}
84 106
85void ConfigureUi::changeEvent(QEvent* event) { 107void ConfigureUi::changeEvent(QEvent* event) {
diff --git a/src/yuzu/configuration/configure_ui.ui b/src/yuzu/configuration/configure_ui.ui
index 0b81747d7..d895b799f 100644
--- a/src/yuzu/configuration/configure_ui.ui
+++ b/src/yuzu/configuration/configure_ui.ui
@@ -6,8 +6,8 @@
6 <rect> 6 <rect>
7 <x>0</x> 7 <x>0</x>
8 <y>0</y> 8 <y>0</y>
9 <width>300</width> 9 <width>363</width>
10 <height>377</height> 10 <height>391</height>
11 </rect> 11 </rect>
12 </property> 12 </property>
13 <property name="windowTitle"> 13 <property name="windowTitle">
@@ -128,6 +128,47 @@
128 </widget> 128 </widget>
129 </item> 129 </item>
130 <item> 130 <item>
131 <widget class="QGroupBox" name="screenshots_GroupBox">
132 <property name="title">
133 <string>Screenshots</string>
134 </property>
135 <layout class="QVBoxLayout" name="verticalLayout_4">
136 <item>
137 <layout class="QVBoxLayout" name="verticalLayout_3">
138 <item>
139 <widget class="QCheckBox" name="enable_screenshot_save_as">
140 <property name="text">
141 <string>Ask Where To Save Screenshots (Windows Only)</string>
142 </property>
143 </widget>
144 </item>
145 <item>
146 <layout class="QHBoxLayout" name="horizontalLayout_4">
147 <item>
148 <widget class="QLabel" name="label">
149 <property name="text">
150 <string>Screenshots Path: </string>
151 </property>
152 </widget>
153 </item>
154 <item>
155 <widget class="QLineEdit" name="screenshot_path_edit"/>
156 </item>
157 <item>
158 <widget class="QToolButton" name="screenshot_path_button">
159 <property name="text">
160 <string>...</string>
161 </property>
162 </widget>
163 </item>
164 </layout>
165 </item>
166 </layout>
167 </item>
168 </layout>
169 </widget>
170 </item>
171 <item>
131 <spacer name="verticalSpacer"> 172 <spacer name="verticalSpacer">
132 <property name="orientation"> 173 <property name="orientation">
133 <enum>Qt::Vertical</enum> 174 <enum>Qt::Vertical</enum>
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index f391a41a9..3439cb333 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -38,7 +38,10 @@ constexpr std::array<std::array<Qt::GlobalColor, 2>, 10> WaitTreeColors{{
38 38
39bool IsDarkTheme() { 39bool IsDarkTheme() {
40 const auto& theme = UISettings::values.theme; 40 const auto& theme = UISettings::values.theme;
41 return theme == QStringLiteral("qdarkstyle") || theme == QStringLiteral("colorful_dark"); 41 return theme == QStringLiteral("qdarkstyle") ||
42 theme == QStringLiteral("qdarkstyle_midnight_blue") ||
43 theme == QStringLiteral("colorful_dark") ||
44 theme == QStringLiteral("colorful_midnight_blue");
42} 45}
43 46
44} // namespace 47} // namespace
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index ab7fc7a24..62acc3720 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -474,28 +474,56 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
474 474
475void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, std::string path) { 475void GameList::AddGamePopup(QMenu& context_menu, u64 program_id, std::string path) {
476 QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location")); 476 QAction* open_save_location = context_menu.addAction(tr("Open Save Data Location"));
477 QAction* open_lfs_location = context_menu.addAction(tr("Open Mod Data Location")); 477 QAction* open_mod_location = context_menu.addAction(tr("Open Mod Data Location"));
478 QAction* open_transferable_shader_cache = 478 QAction* open_transferable_shader_cache =
479 context_menu.addAction(tr("Open Transferable Shader Cache")); 479 context_menu.addAction(tr("Open Transferable Shader Cache"));
480 context_menu.addSeparator(); 480 context_menu.addSeparator();
481 QMenu* remove_menu = context_menu.addMenu(tr("Remove"));
482 QAction* remove_update = remove_menu->addAction(tr("Remove Installed Update"));
483 QAction* remove_dlc = remove_menu->addAction(tr("Remove All Installed DLC"));
484 QAction* remove_shader_cache = remove_menu->addAction(tr("Remove Shader Cache"));
485 QAction* remove_custom_config = remove_menu->addAction(tr("Remove Custom Configuration"));
486 remove_menu->addSeparator();
487 QAction* remove_all_content = remove_menu->addAction(tr("Remove All Installed Contents"));
481 QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS")); 488 QAction* dump_romfs = context_menu.addAction(tr("Dump RomFS"));
482 QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard")); 489 QAction* copy_tid = context_menu.addAction(tr("Copy Title ID to Clipboard"));
483 QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry")); 490 QAction* navigate_to_gamedb_entry = context_menu.addAction(tr("Navigate to GameDB entry"));
484 context_menu.addSeparator(); 491 context_menu.addSeparator();
485 QAction* properties = context_menu.addAction(tr("Properties")); 492 QAction* properties = context_menu.addAction(tr("Properties"));
486 493
487 open_save_location->setEnabled(program_id != 0); 494 open_save_location->setVisible(program_id != 0);
495 open_mod_location->setVisible(program_id != 0);
496 open_transferable_shader_cache->setVisible(program_id != 0);
497 remove_update->setVisible(program_id != 0);
498 remove_dlc->setVisible(program_id != 0);
499 remove_shader_cache->setVisible(program_id != 0);
500 remove_all_content->setVisible(program_id != 0);
488 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id); 501 auto it = FindMatchingCompatibilityEntry(compatibility_list, program_id);
489 navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0); 502 navigate_to_gamedb_entry->setVisible(it != compatibility_list.end() && program_id != 0);
490 503
491 connect(open_save_location, &QAction::triggered, [this, program_id, path]() { 504 connect(open_save_location, &QAction::triggered, [this, program_id, path]() {
492 emit OpenFolderRequested(GameListOpenTarget::SaveData, path); 505 emit OpenFolderRequested(GameListOpenTarget::SaveData, path);
493 }); 506 });
494 connect(open_lfs_location, &QAction::triggered, [this, program_id, path]() { 507 connect(open_mod_location, &QAction::triggered, [this, program_id, path]() {
495 emit OpenFolderRequested(GameListOpenTarget::ModData, path); 508 emit OpenFolderRequested(GameListOpenTarget::ModData, path);
496 }); 509 });
497 connect(open_transferable_shader_cache, &QAction::triggered, 510 connect(open_transferable_shader_cache, &QAction::triggered,
498 [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); }); 511 [this, program_id]() { emit OpenTransferableShaderCacheRequested(program_id); });
512 connect(remove_all_content, &QAction::triggered, [this, program_id]() {
513 emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::Game);
514 });
515 connect(remove_update, &QAction::triggered, [this, program_id]() {
516 emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::Update);
517 });
518 connect(remove_dlc, &QAction::triggered, [this, program_id]() {
519 emit RemoveInstalledEntryRequested(program_id, InstalledEntryType::AddOnContent);
520 });
521 connect(remove_shader_cache, &QAction::triggered, [this, program_id]() {
522 emit RemoveFileRequested(program_id, GameListRemoveTarget::ShaderCache);
523 });
524 connect(remove_custom_config, &QAction::triggered, [this, program_id]() {
525 emit RemoveFileRequested(program_id, GameListRemoveTarget::CustomConfiguration);
526 });
499 connect(dump_romfs, &QAction::triggered, 527 connect(dump_romfs, &QAction::triggered,
500 [this, program_id, path]() { emit DumpRomFSRequested(program_id, path); }); 528 [this, program_id, path]() { emit DumpRomFSRequested(program_id, path); });
501 connect(copy_tid, &QAction::triggered, 529 connect(copy_tid, &QAction::triggered,
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index a38cb2fc3..483835cce 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -39,6 +39,17 @@ enum class GameListOpenTarget {
39 ModData, 39 ModData,
40}; 40};
41 41
42enum class GameListRemoveTarget {
43 ShaderCache,
44 CustomConfiguration,
45};
46
47enum class InstalledEntryType {
48 Game,
49 Update,
50 AddOnContent,
51};
52
42class GameList : public QWidget { 53class GameList : public QWidget {
43 Q_OBJECT 54 Q_OBJECT
44 55
@@ -75,6 +86,8 @@ signals:
75 void ShouldCancelWorker(); 86 void ShouldCancelWorker();
76 void OpenFolderRequested(GameListOpenTarget target, const std::string& game_path); 87 void OpenFolderRequested(GameListOpenTarget target, const std::string& game_path);
77 void OpenTransferableShaderCacheRequested(u64 program_id); 88 void OpenTransferableShaderCacheRequested(u64 program_id);
89 void RemoveInstalledEntryRequested(u64 program_id, InstalledEntryType type);
90 void RemoveFileRequested(u64 program_id, GameListRemoveTarget target);
78 void DumpRomFSRequested(u64 program_id, const std::string& game_path); 91 void DumpRomFSRequested(u64 program_id, const std::string& game_path);
79 void CopyTIDRequested(u64 program_id); 92 void CopyTIDRequested(u64 program_id);
80 void NavigateToGamedbEntryRequested(u64 program_id, 93 void NavigateToGamedbEntryRequested(u64 program_id,
@@ -117,8 +130,6 @@ private:
117 friend class GameListSearchField; 130 friend class GameListSearchField;
118}; 131};
119 132
120Q_DECLARE_METATYPE(GameListOpenTarget);
121
122class GameListPlaceholder : public QWidget { 133class GameListPlaceholder : public QWidget {
123 Q_OBJECT 134 Q_OBJECT
124public: 135public:
diff --git a/src/yuzu/game_list_worker.cpp b/src/yuzu/game_list_worker.cpp
index 2018150db..239016b94 100644
--- a/src/yuzu/game_list_worker.cpp
+++ b/src/yuzu/game_list_worker.cpp
@@ -369,8 +369,8 @@ void GameListWorker::run() {
369 auto* const game_list_dir = new GameListDir(game_dir); 369 auto* const game_list_dir = new GameListDir(game_dir);
370 emit DirEntryReady(game_list_dir); 370 emit DirEntryReady(game_list_dir);
371 provider->ClearAllEntries(); 371 provider->ClearAllEntries();
372 ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(), 2, 372 ScanFileSystem(ScanTarget::FillManualContentProvider, game_dir.path.toStdString(),
373 game_list_dir); 373 game_dir.deep_scan ? 256 : 0, game_list_dir);
374 ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(), 374 ScanFileSystem(ScanTarget::PopulateGameList, game_dir.path.toStdString(),
375 game_dir.deep_scan ? 256 : 0, game_list_dir); 375 game_dir.deep_scan ? 256 : 0, game_list_dir);
376 } 376 }
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 31a635176..592993c36 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -583,7 +583,7 @@ void GMainWindow::InitializeWidgets() {
583 renderer_status_button->setObjectName(QStringLiteral("RendererStatusBarButton")); 583 renderer_status_button->setObjectName(QStringLiteral("RendererStatusBarButton"));
584 renderer_status_button->setCheckable(true); 584 renderer_status_button->setCheckable(true);
585 renderer_status_button->setFocusPolicy(Qt::NoFocus); 585 renderer_status_button->setFocusPolicy(Qt::NoFocus);
586 connect(renderer_status_button, &QPushButton::toggled, [=](bool checked) { 586 connect(renderer_status_button, &QPushButton::toggled, [this](bool checked) {
587 renderer_status_button->setText(checked ? tr("VULKAN") : tr("OPENGL")); 587 renderer_status_button->setText(checked ? tr("VULKAN") : tr("OPENGL"));
588 }); 588 });
589 renderer_status_button->toggle(); 589 renderer_status_button->toggle();
@@ -595,7 +595,7 @@ void GMainWindow::InitializeWidgets() {
595#else 595#else
596 renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() == 596 renderer_status_button->setChecked(Settings::values.renderer_backend.GetValue() ==
597 Settings::RendererBackend::Vulkan); 597 Settings::RendererBackend::Vulkan);
598 connect(renderer_status_button, &QPushButton::clicked, [=] { 598 connect(renderer_status_button, &QPushButton::clicked, [this] {
599 if (emulation_running) { 599 if (emulation_running) {
600 return; 600 return;
601 } 601 }
@@ -847,6 +847,9 @@ void GMainWindow::ConnectWidgetEvents() {
847 connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder); 847 connect(game_list, &GameList::OpenFolderRequested, this, &GMainWindow::OnGameListOpenFolder);
848 connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this, 848 connect(game_list, &GameList::OpenTransferableShaderCacheRequested, this,
849 &GMainWindow::OnTransferableShaderCacheOpenFile); 849 &GMainWindow::OnTransferableShaderCacheOpenFile);
850 connect(game_list, &GameList::RemoveInstalledEntryRequested, this,
851 &GMainWindow::OnGameListRemoveInstalledEntry);
852 connect(game_list, &GameList::RemoveFileRequested, this, &GMainWindow::OnGameListRemoveFile);
850 connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS); 853 connect(game_list, &GameList::DumpRomFSRequested, this, &GMainWindow::OnGameListDumpRomFS);
851 connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID); 854 connect(game_list, &GameList::CopyTIDRequested, this, &GMainWindow::OnGameListCopyTID);
852 connect(game_list, &GameList::NavigateToGamedbEntryRequested, this, 855 connect(game_list, &GameList::NavigateToGamedbEntryRequested, this,
@@ -1257,7 +1260,6 @@ void GMainWindow::OnGameListOpenFolder(GameListOpenTarget target, const std::str
1257 case GameListOpenTarget::SaveData: { 1260 case GameListOpenTarget::SaveData: {
1258 open_target = tr("Save Data"); 1261 open_target = tr("Save Data");
1259 const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir); 1262 const std::string nand_dir = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir);
1260 ASSERT(program_id != 0);
1261 1263
1262 if (has_user_save) { 1264 if (has_user_save) {
1263 // User save data 1265 // User save data
@@ -1322,14 +1324,12 @@ void GMainWindow::OnGameListOpenFolder(GameListOpenTarget target, const std::str
1322} 1324}
1323 1325
1324void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) { 1326void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
1325 ASSERT(program_id != 0);
1326
1327 const QString shader_dir = 1327 const QString shader_dir =
1328 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir)); 1328 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir));
1329 const QString tranferable_shader_cache_folder_path = 1329 const QString transferable_shader_cache_folder_path =
1330 shader_dir + QStringLiteral("opengl") + QDir::separator() + QStringLiteral("transferable"); 1330 shader_dir + QStringLiteral("opengl") + QDir::separator() + QStringLiteral("transferable");
1331 const QString transferable_shader_cache_file_path = 1331 const QString transferable_shader_cache_file_path =
1332 tranferable_shader_cache_folder_path + QDir::separator() + 1332 transferable_shader_cache_folder_path + QDir::separator() +
1333 QString::fromStdString(fmt::format("{:016X}.bin", program_id)); 1333 QString::fromStdString(fmt::format("{:016X}.bin", program_id));
1334 1334
1335 if (!QFile::exists(transferable_shader_cache_file_path)) { 1335 if (!QFile::exists(transferable_shader_cache_file_path)) {
@@ -1350,7 +1350,7 @@ void GMainWindow::OnTransferableShaderCacheOpenFile(u64 program_id) {
1350 param << QDir::toNativeSeparators(transferable_shader_cache_file_path); 1350 param << QDir::toNativeSeparators(transferable_shader_cache_file_path);
1351 QProcess::startDetached(explorer, param); 1351 QProcess::startDetached(explorer, param);
1352#else 1352#else
1353 QDesktopServices::openUrl(QUrl::fromLocalFile(tranferable_shader_cache_folder_path)); 1353 QDesktopServices::openUrl(QUrl::fromLocalFile(transferable_shader_cache_folder_path));
1354#endif 1354#endif
1355} 1355}
1356 1356
@@ -1394,6 +1394,174 @@ static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src
1394 return true; 1394 return true;
1395} 1395}
1396 1396
1397void GMainWindow::OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type) {
1398 const QString entry_type = [this, type] {
1399 switch (type) {
1400 case InstalledEntryType::Game:
1401 return tr("Contents");
1402 case InstalledEntryType::Update:
1403 return tr("Update");
1404 case InstalledEntryType::AddOnContent:
1405 return tr("DLC");
1406 default:
1407 return QString{};
1408 }
1409 }();
1410
1411 if (QMessageBox::question(
1412 this, tr("Remove Entry"), tr("Remove Installed Game %1?").arg(entry_type),
1413 QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes) {
1414 return;
1415 }
1416
1417 switch (type) {
1418 case InstalledEntryType::Game:
1419 RemoveBaseContent(program_id, entry_type);
1420 [[fallthrough]];
1421 case InstalledEntryType::Update:
1422 RemoveUpdateContent(program_id, entry_type);
1423 if (type != InstalledEntryType::Game) {
1424 break;
1425 }
1426 [[fallthrough]];
1427 case InstalledEntryType::AddOnContent:
1428 RemoveAddOnContent(program_id, entry_type);
1429 break;
1430 }
1431 FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
1432 "game_list");
1433 game_list->PopulateAsync(UISettings::values.game_dirs);
1434}
1435
1436void GMainWindow::RemoveBaseContent(u64 program_id, const QString& entry_type) {
1437 const auto& fs_controller = Core::System::GetInstance().GetFileSystemController();
1438 const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(program_id) ||
1439 fs_controller.GetSDMCContents()->RemoveExistingEntry(program_id);
1440
1441 if (res) {
1442 QMessageBox::information(this, tr("Successfully Removed"),
1443 tr("Successfully removed the installed base game."));
1444 } else {
1445 QMessageBox::warning(
1446 this, tr("Error Removing %1").arg(entry_type),
1447 tr("The base game is not installed in the NAND and cannot be removed."));
1448 }
1449}
1450
1451void GMainWindow::RemoveUpdateContent(u64 program_id, const QString& entry_type) {
1452 const auto update_id = program_id | 0x800;
1453 const auto& fs_controller = Core::System::GetInstance().GetFileSystemController();
1454 const auto res = fs_controller.GetUserNANDContents()->RemoveExistingEntry(update_id) ||
1455 fs_controller.GetSDMCContents()->RemoveExistingEntry(update_id);
1456
1457 if (res) {
1458 QMessageBox::information(this, tr("Successfully Removed"),
1459 tr("Successfully removed the installed update."));
1460 } else {
1461 QMessageBox::warning(this, tr("Error Removing %1").arg(entry_type),
1462 tr("There is no update installed for this title."));
1463 }
1464}
1465
1466void GMainWindow::RemoveAddOnContent(u64 program_id, const QString& entry_type) {
1467 u32 count{};
1468 const auto& fs_controller = Core::System::GetInstance().GetFileSystemController();
1469 const auto dlc_entries = Core::System::GetInstance().GetContentProvider().ListEntriesFilter(
1470 FileSys::TitleType::AOC, FileSys::ContentRecordType::Data);
1471
1472 for (const auto& entry : dlc_entries) {
1473 if ((entry.title_id & DLC_BASE_TITLE_ID_MASK) == program_id) {
1474 const auto res =
1475 fs_controller.GetUserNANDContents()->RemoveExistingEntry(entry.title_id) ||
1476 fs_controller.GetSDMCContents()->RemoveExistingEntry(entry.title_id);
1477 if (res) {
1478 ++count;
1479 }
1480 }
1481 }
1482
1483 if (count == 0) {
1484 QMessageBox::warning(this, tr("Error Removing %1").arg(entry_type),
1485 tr("There are no DLC installed for this title."));
1486 return;
1487 }
1488
1489 QMessageBox::information(this, tr("Successfully Removed"),
1490 tr("Successfully removed %1 installed DLC.").arg(count));
1491}
1492
1493void GMainWindow::OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target) {
1494 const QString question = [this, target] {
1495 switch (target) {
1496 case GameListRemoveTarget::ShaderCache:
1497 return tr("Delete Transferable Shader Cache?");
1498 case GameListRemoveTarget::CustomConfiguration:
1499 return tr("Remove Custom Game Configuration?");
1500 default:
1501 return QString{};
1502 }
1503 }();
1504
1505 if (QMessageBox::question(this, tr("Remove File"), question, QMessageBox::Yes | QMessageBox::No,
1506 QMessageBox::No) != QMessageBox::Yes) {
1507 return;
1508 }
1509
1510 switch (target) {
1511 case GameListRemoveTarget::ShaderCache:
1512 RemoveTransferableShaderCache(program_id);
1513 break;
1514 case GameListRemoveTarget::CustomConfiguration:
1515 RemoveCustomConfiguration(program_id);
1516 break;
1517 }
1518}
1519
1520void GMainWindow::RemoveTransferableShaderCache(u64 program_id) {
1521 const QString shader_dir =
1522 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ShaderDir));
1523 const QString transferable_shader_cache_folder_path =
1524 shader_dir + QStringLiteral("opengl") + QDir::separator() + QStringLiteral("transferable");
1525 const QString transferable_shader_cache_file_path =
1526 transferable_shader_cache_folder_path + QDir::separator() +
1527 QString::fromStdString(fmt::format("{:016X}.bin", program_id));
1528
1529 if (!QFile::exists(transferable_shader_cache_file_path)) {
1530 QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"),
1531 tr("A shader cache for this title does not exist."));
1532 return;
1533 }
1534
1535 if (QFile::remove(transferable_shader_cache_file_path)) {
1536 QMessageBox::information(this, tr("Successfully Removed"),
1537 tr("Successfully removed the transferable shader cache."));
1538 } else {
1539 QMessageBox::warning(this, tr("Error Removing Transferable Shader Cache"),
1540 tr("Failed to remove the transferable shader cache."));
1541 }
1542}
1543
1544void GMainWindow::RemoveCustomConfiguration(u64 program_id) {
1545 const QString config_dir =
1546 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir));
1547 const QString custom_config_file_path =
1548 config_dir + QString::fromStdString(fmt::format("{:016X}.ini", program_id));
1549
1550 if (!QFile::exists(custom_config_file_path)) {
1551 QMessageBox::warning(this, tr("Error Removing Custom Configuration"),
1552 tr("A custom configuration for this title does not exist."));
1553 return;
1554 }
1555
1556 if (QFile::remove(custom_config_file_path)) {
1557 QMessageBox::information(this, tr("Successfully Removed"),
1558 tr("Successfully removed the custom game configuration."));
1559 } else {
1560 QMessageBox::warning(this, tr("Error Removing Custom Configuration"),
1561 tr("Failed to remove the custom game configuration."));
1562 }
1563}
1564
1397void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) { 1565void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) {
1398 const auto failed = [this] { 1566 const auto failed = [this] {
1399 QMessageBox::warning(this, tr("RomFS Extraction Failed!"), 1567 QMessageBox::warning(this, tr("RomFS Extraction Failed!"),
@@ -1655,7 +1823,7 @@ void GMainWindow::OnMenuInstallToNAND() {
1655 1823
1656 ui.action_Install_File_NAND->setEnabled(false); 1824 ui.action_Install_File_NAND->setEnabled(false);
1657 1825
1658 install_progress = new QProgressDialog(QStringLiteral(""), tr("Cancel"), 0, total_size, this); 1826 install_progress = new QProgressDialog(QString{}, tr("Cancel"), 0, total_size, this);
1659 install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint & 1827 install_progress->setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint &
1660 ~Qt::WindowMaximizeButtonHint); 1828 ~Qt::WindowMaximizeButtonHint);
1661 install_progress->setAttribute(Qt::WA_DeleteOnClose, true); 1829 install_progress->setAttribute(Qt::WA_DeleteOnClose, true);
@@ -1705,18 +1873,18 @@ void GMainWindow::OnMenuInstallToNAND() {
1705 install_progress->close(); 1873 install_progress->close();
1706 1874
1707 const QString install_results = 1875 const QString install_results =
1708 (new_files.isEmpty() ? QStringLiteral("") 1876 (new_files.isEmpty() ? QString{}
1709 : tr("%n file(s) were newly installed\n", "", new_files.size())) + 1877 : tr("%n file(s) were newly installed\n", "", new_files.size())) +
1710 (overwritten_files.isEmpty() 1878 (overwritten_files.isEmpty()
1711 ? QStringLiteral("") 1879 ? QString{}
1712 : tr("%n file(s) were overwritten\n", "", overwritten_files.size())) + 1880 : tr("%n file(s) were overwritten\n", "", overwritten_files.size())) +
1713 (failed_files.isEmpty() ? QStringLiteral("") 1881 (failed_files.isEmpty() ? QString{}
1714 : tr("%n file(s) failed to install\n", "", failed_files.size())); 1882 : tr("%n file(s) failed to install\n", "", failed_files.size()));
1715 1883
1716 QMessageBox::information(this, tr("Install Results"), install_results); 1884 QMessageBox::information(this, tr("Install Results"), install_results);
1717 game_list->PopulateAsync(UISettings::values.game_dirs);
1718 FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP + 1885 FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
1719 "game_list"); 1886 "game_list");
1887 game_list->PopulateAsync(UISettings::values.game_dirs);
1720 ui.action_Install_File_NAND->setEnabled(true); 1888 ui.action_Install_File_NAND->setEnabled(true);
1721} 1889}
1722 1890
@@ -2153,17 +2321,28 @@ void GMainWindow::OnToggleFilterBar() {
2153 2321
2154void GMainWindow::OnCaptureScreenshot() { 2322void GMainWindow::OnCaptureScreenshot() {
2155 OnPauseGame(); 2323 OnPauseGame();
2156 QFileDialog png_dialog(this, tr("Capture Screenshot"), UISettings::values.screenshot_path, 2324
2157 tr("PNG Image (*.png)")); 2325 const u64 title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
2158 png_dialog.setAcceptMode(QFileDialog::AcceptSave); 2326 const auto screenshot_path =
2159 png_dialog.setDefaultSuffix(QStringLiteral("png")); 2327 QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::ScreenshotsDir));
2160 if (png_dialog.exec()) { 2328 const auto date =
2161 const QString path = png_dialog.selectedFiles().first(); 2329 QDateTime::currentDateTime().toString(QStringLiteral("yyyy-MM-dd_hh-mm-ss-zzz"));
2162 if (!path.isEmpty()) { 2330 QString filename = QStringLiteral("%1%2_%3.png")
2163 UISettings::values.screenshot_path = QFileInfo(path).path(); 2331 .arg(screenshot_path)
2164 render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, path); 2332 .arg(title_id, 16, 16, QLatin1Char{'0'})
2333 .arg(date);
2334
2335#ifdef _WIN32
2336 if (UISettings::values.enable_screenshot_save_as) {
2337 filename = QFileDialog::getSaveFileName(this, tr("Capture Screenshot"), filename,
2338 tr("PNG Image (*.png)"));
2339 if (filename.isEmpty()) {
2340 OnStartGame();
2341 return;
2165 } 2342 }
2166 } 2343 }
2344#endif
2345 render_window->CaptureScreenshot(UISettings::values.screenshot_resolution_factor, filename);
2167 OnStartGame(); 2346 OnStartGame();
2168} 2347}
2169 2348
@@ -2202,8 +2381,7 @@ void GMainWindow::UpdateStatusBar() {
2202 2381
2203 if (shaders_building != 0) { 2382 if (shaders_building != 0) {
2204 shader_building_label->setText( 2383 shader_building_label->setText(
2205 tr("Building: %1 shader").arg(shaders_building) + 2384 tr("Building: %n shader(s)", "", static_cast<int>(shaders_building)));
2206 (shaders_building != 1 ? QString::fromStdString("s") : QString::fromStdString("")));
2207 shader_building_label->setVisible(true); 2385 shader_building_label->setVisible(true);
2208 } else { 2386 } else {
2209 shader_building_label->setVisible(false); 2387 shader_building_label->setVisible(false);
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index db573d606..73a44a3bf 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -32,6 +32,8 @@ class QPushButton;
32class QProgressDialog; 32class QProgressDialog;
33class WaitTreeWidget; 33class WaitTreeWidget;
34enum class GameListOpenTarget; 34enum class GameListOpenTarget;
35enum class GameListRemoveTarget;
36enum class InstalledEntryType;
35class GameListPlaceholder; 37class GameListPlaceholder;
36 38
37namespace Core::Frontend { 39namespace Core::Frontend {
@@ -198,6 +200,8 @@ private slots:
198 void OnGameListLoadFile(QString game_path); 200 void OnGameListLoadFile(QString game_path);
199 void OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path); 201 void OnGameListOpenFolder(GameListOpenTarget target, const std::string& game_path);
200 void OnTransferableShaderCacheOpenFile(u64 program_id); 202 void OnTransferableShaderCacheOpenFile(u64 program_id);
203 void OnGameListRemoveInstalledEntry(u64 program_id, InstalledEntryType type);
204 void OnGameListRemoveFile(u64 program_id, GameListRemoveTarget target);
201 void OnGameListDumpRomFS(u64 program_id, const std::string& game_path); 205 void OnGameListDumpRomFS(u64 program_id, const std::string& game_path);
202 void OnGameListCopyTID(u64 program_id); 206 void OnGameListCopyTID(u64 program_id);
203 void OnGameListNavigateToGamedbEntry(u64 program_id, 207 void OnGameListNavigateToGamedbEntry(u64 program_id,
@@ -229,6 +233,11 @@ private slots:
229 void OnLanguageChanged(const QString& locale); 233 void OnLanguageChanged(const QString& locale);
230 234
231private: 235private:
236 void RemoveBaseContent(u64 program_id, const QString& entry_type);
237 void RemoveUpdateContent(u64 program_id, const QString& entry_type);
238 void RemoveAddOnContent(u64 program_id, const QString& entry_type);
239 void RemoveTransferableShaderCache(u64 program_id);
240 void RemoveCustomConfiguration(u64 program_id);
232 std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id); 241 std::optional<u64> SelectRomFSDumpTarget(const FileSys::ContentProvider&, u64 program_id);
233 InstallResult InstallNSPXCI(const QString& filename); 242 InstallResult InstallNSPXCI(const QString& filename);
234 InstallResult InstallNCA(const QString& filename); 243 InstallResult InstallNCA(const QString& filename);
diff --git a/src/yuzu/uisettings.cpp b/src/yuzu/uisettings.cpp
index 738c4b2fc..a51175f36 100644
--- a/src/yuzu/uisettings.cpp
+++ b/src/yuzu/uisettings.cpp
@@ -11,6 +11,8 @@ const Themes themes{{
11 {"Light Colorful", "colorful"}, 11 {"Light Colorful", "colorful"},
12 {"Dark", "qdarkstyle"}, 12 {"Dark", "qdarkstyle"},
13 {"Dark Colorful", "colorful_dark"}, 13 {"Dark Colorful", "colorful_dark"},
14 {"Midnight Blue", "qdarkstyle_midnight_blue"},
15 {"Midnight Blue Colorful", "colorful_midnight_blue"},
14}}; 16}};
15 17
16Values values = {}; 18Values values = {};
diff --git a/src/yuzu/uisettings.h b/src/yuzu/uisettings.h
index 6cc65736d..bbfeafc55 100644
--- a/src/yuzu/uisettings.h
+++ b/src/yuzu/uisettings.h
@@ -24,7 +24,7 @@ struct Shortcut {
24 ContextualShortcut shortcut; 24 ContextualShortcut shortcut;
25}; 25};
26 26
27using Themes = std::array<std::pair<const char*, const char*>, 4>; 27using Themes = std::array<std::pair<const char*, const char*>, 6>;
28extern const Themes themes; 28extern const Themes themes;
29 29
30struct GameDir { 30struct GameDir {
@@ -66,11 +66,11 @@ struct Values {
66 // Discord RPC 66 // Discord RPC
67 bool enable_discord_presence; 67 bool enable_discord_presence;
68 68
69 bool enable_screenshot_save_as;
69 u16 screenshot_resolution_factor; 70 u16 screenshot_resolution_factor;
70 71
71 QString roms_path; 72 QString roms_path;
72 QString symbols_path; 73 QString symbols_path;
73 QString screenshot_path;
74 QString game_dir_deprecated; 74 QString game_dir_deprecated;
75 bool game_dir_deprecated_deepscan; 75 bool game_dir_deprecated_deepscan;
76 QVector<UISettings::GameDir> game_dirs; 76 QVector<UISettings::GameDir> game_dirs;