early-access version 1592

This commit is contained in:
pineappleEA 2021-04-13 02:50:20 +02:00
parent e839de5014
commit 8233a5069a
68 changed files with 5589 additions and 781 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 1591. This is the source code for early-access 1592.
## 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

@ -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

@ -4,8 +4,4 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_funcs.h" void assert_handle_failure() {}
void assert_handle_failure() {
Crash();
}

View file

@ -2,6 +2,8 @@
// 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
namespace Common { namespace Common {
/// Configure platform specific flags for Nvidia's driver /// Configure platform specific flags for Nvidia's driver

View file

@ -273,6 +273,7 @@ add_library(core STATIC
hle/service/am/applets/profile_select.h hle/service/am/applets/profile_select.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/software_keyboard_types.h
hle/service/am/applets/web_browser.cpp hle/service/am/applets/web_browser.cpp
hle/service/am/applets/web_browser.h hle/service/am/applets/web_browser.h
hle/service/am/applets/web_types.h hle/service/am/applets/web_types.h

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_);
} }
void DefaultSoftwareKeyboardApplet::SendTextCheckDialog( parameters = std::move(initialize_parameters);
std::u16string error_message, std::function<void()> finished_check) const {
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::ShowNormalKeyboard() 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;
union { Service::AM::Applets::SwkbdPasswordMode password_mode;
u8 value; Service::AM::Applets::SwkbdTextDrawType text_draw_type;
Service::AM::Applets::SwkbdKeyDisableFlags key_disable_flags;
BitField<1, 1, u8> disable_space; bool use_blur_background;
BitField<2, 1, u8> disable_address; bool enable_backspace_button;
BitField<3, 1, u8> disable_percent; bool enable_return_button;
BitField<4, 1, u8> disable_slash; bool disable_cancel_button;
BitField<6, 1, u8> disable_number;
BitField<7, 1, u8> disable_download_code;
}; };
struct InlineAppearParameters {
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;
};
struct InlineTextParameters {
std::u16string input_text;
s32 cursor_position;
}; };
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

@ -67,8 +67,13 @@ struct KernelCore::Impl {
is_phantom_mode_for_singlecore = false; is_phantom_mode_for_singlecore = false;
InitializePhysicalCores(); InitializePhysicalCores();
InitializeSystemResourceLimit(kernel, system);
InitializeMemoryLayout(); // Derive the initial memory layout from the emulated board
KMemoryLayout memory_layout;
DeriveInitialMemoryLayout(memory_layout);
InitializeMemoryLayout(memory_layout);
InitializeSystemResourceLimit(kernel, system, memory_layout);
InitializeSlabHeaps();
InitializeSchedulers(); InitializeSchedulers();
InitializeSuspendThreads(); InitializeSuspendThreads();
InitializePreemption(kernel); InitializePreemption(kernel);
@ -137,27 +142,32 @@ struct KernelCore::Impl {
} }
// Creates the default system resource limit // Creates the default system resource limit
void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system) { void InitializeSystemResourceLimit(KernelCore& kernel, Core::System& system,
const KMemoryLayout& memory_layout) {
system_resource_limit = std::make_shared<KResourceLimit>(kernel, system); system_resource_limit = std::make_shared<KResourceLimit>(kernel, system);
const auto [total_size, kernel_size] = memory_layout.GetTotalAndKernelMemorySizes();
// If setting the default system values fails, then something seriously wrong has occurred. // If setting the default system values fails, then something seriously wrong has occurred.
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, 0x100000000) ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size)
.IsSuccess()); .IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess()); ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess()); ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200) ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
.IsSuccess()); .IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess()); ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size);
// Derived from recent software updates. The kernel reserves 27MB
constexpr u64 kernel_size{0x1b00000};
if (!system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size)) {
UNREACHABLE();
}
// Reserve secure applet memory, introduced in firmware 5.0.0 // Reserve secure applet memory, introduced in firmware 5.0.0
constexpr u64 secure_applet_memory_size{0x400000}; constexpr u64 secure_applet_memory_size{Common::Size_4_MB};
ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory, ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
secure_applet_memory_size)); secure_applet_memory_size));
// This memory seems to be reserved on hardware, but is not reserved/used by yuzu.
// Likely Horizon OS reserved memory
// TODO(ameerj): Derive the memory rather than hardcode it.
constexpr u64 unknown_reserved_memory{0x2f896000};
ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
unknown_reserved_memory));
} }
void InitializePreemption(KernelCore& kernel) { void InitializePreemption(KernelCore& kernel) {
@ -531,11 +541,7 @@ struct KernelCore::Impl {
linear_region_start); linear_region_start);
} }
void InitializeMemoryLayout() { void InitializeMemoryLayout(const KMemoryLayout& memory_layout) {
// Derive the initial memory layout from the emulated board
KMemoryLayout memory_layout;
DeriveInitialMemoryLayout(memory_layout);
const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents(); const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents();
const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents(); const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents();
const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents(); const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents();
@ -578,11 +584,14 @@ struct KernelCore::Impl {
system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize}, system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize},
KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size, KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size,
"Time:SharedMemory"); "Time:SharedMemory");
}
void InitializeSlabHeaps() {
// Allocate slab heaps // Allocate slab heaps
user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>(); user_slab_heap_pages = std::make_unique<KSlabHeap<Page>>();
constexpr u64 user_slab_heap_size{0x1ef000}; // TODO(ameerj): This should be derived, not hardcoded within the kernel
constexpr u64 user_slab_heap_size{0x3de000};
// Reserve slab heaps // Reserve slab heaps
ASSERT( ASSERT(
system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size)); system_resource_limit->Reserve(LimitableResource::PhysicalMemory, user_slab_heap_size));

