early-access version 1559

main
pineappleEA 2021-04-05 01:30:07 +02:00
parent 9ecece0489
commit 83a618c598
94 changed files with 6745 additions and 940 deletions

View File

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 1555. This is the source code for early-access 1559.
## Legal Notice ## Legal Notice

View File

@ -281,3 +281,380 @@ QWidget#controllerPlayer7,
QWidget#controllerPlayer8 { QWidget#controllerPlayer8 {
background: transparent; background: transparent;
} }
QDialog#QtSoftwareKeyboardDialog,
QStackedWidget#topOSK {
background: rgba(51, 51, 51, .9);
}
QDialog#OverlayDialog,
QStackedWidget#stackedDialog {
background: rgba(51, 51, 51, .7);
}
QWidget#boxOSK,
QWidget#lineOSK,
QWidget#richDialog,
QWidget#lineDialog {
background: transparent;
}
QStackedWidget#bottomOSK,
QWidget#contentDialog,
QWidget#contentRichDialog {
background: rgba(240, 240, 240, 1);
}
QWidget#contentDialog,
QWidget#contentRichDialog {
margin: 5px;
border-radius: 6px;
}
QWidget#buttonsDialog,
QWidget#buttonsRichDialog {
margin: 5px;
border-top: 2px solid rgba(44, 44, 44, 1);
}
QWidget#legendOSKnum {
border-top: 1px solid rgba(44, 44, 44, 1);
}
QStackedWidget#stackedDialog QTextBrowser QScrollBar::vertical {
background: #cdcdcd;
width: 15px;
margin: 15px 3px 15px 3px;
border: 1px transparent;
border-radius: 4px;
}
QStackedWidget#stackedDialog QTextBrowser QScrollBar::horizoncal {
background: #cdcdcd;
height: 15px;
margin: 3px 15px 3px 15px;
border: 1px transparent;
border-radius: 4px;
}
QStackedWidget#stackedDialog QTextBrowser QScrollBar::handle {
background: #fff;
border-radius: 4px;
min-height: 5px;
min-width: 5px;
}
QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line,
QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-page,
QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-page {
background: none;
}
QWidget#inputOSK {
border-bottom: 3px solid rgba(255, 255, 255, .9);
}
QWidget#inputOSK QLineEdit {
background: transparent;
border: none;
color: #ccc;
}
QWidget#inputBoxOSK {
border: 2px solid rgba(255, 255, 255, .9);
}
QWidget#inputBoxOSK QTextEdit {
background: transparent;
border: none;
color: #ccc;
}
QWidget#richDialog QTextBrowser {
background: transparent;
border: none;
padding: 35px 65px;
}
QWidget#lineOSK QLabel#label_header {
color: #f0f0f0;
}
QWidget#lineOSK QLabel#label_sub,
QWidget#lineOSK QLabel#label_characters,
QWidget#boxOSK QLabel#label_characters_box {
color: #ccc;
}
QWidget#contentDialog QLabel#label_title,
QWidget#contentRichDialog QLabel#label_title_rich {
color: #888;
}
QWidget#contentDialog QLabel#label_dialog {
padding: 20px 65px;
}
QWidget#contentDialog QLabel#label_title,
QWidget#contentRichDialog QLabel#label_title_rich {
padding: 0px 65px;
}
QDialog#OverlayDialog QPushButton {
color: rgba(49, 79, 239, 1);
background: transparent;
border: none;
padding: 0px;
min-width: 0px;
}
QDialog#OverlayDialog QPushButton:focus,
QDialog#OverlayDialog QPushButton:hover {
color: rgba(49, 79, 239, 1);
background: rgba(255, 255, 255, 1);
border: 5px solid rgba(148, 250, 202, 1);
border-radius: 6px;
outline: none;
}
QDialog#OverlayDialog QPushButton:pressed {
color: rgba(240, 240, 240, 1);
background: rgba(150, 150, 150, 1);
border: 5px solid rgba(148, 250, 202, 1);
border-radius: 6px;
outline: none;
}
QDialog#QtSoftwareKeyboardDialog QPushButton {
background: rgba(232, 232, 232, 1);
border: 2px solid rgba(240, 240, 240, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
background: rgba(218, 218, 218, 1);
border: 2px solid rgba(240, 240, 240, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
color: rgba(240, 240, 240, 1);
background: rgba(44, 44, 44, 1);
border: 2px solid rgba(240, 240, 240, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
color: rgba(240, 240, 240, 1);
background: rgba(49, 79, 239, 1);
border: 2px solid rgba(240, 240, 240, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
color: rgba(0, 0, 0, 1);
background: rgba(255, 255, 255, 1);
border: 5px solid rgba(148, 250, 202, 1);
border-radius: 6px;
outline: none;
}
QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
color: rgba(240, 240, 240, 1);
background: rgba(150, 150, 150, 1);
border: 5px solid rgba(148, 250, 202, 1);
border-radius: 6px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
background-position: right top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_B.png);
qproperty-icon: url(:/overlay/osk_button_backspace.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
background-position: right top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_Y.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
background-position: right top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_plus.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
background-position: left top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_shift_lock_off.png);
qproperty-icon: url(:/overlay/osk_button_shift.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
background-position: left top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_shift_lock_off.png);
qproperty-icon: url(:/overlay/osk_button_shift_on.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
padding-bottom: 7px;
}
QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
background: transparent;
color: #ccc;
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
image: url(:/overlay/button_L.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
image: url(:/overlay/arrow_left.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
image: url(:/overlay/button_R.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
image: url(:/overlay/arrow_right.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
image: url(:/overlay/button_press_stick.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
image: url(:/overlay/button_X.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
image: url(:/overlay/button_A.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
color: rgba(164, 164, 164, 1);
background-color: rgba(218, 218, 218, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
color: rgba(164, 164, 164, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
background-image: url(:/overlay/osk_button_plus_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
background-image: url(:/overlay/osk_button_B_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
background-image: url(:/overlay/osk_button_Y_disabled.png);
}

View File

@ -1560,7 +1560,400 @@ QWidget#controllerPlayer8 {
background: transparent; background: transparent;
} }
/* touchscreen mapping widget */ QDialog#QtSoftwareKeyboardDialog,
TouchScreenPreview { QStackedWidget#topOSK {
qproperty-dotHighlightColor: #3daee9; background: rgba(41, 41, 41, .9);
}
QDialog#OverlayDialog,
QStackedWidget#stackedDialog {
background: rgba(41, 41, 41, .7);
}
QWidget#boxOSK,
QWidget#lineOSK,
QWidget#richDialog,
QWidget#lineDialog {
background: transparent;
}
QStackedWidget#bottomOSK,
QWidget#contentDialog,
QWidget#contentRichDialog {
background: rgba(71, 69, 71, 1);
}
QWidget#contentDialog,
QWidget#contentRichDialog {
margin: 5px;
border-radius: 6px;
}
QWidget#buttonsDialog,
QWidget#buttonsRichDialog {
margin: 5px;
border-top: 2px solid rgba(255, 255, 255, .9);
}
QWidget#legendOSKnum {
border-top: 1px solid rgba(255, 255, 255, 1);
}
QStackedWidget#stackedDialog QTextBrowser QWidget {
background: transparent;
}
QStackedWidget#stackedDialog QTextBrowser QScrollBar {
background: #2a2929;
}
QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line {
border-image: none;
}
QWidget#inputOSK {
border-bottom: 3px solid rgba(255, 255, 255, .9);
}
QWidget#inputOSK QLineEdit {
background: transparent;
border: none;
color: #ccc;
padding: 0px;
}
QWidget#inputBoxOSK {
border: 2px solid rgba(255, 255, 255, .9);
}
QWidget#inputBoxOSK QTextEdit {
background: transparent;
border: none;
color: #ccc;
}
QWidget#richDialog QTextBrowser {
background: transparent;
border: none;
color: #fff;
padding: 35px 65px;
}
QWidget#lineOSK QLabel#label_header {
color: #f0f0f0;
}
QWidget#lineOSK QLabel#label_sub,
QWidget#lineOSK QLabel#label_characters,
QWidget#contentDialog QLabel#label_title,
QWidget#contentRichDialog QLabel#label_title_rich,
QWidget#boxOSK QLabel#label_characters_box {
color: #ccc;
}
QWidget#buttonsDialog,
QWidget#buttonsRichDialog,
QWidget#mainOSK,
QWidget#headerOSK,
QWidget#normalOSK,
QWidget#shiftOSK,
QWidget#numOSK,
QWidget#subOSK,
QWidget#inputOSK,
QWidget#inputBoxOSK,
QWidget#charactersOSK,
QWidget#charactersBoxOSK,
QWidget#legendOSK,
QWidget#legendOSK QWidget,
QWidget#legendOSKshift,
QWidget#legendOSKshift QWidget,
QWidget#legendOSKnum,
QWidget#legendOSKnum QWidget {
background: transparent;
}
QWidget#contentDialog QLabel,
QWidget#legendOSK QLabel,
QWidget#legendOSKshift QLabel,
QWidget#legendOSKnum QLabel {
color: rgba(255, 255, 255, 1);
}
QWidget#contentDialog QLabel#label_dialog {
padding: 20px 65px;
}
QWidget#contentDialog QLabel#label_title,
QWidget#contentRichDialog QLabel#label_title_rich {
padding: 0px 65px;
}
QDialog#OverlayDialog QPushButton {
color: rgba(1, 253, 201, 1);
background: transparent;
border: none;
padding: 0px;
min-width: 0px;
}
QDialog#OverlayDialog QPushButton:focus,
QDialog#OverlayDialog QPushButton:hover {
color: rgba(1, 253, 201, 1);
background: rgba(58, 61, 66, 1);
border: 5px solid rgba(56, 189, 225, 1);
border-radius: 6px;
outline: none;
}
QDialog#OverlayDialog QPushButton:pressed {
color: rgba(240, 240, 240, 1);
background: rgba(150, 150, 150, 1);
border: 5px solid rgba(56, 189, 225, 1);
border-radius: 6px;
outline: none;
}
QDialog#QtSoftwareKeyboardDialog QPushButton {
color: rgba(255, 255, 255, 1);
background: rgba(80, 79, 80, 1);
border: 2px solid rgba(71, 69, 71, 1);
padding: 0px;
min-width: 0px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
background: rgba(95, 94, 95, 1);
border: 2px solid rgba(71, 69, 71, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
color: rgba(240, 240, 240, 1);
background: rgba(255, 255, 255, 1);
border: 2px solid rgba(71, 69, 71, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
color: rgba(0, 0, 0, 1);
background: rgba(1, 253, 201, 1);
border: 2px solid rgba(71, 69, 71, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
color: rgba(255, 255, 255, 1);
background: rgba(58, 61, 66, 1);
border: 5px solid rgba(56, 189, 225, 1);
border-radius: 6px;
outline: none;
}
QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
color: rgba(240, 240, 240, 1);
background: rgba(150, 150, 150, 1);
border: 5px solid rgba(56, 189, 225, 1);
border-radius: 6px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
background-position: right top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_B_dark.png);
qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
background-position: right top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_Y_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
color: rgba(44, 44, 44, 1);
background-position: right top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_plus_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
background-position: left top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_shift_lock_off.png);
qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
background-position: left top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_shift_lock_off.png);
qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
padding-bottom: 7px;
}
QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
background: transparent;
color: #ccc;
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
image: url(:/overlay/button_L_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
image: url(:/overlay/arrow_left_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
image: url(:/overlay/button_R_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
image: url(:/overlay/arrow_right_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
image: url(:/overlay/button_press_stick_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
image: url(:/overlay/button_X_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
image: url(:/overlay/button_A_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
color: rgba(144, 144, 144, 1);
background-color: rgba(95, 94, 95, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
color: rgba(144, 144, 144, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
background-image: url(:/overlay/osk_button_plus_dark_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
background-image: url(:/overlay/osk_button_B_dark_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
background-image: url(:/overlay/osk_button_Y_dark_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QFrame,
QDialog#QtSoftwareKeyboardDialog QFrame[frameShape="0"],
QDialog#OverlayDialog QFrame,
QDialog#OverlayDialog QFrame[frameShape="0"] {
border-radius: 0px;
border: none;
} }

View File

@ -1,10 +1,10 @@
/* --------------------------------------------------------------------------- /* ---------------------------------------------------------------------------
Created by the qtsass compiler v0.1.1 Created by the qtsass compiler v0.1.1
The definitions are in the "qdarkstyle.qss._styles.scss" module The definitions are in the "qdarkstyle.qss._styles.scss" module
WARNING! All changes made in this file will be lost! WARNING! All changes made in this file will be lost!
--------------------------------------------------------------------------- */ --------------------------------------------------------------------------- */
/* QDarkStyleSheet ----------------------------------------------------------- /* QDarkStyleSheet -----------------------------------------------------------
@ -15,34 +15,34 @@ It is based on three selecting colors, three greyish (background) colors
plus three whitish (foreground) colors. Each set of widgets of the same plus three whitish (foreground) colors. Each set of widgets of the same
type have a header like this: type have a header like this:
------------------ ------------------
GroupName -------- GroupName --------
------------------ ------------------
And each widget is separated with a header like this: And each widget is separated with a header like this:
QWidgetName ------ QWidgetName ------
This makes more easy to find and change some css field. The basic This makes more easy to find and change some css field. The basic
configuration is described bellow. configuration is described bellow.
BACKGROUND ----------- BACKGROUND -----------
Light (unpressed) Light (unpressed)
Normal (border, disabled, pressed, checked, toolbars, menus) Normal (border, disabled, pressed, checked, toolbars, menus)
Dark (background) Dark (background)
FOREGROUND ----------- FOREGROUND -----------
Light (texts/labels) Light (texts/labels)
Normal (not used yet) Normal (not used yet)
Dark (disabled texts) Dark (disabled texts)
SELECTION ------------ SELECTION ------------
Light (selection/hover/active) Light (selection/hover/active)
Normal (selected) Normal (selected)
Dark (selected disabled) Dark (selected disabled)
If a stranger configuration is required because of a bugfix or anything If a stranger configuration is required because of a bugfix or anything
else, keep the comment on the line above so nobody changes it, including the else, keep the comment on the line above so nobody changes it, including the
@ -2483,3 +2483,404 @@ QWidget#controllerPlayer7,
QWidget#controllerPlayer8 { QWidget#controllerPlayer8 {
background: transparent; background: transparent;
} }
QDialog#QtSoftwareKeyboardDialog,
QStackedWidget#topOSK {
background: rgba(15, 25, 34, .9);
}
QDialog#OverlayDialog,
QStackedWidget#stackedDialog {
background: rgba(15, 25, 34, .7);
}
QWidget#boxOSK,
QWidget#lineOSK,
QWidget#richDialog,
QWidget#lineDialog {
background: transparent;
}
QStackedWidget#bottomOSK,
QWidget#contentDialog,
QWidget#contentRichDialog {
background: rgba(31, 41, 51, 1);
}
QWidget#contentDialog,
QWidget#contentRichDialog {
margin: 5px;
border-radius: 6px;
}
QWidget#buttonsDialog,
QWidget#buttonsRichDialog {
margin: 5px;
border-top: 2px solid rgba(255, 255, 255, .9);
}
QWidget#legendOSKnum {
border-top: 1px solid rgba(255, 255, 255, 1);
}
QStackedWidget#stackedDialog QTextBrowser QWidget {
background: transparent;
}
QStackedWidget#stackedDialog QTextBrowser QScrollBar {
background: #19232d;
border: none;
}
QStackedWidget#stackedDialog QTextBrowser QScrollBar::sub-line,
QStackedWidget#stackedDialog QTextBrowser QScrollBar::add-line {
border-image: none;
}
QWidget#mainOSK QStackedWidget,
QDialog#OverlayDialog QStackedWidget {
border: none;
padding: 0px;
}
QWidget#inputOSK {
border-bottom: 3px solid rgba(255, 255, 255, .9);
}
QWidget#inputOSK QLineEdit {
background: transparent;
border: none;
color: #ccc;
padding: 0px;
}
QWidget#inputBoxOSK {
border: 2px solid rgba(255, 255, 255, .9);
}
QWidget#inputBoxOSK QTextEdit {
background: transparent;
border: none;
color: #ccc;
}
QWidget#richDialog QTextBrowser {
background: transparent;
border: none;
color: #fff;
padding: 35px 65px;
}
QWidget#lineOSK QLabel#label_header {
color: #f0f0f0;
}
QWidget#lineOSK QLabel#label_sub,
QWidget#lineOSK QLabel#label_characters,
QWidget#contentDialog QLabel#label_title,
QWidget#contentRichDialog QLabel#label_title_rich,
QWidget#boxOSK QLabel#label_characters_box {
color: #ccc;
}
QWidget#buttonsDialog,
QWidget#buttonsRichDialog,
QWidget#mainOSK,
QWidget#headerOSK,
QWidget#normalOSK,
QWidget#shiftOSK,
QWidget#numOSK,
QWidget#subOSK,
QWidget#inputOSK,
QWidget#inputBoxOSK,
QWidget#charactersOSK,
QWidget#charactersBoxOSK,
QWidget#legendOSK,
QWidget#legendOSK QWidget,
QWidget#legendOSKshift,
QWidget#legendOSKshift QWidget,
QWidget#legendOSKnum,
QWidget#legendOSKnum QWidget {
background: transparent;
}
QWidget#contentDialog QLabel,
QWidget#legendOSK QLabel,
QWidget#legendOSKshift QLabel,
QWidget#legendOSKnum QLabel {
color: rgba(255, 255, 255, 1);
}
QWidget#contentDialog QLabel#label_dialog {
padding: 20px 65px;
}
QWidget#contentDialog QLabel#label_title,
QWidget#contentRichDialog QLabel#label_title_rich {
padding: 0px 65px;
}
QDialog#OverlayDialog QPushButton {
color: rgba(1, 253, 201, 1);
background: transparent;
border: none;
padding: 0px;
min-width: 0px;
}
QDialog#OverlayDialog QPushButton:focus,
QDialog#OverlayDialog QPushButton:hover {
color: rgba(1, 253, 201, 1);
background: rgba(18, 33, 46, 1);
border: 5px solid rgba(56, 189, 225, 1);
border-radius: 6px;
outline: none;
}
QDialog#OverlayDialog QPushButton:pressed {
color: rgba(240, 240, 240, 1);
background: rgba(110, 122, 130, 1);
border: 5px solid rgba(56, 189, 225, 1);
border-radius: 6px;
outline: none;
}
QDialog#QtSoftwareKeyboardDialog QLabel {
padding: 0px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton {
color: rgba(255, 255, 255, 1);
background: rgba(40, 51, 60, 1);
border: 2px solid rgba(31, 41, 51, 1);
border-radius: 0px;
padding: 0px;
min-width: 0px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
background: rgba(55, 66, 75, 1);
border: 2px solid rgba(31, 41, 51, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
color: rgba(240, 240, 240, 1);
background: rgba(255, 255, 255, 1);
border: 2px solid rgba(31, 41, 51, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
color: rgba(0, 0, 0, 1);
background: rgba(1, 253, 201, 1);
border: 2px solid rgba(31, 41, 51, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:focus,
QDialog#QtSoftwareKeyboardDialog QPushButton:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:hover,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:hover {
color: rgba(255, 255, 255, 1);
background: rgba(18, 33, 46, 1);
border: 5px solid rgba(56, 189, 225, 1);
border-radius: 6px;
outline: none;
}
QDialog#QtSoftwareKeyboardDialog QPushButton:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:pressed,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:pressed {
color: rgba(240, 240, 240, 1);
background: rgba(110, 122, 130, 1);
border: 5px solid rgba(56, 189, 225, 1);
border-radius: 6px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num {
background-position: right top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_B_dark.png);
qproperty-icon: url(:/overlay/osk_button_backspace_dark.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift {
background-position: right top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_Y_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num {
color: rgba(44, 44, 44, 1);
background-position: right top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_plus_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift {
background-position: left top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_shift_lock_off.png);
qproperty-icon: url(:/overlay/osk_button_shift_dark.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_shift_shift {
background-position: left top;
background-repeat: no-repeat;
background-origin: content;
background-image: url(:/overlay/osk_button_shift_lock_off.png);
qproperty-icon: url(:/overlay/osk_button_shift_on_dark.png);
qproperty-iconSize: 36px;
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_bracket,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_bracket,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_left_parenthesis,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_right_parenthesis {
padding-bottom: 7px;
}
QDialog#QtSoftwareKeyboardDialog QWidget#titleOSK QLabel {
background: transparent;
color: #ccc;
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_L,
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_L_num {
image: url(:/overlay/button_L_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_left_num {
image: url(:/overlay/arrow_left_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_R,
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_R_num {
image: url(:/overlay/button_R_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#arrow_right_num {
image: url(:/overlay/arrow_right_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick,
QDialog#QtSoftwareKeyboardDialog QWidget#button_press_stick_shift {
image: url(:/overlay/button_press_stick_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_X,
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_X_num {
image: url(:/overlay/button_X_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QWidget#button_A,
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_shift,
QDialog#QtSoftwareKeyboardDialog QWidget#button_A_num {
image: url(:/overlay/button_A_dark.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
color: rgba(144, 144, 144, 1);
background-color: rgba(55, 66, 75, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_at:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_slash:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_percent:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_1:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_2:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_3:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_4:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_5:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_6:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_7:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_8:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_9:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_0:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_return:disabled {
color: rgba(144, 144, 144, 1);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_ok_num:disabled {
background-image: url(:/overlay/osk_button_plus_dark_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_shift:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_backspace_num:disabled {
background-image: url(:/overlay/osk_button_B_dark_disabled.png);
}
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space:disabled,
QDialog#QtSoftwareKeyboardDialog QPushButton#button_space_shift:disabled {
background-image: url(:/overlay/osk_button_Y_dark_disabled.png);
}

BIN
dist/yuzu.ico vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 25 KiB

2
dist/yuzu.svg vendored
View File

@ -1 +1 @@
<svg id="svg815" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 614.4 682.67"><defs><style>.cls-1{fill:none;}.cls-2{clip-path:url(#clip-path);}.cls-3{fill:#ff3c28;}.cls-4{fill:#0ab9e6;}</style><clipPath id="clip-path"><rect class="cls-1" x="-43" y="-46.67" width="699.6" height="777.33"/></clipPath></defs><title>Artboard 1</title><g id="g823"><g id="right"><g class="cls-2"><g id="g827"><g id="g833"><path id="path835" class="cls-3" d="M340.81,138V682.08c150.26,0,272.06-121.81,272.06-272.06S491.07,138,340.81,138M394,197.55a219.06,219.06,0,0,1,0,424.94V197.55"/></g></g></g></g><g id="left"><g class="cls-2"><g id="g839"><g id="g845"><path id="path847" class="cls-4" d="M272.79,1.92C122.53,1.92.73,123.73.73,274s121.8,272.07,272.06,272.07ZM219.65,61.51v425A219,219,0,0,1,118,119.18,217.51,217.51,0,0,1,219.65,61.51"/></g></g></g></g></g></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 612.15 680.17"><defs><style>.cls-1{fill:#c6c6c6;}.cls-2{fill:#ffdc00;}</style></defs><title>newAsset 7</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><g id="g823"><g id="right"><g id="g827"><g id="g833"><path id="path835" class="cls-1" d="M340.08,136V680.17c150.26,0,272.07-121.81,272.07-272.07S490.34,136,340.08,136m53.14,59.6a219.06,219.06,0,0,1,0,424.94V195.63"/></g></g></g><g id="left"><g id="g839"><g id="g845"><path id="path847" class="cls-2" d="M272.07,0C121.81,0,0,121.81,0,272.07S121.81,544.13,272.07,544.13ZM218.93,59.6V484.54A219,219,0,0,1,117.26,117.26,217.44,217.44,0,0,1,218.93,59.6"/></g></g></g></g></g></g></svg>

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 717 B

View File

@ -109,6 +109,7 @@ add_library(common STATIC
cityhash.h cityhash.h
common_funcs.h common_funcs.h
common_paths.h common_paths.h
common_sizes.h
common_types.h common_types.h
concepts.h concepts.h
div_ceil.h div_ceil.h

View File

@ -29,22 +29,19 @@ assert_noinline_call(const Fn& fn) {
} }
#define ASSERT(_a_) \ #define ASSERT(_a_) \
do \ if (!(_a_)) { \
if (!(_a_)) { \ LOG_CRITICAL(Debug, "Assertion Failed!"); \
assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \ }
} \
while (0)
#define ASSERT_MSG(_a_, ...) \ #define ASSERT_MSG(_a_, ...) \
do \ if (!(_a_)) { \
if (!(_a_)) { \ LOG_CRITICAL(Debug, "Assertion Failed! " __VA_ARGS__); \
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \ }
} \
while (0)
#define UNREACHABLE() assert_noinline_call([] { LOG_CRITICAL(Debug, "Unreachable code!"); }) #define UNREACHABLE() \
{ LOG_CRITICAL(Debug, "Unreachable code!"); }
#define UNREACHABLE_MSG(...) \ #define UNREACHABLE_MSG(...) \
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); }) { LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); }
#ifdef _DEBUG #ifdef _DEBUG
#define DEBUG_ASSERT(_a_) ASSERT(_a_) #define DEBUG_ASSERT(_a_) ASSERT(_a_)

View File

@ -141,6 +141,9 @@ add_library(core STATIC
hardware_interrupt_manager.h hardware_interrupt_manager.h
hle/ipc.h hle/ipc.h
hle/ipc_helpers.h hle/ipc_helpers.h
hle/kernel/board/nintendo/nx/k_system_control.cpp
hle/kernel/board/nintendo/nx/k_system_control.h
hle/kernel/board/nintendo/nx/secure_monitor.h
hle/kernel/client_port.cpp hle/kernel/client_port.cpp
hle/kernel/client_port.h hle/kernel/client_port.h
hle/kernel/client_session.cpp hle/kernel/client_session.cpp
@ -169,9 +172,13 @@ add_library(core STATIC
hle/kernel/k_memory_block.h hle/kernel/k_memory_block.h
hle/kernel/k_memory_block_manager.cpp hle/kernel/k_memory_block_manager.cpp
hle/kernel/k_memory_block_manager.h hle/kernel/k_memory_block_manager.h
hle/kernel/k_memory_layout.cpp
hle/kernel/k_memory_layout.board.nintendo_nx.cpp
hle/kernel/k_memory_layout.h hle/kernel/k_memory_layout.h
hle/kernel/k_memory_manager.cpp hle/kernel/k_memory_manager.cpp
hle/kernel/k_memory_manager.h hle/kernel/k_memory_manager.h
hle/kernel/k_memory_region.h
hle/kernel/k_memory_region_type.h
hle/kernel/k_page_bitmap.h hle/kernel/k_page_bitmap.h
hle/kernel/k_page_heap.cpp hle/kernel/k_page_heap.cpp
hle/kernel/k_page_heap.h hle/kernel/k_page_heap.h
@ -196,11 +203,11 @@ add_library(core STATIC
hle/kernel/k_spin_lock.h hle/kernel/k_spin_lock.h
hle/kernel/k_synchronization_object.cpp hle/kernel/k_synchronization_object.cpp
hle/kernel/k_synchronization_object.h hle/kernel/k_synchronization_object.h
hle/kernel/k_system_control.cpp
hle/kernel/k_system_control.h hle/kernel/k_system_control.h
hle/kernel/k_thread.cpp hle/kernel/k_thread.cpp
hle/kernel/k_thread.h hle/kernel/k_thread.h
hle/kernel/k_thread_queue.h hle/kernel/k_thread_queue.h
hle/kernel/k_trace.h
hle/kernel/k_writable_event.cpp hle/kernel/k_writable_event.cpp
hle/kernel/k_writable_event.h hle/kernel/k_writable_event.h
hle/kernel/kernel.cpp hle/kernel/kernel.cpp
@ -264,6 +271,7 @@ add_library(core STATIC
hle/service/am/applets/general_backend.h hle/service/am/applets/general_backend.h
hle/service/am/applets/profile_select.cpp hle/service/am/applets/profile_select.cpp
hle/service/am/applets/profile_select.h hle/service/am/applets/profile_select.h
hle/service/am/applets/software_keyboard_types.h
hle/service/am/applets/software_keyboard.cpp hle/service/am/applets/software_keyboard.cpp
hle/service/am/applets/software_keyboard.h hle/service/am/applets/software_keyboard.h
hle/service/am/applets/web_browser.cpp hle/service/am/applets/web_browser.cpp

View File

@ -100,6 +100,14 @@ u64 NACP::GetDeviceSaveDataSize() const {
return raw.device_save_data_size; return raw.device_save_data_size;
} }
u32 NACP::GetParentalControlFlag() const {
return raw.parental_control;
}
const std::array<u8, 0x20>& NACP::GetRatingAge() const {
return raw.rating_age;
}
std::vector<u8> NACP::GetRawBytes() const { std::vector<u8> NACP::GetRawBytes() const {
std::vector<u8> out(sizeof(RawNACP)); std::vector<u8> out(sizeof(RawNACP));
std::memcpy(out.data(), &raw, sizeof(RawNACP)); std::memcpy(out.data(), &raw, sizeof(RawNACP));

View File

@ -114,6 +114,8 @@ public:
std::vector<u8> GetRawBytes() const; std::vector<u8> GetRawBytes() const;
bool GetUserAccountSwitchLock() const; bool GetUserAccountSwitchLock() const;
u64 GetDeviceSaveDataSize() const; u64 GetDeviceSaveDataSize() const;
u32 GetParentalControlFlag() const;
const std::array<u8, 0x20>& GetRatingAge() const;
private: private:
RawNACP raw{}; RawNACP raw{};

View File

@ -1,29 +1,149 @@
// Copyright 2018 yuzu emulator team // Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/logging/backend.h" #include <thread>
#include "common/logging/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/software_keyboard.h"
namespace Core::Frontend { namespace Core::Frontend {
SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default; SoftwareKeyboardApplet::~SoftwareKeyboardApplet() = default;
void DefaultSoftwareKeyboardApplet::RequestText( DefaultSoftwareKeyboardApplet::~DefaultSoftwareKeyboardApplet() = default;
std::function<void(std::optional<std::u16string>)> out,
SoftwareKeyboardParameters parameters) const {
if (parameters.initial_text.empty())
out(u"yuzu");
out(parameters.initial_text); void DefaultSoftwareKeyboardApplet::InitializeKeyboard(
bool is_inline, KeyboardInitializeParameters initialize_parameters,
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)> submit_normal_callback_,
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback_) {
if (is_inline) {
LOG_WARNING(
Service_AM,
"(STUBBED) called, backend requested to initialize the inline software keyboard.");
submit_inline_callback = std::move(submit_inline_callback_);
} else {
LOG_WARNING(
Service_AM,
"(STUBBED) called, backend requested to initialize the normal software keyboard.");
submit_normal_callback = std::move(submit_normal_callback_);
}
parameters = std::move(initialize_parameters);
LOG_INFO(Service_AM,
"\nKeyboardInitializeParameters:"
"\nok_text={}"
"\nheader_text={}"
"\nsub_text={}"
"\nguide_text={}"
"\ninitial_text={}"
"\nmax_text_length={}"
"\nmin_text_length={}"
"\ninitial_cursor_position={}"
"\ntype={}"
"\npassword_mode={}"
"\ntext_draw_type={}"
"\nkey_disable_flags={}"
"\nuse_blur_background={}"
"\nenable_backspace_button={}"
"\nenable_return_button={}"
"\ndisable_cancel_button={}",
Common::UTF16ToUTF8(parameters.ok_text), Common::UTF16ToUTF8(parameters.header_text),
Common::UTF16ToUTF8(parameters.sub_text), Common::UTF16ToUTF8(parameters.guide_text),
Common::UTF16ToUTF8(parameters.initial_text), parameters.max_text_length,
parameters.min_text_length, parameters.initial_cursor_position, parameters.type,
parameters.password_mode, parameters.text_draw_type, parameters.key_disable_flags.raw,
parameters.use_blur_background, parameters.enable_backspace_button,
parameters.enable_return_button, parameters.disable_cancel_button);
} }
void DefaultSoftwareKeyboardApplet::SendTextCheckDialog( void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const {
std::u16string error_message, std::function<void()> finished_check) const {
LOG_WARNING(Service_AM, LOG_WARNING(Service_AM,
"(STUBBED) called - Default fallback software keyboard does not support text " "(STUBBED) called, backend requested to show the normal software keyboard.");
"check! (error_message={})",
Common::UTF16ToUTF8(error_message)); SubmitNormalText(u"yuzu");
finished_check();
} }
void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const {
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog.");
}
void DefaultSoftwareKeyboardApplet::ShowInlineKeyboard(
InlineAppearParameters appear_parameters) const {
LOG_WARNING(Service_AM,
"(STUBBED) called, backend requested to show the inline software keyboard.");
LOG_INFO(Service_AM,
"\nInlineAppearParameters:"
"\nmax_text_length={}"
"\nmin_text_length={}"
"\nkey_top_scale_x={}"
"\nkey_top_scale_y={}"
"\nkey_top_translate_x={}"
"\nkey_top_translate_y={}"
"\ntype={}"
"\nkey_disable_flags={}"
"\nkey_top_as_floating={}"
"\nenable_backspace_button={}"
"\nenable_return_button={}"
"\ndisable_cancel_button={}",
appear_parameters.max_text_length, appear_parameters.min_text_length,
appear_parameters.key_top_scale_x, appear_parameters.key_top_scale_y,
appear_parameters.key_top_translate_x, appear_parameters.key_top_translate_y,
appear_parameters.type, appear_parameters.key_disable_flags.raw,
appear_parameters.key_top_as_floating, appear_parameters.enable_backspace_button,
appear_parameters.enable_return_button, appear_parameters.disable_cancel_button);
std::thread([this] { SubmitInlineText(u"yuzu"); }).detach();
}
void DefaultSoftwareKeyboardApplet::HideInlineKeyboard() const {
LOG_WARNING(Service_AM,
"(STUBBED) called, backend requested to hide the inline software keyboard.");
}
void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_parameters) const {
LOG_WARNING(Service_AM,
"(STUBBED) called, backend requested to change the inline keyboard text.");
LOG_INFO(Service_AM,
"\nInlineTextParameters:"
"\ninput_text={}"
"\ncursor_position={}",
Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
text_parameters.input_text, text_parameters.cursor_position);
}
void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to exit the software keyboard.");
}
void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text);
}
void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
for (std::size_t index = 0; index < text.size(); ++index) {
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
std::u16string(text.data(), text.data() + index + 1),
static_cast<s32>(index) + 1);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text),
static_cast<s32>(text.size()));
}
} // namespace Core::Frontend } // namespace Core::Frontend

View File

@ -1,54 +1,116 @@
// Copyright 2018 yuzu emulator team // Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <functional> #include <functional>
#include <optional> #include <thread>
#include <string>
#include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/service/am/applets/software_keyboard_types.h"
namespace Core::Frontend { namespace Core::Frontend {
struct SoftwareKeyboardParameters {
std::u16string submit_text; struct KeyboardInitializeParameters {
std::u16string ok_text;
std::u16string header_text; std::u16string header_text;
std::u16string sub_text; std::u16string sub_text;
std::u16string guide_text; std::u16string guide_text;
std::u16string initial_text; std::u16string initial_text;
std::size_t max_length; u32 max_text_length;
bool password; u32 min_text_length;
bool cursor_at_beginning; s32 initial_cursor_position;
Service::AM::Applets::SwkbdType type;
Service::AM::Applets::SwkbdPasswordMode password_mode;
Service::AM::Applets::SwkbdTextDrawType text_draw_type;
Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
bool use_blur_background;
bool enable_backspace_button;
bool enable_return_button;
bool disable_cancel_button;
};
union { struct InlineAppearParameters {
u8 value; u32 max_text_length;
u32 min_text_length;
f32 key_top_scale_x;
f32 key_top_scale_y;
f32 key_top_translate_x;
f32 key_top_translate_y;
Service::AM::Applets::SwkbdType type;
Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
bool key_top_as_floating;
bool enable_backspace_button;
bool enable_return_button;
bool disable_cancel_button;
};
BitField<1, 1, u8> disable_space; struct InlineTextParameters {
BitField<2, 1, u8> disable_address; std::u16string input_text;
BitField<3, 1, u8> disable_percent; s32 cursor_position;
BitField<4, 1, u8> disable_slash;
BitField<6, 1, u8> disable_number;
BitField<7, 1, u8> disable_download_code;
};
}; };
class SoftwareKeyboardApplet { class SoftwareKeyboardApplet {
public: public:
virtual ~SoftwareKeyboardApplet(); virtual ~SoftwareKeyboardApplet();
virtual void RequestText(std::function<void(std::optional<std::u16string>)> out, virtual void InitializeKeyboard(
SoftwareKeyboardParameters parameters) const = 0; bool is_inline, KeyboardInitializeParameters initialize_parameters,
virtual void SendTextCheckDialog(std::u16string error_message, std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
std::function<void()> finished_check) const = 0; submit_normal_callback_,
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback_) = 0;
virtual void ShowNormalKeyboard() const = 0;
virtual void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const = 0;
virtual void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const = 0;
virtual void HideInlineKeyboard() const = 0;
virtual void InlineTextChanged(InlineTextParameters text_parameters) const = 0;
virtual void ExitKeyboard() const = 0;
}; };
class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet { class DefaultSoftwareKeyboardApplet final : public SoftwareKeyboardApplet {
public: public:
void RequestText(std::function<void(std::optional<std::u16string>)> out, ~DefaultSoftwareKeyboardApplet() override;
SoftwareKeyboardParameters parameters) const override;
void SendTextCheckDialog(std::u16string error_message, void InitializeKeyboard(
std::function<void()> finished_check) const override; bool is_inline, KeyboardInitializeParameters initialize_parameters,
std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
submit_normal_callback_,
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback_) override;
void ShowNormalKeyboard() const override;
void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const override;
void ShowInlineKeyboard(InlineAppearParameters appear_parameters) const override;
void HideInlineKeyboard() const override;
void InlineTextChanged(InlineTextParameters text_parameters) const override;
void ExitKeyboard() const override;
private:
void SubmitNormalText(std::u16string text) const;
void SubmitInlineText(std::u16string_view text) const;
KeyboardInitializeParameters parameters;
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
submit_normal_callback;
mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback;
}; };
} // namespace Core::Frontend } // namespace Core::Frontend

View File

@ -12,7 +12,9 @@ InputInterpreter::InputInterpreter(Core::System& system)
: npad{system.ServiceManager() : npad{system.ServiceManager()
.GetService<Service::HID::Hid>("hid") .GetService<Service::HID::Hid>("hid")
->GetAppletResource() ->GetAppletResource()
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {} ->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad)} {
ResetButtonStates();
}
InputInterpreter::~InputInterpreter() = default; InputInterpreter::~InputInterpreter() = default;
@ -25,6 +27,17 @@ void InputInterpreter::PollInput() {
button_states[current_index] = button_state; button_states[current_index] = button_state;
} }
void InputInterpreter::ResetButtonStates() {
previous_index = 0;
current_index = 0;
button_states[0] = 0xFFFFFFFF;
for (std::size_t i = 1; i < button_states.size(); ++i) {
button_states[i] = 0;
}
}
bool InputInterpreter::IsButtonPressed(HIDButton button) const { bool InputInterpreter::IsButtonPressed(HIDButton button) const {
return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0; return (button_states[current_index] & (1U << static_cast<u8>(button))) != 0;
} }

View File

@ -66,6 +66,9 @@ public:
/// Gets a button state from HID and inserts it into the array of button states. /// Gets a button state from HID and inserts it into the array of button states.
void PollInput(); void PollInput();
/// Resets all the button states to their defaults.
void ResetButtonStates();
/** /**
* Checks whether the button is pressed. * Checks whether the button is pressed.
* *

View File

@ -75,10 +75,14 @@ void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_
if (incoming) { if (incoming) {
// Populate the object lists with the data in the IPC request. // Populate the object lists with the data in the IPC request.
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
copy_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>())); const u32 copy_handle{rp.Pop<Handle>()};
copy_handles.push_back(copy_handle);
copy_objects.push_back(handle_table.GetGeneric(copy_handle));
} }
for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) {
move_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>())); const u32 move_handle{rp.Pop<Handle>()};
move_handles.push_back(move_handle);
move_objects.push_back(handle_table.GetGeneric(move_handle));
} }
} else { } else {
// For responses we just ignore the handles, they're empty and will be populated when // For responses we just ignore the handles, they're empty and will be populated when

View File

@ -210,6 +210,14 @@ public:
/// Helper function to test whether the output buffer at buffer_index can be written /// Helper function to test whether the output buffer at buffer_index can be written
bool CanWriteBuffer(std::size_t buffer_index = 0) const; bool CanWriteBuffer(std::size_t buffer_index = 0) const;
Handle GetCopyHandle(std::size_t index) const {
return copy_handles.at(index);
}
Handle GetMoveHandle(std::size_t index) const {
return move_handles.at(index);
}
template <typename T> template <typename T>
std::shared_ptr<T> GetCopyObject(std::size_t index) { std::shared_ptr<T> GetCopyObject(std::size_t index) {
return DynamicObjectCast<T>(copy_objects.at(index)); return DynamicObjectCast<T>(copy_objects.at(index));
@ -285,6 +293,8 @@ private:
std::shared_ptr<Kernel::ServerSession> server_session; std::shared_ptr<Kernel::ServerSession> server_session;
std::shared_ptr<KThread> thread; std::shared_ptr<KThread> thread;
// TODO(yuriks): Check common usage of this and optimize size accordingly // TODO(yuriks): Check common usage of this and optimize size accordingly
boost::container::small_vector<Handle, 8> move_handles;
boost::container::small_vector<Handle, 8> copy_handles;
boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects; boost::container::small_vector<std::shared_ptr<Object>, 8> move_objects;
boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects; boost::container::small_vector<std::shared_ptr<Object>, 8> copy_objects;
boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects;

View File

@ -5,45 +5,34 @@
#include <array> #include <array>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_sizes.h"
#include "core/hle/kernel/k_address_space_info.h" #include "core/hle/kernel/k_address_space_info.h"
namespace Kernel { namespace Kernel {
namespace { namespace {
enum : u64 {
Size_1_MB = 0x100000,
Size_2_MB = 2 * Size_1_MB,
Size_128_MB = 128 * Size_1_MB,
Size_1_GB = 0x40000000,
Size_2_GB = 2 * Size_1_GB,
Size_4_GB = 4 * Size_1_GB,
Size_6_GB = 6 * Size_1_GB,
Size_64_GB = 64 * Size_1_GB,
Size_512_GB = 512 * Size_1_GB,
Invalid = std::numeric_limits<u64>::max(),
};
// clang-format off // clang-format off
constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{ constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
{ .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, }, { .bit_width = 32, .address = Common::Size_2_MB , .size = Common::Size_1_GB - Common::Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, }, { .bit_width = 32, .address = Common::Size_1_GB , .size = Common::Size_4_GB - Common::Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, }, { .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, }, { .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, }, { .bit_width = 36, .address = Common::Size_128_MB , .size = Common::Size_2_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, }, { .bit_width = 36, .address = Common::Size_2_GB , .size = Common::Size_64_GB - Common::Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, }, { .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, }, { .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, }, { .bit_width = 39, .address = Common::Size_128_MB , .size = Common::Size_512_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
{ .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall }, { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
{ .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, }, { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, }, { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, }, { .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
}}; }};
// clang-format on // clang-format on
constexpr bool IsAllowedIndexForAddress(std::size_t index) { constexpr bool IsAllowedIndexForAddress(std::size_t index) {
return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid; return index < AddressSpaceInfos.size() &&
AddressSpaceInfos[index].address != Common::Size_Invalid;
} }
using IndexArray = using IndexArray =

View File

@ -1,23 +1,69 @@
// Copyright 2020 yuzu Emulator Project // Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <utility>
#include "common/alignment.h"
#include "common/common_sizes.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "core/device_memory.h" #include "core/device_memory.h"
#include "core/hle/kernel/k_memory_region.h"
#include "core/hle/kernel/k_memory_region_type.h"
#include "core/hle/kernel/memory_types.h"
namespace Kernel { namespace Kernel {
constexpr std::size_t KernelAslrAlignment = 2 * 1024 * 1024; constexpr std::size_t L1BlockSize = Common::Size_1_GB;
constexpr std::size_t L2BlockSize = Common::Size_2_MB;
constexpr std::size_t GetMaximumOverheadSize(std::size_t size) {
return (Common::DivideUp(size, L1BlockSize) + Common::DivideUp(size, L2BlockSize)) * PageSize;
}
constexpr std::size_t MainMemorySize = Common::Size_4_GB;
constexpr std::size_t MainMemorySizeMax = Common::Size_8_GB;
constexpr std::size_t ReservedEarlyDramSize = 0x60000;
constexpr std::size_t DramPhysicalAddress = 0x80000000;
constexpr std::size_t KernelAslrAlignment = Common::Size_2_MB;
constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39; constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39;
constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48; constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48;
constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth; constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth;
constexpr std::size_t KernelVirtualAddressSpaceEnd = constexpr std::size_t KernelVirtualAddressSpaceEnd =
KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment); KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment);
constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1; constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1ULL;
constexpr std::size_t KernelVirtualAddressSpaceSize = constexpr std::size_t KernelVirtualAddressSpaceSize =
KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase; KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase;
constexpr std::size_t KernelVirtualAddressCodeBase = KernelVirtualAddressSpaceBase;
constexpr std::size_t KernelVirtualAddressCodeSize = 0x62000;
constexpr std::size_t KernelVirtualAddressCodeEnd =
KernelVirtualAddressCodeBase + KernelVirtualAddressCodeSize;
constexpr std::size_t KernelPhysicalAddressSpaceBase = 0ULL;
constexpr std::size_t KernelPhysicalAddressSpaceEnd =
KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceWidth;
constexpr std::size_t KernelPhysicalAddressSpaceLast = KernelPhysicalAddressSpaceEnd - 1ULL;
constexpr std::size_t KernelPhysicalAddressSpaceSize =
KernelPhysicalAddressSpaceEnd - KernelPhysicalAddressSpaceBase;
constexpr std::size_t KernelPhysicalAddressCodeBase = DramPhysicalAddress + ReservedEarlyDramSize;
constexpr std::size_t KernelPageTableHeapSize = GetMaximumOverheadSize(MainMemorySizeMax);
constexpr std::size_t KernelInitialPageHeapSize = Common::Size_128_KB;
constexpr std::size_t KernelSlabHeapDataSize = Common::Size_5_MB;
constexpr std::size_t KernelSlabHeapGapsSize = Common::Size_2_MB - Common::Size_64_KB;
constexpr std::size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize;
// NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860.
constexpr std::size_t KernelSlabHeapAdditionalSize = 0x68000ULL;
constexpr std::size_t KernelResourceSize =
KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize;
constexpr bool IsKernelAddressKey(VAddr key) { constexpr bool IsKernelAddressKey(VAddr key) {
return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast; return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
@ -27,64 +73,327 @@ constexpr bool IsKernelAddress(VAddr address) {
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd; return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
} }
class KMemoryRegion final {
friend class KMemoryLayout;
public:
constexpr PAddr StartAddress() const {
return start_address;
}
constexpr PAddr EndAddress() const {
return end_address;
}
private:
constexpr KMemoryRegion() = default;
constexpr KMemoryRegion(PAddr start_address, PAddr end_address)
: start_address{start_address}, end_address{end_address} {}
const PAddr start_address{};
const PAddr end_address{};
};
class KMemoryLayout final { class KMemoryLayout final {
public: public:
constexpr const KMemoryRegion& Application() const { KMemoryLayout();
return application;
KMemoryRegionTree& GetVirtualMemoryRegionTree() {
return virtual_tree;
}
const KMemoryRegionTree& GetVirtualMemoryRegionTree() const {
return virtual_tree;
}
KMemoryRegionTree& GetPhysicalMemoryRegionTree() {
return physical_tree;
}
const KMemoryRegionTree& GetPhysicalMemoryRegionTree() const {
return physical_tree;
}
KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() {
return virtual_linear_tree;
}
const KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() const {
return virtual_linear_tree;
}
KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() {
return physical_linear_tree;
}
const KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() const {
return physical_linear_tree;
} }
constexpr const KMemoryRegion& Applet() const { VAddr GetLinearVirtualAddress(PAddr address) const {
return applet; return address + linear_phys_to_virt_diff;
}
PAddr GetLinearPhysicalAddress(VAddr address) const {
return address + linear_virt_to_phys_diff;
} }
constexpr const KMemoryRegion& System() const { const KMemoryRegion* FindVirtual(VAddr address) const {
return system; return Find(address, GetVirtualMemoryRegionTree());
}
const KMemoryRegion* FindPhysical(PAddr address) const {
return Find(address, GetPhysicalMemoryRegionTree());
} }
static constexpr KMemoryLayout GetDefaultLayout() { const KMemoryRegion* FindVirtualLinear(VAddr address) const {
constexpr std::size_t application_size{0xcd500000}; return Find(address, GetVirtualLinearMemoryRegionTree());
constexpr std::size_t applet_size{0x1fb00000}; }
constexpr PAddr application_start_address{Core::DramMemoryMap::End - application_size}; const KMemoryRegion* FindPhysicalLinear(PAddr address) const {
constexpr PAddr application_end_address{Core::DramMemoryMap::End}; return Find(address, GetPhysicalLinearMemoryRegionTree());
constexpr PAddr applet_start_address{application_start_address - applet_size}; }
constexpr PAddr applet_end_address{applet_start_address + applet_size};
constexpr PAddr system_start_address{Core::DramMemoryMap::SlabHeapEnd}; VAddr GetMainStackTopAddress(s32 core_id) const {
constexpr PAddr system_end_address{applet_start_address}; return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscMainStack);
return {application_start_address, application_end_address, applet_start_address, }
applet_end_address, system_start_address, system_end_address}; VAddr GetIdleStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscIdleStack);
}
VAddr GetExceptionStackTopAddress(s32 core_id) const {
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack);
}
VAddr GetSlabRegionAddress() const {
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab))
.GetAddress();
}
const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const {
return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type));
}
PAddr GetDevicePhysicalAddress(KMemoryRegionType type) const {
return GetDeviceRegion(type).GetAddress();
}
VAddr GetDeviceVirtualAddress(KMemoryRegionType type) const {
return GetDeviceRegion(type).GetPairAddress();
}
const KMemoryRegion& GetPoolManagementRegion() const {
return Dereference(
GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramPoolManagement));
}
const KMemoryRegion& GetPageTableHeapRegion() const {
return Dereference(
GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelPtHeap));
}
const KMemoryRegion& GetKernelStackRegion() const {
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelStack));
}
const KMemoryRegion& GetTempRegion() const {
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelTemp));
}
const KMemoryRegion& GetKernelTraceBufferRegion() const {
return Dereference(GetVirtualLinearMemoryRegionTree().FindByType(
KMemoryRegionType_VirtualDramKernelTraceBuffer));
}
const KMemoryRegion& GetVirtualLinearRegion(VAddr address) const {
return Dereference(FindVirtualLinear(address));
}
const KMemoryRegion* GetPhysicalKernelTraceBufferRegion() const {
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_KernelTraceBuffer);
}
const KMemoryRegion* GetPhysicalOnMemoryBootImageRegion() const {
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_OnMemoryBootImage);
}
const KMemoryRegion* GetPhysicalDTBRegion() const {
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DTB);
}
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
KMemoryRegionType_DramUserPool);
}
bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address) const {
return IsTypedAddress(region, address, GetVirtualLinearMemoryRegionTree(),
KMemoryRegionType_VirtualDramUserPool);
}
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address, size_t size) const {
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
KMemoryRegionType_DramUserPool);
}
bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address, size_t size) const {
return IsTypedAddress(region, address, size, GetVirtualLinearMemoryRegionTree(),
KMemoryRegionType_VirtualDramUserPool);
}
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
}
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address,
size_t size) const {
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
}
std::pair<size_t, size_t> GetTotalAndKernelMemorySizes() const {
size_t total_size = 0, kernel_size = 0;
for (const auto& region : GetPhysicalMemoryRegionTree()) {
if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
total_size += region.GetSize();
if (!region.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
kernel_size += region.GetSize();
}
}
}
return std::make_pair(total_size, kernel_size);
}
void InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
VAddr linear_virtual_start);
static size_t GetResourceRegionSizeForInit();
auto GetKernelRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel);
}
auto GetKernelCodeRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelCode);
}
auto GetKernelStackRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelStack);
}
auto GetKernelMiscRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelMisc);
}
auto GetKernelSlabRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelSlab);
}
auto GetLinearRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionAttr_LinearMapped);
}
auto GetLinearRegionVirtualExtents() const {
const auto physical = GetLinearRegionPhysicalExtents();
return KMemoryRegion(GetLinearVirtualAddress(physical.GetAddress()),
GetLinearVirtualAddress(physical.GetLastAddress()), 0,
KMemoryRegionType_None);
}
auto GetMainMemoryPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Dram);
}
auto GetCarveoutRegionExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionAttr_CarveoutProtected);
}
auto GetKernelRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelBase);
}
auto GetKernelCodeRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelCode);
}
auto GetKernelSlabRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelSlab);
}
auto GetKernelPageTableHeapRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelPtHeap);
}
auto GetKernelInitPageTableRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelInitPt);
}
auto GetKernelPoolManagementRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramPoolManagement);
}
auto GetKernelPoolPartitionRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramPoolPartition);
}
auto GetKernelSystemPoolRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramSystemPool);
}
auto GetKernelSystemNonSecurePoolRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramSystemNonSecurePool);
}
auto GetKernelAppletPoolRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramAppletPool);
}
auto GetKernelApplicationPoolRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramApplicationPool);
}
auto GetKernelTraceBufferRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_KernelTraceBuffer);
} }
private: private:
constexpr KMemoryLayout(PAddr application_start_address, std::size_t application_size, template <typename AddressType>
PAddr applet_start_address, std::size_t applet_size, static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address,
PAddr system_start_address, std::size_t system_size) const KMemoryRegionTree& tree, KMemoryRegionType type) {
: application{application_start_address, application_size}, // Check if the cached region already contains the address.
applet{applet_start_address, applet_size}, system{system_start_address, system_size} {} if (region != nullptr && region->Contains(address)) {
return true;
}
const KMemoryRegion application; // Find the containing region, and update the cache.
const KMemoryRegion applet; if (const KMemoryRegion* found = tree.Find(address);
const KMemoryRegion system; found != nullptr && found->IsDerivedFrom(type)) {
region = found;
return true;
} else {
return false;
}
}
template <typename AddressType>
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address, size_t size,
const KMemoryRegionTree& tree, KMemoryRegionType type) {
// Get the end of the checked region.
const u64 last_address = address + size - 1;
// Walk the tree to verify the region is correct.
const KMemoryRegion* cur =
(region != nullptr && region->Contains(address)) ? region : tree.Find(address);
while (cur != nullptr && cur->IsDerivedFrom(type)) {
if (last_address <= cur->GetLastAddress()) {
region = cur;
return true;
}
cur = cur->GetNext();
}
return false;
}
template <typename AddressType>
static const KMemoryRegion* Find(AddressType address, const KMemoryRegionTree& tree) {
return tree.Find(address);
}
static KMemoryRegion& Dereference(KMemoryRegion* region) {
ASSERT(region != nullptr);
return *region;
}
static const KMemoryRegion& Dereference(const KMemoryRegion* region) {
ASSERT(region != nullptr);
return *region;
}
VAddr GetStackTopAddress(s32 core_id, KMemoryRegionType type) const {
const auto& region = Dereference(
GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id)));
ASSERT(region.GetEndAddress() != 0);
return region.GetEndAddress();
}
private:
u64 linear_phys_to_virt_diff{};
u64 linear_virt_to_phys_diff{};
KMemoryRegionAllocator memory_region_allocator;
KMemoryRegionTree virtual_tree;
KMemoryRegionTree physical_tree;
KMemoryRegionTree virtual_linear_tree;
KMemoryRegionTree physical_linear_tree;
}; };
namespace Init {
// These should be generic, regardless of board.
void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout);
// These may be implemented in a board-specific manner.
void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout);
void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout);
} // namespace Init
} // namespace Kernel } // namespace Kernel

View File

@ -173,4 +173,16 @@ ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_page
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
std::size_t KMemoryManager::Impl::CalculateManagementOverheadSize(std::size_t region_size) {
const std::size_t ref_count_size = (region_size / PageSize) * sizeof(u16);
const std::size_t optimize_map_size =
(Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
Common::BitSize<u64>()) *
sizeof(u64);
const std::size_t manager_meta_size =
Common::AlignUp(optimize_map_size + ref_count_size, PageSize);
const std::size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(region_size);
return manager_meta_size + page_heap_size;
}
} // namespace Kernel } // namespace Kernel

View File

@ -29,6 +29,10 @@ public:
Shift = 4, Shift = 4,
Mask = (0xF << Shift), Mask = (0xF << Shift),
// Aliases.
Unsafe = Application,
Secure = System,
}; };
enum class Direction : u32 { enum class Direction : u32 {
@ -56,6 +60,10 @@ public:
static constexpr std::size_t MaxManagerCount = 10; static constexpr std::size_t MaxManagerCount = 10;
public: public:
static std::size_t CalculateManagementOverheadSize(std::size_t region_size) {
return Impl::CalculateManagementOverheadSize(region_size);
}
static constexpr u32 EncodeOption(Pool pool, Direction dir) { static constexpr u32 EncodeOption(Pool pool, Direction dir) {
return (static_cast<u32>(pool) << static_cast<u32>(Pool::Shift)) | return (static_cast<u32>(pool) << static_cast<u32>(Pool::Shift)) |
(static_cast<u32>(dir) << static_cast<u32>(Direction::Shift)); (static_cast<u32>(dir) << static_cast<u32>(Direction::Shift));
@ -85,6 +93,16 @@ private:
KPageHeap heap; KPageHeap heap;
Pool pool{}; Pool pool{};
public:
static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
static constexpr std::size_t CalculateOptimizedProcessOverheadSize(
std::size_t region_size) {
return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
Common::BitSize<u64>()) *
sizeof(u64);
}
public: public:
Impl() = default; Impl() = default;

View File

@ -62,7 +62,7 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
} }
u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) { u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
std::scoped_lock lock{guard}; KScopedSpinLock lk{guard};
if (KThread* prev_highest_thread = state.highest_priority_thread; if (KThread* prev_highest_thread = state.highest_priority_thread;
prev_highest_thread != highest_thread) { prev_highest_thread != highest_thread) {
if (prev_highest_thread != nullptr) { if (prev_highest_thread != nullptr) {
@ -637,11 +637,11 @@ void KScheduler::RescheduleCurrentCore() {
if (phys_core.IsInterrupted()) { if (phys_core.IsInterrupted()) {
phys_core.ClearInterrupt(); phys_core.ClearInterrupt();
} }
guard.lock(); guard.Lock();
if (state.needs_scheduling.load()) { if (state.needs_scheduling.load()) {
Schedule(); Schedule();
} else { } else {
guard.unlock(); guard.Unlock();
} }
} }
@ -669,7 +669,7 @@ void KScheduler::Unload(KThread* thread) {
} else { } else {
prev_thread = nullptr; prev_thread = nullptr;
} }
thread->context_guard.unlock(); thread->context_guard.Unlock();
} }
} }
@ -713,7 +713,7 @@ void KScheduler::ScheduleImpl() {
// If we're not actually switching thread, there's nothing to do. // If we're not actually switching thread, there's nothing to do.
if (next_thread == current_thread.load()) { if (next_thread == current_thread.load()) {
guard.unlock(); guard.Unlock();
return; return;
} }
@ -732,7 +732,7 @@ void KScheduler::ScheduleImpl() {
} else { } else {
old_context = &idle_thread->GetHostContext(); old_context = &idle_thread->GetHostContext();
} }
guard.unlock(); guard.Unlock();
Common::Fiber::YieldTo(*old_context, *switch_fiber); Common::Fiber::YieldTo(*old_context, *switch_fiber);
/// When a thread wakes up, the scheduler may have changed to other in another core. /// When a thread wakes up, the scheduler may have changed to other in another core.
@ -748,24 +748,24 @@ void KScheduler::OnSwitch(void* this_scheduler) {
void KScheduler::SwitchToCurrent() { void KScheduler::SwitchToCurrent() {
while (true) { while (true) {
{ {
std::scoped_lock lock{guard}; KScopedSpinLock lk{guard};
current_thread.store(state.highest_priority_thread); current_thread.store(state.highest_priority_thread);
state.needs_scheduling.store(false); state.needs_scheduling.store(false);
} }
const auto is_switch_pending = [this] { const auto is_switch_pending = [this] {
std::scoped_lock lock{guard}; KScopedSpinLock lk{guard};
return state.needs_scheduling.load(); return state.needs_scheduling.load();
}; };
do { do {
auto next_thread = current_thread.load(); auto next_thread = current_thread.load();
if (next_thread != nullptr) { if (next_thread != nullptr) {
next_thread->context_guard.lock(); next_thread->context_guard.Lock();
if (next_thread->GetRawState() != ThreadState::Runnable) { if (next_thread->GetRawState() != ThreadState::Runnable) {
next_thread->context_guard.unlock(); next_thread->context_guard.Unlock();
break; break;
} }
if (next_thread->GetActiveCore() != core_id) { if (next_thread->GetActiveCore() != core_id) {
next_thread->context_guard.unlock(); next_thread->context_guard.Unlock();
break; break;
} }
} }

View File

@ -2,19 +2,16 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
// This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#pragma once #pragma once
#include <atomic> #include <atomic>
#include "common/common_types.h" #include "common/common_types.h"
#include "common/spin_lock.h"
#include "core/hle/kernel/global_scheduler_context.h" #include "core/hle/kernel/global_scheduler_context.h"
#include "core/hle/kernel/k_priority_queue.h" #include "core/hle/kernel/k_priority_queue.h"
#include "core/hle/kernel/k_scheduler_lock.h" #include "core/hle/kernel/k_scheduler_lock.h"
#include "core/hle/kernel/k_scoped_lock.h" #include "core/hle/kernel/k_scoped_lock.h"
#include "core/hle/kernel/k_spin_lock.h"
namespace Common { namespace Common {
class Fiber; class Fiber;
@ -195,7 +192,7 @@ private:
u64 last_context_switch_time{}; u64 last_context_switch_time{};
const s32 core_id; const s32 core_id;
Common::SpinLock guard{}; KSpinLock guard{};
}; };
class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> { class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {

View File

@ -2,14 +2,11 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
// This file references various implementation details from Atmosphere, an open-source firmware for
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
#pragma once #pragma once
#include "common/assert.h" #include "common/assert.h"
#include "common/spin_lock.h"
#include "core/hardware_properties.h" #include "core/hardware_properties.h"
#include "core/hle/kernel/k_spin_lock.h"
#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
@ -34,7 +31,7 @@ public:
} else { } else {
// Otherwise, we want to disable scheduling and acquire the spinlock. // Otherwise, we want to disable scheduling and acquire the spinlock.
SchedulerType::DisableScheduling(kernel); SchedulerType::DisableScheduling(kernel);
spin_lock.lock(); spin_lock.Lock();
// For debug, ensure that our state is valid. // For debug, ensure that our state is valid.
ASSERT(lock_count == 0); ASSERT(lock_count == 0);
@ -58,7 +55,7 @@ public:
// Note that we no longer hold the lock, and unlock the spinlock. // Note that we no longer hold the lock, and unlock the spinlock.
owner_thread = nullptr; owner_thread = nullptr;
spin_lock.unlock(); spin_lock.Unlock();
// Enable scheduling, and perform a rescheduling operation. // Enable scheduling, and perform a rescheduling operation.
SchedulerType::EnableScheduling(kernel, cores_needing_scheduling); SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
@ -67,7 +64,7 @@ public:
private: private:
KernelCore& kernel; KernelCore& kernel;
Common::SpinLock spin_lock{}; KAlignedSpinLock spin_lock{};
s32 lock_count{}; s32 lock_count{};
KThread* owner_thread{}; KThread* owner_thread{};
}; };

View File

@ -28,6 +28,12 @@ private:
std::atomic_flag lck = ATOMIC_FLAG_INIT; std::atomic_flag lck = ATOMIC_FLAG_INIT;
}; };
// TODO(bunnei): Alias for now, in case we want to implement these accurately in the future.
using KAlignedSpinLock = KSpinLock;
using KNotAlignedSpinLock = KSpinLock;
using KScopedSpinLock = KScopedLock<KSpinLock>; using KScopedSpinLock = KScopedLock<KSpinLock>;
using KScopedAlignedSpinLock = KScopedLock<KAlignedSpinLock>;
using KScopedNotAlignedSpinLock = KScopedLock<KNotAlignedSpinLock>;
} // namespace Kernel } // namespace Kernel

View File

@ -6,14 +6,18 @@
#include "common/common_types.h" #include "common/common_types.h"
#define BOARD_NINTENDO_NX
#ifdef BOARD_NINTENDO_NX
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
namespace Kernel { namespace Kernel {
class KSystemControl { using Kernel::Board::Nintendo::Nx::KSystemControl;
public:
KSystemControl() = default;
static u64 GenerateRandomRange(u64 min, u64 max);
static u64 GenerateRandomU64();
};
} // namespace Kernel } // namespace Kernel
#else
#error "Unknown board for KSystemControl"
#endif

View File

@ -14,10 +14,10 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/intrusive_red_black_tree.h" #include "common/intrusive_red_black_tree.h"
#include "common/spin_lock.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/hle/kernel/k_affinity_mask.h" #include "core/hle/kernel/k_affinity_mask.h"
#include "core/hle/kernel/k_light_lock.h" #include "core/hle/kernel/k_light_lock.h"
#include "core/hle/kernel/k_spin_lock.h"
#include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
#include "core/hle/kernel/svc_common.h" #include "core/hle/kernel/svc_common.h"
@ -732,7 +732,7 @@ private:
s8 priority_inheritance_count{}; s8 priority_inheritance_count{};
bool resource_limit_release_hint{}; bool resource_limit_release_hint{};
StackParameters stack_parameters{}; StackParameters stack_parameters{};
Common::SpinLock context_guard{}; KSpinLock context_guard{};
// For emulation // For emulation
std::shared_ptr<Common::Fiber> host_context{}; std::shared_ptr<Common::Fiber> host_context{};

View File

@ -1,4 +1,4 @@
// Copyright 2014 Citra Emulator Project // Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
@ -12,6 +12,7 @@
#include <utility> #include <utility>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_sizes.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/microprofile.h" #include "common/microprofile.h"
#include "common/thread.h" #include "common/thread.h"
@ -268,45 +269,314 @@ struct KernelCore::Impl {
return schedulers[thread_id]->GetCurrentThread(); return schedulers[thread_id]->GetCurrentThread();
} }
void DeriveInitialMemoryLayout(KMemoryLayout& memory_layout) {
// Insert the root region for the virtual memory tree, from which all other regions will
// derive.
memory_layout.GetVirtualMemoryRegionTree().InsertDirectly(
KernelVirtualAddressSpaceBase,
KernelVirtualAddressSpaceBase + KernelVirtualAddressSpaceSize - 1);
// Insert the root region for the physical memory tree, from which all other regions will
// derive.
memory_layout.GetPhysicalMemoryRegionTree().InsertDirectly(
KernelPhysicalAddressSpaceBase,
KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceSize - 1);
// Save start and end for ease of use.
const VAddr code_start_virt_addr = KernelVirtualAddressCodeBase;
const VAddr code_end_virt_addr = KernelVirtualAddressCodeEnd;
// Setup the containing kernel region.
constexpr size_t KernelRegionSize = Common::Size_1_GB;
constexpr size_t KernelRegionAlign = Common::Size_1_GB;
constexpr VAddr kernel_region_start =
Common::AlignDown(code_start_virt_addr, KernelRegionAlign);
size_t kernel_region_size = KernelRegionSize;
if (!(kernel_region_start + KernelRegionSize - 1 <= KernelVirtualAddressSpaceLast)) {
kernel_region_size = KernelVirtualAddressSpaceEnd - kernel_region_start;
}
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
kernel_region_start, kernel_region_size, KMemoryRegionType_Kernel));
// Setup the code region.
constexpr size_t CodeRegionAlign = PageSize;
constexpr VAddr code_region_start =
Common::AlignDown(code_start_virt_addr, CodeRegionAlign);
constexpr VAddr code_region_end = Common::AlignUp(code_end_virt_addr, CodeRegionAlign);
constexpr size_t code_region_size = code_region_end - code_region_start;
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
code_region_start, code_region_size, KMemoryRegionType_KernelCode));
// Setup board-specific device physical regions.
Init::SetupDevicePhysicalMemoryRegions(memory_layout);
// Determine the amount of space needed for the misc region.
size_t misc_region_needed_size;
{
// Each core has a one page stack for all three stack types (Main, Idle, Exception).
misc_region_needed_size = Core::Hardware::NUM_CPU_CORES * (3 * (PageSize + PageSize));
// Account for each auto-map device.
for (const auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
if (region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
// Check that the region is valid.
ASSERT(region.GetEndAddress() != 0);
// Account for the region.
misc_region_needed_size +=
PageSize + (Common::AlignUp(region.GetLastAddress(), PageSize) -
Common::AlignDown(region.GetAddress(), PageSize));
}
}
// Multiply the needed size by three, to account for the need for guard space.
misc_region_needed_size *= 3;
}
// Decide on the actual size for the misc region.
constexpr size_t MiscRegionAlign = KernelAslrAlignment;
constexpr size_t MiscRegionMinimumSize = Common::Size_32_MB;
const size_t misc_region_size = Common::AlignUp(
std::max(misc_region_needed_size, MiscRegionMinimumSize), MiscRegionAlign);
ASSERT(misc_region_size > 0);
// Setup the misc region.
const VAddr misc_region_start =
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
misc_region_size, MiscRegionAlign, KMemoryRegionType_Kernel);
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
// Setup the stack region.
constexpr size_t StackRegionSize = Common::Size_14_MB;
constexpr size_t StackRegionAlign = KernelAslrAlignment;
const VAddr stack_region_start =
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
StackRegionSize, StackRegionAlign, KMemoryRegionType_Kernel);
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
stack_region_start, StackRegionSize, KMemoryRegionType_KernelStack));
// Determine the size of the resource region.
const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit();
// Determine the size of the slab region.
const size_t slab_region_size = Common::AlignUp(KernelSlabHeapSize, PageSize);
ASSERT(slab_region_size <= resource_region_size);
// Setup the slab region.
const PAddr code_start_phys_addr = KernelPhysicalAddressCodeBase;
const PAddr code_end_phys_addr = code_start_phys_addr + code_region_size;
const PAddr slab_start_phys_addr = code_end_phys_addr;
const PAddr slab_end_phys_addr = slab_start_phys_addr + slab_region_size;
constexpr size_t SlabRegionAlign = KernelAslrAlignment;
const size_t slab_region_needed_size =
Common::AlignUp(code_end_phys_addr + slab_region_size, SlabRegionAlign) -
Common::AlignDown(code_end_phys_addr, SlabRegionAlign);
const VAddr slab_region_start =
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
slab_region_needed_size, SlabRegionAlign, KMemoryRegionType_Kernel) +
(code_end_phys_addr % SlabRegionAlign);
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
slab_region_start, slab_region_size, KMemoryRegionType_KernelSlab));
// Setup the temp region.
constexpr size_t TempRegionSize = Common::Size_128_MB;
constexpr size_t TempRegionAlign = KernelAslrAlignment;
const VAddr temp_region_start =
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
TempRegionSize, TempRegionAlign, KMemoryRegionType_Kernel);
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(temp_region_start, TempRegionSize,
KMemoryRegionType_KernelTemp));
// Automatically map in devices that have auto-map attributes.
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
// We only care about kernel regions.
if (!region.IsDerivedFrom(KMemoryRegionType_Kernel)) {
continue;
}
// Check whether we should map the region.
if (!region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
continue;
}
// If this region has already been mapped, no need to consider it.
if (region.HasTypeAttribute(KMemoryRegionAttr_DidKernelMap)) {
continue;
}
// Check that the region is valid.
ASSERT(region.GetEndAddress() != 0);
// Set the attribute to note we've mapped this region.
region.SetTypeAttribute(KMemoryRegionAttr_DidKernelMap);
// Create a virtual pair region and insert it into the tree.
const PAddr map_phys_addr = Common::AlignDown(region.GetAddress(), PageSize);
const size_t map_size =
Common::AlignUp(region.GetEndAddress(), PageSize) - map_phys_addr;
const VAddr map_virt_addr =
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
map_size, PageSize, KMemoryRegionType_KernelMisc, PageSize);
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
map_virt_addr, map_size, KMemoryRegionType_KernelMiscMappedDevice));
region.SetPairAddress(map_virt_addr + region.GetAddress() - map_phys_addr);
}
Init::SetupDramPhysicalMemoryRegions(memory_layout);
// Insert a physical region for the kernel code region.
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
code_start_phys_addr, code_region_size, KMemoryRegionType_DramKernelCode));
// Insert a physical region for the kernel slab region.
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
slab_start_phys_addr, slab_region_size, KMemoryRegionType_DramKernelSlab));
// Determine size available for kernel page table heaps, requiring > 8 MB.
const PAddr resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
ASSERT(page_table_heap_size / Common::Size_4_MB > 2);
// Insert a physical region for the kernel page table heap region
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
slab_end_phys_addr, page_table_heap_size, KMemoryRegionType_DramKernelPtHeap));
// All DRAM regions that we haven't tagged by this point will be mapped under the linear
// mapping. Tag them.
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
if (region.GetType() == KMemoryRegionType_Dram) {
// Check that the region is valid.
ASSERT(region.GetEndAddress() != 0);
// Set the linear map attribute.
region.SetTypeAttribute(KMemoryRegionAttr_LinearMapped);
}
}
// Get the linear region extents.
const auto linear_extents =
memory_layout.GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionAttr_LinearMapped);
ASSERT(linear_extents.GetEndAddress() != 0);
// Setup the linear mapping region.
constexpr size_t LinearRegionAlign = Common::Size_1_GB;
const PAddr aligned_linear_phys_start =
Common::AlignDown(linear_extents.GetAddress(), LinearRegionAlign);
const size_t linear_region_size =
Common::AlignUp(linear_extents.GetEndAddress(), LinearRegionAlign) -
aligned_linear_phys_start;
const VAddr linear_region_start =
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
linear_region_size, LinearRegionAlign, KMemoryRegionType_None, LinearRegionAlign);
const u64 linear_region_phys_to_virt_diff = linear_region_start - aligned_linear_phys_start;
// Map and create regions for all the linearly-mapped data.
{
PAddr cur_phys_addr = 0;
u64 cur_size = 0;
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
if (!region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
continue;
}
ASSERT(region.GetEndAddress() != 0);
if (cur_size == 0) {
cur_phys_addr = region.GetAddress();
cur_size = region.GetSize();
} else if (cur_phys_addr + cur_size == region.GetAddress()) {
cur_size += region.GetSize();
} else {
cur_phys_addr = region.GetAddress();
cur_size = region.GetSize();
}
const VAddr region_virt_addr =
region.GetAddress() + linear_region_phys_to_virt_diff;
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
region_virt_addr, region.GetSize(),
GetTypeForVirtualLinearMapping(region.GetType())));
region.SetPairAddress(region_virt_addr);
KMemoryRegion* virt_region =
memory_layout.GetVirtualMemoryRegionTree().FindModifiable(region_virt_addr);
ASSERT(virt_region != nullptr);
virt_region->SetPairAddress(region.GetAddress());
}
}
// Insert regions for the initial page table region.
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
resource_end_phys_addr, KernelPageTableHeapSize, KMemoryRegionType_DramKernelInitPt));
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
resource_end_phys_addr + linear_region_phys_to_virt_diff, KernelPageTableHeapSize,
KMemoryRegionType_VirtualDramKernelInitPt));
// All linear-mapped DRAM regions that we haven't tagged by this point will be allocated to
// some pool partition. Tag them.
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
if (region.GetType() == (KMemoryRegionType_Dram | KMemoryRegionAttr_LinearMapped)) {
region.SetType(KMemoryRegionType_DramPoolPartition);
}
}
// Setup all other memory regions needed to arrange the pool partitions.
Init::SetupPoolPartitionMemoryRegions(memory_layout);
// Cache all linear regions in their own trees for faster access, later.
memory_layout.InitializeLinearMemoryRegionTrees(aligned_linear_phys_start,
linear_region_start);
}
void InitializeMemoryLayout() { void InitializeMemoryLayout() {
// Initialize memory layout // Derive the initial memory layout from the emulated board
constexpr KMemoryLayout layout{KMemoryLayout::GetDefaultLayout()}; KMemoryLayout memory_layout;
DeriveInitialMemoryLayout(memory_layout);
const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents();
const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents();
const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents();
// Initialize memory managers
memory_manager = std::make_unique<KMemoryManager>();
memory_manager->InitializeManager(KMemoryManager::Pool::Application,
application_pool.GetAddress(),
application_pool.GetEndAddress());
memory_manager->InitializeManager(KMemoryManager::Pool::Applet, applet_pool.GetAddress(),
applet_pool.GetEndAddress());
memory_manager->InitializeManager(KMemoryManager::Pool::System, system_pool.GetAddress(),
system_pool.GetEndAddress());
// Setup memory regions for emulated processes
// TODO(bunnei): These should not be hardcoded regions initialized within the kernel
constexpr std::size_t hid_size{0x40000}; constexpr std::size_t hid_size{0x40000};
constexpr std::size_t font_size{0x1100000}; constexpr std::size_t font_size{0x1100000};
constexpr std::size_t irs_size{0x8000}; constexpr std::size_t irs_size{0x8000};
constexpr std::size_t time_size{0x1000}; constexpr std::size_t time_size{0x1000};
constexpr PAddr hid_addr{layout.System().StartAddress()};
constexpr PAddr font_pa{layout.System().StartAddress() + hid_size};
constexpr PAddr irs_addr{layout.System().StartAddress() + hid_size + font_size};
constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size};
// Initialize memory manager const PAddr hid_phys_addr{system_pool.GetAddress()};
memory_manager = std::make_unique<KMemoryManager>(); const PAddr font_phys_addr{system_pool.GetAddress() + hid_size};
memory_manager->InitializeManager(KMemoryManager::Pool::Application, const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size};
layout.Application().StartAddress(), const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size};
layout.Application().EndAddress());
memory_manager->InitializeManager(KMemoryManager::Pool::Applet,
layout.Applet().StartAddress(),
layout.Applet().EndAddress());
memory_manager->InitializeManager(KMemoryManager::Pool::System,
layout.System().StartAddress(),
layout.System().EndAddress());
hid_shared_mem = Kernel::KSharedMemory::Create( hid_shared_mem = Kernel::KSharedMemory::Create(
system.Kernel(), system.DeviceMemory(), nullptr, {hid_addr, hid_size / PageSize}, system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize},
KMemoryPermission::None, KMemoryPermission::Read, hid_addr, hid_size, KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size,
"HID:SharedMemory"); "HID:SharedMemory");
font_shared_mem = Kernel::KSharedMemory::Create( font_shared_mem = Kernel::KSharedMemory::Create(
system.Kernel(), system.DeviceMemory(), nullptr, {font_pa, font_size / PageSize}, system.Kernel(), system.DeviceMemory(), nullptr, {font_phys_addr, font_size / PageSize},
KMemoryPermission::None, KMemoryPermission::Read, font_pa, font_size, KMemoryPermission::None, KMemoryPermission::Read, font_phys_addr, font_size,
"Font:SharedMemory"); "Font:SharedMemory");
irs_shared_mem = Kernel::KSharedMemory::Create( irs_shared_mem = Kernel::KSharedMemory::Create(
system.Kernel(), system.DeviceMemory(), nullptr, {irs_addr, irs_size / PageSize}, system.Kernel(), system.DeviceMemory(), nullptr, {irs_phys_addr, irs_size / PageSize},
KMemoryPermission::None, KMemoryPermission::Read, irs_addr, irs_size, KMemoryPermission::None, KMemoryPermission::Read, irs_phys_addr, irs_size,
"IRS:SharedMemory"); "IRS:SharedMemory");
time_shared_mem = Kernel::KSharedMemory::Create( time_shared_mem = Kernel::KSharedMemory::Create(
system.Kernel(), system.DeviceMemory(), nullptr, {time_addr, time_size / PageSize}, system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize},
KMemoryPermission::None, KMemoryPermission::Read, time_addr, time_size, KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size,
"Time:SharedMemory"); "Time:SharedMemory");
// Allocate slab heaps // Allocate slab heaps

View File

@ -1,4 +1,4 @@
// Copyright 2014 Citra Emulator Project / PPSSPP Project // Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.

View File

@ -959,7 +959,7 @@ private:
auto storage = applet->GetBroker().PopNormalDataToGame(); auto storage = applet->GetBroker().PopNormalDataToGame();
if (storage == nullptr) { if (storage == nullptr) {
LOG_ERROR(Service_AM, LOG_DEBUG(Service_AM,
"storage is a nullptr. There is no data in the current normal channel"); "storage is a nullptr. There is no data in the current normal channel");
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_DATA_IN_CHANNEL); rb.Push(ERR_NO_DATA_IN_CHANNEL);
@ -990,7 +990,7 @@ private:
auto storage = applet->GetBroker().PopInteractiveDataToGame(); auto storage = applet->GetBroker().PopInteractiveDataToGame();
if (storage == nullptr) { if (storage == nullptr) {
LOG_ERROR(Service_AM, LOG_DEBUG(Service_AM,
"storage is a nullptr. There is no data in the current interactive channel"); "storage is a nullptr. There is no data in the current interactive channel");
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_DATA_IN_CHANNEL); rb.Push(ERR_NO_DATA_IN_CHANNEL);
@ -1113,7 +1113,7 @@ ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
{2, nullptr, "AreAnyLibraryAppletsLeft"}, {2, nullptr, "AreAnyLibraryAppletsLeft"},
{10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"}, {10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
{11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"}, {11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
{12, nullptr, "CreateHandleStorage"}, {12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
}; };
RegisterHandlers(functions); RegisterHandlers(functions);
} }
@ -1122,14 +1122,15 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default;
void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) { void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto applet_id = rp.PopRaw<Applets::AppletId>(); const auto applet_id = rp.PopRaw<Applets::AppletId>();
const auto applet_mode = rp.PopRaw<u32>(); const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>();
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id, LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
applet_mode); applet_mode);
const auto& applet_manager{system.GetAppletManager()}; const auto& applet_manager{system.GetAppletManager()};
const auto applet = applet_manager.GetApplet(applet_id); const auto applet = applet_manager.GetApplet(applet_id, applet_mode);
if (applet == nullptr) { if (applet == nullptr) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id); LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
@ -1147,9 +1148,18 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const u64 size{rp.Pop<u64>()};
const s64 size{rp.Pop<s64>()};
LOG_DEBUG(Service_AM, "called, size={}", size); LOG_DEBUG(Service_AM, "called, size={}", size);
if (size <= 0) {
LOG_ERROR(Service_AM, "size is less than or equal to 0");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_UNKNOWN);
return;
}
std::vector<u8> buffer(size); std::vector<u8> buffer(size);
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
@ -1158,18 +1168,65 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
} }
void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
rp.SetCurrentOffset(3); struct Parameters {
const auto handle{rp.Pop<Kernel::Handle>()}; u8 permissions;
s64 size;
};
const auto parameters{rp.PopRaw<Parameters>()};
const auto handle{ctx.GetCopyHandle(0)};
LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions,
parameters.size, handle);
if (parameters.size <= 0) {
LOG_ERROR(Service_AM, "size is less than or equal to 0");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_UNKNOWN);
return;
}
auto transfer_mem = auto transfer_mem =
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle); system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
if (transfer_mem == nullptr) { if (transfer_mem == nullptr) {
LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_UNKNOWN);
return;
}
const u8* const mem_begin = transfer_mem->GetPointer();
const u8* const mem_end = mem_begin + transfer_mem->GetSize();
std::vector<u8> memory{mem_begin, mem_end};
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorage>(system, std::move(memory));
}
void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const s64 size{rp.Pop<s64>()};
const auto handle{ctx.GetCopyHandle(0)};
LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
if (size <= 0) {
LOG_ERROR(Service_AM, "size is less than or equal to 0");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_UNKNOWN);
return;
}
auto transfer_mem =
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
if (transfer_mem == nullptr) {
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_UNKNOWN); rb.Push(RESULT_UNKNOWN);
return; return;

View File

@ -254,6 +254,7 @@ private:
void CreateLibraryApplet(Kernel::HLERequestContext& ctx); void CreateLibraryApplet(Kernel::HLERequestContext& ctx);
void CreateStorage(Kernel::HLERequestContext& ctx); void CreateStorage(Kernel::HLERequestContext& ctx);
void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx); void CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx);
void CreateHandleStorage(Kernel::HLERequestContext& ctx);
}; };
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> { class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {

View File

@ -241,31 +241,31 @@ void AppletManager::ClearAll() {
frontend = {}; frontend = {};
} }
std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id) const { std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode mode) const {
switch (id) { switch (id) {
case AppletId::Auth: case AppletId::Auth:
return std::make_shared<Auth>(system, *frontend.parental_controls); return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
case AppletId::Controller: case AppletId::Controller:
return std::make_shared<Controller>(system, *frontend.controller); return std::make_shared<Controller>(system, mode, *frontend.controller);
case AppletId::Error: case AppletId::Error:
return std::make_shared<Error>(system, *frontend.error); return std::make_shared<Error>(system, mode, *frontend.error);
case AppletId::ProfileSelect: case AppletId::ProfileSelect:
return std::make_shared<ProfileSelect>(system, *frontend.profile_select); return std::make_shared<ProfileSelect>(system, mode, *frontend.profile_select);
case AppletId::SoftwareKeyboard: case AppletId::SoftwareKeyboard:
return std::make_shared<SoftwareKeyboard>(system, *frontend.software_keyboard); return std::make_shared<SoftwareKeyboard>(system, mode, *frontend.software_keyboard);
case AppletId::Web: case AppletId::Web:
case AppletId::Shop: case AppletId::Shop:
case AppletId::OfflineWeb: case AppletId::OfflineWeb:
case AppletId::LoginShare: case AppletId::LoginShare:
case AppletId::WebAuth: case AppletId::WebAuth:
return std::make_shared<WebBrowser>(system, *frontend.web_browser); return std::make_shared<WebBrowser>(system, mode, *frontend.web_browser);
case AppletId::PhotoViewer: case AppletId::PhotoViewer:
return std::make_shared<PhotoViewer>(system, *frontend.photo_viewer); return std::make_shared<PhotoViewer>(system, mode, *frontend.photo_viewer);
default: default:
UNIMPLEMENTED_MSG( UNIMPLEMENTED_MSG(
"No backend implementation exists for applet_id={:02X}! Falling back to stub applet.", "No backend implementation exists for applet_id={:02X}! Falling back to stub applet.",
static_cast<u8>(id)); static_cast<u8>(id));
return std::make_shared<StubApplet>(system, id); return std::make_shared<StubApplet>(system, id, mode);
} }
} }

View File

@ -62,6 +62,14 @@ enum class AppletId : u32 {
MyPage = 0x1A, MyPage = 0x1A,
}; };
enum class LibraryAppletMode : u32 {
AllForeground = 0,
Background = 1,
NoUI = 2,
BackgroundIndirectDisplay = 3,
AllForegroundInitiallyHidden = 4,
};
class AppletDataBroker final { class AppletDataBroker final {
public: public:
explicit AppletDataBroker(Kernel::KernelCore& kernel_); explicit AppletDataBroker(Kernel::KernelCore& kernel_);
@ -200,7 +208,7 @@ public:
void SetDefaultAppletsIfMissing(); void SetDefaultAppletsIfMissing();
void ClearAll(); void ClearAll();
std::shared_ptr<Applet> GetApplet(AppletId id) const; std::shared_ptr<Applet> GetApplet(AppletId id, LibraryAppletMode mode) const;
private: private:
AppletFrontendSet frontend; AppletFrontendSet frontend;

View File

@ -45,8 +45,9 @@ static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
}; };
} }
Controller::Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_) Controller::Controller(Core::System& system_, LibraryAppletMode applet_mode_,
: Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} const Core::Frontend::ControllerApplet& frontend_)
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
Controller::~Controller() = default; Controller::~Controller() = default;

View File

@ -106,7 +106,8 @@ static_assert(sizeof(ControllerSupportResultInfo) == 0xC,
class Controller final : public Applet { class Controller final : public Applet {
public: public:
explicit Controller(Core::System& system_, const Core::Frontend::ControllerApplet& frontend_); explicit Controller(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ControllerApplet& frontend_);
~Controller() override; ~Controller() override;
void Initialize() override; void Initialize() override;
@ -119,6 +120,7 @@ public:
void ConfigurationComplete(); void ConfigurationComplete();
private: private:
LibraryAppletMode applet_mode;
const Core::Frontend::ControllerApplet& frontend; const Core::Frontend::ControllerApplet& frontend;
Core::System& system; Core::System& system;

View File

@ -86,8 +86,9 @@ ResultCode Decode64BitError(u64 error) {
} // Anonymous namespace } // Anonymous namespace
Error::Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_) Error::Error(Core::System& system_, LibraryAppletMode applet_mode_,
: Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} const Core::Frontend::ErrorApplet& frontend_)
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
Error::~Error() = default; Error::~Error() = default;

View File

@ -25,7 +25,8 @@ enum class ErrorAppletMode : u8 {
class Error final : public Applet { class Error final : public Applet {
public: public:
explicit Error(Core::System& system_, const Core::Frontend::ErrorApplet& frontend_); explicit Error(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ErrorApplet& frontend_);
~Error() override; ~Error() override;
void Initialize() override; void Initialize() override;
@ -40,6 +41,7 @@ public:
private: private:
union ErrorArguments; union ErrorArguments;
LibraryAppletMode applet_mode;
const Core::Frontend::ErrorApplet& frontend; const Core::Frontend::ErrorApplet& frontend;
ResultCode error_code = RESULT_SUCCESS; ResultCode error_code = RESULT_SUCCESS;
ErrorAppletMode mode = ErrorAppletMode::ShowError; ErrorAppletMode mode = ErrorAppletMode::ShowError;

View File

@ -37,8 +37,9 @@ static void LogCurrentStorage(AppletDataBroker& broker, std::string_view prefix)
} }
} }
Auth::Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_) Auth::Auth(Core::System& system_, LibraryAppletMode applet_mode_,
: Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} Core::Frontend::ParentalControlsApplet& frontend_)
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
Auth::~Auth() = default; Auth::~Auth() = default;
@ -152,8 +153,9 @@ void Auth::AuthFinished(bool is_successful) {
broker.SignalStateChanged(); broker.SignalStateChanged();
} }
PhotoViewer::PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_) PhotoViewer::PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
: Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} const Core::Frontend::PhotoViewerApplet& frontend_)
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
PhotoViewer::~PhotoViewer() = default; PhotoViewer::~PhotoViewer() = default;
@ -202,8 +204,8 @@ void PhotoViewer::ViewFinished() {
broker.SignalStateChanged(); broker.SignalStateChanged();
} }
StubApplet::StubApplet(Core::System& system_, AppletId id_) StubApplet::StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_)
: Applet{system_.Kernel()}, id{id_}, system{system_} {} : Applet{system_.Kernel()}, id{id_}, applet_mode{applet_mode_}, system{system_} {}
StubApplet::~StubApplet() = default; StubApplet::~StubApplet() = default;

View File

@ -20,7 +20,8 @@ enum class AuthAppletType : u32 {
class Auth final : public Applet { class Auth final : public Applet {
public: public:
explicit Auth(Core::System& system_, Core::Frontend::ParentalControlsApplet& frontend_); explicit Auth(Core::System& system_, LibraryAppletMode applet_mode_,
Core::Frontend::ParentalControlsApplet& frontend_);
~Auth() override; ~Auth() override;
void Initialize() override; void Initialize() override;
@ -32,6 +33,7 @@ public:
void AuthFinished(bool is_successful = true); void AuthFinished(bool is_successful = true);
private: private:
LibraryAppletMode applet_mode;
Core::Frontend::ParentalControlsApplet& frontend; Core::Frontend::ParentalControlsApplet& frontend;
Core::System& system; Core::System& system;
bool complete = false; bool complete = false;
@ -50,7 +52,8 @@ enum class PhotoViewerAppletMode : u8 {
class PhotoViewer final : public Applet { class PhotoViewer final : public Applet {
public: public:
explicit PhotoViewer(Core::System& system_, const Core::Frontend::PhotoViewerApplet& frontend_); explicit PhotoViewer(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::PhotoViewerApplet& frontend_);
~PhotoViewer() override; ~PhotoViewer() override;
void Initialize() override; void Initialize() override;
@ -62,6 +65,7 @@ public:
void ViewFinished(); void ViewFinished();
private: private:
LibraryAppletMode applet_mode;
const Core::Frontend::PhotoViewerApplet& frontend; const Core::Frontend::PhotoViewerApplet& frontend;
bool complete = false; bool complete = false;
PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp; PhotoViewerAppletMode mode = PhotoViewerAppletMode::CurrentApp;
@ -70,7 +74,7 @@ private:
class StubApplet final : public Applet { class StubApplet final : public Applet {
public: public:
explicit StubApplet(Core::System& system_, AppletId id_); explicit StubApplet(Core::System& system_, AppletId id_, LibraryAppletMode applet_mode_);
~StubApplet() override; ~StubApplet() override;
void Initialize() override; void Initialize() override;
@ -82,6 +86,7 @@ public:
private: private:
AppletId id; AppletId id;
LibraryAppletMode applet_mode;
Core::System& system; Core::System& system;
}; };

View File

@ -15,9 +15,9 @@ namespace Service::AM::Applets {
constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1}; constexpr ResultCode ERR_USER_CANCELLED_SELECTION{ErrorModule::Account, 1};
ProfileSelect::ProfileSelect(Core::System& system_, ProfileSelect::ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ProfileSelectApplet& frontend_) const Core::Frontend::ProfileSelectApplet& frontend_)
: Applet{system_.Kernel()}, frontend{frontend_}, system{system_} {} : Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend{frontend_}, system{system_} {}
ProfileSelect::~ProfileSelect() = default; ProfileSelect::~ProfileSelect() = default;

View File

@ -33,7 +33,7 @@ static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has inco
class ProfileSelect final : public Applet { class ProfileSelect final : public Applet {
public: public:
explicit ProfileSelect(Core::System& system_, explicit ProfileSelect(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::ProfileSelectApplet& frontend_); const Core::Frontend::ProfileSelectApplet& frontend_);
~ProfileSelect() override; ~ProfileSelect() override;
@ -47,6 +47,7 @@ public:
void SelectionComplete(std::optional<Common::UUID> uuid); void SelectionComplete(std::optional<Common::UUID> uuid);
private: private:
LibraryAppletMode applet_mode;
const Core::Frontend::ProfileSelectApplet& frontend; const Core::Frontend::ProfileSelectApplet& frontend;
UserSelectionConfig config; UserSelectionConfig config;

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +1,14 @@
// Copyright 2018 yuzu emulator team // Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <array>
#include <string>
#include <vector>
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/swap.h" #include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applets.h" #include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/am/applets/software_keyboard_types.h"
union ResultCode;
namespace Core { namespace Core {
class System; class System;
@ -22,45 +16,10 @@ class System;
namespace Service::AM::Applets { namespace Service::AM::Applets {
enum class KeysetDisable : u32 {
Space = 0x02,
Address = 0x04,
Percent = 0x08,
Slashes = 0x10,
Numbers = 0x40,
DownloadCode = 0x80,
};
struct KeyboardConfig {
INSERT_PADDING_BYTES(4);
std::array<char16_t, 9> submit_text;
u16_le left_symbol_key;
u16_le right_symbol_key;
INSERT_PADDING_BYTES(1);
KeysetDisable keyset_disable_bitmask;
u32_le initial_cursor_position;
std::array<char16_t, 65> header_text;
std::array<char16_t, 129> sub_text;
std::array<char16_t, 257> guide_text;
u32_le length_limit;
INSERT_PADDING_BYTES(4);
u32_le is_password;
INSERT_PADDING_BYTES(5);
bool utf_8;
bool draw_background;
u32_le initial_string_offset;
u32_le initial_string_size;
u32_le user_dictionary_offset;
u32_le user_dictionary_size;
bool text_check;
u64_le text_check_callback;
};
static_assert(sizeof(KeyboardConfig) == 0x3E0, "KeyboardConfig has incorrect size.");
class SoftwareKeyboard final : public Applet { class SoftwareKeyboard final : public Applet {
public: public:
explicit SoftwareKeyboard(Core::System& system_, explicit SoftwareKeyboard(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::SoftwareKeyboardApplet& frontend_); Core::Frontend::SoftwareKeyboardApplet& frontend_);
~SoftwareKeyboard() override; ~SoftwareKeyboard() override;
void Initialize() override; void Initialize() override;
@ -70,17 +29,139 @@ public:
void ExecuteInteractive() override; void ExecuteInteractive() override;
void Execute() override; void Execute() override;
void WriteText(std::optional<std::u16string> text); /**
* Submits the input text to the application.
* If text checking is enabled, the application will verify the input text.
* If use_utf8 is enabled, the input text will be converted to UTF-8 prior to being submitted.
* This should only be used by the normal software keyboard.
*
* @param result SwkbdResult enum
* @param submitted_text UTF-16 encoded string
*/
void SubmitTextNormal(SwkbdResult result, std::u16string submitted_text);
/**
* Submits the input text to the application.
* If utf8_mode is enabled, the input text will be converted to UTF-8 prior to being submitted.
* This should only be used by the inline software keyboard.
*
* @param reply_type SwkbdReplyType enum
* @param submitted_text UTF-16 encoded string
* @param cursor_position The current position of the text cursor
*/
void SubmitTextInline(SwkbdReplyType reply_type, std::u16string submitted_text,
s32 cursor_position);
private: private:
const Core::Frontend::SoftwareKeyboardApplet& frontend; /// Initializes the normal software keyboard.
void InitializeForeground();
KeyboardConfig config; /// Initializes the inline software keyboard.
std::u16string initial_text; void InitializeBackground(LibraryAppletMode applet_mode);
bool complete = false;
bool is_inline = false; /// Processes the text check sent by the application.
std::vector<u8> final_data; void ProcessTextCheck();
/// Processes the inline software keyboard request command sent by the application.
void ProcessInlineKeyboardRequest();
/// Submits the input text and exits the applet.
void SubmitNormalOutputAndExit(SwkbdResult result, std::u16string submitted_text);
/// Submits the input text for text checking.
void SubmitForTextCheck(std::u16string submitted_text);
/// Sends a reply to the application after processing a request command.
void SendReply(SwkbdReplyType reply_type);
/// Changes the inline keyboard state.
void ChangeState(SwkbdState state);
/**
* Signals the frontend to initialize the software keyboard with common parameters.
* This initializes either the normal software keyboard or the inline software keyboard
* depending on the state of is_background.
* Note that this does not cause the keyboard to appear.
* Use the respective Show*Keyboard() functions to cause the respective keyboards to appear.
*/
void InitializeFrontendKeyboard();
/// Signals the frontend to show the normal software keyboard.
void ShowNormalKeyboard();
/// Signals the frontend to show the text check dialog.
void ShowTextCheckDialog(SwkbdTextCheckResult text_check_result,
std::u16string text_check_message);
/// Signals the frontend to show the inline software keyboard.
void ShowInlineKeyboard();
/// Signals the frontend to hide the inline software keyboard.
void HideInlineKeyboard();
/// Signals the frontend that the current inline keyboard text has changed.
void InlineTextChanged();
/// Signals both the frontend and application that the software keyboard is exiting.
void ExitKeyboard();
// Inline Software Keyboard Requests
void RequestFinalize(const std::vector<u8>& request_data);
void RequestSetUserWordInfo(const std::vector<u8>& request_data);
void RequestSetCustomizeDic(const std::vector<u8>& request_data);
void RequestCalc(const std::vector<u8>& request_data);
void RequestSetCustomizedDictionaries(const std::vector<u8>& request_data);
void RequestUnsetCustomizedDictionaries(const std::vector<u8>& request_data);
void RequestSetChangedStringV2Flag(const std::vector<u8>& request_data);
void RequestSetMovedCursorV2Flag(const std::vector<u8>& request_data);
// Inline Software Keyboard Replies
void ReplyFinishedInitialize();
void ReplyDefault();
void ReplyChangedString();
void ReplyMovedCursor();
void ReplyMovedTab();
void ReplyDecidedEnter();
void ReplyDecidedCancel();
void ReplyChangedStringUtf8();
void ReplyMovedCursorUtf8();
void ReplyDecidedEnterUtf8();
void ReplyUnsetCustomizeDic();
void ReplyReleasedUserWordInfo();
void ReplyUnsetCustomizedDictionaries();
void ReplyChangedStringV2();
void ReplyMovedCursorV2();
void ReplyChangedStringUtf8V2();
void ReplyMovedCursorUtf8V2();
LibraryAppletMode applet_mode;
Core::Frontend::SoftwareKeyboardApplet& frontend;
Core::System& system; Core::System& system;
SwkbdAppletVersion swkbd_applet_version;
SwkbdConfigCommon swkbd_config_common;
SwkbdConfigOld swkbd_config_old;
SwkbdConfigOld2 swkbd_config_old2;
SwkbdConfigNew swkbd_config_new;
std::u16string initial_text;
SwkbdState swkbd_state{SwkbdState::NotInitialized};
SwkbdInitializeArg swkbd_initialize_arg;
SwkbdCalcArg swkbd_calc_arg;
bool use_changed_string_v2{false};
bool use_moved_cursor_v2{false};
bool inline_use_utf8{false};
s32 current_cursor_position{};
std::u16string current_text;
bool is_background{false};
bool complete{false};
ResultCode status{RESULT_SUCCESS};
}; };
} // namespace Service::AM::Applets } // namespace Service::AM::Applets

View File

@ -13,11 +13,11 @@
namespace Service::AM::Applets { namespace Service::AM::Applets {
static constexpr std::size_t MAX_OK_TEXT_LENGTH = 8; constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
static constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64; constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
static constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128; constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128;
static constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256; constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256;
static constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4; constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4;
enum class SwkbdAppletVersion : u32_le { enum class SwkbdAppletVersion : u32_le {
Version5 = 0x5, // 1.0.0 Version5 = 0x5, // 1.0.0

View File

@ -208,8 +208,9 @@ void ExtractSharedFonts(Core::System& system) {
} // namespace } // namespace
WebBrowser::WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_) WebBrowser::WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
: Applet{system_.Kernel()}, frontend(frontend_), system{system_} {} const Core::Frontend::WebBrowserApplet& frontend_)
: Applet{system_.Kernel()}, applet_mode{applet_mode_}, frontend(frontend_), system{system_} {}
WebBrowser::~WebBrowser() = default; WebBrowser::~WebBrowser() = default;

View File

@ -25,7 +25,8 @@ namespace Service::AM::Applets {
class WebBrowser final : public Applet { class WebBrowser final : public Applet {
public: public:
WebBrowser(Core::System& system_, const Core::Frontend::WebBrowserApplet& frontend_); WebBrowser(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::WebBrowserApplet& frontend_);
~WebBrowser() override; ~WebBrowser() override;
@ -63,6 +64,7 @@ private:
void ExecuteWifi(); void ExecuteWifi();
void ExecuteLobby(); void ExecuteLobby();
LibraryAppletMode applet_mode;
const Core::Frontend::WebBrowserApplet& frontend; const Core::Frontend::WebBrowserApplet& frontend;
bool complete{false}; bool complete{false};

View File

@ -38,7 +38,7 @@ public:
{10600, nullptr, "DeclareOpenOnlinePlaySession"}, {10600, nullptr, "DeclareOpenOnlinePlaySession"},
{10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"}, {10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
{10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"}, {10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
{10700, nullptr, "GetPlayHistoryRegistrationKey"}, {10700, &IFriendService::GetPlayHistoryRegistrationKey, "GetPlayHistoryRegistrationKey"},
{10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"}, {10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
{10702, nullptr, "AddPlayHistory"}, {10702, nullptr, "AddPlayHistory"},
{11000, nullptr, "GetProfileImageUrl"}, {11000, nullptr, "GetProfileImageUrl"},
@ -153,6 +153,18 @@ private:
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
void GetPlayHistoryRegistrationKey(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto local_play = rp.Pop<bool>();
const auto uuid = rp.PopRaw<Common::UUID>();
LOG_WARNING(Service_Friend, "(STUBBED) called local_play={} uuid={}", local_play,
uuid.Format());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void GetFriendList(Kernel::HLERequestContext& ctx) { void GetFriendList(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto friend_offset = rp.Pop<u32>(); const auto friend_offset = rp.Pop<u32>();

View File

@ -36,6 +36,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>&
LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
Tegra::ChCommandHeaderList cmdlist{{0xDEADB33F}}; Tegra::ChCommandHeaderList cmdlist{{0xDEADB33F}};
system.GPU().PushCommandBuffer(cmdlist); system.GPU().PushCommandBuffer(cmdlist);
system.GPU().MemoryManager().InvalidateQueuedCaches();
} }
return UnmapBuffer(input, output); return UnmapBuffer(input, output);
} }

View File

@ -193,7 +193,13 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vec
return NvResult::InvalidState; return NvResult::InvalidState;
} }
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) { if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
gpu.MemoryManager().Unmap(object->dma_map_addr, *size); if (vic_device) {
// UnmapVicFrame defers texture_cache invalidation of the frame address until
// the stream is over
gpu.MemoryManager().UnmapVicFrame(object->dma_map_addr, *size);
} else {
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
}
} else { } else {
// This occurs quite frequently, however does not seem to impact functionality // This occurs quite frequently, however does not seem to impact functionality
LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr, LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,

View File

@ -160,6 +160,7 @@ protected:
s32_le nvmap_fd{}; s32_le nvmap_fd{};
u32_le submit_timeout{}; u32_le submit_timeout{};
bool vic_device{};
std::shared_ptr<nvmap> nvmap_dev; std::shared_ptr<nvmap> nvmap_dev;
SyncpointManager& syncpoint_manager; SyncpointManager& syncpoint_manager;
std::array<u32, MaxSyncPoints> device_syncpoints{}; std::array<u32, MaxSyncPoints> device_syncpoints{};

View File

@ -12,8 +12,9 @@
namespace Service::Nvidia::Devices { namespace Service::Nvidia::Devices {
nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
SyncpointManager& syncpoint_manager) SyncpointManager& syncpoint_manager)
: nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {} : nvhost_nvdec_common(system, std::move(nvmap_dev), syncpoint_manager) {
vic_device = true;
}
nvhost_vic::~nvhost_vic() = default; nvhost_vic::~nvhost_vic() = default;
NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input, NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,

View File

@ -3,16 +3,30 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/process.h"
#include "core/hle/service/pctl/module.h" #include "core/hle/service/pctl/module.h"
#include "core/hle/service/pctl/pctl.h" #include "core/hle/service/pctl/pctl.h"
namespace Service::PCTL { namespace Service::PCTL {
namespace Error {
constexpr ResultCode ResultNoFreeCommunication{ErrorModule::PCTL, 101};
constexpr ResultCode ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
constexpr ResultCode ResultNoCapability{ErrorModule::PCTL, 131};
constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
} // namespace Error
class IParentalControlService final : public ServiceFramework<IParentalControlService> { class IParentalControlService final : public ServiceFramework<IParentalControlService> {
public: public:
explicit IParentalControlService(Core::System& system_) explicit IParentalControlService(Core::System& system_, Capability capability)
: ServiceFramework{system_, "IParentalControlService"} { : ServiceFramework{system_, "IParentalControlService"}, system(system_),
capability(capability) {
// clang-format off // clang-format off
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{1, &IParentalControlService::Initialize, "Initialize"}, {1, &IParentalControlService::Initialize, "Initialize"},
@ -28,13 +42,13 @@ public:
{1010, nullptr, "IsRestrictedSystemSettingsEntered"}, {1010, nullptr, "IsRestrictedSystemSettingsEntered"},
{1011, nullptr, "RevertRestrictedSystemSettingsEntered"}, {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
{1012, nullptr, "GetRestrictedFeatures"}, {1012, nullptr, "GetRestrictedFeatures"},
{1013, nullptr, "ConfirmStereoVisionPermission"}, {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
{1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
{1015, nullptr, "ConfirmPlayableApplicationVideo"}, {1015, nullptr, "ConfirmPlayableApplicationVideo"},
{1016, nullptr, "ConfirmShowNewsPermission"}, {1016, nullptr, "ConfirmShowNewsPermission"},
{1017, nullptr, "EndFreeCommunication"}, {1017, nullptr, "EndFreeCommunication"},
{1018, nullptr, "IsFreeCommunicationAvailable"}, {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
{1031, nullptr, "IsRestrictionEnabled"}, {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
{1032, nullptr, "GetSafetyLevel"}, {1032, nullptr, "GetSafetyLevel"},
{1033, nullptr, "SetSafetyLevel"}, {1033, nullptr, "SetSafetyLevel"},
{1034, nullptr, "GetSafetyLevelSettings"}, {1034, nullptr, "GetSafetyLevelSettings"},
@ -119,62 +133,235 @@ public:
} }
private: private:
void Initialize(Kernel::HLERequestContext& ctx) { bool CheckFreeCommunicationPermissionImpl() const {
LOG_WARNING(Service_PCTL, "(STUBBED) called"); if (states.temporary_unlocked) {
return true;
}
if ((states.application_info.parental_control_flag & 1) == 0) {
return true;
}
if (pin_code[0] == '\0') {
return true;
}
if (!settings.is_free_communication_default_on) {
return true;
}
// TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
// but as we don't have multiproceses support yet, we can just assume our application is
// valid for the time being
return true;
}
bool ConfirmStereoVisionPermissionImpl() const {
if (states.temporary_unlocked) {
return true;
}
if (pin_code[0] == '\0') {
return true;
}
if (!settings.is_stero_vision_restricted) {
return false;
}
return true;
}
void SetStereoVisionRestrictionImpl(bool is_restricted) {
if (settings.disabled) {
return;
}
if (pin_code[0] == '\0') {
return;
}
settings.is_stero_vision_restricted = is_restricted;
}
void Initialize(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2};
if (False(capability & (Capability::Application | Capability::System))) {
LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
return;
}
// TODO(ogniK): Recovery flag initialization for pctl:r
const auto tid = system.CurrentProcess()->GetTitleID();
if (tid != 0) {
const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
if (control.first) {
states.tid_from_event = 0;
states.launch_time_valid = false;
states.is_suspended = false;
states.free_communication = false;
states.stereo_vision = false;
states.application_info = ApplicationInfo{
.tid = tid,
.age_rating = control.first->GetRatingAge(),
.parental_control_flag = control.first->GetParentalControlFlag(),
.capability = capability,
};
if (False(capability & (Capability::System | Capability::Recovery))) {
// TODO(ogniK): Signal application launch event
}
}
}
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called"); LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2};
if (!CheckFreeCommunicationPermissionImpl()) {
rb.Push(Error::ResultNoFreeCommunication);
} else {
rb.Push(RESULT_SUCCESS);
}
states.free_communication = true;
}
void ConfirmStereoVisionPermission(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
states.stereo_vision = true;
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) { void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called"); LOG_WARNING(Service_PCTL, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
if (!CheckFreeCommunicationPermissionImpl()) {
rb.Push(Error::ResultNoFreeCommunication);
} else {
rb.Push(RESULT_SUCCESS);
}
}
void IsRestrictionEnabled(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 3};
if (False(capability & (Capability::Status | Capability::Recovery))) {
LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
rb.Push(Error::ResultNoCapability);
rb.Push(false);
return;
}
rb.Push(pin_code[0] != '\0');
}
void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 2};
if (False(capability & Capability::StereoVision)) {
LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
rb.Push(Error::ResultNoCapability);
return;
}
if (pin_code[0] == '\0') {
rb.Push(Error::ResultNoRestrictionEnabled);
return;
}
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) { void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called"); LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS); if (!ConfirmStereoVisionPermissionImpl()) {
rb.Push(true); rb.Push(Error::ResultStereoVisionRestricted);
rb.Push(false);
} else {
rb.Push(RESULT_SUCCESS);
rb.Push(true);
}
} }
void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto can_use = rp.Pop<bool>(); const auto can_use = rp.Pop<bool>();
LOG_WARNING(Service_PCTL, "(STUBBED) called, can_use={}", can_use); LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
can_use_stereo_vision = can_use;
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
if (False(capability & Capability::StereoVision)) {
LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
rb.Push(Error::ResultNoCapability);
return;
}
SetStereoVisionRestrictionImpl(can_use);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called"); LOG_DEBUG(Service_PCTL, "called");
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
if (False(capability & Capability::StereoVision)) {
LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
rb.Push(Error::ResultNoCapability);
rb.Push(false);
return;
}
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push(can_use_stereo_vision); rb.Push(settings.is_stero_vision_restricted);
} }
void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) { void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_PCTL, "(STUBBED) called"); LOG_DEBUG(Service_PCTL, "called");
states.stereo_vision = false;
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
struct ApplicationInfo {
u64 tid{};
std::array<u8, 32> age_rating{};
u32 parental_control_flag{};
Capability capability{};
};
struct States {
u64 current_tid{};
ApplicationInfo application_info{};
u64 tid_from_event{};
bool launch_time_valid{};
bool is_suspended{};
bool temporary_unlocked{};
bool free_communication{};
bool stereo_vision{};
};
struct ParentalControlSettings {
bool is_stero_vision_restricted{};
bool is_free_communication_default_on{};
bool disabled{};
};
States states{};
ParentalControlSettings settings{};
std::array<char, 8> pin_code{};
bool can_use_stereo_vision = true; bool can_use_stereo_vision = true;
Core::System& system;
Capability capability{};
}; };
void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
@ -182,7 +369,9 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IParentalControlService>(system); // TODO(ogniK): Get TID from process
rb.PushIpcInterface<IParentalControlService>(system, capability);
} }
void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
@ -190,21 +379,28 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
IPC::ResponseBuilder rb{ctx, 2, 0, 1}; IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IParentalControlService>(system); rb.PushIpcInterface<IParentalControlService>(system, capability);
} }
Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
const char* name) const char* name, Capability capability)
: ServiceFramework{system_, name}, module{std::move(module_)} {} : ServiceFramework{system_, name}, module{std::move(module_)}, capability(capability) {}
Module::Interface::~Interface() = default; Module::Interface::~Interface() = default;
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>(); auto module = std::make_shared<Module>();
std::make_shared<PCTL>(system, module, "pctl")->InstallAsService(service_manager); std::make_shared<PCTL>(system, module, "pctl",
std::make_shared<PCTL>(system, module, "pctl:a")->InstallAsService(service_manager); Capability::Application | Capability::SnsPost | Capability::Status |
std::make_shared<PCTL>(system, module, "pctl:r")->InstallAsService(service_manager); Capability::StereoVision)
std::make_shared<PCTL>(system, module, "pctl:s")->InstallAsService(service_manager); ->InstallAsService(service_manager);
// TODO(ogniK): Implement remaining capabilities
std::make_shared<PCTL>(system, module, "pctl:a", Capability::None)
->InstallAsService(service_manager);
std::make_shared<PCTL>(system, module, "pctl:r", Capability::None)
->InstallAsService(service_manager);
std::make_shared<PCTL>(system, module, "pctl:s", Capability::None)
->InstallAsService(service_manager);
} }
} // namespace Service::PCTL } // namespace Service::PCTL

View File

@ -4,6 +4,7 @@
#pragma once #pragma once
#include "common/common_funcs.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
namespace Core { namespace Core {
@ -12,12 +13,23 @@ class System;
namespace Service::PCTL { namespace Service::PCTL {
enum class Capability : u32 {
None = 0,
Application = 1 << 0,
SnsPost = 1 << 1,
Recovery = 1 << 6,
Status = 1 << 8,
StereoVision = 1 << 9,
System = 1 << 15,
};
DECLARE_ENUM_FLAG_OPERATORS(Capability);
class Module final { class Module final {
public: public:
class Interface : public ServiceFramework<Interface> { class Interface : public ServiceFramework<Interface> {
public: public:
explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
const char* name); Capability capability);
~Interface() override; ~Interface() override;
void CreateService(Kernel::HLERequestContext& ctx); void CreateService(Kernel::HLERequestContext& ctx);
@ -25,6 +37,9 @@ public:
protected: protected:
std::shared_ptr<Module> module; std::shared_ptr<Module> module;
private:
Capability capability{};
}; };
}; };

View File

@ -6,8 +6,9 @@
namespace Service::PCTL { namespace Service::PCTL {
PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name) PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
: Interface{system_, std::move(module_), name} { Capability capability)
: Interface{system_, std::move(module_), name, capability} {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
{0, &PCTL::CreateService, "CreateService"}, {0, &PCTL::CreateService, "CreateService"},
{1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},

View File

@ -14,7 +14,8 @@ namespace Service::PCTL {
class PCTL final : public Module::Interface { class PCTL final : public Module::Interface {
public: public:
explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name); explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
Capability capability);
~PCTL() override; ~PCTL() override;
}; };

View File

@ -70,6 +70,7 @@
#include "core/hle/service/vi/vi.h" #include "core/hle/service/vi/vi.h"
#include "core/hle/service/wlan/wlan.h" #include "core/hle/service/wlan/wlan.h"
#include "core/reporter.h" #include "core/reporter.h"
#include "core/settings.h"
namespace Service { namespace Service {
@ -146,6 +147,11 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name, system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name,
service_name); service_name);
UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf)); UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
if (Settings::values.use_auto_stub) {
LOG_WARNING(Service, "Using auto stub fallback!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
} }
void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) { void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {

View File

@ -139,6 +139,7 @@ struct Values {
Setting<int> vulkan_device; Setting<int> vulkan_device;
Setting<u16> resolution_factor{1}; Setting<u16> resolution_factor{1};
Setting<int> fullscreen_mode;
Setting<int> aspect_ratio; Setting<int> aspect_ratio;
Setting<int> max_anisotropy; Setting<int> max_anisotropy;
Setting<bool> use_frame_limit; Setting<bool> use_frame_limit;
@ -222,6 +223,7 @@ struct Values {
bool quest_flag; bool quest_flag;
bool disable_macro_jit; bool disable_macro_jit;
bool extended_logging; bool extended_logging;
bool use_auto_stub;
// Miscellaneous // Miscellaneous
std::string log_filter; std::string log_filter;

View File

@ -761,7 +761,7 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
for (const auto& joystick : value) { for (const auto& joystick : value) {
if (auto* const controller = joystick->GetSDLGameController()) { if (auto* const controller = joystick->GetSDLGameController()) {
std::string name = std::string name =
fmt::format("{} {}", SDL_GameControllerName(controller), joystick->GetPort()); fmt::format("{} {}", GetControllerName(controller), joystick->GetPort());
devices.emplace_back(Common::ParamPackage{ devices.emplace_back(Common::ParamPackage{
{"class", "sdl"}, {"class", "sdl"},
{"display", std::move(name)}, {"display", std::move(name)},
@ -782,6 +782,17 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
return devices; return devices;
} }
std::string SDLState::GetControllerName(SDL_GameController* controller) const {
switch (SDL_GameControllerGetType(controller)) {
case SDL_CONTROLLER_TYPE_XBOX360:
return "XBox 360 Controller";
case SDL_CONTROLLER_TYPE_XBOXONE:
return "XBox One Controller";
default:
return SDL_GameControllerName(controller);
}
}
namespace { namespace {
Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis,
float value = 0.1f) { float value = 0.1f) {
@ -930,16 +941,19 @@ ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& pa
return {}; return {};
} }
const bool invert =
SDL_GameControllerGetType(controller) != SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
// This list is missing ZL/ZR since those are not considered buttons in SDL GameController. // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
// We will add those afterwards // We will add those afterwards
// This list also excludes Screenshot since theres not really a mapping for that // This list also excludes Screenshot since theres not really a mapping for that
using ButtonBindings = using ButtonBindings =
std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>; std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
static constexpr ButtonBindings switch_to_sdl_button{{ const ButtonBindings switch_to_sdl_button{{
{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, {Settings::NativeButton::A, invert ? SDL_CONTROLLER_BUTTON_B : SDL_CONTROLLER_BUTTON_A},
{Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, {Settings::NativeButton::B, invert ? SDL_CONTROLLER_BUTTON_A : SDL_CONTROLLER_BUTTON_B},
{Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, {Settings::NativeButton::X, invert ? SDL_CONTROLLER_BUTTON_Y : SDL_CONTROLLER_BUTTON_X},
{Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, {Settings::NativeButton::Y, invert ? SDL_CONTROLLER_BUTTON_X : SDL_CONTROLLER_BUTTON_Y},
{Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
{Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
{Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},

View File

@ -14,6 +14,7 @@
#include "input_common/sdl/sdl.h" #include "input_common/sdl/sdl.h"
union SDL_Event; union SDL_Event;
using SDL_GameController = struct _SDL_GameController;
using SDL_Joystick = struct _SDL_Joystick; using SDL_Joystick = struct _SDL_Joystick;
using SDL_JoystickID = s32; using SDL_JoystickID = s32;
@ -64,6 +65,9 @@ private:
/// Needs to be called before SDL_QuitSubSystem. /// Needs to be called before SDL_QuitSubSystem.
void CloseJoysticks(); void CloseJoysticks();
/// Returns a custom name for specific controllers because the default name is not correct
std::string GetControllerName(SDL_GameController* controller) const;
// Set to true if SDL supports game controller subsystem // Set to true if SDL supports game controller subsystem
bool has_gamecontroller = false; bool has_gamecontroller = false;

View File

@ -1785,6 +1785,8 @@ public:
SSY, SSY,
SYNC, SYNC,
BRK, BRK,
CAL,
RET,
DEPBAR, DEPBAR,
VOTE, VOTE,
VOTE_VTG, VOTE_VTG,
@ -2108,6 +2110,8 @@ private:
INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"), INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"),
INST("111000110100----", Id::BRK, Type::Flow, "BRK"), INST("111000110100----", Id::BRK, Type::Flow, "BRK"),
INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"), INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"),
INST("111000100110----", Id::CAL, Type::Flow, "CAL"),
INST("111000110010----", Id::RET, Type::Flow, "RET"),
INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"), INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"),
INST("0101000011011---", Id::VOTE, Type::Warp, "VOTE"), INST("0101000011011---", Id::VOTE, Type::Warp, "VOTE"),
INST("0101000011100---", Id::VOTE_VTG, Type::Warp, "VOTE_VTG"), INST("0101000011100---", Id::VOTE_VTG, Type::Warp, "VOTE_VTG"),

View File

@ -114,6 +114,25 @@ void MemoryManager::TryUnlockPage(PageEntry page_entry, std::size_t size) {
.IsSuccess()); .IsSuccess());
} }
void MemoryManager::UnmapVicFrame(GPUVAddr gpu_addr, std::size_t size) {
if (!size) {
return;
}
const std::optional<VAddr> cpu_addr = GpuToCpuAddress(gpu_addr);
ASSERT(cpu_addr);
rasterizer->InvalidateExceptTextureCache(*cpu_addr, size);
cache_invalidate_queue.push_back({*cpu_addr, size});
UpdateRange(gpu_addr, PageEntry::State::Unmapped, size);
}
void MemoryManager::InvalidateQueuedCaches() {
for (const auto& entry : cache_invalidate_queue) {
rasterizer->InvalidateTextureCache(entry.first, entry.second);
}
cache_invalidate_queue.clear();
}
PageEntry MemoryManager::GetPageEntry(GPUVAddr gpu_addr) const { PageEntry MemoryManager::GetPageEntry(GPUVAddr gpu_addr) const {
return page_table[PageEntryIndex(gpu_addr)]; return page_table[PageEntryIndex(gpu_addr)];
} }

View File

@ -123,6 +123,14 @@ public:
[[nodiscard]] GPUVAddr Allocate(std::size_t size, std::size_t align); [[nodiscard]] GPUVAddr Allocate(std::size_t size, std::size_t align);
void Unmap(GPUVAddr gpu_addr, std::size_t size); void Unmap(GPUVAddr gpu_addr, std::size_t size);
/**
* Some Decoded NVDEC frames require that texture cache does not get invalidated.
* UnmapVicFrame defers the texture cache invalidation until the stream ends
* by invoking InvalidateQueuedCaches to invalidate all frame texture caches.
*/
void UnmapVicFrame(GPUVAddr gpu_addr, std::size_t size);
void InvalidateQueuedCaches();
private: private:
[[nodiscard]] PageEntry GetPageEntry(GPUVAddr gpu_addr) const; [[nodiscard]] PageEntry GetPageEntry(GPUVAddr gpu_addr) const;
void SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size = page_size); void SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size = page_size);

View File

@ -69,6 +69,12 @@ public:
/// Notify rasterizer that any caches of the specified region should be flushed to Switch memory /// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
virtual void FlushRegion(VAddr addr, u64 size) = 0; virtual void FlushRegion(VAddr addr, u64 size) = 0;
/// Notify rasterizer to flush the texture cache to Switch memory
virtual void InvalidateExceptTextureCache(VAddr addr, u64 size) = 0;
/// Notify rasterizer to invalidate the texture cache
virtual void InvalidateTextureCache(VAddr addr, u64 size) = 0;
/// Check if the the specified memory area requires flushing to CPU Memory. /// Check if the the specified memory area requires flushing to CPU Memory.
virtual bool MustFlushRegion(VAddr addr, u64 size) = 0; virtual bool MustFlushRegion(VAddr addr, u64 size) = 0;

View File

@ -491,6 +491,9 @@ private:
const Registry& registry; const Registry& registry;
const ShaderType stage; const ShaderType stage;
std::shared_ptr<ShaderFunctionIR> context_func;
u32 ast_var_base{};
std::size_t num_temporaries = 0; std::size_t num_temporaries = 0;
std::size_t max_temporaries = 0; std::size_t max_temporaries = 0;
@ -807,13 +810,33 @@ ARBDecompiler::ARBDecompiler(const Device& device_, const ShaderIR& ir_, const R
: device{device_}, ir{ir_}, registry{registry_}, stage{stage_} { : device{device_}, ir{ir_}, registry{registry_}, stage{stage_} {
DefineGlobalMemory(); DefineGlobalMemory();
context_func = ir.GetMainFunction();
ast_var_base = 0;
AddLine("TEMP RC;"); AddLine("TEMP RC;");
AddLine("TEMP FSWZA[4];"); AddLine("TEMP FSWZA[4];");
AddLine("TEMP FSWZB[4];"); AddLine("TEMP FSWZB[4];");
if (ir.IsDecompiled()) { InitializeVariables();
AddLine("main:");
if (context_func->IsDecompiled()) {
DecompileAST(); DecompileAST();
} else { } else {
DecompileBranchMode(); DecompileBranchMode();
AddLine("RET;");
}
const auto& subfunctions = ir.GetSubFunctions();
auto it = subfunctions.begin();
while (it != subfunctions.end()) {
context_func = *it;
AddLine("func_{}:", context_func->GetId());
if (context_func->IsDecompiled()) {
DecompileAST();
} else {
DecompileBranchMode();
AddLine("RET;");
}
it++;
} }
AddLine("END"); AddLine("END");
@ -1060,41 +1083,38 @@ void ARBDecompiler::InitializeVariables() {
} }
void ARBDecompiler::DecompileAST() { void ARBDecompiler::DecompileAST() {
const u32 num_flow_variables = ir.GetASTNumVariables(); const u32 num_flow_variables = context_func->GetASTNumVariables();
for (u32 i = 0; i < num_flow_variables; ++i) { for (u32 i = 0; i < num_flow_variables; ++i) {
AddLine("TEMP F{};", i); AddLine("TEMP F{};", i + ast_var_base);
} }
for (u32 i = 0; i < num_flow_variables; ++i) { for (u32 i = 0; i < num_flow_variables; ++i) {
AddLine("MOV.U F{}, {{0, 0, 0, 0}};", i); AddLine("MOV.U F{}, {{0, 0, 0, 0}};", i + ast_var_base);
} }
InitializeVariables(); VisitAST(context_func->GetASTProgram());
ast_var_base += num_flow_variables;
VisitAST(ir.GetASTProgram());
} }
void ARBDecompiler::DecompileBranchMode() { void ARBDecompiler::DecompileBranchMode() {
static constexpr u32 FLOW_STACK_SIZE = 20; static constexpr u32 FLOW_STACK_SIZE = 20;
if (!ir.IsFlowStackDisabled()) { if (!context_func->IsFlowStackDisabled()) {
AddLine("TEMP SSY[{}];", FLOW_STACK_SIZE); AddLine("TEMP SSY[{}];", FLOW_STACK_SIZE);
AddLine("TEMP PBK[{}];", FLOW_STACK_SIZE); AddLine("TEMP PBK[{}];", FLOW_STACK_SIZE);
AddLine("TEMP SSY_TOP;"); AddLine("TEMP SSY_TOP;");
AddLine("TEMP PBK_TOP;"); AddLine("TEMP PBK_TOP;");
} }
AddLine("TEMP PC;"); AddLine("TEMP PC{};", context_func->GetId());
if (!ir.IsFlowStackDisabled()) { if (!context_func->IsFlowStackDisabled()) {
AddLine("MOV.U SSY_TOP.x, 0;"); AddLine("MOV.U SSY_TOP.x, 0;");
AddLine("MOV.U PBK_TOP.x, 0;"); AddLine("MOV.U PBK_TOP.x, 0;");
} }
InitializeVariables(); const auto basic_block_end = context_func->GetBasicBlocks().end();
auto basic_block_it = context_func->GetBasicBlocks().begin();
const auto basic_block_end = ir.GetBasicBlocks().end();
auto basic_block_it = ir.GetBasicBlocks().begin();
const u32 first_address = basic_block_it->first; const u32 first_address = basic_block_it->first;
AddLine("MOV.U PC.x, {};", first_address); AddLine("MOV.U PC{}.x, {};", context_func->GetId(), first_address);
AddLine("REP;"); AddLine("REP;");
@ -1103,7 +1123,7 @@ void ARBDecompiler::DecompileBranchMode() {
const auto& [address, bb] = *basic_block_it; const auto& [address, bb] = *basic_block_it;
++num_blocks; ++num_blocks;
AddLine("SEQ.S.CC RC.x, PC.x, {};", address); AddLine("SEQ.S.CC RC.x, PC{}.x, {};", context_func->GetId(), address);
AddLine("IF NE.x;"); AddLine("IF NE.x;");
VisitBlock(bb); VisitBlock(bb);
@ -1114,7 +1134,7 @@ void ARBDecompiler::DecompileBranchMode() {
const auto op = std::get_if<OperationNode>(&*bb[bb.size() - 1]); const auto op = std::get_if<OperationNode>(&*bb[bb.size() - 1]);
if (!op || op->GetCode() != OperationCode::Branch) { if (!op || op->GetCode() != OperationCode::Branch) {
const u32 next_address = basic_block_it->first; const u32 next_address = basic_block_it->first;
AddLine("MOV.U PC.x, {};", next_address); AddLine("MOV.U PC{}.x, {};", context_func->GetId(), next_address);
AddLine("CONT;"); AddLine("CONT;");
} }
} }
@ -1152,7 +1172,8 @@ void ARBDecompiler::VisitAST(const ASTNode& node) {
} else if (const auto decoded = std::get_if<ASTBlockDecoded>(&*node->GetInnerData())) { } else if (const auto decoded = std::get_if<ASTBlockDecoded>(&*node->GetInnerData())) {
VisitBlock(decoded->nodes); VisitBlock(decoded->nodes);
} else if (const auto var_set = std::get_if<ASTVarSet>(&*node->GetInnerData())) { } else if (const auto var_set = std::get_if<ASTVarSet>(&*node->GetInnerData())) {
AddLine("MOV.U F{}, {};", var_set->index, VisitExpression(var_set->condition)); AddLine("MOV.U F{}, {};", var_set->index + ast_var_base,
VisitExpression(var_set->condition));
ResetTemporaries(); ResetTemporaries();
} else if (const auto do_while = std::get_if<ASTDoWhile>(&*node->GetInnerData())) { } else if (const auto do_while = std::get_if<ASTDoWhile>(&*node->GetInnerData())) {
const std::string condition = VisitExpression(do_while->condition); const std::string condition = VisitExpression(do_while->condition);
@ -1172,7 +1193,11 @@ void ARBDecompiler::VisitAST(const ASTNode& node) {
ResetTemporaries(); ResetTemporaries();
} }
if (ast_return->kills) { if (ast_return->kills) {
AddLine("KIL TR;"); if (stage == ShaderType::Fragment) {
AddLine("KIL TR;");
} else {
AddLine("RET;");
}
} else { } else {
Exit(); Exit();
} }
@ -1219,7 +1244,7 @@ std::string ARBDecompiler::VisitExpression(const Expr& node) {
return Visit(ir.GetConditionCode(expr->cc)); return Visit(ir.GetConditionCode(expr->cc));
} }
if (const auto expr = std::get_if<ExprVar>(&*node)) { if (const auto expr = std::get_if<ExprVar>(&*node)) {
return fmt::format("F{}.x", expr->var_index); return fmt::format("F{}.x", expr->var_index + ast_var_base);
} }
if (const auto expr = std::get_if<ExprBoolean>(&*node)) { if (const auto expr = std::get_if<ExprBoolean>(&*node)) {
return expr->value ? "0xffffffff" : "0"; return expr->value ? "0xffffffff" : "0";
@ -1406,6 +1431,11 @@ std::string ARBDecompiler::Visit(const Node& node) {
return {}; return {};
} }
if (const auto func_call = std::get_if<FunctionCallNode>(&*node)) {
AddLine("CAL func_{};", func_call->GetFuncId());
return {};
}
if ([[maybe_unused]] const auto cmt = std::get_if<CommentNode>(&*node)) { if ([[maybe_unused]] const auto cmt = std::get_if<CommentNode>(&*node)) {
// Uncommenting this will generate invalid code. GLASM lacks comments. // Uncommenting this will generate invalid code. GLASM lacks comments.
// AddLine("// {}", cmt->GetText()); // AddLine("// {}", cmt->GetText());
@ -1479,7 +1509,7 @@ std::string ARBDecompiler::GlobalMemoryPointer(const GmemNode& gmem) {
} }
void ARBDecompiler::Exit() { void ARBDecompiler::Exit() {
if (stage != ShaderType::Fragment) { if (!context_func->IsMain() || stage != ShaderType::Fragment) {
AddLine("RET;"); AddLine("RET;");
return; return;
} }
@ -2021,13 +2051,13 @@ std::string ARBDecompiler::ImageStore(Operation operation) {
std::string ARBDecompiler::Branch(Operation operation) { std::string ARBDecompiler::Branch(Operation operation) {
const auto target = std::get<ImmediateNode>(*operation[0]); const auto target = std::get<ImmediateNode>(*operation[0]);
AddLine("MOV.U PC.x, {};", target.GetValue()); AddLine("MOV.U PC{}.x, {};", context_func->GetId(), target.GetValue());
AddLine("CONT;"); AddLine("CONT;");
return {}; return {};
} }
std::string ARBDecompiler::BranchIndirect(Operation operation) { std::string ARBDecompiler::BranchIndirect(Operation operation) {
AddLine("MOV.U PC.x, {};", Visit(operation[0])); AddLine("MOV.U PC{}.x, {};", context_func->GetId(), Visit(operation[0]));
AddLine("CONT;"); AddLine("CONT;");
return {}; return {};
} }
@ -2045,7 +2075,7 @@ std::string ARBDecompiler::PopFlowStack(Operation operation) {
const auto stack = std::get<MetaStackClass>(operation.GetMeta()); const auto stack = std::get<MetaStackClass>(operation.GetMeta());
const std::string_view stack_name = StackName(stack); const std::string_view stack_name = StackName(stack);
AddLine("SUB.S {}_TOP.x, {}_TOP.x, 1;", stack_name, stack_name); AddLine("SUB.S {}_TOP.x, {}_TOP.x, 1;", stack_name, stack_name);
AddLine("MOV.U PC.x, {}[{}_TOP.x].x;", stack_name, stack_name); AddLine("MOV.U PC{}.x, {}[{}_TOP.x].x;", context_func->GetId(), stack_name, stack_name);
AddLine("CONT;"); AddLine("CONT;");
return {}; return {};
} }
@ -2056,6 +2086,10 @@ std::string ARBDecompiler::Exit(Operation) {
} }
std::string ARBDecompiler::Discard(Operation) { std::string ARBDecompiler::Discard(Operation) {
if (stage != ShaderType::Fragment) {
AddLine("RET;");
return {};
}
AddLine("KIL TR;"); AddLine("KIL TR;");
return {}; return {};
} }

View File

@ -544,6 +544,26 @@ void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
query_cache.FlushRegion(addr, size); query_cache.FlushRegion(addr, size);
} }
void RasterizerOpenGL::InvalidateExceptTextureCache(VAddr addr, u64 size) {
if (addr == 0 || size == 0) {
return;
}
shader_cache.InvalidateRegion(addr, size);
{
std::scoped_lock lock{buffer_cache.mutex};
buffer_cache.WriteMemory(addr, size);
}
query_cache.InvalidateRegion(addr, size);
}
void RasterizerOpenGL::InvalidateTextureCache(VAddr addr, u64 size) {
if (addr == 0 || size == 0) {
return;
}
std::scoped_lock lock{texture_cache.mutex};
texture_cache.UnmapMemory(addr, size);
}
bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size) { bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size) {
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex}; std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
if (!Settings::IsGPULevelHigh()) { if (!Settings::IsGPULevelHigh()) {

View File

@ -74,6 +74,8 @@ public:
void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override; void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override;
void FlushAll() override; void FlushAll() override;
void FlushRegion(VAddr addr, u64 size) override; void FlushRegion(VAddr addr, u64 size) override;
void InvalidateExceptTextureCache(VAddr addr, u64 size) override;
void InvalidateTextureCache(VAddr addr, u64 size) override;
bool MustFlushRegion(VAddr addr, u64 size) override; bool MustFlushRegion(VAddr addr, u64 size) override;
void InvalidateRegion(VAddr addr, u64 size) override; void InvalidateRegion(VAddr addr, u64 size) override;
void OnCPUWrite(VAddr addr, u64 size) override; void OnCPUWrite(VAddr addr, u64 size) override;

View File

@ -79,6 +79,11 @@ const float fswzadd_modifiers_a[] = float[4](-1.0f, 1.0f, -1.0f, 0.0f );
const float fswzadd_modifiers_b[] = float[4](-1.0f, -1.0f, 1.0f, -1.0f ); const float fswzadd_modifiers_b[] = float[4](-1.0f, -1.0f, 1.0f, -1.0f );
)"; )";
enum class HelperFunction {
SignedAtomic = 0,
Total,
};
class ShaderWriter final { class ShaderWriter final {
public: public:
void AddExpression(std::string_view text) { void AddExpression(std::string_view text) {
@ -434,6 +439,28 @@ public:
DeclareInternalFlags(); DeclareInternalFlags();
DeclareCustomVariables(); DeclareCustomVariables();
DeclarePhysicalAttributeReader(); DeclarePhysicalAttributeReader();
DeclareHelpersForward();
const auto& subfunctions = ir.GetSubFunctions();
auto it = subfunctions.rbegin();
while (it != subfunctions.rend()) {
context_func = *it;
code.AddLine("void func_{}() {{", context_func->GetId());
++code.scope;
if (context_func->IsDecompiled()) {
DecompileAST();
} else {
DecompileBranchMode();
}
--code.scope;
code.AddLine("}}");
it++;
}
context_func = ir.GetMainFunction();
code.AddLine("void main() {{"); code.AddLine("void main() {{");
++code.scope; ++code.scope;
@ -442,7 +469,7 @@ public:
code.AddLine("gl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);"); code.AddLine("gl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);");
} }
if (ir.IsDecompiled()) { if (context_func->IsDecompiled()) {
DecompileAST(); DecompileAST();
} else { } else {
DecompileBranchMode(); DecompileBranchMode();
@ -450,6 +477,9 @@ public:
--code.scope; --code.scope;
code.AddLine("}}"); code.AddLine("}}");
code.AddNewLine();
DeclareHelpers();
} }
std::string GetResult() { std::string GetResult() {
@ -462,13 +492,13 @@ private:
void DecompileBranchMode() { void DecompileBranchMode() {
// VM's program counter // VM's program counter
const auto first_address = ir.GetBasicBlocks().begin()->first; const auto first_address = context_func->GetBasicBlocks().begin()->first;
code.AddLine("uint jmp_to = {}U;", first_address); code.AddLine("uint jmp_to = {}U;", first_address);
// TODO(Subv): Figure out the actual depth of the flow stack, for now it seems // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
// unlikely that shaders will use 20 nested SSYs and PBKs. // unlikely that shaders will use 20 nested SSYs and PBKs.
constexpr u32 FLOW_STACK_SIZE = 20; constexpr u32 FLOW_STACK_SIZE = 20;
if (!ir.IsFlowStackDisabled()) { if (!context_func->IsFlowStackDisabled()) {
for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) { for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) {
code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE); code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE);
code.AddLine("uint {} = 0U;", FlowStackTopName(stack)); code.AddLine("uint {} = 0U;", FlowStackTopName(stack));
@ -480,7 +510,7 @@ private:
code.AddLine("switch (jmp_to) {{"); code.AddLine("switch (jmp_to) {{");
for (const auto& pair : ir.GetBasicBlocks()) { for (const auto& pair : context_func->GetBasicBlocks()) {
const auto& [address, bb] = pair; const auto& [address, bb] = pair;
code.AddLine("case 0x{:X}U: {{", address); code.AddLine("case 0x{:X}U: {{", address);
++code.scope; ++code.scope;
@ -599,7 +629,7 @@ private:
size = limit; size = limit;
} }
code.AddLine("shared uint smem[{}];", size / 4); code.AddLine("shared uint {}[{}];", GetSharedMemory(), size / 4);
code.AddNewLine(); code.AddNewLine();
} }
code.AddLine("layout (local_size_x = {}, local_size_y = {}, local_size_z = {}) in;", code.AddLine("layout (local_size_x = {}, local_size_y = {}, local_size_z = {}) in;",
@ -983,6 +1013,27 @@ private:
} }
} }
void DeclareHelpersForward() {
code.AddLine("int Helpers_AtomicShared(uint offset, int value, bool is_min);");
code.AddNewLine();
}
void DeclareHelpers() {
if (IsHelperEnabled(HelperFunction::SignedAtomic)) {
code.AddLine(
R"(int Helpers_AtomicShared(uint offset, int value, bool is_min) {{
uint oldValue, newValue;
do {{
oldValue = {}[offset];
newValue = is_min ? uint(min(int(oldValue), value)) : uint(max(int(oldValue), value));
}} while (atomicCompSwap({}[offset], newValue, oldValue) != oldValue);
return int(oldValue);
}})",
GetSharedMemory(), GetSharedMemory());
code.AddNewLine();
}
}
void VisitBlock(const NodeBlock& bb) { void VisitBlock(const NodeBlock& bb) {
for (const auto& node : bb) { for (const auto& node : bb) {
Visit(node).CheckVoid(); Visit(node).CheckVoid();
@ -1109,7 +1160,9 @@ private:
} }
if (const auto smem = std::get_if<SmemNode>(&*node)) { if (const auto smem = std::get_if<SmemNode>(&*node)) {
return {fmt::format("smem[{} >> 2]", Visit(smem->GetAddress()).AsUint()), Type::Uint}; return {
fmt::format("{}[{} >> 2]", GetSharedMemory(), Visit(smem->GetAddress()).AsUint()),
Type::Uint};
} }
if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) { if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) {
@ -1131,6 +1184,11 @@ private:
return {}; return {};
} }
if (const auto func_call = std::get_if<FunctionCallNode>(&*node)) {
code.AddLine("func_{}();", func_call->GetFuncId());
return {};
}
if (const auto comment = std::get_if<CommentNode>(&*node)) { if (const auto comment = std::get_if<CommentNode>(&*node)) {
code.AddLine("// " + comment->GetText()); code.AddLine("// " + comment->GetText());
return {}; return {};
@ -1598,7 +1656,9 @@ private:
Type::Uint}; Type::Uint};
} else if (const auto smem = std::get_if<SmemNode>(&*dest)) { } else if (const auto smem = std::get_if<SmemNode>(&*dest)) {
ASSERT(stage == ShaderType::Compute); ASSERT(stage == ShaderType::Compute);
target = {fmt::format("smem[{} >> 2]", Visit(smem->GetAddress()).AsUint()), Type::Uint}; target = {
fmt::format("{}[{} >> 2]", GetSharedMemory(), Visit(smem->GetAddress()).AsUint()),
Type::Uint};
} else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
const std::string real = Visit(gmem->GetRealAddress()).AsUint(); const std::string real = Visit(gmem->GetRealAddress()).AsUint();
const std::string base = Visit(gmem->GetBaseAddress()).AsUint(); const std::string base = Visit(gmem->GetBaseAddress()).AsUint();
@ -2115,7 +2175,14 @@ private:
UNIMPLEMENTED_IF(meta->sampler.is_array); UNIMPLEMENTED_IF(meta->sampler.is_array);
const std::size_t count = operation.GetOperandsCount(); const std::size_t count = operation.GetOperandsCount();
std::string expr = "texelFetch("; std::string expr = "texelFetch";
if (!meta->aoffi.empty()) {
expr += "Offset";
}
expr += '(';
expr += GetSampler(meta->sampler); expr += GetSampler(meta->sampler);
expr += ", "; expr += ", ";
@ -2137,6 +2204,20 @@ private:
expr += ", "; expr += ", ";
expr += Visit(meta->lod).AsInt(); expr += Visit(meta->lod).AsInt();
} }
if (!meta->aoffi.empty()) {
expr += ", ";
expr += constructors.at(meta->aoffi.size() - 1);
expr += '(';
for (size_t i = 0; i < meta->aoffi.size(); ++i) {
if (i > 0) {
expr += ", ";
}
expr += Visit(meta->aoffi[i]).AsInt();
}
expr += ')';
}
expr += ')'; expr += ')';
expr += GetSwizzle(meta->element); expr += GetSwizzle(meta->element);
@ -2183,8 +2264,11 @@ private:
template <const std::string_view& opname, Type type> template <const std::string_view& opname, Type type>
Expression Atomic(Operation operation) { Expression Atomic(Operation operation) {
if ((opname == Func::Min || opname == Func::Max) && type == Type::Int) { if ((opname == Func::Min || opname == Func::Max) && type == Type::Int) {
UNIMPLEMENTED_MSG("Unimplemented Min & Max for atomic operations"); // Use a helper as a workaround due to memory being uint
return {}; SetHelperEnabled(HelperFunction::SignedAtomic, true);
return {fmt::format("Helpers_AtomicShared({}, {}, {})", Visit(operation[0]).AsInt(),
Visit(operation[1]).AsInt(), opname == Func::Min),
Type::Int};
} }
return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(), return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(),
Visit(operation[1]).AsUint()), Visit(operation[1]).AsUint()),
@ -2267,7 +2351,9 @@ private:
} }
Expression Exit(Operation operation) { Expression Exit(Operation operation) {
PreExit(); if (context_func->IsMain()) {
PreExit();
}
code.AddLine("return;"); code.AddLine("return;");
return {}; return {};
} }
@ -2277,7 +2363,11 @@ private:
// about unexecuted instructions that may follow this. // about unexecuted instructions that may follow this.
code.AddLine("if (true) {{"); code.AddLine("if (true) {{");
++code.scope; ++code.scope;
code.AddLine("discard;"); if (stage != ShaderType::Fragment) {
code.AddLine("return;");
} else {
code.AddLine("discard;");
}
--code.scope; --code.scope;
code.AddLine("}}"); code.AddLine("}}");
return {}; return {};
@ -2388,7 +2478,7 @@ private:
} }
Expression Barrier(Operation) { Expression Barrier(Operation) {
if (!ir.IsDecompiled()) { if (!context_func->IsDecompiled()) {
LOG_ERROR(Render_OpenGL, "barrier() used but shader is not decompiled"); LOG_ERROR(Render_OpenGL, "barrier() used but shader is not decompiled");
return {}; return {};
} }
@ -2705,6 +2795,10 @@ private:
} }
} }
constexpr std::string_view GetSharedMemory() const {
return "shared_mem";
}
std::string GetInternalFlag(InternalFlag flag) const { std::string GetInternalFlag(InternalFlag flag) const {
constexpr std::array InternalFlagNames = {"zero_flag", "sign_flag", "carry_flag", constexpr std::array InternalFlagNames = {"zero_flag", "sign_flag", "carry_flag",
"overflow_flag"}; "overflow_flag"};
@ -2746,6 +2840,14 @@ private:
return std::min<u32>(device.GetMaxVaryings(), Maxwell::NumVaryings); return std::min<u32>(device.GetMaxVaryings(), Maxwell::NumVaryings);
} }
void SetHelperEnabled(HelperFunction hf, bool enabled) {
helper_functions_enabled[static_cast<size_t>(hf)] = enabled;
}
bool IsHelperEnabled(HelperFunction hf) const {
return helper_functions_enabled[static_cast<size_t>(hf)];
}
const Device& device; const Device& device;
const ShaderIR& ir; const ShaderIR& ir;
const Registry& registry; const Registry& registry;
@ -2755,9 +2857,13 @@ private:
const Header header; const Header header;
std::unordered_map<u8, VaryingTFB> transform_feedback; std::unordered_map<u8, VaryingTFB> transform_feedback;
std::shared_ptr<ShaderFunctionIR> context_func;
ShaderWriter code; ShaderWriter code;
std::optional<u32> max_input_vertices; std::optional<u32> max_input_vertices;
std::array<bool, static_cast<size_t>(HelperFunction::Total)> helper_functions_enabled{};
}; };
std::string GetFlowVariable(u32 index) { std::string GetFlowVariable(u32 index) {
@ -2902,9 +3008,15 @@ public:
decomp.code.scope++; decomp.code.scope++;
} }
if (ast.kills) { if (ast.kills) {
decomp.code.AddLine("discard;"); if (decomp.stage != ShaderType::Fragment) {
decomp.code.AddLine("return;");
} else {
decomp.code.AddLine("discard;");
}
} else { } else {
decomp.PreExit(); if (decomp.context_func->IsMain()) {
decomp.PreExit();
}
decomp.code.AddLine("return;"); decomp.code.AddLine("return;");
} }
if (!is_true) { if (!is_true) {
@ -2937,13 +3049,13 @@ private:
}; };
void GLSLDecompiler::DecompileAST() { void GLSLDecompiler::DecompileAST() {
const u32 num_flow_variables = ir.GetASTNumVariables(); const u32 num_flow_variables = context_func->GetASTNumVariables();
for (u32 i = 0; i < num_flow_variables; i++) { for (u32 i = 0; i < num_flow_variables; i++) {
code.AddLine("bool {} = false;", GetFlowVariable(i)); code.AddLine("bool {} = false;", GetFlowVariable(i));
} }
ASTDecompiler decompiler{*this}; ASTDecompiler decompiler{*this};
decompiler.Visit(ir.GetASTProgram()); decompiler.Visit(context_func->GetASTProgram());
} }
} // Anonymous namespace } // Anonymous namespace

View File

@ -493,6 +493,26 @@ void RasterizerVulkan::FlushRegion(VAddr addr, u64 size) {
query_cache.FlushRegion(addr, size); query_cache.FlushRegion(addr, size);
} }
void Vulkan::RasterizerVulkan::InvalidateExceptTextureCache(VAddr addr, u64 size) {
if (addr == 0 || size == 0) {
return;
}
pipeline_cache.InvalidateRegion(addr, size);
{
std::scoped_lock lock{buffer_cache.mutex};
buffer_cache.WriteMemory(addr, size);
}
query_cache.InvalidateRegion(addr, size);
}
void Vulkan::RasterizerVulkan::InvalidateTextureCache(VAddr addr, u64 size) {
if (addr == 0 || size == 0) {
return;
}
std::scoped_lock lock{texture_cache.mutex};
texture_cache.UnmapMemory(addr, size);
}
bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size) { bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size) {
std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex}; std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex};
if (!Settings::IsGPULevelHigh()) { if (!Settings::IsGPULevelHigh()) {

View File

@ -66,6 +66,8 @@ public:
void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override; void BindGraphicsUniformBuffer(size_t stage, u32 index, GPUVAddr gpu_addr, u32 size) override;
void FlushAll() override; void FlushAll() override;
void FlushRegion(VAddr addr, u64 size) override; void FlushRegion(VAddr addr, u64 size) override;
void InvalidateExceptTextureCache(VAddr addr, u64 size) override;
void InvalidateTextureCache(VAddr addr, u64 size) override;
bool MustFlushRegion(VAddr addr, u64 size) override; bool MustFlushRegion(VAddr addr, u64 size) override;
void InvalidateRegion(VAddr addr, u64 size) override; void InvalidateRegion(VAddr addr, u64 size) override;
void OnCPUWrite(VAddr addr, u64 size) override; void OnCPUWrite(VAddr addr, u64 size) override;

View File

@ -406,10 +406,38 @@ private:
binding = DeclareStorageTexels(binding); binding = DeclareStorageTexels(binding);
binding = DeclareImages(binding); binding = DeclareImages(binding);
const auto& subfunctions = ir.GetSubFunctions();
labels.resize(subfunctions.size() + 1);
other_functions.resize(subfunctions.size());
auto it = subfunctions.rbegin();
while (it != subfunctions.rend()) {
context_func = *it;
other_functions[context_func->GetId() - 1] =
OpFunction(t_void, {}, TypeFunction(t_void));
AddLabel();
if (context_func->IsDecompiled()) {
DeclareFlowVariables();
DecompileAST();
} else {
AllocateLabels();
DecompileBranchMode();
}
OpReturn();
OpFunctionEnd();
it++;
}
context_func = ir.GetMainFunction();
const Id main = OpFunction(t_void, {}, TypeFunction(t_void)); const Id main = OpFunction(t_void, {}, TypeFunction(t_void));
AddLabel(); AddLabel();
if (ir.IsDecompiled()) { if (context_func->IsDecompiled()) {
DeclareFlowVariables(); DeclareFlowVariables();
DecompileAST(); DecompileAST();
} else { } else {
@ -441,16 +469,18 @@ private:
void DecompileAST(); void DecompileAST();
void DecompileBranchMode() { void DecompileBranchMode() {
const u32 first_address = ir.GetBasicBlocks().begin()->first; const u32 first_address = context_func->GetBasicBlocks().begin()->first;
const Id loop_label = OpLabel("loop"); const u32 func_id = context_func->GetId();
const Id merge_label = OpLabel("merge"); const std::string func_id_msg = std::to_string(func_id);
const Id loop_label = OpLabel("loop_" + func_id_msg);
const Id merge_label = OpLabel("merge_" + func_id_msg);
const Id dummy_label = OpLabel(); const Id dummy_label = OpLabel();
const Id jump_label = OpLabel(); const Id jump_label = OpLabel();
continue_label = OpLabel("continue"); continue_label = OpLabel("continue_" + func_id_msg);
std::vector<Sirit::Literal> literals; std::vector<Sirit::Literal> literals;
std::vector<Id> branch_labels; std::vector<Id> branch_labels;
for (const auto& [literal, label] : labels) { for (const auto& [literal, label] : labels[func_id]) {
literals.push_back(literal); literals.push_back(literal);
branch_labels.push_back(label); branch_labels.push_back(label);
} }
@ -462,11 +492,11 @@ private:
std::tie(ssy_flow_stack, ssy_flow_stack_top) = CreateFlowStack(); std::tie(ssy_flow_stack, ssy_flow_stack_top) = CreateFlowStack();
std::tie(pbk_flow_stack, pbk_flow_stack_top) = CreateFlowStack(); std::tie(pbk_flow_stack, pbk_flow_stack_top) = CreateFlowStack();
Name(jmp_to, "jmp_to"); Name(jmp_to, "jmp_to_" + func_id_msg);
Name(ssy_flow_stack, "ssy_flow_stack"); Name(ssy_flow_stack, "ssy_flow_stack_" + func_id_msg);
Name(ssy_flow_stack_top, "ssy_flow_stack_top"); Name(ssy_flow_stack_top, "ssy_flow_stack_top_" + func_id_msg);
Name(pbk_flow_stack, "pbk_flow_stack"); Name(pbk_flow_stack, "pbk_flow_stack_" + func_id_msg);
Name(pbk_flow_stack_top, "pbk_flow_stack_top"); Name(pbk_flow_stack_top, "pbk_flow_stack_top_" + func_id_msg);
DefinePrologue(); DefinePrologue();
@ -484,13 +514,14 @@ private:
AddLabel(default_branch); AddLabel(default_branch);
OpReturn(); OpReturn();
for (const auto& [address, bb] : ir.GetBasicBlocks()) { for (const auto& [address, bb] : context_func->GetBasicBlocks()) {
AddLabel(labels.at(address)); AddLabel(labels[func_id].at(address));
VisitBasicBlock(bb); VisitBasicBlock(bb);
const auto next_it = labels.lower_bound(address + 1); const auto next_it = labels[func_id].lower_bound(address + 1);
const Id next_label = next_it != labels.end() ? next_it->second : default_branch; const Id next_label =
next_it != labels[func_id].end() ? next_it->second : default_branch;
OpBranch(next_label); OpBranch(next_label);
} }
@ -508,9 +539,10 @@ private:
static constexpr auto INTERNAL_FLAGS_COUNT = static_cast<std::size_t>(InternalFlag::Amount); static constexpr auto INTERNAL_FLAGS_COUNT = static_cast<std::size_t>(InternalFlag::Amount);
void AllocateLabels() { void AllocateLabels() {
for (const auto& pair : ir.GetBasicBlocks()) { const u32 func_id = context_func->GetId();
for (const auto& pair : context_func->GetBasicBlocks()) {
const u32 address = pair.first; const u32 address = pair.first;
labels.emplace(address, OpLabel(fmt::format("label_0x{:x}", address))); labels[func_id].emplace(address, OpLabel(fmt::format("label_0x{:x}", address)));
} }
} }
@ -589,6 +621,14 @@ private:
DeclareOutputVertex(); DeclareOutputVertex();
} }
void SafeKill() {
if (stage != ShaderType::Fragment) {
OpReturn();
return;
}
OpKill();
}
void DeclareFragment() { void DeclareFragment() {
if (stage != ShaderType::Fragment) { if (stage != ShaderType::Fragment) {
return; return;
@ -656,7 +696,7 @@ private:
} }
void DeclareFlowVariables() { void DeclareFlowVariables() {
for (u32 i = 0; i < ir.GetASTNumVariables(); i++) { for (u32 i = 0; i < context_func->GetASTNumVariables(); i++) {
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
Name(id, fmt::format("flow_var_{}", static_cast<u32>(i))); Name(id, fmt::format("flow_var_{}", static_cast<u32>(i)));
flow_variables.emplace(i, AddGlobalVariable(id)); flow_variables.emplace(i, AddGlobalVariable(id));
@ -1333,6 +1373,12 @@ private:
return {}; return {};
} }
if (const auto func_call = std::get_if<FunctionCallNode>(&*node)) {
const u32 func_id = func_call->GetFuncId();
OpFunctionCall(t_void, other_functions[func_id - 1]);
return {};
}
if (const auto comment = std::get_if<CommentNode>(&*node)) { if (const auto comment = std::get_if<CommentNode>(&*node)) {
if (device.HasDebuggingToolAttached()) { if (device.HasDebuggingToolAttached()) {
// We should insert comments with OpString instead of using named variables // We should insert comments with OpString instead of using named variables
@ -2124,7 +2170,7 @@ private:
OpBranchConditional(condition, true_label, discard_label); OpBranchConditional(condition, true_label, discard_label);
AddLabel(discard_label); AddLabel(discard_label);
OpKill(); SafeKill();
AddLabel(true_label); AddLabel(true_label);
} }
@ -2175,7 +2221,9 @@ private:
} }
Expression Exit(Operation operation) { Expression Exit(Operation operation) {
PreExit(); if (context_func->IsMain()) {
PreExit();
}
inside_branch = true; inside_branch = true;
if (conditional_branch_set) { if (conditional_branch_set) {
OpReturn(); OpReturn();
@ -2192,12 +2240,12 @@ private:
Expression Discard(Operation operation) { Expression Discard(Operation operation) {
inside_branch = true; inside_branch = true;
if (conditional_branch_set) { if (conditional_branch_set) {
OpKill(); SafeKill();
} else { } else {
const Id dummy = OpLabel(); const Id dummy = OpLabel();
OpBranch(dummy); OpBranch(dummy);
AddLabel(dummy); AddLabel(dummy);
OpKill(); SafeKill();
AddLabel(); AddLabel();
} }
return {}; return {};
@ -2276,7 +2324,7 @@ private:
} }
Expression Barrier(Operation) { Expression Barrier(Operation) {
if (!ir.IsDecompiled()) { if (!context_func->IsDecompiled()) {
LOG_ERROR(Render_Vulkan, "OpBarrier used by shader is not decompiled"); LOG_ERROR(Render_Vulkan, "OpBarrier used by shader is not decompiled");
return {}; return {};
} }
@ -2770,6 +2818,8 @@ private:
const Specialization& specialization; const Specialization& specialization;
std::unordered_map<u8, VaryingTFB> transform_feedback; std::unordered_map<u8, VaryingTFB> transform_feedback;
std::shared_ptr<ShaderFunctionIR> context_func;
const Id t_void = Name(TypeVoid(), "void"); const Id t_void = Name(TypeVoid(), "void");
const Id t_bool = Name(TypeBool(), "bool"); const Id t_bool = Name(TypeBool(), "bool");
@ -2896,7 +2946,8 @@ private:
Id ssy_flow_stack{}; Id ssy_flow_stack{};
Id pbk_flow_stack{}; Id pbk_flow_stack{};
Id continue_label{}; Id continue_label{};
std::map<u32, Id> labels; std::vector<std::map<u32, Id>> labels;
std::vector<Id> other_functions;
bool conditional_branch_set{}; bool conditional_branch_set{};
bool inside_branch{}; bool inside_branch{};
@ -3047,9 +3098,11 @@ public:
decomp.OpBranchConditional(condition, then_label, endif_label); decomp.OpBranchConditional(condition, then_label, endif_label);
decomp.AddLabel(then_label); decomp.AddLabel(then_label);
if (ast.kills) { if (ast.kills) {
decomp.OpKill(); decomp.SafeKill();
} else { } else {
decomp.PreExit(); if (decomp.context_func->IsMain()) {
decomp.PreExit();
}
decomp.OpReturn(); decomp.OpReturn();
} }
decomp.AddLabel(endif_label); decomp.AddLabel(endif_label);
@ -3058,9 +3111,11 @@ public:
decomp.OpBranch(next_block); decomp.OpBranch(next_block);
decomp.AddLabel(next_block); decomp.AddLabel(next_block);
if (ast.kills) { if (ast.kills) {
decomp.OpKill(); decomp.SafeKill();
} else { } else {
decomp.PreExit(); if (decomp.context_func->IsMain()) {
decomp.PreExit();
}
decomp.OpReturn(); decomp.OpReturn();
} }
decomp.AddLabel(decomp.OpLabel()); decomp.AddLabel(decomp.OpLabel());
@ -3097,7 +3152,7 @@ private:
}; };
void SPIRVDecompiler::DecompileAST() { void SPIRVDecompiler::DecompileAST() {
const u32 num_flow_variables = ir.GetASTNumVariables(); const u32 num_flow_variables = context_func->GetASTNumVariables();
for (u32 i = 0; i < num_flow_variables; i++) { for (u32 i = 0; i < num_flow_variables; i++) {
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false); const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
Name(id, fmt::format("flow_var_{}", i)); Name(id, fmt::format("flow_var_{}", i));
@ -3106,7 +3161,7 @@ void SPIRVDecompiler::DecompileAST() {
DefinePrologue(); DefinePrologue();
const ASTNode program = ir.GetASTProgram(); const ASTNode program = context_func->GetASTProgram();
ASTDecompiler decompiler{*this}; ASTDecompiler decompiler{*this};
decompiler.Visit(program); decompiler.Visit(program);

View File

@ -7,6 +7,7 @@
#include <set> #include <set>
#include <stack> #include <stack>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <vector> #include <vector>
#include "common/assert.h" #include "common/assert.h"
@ -26,17 +27,29 @@ using Tegra::Shader::OpCode;
constexpr s32 unassigned_branch = -2; constexpr s32 unassigned_branch = -2;
enum class JumpLabel : u32 {
SSYClass = 0,
PBKClass = 1,
};
struct JumpItem {
JumpLabel type;
u32 address;
bool operator==(const JumpItem& other) const {
return std::tie(type, address) == std::tie(other.type, other.address);
}
};
struct Query { struct Query {
u32 address{}; u32 address{};
std::stack<u32> ssy_stack{}; std::stack<JumpItem> stack{};
std::stack<u32> pbk_stack{};
}; };
struct BlockStack { struct BlockStack {
BlockStack() = default; BlockStack() = default;
explicit BlockStack(const Query& q) : ssy_stack{q.ssy_stack}, pbk_stack{q.pbk_stack} {} explicit BlockStack(const Query& q) : stack{q.stack} {}
std::stack<u32> ssy_stack{}; std::stack<JumpItem> stack{};
std::stack<u32> pbk_stack{};
}; };
template <typename T, typename... Args> template <typename T, typename... Args>
@ -65,20 +78,36 @@ struct BlockInfo {
} }
}; };
struct CFGRebuildState { struct ProgramControl {
explicit CFGRebuildState(const ProgramCode& program_code_, u32 start_, Registry& registry_) std::unordered_set<u32> found_functions{};
: program_code{program_code_}, registry{registry_}, start{start_} {} std::list<u32> pending_functions{};
void RegisterFunction(u32 address) {
if (found_functions.count(address) != 0) {
return;
}
found_functions.insert(address);
pending_functions.emplace_back(address);
}
};
struct CFGRebuildState {
explicit CFGRebuildState(ProgramControl& control_, const ProgramCode& program_code_, u32 start_,
u32 base_start_, Registry& registry_)
: control{control_}, program_code{program_code_}, registry{registry_}, start{start_},
base_start{base_start_} {}
ProgramControl& control;
const ProgramCode& program_code; const ProgramCode& program_code;
Registry& registry; Registry& registry;
u32 start{}; u32 start{};
u32 base_start{};
std::vector<BlockInfo> block_info; std::vector<BlockInfo> block_info;
std::list<u32> inspect_queries; std::list<u32> inspect_queries;
std::list<Query> queries; std::list<Query> queries;
std::unordered_map<u32, u32> registered; std::unordered_map<u32, u32> registered;
std::set<u32> labels; std::set<u32> labels;
std::map<u32, u32> ssy_labels; std::map<u32, JumpItem> jump_labels;
std::map<u32, u32> pbk_labels;
std::unordered_map<u32, BlockStack> stacks; std::unordered_map<u32, BlockStack> stacks;
ASTManager* manager{}; ASTManager* manager{};
}; };
@ -153,7 +182,7 @@ template <typename Result, typename TestCallable, typename PackCallable>
std::optional<Result> TrackInstruction(const CFGRebuildState& state, u32& pos, TestCallable test, std::optional<Result> TrackInstruction(const CFGRebuildState& state, u32& pos, TestCallable test,
PackCallable pack) { PackCallable pack) {
for (; pos >= state.start; --pos) { for (; pos >= state.start; --pos) {
if (IsSchedInstruction(pos, state.start)) { if (IsSchedInstruction(pos, state.base_start)) {
continue; continue;
} }
const Instruction instr = state.program_code[pos]; const Instruction instr = state.program_code[pos];
@ -262,7 +291,7 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
single_branch.ignore = true; single_branch.ignore = true;
break; break;
} }
if (IsSchedInstruction(offset, state.start)) { if (IsSchedInstruction(offset, state.base_start)) {
offset++; offset++;
continue; continue;
} }
@ -274,6 +303,7 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
} }
switch (opcode->get().GetId()) { switch (opcode->get().GetId()) {
case OpCode::Id::RET:
case OpCode::Id::EXIT: { case OpCode::Id::EXIT: {
const auto pred_index = static_cast<u32>(instr.pred.pred_index); const auto pred_index = static_cast<u32>(instr.pred.pred_index);
single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0); single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
@ -411,13 +441,20 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
case OpCode::Id::SSY: { case OpCode::Id::SSY: {
const u32 target = offset + instr.bra.GetBranchTarget(); const u32 target = offset + instr.bra.GetBranchTarget();
insert_label(state, target); insert_label(state, target);
state.ssy_labels.emplace(offset, target); JumpItem it = {JumpLabel::SSYClass, target};
state.jump_labels.emplace(offset, it);
break; break;
} }
case OpCode::Id::PBK: { case OpCode::Id::PBK: {
const u32 target = offset + instr.bra.GetBranchTarget(); const u32 target = offset + instr.bra.GetBranchTarget();
insert_label(state, target); insert_label(state, target);
state.pbk_labels.emplace(offset, target); JumpItem it = {JumpLabel::PBKClass, target};
state.jump_labels.emplace(offset, it);
break;
}
case OpCode::Id::CAL: {
const u32 target = offset + instr.bra.GetBranchTarget();
state.control.RegisterFunction(target);
break; break;
} }
case OpCode::Id::BRX: { case OpCode::Id::BRX: {
@ -513,7 +550,7 @@ bool TryInspectAddress(CFGRebuildState& state) {
} }
bool TryQuery(CFGRebuildState& state) { bool TryQuery(CFGRebuildState& state) {
const auto gather_labels = [](std::stack<u32>& cc, std::map<u32, u32>& labels, const auto gather_labels = [](std::stack<JumpItem>& cc, std::map<u32, JumpItem>& labels,
BlockInfo& block) { BlockInfo& block) {
auto gather_start = labels.lower_bound(block.start); auto gather_start = labels.lower_bound(block.start);
const auto gather_end = labels.upper_bound(block.end); const auto gather_end = labels.upper_bound(block.end);
@ -522,6 +559,19 @@ bool TryQuery(CFGRebuildState& state) {
++gather_start; ++gather_start;
} }
}; };
const auto pop_labels = [](JumpLabel type, SingleBranch* branch, Query& query) -> bool {
while (!query.stack.empty() && query.stack.top().type != type) {
query.stack.pop();
}
if (query.stack.empty()) {
return false;
}
if (branch->address == unassigned_branch) {
branch->address = query.stack.top().address;
}
query.stack.pop();
return true;
};
if (state.queries.empty()) { if (state.queries.empty()) {
return false; return false;
} }
@ -534,8 +584,7 @@ bool TryQuery(CFGRebuildState& state) {
// consumes a label. Schedule new queries accordingly // consumes a label. Schedule new queries accordingly
if (block.visited) { if (block.visited) {
BlockStack& stack = state.stacks[q.address]; BlockStack& stack = state.stacks[q.address];
const bool all_okay = (stack.ssy_stack.empty() || q.ssy_stack == stack.ssy_stack) && const bool all_okay = (stack.stack.empty() || q.stack == stack.stack);
(stack.pbk_stack.empty() || q.pbk_stack == stack.pbk_stack);
state.queries.pop_front(); state.queries.pop_front();
return all_okay; return all_okay;
} }
@ -544,8 +593,7 @@ bool TryQuery(CFGRebuildState& state) {
Query q2(q); Query q2(q);
state.queries.pop_front(); state.queries.pop_front();
gather_labels(q2.ssy_stack, state.ssy_labels, block); gather_labels(q2.stack, state.jump_labels, block);
gather_labels(q2.pbk_stack, state.pbk_labels, block);
if (std::holds_alternative<SingleBranch>(*block.branch)) { if (std::holds_alternative<SingleBranch>(*block.branch)) {
auto* branch = std::get_if<SingleBranch>(block.branch.get()); auto* branch = std::get_if<SingleBranch>(block.branch.get());
if (!branch->condition.IsUnconditional()) { if (!branch->condition.IsUnconditional()) {
@ -555,16 +603,10 @@ bool TryQuery(CFGRebuildState& state) {
auto& conditional_query = state.queries.emplace_back(q2); auto& conditional_query = state.queries.emplace_back(q2);
if (branch->is_sync) { if (branch->is_sync) {
if (branch->address == unassigned_branch) { pop_labels(JumpLabel::SSYClass, branch, conditional_query);
branch->address = conditional_query.ssy_stack.top();
}
conditional_query.ssy_stack.pop();
} }
if (branch->is_brk) { if (branch->is_brk) {
if (branch->address == unassigned_branch) { pop_labels(JumpLabel::PBKClass, branch, conditional_query);
branch->address = conditional_query.pbk_stack.top();
}
conditional_query.pbk_stack.pop();
} }
conditional_query.address = branch->address; conditional_query.address = branch->address;
return true; return true;
@ -646,25 +688,23 @@ void DecompileShader(CFGRebuildState& state) {
state.manager->Decompile(); state.manager->Decompile();
} }
} // Anonymous namespace ShaderFunction ScanFunction(ProgramControl& control, const ProgramCode& program_code,
u32 start_address, u32 base_start, const CompilerSettings& settings,
std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 start_address, Registry& registry) {
const CompilerSettings& settings, ShaderFunction result_out{};
Registry& registry) {
auto result_out = std::make_unique<ShaderCharacteristics>();
if (settings.depth == CompileDepth::BruteForce) { if (settings.depth == CompileDepth::BruteForce) {
result_out->settings.depth = CompileDepth::BruteForce; result_out.settings.depth = CompileDepth::BruteForce;
return result_out; return result_out;
} }
CFGRebuildState state{program_code, start_address, registry}; CFGRebuildState state{control, program_code, start_address, base_start, registry};
// Inspect Code and generate blocks // Inspect Code and generate blocks
state.labels.clear(); state.labels.clear();
state.labels.emplace(start_address); state.labels.emplace(start_address);
state.inspect_queries.push_back(state.start); state.inspect_queries.push_back(state.start);
while (!state.inspect_queries.empty()) { while (!state.inspect_queries.empty()) {
if (!TryInspectAddress(state)) { if (!TryInspectAddress(state)) {
result_out->settings.depth = CompileDepth::BruteForce; result_out.settings.depth = CompileDepth::BruteForce;
return result_out; return result_out;
} }
} }
@ -675,7 +715,7 @@ std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
if (settings.depth != CompileDepth::FlowStack) { if (settings.depth != CompileDepth::FlowStack) {
// Decompile Stacks // Decompile Stacks
state.queries.push_back(Query{state.start, {}, {}}); state.queries.push_back(Query{state.start, {}});
decompiled = true; decompiled = true;
while (!state.queries.empty()) { while (!state.queries.empty()) {
if (!TryQuery(state)) { if (!TryQuery(state)) {
@ -705,19 +745,18 @@ std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
state.manager->ShowCurrentState("Of Shader"); state.manager->ShowCurrentState("Of Shader");
state.manager->Clear(); state.manager->Clear();
} else { } else {
auto characteristics = std::make_unique<ShaderCharacteristics>(); result_out.start = start_address;
characteristics->start = start_address; result_out.settings.depth = settings.depth;
characteristics->settings.depth = settings.depth; result_out.manager = std::move(manager);
characteristics->manager = std::move(manager); result_out.end = state.block_info.back().end + 1;
characteristics->end = state.block_info.back().end + 1; return result_out;
return characteristics;
} }
} }
result_out->start = start_address; result_out.start = start_address;
result_out->settings.depth = result_out.settings.depth =
use_flow_stack ? CompileDepth::FlowStack : CompileDepth::NoFlowStack; use_flow_stack ? CompileDepth::FlowStack : CompileDepth::NoFlowStack;
result_out->blocks.clear(); result_out.blocks.clear();
for (auto& block : state.block_info) { for (auto& block : state.block_info) {
ShaderBlock new_block{}; ShaderBlock new_block{};
new_block.start = block.start; new_block.start = block.start;
@ -726,20 +765,20 @@ std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
if (!new_block.ignore_branch) { if (!new_block.ignore_branch) {
new_block.branch = block.branch; new_block.branch = block.branch;
} }
result_out->end = std::max(result_out->end, block.end); result_out.end = std::max(result_out.end, block.end);
result_out->blocks.push_back(new_block); result_out.blocks.push_back(new_block);
} }
if (!use_flow_stack) { if (!use_flow_stack) {
result_out->labels = std::move(state.labels); result_out.labels = std::move(state.labels);
return result_out; return result_out;
} }
auto back = result_out->blocks.begin(); auto back = result_out.blocks.begin();
auto next = std::next(back); auto next = std::next(back);
while (next != result_out->blocks.end()) { while (next != result_out.blocks.end()) {
if (!state.labels.contains(next->start) && next->start == back->end + 1) { if (!state.labels.contains(next->start) && next->start == back->end + 1) {
back->end = next->end; back->end = next->end;
next = result_out->blocks.erase(next); next = result_out.blocks.erase(next);
continue; continue;
} }
back = next; back = next;
@ -748,4 +787,22 @@ std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
return result_out; return result_out;
} }
} // Anonymous namespace
std::unique_ptr<ShaderProgram> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings, Registry& registry) {
ProgramControl control{};
auto result_out = std::make_unique<ShaderProgram>();
result_out->main =
ScanFunction(control, program_code, start_address, start_address, settings, registry);
while (!control.pending_functions.empty()) {
u32 address = control.pending_functions.front();
auto fun = ScanFunction(control, program_code, address, start_address, settings, registry);
result_out->subfunctions.emplace(address, std::move(fun));
control.pending_functions.pop_front();
}
return result_out;
}
} // namespace VideoCommon::Shader } // namespace VideoCommon::Shader

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <list> #include <list>
#include <map>
#include <optional> #include <optional>
#include <set> #include <set>
#include <variant> #include <variant>
@ -101,7 +102,7 @@ struct ShaderBlock {
} }
}; };
struct ShaderCharacteristics { struct ShaderFunction {
std::list<ShaderBlock> blocks{}; std::list<ShaderBlock> blocks{};
std::set<u32> labels{}; std::set<u32> labels{};
u32 start{}; u32 start{};
@ -110,8 +111,12 @@ struct ShaderCharacteristics {
CompilerSettings settings{}; CompilerSettings settings{};
}; };
std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 start_address, struct ShaderProgram {
const CompilerSettings& settings, ShaderFunction main;
Registry& registry); std::map<u32, ShaderFunction> subfunctions;
};
std::unique_ptr<ShaderProgram> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings, Registry& registry);
} // namespace VideoCommon::Shader } // namespace VideoCommon::Shader

View File

@ -64,9 +64,52 @@ std::optional<u32> TryDeduceSamplerSize(const SamplerEntry& sampler_to_deduce,
} // Anonymous namespace } // Anonymous namespace
class ExprDecoder {
public:
explicit ExprDecoder(ShaderIR& ir_) : ir(ir_) {}
void operator()(const ExprAnd& expr) {
Visit(expr.operand1);
Visit(expr.operand2);
}
void operator()(const ExprOr& expr) {
Visit(expr.operand1);
Visit(expr.operand2);
}
void operator()(const ExprNot& expr) {
Visit(expr.operand1);
}
void operator()(const ExprPredicate& expr) {
const auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate);
if (pred != Pred::UnusedIndex && pred != Pred::NeverExecute) {
ir.used_predicates.insert(pred);
}
}
void operator()(const ExprCondCode& expr) {}
void operator()(const ExprVar& expr) {}
void operator()(const ExprBoolean& expr) {}
void operator()(const ExprGprEqual& expr) {
ir.used_registers.insert(expr.gpr);
}
void Visit(const Expr& node) {
return std::visit(*this, *node);
}
private:
ShaderIR& ir;
};
class ASTDecoder { class ASTDecoder {
public: public:
explicit ASTDecoder(ShaderIR& ir_) : ir(ir_) {} explicit ASTDecoder(ShaderIR& ir_) : ir(ir_), decoder(ir_) {}
void operator()(ASTProgram& ast) { void operator()(ASTProgram& ast) {
ASTNode current = ast.nodes.GetFirst(); ASTNode current = ast.nodes.GetFirst();
@ -77,6 +120,7 @@ public:
} }
void operator()(ASTIfThen& ast) { void operator()(ASTIfThen& ast) {
decoder.Visit(ast.condition);
ASTNode current = ast.nodes.GetFirst(); ASTNode current = ast.nodes.GetFirst();
while (current) { while (current) {
Visit(current); Visit(current);
@ -96,13 +140,18 @@ public:
void operator()(ASTBlockDecoded& ast) {} void operator()(ASTBlockDecoded& ast) {}
void operator()(ASTVarSet& ast) {} void operator()(ASTVarSet& ast) {
decoder.Visit(ast.condition);
}
void operator()(ASTLabel& ast) {} void operator()(ASTLabel& ast) {}
void operator()(ASTGoto& ast) {} void operator()(ASTGoto& ast) {
decoder.Visit(ast.condition);
}
void operator()(ASTDoWhile& ast) { void operator()(ASTDoWhile& ast) {
decoder.Visit(ast.condition);
ASTNode current = ast.nodes.GetFirst(); ASTNode current = ast.nodes.GetFirst();
while (current) { while (current) {
Visit(current); Visit(current);
@ -110,9 +159,13 @@ public:
} }
} }
void operator()(ASTReturn& ast) {} void operator()(ASTReturn& ast) {
decoder.Visit(ast.condition);
}
void operator()(ASTBreak& ast) {} void operator()(ASTBreak& ast) {
decoder.Visit(ast.condition);
}
void Visit(ASTNode& node) { void Visit(ASTNode& node) {
std::visit(*this, *node->GetInnerData()); std::visit(*this, *node->GetInnerData());
@ -125,77 +178,113 @@ public:
private: private:
ShaderIR& ir; ShaderIR& ir;
ExprDecoder decoder;
}; };
void ShaderIR::Decode() { void ShaderIR::Decode() {
const auto decode_function = ([this](ShaderFunction& shader_info) {
coverage_end = std::max<u32>(0, shader_info.end);
switch (shader_info.settings.depth) {
case CompileDepth::FlowStack: {
for (const auto& block : shader_info.blocks) {
basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)});
}
break;
}
case CompileDepth::NoFlowStack: {
disable_flow_stack = true;
const auto insert_block = [this](NodeBlock& nodes, u32 label) {
if (label == static_cast<u32>(exit_branch)) {
return;
}
basic_blocks.insert({label, nodes});
};
const auto& blocks = shader_info.blocks;
NodeBlock current_block;
u32 current_label = static_cast<u32>(exit_branch);
for (const auto& block : blocks) {
if (shader_info.labels.contains(block.start)) {
insert_block(current_block, current_label);
current_block.clear();
current_label = block.start;
}
if (!block.ignore_branch) {
DecodeRangeInner(current_block, block.start, block.end);
InsertControlFlow(current_block, block);
} else {
DecodeRangeInner(current_block, block.start, block.end + 1);
}
}
insert_block(current_block, current_label);
break;
}
case CompileDepth::DecompileBackwards:
case CompileDepth::FullDecompile: {
program_manager = std::move(shader_info.manager);
disable_flow_stack = true;
decompiled = true;
ASTDecoder decoder{*this};
ASTNode program = program_manager.GetProgram();
decoder.Visit(program);
break;
}
default:
LOG_CRITICAL(HW_GPU, "Unknown decompilation mode!");
[[fallthrough]];
case CompileDepth::BruteForce: {
const auto shader_end = static_cast<u32>(program_code.size());
coverage_begin = main_offset;
coverage_end = shader_end;
for (u32 label = main_offset; label < shader_end; ++label) {
basic_blocks.insert({label, DecodeRange(label, label + 1)});
}
break;
}
}
if (settings.depth != shader_info.settings.depth) {
LOG_WARNING(
HW_GPU,
"Decompiling to this setting \"{}\" failed, downgrading to this setting \"{}\"",
CompileDepthAsString(settings.depth),
CompileDepthAsString(shader_info.settings.depth));
}
});
const auto gen_function =
([this](ShaderFunction& shader_info, u32 id) -> std::shared_ptr<ShaderFunctionIR> {
std::shared_ptr<ShaderFunctionIR> result;
if (decompiled) {
result = std::make_shared<ShaderFunctionIR>(std::move(program_manager), id,
shader_info.start, shader_info.end);
} else {
result =
std::make_shared<ShaderFunctionIR>(std::move(basic_blocks), disable_flow_stack,
id, shader_info.start, shader_info.end);
}
decompiled = false;
disable_flow_stack = false;
basic_blocks.clear();
program_manager.Clear();
return result;
});
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
decompiled = false; decompiled = false;
auto info = ScanFlow(program_code, main_offset, settings, registry); auto info = ScanFlow(program_code, main_offset, settings, registry);
auto& shader_info = *info; u32 id_start = 1;
coverage_begin = shader_info.start; for (auto& pair : info->subfunctions) {
coverage_end = shader_info.end; func_map.emplace(pair.first, id_start);
switch (shader_info.settings.depth) { id_start++;
case CompileDepth::FlowStack: {
for (const auto& block : shader_info.blocks) {
basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)});
}
break;
} }
case CompileDepth::NoFlowStack: { coverage_begin = info->main.start;
disable_flow_stack = true; coverage_end = 0;
const auto insert_block = [this](NodeBlock& nodes, u32 label) { decode_function(info->main);
if (label == static_cast<u32>(exit_branch)) { main_function = gen_function(info->main, 0);
return; subfunctions.resize(info->subfunctions.size());
} for (auto& pair : info->subfunctions) {
basic_blocks.insert({label, nodes}); auto& func_info = pair.second;
}; decode_function(func_info);
const auto& blocks = shader_info.blocks; u32 id = func_map[pair.first];
NodeBlock current_block; subfunctions[id - 1] = gen_function(func_info, id);
u32 current_label = static_cast<u32>(exit_branch);
for (const auto& block : blocks) {
if (shader_info.labels.contains(block.start)) {
insert_block(current_block, current_label);
current_block.clear();
current_label = block.start;
}
if (!block.ignore_branch) {
DecodeRangeInner(current_block, block.start, block.end);
InsertControlFlow(current_block, block);
} else {
DecodeRangeInner(current_block, block.start, block.end + 1);
}
}
insert_block(current_block, current_label);
break;
}
case CompileDepth::DecompileBackwards:
case CompileDepth::FullDecompile: {
program_manager = std::move(shader_info.manager);
disable_flow_stack = true;
decompiled = true;
ASTDecoder decoder{*this};
ASTNode program = GetASTProgram();
decoder.Visit(program);
break;
}
default:
LOG_CRITICAL(HW_GPU, "Unknown decompilation mode!");
[[fallthrough]];
case CompileDepth::BruteForce: {
const auto shader_end = static_cast<u32>(program_code.size());
coverage_begin = main_offset;
coverage_end = shader_end;
for (u32 label = main_offset; label < shader_end; ++label) {
basic_blocks.insert({label, DecodeRange(label, label + 1)});
}
break;
}
}
if (settings.depth != shader_info.settings.depth) {
LOG_WARNING(
HW_GPU, "Decompiling to this setting \"{}\" failed, downgrading to this setting \"{}\"",
CompileDepthAsString(settings.depth), CompileDepthAsString(shader_info.settings.depth));
} }
} }

View File

@ -33,6 +33,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
// With the previous preconditions, this instruction is a no-operation. // With the previous preconditions, this instruction is a no-operation.
break; break;
} }
case OpCode::Id::RET:
case OpCode::Id::EXIT: { case OpCode::Id::EXIT: {
const ConditionCode cc = instr.flow_condition_code; const ConditionCode cc = instr.flow_condition_code;
UNIMPLEMENTED_IF_MSG(cc != ConditionCode::T, "EXIT condition code used: {}", cc); UNIMPLEMENTED_IF_MSG(cc != ConditionCode::T, "EXIT condition code used: {}", cc);
@ -312,6 +313,16 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
LOG_DEBUG(HW_GPU, "DEPBAR instruction is stubbed"); LOG_DEBUG(HW_GPU, "DEPBAR instruction is stubbed");
break; break;
} }
case OpCode::Id::CAL: {
const u32 target = pc + instr.bra.GetBranchTarget();
const auto it = func_map.find(target);
if (it == func_map.end()) {
UNREACHABLE();
break;
}
bb.push_back(FunctionCall(it->second));
break;
}
default: default:
UNIMPLEMENTED_MSG("Unhandled instruction: {}", opcode->get().GetName()); UNIMPLEMENTED_MSG("Unhandled instruction: {}", opcode->get().GetName());
} }

View File

@ -339,8 +339,6 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
const TextureType texture_type{instr.tlds.GetTextureType()}; const TextureType texture_type{instr.tlds.GetTextureType()};
const bool is_array{instr.tlds.IsArrayTexture()}; const bool is_array{instr.tlds.IsArrayTexture()};
UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(TextureMiscMode::AOFFI),
"AOFFI is not implemented");
UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(TextureMiscMode::MZ), "MZ is not implemented"); UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(TextureMiscMode::MZ), "MZ is not implemented");
const Node4 components = GetTldsCode(instr, texture_type, is_array); const Node4 components = GetTldsCode(instr, texture_type, is_array);
@ -822,7 +820,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
for (std::size_t i = 0; i < type_coord_count; ++i) { for (std::size_t i = 0; i < type_coord_count; ++i) {
const bool last = (i == (type_coord_count - 1)) && (type_coord_count > 1); const bool last = (i == (type_coord_count - 1)) && (type_coord_count > 1);
coords.push_back( coords.push_back(
GetRegister(last && !aoffi_enabled ? last_coord_register : coord_register + i)); GetRegister(last && !aoffi_enabled ? last_coord_register : (coord_register + i)));
} }
const Node array = is_array ? GetRegister(array_register) : nullptr; const Node array = is_array ? GetRegister(array_register) : nullptr;

View File

@ -267,10 +267,11 @@ class PatchNode;
class SmemNode; class SmemNode;
class GmemNode; class GmemNode;
class CommentNode; class CommentNode;
class FunctionCallNode;
using NodeData = std::variant<OperationNode, ConditionalNode, GprNode, CustomVarNode, ImmediateNode, using NodeData = std::variant<OperationNode, ConditionalNode, GprNode, CustomVarNode, ImmediateNode,
InternalFlagNode, PredicateNode, AbufNode, PatchNode, CbufNode, InternalFlagNode, PredicateNode, AbufNode, PatchNode, CbufNode,
LmemNode, SmemNode, GmemNode, CommentNode>; LmemNode, SmemNode, GmemNode, FunctionCallNode, CommentNode>;
using Node = std::shared_ptr<NodeData>; using Node = std::shared_ptr<NodeData>;
using Node4 = std::array<Node, 4>; using Node4 = std::array<Node, 4>;
using NodeBlock = std::vector<Node>; using NodeBlock = std::vector<Node>;
@ -494,6 +495,18 @@ private:
std::vector<Node> code; ///< Code to execute std::vector<Node> code; ///< Code to execute
}; };
class FunctionCallNode final : public AmendNode {
public:
explicit FunctionCallNode(u32 func_id_) : func_id{func_id_} {}
[[nodiscard]] u32 GetFuncId() const {
return func_id;
}
private:
u32 func_id; ///< Id of the function to call
};
/// A general purpose register /// A general purpose register
class GprNode final { class GprNode final {
public: public:

View File

@ -19,6 +19,11 @@ Node Comment(std::string text) {
return MakeNode<CommentNode>(std::move(text)); return MakeNode<CommentNode>(std::move(text));
} }
/// Creates a function call
Node FunctionCall(u32 func_id) {
return MakeNode<FunctionCallNode>(func_id);
}
Node Immediate(u32 value) { Node Immediate(u32 value) {
return MakeNode<ImmediateNode>(value); return MakeNode<ImmediateNode>(value);
} }

View File

@ -27,6 +27,9 @@ Node Conditional(Node condition, std::vector<Node> code);
/// Creates a commentary node /// Creates a commentary node
Node Comment(std::string text); Node Comment(std::string text);
/// Creates a function call
Node FunctionCall(u32 func_id);
/// Creates an u32 immediate /// Creates an u32 immediate
Node Immediate(u32 value); Node Immediate(u32 value);

View File

@ -26,7 +26,7 @@ namespace VideoCommon::Shader {
struct ShaderBlock; struct ShaderBlock;
constexpr u32 MAX_PROGRAM_LENGTH = 0x1000; constexpr u32 MAX_PROGRAM_LENGTH = 0x2000;
struct ConstBuffer { struct ConstBuffer {
constexpr explicit ConstBuffer(u32 max_offset_, bool is_indirect_) constexpr explicit ConstBuffer(u32 max_offset_, bool is_indirect_)
@ -64,16 +64,68 @@ struct GlobalMemoryUsage {
bool is_written{}; bool is_written{};
}; };
class ShaderFunctionIR final {
public:
explicit ShaderFunctionIR(std::map<u32, NodeBlock>&& basic_blocks_, bool disable_flow_stack_,
u32 id_, u32 coverage_begin_, u32 coverage_end_)
: basic_blocks{std::move(basic_blocks_)}, decompiled{false},
disable_flow_stack{disable_flow_stack_}, id{id_}, coverage_begin{coverage_begin_},
coverage_end{coverage_end_} {}
explicit ShaderFunctionIR(ASTManager&& program_manager_, u32 id_, u32 coverage_begin_,
u32 coverage_end_)
: program_manager{std::move(program_manager_)}, decompiled{true}, disable_flow_stack{true},
id{id_}, coverage_begin{coverage_begin_}, coverage_end{coverage_end_} {}
const std::map<u32, NodeBlock>& GetBasicBlocks() const {
return basic_blocks;
}
[[nodiscard]] bool IsFlowStackDisabled() const {
return disable_flow_stack;
}
[[nodiscard]] bool IsDecompiled() const {
return decompiled;
}
const ASTManager& GetASTManager() const {
return program_manager;
}
[[nodiscard]] ASTNode GetASTProgram() const {
return program_manager.GetProgram();
}
[[nodiscard]] u32 GetASTNumVariables() const {
return program_manager.GetVariables();
}
[[nodiscard]] bool IsMain() const {
return id == 0;
}
[[nodiscard]] u32 GetId() const {
return id;
}
private:
std::map<u32, NodeBlock> basic_blocks;
ASTManager program_manager{true, true};
bool decompiled{};
bool disable_flow_stack{};
u32 id{};
u32 coverage_begin{};
u32 coverage_end{};
};
class ShaderIR final { class ShaderIR final {
public: public:
explicit ShaderIR(const ProgramCode& program_code_, u32 main_offset_, explicit ShaderIR(const ProgramCode& program_code_, u32 main_offset_,
CompilerSettings settings_, Registry& registry_); CompilerSettings settings_, Registry& registry_);
~ShaderIR(); ~ShaderIR();
const std::map<u32, NodeBlock>& GetBasicBlocks() const {
return basic_blocks;
}
const std::set<u32>& GetRegisters() const { const std::set<u32>& GetRegisters() const {
return used_registers; return used_registers;
} }
@ -155,26 +207,6 @@ public:
return header; return header;
} }
bool IsFlowStackDisabled() const {
return disable_flow_stack;
}
bool IsDecompiled() const {
return decompiled;
}
const ASTManager& GetASTManager() const {
return program_manager;
}
ASTNode GetASTProgram() const {
return program_manager.GetProgram();
}
u32 GetASTNumVariables() const {
return program_manager.GetVariables();
}
u32 ConvertAddressToNvidiaSpace(u32 address) const { u32 ConvertAddressToNvidiaSpace(u32 address) const {
return (address - main_offset) * static_cast<u32>(sizeof(Tegra::Shader::Instruction)); return (address - main_offset) * static_cast<u32>(sizeof(Tegra::Shader::Instruction));
} }
@ -190,7 +222,16 @@ public:
return num_custom_variables; return num_custom_variables;
} }
std::shared_ptr<ShaderFunctionIR> GetMainFunction() const {
return main_function;
}
const std::vector<std::shared_ptr<ShaderFunctionIR>>& GetSubFunctions() const {
return subfunctions;
}
private: private:
friend class ExprDecoder;
friend class ASTDecoder; friend class ASTDecoder;
struct SamplerInfo { struct SamplerInfo {
@ -453,6 +494,10 @@ private:
std::vector<Node> amend_code; std::vector<Node> amend_code;
u32 num_custom_variables{}; u32 num_custom_variables{};
std::shared_ptr<ShaderFunctionIR> main_function;
std::vector<std::shared_ptr<ShaderFunctionIR>> subfunctions;
std::unordered_map<u32, u32> func_map;
std::set<u32> used_registers; std::set<u32> used_registers;
std::set<Tegra::Shader::Pred> used_predicates; std::set<Tegra::Shader::Pred> used_predicates;
std::set<Tegra::Shader::Attribute::Index> used_input_attributes; std::set<Tegra::Shader::Attribute::Index> used_input_attributes;

View File

@ -18,6 +18,7 @@ add_executable(yuzu
applets/profile_select.h applets/profile_select.h
applets/software_keyboard.cpp applets/software_keyboard.cpp
applets/software_keyboard.h applets/software_keyboard.h
applets/software_keyboard.ui
applets/web_browser.cpp applets/web_browser.cpp
applets/web_browser.h applets/web_browser.h
bootmanager.cpp bootmanager.cpp
@ -143,6 +144,9 @@ add_executable(yuzu
uisettings.h uisettings.h
util/limitable_input_dialog.cpp util/limitable_input_dialog.cpp
util/limitable_input_dialog.h util/limitable_input_dialog.h
util/overlay_dialog.cpp
util/overlay_dialog.h
util/overlay_dialog.ui
util/sequence_dialog/sequence_dialog.cpp util/sequence_dialog/sequence_dialog.cpp
util/sequence_dialog/sequence_dialog.h util/sequence_dialog/sequence_dialog.h
util/url_request_interceptor.cpp util/url_request_interceptor.cpp

View File

@ -19,11 +19,11 @@ QtErrorDisplay::~QtErrorDisplay() = default;
void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const { void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished) const {
callback = std::move(finished); callback = std::move(finished);
emit MainWindowDisplayError( emit MainWindowDisplayError(
tr("An error has occurred.\nPlease try again or contact the developer of the " tr("Error Code: %1-%2 (0x%3)")
"software.\n\nError Code: %1-%2 (0x%3)")
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0')) .arg(error.description, 4, 10, QChar::fromLatin1('0'))
.arg(error.raw, 8, 16, QChar::fromLatin1('0'))); .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
tr("An error has occurred.\nPlease try again or contact the developer of the software."));
} }
void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time, void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
@ -32,13 +32,14 @@ void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::secon
const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count()); const QDateTime date_time = QDateTime::fromSecsSinceEpoch(time.count());
emit MainWindowDisplayError( emit MainWindowDisplayError(
tr("An error occurred on %1 at %2.\nPlease try again or contact the " tr("Error Code: %1-%2 (0x%3)")
"developer of the software.\n\nError Code: %3-%4 (0x%5)")
.arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy")))
.arg(date_time.toString(QStringLiteral("h:mm:ss A")))
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0')) .arg(error.description, 4, 10, QChar::fromLatin1('0'))
.arg(error.raw, 8, 16, QChar::fromLatin1('0'))); .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
tr("An error occurred on %1 at %2.\nPlease try again or contact the developer of the "
"software.")
.arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy")))
.arg(date_time.toString(QStringLiteral("h:mm:ss A"))));
} }
void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text, void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_text,
@ -46,10 +47,11 @@ void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_te
std::function<void()> finished) const { std::function<void()> finished) const {
callback = std::move(finished); callback = std::move(finished);
emit MainWindowDisplayError( emit MainWindowDisplayError(
tr("An error has occurred.\nError Code: %1-%2 (0x%3)\n\n%4\n\n%5") tr("Error Code: %1-%2 (0x%3)")
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0')) .arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0')) .arg(error.description, 4, 10, QChar::fromLatin1('0'))
.arg(error.raw, 8, 16, QChar::fromLatin1('0')) .arg(error.raw, 8, 16, QChar::fromLatin1('0')),
tr("An error has occurred.\n\n%1\n\n%2")
.arg(QString::fromStdString(dialog_text)) .arg(QString::fromStdString(dialog_text))
.arg(QString::fromStdString(fullscreen_text))); .arg(QString::fromStdString(fullscreen_text)));
} }

View File

@ -24,7 +24,7 @@ public:
std::function<void()> finished) const override; std::function<void()> finished) const override;
signals: signals:
void MainWindowDisplayError(QString error) const; void MainWindowDisplayError(QString error_code, QString error_text) const;
private: private:
void MainWindowFinishedError(); void MainWindowFinishedError();

File diff suppressed because it is too large Load Diff

View File

@ -1,54 +1,228 @@
// Copyright 2018 yuzu Emulator Project // Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#pragma once #pragma once
#include <array>
#include <atomic>
#include <memory>
#include <thread>
#include <QDialog> #include <QDialog>
#include <QValidator> #include <QValidator>
#include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/software_keyboard.h"
enum class HIDButton : u8;
class InputInterpreter;
namespace Core {
class System;
}
namespace Ui {
class QtSoftwareKeyboardDialog;
}
class GMainWindow; class GMainWindow;
class QDialogButtonBox;
class QLabel;
class QLineEdit;
class QVBoxLayout;
class QtSoftwareKeyboard;
class QtSoftwareKeyboardValidator final : public QValidator {
public:
explicit QtSoftwareKeyboardValidator(Core::Frontend::SoftwareKeyboardParameters parameters);
State validate(QString& input, int& pos) const override;
private:
Core::Frontend::SoftwareKeyboardParameters parameters;
};
class QtSoftwareKeyboardDialog final : public QDialog { class QtSoftwareKeyboardDialog final : public QDialog {
Q_OBJECT Q_OBJECT
public: public:
QtSoftwareKeyboardDialog(QWidget* parent, QtSoftwareKeyboardDialog(QWidget* parent, Core::System& system_, bool is_inline_,
Core::Frontend::SoftwareKeyboardParameters parameters); Core::Frontend::KeyboardInitializeParameters initialize_parameters_);
~QtSoftwareKeyboardDialog() override; ~QtSoftwareKeyboardDialog() override;
void accept() override; void ShowNormalKeyboard(QPoint pos, QSize size);
void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message);
void ShowInlineKeyboard(Core::Frontend::InlineAppearParameters appear_parameters, QPoint pos,
QSize size);
void HideInlineKeyboard();
void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters);
void ExitKeyboard();
signals:
void SubmitNormalText(Service::AM::Applets::SwkbdResult result,
std::u16string submitted_text) const;
void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
std::u16string submitted_text, s32 cursor_position) const;
public slots:
void open() override;
void reject() override; void reject() override;
std::u16string GetText() const; protected:
/// We override the keyPressEvent for inputting text into the inline software keyboard.
void keyPressEvent(QKeyEvent* event) override;
private: private:
std::u16string text; enum class Direction {
Left,
Up,
Right,
Down,
};
QDialogButtonBox* buttons; enum class BottomOSKIndex {
QLabel* header_label; LowerCase,
QLabel* sub_label; UpperCase,
QLabel* guide_label; NumberPad,
QLabel* length_label; };
QLineEdit* line_edit;
QVBoxLayout* layout;
Core::Frontend::SoftwareKeyboardParameters parameters; /**
* Moves and resizes the window to a specified position and size.
*
* @param pos Top-left window position
* @param size Window size
*/
void MoveAndResizeWindow(QPoint pos, QSize size);
/**
* Rescales all keyboard elements to account for High DPI displays.
*
* @param width Window width
* @param height Window height
* @param dpi_scale Display scaling factor
*/
void RescaleKeyboardElements(float width, float height, float dpi_scale);
/// Sets the keyboard type based on initialize_parameters.
void SetKeyboardType();
/// Sets the password mode based on initialize_parameters.
void SetPasswordMode();
/// Sets the text draw type based on initialize_parameters.
void SetTextDrawType();
/// Sets the controller image at the bottom left of the software keyboard.
void SetControllerImage();
/// Disables buttons based on initialize_parameters.
void DisableKeyboardButtons();
/// Changes whether the backspace or/and ok buttons should be enabled or disabled.
void SetBackspaceOkEnabled();
/**
* Validates the input text sent in based on the parameters in initialize_parameters.
*
* @param input_text Input text
*
* @returns True if the input text is valid, false otherwise.
*/
bool ValidateInputText(const QString& input_text);
/// Switches between LowerCase and UpperCase (Shift and Caps Lock)
void ChangeBottomOSKIndex();
/// Processes a keyboard button click from the UI as normal keyboard input.
void NormalKeyboardButtonClicked(QPushButton* button);
/// Processes a keyboard button click from the UI as inline keyboard input.
void InlineKeyboardButtonClicked(QPushButton* button);
/**
* Inserts a string of arbitrary length into the current_text at the current cursor position.
* This is only used for the inline software keyboard.
*/
void InlineTextInsertString(std::u16string_view string);
/// Setup the mouse hover workaround for "focusing" buttons. This should only be called once.
void SetupMouseHover();
/**
* Handles button presses and converts them into keyboard input.
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
void HandleButtonPressedOnce();
/**
* Handles button holds and converts them into keyboard input.
*
* @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/
template <HIDButton... T>
void HandleButtonHold();
/**
* Translates a button press to focus or click a keyboard button.
*
* @param button The button press to process.
*/
void TranslateButtonPress(HIDButton button);
/**
* Moves the focus of a button in a certain direction.
*
* @param direction The direction to move.
*/
void MoveButtonDirection(Direction direction);
/**
* Moves the text cursor in a certain direction.
*
* @param direction The direction to move.
*/
void MoveTextCursorDirection(Direction direction);
void StartInputThread();
void StopInputThread();
/// The thread where input is being polled and processed.
void InputThread();
std::unique_ptr<Ui::QtSoftwareKeyboardDialog> ui;
Core::System& system;
// True if it is the inline software keyboard.
bool is_inline;
// Common software keyboard initialize parameters.
Core::Frontend::KeyboardInitializeParameters initialize_parameters;
// Used only by the inline software keyboard since the QLineEdit or QTextEdit is hidden.
std::u16string current_text;
s32 cursor_position{0};
static constexpr std::size_t NUM_ROWS_NORMAL = 5;
static constexpr std::size_t NUM_COLUMNS_NORMAL = 12;
static constexpr std::size_t NUM_ROWS_NUMPAD = 4;
static constexpr std::size_t NUM_COLUMNS_NUMPAD = 4;
// Stores the normal keyboard layout.
std::array<std::array<std::array<QPushButton*, NUM_COLUMNS_NORMAL>, NUM_ROWS_NORMAL>, 2>
keyboard_buttons;
// Stores the numberpad keyboard layout.
std::array<std::array<QPushButton*, NUM_COLUMNS_NUMPAD>, NUM_ROWS_NUMPAD> numberpad_buttons;
// Contains a set of all buttons used in keyboard_buttons and numberpad_buttons.
std::array<QPushButton*, 110> all_buttons;
std::size_t row{0};
std::size_t column{0};
BottomOSKIndex bottom_osk_index{BottomOSKIndex::LowerCase};
std::atomic<bool> caps_lock_enabled{false};
std::unique_ptr<InputInterpreter> input_interpreter;
std::thread input_thread;
std::atomic<bool> input_thread_running{};
}; };
class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet { class QtSoftwareKeyboard final : public QObject, public Core::Frontend::SoftwareKeyboardApplet {
@ -58,19 +232,54 @@ public:
explicit QtSoftwareKeyboard(GMainWindow& parent); explicit QtSoftwareKeyboard(GMainWindow& parent);
~QtSoftwareKeyboard() override; ~QtSoftwareKeyboard() override;
void RequestText(std::function<void(std::optional<std::u16string>)> out, void InitializeKeyboard(
Core::Frontend::SoftwareKeyboardParameters parameters) const override; bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters,
void SendTextCheckDialog(std::u16string error_message, std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
std::function<void()> finished_check_) const override; submit_normal_callback_,
std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback_) override;
void ShowNormalKeyboard() const override;
void ShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const override;
void ShowInlineKeyboard(
Core::Frontend::InlineAppearParameters appear_parameters) const override;
void HideInlineKeyboard() const override;
void InlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const override;
void ExitKeyboard() const override;
signals: signals:
void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const; void MainWindowInitializeKeyboard(
void MainWindowTextCheckDialog(std::u16string error_message) const; bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) const;
void MainWindowShowNormalKeyboard() const;
void MainWindowShowTextCheckDialog(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const;
void MainWindowShowInlineKeyboard(
Core::Frontend::InlineAppearParameters appear_parameters) const;
void MainWindowHideInlineKeyboard() const;
void MainWindowInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters) const;
void MainWindowExitKeyboard() const;
private: private:
void MainWindowFinishedText(std::optional<std::u16string> text); void SubmitNormalText(Service::AM::Applets::SwkbdResult result,
void MainWindowFinishedCheckDialog(); std::u16string submitted_text) const;
mutable std::function<void(std::optional<std::u16string>)> text_output; void SubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
mutable std::function<void()> finished_check; std::u16string submitted_text, s32 cursor_position) const;
mutable std::function<void(Service::AM::Applets::SwkbdResult, std::u16string)>
submit_normal_callback;
mutable std::function<void(Service::AM::Applets::SwkbdReplyType, std::u16string, s32)>
submit_inline_callback;
}; };

