early-access version 1559
This commit is contained in:
parent
9ecece0489
commit
83a618c598
94 changed files with 6745 additions and 940 deletions
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 1555.
|
This is the source code for early-access 1559.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
377
dist/qt_themes/default/style.qss
vendored
377
dist/qt_themes/default/style.qss
vendored
|
@ -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);
|
||||||
|
}
|
||||||
|
|
399
dist/qt_themes/qdarkstyle/style.qss
vendored
399
dist/qt_themes/qdarkstyle/style.qss
vendored
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
439
dist/qt_themes/qdarkstyle_midnight_blue/style.qss
vendored
439
dist/qt_themes/qdarkstyle_midnight_blue/style.qss
vendored
|
@ -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
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
2
dist/yuzu.svg
vendored
|
@ -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 |
|
@ -109,6 +109,7 @@ add_library(common STATIC
|
||||||
cityhash.h
|
cityhash.h
|
||||||
common_funcs.h
|
common_funcs.h
|
||||||
common_paths.h
|
common_paths.h
|
||||||
|
common_sizes.h
|
||||||
common_types.h
|
common_types.h
|
||||||
concepts.h
|
concepts.h
|
||||||
div_ceil.h
|
div_ceil.h
|
||||||
|
|
|
@ -29,22 +29,19 @@ assert_noinline_call(const Fn& fn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ASSERT(_a_) \
|
#define ASSERT(_a_) \
|
||||||
do \
|
if (!(_a_)) { \
|
||||||
if (!(_a_)) { \
|
LOG_CRITICAL(Debug, "Assertion Failed!"); \
|
||||||
assert_noinline_call([] { LOG_CRITICAL(Debug, "Assertion Failed!"); }); \
|
}
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
|
|
||||||
#define ASSERT_MSG(_a_, ...) \
|
#define ASSERT_MSG(_a_, ...) \
|
||||||
do \
|
if (!(_a_)) { \
|
||||||
if (!(_a_)) { \
|
LOG_CRITICAL(Debug, "Assertion Failed! " __VA_ARGS__); \
|
||||||
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Assertion Failed!\n" __VA_ARGS__); }); \
|
}
|
||||||
} \
|
|
||||||
while (0)
|
|
||||||
|
|
||||||
#define UNREACHABLE() assert_noinline_call([] { LOG_CRITICAL(Debug, "Unreachable code!"); })
|
#define UNREACHABLE() \
|
||||||
|
{ LOG_CRITICAL(Debug, "Unreachable code!"); }
|
||||||
#define UNREACHABLE_MSG(...) \
|
#define UNREACHABLE_MSG(...) \
|
||||||
assert_noinline_call([&] { LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); })
|
{ LOG_CRITICAL(Debug, "Unreachable code!\n" __VA_ARGS__); }
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define DEBUG_ASSERT(_a_) ASSERT(_a_)
|
#define DEBUG_ASSERT(_a_) ASSERT(_a_)
|
||||||
|
|
|
@ -141,6 +141,9 @@ add_library(core STATIC
|
||||||
hardware_interrupt_manager.h
|
hardware_interrupt_manager.h
|
||||||
hle/ipc.h
|
hle/ipc.h
|
||||||
hle/ipc_helpers.h
|
hle/ipc_helpers.h
|
||||||
|
hle/kernel/board/nintendo/nx/k_system_control.cpp
|
||||||
|
hle/kernel/board/nintendo/nx/k_system_control.h
|
||||||
|
hle/kernel/board/nintendo/nx/secure_monitor.h
|
||||||
hle/kernel/client_port.cpp
|
hle/kernel/client_port.cpp
|
||||||
hle/kernel/client_port.h
|
hle/kernel/client_port.h
|
||||||
hle/kernel/client_session.cpp
|
hle/kernel/client_session.cpp
|
||||||
|
@ -169,9 +172,13 @@ add_library(core STATIC
|
||||||
hle/kernel/k_memory_block.h
|
hle/kernel/k_memory_block.h
|
||||||
hle/kernel/k_memory_block_manager.cpp
|
hle/kernel/k_memory_block_manager.cpp
|
||||||
hle/kernel/k_memory_block_manager.h
|
hle/kernel/k_memory_block_manager.h
|
||||||
|
hle/kernel/k_memory_layout.cpp
|
||||||
|
hle/kernel/k_memory_layout.board.nintendo_nx.cpp
|
||||||
hle/kernel/k_memory_layout.h
|
hle/kernel/k_memory_layout.h
|
||||||
hle/kernel/k_memory_manager.cpp
|
hle/kernel/k_memory_manager.cpp
|
||||||
hle/kernel/k_memory_manager.h
|
hle/kernel/k_memory_manager.h
|
||||||
|
hle/kernel/k_memory_region.h
|
||||||
|
hle/kernel/k_memory_region_type.h
|
||||||
hle/kernel/k_page_bitmap.h
|
hle/kernel/k_page_bitmap.h
|
||||||
hle/kernel/k_page_heap.cpp
|
hle/kernel/k_page_heap.cpp
|
||||||
hle/kernel/k_page_heap.h
|
hle/kernel/k_page_heap.h
|
||||||
|
@ -196,11 +203,11 @@ add_library(core STATIC
|
||||||
hle/kernel/k_spin_lock.h
|
hle/kernel/k_spin_lock.h
|
||||||
hle/kernel/k_synchronization_object.cpp
|
hle/kernel/k_synchronization_object.cpp
|
||||||
hle/kernel/k_synchronization_object.h
|
hle/kernel/k_synchronization_object.h
|
||||||
hle/kernel/k_system_control.cpp
|
|
||||||
hle/kernel/k_system_control.h
|
hle/kernel/k_system_control.h
|
||||||
hle/kernel/k_thread.cpp
|
hle/kernel/k_thread.cpp
|
||||||
hle/kernel/k_thread.h
|
hle/kernel/k_thread.h
|
||||||
hle/kernel/k_thread_queue.h
|
hle/kernel/k_thread_queue.h
|
||||||
|
hle/kernel/k_trace.h
|
||||||
hle/kernel/k_writable_event.cpp
|
hle/kernel/k_writable_event.cpp
|
||||||
hle/kernel/k_writable_event.h
|
hle/kernel/k_writable_event.h
|
||||||
hle/kernel/kernel.cpp
|
hle/kernel/kernel.cpp
|
||||||
|
@ -264,6 +271,7 @@ add_library(core STATIC
|
||||||
hle/service/am/applets/general_backend.h
|
hle/service/am/applets/general_backend.h
|
||||||
hle/service/am/applets/profile_select.cpp
|
hle/service/am/applets/profile_select.cpp
|
||||||
hle/service/am/applets/profile_select.h
|
hle/service/am/applets/profile_select.h
|
||||||
|
hle/service/am/applets/software_keyboard_types.h
|
||||||
hle/service/am/applets/software_keyboard.cpp
|
hle/service/am/applets/software_keyboard.cpp
|
||||||
hle/service/am/applets/software_keyboard.h
|
hle/service/am/applets/software_keyboard.h
|
||||||
hle/service/am/applets/web_browser.cpp
|
hle/service/am/applets/web_browser.cpp
|
||||||
|
|
|
@ -100,6 +100,14 @@ u64 NACP::GetDeviceSaveDataSize() const {
|
||||||
return raw.device_save_data_size;
|
return raw.device_save_data_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 NACP::GetParentalControlFlag() const {
|
||||||
|
return raw.parental_control;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::array<u8, 0x20>& NACP::GetRatingAge() const {
|
||||||
|
return raw.rating_age;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<u8> NACP::GetRawBytes() const {
|
std::vector<u8> NACP::GetRawBytes() const {
|
||||||
std::vector<u8> out(sizeof(RawNACP));
|
std::vector<u8> out(sizeof(RawNACP));
|
||||||
std::memcpy(out.data(), &raw, sizeof(RawNACP));
|
std::memcpy(out.data(), &raw, sizeof(RawNACP));
|
||||||
|
|
|
@ -114,6 +114,8 @@ public:
|
||||||
std::vector<u8> GetRawBytes() const;
|
std::vector<u8> GetRawBytes() const;
|
||||||
bool GetUserAccountSwitchLock() const;
|
bool GetUserAccountSwitchLock() const;
|
||||||
u64 GetDeviceSaveDataSize() const;
|
u64 GetDeviceSaveDataSize() const;
|
||||||
|
u32 GetParentalControlFlag() const;
|
||||||
|
const std::array<u8, 0x20>& GetRatingAge() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RawNACP raw{};
|
RawNACP raw{};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -5,45 +5,34 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/common_sizes.h"
|
||||||
#include "core/hle/kernel/k_address_space_info.h"
|
#include "core/hle/kernel/k_address_space_info.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
enum : u64 {
|
|
||||||
Size_1_MB = 0x100000,
|
|
||||||
Size_2_MB = 2 * Size_1_MB,
|
|
||||||
Size_128_MB = 128 * Size_1_MB,
|
|
||||||
Size_1_GB = 0x40000000,
|
|
||||||
Size_2_GB = 2 * Size_1_GB,
|
|
||||||
Size_4_GB = 4 * Size_1_GB,
|
|
||||||
Size_6_GB = 6 * Size_1_GB,
|
|
||||||
Size_64_GB = 64 * Size_1_GB,
|
|
||||||
Size_512_GB = 512 * Size_1_GB,
|
|
||||||
Invalid = std::numeric_limits<u64>::max(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
|
constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
|
||||||
{ .bit_width = 32, .address = Size_2_MB , .size = Size_1_GB - Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
|
{ .bit_width = 32, .address = Common::Size_2_MB , .size = Common::Size_1_GB - Common::Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
|
||||||
{ .bit_width = 32, .address = Size_1_GB , .size = Size_4_GB - Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
|
{ .bit_width = 32, .address = Common::Size_1_GB , .size = Common::Size_4_GB - Common::Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
|
||||||
{ .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
{ .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
||||||
{ .bit_width = 32, .address = Invalid , .size = Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
{ .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
||||||
{ .bit_width = 36, .address = Size_128_MB, .size = Size_2_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
|
{ .bit_width = 36, .address = Common::Size_128_MB , .size = Common::Size_2_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
|
||||||
{ .bit_width = 36, .address = Size_2_GB , .size = Size_64_GB - Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
|
{ .bit_width = 36, .address = Common::Size_2_GB , .size = Common::Size_64_GB - Common::Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
|
||||||
{ .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
{ .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
||||||
{ .bit_width = 36, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
{ .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
||||||
{ .bit_width = 39, .address = Size_128_MB, .size = Size_512_GB - Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
|
{ .bit_width = 39, .address = Common::Size_128_MB , .size = Common::Size_512_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
|
||||||
{ .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
|
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
|
||||||
{ .bit_width = 39, .address = Invalid , .size = Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
|
||||||
{ .bit_width = 39, .address = Invalid , .size = Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
|
||||||
{ .bit_width = 39, .address = Invalid , .size = Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
|
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
|
||||||
}};
|
}};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
constexpr bool IsAllowedIndexForAddress(std::size_t index) {
|
constexpr bool IsAllowedIndexForAddress(std::size_t index) {
|
||||||
return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Invalid;
|
return index < AddressSpaceInfos.size() &&
|
||||||
|
AddressSpaceInfos[index].address != Common::Size_Invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
using IndexArray =
|
using IndexArray =
|
||||||
|
|
|
@ -1,23 +1,69 @@
|
||||||
// Copyright 2020 yuzu Emulator Project
|
// Copyright 2021 yuzu Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "common/alignment.h"
|
||||||
|
#include "common/common_sizes.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/device_memory.h"
|
#include "core/device_memory.h"
|
||||||
|
#include "core/hle/kernel/k_memory_region.h"
|
||||||
|
#include "core/hle/kernel/k_memory_region_type.h"
|
||||||
|
#include "core/hle/kernel/memory_types.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
constexpr std::size_t KernelAslrAlignment = 2 * 1024 * 1024;
|
constexpr std::size_t L1BlockSize = Common::Size_1_GB;
|
||||||
|
constexpr std::size_t L2BlockSize = Common::Size_2_MB;
|
||||||
|
|
||||||
|
constexpr std::size_t GetMaximumOverheadSize(std::size_t size) {
|
||||||
|
return (Common::DivideUp(size, L1BlockSize) + Common::DivideUp(size, L2BlockSize)) * PageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr std::size_t MainMemorySize = Common::Size_4_GB;
|
||||||
|
constexpr std::size_t MainMemorySizeMax = Common::Size_8_GB;
|
||||||
|
|
||||||
|
constexpr std::size_t ReservedEarlyDramSize = 0x60000;
|
||||||
|
constexpr std::size_t DramPhysicalAddress = 0x80000000;
|
||||||
|
|
||||||
|
constexpr std::size_t KernelAslrAlignment = Common::Size_2_MB;
|
||||||
constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39;
|
constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39;
|
||||||
constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48;
|
constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48;
|
||||||
|
|
||||||
constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth;
|
constexpr std::size_t KernelVirtualAddressSpaceBase = 0ULL - KernelVirtualAddressSpaceWidth;
|
||||||
constexpr std::size_t KernelVirtualAddressSpaceEnd =
|
constexpr std::size_t KernelVirtualAddressSpaceEnd =
|
||||||
KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment);
|
KernelVirtualAddressSpaceBase + (KernelVirtualAddressSpaceWidth - KernelAslrAlignment);
|
||||||
constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1;
|
constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceEnd - 1ULL;
|
||||||
constexpr std::size_t KernelVirtualAddressSpaceSize =
|
constexpr std::size_t KernelVirtualAddressSpaceSize =
|
||||||
KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase;
|
KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase;
|
||||||
|
constexpr std::size_t KernelVirtualAddressCodeBase = KernelVirtualAddressSpaceBase;
|
||||||
|
constexpr std::size_t KernelVirtualAddressCodeSize = 0x62000;
|
||||||
|
constexpr std::size_t KernelVirtualAddressCodeEnd =
|
||||||
|
KernelVirtualAddressCodeBase + KernelVirtualAddressCodeSize;
|
||||||
|
|
||||||
|
constexpr std::size_t KernelPhysicalAddressSpaceBase = 0ULL;
|
||||||
|
constexpr std::size_t KernelPhysicalAddressSpaceEnd =
|
||||||
|
KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceWidth;
|
||||||
|
constexpr std::size_t KernelPhysicalAddressSpaceLast = KernelPhysicalAddressSpaceEnd - 1ULL;
|
||||||
|
constexpr std::size_t KernelPhysicalAddressSpaceSize =
|
||||||
|
KernelPhysicalAddressSpaceEnd - KernelPhysicalAddressSpaceBase;
|
||||||
|
constexpr std::size_t KernelPhysicalAddressCodeBase = DramPhysicalAddress + ReservedEarlyDramSize;
|
||||||
|
|
||||||
|
constexpr std::size_t KernelPageTableHeapSize = GetMaximumOverheadSize(MainMemorySizeMax);
|
||||||
|
constexpr std::size_t KernelInitialPageHeapSize = Common::Size_128_KB;
|
||||||
|
|
||||||
|
constexpr std::size_t KernelSlabHeapDataSize = Common::Size_5_MB;
|
||||||
|
constexpr std::size_t KernelSlabHeapGapsSize = Common::Size_2_MB - Common::Size_64_KB;
|
||||||
|
constexpr std::size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize;
|
||||||
|
|
||||||
|
// NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860.
|
||||||
|
constexpr std::size_t KernelSlabHeapAdditionalSize = 0x68000ULL;
|
||||||
|
|
||||||
|
constexpr std::size_t KernelResourceSize =
|
||||||
|
KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize;
|
||||||
|
|
||||||
constexpr bool IsKernelAddressKey(VAddr key) {
|
constexpr bool IsKernelAddressKey(VAddr key) {
|
||||||
return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
|
return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
|
||||||
|
@ -27,64 +73,327 @@ constexpr bool IsKernelAddress(VAddr address) {
|
||||||
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
|
return KernelVirtualAddressSpaceBase <= address && address < KernelVirtualAddressSpaceEnd;
|
||||||
}
|
}
|
||||||
|
|
||||||
class KMemoryRegion final {
|
|
||||||
friend class KMemoryLayout;
|
|
||||||
|
|
||||||
public:
|
|
||||||
constexpr PAddr StartAddress() const {
|
|
||||||
return start_address;
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr PAddr EndAddress() const {
|
|
||||||
return end_address;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
constexpr KMemoryRegion() = default;
|
|
||||||
constexpr KMemoryRegion(PAddr start_address, PAddr end_address)
|
|
||||||
: start_address{start_address}, end_address{end_address} {}
|
|
||||||
|
|
||||||
const PAddr start_address{};
|
|
||||||
const PAddr end_address{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class KMemoryLayout final {
|
class KMemoryLayout final {
|
||||||
public:
|
public:
|
||||||
constexpr const KMemoryRegion& Application() const {
|
KMemoryLayout();
|
||||||
return application;
|
|
||||||
|
KMemoryRegionTree& GetVirtualMemoryRegionTree() {
|
||||||
|
return virtual_tree;
|
||||||
|
}
|
||||||
|
const KMemoryRegionTree& GetVirtualMemoryRegionTree() const {
|
||||||
|
return virtual_tree;
|
||||||
|
}
|
||||||
|
KMemoryRegionTree& GetPhysicalMemoryRegionTree() {
|
||||||
|
return physical_tree;
|
||||||
|
}
|
||||||
|
const KMemoryRegionTree& GetPhysicalMemoryRegionTree() const {
|
||||||
|
return physical_tree;
|
||||||
|
}
|
||||||
|
KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() {
|
||||||
|
return virtual_linear_tree;
|
||||||
|
}
|
||||||
|
const KMemoryRegionTree& GetVirtualLinearMemoryRegionTree() const {
|
||||||
|
return virtual_linear_tree;
|
||||||
|
}
|
||||||
|
KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() {
|
||||||
|
return physical_linear_tree;
|
||||||
|
}
|
||||||
|
const KMemoryRegionTree& GetPhysicalLinearMemoryRegionTree() const {
|
||||||
|
return physical_linear_tree;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const KMemoryRegion& Applet() const {
|
VAddr GetLinearVirtualAddress(PAddr address) const {
|
||||||
return applet;
|
return address + linear_phys_to_virt_diff;
|
||||||
|
}
|
||||||
|
PAddr GetLinearPhysicalAddress(VAddr address) const {
|
||||||
|
return address + linear_virt_to_phys_diff;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const KMemoryRegion& System() const {
|
const KMemoryRegion* FindVirtual(VAddr address) const {
|
||||||
return system;
|
return Find(address, GetVirtualMemoryRegionTree());
|
||||||
|
}
|
||||||
|
const KMemoryRegion* FindPhysical(PAddr address) const {
|
||||||
|
return Find(address, GetPhysicalMemoryRegionTree());
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr KMemoryLayout GetDefaultLayout() {
|
const KMemoryRegion* FindVirtualLinear(VAddr address) const {
|
||||||
constexpr std::size_t application_size{0xcd500000};
|
return Find(address, GetVirtualLinearMemoryRegionTree());
|
||||||
constexpr std::size_t applet_size{0x1fb00000};
|
}
|
||||||
constexpr PAddr application_start_address{Core::DramMemoryMap::End - application_size};
|
const KMemoryRegion* FindPhysicalLinear(PAddr address) const {
|
||||||
constexpr PAddr application_end_address{Core::DramMemoryMap::End};
|
return Find(address, GetPhysicalLinearMemoryRegionTree());
|
||||||
constexpr PAddr applet_start_address{application_start_address - applet_size};
|
}
|
||||||
constexpr PAddr applet_end_address{applet_start_address + applet_size};
|
|
||||||
constexpr PAddr system_start_address{Core::DramMemoryMap::SlabHeapEnd};
|
VAddr GetMainStackTopAddress(s32 core_id) const {
|
||||||
constexpr PAddr system_end_address{applet_start_address};
|
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscMainStack);
|
||||||
return {application_start_address, application_end_address, applet_start_address,
|
}
|
||||||
applet_end_address, system_start_address, system_end_address};
|
VAddr GetIdleStackTopAddress(s32 core_id) const {
|
||||||
|
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscIdleStack);
|
||||||
|
}
|
||||||
|
VAddr GetExceptionStackTopAddress(s32 core_id) const {
|
||||||
|
return GetStackTopAddress(core_id, KMemoryRegionType_KernelMiscExceptionStack);
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr GetSlabRegionAddress() const {
|
||||||
|
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelSlab))
|
||||||
|
.GetAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
const KMemoryRegion& GetDeviceRegion(KMemoryRegionType type) const {
|
||||||
|
return Dereference(GetPhysicalMemoryRegionTree().FindFirstDerived(type));
|
||||||
|
}
|
||||||
|
PAddr GetDevicePhysicalAddress(KMemoryRegionType type) const {
|
||||||
|
return GetDeviceRegion(type).GetAddress();
|
||||||
|
}
|
||||||
|
VAddr GetDeviceVirtualAddress(KMemoryRegionType type) const {
|
||||||
|
return GetDeviceRegion(type).GetPairAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
const KMemoryRegion& GetPoolManagementRegion() const {
|
||||||
|
return Dereference(
|
||||||
|
GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramPoolManagement));
|
||||||
|
}
|
||||||
|
const KMemoryRegion& GetPageTableHeapRegion() const {
|
||||||
|
return Dereference(
|
||||||
|
GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_VirtualDramKernelPtHeap));
|
||||||
|
}
|
||||||
|
const KMemoryRegion& GetKernelStackRegion() const {
|
||||||
|
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelStack));
|
||||||
|
}
|
||||||
|
const KMemoryRegion& GetTempRegion() const {
|
||||||
|
return Dereference(GetVirtualMemoryRegionTree().FindByType(KMemoryRegionType_KernelTemp));
|
||||||
|
}
|
||||||
|
|
||||||
|
const KMemoryRegion& GetKernelTraceBufferRegion() const {
|
||||||
|
return Dereference(GetVirtualLinearMemoryRegionTree().FindByType(
|
||||||
|
KMemoryRegionType_VirtualDramKernelTraceBuffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
const KMemoryRegion& GetVirtualLinearRegion(VAddr address) const {
|
||||||
|
return Dereference(FindVirtualLinear(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
const KMemoryRegion* GetPhysicalKernelTraceBufferRegion() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_KernelTraceBuffer);
|
||||||
|
}
|
||||||
|
const KMemoryRegion* GetPhysicalOnMemoryBootImageRegion() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_OnMemoryBootImage);
|
||||||
|
}
|
||||||
|
const KMemoryRegion* GetPhysicalDTBRegion() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_DTB);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
|
||||||
|
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
|
||||||
|
KMemoryRegionType_DramUserPool);
|
||||||
|
}
|
||||||
|
bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address) const {
|
||||||
|
return IsTypedAddress(region, address, GetVirtualLinearMemoryRegionTree(),
|
||||||
|
KMemoryRegionType_VirtualDramUserPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsHeapPhysicalAddress(const KMemoryRegion*& region, PAddr address, size_t size) const {
|
||||||
|
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
|
||||||
|
KMemoryRegionType_DramUserPool);
|
||||||
|
}
|
||||||
|
bool IsHeapVirtualAddress(const KMemoryRegion*& region, VAddr address, size_t size) const {
|
||||||
|
return IsTypedAddress(region, address, size, GetVirtualLinearMemoryRegionTree(),
|
||||||
|
KMemoryRegionType_VirtualDramUserPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address) const {
|
||||||
|
return IsTypedAddress(region, address, GetPhysicalLinearMemoryRegionTree(),
|
||||||
|
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
|
||||||
|
}
|
||||||
|
bool IsLinearMappedPhysicalAddress(const KMemoryRegion*& region, PAddr address,
|
||||||
|
size_t size) const {
|
||||||
|
return IsTypedAddress(region, address, size, GetPhysicalLinearMemoryRegionTree(),
|
||||||
|
static_cast<KMemoryRegionType>(KMemoryRegionAttr_LinearMapped));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<size_t, size_t> GetTotalAndKernelMemorySizes() const {
|
||||||
|
size_t total_size = 0, kernel_size = 0;
|
||||||
|
for (const auto& region : GetPhysicalMemoryRegionTree()) {
|
||||||
|
if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
|
||||||
|
total_size += region.GetSize();
|
||||||
|
if (!region.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
|
||||||
|
kernel_size += region.GetSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::make_pair(total_size, kernel_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
|
||||||
|
VAddr linear_virtual_start);
|
||||||
|
static size_t GetResourceRegionSizeForInit();
|
||||||
|
|
||||||
|
auto GetKernelRegionExtents() const {
|
||||||
|
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel);
|
||||||
|
}
|
||||||
|
auto GetKernelCodeRegionExtents() const {
|
||||||
|
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelCode);
|
||||||
|
}
|
||||||
|
auto GetKernelStackRegionExtents() const {
|
||||||
|
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelStack);
|
||||||
|
}
|
||||||
|
auto GetKernelMiscRegionExtents() const {
|
||||||
|
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelMisc);
|
||||||
|
}
|
||||||
|
auto GetKernelSlabRegionExtents() const {
|
||||||
|
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_KernelSlab);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetLinearRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionAttr_LinearMapped);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetLinearRegionVirtualExtents() const {
|
||||||
|
const auto physical = GetLinearRegionPhysicalExtents();
|
||||||
|
return KMemoryRegion(GetLinearVirtualAddress(physical.GetAddress()),
|
||||||
|
GetLinearVirtualAddress(physical.GetLastAddress()), 0,
|
||||||
|
KMemoryRegionType_None);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetMainMemoryPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Dram);
|
||||||
|
}
|
||||||
|
auto GetCarveoutRegionExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionAttr_CarveoutProtected);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetKernelRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramKernelBase);
|
||||||
|
}
|
||||||
|
auto GetKernelCodeRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramKernelCode);
|
||||||
|
}
|
||||||
|
auto GetKernelSlabRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramKernelSlab);
|
||||||
|
}
|
||||||
|
auto GetKernelPageTableHeapRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramKernelPtHeap);
|
||||||
|
}
|
||||||
|
auto GetKernelInitPageTableRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramKernelInitPt);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetKernelPoolManagementRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramPoolManagement);
|
||||||
|
}
|
||||||
|
auto GetKernelPoolPartitionRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramPoolPartition);
|
||||||
|
}
|
||||||
|
auto GetKernelSystemPoolRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramSystemPool);
|
||||||
|
}
|
||||||
|
auto GetKernelSystemNonSecurePoolRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramSystemNonSecurePool);
|
||||||
|
}
|
||||||
|
auto GetKernelAppletPoolRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramAppletPool);
|
||||||
|
}
|
||||||
|
auto GetKernelApplicationPoolRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_DramApplicationPool);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetKernelTraceBufferRegionPhysicalExtents() const {
|
||||||
|
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionType_KernelTraceBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
constexpr KMemoryLayout(PAddr application_start_address, std::size_t application_size,
|
template <typename AddressType>
|
||||||
PAddr applet_start_address, std::size_t applet_size,
|
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address,
|
||||||
PAddr system_start_address, std::size_t system_size)
|
const KMemoryRegionTree& tree, KMemoryRegionType type) {
|
||||||
: application{application_start_address, application_size},
|
// Check if the cached region already contains the address.
|
||||||
applet{applet_start_address, applet_size}, system{system_start_address, system_size} {}
|
if (region != nullptr && region->Contains(address)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const KMemoryRegion application;
|
// Find the containing region, and update the cache.
|
||||||
const KMemoryRegion applet;
|
if (const KMemoryRegion* found = tree.Find(address);
|
||||||
const KMemoryRegion system;
|
found != nullptr && found->IsDerivedFrom(type)) {
|
||||||
|
region = found;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename AddressType>
|
||||||
|
static bool IsTypedAddress(const KMemoryRegion*& region, AddressType address, size_t size,
|
||||||
|
const KMemoryRegionTree& tree, KMemoryRegionType type) {
|
||||||
|
// Get the end of the checked region.
|
||||||
|
const u64 last_address = address + size - 1;
|
||||||
|
|
||||||
|
// Walk the tree to verify the region is correct.
|
||||||
|
const KMemoryRegion* cur =
|
||||||
|
(region != nullptr && region->Contains(address)) ? region : tree.Find(address);
|
||||||
|
while (cur != nullptr && cur->IsDerivedFrom(type)) {
|
||||||
|
if (last_address <= cur->GetLastAddress()) {
|
||||||
|
region = cur;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cur = cur->GetNext();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename AddressType>
|
||||||
|
static const KMemoryRegion* Find(AddressType address, const KMemoryRegionTree& tree) {
|
||||||
|
return tree.Find(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
static KMemoryRegion& Dereference(KMemoryRegion* region) {
|
||||||
|
ASSERT(region != nullptr);
|
||||||
|
return *region;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const KMemoryRegion& Dereference(const KMemoryRegion* region) {
|
||||||
|
ASSERT(region != nullptr);
|
||||||
|
return *region;
|
||||||
|
}
|
||||||
|
|
||||||
|
VAddr GetStackTopAddress(s32 core_id, KMemoryRegionType type) const {
|
||||||
|
const auto& region = Dereference(
|
||||||
|
GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id)));
|
||||||
|
ASSERT(region.GetEndAddress() != 0);
|
||||||
|
return region.GetEndAddress();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
u64 linear_phys_to_virt_diff{};
|
||||||
|
u64 linear_virt_to_phys_diff{};
|
||||||
|
KMemoryRegionAllocator memory_region_allocator;
|
||||||
|
KMemoryRegionTree virtual_tree;
|
||||||
|
KMemoryRegionTree physical_tree;
|
||||||
|
KMemoryRegionTree virtual_linear_tree;
|
||||||
|
KMemoryRegionTree physical_linear_tree;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace Init {
|
||||||
|
|
||||||
|
// These should be generic, regardless of board.
|
||||||
|
void SetupPoolPartitionMemoryRegions(KMemoryLayout& memory_layout);
|
||||||
|
|
||||||
|
// These may be implemented in a board-specific manner.
|
||||||
|
void SetupDevicePhysicalMemoryRegions(KMemoryLayout& memory_layout);
|
||||||
|
void SetupDramPhysicalMemoryRegions(KMemoryLayout& memory_layout);
|
||||||
|
|
||||||
|
} // namespace Init
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -173,4 +173,16 @@ ResultCode KMemoryManager::Free(KPageLinkedList& page_list, std::size_t num_page
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t KMemoryManager::Impl::CalculateManagementOverheadSize(std::size_t region_size) {
|
||||||
|
const std::size_t ref_count_size = (region_size / PageSize) * sizeof(u16);
|
||||||
|
const std::size_t optimize_map_size =
|
||||||
|
(Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
|
||||||
|
Common::BitSize<u64>()) *
|
||||||
|
sizeof(u64);
|
||||||
|
const std::size_t manager_meta_size =
|
||||||
|
Common::AlignUp(optimize_map_size + ref_count_size, PageSize);
|
||||||
|
const std::size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(region_size);
|
||||||
|
return manager_meta_size + page_heap_size;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -29,6 +29,10 @@ public:
|
||||||
|
|
||||||
Shift = 4,
|
Shift = 4,
|
||||||
Mask = (0xF << Shift),
|
Mask = (0xF << Shift),
|
||||||
|
|
||||||
|
// Aliases.
|
||||||
|
Unsafe = Application,
|
||||||
|
Secure = System,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class Direction : u32 {
|
enum class Direction : u32 {
|
||||||
|
@ -56,6 +60,10 @@ public:
|
||||||
static constexpr std::size_t MaxManagerCount = 10;
|
static constexpr std::size_t MaxManagerCount = 10;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static std::size_t CalculateManagementOverheadSize(std::size_t region_size) {
|
||||||
|
return Impl::CalculateManagementOverheadSize(region_size);
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr u32 EncodeOption(Pool pool, Direction dir) {
|
static constexpr u32 EncodeOption(Pool pool, Direction dir) {
|
||||||
return (static_cast<u32>(pool) << static_cast<u32>(Pool::Shift)) |
|
return (static_cast<u32>(pool) << static_cast<u32>(Pool::Shift)) |
|
||||||
(static_cast<u32>(dir) << static_cast<u32>(Direction::Shift));
|
(static_cast<u32>(dir) << static_cast<u32>(Direction::Shift));
|
||||||
|
@ -85,6 +93,16 @@ private:
|
||||||
KPageHeap heap;
|
KPageHeap heap;
|
||||||
Pool pool{};
|
Pool pool{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static std::size_t CalculateManagementOverheadSize(std::size_t region_size);
|
||||||
|
|
||||||
|
static constexpr std::size_t CalculateOptimizedProcessOverheadSize(
|
||||||
|
std::size_t region_size) {
|
||||||
|
return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
|
||||||
|
Common::BitSize<u64>()) *
|
||||||
|
sizeof(u64);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Impl() = default;
|
Impl() = default;
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedul
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
|
u64 KScheduler::UpdateHighestPriorityThread(KThread* highest_thread) {
|
||||||
std::scoped_lock lock{guard};
|
KScopedSpinLock lk{guard};
|
||||||
if (KThread* prev_highest_thread = state.highest_priority_thread;
|
if (KThread* prev_highest_thread = state.highest_priority_thread;
|
||||||
prev_highest_thread != highest_thread) {
|
prev_highest_thread != highest_thread) {
|
||||||
if (prev_highest_thread != nullptr) {
|
if (prev_highest_thread != nullptr) {
|
||||||
|
@ -637,11 +637,11 @@ void KScheduler::RescheduleCurrentCore() {
|
||||||
if (phys_core.IsInterrupted()) {
|
if (phys_core.IsInterrupted()) {
|
||||||
phys_core.ClearInterrupt();
|
phys_core.ClearInterrupt();
|
||||||
}
|
}
|
||||||
guard.lock();
|
guard.Lock();
|
||||||
if (state.needs_scheduling.load()) {
|
if (state.needs_scheduling.load()) {
|
||||||
Schedule();
|
Schedule();
|
||||||
} else {
|
} else {
|
||||||
guard.unlock();
|
guard.Unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -669,7 +669,7 @@ void KScheduler::Unload(KThread* thread) {
|
||||||
} else {
|
} else {
|
||||||
prev_thread = nullptr;
|
prev_thread = nullptr;
|
||||||
}
|
}
|
||||||
thread->context_guard.unlock();
|
thread->context_guard.Unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,7 +713,7 @@ void KScheduler::ScheduleImpl() {
|
||||||
|
|
||||||
// If we're not actually switching thread, there's nothing to do.
|
// If we're not actually switching thread, there's nothing to do.
|
||||||
if (next_thread == current_thread.load()) {
|
if (next_thread == current_thread.load()) {
|
||||||
guard.unlock();
|
guard.Unlock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -732,7 +732,7 @@ void KScheduler::ScheduleImpl() {
|
||||||
} else {
|
} else {
|
||||||
old_context = &idle_thread->GetHostContext();
|
old_context = &idle_thread->GetHostContext();
|
||||||
}
|
}
|
||||||
guard.unlock();
|
guard.Unlock();
|
||||||
|
|
||||||
Common::Fiber::YieldTo(*old_context, *switch_fiber);
|
Common::Fiber::YieldTo(*old_context, *switch_fiber);
|
||||||
/// When a thread wakes up, the scheduler may have changed to other in another core.
|
/// When a thread wakes up, the scheduler may have changed to other in another core.
|
||||||
|
@ -748,24 +748,24 @@ void KScheduler::OnSwitch(void* this_scheduler) {
|
||||||
void KScheduler::SwitchToCurrent() {
|
void KScheduler::SwitchToCurrent() {
|
||||||
while (true) {
|
while (true) {
|
||||||
{
|
{
|
||||||
std::scoped_lock lock{guard};
|
KScopedSpinLock lk{guard};
|
||||||
current_thread.store(state.highest_priority_thread);
|
current_thread.store(state.highest_priority_thread);
|
||||||
state.needs_scheduling.store(false);
|
state.needs_scheduling.store(false);
|
||||||
}
|
}
|
||||||
const auto is_switch_pending = [this] {
|
const auto is_switch_pending = [this] {
|
||||||
std::scoped_lock lock{guard};
|
KScopedSpinLock lk{guard};
|
||||||
return state.needs_scheduling.load();
|
return state.needs_scheduling.load();
|
||||||
};
|
};
|
||||||
do {
|
do {
|
||||||
auto next_thread = current_thread.load();
|
auto next_thread = current_thread.load();
|
||||||
if (next_thread != nullptr) {
|
if (next_thread != nullptr) {
|
||||||
next_thread->context_guard.lock();
|
next_thread->context_guard.Lock();
|
||||||
if (next_thread->GetRawState() != ThreadState::Runnable) {
|
if (next_thread->GetRawState() != ThreadState::Runnable) {
|
||||||
next_thread->context_guard.unlock();
|
next_thread->context_guard.Unlock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (next_thread->GetActiveCore() != core_id) {
|
if (next_thread->GetActiveCore() != core_id) {
|
||||||
next_thread->context_guard.unlock();
|
next_thread->context_guard.Unlock();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,16 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
// This file references various implementation details from Atmosphere, an open-source firmware for
|
|
||||||
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/spin_lock.h"
|
|
||||||
#include "core/hle/kernel/global_scheduler_context.h"
|
#include "core/hle/kernel/global_scheduler_context.h"
|
||||||
#include "core/hle/kernel/k_priority_queue.h"
|
#include "core/hle/kernel/k_priority_queue.h"
|
||||||
#include "core/hle/kernel/k_scheduler_lock.h"
|
#include "core/hle/kernel/k_scheduler_lock.h"
|
||||||
#include "core/hle/kernel/k_scoped_lock.h"
|
#include "core/hle/kernel/k_scoped_lock.h"
|
||||||
|
#include "core/hle/kernel/k_spin_lock.h"
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
class Fiber;
|
class Fiber;
|
||||||
|
@ -195,7 +192,7 @@ private:
|
||||||
u64 last_context_switch_time{};
|
u64 last_context_switch_time{};
|
||||||
const s32 core_id;
|
const s32 core_id;
|
||||||
|
|
||||||
Common::SpinLock guard{};
|
KSpinLock guard{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
|
class KScopedSchedulerLock : KScopedLock<GlobalSchedulerContext::LockType> {
|
||||||
|
|
|
@ -2,14 +2,11 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
// This file references various implementation details from Atmosphere, an open-source firmware for
|
|
||||||
// the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX.
|
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/spin_lock.h"
|
|
||||||
#include "core/hardware_properties.h"
|
#include "core/hardware_properties.h"
|
||||||
|
#include "core/hle/kernel/k_spin_lock.h"
|
||||||
#include "core/hle/kernel/k_thread.h"
|
#include "core/hle/kernel/k_thread.h"
|
||||||
#include "core/hle/kernel/kernel.h"
|
#include "core/hle/kernel/kernel.h"
|
||||||
|
|
||||||
|
@ -34,7 +31,7 @@ public:
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, we want to disable scheduling and acquire the spinlock.
|
// Otherwise, we want to disable scheduling and acquire the spinlock.
|
||||||
SchedulerType::DisableScheduling(kernel);
|
SchedulerType::DisableScheduling(kernel);
|
||||||
spin_lock.lock();
|
spin_lock.Lock();
|
||||||
|
|
||||||
// For debug, ensure that our state is valid.
|
// For debug, ensure that our state is valid.
|
||||||
ASSERT(lock_count == 0);
|
ASSERT(lock_count == 0);
|
||||||
|
@ -58,7 +55,7 @@ public:
|
||||||
|
|
||||||
// Note that we no longer hold the lock, and unlock the spinlock.
|
// Note that we no longer hold the lock, and unlock the spinlock.
|
||||||
owner_thread = nullptr;
|
owner_thread = nullptr;
|
||||||
spin_lock.unlock();
|
spin_lock.Unlock();
|
||||||
|
|
||||||
// Enable scheduling, and perform a rescheduling operation.
|
// Enable scheduling, and perform a rescheduling operation.
|
||||||
SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
|
SchedulerType::EnableScheduling(kernel, cores_needing_scheduling);
|
||||||
|
@ -67,7 +64,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
KernelCore& kernel;
|
KernelCore& kernel;
|
||||||
Common::SpinLock spin_lock{};
|
KAlignedSpinLock spin_lock{};
|
||||||
s32 lock_count{};
|
s32 lock_count{};
|
||||||
KThread* owner_thread{};
|
KThread* owner_thread{};
|
||||||
};
|
};
|
||||||
|
|
|
@ -28,6 +28,12 @@ private:
|
||||||
std::atomic_flag lck = ATOMIC_FLAG_INIT;
|
std::atomic_flag lck = ATOMIC_FLAG_INIT;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO(bunnei): Alias for now, in case we want to implement these accurately in the future.
|
||||||
|
using KAlignedSpinLock = KSpinLock;
|
||||||
|
using KNotAlignedSpinLock = KSpinLock;
|
||||||
|
|
||||||
using KScopedSpinLock = KScopedLock<KSpinLock>;
|
using KScopedSpinLock = KScopedLock<KSpinLock>;
|
||||||
|
using KScopedAlignedSpinLock = KScopedLock<KAlignedSpinLock>;
|
||||||
|
using KScopedNotAlignedSpinLock = KScopedLock<KNotAlignedSpinLock>;
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -6,14 +6,18 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
#define BOARD_NINTENDO_NX
|
||||||
|
|
||||||
|
#ifdef BOARD_NINTENDO_NX
|
||||||
|
|
||||||
|
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class KSystemControl {
|
using Kernel::Board::Nintendo::Nx::KSystemControl;
|
||||||
public:
|
|
||||||
KSystemControl() = default;
|
|
||||||
|
|
||||||
static u64 GenerateRandomRange(u64 min, u64 max);
|
|
||||||
static u64 GenerateRandomU64();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "Unknown board for KSystemControl"
|
||||||
|
#endif
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/intrusive_red_black_tree.h"
|
#include "common/intrusive_red_black_tree.h"
|
||||||
#include "common/spin_lock.h"
|
|
||||||
#include "core/arm/arm_interface.h"
|
#include "core/arm/arm_interface.h"
|
||||||
#include "core/hle/kernel/k_affinity_mask.h"
|
#include "core/hle/kernel/k_affinity_mask.h"
|
||||||
#include "core/hle/kernel/k_light_lock.h"
|
#include "core/hle/kernel/k_light_lock.h"
|
||||||
|
#include "core/hle/kernel/k_spin_lock.h"
|
||||||
#include "core/hle/kernel/k_synchronization_object.h"
|
#include "core/hle/kernel/k_synchronization_object.h"
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/svc_common.h"
|
#include "core/hle/kernel/svc_common.h"
|
||||||
|
@ -732,7 +732,7 @@ private:
|
||||||
s8 priority_inheritance_count{};
|
s8 priority_inheritance_count{};
|
||||||
bool resource_limit_release_hint{};
|
bool resource_limit_release_hint{};
|
||||||
StackParameters stack_parameters{};
|
StackParameters stack_parameters{};
|
||||||
Common::SpinLock context_guard{};
|
KSpinLock context_guard{};
|
||||||
|
|
||||||
// For emulation
|
// For emulation
|
||||||
std::shared_ptr<Common::Fiber> host_context{};
|
std::shared_ptr<Common::Fiber> host_context{};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 Citra Emulator Project
|
// Copyright 2021 yuzu Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
#include "common/common_sizes.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
|
@ -268,45 +269,314 @@ struct KernelCore::Impl {
|
||||||
return schedulers[thread_id]->GetCurrentThread();
|
return schedulers[thread_id]->GetCurrentThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeriveInitialMemoryLayout(KMemoryLayout& memory_layout) {
|
||||||
|
// Insert the root region for the virtual memory tree, from which all other regions will
|
||||||
|
// derive.
|
||||||
|
memory_layout.GetVirtualMemoryRegionTree().InsertDirectly(
|
||||||
|
KernelVirtualAddressSpaceBase,
|
||||||
|
KernelVirtualAddressSpaceBase + KernelVirtualAddressSpaceSize - 1);
|
||||||
|
|
||||||
|
// Insert the root region for the physical memory tree, from which all other regions will
|
||||||
|
// derive.
|
||||||
|
memory_layout.GetPhysicalMemoryRegionTree().InsertDirectly(
|
||||||
|
KernelPhysicalAddressSpaceBase,
|
||||||
|
KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceSize - 1);
|
||||||
|
|
||||||
|
// Save start and end for ease of use.
|
||||||
|
const VAddr code_start_virt_addr = KernelVirtualAddressCodeBase;
|
||||||
|
const VAddr code_end_virt_addr = KernelVirtualAddressCodeEnd;
|
||||||
|
|
||||||
|
// Setup the containing kernel region.
|
||||||
|
constexpr size_t KernelRegionSize = Common::Size_1_GB;
|
||||||
|
constexpr size_t KernelRegionAlign = Common::Size_1_GB;
|
||||||
|
constexpr VAddr kernel_region_start =
|
||||||
|
Common::AlignDown(code_start_virt_addr, KernelRegionAlign);
|
||||||
|
size_t kernel_region_size = KernelRegionSize;
|
||||||
|
if (!(kernel_region_start + KernelRegionSize - 1 <= KernelVirtualAddressSpaceLast)) {
|
||||||
|
kernel_region_size = KernelVirtualAddressSpaceEnd - kernel_region_start;
|
||||||
|
}
|
||||||
|
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||||
|
kernel_region_start, kernel_region_size, KMemoryRegionType_Kernel));
|
||||||
|
|
||||||
|
// Setup the code region.
|
||||||
|
constexpr size_t CodeRegionAlign = PageSize;
|
||||||
|
constexpr VAddr code_region_start =
|
||||||
|
Common::AlignDown(code_start_virt_addr, CodeRegionAlign);
|
||||||
|
constexpr VAddr code_region_end = Common::AlignUp(code_end_virt_addr, CodeRegionAlign);
|
||||||
|
constexpr size_t code_region_size = code_region_end - code_region_start;
|
||||||
|
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||||
|
code_region_start, code_region_size, KMemoryRegionType_KernelCode));
|
||||||
|
|
||||||
|
// Setup board-specific device physical regions.
|
||||||
|
Init::SetupDevicePhysicalMemoryRegions(memory_layout);
|
||||||
|
|
||||||
|
// Determine the amount of space needed for the misc region.
|
||||||
|
size_t misc_region_needed_size;
|
||||||
|
{
|
||||||
|
// Each core has a one page stack for all three stack types (Main, Idle, Exception).
|
||||||
|
misc_region_needed_size = Core::Hardware::NUM_CPU_CORES * (3 * (PageSize + PageSize));
|
||||||
|
|
||||||
|
// Account for each auto-map device.
|
||||||
|
for (const auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
|
||||||
|
if (region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
|
||||||
|
// Check that the region is valid.
|
||||||
|
ASSERT(region.GetEndAddress() != 0);
|
||||||
|
|
||||||
|
// Account for the region.
|
||||||
|
misc_region_needed_size +=
|
||||||
|
PageSize + (Common::AlignUp(region.GetLastAddress(), PageSize) -
|
||||||
|
Common::AlignDown(region.GetAddress(), PageSize));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiply the needed size by three, to account for the need for guard space.
|
||||||
|
misc_region_needed_size *= 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decide on the actual size for the misc region.
|
||||||
|
constexpr size_t MiscRegionAlign = KernelAslrAlignment;
|
||||||
|
constexpr size_t MiscRegionMinimumSize = Common::Size_32_MB;
|
||||||
|
const size_t misc_region_size = Common::AlignUp(
|
||||||
|
std::max(misc_region_needed_size, MiscRegionMinimumSize), MiscRegionAlign);
|
||||||
|
ASSERT(misc_region_size > 0);
|
||||||
|
|
||||||
|
// Setup the misc region.
|
||||||
|
const VAddr misc_region_start =
|
||||||
|
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
|
||||||
|
misc_region_size, MiscRegionAlign, KMemoryRegionType_Kernel);
|
||||||
|
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||||
|
misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
|
||||||
|
|
||||||
|
// Setup the stack region.
|
||||||
|
constexpr size_t StackRegionSize = Common::Size_14_MB;
|
||||||
|
constexpr size_t StackRegionAlign = KernelAslrAlignment;
|
||||||
|
const VAddr stack_region_start =
|
||||||
|
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
|
||||||
|
StackRegionSize, StackRegionAlign, KMemoryRegionType_Kernel);
|
||||||
|
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||||
|
stack_region_start, StackRegionSize, KMemoryRegionType_KernelStack));
|
||||||
|
|
||||||
|
// Determine the size of the resource region.
|
||||||
|
const size_t resource_region_size = memory_layout.GetResourceRegionSizeForInit();
|
||||||
|
|
||||||
|
// Determine the size of the slab region.
|
||||||
|
const size_t slab_region_size = Common::AlignUp(KernelSlabHeapSize, PageSize);
|
||||||
|
ASSERT(slab_region_size <= resource_region_size);
|
||||||
|
|
||||||
|
// Setup the slab region.
|
||||||
|
const PAddr code_start_phys_addr = KernelPhysicalAddressCodeBase;
|
||||||
|
const PAddr code_end_phys_addr = code_start_phys_addr + code_region_size;
|
||||||
|
const PAddr slab_start_phys_addr = code_end_phys_addr;
|
||||||
|
const PAddr slab_end_phys_addr = slab_start_phys_addr + slab_region_size;
|
||||||
|
constexpr size_t SlabRegionAlign = KernelAslrAlignment;
|
||||||
|
const size_t slab_region_needed_size =
|
||||||
|
Common::AlignUp(code_end_phys_addr + slab_region_size, SlabRegionAlign) -
|
||||||
|
Common::AlignDown(code_end_phys_addr, SlabRegionAlign);
|
||||||
|
const VAddr slab_region_start =
|
||||||
|
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
|
||||||
|
slab_region_needed_size, SlabRegionAlign, KMemoryRegionType_Kernel) +
|
||||||
|
(code_end_phys_addr % SlabRegionAlign);
|
||||||
|
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||||
|
slab_region_start, slab_region_size, KMemoryRegionType_KernelSlab));
|
||||||
|
|
||||||
|
// Setup the temp region.
|
||||||
|
constexpr size_t TempRegionSize = Common::Size_128_MB;
|
||||||
|
constexpr size_t TempRegionAlign = KernelAslrAlignment;
|
||||||
|
const VAddr temp_region_start =
|
||||||
|
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
|
||||||
|
TempRegionSize, TempRegionAlign, KMemoryRegionType_Kernel);
|
||||||
|
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(temp_region_start, TempRegionSize,
|
||||||
|
KMemoryRegionType_KernelTemp));
|
||||||
|
|
||||||
|
// Automatically map in devices that have auto-map attributes.
|
||||||
|
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
|
||||||
|
// We only care about kernel regions.
|
||||||
|
if (!region.IsDerivedFrom(KMemoryRegionType_Kernel)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether we should map the region.
|
||||||
|
if (!region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this region has already been mapped, no need to consider it.
|
||||||
|
if (region.HasTypeAttribute(KMemoryRegionAttr_DidKernelMap)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that the region is valid.
|
||||||
|
ASSERT(region.GetEndAddress() != 0);
|
||||||
|
|
||||||
|
// Set the attribute to note we've mapped this region.
|
||||||
|
region.SetTypeAttribute(KMemoryRegionAttr_DidKernelMap);
|
||||||
|
|
||||||
|
// Create a virtual pair region and insert it into the tree.
|
||||||
|
const PAddr map_phys_addr = Common::AlignDown(region.GetAddress(), PageSize);
|
||||||
|
const size_t map_size =
|
||||||
|
Common::AlignUp(region.GetEndAddress(), PageSize) - map_phys_addr;
|
||||||
|
const VAddr map_virt_addr =
|
||||||
|
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
|
||||||
|
map_size, PageSize, KMemoryRegionType_KernelMisc, PageSize);
|
||||||
|
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||||
|
map_virt_addr, map_size, KMemoryRegionType_KernelMiscMappedDevice));
|
||||||
|
region.SetPairAddress(map_virt_addr + region.GetAddress() - map_phys_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Init::SetupDramPhysicalMemoryRegions(memory_layout);
|
||||||
|
|
||||||
|
// Insert a physical region for the kernel code region.
|
||||||
|
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
|
||||||
|
code_start_phys_addr, code_region_size, KMemoryRegionType_DramKernelCode));
|
||||||
|
|
||||||
|
// Insert a physical region for the kernel slab region.
|
||||||
|
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
|
||||||
|
slab_start_phys_addr, slab_region_size, KMemoryRegionType_DramKernelSlab));
|
||||||
|
|
||||||
|
// Determine size available for kernel page table heaps, requiring > 8 MB.
|
||||||
|
const PAddr resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
|
||||||
|
const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
|
||||||
|
ASSERT(page_table_heap_size / Common::Size_4_MB > 2);
|
||||||
|
|
||||||
|
// Insert a physical region for the kernel page table heap region
|
||||||
|
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
|
||||||
|
slab_end_phys_addr, page_table_heap_size, KMemoryRegionType_DramKernelPtHeap));
|
||||||
|
|
||||||
|
// All DRAM regions that we haven't tagged by this point will be mapped under the linear
|
||||||
|
// mapping. Tag them.
|
||||||
|
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
|
||||||
|
if (region.GetType() == KMemoryRegionType_Dram) {
|
||||||
|
// Check that the region is valid.
|
||||||
|
ASSERT(region.GetEndAddress() != 0);
|
||||||
|
|
||||||
|
// Set the linear map attribute.
|
||||||
|
region.SetTypeAttribute(KMemoryRegionAttr_LinearMapped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the linear region extents.
|
||||||
|
const auto linear_extents =
|
||||||
|
memory_layout.GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
|
||||||
|
KMemoryRegionAttr_LinearMapped);
|
||||||
|
ASSERT(linear_extents.GetEndAddress() != 0);
|
||||||
|
|
||||||
|
// Setup the linear mapping region.
|
||||||
|
constexpr size_t LinearRegionAlign = Common::Size_1_GB;
|
||||||
|
const PAddr aligned_linear_phys_start =
|
||||||
|
Common::AlignDown(linear_extents.GetAddress(), LinearRegionAlign);
|
||||||
|
const size_t linear_region_size =
|
||||||
|
Common::AlignUp(linear_extents.GetEndAddress(), LinearRegionAlign) -
|
||||||
|
aligned_linear_phys_start;
|
||||||
|
const VAddr linear_region_start =
|
||||||
|
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(
|
||||||
|
linear_region_size, LinearRegionAlign, KMemoryRegionType_None, LinearRegionAlign);
|
||||||
|
|
||||||
|
const u64 linear_region_phys_to_virt_diff = linear_region_start - aligned_linear_phys_start;
|
||||||
|
|
||||||
|
// Map and create regions for all the linearly-mapped data.
|
||||||
|
{
|
||||||
|
PAddr cur_phys_addr = 0;
|
||||||
|
u64 cur_size = 0;
|
||||||
|
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
|
||||||
|
if (!region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ASSERT(region.GetEndAddress() != 0);
|
||||||
|
|
||||||
|
if (cur_size == 0) {
|
||||||
|
cur_phys_addr = region.GetAddress();
|
||||||
|
cur_size = region.GetSize();
|
||||||
|
} else if (cur_phys_addr + cur_size == region.GetAddress()) {
|
||||||
|
cur_size += region.GetSize();
|
||||||
|
} else {
|
||||||
|
cur_phys_addr = region.GetAddress();
|
||||||
|
cur_size = region.GetSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
const VAddr region_virt_addr =
|
||||||
|
region.GetAddress() + linear_region_phys_to_virt_diff;
|
||||||
|
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||||
|
region_virt_addr, region.GetSize(),
|
||||||
|
GetTypeForVirtualLinearMapping(region.GetType())));
|
||||||
|
region.SetPairAddress(region_virt_addr);
|
||||||
|
|
||||||
|
KMemoryRegion* virt_region =
|
||||||
|
memory_layout.GetVirtualMemoryRegionTree().FindModifiable(region_virt_addr);
|
||||||
|
ASSERT(virt_region != nullptr);
|
||||||
|
virt_region->SetPairAddress(region.GetAddress());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert regions for the initial page table region.
|
||||||
|
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
|
||||||
|
resource_end_phys_addr, KernelPageTableHeapSize, KMemoryRegionType_DramKernelInitPt));
|
||||||
|
ASSERT(memory_layout.GetVirtualMemoryRegionTree().Insert(
|
||||||
|
resource_end_phys_addr + linear_region_phys_to_virt_diff, KernelPageTableHeapSize,
|
||||||
|
KMemoryRegionType_VirtualDramKernelInitPt));
|
||||||
|
|
||||||
|
// All linear-mapped DRAM regions that we haven't tagged by this point will be allocated to
|
||||||
|
// some pool partition. Tag them.
|
||||||
|
for (auto& region : memory_layout.GetPhysicalMemoryRegionTree()) {
|
||||||
|
if (region.GetType() == (KMemoryRegionType_Dram | KMemoryRegionAttr_LinearMapped)) {
|
||||||
|
region.SetType(KMemoryRegionType_DramPoolPartition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup all other memory regions needed to arrange the pool partitions.
|
||||||
|
Init::SetupPoolPartitionMemoryRegions(memory_layout);
|
||||||
|
|
||||||
|
// Cache all linear regions in their own trees for faster access, later.
|
||||||
|
memory_layout.InitializeLinearMemoryRegionTrees(aligned_linear_phys_start,
|
||||||
|
linear_region_start);
|
||||||
|
}
|
||||||
|
|
||||||
void InitializeMemoryLayout() {
|
void InitializeMemoryLayout() {
|
||||||
// Initialize memory layout
|
// Derive the initial memory layout from the emulated board
|
||||||
constexpr KMemoryLayout layout{KMemoryLayout::GetDefaultLayout()};
|
KMemoryLayout memory_layout;
|
||||||
|
DeriveInitialMemoryLayout(memory_layout);
|
||||||
|
|
||||||
|
const auto system_pool = memory_layout.GetKernelSystemPoolRegionPhysicalExtents();
|
||||||
|
const auto applet_pool = memory_layout.GetKernelAppletPoolRegionPhysicalExtents();
|
||||||
|
const auto application_pool = memory_layout.GetKernelApplicationPoolRegionPhysicalExtents();
|
||||||
|
|
||||||
|
// Initialize memory managers
|
||||||
|
memory_manager = std::make_unique<KMemoryManager>();
|
||||||
|
memory_manager->InitializeManager(KMemoryManager::Pool::Application,
|
||||||
|
application_pool.GetAddress(),
|
||||||
|
application_pool.GetEndAddress());
|
||||||
|
memory_manager->InitializeManager(KMemoryManager::Pool::Applet, applet_pool.GetAddress(),
|
||||||
|
applet_pool.GetEndAddress());
|
||||||
|
memory_manager->InitializeManager(KMemoryManager::Pool::System, system_pool.GetAddress(),
|
||||||
|
system_pool.GetEndAddress());
|
||||||
|
|
||||||
|
// Setup memory regions for emulated processes
|
||||||
|
// TODO(bunnei): These should not be hardcoded regions initialized within the kernel
|
||||||
constexpr std::size_t hid_size{0x40000};
|
constexpr std::size_t hid_size{0x40000};
|
||||||
constexpr std::size_t font_size{0x1100000};
|
constexpr std::size_t font_size{0x1100000};
|
||||||
constexpr std::size_t irs_size{0x8000};
|
constexpr std::size_t irs_size{0x8000};
|
||||||
constexpr std::size_t time_size{0x1000};
|
constexpr std::size_t time_size{0x1000};
|
||||||
constexpr PAddr hid_addr{layout.System().StartAddress()};
|
|
||||||
constexpr PAddr font_pa{layout.System().StartAddress() + hid_size};
|
|
||||||
constexpr PAddr irs_addr{layout.System().StartAddress() + hid_size + font_size};
|
|
||||||
constexpr PAddr time_addr{layout.System().StartAddress() + hid_size + font_size + irs_size};
|
|
||||||
|
|
||||||
// Initialize memory manager
|
const PAddr hid_phys_addr{system_pool.GetAddress()};
|
||||||
memory_manager = std::make_unique<KMemoryManager>();
|
const PAddr font_phys_addr{system_pool.GetAddress() + hid_size};
|
||||||
memory_manager->InitializeManager(KMemoryManager::Pool::Application,
|
const PAddr irs_phys_addr{system_pool.GetAddress() + hid_size + font_size};
|
||||||
layout.Application().StartAddress(),
|
const PAddr time_phys_addr{system_pool.GetAddress() + hid_size + font_size + irs_size};
|
||||||
layout.Application().EndAddress());
|
|
||||||
memory_manager->InitializeManager(KMemoryManager::Pool::Applet,
|
|
||||||
layout.Applet().StartAddress(),
|
|
||||||
layout.Applet().EndAddress());
|
|
||||||
memory_manager->InitializeManager(KMemoryManager::Pool::System,
|
|
||||||
layout.System().StartAddress(),
|
|
||||||
layout.System().EndAddress());
|
|
||||||
|
|
||||||
hid_shared_mem = Kernel::KSharedMemory::Create(
|
hid_shared_mem = Kernel::KSharedMemory::Create(
|
||||||
system.Kernel(), system.DeviceMemory(), nullptr, {hid_addr, hid_size / PageSize},
|
system.Kernel(), system.DeviceMemory(), nullptr, {hid_phys_addr, hid_size / PageSize},
|
||||||
KMemoryPermission::None, KMemoryPermission::Read, hid_addr, hid_size,
|
KMemoryPermission::None, KMemoryPermission::Read, hid_phys_addr, hid_size,
|
||||||
"HID:SharedMemory");
|
"HID:SharedMemory");
|
||||||
font_shared_mem = Kernel::KSharedMemory::Create(
|
font_shared_mem = Kernel::KSharedMemory::Create(
|
||||||
system.Kernel(), system.DeviceMemory(), nullptr, {font_pa, font_size / PageSize},
|
system.Kernel(), system.DeviceMemory(), nullptr, {font_phys_addr, font_size / PageSize},
|
||||||
KMemoryPermission::None, KMemoryPermission::Read, font_pa, font_size,
|
KMemoryPermission::None, KMemoryPermission::Read, font_phys_addr, font_size,
|
||||||
"Font:SharedMemory");
|
"Font:SharedMemory");
|
||||||
irs_shared_mem = Kernel::KSharedMemory::Create(
|
irs_shared_mem = Kernel::KSharedMemory::Create(
|
||||||
system.Kernel(), system.DeviceMemory(), nullptr, {irs_addr, irs_size / PageSize},
|
system.Kernel(), system.DeviceMemory(), nullptr, {irs_phys_addr, irs_size / PageSize},
|
||||||
KMemoryPermission::None, KMemoryPermission::Read, irs_addr, irs_size,
|
KMemoryPermission::None, KMemoryPermission::Read, irs_phys_addr, irs_size,
|
||||||
"IRS:SharedMemory");
|
"IRS:SharedMemory");
|
||||||
time_shared_mem = Kernel::KSharedMemory::Create(
|
time_shared_mem = Kernel::KSharedMemory::Create(
|
||||||
system.Kernel(), system.DeviceMemory(), nullptr, {time_addr, time_size / PageSize},
|
system.Kernel(), system.DeviceMemory(), nullptr, {time_phys_addr, time_size / PageSize},
|
||||||
KMemoryPermission::None, KMemoryPermission::Read, time_addr, time_size,
|
KMemoryPermission::None, KMemoryPermission::Read, time_phys_addr, time_size,
|
||||||
"Time:SharedMemory");
|
"Time:SharedMemory");
|
||||||
|
|
||||||
// Allocate slab heaps
|
// Allocate slab heaps
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 Citra Emulator Project / PPSSPP Project
|
// Copyright 2021 yuzu Emulator Project
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
|
|
@ -959,7 +959,7 @@ private:
|
||||||
|
|
||||||
auto storage = applet->GetBroker().PopNormalDataToGame();
|
auto storage = applet->GetBroker().PopNormalDataToGame();
|
||||||
if (storage == nullptr) {
|
if (storage == nullptr) {
|
||||||
LOG_ERROR(Service_AM,
|
LOG_DEBUG(Service_AM,
|
||||||
"storage is a nullptr. There is no data in the current normal channel");
|
"storage is a nullptr. There is no data in the current normal channel");
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||||
|
@ -990,7 +990,7 @@ private:
|
||||||
|
|
||||||
auto storage = applet->GetBroker().PopInteractiveDataToGame();
|
auto storage = applet->GetBroker().PopInteractiveDataToGame();
|
||||||
if (storage == nullptr) {
|
if (storage == nullptr) {
|
||||||
LOG_ERROR(Service_AM,
|
LOG_DEBUG(Service_AM,
|
||||||
"storage is a nullptr. There is no data in the current interactive channel");
|
"storage is a nullptr. There is no data in the current interactive channel");
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
rb.Push(ERR_NO_DATA_IN_CHANNEL);
|
||||||
|
@ -1113,7 +1113,7 @@ ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_)
|
||||||
{2, nullptr, "AreAnyLibraryAppletsLeft"},
|
{2, nullptr, "AreAnyLibraryAppletsLeft"},
|
||||||
{10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
|
{10, &ILibraryAppletCreator::CreateStorage, "CreateStorage"},
|
||||||
{11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
|
{11, &ILibraryAppletCreator::CreateTransferMemoryStorage, "CreateTransferMemoryStorage"},
|
||||||
{12, nullptr, "CreateHandleStorage"},
|
{12, &ILibraryAppletCreator::CreateHandleStorage, "CreateHandleStorage"},
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
}
|
}
|
||||||
|
@ -1122,14 +1122,15 @@ ILibraryAppletCreator::~ILibraryAppletCreator() = default;
|
||||||
|
|
||||||
void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
|
void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
const auto applet_id = rp.PopRaw<Applets::AppletId>();
|
const auto applet_id = rp.PopRaw<Applets::AppletId>();
|
||||||
const auto applet_mode = rp.PopRaw<u32>();
|
const auto applet_mode = rp.PopRaw<Applets::LibraryAppletMode>();
|
||||||
|
|
||||||
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
|
LOG_DEBUG(Service_AM, "called with applet_id={:08X}, applet_mode={:08X}", applet_id,
|
||||||
applet_mode);
|
applet_mode);
|
||||||
|
|
||||||
const auto& applet_manager{system.GetAppletManager()};
|
const auto& applet_manager{system.GetAppletManager()};
|
||||||
const auto applet = applet_manager.GetApplet(applet_id);
|
const auto applet = applet_manager.GetApplet(applet_id, applet_mode);
|
||||||
|
|
||||||
if (applet == nullptr) {
|
if (applet == nullptr) {
|
||||||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
|
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
|
||||||
|
@ -1147,9 +1148,18 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx)
|
||||||
|
|
||||||
void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
|
void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const u64 size{rp.Pop<u64>()};
|
|
||||||
|
const s64 size{rp.Pop<s64>()};
|
||||||
|
|
||||||
LOG_DEBUG(Service_AM, "called, size={}", size);
|
LOG_DEBUG(Service_AM, "called, size={}", size);
|
||||||
|
|
||||||
|
if (size <= 0) {
|
||||||
|
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(RESULT_UNKNOWN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<u8> buffer(size);
|
std::vector<u8> buffer(size);
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
|
@ -1158,18 +1168,65 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
|
void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_AM, "called");
|
|
||||||
|
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
rp.SetCurrentOffset(3);
|
struct Parameters {
|
||||||
const auto handle{rp.Pop<Kernel::Handle>()};
|
u8 permissions;
|
||||||
|
s64 size;
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto parameters{rp.PopRaw<Parameters>()};
|
||||||
|
const auto handle{ctx.GetCopyHandle(0)};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_AM, "called, permissions={}, size={}, handle={:08X}", parameters.permissions,
|
||||||
|
parameters.size, handle);
|
||||||
|
|
||||||
|
if (parameters.size <= 0) {
|
||||||
|
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(RESULT_UNKNOWN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
auto transfer_mem =
|
auto transfer_mem =
|
||||||
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
|
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
|
||||||
|
|
||||||
if (transfer_mem == nullptr) {
|
if (transfer_mem == nullptr) {
|
||||||
LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle);
|
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(RESULT_UNKNOWN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const u8* const mem_begin = transfer_mem->GetPointer();
|
||||||
|
const u8* const mem_end = mem_begin + transfer_mem->GetSize();
|
||||||
|
std::vector<u8> memory{mem_begin, mem_end};
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushIpcInterface<IStorage>(system, std::move(memory));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ILibraryAppletCreator::CreateHandleStorage(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
|
||||||
|
const s64 size{rp.Pop<s64>()};
|
||||||
|
const auto handle{ctx.GetCopyHandle(0)};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_AM, "called, size={}, handle={:08X}", size, handle);
|
||||||
|
|
||||||
|
if (size <= 0) {
|
||||||
|
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(RESULT_UNKNOWN);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto transfer_mem =
|
||||||
|
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
|
||||||
|
|
||||||
|
if (transfer_mem == nullptr) {
|
||||||
|
LOG_ERROR(Service_AM, "transfer_mem is a nullptr for handle={:08X}", handle);
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_UNKNOWN);
|
rb.Push(RESULT_UNKNOWN);
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
@ -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
|
||||||
|
|
|
@ -13,11 +13,11 @@
|
||||||
|
|
||||||
namespace Service::AM::Applets {
|
namespace Service::AM::Applets {
|
||||||
|
|
||||||
static constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
|
constexpr std::size_t MAX_OK_TEXT_LENGTH = 8;
|
||||||
static constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
|
constexpr std::size_t MAX_HEADER_TEXT_LENGTH = 64;
|
||||||
static constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128;
|
constexpr std::size_t MAX_SUB_TEXT_LENGTH = 128;
|
||||||
static constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256;
|
constexpr std::size_t MAX_GUIDE_TEXT_LENGTH = 256;
|
||||||
static constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4;
|
constexpr std::size_t STRING_BUFFER_SIZE = 0x7D4;
|
||||||
|
|
||||||
enum class SwkbdAppletVersion : u32_le {
|
enum class SwkbdAppletVersion : u32_le {
|
||||||
Version5 = 0x5, // 1.0.0
|
Version5 = 0x5, // 1.0.0
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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};
|
||||||
|
|
|
@ -38,7 +38,7 @@ public:
|
||||||
{10600, nullptr, "DeclareOpenOnlinePlaySession"},
|
{10600, nullptr, "DeclareOpenOnlinePlaySession"},
|
||||||
{10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
|
{10601, &IFriendService::DeclareCloseOnlinePlaySession, "DeclareCloseOnlinePlaySession"},
|
||||||
{10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
|
{10610, &IFriendService::UpdateUserPresence, "UpdateUserPresence"},
|
||||||
{10700, nullptr, "GetPlayHistoryRegistrationKey"},
|
{10700, &IFriendService::GetPlayHistoryRegistrationKey, "GetPlayHistoryRegistrationKey"},
|
||||||
{10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
|
{10701, nullptr, "GetPlayHistoryRegistrationKeyWithNetworkServiceAccountId"},
|
||||||
{10702, nullptr, "AddPlayHistory"},
|
{10702, nullptr, "AddPlayHistory"},
|
||||||
{11000, nullptr, "GetProfileImageUrl"},
|
{11000, nullptr, "GetProfileImageUrl"},
|
||||||
|
@ -153,6 +153,18 @@ private:
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GetPlayHistoryRegistrationKey(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto local_play = rp.Pop<bool>();
|
||||||
|
const auto uuid = rp.PopRaw<Common::UUID>();
|
||||||
|
|
||||||
|
LOG_WARNING(Service_Friend, "(STUBBED) called local_play={} uuid={}", local_play,
|
||||||
|
uuid.Format());
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
void GetFriendList(Kernel::HLERequestContext& ctx) {
|
void GetFriendList(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto friend_offset = rp.Pop<u32>();
|
const auto friend_offset = rp.Pop<u32>();
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,13 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vec
|
||||||
return NvResult::InvalidState;
|
return NvResult::InvalidState;
|
||||||
}
|
}
|
||||||
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
|
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
|
||||||
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
|
if (vic_device) {
|
||||||
|
// UnmapVicFrame defers texture_cache invalidation of the frame address until
|
||||||
|
// the stream is over
|
||||||
|
gpu.MemoryManager().UnmapVicFrame(object->dma_map_addr, *size);
|
||||||
|
} else {
|
||||||
|
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// This occurs quite frequently, however does not seem to impact functionality
|
// This occurs quite frequently, however does not seem to impact functionality
|
||||||
LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
|
LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
|
||||||
|
|
|
@ -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{};
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -3,16 +3,30 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/file_sys/control_metadata.h"
|
||||||
|
#include "core/file_sys/patch_manager.h"
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
|
#include "core/hle/kernel/process.h"
|
||||||
#include "core/hle/service/pctl/module.h"
|
#include "core/hle/service/pctl/module.h"
|
||||||
#include "core/hle/service/pctl/pctl.h"
|
#include "core/hle/service/pctl/pctl.h"
|
||||||
|
|
||||||
namespace Service::PCTL {
|
namespace Service::PCTL {
|
||||||
|
|
||||||
|
namespace Error {
|
||||||
|
|
||||||
|
constexpr ResultCode ResultNoFreeCommunication{ErrorModule::PCTL, 101};
|
||||||
|
constexpr ResultCode ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
|
||||||
|
constexpr ResultCode ResultNoCapability{ErrorModule::PCTL, 131};
|
||||||
|
constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
|
||||||
|
|
||||||
|
} // namespace Error
|
||||||
|
|
||||||
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
|
class IParentalControlService final : public ServiceFramework<IParentalControlService> {
|
||||||
public:
|
public:
|
||||||
explicit IParentalControlService(Core::System& system_)
|
explicit IParentalControlService(Core::System& system_, Capability capability)
|
||||||
: ServiceFramework{system_, "IParentalControlService"} {
|
: ServiceFramework{system_, "IParentalControlService"}, system(system_),
|
||||||
|
capability(capability) {
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{1, &IParentalControlService::Initialize, "Initialize"},
|
{1, &IParentalControlService::Initialize, "Initialize"},
|
||||||
|
@ -28,13 +42,13 @@ public:
|
||||||
{1010, nullptr, "IsRestrictedSystemSettingsEntered"},
|
{1010, nullptr, "IsRestrictedSystemSettingsEntered"},
|
||||||
{1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
|
{1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
|
||||||
{1012, nullptr, "GetRestrictedFeatures"},
|
{1012, nullptr, "GetRestrictedFeatures"},
|
||||||
{1013, nullptr, "ConfirmStereoVisionPermission"},
|
{1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
|
||||||
{1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
|
{1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
|
||||||
{1015, nullptr, "ConfirmPlayableApplicationVideo"},
|
{1015, nullptr, "ConfirmPlayableApplicationVideo"},
|
||||||
{1016, nullptr, "ConfirmShowNewsPermission"},
|
{1016, nullptr, "ConfirmShowNewsPermission"},
|
||||||
{1017, nullptr, "EndFreeCommunication"},
|
{1017, nullptr, "EndFreeCommunication"},
|
||||||
{1018, nullptr, "IsFreeCommunicationAvailable"},
|
{1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
|
||||||
{1031, nullptr, "IsRestrictionEnabled"},
|
{1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
|
||||||
{1032, nullptr, "GetSafetyLevel"},
|
{1032, nullptr, "GetSafetyLevel"},
|
||||||
{1033, nullptr, "SetSafetyLevel"},
|
{1033, nullptr, "SetSafetyLevel"},
|
||||||
{1034, nullptr, "GetSafetyLevelSettings"},
|
{1034, nullptr, "GetSafetyLevelSettings"},
|
||||||
|
@ -119,62 +133,235 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Initialize(Kernel::HLERequestContext& ctx) {
|
bool CheckFreeCommunicationPermissionImpl() const {
|
||||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
if (states.temporary_unlocked) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if ((states.application_info.parental_control_flag & 1) == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pin_code[0] == '\0') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!settings.is_free_communication_default_on) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// TODO(ogniK): Check for blacklisted/exempted applications. Return false can happen here
|
||||||
|
// but as we don't have multiproceses support yet, we can just assume our application is
|
||||||
|
// valid for the time being
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfirmStereoVisionPermissionImpl() const {
|
||||||
|
if (states.temporary_unlocked) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pin_code[0] == '\0') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!settings.is_stero_vision_restricted) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetStereoVisionRestrictionImpl(bool is_restricted) {
|
||||||
|
if (settings.disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pin_code[0] == '\0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settings.is_stero_vision_restricted = is_restricted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Initialize(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_PCTL, "called");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
|
||||||
|
if (False(capability & (Capability::Application | Capability::System))) {
|
||||||
|
LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}", capability);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(ogniK): Recovery flag initialization for pctl:r
|
||||||
|
|
||||||
|
const auto tid = system.CurrentProcess()->GetTitleID();
|
||||||
|
if (tid != 0) {
|
||||||
|
const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
|
||||||
|
system.GetContentProvider()};
|
||||||
|
const auto control = pm.GetControlMetadata();
|
||||||
|
if (control.first) {
|
||||||
|
states.tid_from_event = 0;
|
||||||
|
states.launch_time_valid = false;
|
||||||
|
states.is_suspended = false;
|
||||||
|
states.free_communication = false;
|
||||||
|
states.stereo_vision = false;
|
||||||
|
states.application_info = ApplicationInfo{
|
||||||
|
.tid = tid,
|
||||||
|
.age_rating = control.first->GetRatingAge(),
|
||||||
|
.parental_control_flag = control.first->GetParentalControlFlag(),
|
||||||
|
.capability = capability,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (False(capability & (Capability::System | Capability::Recovery))) {
|
||||||
|
// TODO(ogniK): Signal application launch event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
|
void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
LOG_DEBUG(Service_PCTL, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
if (!CheckFreeCommunicationPermissionImpl()) {
|
||||||
|
rb.Push(Error::ResultNoFreeCommunication);
|
||||||
|
} else {
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
states.free_communication = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfirmStereoVisionPermission(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_PCTL, "called");
|
||||||
|
states.stereo_vision = true;
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) {
|
void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
if (!CheckFreeCommunicationPermissionImpl()) {
|
||||||
|
rb.Push(Error::ResultNoFreeCommunication);
|
||||||
|
} else {
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IsRestrictionEnabled(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_PCTL, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
if (False(capability & (Capability::Status | Capability::Recovery))) {
|
||||||
|
LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
|
||||||
|
rb.Push(Error::ResultNoCapability);
|
||||||
|
rb.Push(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rb.Push(pin_code[0] != '\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_PCTL, "called");
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
|
||||||
|
if (False(capability & Capability::StereoVision)) {
|
||||||
|
LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
|
||||||
|
rb.Push(Error::ResultNoCapability);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pin_code[0] == '\0') {
|
||||||
|
rb.Push(Error::ResultNoRestrictionEnabled);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) {
|
void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
LOG_DEBUG(Service_PCTL, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
rb.Push(RESULT_SUCCESS);
|
if (!ConfirmStereoVisionPermissionImpl()) {
|
||||||
rb.Push(true);
|
rb.Push(Error::ResultStereoVisionRestricted);
|
||||||
|
rb.Push(false);
|
||||||
|
} else {
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.Push(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
|
void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto can_use = rp.Pop<bool>();
|
const auto can_use = rp.Pop<bool>();
|
||||||
LOG_WARNING(Service_PCTL, "(STUBBED) called, can_use={}", can_use);
|
LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
|
||||||
|
|
||||||
can_use_stereo_vision = can_use;
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
if (False(capability & Capability::StereoVision)) {
|
||||||
|
LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
|
||||||
|
rb.Push(Error::ResultNoCapability);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetStereoVisionRestrictionImpl(can_use);
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
|
void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
LOG_DEBUG(Service_PCTL, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
if (False(capability & Capability::StereoVision)) {
|
||||||
|
LOG_ERROR(Service_PCTL, "Application does not have StereoVision capability!");
|
||||||
|
rb.Push(Error::ResultNoCapability);
|
||||||
|
rb.Push(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push(can_use_stereo_vision);
|
rb.Push(settings.is_stero_vision_restricted);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) {
|
void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
LOG_DEBUG(Service_PCTL, "called");
|
||||||
|
|
||||||
|
states.stereo_vision = false;
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ApplicationInfo {
|
||||||
|
u64 tid{};
|
||||||
|
std::array<u8, 32> age_rating{};
|
||||||
|
u32 parental_control_flag{};
|
||||||
|
Capability capability{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct States {
|
||||||
|
u64 current_tid{};
|
||||||
|
ApplicationInfo application_info{};
|
||||||
|
u64 tid_from_event{};
|
||||||
|
bool launch_time_valid{};
|
||||||
|
bool is_suspended{};
|
||||||
|
bool temporary_unlocked{};
|
||||||
|
bool free_communication{};
|
||||||
|
bool stereo_vision{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ParentalControlSettings {
|
||||||
|
bool is_stero_vision_restricted{};
|
||||||
|
bool is_free_communication_default_on{};
|
||||||
|
bool disabled{};
|
||||||
|
};
|
||||||
|
|
||||||
|
States states{};
|
||||||
|
ParentalControlSettings settings{};
|
||||||
|
std::array<char, 8> pin_code{};
|
||||||
bool can_use_stereo_vision = true;
|
bool can_use_stereo_vision = true;
|
||||||
|
Core::System& system;
|
||||||
|
Capability capability{};
|
||||||
};
|
};
|
||||||
|
|
||||||
void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -182,7 +369,9 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<IParentalControlService>(system);
|
// TODO(ogniK): Get TID from process
|
||||||
|
|
||||||
|
rb.PushIpcInterface<IParentalControlService>(system, capability);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
|
||||||
|
@ -190,21 +379,28 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<IParentalControlService>(system);
|
rb.PushIpcInterface<IParentalControlService>(system, capability);
|
||||||
}
|
}
|
||||||
|
|
||||||
Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
|
Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
|
||||||
const char* name)
|
const char* name, Capability capability)
|
||||||
: ServiceFramework{system_, name}, module{std::move(module_)} {}
|
: ServiceFramework{system_, name}, module{std::move(module_)}, capability(capability) {}
|
||||||
|
|
||||||
Module::Interface::~Interface() = default;
|
Module::Interface::~Interface() = default;
|
||||||
|
|
||||||
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
|
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
|
||||||
auto module = std::make_shared<Module>();
|
auto module = std::make_shared<Module>();
|
||||||
std::make_shared<PCTL>(system, module, "pctl")->InstallAsService(service_manager);
|
std::make_shared<PCTL>(system, module, "pctl",
|
||||||
std::make_shared<PCTL>(system, module, "pctl:a")->InstallAsService(service_manager);
|
Capability::Application | Capability::SnsPost | Capability::Status |
|
||||||
std::make_shared<PCTL>(system, module, "pctl:r")->InstallAsService(service_manager);
|
Capability::StereoVision)
|
||||||
std::make_shared<PCTL>(system, module, "pctl:s")->InstallAsService(service_manager);
|
->InstallAsService(service_manager);
|
||||||
|
// TODO(ogniK): Implement remaining capabilities
|
||||||
|
std::make_shared<PCTL>(system, module, "pctl:a", Capability::None)
|
||||||
|
->InstallAsService(service_manager);
|
||||||
|
std::make_shared<PCTL>(system, module, "pctl:r", Capability::None)
|
||||||
|
->InstallAsService(service_manager);
|
||||||
|
std::make_shared<PCTL>(system, module, "pctl:s", Capability::None)
|
||||||
|
->InstallAsService(service_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::PCTL
|
} // namespace Service::PCTL
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_funcs.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -12,12 +13,23 @@ class System;
|
||||||
|
|
||||||
namespace Service::PCTL {
|
namespace Service::PCTL {
|
||||||
|
|
||||||
|
enum class Capability : u32 {
|
||||||
|
None = 0,
|
||||||
|
Application = 1 << 0,
|
||||||
|
SnsPost = 1 << 1,
|
||||||
|
Recovery = 1 << 6,
|
||||||
|
Status = 1 << 8,
|
||||||
|
StereoVision = 1 << 9,
|
||||||
|
System = 1 << 15,
|
||||||
|
};
|
||||||
|
DECLARE_ENUM_FLAG_OPERATORS(Capability);
|
||||||
|
|
||||||
class Module final {
|
class Module final {
|
||||||
public:
|
public:
|
||||||
class Interface : public ServiceFramework<Interface> {
|
class Interface : public ServiceFramework<Interface> {
|
||||||
public:
|
public:
|
||||||
explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
|
explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
|
||||||
const char* name);
|
Capability capability);
|
||||||
~Interface() override;
|
~Interface() override;
|
||||||
|
|
||||||
void CreateService(Kernel::HLERequestContext& ctx);
|
void CreateService(Kernel::HLERequestContext& ctx);
|
||||||
|
@ -25,6 +37,9 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<Module> module;
|
std::shared_ptr<Module> module;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Capability capability{};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
|
|
||||||
namespace Service::PCTL {
|
namespace Service::PCTL {
|
||||||
|
|
||||||
PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name)
|
PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
|
||||||
: Interface{system_, std::move(module_), name} {
|
Capability capability)
|
||||||
|
: Interface{system_, std::move(module_), name, capability} {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &PCTL::CreateService, "CreateService"},
|
{0, &PCTL::CreateService, "CreateService"},
|
||||||
{1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
|
{1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
|
||||||
|
|
|
@ -14,7 +14,8 @@ namespace Service::PCTL {
|
||||||
|
|
||||||
class PCTL final : public Module::Interface {
|
class PCTL final : public Module::Interface {
|
||||||
public:
|
public:
|
||||||
explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name);
|
explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
|
||||||
|
Capability capability);
|
||||||
~PCTL() override;
|
~PCTL() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
#include "core/hle/service/vi/vi.h"
|
#include "core/hle/service/vi/vi.h"
|
||||||
#include "core/hle/service/wlan/wlan.h"
|
#include "core/hle/service/wlan/wlan.h"
|
||||||
#include "core/reporter.h"
|
#include "core/reporter.h"
|
||||||
|
#include "core/settings.h"
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
|
|
||||||
|
@ -146,6 +147,11 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(Kernel::HLERequestContext
|
||||||
system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name,
|
system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name,
|
||||||
service_name);
|
service_name);
|
||||||
UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
|
UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
|
||||||
|
if (Settings::values.use_auto_stub) {
|
||||||
|
LOG_WARNING(Service, "Using auto stub fallback!");
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
|
void ServiceFrameworkBase::InvokeRequest(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
|
@ -139,6 +139,7 @@ struct Values {
|
||||||
Setting<int> vulkan_device;
|
Setting<int> vulkan_device;
|
||||||
|
|
||||||
Setting<u16> resolution_factor{1};
|
Setting<u16> resolution_factor{1};
|
||||||
|
Setting<int> fullscreen_mode;
|
||||||
Setting<int> aspect_ratio;
|
Setting<int> aspect_ratio;
|
||||||
Setting<int> max_anisotropy;
|
Setting<int> max_anisotropy;
|
||||||
Setting<bool> use_frame_limit;
|
Setting<bool> use_frame_limit;
|
||||||
|
@ -222,6 +223,7 @@ struct Values {
|
||||||
bool quest_flag;
|
bool quest_flag;
|
||||||
bool disable_macro_jit;
|
bool disable_macro_jit;
|
||||||
bool extended_logging;
|
bool extended_logging;
|
||||||
|
bool use_auto_stub;
|
||||||
|
|
||||||
// Miscellaneous
|
// Miscellaneous
|
||||||
std::string log_filter;
|
std::string log_filter;
|
||||||
|
|
|
@ -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},
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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)];
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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 {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -641,6 +641,7 @@ void Config::ReadDebuggingValues() {
|
||||||
ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
|
ReadSetting(QStringLiteral("disable_macro_jit"), false).toBool();
|
||||||
Settings::values.extended_logging =
|
Settings::values.extended_logging =
|
||||||
ReadSetting(QStringLiteral("extended_logging"), false).toBool();
|
ReadSetting(QStringLiteral("extended_logging"), false).toBool();
|
||||||
|
Settings::values.use_auto_stub = ReadSetting(QStringLiteral("use_auto_stub"), false).toBool();
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
|
@ -770,6 +771,13 @@ void Config::ReadRendererValues() {
|
||||||
ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0);
|
ReadSettingGlobal(Settings::values.renderer_backend, QStringLiteral("backend"), 0);
|
||||||
ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
|
ReadSettingGlobal(Settings::values.renderer_debug, QStringLiteral("debug"), false);
|
||||||
ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0);
|
ReadSettingGlobal(Settings::values.vulkan_device, QStringLiteral("vulkan_device"), 0);
|
||||||
|
#ifdef _WIN32
|
||||||
|
ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 0);
|
||||||
|
#else
|
||||||
|
// *nix platforms may have issues with the borderless windowed fullscreen mode.
|
||||||
|
// Default to exclusive fullscreen on these platforms for now.
|
||||||
|
ReadSettingGlobal(Settings::values.fullscreen_mode, QStringLiteral("fullscreen_mode"), 1);
|
||||||
|
#endif
|
||||||
ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0);
|
ReadSettingGlobal(Settings::values.aspect_ratio, QStringLiteral("aspect_ratio"), 0);
|
||||||
ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0);
|
ReadSettingGlobal(Settings::values.max_anisotropy, QStringLiteral("max_anisotropy"), 0);
|
||||||
ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true);
|
ReadSettingGlobal(Settings::values.use_frame_limit, QStringLiteral("use_frame_limit"), true);
|
||||||
|
@ -1333,6 +1341,13 @@ void Config::SaveRendererValues() {
|
||||||
Settings::values.renderer_backend.UsingGlobal(), 0);
|
Settings::values.renderer_backend.UsingGlobal(), 0);
|
||||||
WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false);
|
WriteSetting(QStringLiteral("debug"), Settings::values.renderer_debug, false);
|
||||||
WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
|
WriteSettingGlobal(QStringLiteral("vulkan_device"), Settings::values.vulkan_device, 0);
|
||||||
|
#ifdef _WIN32
|
||||||
|
WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 0);
|
||||||
|
#else
|
||||||
|
// *nix platforms may have issues with the borderless windowed fullscreen mode.
|
||||||
|
// Default to exclusive fullscreen on these platforms for now.
|
||||||
|
WriteSettingGlobal(QStringLiteral("fullscreen_mode"), Settings::values.fullscreen_mode, 1);
|
||||||
|
#endif
|
||||||
WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
|
WriteSettingGlobal(QStringLiteral("aspect_ratio"), Settings::values.aspect_ratio, 0);
|
||||||
WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
|
WriteSettingGlobal(QStringLiteral("max_anisotropy"), Settings::values.max_anisotropy, 0);
|
||||||
WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
|
WriteSettingGlobal(QStringLiteral("use_frame_limit"), Settings::values.use_frame_limit, true);
|
||||||
|
|
|
@ -34,6 +34,7 @@ void ConfigureDebug::SetConfiguration() {
|
||||||
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
|
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
|
||||||
ui->reporting_services->setChecked(Settings::values.reporting_services);
|
ui->reporting_services->setChecked(Settings::values.reporting_services);
|
||||||
ui->quest_flag->setChecked(Settings::values.quest_flag);
|
ui->quest_flag->setChecked(Settings::values.quest_flag);
|
||||||
|
ui->use_auto_stub->setChecked(Settings::values.use_auto_stub);
|
||||||
ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
ui->enable_graphics_debugging->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||||
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
|
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug);
|
||||||
ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
ui->disable_macro_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||||
|
@ -47,6 +48,7 @@ void ConfigureDebug::ApplyConfiguration() {
|
||||||
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
|
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
|
||||||
Settings::values.reporting_services = ui->reporting_services->isChecked();
|
Settings::values.reporting_services = ui->reporting_services->isChecked();
|
||||||
Settings::values.quest_flag = ui->quest_flag->isChecked();
|
Settings::values.quest_flag = ui->quest_flag->isChecked();
|
||||||
|
Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
|
||||||
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
|
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
|
||||||
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
|
Settings::values.disable_macro_jit = ui->disable_macro_jit->isChecked();
|
||||||
Settings::values.extended_logging = ui->extended_logging->isChecked();
|
Settings::values.extended_logging = ui->extended_logging->isChecked();
|
||||||
|
|
|
@ -185,6 +185,28 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="use_auto_stub">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable Auto-Stub</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<italic>true</italic>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>This will be reset automatically when yuzu closes.</string>
|
||||||
|
</property>
|
||||||
|
<property name="indent">
|
||||||
|
<number>20</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|
|
@ -77,18 +77,25 @@ void ConfigureGraphics::SetConfiguration() {
|
||||||
|
|
||||||
if (Settings::IsConfiguringGlobal()) {
|
if (Settings::IsConfiguringGlobal()) {
|
||||||
ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
|
ui->api->setCurrentIndex(static_cast<int>(Settings::values.renderer_backend.GetValue()));
|
||||||
|
ui->fullscreen_mode_combobox->setCurrentIndex(Settings::values.fullscreen_mode.GetValue());
|
||||||
ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
|
ui->aspect_ratio_combobox->setCurrentIndex(Settings::values.aspect_ratio.GetValue());
|
||||||
} else {
|
} else {
|
||||||
ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
|
ConfigurationShared::SetPerGameSetting(ui->api, &Settings::values.renderer_backend);
|
||||||
ConfigurationShared::SetHighlight(ui->api_layout,
|
ConfigurationShared::SetHighlight(ui->api_layout,
|
||||||
!Settings::values.renderer_backend.UsingGlobal());
|
!Settings::values.renderer_backend.UsingGlobal());
|
||||||
|
|
||||||
|
ConfigurationShared::SetPerGameSetting(ui->fullscreen_mode_combobox,
|
||||||
|
&Settings::values.fullscreen_mode);
|
||||||
|
ConfigurationShared::SetHighlight(ui->fullscreen_mode_label,
|
||||||
|
!Settings::values.fullscreen_mode.UsingGlobal());
|
||||||
|
|
||||||
ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
|
ConfigurationShared::SetPerGameSetting(ui->aspect_ratio_combobox,
|
||||||
&Settings::values.aspect_ratio);
|
&Settings::values.aspect_ratio);
|
||||||
|
ConfigurationShared::SetHighlight(ui->ar_label,
|
||||||
|
!Settings::values.aspect_ratio.UsingGlobal());
|
||||||
|
|
||||||
ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
|
ui->bg_combobox->setCurrentIndex(Settings::values.bg_red.UsingGlobal() ? 0 : 1);
|
||||||
ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
|
ui->bg_button->setEnabled(!Settings::values.bg_red.UsingGlobal());
|
||||||
ConfigurationShared::SetHighlight(ui->ar_label,
|
|
||||||
!Settings::values.aspect_ratio.UsingGlobal());
|
|
||||||
ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal());
|
ConfigurationShared::SetHighlight(ui->bg_layout, !Settings::values.bg_red.UsingGlobal());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +114,9 @@ void ConfigureGraphics::ApplyConfiguration() {
|
||||||
if (Settings::values.vulkan_device.UsingGlobal()) {
|
if (Settings::values.vulkan_device.UsingGlobal()) {
|
||||||
Settings::values.vulkan_device.SetValue(vulkan_device);
|
Settings::values.vulkan_device.SetValue(vulkan_device);
|
||||||
}
|
}
|
||||||
|
if (Settings::values.fullscreen_mode.UsingGlobal()) {
|
||||||
|
Settings::values.fullscreen_mode.SetValue(ui->fullscreen_mode_combobox->currentIndex());
|
||||||
|
}
|
||||||
if (Settings::values.aspect_ratio.UsingGlobal()) {
|
if (Settings::values.aspect_ratio.UsingGlobal()) {
|
||||||
Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
|
Settings::values.aspect_ratio.SetValue(ui->aspect_ratio_combobox->currentIndex());
|
||||||
}
|
}
|
||||||
|
@ -140,6 +150,8 @@ void ConfigureGraphics::ApplyConfiguration() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ConfigurationShared::ApplyPerGameSetting(&Settings::values.fullscreen_mode,
|
||||||
|
ui->fullscreen_mode_combobox);
|
||||||
ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
|
ConfigurationShared::ApplyPerGameSetting(&Settings::values.aspect_ratio,
|
||||||
ui->aspect_ratio_combobox);
|
ui->aspect_ratio_combobox);
|
||||||
|
|
||||||
|
@ -227,7 +239,7 @@ void ConfigureGraphics::RetrieveVulkanDevices() try {
|
||||||
vulkan_devices.clear();
|
vulkan_devices.clear();
|
||||||
vulkan_devices.reserve(physical_devices.size());
|
vulkan_devices.reserve(physical_devices.size());
|
||||||
for (const VkPhysicalDevice device : physical_devices) {
|
for (const VkPhysicalDevice device : physical_devices) {
|
||||||
const char* const name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
|
const std::string name = vk::PhysicalDevice(device, dld).GetProperties().deviceName;
|
||||||
vulkan_devices.push_back(QString::fromStdString(name));
|
vulkan_devices.push_back(QString::fromStdString(name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +265,7 @@ void ConfigureGraphics::SetupPerGameUI() {
|
||||||
if (Settings::IsConfiguringGlobal()) {
|
if (Settings::IsConfiguringGlobal()) {
|
||||||
ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
|
ui->api->setEnabled(Settings::values.renderer_backend.UsingGlobal());
|
||||||
ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
|
ui->device->setEnabled(Settings::values.renderer_backend.UsingGlobal());
|
||||||
|
ui->fullscreen_mode_combobox->setEnabled(Settings::values.fullscreen_mode.UsingGlobal());
|
||||||
ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
|
ui->aspect_ratio_combobox->setEnabled(Settings::values.aspect_ratio.UsingGlobal());
|
||||||
ui->use_asynchronous_gpu_emulation->setEnabled(
|
ui->use_asynchronous_gpu_emulation->setEnabled(
|
||||||
Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
|
Settings::values.use_asynchronous_gpu_emulation.UsingGlobal());
|
||||||
|
@ -278,6 +291,8 @@ void ConfigureGraphics::SetupPerGameUI() {
|
||||||
|
|
||||||
ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label,
|
ConfigurationShared::SetColoredComboBox(ui->aspect_ratio_combobox, ui->ar_label,
|
||||||
Settings::values.aspect_ratio.GetValue(true));
|
Settings::values.aspect_ratio.GetValue(true));
|
||||||
|
ConfigurationShared::SetColoredComboBox(ui->fullscreen_mode_combobox, ui->fullscreen_mode_label,
|
||||||
|
Settings::values.fullscreen_mode.GetValue(true));
|
||||||
ConfigurationShared::InsertGlobalItem(
|
ConfigurationShared::InsertGlobalItem(
|
||||||
ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
|
ui->api, static_cast<int>(Settings::values.renderer_backend.GetValue(true)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,9 +104,48 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QWidget" name="fullscreen_mode_layout" native="true">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_1">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="fullscreen_mode_label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Fullscreen Mode:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="fullscreen_mode_combobox">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Borderless Windowed (Default)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Exclusive Fullscreen</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QWidget" name="aspect_ratio_layout" native="true">
|
<widget class="QWidget" name="aspect_ratio_layout" native="true">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<property name="leftMargin">
|
<property name="leftMargin">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -101,6 +101,7 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "core/telemetry_session.h"
|
#include "core/telemetry_session.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
|
#include "util/overlay_dialog.h"
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
#include "video_core/shader_notify.h"
|
#include "video_core/shader_notify.h"
|
||||||
#include "yuzu/about_dialog.h"
|
#include "yuzu/about_dialog.h"
|
||||||
|
@ -225,6 +226,8 @@ GMainWindow::GMainWindow()
|
||||||
SetDiscordEnabled(UISettings::values.enable_discord_presence);
|
SetDiscordEnabled(UISettings::values.enable_discord_presence);
|
||||||
discord_rpc->Update();
|
discord_rpc->Update();
|
||||||
|
|
||||||
|
RegisterMetaTypes();
|
||||||
|
|
||||||
InitializeWidgets();
|
InitializeWidgets();
|
||||||
InitializeDebugWidgets();
|
InitializeDebugWidgets();
|
||||||
InitializeRecentFileMenuActions();
|
InitializeRecentFileMenuActions();
|
||||||
|
@ -373,6 +376,55 @@ GMainWindow::~GMainWindow() {
|
||||||
delete render_window;
|
delete render_window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GMainWindow::RegisterMetaTypes() {
|
||||||
|
// Register integral and floating point types
|
||||||
|
qRegisterMetaType<u8>("u8");
|
||||||
|
qRegisterMetaType<u16>("u16");
|
||||||
|
qRegisterMetaType<u32>("u32");
|
||||||
|
qRegisterMetaType<u64>("u64");
|
||||||
|
qRegisterMetaType<u128>("u128");
|
||||||
|
qRegisterMetaType<s8>("s8");
|
||||||
|
qRegisterMetaType<s16>("s16");
|
||||||
|
qRegisterMetaType<s32>("s32");
|
||||||
|
qRegisterMetaType<s64>("s64");
|
||||||
|
qRegisterMetaType<f32>("f32");
|
||||||
|
qRegisterMetaType<f64>("f64");
|
||||||
|
|
||||||
|
// Register string types
|
||||||
|
qRegisterMetaType<std::string>("std::string");
|
||||||
|
qRegisterMetaType<std::wstring>("std::wstring");
|
||||||
|
qRegisterMetaType<std::u8string>("std::u8string");
|
||||||
|
qRegisterMetaType<std::u16string>("std::u16string");
|
||||||
|
qRegisterMetaType<std::u32string>("std::u32string");
|
||||||
|
qRegisterMetaType<std::string_view>("std::string_view");
|
||||||
|
qRegisterMetaType<std::wstring_view>("std::wstring_view");
|
||||||
|
qRegisterMetaType<std::u8string_view>("std::u8string_view");
|
||||||
|
qRegisterMetaType<std::u16string_view>("std::u16string_view");
|
||||||
|
qRegisterMetaType<std::u32string_view>("std::u32string_view");
|
||||||
|
|
||||||
|
// Register applet types
|
||||||
|
|
||||||
|
// Controller Applet
|
||||||
|
qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
|
||||||
|
|
||||||
|
// Software Keyboard Applet
|
||||||
|
qRegisterMetaType<Core::Frontend::KeyboardInitializeParameters>(
|
||||||
|
"Core::Frontend::KeyboardInitializeParameters");
|
||||||
|
qRegisterMetaType<Core::Frontend::InlineAppearParameters>(
|
||||||
|
"Core::Frontend::InlineAppearParameters");
|
||||||
|
qRegisterMetaType<Core::Frontend::InlineTextParameters>("Core::Frontend::InlineTextParameters");
|
||||||
|
qRegisterMetaType<Service::AM::Applets::SwkbdResult>("Service::AM::Applets::SwkbdResult");
|
||||||
|
qRegisterMetaType<Service::AM::Applets::SwkbdTextCheckResult>(
|
||||||
|
"Service::AM::Applets::SwkbdTextCheckResult");
|
||||||
|
qRegisterMetaType<Service::AM::Applets::SwkbdReplyType>("Service::AM::Applets::SwkbdReplyType");
|
||||||
|
|
||||||
|
// Web Browser Applet
|
||||||
|
qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason");
|
||||||
|
|
||||||
|
// Register loader types
|
||||||
|
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
|
||||||
|
}
|
||||||
|
|
||||||
void GMainWindow::ControllerSelectorReconfigureControllers(
|
void GMainWindow::ControllerSelectorReconfigureControllers(
|
||||||
const Core::Frontend::ControllerParameters& parameters) {
|
const Core::Frontend::ControllerParameters& parameters) {
|
||||||
QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get());
|
QtControllerSelectorDialog dialog(this, parameters, input_subsystem.get());
|
||||||
|
@ -412,25 +464,112 @@ void GMainWindow::ProfileSelectorSelectProfile() {
|
||||||
emit ProfileSelectorFinishedSelection(uuid);
|
emit ProfileSelectorFinishedSelection(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::SoftwareKeyboardGetText(
|
void GMainWindow::SoftwareKeyboardInitialize(
|
||||||
const Core::Frontend::SoftwareKeyboardParameters& parameters) {
|
bool is_inline, Core::Frontend::KeyboardInitializeParameters initialize_parameters) {
|
||||||
QtSoftwareKeyboardDialog dialog(this, parameters);
|
if (software_keyboard) {
|
||||||
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
|
LOG_ERROR(Frontend, "The software keyboard is already initialized!");
|
||||||
Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
|
|
||||||
Qt::WindowCloseButtonHint);
|
|
||||||
dialog.setWindowModality(Qt::WindowModal);
|
|
||||||
|
|
||||||
if (dialog.exec() == QDialog::Rejected) {
|
|
||||||
emit SoftwareKeyboardFinishedText(std::nullopt);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
emit SoftwareKeyboardFinishedText(dialog.GetText());
|
software_keyboard = new QtSoftwareKeyboardDialog(render_window, Core::System::GetInstance(),
|
||||||
|
is_inline, std::move(initialize_parameters));
|
||||||
|
|
||||||
|
if (is_inline) {
|
||||||
|
connect(
|
||||||
|
software_keyboard, &QtSoftwareKeyboardDialog::SubmitInlineText, this,
|
||||||
|
[this](Service::AM::Applets::SwkbdReplyType reply_type, std::u16string submitted_text,
|
||||||
|
s32 cursor_position) {
|
||||||
|
emit SoftwareKeyboardSubmitInlineText(reply_type, submitted_text, cursor_position);
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
} else {
|
||||||
|
connect(
|
||||||
|
software_keyboard, &QtSoftwareKeyboardDialog::SubmitNormalText, this,
|
||||||
|
[this](Service::AM::Applets::SwkbdResult result, std::u16string submitted_text) {
|
||||||
|
emit SoftwareKeyboardSubmitNormalText(result, submitted_text);
|
||||||
|
},
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::SoftwareKeyboardInvokeCheckDialog(std::u16string error_message) {
|
void GMainWindow::SoftwareKeyboardShowNormal() {
|
||||||
QMessageBox::warning(this, tr("Text Check Failed"), QString::fromStdU16String(error_message));
|
if (!software_keyboard) {
|
||||||
emit SoftwareKeyboardFinishedCheckDialog();
|
LOG_ERROR(Frontend, "The software keyboard is not initialized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& layout = render_window->GetFramebufferLayout();
|
||||||
|
|
||||||
|
const auto x = layout.screen.left;
|
||||||
|
const auto y = layout.screen.top;
|
||||||
|
const auto w = layout.screen.GetWidth();
|
||||||
|
const auto h = layout.screen.GetHeight();
|
||||||
|
|
||||||
|
software_keyboard->ShowNormalKeyboard(render_window->mapToGlobal(QPoint(x, y)), QSize(w, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMainWindow::SoftwareKeyboardShowTextCheck(
|
||||||
|
Service::AM::Applets::SwkbdTextCheckResult text_check_result,
|
||||||
|
std::u16string text_check_message) {
|
||||||
|
if (!software_keyboard) {
|
||||||
|
LOG_ERROR(Frontend, "The software keyboard is not initialized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
software_keyboard->ShowTextCheckDialog(text_check_result, text_check_message);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMainWindow::SoftwareKeyboardShowInline(
|
||||||
|
Core::Frontend::InlineAppearParameters appear_parameters) {
|
||||||
|
if (!software_keyboard) {
|
||||||
|
LOG_ERROR(Frontend, "The software keyboard is not initialized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& layout = render_window->GetFramebufferLayout();
|
||||||
|
|
||||||
|
const auto x =
|
||||||
|
static_cast<int>(layout.screen.left + (0.5f * layout.screen.GetWidth() *
|
||||||
|
((2.0f * appear_parameters.key_top_translate_x) +
|
||||||
|
(1.0f - appear_parameters.key_top_scale_x))));
|
||||||
|
const auto y =
|
||||||
|
static_cast<int>(layout.screen.top + (layout.screen.GetHeight() *
|
||||||
|
((2.0f * appear_parameters.key_top_translate_y) +
|
||||||
|
(1.0f - appear_parameters.key_top_scale_y))));
|
||||||
|
const auto w = static_cast<int>(layout.screen.GetWidth() * appear_parameters.key_top_scale_x);
|
||||||
|
const auto h = static_cast<int>(layout.screen.GetHeight() * appear_parameters.key_top_scale_y);
|
||||||
|
|
||||||
|
software_keyboard->ShowInlineKeyboard(std::move(appear_parameters),
|
||||||
|
render_window->mapToGlobal(QPoint(x, y)), QSize(w, h));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMainWindow::SoftwareKeyboardHideInline() {
|
||||||
|
if (!software_keyboard) {
|
||||||
|
LOG_ERROR(Frontend, "The software keyboard is not initialized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
software_keyboard->HideInlineKeyboard();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMainWindow::SoftwareKeyboardInlineTextChanged(
|
||||||
|
Core::Frontend::InlineTextParameters text_parameters) {
|
||||||
|
if (!software_keyboard) {
|
||||||
|
LOG_ERROR(Frontend, "The software keyboard is not initialized!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
software_keyboard->InlineTextChanged(std::move(text_parameters));
|
||||||
|
}
|
||||||
|
|
||||||
|
void GMainWindow::SoftwareKeyboardExit() {
|
||||||
|
if (!software_keyboard) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
software_keyboard->ExitKeyboard();
|
||||||
|
|
||||||
|
software_keyboard = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args,
|
void GMainWindow::WebBrowserOpenWebPage(std::string_view main_url, std::string_view additional_args,
|
||||||
|
@ -976,6 +1115,10 @@ void GMainWindow::ConnectWidgetEvents() {
|
||||||
connect(this, &GMainWindow::EmulationStopping, render_window,
|
connect(this, &GMainWindow::EmulationStopping, render_window,
|
||||||
&GRenderWindow::OnEmulationStopping);
|
&GRenderWindow::OnEmulationStopping);
|
||||||
|
|
||||||
|
// Software Keyboard Applet
|
||||||
|
connect(this, &GMainWindow::EmulationStarting, this, &GMainWindow::SoftwareKeyboardExit);
|
||||||
|
connect(this, &GMainWindow::EmulationStopping, this, &GMainWindow::SoftwareKeyboardExit);
|
||||||
|
|
||||||
connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar);
|
connect(&status_bar_update_timer, &QTimer::timeout, this, &GMainWindow::UpdateStatusBar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2185,15 +2328,6 @@ void GMainWindow::OnStartGame() {
|
||||||
|
|
||||||
emu_thread->SetRunning(true);
|
emu_thread->SetRunning(true);
|
||||||
|
|
||||||
qRegisterMetaType<Core::Frontend::ControllerParameters>("Core::Frontend::ControllerParameters");
|
|
||||||
qRegisterMetaType<Core::Frontend::SoftwareKeyboardParameters>(
|
|
||||||
"Core::Frontend::SoftwareKeyboardParameters");
|
|
||||||
qRegisterMetaType<Core::System::ResultStatus>("Core::System::ResultStatus");
|
|
||||||
qRegisterMetaType<std::string>("std::string");
|
|
||||||
qRegisterMetaType<std::optional<std::u16string>>("std::optional<std::u16string>");
|
|
||||||
qRegisterMetaType<std::string_view>("std::string_view");
|
|
||||||
qRegisterMetaType<Service::AM::Applets::WebExitReason>("Service::AM::Applets::WebExitReason");
|
|
||||||
|
|
||||||
connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
|
connect(emu_thread.get(), &EmuThread::ErrorThrown, this, &GMainWindow::OnCoreError);
|
||||||
|
|
||||||
ui.action_Start->setEnabled(false);
|
ui.action_Start->setEnabled(false);
|
||||||
|
@ -2242,8 +2376,11 @@ void GMainWindow::OnExecuteProgram(std::size_t program_index) {
|
||||||
BootGame(last_filename_booted, program_index);
|
BootGame(last_filename_booted, program_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::ErrorDisplayDisplayError(QString body) {
|
void GMainWindow::ErrorDisplayDisplayError(QString error_code, QString error_text) {
|
||||||
QMessageBox::critical(this, tr("Error Display"), body);
|
OverlayDialog dialog(render_window, Core::System::GetInstance(), error_code, error_text,
|
||||||
|
QString{}, tr("OK"), Qt::AlignLeft | Qt::AlignVCenter);
|
||||||
|
dialog.exec();
|
||||||
|
|
||||||
emit ErrorDisplayFinished();
|
emit ErrorDisplayFinished();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2295,24 +2432,66 @@ void GMainWindow::ToggleFullscreen() {
|
||||||
void GMainWindow::ShowFullscreen() {
|
void GMainWindow::ShowFullscreen() {
|
||||||
if (ui.action_Single_Window_Mode->isChecked()) {
|
if (ui.action_Single_Window_Mode->isChecked()) {
|
||||||
UISettings::values.geometry = saveGeometry();
|
UISettings::values.geometry = saveGeometry();
|
||||||
|
|
||||||
ui.menubar->hide();
|
ui.menubar->hide();
|
||||||
statusBar()->hide();
|
statusBar()->hide();
|
||||||
showFullScreen();
|
|
||||||
|
if (Settings::values.fullscreen_mode.GetValue() == 1) {
|
||||||
|
showFullScreen();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hide();
|
||||||
|
setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
||||||
|
const auto screen_geometry = QApplication::desktop()->screenGeometry(this);
|
||||||
|
setGeometry(screen_geometry.x(), screen_geometry.y(), screen_geometry.width(),
|
||||||
|
screen_geometry.height() + 1);
|
||||||
|
raise();
|
||||||
|
showNormal();
|
||||||
} else {
|
} else {
|
||||||
UISettings::values.renderwindow_geometry = render_window->saveGeometry();
|
UISettings::values.renderwindow_geometry = render_window->saveGeometry();
|
||||||
render_window->showFullScreen();
|
|
||||||
|
if (Settings::values.fullscreen_mode.GetValue() == 1) {
|
||||||
|
render_window->showFullScreen();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
render_window->hide();
|
||||||
|
render_window->setWindowFlags(windowFlags() | Qt::FramelessWindowHint);
|
||||||
|
const auto screen_geometry = QApplication::desktop()->screenGeometry(this);
|
||||||
|
render_window->setGeometry(screen_geometry.x(), screen_geometry.y(),
|
||||||
|
screen_geometry.width(), screen_geometry.height() + 1);
|
||||||
|
render_window->raise();
|
||||||
|
render_window->showNormal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::HideFullscreen() {
|
void GMainWindow::HideFullscreen() {
|
||||||
if (ui.action_Single_Window_Mode->isChecked()) {
|
if (ui.action_Single_Window_Mode->isChecked()) {
|
||||||
|
if (Settings::values.fullscreen_mode.GetValue() == 1) {
|
||||||
|
showNormal();
|
||||||
|
restoreGeometry(UISettings::values.geometry);
|
||||||
|
} else {
|
||||||
|
hide();
|
||||||
|
setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
|
||||||
|
restoreGeometry(UISettings::values.geometry);
|
||||||
|
raise();
|
||||||
|
show();
|
||||||
|
}
|
||||||
|
|
||||||
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
|
statusBar()->setVisible(ui.action_Show_Status_Bar->isChecked());
|
||||||
ui.menubar->show();
|
ui.menubar->show();
|
||||||
showNormal();
|
|
||||||
restoreGeometry(UISettings::values.geometry);
|
|
||||||
} else {
|
} else {
|
||||||
render_window->showNormal();
|
if (Settings::values.fullscreen_mode.GetValue() == 1) {
|
||||||
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
|
render_window->showNormal();
|
||||||
|
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
|
||||||
|
} else {
|
||||||
|
render_window->hide();
|
||||||
|
render_window->setWindowFlags(windowFlags() & ~Qt::FramelessWindowHint);
|
||||||
|
render_window->restoreGeometry(UISettings::values.renderwindow_geometry);
|
||||||
|
render_window->raise();
|
||||||
|
render_window->show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -62,7 +62,7 @@ void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const
|
||||||
ui->label_title->setText(title_text);
|
ui->label_title->setText(title_text);
|
||||||
ui->label_dialog->setText(body_text);
|
ui->label_dialog->setText(body_text);
|
||||||
ui->button_cancel->setText(left_button_text);
|
ui->button_cancel->setText(left_button_text);
|
||||||
ui->button_ok->setText(right_button_text);
|
ui->button_ok_label->setText(right_button_text);
|
||||||
|
|
||||||
ui->label_dialog->setAlignment(alignment);
|
ui->label_dialog->setAlignment(alignment);
|
||||||
|
|
||||||
|
@ -79,8 +79,8 @@ void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const
|
||||||
}
|
}
|
||||||
|
|
||||||
if (right_button_text.isEmpty()) {
|
if (right_button_text.isEmpty()) {
|
||||||
ui->button_ok->hide();
|
ui->button_ok_label->hide();
|
||||||
ui->button_ok->setEnabled(false);
|
ui->button_ok_label->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(
|
connect(
|
||||||
|
@ -91,7 +91,7 @@ void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const
|
||||||
},
|
},
|
||||||
Qt::QueuedConnection);
|
Qt::QueuedConnection);
|
||||||
connect(
|
connect(
|
||||||
ui->button_ok, &QPushButton::clicked, this,
|
ui->button_ok_label, &QPushButton::clicked, this,
|
||||||
[this](bool) {
|
[this](bool) {
|
||||||
StopInputThread();
|
StopInputThread();
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
|
@ -172,7 +172,7 @@ void OverlayDialog::MoveAndResizeWindow() {
|
||||||
ui->label_title->setFont(title_text_font);
|
ui->label_title->setFont(title_text_font);
|
||||||
ui->label_dialog->setFont(body_text_font);
|
ui->label_dialog->setFont(body_text_font);
|
||||||
ui->button_cancel->setFont(button_text_font);
|
ui->button_cancel->setFont(button_text_font);
|
||||||
ui->button_ok->setFont(button_text_font);
|
ui->button_ok_label->setFont(button_text_font);
|
||||||
}
|
}
|
||||||
|
|
||||||
QDialog::move(pos);
|
QDialog::move(pos);
|
||||||
|
@ -192,7 +192,7 @@ void OverlayDialog::HandleButtonPressedOnce() {
|
||||||
|
|
||||||
void OverlayDialog::TranslateButtonPress(HIDButton button) {
|
void OverlayDialog::TranslateButtonPress(HIDButton button) {
|
||||||
QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel;
|
QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel;
|
||||||
QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok;
|
QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label;
|
||||||
|
|
||||||
// TODO (Morph): Handle QTextBrowser text scrolling
|
// TODO (Morph): Handle QTextBrowser text scrolling
|
||||||
// TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it
|
// TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it
|
||||||
|
|
|
@ -136,7 +136,7 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="button_ok">
|
<widget class="QPushButton" name="button_ok_label">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
|
|
Loading…
Reference in a new issue