diff options
55 files changed, 1153 insertions, 882 deletions
diff --git a/dist/qt_themes/qdarkstyle/style.qss b/dist/qt_themes/qdarkstyle/style.qss index a3983b27e..9814b06dd 100644 --- a/dist/qt_themes/qdarkstyle/style.qss +++ b/dist/qt_themes/qdarkstyle/style.qss | |||
| @@ -2,7 +2,8 @@ QToolTip { | |||
| 2 | border: 1px solid #76797C; | 2 | border: 1px solid #76797C; |
| 3 | background-color: #5A7566; | 3 | background-color: #5A7566; |
| 4 | color: white; | 4 | color: white; |
| 5 | padding: 0px; /*remove padding, for fix combobox tooltip.*/ | 5 | /*remove padding, for fix combobox tooltip.*/ |
| 6 | padding: 0; | ||
| 6 | opacity: 200; | 7 | opacity: 200; |
| 7 | } | 8 | } |
| 8 | 9 | ||
| @@ -13,7 +14,7 @@ QWidget { | |||
| 13 | selection-color: #eff0f1; | 14 | selection-color: #eff0f1; |
| 14 | background-clip: border; | 15 | background-clip: border; |
| 15 | border-image: none; | 16 | border-image: none; |
| 16 | border: 0px transparent black; | 17 | border: 0; |
| 17 | outline: 0; | 18 | outline: 0; |
| 18 | } | 19 | } |
| 19 | 20 | ||
| @@ -27,10 +28,10 @@ QWidget:item:selected { | |||
| 27 | } | 28 | } |
| 28 | 29 | ||
| 29 | QCheckBox { | 30 | QCheckBox { |
| 30 | spacing: 5px; | 31 | spacing: 6px; |
| 31 | outline: none; | 32 | outline: none; |
| 32 | color: #eff0f1; | 33 | color: #eff0f1; |
| 33 | margin-bottom: 2px; | 34 | margin: 0 2px 1px 0; |
| 34 | } | 35 | } |
| 35 | 36 | ||
| 36 | QCheckBox:disabled { | 37 | QCheckBox:disabled { |
| @@ -163,7 +164,7 @@ QMenuBar::item:selected { | |||
| 163 | } | 164 | } |
| 164 | 165 | ||
| 165 | QMenuBar::item:pressed { | 166 | QMenuBar::item:pressed { |
| 166 | border: 1px solid #76797C; | 167 | border: 1px solid #18465d; |
| 167 | background-color: #3daee9; | 168 | background-color: #3daee9; |
| 168 | color: #eff0f1; | 169 | color: #eff0f1; |
| 169 | margin-bottom: -1px; | 170 | margin-bottom: -1px; |
| @@ -171,9 +172,9 @@ QMenuBar::item:pressed { | |||
| 171 | } | 172 | } |
| 172 | 173 | ||
| 173 | QMenu { | 174 | QMenu { |
| 174 | border: 1px solid #76797C; | 175 | border: 1px solid #434242; |
| 176 | padding: 2px; | ||
| 175 | color: #eff0f1; | 177 | color: #eff0f1; |
| 176 | margin: 2px; | ||
| 177 | } | 178 | } |
| 178 | 179 | ||
| 179 | QMenu::icon { | 180 | QMenu::icon { |
| @@ -190,11 +191,21 @@ QMenu::item:selected { | |||
| 190 | color: #eff0f1; | 191 | color: #eff0f1; |
| 191 | } | 192 | } |
| 192 | 193 | ||
| 193 | QMenu::separator { | 194 | QMenu::item:disabled { |
| 194 | height: 2px; | 195 | color: #54575B; |
| 195 | background: #76797C; | 196 | } |
| 196 | margin-left: 10px; | 197 | |
| 197 | margin-right: 5px; | 198 | QMenu::item:disabled:hover, |
| 199 | QMenu::item:disabled:selected { | ||
| 200 | background-color: #393e43; | ||
| 201 | color: #666; | ||
| 202 | } | ||
| 203 | |||
| 204 | QMenu::separator, | ||
| 205 | QMenuBar::separator { | ||
| 206 | height: 1px; | ||
| 207 | background-color: #54575B; | ||
| 208 | margin: 2px 4px 2px 40px; | ||
| 198 | } | 209 | } |
| 199 | 210 | ||
| 200 | QMenu::indicator { | 211 | QMenu::indicator { |
| @@ -203,10 +214,7 @@ QMenu::indicator { | |||
| 203 | height: 18px; | 214 | height: 18px; |
| 204 | } | 215 | } |
| 205 | 216 | ||
| 206 | 217 | /* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */ | |
| 207 | /* non-exclusive indicator = check box style indicator | ||
| 208 | (see QActionGroup::setExclusive) */ | ||
| 209 | |||
| 210 | QMenu::indicator:non-exclusive:unchecked { | 218 | QMenu::indicator:non-exclusive:unchecked { |
| 211 | image: url(:/qss_icons/rc/checkbox_unchecked.png); | 219 | image: url(:/qss_icons/rc/checkbox_unchecked.png); |
| 212 | } | 220 | } |
| @@ -223,9 +231,7 @@ QMenu::indicator:non-exclusive:checked:selected { | |||
| 223 | image: url(:/qss_icons/rc/checkbox_checked_disabled.png); | 231 | image: url(:/qss_icons/rc/checkbox_checked_disabled.png); |
| 224 | } | 232 | } |
| 225 | 233 | ||
| 226 | |||
| 227 | /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ | 234 | /* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */ |
| 228 | |||
| 229 | QMenu::indicator:exclusive:unchecked { | 235 | QMenu::indicator:exclusive:unchecked { |
| 230 | image: url(:/qss_icons/rc/radio_unchecked.png); | 236 | image: url(:/qss_icons/rc/radio_unchecked.png); |
| 231 | } | 237 | } |
| @@ -243,12 +249,12 @@ QMenu::indicator:exclusive:checked:selected { | |||
| 243 | } | 249 | } |
| 244 | 250 | ||
| 245 | QMenu::right-arrow { | 251 | QMenu::right-arrow { |
| 246 | margin: 5px; | 252 | margin-right: 10px; |
| 247 | image: url(:/qss_icons/rc/right_arrow.png) | 253 | image: url(:/qss_icons/rc/right_arrow.png) |
| 248 | } | 254 | } |
| 249 | 255 | ||
| 250 | QWidget:disabled { | 256 | QWidget:disabled { |
| 251 | color: #454545; | 257 | color: #4f515b; |
| 252 | background-color: #31363b; | 258 | background-color: #31363b; |
| 253 | } | 259 | } |
| 254 | 260 | ||
| @@ -259,23 +265,30 @@ QAbstractItemView { | |||
| 259 | border-radius: 2px; | 265 | border-radius: 2px; |
| 260 | } | 266 | } |
| 261 | 267 | ||
| 262 | QWidget:focus, | 268 | QAbstractItemView:disabled, |
| 263 | QMenuBar:focus { | 269 | QAbstractItemView:read-only { |
| 270 | alternate-background-color: #232629; | ||
| 271 | } | ||
| 272 | |||
| 273 | QWidget:focus { | ||
| 264 | border: 1px solid #3daee9; | 274 | border: 1px solid #3daee9; |
| 265 | } | 275 | } |
| 266 | 276 | ||
| 267 | QTabWidget:focus, | 277 | QTabWidget:focus, |
| 268 | QCheckBox:focus, | 278 | QCheckBox:focus, |
| 269 | QRadioButton:focus, | 279 | QRadioButton:focus, |
| 270 | QSlider:focus { | 280 | QSlider:focus, |
| 281 | QTreeView:focus, | ||
| 282 | QMenu:focus, | ||
| 283 | QMenuBar:focus, | ||
| 284 | QTabBar:focus { | ||
| 271 | border: none; | 285 | border: none; |
| 272 | } | 286 | } |
| 273 | 287 | ||
| 274 | QLineEdit { | 288 | QLineEdit { |
| 275 | background-color: #232629; | 289 | background-color: #232629; |
| 276 | padding: 5px; | 290 | padding: 5px; |
| 277 | border-style: solid; | 291 | border: 1px solid #54575B; |
| 278 | border: 1px solid #76797C; | ||
| 279 | border-radius: 2px; | 292 | border-radius: 2px; |
| 280 | color: #eff0f1; | 293 | color: #eff0f1; |
| 281 | } | 294 | } |
| @@ -285,9 +298,10 @@ QAbstractItemView QLineEdit { | |||
| 285 | } | 298 | } |
| 286 | 299 | ||
| 287 | QGroupBox { | 300 | QGroupBox { |
| 288 | border: 1px solid #76797C; | 301 | border: 1px solid #54575B; |
| 289 | border-radius: 2px; | 302 | border-radius: 2px; |
| 290 | margin-top: 20px; | 303 | margin-top: 12px; |
| 304 | padding-top: 2px; | ||
| 291 | } | 305 | } |
| 292 | 306 | ||
| 293 | QGroupBox::title { | 307 | QGroupBox::title { |
| @@ -295,12 +309,12 @@ QGroupBox::title { | |||
| 295 | subcontrol-position: top center; | 309 | subcontrol-position: top center; |
| 296 | padding-left: 10px; | 310 | padding-left: 10px; |
| 297 | padding-right: 10px; | 311 | padding-right: 10px; |
| 298 | padding-top: 10px; | 312 | padding-top: 2px; |
| 299 | } | 313 | } |
| 300 | 314 | ||
| 301 | QAbstractScrollArea { | 315 | QAbstractScrollArea { |
| 302 | border-radius: 2px; | 316 | border-radius: 2px; |
| 303 | border: 1px solid #76797C; | 317 | border: 1px solid #54575B; |
| 304 | background-color: transparent; | 318 | background-color: transparent; |
| 305 | } | 319 | } |
| 306 | 320 | ||
| @@ -319,7 +333,7 @@ QScrollBar::handle:horizontal { | |||
| 319 | } | 333 | } |
| 320 | 334 | ||
| 321 | QScrollBar::add-line:horizontal { | 335 | QScrollBar::add-line:horizontal { |
| 322 | margin: 0px 3px 0px 3px; | 336 | margin: 0 3px; |
| 323 | border-image: url(:/qss_icons/rc/right_arrow_disabled.png); | 337 | border-image: url(:/qss_icons/rc/right_arrow_disabled.png); |
| 324 | width: 10px; | 338 | width: 10px; |
| 325 | height: 10px; | 339 | height: 10px; |
| @@ -328,7 +342,7 @@ QScrollBar::add-line:horizontal { | |||
| 328 | } | 342 | } |
| 329 | 343 | ||
| 330 | QScrollBar::sub-line:horizontal { | 344 | QScrollBar::sub-line:horizontal { |
| 331 | margin: 0px 3px 0px 3px; | 345 | margin: 0 3px; |
| 332 | border-image: url(:/qss_icons/rc/left_arrow_disabled.png); | 346 | border-image: url(:/qss_icons/rc/left_arrow_disabled.png); |
| 333 | height: 10px; | 347 | height: 10px; |
| 334 | width: 10px; | 348 | width: 10px; |
| @@ -379,7 +393,7 @@ QScrollBar::handle:vertical { | |||
| 379 | } | 393 | } |
| 380 | 394 | ||
| 381 | QScrollBar::sub-line:vertical { | 395 | QScrollBar::sub-line:vertical { |
| 382 | margin: 3px 0px 3px 0px; | 396 | margin: 3px 0; |
| 383 | border-image: url(:/qss_icons/rc/up_arrow_disabled.png); | 397 | border-image: url(:/qss_icons/rc/up_arrow_disabled.png); |
| 384 | height: 10px; | 398 | height: 10px; |
| 385 | width: 10px; | 399 | width: 10px; |
| @@ -388,7 +402,7 @@ QScrollBar::sub-line:vertical { | |||
| 388 | } | 402 | } |
| 389 | 403 | ||
| 390 | QScrollBar::add-line:vertical { | 404 | QScrollBar::add-line:vertical { |
| 391 | margin: 3px 0px 3px 0px; | 405 | margin: 3px 0; |
| 392 | border-image: url(:/qss_icons/rc/down_arrow_disabled.png); | 406 | border-image: url(:/qss_icons/rc/down_arrow_disabled.png); |
| 393 | height: 10px; | 407 | height: 10px; |
| 394 | width: 10px; | 408 | width: 10px; |
| @@ -427,15 +441,14 @@ QScrollBar::sub-page:vertical { | |||
| 427 | QTextEdit { | 441 | QTextEdit { |
| 428 | background-color: #232629; | 442 | background-color: #232629; |
| 429 | color: #eff0f1; | 443 | color: #eff0f1; |
| 430 | border: 1px solid #76797C; | 444 | border: 1px solid #54575B; |
| 431 | } | 445 | } |
| 432 | 446 | ||
| 433 | QPlainTextEdit { | 447 | QPlainTextEdit { |
| 434 | background-color: #232629; | 448 | background-color: #232629; |
| 435 | ; | ||
| 436 | color: #eff0f1; | 449 | color: #eff0f1; |
| 437 | border-radius: 2px; | 450 | border-radius: 2px; |
| 438 | border: 1px solid #76797C; | 451 | border: 1px solid #54575B; |
| 439 | } | 452 | } |
| 440 | 453 | ||
| 441 | QHeaderView::section { | 454 | QHeaderView::section { |
| @@ -467,15 +480,6 @@ QMainWindow::separator:hover { | |||
| 467 | spacing: 2px; | 480 | spacing: 2px; |
| 468 | } | 481 | } |
| 469 | 482 | ||
| 470 | QMenu::separator { | ||
| 471 | height: 1px; | ||
| 472 | background-color: #76797C; | ||
| 473 | color: white; | ||
| 474 | padding-left: 4px; | ||
| 475 | margin-left: 10px; | ||
| 476 | margin-right: 5px; | ||
| 477 | } | ||
| 478 | |||
| 479 | QFrame { | 483 | QFrame { |
| 480 | border-radius: 2px; | 484 | border-radius: 2px; |
| 481 | border: 1px solid #76797C; | 485 | border: 1px solid #76797C; |
| @@ -518,25 +522,19 @@ QToolButton#qt_toolbar_ext_button { | |||
| 518 | 522 | ||
| 519 | QPushButton { | 523 | QPushButton { |
| 520 | color: #eff0f1; | 524 | color: #eff0f1; |
| 521 | background-color: #31363b; | ||
| 522 | border-width: 1px; | 525 | border-width: 1px; |
| 523 | border-color: #76797C; | 526 | border-color: #54575B; |
| 524 | border-style: solid; | 527 | border-style: solid; |
| 525 | padding: 5px; | 528 | padding: 6px 4px; |
| 526 | border-radius: 2px; | 529 | border-radius: 2px; |
| 527 | outline: none; | 530 | outline: none; |
| 531 | min-width: 100px; | ||
| 532 | background-color: #232629; | ||
| 528 | } | 533 | } |
| 529 | 534 | ||
| 530 | QPushButton:disabled { | 535 | QPushButton:disabled { |
| 531 | background-color: #31363b; | 536 | background-color: #31363b; |
| 532 | border-width: 1px; | ||
| 533 | border-color: #454545; | 537 | border-color: #454545; |
| 534 | border-style: solid; | ||
| 535 | padding-top: 5px; | ||
| 536 | padding-bottom: 5px; | ||
| 537 | padding-left: 10px; | ||
| 538 | padding-right: 10px; | ||
| 539 | border-radius: 2px; | ||
| 540 | color: #454545; | 538 | color: #454545; |
| 541 | } | 539 | } |
| 542 | 540 | ||
| @@ -553,11 +551,11 @@ QPushButton:pressed { | |||
| 553 | 551 | ||
| 554 | QComboBox { | 552 | QComboBox { |
| 555 | selection-background-color: #3daee9; | 553 | selection-background-color: #3daee9; |
| 556 | border-style: solid; | 554 | border: 1px solid #54575B; |
| 557 | border: 1px solid #76797C; | ||
| 558 | border-radius: 2px; | 555 | border-radius: 2px; |
| 559 | padding: 5px; | 556 | padding: 4px 6px; |
| 560 | min-width: 75px; | 557 | min-width: 75px; |
| 558 | background-color: #232629; | ||
| 561 | } | 559 | } |
| 562 | 560 | ||
| 563 | QPushButton:checked { | 561 | QPushButton:checked { |
| @@ -571,8 +569,7 @@ QAbstractSpinBox:hover, | |||
| 571 | QLineEdit:hover, | 569 | QLineEdit:hover, |
| 572 | QTextEdit:hover, | 570 | QTextEdit:hover, |
| 573 | QPlainTextEdit:hover, | 571 | QPlainTextEdit:hover, |
| 574 | QAbstractView:hover, | 572 | QAbstractView:hover { |
| 575 | QTreeView:hover { | ||
| 576 | border: 1px solid #3daee9; | 573 | border: 1px solid #3daee9; |
| 577 | color: #eff0f1; | 574 | color: #eff0f1; |
| 578 | } | 575 | } |
| @@ -591,6 +588,7 @@ QComboBox QAbstractItemView { | |||
| 591 | QComboBox::drop-down { | 588 | QComboBox::drop-down { |
| 592 | subcontrol-origin: padding; | 589 | subcontrol-origin: padding; |
| 593 | subcontrol-position: top right; | 590 | subcontrol-position: top right; |
| 591 | left: -6px; | ||
| 594 | width: 15px; | 592 | width: 15px; |
| 595 | border-left-width: 0px; | 593 | border-left-width: 0px; |
| 596 | border-left-color: darkgray; | 594 | border-left-color: darkgray; |
| @@ -610,8 +608,8 @@ QComboBox::down-arrow:focus { | |||
| 610 | } | 608 | } |
| 611 | 609 | ||
| 612 | QAbstractSpinBox { | 610 | QAbstractSpinBox { |
| 613 | padding: 5px; | 611 | padding: 4px 6px; |
| 614 | border: 1px solid #76797C; | 612 | border: 1px solid #54575B; |
| 615 | background-color: #232629; | 613 | background-color: #232629; |
| 616 | color: #eff0f1; | 614 | color: #eff0f1; |
| 617 | border-radius: 2px; | 615 | border-radius: 2px; |
| @@ -622,12 +620,14 @@ QAbstractSpinBox:up-button { | |||
| 622 | background-color: transparent; | 620 | background-color: transparent; |
| 623 | subcontrol-origin: border; | 621 | subcontrol-origin: border; |
| 624 | subcontrol-position: center right; | 622 | subcontrol-position: center right; |
| 623 | left: -6px; | ||
| 625 | } | 624 | } |
| 626 | 625 | ||
| 627 | QAbstractSpinBox:down-button { | 626 | QAbstractSpinBox:down-button { |
| 628 | background-color: transparent; | 627 | background-color: transparent; |
| 629 | subcontrol-origin: border; | 628 | subcontrol-origin: border; |
| 630 | subcontrol-position: center left; | 629 | subcontrol-position: center left; |
| 630 | right: -6px; | ||
| 631 | } | 631 | } |
| 632 | 632 | ||
| 633 | QAbstractSpinBox::up-arrow, | 633 | QAbstractSpinBox::up-arrow, |
| @@ -654,22 +654,27 @@ QAbstractSpinBox::down-arrow:hover { | |||
| 654 | image: url(:/qss_icons/rc/down_arrow.png); | 654 | image: url(:/qss_icons/rc/down_arrow.png); |
| 655 | } | 655 | } |
| 656 | 656 | ||
| 657 | QLabel { | 657 | QLabel, |
| 658 | border: 0px solid black; | 658 | QTabWidget { |
| 659 | border: 0; | ||
| 659 | } | 660 | } |
| 660 | 661 | ||
| 661 | QTabWidget { | 662 | QTabWidget { |
| 662 | border: 0px transparent black; | 663 | padding-top: 1px; |
| 663 | } | 664 | } |
| 664 | 665 | ||
| 665 | QTabWidget::pane { | 666 | QTabWidget::pane { |
| 666 | border: 1px solid #76797C; | 667 | border: 1px solid #76797C; |
| 667 | padding: 5px; | 668 | padding: 5px; |
| 668 | margin: 0px; | 669 | position: absolute; |
| 670 | top: -1px; | ||
| 671 | border-top-right-radius: 2px; | ||
| 672 | border-bottom-right-radius: 2px; | ||
| 673 | border-bottom-left-radius: 2px; | ||
| 669 | } | 674 | } |
| 670 | 675 | ||
| 671 | QTabWidget::tab-bar { | 676 | QTabWidget::tab-bar { |
| 672 | /* left: 5px; move to the right by 5px */ | 677 | overflow: visible; |
| 673 | } | 678 | } |
| 674 | 679 | ||
| 675 | QTabBar { | 680 | QTabBar { |
| @@ -677,10 +682,6 @@ QTabBar { | |||
| 677 | border-radius: 3px; | 682 | border-radius: 3px; |
| 678 | } | 683 | } |
| 679 | 684 | ||
| 680 | QTabBar:focus { | ||
| 681 | border: 0px transparent black; | ||
| 682 | } | ||
| 683 | |||
| 684 | QTabBar::close-button { | 685 | QTabBar::close-button { |
| 685 | image: url(:/qss_icons/rc/close.png); | 686 | image: url(:/qss_icons/rc/close.png); |
| 686 | background: transparent; | 687 | background: transparent; |
| @@ -696,36 +697,33 @@ QTabBar::close-button:pressed { | |||
| 696 | background: transparent; | 697 | background: transparent; |
| 697 | } | 698 | } |
| 698 | 699 | ||
| 699 | |||
| 700 | /* TOP TABS */ | 700 | /* TOP TABS */ |
| 701 | |||
| 702 | QTabBar::tab:top { | 701 | QTabBar::tab:top { |
| 703 | color: #eff0f1; | 702 | color: #eff0f1; |
| 704 | border: 1px solid #76797C; | 703 | border: 1px solid #54575B; |
| 705 | border-bottom: 2px transparent; | 704 | background-color: #2a2f33; |
| 706 | background-color: #31363b; | 705 | padding: 4px 16px 5px; |
| 707 | padding: 4px 16px 2px; | 706 | min-width: 36px; |
| 708 | min-width: 38px; | ||
| 709 | border-top-left-radius: 2px; | 707 | border-top-left-radius: 2px; |
| 710 | border-top-right-radius: 2px; | 708 | border-top-right-radius: 2px; |
| 711 | } | 709 | } |
| 712 | 710 | ||
| 713 | QTabBar::tab:top:selected { | 711 | QTabBar::tab:top:selected { |
| 714 | color: #eff0f1; | 712 | border-color: #76797C; |
| 715 | background-color: #54575B; | 713 | background-color: #31363b; |
| 716 | border: 1px solid #76797C; | 714 | border-bottom-color: #31363b; |
| 717 | border-bottom: 2px solid #3daee9; | 715 | } |
| 718 | border-top-left-radius: 2px; | 716 | |
| 719 | border-top-right-radius: 2px; | 717 | QTabBar::tab:top:!selected { |
| 718 | margin-top: 1px; | ||
| 719 | border-bottom-color: #76797C; | ||
| 720 | } | 720 | } |
| 721 | 721 | ||
| 722 | QTabBar::tab:top:!selected:hover { | 722 | QTabBar::tab:top:!selected:hover { |
| 723 | background-color: #3daee9; | 723 | background-color: #3daee9; |
| 724 | } | 724 | } |
| 725 | 725 | ||
| 726 | |||
| 727 | /* BOTTOM TABS */ | 726 | /* BOTTOM TABS */ |
| 728 | |||
| 729 | QTabBar::tab:bottom { | 727 | QTabBar::tab:bottom { |
| 730 | color: #eff0f1; | 728 | color: #eff0f1; |
| 731 | border: 1px solid #76797C; | 729 | border: 1px solid #76797C; |
| @@ -750,9 +748,7 @@ QTabBar::tab:bottom:!selected:hover { | |||
| 750 | background-color: #3daee9; | 748 | background-color: #3daee9; |
| 751 | } | 749 | } |
| 752 | 750 | ||
| 753 | |||
| 754 | /* LEFT TABS */ | 751 | /* LEFT TABS */ |
| 755 | |||
| 756 | QTabBar::tab:left { | 752 | QTabBar::tab:left { |
| 757 | color: #eff0f1; | 753 | color: #eff0f1; |
| 758 | border: 1px solid #76797C; | 754 | border: 1px solid #76797C; |
| @@ -777,9 +773,7 @@ QTabBar::tab:left:!selected:hover { | |||
| 777 | background-color: #3daee9; | 773 | background-color: #3daee9; |
| 778 | } | 774 | } |
| 779 | 775 | ||
| 780 | |||
| 781 | /* RIGHT TABS */ | 776 | /* RIGHT TABS */ |
| 782 | |||
| 783 | QTabBar::tab:right { | 777 | QTabBar::tab:right { |
| 784 | color: #eff0f1; | 778 | color: #eff0f1; |
| 785 | border: 1px solid #76797C; | 779 | border: 1px solid #76797C; |
| @@ -847,7 +841,7 @@ QDockWidget::float-button:pressed { | |||
| 847 | 841 | ||
| 848 | QTreeView, | 842 | QTreeView, |
| 849 | QListView { | 843 | QListView { |
| 850 | border: 1px solid #76797C; | 844 | border: 1px solid #54575B; |
| 851 | background-color: #232629; | 845 | background-color: #232629; |
| 852 | } | 846 | } |
| 853 | 847 | ||
| @@ -978,8 +972,8 @@ QSlider::handle:vertical { | |||
| 978 | } | 972 | } |
| 979 | 973 | ||
| 980 | QToolButton { | 974 | QToolButton { |
| 981 | background-color: transparent; | 975 | background-color: #232629; |
| 982 | border: 1px transparent #76797C; | 976 | border: 1px solid #54575B; |
| 983 | border-radius: 2px; | 977 | border-radius: 2px; |
| 984 | margin: 3px; | 978 | margin: 3px; |
| 985 | padding: 5px; | 979 | padding: 5px; |
| @@ -988,7 +982,6 @@ QToolButton { | |||
| 988 | QToolButton[popupMode="1"] { | 982 | QToolButton[popupMode="1"] { |
| 989 | /* only for MenuButtonPopup */ | 983 | /* only for MenuButtonPopup */ |
| 990 | padding-right: 20px; | 984 | padding-right: 20px; |
| 991 | /* make way for the popup button */ | ||
| 992 | border: 1px #76797C; | 985 | border: 1px #76797C; |
| 993 | border-radius: 5px; | 986 | border-radius: 5px; |
| 994 | } | 987 | } |
| @@ -996,7 +989,6 @@ QToolButton[popupMode="1"] { | |||
| 996 | QToolButton[popupMode="2"] { | 989 | QToolButton[popupMode="2"] { |
| 997 | /* only for InstantPopup */ | 990 | /* only for InstantPopup */ |
| 998 | padding-right: 10px; | 991 | padding-right: 10px; |
| 999 | /* make way for the popup button */ | ||
| 1000 | border: 1px #76797C; | 992 | border: 1px #76797C; |
| 1001 | } | 993 | } |
| 1002 | 994 | ||
| @@ -1015,19 +1007,14 @@ QToolButton::menu-button:pressed { | |||
| 1015 | padding: 5px; | 1007 | padding: 5px; |
| 1016 | } | 1008 | } |
| 1017 | 1009 | ||
| 1018 | |||
| 1019 | /* the subcontrol below is used only in the InstantPopup or DelayedPopup mode */ | 1010 | /* the subcontrol below is used only in the InstantPopup or DelayedPopup mode */ |
| 1020 | |||
| 1021 | QToolButton::menu-indicator { | 1011 | QToolButton::menu-indicator { |
| 1022 | image: url(:/qss_icons/rc/down_arrow.png); | 1012 | image: url(:/qss_icons/rc/down_arrow.png); |
| 1023 | top: -7px; | 1013 | top: -7px; |
| 1024 | left: -2px; | 1014 | left: -2px; |
| 1025 | /* shift it a bit */ | ||
| 1026 | } | 1015 | } |
| 1027 | 1016 | ||
| 1028 | |||
| 1029 | /* the subcontrols below are used only in the MenuButtonPopup mode */ | 1017 | /* the subcontrols below are used only in the MenuButtonPopup mode */ |
| 1030 | |||
| 1031 | QToolButton::menu-button { | 1018 | QToolButton::menu-button { |
| 1032 | border: 1px transparent #76797C; | 1019 | border: 1px transparent #76797C; |
| 1033 | border-top-right-radius: 6px; | 1020 | border-top-right-radius: 6px; |
| @@ -1052,14 +1039,22 @@ QPushButton::menu-indicator { | |||
| 1052 | } | 1039 | } |
| 1053 | 1040 | ||
| 1054 | QTableView { | 1041 | QTableView { |
| 1055 | border: 1px solid #76797C; | 1042 | border: 1px solid #54575B; |
| 1056 | gridline-color: #31363b; | 1043 | gridline-color: #31363b; |
| 1057 | background-color: #232629; | 1044 | background-color: #232629; |
| 1058 | } | 1045 | } |
| 1059 | 1046 | ||
| 1047 | QTreeView:disabled { | ||
| 1048 | background-color: #1f2225; | ||
| 1049 | } | ||
| 1050 | |||
| 1060 | QTableView, | 1051 | QTableView, |
| 1061 | QHeaderView { | 1052 | QHeaderView { |
| 1062 | border-radius: 0px; | 1053 | border-radius: 0; |
| 1054 | } | ||
| 1055 | |||
| 1056 | QListView:focus { | ||
| 1057 | border-color: #54575B; | ||
| 1063 | } | 1058 | } |
| 1064 | 1059 | ||
| 1065 | QTableView::item:pressed, | 1060 | QTableView::item:pressed, |
| @@ -1088,7 +1083,7 @@ QHeaderView::section { | |||
| 1088 | background-color: #232629; | 1083 | background-color: #232629; |
| 1089 | color: #eff0f1; | 1084 | color: #eff0f1; |
| 1090 | padding: 0 5px; | 1085 | padding: 0 5px; |
| 1091 | border: 1px solid #403F3F; | 1086 | border: 1px solid #434242; |
| 1092 | border-bottom: 0; | 1087 | border-bottom: 0; |
| 1093 | border-radius: 0px; | 1088 | border-radius: 0px; |
| 1094 | text-align: center; | 1089 | text-align: center; |
| @@ -1118,9 +1113,7 @@ QHeaderView::section:checked { | |||
| 1118 | background-color: #334e5e; | 1113 | background-color: #334e5e; |
| 1119 | } | 1114 | } |
| 1120 | 1115 | ||
| 1121 | 1116 | /* sort indicator */ | |
| 1122 | /* style the sort indicator */ | ||
| 1123 | |||
| 1124 | QHeaderView::down-arrow { | 1117 | QHeaderView::down-arrow { |
| 1125 | image: url(:/qss_icons/rc/down_arrow.png); | 1118 | image: url(:/qss_icons/rc/down_arrow.png); |
| 1126 | } | 1119 | } |
| @@ -1150,14 +1143,13 @@ QToolBox::tab { | |||
| 1150 | } | 1143 | } |
| 1151 | 1144 | ||
| 1152 | QToolBox::tab:selected { | 1145 | QToolBox::tab:selected { |
| 1153 | /* italicize selected tabs */ | ||
| 1154 | font: italic; | 1146 | font: italic; |
| 1155 | background-color: #31363b; | 1147 | background-color: #31363b; |
| 1156 | border-color: #3daee9; | 1148 | border-color: #3daee9; |
| 1157 | } | 1149 | } |
| 1158 | 1150 | ||
| 1159 | QStatusBar::item { | 1151 | QStatusBar::item { |
| 1160 | border: 0px transparent dark; | 1152 | border: 0; |
| 1161 | } | 1153 | } |
| 1162 | 1154 | ||
| 1163 | QFrame[height="3"], | 1155 | QFrame[height="3"], |
| @@ -1194,7 +1186,6 @@ QProgressBar::chunk { | |||
| 1194 | 1186 | ||
| 1195 | QDateEdit { | 1187 | QDateEdit { |
| 1196 | selection-background-color: #3daee9; | 1188 | selection-background-color: #3daee9; |
| 1197 | border-style: solid; | ||
| 1198 | border: 1px solid #3375A3; | 1189 | border: 1px solid #3375A3; |
| 1199 | border-radius: 2px; | 1190 | border-radius: 2px; |
| 1200 | padding: 1px; | 1191 | padding: 1px; |
| @@ -1218,7 +1209,7 @@ QDateEdit::drop-down { | |||
| 1218 | subcontrol-origin: padding; | 1209 | subcontrol-origin: padding; |
| 1219 | subcontrol-position: top right; | 1210 | subcontrol-position: top right; |
| 1220 | width: 15px; | 1211 | width: 15px; |
| 1221 | border-left-width: 0px; | 1212 | border-left-width: 0; |
| 1222 | border-left-color: darkgray; | 1213 | border-left-color: darkgray; |
| 1223 | border-left-style: solid; | 1214 | border-left-style: solid; |
| 1224 | border-top-right-radius: 3px; | 1215 | border-top-right-radius: 3px; |
| @@ -1234,3 +1225,14 @@ QDateEdit::down-arrow:hover, | |||
| 1234 | QDateEdit::down-arrow:focus { | 1225 | QDateEdit::down-arrow:focus { |
| 1235 | image: url(:/qss_icons/rc/down_arrow.png); | 1226 | image: url(:/qss_icons/rc/down_arrow.png); |
| 1236 | } | 1227 | } |
| 1228 | |||
| 1229 | QComboBox:disabled, | ||
| 1230 | QPushButton:disabled, | ||
| 1231 | QAbstractSpinBox:disabled, | ||
| 1232 | QDateEdit:disabled, | ||
| 1233 | QLineEdit:disabled, | ||
| 1234 | QTextEdit:disabled, | ||
| 1235 | QToolButton:disabled, | ||
| 1236 | QPlainTextEdit:disabled { | ||
| 1237 | background-color: #2b2e31; | ||
| 1238 | } | ||
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 8f2591d53..04bc3128f 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -120,7 +120,7 @@ private: | |||
| 120 | duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin); | 120 | duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin); |
| 121 | entry.log_class = log_class; | 121 | entry.log_class = log_class; |
| 122 | entry.log_level = log_level; | 122 | entry.log_level = log_level; |
| 123 | entry.filename = Common::TrimSourcePath(filename); | 123 | entry.filename = filename; |
| 124 | entry.line_num = line_nr; | 124 | entry.line_num = line_nr; |
| 125 | entry.function = function; | 125 | entry.function = function; |
| 126 | entry.message = std::move(message); | 126 | entry.message = std::move(message); |
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h index fca0267a1..fc338c70d 100644 --- a/src/common/logging/backend.h +++ b/src/common/logging/backend.h | |||
| @@ -23,7 +23,7 @@ struct Entry { | |||
| 23 | std::chrono::microseconds timestamp; | 23 | std::chrono::microseconds timestamp; |
| 24 | Class log_class; | 24 | Class log_class; |
| 25 | Level log_level; | 25 | Level log_level; |
| 26 | std::string filename; | 26 | const char* filename; |
| 27 | unsigned int line_num; | 27 | unsigned int line_num; |
| 28 | std::string function; | 28 | std::string function; |
| 29 | std::string message; | 29 | std::string message; |
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index 259708116..13a4f1e30 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -9,6 +9,15 @@ | |||
| 9 | 9 | ||
| 10 | namespace Log { | 10 | namespace Log { |
| 11 | 11 | ||
| 12 | // trims up to and including the last of ../, ..\, src/, src\ in a string | ||
| 13 | constexpr const char* TrimSourcePath(std::string_view source) { | ||
| 14 | const auto rfind = [source](const std::string_view match) { | ||
| 15 | return source.rfind(match) == source.npos ? 0 : (source.rfind(match) + match.size()); | ||
| 16 | }; | ||
| 17 | auto idx = std::max({rfind("src/"), rfind("src\\"), rfind("../"), rfind("..\\")}); | ||
| 18 | return source.data() + idx; | ||
| 19 | } | ||
| 20 | |||
| 12 | /// Specifies the severity or level of detail of the log message. | 21 | /// Specifies the severity or level of detail of the log message. |
| 13 | enum class Level : u8 { | 22 | enum class Level : u8 { |
| 14 | Trace, ///< Extremely detailed and repetitive debugging information that is likely to | 23 | Trace, ///< Extremely detailed and repetitive debugging information that is likely to |
| @@ -141,24 +150,24 @@ void FmtLogMessage(Class log_class, Level log_level, const char* filename, unsig | |||
| 141 | 150 | ||
| 142 | #ifdef _DEBUG | 151 | #ifdef _DEBUG |
| 143 | #define LOG_TRACE(log_class, ...) \ | 152 | #define LOG_TRACE(log_class, ...) \ |
| 144 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, __FILE__, __LINE__, \ | 153 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Trace, \ |
| 145 | __func__, __VA_ARGS__) | 154 | ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) |
| 146 | #else | 155 | #else |
| 147 | #define LOG_TRACE(log_class, fmt, ...) (void(0)) | 156 | #define LOG_TRACE(log_class, fmt, ...) (void(0)) |
| 148 | #endif | 157 | #endif |
| 149 | 158 | ||
| 150 | #define LOG_DEBUG(log_class, ...) \ | 159 | #define LOG_DEBUG(log_class, ...) \ |
| 151 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Debug, __FILE__, __LINE__, \ | 160 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Debug, \ |
| 152 | __func__, __VA_ARGS__) | 161 | ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) |
| 153 | #define LOG_INFO(log_class, ...) \ | 162 | #define LOG_INFO(log_class, ...) \ |
| 154 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Info, __FILE__, __LINE__, \ | 163 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Info, \ |
| 155 | __func__, __VA_ARGS__) | 164 | ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) |
| 156 | #define LOG_WARNING(log_class, ...) \ | 165 | #define LOG_WARNING(log_class, ...) \ |
| 157 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Warning, __FILE__, __LINE__, \ | 166 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Warning, \ |
| 158 | __func__, __VA_ARGS__) | 167 | ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) |
| 159 | #define LOG_ERROR(log_class, ...) \ | 168 | #define LOG_ERROR(log_class, ...) \ |
| 160 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Error, __FILE__, __LINE__, \ | 169 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Error, \ |
| 161 | __func__, __VA_ARGS__) | 170 | ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) |
| 162 | #define LOG_CRITICAL(log_class, ...) \ | 171 | #define LOG_CRITICAL(log_class, ...) \ |
| 163 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Critical, __FILE__, __LINE__, \ | 172 | ::Log::FmtLogMessage(::Log::Class::log_class, ::Log::Level::Critical, \ |
| 164 | __func__, __VA_ARGS__) | 173 | ::Log::TrimSourcePath(__FILE__), __LINE__, __func__, __VA_ARGS__) |
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp index 959f278aa..84883a1d3 100644 --- a/src/common/string_util.cpp +++ b/src/common/string_util.cpp | |||
| @@ -223,26 +223,4 @@ std::u16string UTF16StringFromFixedZeroTerminatedBuffer(std::u16string_view buff | |||
| 223 | return std::u16string(buffer.begin(), buffer.begin() + len); | 223 | return std::u16string(buffer.begin(), buffer.begin() + len); |
| 224 | } | 224 | } |
| 225 | 225 | ||
| 226 | const char* TrimSourcePath(const char* path, const char* root) { | ||
| 227 | const char* p = path; | ||
| 228 | |||
| 229 | while (*p != '\0') { | ||
| 230 | const char* next_slash = p; | ||
| 231 | while (*next_slash != '\0' && *next_slash != '/' && *next_slash != '\\') { | ||
| 232 | ++next_slash; | ||
| 233 | } | ||
| 234 | |||
| 235 | bool is_src = Common::ComparePartialString(p, next_slash, root); | ||
| 236 | p = next_slash; | ||
| 237 | |||
| 238 | if (*p != '\0') { | ||
| 239 | ++p; | ||
| 240 | } | ||
| 241 | if (is_src) { | ||
| 242 | path = p; | ||
| 243 | } | ||
| 244 | } | ||
| 245 | return path; | ||
| 246 | } | ||
| 247 | |||
| 248 | } // namespace Common | 226 | } // namespace Common |
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1a3647a67..d342cafe0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -15,14 +15,14 @@ add_library(core STATIC | |||
| 15 | constants.h | 15 | constants.h |
| 16 | core.cpp | 16 | core.cpp |
| 17 | core.h | 17 | core.h |
| 18 | core_cpu.cpp | 18 | core_manager.cpp |
| 19 | core_cpu.h | 19 | core_manager.h |
| 20 | core_timing.cpp | 20 | core_timing.cpp |
| 21 | core_timing.h | 21 | core_timing.h |
| 22 | core_timing_util.cpp | 22 | core_timing_util.cpp |
| 23 | core_timing_util.h | 23 | core_timing_util.h |
| 24 | cpu_core_manager.cpp | 24 | cpu_manager.cpp |
| 25 | cpu_core_manager.h | 25 | cpu_manager.h |
| 26 | crypto/aes_util.cpp | 26 | crypto/aes_util.cpp |
| 27 | crypto/aes_util.h | 27 | crypto/aes_util.h |
| 28 | crypto/encryption_layer.cpp | 28 | crypto/encryption_layer.cpp |
| @@ -158,6 +158,8 @@ add_library(core STATIC | |||
| 158 | hle/kernel/mutex.h | 158 | hle/kernel/mutex.h |
| 159 | hle/kernel/object.cpp | 159 | hle/kernel/object.cpp |
| 160 | hle/kernel/object.h | 160 | hle/kernel/object.h |
| 161 | hle/kernel/physical_core.cpp | ||
| 162 | hle/kernel/physical_core.h | ||
| 161 | hle/kernel/process.cpp | 163 | hle/kernel/process.cpp |
| 162 | hle/kernel/process.h | 164 | hle/kernel/process.h |
| 163 | hle/kernel/process_capability.cpp | 165 | hle/kernel/process_capability.cpp |
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp index e825c0526..791640a3a 100644 --- a/src/core/arm/dynarmic/arm_dynarmic.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic.cpp | |||
| @@ -10,11 +10,12 @@ | |||
| 10 | #include "common/microprofile.h" | 10 | #include "common/microprofile.h" |
| 11 | #include "core/arm/dynarmic/arm_dynarmic.h" | 11 | #include "core/arm/dynarmic/arm_dynarmic.h" |
| 12 | #include "core/core.h" | 12 | #include "core/core.h" |
| 13 | #include "core/core_cpu.h" | 13 | #include "core/core_manager.h" |
| 14 | #include "core/core_timing.h" | 14 | #include "core/core_timing.h" |
| 15 | #include "core/core_timing_util.h" | 15 | #include "core/core_timing_util.h" |
| 16 | #include "core/gdbstub/gdbstub.h" | 16 | #include "core/gdbstub/gdbstub.h" |
| 17 | #include "core/hle/kernel/process.h" | 17 | #include "core/hle/kernel/process.h" |
| 18 | #include "core/hle/kernel/scheduler.h" | ||
| 18 | #include "core/hle/kernel/svc.h" | 19 | #include "core/hle/kernel/svc.h" |
| 19 | #include "core/hle/kernel/vm_manager.h" | 20 | #include "core/hle/kernel/vm_manager.h" |
| 20 | #include "core/memory.h" | 21 | #include "core/memory.h" |
| @@ -87,7 +88,7 @@ public: | |||
| 87 | if (GDBStub::IsServerEnabled()) { | 88 | if (GDBStub::IsServerEnabled()) { |
| 88 | parent.jit->HaltExecution(); | 89 | parent.jit->HaltExecution(); |
| 89 | parent.SetPC(pc); | 90 | parent.SetPC(pc); |
| 90 | Kernel::Thread* thread = Kernel::GetCurrentThread(); | 91 | Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread(); |
| 91 | parent.SaveContext(thread->GetContext()); | 92 | parent.SaveContext(thread->GetContext()); |
| 92 | GDBStub::Break(); | 93 | GDBStub::Break(); |
| 93 | GDBStub::SendTrap(thread, 5); | 94 | GDBStub::SendTrap(thread, 5); |
diff --git a/src/core/arm/exclusive_monitor.cpp b/src/core/arm/exclusive_monitor.cpp index abd59ff4b..94570e520 100644 --- a/src/core/arm/exclusive_monitor.cpp +++ b/src/core/arm/exclusive_monitor.cpp | |||
| @@ -2,10 +2,24 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #ifdef ARCHITECTURE_x86_64 | ||
| 6 | #include "core/arm/dynarmic/arm_dynarmic.h" | ||
| 7 | #endif | ||
| 5 | #include "core/arm/exclusive_monitor.h" | 8 | #include "core/arm/exclusive_monitor.h" |
| 9 | #include "core/memory.h" | ||
| 6 | 10 | ||
| 7 | namespace Core { | 11 | namespace Core { |
| 8 | 12 | ||
| 9 | ExclusiveMonitor::~ExclusiveMonitor() = default; | 13 | ExclusiveMonitor::~ExclusiveMonitor() = default; |
| 10 | 14 | ||
| 15 | std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory, | ||
| 16 | std::size_t num_cores) { | ||
| 17 | #ifdef ARCHITECTURE_x86_64 | ||
| 18 | return std::make_unique<Core::DynarmicExclusiveMonitor>(memory, num_cores); | ||
| 19 | #else | ||
| 20 | // TODO(merry): Passthrough exclusive monitor | ||
| 21 | return nullptr; | ||
| 22 | #endif | ||
| 23 | } | ||
| 24 | |||
| 11 | } // namespace Core | 25 | } // namespace Core |
diff --git a/src/core/arm/exclusive_monitor.h b/src/core/arm/exclusive_monitor.h index f59aca667..4ef418b90 100644 --- a/src/core/arm/exclusive_monitor.h +++ b/src/core/arm/exclusive_monitor.h | |||
| @@ -4,8 +4,14 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <memory> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | 10 | ||
| 11 | namespace Memory { | ||
| 12 | class Memory; | ||
| 13 | } | ||
| 14 | |||
| 9 | namespace Core { | 15 | namespace Core { |
| 10 | 16 | ||
| 11 | class ExclusiveMonitor { | 17 | class ExclusiveMonitor { |
| @@ -22,4 +28,7 @@ public: | |||
| 22 | virtual bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) = 0; | 28 | virtual bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) = 0; |
| 23 | }; | 29 | }; |
| 24 | 30 | ||
| 31 | std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory, | ||
| 32 | std::size_t num_cores); | ||
| 33 | |||
| 25 | } // namespace Core | 34 | } // namespace Core |
diff --git a/src/core/arm/unicorn/arm_unicorn.cpp b/src/core/arm/unicorn/arm_unicorn.cpp index 48182c99a..f99ad5802 100644 --- a/src/core/arm/unicorn/arm_unicorn.cpp +++ b/src/core/arm/unicorn/arm_unicorn.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/arm/unicorn/arm_unicorn.h" | 9 | #include "core/arm/unicorn/arm_unicorn.h" |
| 10 | #include "core/core.h" | 10 | #include "core/core.h" |
| 11 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 12 | #include "core/hle/kernel/scheduler.h" | ||
| 12 | #include "core/hle/kernel/svc.h" | 13 | #include "core/hle/kernel/svc.h" |
| 13 | 14 | ||
| 14 | namespace Core { | 15 | namespace Core { |
| @@ -177,7 +178,7 @@ void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) { | |||
| 177 | uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); | 178 | uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address); |
| 178 | } | 179 | } |
| 179 | 180 | ||
| 180 | Kernel::Thread* thread = Kernel::GetCurrentThread(); | 181 | Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread(); |
| 181 | SaveContext(thread->GetContext()); | 182 | SaveContext(thread->GetContext()); |
| 182 | if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) { | 183 | if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) { |
| 183 | last_bkpt_hit = false; | 184 | last_bkpt_hit = false; |
diff --git a/src/core/core.cpp b/src/core/core.cpp index d697b80ef..c53d122be 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -11,9 +11,9 @@ | |||
| 11 | #include "common/string_util.h" | 11 | #include "common/string_util.h" |
| 12 | #include "core/arm/exclusive_monitor.h" | 12 | #include "core/arm/exclusive_monitor.h" |
| 13 | #include "core/core.h" | 13 | #include "core/core.h" |
| 14 | #include "core/core_cpu.h" | 14 | #include "core/core_manager.h" |
| 15 | #include "core/core_timing.h" | 15 | #include "core/core_timing.h" |
| 16 | #include "core/cpu_core_manager.h" | 16 | #include "core/cpu_manager.h" |
| 17 | #include "core/file_sys/bis_factory.h" | 17 | #include "core/file_sys/bis_factory.h" |
| 18 | #include "core/file_sys/card_image.h" | 18 | #include "core/file_sys/card_image.h" |
| 19 | #include "core/file_sys/mode.h" | 19 | #include "core/file_sys/mode.h" |
| @@ -28,6 +28,7 @@ | |||
| 28 | #include "core/hardware_interrupt_manager.h" | 28 | #include "core/hardware_interrupt_manager.h" |
| 29 | #include "core/hle/kernel/client_port.h" | 29 | #include "core/hle/kernel/client_port.h" |
| 30 | #include "core/hle/kernel/kernel.h" | 30 | #include "core/hle/kernel/kernel.h" |
| 31 | #include "core/hle/kernel/physical_core.h" | ||
| 31 | #include "core/hle/kernel/process.h" | 32 | #include "core/hle/kernel/process.h" |
| 32 | #include "core/hle/kernel/scheduler.h" | 33 | #include "core/hle/kernel/scheduler.h" |
| 33 | #include "core/hle/kernel/thread.h" | 34 | #include "core/hle/kernel/thread.h" |
| @@ -113,16 +114,25 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 113 | struct System::Impl { | 114 | struct System::Impl { |
| 114 | explicit Impl(System& system) | 115 | explicit Impl(System& system) |
| 115 | : kernel{system}, fs_controller{system}, memory{system}, | 116 | : kernel{system}, fs_controller{system}, memory{system}, |
| 116 | cpu_core_manager{system}, reporter{system}, applet_manager{system} {} | 117 | cpu_manager{system}, reporter{system}, applet_manager{system} {} |
| 117 | 118 | ||
| 118 | Cpu& CurrentCpuCore() { | 119 | CoreManager& CurrentCoreManager() { |
| 119 | return cpu_core_manager.GetCurrentCore(); | 120 | return cpu_manager.GetCurrentCoreManager(); |
| 121 | } | ||
| 122 | |||
| 123 | Kernel::PhysicalCore& CurrentPhysicalCore() { | ||
| 124 | const auto index = cpu_manager.GetActiveCoreIndex(); | ||
| 125 | return kernel.PhysicalCore(index); | ||
| 126 | } | ||
| 127 | |||
| 128 | Kernel::PhysicalCore& GetPhysicalCore(std::size_t index) { | ||
| 129 | return kernel.PhysicalCore(index); | ||
| 120 | } | 130 | } |
| 121 | 131 | ||
| 122 | ResultStatus RunLoop(bool tight_loop) { | 132 | ResultStatus RunLoop(bool tight_loop) { |
| 123 | status = ResultStatus::Success; | 133 | status = ResultStatus::Success; |
| 124 | 134 | ||
| 125 | cpu_core_manager.RunLoop(tight_loop); | 135 | cpu_manager.RunLoop(tight_loop); |
| 126 | 136 | ||
| 127 | return status; | 137 | return status; |
| 128 | } | 138 | } |
| @@ -131,8 +141,8 @@ struct System::Impl { | |||
| 131 | LOG_DEBUG(HW_Memory, "initialized OK"); | 141 | LOG_DEBUG(HW_Memory, "initialized OK"); |
| 132 | 142 | ||
| 133 | core_timing.Initialize(); | 143 | core_timing.Initialize(); |
| 134 | cpu_core_manager.Initialize(); | ||
| 135 | kernel.Initialize(); | 144 | kernel.Initialize(); |
| 145 | cpu_manager.Initialize(); | ||
| 136 | 146 | ||
| 137 | const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( | 147 | const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( |
| 138 | std::chrono::system_clock::now().time_since_epoch()); | 148 | std::chrono::system_clock::now().time_since_epoch()); |
| @@ -205,7 +215,6 @@ struct System::Impl { | |||
| 205 | // Main process has been loaded and been made current. | 215 | // Main process has been loaded and been made current. |
| 206 | // Begin GPU and CPU execution. | 216 | // Begin GPU and CPU execution. |
| 207 | gpu_core->Start(); | 217 | gpu_core->Start(); |
| 208 | cpu_core_manager.StartThreads(); | ||
| 209 | 218 | ||
| 210 | // Initialize cheat engine | 219 | // Initialize cheat engine |
| 211 | if (cheat_engine) { | 220 | if (cheat_engine) { |
| @@ -272,7 +281,7 @@ struct System::Impl { | |||
| 272 | gpu_core.reset(); | 281 | gpu_core.reset(); |
| 273 | 282 | ||
| 274 | // Close all CPU/threading state | 283 | // Close all CPU/threading state |
| 275 | cpu_core_manager.Shutdown(); | 284 | cpu_manager.Shutdown(); |
| 276 | 285 | ||
| 277 | // Shutdown kernel and core timing | 286 | // Shutdown kernel and core timing |
| 278 | kernel.Shutdown(); | 287 | kernel.Shutdown(); |
| @@ -342,7 +351,7 @@ struct System::Impl { | |||
| 342 | std::unique_ptr<Tegra::GPU> gpu_core; | 351 | std::unique_ptr<Tegra::GPU> gpu_core; |
| 343 | std::unique_ptr<Hardware::InterruptManager> interrupt_manager; | 352 | std::unique_ptr<Hardware::InterruptManager> interrupt_manager; |
| 344 | Memory::Memory memory; | 353 | Memory::Memory memory; |
| 345 | CpuCoreManager cpu_core_manager; | 354 | CpuManager cpu_manager; |
| 346 | bool is_powered_on = false; | 355 | bool is_powered_on = false; |
| 347 | bool exit_lock = false; | 356 | bool exit_lock = false; |
| 348 | 357 | ||
| @@ -377,12 +386,12 @@ struct System::Impl { | |||
| 377 | System::System() : impl{std::make_unique<Impl>(*this)} {} | 386 | System::System() : impl{std::make_unique<Impl>(*this)} {} |
| 378 | System::~System() = default; | 387 | System::~System() = default; |
| 379 | 388 | ||
| 380 | Cpu& System::CurrentCpuCore() { | 389 | CoreManager& System::CurrentCoreManager() { |
| 381 | return impl->CurrentCpuCore(); | 390 | return impl->CurrentCoreManager(); |
| 382 | } | 391 | } |
| 383 | 392 | ||
| 384 | const Cpu& System::CurrentCpuCore() const { | 393 | const CoreManager& System::CurrentCoreManager() const { |
| 385 | return impl->CurrentCpuCore(); | 394 | return impl->CurrentCoreManager(); |
| 386 | } | 395 | } |
| 387 | 396 | ||
| 388 | System::ResultStatus System::RunLoop(bool tight_loop) { | 397 | System::ResultStatus System::RunLoop(bool tight_loop) { |
| @@ -394,7 +403,7 @@ System::ResultStatus System::SingleStep() { | |||
| 394 | } | 403 | } |
| 395 | 404 | ||
| 396 | void System::InvalidateCpuInstructionCaches() { | 405 | void System::InvalidateCpuInstructionCaches() { |
| 397 | impl->cpu_core_manager.InvalidateAllInstructionCaches(); | 406 | impl->kernel.InvalidateAllInstructionCaches(); |
| 398 | } | 407 | } |
| 399 | 408 | ||
| 400 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | 409 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { |
| @@ -406,13 +415,11 @@ bool System::IsPoweredOn() const { | |||
| 406 | } | 415 | } |
| 407 | 416 | ||
| 408 | void System::PrepareReschedule() { | 417 | void System::PrepareReschedule() { |
| 409 | CurrentCpuCore().PrepareReschedule(); | 418 | impl->CurrentPhysicalCore().Stop(); |
| 410 | } | 419 | } |
| 411 | 420 | ||
| 412 | void System::PrepareReschedule(const u32 core_index) { | 421 | void System::PrepareReschedule(const u32 core_index) { |
| 413 | if (core_index < GlobalScheduler().CpuCoresCount()) { | 422 | impl->kernel.PrepareReschedule(core_index); |
| 414 | CpuCore(core_index).PrepareReschedule(); | ||
| 415 | } | ||
| 416 | } | 423 | } |
| 417 | 424 | ||
| 418 | PerfStatsResults System::GetAndResetPerfStats() { | 425 | PerfStatsResults System::GetAndResetPerfStats() { |
| @@ -428,31 +435,31 @@ const TelemetrySession& System::TelemetrySession() const { | |||
| 428 | } | 435 | } |
| 429 | 436 | ||
| 430 | ARM_Interface& System::CurrentArmInterface() { | 437 | ARM_Interface& System::CurrentArmInterface() { |
| 431 | return CurrentCpuCore().ArmInterface(); | 438 | return impl->CurrentPhysicalCore().ArmInterface(); |
| 432 | } | 439 | } |
| 433 | 440 | ||
| 434 | const ARM_Interface& System::CurrentArmInterface() const { | 441 | const ARM_Interface& System::CurrentArmInterface() const { |
| 435 | return CurrentCpuCore().ArmInterface(); | 442 | return impl->CurrentPhysicalCore().ArmInterface(); |
| 436 | } | 443 | } |
| 437 | 444 | ||
| 438 | std::size_t System::CurrentCoreIndex() const { | 445 | std::size_t System::CurrentCoreIndex() const { |
| 439 | return CurrentCpuCore().CoreIndex(); | 446 | return impl->cpu_manager.GetActiveCoreIndex(); |
| 440 | } | 447 | } |
| 441 | 448 | ||
| 442 | Kernel::Scheduler& System::CurrentScheduler() { | 449 | Kernel::Scheduler& System::CurrentScheduler() { |
| 443 | return CurrentCpuCore().Scheduler(); | 450 | return impl->CurrentPhysicalCore().Scheduler(); |
| 444 | } | 451 | } |
| 445 | 452 | ||
| 446 | const Kernel::Scheduler& System::CurrentScheduler() const { | 453 | const Kernel::Scheduler& System::CurrentScheduler() const { |
| 447 | return CurrentCpuCore().Scheduler(); | 454 | return impl->CurrentPhysicalCore().Scheduler(); |
| 448 | } | 455 | } |
| 449 | 456 | ||
| 450 | Kernel::Scheduler& System::Scheduler(std::size_t core_index) { | 457 | Kernel::Scheduler& System::Scheduler(std::size_t core_index) { |
| 451 | return CpuCore(core_index).Scheduler(); | 458 | return impl->GetPhysicalCore(core_index).Scheduler(); |
| 452 | } | 459 | } |
| 453 | 460 | ||
| 454 | const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const { | 461 | const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const { |
| 455 | return CpuCore(core_index).Scheduler(); | 462 | return impl->GetPhysicalCore(core_index).Scheduler(); |
| 456 | } | 463 | } |
| 457 | 464 | ||
| 458 | /// Gets the global scheduler | 465 | /// Gets the global scheduler |
| @@ -474,28 +481,28 @@ const Kernel::Process* System::CurrentProcess() const { | |||
| 474 | } | 481 | } |
| 475 | 482 | ||
| 476 | ARM_Interface& System::ArmInterface(std::size_t core_index) { | 483 | ARM_Interface& System::ArmInterface(std::size_t core_index) { |
| 477 | return CpuCore(core_index).ArmInterface(); | 484 | return impl->GetPhysicalCore(core_index).ArmInterface(); |
| 478 | } | 485 | } |
| 479 | 486 | ||
| 480 | const ARM_Interface& System::ArmInterface(std::size_t core_index) const { | 487 | const ARM_Interface& System::ArmInterface(std::size_t core_index) const { |
| 481 | return CpuCore(core_index).ArmInterface(); | 488 | return impl->GetPhysicalCore(core_index).ArmInterface(); |
| 482 | } | 489 | } |
| 483 | 490 | ||
| 484 | Cpu& System::CpuCore(std::size_t core_index) { | 491 | CoreManager& System::GetCoreManager(std::size_t core_index) { |
| 485 | return impl->cpu_core_manager.GetCore(core_index); | 492 | return impl->cpu_manager.GetCoreManager(core_index); |
| 486 | } | 493 | } |
| 487 | 494 | ||
| 488 | const Cpu& System::CpuCore(std::size_t core_index) const { | 495 | const CoreManager& System::GetCoreManager(std::size_t core_index) const { |
| 489 | ASSERT(core_index < NUM_CPU_CORES); | 496 | ASSERT(core_index < NUM_CPU_CORES); |
| 490 | return impl->cpu_core_manager.GetCore(core_index); | 497 | return impl->cpu_manager.GetCoreManager(core_index); |
| 491 | } | 498 | } |
| 492 | 499 | ||
| 493 | ExclusiveMonitor& System::Monitor() { | 500 | ExclusiveMonitor& System::Monitor() { |
| 494 | return impl->cpu_core_manager.GetExclusiveMonitor(); | 501 | return impl->kernel.GetExclusiveMonitor(); |
| 495 | } | 502 | } |
| 496 | 503 | ||
| 497 | const ExclusiveMonitor& System::Monitor() const { | 504 | const ExclusiveMonitor& System::Monitor() const { |
| 498 | return impl->cpu_core_manager.GetExclusiveMonitor(); | 505 | return impl->kernel.GetExclusiveMonitor(); |
| 499 | } | 506 | } |
| 500 | 507 | ||
| 501 | Memory::Memory& System::Memory() { | 508 | Memory::Memory& System::Memory() { |
diff --git a/src/core/core.h b/src/core/core.h index e240c5c58..e69d68fcf 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -93,7 +93,7 @@ class Memory; | |||
| 93 | namespace Core { | 93 | namespace Core { |
| 94 | 94 | ||
| 95 | class ARM_Interface; | 95 | class ARM_Interface; |
| 96 | class Cpu; | 96 | class CoreManager; |
| 97 | class ExclusiveMonitor; | 97 | class ExclusiveMonitor; |
| 98 | class FrameLimiter; | 98 | class FrameLimiter; |
| 99 | class PerfStats; | 99 | class PerfStats; |
| @@ -218,10 +218,10 @@ public: | |||
| 218 | const ARM_Interface& ArmInterface(std::size_t core_index) const; | 218 | const ARM_Interface& ArmInterface(std::size_t core_index) const; |
| 219 | 219 | ||
| 220 | /// Gets a CPU interface to the CPU core with the specified index | 220 | /// Gets a CPU interface to the CPU core with the specified index |
| 221 | Cpu& CpuCore(std::size_t core_index); | 221 | CoreManager& GetCoreManager(std::size_t core_index); |
| 222 | 222 | ||
| 223 | /// Gets a CPU interface to the CPU core with the specified index | 223 | /// Gets a CPU interface to the CPU core with the specified index |
| 224 | const Cpu& CpuCore(std::size_t core_index) const; | 224 | const CoreManager& GetCoreManager(std::size_t core_index) const; |
| 225 | 225 | ||
| 226 | /// Gets a reference to the exclusive monitor | 226 | /// Gets a reference to the exclusive monitor |
| 227 | ExclusiveMonitor& Monitor(); | 227 | ExclusiveMonitor& Monitor(); |
| @@ -364,10 +364,10 @@ private: | |||
| 364 | System(); | 364 | System(); |
| 365 | 365 | ||
| 366 | /// Returns the currently running CPU core | 366 | /// Returns the currently running CPU core |
| 367 | Cpu& CurrentCpuCore(); | 367 | CoreManager& CurrentCoreManager(); |
| 368 | 368 | ||
| 369 | /// Returns the currently running CPU core | 369 | /// Returns the currently running CPU core |
| 370 | const Cpu& CurrentCpuCore() const; | 370 | const CoreManager& CurrentCoreManager() const; |
| 371 | 371 | ||
| 372 | /** | 372 | /** |
| 373 | * Initialize the emulated system. | 373 | * Initialize the emulated system. |
diff --git a/src/core/core_cpu.cpp b/src/core/core_cpu.cpp deleted file mode 100644 index 630cd4feb..000000000 --- a/src/core/core_cpu.cpp +++ /dev/null | |||
| @@ -1,127 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <condition_variable> | ||
| 6 | #include <mutex> | ||
| 7 | |||
| 8 | #include "common/logging/log.h" | ||
| 9 | #ifdef ARCHITECTURE_x86_64 | ||
| 10 | #include "core/arm/dynarmic/arm_dynarmic.h" | ||
| 11 | #endif | ||
| 12 | #include "core/arm/exclusive_monitor.h" | ||
| 13 | #include "core/arm/unicorn/arm_unicorn.h" | ||
| 14 | #include "core/core.h" | ||
| 15 | #include "core/core_cpu.h" | ||
| 16 | #include "core/core_timing.h" | ||
| 17 | #include "core/hle/kernel/scheduler.h" | ||
| 18 | #include "core/hle/kernel/thread.h" | ||
| 19 | #include "core/hle/lock.h" | ||
| 20 | #include "core/settings.h" | ||
| 21 | |||
| 22 | namespace Core { | ||
| 23 | |||
| 24 | void CpuBarrier::NotifyEnd() { | ||
| 25 | std::unique_lock lock{mutex}; | ||
| 26 | end = true; | ||
| 27 | condition.notify_all(); | ||
| 28 | } | ||
| 29 | |||
| 30 | bool CpuBarrier::Rendezvous() { | ||
| 31 | if (!Settings::values.use_multi_core) { | ||
| 32 | // Meaningless when running in single-core mode | ||
| 33 | return true; | ||
| 34 | } | ||
| 35 | |||
| 36 | if (!end) { | ||
| 37 | std::unique_lock lock{mutex}; | ||
| 38 | |||
| 39 | --cores_waiting; | ||
| 40 | if (!cores_waiting) { | ||
| 41 | cores_waiting = NUM_CPU_CORES; | ||
| 42 | condition.notify_all(); | ||
| 43 | return true; | ||
| 44 | } | ||
| 45 | |||
| 46 | condition.wait(lock); | ||
| 47 | return true; | ||
| 48 | } | ||
| 49 | |||
| 50 | return false; | ||
| 51 | } | ||
| 52 | |||
| 53 | Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, | ||
| 54 | std::size_t core_index) | ||
| 55 | : cpu_barrier{cpu_barrier}, global_scheduler{system.GlobalScheduler()}, | ||
| 56 | core_timing{system.CoreTiming()}, core_index{core_index} { | ||
| 57 | #ifdef ARCHITECTURE_x86_64 | ||
| 58 | arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index); | ||
| 59 | #else | ||
| 60 | arm_interface = std::make_unique<ARM_Unicorn>(system); | ||
| 61 | LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); | ||
| 62 | #endif | ||
| 63 | |||
| 64 | scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index); | ||
| 65 | } | ||
| 66 | |||
| 67 | Cpu::~Cpu() = default; | ||
| 68 | |||
| 69 | std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor( | ||
| 70 | [[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) { | ||
| 71 | #ifdef ARCHITECTURE_x86_64 | ||
| 72 | return std::make_unique<DynarmicExclusiveMonitor>(memory, num_cores); | ||
| 73 | #else | ||
| 74 | // TODO(merry): Passthrough exclusive monitor | ||
| 75 | return nullptr; | ||
| 76 | #endif | ||
| 77 | } | ||
| 78 | |||
| 79 | void Cpu::RunLoop(bool tight_loop) { | ||
| 80 | // Wait for all other CPU cores to complete the previous slice, such that they run in lock-step | ||
| 81 | if (!cpu_barrier.Rendezvous()) { | ||
| 82 | // If rendezvous failed, session has been killed | ||
| 83 | return; | ||
| 84 | } | ||
| 85 | |||
| 86 | Reschedule(); | ||
| 87 | |||
| 88 | // If we don't have a currently active thread then don't execute instructions, | ||
| 89 | // instead advance to the next event and try to yield to the next thread | ||
| 90 | if (Kernel::GetCurrentThread() == nullptr) { | ||
| 91 | LOG_TRACE(Core, "Core-{} idling", core_index); | ||
| 92 | core_timing.Idle(); | ||
| 93 | } else { | ||
| 94 | if (tight_loop) { | ||
| 95 | arm_interface->Run(); | ||
| 96 | } else { | ||
| 97 | arm_interface->Step(); | ||
| 98 | } | ||
| 99 | // We are stopping a run, exclusive state must be cleared | ||
| 100 | arm_interface->ClearExclusiveState(); | ||
| 101 | } | ||
| 102 | core_timing.Advance(); | ||
| 103 | |||
| 104 | Reschedule(); | ||
| 105 | } | ||
| 106 | |||
| 107 | void Cpu::SingleStep() { | ||
| 108 | return RunLoop(false); | ||
| 109 | } | ||
| 110 | |||
| 111 | void Cpu::PrepareReschedule() { | ||
| 112 | arm_interface->PrepareReschedule(); | ||
| 113 | } | ||
| 114 | |||
| 115 | void Cpu::Reschedule() { | ||
| 116 | // Lock the global kernel mutex when we manipulate the HLE state | ||
| 117 | std::lock_guard lock(HLE::g_hle_lock); | ||
| 118 | |||
| 119 | global_scheduler.SelectThread(core_index); | ||
| 120 | scheduler->TryDoContextSwitch(); | ||
| 121 | } | ||
| 122 | |||
| 123 | void Cpu::Shutdown() { | ||
| 124 | scheduler->Shutdown(); | ||
| 125 | } | ||
| 126 | |||
| 127 | } // namespace Core | ||
diff --git a/src/core/core_cpu.h b/src/core/core_cpu.h deleted file mode 100644 index 78f5021a2..000000000 --- a/src/core/core_cpu.h +++ /dev/null | |||
| @@ -1,120 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | #include <condition_variable> | ||
| 9 | #include <cstddef> | ||
| 10 | #include <memory> | ||
| 11 | #include <mutex> | ||
| 12 | #include "common/common_types.h" | ||
| 13 | |||
| 14 | namespace Kernel { | ||
| 15 | class GlobalScheduler; | ||
| 16 | class Scheduler; | ||
| 17 | } // namespace Kernel | ||
| 18 | |||
| 19 | namespace Core { | ||
| 20 | class System; | ||
| 21 | } | ||
| 22 | |||
| 23 | namespace Core::Timing { | ||
| 24 | class CoreTiming; | ||
| 25 | } | ||
| 26 | |||
| 27 | namespace Memory { | ||
| 28 | class Memory; | ||
| 29 | } | ||
| 30 | |||
| 31 | namespace Core { | ||
| 32 | |||
| 33 | class ARM_Interface; | ||
| 34 | class ExclusiveMonitor; | ||
| 35 | |||
| 36 | constexpr unsigned NUM_CPU_CORES{4}; | ||
| 37 | |||
| 38 | class CpuBarrier { | ||
| 39 | public: | ||
| 40 | bool IsAlive() const { | ||
| 41 | return !end; | ||
| 42 | } | ||
| 43 | |||
| 44 | void NotifyEnd(); | ||
| 45 | |||
| 46 | bool Rendezvous(); | ||
| 47 | |||
| 48 | private: | ||
| 49 | unsigned cores_waiting{NUM_CPU_CORES}; | ||
| 50 | std::mutex mutex; | ||
| 51 | std::condition_variable condition; | ||
| 52 | std::atomic<bool> end{}; | ||
| 53 | }; | ||
| 54 | |||
| 55 | class Cpu { | ||
| 56 | public: | ||
| 57 | Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier, | ||
| 58 | std::size_t core_index); | ||
| 59 | ~Cpu(); | ||
| 60 | |||
| 61 | void RunLoop(bool tight_loop = true); | ||
| 62 | |||
| 63 | void SingleStep(); | ||
| 64 | |||
| 65 | void PrepareReschedule(); | ||
| 66 | |||
| 67 | ARM_Interface& ArmInterface() { | ||
| 68 | return *arm_interface; | ||
| 69 | } | ||
| 70 | |||
| 71 | const ARM_Interface& ArmInterface() const { | ||
| 72 | return *arm_interface; | ||
| 73 | } | ||
| 74 | |||
| 75 | Kernel::Scheduler& Scheduler() { | ||
| 76 | return *scheduler; | ||
| 77 | } | ||
| 78 | |||
| 79 | const Kernel::Scheduler& Scheduler() const { | ||
| 80 | return *scheduler; | ||
| 81 | } | ||
| 82 | |||
| 83 | bool IsMainCore() const { | ||
| 84 | return core_index == 0; | ||
| 85 | } | ||
| 86 | |||
| 87 | std::size_t CoreIndex() const { | ||
| 88 | return core_index; | ||
| 89 | } | ||
| 90 | |||
| 91 | void Shutdown(); | ||
| 92 | |||
| 93 | /** | ||
| 94 | * Creates an exclusive monitor to handle exclusive reads/writes. | ||
| 95 | * | ||
| 96 | * @param memory The current memory subsystem that the monitor may wish | ||
| 97 | * to keep track of. | ||
| 98 | * | ||
| 99 | * @param num_cores The number of cores to assume about the CPU. | ||
| 100 | * | ||
| 101 | * @returns The constructed exclusive monitor instance, or nullptr if the current | ||
| 102 | * CPU backend is unable to use an exclusive monitor. | ||
| 103 | */ | ||
| 104 | static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory, | ||
| 105 | std::size_t num_cores); | ||
| 106 | |||
| 107 | private: | ||
| 108 | void Reschedule(); | ||
| 109 | |||
| 110 | std::unique_ptr<ARM_Interface> arm_interface; | ||
| 111 | CpuBarrier& cpu_barrier; | ||
| 112 | Kernel::GlobalScheduler& global_scheduler; | ||
| 113 | std::unique_ptr<Kernel::Scheduler> scheduler; | ||
| 114 | Timing::CoreTiming& core_timing; | ||
| 115 | |||
| 116 | std::atomic<bool> reschedule_pending = false; | ||
| 117 | std::size_t core_index; | ||
| 118 | }; | ||
| 119 | |||
| 120 | } // namespace Core | ||
diff --git a/src/core/core_manager.cpp b/src/core/core_manager.cpp new file mode 100644 index 000000000..8eacf92dd --- /dev/null +++ b/src/core/core_manager.cpp | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <condition_variable> | ||
| 6 | #include <mutex> | ||
| 7 | |||
| 8 | #include "common/logging/log.h" | ||
| 9 | #ifdef ARCHITECTURE_x86_64 | ||
| 10 | #include "core/arm/dynarmic/arm_dynarmic.h" | ||
| 11 | #endif | ||
| 12 | #include "core/arm/exclusive_monitor.h" | ||
| 13 | #include "core/arm/unicorn/arm_unicorn.h" | ||
| 14 | #include "core/core.h" | ||
| 15 | #include "core/core_manager.h" | ||
| 16 | #include "core/core_timing.h" | ||
| 17 | #include "core/hle/kernel/kernel.h" | ||
| 18 | #include "core/hle/kernel/physical_core.h" | ||
| 19 | #include "core/hle/kernel/scheduler.h" | ||
| 20 | #include "core/hle/kernel/thread.h" | ||
| 21 | #include "core/hle/lock.h" | ||
| 22 | #include "core/settings.h" | ||
| 23 | |||
| 24 | namespace Core { | ||
| 25 | |||
| 26 | CoreManager::CoreManager(System& system, std::size_t core_index) | ||
| 27 | : global_scheduler{system.GlobalScheduler()}, physical_core{system.Kernel().PhysicalCore( | ||
| 28 | core_index)}, | ||
| 29 | core_timing{system.CoreTiming()}, core_index{core_index} {} | ||
| 30 | |||
| 31 | CoreManager::~CoreManager() = default; | ||
| 32 | |||
| 33 | void CoreManager::RunLoop(bool tight_loop) { | ||
| 34 | Reschedule(); | ||
| 35 | |||
| 36 | // If we don't have a currently active thread then don't execute instructions, | ||
| 37 | // instead advance to the next event and try to yield to the next thread | ||
| 38 | if (Kernel::GetCurrentThread() == nullptr) { | ||
| 39 | LOG_TRACE(Core, "Core-{} idling", core_index); | ||
| 40 | core_timing.Idle(); | ||
| 41 | } else { | ||
| 42 | if (tight_loop) { | ||
| 43 | physical_core.Run(); | ||
| 44 | } else { | ||
| 45 | physical_core.Step(); | ||
| 46 | } | ||
| 47 | } | ||
| 48 | core_timing.Advance(); | ||
| 49 | |||
| 50 | Reschedule(); | ||
| 51 | } | ||
| 52 | |||
| 53 | void CoreManager::SingleStep() { | ||
| 54 | return RunLoop(false); | ||
| 55 | } | ||
| 56 | |||
| 57 | void CoreManager::PrepareReschedule() { | ||
| 58 | physical_core.Stop(); | ||
| 59 | } | ||
| 60 | |||
| 61 | void CoreManager::Reschedule() { | ||
| 62 | // Lock the global kernel mutex when we manipulate the HLE state | ||
| 63 | std::lock_guard lock(HLE::g_hle_lock); | ||
| 64 | |||
| 65 | global_scheduler.SelectThread(core_index); | ||
| 66 | |||
| 67 | physical_core.Scheduler().TryDoContextSwitch(); | ||
| 68 | } | ||
| 69 | |||
| 70 | } // namespace Core | ||
diff --git a/src/core/core_manager.h b/src/core/core_manager.h new file mode 100644 index 000000000..b14e723d7 --- /dev/null +++ b/src/core/core_manager.h | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <atomic> | ||
| 8 | #include <cstddef> | ||
| 9 | #include <memory> | ||
| 10 | #include "common/common_types.h" | ||
| 11 | |||
| 12 | namespace Kernel { | ||
| 13 | class GlobalScheduler; | ||
| 14 | class PhysicalCore; | ||
| 15 | } // namespace Kernel | ||
| 16 | |||
| 17 | namespace Core { | ||
| 18 | class System; | ||
| 19 | } | ||
| 20 | |||
| 21 | namespace Core::Timing { | ||
| 22 | class CoreTiming; | ||
| 23 | } | ||
| 24 | |||
| 25 | namespace Memory { | ||
| 26 | class Memory; | ||
| 27 | } | ||
| 28 | |||
| 29 | namespace Core { | ||
| 30 | |||
| 31 | constexpr unsigned NUM_CPU_CORES{4}; | ||
| 32 | |||
| 33 | class CoreManager { | ||
| 34 | public: | ||
| 35 | CoreManager(System& system, std::size_t core_index); | ||
| 36 | ~CoreManager(); | ||
| 37 | |||
| 38 | void RunLoop(bool tight_loop = true); | ||
| 39 | |||
| 40 | void SingleStep(); | ||
| 41 | |||
| 42 | void PrepareReschedule(); | ||
| 43 | |||
| 44 | bool IsMainCore() const { | ||
| 45 | return core_index == 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | std::size_t CoreIndex() const { | ||
| 49 | return core_index; | ||
| 50 | } | ||
| 51 | |||
| 52 | private: | ||
| 53 | void Reschedule(); | ||
| 54 | |||
| 55 | Kernel::GlobalScheduler& global_scheduler; | ||
| 56 | Kernel::PhysicalCore& physical_core; | ||
| 57 | Timing::CoreTiming& core_timing; | ||
| 58 | |||
| 59 | std::atomic<bool> reschedule_pending = false; | ||
| 60 | std::size_t core_index; | ||
| 61 | }; | ||
| 62 | |||
| 63 | } // namespace Core | ||
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp deleted file mode 100644 index f04a34133..000000000 --- a/src/core/cpu_core_manager.cpp +++ /dev/null | |||
| @@ -1,152 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "core/arm/exclusive_monitor.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/core_cpu.h" | ||
| 9 | #include "core/core_timing.h" | ||
| 10 | #include "core/cpu_core_manager.h" | ||
| 11 | #include "core/gdbstub/gdbstub.h" | ||
| 12 | #include "core/settings.h" | ||
| 13 | |||
| 14 | namespace Core { | ||
| 15 | namespace { | ||
| 16 | void RunCpuCore(const System& system, Cpu& cpu_state) { | ||
| 17 | while (system.IsPoweredOn()) { | ||
| 18 | cpu_state.RunLoop(true); | ||
| 19 | } | ||
| 20 | } | ||
| 21 | } // Anonymous namespace | ||
| 22 | |||
| 23 | CpuCoreManager::CpuCoreManager(System& system) : system{system} {} | ||
| 24 | CpuCoreManager::~CpuCoreManager() = default; | ||
| 25 | |||
| 26 | void CpuCoreManager::Initialize() { | ||
| 27 | barrier = std::make_unique<CpuBarrier>(); | ||
| 28 | exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size()); | ||
| 29 | |||
| 30 | for (std::size_t index = 0; index < cores.size(); ++index) { | ||
| 31 | cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | void CpuCoreManager::StartThreads() { | ||
| 36 | // Create threads for CPU cores 1-3, and build thread_to_cpu map | ||
| 37 | // CPU core 0 is run on the main thread | ||
| 38 | thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); | ||
| 39 | if (!Settings::values.use_multi_core) { | ||
| 40 | return; | ||
| 41 | } | ||
| 42 | |||
| 43 | for (std::size_t index = 0; index < core_threads.size(); ++index) { | ||
| 44 | core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system), | ||
| 45 | std::ref(*cores[index + 1])); | ||
| 46 | thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get(); | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | void CpuCoreManager::Shutdown() { | ||
| 51 | barrier->NotifyEnd(); | ||
| 52 | if (Settings::values.use_multi_core) { | ||
| 53 | for (auto& thread : core_threads) { | ||
| 54 | thread->join(); | ||
| 55 | thread.reset(); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | thread_to_cpu.clear(); | ||
| 60 | for (auto& cpu_core : cores) { | ||
| 61 | cpu_core->Shutdown(); | ||
| 62 | cpu_core.reset(); | ||
| 63 | } | ||
| 64 | |||
| 65 | exclusive_monitor.reset(); | ||
| 66 | barrier.reset(); | ||
| 67 | } | ||
| 68 | |||
| 69 | Cpu& CpuCoreManager::GetCore(std::size_t index) { | ||
| 70 | return *cores.at(index); | ||
| 71 | } | ||
| 72 | |||
| 73 | const Cpu& CpuCoreManager::GetCore(std::size_t index) const { | ||
| 74 | return *cores.at(index); | ||
| 75 | } | ||
| 76 | |||
| 77 | ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() { | ||
| 78 | return *exclusive_monitor; | ||
| 79 | } | ||
| 80 | |||
| 81 | const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const { | ||
| 82 | return *exclusive_monitor; | ||
| 83 | } | ||
| 84 | |||
| 85 | Cpu& CpuCoreManager::GetCurrentCore() { | ||
| 86 | if (Settings::values.use_multi_core) { | ||
| 87 | const auto& search = thread_to_cpu.find(std::this_thread::get_id()); | ||
| 88 | ASSERT(search != thread_to_cpu.end()); | ||
| 89 | ASSERT(search->second); | ||
| 90 | return *search->second; | ||
| 91 | } | ||
| 92 | |||
| 93 | // Otherwise, use single-threaded mode active_core variable | ||
| 94 | return *cores[active_core]; | ||
| 95 | } | ||
| 96 | |||
| 97 | const Cpu& CpuCoreManager::GetCurrentCore() const { | ||
| 98 | if (Settings::values.use_multi_core) { | ||
| 99 | const auto& search = thread_to_cpu.find(std::this_thread::get_id()); | ||
| 100 | ASSERT(search != thread_to_cpu.end()); | ||
| 101 | ASSERT(search->second); | ||
| 102 | return *search->second; | ||
| 103 | } | ||
| 104 | |||
| 105 | // Otherwise, use single-threaded mode active_core variable | ||
| 106 | return *cores[active_core]; | ||
| 107 | } | ||
| 108 | |||
| 109 | void CpuCoreManager::RunLoop(bool tight_loop) { | ||
| 110 | // Update thread_to_cpu in case Core 0 is run from a different host thread | ||
| 111 | thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); | ||
| 112 | |||
| 113 | if (GDBStub::IsServerEnabled()) { | ||
| 114 | GDBStub::HandlePacket(); | ||
| 115 | |||
| 116 | // If the loop is halted and we want to step, use a tiny (1) number of instructions to | ||
| 117 | // execute. Otherwise, get out of the loop function. | ||
| 118 | if (GDBStub::GetCpuHaltFlag()) { | ||
| 119 | if (GDBStub::GetCpuStepFlag()) { | ||
| 120 | tight_loop = false; | ||
| 121 | } else { | ||
| 122 | return; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | auto& core_timing = system.CoreTiming(); | ||
| 128 | core_timing.ResetRun(); | ||
| 129 | bool keep_running{}; | ||
| 130 | do { | ||
| 131 | keep_running = false; | ||
| 132 | for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { | ||
| 133 | core_timing.SwitchContext(active_core); | ||
| 134 | if (core_timing.CanCurrentContextRun()) { | ||
| 135 | cores[active_core]->RunLoop(tight_loop); | ||
| 136 | } | ||
| 137 | keep_running |= core_timing.CanCurrentContextRun(); | ||
| 138 | } | ||
| 139 | } while (keep_running); | ||
| 140 | |||
| 141 | if (GDBStub::IsServerEnabled()) { | ||
| 142 | GDBStub::SetCpuStepFlag(false); | ||
| 143 | } | ||
| 144 | } | ||
| 145 | |||
| 146 | void CpuCoreManager::InvalidateAllInstructionCaches() { | ||
| 147 | for (auto& cpu : cores) { | ||
| 148 | cpu->ArmInterface().ClearInstructionCache(); | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | } // namespace Core | ||
diff --git a/src/core/cpu_core_manager.h b/src/core/cpu_core_manager.h deleted file mode 100644 index 2cbbf8216..000000000 --- a/src/core/cpu_core_manager.h +++ /dev/null | |||
| @@ -1,62 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <map> | ||
| 9 | #include <memory> | ||
| 10 | #include <thread> | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | |||
| 14 | class Cpu; | ||
| 15 | class CpuBarrier; | ||
| 16 | class ExclusiveMonitor; | ||
| 17 | class System; | ||
| 18 | |||
| 19 | class CpuCoreManager { | ||
| 20 | public: | ||
| 21 | explicit CpuCoreManager(System& system); | ||
| 22 | CpuCoreManager(const CpuCoreManager&) = delete; | ||
| 23 | CpuCoreManager(CpuCoreManager&&) = delete; | ||
| 24 | |||
| 25 | ~CpuCoreManager(); | ||
| 26 | |||
| 27 | CpuCoreManager& operator=(const CpuCoreManager&) = delete; | ||
| 28 | CpuCoreManager& operator=(CpuCoreManager&&) = delete; | ||
| 29 | |||
| 30 | void Initialize(); | ||
| 31 | void StartThreads(); | ||
| 32 | void Shutdown(); | ||
| 33 | |||
| 34 | Cpu& GetCore(std::size_t index); | ||
| 35 | const Cpu& GetCore(std::size_t index) const; | ||
| 36 | |||
| 37 | Cpu& GetCurrentCore(); | ||
| 38 | const Cpu& GetCurrentCore() const; | ||
| 39 | |||
| 40 | ExclusiveMonitor& GetExclusiveMonitor(); | ||
| 41 | const ExclusiveMonitor& GetExclusiveMonitor() const; | ||
| 42 | |||
| 43 | void RunLoop(bool tight_loop); | ||
| 44 | |||
| 45 | void InvalidateAllInstructionCaches(); | ||
| 46 | |||
| 47 | private: | ||
| 48 | static constexpr std::size_t NUM_CPU_CORES = 4; | ||
| 49 | |||
| 50 | std::unique_ptr<ExclusiveMonitor> exclusive_monitor; | ||
| 51 | std::unique_ptr<CpuBarrier> barrier; | ||
| 52 | std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores; | ||
| 53 | std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads; | ||
| 54 | std::size_t active_core{}; ///< Active core, only used in single thread mode | ||
| 55 | |||
| 56 | /// Map of guest threads to CPU cores | ||
| 57 | std::map<std::thread::id, Cpu*> thread_to_cpu; | ||
| 58 | |||
| 59 | System& system; | ||
| 60 | }; | ||
| 61 | |||
| 62 | } // namespace Core | ||
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp new file mode 100644 index 000000000..70ddbdcca --- /dev/null +++ b/src/core/cpu_manager.cpp | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/arm/exclusive_monitor.h" | ||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/core_manager.h" | ||
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/cpu_manager.h" | ||
| 10 | #include "core/gdbstub/gdbstub.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | |||
| 14 | CpuManager::CpuManager(System& system) : system{system} {} | ||
| 15 | CpuManager::~CpuManager() = default; | ||
| 16 | |||
| 17 | void CpuManager::Initialize() { | ||
| 18 | for (std::size_t index = 0; index < core_managers.size(); ++index) { | ||
| 19 | core_managers[index] = std::make_unique<CoreManager>(system, index); | ||
| 20 | } | ||
| 21 | } | ||
| 22 | |||
| 23 | void CpuManager::Shutdown() { | ||
| 24 | for (auto& cpu_core : core_managers) { | ||
| 25 | cpu_core.reset(); | ||
| 26 | } | ||
| 27 | } | ||
| 28 | |||
| 29 | CoreManager& CpuManager::GetCoreManager(std::size_t index) { | ||
| 30 | return *core_managers.at(index); | ||
| 31 | } | ||
| 32 | |||
| 33 | const CoreManager& CpuManager::GetCoreManager(std::size_t index) const { | ||
| 34 | return *core_managers.at(index); | ||
| 35 | } | ||
| 36 | |||
| 37 | CoreManager& CpuManager::GetCurrentCoreManager() { | ||
| 38 | // Otherwise, use single-threaded mode active_core variable | ||
| 39 | return *core_managers[active_core]; | ||
| 40 | } | ||
| 41 | |||
| 42 | const CoreManager& CpuManager::GetCurrentCoreManager() const { | ||
| 43 | // Otherwise, use single-threaded mode active_core variable | ||
| 44 | return *core_managers[active_core]; | ||
| 45 | } | ||
| 46 | |||
| 47 | void CpuManager::RunLoop(bool tight_loop) { | ||
| 48 | if (GDBStub::IsServerEnabled()) { | ||
| 49 | GDBStub::HandlePacket(); | ||
| 50 | |||
| 51 | // If the loop is halted and we want to step, use a tiny (1) number of instructions to | ||
| 52 | // execute. Otherwise, get out of the loop function. | ||
| 53 | if (GDBStub::GetCpuHaltFlag()) { | ||
| 54 | if (GDBStub::GetCpuStepFlag()) { | ||
| 55 | tight_loop = false; | ||
| 56 | } else { | ||
| 57 | return; | ||
| 58 | } | ||
| 59 | } | ||
| 60 | } | ||
| 61 | |||
| 62 | auto& core_timing = system.CoreTiming(); | ||
| 63 | core_timing.ResetRun(); | ||
| 64 | bool keep_running{}; | ||
| 65 | do { | ||
| 66 | keep_running = false; | ||
| 67 | for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { | ||
| 68 | core_timing.SwitchContext(active_core); | ||
| 69 | if (core_timing.CanCurrentContextRun()) { | ||
| 70 | core_managers[active_core]->RunLoop(tight_loop); | ||
| 71 | } | ||
| 72 | keep_running |= core_timing.CanCurrentContextRun(); | ||
| 73 | } | ||
| 74 | } while (keep_running); | ||
| 75 | |||
| 76 | if (GDBStub::IsServerEnabled()) { | ||
| 77 | GDBStub::SetCpuStepFlag(false); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | } // namespace Core | ||
diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h new file mode 100644 index 000000000..feb619e1b --- /dev/null +++ b/src/core/cpu_manager.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <memory> | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | |||
| 12 | class CoreManager; | ||
| 13 | class System; | ||
| 14 | |||
| 15 | class CpuManager { | ||
| 16 | public: | ||
| 17 | explicit CpuManager(System& system); | ||
| 18 | CpuManager(const CpuManager&) = delete; | ||
| 19 | CpuManager(CpuManager&&) = delete; | ||
| 20 | |||
| 21 | ~CpuManager(); | ||
| 22 | |||
| 23 | CpuManager& operator=(const CpuManager&) = delete; | ||
| 24 | CpuManager& operator=(CpuManager&&) = delete; | ||
| 25 | |||
| 26 | void Initialize(); | ||
| 27 | void Shutdown(); | ||
| 28 | |||
| 29 | CoreManager& GetCoreManager(std::size_t index); | ||
| 30 | const CoreManager& GetCoreManager(std::size_t index) const; | ||
| 31 | |||
| 32 | CoreManager& GetCurrentCoreManager(); | ||
| 33 | const CoreManager& GetCurrentCoreManager() const; | ||
| 34 | |||
| 35 | std::size_t GetActiveCoreIndex() const { | ||
| 36 | return active_core; | ||
| 37 | } | ||
| 38 | |||
| 39 | void RunLoop(bool tight_loop); | ||
| 40 | |||
| 41 | private: | ||
| 42 | static constexpr std::size_t NUM_CPU_CORES = 4; | ||
| 43 | |||
| 44 | std::array<std::unique_ptr<CoreManager>, NUM_CPU_CORES> core_managers; | ||
| 45 | std::size_t active_core{}; ///< Active core, only used in single thread mode | ||
| 46 | |||
| 47 | System& system; | ||
| 48 | }; | ||
| 49 | |||
| 50 | } // namespace Core | ||
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index 7c11d7546..2b098b7c6 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -15,6 +15,13 @@ | |||
| 15 | 15 | ||
| 16 | namespace Input { | 16 | namespace Input { |
| 17 | 17 | ||
| 18 | enum class AnalogDirection : u8 { | ||
| 19 | RIGHT, | ||
| 20 | LEFT, | ||
| 21 | UP, | ||
| 22 | DOWN, | ||
| 23 | }; | ||
| 24 | |||
| 18 | /// An abstract class template for an input device (a button, an analog input, etc.). | 25 | /// An abstract class template for an input device (a button, an analog input, etc.). |
| 19 | template <typename StatusType> | 26 | template <typename StatusType> |
| 20 | class InputDevice { | 27 | class InputDevice { |
| @@ -23,6 +30,9 @@ public: | |||
| 23 | virtual StatusType GetStatus() const { | 30 | virtual StatusType GetStatus() const { |
| 24 | return {}; | 31 | return {}; |
| 25 | } | 32 | } |
| 33 | virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const { | ||
| 34 | return {}; | ||
| 35 | } | ||
| 26 | }; | 36 | }; |
| 27 | 37 | ||
| 28 | /// An abstract class template for a factory that can create input devices. | 38 | /// An abstract class template for a factory that can create input devices. |
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index 37cb28848..67e95999d 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -35,7 +35,7 @@ | |||
| 35 | #include "common/swap.h" | 35 | #include "common/swap.h" |
| 36 | #include "core/arm/arm_interface.h" | 36 | #include "core/arm/arm_interface.h" |
| 37 | #include "core/core.h" | 37 | #include "core/core.h" |
| 38 | #include "core/core_cpu.h" | 38 | #include "core/core_manager.h" |
| 39 | #include "core/gdbstub/gdbstub.h" | 39 | #include "core/gdbstub/gdbstub.h" |
| 40 | #include "core/hle/kernel/process.h" | 40 | #include "core/hle/kernel/process.h" |
| 41 | #include "core/hle/kernel/scheduler.h" | 41 | #include "core/hle/kernel/scheduler.h" |
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp index db189c8e3..2ea3dcb61 100644 --- a/src/core/hle/kernel/address_arbiter.cpp +++ b/src/core/hle/kernel/address_arbiter.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "core/core.h" | 10 | #include "core/core.h" |
| 11 | #include "core/core_cpu.h" | ||
| 12 | #include "core/hle/kernel/address_arbiter.h" | 11 | #include "core/hle/kernel/address_arbiter.h" |
| 13 | #include "core/hle/kernel/errors.h" | 12 | #include "core/hle/kernel/errors.h" |
| 14 | #include "core/hle/kernel/scheduler.h" | 13 | #include "core/hle/kernel/scheduler.h" |
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 1d0783bd3..edd4c4259 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp | |||
| @@ -3,13 +3,15 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <atomic> | 5 | #include <atomic> |
| 6 | #include <functional> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | #include <mutex> | 8 | #include <mutex> |
| 8 | #include <utility> | 9 | #include <utility> |
| 9 | 10 | ||
| 10 | #include "common/assert.h" | 11 | #include "common/assert.h" |
| 11 | #include "common/logging/log.h" | 12 | #include "common/logging/log.h" |
| 12 | 13 | #include "core/arm/arm_interface.h" | |
| 14 | #include "core/arm/exclusive_monitor.h" | ||
| 13 | #include "core/core.h" | 15 | #include "core/core.h" |
| 14 | #include "core/core_timing.h" | 16 | #include "core/core_timing.h" |
| 15 | #include "core/core_timing_util.h" | 17 | #include "core/core_timing_util.h" |
| @@ -17,6 +19,7 @@ | |||
| 17 | #include "core/hle/kernel/errors.h" | 19 | #include "core/hle/kernel/errors.h" |
| 18 | #include "core/hle/kernel/handle_table.h" | 20 | #include "core/hle/kernel/handle_table.h" |
| 19 | #include "core/hle/kernel/kernel.h" | 21 | #include "core/hle/kernel/kernel.h" |
| 22 | #include "core/hle/kernel/physical_core.h" | ||
| 20 | #include "core/hle/kernel/process.h" | 23 | #include "core/hle/kernel/process.h" |
| 21 | #include "core/hle/kernel/resource_limit.h" | 24 | #include "core/hle/kernel/resource_limit.h" |
| 22 | #include "core/hle/kernel/scheduler.h" | 25 | #include "core/hle/kernel/scheduler.h" |
| @@ -98,6 +101,7 @@ struct KernelCore::Impl { | |||
| 98 | void Initialize(KernelCore& kernel) { | 101 | void Initialize(KernelCore& kernel) { |
| 99 | Shutdown(); | 102 | Shutdown(); |
| 100 | 103 | ||
| 104 | InitializePhysicalCores(); | ||
| 101 | InitializeSystemResourceLimit(kernel); | 105 | InitializeSystemResourceLimit(kernel); |
| 102 | InitializeThreads(); | 106 | InitializeThreads(); |
| 103 | InitializePreemption(); | 107 | InitializePreemption(); |
| @@ -121,6 +125,21 @@ struct KernelCore::Impl { | |||
| 121 | global_scheduler.Shutdown(); | 125 | global_scheduler.Shutdown(); |
| 122 | 126 | ||
| 123 | named_ports.clear(); | 127 | named_ports.clear(); |
| 128 | |||
| 129 | for (auto& core : cores) { | ||
| 130 | core.Shutdown(); | ||
| 131 | } | ||
| 132 | cores.clear(); | ||
| 133 | |||
| 134 | exclusive_monitor.reset(); | ||
| 135 | } | ||
| 136 | |||
| 137 | void InitializePhysicalCores() { | ||
| 138 | exclusive_monitor = | ||
| 139 | Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount()); | ||
| 140 | for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) { | ||
| 141 | cores.emplace_back(system, i, *exclusive_monitor); | ||
| 142 | } | ||
| 124 | } | 143 | } |
| 125 | 144 | ||
| 126 | // Creates the default system resource limit | 145 | // Creates the default system resource limit |
| @@ -186,6 +205,9 @@ struct KernelCore::Impl { | |||
| 186 | /// the ConnectToPort SVC. | 205 | /// the ConnectToPort SVC. |
| 187 | NamedPortTable named_ports; | 206 | NamedPortTable named_ports; |
| 188 | 207 | ||
| 208 | std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; | ||
| 209 | std::vector<Kernel::PhysicalCore> cores; | ||
| 210 | |||
| 189 | // System context | 211 | // System context |
| 190 | Core::System& system; | 212 | Core::System& system; |
| 191 | }; | 213 | }; |
| @@ -240,6 +262,34 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const { | |||
| 240 | return impl->global_scheduler; | 262 | return impl->global_scheduler; |
| 241 | } | 263 | } |
| 242 | 264 | ||
| 265 | Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { | ||
| 266 | return impl->cores[id]; | ||
| 267 | } | ||
| 268 | |||
| 269 | const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { | ||
| 270 | return impl->cores[id]; | ||
| 271 | } | ||
| 272 | |||
| 273 | Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() { | ||
| 274 | return *impl->exclusive_monitor; | ||
| 275 | } | ||
| 276 | |||
| 277 | const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const { | ||
| 278 | return *impl->exclusive_monitor; | ||
| 279 | } | ||
| 280 | |||
| 281 | void KernelCore::InvalidateAllInstructionCaches() { | ||
| 282 | for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) { | ||
| 283 | PhysicalCore(i).ArmInterface().ClearInstructionCache(); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | void KernelCore::PrepareReschedule(std::size_t id) { | ||
| 288 | if (id < impl->global_scheduler.CpuCoresCount()) { | ||
| 289 | impl->cores[id].Stop(); | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 243 | void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) { | 293 | void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) { |
| 244 | impl->named_ports.emplace(std::move(name), std::move(port)); | 294 | impl->named_ports.emplace(std::move(name), std::move(port)); |
| 245 | } | 295 | } |
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 3bf0068ed..fccffaf3a 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -11,8 +11,9 @@ | |||
| 11 | #include "core/hle/kernel/object.h" | 11 | #include "core/hle/kernel/object.h" |
| 12 | 12 | ||
| 13 | namespace Core { | 13 | namespace Core { |
| 14 | class ExclusiveMonitor; | ||
| 14 | class System; | 15 | class System; |
| 15 | } | 16 | } // namespace Core |
| 16 | 17 | ||
| 17 | namespace Core::Timing { | 18 | namespace Core::Timing { |
| 18 | class CoreTiming; | 19 | class CoreTiming; |
| @@ -25,6 +26,7 @@ class AddressArbiter; | |||
| 25 | class ClientPort; | 26 | class ClientPort; |
| 26 | class GlobalScheduler; | 27 | class GlobalScheduler; |
| 27 | class HandleTable; | 28 | class HandleTable; |
| 29 | class PhysicalCore; | ||
| 28 | class Process; | 30 | class Process; |
| 29 | class ResourceLimit; | 31 | class ResourceLimit; |
| 30 | class Thread; | 32 | class Thread; |
| @@ -84,6 +86,21 @@ public: | |||
| 84 | /// Gets the sole instance of the global scheduler | 86 | /// Gets the sole instance of the global scheduler |
| 85 | const Kernel::GlobalScheduler& GlobalScheduler() const; | 87 | const Kernel::GlobalScheduler& GlobalScheduler() const; |
| 86 | 88 | ||
| 89 | /// Gets the an instance of the respective physical CPU core. | ||
| 90 | Kernel::PhysicalCore& PhysicalCore(std::size_t id); | ||
| 91 | |||
| 92 | /// Gets the an instance of the respective physical CPU core. | ||
| 93 | const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const; | ||
| 94 | |||
| 95 | /// Stops execution of 'id' core, in order to reschedule a new thread. | ||
| 96 | void PrepareReschedule(std::size_t id); | ||
| 97 | |||
| 98 | Core::ExclusiveMonitor& GetExclusiveMonitor(); | ||
| 99 | |||
| 100 | const Core::ExclusiveMonitor& GetExclusiveMonitor() const; | ||
| 101 | |||
| 102 | void InvalidateAllInstructionCaches(); | ||
| 103 | |||
| 87 | /// Adds a port to the named port table | 104 | /// Adds a port to the named port table |
| 88 | void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); | 105 | void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port); |
| 89 | 106 | ||
diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp new file mode 100644 index 000000000..9303dd273 --- /dev/null +++ b/src/core/hle/kernel/physical_core.cpp | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/arm/arm_interface.h" | ||
| 7 | #ifdef ARCHITECTURE_x86_64 | ||
| 8 | #include "core/arm/dynarmic/arm_dynarmic.h" | ||
| 9 | #endif | ||
| 10 | #include "core/arm/exclusive_monitor.h" | ||
| 11 | #include "core/arm/unicorn/arm_unicorn.h" | ||
| 12 | #include "core/core.h" | ||
| 13 | #include "core/hle/kernel/physical_core.h" | ||
| 14 | #include "core/hle/kernel/scheduler.h" | ||
| 15 | #include "core/hle/kernel/thread.h" | ||
| 16 | |||
| 17 | namespace Kernel { | ||
| 18 | |||
| 19 | PhysicalCore::PhysicalCore(Core::System& system, std::size_t id, | ||
| 20 | Core::ExclusiveMonitor& exclusive_monitor) | ||
| 21 | : core_index{id} { | ||
| 22 | #ifdef ARCHITECTURE_x86_64 | ||
| 23 | arm_interface = std::make_unique<Core::ARM_Dynarmic>(system, exclusive_monitor, core_index); | ||
| 24 | #else | ||
| 25 | arm_interface = std::make_shared<Core::ARM_Unicorn>(system); | ||
| 26 | LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available"); | ||
| 27 | #endif | ||
| 28 | |||
| 29 | scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index); | ||
| 30 | } | ||
| 31 | |||
| 32 | PhysicalCore::~PhysicalCore() = default; | ||
| 33 | |||
| 34 | void PhysicalCore::Run() { | ||
| 35 | arm_interface->Run(); | ||
| 36 | arm_interface->ClearExclusiveState(); | ||
| 37 | } | ||
| 38 | |||
| 39 | void PhysicalCore::Step() { | ||
| 40 | arm_interface->Step(); | ||
| 41 | } | ||
| 42 | |||
| 43 | void PhysicalCore::Stop() { | ||
| 44 | arm_interface->PrepareReschedule(); | ||
| 45 | } | ||
| 46 | |||
| 47 | void PhysicalCore::Shutdown() { | ||
| 48 | scheduler->Shutdown(); | ||
| 49 | } | ||
| 50 | |||
| 51 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h new file mode 100644 index 000000000..4c32c0f1b --- /dev/null +++ b/src/core/hle/kernel/physical_core.h | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <cstddef> | ||
| 8 | #include <memory> | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | class Scheduler; | ||
| 12 | } // namespace Kernel | ||
| 13 | |||
| 14 | namespace Core { | ||
| 15 | class ARM_Interface; | ||
| 16 | class ExclusiveMonitor; | ||
| 17 | class System; | ||
| 18 | } // namespace Core | ||
| 19 | |||
| 20 | namespace Kernel { | ||
| 21 | |||
| 22 | class PhysicalCore { | ||
| 23 | public: | ||
| 24 | PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor); | ||
| 25 | ~PhysicalCore(); | ||
| 26 | |||
| 27 | PhysicalCore(const PhysicalCore&) = delete; | ||
| 28 | PhysicalCore& operator=(const PhysicalCore&) = delete; | ||
| 29 | |||
| 30 | PhysicalCore(PhysicalCore&&) = default; | ||
| 31 | PhysicalCore& operator=(PhysicalCore&&) = default; | ||
| 32 | |||
| 33 | /// Execute current jit state | ||
| 34 | void Run(); | ||
| 35 | /// Execute a single instruction in current jit. | ||
| 36 | void Step(); | ||
| 37 | /// Stop JIT execution/exit | ||
| 38 | void Stop(); | ||
| 39 | |||
| 40 | // Shutdown this physical core. | ||
| 41 | void Shutdown(); | ||
| 42 | |||
| 43 | Core::ARM_Interface& ArmInterface() { | ||
| 44 | return *arm_interface; | ||
| 45 | } | ||
| 46 | |||
| 47 | const Core::ARM_Interface& ArmInterface() const { | ||
| 48 | return *arm_interface; | ||
| 49 | } | ||
| 50 | |||
| 51 | bool IsMainCore() const { | ||
| 52 | return core_index == 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | bool IsSystemCore() const { | ||
| 56 | return core_index == 3; | ||
| 57 | } | ||
| 58 | |||
| 59 | std::size_t CoreIndex() const { | ||
| 60 | return core_index; | ||
| 61 | } | ||
| 62 | |||
| 63 | Kernel::Scheduler& Scheduler() { | ||
| 64 | return *scheduler; | ||
| 65 | } | ||
| 66 | |||
| 67 | const Kernel::Scheduler& Scheduler() const { | ||
| 68 | return *scheduler; | ||
| 69 | } | ||
| 70 | |||
| 71 | private: | ||
| 72 | std::size_t core_index; | ||
| 73 | std::unique_ptr<Core::ARM_Interface> arm_interface; | ||
| 74 | std::unique_ptr<Kernel::Scheduler> scheduler; | ||
| 75 | }; | ||
| 76 | |||
| 77 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/scheduler.cpp b/src/core/hle/kernel/scheduler.cpp index d36fcd7d9..eb196a690 100644 --- a/src/core/hle/kernel/scheduler.cpp +++ b/src/core/hle/kernel/scheduler.cpp | |||
| @@ -14,7 +14,6 @@ | |||
| 14 | #include "common/logging/log.h" | 14 | #include "common/logging/log.h" |
| 15 | #include "core/arm/arm_interface.h" | 15 | #include "core/arm/arm_interface.h" |
| 16 | #include "core/core.h" | 16 | #include "core/core.h" |
| 17 | #include "core/core_cpu.h" | ||
| 18 | #include "core/core_timing.h" | 17 | #include "core/core_timing.h" |
| 19 | #include "core/hle/kernel/kernel.h" | 18 | #include "core/hle/kernel/kernel.h" |
| 20 | #include "core/hle/kernel/process.h" | 19 | #include "core/hle/kernel/process.h" |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index dbcdb0b88..1d99bf7a2 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -15,7 +15,7 @@ | |||
| 15 | #include "common/string_util.h" | 15 | #include "common/string_util.h" |
| 16 | #include "core/arm/exclusive_monitor.h" | 16 | #include "core/arm/exclusive_monitor.h" |
| 17 | #include "core/core.h" | 17 | #include "core/core.h" |
| 18 | #include "core/core_cpu.h" | 18 | #include "core/core_manager.h" |
| 19 | #include "core/core_timing.h" | 19 | #include "core/core_timing.h" |
| 20 | #include "core/core_timing_util.h" | 20 | #include "core/core_timing_util.h" |
| 21 | #include "core/hle/kernel/address_arbiter.h" | 21 | #include "core/hle/kernel/address_arbiter.h" |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index e84e5ce0d..e965b5b04 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include "common/thread_queue_list.h" | 13 | #include "common/thread_queue_list.h" |
| 14 | #include "core/arm/arm_interface.h" | 14 | #include "core/arm/arm_interface.h" |
| 15 | #include "core/core.h" | 15 | #include "core/core.h" |
| 16 | #include "core/core_cpu.h" | ||
| 17 | #include "core/core_timing.h" | 16 | #include "core/core_timing.h" |
| 18 | #include "core/core_timing_util.h" | 17 | #include "core/core_timing_util.h" |
| 19 | #include "core/hle/kernel/errors.h" | 18 | #include "core/hle/kernel/errors.h" |
| @@ -356,7 +355,7 @@ void Thread::SetActivity(ThreadActivity value) { | |||
| 356 | // Set status if not waiting | 355 | // Set status if not waiting |
| 357 | if (status == ThreadStatus::Ready || status == ThreadStatus::Running) { | 356 | if (status == ThreadStatus::Ready || status == ThreadStatus::Running) { |
| 358 | SetStatus(ThreadStatus::Paused); | 357 | SetStatus(ThreadStatus::Paused); |
| 359 | Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule(); | 358 | kernel.PrepareReschedule(processor_id); |
| 360 | } | 359 | } |
| 361 | } else if (status == ThreadStatus::Paused) { | 360 | } else if (status == ThreadStatus::Paused) { |
| 362 | // Ready to reschedule | 361 | // Ready to reschedule |
diff --git a/src/core/hle/kernel/wait_object.cpp b/src/core/hle/kernel/wait_object.cpp index 745f2c4e8..a0c806e8f 100644 --- a/src/core/hle/kernel/wait_object.cpp +++ b/src/core/hle/kernel/wait_object.cpp | |||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/core.h" | 9 | #include "core/core.h" |
| 10 | #include "core/core_cpu.h" | ||
| 11 | #include "core/hle/kernel/kernel.h" | 10 | #include "core/hle/kernel/kernel.h" |
| 12 | #include "core/hle/kernel/object.h" | 11 | #include "core/hle/kernel/object.h" |
| 13 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
| @@ -96,7 +95,7 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) { | |||
| 96 | } | 95 | } |
| 97 | if (resume) { | 96 | if (resume) { |
| 98 | thread->ResumeFromWait(); | 97 | thread->ResumeFromWait(); |
| 99 | Core::System::GetInstance().PrepareReschedule(thread->GetProcessorID()); | 98 | kernel.PrepareReschedule(thread->GetProcessorID()); |
| 100 | } | 99 | } |
| 101 | } | 100 | } |
| 102 | 101 | ||
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 4d952adc0..15c09f04c 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -250,6 +250,10 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { | |||
| 250 | auto& rstick_entry = npad_pad_states[controller_idx].r_stick; | 250 | auto& rstick_entry = npad_pad_states[controller_idx].r_stick; |
| 251 | const auto& button_state = buttons[controller_idx]; | 251 | const auto& button_state = buttons[controller_idx]; |
| 252 | const auto& analog_state = sticks[controller_idx]; | 252 | const auto& analog_state = sticks[controller_idx]; |
| 253 | const auto [stick_l_x_f, stick_l_y_f] = | ||
| 254 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); | ||
| 255 | const auto [stick_r_x_f, stick_r_y_f] = | ||
| 256 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); | ||
| 253 | 257 | ||
| 254 | using namespace Settings::NativeButton; | 258 | using namespace Settings::NativeButton; |
| 255 | pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); | 259 | pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); |
| @@ -270,23 +274,32 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { | |||
| 270 | pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); | 274 | pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); |
| 271 | pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); | 275 | pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); |
| 272 | 276 | ||
| 273 | pad_state.l_stick_left.Assign(button_state[LStick_Left - BUTTON_HID_BEGIN]->GetStatus()); | 277 | pad_state.l_stick_right.Assign( |
| 274 | pad_state.l_stick_up.Assign(button_state[LStick_Up - BUTTON_HID_BEGIN]->GetStatus()); | 278 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( |
| 275 | pad_state.l_stick_right.Assign(button_state[LStick_Right - BUTTON_HID_BEGIN]->GetStatus()); | 279 | Input::AnalogDirection::RIGHT)); |
| 276 | pad_state.l_stick_down.Assign(button_state[LStick_Down - BUTTON_HID_BEGIN]->GetStatus()); | 280 | pad_state.l_stick_left.Assign( |
| 277 | 281 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( | |
| 278 | pad_state.r_stick_left.Assign(button_state[RStick_Left - BUTTON_HID_BEGIN]->GetStatus()); | 282 | Input::AnalogDirection::LEFT)); |
| 279 | pad_state.r_stick_up.Assign(button_state[RStick_Up - BUTTON_HID_BEGIN]->GetStatus()); | 283 | pad_state.l_stick_up.Assign( |
| 280 | pad_state.r_stick_right.Assign(button_state[RStick_Right - BUTTON_HID_BEGIN]->GetStatus()); | 284 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( |
| 281 | pad_state.r_stick_down.Assign(button_state[RStick_Down - BUTTON_HID_BEGIN]->GetStatus()); | 285 | Input::AnalogDirection::UP)); |
| 286 | pad_state.l_stick_down.Assign( | ||
| 287 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( | ||
| 288 | Input::AnalogDirection::DOWN)); | ||
| 289 | |||
| 290 | pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | ||
| 291 | ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); | ||
| 292 | pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | ||
| 293 | ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); | ||
| 294 | pad_state.r_stick_right.Assign( | ||
| 295 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | ||
| 296 | ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); | ||
| 297 | pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | ||
| 298 | ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); | ||
| 282 | 299 | ||
| 283 | pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); | 300 | pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); |
| 284 | pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); | 301 | pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); |
| 285 | 302 | ||
| 286 | const auto [stick_l_x_f, stick_l_y_f] = | ||
| 287 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); | ||
| 288 | const auto [stick_r_x_f, stick_r_y_f] = | ||
| 289 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus(); | ||
| 290 | lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); | 303 | lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX); |
| 291 | lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); | 304 | lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX); |
| 292 | rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); | 305 | rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); |
diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 884ad173b..f67fab2f9 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp | |||
| @@ -42,6 +42,26 @@ void BSD::Socket(Kernel::HLERequestContext& ctx) { | |||
| 42 | rb.Push<u32>(0); // bsd errno | 42 | rb.Push<u32>(0); // bsd errno |
| 43 | } | 43 | } |
| 44 | 44 | ||
| 45 | void BSD::Select(Kernel::HLERequestContext& ctx) { | ||
| 46 | LOG_WARNING(Service, "(STUBBED) called"); | ||
| 47 | |||
| 48 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 49 | |||
| 50 | rb.Push(RESULT_SUCCESS); | ||
| 51 | rb.Push<u32>(0); // ret | ||
| 52 | rb.Push<u32>(0); // bsd errno | ||
| 53 | } | ||
| 54 | |||
| 55 | void BSD::Bind(Kernel::HLERequestContext& ctx) { | ||
| 56 | LOG_WARNING(Service, "(STUBBED) called"); | ||
| 57 | |||
| 58 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 59 | |||
| 60 | rb.Push(RESULT_SUCCESS); | ||
| 61 | rb.Push<u32>(0); // ret | ||
| 62 | rb.Push<u32>(0); // bsd errno | ||
| 63 | } | ||
| 64 | |||
| 45 | void BSD::Connect(Kernel::HLERequestContext& ctx) { | 65 | void BSD::Connect(Kernel::HLERequestContext& ctx) { |
| 46 | LOG_WARNING(Service, "(STUBBED) called"); | 66 | LOG_WARNING(Service, "(STUBBED) called"); |
| 47 | 67 | ||
| @@ -52,6 +72,26 @@ void BSD::Connect(Kernel::HLERequestContext& ctx) { | |||
| 52 | rb.Push<u32>(0); // bsd errno | 72 | rb.Push<u32>(0); // bsd errno |
| 53 | } | 73 | } |
| 54 | 74 | ||
| 75 | void BSD::Listen(Kernel::HLERequestContext& ctx) { | ||
| 76 | LOG_WARNING(Service, "(STUBBED) called"); | ||
| 77 | |||
| 78 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 79 | |||
| 80 | rb.Push(RESULT_SUCCESS); | ||
| 81 | rb.Push<u32>(0); // ret | ||
| 82 | rb.Push<u32>(0); // bsd errno | ||
| 83 | } | ||
| 84 | |||
| 85 | void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) { | ||
| 86 | LOG_WARNING(Service, "(STUBBED) called"); | ||
| 87 | |||
| 88 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 89 | |||
| 90 | rb.Push(RESULT_SUCCESS); | ||
| 91 | rb.Push<u32>(0); // ret | ||
| 92 | rb.Push<u32>(0); // bsd errno | ||
| 93 | } | ||
| 94 | |||
| 55 | void BSD::SendTo(Kernel::HLERequestContext& ctx) { | 95 | void BSD::SendTo(Kernel::HLERequestContext& ctx) { |
| 56 | LOG_WARNING(Service, "(STUBBED) called"); | 96 | LOG_WARNING(Service, "(STUBBED) called"); |
| 57 | 97 | ||
| @@ -80,7 +120,7 @@ BSD::BSD(const char* name) : ServiceFramework(name) { | |||
| 80 | {2, &BSD::Socket, "Socket"}, | 120 | {2, &BSD::Socket, "Socket"}, |
| 81 | {3, nullptr, "SocketExempt"}, | 121 | {3, nullptr, "SocketExempt"}, |
| 82 | {4, nullptr, "Open"}, | 122 | {4, nullptr, "Open"}, |
| 83 | {5, nullptr, "Select"}, | 123 | {5, &BSD::Select, "Select"}, |
| 84 | {6, nullptr, "Poll"}, | 124 | {6, nullptr, "Poll"}, |
| 85 | {7, nullptr, "Sysctl"}, | 125 | {7, nullptr, "Sysctl"}, |
| 86 | {8, nullptr, "Recv"}, | 126 | {8, nullptr, "Recv"}, |
| @@ -88,15 +128,15 @@ BSD::BSD(const char* name) : ServiceFramework(name) { | |||
| 88 | {10, nullptr, "Send"}, | 128 | {10, nullptr, "Send"}, |
| 89 | {11, &BSD::SendTo, "SendTo"}, | 129 | {11, &BSD::SendTo, "SendTo"}, |
| 90 | {12, nullptr, "Accept"}, | 130 | {12, nullptr, "Accept"}, |
| 91 | {13, nullptr, "Bind"}, | 131 | {13, &BSD::Bind, "Bind"}, |
| 92 | {14, &BSD::Connect, "Connect"}, | 132 | {14, &BSD::Connect, "Connect"}, |
| 93 | {15, nullptr, "GetPeerName"}, | 133 | {15, nullptr, "GetPeerName"}, |
| 94 | {16, nullptr, "GetSockName"}, | 134 | {16, nullptr, "GetSockName"}, |
| 95 | {17, nullptr, "GetSockOpt"}, | 135 | {17, nullptr, "GetSockOpt"}, |
| 96 | {18, nullptr, "Listen"}, | 136 | {18, &BSD::Listen, "Listen"}, |
| 97 | {19, nullptr, "Ioctl"}, | 137 | {19, nullptr, "Ioctl"}, |
| 98 | {20, nullptr, "Fcntl"}, | 138 | {20, nullptr, "Fcntl"}, |
| 99 | {21, nullptr, "SetSockOpt"}, | 139 | {21, &BSD::SetSockOpt, "SetSockOpt"}, |
| 100 | {22, nullptr, "Shutdown"}, | 140 | {22, nullptr, "Shutdown"}, |
| 101 | {23, nullptr, "ShutdownAllSockets"}, | 141 | {23, nullptr, "ShutdownAllSockets"}, |
| 102 | {24, nullptr, "Write"}, | 142 | {24, nullptr, "Write"}, |
diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 0fe0e65c6..3098e3baf 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h | |||
| @@ -18,7 +18,11 @@ private: | |||
| 18 | void RegisterClient(Kernel::HLERequestContext& ctx); | 18 | void RegisterClient(Kernel::HLERequestContext& ctx); |
| 19 | void StartMonitoring(Kernel::HLERequestContext& ctx); | 19 | void StartMonitoring(Kernel::HLERequestContext& ctx); |
| 20 | void Socket(Kernel::HLERequestContext& ctx); | 20 | void Socket(Kernel::HLERequestContext& ctx); |
| 21 | void Select(Kernel::HLERequestContext& ctx); | ||
| 22 | void Bind(Kernel::HLERequestContext& ctx); | ||
| 21 | void Connect(Kernel::HLERequestContext& ctx); | 23 | void Connect(Kernel::HLERequestContext& ctx); |
| 24 | void Listen(Kernel::HLERequestContext& ctx); | ||
| 25 | void SetSockOpt(Kernel::HLERequestContext& ctx); | ||
| 22 | void SendTo(Kernel::HLERequestContext& ctx); | 26 | void SendTo(Kernel::HLERequestContext& ctx); |
| 23 | void Close(Kernel::HLERequestContext& ctx); | 27 | void Close(Kernel::HLERequestContext& ctx); |
| 24 | 28 | ||
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index d2e9d278f..a2e0c0bd2 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -342,6 +342,22 @@ public: | |||
| 342 | return std::make_tuple<float, float>(0.0f, 0.0f); | 342 | return std::make_tuple<float, float>(0.0f, 0.0f); |
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | ||
| 346 | const auto [x, y] = GetStatus(); | ||
| 347 | const float directional_deadzone = 0.4f; | ||
| 348 | switch (direction) { | ||
| 349 | case Input::AnalogDirection::RIGHT: | ||
| 350 | return x > directional_deadzone; | ||
| 351 | case Input::AnalogDirection::LEFT: | ||
| 352 | return x < -directional_deadzone; | ||
| 353 | case Input::AnalogDirection::UP: | ||
| 354 | return y > directional_deadzone; | ||
| 355 | case Input::AnalogDirection::DOWN: | ||
| 356 | return y < -directional_deadzone; | ||
| 357 | } | ||
| 358 | return false; | ||
| 359 | } | ||
| 360 | |||
| 345 | private: | 361 | private: |
| 346 | std::shared_ptr<SDLJoystick> joystick; | 362 | std::shared_ptr<SDLJoystick> joystick; |
| 347 | const int axis_x; | 363 | const int axis_x; |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 6f98bd827..f443ec0fe 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -227,6 +227,28 @@ enum class AtomicOp : u64 { | |||
| 227 | Exch = 8, | 227 | Exch = 8, |
| 228 | }; | 228 | }; |
| 229 | 229 | ||
| 230 | enum class GlobalAtomicOp : u64 { | ||
| 231 | Add = 0, | ||
| 232 | Min = 1, | ||
| 233 | Max = 2, | ||
| 234 | Inc = 3, | ||
| 235 | Dec = 4, | ||
| 236 | And = 5, | ||
| 237 | Or = 6, | ||
| 238 | Xor = 7, | ||
| 239 | Exch = 8, | ||
| 240 | SafeAdd = 10, | ||
| 241 | }; | ||
| 242 | |||
| 243 | enum class GlobalAtomicType : u64 { | ||
| 244 | U32 = 0, | ||
| 245 | S32 = 1, | ||
| 246 | U64 = 2, | ||
| 247 | F32_FTZ_RN = 3, | ||
| 248 | F16x2_FTZ_RN = 4, | ||
| 249 | S64 = 5, | ||
| 250 | }; | ||
| 251 | |||
| 230 | enum class UniformType : u64 { | 252 | enum class UniformType : u64 { |
| 231 | UnsignedByte = 0, | 253 | UnsignedByte = 0, |
| 232 | SignedByte = 1, | 254 | SignedByte = 1, |
| @@ -958,6 +980,12 @@ union Instruction { | |||
| 958 | } stg; | 980 | } stg; |
| 959 | 981 | ||
| 960 | union { | 982 | union { |
| 983 | BitField<52, 4, GlobalAtomicOp> operation; | ||
| 984 | BitField<49, 3, GlobalAtomicType> type; | ||
| 985 | BitField<28, 20, s64> offset; | ||
| 986 | } atom; | ||
| 987 | |||
| 988 | union { | ||
| 961 | BitField<52, 4, AtomicOp> operation; | 989 | BitField<52, 4, AtomicOp> operation; |
| 962 | BitField<28, 2, AtomicType> type; | 990 | BitField<28, 2, AtomicType> type; |
| 963 | BitField<30, 22, s64> offset; | 991 | BitField<30, 22, s64> offset; |
| @@ -1690,6 +1718,7 @@ public: | |||
| 1690 | ST_S, | 1718 | ST_S, |
| 1691 | ST, // Store in generic memory | 1719 | ST, // Store in generic memory |
| 1692 | STG, // Store in global memory | 1720 | STG, // Store in global memory |
| 1721 | ATOM, // Atomic operation on global memory | ||
| 1693 | ATOMS, // Atomic operation on shared memory | 1722 | ATOMS, // Atomic operation on shared memory |
| 1694 | AL2P, // Transforms attribute memory into physical memory | 1723 | AL2P, // Transforms attribute memory into physical memory |
| 1695 | TEX, | 1724 | TEX, |
| @@ -1994,6 +2023,7 @@ private: | |||
| 1994 | INST("1110111101010---", Id::ST_L, Type::Memory, "ST_L"), | 2023 | INST("1110111101010---", Id::ST_L, Type::Memory, "ST_L"), |
| 1995 | INST("101-------------", Id::ST, Type::Memory, "ST"), | 2024 | INST("101-------------", Id::ST, Type::Memory, "ST"), |
| 1996 | INST("1110111011011---", Id::STG, Type::Memory, "STG"), | 2025 | INST("1110111011011---", Id::STG, Type::Memory, "STG"), |
| 2026 | INST("11101101--------", Id::ATOM, Type::Memory, "ATOM"), | ||
| 1997 | INST("11101100--------", Id::ATOMS, Type::Memory, "ATOMS"), | 2027 | INST("11101100--------", Id::ATOMS, Type::Memory, "ATOMS"), |
| 1998 | INST("1110111110100---", Id::AL2P, Type::Memory, "AL2P"), | 2028 | INST("1110111110100---", Id::AL2P, Type::Memory, "AL2P"), |
| 1999 | INST("110000----111---", Id::TEX, Type::Texture, "TEX"), | 2029 | INST("110000----111---", Id::TEX, Type::Texture, "TEX"), |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index cb1a5f35c..4735000b5 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -1040,7 +1040,6 @@ private: | |||
| 1040 | } | 1040 | } |
| 1041 | return {{"gl_ViewportIndex", Type::Int}}; | 1041 | return {{"gl_ViewportIndex", Type::Int}}; |
| 1042 | case 3: | 1042 | case 3: |
| 1043 | UNIMPLEMENTED_MSG("Requires some state changes for gl_PointSize to work in shader"); | ||
| 1044 | return {{"gl_PointSize", Type::Float}}; | 1043 | return {{"gl_PointSize", Type::Float}}; |
| 1045 | } | 1044 | } |
| 1046 | return {}; | 1045 | return {}; |
| @@ -1885,10 +1884,7 @@ private: | |||
| 1885 | 1884 | ||
| 1886 | template <const std::string_view& opname, Type type> | 1885 | template <const std::string_view& opname, Type type> |
| 1887 | Expression Atomic(Operation operation) { | 1886 | Expression Atomic(Operation operation) { |
| 1888 | ASSERT(stage == ShaderType::Compute); | 1887 | return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(), |
| 1889 | auto& smem = std::get<SmemNode>(*operation[0]); | ||
| 1890 | |||
| 1891 | return {fmt::format("atomic{}(smem[{} >> 2], {})", opname, Visit(smem.GetAddress()).AsInt(), | ||
| 1892 | Visit(operation[1]).As(type)), | 1888 | Visit(operation[1]).As(type)), |
| 1893 | type}; | 1889 | type}; |
| 1894 | } | 1890 | } |
diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index e95eb069e..d4b81cd87 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp | |||
| @@ -176,6 +176,19 @@ GLint GetSwizzleSource(SwizzleSource source) { | |||
| 176 | return GL_NONE; | 176 | return GL_NONE; |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | GLenum GetComponent(PixelFormat format, bool is_first) { | ||
| 180 | switch (format) { | ||
| 181 | case PixelFormat::Z24S8: | ||
| 182 | case PixelFormat::Z32FS8: | ||
| 183 | return is_first ? GL_DEPTH_COMPONENT : GL_STENCIL_INDEX; | ||
| 184 | case PixelFormat::S8Z24: | ||
| 185 | return is_first ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT; | ||
| 186 | default: | ||
| 187 | UNREACHABLE(); | ||
| 188 | return GL_DEPTH_COMPONENT; | ||
| 189 | } | ||
| 190 | } | ||
| 191 | |||
| 179 | void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) { | 192 | void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) { |
| 180 | if (params.IsBuffer()) { | 193 | if (params.IsBuffer()) { |
| 181 | return; | 194 | return; |
| @@ -184,7 +197,7 @@ void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) { | |||
| 184 | glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 197 | glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
| 185 | glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 198 | glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 186 | glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 199 | glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 187 | glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, params.num_levels - 1); | 200 | glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(params.num_levels - 1)); |
| 188 | if (params.num_levels == 1) { | 201 | if (params.num_levels == 1) { |
| 189 | glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0f); | 202 | glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0f); |
| 190 | } | 203 | } |
| @@ -416,11 +429,21 @@ void CachedSurfaceView::ApplySwizzle(SwizzleSource x_source, SwizzleSource y_sou | |||
| 416 | if (new_swizzle == swizzle) | 429 | if (new_swizzle == swizzle) |
| 417 | return; | 430 | return; |
| 418 | swizzle = new_swizzle; | 431 | swizzle = new_swizzle; |
| 419 | const std::array<GLint, 4> gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source), | 432 | const std::array gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source), |
| 420 | GetSwizzleSource(z_source), | 433 | GetSwizzleSource(z_source), GetSwizzleSource(w_source)}; |
| 421 | GetSwizzleSource(w_source)}; | ||
| 422 | const GLuint handle = GetTexture(); | 434 | const GLuint handle = GetTexture(); |
| 423 | glTextureParameteriv(handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data()); | 435 | const PixelFormat format = surface.GetSurfaceParams().pixel_format; |
| 436 | switch (format) { | ||
| 437 | case PixelFormat::Z24S8: | ||
| 438 | case PixelFormat::Z32FS8: | ||
| 439 | case PixelFormat::S8Z24: | ||
| 440 | glTextureParameteri(handle, GL_DEPTH_STENCIL_TEXTURE_MODE, | ||
| 441 | GetComponent(format, x_source == SwizzleSource::R)); | ||
| 442 | break; | ||
| 443 | default: | ||
| 444 | glTextureParameteriv(handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data()); | ||
| 445 | break; | ||
| 446 | } | ||
| 424 | } | 447 | } |
| 425 | 448 | ||
| 426 | OGLTextureView CachedSurfaceView::CreateTextureView() const { | 449 | OGLTextureView CachedSurfaceView::CreateTextureView() const { |
| @@ -529,8 +552,11 @@ void TextureCacheOpenGL::ImageBlit(View& src_view, View& dst_view, | |||
| 529 | const Common::Rectangle<u32>& dst_rect = copy_config.dst_rect; | 552 | const Common::Rectangle<u32>& dst_rect = copy_config.dst_rect; |
| 530 | const bool is_linear = copy_config.filter == Tegra::Engines::Fermi2D::Filter::Linear; | 553 | const bool is_linear = copy_config.filter == Tegra::Engines::Fermi2D::Filter::Linear; |
| 531 | 554 | ||
| 532 | glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left, | 555 | glBlitFramebuffer(static_cast<GLint>(src_rect.left), static_cast<GLint>(src_rect.top), |
| 533 | dst_rect.top, dst_rect.right, dst_rect.bottom, buffers, | 556 | static_cast<GLint>(src_rect.right), static_cast<GLint>(src_rect.bottom), |
| 557 | static_cast<GLint>(dst_rect.left), static_cast<GLint>(dst_rect.top), | ||
| 558 | static_cast<GLint>(dst_rect.right), static_cast<GLint>(dst_rect.bottom), | ||
| 559 | buffers, | ||
| 534 | is_linear && (buffers == GL_COLOR_BUFFER_BIT) ? GL_LINEAR : GL_NEAREST); | 560 | is_linear && (buffers == GL_COLOR_BUFFER_BIT) ? GL_LINEAR : GL_NEAREST); |
| 535 | } | 561 | } |
| 536 | 562 | ||
diff --git a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp index 48e23d4cd..7ddf7d3ee 100644 --- a/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_pipeline_cache.cpp | |||
| @@ -325,9 +325,6 @@ VKPipelineCache::DecompileShaders(const GraphicsPipelineCacheKey& key) { | |||
| 325 | specialization.tessellation.primitive = fixed_state.tessellation.primitive; | 325 | specialization.tessellation.primitive = fixed_state.tessellation.primitive; |
| 326 | specialization.tessellation.spacing = fixed_state.tessellation.spacing; | 326 | specialization.tessellation.spacing = fixed_state.tessellation.spacing; |
| 327 | specialization.tessellation.clockwise = fixed_state.tessellation.clockwise; | 327 | specialization.tessellation.clockwise = fixed_state.tessellation.clockwise; |
| 328 | for (const auto& rt : key.renderpass_params.color_attachments) { | ||
| 329 | specialization.enabled_rendertargets.set(rt.index); | ||
| 330 | } | ||
| 331 | 328 | ||
| 332 | SPIRVProgram program; | 329 | SPIRVProgram program; |
| 333 | std::vector<vk::DescriptorSetLayoutBinding> bindings; | 330 | std::vector<vk::DescriptorSetLayoutBinding> bindings; |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 36d928fab..24a658dce 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -543,11 +543,10 @@ private: | |||
| 543 | return; | 543 | return; |
| 544 | } | 544 | } |
| 545 | 545 | ||
| 546 | for (u32 rt = 0; rt < static_cast<u32>(frag_colors.size()); ++rt) { | 546 | for (u32 rt = 0; rt < static_cast<u32>(std::size(frag_colors)); ++rt) { |
| 547 | if (!specialization.enabled_rendertargets[rt]) { | 547 | if (!IsRenderTargetEnabled(rt)) { |
| 548 | continue; | 548 | continue; |
| 549 | } | 549 | } |
| 550 | |||
| 551 | const Id id = AddGlobalVariable(OpVariable(t_out_float4, spv::StorageClass::Output)); | 550 | const Id id = AddGlobalVariable(OpVariable(t_out_float4, spv::StorageClass::Output)); |
| 552 | Name(id, fmt::format("frag_color{}", rt)); | 551 | Name(id, fmt::format("frag_color{}", rt)); |
| 553 | Decorate(id, spv::Decoration::Location, rt); | 552 | Decorate(id, spv::Decoration::Location, rt); |
| @@ -862,6 +861,15 @@ private: | |||
| 862 | return binding; | 861 | return binding; |
| 863 | } | 862 | } |
| 864 | 863 | ||
| 864 | bool IsRenderTargetEnabled(u32 rt) const { | ||
| 865 | for (u32 component = 0; component < 4; ++component) { | ||
| 866 | if (header.ps.IsColorComponentOutputEnabled(rt, component)) { | ||
| 867 | return true; | ||
| 868 | } | ||
| 869 | } | ||
| 870 | return false; | ||
| 871 | } | ||
| 872 | |||
| 865 | bool IsInputAttributeArray() const { | 873 | bool IsInputAttributeArray() const { |
| 866 | return stage == ShaderType::TesselationControl || stage == ShaderType::TesselationEval || | 874 | return stage == ShaderType::TesselationControl || stage == ShaderType::TesselationEval || |
| 867 | stage == ShaderType::Geometry; | 875 | stage == ShaderType::Geometry; |
| @@ -1130,15 +1138,7 @@ private: | |||
| 1130 | } | 1138 | } |
| 1131 | 1139 | ||
| 1132 | if (const auto gmem = std::get_if<GmemNode>(&*node)) { | 1140 | if (const auto gmem = std::get_if<GmemNode>(&*node)) { |
| 1133 | const Id gmem_buffer = global_buffers.at(gmem->GetDescriptor()); | 1141 | return {OpLoad(t_uint, GetGlobalMemoryPointer(*gmem)), Type::Uint}; |
| 1134 | const Id real = AsUint(Visit(gmem->GetRealAddress())); | ||
| 1135 | const Id base = AsUint(Visit(gmem->GetBaseAddress())); | ||
| 1136 | |||
| 1137 | Id offset = OpISub(t_uint, real, base); | ||
| 1138 | offset = OpUDiv(t_uint, offset, Constant(t_uint, 4U)); | ||
| 1139 | return {OpLoad(t_float, | ||
| 1140 | OpAccessChain(t_gmem_float, gmem_buffer, Constant(t_uint, 0U), offset)), | ||
| 1141 | Type::Float}; | ||
| 1142 | } | 1142 | } |
| 1143 | 1143 | ||
| 1144 | if (const auto lmem = std::get_if<LmemNode>(&*node)) { | 1144 | if (const auto lmem = std::get_if<LmemNode>(&*node)) { |
| @@ -1149,10 +1149,7 @@ private: | |||
| 1149 | } | 1149 | } |
| 1150 | 1150 | ||
| 1151 | if (const auto smem = std::get_if<SmemNode>(&*node)) { | 1151 | if (const auto smem = std::get_if<SmemNode>(&*node)) { |
| 1152 | Id address = AsUint(Visit(smem->GetAddress())); | 1152 | return {OpLoad(t_uint, GetSharedMemoryPointer(*smem)), Type::Uint}; |
| 1153 | address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U)); | ||
| 1154 | const Id pointer = OpAccessChain(t_smem_uint, shared_memory, address); | ||
| 1155 | return {OpLoad(t_uint, pointer), Type::Uint}; | ||
| 1156 | } | 1153 | } |
| 1157 | 1154 | ||
| 1158 | if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) { | 1155 | if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) { |
| @@ -1346,20 +1343,10 @@ private: | |||
| 1346 | target = {OpAccessChain(t_prv_float, local_memory, address), Type::Float}; | 1343 | target = {OpAccessChain(t_prv_float, local_memory, address), Type::Float}; |
| 1347 | 1344 | ||
| 1348 | } else if (const auto smem = std::get_if<SmemNode>(&*dest)) { | 1345 | } else if (const auto smem = std::get_if<SmemNode>(&*dest)) { |
| 1349 | ASSERT(stage == ShaderType::Compute); | 1346 | target = {GetSharedMemoryPointer(*smem), Type::Uint}; |
| 1350 | Id address = AsUint(Visit(smem->GetAddress())); | ||
| 1351 | address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U)); | ||
| 1352 | target = {OpAccessChain(t_smem_uint, shared_memory, address), Type::Uint}; | ||
| 1353 | 1347 | ||
| 1354 | } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { | 1348 | } else if (const auto gmem = std::get_if<GmemNode>(&*dest)) { |
| 1355 | const Id real = AsUint(Visit(gmem->GetRealAddress())); | 1349 | target = {GetGlobalMemoryPointer(*gmem), Type::Uint}; |
| 1356 | const Id base = AsUint(Visit(gmem->GetBaseAddress())); | ||
| 1357 | const Id diff = OpISub(t_uint, real, base); | ||
| 1358 | const Id offset = OpShiftRightLogical(t_uint, diff, Constant(t_uint, 2)); | ||
| 1359 | |||
| 1360 | const Id gmem_buffer = global_buffers.at(gmem->GetDescriptor()); | ||
| 1361 | target = {OpAccessChain(t_gmem_float, gmem_buffer, Constant(t_uint, 0), offset), | ||
| 1362 | Type::Float}; | ||
| 1363 | 1350 | ||
| 1364 | } else if (const auto cv = std::get_if<CustomVarNode>(&*dest)) { | 1351 | } else if (const auto cv = std::get_if<CustomVarNode>(&*dest)) { |
| 1365 | target = {custom_variables.at(cv->GetIndex()), Type::Float}; | 1352 | target = {custom_variables.at(cv->GetIndex()), Type::Float}; |
| @@ -1814,11 +1801,16 @@ private: | |||
| 1814 | return {}; | 1801 | return {}; |
| 1815 | } | 1802 | } |
| 1816 | 1803 | ||
| 1817 | Expression UAtomicAdd(Operation operation) { | 1804 | Expression AtomicAdd(Operation operation) { |
| 1818 | const auto& smem = std::get<SmemNode>(*operation[0]); | 1805 | Id pointer; |
| 1819 | Id address = AsUint(Visit(smem.GetAddress())); | 1806 | if (const auto smem = std::get_if<SmemNode>(&*operation[0])) { |
| 1820 | address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U)); | 1807 | pointer = GetSharedMemoryPointer(*smem); |
| 1821 | const Id pointer = OpAccessChain(t_smem_uint, shared_memory, address); | 1808 | } else if (const auto gmem = std::get_if<GmemNode>(&*operation[0])) { |
| 1809 | pointer = GetGlobalMemoryPointer(*gmem); | ||
| 1810 | } else { | ||
| 1811 | UNREACHABLE(); | ||
| 1812 | return {Constant(t_uint, 0), Type::Uint}; | ||
| 1813 | } | ||
| 1822 | 1814 | ||
| 1823 | const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); | 1815 | const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); |
| 1824 | const Id semantics = Constant(t_uint, 0U); | 1816 | const Id semantics = Constant(t_uint, 0U); |
| @@ -1907,19 +1899,14 @@ private: | |||
| 1907 | // rendertargets/components are skipped in the register assignment. | 1899 | // rendertargets/components are skipped in the register assignment. |
| 1908 | u32 current_reg = 0; | 1900 | u32 current_reg = 0; |
| 1909 | for (u32 rt = 0; rt < Maxwell::NumRenderTargets; ++rt) { | 1901 | for (u32 rt = 0; rt < Maxwell::NumRenderTargets; ++rt) { |
| 1910 | if (!specialization.enabled_rendertargets[rt]) { | ||
| 1911 | // Skip rendertargets that are not enabled | ||
| 1912 | continue; | ||
| 1913 | } | ||
| 1914 | // TODO(Subv): Figure out how dual-source blending is configured in the Switch. | 1902 | // TODO(Subv): Figure out how dual-source blending is configured in the Switch. |
| 1915 | for (u32 component = 0; component < 4; ++component) { | 1903 | for (u32 component = 0; component < 4; ++component) { |
| 1916 | const Id pointer = AccessElement(t_out_float, frag_colors.at(rt), component); | 1904 | if (!header.ps.IsColorComponentOutputEnabled(rt, component)) { |
| 1917 | if (header.ps.IsColorComponentOutputEnabled(rt, component)) { | 1905 | continue; |
| 1918 | OpStore(pointer, SafeGetRegister(current_reg)); | ||
| 1919 | ++current_reg; | ||
| 1920 | } else { | ||
| 1921 | OpStore(pointer, component == 3 ? v_float_one : v_float_zero); | ||
| 1922 | } | 1906 | } |
| 1907 | const Id pointer = AccessElement(t_out_float, frag_colors[rt], component); | ||
| 1908 | OpStore(pointer, SafeGetRegister(current_reg)); | ||
| 1909 | ++current_reg; | ||
| 1923 | } | 1910 | } |
| 1924 | } | 1911 | } |
| 1925 | if (header.ps.omap.depth) { | 1912 | if (header.ps.omap.depth) { |
| @@ -2258,6 +2245,22 @@ private: | |||
| 2258 | return {}; | 2245 | return {}; |
| 2259 | } | 2246 | } |
| 2260 | 2247 | ||
| 2248 | Id GetGlobalMemoryPointer(const GmemNode& gmem) { | ||
| 2249 | const Id real = AsUint(Visit(gmem.GetRealAddress())); | ||
| 2250 | const Id base = AsUint(Visit(gmem.GetBaseAddress())); | ||
| 2251 | const Id diff = OpISub(t_uint, real, base); | ||
| 2252 | const Id offset = OpShiftRightLogical(t_uint, diff, Constant(t_uint, 2)); | ||
| 2253 | const Id buffer = global_buffers.at(gmem.GetDescriptor()); | ||
| 2254 | return OpAccessChain(t_gmem_uint, buffer, Constant(t_uint, 0), offset); | ||
| 2255 | } | ||
| 2256 | |||
| 2257 | Id GetSharedMemoryPointer(const SmemNode& smem) { | ||
| 2258 | ASSERT(stage == ShaderType::Compute); | ||
| 2259 | Id address = AsUint(Visit(smem.GetAddress())); | ||
| 2260 | address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U)); | ||
| 2261 | return OpAccessChain(t_smem_uint, shared_memory, address); | ||
| 2262 | } | ||
| 2263 | |||
| 2261 | static constexpr std::array operation_decompilers = { | 2264 | static constexpr std::array operation_decompilers = { |
| 2262 | &SPIRVDecompiler::Assign, | 2265 | &SPIRVDecompiler::Assign, |
| 2263 | 2266 | ||
| @@ -2404,7 +2407,7 @@ private: | |||
| 2404 | &SPIRVDecompiler::AtomicImageXor, | 2407 | &SPIRVDecompiler::AtomicImageXor, |
| 2405 | &SPIRVDecompiler::AtomicImageExchange, | 2408 | &SPIRVDecompiler::AtomicImageExchange, |
| 2406 | 2409 | ||
| 2407 | &SPIRVDecompiler::UAtomicAdd, | 2410 | &SPIRVDecompiler::AtomicAdd, |
| 2408 | 2411 | ||
| 2409 | &SPIRVDecompiler::Branch, | 2412 | &SPIRVDecompiler::Branch, |
| 2410 | &SPIRVDecompiler::BranchIndirect, | 2413 | &SPIRVDecompiler::BranchIndirect, |
| @@ -2500,9 +2503,9 @@ private: | |||
| 2500 | 2503 | ||
| 2501 | Id t_smem_uint{}; | 2504 | Id t_smem_uint{}; |
| 2502 | 2505 | ||
| 2503 | const Id t_gmem_float = TypePointer(spv::StorageClass::StorageBuffer, t_float); | 2506 | const Id t_gmem_uint = TypePointer(spv::StorageClass::StorageBuffer, t_uint); |
| 2504 | const Id t_gmem_array = | 2507 | const Id t_gmem_array = |
| 2505 | Name(Decorate(TypeRuntimeArray(t_float), spv::Decoration::ArrayStride, 4U), "GmemArray"); | 2508 | Name(Decorate(TypeRuntimeArray(t_uint), spv::Decoration::ArrayStride, 4U), "GmemArray"); |
| 2506 | const Id t_gmem_struct = MemberDecorate( | 2509 | const Id t_gmem_struct = MemberDecorate( |
| 2507 | Decorate(TypeStruct(t_gmem_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0); | 2510 | Decorate(TypeStruct(t_gmem_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0); |
| 2508 | const Id t_gmem_ssbo = TypePointer(spv::StorageClass::StorageBuffer, t_gmem_struct); | 2511 | const Id t_gmem_ssbo = TypePointer(spv::StorageClass::StorageBuffer, t_gmem_struct); |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.h b/src/video_core/renderer_vulkan/vk_shader_decompiler.h index 10794be1c..f5dc14d9e 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.h +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.h | |||
| @@ -102,9 +102,6 @@ struct Specialization final { | |||
| 102 | Maxwell::TessellationSpacing spacing{}; | 102 | Maxwell::TessellationSpacing spacing{}; |
| 103 | bool clockwise{}; | 103 | bool clockwise{}; |
| 104 | } tessellation; | 104 | } tessellation; |
| 105 | |||
| 106 | // Fragment specific | ||
| 107 | std::bitset<8> enabled_rendertargets; | ||
| 108 | }; | 105 | }; |
| 109 | // Old gcc versions don't consider this trivially copyable. | 106 | // Old gcc versions don't consider this trivially copyable. |
| 110 | // static_assert(std::is_trivially_copyable_v<Specialization>); | 107 | // static_assert(std::is_trivially_copyable_v<Specialization>); |
diff --git a/src/video_core/shader/decode/memory.cpp b/src/video_core/shader/decode/memory.cpp index 7591a715f..b5fbc4d58 100644 --- a/src/video_core/shader/decode/memory.cpp +++ b/src/video_core/shader/decode/memory.cpp | |||
| @@ -19,9 +19,12 @@ namespace VideoCommon::Shader { | |||
| 19 | using Tegra::Shader::AtomicOp; | 19 | using Tegra::Shader::AtomicOp; |
| 20 | using Tegra::Shader::AtomicType; | 20 | using Tegra::Shader::AtomicType; |
| 21 | using Tegra::Shader::Attribute; | 21 | using Tegra::Shader::Attribute; |
| 22 | using Tegra::Shader::GlobalAtomicOp; | ||
| 23 | using Tegra::Shader::GlobalAtomicType; | ||
| 22 | using Tegra::Shader::Instruction; | 24 | using Tegra::Shader::Instruction; |
| 23 | using Tegra::Shader::OpCode; | 25 | using Tegra::Shader::OpCode; |
| 24 | using Tegra::Shader::Register; | 26 | using Tegra::Shader::Register; |
| 27 | using Tegra::Shader::StoreType; | ||
| 25 | 28 | ||
| 26 | namespace { | 29 | namespace { |
| 27 | 30 | ||
| @@ -61,6 +64,27 @@ u32 GetMemorySize(Tegra::Shader::UniformType uniform_type) { | |||
| 61 | } | 64 | } |
| 62 | } | 65 | } |
| 63 | 66 | ||
| 67 | Node ExtractUnaligned(Node value, Node address, u32 mask, u32 size) { | ||
| 68 | Node offset = Operation(OperationCode::UBitwiseAnd, address, Immediate(mask)); | ||
| 69 | offset = Operation(OperationCode::ULogicalShiftLeft, std::move(offset), Immediate(3)); | ||
| 70 | return Operation(OperationCode::UBitfieldExtract, std::move(value), std::move(offset), | ||
| 71 | Immediate(size)); | ||
| 72 | } | ||
| 73 | |||
| 74 | Node InsertUnaligned(Node dest, Node value, Node address, u32 mask, u32 size) { | ||
| 75 | Node offset = Operation(OperationCode::UBitwiseAnd, std::move(address), Immediate(mask)); | ||
| 76 | offset = Operation(OperationCode::ULogicalShiftLeft, std::move(offset), Immediate(3)); | ||
| 77 | return Operation(OperationCode::UBitfieldInsert, std::move(dest), std::move(value), | ||
| 78 | std::move(offset), Immediate(size)); | ||
| 79 | } | ||
| 80 | |||
| 81 | Node Sign16Extend(Node value) { | ||
| 82 | Node sign = Operation(OperationCode::UBitwiseAnd, value, Immediate(1U << 15)); | ||
| 83 | Node is_sign = Operation(OperationCode::LogicalUEqual, std::move(sign), Immediate(1U << 15)); | ||
| 84 | Node extend = Operation(OperationCode::Select, is_sign, Immediate(0xFFFF0000), Immediate(0)); | ||
| 85 | return Operation(OperationCode::UBitwiseOr, std::move(value), std::move(extend)); | ||
| 86 | } | ||
| 87 | |||
| 64 | } // Anonymous namespace | 88 | } // Anonymous namespace |
| 65 | 89 | ||
| 66 | u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | 90 | u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { |
| @@ -136,26 +160,31 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 136 | LOG_DEBUG(HW_GPU, "LD_L cache management mode: {}", static_cast<u64>(instr.ld_l.unknown)); | 160 | LOG_DEBUG(HW_GPU, "LD_L cache management mode: {}", static_cast<u64>(instr.ld_l.unknown)); |
| 137 | [[fallthrough]]; | 161 | [[fallthrough]]; |
| 138 | case OpCode::Id::LD_S: { | 162 | case OpCode::Id::LD_S: { |
| 139 | const auto GetMemory = [&](s32 offset) { | 163 | const auto GetAddress = [&](s32 offset) { |
| 140 | ASSERT(offset % 4 == 0); | 164 | ASSERT(offset % 4 == 0); |
| 141 | const Node immediate_offset = Immediate(static_cast<s32>(instr.smem_imm) + offset); | 165 | const Node immediate_offset = Immediate(static_cast<s32>(instr.smem_imm) + offset); |
| 142 | const Node address = Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8), | 166 | return Operation(OperationCode::IAdd, GetRegister(instr.gpr8), immediate_offset); |
| 143 | immediate_offset); | 167 | }; |
| 144 | return opcode->get().GetId() == OpCode::Id::LD_S ? GetSharedMemory(address) | 168 | const auto GetMemory = [&](s32 offset) { |
| 145 | : GetLocalMemory(address); | 169 | return opcode->get().GetId() == OpCode::Id::LD_S ? GetSharedMemory(GetAddress(offset)) |
| 170 | : GetLocalMemory(GetAddress(offset)); | ||
| 146 | }; | 171 | }; |
| 147 | 172 | ||
| 148 | switch (instr.ldst_sl.type.Value()) { | 173 | switch (instr.ldst_sl.type.Value()) { |
| 149 | case Tegra::Shader::StoreType::Bits32: | 174 | case StoreType::Signed16: |
| 150 | case Tegra::Shader::StoreType::Bits64: | 175 | SetRegister(bb, instr.gpr0, |
| 151 | case Tegra::Shader::StoreType::Bits128: { | 176 | Sign16Extend(ExtractUnaligned(GetMemory(0), GetAddress(0), 0b10, 16))); |
| 152 | const u32 count = [&]() { | 177 | break; |
| 178 | case StoreType::Bits32: | ||
| 179 | case StoreType::Bits64: | ||
| 180 | case StoreType::Bits128: { | ||
| 181 | const u32 count = [&] { | ||
| 153 | switch (instr.ldst_sl.type.Value()) { | 182 | switch (instr.ldst_sl.type.Value()) { |
| 154 | case Tegra::Shader::StoreType::Bits32: | 183 | case StoreType::Bits32: |
| 155 | return 1; | 184 | return 1; |
| 156 | case Tegra::Shader::StoreType::Bits64: | 185 | case StoreType::Bits64: |
| 157 | return 2; | 186 | return 2; |
| 158 | case Tegra::Shader::StoreType::Bits128: | 187 | case StoreType::Bits128: |
| 159 | return 4; | 188 | return 4; |
| 160 | default: | 189 | default: |
| 161 | UNREACHABLE(); | 190 | UNREACHABLE(); |
| @@ -212,12 +241,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 212 | // To handle unaligned loads get the bytes used to dereference global memory and extract | 241 | // To handle unaligned loads get the bytes used to dereference global memory and extract |
| 213 | // those bytes from the loaded u32. | 242 | // those bytes from the loaded u32. |
| 214 | if (IsUnaligned(type)) { | 243 | if (IsUnaligned(type)) { |
| 215 | Node mask = Immediate(GetUnalignedMask(type)); | 244 | gmem = ExtractUnaligned(gmem, real_address, GetUnalignedMask(type), size); |
| 216 | Node offset = Operation(OperationCode::UBitwiseAnd, real_address, std::move(mask)); | ||
| 217 | offset = Operation(OperationCode::ULogicalShiftLeft, offset, Immediate(3)); | ||
| 218 | |||
| 219 | gmem = Operation(OperationCode::UBitfieldExtract, std::move(gmem), | ||
| 220 | std::move(offset), Immediate(size)); | ||
| 221 | } | 245 | } |
| 222 | 246 | ||
| 223 | SetTemporary(bb, i, gmem); | 247 | SetTemporary(bb, i, gmem); |
| @@ -269,21 +293,28 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 269 | return Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8), immediate); | 293 | return Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8), immediate); |
| 270 | }; | 294 | }; |
| 271 | 295 | ||
| 272 | const auto set_memory = opcode->get().GetId() == OpCode::Id::ST_L | 296 | const bool is_local = opcode->get().GetId() == OpCode::Id::ST_L; |
| 273 | ? &ShaderIR::SetLocalMemory | 297 | const auto set_memory = is_local ? &ShaderIR::SetLocalMemory : &ShaderIR::SetSharedMemory; |
| 274 | : &ShaderIR::SetSharedMemory; | 298 | const auto get_memory = is_local ? &ShaderIR::GetLocalMemory : &ShaderIR::GetSharedMemory; |
| 275 | 299 | ||
| 276 | switch (instr.ldst_sl.type.Value()) { | 300 | switch (instr.ldst_sl.type.Value()) { |
| 277 | case Tegra::Shader::StoreType::Bits128: | 301 | case StoreType::Bits128: |
| 278 | (this->*set_memory)(bb, GetAddress(12), GetRegister(instr.gpr0.Value() + 3)); | 302 | (this->*set_memory)(bb, GetAddress(12), GetRegister(instr.gpr0.Value() + 3)); |
| 279 | (this->*set_memory)(bb, GetAddress(8), GetRegister(instr.gpr0.Value() + 2)); | 303 | (this->*set_memory)(bb, GetAddress(8), GetRegister(instr.gpr0.Value() + 2)); |
| 280 | [[fallthrough]]; | 304 | [[fallthrough]]; |
| 281 | case Tegra::Shader::StoreType::Bits64: | 305 | case StoreType::Bits64: |
| 282 | (this->*set_memory)(bb, GetAddress(4), GetRegister(instr.gpr0.Value() + 1)); | 306 | (this->*set_memory)(bb, GetAddress(4), GetRegister(instr.gpr0.Value() + 1)); |
| 283 | [[fallthrough]]; | 307 | [[fallthrough]]; |
| 284 | case Tegra::Shader::StoreType::Bits32: | 308 | case StoreType::Bits32: |
| 285 | (this->*set_memory)(bb, GetAddress(0), GetRegister(instr.gpr0)); | 309 | (this->*set_memory)(bb, GetAddress(0), GetRegister(instr.gpr0)); |
| 286 | break; | 310 | break; |
| 311 | case StoreType::Signed16: { | ||
| 312 | Node address = GetAddress(0); | ||
| 313 | Node memory = (this->*get_memory)(address); | ||
| 314 | (this->*set_memory)( | ||
| 315 | bb, address, InsertUnaligned(memory, GetRegister(instr.gpr0), address, 0b10, 16)); | ||
| 316 | break; | ||
| 317 | } | ||
| 287 | default: | 318 | default: |
| 288 | UNIMPLEMENTED_MSG("{} unhandled type: {}", opcode->get().GetName(), | 319 | UNIMPLEMENTED_MSG("{} unhandled type: {}", opcode->get().GetName(), |
| 289 | static_cast<u32>(instr.ldst_sl.type.Value())); | 320 | static_cast<u32>(instr.ldst_sl.type.Value())); |
| @@ -323,18 +354,32 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 323 | Node value = GetRegister(instr.gpr0.Value() + i); | 354 | Node value = GetRegister(instr.gpr0.Value() + i); |
| 324 | 355 | ||
| 325 | if (IsUnaligned(type)) { | 356 | if (IsUnaligned(type)) { |
| 326 | Node mask = Immediate(GetUnalignedMask(type)); | 357 | const u32 mask = GetUnalignedMask(type); |
| 327 | Node offset = Operation(OperationCode::UBitwiseAnd, real_address, std::move(mask)); | 358 | value = InsertUnaligned(gmem, std::move(value), real_address, mask, size); |
| 328 | offset = Operation(OperationCode::ULogicalShiftLeft, offset, Immediate(3)); | ||
| 329 | |||
| 330 | value = Operation(OperationCode::UBitfieldInsert, gmem, std::move(value), offset, | ||
| 331 | Immediate(size)); | ||
| 332 | } | 359 | } |
| 333 | 360 | ||
| 334 | bb.push_back(Operation(OperationCode::Assign, gmem, value)); | 361 | bb.push_back(Operation(OperationCode::Assign, gmem, value)); |
| 335 | } | 362 | } |
| 336 | break; | 363 | break; |
| 337 | } | 364 | } |
| 365 | case OpCode::Id::ATOM: { | ||
| 366 | UNIMPLEMENTED_IF_MSG(instr.atom.operation != GlobalAtomicOp::Add, "operation={}", | ||
| 367 | static_cast<int>(instr.atom.operation.Value())); | ||
| 368 | UNIMPLEMENTED_IF_MSG(instr.atom.type != GlobalAtomicType::S32, "type={}", | ||
| 369 | static_cast<int>(instr.atom.type.Value())); | ||
| 370 | |||
| 371 | const auto [real_address, base_address, descriptor] = | ||
| 372 | TrackGlobalMemory(bb, instr, true, true); | ||
| 373 | if (!real_address || !base_address) { | ||
| 374 | // Tracking failed, skip atomic. | ||
| 375 | break; | ||
| 376 | } | ||
| 377 | |||
| 378 | Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor); | ||
| 379 | Node value = Operation(OperationCode::AtomicAdd, std::move(gmem), GetRegister(instr.gpr20)); | ||
| 380 | SetRegister(bb, instr.gpr0, std::move(value)); | ||
| 381 | break; | ||
| 382 | } | ||
| 338 | case OpCode::Id::ATOMS: { | 383 | case OpCode::Id::ATOMS: { |
| 339 | UNIMPLEMENTED_IF_MSG(instr.atoms.operation != AtomicOp::Add, "operation={}", | 384 | UNIMPLEMENTED_IF_MSG(instr.atoms.operation != AtomicOp::Add, "operation={}", |
| 340 | static_cast<int>(instr.atoms.operation.Value())); | 385 | static_cast<int>(instr.atoms.operation.Value())); |
| @@ -348,7 +393,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { | |||
| 348 | Node memory = GetSharedMemory(std::move(address)); | 393 | Node memory = GetSharedMemory(std::move(address)); |
| 349 | Node data = GetRegister(instr.gpr20); | 394 | Node data = GetRegister(instr.gpr20); |
| 350 | 395 | ||
| 351 | Node value = Operation(OperationCode::UAtomicAdd, std::move(memory), std::move(data)); | 396 | Node value = Operation(OperationCode::AtomicAdd, std::move(memory), std::move(data)); |
| 352 | SetRegister(bb, instr.gpr0, std::move(value)); | 397 | SetRegister(bb, instr.gpr0, std::move(value)); |
| 353 | break; | 398 | break; |
| 354 | } | 399 | } |
diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index 53a551d27..5f83403db 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h | |||
| @@ -162,7 +162,7 @@ enum class OperationCode { | |||
| 162 | AtomicImageXor, /// (MetaImage, int[N] coords) -> void | 162 | AtomicImageXor, /// (MetaImage, int[N] coords) -> void |
| 163 | AtomicImageExchange, /// (MetaImage, int[N] coords) -> void | 163 | AtomicImageExchange, /// (MetaImage, int[N] coords) -> void |
| 164 | 164 | ||
| 165 | UAtomicAdd, /// (smem, uint) -> uint | 165 | AtomicAdd, /// (memory, {u}int) -> {u}int |
| 166 | 166 | ||
| 167 | Branch, /// (uint branch_target) -> void | 167 | Branch, /// (uint branch_target) -> void |
| 168 | BranchIndirect, /// (uint branch_target) -> void | 168 | BranchIndirect, /// (uint branch_target) -> void |
diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp index 829268b4c..84469b7ba 100644 --- a/src/video_core/texture_cache/surface_base.cpp +++ b/src/video_core/texture_cache/surface_base.cpp | |||
| @@ -135,7 +135,7 @@ std::vector<CopyParams> SurfaceBaseImpl::BreakDownLayered(const SurfaceParams& i | |||
| 135 | for (u32 level = 0; level < mipmaps; level++) { | 135 | for (u32 level = 0; level < mipmaps; level++) { |
| 136 | const u32 width = SurfaceParams::IntersectWidth(params, in_params, level, level); | 136 | const u32 width = SurfaceParams::IntersectWidth(params, in_params, level, level); |
| 137 | const u32 height = SurfaceParams::IntersectHeight(params, in_params, level, level); | 137 | const u32 height = SurfaceParams::IntersectHeight(params, in_params, level, level); |
| 138 | result.emplace_back(width, height, layer, level); | 138 | result.emplace_back(0, 0, layer, 0, 0, layer, level, level, width, height, 1); |
| 139 | } | 139 | } |
| 140 | } | 140 | } |
| 141 | return result; | 141 | return result; |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 11ae1e66e..a3fb91d29 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -36,9 +36,6 @@ add_executable(yuzu | |||
| 36 | configuration/configure_filesystem.cpp | 36 | configuration/configure_filesystem.cpp |
| 37 | configuration/configure_filesystem.h | 37 | configuration/configure_filesystem.h |
| 38 | configuration/configure_filesystem.ui | 38 | configuration/configure_filesystem.ui |
| 39 | configuration/configure_gamelist.cpp | ||
| 40 | configuration/configure_gamelist.h | ||
| 41 | configuration/configure_gamelist.ui | ||
| 42 | configuration/configure_general.cpp | 39 | configuration/configure_general.cpp |
| 43 | configuration/configure_general.h | 40 | configuration/configure_general.h |
| 44 | configuration/configure_general.ui | 41 | configuration/configure_general.ui |
| @@ -75,6 +72,9 @@ add_executable(yuzu | |||
| 75 | configuration/configure_touchscreen_advanced.cpp | 72 | configuration/configure_touchscreen_advanced.cpp |
| 76 | configuration/configure_touchscreen_advanced.h | 73 | configuration/configure_touchscreen_advanced.h |
| 77 | configuration/configure_touchscreen_advanced.ui | 74 | configuration/configure_touchscreen_advanced.ui |
| 75 | configuration/configure_ui.cpp | ||
| 76 | configuration/configure_ui.h | ||
| 77 | configuration/configure_ui.ui | ||
| 78 | configuration/configure_web.cpp | 78 | configuration/configure_web.cpp |
| 79 | configuration/configure_web.h | 79 | configuration/configure_web.h |
| 80 | configuration/configure_web.ui | 80 | configuration/configure_web.ui |
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index 372427ae2..67b990f1a 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui | |||
| @@ -48,7 +48,7 @@ | |||
| 48 | <string>General</string> | 48 | <string>General</string> |
| 49 | </attribute> | 49 | </attribute> |
| 50 | </widget> | 50 | </widget> |
| 51 | <widget class="ConfigureGameList" name="gameListTab"> | 51 | <widget class="ConfigureUi" name="uiTab"> |
| 52 | <attribute name="title"> | 52 | <attribute name="title"> |
| 53 | <string>Game List</string> | 53 | <string>Game List</string> |
| 54 | </attribute> | 54 | </attribute> |
| @@ -166,9 +166,9 @@ | |||
| 166 | <container>1</container> | 166 | <container>1</container> |
| 167 | </customwidget> | 167 | </customwidget> |
| 168 | <customwidget> | 168 | <customwidget> |
| 169 | <class>ConfigureGameList</class> | 169 | <class>ConfigureUi</class> |
| 170 | <extends>QWidget</extends> | 170 | <extends>QWidget</extends> |
| 171 | <header>configuration/configure_gamelist.h</header> | 171 | <header>configuration/configure_ui.h</header> |
| 172 | <container>1</container> | 172 | <container>1</container> |
| 173 | </customwidget> | 173 | </customwidget> |
| 174 | <customwidget> | 174 | <customwidget> |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 8497eaa14..db3b19352 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -34,7 +34,7 @@ void ConfigureDialog::SetConfiguration() {} | |||
| 34 | 34 | ||
| 35 | void ConfigureDialog::ApplyConfiguration() { | 35 | void ConfigureDialog::ApplyConfiguration() { |
| 36 | ui->generalTab->ApplyConfiguration(); | 36 | ui->generalTab->ApplyConfiguration(); |
| 37 | ui->gameListTab->ApplyConfiguration(); | 37 | ui->uiTab->ApplyConfiguration(); |
| 38 | ui->systemTab->ApplyConfiguration(); | 38 | ui->systemTab->ApplyConfiguration(); |
| 39 | ui->profileManagerTab->ApplyConfiguration(); | 39 | ui->profileManagerTab->ApplyConfiguration(); |
| 40 | ui->filesystemTab->applyConfiguration(); | 40 | ui->filesystemTab->applyConfiguration(); |
| @@ -74,7 +74,7 @@ Q_DECLARE_METATYPE(QList<QWidget*>); | |||
| 74 | 74 | ||
| 75 | void ConfigureDialog::PopulateSelectionList() { | 75 | void ConfigureDialog::PopulateSelectionList() { |
| 76 | const std::array<std::pair<QString, QList<QWidget*>>, 5> items{ | 76 | const std::array<std::pair<QString, QList<QWidget*>>, 5> items{ |
| 77 | {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->gameListTab}}, | 77 | {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->uiTab}}, |
| 78 | {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, | 78 | {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, |
| 79 | {tr("Graphics"), {ui->graphicsTab}}, | 79 | {tr("Graphics"), {ui->graphicsTab}}, |
| 80 | {tr("Audio"), {ui->audioTab}}, | 80 | {tr("Audio"), {ui->audioTab}}, |
| @@ -108,7 +108,7 @@ void ConfigureDialog::UpdateVisibleTabs() { | |||
| 108 | {ui->audioTab, tr("Audio")}, | 108 | {ui->audioTab, tr("Audio")}, |
| 109 | {ui->debugTab, tr("Debug")}, | 109 | {ui->debugTab, tr("Debug")}, |
| 110 | {ui->webTab, tr("Web")}, | 110 | {ui->webTab, tr("Web")}, |
| 111 | {ui->gameListTab, tr("Game List")}, | 111 | {ui->uiTab, tr("UI")}, |
| 112 | {ui->filesystemTab, tr("Filesystem")}, | 112 | {ui->filesystemTab, tr("Filesystem")}, |
| 113 | {ui->serviceTab, tr("Services")}, | 113 | {ui->serviceTab, tr("Services")}, |
| 114 | }; | 114 | }; |
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 34e1d7fea..5ef927114 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp | |||
| @@ -15,11 +15,6 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent) | |||
| 15 | 15 | ||
| 16 | ui->setupUi(this); | 16 | ui->setupUi(this); |
| 17 | 17 | ||
| 18 | for (const auto& theme : UISettings::themes) { | ||
| 19 | ui->theme_combobox->addItem(QString::fromUtf8(theme.first), | ||
| 20 | QString::fromUtf8(theme.second)); | ||
| 21 | } | ||
| 22 | |||
| 23 | SetConfiguration(); | 18 | SetConfiguration(); |
| 24 | 19 | ||
| 25 | connect(ui->toggle_frame_limit, &QCheckBox::toggled, ui->frame_limit, &QSpinBox::setEnabled); | 20 | connect(ui->toggle_frame_limit, &QCheckBox::toggled, ui->frame_limit, &QSpinBox::setEnabled); |
| @@ -30,7 +25,6 @@ ConfigureGeneral::~ConfigureGeneral() = default; | |||
| 30 | void ConfigureGeneral::SetConfiguration() { | 25 | void ConfigureGeneral::SetConfiguration() { |
| 31 | ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); | 26 | ui->toggle_check_exit->setChecked(UISettings::values.confirm_before_closing); |
| 32 | ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot); | 27 | ui->toggle_user_on_boot->setChecked(UISettings::values.select_user_on_boot); |
| 33 | ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); | ||
| 34 | ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background); | 28 | ui->toggle_background_pause->setChecked(UISettings::values.pause_when_in_background); |
| 35 | 29 | ||
| 36 | ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); | 30 | ui->toggle_frame_limit->setChecked(Settings::values.use_frame_limit); |
| @@ -41,8 +35,6 @@ void ConfigureGeneral::SetConfiguration() { | |||
| 41 | void ConfigureGeneral::ApplyConfiguration() { | 35 | void ConfigureGeneral::ApplyConfiguration() { |
| 42 | UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); | 36 | UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); |
| 43 | UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); | 37 | UISettings::values.select_user_on_boot = ui->toggle_user_on_boot->isChecked(); |
| 44 | UISettings::values.theme = | ||
| 45 | ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); | ||
| 46 | UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); | 38 | UISettings::values.pause_when_in_background = ui->toggle_background_pause->isChecked(); |
| 47 | 39 | ||
| 48 | Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); | 40 | Settings::values.use_frame_limit = ui->toggle_frame_limit->isChecked(); |
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index 26b3486ff..857119bb3 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui | |||
| @@ -65,39 +65,12 @@ | |||
| 65 | </property> | 65 | </property> |
| 66 | </widget> | 66 | </widget> |
| 67 | </item> | 67 | </item> |
| 68 | <item> | ||
| 69 | <widget class="QCheckBox" name="toggle_background_pause"> | ||
| 70 | <property name="text"> | ||
| 71 | <string>Pause emulation when in background</string> | ||
| 72 | </property> | ||
| 73 | </widget> | ||
| 74 | </item> | ||
| 75 | </layout> | ||
| 76 | </item> | ||
| 77 | </layout> | ||
| 78 | </widget> | ||
| 79 | </item> | ||
| 80 | <item> | ||
| 81 | <widget class="QGroupBox" name="theme_group_box"> | ||
| 82 | <property name="title"> | ||
| 83 | <string>Theme</string> | ||
| 84 | </property> | ||
| 85 | <layout class="QHBoxLayout" name="theme_qhbox_layout"> | ||
| 86 | <item> | ||
| 87 | <layout class="QVBoxLayout" name="theme_qvbox_layout"> | ||
| 88 | <item> | 68 | <item> |
| 89 | <layout class="QHBoxLayout" name="theme_qhbox_layout_2"> | 69 | <widget class="QCheckBox" name="toggle_background_pause"> |
| 90 | <item> | 70 | <property name="text"> |
| 91 | <widget class="QLabel" name="theme_label"> | 71 | <string>Pause emulation when in background</string> |
| 92 | <property name="text"> | 72 | </property> |
| 93 | <string>Theme:</string> | 73 | </widget> |
| 94 | </property> | ||
| 95 | </widget> | ||
| 96 | </item> | ||
| 97 | <item> | ||
| 98 | <widget class="QComboBox" name="theme_combobox"/> | ||
| 99 | </item> | ||
| 100 | </layout> | ||
| 101 | </item> | 74 | </item> |
| 102 | </layout> | 75 | </layout> |
| 103 | </item> | 76 | </item> |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 67c9a7c6d..96dec50e2 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -236,6 +236,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 236 | widget->setVisible(false); | 236 | widget->setVisible(false); |
| 237 | 237 | ||
| 238 | analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog}; | 238 | analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog}; |
| 239 | analog_map_deadzone = {ui->sliderLStickDeadzone, ui->sliderRStickDeadzone}; | ||
| 240 | analog_map_deadzone_label = {ui->labelLStickDeadzone, ui->labelRStickDeadzone}; | ||
| 239 | 241 | ||
| 240 | for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { | 242 | for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) { |
| 241 | auto* const button = button_map[button_id]; | 243 | auto* const button = button_map[button_id]; |
| @@ -326,6 +328,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 326 | InputCommon::Polling::DeviceType::Analog); | 328 | InputCommon::Polling::DeviceType::Analog); |
| 327 | } | 329 | } |
| 328 | }); | 330 | }); |
| 331 | connect(analog_map_deadzone[analog_id], &QSlider::valueChanged, [=] { | ||
| 332 | const float deadzone = analog_map_deadzone[analog_id]->value() / 100.0f; | ||
| 333 | analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1").arg(deadzone)); | ||
| 334 | analogs_param[analog_id].Set("deadzone", deadzone); | ||
| 335 | }); | ||
| 329 | } | 336 | } |
| 330 | 337 | ||
| 331 | connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); | 338 | connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); |
| @@ -484,7 +491,7 @@ void ConfigureInputPlayer::ClearAll() { | |||
| 484 | continue; | 491 | continue; |
| 485 | } | 492 | } |
| 486 | 493 | ||
| 487 | analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); | 494 | analogs_param[analog_id].Clear(); |
| 488 | } | 495 | } |
| 489 | } | 496 | } |
| 490 | 497 | ||
| @@ -508,6 +515,23 @@ void ConfigureInputPlayer::UpdateButtonLabels() { | |||
| 508 | AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id])); | 515 | AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id])); |
| 509 | } | 516 | } |
| 510 | analog_map_stick[analog_id]->setText(tr("Set Analog Stick")); | 517 | analog_map_stick[analog_id]->setText(tr("Set Analog Stick")); |
| 518 | |||
| 519 | auto& param = analogs_param[analog_id]; | ||
| 520 | auto* const analog_deadzone_slider = analog_map_deadzone[analog_id]; | ||
| 521 | auto* const analog_deadzone_label = analog_map_deadzone_label[analog_id]; | ||
| 522 | |||
| 523 | if (param.Has("engine") && param.Get("engine", "") == "sdl") { | ||
| 524 | if (!param.Has("deadzone")) { | ||
| 525 | param.Set("deadzone", 0.1f); | ||
| 526 | } | ||
| 527 | |||
| 528 | analog_deadzone_slider->setValue(static_cast<int>(param.Get("deadzone", 0.1f) * 100)); | ||
| 529 | analog_deadzone_slider->setVisible(true); | ||
| 530 | analog_deadzone_label->setVisible(true); | ||
| 531 | } else { | ||
| 532 | analog_deadzone_slider->setVisible(false); | ||
| 533 | analog_deadzone_label->setVisible(false); | ||
| 534 | } | ||
| 511 | } | 535 | } |
| 512 | } | 536 | } |
| 513 | 537 | ||
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index c66027651..045704e47 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h | |||
| @@ -97,6 +97,8 @@ private: | |||
| 97 | /// Analog inputs are also represented each with a single button, used to configure with an | 97 | /// Analog inputs are also represented each with a single button, used to configure with an |
| 98 | /// actual analog stick | 98 | /// actual analog stick |
| 99 | std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick; | 99 | std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick; |
| 100 | std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone; | ||
| 101 | std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_label; | ||
| 100 | 102 | ||
| 101 | static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons; | 103 | static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons; |
| 102 | 104 | ||
diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index 42db020be..1556481d0 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui | |||
| @@ -170,6 +170,44 @@ | |||
| 170 | </item> | 170 | </item> |
| 171 | </layout> | 171 | </layout> |
| 172 | </item> | 172 | </item> |
| 173 | <item row="4" column="0" colspan="2"> | ||
| 174 | <layout class="QVBoxLayout" name="sliderRStickDeadzoneVerticalLayout"> | ||
| 175 | <item> | ||
| 176 | <layout class="QHBoxLayout" name="sliderRStickDeadzoneHorizontalLayout"> | ||
| 177 | <item> | ||
| 178 | <widget class="QLabel" name="labelRStickDeadzone"> | ||
| 179 | <property name="text"> | ||
| 180 | <string>Deadzone: 0</string> | ||
| 181 | </property> | ||
| 182 | <property name="alignment"> | ||
| 183 | <enum>Qt::AlignHCenter</enum> | ||
| 184 | </property> | ||
| 185 | </widget> | ||
| 186 | </item> | ||
| 187 | </layout> | ||
| 188 | </item> | ||
| 189 | <item> | ||
| 190 | <widget class="QSlider" name="sliderRStickDeadzone"> | ||
| 191 | <property name="orientation"> | ||
| 192 | <enum>Qt::Horizontal</enum> | ||
| 193 | </property> | ||
| 194 | </widget> | ||
| 195 | </item> | ||
| 196 | </layout> | ||
| 197 | </item> | ||
| 198 | <item row="5" column="0"> | ||
| 199 | <spacer name="RStick_verticalSpacer"> | ||
| 200 | <property name="orientation"> | ||
| 201 | <enum>Qt::Vertical</enum> | ||
| 202 | </property> | ||
| 203 | <property name="sizeHint" stdset="0"> | ||
| 204 | <size> | ||
| 205 | <width>0</width> | ||
| 206 | <height>0</height> | ||
| 207 | </size> | ||
| 208 | </property> | ||
| 209 | </spacer> | ||
| 210 | </item> | ||
| 173 | </layout> | 211 | </layout> |
| 174 | </widget> | 212 | </widget> |
| 175 | </item> | 213 | </item> |
| @@ -745,6 +783,47 @@ | |||
| 745 | </item> | 783 | </item> |
| 746 | </layout> | 784 | </layout> |
| 747 | </item> | 785 | </item> |
| 786 | <item row="5" column="1" colspan="2"> | ||
| 787 | <layout class="QVBoxLayout" name="sliderLStickDeadzoneVerticalLayout"> | ||
| 788 | <property name="sizeConstraint"> | ||
| 789 | <enum>QLayout::SetDefaultConstraint</enum> | ||
| 790 | </property> | ||
| 791 | <item> | ||
| 792 | <layout class="QHBoxLayout" name="sliderLStickDeadzoneHorizontalLayout"> | ||
| 793 | <item> | ||
| 794 | <widget class="QLabel" name="labelLStickDeadzone"> | ||
| 795 | <property name="text"> | ||
| 796 | <string>Deadzone: 0</string> | ||
| 797 | </property> | ||
| 798 | <property name="alignment"> | ||
| 799 | <enum>Qt::AlignHCenter</enum> | ||
| 800 | </property> | ||
| 801 | </widget> | ||
| 802 | </item> | ||
| 803 | </layout> | ||
| 804 | </item> | ||
| 805 | <item> | ||
| 806 | <widget class="QSlider" name="sliderLStickDeadzone"> | ||
| 807 | <property name="orientation"> | ||
| 808 | <enum>Qt::Horizontal</enum> | ||
| 809 | </property> | ||
| 810 | </widget> | ||
| 811 | </item> | ||
| 812 | </layout> | ||
| 813 | </item> | ||
| 814 | <item row="6" column="1"> | ||
| 815 | <spacer name="LStick_verticalSpacer"> | ||
| 816 | <property name="orientation"> | ||
| 817 | <enum>Qt::Vertical</enum> | ||
| 818 | </property> | ||
| 819 | <property name="sizeHint" stdset="0"> | ||
| 820 | <size> | ||
| 821 | <width>0</width> | ||
| 822 | <height>0</height> | ||
| 823 | </size> | ||
| 824 | </property> | ||
| 825 | </spacer> | ||
| 826 | </item> | ||
| 748 | </layout> | 827 | </layout> |
| 749 | </widget> | 828 | </widget> |
| 750 | </item> | 829 | </item> |
diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_ui.cpp index e43e84d39..c4a84cc67 100644 --- a/src/yuzu/configuration/configure_gamelist.cpp +++ b/src/yuzu/configuration/configure_ui.cpp | |||
| @@ -7,8 +7,8 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/common_types.h" | 8 | #include "common/common_types.h" |
| 9 | #include "core/settings.h" | 9 | #include "core/settings.h" |
| 10 | #include "ui_configure_gamelist.h" | 10 | #include "ui_configure_ui.h" |
| 11 | #include "yuzu/configuration/configure_gamelist.h" | 11 | #include "yuzu/configuration/configure_ui.h" |
| 12 | #include "yuzu/uisettings.h" | 12 | #include "yuzu/uisettings.h" |
| 13 | 13 | ||
| 14 | namespace { | 14 | namespace { |
| @@ -26,35 +26,40 @@ constexpr std::array row_text_names{ | |||
| 26 | }; | 26 | }; |
| 27 | } // Anonymous namespace | 27 | } // Anonymous namespace |
| 28 | 28 | ||
| 29 | ConfigureGameList::ConfigureGameList(QWidget* parent) | 29 | ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::ConfigureUi) { |
| 30 | : QWidget(parent), ui(new Ui::ConfigureGameList) { | ||
| 31 | ui->setupUi(this); | 30 | ui->setupUi(this); |
| 32 | 31 | ||
| 32 | for (const auto& theme : UISettings::themes) { | ||
| 33 | ui->theme_combobox->addItem(QString::fromUtf8(theme.first), | ||
| 34 | QString::fromUtf8(theme.second)); | ||
| 35 | } | ||
| 36 | |||
| 33 | InitializeIconSizeComboBox(); | 37 | InitializeIconSizeComboBox(); |
| 34 | InitializeRowComboBoxes(); | 38 | InitializeRowComboBoxes(); |
| 35 | 39 | ||
| 36 | SetConfiguration(); | 40 | SetConfiguration(); |
| 37 | 41 | ||
| 38 | // Force game list reload if any of the relevant settings are changed. | 42 | // Force game list reload if any of the relevant settings are changed. |
| 39 | connect(ui->show_unknown, &QCheckBox::stateChanged, this, | 43 | connect(ui->show_unknown, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); |
| 40 | &ConfigureGameList::RequestGameListUpdate); | ||
| 41 | connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | 44 | connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, |
| 42 | &ConfigureGameList::RequestGameListUpdate); | 45 | &ConfigureUi::RequestGameListUpdate); |
| 43 | connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | 46 | connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, |
| 44 | &ConfigureGameList::RequestGameListUpdate); | 47 | &ConfigureUi::RequestGameListUpdate); |
| 45 | connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | 48 | connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, |
| 46 | &ConfigureGameList::RequestGameListUpdate); | 49 | &ConfigureUi::RequestGameListUpdate); |
| 47 | 50 | ||
| 48 | // Update text ComboBoxes after user interaction. | 51 | // Update text ComboBoxes after user interaction. |
| 49 | connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::activated), | 52 | connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::activated), |
| 50 | [=]() { ConfigureGameList::UpdateSecondRowComboBox(); }); | 53 | [=]() { ConfigureUi::UpdateSecondRowComboBox(); }); |
| 51 | connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::activated), | 54 | connect(ui->row_2_text_combobox, QOverload<int>::of(&QComboBox::activated), |
| 52 | [=]() { ConfigureGameList::UpdateFirstRowComboBox(); }); | 55 | [=]() { ConfigureUi::UpdateFirstRowComboBox(); }); |
| 53 | } | 56 | } |
| 54 | 57 | ||
| 55 | ConfigureGameList::~ConfigureGameList() = default; | 58 | ConfigureUi::~ConfigureUi() = default; |
| 56 | 59 | ||
| 57 | void ConfigureGameList::ApplyConfiguration() { | 60 | void ConfigureUi::ApplyConfiguration() { |
| 61 | UISettings::values.theme = | ||
| 62 | ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString(); | ||
| 58 | UISettings::values.show_unknown = ui->show_unknown->isChecked(); | 63 | UISettings::values.show_unknown = ui->show_unknown->isChecked(); |
| 59 | UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); | 64 | UISettings::values.show_add_ons = ui->show_add_ons->isChecked(); |
| 60 | UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); | 65 | UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); |
| @@ -63,18 +68,19 @@ void ConfigureGameList::ApplyConfiguration() { | |||
| 63 | Settings::Apply(); | 68 | Settings::Apply(); |
| 64 | } | 69 | } |
| 65 | 70 | ||
| 66 | void ConfigureGameList::RequestGameListUpdate() { | 71 | void ConfigureUi::RequestGameListUpdate() { |
| 67 | UISettings::values.is_game_list_reload_pending.exchange(true); | 72 | UISettings::values.is_game_list_reload_pending.exchange(true); |
| 68 | } | 73 | } |
| 69 | 74 | ||
| 70 | void ConfigureGameList::SetConfiguration() { | 75 | void ConfigureUi::SetConfiguration() { |
| 76 | ui->theme_combobox->setCurrentIndex(ui->theme_combobox->findData(UISettings::values.theme)); | ||
| 71 | ui->show_unknown->setChecked(UISettings::values.show_unknown); | 77 | ui->show_unknown->setChecked(UISettings::values.show_unknown); |
| 72 | ui->show_add_ons->setChecked(UISettings::values.show_add_ons); | 78 | ui->show_add_ons->setChecked(UISettings::values.show_add_ons); |
| 73 | ui->icon_size_combobox->setCurrentIndex( | 79 | ui->icon_size_combobox->setCurrentIndex( |
| 74 | ui->icon_size_combobox->findData(UISettings::values.icon_size)); | 80 | ui->icon_size_combobox->findData(UISettings::values.icon_size)); |
| 75 | } | 81 | } |
| 76 | 82 | ||
| 77 | void ConfigureGameList::changeEvent(QEvent* event) { | 83 | void ConfigureUi::changeEvent(QEvent* event) { |
| 78 | if (event->type() == QEvent::LanguageChange) { | 84 | if (event->type() == QEvent::LanguageChange) { |
| 79 | RetranslateUI(); | 85 | RetranslateUI(); |
| 80 | } | 86 | } |
| @@ -82,7 +88,7 @@ void ConfigureGameList::changeEvent(QEvent* event) { | |||
| 82 | QWidget::changeEvent(event); | 88 | QWidget::changeEvent(event); |
| 83 | } | 89 | } |
| 84 | 90 | ||
| 85 | void ConfigureGameList::RetranslateUI() { | 91 | void ConfigureUi::RetranslateUI() { |
| 86 | ui->retranslateUi(this); | 92 | ui->retranslateUi(this); |
| 87 | 93 | ||
| 88 | for (int i = 0; i < ui->icon_size_combobox->count(); i++) { | 94 | for (int i = 0; i < ui->icon_size_combobox->count(); i++) { |
| @@ -97,18 +103,18 @@ void ConfigureGameList::RetranslateUI() { | |||
| 97 | } | 103 | } |
| 98 | } | 104 | } |
| 99 | 105 | ||
| 100 | void ConfigureGameList::InitializeIconSizeComboBox() { | 106 | void ConfigureUi::InitializeIconSizeComboBox() { |
| 101 | for (const auto& size : default_icon_sizes) { | 107 | for (const auto& size : default_icon_sizes) { |
| 102 | ui->icon_size_combobox->addItem(QString::fromUtf8(size.second), size.first); | 108 | ui->icon_size_combobox->addItem(QString::fromUtf8(size.second), size.first); |
| 103 | } | 109 | } |
| 104 | } | 110 | } |
| 105 | 111 | ||
| 106 | void ConfigureGameList::InitializeRowComboBoxes() { | 112 | void ConfigureUi::InitializeRowComboBoxes() { |
| 107 | UpdateFirstRowComboBox(true); | 113 | UpdateFirstRowComboBox(true); |
| 108 | UpdateSecondRowComboBox(true); | 114 | UpdateSecondRowComboBox(true); |
| 109 | } | 115 | } |
| 110 | 116 | ||
| 111 | void ConfigureGameList::UpdateFirstRowComboBox(bool init) { | 117 | void ConfigureUi::UpdateFirstRowComboBox(bool init) { |
| 112 | const int currentIndex = | 118 | const int currentIndex = |
| 113 | init ? UISettings::values.row_1_text_id | 119 | init ? UISettings::values.row_1_text_id |
| 114 | : ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData()); | 120 | : ui->row_1_text_combobox->findData(ui->row_1_text_combobox->currentData()); |
| @@ -127,7 +133,7 @@ void ConfigureGameList::UpdateFirstRowComboBox(bool init) { | |||
| 127 | ui->row_1_text_combobox->findData(ui->row_2_text_combobox->currentData())); | 133 | ui->row_1_text_combobox->findData(ui->row_2_text_combobox->currentData())); |
| 128 | } | 134 | } |
| 129 | 135 | ||
| 130 | void ConfigureGameList::UpdateSecondRowComboBox(bool init) { | 136 | void ConfigureUi::UpdateSecondRowComboBox(bool init) { |
| 131 | const int currentIndex = | 137 | const int currentIndex = |
| 132 | init ? UISettings::values.row_2_text_id | 138 | init ? UISettings::values.row_2_text_id |
| 133 | : ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData()); | 139 | : ui->row_2_text_combobox->findData(ui->row_2_text_combobox->currentData()); |
diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_ui.h index ecd3fa174..d471afe99 100644 --- a/src/yuzu/configuration/configure_gamelist.h +++ b/src/yuzu/configuration/configure_ui.h | |||
| @@ -8,15 +8,15 @@ | |||
| 8 | #include <QWidget> | 8 | #include <QWidget> |
| 9 | 9 | ||
| 10 | namespace Ui { | 10 | namespace Ui { |
| 11 | class ConfigureGameList; | 11 | class ConfigureUi; |
| 12 | } | 12 | } |
| 13 | 13 | ||
| 14 | class ConfigureGameList : public QWidget { | 14 | class ConfigureUi : public QWidget { |
| 15 | Q_OBJECT | 15 | Q_OBJECT |
| 16 | 16 | ||
| 17 | public: | 17 | public: |
| 18 | explicit ConfigureGameList(QWidget* parent = nullptr); | 18 | explicit ConfigureUi(QWidget* parent = nullptr); |
| 19 | ~ConfigureGameList() override; | 19 | ~ConfigureUi() override; |
| 20 | 20 | ||
| 21 | void ApplyConfiguration(); | 21 | void ApplyConfiguration(); |
| 22 | 22 | ||
| @@ -34,5 +34,5 @@ private: | |||
| 34 | void UpdateFirstRowComboBox(bool init = false); | 34 | void UpdateFirstRowComboBox(bool init = false); |
| 35 | void UpdateSecondRowComboBox(bool init = false); | 35 | void UpdateSecondRowComboBox(bool init = false); |
| 36 | 36 | ||
| 37 | std::unique_ptr<Ui::ConfigureGameList> ui; | 37 | std::unique_ptr<Ui::ConfigureUi> ui; |
| 38 | }; | 38 | }; |
diff --git a/src/yuzu/configuration/configure_gamelist.ui b/src/yuzu/configuration/configure_ui.ui index 7a69377e7..aa36bd112 100644 --- a/src/yuzu/configuration/configure_gamelist.ui +++ b/src/yuzu/configuration/configure_ui.ui | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | 1 | <?xml version="1.0" encoding="UTF-8"?> |
| 2 | <ui version="4.0"> | 2 | <ui version="4.0"> |
| 3 | <class>ConfigureGameList</class> | 3 | <class>ConfigureUi</class> |
| 4 | <widget class="QWidget" name="ConfigureGameList"> | 4 | <widget class="QWidget" name="ConfigureUi"> |
| 5 | <property name="geometry"> | 5 | <property name="geometry"> |
| 6 | <rect> | 6 | <rect> |
| 7 | <x>0</x> | 7 | <x>0</x> |
| @@ -21,7 +21,34 @@ | |||
| 21 | <property name="title"> | 21 | <property name="title"> |
| 22 | <string>General</string> | 22 | <string>General</string> |
| 23 | </property> | 23 | </property> |
| 24 | <layout class="QHBoxLayout" name="GeneralHorizontalLayout"> | 24 | <layout class="QHBoxLayout" name="horizontalLayout"> |
| 25 | <item> | ||
| 26 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
| 27 | <item> | ||
| 28 | <layout class="QHBoxLayout" name="horizontalLayout_3"> | ||
| 29 | <item> | ||
| 30 | <widget class="QLabel" name="theme_label"> | ||
| 31 | <property name="text"> | ||
| 32 | <string>Theme:</string> | ||
| 33 | </property> | ||
| 34 | </widget> | ||
| 35 | </item> | ||
| 36 | <item> | ||
| 37 | <widget class="QComboBox" name="theme_combobox"/> | ||
| 38 | </item> | ||
| 39 | </layout> | ||
| 40 | </item> | ||
| 41 | </layout> | ||
| 42 | </item> | ||
| 43 | </layout> | ||
| 44 | </widget> | ||
| 45 | </item> | ||
| 46 | <item> | ||
| 47 | <widget class="QGroupBox" name="GameListGroupBox"> | ||
| 48 | <property name="title"> | ||
| 49 | <string>Game List</string> | ||
| 50 | </property> | ||
| 51 | <layout class="QHBoxLayout" name="GameListHorizontalLayout"> | ||
| 25 | <item> | 52 | <item> |
| 26 | <layout class="QVBoxLayout" name="GeneralVerticalLayout"> | 53 | <layout class="QVBoxLayout" name="GeneralVerticalLayout"> |
| 27 | <item> | 54 | <item> |
| @@ -38,19 +65,6 @@ | |||
| 38 | </property> | 65 | </property> |
| 39 | </widget> | 66 | </widget> |
| 40 | </item> | 67 | </item> |
| 41 | </layout> | ||
| 42 | </item> | ||
| 43 | </layout> | ||
| 44 | </widget> | ||
| 45 | </item> | ||
| 46 | <item> | ||
| 47 | <widget class="QGroupBox" name="IconSizeGroupBox"> | ||
| 48 | <property name="title"> | ||
| 49 | <string>Icon Size</string> | ||
| 50 | </property> | ||
| 51 | <layout class="QHBoxLayout" name="icon_size_qhbox_layout"> | ||
| 52 | <item> | ||
| 53 | <layout class="QVBoxLayout" name="icon_size_qvbox_layout"> | ||
| 54 | <item> | 68 | <item> |
| 55 | <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2"> | 69 | <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2"> |
| 56 | <item> | 70 | <item> |
| @@ -65,19 +79,6 @@ | |||
| 65 | </item> | 79 | </item> |
| 66 | </layout> | 80 | </layout> |
| 67 | </item> | 81 | </item> |
| 68 | </layout> | ||
| 69 | </item> | ||
| 70 | </layout> | ||
| 71 | </widget> | ||
| 72 | </item> | ||
| 73 | <item> | ||
| 74 | <widget class="QGroupBox" name="RowGroupBox"> | ||
| 75 | <property name="title"> | ||
| 76 | <string>Row Text</string> | ||
| 77 | </property> | ||
| 78 | <layout class="QHBoxLayout" name="RowHorizontalLayout"> | ||
| 79 | <item> | ||
| 80 | <layout class="QVBoxLayout" name="RowVerticalLayout"> | ||
| 81 | <item> | 82 | <item> |
| 82 | <layout class="QHBoxLayout" name="row_1_qhbox_layout"> | 83 | <layout class="QHBoxLayout" name="row_1_qhbox_layout"> |
| 83 | <item> | 84 | <item> |