View File

@ -641,6 +641,7 @@ void Config::ReadDebuggingValues() {
ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool(); ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
Settings::values.extended_logging = Settings::values.extended_logging =
ReadSetting(QStringLiteral("extended_logging"), false).toBool(); ReadSetting(QStringLiteral("extended_logging"), false).toBool();
Settings::values.use_auto_stub = ReadSetting(QStringLiteral("use_auto_stub"), false).toBool();
qt_config->endGroup(); qt_config->endGroup();
} }
@ -770,6 +771,13 @@ void Config::ReadRendererValues() {
ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0); ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0);
ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false); ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0); ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0);
#ifdef _WIN32
ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 0);
#else
// *nix platforms may have issues with the borderless windowed fullscreen mode.
// Default to exclusive fullscreen on these platforms for now.
ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 1);
#endif
ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0); ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0);
ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0); ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0);
ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true); ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true);
@ -1333,6 +1341,13 @@ void Config::SaveRendererValues() {
Settings::values.renderer_backend.UsingGlobal(), 0); Settings::values.renderer_backend.UsingGlobal(), 0);
WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false); WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false);
WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0); WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
#ifdef _WIN32
WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 0);
#else
// *nix platforms may have issues with the borderless windowed fullscreen mode.
// Default to exclusive fullscreen on these platforms for now.
WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 1);
#endif
WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0); WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0); WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true); WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);