View file

@ -120,9 +120,7 @@ std::shared_ptr<Process> Process::Create(Core::System& system, std::string name,
std::shared_ptr<Process> process = std::make_shared<Process>(system); std::shared_ptr<Process> process = std::make_shared<Process>(system);
process->name = std::move(name); process->name = std::move(name);
// TODO: This is inaccurate process->resource_limit = kernel.GetSystemResourceLimit();
// The process should hold a reference to the kernel-wide resource limit.
process->resource_limit = std::make_shared<KResourceLimit>(kernel, system);
process->status = ProcessStatus::Created; process->status = ProcessStatus::Created;
process->program_id = 0; process->program_id = 0;
process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID() process->process_id = type == ProcessType::KernelInternal ? kernel.CreateNewKernelProcessID()
@ -160,17 +158,13 @@ void Process::DecrementThreadCount() {
} }
u64 Process::GetTotalPhysicalMemoryAvailable() const { u64 Process::GetTotalPhysicalMemoryAvailable() const {
// TODO: This is expected to always return the application memory pool size after accurately
// reserving kernel resources. The current workaround uses a process-local resource limit of
// application memory pool size, which is inaccurate.
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) + const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size + page_table->GetTotalHeapSize() + GetSystemResourceSize() + image_size +
main_thread_stack_size}; main_thread_stack_size};
ASSERT(capacity == kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
if (capacity < memory_usage_capacity) { if (capacity < memory_usage_capacity) {
return capacity; return capacity;
} }
return memory_usage_capacity; return memory_usage_capacity;
} }
@ -272,10 +266,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
system_resource_size = metadata.GetSystemResourceSize(); system_resource_size = metadata.GetSystemResourceSize();
image_size = code_size; image_size = code_size;
// Set initial resource limits
resource_limit->SetLimitValue(
LimitableResource::PhysicalMemory,
kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory, KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
code_size + system_resource_size); code_size + system_resource_size);
if (!memory_reservation.Succeeded()) { if (!memory_reservation.Succeeded()) {
@ -324,16 +314,6 @@ ResultCode Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata,
UNREACHABLE(); UNREACHABLE();
} }
// Set initial resource limits
resource_limit->SetLimitValue(
LimitableResource::PhysicalMemory,
kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application));
resource_limit->SetLimitValue(LimitableResource::Threads, 608);
resource_limit->SetLimitValue(LimitableResource::Events, 700);
resource_limit->SetLimitValue(LimitableResource::TransferMemory, 128);
resource_limit->SetLimitValue(LimitableResource::Sessions, 894);
// Create TLS region // Create TLS region
tls_region_address = CreateTLSRegion(); tls_region_address = CreateTLSRegion();
memory_reservation.Commit(); memory_reservation.Commit();

