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

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

BIN
dist/yuzu.ico vendored

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 25 KiB

2
dist/yuzu.svg vendored
View file

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

Before

Width:  |  Height:  |  Size: 889 B

After

Width:  |  Height:  |  Size: 717 B

View file

@ -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_);
}
parameters = std::move(initialize_parameters);
LOG_INFO(Service_AM,
"\nKeyboardInitializeParameters:"
"\nok_text={}"
"\nheader_text={}"
"\nsub_text={}"
"\nguide_text={}"
"\ninitial_text={}"
"\nmax_text_length={}"
"\nmin_text_length={}"
"\ninitial_cursor_position={}"
"\ntype={}"
"\npassword_mode={}"
"\ntext_draw_type={}"
"\nkey_disable_flags={}"
"\nuse_blur_background={}"
"\nenable_backspace_button={}"
"\nenable_return_button={}"
"\ndisable_cancel_button={}",
Common::UTF16ToUTF8(parameters.ok_text), Common::UTF16ToUTF8(parameters.header_text),
Common::UTF16ToUTF8(parameters.sub_text), Common::UTF16ToUTF8(parameters.guide_text),
Common::UTF16ToUTF8(parameters.initial_text), parameters.max_text_length,
parameters.min_text_length, parameters.initial_cursor_position, parameters.type,
parameters.password_mode, parameters.text_draw_type, parameters.key_disable_flags.raw,
parameters.use_blur_background, parameters.enable_backspace_button,
parameters.enable_return_button, parameters.disable_cancel_button);
} }
void DefaultSoftwareKeyboardApplet::SendTextCheckDialog( void DefaultSoftwareKeyboardApplet::ShowNormalKeyboard() const {
std::u16string error_message, std::function<void()> finished_check) const {
LOG_WARNING(Service_AM, LOG_WARNING(Service_AM,
"(STUBBED) called - Default fallback software keyboard does not support text " "(STUBBED) called, backend requested to show the normal software keyboard.");
"check! (error_message={})",
Common::UTF16ToUTF8(error_message)); SubmitNormalText(u"yuzu");
finished_check();
} }
void DefaultSoftwareKeyboardApplet::ShowTextCheckDialog(
Service::AM::Applets::SwkbdTextCheckResult text_check_result,
std::u16string text_check_message) const {
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to show the text check dialog.");
}
void DefaultSoftwareKeyboardApplet::ShowInlineKeyboard(
InlineAppearParameters appear_parameters) const {
LOG_WARNING(Service_AM,
"(STUBBED) called, backend requested to show the inline software keyboard.");
LOG_INFO(Service_AM,
"\nInlineAppearParameters:"
"\nmax_text_length={}"
"\nmin_text_length={}"
"\nkey_top_scale_x={}"
"\nkey_top_scale_y={}"
"\nkey_top_translate_x={}"
"\nkey_top_translate_y={}"
"\ntype={}"
"\nkey_disable_flags={}"
"\nkey_top_as_floating={}"
"\nenable_backspace_button={}"
"\nenable_return_button={}"
"\ndisable_cancel_button={}",
appear_parameters.max_text_length, appear_parameters.min_text_length,
appear_parameters.key_top_scale_x, appear_parameters.key_top_scale_y,
appear_parameters.key_top_translate_x, appear_parameters.key_top_translate_y,
appear_parameters.type, appear_parameters.key_disable_flags.raw,
appear_parameters.key_top_as_floating, appear_parameters.enable_backspace_button,
appear_parameters.enable_return_button, appear_parameters.disable_cancel_button);
std::thread([this] { SubmitInlineText(u"yuzu"); }).detach();
}
void DefaultSoftwareKeyboardApplet::HideInlineKeyboard() const {
LOG_WARNING(Service_AM,
"(STUBBED) called, backend requested to hide the inline software keyboard.");
}
void DefaultSoftwareKeyboardApplet::InlineTextChanged(InlineTextParameters text_parameters) const {
LOG_WARNING(Service_AM,
"(STUBBED) called, backend requested to change the inline keyboard text.");
LOG_INFO(Service_AM,
"\nInlineTextParameters:"
"\ninput_text={}"
"\ncursor_position={}",
Common::UTF16ToUTF8(text_parameters.input_text), text_parameters.cursor_position);
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
text_parameters.input_text, text_parameters.cursor_position);
}
void DefaultSoftwareKeyboardApplet::ExitKeyboard() const {
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to exit the software keyboard.");
}
void DefaultSoftwareKeyboardApplet::SubmitNormalText(std::u16string text) const {
submit_normal_callback(Service::AM::Applets::SwkbdResult::Ok, text);
}
void DefaultSoftwareKeyboardApplet::SubmitInlineText(std::u16string_view text) const {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
for (std::size_t index = 0; index < text.size(); ++index) {
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::ChangedString,
std::u16string(text.data(), text.data() + index + 1),
static_cast<s32>(index) + 1);
std::this_thread::sleep_for(std::chrono::milliseconds(250));
}
submit_inline_callback(Service::AM::Applets::SwkbdReplyType::DecidedEnter, std::u16string(text),
static_cast<s32>(text.size()));
}
} // namespace Core::Frontend } // namespace Core::Frontend

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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) {
gpu.MemoryManager().Unmap(object->dma_map_addr, *size); if (vic_device) {
// UnmapVicFrame defers texture_cache invalidation of the frame address until
// the stream is over
gpu.MemoryManager().UnmapVicFrame(object->dma_map_addr, *size);
} else {
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
}
} else { } else {
// This occurs quite frequently, however does not seem to impact functionality // This occurs quite frequently, however does not seem to impact functionality
LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr, LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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