View File

@ -34,6 +34,7 @@ void ConfigureDebug::SetConfiguration() {
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
ui->reporting_services->setChecked(Settings::values.reporting_services); ui->reporting_services->setChecked(Settings::values.reporting_services);
ui->quest_flag->setChecked(Settings::values.quest_flag); ui->quest_flag->setChecked(Settings::values.quest_flag);
ui->use_auto_stub->setChecked(Settings::values.use_auto_stub);
ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn()); ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn());
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug); ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn()); ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
@ -47,6 +48,7 @@ void ConfigureDebug::ApplyConfiguration() {
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
Settings::values.reporting_services = ui->reporting_services->isChecked(); Settings::values.reporting_services = ui->reporting_services->isChecked();
Settings::values.quest_flag = ui->quest_flag->isChecked(); Settings::values.quest_flag = ui->quest_flag->isChecked();
Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked(); Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked(); Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
Settings::values.extended_logging = ui->extended_logging->isChecked(); Settings::values.extended_logging = ui->extended_logging->isChecked();

View File

@ -185,6 +185,28 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="use_auto_stub">
<property name="text">
<string>Enable Auto-Stub</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>This will be reset automatically when yuzu closes.</string>
</property>
<property name="indent">
<number>20</number>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

View File

@ -77,18 +77,25 @@ void ConfigureGraphics::SetConfiguration() {
if (Settings::IsConfiguringGlobal()) { if (Settings::IsConfiguringGlobal()) {
ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue())); ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
ui->fullscreen_mode_combobox->setCurrentIndex(Settings::values.fullscreen_mode.GetValue());
ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue()); ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
} else { } else {
ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend); ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
ConfigurationShared::SetHighlight(ui->api_layout, ConfigurationShared::SetHighlight(ui->api_layout,
!Settings::values.renderer_backend.UsingGlobal()); !Settings::values.renderer_backend.UsingGlobal());
ConfigurationShared::SetPerGameSetting(ui->fullscreen_mode_combobox,
&Settings::values.fullscreen_mode);
ConfigurationShared::SetHighlight(ui->fullscreen_mode_label,
!Settings::values.fullscreen_mode.UsingGlobal());
ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox, ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
&Settings::values.aspect_ratio); &Settings::values.aspect_ratio);
ConfigurationShared::SetHighlight(ui->ar_label,
!Settings::values.aspect_ratio.UsingGlobal());
ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1); ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal()); ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
ConfigurationShared::SetHighlight(ui->ar_label,
!Settings::values.aspect_ratio.UsingGlobal());
ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal()); ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal());
} }
@ -107,6 +114,9 @@ void ConfigureGraphics::ApplyConfiguration() {
if (Settings::values.vulkan_device.UsingGlobal()) { if (Settings::values.vulkan_device.UsingGlobal()) {
Settings::values.vulkan_device.SetValue(vulkan_device); Settings::values.vulkan_device.SetValue(vulkan_device);
} }
if (Settings::values.fullscreen_mode.UsingGlobal()) {
Settings::values.fullscreen_mode.SetValue(ui->fullscreen_mode_combobox->currentIndex());
}
if (Settings::values.aspect_ratio.UsingGlobal()) { if (Settings::values.aspect_ratio.UsingGlobal()) {
Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex()); Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
} }
@ -140,6 +150,8 @@ void ConfigureGraphics::ApplyConfiguration() {
} }
} }
ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
ui->fullscreen_mode_combobox);
ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio, ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
ui->aspect_ratio_combobox); ui->aspect_ratio_combobox);
@ -227,7 +239,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
vulkan_devices.clear(); vulkan_devices.clear();
vulkan_devices.reserve(physical_devices.size()); vulkan_devices.reserve(physical_devices.size());
for (const VkPhysicalDevice device : physical_devices) { for (const VkPhysicalDevice device : physical_devices) {
const char* const name = vk::PhysicalDevice(device, dld).GetProperties().deviceName; const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
vulkan_devices.push_back(QString::fromStdString(name)); vulkan_devices.push_back(QString::fromStdString(name));
} }
@ -253,6 +265,7 @@ void ConfigureGraphics::SetupPerGameUI() {
if (Settings::IsConfiguringGlobal()) { if (Settings::IsConfiguringGlobal()) {
ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal()); ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal()); ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
ui->fullscreen_mode_combobox->setEnabled(Settings::values.fullscreen_mode.UsingGlobal());
ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal()); ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
ui->use_asynchronous_gpu_emulation->setEnabled( ui->use_asynchronous_gpu_emulation->setEnabled(
Settings::values.use_asynchronous_gpu_emulation.UsingGlobal()); Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
@ -278,6 +291,8 @@ void ConfigureGraphics::SetupPerGameUI() {
ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label, ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label,
Settings::values.aspect_ratio.GetValue(true)); Settings::values.aspect_ratio.GetValue(true));
ConfigurationShared::SetColoredComboBox(ui->fullscreen_mode_combobox, ui->fullscreen_mode_label,
Settings::values.fullscreen_mode.GetValue(true));
ConfigurationShared::InsertGlobalItem( ConfigurationShared::InsertGlobalItem(
ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true))); ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
} }