View file

@ -971,7 +971,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);
@ -1002,7 +1002,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);
@ -1125,7 +1125,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);
} }
@ -1134,14 +1134,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);
@ -1159,9 +1160,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};
@ -1170,18 +1180,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

@ -176,7 +176,7 @@ struct SwkbdConfigNew {
std::array<u64, 24> customized_dictionary_set_entries{}; std::array<u64, 24> customized_dictionary_set_entries{};
u8 total_customized_dictionary_set_entries{}; u8 total_customized_dictionary_set_entries{};
bool disable_cancel_button{}; bool disable_cancel_button{};
INSERT_PADDING_BYTES(15); INSERT_PADDING_BYTES(18);
}; };
static_assert(sizeof(SwkbdConfigNew) == 0x4C8 - sizeof(SwkbdConfigCommon), static_assert(sizeof(SwkbdConfigNew) == 0x4C8 - sizeof(SwkbdConfigCommon),
"SwkbdConfigNew has incorrect size."); "SwkbdConfigNew has incorrect size.");

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

@ -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

@ -198,7 +198,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) {
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); 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

@ -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) {
if (stage == ShaderType::Fragment) {
AddLine("KIL TR;"); 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) {
if (context_func->IsMain()) {
PreExit(); 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;
if (stage != ShaderType::Fragment) {
code.AddLine("return;");
} else {
code.AddLine("discard;"); 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 { } else {
decomp.code.AddLine("discard;");
}
} else {
if (decomp.context_func->IsMain()) {
decomp.PreExit(); 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) {
if (context_func->IsMain()) {
PreExit(); 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 {
if (decomp.context_func->IsMain()) {
decomp.PreExit(); 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 {
if (decomp.context_func->IsMain()) {
decomp.PreExit(); 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,
const CompilerSettings& settings,
Registry& registry) { Registry& registry) {
auto result_out = std::make_unique<ShaderCharacteristics>(); ShaderFunction result_out{};
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,16 +178,12 @@ public:
private: private:
ShaderIR& ir; ShaderIR& ir;
ExprDecoder decoder;
}; };
void ShaderIR::Decode() { void ShaderIR::Decode() {
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); const auto decode_function = ([this](ShaderFunction& shader_info) {
coverage_end = std::max<u32>(0, shader_info.end);
decompiled = false;
auto info = ScanFlow(program_code, main_offset, settings, registry);
auto& shader_info = *info;
coverage_begin = shader_info.start;
coverage_end = shader_info.end;
switch (shader_info.settings.depth) { switch (shader_info.settings.depth) {
case CompileDepth::FlowStack: { case CompileDepth::FlowStack: {
for (const auto& block : shader_info.blocks) { for (const auto& block : shader_info.blocks) {
@ -175,7 +224,7 @@ void ShaderIR::Decode() {
disable_flow_stack = true; disable_flow_stack = true;
decompiled = true; decompiled = true;
ASTDecoder decoder{*this}; ASTDecoder decoder{*this};
ASTNode program = GetASTProgram(); ASTNode program = program_manager.GetProgram();
decoder.Visit(program); decoder.Visit(program);
break; break;
} }
@ -194,8 +243,48 @@ void ShaderIR::Decode() {
} }
if (settings.depth != shader_info.settings.depth) { if (settings.depth != shader_info.settings.depth) {
LOG_WARNING( LOG_WARNING(
HW_GPU, "Decompiling to this setting \"{}\" failed, downgrading to this setting \"{}\"", HW_GPU,
CompileDepthAsString(settings.depth), CompileDepthAsString(shader_info.settings.depth)); "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));
decompiled = false;
auto info = ScanFlow(program_code, main_offset, settings, registry);
u32 id_start = 1;
for (auto& pair : info->subfunctions) {
func_map.emplace(pair.first, id_start);
id_start++;
}
coverage_begin = info->main.start;
coverage_end = 0;
decode_function(info->main);
main_function = gen_function(info->main, 0);
subfunctions.resize(info->subfunctions.size());
for (auto& pair : info->subfunctions) {
auto& func_info = pair.second;
decode_function(func_info);
u32 id = func_map[pair.first];
subfunctions[id - 1] = gen_function(func_info, id);
} }
} }

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

@ -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();
} }

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;