summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dist/qt_themes/qdarkstyle/style.qss222
-rw-r--r--src/common/logging/backend.cpp2
-rw-r--r--src/common/logging/backend.h2
-rw-r--r--src/common/logging/log.h33
-rw-r--r--src/common/string_util.cpp22
-rw-r--r--src/core/CMakeLists.txt10
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp5
-rw-r--r--src/core/arm/exclusive_monitor.cpp14
-rw-r--r--src/core/arm/exclusive_monitor.h9
-rw-r--r--src/core/arm/unicorn/arm_unicorn.cpp3
-rw-r--r--src/core/core.cpp75
-rw-r--r--src/core/core.h10
-rw-r--r--src/core/core_cpu.cpp127
-rw-r--r--src/core/core_cpu.h120
-rw-r--r--src/core/core_manager.cpp70
-rw-r--r--src/core/core_manager.h63
-rw-r--r--src/core/cpu_core_manager.cpp152
-rw-r--r--src/core/cpu_core_manager.h62
-rw-r--r--src/core/cpu_manager.cpp81
-rw-r--r--src/core/cpu_manager.h50
-rw-r--r--src/core/frontend/input.h10
-rw-r--r--src/core/gdbstub/gdbstub.cpp2
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp1
-rw-r--r--src/core/hle/kernel/kernel.cpp52
-rw-r--r--src/core/hle/kernel/kernel.h19
-rw-r--r--src/core/hle/kernel/physical_core.cpp51
-rw-r--r--src/core/hle/kernel/physical_core.h77
-rw-r--r--src/core/hle/kernel/scheduler.cpp1
-rw-r--r--src/core/hle/kernel/svc.cpp2
-rw-r--r--src/core/hle/kernel/thread.cpp3
-rw-r--r--src/core/hle/kernel/wait_object.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp39
-rw-r--r--src/core/hle/service/sockets/bsd.cpp48
-rw-r--r--src/core/hle/service/sockets/bsd.h4
-rw-r--r--src/input_common/sdl/sdl_impl.cpp16
-rw-r--r--src/video_core/engines/shader_bytecode.h30
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp6
-rw-r--r--src/video_core/renderer_opengl/gl_texture_cache.cpp40
-rw-r--r--src/video_core/renderer_vulkan/vk_pipeline_cache.cpp3
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.cpp95
-rw-r--r--src/video_core/renderer_vulkan/vk_shader_decompiler.h3
-rw-r--r--src/video_core/shader/decode/memory.cpp107
-rw-r--r--src/video_core/shader/node.h2
-rw-r--r--src/video_core/texture_cache/surface_base.cpp2
-rw-r--r--src/yuzu/CMakeLists.txt6
-rw-r--r--src/yuzu/configuration/configure.ui6
-rw-r--r--src/yuzu/configuration/configure_dialog.cpp6
-rw-r--r--src/yuzu/configuration/configure_general.cpp8
-rw-r--r--src/yuzu/configuration/configure_general.ui37
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp26
-rw-r--r--src/yuzu/configuration/configure_input_player.h2
-rw-r--r--src/yuzu/configuration/configure_input_player.ui79
-rw-r--r--src/yuzu/configuration/configure_ui.cpp (renamed from src/yuzu/configuration/configure_gamelist.cpp)48
-rw-r--r--src/yuzu/configuration/configure_ui.h (renamed from src/yuzu/configuration/configure_gamelist.h)10
-rw-r--r--src/yuzu/configuration/configure_ui.ui (renamed from src/yuzu/configuration/configure_gamelist.ui)59
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
29QCheckBox { 30QCheckBox {
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
36QCheckBox:disabled { 37QCheckBox:disabled {
@@ -163,7 +164,7 @@ QMenuBar::item:selected {
163} 164}
164 165
165QMenuBar::item:pressed { 166QMenuBar::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
173QMenu { 174QMenu {
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
179QMenu::icon { 180QMenu::icon {
@@ -190,11 +191,21 @@ QMenu::item:selected {
190 color: #eff0f1; 191 color: #eff0f1;
191} 192}
192 193
193QMenu::separator { 194QMenu::item:disabled {
194 height: 2px; 195 color: #54575B;
195 background: #76797C; 196}
196 margin-left: 10px; 197
197 margin-right: 5px; 198QMenu::item:disabled:hover,
199QMenu::item:disabled:selected {
200 background-color: #393e43;
201 color: #666;
202}
203
204QMenu::separator,
205QMenuBar::separator {
206 height: 1px;
207 background-color: #54575B;
208 margin: 2px 4px 2px 40px;
198} 209}
199 210
200QMenu::indicator { 211QMenu::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
210QMenu::indicator:non-exclusive:unchecked { 218QMenu::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
229QMenu::indicator:exclusive:unchecked { 235QMenu::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
245QMenu::right-arrow { 251QMenu::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
250QWidget:disabled { 256QWidget: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
262QWidget:focus, 268QAbstractItemView:disabled,
263QMenuBar:focus { 269QAbstractItemView:read-only {
270 alternate-background-color: #232629;
271}
272
273QWidget:focus {
264 border: 1px solid #3daee9; 274 border: 1px solid #3daee9;
265} 275}
266 276
267QTabWidget:focus, 277QTabWidget:focus,
268QCheckBox:focus, 278QCheckBox:focus,
269QRadioButton:focus, 279QRadioButton:focus,
270QSlider:focus { 280QSlider:focus,
281QTreeView:focus,
282QMenu:focus,
283QMenuBar:focus,
284QTabBar:focus {
271 border: none; 285 border: none;
272} 286}
273 287
274QLineEdit { 288QLineEdit {
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
287QGroupBox { 300QGroupBox {
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
293QGroupBox::title { 307QGroupBox::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
301QAbstractScrollArea { 315QAbstractScrollArea {
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
321QScrollBar::add-line:horizontal { 335QScrollBar::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
330QScrollBar::sub-line:horizontal { 344QScrollBar::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
381QScrollBar::sub-line:vertical { 395QScrollBar::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
390QScrollBar::add-line:vertical { 404QScrollBar::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 {
427QTextEdit { 441QTextEdit {
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
433QPlainTextEdit { 447QPlainTextEdit {
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
441QHeaderView::section { 454QHeaderView::section {
@@ -467,15 +480,6 @@ QMainWindow::separator:hover {
467 spacing: 2px; 480 spacing: 2px;
468} 481}
469 482
470QMenu::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
479QFrame { 483QFrame {
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
519QPushButton { 523QPushButton {
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
530QPushButton:disabled { 535QPushButton: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
554QComboBox { 552QComboBox {
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
563QPushButton:checked { 561QPushButton:checked {
@@ -571,8 +569,7 @@ QAbstractSpinBox:hover,
571QLineEdit:hover, 569QLineEdit:hover,
572QTextEdit:hover, 570QTextEdit:hover,
573QPlainTextEdit:hover, 571QPlainTextEdit:hover,
574QAbstractView:hover, 572QAbstractView:hover {
575QTreeView: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 {
591QComboBox::drop-down { 588QComboBox::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
612QAbstractSpinBox { 610QAbstractSpinBox {
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
627QAbstractSpinBox:down-button { 626QAbstractSpinBox: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
633QAbstractSpinBox::up-arrow, 633QAbstractSpinBox::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
657QLabel { 657QLabel,
658 border: 0px solid black; 658QTabWidget {
659 border: 0;
659} 660}
660 661
661QTabWidget { 662QTabWidget {
662 border: 0px transparent black; 663 padding-top: 1px;
663} 664}
664 665
665QTabWidget::pane { 666QTabWidget::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
671QTabWidget::tab-bar { 676QTabWidget::tab-bar {
672 /* left: 5px; move to the right by 5px */ 677 overflow: visible;
673} 678}
674 679
675QTabBar { 680QTabBar {
@@ -677,10 +682,6 @@ QTabBar {
677 border-radius: 3px; 682 border-radius: 3px;
678} 683}
679 684
680QTabBar:focus {
681 border: 0px transparent black;
682}
683
684QTabBar::close-button { 685QTabBar::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
702QTabBar::tab:top { 701QTabBar::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
713QTabBar::tab:top:selected { 711QTabBar::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; 717QTabBar::tab:top:!selected {
718 margin-top: 1px;
719 border-bottom-color: #76797C;
720} 720}
721 721
722QTabBar::tab:top:!selected:hover { 722QTabBar::tab:top:!selected:hover {
723 background-color: #3daee9; 723 background-color: #3daee9;
724} 724}
725 725
726
727/* BOTTOM TABS */ 726/* BOTTOM TABS */
728
729QTabBar::tab:bottom { 727QTabBar::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
756QTabBar::tab:left { 752QTabBar::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
783QTabBar::tab:right { 777QTabBar::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
848QTreeView, 842QTreeView,
849QListView { 843QListView {
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
980QToolButton { 974QToolButton {
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 {
988QToolButton[popupMode="1"] { 982QToolButton[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"] {
996QToolButton[popupMode="2"] { 989QToolButton[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
1021QToolButton::menu-indicator { 1011QToolButton::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
1031QToolButton::menu-button { 1018QToolButton::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
1054QTableView { 1041QTableView {
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
1047QTreeView:disabled {
1048 background-color: #1f2225;
1049}
1050
1060QTableView, 1051QTableView,
1061QHeaderView { 1052QHeaderView {
1062 border-radius: 0px; 1053 border-radius: 0;
1054}
1055
1056QListView:focus {
1057 border-color: #54575B;
1063} 1058}
1064 1059
1065QTableView::item:pressed, 1060QTableView::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
1124QHeaderView::down-arrow { 1117QHeaderView::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
1152QToolBox::tab:selected { 1145QToolBox::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
1159QStatusBar::item { 1151QStatusBar::item {
1160 border: 0px transparent dark; 1152 border: 0;
1161} 1153}
1162 1154
1163QFrame[height="3"], 1155QFrame[height="3"],
@@ -1194,7 +1186,6 @@ QProgressBar::chunk {
1194 1186
1195QDateEdit { 1187QDateEdit {
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,
1234QDateEdit::down-arrow:focus { 1225QDateEdit::down-arrow:focus {
1235 image: url(:/qss_icons/rc/down_arrow.png); 1226 image: url(:/qss_icons/rc/down_arrow.png);
1236} 1227}
1228
1229QComboBox:disabled,
1230QPushButton:disabled,
1231QAbstractSpinBox:disabled,
1232QDateEdit:disabled,
1233QLineEdit:disabled,
1234QTextEdit:disabled,
1235QToolButton:disabled,
1236QPlainTextEdit: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
10namespace Log { 10namespace Log {
11 11
12// trims up to and including the last of ../, ..\, src/, src\ in a string
13constexpr 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.
13enum class Level : u8 { 22enum 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
226const 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
7namespace Core { 11namespace Core {
8 12
9ExclusiveMonitor::~ExclusiveMonitor() = default; 13ExclusiveMonitor::~ExclusiveMonitor() = default;
10 14
15std::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
11namespace Memory {
12class Memory;
13}
14
9namespace Core { 15namespace Core {
10 16
11class ExclusiveMonitor { 17class 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
31std::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
14namespace Core { 15namespace 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,
113struct System::Impl { 114struct 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 {
377System::System() : impl{std::make_unique<Impl>(*this)} {} 386System::System() : impl{std::make_unique<Impl>(*this)} {}
378System::~System() = default; 387System::~System() = default;
379 388
380Cpu& System::CurrentCpuCore() { 389CoreManager& System::CurrentCoreManager() {
381 return impl->CurrentCpuCore(); 390 return impl->CurrentCoreManager();
382} 391}
383 392
384const Cpu& System::CurrentCpuCore() const { 393const CoreManager& System::CurrentCoreManager() const {
385 return impl->CurrentCpuCore(); 394 return impl->CurrentCoreManager();
386} 395}
387 396
388System::ResultStatus System::RunLoop(bool tight_loop) { 397System::ResultStatus System::RunLoop(bool tight_loop) {
@@ -394,7 +403,7 @@ System::ResultStatus System::SingleStep() {
394} 403}
395 404
396void System::InvalidateCpuInstructionCaches() { 405void System::InvalidateCpuInstructionCaches() {
397 impl->cpu_core_manager.InvalidateAllInstructionCaches(); 406 impl->kernel.InvalidateAllInstructionCaches();
398} 407}
399 408
400System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { 409System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
@@ -406,13 +415,11 @@ bool System::IsPoweredOn() const {
406} 415}
407 416
408void System::PrepareReschedule() { 417void System::PrepareReschedule() {
409 CurrentCpuCore().PrepareReschedule(); 418 impl->CurrentPhysicalCore().Stop();
410} 419}
411 420
412void System::PrepareReschedule(const u32 core_index) { 421void 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
418PerfStatsResults System::GetAndResetPerfStats() { 425PerfStatsResults System::GetAndResetPerfStats() {
@@ -428,31 +435,31 @@ const TelemetrySession& System::TelemetrySession() const {
428} 435}
429 436
430ARM_Interface& System::CurrentArmInterface() { 437ARM_Interface& System::CurrentArmInterface() {
431 return CurrentCpuCore().ArmInterface(); 438 return impl->CurrentPhysicalCore().ArmInterface();
432} 439}
433 440
434const ARM_Interface& System::CurrentArmInterface() const { 441const ARM_Interface& System::CurrentArmInterface() const {
435 return CurrentCpuCore().ArmInterface(); 442 return impl->CurrentPhysicalCore().ArmInterface();
436} 443}
437 444
438std::size_t System::CurrentCoreIndex() const { 445std::size_t System::CurrentCoreIndex() const {
439 return CurrentCpuCore().CoreIndex(); 446 return impl->cpu_manager.GetActiveCoreIndex();
440} 447}
441 448
442Kernel::Scheduler& System::CurrentScheduler() { 449Kernel::Scheduler& System::CurrentScheduler() {
443 return CurrentCpuCore().Scheduler(); 450 return impl->CurrentPhysicalCore().Scheduler();
444} 451}
445 452
446const Kernel::Scheduler& System::CurrentScheduler() const { 453const Kernel::Scheduler& System::CurrentScheduler() const {
447 return CurrentCpuCore().Scheduler(); 454 return impl->CurrentPhysicalCore().Scheduler();
448} 455}
449 456
450Kernel::Scheduler& System::Scheduler(std::size_t core_index) { 457Kernel::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
454const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const { 461const 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
476ARM_Interface& System::ArmInterface(std::size_t core_index) { 483ARM_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
480const ARM_Interface& System::ArmInterface(std::size_t core_index) const { 487const 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
484Cpu& System::CpuCore(std::size_t core_index) { 491CoreManager& 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
488const Cpu& System::CpuCore(std::size_t core_index) const { 495const 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
493ExclusiveMonitor& System::Monitor() { 500ExclusiveMonitor& System::Monitor() {
494 return impl->cpu_core_manager.GetExclusiveMonitor(); 501 return impl->kernel.GetExclusiveMonitor();
495} 502}
496 503
497const ExclusiveMonitor& System::Monitor() const { 504const ExclusiveMonitor& System::Monitor() const {
498 return impl->cpu_core_manager.GetExclusiveMonitor(); 505 return impl->kernel.GetExclusiveMonitor();
499} 506}
500 507
501Memory::Memory& System::Memory() { 508Memory::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;
93namespace Core { 93namespace Core {
94 94
95class ARM_Interface; 95class ARM_Interface;
96class Cpu; 96class CoreManager;
97class ExclusiveMonitor; 97class ExclusiveMonitor;
98class FrameLimiter; 98class FrameLimiter;
99class PerfStats; 99class 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
22namespace Core {
23
24void CpuBarrier::NotifyEnd() {
25 std::unique_lock lock{mutex};
26 end = true;
27 condition.notify_all();
28}
29
30bool 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
53Cpu::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
67Cpu::~Cpu() = default;
68
69std::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
79void 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
107void Cpu::SingleStep() {
108 return RunLoop(false);
109}
110
111void Cpu::PrepareReschedule() {
112 arm_interface->PrepareReschedule();
113}
114
115void 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
123void 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
14namespace Kernel {
15class GlobalScheduler;
16class Scheduler;
17} // namespace Kernel
18
19namespace Core {
20class System;
21}
22
23namespace Core::Timing {
24class CoreTiming;
25}
26
27namespace Memory {
28class Memory;
29}
30
31namespace Core {
32
33class ARM_Interface;
34class ExclusiveMonitor;
35
36constexpr unsigned NUM_CPU_CORES{4};
37
38class CpuBarrier {
39public:
40 bool IsAlive() const {
41 return !end;
42 }
43
44 void NotifyEnd();
45
46 bool Rendezvous();
47
48private:
49 unsigned cores_waiting{NUM_CPU_CORES};
50 std::mutex mutex;
51 std::condition_variable condition;
52 std::atomic<bool> end{};
53};
54
55class Cpu {
56public:
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
107private:
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
24namespace Core {
25
26CoreManager::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
31CoreManager::~CoreManager() = default;
32
33void 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
53void CoreManager::SingleStep() {
54 return RunLoop(false);
55}
56
57void CoreManager::PrepareReschedule() {
58 physical_core.Stop();
59}
60
61void 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
12namespace Kernel {
13class GlobalScheduler;
14class PhysicalCore;
15} // namespace Kernel
16
17namespace Core {
18class System;
19}
20
21namespace Core::Timing {
22class CoreTiming;
23}
24
25namespace Memory {
26class Memory;
27}
28
29namespace Core {
30
31constexpr unsigned NUM_CPU_CORES{4};
32
33class CoreManager {
34public:
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
52private:
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
14namespace Core {
15namespace {
16void RunCpuCore(const System& system, Cpu& cpu_state) {
17 while (system.IsPoweredOn()) {
18 cpu_state.RunLoop(true);
19 }
20}
21} // Anonymous namespace
22
23CpuCoreManager::CpuCoreManager(System& system) : system{system} {}
24CpuCoreManager::~CpuCoreManager() = default;
25
26void 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
35void 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
50void 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
69Cpu& CpuCoreManager::GetCore(std::size_t index) {
70 return *cores.at(index);
71}
72
73const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
74 return *cores.at(index);
75}
76
77ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
78 return *exclusive_monitor;
79}
80
81const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
82 return *exclusive_monitor;
83}
84
85Cpu& 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
97const 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
109void 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
146void 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
12namespace Core {
13
14class Cpu;
15class CpuBarrier;
16class ExclusiveMonitor;
17class System;
18
19class CpuCoreManager {
20public:
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
47private:
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
12namespace Core {
13
14CpuManager::CpuManager(System& system) : system{system} {}
15CpuManager::~CpuManager() = default;
16
17void 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
23void CpuManager::Shutdown() {
24 for (auto& cpu_core : core_managers) {
25 cpu_core.reset();
26 }
27}
28
29CoreManager& CpuManager::GetCoreManager(std::size_t index) {
30 return *core_managers.at(index);
31}
32
33const CoreManager& CpuManager::GetCoreManager(std::size_t index) const {
34 return *core_managers.at(index);
35}
36
37CoreManager& CpuManager::GetCurrentCoreManager() {
38 // Otherwise, use single-threaded mode active_core variable
39 return *core_managers[active_core];
40}
41
42const CoreManager& CpuManager::GetCurrentCoreManager() const {
43 // Otherwise, use single-threaded mode active_core variable
44 return *core_managers[active_core];
45}
46
47void 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
10namespace Core {
11
12class CoreManager;
13class System;
14
15class CpuManager {
16public:
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
41private:
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
16namespace Input { 16namespace Input {
17 17
18enum 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.).
19template <typename StatusType> 26template <typename StatusType>
20class InputDevice { 27class 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
265Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
266 return impl->cores[id];
267}
268
269const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
270 return impl->cores[id];
271}
272
273Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
274 return *impl->exclusive_monitor;
275}
276
277const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
278 return *impl->exclusive_monitor;
279}
280
281void KernelCore::InvalidateAllInstructionCaches() {
282 for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) {
283 PhysicalCore(i).ArmInterface().ClearInstructionCache();
284 }
285}
286
287void KernelCore::PrepareReschedule(std::size_t id) {
288 if (id < impl->global_scheduler.CpuCoresCount()) {
289 impl->cores[id].Stop();
290 }
291}
292
243void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) { 293void 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
13namespace Core { 13namespace Core {
14class ExclusiveMonitor;
14class System; 15class System;
15} 16} // namespace Core
16 17
17namespace Core::Timing { 18namespace Core::Timing {
18class CoreTiming; 19class CoreTiming;
@@ -25,6 +26,7 @@ class AddressArbiter;
25class ClientPort; 26class ClientPort;
26class GlobalScheduler; 27class GlobalScheduler;
27class HandleTable; 28class HandleTable;
29class PhysicalCore;
28class Process; 30class Process;
29class ResourceLimit; 31class ResourceLimit;
30class Thread; 32class 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
17namespace Kernel {
18
19PhysicalCore::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
32PhysicalCore::~PhysicalCore() = default;
33
34void PhysicalCore::Run() {
35 arm_interface->Run();
36 arm_interface->ClearExclusiveState();
37}
38
39void PhysicalCore::Step() {
40 arm_interface->Step();
41}
42
43void PhysicalCore::Stop() {
44 arm_interface->PrepareReschedule();
45}
46
47void 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
10namespace Kernel {
11class Scheduler;
12} // namespace Kernel
13
14namespace Core {
15class ARM_Interface;
16class ExclusiveMonitor;
17class System;
18} // namespace Core
19
20namespace Kernel {
21
22class PhysicalCore {
23public:
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
71private:
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
45void 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
55void 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
45void BSD::Connect(Kernel::HLERequestContext& ctx) { 65void 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
75void 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
85void 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
55void BSD::SendTo(Kernel::HLERequestContext& ctx) { 95void 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
345private: 361private:
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
230enum 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
243enum 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
230enum class UniformType : u64 { 252enum 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
179GLenum 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
179void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) { 192void 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
426OGLTextureView CachedSurfaceView::CreateTextureView() const { 449OGLTextureView 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 {
19using Tegra::Shader::AtomicOp; 19using Tegra::Shader::AtomicOp;
20using Tegra::Shader::AtomicType; 20using Tegra::Shader::AtomicType;
21using Tegra::Shader::Attribute; 21using Tegra::Shader::Attribute;
22using Tegra::Shader::GlobalAtomicOp;
23using Tegra::Shader::GlobalAtomicType;
22using Tegra::Shader::Instruction; 24using Tegra::Shader::Instruction;
23using Tegra::Shader::OpCode; 25using Tegra::Shader::OpCode;
24using Tegra::Shader::Register; 26using Tegra::Shader::Register;
27using Tegra::Shader::StoreType;
25 28
26namespace { 29namespace {
27 30
@@ -61,6 +64,27 @@ u32 GetMemorySize(Tegra::Shader::UniformType uniform_type) {
61 } 64 }
62} 65}
63 66
67Node 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
74Node 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
81Node 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
66u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) { 90u32 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
35void ConfigureDialog::ApplyConfiguration() { 35void 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
75void ConfigureDialog::PopulateSelectionList() { 75void 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;
30void ConfigureGeneral::SetConfiguration() { 25void 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() {
41void ConfigureGeneral::ApplyConfiguration() { 35void 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
14namespace { 14namespace {
@@ -26,35 +26,40 @@ constexpr std::array row_text_names{
26}; 26};
27} // Anonymous namespace 27} // Anonymous namespace
28 28
29ConfigureGameList::ConfigureGameList(QWidget* parent) 29ConfigureUi::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
55ConfigureGameList::~ConfigureGameList() = default; 58ConfigureUi::~ConfigureUi() = default;
56 59
57void ConfigureGameList::ApplyConfiguration() { 60void 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
66void ConfigureGameList::RequestGameListUpdate() { 71void 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
70void ConfigureGameList::SetConfiguration() { 75void 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
77void ConfigureGameList::changeEvent(QEvent* event) { 83void 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
85void ConfigureGameList::RetranslateUI() { 91void 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
100void ConfigureGameList::InitializeIconSizeComboBox() { 106void 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
106void ConfigureGameList::InitializeRowComboBoxes() { 112void ConfigureUi::InitializeRowComboBoxes() {
107 UpdateFirstRowComboBox(true); 113 UpdateFirstRowComboBox(true);
108 UpdateSecondRowComboBox(true); 114 UpdateSecondRowComboBox(true);
109} 115}
110 116
111void ConfigureGameList::UpdateFirstRowComboBox(bool init) { 117void 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
130void ConfigureGameList::UpdateSecondRowComboBox(bool init) { 136void 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
10namespace Ui { 10namespace Ui {
11class ConfigureGameList; 11class ConfigureUi;
12} 12}
13 13
14class ConfigureGameList : public QWidget { 14class ConfigureUi : public QWidget {
15 Q_OBJECT 15 Q_OBJECT
16 16
17public: 17public:
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>