View File

@ -104,9 +104,48 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QWidget" name="fullscreen_mode_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="fullscreen_mode_label">
<property name="text">
<string>Fullscreen Mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="fullscreen_mode_combobox">
<item>
<property name="text">
<string>Borderless Windowed (Default)</string>
</property>
</item>
<item>
<property name="text">
<string>Exclusive Fullscreen</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QWidget" name="aspect_ratio_layout" native="true"> <widget class="QWidget" name="aspect_ratio_layout" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_6"> <layout class="QHBoxLayout" name="horizontalLayout_2">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>

View File

@ -38,7 +38,7 @@ void DiscordImpl::Update() {
if (Core::System::GetInstance().IsPoweredOn()) if (Core::System::GetInstance().IsPoweredOn())
Core::System::GetInstance().GetAppLoader().ReadTitle(title); Core::System::GetInstance().GetAppLoader().ReadTitle(title);
DiscordRichPresence presence{}; DiscordRichPresence presence{};
presence.largeImageKey = "yuzu_logo"; presence.largeImageKey = "yuzu_logo_ea";
presence.largeImageText = "yuzu is an emulator for the Nintendo Switch"; presence.largeImageText = "yuzu is an emulator for the Nintendo Switch";
if (Core::System::GetInstance().IsPoweredOn()) { if (Core::System::GetInstance().IsPoweredOn()) {
presence.state = title.c_str(); presence.state = title.c_str();

View File

@ -101,6 +101,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "core/settings.h" #include "core/settings.h"
#include "core/telemetry_session.h" #include "core/telemetry_session.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "util/overlay_dialog.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
#include "video_core/shader_notify.h" #include "video_core/shader_notify.h"
#include "yuzu/about_dialog.h" #include "yuzu/about_dialog.h"
@ -225,6 +226,8 @@ GMainWindow::GMainWindow()
SetDiscordEnabled(UISettings::values.enable_discord_presence); SetDiscordEnabled(UISettings::values.enable_discord_presence);
discord_rpc->Update(); discord_rpc->Update();
RegisterMetaTypes();
InitializeWidgets(); InitializeWidgets();
InitializeDebugWidgets(); InitializeDebugWidgets();
InitializeRecentFileMenuActions(); InitializeRecentFileMenuActions();
@ -373,6 +376,55 @@ GMainWindow::~GMainWindow() {
delete render_window; delete render_window;
} }
void GMainWindow::RegisterMetaTypes() {
// Register integral and floating point types
qRegisterMetaType<u8>("u8");
qRegisterMetaType<u16>("u16");
qRegisterMetaType<u32>("u32");
qRegisterMetaType<u64>("u64");
qRegisterMetaType<u128>("u128");
qRegisterMetaType<s8>("s8");
qRegisterMetaType<s16>("s16");
qRegisterMetaType<s32>("s32");
qRegisterMetaType<s64>("s64");
qRegisterMetaType<f32>("f32");
qRegisterMetaType<f64>("f64");
// Register string types
qRegisterMetaType<std::string>("std::string");
qRegisterMetaType<std::wstring>("std::wstring");
qRegisterMetaType<std::u8string>("std::u8string");
qRegisterMetaType<std::u16string>("std::u16string");
qRegisterMetaType<std::u32string>("std::u32string");
qRegisterMetaType<std::string_view>("std::string_view");
qRegisterMetaType<std::wstring_view>("std::wstring_view");
qRegisterMetaType<std::u8string_view>("std::u8string_view");
qRegisterMetaType<std::u16string_view>("std::u16string_view");
qRegisterMetaType<std::u32string_view>("std::u32string_view");
// Register applet types
// Controller Applet
qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
// Software Keyboard Applet
qRegisterMetaType<Core::Frontend::KeyboardInitializeParameters>(
"Core::Frontend::KeyboardInitializeParameters");
qRegisterMetaType<Core::Frontend::InlineAppearParameters>(
"Core::Frontend::InlineAppearParameters");
qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters");
qRegisterMetaType<Service::AM::Applets::SwkbdResult>("Service::AM::Applets::SwkbdResult");
qRegisterMetaType<Service::AM::Applets::SwkbdTextCheckResult>(
"Service::AM::Applets::SwkbdTextCheckResult");
qRegisterMetaType<Service::AM::Applets::SwkbdReplyType>("Service::AM::Applets::SwkbdReplyType");
// Web Browser Applet
qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason");
// Register loader types
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
}
void GMainWindow::ControllerSelectorReconfigureControllers( void GMainWindow::ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters) { const Core::Frontend::ControllerParameters& parameters) {
QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get()); QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get());
@ -412,25 +464,112 @@ void GMainWindow::ProfileSelectorSelectProfile() {
emit ProfileSelectorFinishedSelection(uuid); emit ProfileSelectorFinishedSelection(uuid);
} }
void GMainWindow::SoftwareKeyboardGetText( void GMainWindow::SoftwareKeyboardInitialize(
const Core::Frontend::SoftwareKeyboardParameters& parameters) { bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) {
QtSoftwareKeyboardDialog dialog(this, parameters); if (software_keyboard) {
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint | LOG_ERROR(Frontend, "The software keyboard is already initialized!");
Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
Qt::WindowCloseButtonHint);
dialog.setWindowModality(Qt::WindowModal);
if (dialog.exec() == QDialog::Rejected) {
emit SoftwareKeyboardFinishedText(std::nullopt);
return; return;
} }
emit SoftwareKeyboardFinishedText(dialog.GetText()); software_keyboard = new QtSoftwareKeyboardDialog(render_window, Core::System::GetInstance(),
is_inline, std::move(initialize_parameters));
if (is_inline) {
connect(
software_keyboard, &QtSoftwareKeyboardDialog::SubmitInlineText, this,
[this](Service::AM::Applets::SwkbdReplyType reply_type, std::u16string submitted_text,
s32 cursor_position) {
emit SoftwareKeyboardSubmitInlineText(reply_type, submitted_text, cursor_position);
},
Qt::QueuedConnection);
} else {
connect(
software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this,
[this](Service::AM::Applets::SwkbdResult result, std::u16string submitted_text) {
emit SoftwareKeyboardSubmitNormalText(result, submitted_text);
},
Qt::QueuedConnection);
}
} }
void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message) { void GMainWindow::SoftwareKeyboardShowNormal() {
QMessageBox::warning(this, tr("Text Check Failed"), QString::fromStdU16String(error_message)); if (!software_keyboard) {
emit SoftwareKeyboardFinishedCheckDialog(); LOG_ERROR(Frontend, "The software keyboard is not initialized!");
return;
}
const auto& layout = render_window->GetFramebufferLayout();
const auto x = layout.screen.left;
const auto y = layout.screen.top;
const auto w = layout.screen.GetWidth();
const auto h = layout.screen.GetHeight();
software_keyboard->ShowNormalKeyboard(render_window->mapToGlobal(QPoint(x, y)), QSize(w, h));
}
void GMainWindow::SoftwareKeyboardShowTextCheck(
Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) {
if (!software_keyboard) {
LOG_ERROR(Frontend, "The software keyboard is not initialized!");
return;
}
software_keyboard->ShowTextCheckDialog(text_check_result, text_check_message);
}
void GMainWindow::SoftwareKeyboardShowInline(
Core::Frontend::InlineAppearParameters appear_parameters) {
if (!software_keyboard) {
LOG_ERROR(Frontend, "The software keyboard is not initialized!");
return;
}
const auto& layout = render_window->GetFramebufferLayout();
const auto x =
static_cast<int>(layout.screen.left + (0.5f * layout.screen.GetWidth() *
((2.0f * appear_parameters.key_top_translate_x) +
(1.0f - appear_parameters.key_top_scale_x))));
const auto y =
static_cast<int>(layout.screen.top + (layout.screen.GetHeight() *
((2.0f * appear_parameters.key_top_translate_y) +
(1.0f - appear_parameters.key_top_scale_y))));
const auto w = static_cast<int>(layout.screen.GetWidth() * appear_parameters.key_top_scale_x);
const auto h = static_cast<int>(layout.screen.GetHeight() * appear_parameters.key_top_scale_y);
software_keyboard->ShowInlineKeyboard(std::move(appear_parameters),
render_window->mapToGlobal(QPoint(x, y)), QSize(w, h));
}
void GMainWindow::SoftwareKeyboardHideInline() {
if (!software_keyboard) {
LOG_ERROR(Frontend, "The software keyboard is not initialized!");
return;
}
software_keyboard->HideInlineKeyboard();
}
void GMainWindow::SoftwareKeyboardInlineTextChanged(
Core::Frontend::InlineTextParameters text_parameters) {
if (!software_keyboard) {
LOG_ERROR(Frontend, "The software keyboard is not initialized!");
return;
}
software_keyboard->InlineTextChanged(std::move(text_parameters));
}
void GMainWindow::SoftwareKeyboardExit() {
if (!software_keyboard) {
return;
}
software_keyboard->ExitKeyboard();
software_keyboard = nullptr;
} }
void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args,
@ -976,6 +1115,10 @@ void GMainWindow::ConnectWidgetEvents() {
connect(this, &GMainWindow::EmulationStopping, render_window, connect(this, &GMainWindow::EmulationStopping, render_window,
&GRenderWindow::OnEmulationStopping); &GRenderWindow::OnEmulationStopping);
// Software Keyboard Applet
connect(this, &GMainWindow::EmulationStarting, this, &GMainWindow::SoftwareKeyboardExit);
connect(this, &GMainWindow::EmulationStopping, this, &GMainWindow::SoftwareKeyboardExit);
connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar); connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar);
} }
@ -2185,15 +2328,6 @@ void GMainWindow::OnStartGame() {
emu_thread->SetRunning(true); emu_thread->SetRunning(true);
qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
"Core::Frontend::SoftwareKeyboardParameters");
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
qRegisterMetaType<std::string>("std::string");
qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>");
qRegisterMetaType<std::string_view>("std::string_view");
qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason");
connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError); connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
ui.action_Start->setEnabled(false); ui.action_Start->setEnabled(false);
@ -2242,8 +2376,11 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) {
BootGame(last_filename_booted, program_index); BootGame(last_filename_booted, program_index);
} }
void GMainWindow::ErrorDisplayDisplayError(QString body) { void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
QMessageBox::critical(this, tr("Error Display"), body); OverlayDialog dialog(render_window, Core::System::GetInstance(), error_code, error_text,
QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter);
dialog.exec();
emit ErrorDisplayFinished(); emit ErrorDisplayFinished();
} }
@ -2295,24 +2432,66 @@ void GMainWindow::ToggleFullscreen() {
void GMainWindow::ShowFullscreen() { void GMainWindow::ShowFullscreen() {
if (ui.action_Single_Window_Mode->isChecked()) { if (ui.action_Single_Window_Mode->isChecked()) {
UISettings::values.geometry = saveGeometry(); UISettings::values.geometry = saveGeometry();
ui.menubar->hide(); ui.menubar->hide();
statusBar()->hide(); statusBar()->hide();
showFullScreen();
if (Settings::values.fullscreen_mode.GetValue() == 1) {
showFullScreen();
return;
}
hide();
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
const auto screen_geometry = QApplication::desktop()->screenGeometry(this);
setGeometry(screen_geometry.x(), screen_geometry.y(), screen_geometry.width(),
screen_geometry.height() + 1);
raise();
showNormal();
} else { } else {
UISettings::values.renderwindow_geometry = render_window->saveGeometry(); UISettings::values.renderwindow_geometry = render_window->saveGeometry();
render_window->showFullScreen();
if (Settings::values.fullscreen_mode.GetValue() == 1) {
render_window->showFullScreen();
return;
}
render_window->hide();
render_window->setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
const auto screen_geometry = QApplication::desktop()->screenGeometry(this);
render_window->setGeometry(screen_geometry.x(), screen_geometry.y(),
screen_geometry.width(), screen_geometry.height() + 1);
render_window->raise();
render_window->showNormal();
} }
} }
void GMainWindow::HideFullscreen() { void GMainWindow::HideFullscreen() {
if (ui.action_Single_Window_Mode->isChecked()) { if (ui.action_Single_Window_Mode->isChecked()) {
if (Settings::values.fullscreen_mode.GetValue() == 1) {
showNormal();
restoreGeometry(UISettings::values.geometry);
} else {
hide();
setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
restoreGeometry(UISettings::values.geometry);
raise();
show();
}
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked()); statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
ui.menubar->show(); ui.menubar->show();
showNormal();
restoreGeometry(UISettings::values.geometry);
} else { } else {
render_window->showNormal(); if (Settings::values.fullscreen_mode.GetValue() == 1) {
render_window->restoreGeometry(UISettings::values.renderwindow_geometry); render_window->showNormal();
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
} else {
render_window->hide();
render_window->setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
render_window->raise();
render_window->show();
}
} }
} }

View File

@ -37,9 +37,13 @@ enum class GameListRemoveTarget;
enum class InstalledEntryType; enum class InstalledEntryType;
class GameListPlaceholder; class GameListPlaceholder;
class QtSoftwareKeyboardDialog;
namespace Core::Frontend { namespace Core::Frontend {
struct ControllerParameters; struct ControllerParameters;
struct SoftwareKeyboardParameters; struct InlineAppearParameters;
struct InlineTextParameters;
struct KeyboardInitializeParameters;
} // namespace Core::Frontend } // namespace Core::Frontend
namespace DiscordRPC { namespace DiscordRPC {
@ -57,8 +61,11 @@ class InputSubsystem;
} }
namespace Service::AM::Applets { namespace Service::AM::Applets {
enum class SwkbdResult : u32;
enum class SwkbdTextCheckResult : u32;
enum class SwkbdReplyType : u32;
enum class WebExitReason : u32; enum class WebExitReason : u32;
} } // namespace Service::AM::Applets
enum class EmulatedDirectoryTarget { enum class EmulatedDirectoryTarget {
NAND, NAND,
@ -128,8 +135,10 @@ signals:
void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid); void ProfileSelectorFinishedSelection(std::optional<Common::UUID> uuid);
void SoftwareKeyboardFinishedText(std::optional<std::u16string> text); void SoftwareKeyboardSubmitNormalText(Service::AM::Applets::SwkbdResult result,
void SoftwareKeyboardFinishedCheckDialog(); std::u16string submitted_text);
void SoftwareKeyboardSubmitInlineText(Service::AM::Applets::SwkbdReplyType reply_type,
std::u16string submitted_text, s32 cursor_position);
void WebBrowserExtractOfflineRomFS(); void WebBrowserExtractOfflineRomFS();
void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url); void WebBrowserClosed(Service::AM::Applets::WebExitReason exit_reason, std::string last_url);
@ -139,15 +148,24 @@ public slots:
void OnExecuteProgram(std::size_t program_index); void OnExecuteProgram(std::size_t program_index);
void ControllerSelectorReconfigureControllers( void ControllerSelectorReconfigureControllers(
const Core::Frontend::ControllerParameters& parameters); const Core::Frontend::ControllerParameters& parameters);
void ErrorDisplayDisplayError(QString body); void SoftwareKeyboardInitialize(
bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters);
void SoftwareKeyboardShowNormal();
void SoftwareKeyboardShowTextCheck(Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message);
void SoftwareKeyboardShowInline(Core::Frontend::InlineAppearParameters appear_parameters);
void SoftwareKeyboardHideInline();
void SoftwareKeyboardInlineTextChanged(Core::Frontend::InlineTextParameters text_parameters);
void SoftwareKeyboardExit();
void ErrorDisplayDisplayError(QString error_code, QString error_text);
void ProfileSelectorSelectProfile(); void ProfileSelectorSelectProfile();
void SoftwareKeyboardGetText(const Core::Frontend::SoftwareKeyboardParameters& parameters);
void SoftwareKeyboardInvokeCheckDialog(std::u16string error_message);
void WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args, void WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args,
bool is_local); bool is_local);
void OnAppFocusStateChanged(Qt::ApplicationState state); void OnAppFocusStateChanged(Qt::ApplicationState state);
private: private:
void RegisterMetaTypes();
void InitializeWidgets(); void InitializeWidgets();
void InitializeDebugWidgets(); void InitializeDebugWidgets();
void InitializeRecentFileMenuActions(); void InitializeRecentFileMenuActions();
@ -334,6 +352,9 @@ private:
// Disables the web applet for the rest of the emulated session // Disables the web applet for the rest of the emulated session
bool disable_web_applet{}; bool disable_web_applet{};
// Applets
QtSoftwareKeyboardDialog* software_keyboard = nullptr;
protected: protected:
void dropEvent(QDropEvent* event) override; void dropEvent(QDropEvent* event) override;
void dragEnterEvent(QDragEnterEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override;

View File

@ -62,7 +62,7 @@ void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const
ui->label_title->setText(title_text); ui->label_title->setText(title_text);
ui->label_dialog->setText(body_text); ui->label_dialog->setText(body_text);
ui->button_cancel->setText(left_button_text); ui->button_cancel->setText(left_button_text);
ui->button_ok->setText(right_button_text); ui->button_ok_label->setText(right_button_text);
ui->label_dialog->setAlignment(alignment); ui->label_dialog->setAlignment(alignment);
@ -79,8 +79,8 @@ void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const
} }
if (right_button_text.isEmpty()) { if (right_button_text.isEmpty()) {
ui->button_ok->hide(); ui->button_ok_label->hide();
ui->button_ok->setEnabled(false); ui->button_ok_label->setEnabled(false);
} }
connect( connect(
@ -91,7 +91,7 @@ void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const
}, },
Qt::QueuedConnection); Qt::QueuedConnection);
connect( connect(
ui->button_ok, &QPushButton::clicked, this, ui->button_ok_label, &QPushButton::clicked, this,
[this](bool) { [this](bool) {
StopInputThread(); StopInputThread();
QDialog::accept(); QDialog::accept();
@ -172,7 +172,7 @@ void OverlayDialog::MoveAndResizeWindow() {
ui->label_title->setFont(title_text_font); ui->label_title->setFont(title_text_font);
ui->label_dialog->setFont(body_text_font); ui->label_dialog->setFont(body_text_font);
ui->button_cancel->setFont(button_text_font); ui->button_cancel->setFont(button_text_font);
ui->button_ok->setFont(button_text_font); ui->button_ok_label->setFont(button_text_font);
} }
QDialog::move(pos); QDialog::move(pos);
@ -192,7 +192,7 @@ void OverlayDialog::HandleButtonPressedOnce() {
void OverlayDialog::TranslateButtonPress(HIDButton button) { void OverlayDialog::TranslateButtonPress(HIDButton button) {
QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel; QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel;
QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok; QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label;
// TODO (Morph): Handle QTextBrowser text scrolling // TODO (Morph): Handle QTextBrowser text scrolling
// TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it // TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it

View File

@ -136,7 +136,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="button_ok"> <widget class="QPushButton" name="button_ok_label">
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding"> <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch> <horstretch>0</horstretch>