Compare commits

..
Author SHA1 Message Date
yuzubot 99976a61cc "Merge Tagged PR 1012" 2020-01-25 13:01:09 +00:00
yuzubot 1331d73e66 "Merge Tagged PR 1340" 2020-01-25 13:01:08 +00:00
yuzubot 7af854a719 "Merge Tagged PR 1703" 2020-01-25 13:01:07 +00:00
yuzubot 0ebfd9e89f "Merge Tagged PR 2710" 2020-01-25 13:01:06 +00:00
76 changed files with 881 additions and 1856 deletions

No files matched your search

+110 -112
View File
@@ -2,8 +2,7 @@ QToolTip {
border: 1px solid #76797C;
background-color: #5A7566;
color: white;
/*remove padding, for fix combobox tooltip.*/
padding: 0;
padding: 0px; /*remove padding, for fix combobox tooltip.*/
opacity: 200;
}
@@ -14,7 +13,7 @@ QWidget {
selection-color: #eff0f1;
background-clip: border;
border-image: none;
border: 0;
border: 0px transparent black;
outline: 0;
}
@@ -28,10 +27,10 @@ QWidget:item:selected {
}
QCheckBox {
spacing: 6px;
spacing: 5px;
outline: none;
color: #eff0f1;
margin: 0 2px 1px 0;
margin-bottom: 2px;
}
QCheckBox:disabled {
@@ -164,7 +163,7 @@ QMenuBar::item:selected {
}
QMenuBar::item:pressed {
border: 1px solid #18465d;
border: 1px solid #76797C;
background-color: #3daee9;
color: #eff0f1;
margin-bottom: -1px;
@@ -172,9 +171,9 @@ QMenuBar::item:pressed {
}
QMenu {
border: 1px solid #434242;
padding: 2px;
border: 1px solid #76797C;
color: #eff0f1;
margin: 2px;
}
QMenu::icon {
@@ -191,21 +190,11 @@ QMenu::item:selected {
color: #eff0f1;
}
QMenu::item:disabled {
color: #54575B;
}
QMenu::item:disabled:hover,
QMenu::item:disabled:selected {
background-color: #393e43;
color: #666;
}
QMenu::separator,
QMenuBar::separator {
height: 1px;
background-color: #54575B;
margin: 2px 4px 2px 40px;
QMenu::separator {
height: 2px;
background: #76797C;
margin-left: 10px;
margin-right: 5px;
}
QMenu::indicator {
@@ -214,7 +203,10 @@ QMenu::indicator {
height: 18px;
}
/* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */
/* non-exclusive indicator = check box style indicator
(see QActionGroup::setExclusive) */
QMenu::indicator:non-exclusive:unchecked {
image: url(:/qss_icons/rc/checkbox_unchecked.png);
}
@@ -231,7 +223,9 @@ QMenu::indicator:non-exclusive:checked:selected {
image: url(:/qss_icons/rc/checkbox_checked_disabled.png);
}
/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */
QMenu::indicator:exclusive:unchecked {
image: url(:/qss_icons/rc/radio_unchecked.png);
}
@@ -249,12 +243,12 @@ QMenu::indicator:exclusive:checked:selected {
}
QMenu::right-arrow {
margin-right: 10px;
margin: 5px;
image: url(:/qss_icons/rc/right_arrow.png)
}
QWidget:disabled {
color: #4f515b;
color: #454545;
background-color: #31363b;
}
@@ -265,30 +259,23 @@ QAbstractItemView {
border-radius: 2px;
}
QAbstractItemView:disabled,
QAbstractItemView:read-only {
alternate-background-color: #232629;
}
QWidget:focus {
QWidget:focus,
QMenuBar:focus {
border: 1px solid #3daee9;
}
QTabWidget:focus,
QCheckBox:focus,
QRadioButton:focus,
QSlider:focus,
QTreeView:focus,
QMenu:focus,
QMenuBar:focus,
QTabBar:focus {
QSlider:focus {
border: none;
}
QLineEdit {
background-color: #232629;
padding: 5px;
border: 1px solid #54575B;
border-style: solid;
border: 1px solid #76797C;
border-radius: 2px;
color: #eff0f1;
}
@@ -298,10 +285,9 @@ QAbstractItemView QLineEdit {
}
QGroupBox {
border: 1px solid #54575B;
border: 1px solid #76797C;
border-radius: 2px;
margin-top: 12px;
padding-top: 2px;
margin-top: 20px;
}
QGroupBox::title {
@@ -309,12 +295,12 @@ QGroupBox::title {
subcontrol-position: top center;
padding-left: 10px;
padding-right: 10px;
padding-top: 2px;
padding-top: 10px;
}
QAbstractScrollArea {
border-radius: 2px;
border: 1px solid #54575B;
border: 1px solid #76797C;
background-color: transparent;
}
@@ -333,7 +319,7 @@ QScrollBar::handle:horizontal {
}
QScrollBar::add-line:horizontal {
margin: 0 3px;
margin: 0px 3px 0px 3px;
border-image: url(:/qss_icons/rc/right_arrow_disabled.png);
width: 10px;
height: 10px;
@@ -342,7 +328,7 @@ QScrollBar::add-line:horizontal {
}
QScrollBar::sub-line:horizontal {
margin: 0 3px;
margin: 0px 3px 0px 3px;
border-image: url(:/qss_icons/rc/left_arrow_disabled.png);
height: 10px;
width: 10px;
@@ -393,7 +379,7 @@ QScrollBar::handle:vertical {
}
QScrollBar::sub-line:vertical {
margin: 3px 0;
margin: 3px 0px 3px 0px;
border-image: url(:/qss_icons/rc/up_arrow_disabled.png);
height: 10px;
width: 10px;
@@ -402,7 +388,7 @@ QScrollBar::sub-line:vertical {
}
QScrollBar::add-line:vertical {
margin: 3px 0;
margin: 3px 0px 3px 0px;
border-image: url(:/qss_icons/rc/down_arrow_disabled.png);
height: 10px;
width: 10px;
@@ -441,14 +427,15 @@ QScrollBar::sub-page:vertical {
QTextEdit {
background-color: #232629;
color: #eff0f1;
border: 1px solid #54575B;
border: 1px solid #76797C;
}
QPlainTextEdit {
background-color: #232629;
;
color: #eff0f1;
border-radius: 2px;
border: 1px solid #54575B;
border: 1px solid #76797C;
}
QHeaderView::section {
@@ -480,6 +467,15 @@ QMainWindow::separator:hover {
spacing: 2px;
}
QMenu::separator {
height: 1px;
background-color: #76797C;
color: white;
padding-left: 4px;
margin-left: 10px;
margin-right: 5px;
}
QFrame {
border-radius: 2px;
border: 1px solid #76797C;
@@ -522,19 +518,25 @@ QToolButton#qt_toolbar_ext_button {
QPushButton {
color: #eff0f1;
background-color: #31363b;
border-width: 1px;
border-color: #54575B;
border-color: #76797C;
border-style: solid;
padding: 6px 4px;
padding: 5px;
border-radius: 2px;
outline: none;
min-width: 100px;
background-color: #232629;
}
QPushButton:disabled {
background-color: #31363b;
border-width: 1px;
border-color: #454545;
border-style: solid;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 10px;
padding-right: 10px;
border-radius: 2px;
color: #454545;
}
@@ -551,11 +553,11 @@ QPushButton:pressed {
QComboBox {
selection-background-color: #3daee9;
border: 1px solid #54575B;
border-style: solid;
border: 1px solid #76797C;
border-radius: 2px;
padding: 4px 6px;
padding: 5px;
min-width: 75px;
background-color: #232629;
}
QPushButton:checked {
@@ -569,7 +571,8 @@ QAbstractSpinBox:hover,
QLineEdit:hover,
QTextEdit:hover,
QPlainTextEdit:hover,
QAbstractView:hover {
QAbstractView:hover,
QTreeView:hover {
border: 1px solid #3daee9;
color: #eff0f1;
}
@@ -588,7 +591,6 @@ QComboBox QAbstractItemView {
QComboBox::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
left: -6px;
width: 15px;
border-left-width: 0px;
border-left-color: darkgray;
@@ -608,8 +610,8 @@ QComboBox::down-arrow:focus {
}
QAbstractSpinBox {
padding: 4px 6px;
border: 1px solid #54575B;
padding: 5px;
border: 1px solid #76797C;
background-color: #232629;
color: #eff0f1;
border-radius: 2px;
@@ -620,14 +622,12 @@ QAbstractSpinBox:up-button {
background-color: transparent;
subcontrol-origin: border;
subcontrol-position: center right;
left: -6px;
}
QAbstractSpinBox:down-button {
background-color: transparent;
subcontrol-origin: border;
subcontrol-position: center left;
right: -6px;
}
QAbstractSpinBox::up-arrow,
@@ -654,27 +654,22 @@ QAbstractSpinBox::down-arrow:hover {
image: url(:/qss_icons/rc/down_arrow.png);
}
QLabel,
QTabWidget {
border: 0;
QLabel {
border: 0px solid black;
}
QTabWidget {
padding-top: 1px;
border: 0px transparent black;
}
QTabWidget::pane {
border: 1px solid #76797C;
padding: 5px;
position: absolute;
top: -1px;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
border-bottom-left-radius: 2px;
margin: 0px;
}
QTabWidget::tab-bar {
overflow: visible;
/* left: 5px; move to the right by 5px */
}
QTabBar {
@@ -682,6 +677,10 @@ QTabBar {
border-radius: 3px;
}
QTabBar:focus {
border: 0px transparent black;
}
QTabBar::close-button {
image: url(:/qss_icons/rc/close.png);
background: transparent;
@@ -697,33 +696,36 @@ QTabBar::close-button:pressed {
background: transparent;
}
/* TOP TABS */
QTabBar::tab:top {
color: #eff0f1;
border: 1px solid #54575B;
background-color: #2a2f33;
padding: 4px 16px 5px;
min-width: 36px;
border: 1px solid #76797C;
border-bottom: 2px transparent;
background-color: #31363b;
padding: 4px 16px 2px;
min-width: 38px;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
QTabBar::tab:top:selected {
border-color: #76797C;
background-color: #31363b;
border-bottom-color: #31363b;
}
QTabBar::tab:top:!selected {
margin-top: 1px;
border-bottom-color: #76797C;
color: #eff0f1;
background-color: #54575B;
border: 1px solid #76797C;
border-bottom: 2px solid #3daee9;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
QTabBar::tab:top:!selected:hover {
background-color: #3daee9;
}
/* BOTTOM TABS */
QTabBar::tab:bottom {
color: #eff0f1;
border: 1px solid #76797C;
@@ -748,7 +750,9 @@ QTabBar::tab:bottom:!selected:hover {
background-color: #3daee9;
}
/* LEFT TABS */
QTabBar::tab:left {
color: #eff0f1;
border: 1px solid #76797C;
@@ -773,7 +777,9 @@ QTabBar::tab:left:!selected:hover {
background-color: #3daee9;
}
/* RIGHT TABS */
QTabBar::tab:right {
color: #eff0f1;
border: 1px solid #76797C;
@@ -841,7 +847,7 @@ QDockWidget::float-button:pressed {
QTreeView,
QListView {
border: 1px solid #54575B;
border: 1px solid #76797C;
background-color: #232629;
}
@@ -972,8 +978,8 @@ QSlider::handle:vertical {
}
QToolButton {
background-color: #232629;
border: 1px solid #54575B;
background-color: transparent;
border: 1px transparent #76797C;
border-radius: 2px;
margin: 3px;
padding: 5px;
@@ -982,6 +988,7 @@ QToolButton {
QToolButton[popupMode="1"] {
/* only for MenuButtonPopup */
padding-right: 20px;
/* make way for the popup button */
border: 1px #76797C;
border-radius: 5px;
}
@@ -989,6 +996,7 @@ QToolButton[popupMode="1"] {
QToolButton[popupMode="2"] {
/* only for InstantPopup */
padding-right: 10px;
/* make way for the popup button */
border: 1px #76797C;
}
@@ -1007,14 +1015,19 @@ QToolButton::menu-button:pressed {
padding: 5px;
}
/* the subcontrol below is used only in the InstantPopup or DelayedPopup mode */
QToolButton::menu-indicator {
image: url(:/qss_icons/rc/down_arrow.png);
top: -7px;
left: -2px;
/* shift it a bit */
}
/* the subcontrols below are used only in the MenuButtonPopup mode */
QToolButton::menu-button {
border: 1px transparent #76797C;
border-top-right-radius: 6px;
@@ -1039,22 +1052,14 @@ QPushButton::menu-indicator {
}
QTableView {
border: 1px solid #54575B;
border: 1px solid #76797C;
gridline-color: #31363b;
background-color: #232629;
}
QTreeView:disabled {
background-color: #1f2225;
}
QTableView,
QHeaderView {
border-radius: 0;
}
QListView:focus {
border-color: #54575B;
border-radius: 0px;
}
QTableView::item:pressed,
@@ -1083,7 +1088,7 @@ QHeaderView::section {
background-color: #232629;
color: #eff0f1;
padding: 0 5px;
border: 1px solid #434242;
border: 1px solid #403F3F;
border-bottom: 0;
border-radius: 0px;
text-align: center;
@@ -1113,7 +1118,9 @@ QHeaderView::section:checked {
background-color: #334e5e;
}
/* sort indicator */
/* style the sort indicator */
QHeaderView::down-arrow {
image: url(:/qss_icons/rc/down_arrow.png);
}
@@ -1143,13 +1150,14 @@ QToolBox::tab {
}
QToolBox::tab:selected {
/* italicize selected tabs */
font: italic;
background-color: #31363b;
border-color: #3daee9;
}
QStatusBar::item {
border: 0;
border: 0px transparent dark;
}
QFrame[height="3"],
@@ -1186,6 +1194,7 @@ QProgressBar::chunk {
QDateEdit {
selection-background-color: #3daee9;
border-style: solid;
border: 1px solid #3375A3;
border-radius: 2px;
padding: 1px;
@@ -1209,7 +1218,7 @@ QDateEdit::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 15px;
border-left-width: 0;
border-left-width: 0px;
border-left-color: darkgray;
border-left-style: solid;
border-top-right-radius: 3px;
@@ -1225,14 +1234,3 @@ QDateEdit::down-arrow:hover,
QDateEdit::down-arrow:focus {
image: url(:/qss_icons/rc/down_arrow.png);
}
QComboBox:disabled,
QPushButton:disabled,
QAbstractSpinBox:disabled,
QDateEdit:disabled,
QLineEdit:disabled,
QTextEdit:disabled,
QToolButton:disabled,
QPlainTextEdit:disabled {
background-color: #2b2e31;
}
+4 -6
View File
@@ -15,14 +15,14 @@ add_library(core STATIC
constants.h
core.cpp
core.h
core_manager.cpp
core_manager.h
core_cpu.cpp
core_cpu.h
core_timing.cpp
core_timing.h
core_timing_util.cpp
core_timing_util.h
cpu_manager.cpp
cpu_manager.h
cpu_core_manager.cpp
cpu_core_manager.h
crypto/aes_util.cpp
crypto/aes_util.h
crypto/encryption_layer.cpp
@@ -158,8 +158,6 @@ add_library(core STATIC
hle/kernel/mutex.h
hle/kernel/object.cpp
hle/kernel/object.h
hle/kernel/physical_core.cpp
hle/kernel/physical_core.h
hle/kernel/process.cpp
hle/kernel/process.h
hle/kernel/process_capability.cpp
+2 -3
View File
@@ -10,12 +10,11 @@
#include "common/microprofile.h"
#include "core/arm/dynarmic/arm_dynarmic.h"
#include "core/core.h"
#include "core/core_manager.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
@@ -88,7 +87,7 @@ public:
if (GDBStub::IsServerEnabled()) {
parent.jit->HaltExecution();
parent.SetPC(pc);
Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread();
Kernel::Thread* thread = Kernel::GetCurrentThread();
parent.SaveContext(thread->GetContext());
GDBStub::Break();
GDBStub::SendTrap(thread, 5);
-14
View File
@@ -2,24 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic.h"
#endif
#include "core/arm/exclusive_monitor.h"
#include "core/memory.h"
namespace Core {
ExclusiveMonitor::~ExclusiveMonitor() = default;
std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
std::size_t num_cores) {
#ifdef ARCHITECTURE_x86_64
return std::make_unique<Core::DynarmicExclusiveMonitor>(memory, num_cores);
#else
// TODO(merry): Passthrough exclusive monitor
return nullptr;
#endif
}
} // namespace Core
-9
View File
@@ -4,14 +4,8 @@
#pragma once
#include <memory>
#include "common/common_types.h"
namespace Memory {
class Memory;
}
namespace Core {
class ExclusiveMonitor {
@@ -28,7 +22,4 @@ public:
virtual bool ExclusiveWrite128(std::size_t core_index, VAddr vaddr, u128 value) = 0;
};
std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
std::size_t num_cores);
} // namespace Core
+1 -2
View File
@@ -9,7 +9,6 @@
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/svc.h"
namespace Core {
@@ -178,7 +177,7 @@ void ARM_Unicorn::ExecuteInstructions(std::size_t num_instructions) {
uc_reg_write(uc, UC_ARM64_REG_PC, &last_bkpt.address);
}
Kernel::Thread* const thread = system.CurrentScheduler().GetCurrentThread();
Kernel::Thread* thread = Kernel::GetCurrentThread();
SaveContext(thread->GetContext());
if (last_bkpt_hit || GDBStub::IsMemoryBreak() || GDBStub::GetCpuStepFlag()) {
last_bkpt_hit = false;
+34 -41
View File
@@ -11,9 +11,9 @@
#include "common/string_util.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_manager.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/cpu_manager.h"
#include "core/cpu_core_manager.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/mode.h"
@@ -28,7 +28,6 @@
#include "core/hardware_interrupt_manager.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
@@ -114,25 +113,16 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl {
explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system},
cpu_manager{system}, reporter{system}, applet_manager{system} {}
cpu_core_manager{system}, reporter{system}, applet_manager{system} {}
CoreManager& CurrentCoreManager() {
return cpu_manager.GetCurrentCoreManager();
}
Kernel::PhysicalCore& CurrentPhysicalCore() {
const auto index = cpu_manager.GetActiveCoreIndex();
return kernel.PhysicalCore(index);
}
Kernel::PhysicalCore& GetPhysicalCore(std::size_t index) {
return kernel.PhysicalCore(index);
Cpu& CurrentCpuCore() {
return cpu_core_manager.GetCurrentCore();
}
ResultStatus RunLoop(bool tight_loop) {
status = ResultStatus::Success;
cpu_manager.RunLoop(tight_loop);
cpu_core_manager.RunLoop(tight_loop);
return status;
}
@@ -141,8 +131,8 @@ struct System::Impl {
LOG_DEBUG(HW_Memory, "initialized OK");
core_timing.Initialize();
cpu_core_manager.Initialize();
kernel.Initialize();
cpu_manager.Initialize();
const auto current_time = std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::system_clock::now().time_since_epoch());
@@ -215,6 +205,7 @@ struct System::Impl {
// Main process has been loaded and been made current.
// Begin GPU and CPU execution.
gpu_core->Start();
cpu_core_manager.StartThreads();
// Initialize cheat engine
if (cheat_engine) {
@@ -281,7 +272,7 @@ struct System::Impl {
gpu_core.reset();
// Close all CPU/threading state
cpu_manager.Shutdown();
cpu_core_manager.Shutdown();
// Shutdown kernel and core timing
kernel.Shutdown();
@@ -351,7 +342,7 @@ struct System::Impl {
std::unique_ptr<Tegra::GPU> gpu_core;
std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
Memory::Memory memory;
CpuManager cpu_manager;
CpuCoreManager cpu_core_manager;
bool is_powered_on = false;
bool exit_lock = false;
@@ -386,12 +377,12 @@ struct System::Impl {
System::System() : impl{std::make_unique<Impl>(*this)} {}
System::~System() = default;
CoreManager& System::CurrentCoreManager() {
return impl->CurrentCoreManager();
Cpu& System::CurrentCpuCore() {
return impl->CurrentCpuCore();
}
const CoreManager& System::CurrentCoreManager() const {
return impl->CurrentCoreManager();
const Cpu& System::CurrentCpuCore() const {
return impl->CurrentCpuCore();
}
System::ResultStatus System::RunLoop(bool tight_loop) {
@@ -403,7 +394,7 @@ System::ResultStatus System::SingleStep() {
}
void System::InvalidateCpuInstructionCaches() {
impl->kernel.InvalidateAllInstructionCaches();
impl->cpu_core_manager.InvalidateAllInstructionCaches();
}
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
@@ -415,11 +406,13 @@ bool System::IsPoweredOn() const {
}
void System::PrepareReschedule() {
impl->CurrentPhysicalCore().Stop();
CurrentCpuCore().PrepareReschedule();
}
void System::PrepareReschedule(const u32 core_index) {
impl->kernel.PrepareReschedule(core_index);
if (core_index < GlobalScheduler().CpuCoresCount()) {
CpuCore(core_index).PrepareReschedule();
}
}
PerfStatsResults System::GetAndResetPerfStats() {
@@ -435,31 +428,31 @@ const TelemetrySession& System::TelemetrySession() const {
}
ARM_Interface& System::CurrentArmInterface() {
return impl->CurrentPhysicalCore().ArmInterface();
return CurrentCpuCore().ArmInterface();
}
const ARM_Interface& System::CurrentArmInterface() const {
return impl->CurrentPhysicalCore().ArmInterface();
return CurrentCpuCore().ArmInterface();
}
std::size_t System::CurrentCoreIndex() const {
return impl->cpu_manager.GetActiveCoreIndex();
return CurrentCpuCore().CoreIndex();
}
Kernel::Scheduler& System::CurrentScheduler() {
return impl->CurrentPhysicalCore().Scheduler();
return CurrentCpuCore().Scheduler();
}
const Kernel::Scheduler& System::CurrentScheduler() const {
return impl->CurrentPhysicalCore().Scheduler();
return CurrentCpuCore().Scheduler();
}
Kernel::Scheduler& System::Scheduler(std::size_t core_index) {
return impl->GetPhysicalCore(core_index).Scheduler();
return CpuCore(core_index).Scheduler();
}
const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const {
return impl->GetPhysicalCore(core_index).Scheduler();
return CpuCore(core_index).Scheduler();
}
/// Gets the global scheduler
@@ -481,28 +474,28 @@ const Kernel::Process* System::CurrentProcess() const {
}
ARM_Interface& System::ArmInterface(std::size_t core_index) {
return impl->GetPhysicalCore(core_index).ArmInterface();
return CpuCore(core_index).ArmInterface();
}
const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
return impl->GetPhysicalCore(core_index).ArmInterface();
return CpuCore(core_index).ArmInterface();
}
CoreManager& System::GetCoreManager(std::size_t core_index) {
return impl->cpu_manager.GetCoreManager(core_index);
Cpu& System::CpuCore(std::size_t core_index) {
return impl->cpu_core_manager.GetCore(core_index);
}
const CoreManager& System::GetCoreManager(std::size_t core_index) const {
const Cpu& System::CpuCore(std::size_t core_index) const {
ASSERT(core_index < NUM_CPU_CORES);
return impl->cpu_manager.GetCoreManager(core_index);
return impl->cpu_core_manager.GetCore(core_index);
}
ExclusiveMonitor& System::Monitor() {
return impl->kernel.GetExclusiveMonitor();
return impl->cpu_core_manager.GetExclusiveMonitor();
}
const ExclusiveMonitor& System::Monitor() const {
return impl->kernel.GetExclusiveMonitor();
return impl->cpu_core_manager.GetExclusiveMonitor();
}
Memory::Memory& System::Memory() {
+5 -5
View File
@@ -93,7 +93,7 @@ class Memory;
namespace Core {
class ARM_Interface;
class CoreManager;
class Cpu;
class ExclusiveMonitor;
class FrameLimiter;
class PerfStats;
@@ -218,10 +218,10 @@ public:
const ARM_Interface& ArmInterface(std::size_t core_index) const;
/// Gets a CPU interface to the CPU core with the specified index
CoreManager& GetCoreManager(std::size_t core_index);
Cpu& CpuCore(std::size_t core_index);
/// Gets a CPU interface to the CPU core with the specified index
const CoreManager& GetCoreManager(std::size_t core_index) const;
const Cpu& CpuCore(std::size_t core_index) const;
/// Gets a reference to the exclusive monitor
ExclusiveMonitor& Monitor();
@@ -364,10 +364,10 @@ private:
System();
/// Returns the currently running CPU core
CoreManager& CurrentCoreManager();
Cpu& CurrentCpuCore();
/// Returns the currently running CPU core
const CoreManager& CurrentCoreManager() const;
const Cpu& CurrentCpuCore() const;
/**
* Initialize the emulated system.
+127
View File
@@ -0,0 +1,127 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <condition_variable>
#include <mutex>
#include "common/logging/log.h"
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic.h"
#endif
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/lock.h"
#include "core/settings.h"
namespace Core {
void CpuBarrier::NotifyEnd() {
std::unique_lock lock{mutex};
end = true;
condition.notify_all();
}
bool CpuBarrier::Rendezvous() {
if (!Settings::values.use_multi_core) {
// Meaningless when running in single-core mode
return true;
}
if (!end) {
std::unique_lock lock{mutex};
--cores_waiting;
if (!cores_waiting) {
cores_waiting = NUM_CPU_CORES;
condition.notify_all();
return true;
}
condition.wait(lock);
return true;
}
return false;
}
Cpu::Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier,
std::size_t core_index)
: cpu_barrier{cpu_barrier}, global_scheduler{system.GlobalScheduler()},
core_timing{system.CoreTiming()}, core_index{core_index} {
#ifdef ARCHITECTURE_x86_64
arm_interface = std::make_unique<ARM_Dynarmic>(system, exclusive_monitor, core_index);
#else
arm_interface = std::make_unique<ARM_Unicorn>(system);
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index);
}
Cpu::~Cpu() = default;
std::unique_ptr<ExclusiveMonitor> Cpu::MakeExclusiveMonitor(
[[maybe_unused]] Memory::Memory& memory, [[maybe_unused]] std::size_t num_cores) {
#ifdef ARCHITECTURE_x86_64
return std::make_unique<DynarmicExclusiveMonitor>(memory, num_cores);
#else
// TODO(merry): Passthrough exclusive monitor
return nullptr;
#endif
}
void Cpu::RunLoop(bool tight_loop) {
// Wait for all other CPU cores to complete the previous slice, such that they run in lock-step
if (!cpu_barrier.Rendezvous()) {
// If rendezvous failed, session has been killed
return;
}
Reschedule();
// If we don't have a currently active thread then don't execute instructions,
// instead advance to the next event and try to yield to the next thread
if (Kernel::GetCurrentThread() == nullptr) {
LOG_TRACE(Core, "Core-{} idling", core_index);
core_timing.Idle();
} else {
if (tight_loop) {
arm_interface->Run();
} else {
arm_interface->Step();
}
// We are stopping a run, exclusive state must be cleared
arm_interface->ClearExclusiveState();
}
core_timing.Advance();
Reschedule();
}
void Cpu::SingleStep() {
return RunLoop(false);
}
void Cpu::PrepareReschedule() {
arm_interface->PrepareReschedule();
}
void Cpu::Reschedule() {
// Lock the global kernel mutex when we manipulate the HLE state
std::lock_guard lock(HLE::g_hle_lock);
global_scheduler.SelectThread(core_index);
scheduler->TryDoContextSwitch();
}
void Cpu::Shutdown() {
scheduler->Shutdown();
}
} // namespace Core
+120
View File
@@ -0,0 +1,120 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <atomic>
#include <condition_variable>
#include <cstddef>
#include <memory>
#include <mutex>
#include "common/common_types.h"
namespace Kernel {
class GlobalScheduler;
class Scheduler;
} // namespace Kernel
namespace Core {
class System;
}
namespace Core::Timing {
class CoreTiming;
}
namespace Memory {
class Memory;
}
namespace Core {
class ARM_Interface;
class ExclusiveMonitor;
constexpr unsigned NUM_CPU_CORES{4};
class CpuBarrier {
public:
bool IsAlive() const {
return !end;
}
void NotifyEnd();
bool Rendezvous();
private:
unsigned cores_waiting{NUM_CPU_CORES};
std::mutex mutex;
std::condition_variable condition;
std::atomic<bool> end{};
};
class Cpu {
public:
Cpu(System& system, ExclusiveMonitor& exclusive_monitor, CpuBarrier& cpu_barrier,
std::size_t core_index);
~Cpu();
void RunLoop(bool tight_loop = true);
void SingleStep();
void PrepareReschedule();
ARM_Interface& ArmInterface() {
return *arm_interface;
}
const ARM_Interface& ArmInterface() const {
return *arm_interface;
}
Kernel::Scheduler& Scheduler() {
return *scheduler;
}
const Kernel::Scheduler& Scheduler() const {
return *scheduler;
}
bool IsMainCore() const {
return core_index == 0;
}
std::size_t CoreIndex() const {
return core_index;
}
void Shutdown();
/**
* Creates an exclusive monitor to handle exclusive reads/writes.
*
* @param memory The current memory subsystem that the monitor may wish
* to keep track of.
*
* @param num_cores The number of cores to assume about the CPU.
*
* @returns The constructed exclusive monitor instance, or nullptr if the current
* CPU backend is unable to use an exclusive monitor.
*/
static std::unique_ptr<ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
std::size_t num_cores);
private:
void Reschedule();
std::unique_ptr<ARM_Interface> arm_interface;
CpuBarrier& cpu_barrier;
Kernel::GlobalScheduler& global_scheduler;
std::unique_ptr<Kernel::Scheduler> scheduler;
Timing::CoreTiming& core_timing;
std::atomic<bool> reschedule_pending = false;
std::size_t core_index;
};
} // namespace Core
-70
View File
@@ -1,70 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <condition_variable>
#include <mutex>
#include "common/logging/log.h"
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic.h"
#endif
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h"
#include "core/core_manager.h"
#include "core/core_timing.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/lock.h"
#include "core/settings.h"
namespace Core {
CoreManager::CoreManager(System& system, std::size_t core_index)
: global_scheduler{system.GlobalScheduler()}, physical_core{system.Kernel().PhysicalCore(
core_index)},
core_timing{system.CoreTiming()}, core_index{core_index} {}
CoreManager::~CoreManager() = default;
void CoreManager::RunLoop(bool tight_loop) {
Reschedule();
// If we don't have a currently active thread then don't execute instructions,
// instead advance to the next event and try to yield to the next thread
if (Kernel::GetCurrentThread() == nullptr) {
LOG_TRACE(Core, "Core-{} idling", core_index);
core_timing.Idle();
} else {
if (tight_loop) {
physical_core.Run();
} else {
physical_core.Step();
}
}
core_timing.Advance();
Reschedule();
}
void CoreManager::SingleStep() {
return RunLoop(false);
}
void CoreManager::PrepareReschedule() {
physical_core.Stop();
}
void CoreManager::Reschedule() {
// Lock the global kernel mutex when we manipulate the HLE state
std::lock_guard lock(HLE::g_hle_lock);
global_scheduler.SelectThread(core_index);
physical_core.Scheduler().TryDoContextSwitch();
}
} // namespace Core
-63
View File
@@ -1,63 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <atomic>
#include <cstddef>
#include <memory>
#include "common/common_types.h"
namespace Kernel {
class GlobalScheduler;
class PhysicalCore;
} // namespace Kernel
namespace Core {
class System;
}
namespace Core::Timing {
class CoreTiming;
}
namespace Memory {
class Memory;
}
namespace Core {
constexpr unsigned NUM_CPU_CORES{4};
class CoreManager {
public:
CoreManager(System& system, std::size_t core_index);
~CoreManager();
void RunLoop(bool tight_loop = true);
void SingleStep();
void PrepareReschedule();
bool IsMainCore() const {
return core_index == 0;
}
std::size_t CoreIndex() const {
return core_index;
}
private:
void Reschedule();
Kernel::GlobalScheduler& global_scheduler;
Kernel::PhysicalCore& physical_core;
Timing::CoreTiming& core_timing;
std::atomic<bool> reschedule_pending = false;
std::size_t core_index;
};
} // namespace Core
+152
View File
@@ -0,0 +1,152 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/assert.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/cpu_core_manager.h"
#include "core/gdbstub/gdbstub.h"
#include "core/settings.h"
namespace Core {
namespace {
void RunCpuCore(const System& system, Cpu& cpu_state) {
while (system.IsPoweredOn()) {
cpu_state.RunLoop(true);
}
}
} // Anonymous namespace
CpuCoreManager::CpuCoreManager(System& system) : system{system} {}
CpuCoreManager::~CpuCoreManager() = default;
void CpuCoreManager::Initialize() {
barrier = std::make_unique<CpuBarrier>();
exclusive_monitor = Cpu::MakeExclusiveMonitor(system.Memory(), cores.size());
for (std::size_t index = 0; index < cores.size(); ++index) {
cores[index] = std::make_unique<Cpu>(system, *exclusive_monitor, *barrier, index);
}
}
void CpuCoreManager::StartThreads() {
// Create threads for CPU cores 1-3, and build thread_to_cpu map
// CPU core 0 is run on the main thread
thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
if (!Settings::values.use_multi_core) {
return;
}
for (std::size_t index = 0; index < core_threads.size(); ++index) {
core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system),
std::ref(*cores[index + 1]));
thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get();
}
}
void CpuCoreManager::Shutdown() {
barrier->NotifyEnd();
if (Settings::values.use_multi_core) {
for (auto& thread : core_threads) {
thread->join();
thread.reset();
}
}
thread_to_cpu.clear();
for (auto& cpu_core : cores) {
cpu_core->Shutdown();
cpu_core.reset();
}
exclusive_monitor.reset();
barrier.reset();
}
Cpu& CpuCoreManager::GetCore(std::size_t index) {
return *cores.at(index);
}
const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
return *cores.at(index);
}
ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
return *exclusive_monitor;
}
const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
return *exclusive_monitor;
}
Cpu& CpuCoreManager::GetCurrentCore() {
if (Settings::values.use_multi_core) {
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
ASSERT(search != thread_to_cpu.end());
ASSERT(search->second);
return *search->second;
}
// Otherwise, use single-threaded mode active_core variable
return *cores[active_core];
}
const Cpu& CpuCoreManager::GetCurrentCore() const {
if (Settings::values.use_multi_core) {
const auto& search = thread_to_cpu.find(std::this_thread::get_id());
ASSERT(search != thread_to_cpu.end());
ASSERT(search->second);
return *search->second;
}
// Otherwise, use single-threaded mode active_core variable
return *cores[active_core];
}
void CpuCoreManager::RunLoop(bool tight_loop) {
// Update thread_to_cpu in case Core 0 is run from a different host thread
thread_to_cpu[std::this_thread::get_id()] = cores[0].get();
if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket();
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
// execute. Otherwise, get out of the loop function.
if (GDBStub::GetCpuHaltFlag()) {
if (GDBStub::GetCpuStepFlag()) {
tight_loop = false;
} else {
return;
}
}
}
auto& core_timing = system.CoreTiming();
core_timing.ResetRun();
bool keep_running{};
do {
keep_running = false;
for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
core_timing.SwitchContext(active_core);
if (core_timing.CanCurrentContextRun()) {
cores[active_core]->RunLoop(tight_loop);
}
keep_running |= core_timing.CanCurrentContextRun();
}
} while (keep_running);
if (GDBStub::IsServerEnabled()) {
GDBStub::SetCpuStepFlag(false);
}
}
void CpuCoreManager::InvalidateAllInstructionCaches() {
for (auto& cpu : cores) {
cpu->ArmInterface().ClearInstructionCache();
}
}
} // namespace Core
+62
View File
@@ -0,0 +1,62 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <map>
#include <memory>
#include <thread>
namespace Core {
class Cpu;
class CpuBarrier;
class ExclusiveMonitor;
class System;
class CpuCoreManager {
public:
explicit CpuCoreManager(System& system);
CpuCoreManager(const CpuCoreManager&) = delete;
CpuCoreManager(CpuCoreManager&&) = delete;
~CpuCoreManager();
CpuCoreManager& operator=(const CpuCoreManager&) = delete;
CpuCoreManager& operator=(CpuCoreManager&&) = delete;
void Initialize();
void StartThreads();
void Shutdown();
Cpu& GetCore(std::size_t index);
const Cpu& GetCore(std::size_t index) const;
Cpu& GetCurrentCore();
const Cpu& GetCurrentCore() const;
ExclusiveMonitor& GetExclusiveMonitor();
const ExclusiveMonitor& GetExclusiveMonitor() const;
void RunLoop(bool tight_loop);
void InvalidateAllInstructionCaches();
private:
static constexpr std::size_t NUM_CPU_CORES = 4;
std::unique_ptr<ExclusiveMonitor> exclusive_monitor;
std::unique_ptr<CpuBarrier> barrier;
std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores;
std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads;
std::size_t active_core{}; ///< Active core, only used in single thread mode
/// Map of guest threads to CPU cores
std::map<std::thread::id, Cpu*> thread_to_cpu;
System& system;
};
} // namespace Core
-81
View File
@@ -1,81 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_manager.h"
#include "core/core_timing.h"
#include "core/cpu_manager.h"
#include "core/gdbstub/gdbstub.h"
namespace Core {
CpuManager::CpuManager(System& system) : system{system} {}
CpuManager::~CpuManager() = default;
void CpuManager::Initialize() {
for (std::size_t index = 0; index < core_managers.size(); ++index) {
core_managers[index] = std::make_unique<CoreManager>(system, index);
}
}
void CpuManager::Shutdown() {
for (auto& cpu_core : core_managers) {
cpu_core.reset();
}
}
CoreManager& CpuManager::GetCoreManager(std::size_t index) {
return *core_managers.at(index);
}
const CoreManager& CpuManager::GetCoreManager(std::size_t index) const {
return *core_managers.at(index);
}
CoreManager& CpuManager::GetCurrentCoreManager() {
// Otherwise, use single-threaded mode active_core variable
return *core_managers[active_core];
}
const CoreManager& CpuManager::GetCurrentCoreManager() const {
// Otherwise, use single-threaded mode active_core variable
return *core_managers[active_core];
}
void CpuManager::RunLoop(bool tight_loop) {
if (GDBStub::IsServerEnabled()) {
GDBStub::HandlePacket();
// If the loop is halted and we want to step, use a tiny (1) number of instructions to
// execute. Otherwise, get out of the loop function.
if (GDBStub::GetCpuHaltFlag()) {
if (GDBStub::GetCpuStepFlag()) {
tight_loop = false;
} else {
return;
}
}
}
auto& core_timing = system.CoreTiming();
core_timing.ResetRun();
bool keep_running{};
do {
keep_running = false;
for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) {
core_timing.SwitchContext(active_core);
if (core_timing.CanCurrentContextRun()) {
core_managers[active_core]->RunLoop(tight_loop);
}
keep_running |= core_timing.CanCurrentContextRun();
}
} while (keep_running);
if (GDBStub::IsServerEnabled()) {
GDBStub::SetCpuStepFlag(false);
}
}
} // namespace Core
-50
View File
@@ -1,50 +0,0 @@
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <memory>
namespace Core {
class CoreManager;
class System;
class CpuManager {
public:
explicit CpuManager(System& system);
CpuManager(const CpuManager&) = delete;
CpuManager(CpuManager&&) = delete;
~CpuManager();
CpuManager& operator=(const CpuManager&) = delete;
CpuManager& operator=(CpuManager&&) = delete;
void Initialize();
void Shutdown();
CoreManager& GetCoreManager(std::size_t index);
const CoreManager& GetCoreManager(std::size_t index) const;
CoreManager& GetCurrentCoreManager();
const CoreManager& GetCurrentCoreManager() const;
std::size_t GetActiveCoreIndex() const {
return active_core;
}
void RunLoop(bool tight_loop);
private:
static constexpr std::size_t NUM_CPU_CORES = 4;
std::array<std::unique_ptr<CoreManager>, NUM_CPU_CORES> core_managers;
std::size_t active_core{}; ///< Active core, only used in single thread mode
System& system;
};
} // namespace Core
-10
View File
@@ -15,13 +15,6 @@
namespace Input {
enum class AnalogDirection : u8 {
RIGHT,
LEFT,
UP,
DOWN,
};
/// An abstract class template for an input device (a button, an analog input, etc.).
template <typename StatusType>
class InputDevice {
@@ -30,9 +23,6 @@ public:
virtual StatusType GetStatus() const {
return {};
}
virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const {
return {};
}
};
/// An abstract class template for a factory that can create input devices.
+1 -1
View File
@@ -35,7 +35,7 @@
#include "common/swap.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/core_manager.h"
#include "core/core_cpu.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/scheduler.h"
+1
View File
@@ -8,6 +8,7 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/scheduler.h"
+1 -51
View File
@@ -3,15 +3,13 @@
// Refer to the license.txt file included.
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <utility>
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
@@ -19,7 +17,6 @@
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/scheduler.h"
@@ -101,7 +98,6 @@ struct KernelCore::Impl {
void Initialize(KernelCore& kernel) {
Shutdown();
InitializePhysicalCores();
InitializeSystemResourceLimit(kernel);
InitializeThreads();
InitializePreemption();
@@ -125,21 +121,6 @@ struct KernelCore::Impl {
global_scheduler.Shutdown();
named_ports.clear();
for (auto& core : cores) {
core.Shutdown();
}
cores.clear();
exclusive_monitor.reset();
}
void InitializePhysicalCores() {
exclusive_monitor =
Core::MakeExclusiveMonitor(system.Memory(), global_scheduler.CpuCoresCount());
for (std::size_t i = 0; i < global_scheduler.CpuCoresCount(); i++) {
cores.emplace_back(system, i, *exclusive_monitor);
}
}
// Creates the default system resource limit
@@ -205,9 +186,6 @@ struct KernelCore::Impl {
/// the ConnectToPort SVC.
NamedPortTable named_ports;
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
std::vector<Kernel::PhysicalCore> cores;
// System context
Core::System& system;
};
@@ -262,34 +240,6 @@ const Kernel::GlobalScheduler& KernelCore::GlobalScheduler() const {
return impl->global_scheduler;
}
Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
return impl->cores[id];
}
const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
return impl->cores[id];
}
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
return *impl->exclusive_monitor;
}
const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
return *impl->exclusive_monitor;
}
void KernelCore::InvalidateAllInstructionCaches() {
for (std::size_t i = 0; i < impl->global_scheduler.CpuCoresCount(); i++) {
PhysicalCore(i).ArmInterface().ClearInstructionCache();
}
}
void KernelCore::PrepareReschedule(std::size_t id) {
if (id < impl->global_scheduler.CpuCoresCount()) {
impl->cores[id].Stop();
}
}
void KernelCore::AddNamedPort(std::string name, std::shared_ptr<ClientPort> port) {
impl->named_ports.emplace(std::move(name), std::move(port));
}
+1 -18
View File
@@ -11,9 +11,8 @@
#include "core/hle/kernel/object.h"
namespace Core {
class ExclusiveMonitor;
class System;
} // namespace Core
}
namespace Core::Timing {
class CoreTiming;
@@ -26,7 +25,6 @@ class AddressArbiter;
class ClientPort;
class GlobalScheduler;
class HandleTable;
class PhysicalCore;
class Process;
class ResourceLimit;
class Thread;
@@ -86,21 +84,6 @@ public:
/// Gets the sole instance of the global scheduler
const Kernel::GlobalScheduler& GlobalScheduler() const;
/// Gets the an instance of the respective physical CPU core.
Kernel::PhysicalCore& PhysicalCore(std::size_t id);
/// Gets the an instance of the respective physical CPU core.
const Kernel::PhysicalCore& PhysicalCore(std::size_t id) const;
/// Stops execution of 'id' core, in order to reschedule a new thread.
void PrepareReschedule(std::size_t id);
Core::ExclusiveMonitor& GetExclusiveMonitor();
const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
void InvalidateAllInstructionCaches();
/// Adds a port to the named port table
void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port);
-51
View File
@@ -1,51 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_dynarmic.h"
#endif
#include "core/arm/exclusive_monitor.h"
#include "core/arm/unicorn/arm_unicorn.h"
#include "core/core.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
namespace Kernel {
PhysicalCore::PhysicalCore(Core::System& system, std::size_t id,
Core::ExclusiveMonitor& exclusive_monitor)
: core_index{id} {
#ifdef ARCHITECTURE_x86_64
arm_interface = std::make_unique<Core::ARM_Dynarmic>(system, exclusive_monitor, core_index);
#else
arm_interface = std::make_shared<Core::ARM_Unicorn>(system);
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
#endif
scheduler = std::make_unique<Kernel::Scheduler>(system, *arm_interface, core_index);
}
PhysicalCore::~PhysicalCore() = default;
void PhysicalCore::Run() {
arm_interface->Run();
arm_interface->ClearExclusiveState();
}
void PhysicalCore::Step() {
arm_interface->Step();
}
void PhysicalCore::Stop() {
arm_interface->PrepareReschedule();
}
void PhysicalCore::Shutdown() {
scheduler->Shutdown();
}
} // namespace Kernel
-77
View File
@@ -1,77 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <cstddef>
#include <memory>
namespace Kernel {
class Scheduler;
} // namespace Kernel
namespace Core {
class ARM_Interface;
class ExclusiveMonitor;
class System;
} // namespace Core
namespace Kernel {
class PhysicalCore {
public:
PhysicalCore(Core::System& system, std::size_t id, Core::ExclusiveMonitor& exclusive_monitor);
~PhysicalCore();
PhysicalCore(const PhysicalCore&) = delete;
PhysicalCore& operator=(const PhysicalCore&) = delete;
PhysicalCore(PhysicalCore&&) = default;
PhysicalCore& operator=(PhysicalCore&&) = default;
/// Execute current jit state
void Run();
/// Execute a single instruction in current jit.
void Step();
/// Stop JIT execution/exit
void Stop();
// Shutdown this physical core.
void Shutdown();
Core::ARM_Interface& ArmInterface() {
return *arm_interface;
}
const Core::ARM_Interface& ArmInterface() const {
return *arm_interface;
}
bool IsMainCore() const {
return core_index == 0;
}
bool IsSystemCore() const {
return core_index == 3;
}
std::size_t CoreIndex() const {
return core_index;
}
Kernel::Scheduler& Scheduler() {
return *scheduler;
}
const Kernel::Scheduler& Scheduler() const {
return *scheduler;
}
private:
std::size_t core_index;
std::unique_ptr<Core::ARM_Interface> arm_interface;
std::unique_ptr<Kernel::Scheduler> scheduler;
};
} // namespace Kernel
+1
View File
@@ -14,6 +14,7 @@
#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
+3 -7
View File
@@ -15,7 +15,7 @@
#include "common/string_util.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_manager.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/hle/kernel/address_arbiter.h"
@@ -1863,14 +1863,10 @@ static ResultCode CreateTransferMemory(Core::System& system, Handle* handle, VAd
}
auto& kernel = system.Kernel();
auto transfer_mem_handle = TransferMemory::Create(kernel, system.Memory(), addr, size, perms);
if (const auto reserve_result{transfer_mem_handle->Reserve()}; reserve_result.IsError()) {
return reserve_result;
}
auto transfer_mem_handle = TransferMemory::Create(kernel, addr, size, perms);
auto& handle_table = kernel.CurrentProcess()->GetHandleTable();
const auto result{handle_table.Create(std::move(transfer_mem_handle))};
const auto result = handle_table.Create(std::move(transfer_mem_handle));
if (result.Failed()) {
return result.Code();
}
+2 -1
View File
@@ -13,6 +13,7 @@
#include "common/thread_queue_list.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/core_timing_util.h"
#include "core/hle/kernel/errors.h"
@@ -355,7 +356,7 @@ void Thread::SetActivity(ThreadActivity value) {
// Set status if not waiting
if (status == ThreadStatus::Ready || status == ThreadStatus::Running) {
SetStatus(ThreadStatus::Paused);
kernel.PrepareReschedule(processor_id);
Core::System::GetInstance().CpuCore(processor_id).PrepareReschedule();
}
} else if (status == ThreadStatus::Paused) {
// Ready to reschedule
+8 -60
View File
@@ -8,34 +8,28 @@
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/transfer_memory.h"
#include "core/hle/result.h"
#include "core/memory.h"
namespace Kernel {
TransferMemory::TransferMemory(KernelCore& kernel, Memory::Memory& memory)
: Object{kernel}, memory{memory} {}
TransferMemory::TransferMemory(KernelCore& kernel) : Object{kernel} {}
TransferMemory::~TransferMemory() = default;
TransferMemory::~TransferMemory() {
// Release memory region when transfer memory is destroyed
Reset();
}
std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, Memory::Memory& memory,
VAddr base_address, u64 size,
MemoryPermission permissions) {
std::shared_ptr<TransferMemory> transfer_memory{
std::make_shared<TransferMemory>(kernel, memory)};
std::shared_ptr<TransferMemory> TransferMemory::Create(KernelCore& kernel, VAddr base_address,
u64 size, MemoryPermission permissions) {
std::shared_ptr<TransferMemory> transfer_memory{std::make_shared<TransferMemory>(kernel)};
transfer_memory->base_address = base_address;
transfer_memory->memory_size = size;
transfer_memory->owner_permissions = permissions;
transfer_memory->owner_process = kernel.CurrentProcess();
transfer_memory->MapMemory(base_address, size, permissions);
return transfer_memory;
}
const u8* TransferMemory::GetPointer() const {
return memory.GetPointer(base_address);
return backing_block.get()->data();
}
u64 TransferMemory::GetSize() const {
@@ -70,52 +64,6 @@ ResultCode TransferMemory::MapMemory(VAddr address, u64 size, MemoryPermission p
return RESULT_SUCCESS;
}
ResultCode TransferMemory::Reserve() {
auto& vm_manager{owner_process->VMManager()};
const auto check_range_result{vm_manager.CheckRangeState(
base_address, memory_size, MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated,
MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::All,
VMAPermission::ReadWrite, MemoryAttribute::Mask, MemoryAttribute::None,
MemoryAttribute::IpcAndDeviceMapped)};
if (check_range_result.Failed()) {
return check_range_result.Code();
}
auto [state_, permissions_, attribute] = *check_range_result;
if (const auto result{vm_manager.ReprotectRange(
base_address, memory_size, SharedMemory::ConvertPermissions(owner_permissions))};
result.IsError()) {
return result;
}
return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask,
attribute | MemoryAttribute::Locked);
}
ResultCode TransferMemory::Reset() {
auto& vm_manager{owner_process->VMManager()};
if (const auto result{vm_manager.CheckRangeState(
base_address, memory_size,
MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated,
MemoryState::FlagTransfer | MemoryState::FlagMemoryPoolAllocated, VMAPermission::None,
VMAPermission::None, MemoryAttribute::Mask, MemoryAttribute::Locked,
MemoryAttribute::IpcAndDeviceMapped)};
result.Failed()) {
return result.Code();
}
if (const auto result{
vm_manager.ReprotectRange(base_address, memory_size, VMAPermission::ReadWrite)};
result.IsError()) {
return result;
}
return vm_manager.SetMemoryAttribute(base_address, memory_size, MemoryAttribute::Mask,
MemoryAttribute::None);
}
ResultCode TransferMemory::UnmapMemory(VAddr address, u64 size) {
if (memory_size != size) {
return ERR_INVALID_SIZE;
+2 -17
View File
@@ -11,10 +11,6 @@
union ResultCode;
namespace Memory {
class Memory;
}
namespace Kernel {
class KernelCore;
@@ -30,13 +26,12 @@ enum class MemoryPermission : u32;
///
class TransferMemory final : public Object {
public:
explicit TransferMemory(KernelCore& kernel, Memory::Memory& memory);
explicit TransferMemory(KernelCore& kernel);
~TransferMemory() override;
static constexpr HandleType HANDLE_TYPE = HandleType::TransferMemory;
static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, Memory::Memory& memory,
VAddr base_address, u64 size,
static std::shared_ptr<TransferMemory> Create(KernelCore& kernel, VAddr base_address, u64 size,
MemoryPermission permissions);
TransferMemory(const TransferMemory&) = delete;
@@ -85,14 +80,6 @@ public:
///
ResultCode UnmapMemory(VAddr address, u64 size);
/// Reserves the region to be used for the transfer memory, called after the transfer memory is
/// created.
ResultCode Reserve();
/// Resets the region previously used for the transfer memory, called after the transfer memory
/// is closed.
ResultCode Reset();
private:
/// Memory block backing this instance.
std::shared_ptr<PhysicalMemory> backing_block;
@@ -111,8 +98,6 @@ private:
/// Whether or not this transfer memory instance has mapped memory.
bool is_mapped = false;
Memory::Memory& memory;
};
} // namespace Kernel
+1 -2
View File
@@ -544,8 +544,7 @@ MemoryInfo VMManager::QueryMemory(VAddr address) const {
ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask,
MemoryAttribute attribute) {
constexpr auto ignore_mask =
MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped | MemoryAttribute::Locked;
constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped;
constexpr auto attribute_mask = ~ignore_mask;
const auto result = CheckRangeState(
+29 -31
View File
@@ -98,8 +98,6 @@ enum class MemoryAttribute : u32 {
DeviceMapped = 4,
/// Uncached memory
Uncached = 8,
IpcAndDeviceMapped = LockedForIPC | DeviceMapped,
};
constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) {
@@ -656,35 +654,6 @@ public:
/// is scheduled.
Common::PageTable page_table{Memory::PAGE_BITS};
using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>;
/// Checks if an address range adheres to the specified states provided.
///
/// @param address The starting address of the address range.
/// @param size The size of the address range.
/// @param state_mask The memory state mask.
/// @param state The state to compare the individual VMA states against,
/// which is done in the form of: (vma.state & state_mask) != state.
/// @param permission_mask The memory permissions mask.
/// @param permissions The permission to compare the individual VMA permissions against,
/// which is done in the form of:
/// (vma.permission & permission_mask) != permission.
/// @param attribute_mask The memory attribute mask.
/// @param attribute The memory attributes to compare the individual VMA attributes
/// against, which is done in the form of:
/// (vma.attributes & attribute_mask) != attribute.
/// @param ignore_mask The memory attributes to ignore during the check.
///
/// @returns If successful, returns a tuple containing the memory attributes
/// (with ignored bits specified by ignore_mask unset), memory permissions, and
/// memory state across the memory range.
/// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
///
CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state,
VMAPermission permission_mask, VMAPermission permissions,
MemoryAttribute attribute_mask, MemoryAttribute attribute,
MemoryAttribute ignore_mask) const;
private:
using VMAIter = VMAMap::iterator;
@@ -738,6 +707,35 @@ private:
/// Clears out the page table
void ClearPageTable();
using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>;
/// Checks if an address range adheres to the specified states provided.
///
/// @param address The starting address of the address range.
/// @param size The size of the address range.
/// @param state_mask The memory state mask.
/// @param state The state to compare the individual VMA states against,
/// which is done in the form of: (vma.state & state_mask) != state.
/// @param permission_mask The memory permissions mask.
/// @param permissions The permission to compare the individual VMA permissions against,
/// which is done in the form of:
/// (vma.permission & permission_mask) != permission.
/// @param attribute_mask The memory attribute mask.
/// @param attribute The memory attributes to compare the individual VMA attributes
/// against, which is done in the form of:
/// (vma.attributes & attribute_mask) != attribute.
/// @param ignore_mask The memory attributes to ignore during the check.
///
/// @returns If successful, returns a tuple containing the memory attributes
/// (with ignored bits specified by ignore_mask unset), memory permissions, and
/// memory state across the memory range.
/// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
///
CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state,
VMAPermission permission_mask, VMAPermission permissions,
MemoryAttribute attribute_mask, MemoryAttribute attribute,
MemoryAttribute ignore_mask) const;
/// Gets the amount of memory currently mapped (state != Unmapped) in a range.
ResultVal<std::size_t> SizeOfAllocatedVMAsInRange(VAddr address, std::size_t size) const;
+2 -1
View File
@@ -7,6 +7,7 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h"
@@ -86,7 +87,7 @@ void WaitObject::WakeupWaitingThread(std::shared_ptr<Thread> thread) {
}
if (resume) {
thread->ResumeFromWait();
kernel.PrepareReschedule(thread->GetProcessorID());
Core::System::GetInstance().PrepareReschedule(thread->GetProcessorID());
}
}
+30 -47
View File
@@ -709,32 +709,8 @@ void ICommonStateGetter::SetCpuBoostMode(Kernel::HLERequestContext& ctx) {
apm_sys->SetCpuBoostMode(ctx);
}
class StorageDataImpl final : public IStorageImpl {
public:
explicit StorageDataImpl(std::vector<u8>&& buffer) : buffer{std::move(buffer)} {}
std::vector<u8>& GetData() override {
return buffer;
}
const std::vector<u8>& GetData() const override {
return buffer;
}
std::size_t GetSize() const override {
return buffer.size();
}
private:
std::vector<u8> buffer;
};
IStorage::IStorage(std::vector<u8>&& buffer)
: ServiceFramework("IStorage"), impl{std::make_shared<StorageDataImpl>(std::move(buffer))} {
Register();
}
void IStorage::Register() {
IStorage::IStorage(std::vector<u8> buffer)
: ServiceFramework("IStorage"), buffer(std::move(buffer)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IStorage::Open, "Open"},
@@ -747,13 +723,8 @@ void IStorage::Register() {
IStorage::~IStorage() = default;
void IStorage::Open(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorageAccessor>(*this);
const std::vector<u8>& IStorage::GetData() const {
return buffer;
}
void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
@@ -854,16 +825,17 @@ private:
void PopOutData(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
const auto storage = applet->GetBroker().PopNormalDataToGame();
if (storage == nullptr) {
LOG_ERROR(Service_AM,
"storage is a nullptr. There is no data in the current normal channel");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_NO_DATA_IN_CHANNEL);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorage>(std::move(*storage));
}
@@ -918,6 +890,15 @@ private:
std::shared_ptr<Applets::Applet> applet;
};
void IStorage::Open(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorageAccessor>(*this);
}
IStorageAccessor::IStorageAccessor(IStorage& storage)
: ServiceFramework("IStorageAccessor"), backing(storage) {
// clang-format off
@@ -939,7 +920,7 @@ void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u64>(backing.GetSize()));
rb.Push(static_cast<u64>(backing.buffer.size()));
}
void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
@@ -950,17 +931,17 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, data.size());
if (data.size() > backing.GetSize() - offset) {
if (data.size() > backing.buffer.size() - offset) {
LOG_ERROR(Service_AM,
"offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}",
backing.GetSize(), data.size(), offset);
backing.buffer.size(), data.size(), offset);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
return;
}
std::memcpy(backing.GetData().data() + offset, data.data(), data.size());
std::memcpy(backing.buffer.data() + offset, data.data(), data.size());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -974,16 +955,16 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size);
if (size > backing.GetSize() - offset) {
if (size > backing.buffer.size() - offset) {
LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}",
backing.GetSize(), size, offset);
backing.buffer.size(), size, offset);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERR_SIZE_OUT_OF_BOUNDS);
return;
}
ctx.WriteBuffer(backing.GetData().data() + offset, size);
ctx.WriteBuffer(backing.buffer.data() + offset, size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -1049,7 +1030,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
rp.SetCurrentOffset(3);
const auto handle{rp.Pop<Kernel::Handle>()};
auto transfer_mem =
const auto transfer_mem =
system.CurrentProcess()->GetHandleTable().Get<Kernel::TransferMemory>(handle);
if (transfer_mem == nullptr) {
@@ -1065,7 +1046,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorage>(std::move(memory));
rb.PushIpcInterface(std::make_shared<IStorage>(std::move(memory)));
}
IApplicationFunctions::IApplicationFunctions(Core::System& system_)
@@ -1207,11 +1188,13 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
u64 build_id{};
std::memcpy(&build_id, build_id_full.data(), sizeof(u64));
auto data = backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id});
const auto data =
backend->GetLaunchParameter({system.CurrentProcess()->GetTitleID(), build_id});
if (data.has_value()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<IStorage>(std::move(*data));
rb.PushIpcInterface<AM::IStorage>(*data);
launch_popped_application_specific = true;
return;
}
@@ -1234,7 +1217,7 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) {
std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser));
std::memcpy(buffer.data(), &params, buffer.size());
rb.PushIpcInterface<IStorage>(std::move(buffer));
rb.PushIpcInterface<AM::IStorage>(buffer);
launch_popped_account_preselect = true;
return;
}
+6 -23
View File
@@ -12,8 +12,7 @@
namespace Kernel {
class KernelCore;
class TransferMemory;
} // namespace Kernel
}
namespace Service::NVFlinger {
class NVFlinger;
@@ -189,35 +188,19 @@ private:
std::shared_ptr<AppletMessageQueue> msg_queue;
};
class IStorageImpl {
public:
virtual std::vector<u8>& GetData() = 0;
virtual const std::vector<u8>& GetData() const = 0;
virtual std::size_t GetSize() const = 0;
};
class IStorage final : public ServiceFramework<IStorage> {
public:
explicit IStorage(std::vector<u8>&& buffer);
explicit IStorage(std::vector<u8> buffer);
~IStorage() override;
std::vector<u8>& GetData() {
return impl->GetData();
}
const std::vector<u8>& GetData() const {
return impl->GetData();
}
std::size_t GetSize() const {
return impl->GetSize();
}
const std::vector<u8>& GetData() const;
private:
void Register();
void Open(Kernel::HLERequestContext& ctx);
std::shared_ptr<IStorageImpl> impl;
std::vector<u8> buffer;
friend class IStorageAccessor;
};
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
+2 -2
View File
@@ -56,7 +56,6 @@ std::unique_ptr<IStorage> AppletDataBroker::PopNormalDataToGame() {
auto out = std::move(out_channel.front());
out_channel.pop_front();
pop_out_data_event.writable->Clear();
return out;
}
@@ -75,7 +74,6 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToGame() {
auto out = std::move(out_interactive_channel.front());
out_interactive_channel.pop_front();
pop_interactive_out_data_event.writable->Clear();
return out;
}
@@ -90,6 +88,7 @@ std::unique_ptr<IStorage> AppletDataBroker::PopInteractiveDataToApplet() {
void AppletDataBroker::PushNormalDataFromGame(IStorage storage) {
in_channel.push_back(std::make_unique<IStorage>(storage));
pop_out_data_event.writable->Clear();
}
void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
@@ -99,6 +98,7 @@ void AppletDataBroker::PushNormalDataFromApplet(IStorage storage) {
void AppletDataBroker::PushInteractiveDataFromGame(IStorage storage) {
in_interactive_channel.push_back(std::make_unique<IStorage>(storage));
pop_interactive_out_data_event.writable->Clear();
}
void AppletDataBroker::PushInteractiveDataFromApplet(IStorage storage) {
+1 -1
View File
@@ -186,7 +186,7 @@ void Error::Execute() {
void Error::DisplayCompleted() {
complete = true;
broker.PushNormalDataFromApplet(IStorage{std::vector<u8>{}});
broker.PushNormalDataFromApplet(IStorage{{}});
broker.SignalStateChanged();
}
@@ -148,7 +148,7 @@ void Auth::AuthFinished(bool successful) {
std::vector<u8> out(sizeof(Return));
std::memcpy(out.data(), &return_, sizeof(Return));
broker.PushNormalDataFromApplet(IStorage{std::move(out)});
broker.PushNormalDataFromApplet(IStorage{out});
broker.SignalStateChanged();
}
@@ -198,7 +198,7 @@ void PhotoViewer::Execute() {
}
void PhotoViewer::ViewFinished() {
broker.PushNormalDataFromApplet(IStorage{std::vector<u8>{}});
broker.PushNormalDataFromApplet(IStorage{{}});
broker.SignalStateChanged();
}
@@ -50,7 +50,7 @@ void ProfileSelect::ExecuteInteractive() {
void ProfileSelect::Execute() {
if (complete) {
broker.PushNormalDataFromApplet(IStorage{std::move(final_data)});
broker.PushNormalDataFromApplet(IStorage{final_data});
return;
}
@@ -71,7 +71,7 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) {
final_data = std::vector<u8>(sizeof(UserSelectionOutput));
std::memcpy(final_data.data(), &output, final_data.size());
broker.PushNormalDataFromApplet(IStorage{std::move(final_data)});
broker.PushNormalDataFromApplet(IStorage{final_data});
broker.SignalStateChanged();
}
@@ -91,6 +91,7 @@ void SoftwareKeyboard::ExecuteInteractive() {
if (status == INTERACTIVE_STATUS_OK) {
complete = true;
broker.SignalStateChanged();
} else {
std::array<char16_t, SWKBD_OUTPUT_INTERACTIVE_BUFFER_SIZE / 2 - 2> string;
std::memcpy(string.data(), data.data() + 4, string.size() * 2);
@@ -102,8 +103,7 @@ void SoftwareKeyboard::ExecuteInteractive() {
void SoftwareKeyboard::Execute() {
if (complete) {
broker.PushNormalDataFromApplet(IStorage{std::move(final_data)});
broker.SignalStateChanged();
broker.PushNormalDataFromApplet(IStorage{final_data});
return;
}
@@ -120,7 +120,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
std::vector<u8> output_sub(SWKBD_OUTPUT_BUFFER_SIZE);
if (config.utf_8) {
const u64 size = text->size() + sizeof(u64);
const u64 size = text->size() + 8;
const auto new_text = Common::UTF16ToUTF8(*text);
std::memcpy(output_sub.data(), &size, sizeof(u64));
@@ -131,7 +131,7 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
std::memcpy(output_main.data() + 4, new_text.data(),
std::min(new_text.size(), SWKBD_OUTPUT_BUFFER_SIZE - 4));
} else {
const u64 size = text->size() * 2 + sizeof(u64);
const u64 size = text->size() * 2 + 8;
std::memcpy(output_sub.data(), &size, sizeof(u64));
std::memcpy(output_sub.data() + 8, text->data(),
std::min(text->size() * 2, SWKBD_OUTPUT_BUFFER_SIZE - 8));
@@ -145,15 +145,15 @@ void SoftwareKeyboard::WriteText(std::optional<std::u16string> text) {
final_data = output_main;
if (complete) {
broker.PushNormalDataFromApplet(IStorage{std::move(output_main)});
broker.PushNormalDataFromApplet(IStorage{output_main});
broker.SignalStateChanged();
} else {
broker.PushInteractiveDataFromApplet(IStorage{std::move(output_sub)});
broker.PushInteractiveDataFromApplet(IStorage{output_sub});
}
} else {
output_main[0] = 1;
complete = true;
broker.PushNormalDataFromApplet(IStorage{std::move(output_main)});
broker.PushNormalDataFromApplet(IStorage{output_main});
broker.SignalStateChanged();
}
}
@@ -284,7 +284,7 @@ void WebBrowser::Finalize() {
std::vector<u8> data(sizeof(WebCommonReturnValue));
std::memcpy(data.data(), &out, sizeof(WebCommonReturnValue));
broker.PushNormalDataFromApplet(IStorage{std::move(data)});
broker.PushNormalDataFromApplet(IStorage{data});
broker.SignalStateChanged();
if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) {
+12 -25
View File
@@ -250,10 +250,6 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
const auto& button_state = buttons[controller_idx];
const auto& analog_state = sticks[controller_idx];
const auto [stick_l_x_f, stick_l_y_f] =
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
const auto [stick_r_x_f, stick_r_y_f] =
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
using namespace Settings::NativeButton;
pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus());
@@ -274,32 +270,23 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus());
pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus());
pad_state.l_stick_right.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
Input::AnalogDirection::RIGHT));
pad_state.l_stick_left.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
Input::AnalogDirection::LEFT));
pad_state.l_stick_up.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
Input::AnalogDirection::UP));
pad_state.l_stick_down.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus(
Input::AnalogDirection::DOWN));
pad_state.l_stick_left.Assign(button_state[LStick_Left - BUTTON_HID_BEGIN]->GetStatus());
pad_state.l_stick_up.Assign(button_state[LStick_Up - BUTTON_HID_BEGIN]->GetStatus());
pad_state.l_stick_right.Assign(button_state[LStick_Right - BUTTON_HID_BEGIN]->GetStatus());
pad_state.l_stick_down.Assign(button_state[LStick_Down - BUTTON_HID_BEGIN]->GetStatus());
pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT));
pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT));
pad_state.r_stick_right.Assign(
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::UP));
pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]
->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN));
pad_state.r_stick_left.Assign(button_state[RStick_Left - BUTTON_HID_BEGIN]->GetStatus());
pad_state.r_stick_up.Assign(button_state[RStick_Up - BUTTON_HID_BEGIN]->GetStatus());
pad_state.r_stick_right.Assign(button_state[RStick_Right - BUTTON_HID_BEGIN]->GetStatus());
pad_state.r_stick_down.Assign(button_state[RStick_Down - BUTTON_HID_BEGIN]->GetStatus());
pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus());
pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus());
const auto [stick_l_x_f, stick_l_y_f] =
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
const auto [stick_r_x_f, stick_r_y_f] =
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
lstick_entry.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
lstick_entry.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
+4 -44
View File
@@ -42,26 +42,6 @@ void BSD::Socket(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno
}
void BSD::Select(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // ret
rb.Push<u32>(0); // bsd errno
}
void BSD::Bind(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // ret
rb.Push<u32>(0); // bsd errno
}
void BSD::Connect(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
@@ -72,26 +52,6 @@ void BSD::Connect(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(0); // bsd errno
}
void BSD::Listen(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // ret
rb.Push<u32>(0); // bsd errno
}
void BSD::SetSockOpt(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); // ret
rb.Push<u32>(0); // bsd errno
}
void BSD::SendTo(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) called");
@@ -120,7 +80,7 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
{2, &BSD::Socket, "Socket"},
{3, nullptr, "SocketExempt"},
{4, nullptr, "Open"},
{5, &BSD::Select, "Select"},
{5, nullptr, "Select"},
{6, nullptr, "Poll"},
{7, nullptr, "Sysctl"},
{8, nullptr, "Recv"},
@@ -128,15 +88,15 @@ BSD::BSD(const char* name) : ServiceFramework(name) {
{10, nullptr, "Send"},
{11, &BSD::SendTo, "SendTo"},
{12, nullptr, "Accept"},
{13, &BSD::Bind, "Bind"},
{13, nullptr, "Bind"},
{14, &BSD::Connect, "Connect"},
{15, nullptr, "GetPeerName"},
{16, nullptr, "GetSockName"},
{17, nullptr, "GetSockOpt"},
{18, &BSD::Listen, "Listen"},
{18, nullptr, "Listen"},
{19, nullptr, "Ioctl"},
{20, nullptr, "Fcntl"},
{21, &BSD::SetSockOpt, "SetSockOpt"},
{21, nullptr, "SetSockOpt"},
{22, nullptr, "Shutdown"},
{23, nullptr, "ShutdownAllSockets"},
{24, nullptr, "Write"},
-4
View File
@@ -18,11 +18,7 @@ private:
void RegisterClient(Kernel::HLERequestContext& ctx);
void StartMonitoring(Kernel::HLERequestContext& ctx);
void Socket(Kernel::HLERequestContext& ctx);
void Select(Kernel::HLERequestContext& ctx);
void Bind(Kernel::HLERequestContext& ctx);
void Connect(Kernel::HLERequestContext& ctx);
void Listen(Kernel::HLERequestContext& ctx);
void SetSockOpt(Kernel::HLERequestContext& ctx);
void SendTo(Kernel::HLERequestContext& ctx);
void Close(Kernel::HLERequestContext& ctx);
-16
View File
@@ -342,22 +342,6 @@ public:
return std::make_tuple<float, float>(0.0f, 0.0f);
}
bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
const auto [x, y] = GetStatus();
const float directional_deadzone = 0.4f;
switch (direction) {
case Input::AnalogDirection::RIGHT:
return x > directional_deadzone;
case Input::AnalogDirection::LEFT:
return x < -directional_deadzone;
case Input::AnalogDirection::UP:
return y > directional_deadzone;
case Input::AnalogDirection::DOWN:
return y < -directional_deadzone;
}
return false;
}
private:
std::shared_ptr<SDLJoystick> joystick;
const int axis_x;
-2
View File
@@ -29,8 +29,6 @@ add_library(video_core STATIC
gpu_synch.h
gpu_thread.cpp
gpu_thread.h
guest_driver.cpp
guest_driver.h
macro_interpreter.cpp
macro_interpreter.h
memory_manager.cpp
@@ -9,7 +9,6 @@
#include "common/common_types.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/engines/shader_type.h"
#include "video_core/guest_driver.h"
#include "video_core/textures/texture.h"
namespace Tegra::Engines {
@@ -107,9 +106,6 @@ public:
virtual SamplerDescriptor AccessBindlessSampler(ShaderType stage, u64 const_buffer,
u64 offset) const = 0;
virtual u32 GetBoundBuffer() const = 0;
virtual VideoCore::GuestDriverProfile& AccessGuestDriverProfile() = 0;
virtual const VideoCore::GuestDriverProfile& AccessGuestDriverProfile() const = 0;
};
} // namespace Tegra::Engines
@@ -94,14 +94,6 @@ SamplerDescriptor KeplerCompute::AccessBindlessSampler(ShaderType stage, u64 con
return result;
}
VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() {
return rasterizer.AccessGuestDriverProfile();
}
const VideoCore::GuestDriverProfile& KeplerCompute::AccessGuestDriverProfile() const {
return rasterizer.AccessGuestDriverProfile();
}
void KeplerCompute::ProcessLaunch() {
const GPUVAddr launch_desc_loc = regs.launch_desc_loc.Address();
memory_manager.ReadBlockUnsafe(launch_desc_loc, &launch_description,
-4
View File
@@ -218,10 +218,6 @@ public:
return regs.tex_cb_index;
}
VideoCore::GuestDriverProfile& AccessGuestDriverProfile() override;
const VideoCore::GuestDriverProfile& AccessGuestDriverProfile() const override;
private:
Core::System& system;
VideoCore::RasterizerInterface& rasterizer;
-8
View File
@@ -784,12 +784,4 @@ SamplerDescriptor Maxwell3D::AccessBindlessSampler(ShaderType stage, u64 const_b
return result;
}
VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() {
return rasterizer.AccessGuestDriverProfile();
}
const VideoCore::GuestDriverProfile& Maxwell3D::AccessGuestDriverProfile() const {
return rasterizer.AccessGuestDriverProfile();
}
} // namespace Tegra::Engines
-4
View File
@@ -1306,10 +1306,6 @@ public:
return regs.tex_cb_index;
}
VideoCore::GuestDriverProfile& AccessGuestDriverProfile() override;
const VideoCore::GuestDriverProfile& AccessGuestDriverProfile() const override;
/// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than
/// we've seen used.
using MacroMemory = std::array<u32, 0x40000>;
-30
View File
@@ -227,28 +227,6 @@ enum class AtomicOp : u64 {
Exch = 8,
};
enum class GlobalAtomicOp : u64 {
Add = 0,
Min = 1,
Max = 2,
Inc = 3,
Dec = 4,
And = 5,
Or = 6,
Xor = 7,
Exch = 8,
SafeAdd = 10,
};
enum class GlobalAtomicType : u64 {
U32 = 0,
S32 = 1,
U64 = 2,
F32_FTZ_RN = 3,
F16x2_FTZ_RN = 4,
S64 = 5,
};
enum class UniformType : u64 {
UnsignedByte = 0,
SignedByte = 1,
@@ -979,12 +957,6 @@ union Instruction {
BitField<46, 2, u64> cache_mode;
} stg;
union {
BitField<52, 4, GlobalAtomicOp> operation;
BitField<49, 3, GlobalAtomicType> type;
BitField<28, 20, s64> offset;
} atom;
union {
BitField<52, 4, AtomicOp> operation;
BitField<28, 2, AtomicType> type;
@@ -1718,7 +1690,6 @@ public:
ST_S,
ST, // Store in generic memory
STG, // Store in global memory
ATOM, // Atomic operation on global memory
ATOMS, // Atomic operation on shared memory
AL2P, // Transforms attribute memory into physical memory
TEX,
@@ -2023,7 +1994,6 @@ private:
INST("1110111101010---", Id::ST_L, Type::Memory, "ST_L"),
INST("101-------------", Id::ST, Type::Memory, "ST"),
INST("1110111011011---", Id::STG, Type::Memory, "STG"),
INST("11101101--------", Id::ATOM, Type::Memory, "ATOM"),
INST("11101100--------", Id::ATOMS, Type::Memory, "ATOMS"),
INST("1110111110100---", Id::AL2P, Type::Memory, "AL2P"),
INST("110000----111---", Id::TEX, Type::Texture, "TEX"),
-36
View File
@@ -1,36 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <limits>
#include "video_core/guest_driver.h"
namespace VideoCore {
void GuestDriverProfile::DeduceTextureHandlerSize(std::vector<u32>&& bound_offsets) {
if (texture_handler_size_deduced) {
return;
}
const std::size_t size = bound_offsets.size();
if (size < 2) {
return;
}
std::sort(bound_offsets.begin(), bound_offsets.end(), std::less{});
u32 min_val = std::numeric_limits<u32>::max();
for (std::size_t i = 1; i < size; ++i) {
if (bound_offsets[i] == bound_offsets[i - 1]) {
continue;
}
const u32 new_min = bound_offsets[i] - bound_offsets[i - 1];
min_val = std::min(min_val, new_min);
}
if (min_val > 2) {
return;
}
texture_handler_size_deduced = true;
texture_handler_size = min_texture_handler_size * min_val;
}
} // namespace VideoCore
-41
View File
@@ -1,41 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include "common/common_types.h"
namespace VideoCore {
/**
* The GuestDriverProfile class is used to learn about the GPU drivers behavior and collect
* information necessary for impossible to avoid HLE methods like shader tracks as they are
* Entscheidungsproblems.
*/
class GuestDriverProfile {
public:
void DeduceTextureHandlerSize(std::vector<u32>&& bound_offsets);
u32 GetTextureHandlerSize() const {
return texture_handler_size;
}
bool TextureHandlerSizeKnown() const {
return texture_handler_size_deduced;
}
private:
// Minimum size of texture handler any driver can use.
static constexpr u32 min_texture_handler_size = 4;
// This goes with Vulkan and OpenGL standards but Nvidia GPUs can easily
// use 4 bytes instead. Thus, certain drivers may squish the size.
static constexpr u32 default_texture_handler_size = 8;
u32 texture_handler_size = default_texture_handler_size;
bool texture_handler_size_deduced = false;
};
} // namespace VideoCore
-14
View File
@@ -9,7 +9,6 @@
#include "common/common_types.h"
#include "video_core/engines/fermi_2d.h"
#include "video_core/gpu.h"
#include "video_core/guest_driver.h"
namespace Tegra {
class MemoryManager;
@@ -79,18 +78,5 @@ public:
/// Initialize disk cached resources for the game being emulated
virtual void LoadDiskResources(const std::atomic_bool& stop_loading = false,
const DiskResourceLoadCallback& callback = {}) {}
/// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver.
GuestDriverProfile& AccessGuestDriverProfile() {
return guest_driver_profile;
}
/// Grant access to the Guest Driver Profile for recording/obtaining info on the guest driver.
const GuestDriverProfile& AccessGuestDriverProfile() const {
return guest_driver_profile;
}
private:
GuestDriverProfile guest_driver_profile{};
};
} // namespace VideoCore
@@ -55,20 +55,16 @@ namespace {
template <typename Engine, typename Entry>
Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry& entry,
Tegra::Engines::ShaderType shader_type,
std::size_t index = 0) {
Tegra::Engines::ShaderType shader_type) {
if (entry.IsBindless()) {
const Tegra::Texture::TextureHandle tex_handle =
engine.AccessConstBuffer32(shader_type, entry.GetBuffer(), entry.GetOffset());
return engine.GetTextureInfo(tex_handle);
}
const auto& gpu_profile = engine.AccessGuestDriverProfile();
const u32 offset =
entry.GetOffset() + static_cast<u32>(index * gpu_profile.GetTextureHandlerSize());
if constexpr (std::is_same_v<Engine, Tegra::Engines::Maxwell3D>) {
return engine.GetStageTexture(shader_type, offset);
return engine.GetStageTexture(shader_type, entry.GetOffset());
} else {
return engine.GetTexture(offset);
return engine.GetTexture(entry.GetOffset());
}
}
@@ -946,15 +942,8 @@ void RasterizerOpenGL::SetupDrawTextures(std::size_t stage_index, const Shader&
u32 binding = device.GetBaseBindings(stage_index).sampler;
for (const auto& entry : shader->GetShaderEntries().samplers) {
const auto shader_type = static_cast<Tegra::Engines::ShaderType>(stage_index);
if (!entry.IsIndexed()) {
const auto texture = GetTextureInfo(maxwell3d, entry, shader_type);
SetupTexture(binding++, texture, entry);
} else {
for (std::size_t i = 0; i < entry.Size(); ++i) {
const auto texture = GetTextureInfo(maxwell3d, entry, shader_type, i);
SetupTexture(binding++, texture, entry);
}
}
const auto texture = GetTextureInfo(maxwell3d, entry, shader_type);
SetupTexture(binding++, texture, entry);
}
}
@@ -963,17 +952,8 @@ void RasterizerOpenGL::SetupComputeTextures(const Shader& kernel) {
const auto& compute = system.GPU().KeplerCompute();
u32 binding = 0;
for (const auto& entry : kernel->GetShaderEntries().samplers) {
if (!entry.IsIndexed()) {
const auto texture =
GetTextureInfo(compute, entry, Tegra::Engines::ShaderType::Compute);
SetupTexture(binding++, texture, entry);
} else {
for (std::size_t i = 0; i < entry.Size(); ++i) {
const auto texture =
GetTextureInfo(compute, entry, Tegra::Engines::ShaderType::Compute, i);
SetupTexture(binding++, texture, entry);
}
}
const auto texture = GetTextureInfo(compute, entry, Tegra::Engines::ShaderType::Compute);
SetupTexture(binding++, texture, entry);
}
}
@@ -214,7 +214,6 @@ std::unique_ptr<ConstBufferLocker> MakeLocker(Core::System& system, ShaderType s
}
void FillLocker(ConstBufferLocker& locker, const ShaderDiskCacheUsage& usage) {
locker.SetBoundBuffer(usage.bound_buffer);
for (const auto& key : usage.keys) {
const auto [buffer, offset] = key.first;
locker.InsertKey(buffer, offset, key.second);
@@ -419,8 +418,7 @@ bool CachedShader::EnsureValidLockerVariant() {
ShaderDiskCacheUsage CachedShader::GetUsage(const ProgramVariant& variant,
const ConstBufferLocker& locker) const {
return ShaderDiskCacheUsage{unique_identifier, variant,
locker.GetBoundBuffer(), locker.GetKeys(),
return ShaderDiskCacheUsage{unique_identifier, variant, locker.GetKeys(),
locker.GetBoundSamplers(), locker.GetBindlessSamplers()};
}
@@ -391,7 +391,6 @@ public:
DeclareVertex();
DeclareGeometry();
DeclareRegisters();
DeclareCustomVariables();
DeclarePredicates();
DeclareLocalMemory();
DeclareInternalFlags();
@@ -504,16 +503,6 @@ private:
}
}
void DeclareCustomVariables() {
const u32 num_custom_variables = ir.GetNumCustomVariables();
for (u32 i = 0; i < num_custom_variables; ++i) {
code.AddLine("float {} = 0.0f;", GetCustomVariable(i));
}
if (num_custom_variables > 0) {
code.AddNewLine();
}
}
void DeclarePredicates() {
const auto& predicates = ir.GetPredicates();
for (const auto pred : predicates) {
@@ -666,8 +655,7 @@ private:
u32 binding = device.GetBaseBindings(stage).sampler;
for (const auto& sampler : ir.GetSamplers()) {
const std::string name = GetSampler(sampler);
const std::string description = fmt::format("layout (binding = {}) uniform", binding);
binding += sampler.IsIndexed() ? sampler.Size() : 1;
const std::string description = fmt::format("layout (binding = {}) uniform", binding++);
std::string sampler_type = [&]() {
if (sampler.IsBuffer()) {
@@ -694,11 +682,7 @@ private:
sampler_type += "Shadow";
}
if (!sampler.IsIndexed()) {
code.AddLine("{} {} {};", description, sampler_type, name);
} else {
code.AddLine("{} {} {}[{}];", description, sampler_type, name, sampler.Size());
}
code.AddLine("{} {} {};", description, sampler_type, name);
}
if (!ir.GetSamplers().empty()) {
code.AddNewLine();
@@ -791,11 +775,6 @@ private:
return {GetRegister(index), Type::Float};
}
if (const auto cv = std::get_if<CustomVarNode>(&*node)) {
const u32 index = cv->GetIndex();
return {GetCustomVariable(index), Type::Float};
}
if (const auto immediate = std::get_if<ImmediateNode>(&*node)) {
const u32 value = immediate->GetValue();
if (value < 10) {
@@ -1040,6 +1019,7 @@ private:
}
return {{"gl_ViewportIndex", Type::Int}};
case 3:
UNIMPLEMENTED_MSG("Requires some state changes for gl_PointSize to work in shader");
return {{"gl_PointSize", Type::Float}};
}
return {};
@@ -1119,11 +1099,7 @@ private:
} else if (!meta->ptp.empty()) {
expr += "Offsets";
}
if (!meta->sampler.IsIndexed()) {
expr += '(' + GetSampler(meta->sampler) + ", ";
} else {
expr += '(' + GetSampler(meta->sampler) + '[' + Visit(meta->index).AsUint() + "], ";
}
expr += '(' + GetSampler(meta->sampler) + ", ";
expr += coord_constructors.at(count + (has_array ? 1 : 0) +
(has_shadow && !separate_dc ? 1 : 0) - 1);
expr += '(';
@@ -1335,8 +1311,6 @@ private:
const std::string final_offset = fmt::format("({} - {}) >> 2", real, base);
target = {fmt::format("{}[{}]", GetGlobalMemory(gmem->GetDescriptor()), final_offset),
Type::Uint};
} else if (const auto cv = std::get_if<CustomVarNode>(&*dest)) {
target = {GetCustomVariable(cv->GetIndex()), Type::Float};
} else {
UNREACHABLE_MSG("Assign called without a proper target");
}
@@ -1884,7 +1858,10 @@ private:
template <const std::string_view& opname, Type type>
Expression Atomic(Operation operation) {
return {fmt::format("atomic{}({}, {})", opname, Visit(operation[0]).GetCode(),
ASSERT(stage == ShaderType::Compute);
auto& smem = std::get<SmemNode>(*operation[0]);
return {fmt::format("atomic{}(smem[{} >> 2], {})", opname, Visit(smem.GetAddress()).AsInt(),
Visit(operation[1]).As(type)),
type};
}
@@ -2264,10 +2241,6 @@ private:
return GetDeclarationWithSuffix(index, "gpr");
}
std::string GetCustomVariable(u32 index) const {
return GetDeclarationWithSuffix(index, "custom_var");
}
std::string GetPredicate(Tegra::Shader::Pred pred) const {
return GetDeclarationWithSuffix(static_cast<u32>(pred), "pred");
}
@@ -53,7 +53,7 @@ struct BindlessSamplerKey {
Tegra::Engines::SamplerDescriptor sampler{};
};
constexpr u32 NativeVersion = 12;
constexpr u32 NativeVersion = 11;
// Making sure sizes doesn't change by accident
static_assert(sizeof(ProgramVariant) == 20);
@@ -186,8 +186,7 @@ ShaderDiskCacheOpenGL::LoadTransferable() {
u32 num_bound_samplers{};
u32 num_bindless_samplers{};
if (file.ReadArray(&usage.unique_identifier, 1) != 1 ||
file.ReadArray(&usage.variant, 1) != 1 ||
file.ReadArray(&usage.bound_buffer, 1) != 1 || file.ReadArray(&num_keys, 1) != 1 ||
file.ReadArray(&usage.variant, 1) != 1 || file.ReadArray(&num_keys, 1) != 1 ||
file.ReadArray(&num_bound_samplers, 1) != 1 ||
file.ReadArray(&num_bindless_samplers, 1) != 1) {
LOG_ERROR(Render_OpenGL, error_loading);
@@ -282,9 +281,7 @@ ShaderDiskCacheOpenGL::LoadPrecompiledFile(FileUtil::IOFile& file) {
u32 num_bindless_samplers{};
ShaderDiskCacheUsage usage;
if (!LoadObjectFromPrecompiled(usage.unique_identifier) ||
!LoadObjectFromPrecompiled(usage.variant) ||
!LoadObjectFromPrecompiled(usage.bound_buffer) ||
!LoadObjectFromPrecompiled(num_keys) ||
!LoadObjectFromPrecompiled(usage.variant) || !LoadObjectFromPrecompiled(num_keys) ||
!LoadObjectFromPrecompiled(num_bound_samplers) ||
!LoadObjectFromPrecompiled(num_bindless_samplers)) {
return {};
@@ -396,7 +393,6 @@ void ShaderDiskCacheOpenGL::SaveUsage(const ShaderDiskCacheUsage& usage) {
if (file.WriteObject(TransferableEntryKind::Usage) != 1 ||
file.WriteObject(usage.unique_identifier) != 1 || file.WriteObject(usage.variant) != 1 ||
file.WriteObject(usage.bound_buffer) != 1 ||
file.WriteObject(static_cast<u32>(usage.keys.size())) != 1 ||
file.WriteObject(static_cast<u32>(usage.bound_samplers.size())) != 1 ||
file.WriteObject(static_cast<u32>(usage.bindless_samplers.size())) != 1) {
@@ -451,7 +447,7 @@ void ShaderDiskCacheOpenGL::SaveDump(const ShaderDiskCacheUsage& usage, GLuint p
};
if (!SaveObjectToPrecompiled(usage.unique_identifier) ||
!SaveObjectToPrecompiled(usage.variant) || !SaveObjectToPrecompiled(usage.bound_buffer) ||
!SaveObjectToPrecompiled(usage.variant) ||
!SaveObjectToPrecompiled(static_cast<u32>(usage.keys.size())) ||
!SaveObjectToPrecompiled(static_cast<u32>(usage.bound_samplers.size())) ||
!SaveObjectToPrecompiled(static_cast<u32>(usage.bindless_samplers.size()))) {
@@ -79,7 +79,6 @@ static_assert(std::is_trivially_copyable_v<ProgramVariant>);
struct ShaderDiskCacheUsage {
u64 unique_identifier{};
ProgramVariant variant;
u32 bound_buffer{};
VideoCommon::Shader::KeyMap keys;
VideoCommon::Shader::BoundSamplerMap bound_samplers;
VideoCommon::Shader::BindlessSamplerMap bindless_samplers;
@@ -176,19 +176,6 @@ GLint GetSwizzleSource(SwizzleSource source) {
return GL_NONE;
}
GLenum GetComponent(PixelFormat format, bool is_first) {
switch (format) {
case PixelFormat::Z24S8:
case PixelFormat::Z32FS8:
return is_first ? GL_DEPTH_COMPONENT : GL_STENCIL_INDEX;
case PixelFormat::S8Z24:
return is_first ? GL_STENCIL_INDEX : GL_DEPTH_COMPONENT;
default:
UNREACHABLE();
return GL_DEPTH_COMPONENT;
}
}
void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) {
if (params.IsBuffer()) {
return;
@@ -197,7 +184,7 @@ void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) {
glTextureParameteri(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTextureParameteri(texture, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTextureParameteri(texture, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, static_cast<GLint>(params.num_levels - 1));
glTextureParameteri(texture, GL_TEXTURE_MAX_LEVEL, params.num_levels - 1);
if (params.num_levels == 1) {
glTextureParameterf(texture, GL_TEXTURE_LOD_BIAS, 1000.0f);
}
@@ -429,21 +416,11 @@ void CachedSurfaceView::ApplySwizzle(SwizzleSource x_source, SwizzleSource y_sou
if (new_swizzle == swizzle)
return;
swizzle = new_swizzle;
const std::array gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source),
GetSwizzleSource(z_source), GetSwizzleSource(w_source)};
const std::array<GLint, 4> gl_swizzle = {GetSwizzleSource(x_source), GetSwizzleSource(y_source),
GetSwizzleSource(z_source),
GetSwizzleSource(w_source)};
const GLuint handle = GetTexture();
const PixelFormat format = surface.GetSurfaceParams().pixel_format;
switch (format) {
case PixelFormat::Z24S8:
case PixelFormat::Z32FS8:
case PixelFormat::S8Z24:
glTextureParameteri(handle, GL_DEPTH_STENCIL_TEXTURE_MODE,
GetComponent(format, x_source == SwizzleSource::R));
break;
default:
glTextureParameteriv(handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data());
break;
}
glTextureParameteriv(handle, GL_TEXTURE_SWIZZLE_RGBA, gl_swizzle.data());
}
OGLTextureView CachedSurfaceView::CreateTextureView() const {
@@ -552,11 +529,8 @@ void TextureCacheOpenGL::ImageBlit(View& src_view, View& dst_view,
const Common::Rectangle<u32>& dst_rect = copy_config.dst_rect;
const bool is_linear = copy_config.filter == Tegra::Engines::Fermi2D::Filter::Linear;
glBlitFramebuffer(static_cast<GLint>(src_rect.left), static_cast<GLint>(src_rect.top),
static_cast<GLint>(src_rect.right), static_cast<GLint>(src_rect.bottom),
static_cast<GLint>(dst_rect.left), static_cast<GLint>(dst_rect.top),
static_cast<GLint>(dst_rect.right), static_cast<GLint>(dst_rect.bottom),
buffers,
glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
dst_rect.top, dst_rect.right, dst_rect.bottom, buffers,
is_linear && (buffers == GL_COLOR_BUFFER_BIT) ? GL_LINEAR : GL_NEAREST);
}
@@ -353,7 +353,6 @@ private:
DeclareFragment();
DeclareCompute();
DeclareRegisters();
DeclareCustomVariables();
DeclarePredicates();
DeclareLocalMemory();
DeclareSharedMemory();
@@ -587,15 +586,6 @@ private:
}
}
void DeclareCustomVariables() {
const u32 num_custom_variables = ir.GetNumCustomVariables();
for (u32 i = 0; i < num_custom_variables; ++i) {
const Id id = OpVariable(t_prv_float, spv::StorageClass::Private, v_float_zero);
Name(id, fmt::format("custom_var_{}", i));
custom_variables.emplace(i, AddGlobalVariable(id));
}
}
void DeclarePredicates() {
for (const auto pred : ir.GetPredicates()) {
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
@@ -992,11 +982,6 @@ private:
return {OpLoad(t_float, registers.at(index)), Type::Float};
}
if (const auto cv = std::get_if<CustomVarNode>(&*node)) {
const u32 index = cv->GetIndex();
return {OpLoad(t_float, custom_variables.at(index)), Type::Float};
}
if (const auto immediate = std::get_if<ImmediateNode>(&*node)) {
return {Constant(t_uint, immediate->GetValue()), Type::Uint};
}
@@ -1138,7 +1123,15 @@ private:
}
if (const auto gmem = std::get_if<GmemNode>(&*node)) {
return {OpLoad(t_uint, GetGlobalMemoryPointer(*gmem)), Type::Uint};
const Id gmem_buffer = global_buffers.at(gmem->GetDescriptor());
const Id real = AsUint(Visit(gmem->GetRealAddress()));
const Id base = AsUint(Visit(gmem->GetBaseAddress()));
Id offset = OpISub(t_uint, real, base);
offset = OpUDiv(t_uint, offset, Constant(t_uint, 4U));
return {OpLoad(t_float,
OpAccessChain(t_gmem_float, gmem_buffer, Constant(t_uint, 0U), offset)),
Type::Float};
}
if (const auto lmem = std::get_if<LmemNode>(&*node)) {
@@ -1149,7 +1142,10 @@ private:
}
if (const auto smem = std::get_if<SmemNode>(&*node)) {
return {OpLoad(t_uint, GetSharedMemoryPointer(*smem)), Type::Uint};
Id address = AsUint(Visit(smem->GetAddress()));
address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U));
const Id pointer = OpAccessChain(t_smem_uint, shared_memory, address);
return {OpLoad(t_uint, pointer), Type::Uint};
}
if (const auto internal_flag = std::get_if<InternalFlagNode>(&*node)) {
@@ -1343,13 +1339,20 @@ private:
target = {OpAccessChain(t_prv_float, local_memory, address), Type::Float};
} else if (const auto smem = std::get_if<SmemNode>(&*dest)) {
target = {GetSharedMemoryPointer(*smem), Type::Uint};
ASSERT(stage == ShaderType::Compute);
Id address = AsUint(Visit(smem->GetAddress()));
address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U));
target = {OpAccessChain(t_smem_uint, shared_memory, address), Type::Uint};
} else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
target = {GetGlobalMemoryPointer(*gmem), Type::Uint};
const Id real = AsUint(Visit(gmem->GetRealAddress()));
const Id base = AsUint(Visit(gmem->GetBaseAddress()));
const Id diff = OpISub(t_uint, real, base);
const Id offset = OpShiftRightLogical(t_uint, diff, Constant(t_uint, 2));
} else if (const auto cv = std::get_if<CustomVarNode>(&*dest)) {
target = {custom_variables.at(cv->GetIndex()), Type::Float};
const Id gmem_buffer = global_buffers.at(gmem->GetDescriptor());
target = {OpAccessChain(t_gmem_float, gmem_buffer, Constant(t_uint, 0), offset),
Type::Float};
} else {
UNIMPLEMENTED();
@@ -1801,16 +1804,11 @@ private:
return {};
}
Expression AtomicAdd(Operation operation) {
Id pointer;
if (const auto smem = std::get_if<SmemNode>(&*operation[0])) {
pointer = GetSharedMemoryPointer(*smem);
} else if (const auto gmem = std::get_if<GmemNode>(&*operation[0])) {
pointer = GetGlobalMemoryPointer(*gmem);
} else {
UNREACHABLE();
return {Constant(t_uint, 0), Type::Uint};
}
Expression UAtomicAdd(Operation operation) {
const auto& smem = std::get<SmemNode>(*operation[0]);
Id address = AsUint(Visit(smem.GetAddress()));
address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U));
const Id pointer = OpAccessChain(t_smem_uint, shared_memory, address);
const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device));
const Id semantics = Constant(t_uint, 0U);
@@ -2245,22 +2243,6 @@ private:
return {};
}
Id GetGlobalMemoryPointer(const GmemNode& gmem) {
const Id real = AsUint(Visit(gmem.GetRealAddress()));
const Id base = AsUint(Visit(gmem.GetBaseAddress()));
const Id diff = OpISub(t_uint, real, base);
const Id offset = OpShiftRightLogical(t_uint, diff, Constant(t_uint, 2));
const Id buffer = global_buffers.at(gmem.GetDescriptor());
return OpAccessChain(t_gmem_uint, buffer, Constant(t_uint, 0), offset);
}
Id GetSharedMemoryPointer(const SmemNode& smem) {
ASSERT(stage == ShaderType::Compute);
Id address = AsUint(Visit(smem.GetAddress()));
address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U));
return OpAccessChain(t_smem_uint, shared_memory, address);
}
static constexpr std::array operation_decompilers = {
&SPIRVDecompiler::Assign,
@@ -2407,7 +2389,7 @@ private:
&SPIRVDecompiler::AtomicImageXor,
&SPIRVDecompiler::AtomicImageExchange,
&SPIRVDecompiler::AtomicAdd,
&SPIRVDecompiler::UAtomicAdd,
&SPIRVDecompiler::Branch,
&SPIRVDecompiler::BranchIndirect,
@@ -2503,9 +2485,9 @@ private:
Id t_smem_uint{};
const Id t_gmem_uint = TypePointer(spv::StorageClass::StorageBuffer, t_uint);
const Id t_gmem_float = TypePointer(spv::StorageClass::StorageBuffer, t_float);
const Id t_gmem_array =
Name(Decorate(TypeRuntimeArray(t_uint), spv::Decoration::ArrayStride, 4U), "GmemArray");
Name(Decorate(TypeRuntimeArray(t_float), spv::Decoration::ArrayStride, 4U), "GmemArray");
const Id t_gmem_struct = MemberDecorate(
Decorate(TypeStruct(t_gmem_array), spv::Decoration::Block), 0, spv::Decoration::Offset, 0);
const Id t_gmem_ssbo = TypePointer(spv::StorageClass::StorageBuffer, t_gmem_struct);
@@ -2526,7 +2508,6 @@ private:
Id out_vertex{};
Id in_vertex{};
std::map<u32, Id> registers;
std::map<u32, Id> custom_variables;
std::map<Tegra::Shader::Pred, Id> predicates;
std::map<u32, Id> flow_variables;
Id local_memory{};
+5 -5
View File
@@ -65,8 +65,8 @@ public:
void DetachSegment(ASTNode start, ASTNode end);
void Remove(ASTNode node);
ASTNode first;
ASTNode last;
ASTNode first{};
ASTNode last{};
};
class ASTProgram {
@@ -299,9 +299,9 @@ private:
friend class ASTZipper;
ASTData data;
ASTNode parent;
ASTNode next;
ASTNode previous;
ASTNode parent{};
ASTNode next{};
ASTNode previous{};
ASTZipper* manager{};
};
@@ -66,18 +66,6 @@ std::optional<Tegra::Engines::SamplerDescriptor> ConstBufferLocker::ObtainBindle
return value;
}
std::optional<u32> ConstBufferLocker::ObtainBoundBuffer() {
if (bound_buffer_saved) {
return bound_buffer;
}
if (!engine) {
return std::nullopt;
}
bound_buffer_saved = true;
bound_buffer = engine->GetBoundBuffer();
return bound_buffer;
}
void ConstBufferLocker::InsertKey(u32 buffer, u32 offset, u32 value) {
keys.insert_or_assign({buffer, offset}, value);
}
@@ -90,11 +78,6 @@ void ConstBufferLocker::InsertBindlessSampler(u32 buffer, u32 offset, SamplerDes
bindless_samplers.insert_or_assign({buffer, offset}, sampler);
}
void ConstBufferLocker::SetBoundBuffer(u32 buffer) {
bound_buffer_saved = true;
bound_buffer = buffer;
}
bool ConstBufferLocker::IsConsistent() const {
if (!engine) {
return false;
@@ -10,7 +10,6 @@
#include "common/hash.h"
#include "video_core/engines/const_buffer_engine_interface.h"
#include "video_core/engines/shader_type.h"
#include "video_core/guest_driver.h"
namespace VideoCommon::Shader {
@@ -41,8 +40,6 @@ public:
std::optional<Tegra::Engines::SamplerDescriptor> ObtainBindlessSampler(u32 buffer, u32 offset);
std::optional<u32> ObtainBoundBuffer();
/// Inserts a key.
void InsertKey(u32 buffer, u32 offset, u32 value);
@@ -52,9 +49,6 @@ public:
/// Inserts a bindless sampler key.
void InsertBindlessSampler(u32 buffer, u32 offset, Tegra::Engines::SamplerDescriptor sampler);
/// Set the bound buffer for this locker.
void SetBoundBuffer(u32 buffer);
/// Checks keys and samplers against engine's current const buffers. Returns true if they are
/// the same value, false otherwise;
bool IsConsistent() const;
@@ -77,27 +71,12 @@ public:
return bindless_samplers;
}
/// Gets bound buffer used on this shader
u32 GetBoundBuffer() const {
return bound_buffer;
}
/// Obtains access to the guest driver's profile.
VideoCore::GuestDriverProfile* AccessGuestDriverProfile() const {
if (engine) {
return &engine->AccessGuestDriverProfile();
}
return nullptr;
}
private:
const Tegra::Engines::ShaderType stage;
Tegra::Engines::ConstBufferEngineInterface* engine = nullptr;
KeyMap keys;
BoundSamplerMap bound_samplers;
BindlessSamplerMap bindless_samplers;
bool bound_buffer_saved{};
u32 bound_buffer{};
};
} // namespace VideoCommon::Shader
-68
View File
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <cstring>
#include <limits>
#include <set>
#include <fmt/format.h>
@@ -34,52 +33,6 @@ constexpr bool IsSchedInstruction(u32 offset, u32 main_offset) {
return (absolute_offset % SchedPeriod) == 0;
}
void DeduceTextureHandlerSize(VideoCore::GuestDriverProfile* gpu_driver,
const std::list<Sampler>& used_samplers) {
if (gpu_driver == nullptr) {
LOG_CRITICAL(HW_GPU, "GPU driver profile has not been created yet");
return;
}
if (gpu_driver->TextureHandlerSizeKnown() || used_samplers.size() <= 1) {
return;
}
u32 count{};
std::vector<u32> bound_offsets;
for (const auto& sampler : used_samplers) {
if (sampler.IsBindless()) {
continue;
}
++count;
bound_offsets.emplace_back(sampler.GetOffset());
}
if (count > 1) {
gpu_driver->DeduceTextureHandlerSize(std::move(bound_offsets));
}
}
std::optional<u32> TryDeduceSamplerSize(const Sampler& sampler_to_deduce,
VideoCore::GuestDriverProfile* gpu_driver,
const std::list<Sampler>& used_samplers) {
if (gpu_driver == nullptr) {
LOG_CRITICAL(HW_GPU, "GPU Driver profile has not been created yet");
return std::nullopt;
}
const u32 base_offset = sampler_to_deduce.GetOffset();
u32 max_offset{std::numeric_limits<u32>::max()};
for (const auto& sampler : used_samplers) {
if (sampler.IsBindless()) {
continue;
}
if (sampler.GetOffset() > base_offset) {
max_offset = std::min(sampler.GetOffset(), max_offset);
}
}
if (max_offset == std::numeric_limits<u32>::max()) {
return std::nullopt;
}
return ((max_offset - base_offset) * 4) / gpu_driver->GetTextureHandlerSize();
}
} // Anonymous namespace
class ASTDecoder {
@@ -362,25 +315,4 @@ u32 ShaderIR::DecodeInstr(NodeBlock& bb, u32 pc) {
return pc + 1;
}
void ShaderIR::PostDecode() {
// Deduce texture handler size if needed
auto gpu_driver = locker.AccessGuestDriverProfile();
DeduceTextureHandlerSize(gpu_driver, used_samplers);
// Deduce Indexed Samplers
if (!uses_indexed_samplers) {
return;
}
for (auto& sampler : used_samplers) {
if (!sampler.IsIndexed()) {
continue;
}
if (const auto size = TryDeduceSamplerSize(sampler, gpu_driver, used_samplers)) {
sampler.SetSize(*size);
} else {
LOG_CRITICAL(HW_GPU, "Failed to deduce size of indexed sampler");
sampler.SetSize(1);
}
}
}
} // namespace VideoCommon::Shader
@@ -297,7 +297,7 @@ void ShaderIR::WriteLop3Instruction(NodeBlock& bb, Register dest, Node op_a, Nod
const Node one = Immediate(1);
const Node two = Immediate(2);
Node value;
Node value{};
for (u32 i = 0; i < lop_iterations; ++i) {
const Node shift_amount = Immediate(i);
+31 -76
View File
@@ -19,12 +19,9 @@ namespace VideoCommon::Shader {
using Tegra::Shader::AtomicOp;
using Tegra::Shader::AtomicType;
using Tegra::Shader::Attribute;
using Tegra::Shader::GlobalAtomicOp;
using Tegra::Shader::GlobalAtomicType;
using Tegra::Shader::Instruction;
using Tegra::Shader::OpCode;
using Tegra::Shader::Register;
using Tegra::Shader::StoreType;
namespace {
@@ -64,27 +61,6 @@ u32 GetMemorySize(Tegra::Shader::UniformType uniform_type) {
}
}
Node ExtractUnaligned(Node value, Node address, u32 mask, u32 size) {
Node offset = Operation(OperationCode::UBitwiseAnd, address, Immediate(mask));
offset = Operation(OperationCode::ULogicalShiftLeft, std::move(offset), Immediate(3));
return Operation(OperationCode::UBitfieldExtract, std::move(value), std::move(offset),
Immediate(size));
}
Node InsertUnaligned(Node dest, Node value, Node address, u32 mask, u32 size) {
Node offset = Operation(OperationCode::UBitwiseAnd, std::move(address), Immediate(mask));
offset = Operation(OperationCode::ULogicalShiftLeft, std::move(offset), Immediate(3));
return Operation(OperationCode::UBitfieldInsert, std::move(dest), std::move(value),
std::move(offset), Immediate(size));
}
Node Sign16Extend(Node value) {
Node sign = Operation(OperationCode::UBitwiseAnd, value, Immediate(1U << 15));
Node is_sign = Operation(OperationCode::LogicalUEqual, std::move(sign), Immediate(1U << 15));
Node extend = Operation(OperationCode::Select, is_sign, Immediate(0xFFFF0000), Immediate(0));
return Operation(OperationCode::UBitwiseOr, std::move(value), std::move(extend));
}
} // Anonymous namespace
u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
@@ -160,31 +136,26 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
LOG_DEBUG(HW_GPU, "LD_L cache management mode: {}", static_cast<u64>(instr.ld_l.unknown));
[[fallthrough]];
case OpCode::Id::LD_S: {
const auto GetAddress = [&](s32 offset) {
const auto GetMemory = [&](s32 offset) {
ASSERT(offset % 4 == 0);
const Node immediate_offset = Immediate(static_cast<s32>(instr.smem_imm) + offset);
return Operation(OperationCode::IAdd, GetRegister(instr.gpr8), immediate_offset);
};
const auto GetMemory = [&](s32 offset) {
return opcode->get().GetId() == OpCode::Id::LD_S ? GetSharedMemory(GetAddress(offset))
: GetLocalMemory(GetAddress(offset));
const Node address = Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8),
immediate_offset);
return opcode->get().GetId() == OpCode::Id::LD_S ? GetSharedMemory(address)
: GetLocalMemory(address);
};
switch (instr.ldst_sl.type.Value()) {
case StoreType::Signed16:
SetRegister(bb, instr.gpr0,
Sign16Extend(ExtractUnaligned(GetMemory(0), GetAddress(0), 0b10, 16)));
break;
case StoreType::Bits32:
case StoreType::Bits64:
case StoreType::Bits128: {
const u32 count = [&] {
case Tegra::Shader::StoreType::Bits32:
case Tegra::Shader::StoreType::Bits64:
case Tegra::Shader::StoreType::Bits128: {
const u32 count = [&]() {
switch (instr.ldst_sl.type.Value()) {
case StoreType::Bits32:
case Tegra::Shader::StoreType::Bits32:
return 1;
case StoreType::Bits64:
case Tegra::Shader::StoreType::Bits64:
return 2;
case StoreType::Bits128:
case Tegra::Shader::StoreType::Bits128:
return 4;
default:
UNREACHABLE();
@@ -241,7 +212,12 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
// To handle unaligned loads get the bytes used to dereference global memory and extract
// those bytes from the loaded u32.
if (IsUnaligned(type)) {
gmem = ExtractUnaligned(gmem, real_address, GetUnalignedMask(type), size);
Node mask = Immediate(GetUnalignedMask(type));
Node offset = Operation(OperationCode::UBitwiseAnd, real_address, std::move(mask));
offset = Operation(OperationCode::ULogicalShiftLeft, offset, Immediate(3));
gmem = Operation(OperationCode::UBitfieldExtract, std::move(gmem),
std::move(offset), Immediate(size));
}
SetTemporary(bb, i, gmem);
@@ -293,28 +269,21 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
return Operation(OperationCode::IAdd, NO_PRECISE, GetRegister(instr.gpr8), immediate);
};
const bool is_local = opcode->get().GetId() == OpCode::Id::ST_L;
const auto set_memory = is_local ? &ShaderIR::SetLocalMemory : &ShaderIR::SetSharedMemory;
const auto get_memory = is_local ? &ShaderIR::GetLocalMemory : &ShaderIR::GetSharedMemory;
const auto set_memory = opcode->get().GetId() == OpCode::Id::ST_L
? &ShaderIR::SetLocalMemory
: &ShaderIR::SetSharedMemory;
switch (instr.ldst_sl.type.Value()) {
case StoreType::Bits128:
case Tegra::Shader::StoreType::Bits128:
(this->*set_memory)(bb, GetAddress(12), GetRegister(instr.gpr0.Value() + 3));
(this->*set_memory)(bb, GetAddress(8), GetRegister(instr.gpr0.Value() + 2));
[[fallthrough]];
case StoreType::Bits64:
case Tegra::Shader::StoreType::Bits64:
(this->*set_memory)(bb, GetAddress(4), GetRegister(instr.gpr0.Value() + 1));
[[fallthrough]];
case StoreType::Bits32:
case Tegra::Shader::StoreType::Bits32:
(this->*set_memory)(bb, GetAddress(0), GetRegister(instr.gpr0));
break;
case StoreType::Signed16: {
Node address = GetAddress(0);
Node memory = (this->*get_memory)(address);
(this->*set_memory)(
bb, address, InsertUnaligned(memory, GetRegister(instr.gpr0), address, 0b10, 16));
break;
}
default:
UNIMPLEMENTED_MSG("{} unhandled type: {}", opcode->get().GetName(),
static_cast<u32>(instr.ldst_sl.type.Value()));
@@ -354,32 +323,18 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
Node value = GetRegister(instr.gpr0.Value() + i);
if (IsUnaligned(type)) {
const u32 mask = GetUnalignedMask(type);
value = InsertUnaligned(gmem, std::move(value), real_address, mask, size);
Node mask = Immediate(GetUnalignedMask(type));
Node offset = Operation(OperationCode::UBitwiseAnd, real_address, std::move(mask));
offset = Operation(OperationCode::ULogicalShiftLeft, offset, Immediate(3));
value = Operation(OperationCode::UBitfieldInsert, gmem, std::move(value), offset,
Immediate(size));
}
bb.push_back(Operation(OperationCode::Assign, gmem, value));
}
break;
}
case OpCode::Id::ATOM: {
UNIMPLEMENTED_IF_MSG(instr.atom.operation != GlobalAtomicOp::Add, "operation={}",
static_cast<int>(instr.atom.operation.Value()));
UNIMPLEMENTED_IF_MSG(instr.atom.type != GlobalAtomicType::S32, "type={}",
static_cast<int>(instr.atom.type.Value()));
const auto [real_address, base_address, descriptor] =
TrackGlobalMemory(bb, instr, true, true);
if (!real_address || !base_address) {
// Tracking failed, skip atomic.
break;
}
Node gmem = MakeNode<GmemNode>(real_address, base_address, descriptor);
Node value = Operation(OperationCode::AtomicAdd, std::move(gmem), GetRegister(instr.gpr20));
SetRegister(bb, instr.gpr0, std::move(value));
break;
}
case OpCode::Id::ATOMS: {
UNIMPLEMENTED_IF_MSG(instr.atoms.operation != AtomicOp::Add, "operation={}",
static_cast<int>(instr.atoms.operation.Value()));
@@ -393,7 +348,7 @@ u32 ShaderIR::DecodeMemory(NodeBlock& bb, u32 pc) {
Node memory = GetSharedMemory(std::move(address));
Node data = GetRegister(instr.gpr20);
Node value = Operation(OperationCode::AtomicAdd, std::move(memory), std::move(data));
Node value = Operation(OperationCode::UAtomicAdd, std::move(memory), std::move(data));
SetRegister(bb, instr.gpr0, std::move(value));
break;
}
+39 -75
View File
@@ -144,8 +144,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
auto coords_copy = coords;
MetaTexture meta{sampler, {}, depth_compare, aoffi, {}, {},
{}, {}, component, element, {}};
MetaTexture meta{sampler, {}, depth_compare, aoffi, {}, {}, {}, {}, component, element};
values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy));
}
@@ -168,9 +167,9 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
const auto derivate_reg = instr.gpr20.Value();
const auto texture_type = instr.txd.texture_type.Value();
const auto coord_count = GetCoordCount(texture_type);
Node index_var{};
const Sampler* sampler =
is_bindless ? GetBindlessSampler(base_reg, index_var, {{texture_type, is_array, false}})
is_bindless ? GetBindlessSampler(base_reg, {{texture_type, is_array, false}})
: GetSampler(instr.sampler, {{texture_type, is_array, false}});
Node4 values;
if (sampler == nullptr) {
@@ -201,8 +200,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
}
for (u32 element = 0; element < values.size(); ++element) {
MetaTexture meta{*sampler, array_node, {}, {}, {}, derivates,
{}, {}, {}, element, index_var};
MetaTexture meta{*sampler, array_node, {}, {}, {}, derivates, {}, {}, {}, element};
values[element] = Operation(OperationCode::TextureGradient, std::move(meta), coords);
}
@@ -217,9 +215,8 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
// TODO: The new commits on the texture refactor, change the way samplers work.
// Sadly, not all texture instructions specify the type of texture their sampler
// uses. This must be fixed at a later instance.
Node index_var{};
const Sampler* sampler =
is_bindless ? GetBindlessSampler(instr.gpr8, index_var) : GetSampler(instr.sampler);
is_bindless ? GetBindlessSampler(instr.gpr8) : GetSampler(instr.sampler);
if (sampler == nullptr) {
u32 indexer = 0;
@@ -243,7 +240,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
if (!instr.txq.IsComponentEnabled(element)) {
continue;
}
MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, {}, element, index_var};
MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, {}, element};
const Node value =
Operation(OperationCode::TextureQueryDimensions, meta,
GetRegister(instr.gpr8.Value() + (is_bindless ? 1 : 0)));
@@ -269,9 +266,8 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
auto texture_type = instr.tmml.texture_type.Value();
const bool is_array = instr.tmml.array != 0;
Node index_var{};
const Sampler* sampler =
is_bindless ? GetBindlessSampler(instr.gpr20, index_var) : GetSampler(instr.sampler);
is_bindless ? GetBindlessSampler(instr.gpr20) : GetSampler(instr.sampler);
if (sampler == nullptr) {
u32 indexer = 0;
@@ -313,7 +309,7 @@ u32 ShaderIR::DecodeTexture(NodeBlock& bb, u32 pc) {
continue;
}
auto params = coords;
MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, {}, element, index_var};
MetaTexture meta{*sampler, {}, {}, {}, {}, {}, {}, {}, {}, element};
const Node value = Operation(OperationCode::TextureQueryLod, meta, std::move(params));
SetTemporary(bb, indexer++, value);
}
@@ -387,65 +383,37 @@ const Sampler* ShaderIR::GetSampler(const Tegra::Shader::Sampler& sampler,
// Otherwise create a new mapping for this sampler
const auto next_index = static_cast<u32>(used_samplers.size());
return &used_samplers.emplace_back(next_index, offset, info.type, info.is_array, info.is_shadow,
info.is_buffer, false);
info.is_buffer);
}
const Sampler* ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg, Node& index_var,
const Sampler* ShaderIR::GetBindlessSampler(Tegra::Shader::Register reg,
std::optional<SamplerInfo> sampler_info) {
const Node sampler_register = GetRegister(reg);
const auto [base_node, tracked_sampler_info] =
TrackBindlessSampler(sampler_register, global_code, static_cast<s64>(global_code.size()));
ASSERT(base_node != nullptr);
if (base_node == nullptr) {
const auto [base_sampler, buffer, offset] =
TrackCbuf(sampler_register, global_code, static_cast<s64>(global_code.size()));
ASSERT(base_sampler != nullptr);
if (base_sampler == nullptr) {
return nullptr;
}
if (const auto bindless_sampler_info =
std::get_if<BindlessSamplerNode>(&*tracked_sampler_info)) {
const u32 buffer = bindless_sampler_info->GetIndex();
const u32 offset = bindless_sampler_info->GetOffset();
const auto info = GetSamplerInfo(sampler_info, offset, buffer);
const auto info = GetSamplerInfo(sampler_info, offset, buffer);
// If this sampler has already been used, return the existing mapping.
const auto it =
std::find_if(used_samplers.begin(), used_samplers.end(),
[buffer = buffer, offset = offset](const Sampler& entry) {
return entry.GetBuffer() == buffer && entry.GetOffset() == offset;
});
if (it != used_samplers.end()) {
ASSERT(it->IsBindless() && it->GetType() == info.type &&
it->IsArray() == info.is_array && it->IsShadow() == info.is_shadow);
return &*it;
}
// Otherwise create a new mapping for this sampler
const auto next_index = static_cast<u32>(used_samplers.size());
return &used_samplers.emplace_back(next_index, offset, buffer, info.type, info.is_array,
info.is_shadow, info.is_buffer, false);
} else if (const auto array_sampler_info =
std::get_if<ArraySamplerNode>(&*tracked_sampler_info)) {
const u32 base_offset = array_sampler_info->GetBaseOffset() / 4;
index_var = GetCustomVariable(array_sampler_info->GetIndexVar());
const auto info = GetSamplerInfo(sampler_info, base_offset);
// If this sampler has already been used, return the existing mapping.
const auto it = std::find_if(
used_samplers.begin(), used_samplers.end(),
[base_offset](const Sampler& entry) { return entry.GetOffset() == base_offset; });
if (it != used_samplers.end()) {
ASSERT(!it->IsBindless() && it->GetType() == info.type &&
it->IsArray() == info.is_array && it->IsShadow() == info.is_shadow &&
it->IsBuffer() == info.is_buffer && it->IsIndexed());
return &*it;
}
uses_indexed_samplers = true;
// Otherwise create a new mapping for this sampler
const auto next_index = static_cast<u32>(used_samplers.size());
return &used_samplers.emplace_back(next_index, base_offset, info.type, info.is_array,
info.is_shadow, info.is_buffer, true);
// If this sampler has already been used, return the existing mapping.
const auto it =
std::find_if(used_samplers.begin(), used_samplers.end(),
[buffer = buffer, offset = offset](const Sampler& entry) {
return entry.GetBuffer() == buffer && entry.GetOffset() == offset;
});
if (it != used_samplers.end()) {
ASSERT(it->IsBindless() && it->GetType() == info.type && it->IsArray() == info.is_array &&
it->IsShadow() == info.is_shadow);
return &*it;
}
return nullptr;
// Otherwise create a new mapping for this sampler
const auto next_index = static_cast<u32>(used_samplers.size());
return &used_samplers.emplace_back(next_index, offset, buffer, info.type, info.is_array,
info.is_shadow, info.is_buffer);
}
void ShaderIR::WriteTexInstructionFloat(NodeBlock& bb, Instruction instr, const Node4& components) {
@@ -531,9 +499,8 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
"This method is not supported.");
const SamplerInfo info{texture_type, is_array, is_shadow, false};
Node index_var{};
const Sampler* sampler = is_bindless ? GetBindlessSampler(*bindless_reg, index_var, info)
: GetSampler(instr.sampler, info);
const Sampler* sampler =
is_bindless ? GetBindlessSampler(*bindless_reg, info) : GetSampler(instr.sampler, info);
Node4 values;
if (sampler == nullptr) {
for (u32 element = 0; element < values.size(); ++element) {
@@ -581,8 +548,7 @@ Node4 ShaderIR::GetTextureCode(Instruction instr, TextureType texture_type,
for (u32 element = 0; element < values.size(); ++element) {
auto copy_coords = coords;
MetaTexture meta{*sampler, array, depth_compare, aoffi, {}, {}, bias,
lod, {}, element, index_var};
MetaTexture meta{*sampler, array, depth_compare, aoffi, {}, {}, bias, lod, {}, element};
values[element] = Operation(read_method, meta, std::move(copy_coords));
}
@@ -630,7 +596,7 @@ Node4 ShaderIR::GetTexCode(Instruction instr, TextureType texture_type,
aoffi = GetAoffiCoordinates(GetRegister(parameter_register++), coord_count, false);
}
Node dc;
Node dc{};
if (depth_compare) {
// Depth is always stored in the register signaled by gpr20 or in the next register if lod
// or bias are used
@@ -666,7 +632,7 @@ Node4 ShaderIR::GetTexsCode(Instruction instr, TextureType texture_type,
const Node array = is_array ? GetRegister(array_register) : nullptr;
Node dc;
Node dc{};
if (depth_compare) {
// Depth is always stored in the register signaled by gpr20 or in the next register if lod
// or bias are used
@@ -697,8 +663,7 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
u64 parameter_register = instr.gpr20.Value();
const SamplerInfo info{texture_type, is_array, depth_compare, false};
Node index_var{};
const Sampler* sampler = is_bindless ? GetBindlessSampler(parameter_register++, index_var, info)
const Sampler* sampler = is_bindless ? GetBindlessSampler(parameter_register++, info)
: GetSampler(instr.sampler, info);
Node4 values;
if (sampler == nullptr) {
@@ -727,8 +692,7 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
for (u32 element = 0; element < values.size(); ++element) {
auto coords_copy = coords;
MetaTexture meta{
*sampler, GetRegister(array_register), dc, aoffi, ptp, {}, {}, {}, component, element,
index_var};
*sampler, GetRegister(array_register), dc, aoffi, ptp, {}, {}, {}, component, element};
values[element] = Operation(OperationCode::TextureGather, meta, std::move(coords_copy));
}
@@ -761,7 +725,7 @@ Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) {
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
auto coords_copy = coords;
MetaTexture meta{sampler, array_register, {}, {}, {}, {}, {}, lod, {}, element, {}};
MetaTexture meta{sampler, array_register, {}, {}, {}, {}, {}, lod, {}, element};
values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy));
}
@@ -811,7 +775,7 @@ Node4 ShaderIR::GetTldsCode(Instruction instr, TextureType texture_type, bool is
Node4 values;
for (u32 element = 0; element < values.size(); ++element) {
auto coords_copy = coords;
MetaTexture meta{sampler, array, {}, {}, {}, {}, {}, lod, {}, element, {}};
MetaTexture meta{sampler, array, {}, {}, {}, {}, {}, lod, {}, element};
values[element] = Operation(OperationCode::TexelFetch, meta, std::move(coords_copy));
}
return values;
+7 -84
View File
@@ -162,7 +162,7 @@ enum class OperationCode {
AtomicImageXor, /// (MetaImage, int[N] coords) -> void
AtomicImageExchange, /// (MetaImage, int[N] coords) -> void
AtomicAdd, /// (memory, {u}int) -> {u}int
UAtomicAdd, /// (smem, uint) -> uint
Branch, /// (uint branch_target) -> void
BranchIndirect, /// (uint branch_target) -> void
@@ -212,7 +212,6 @@ enum class MetaStackClass {
class OperationNode;
class ConditionalNode;
class GprNode;
class CustomVarNode;
class ImmediateNode;
class InternalFlagNode;
class PredicateNode;
@@ -224,32 +223,26 @@ class SmemNode;
class GmemNode;
class CommentNode;
using NodeData = std::variant<OperationNode, ConditionalNode, GprNode, CustomVarNode, ImmediateNode,
using NodeData = std::variant<OperationNode, ConditionalNode, GprNode, ImmediateNode,
InternalFlagNode, PredicateNode, AbufNode, PatchNode, CbufNode,
LmemNode, SmemNode, GmemNode, CommentNode>;
using Node = std::shared_ptr<NodeData>;
using Node4 = std::array<Node, 4>;
using NodeBlock = std::vector<Node>;
class BindlessSamplerNode;
class ArraySamplerNode;
using TrackSamplerData = std::variant<BindlessSamplerNode, ArraySamplerNode>;
using TrackSampler = std::shared_ptr<TrackSamplerData>;
class Sampler {
public:
/// This constructor is for bound samplers
constexpr explicit Sampler(u32 index, u32 offset, Tegra::Shader::TextureType type,
bool is_array, bool is_shadow, bool is_buffer, bool is_indexed)
bool is_array, bool is_shadow, bool is_buffer)
: index{index}, offset{offset}, type{type}, is_array{is_array}, is_shadow{is_shadow},
is_buffer{is_buffer}, is_indexed{is_indexed} {}
is_buffer{is_buffer} {}
/// This constructor is for bindless samplers
constexpr explicit Sampler(u32 index, u32 offset, u32 buffer, Tegra::Shader::TextureType type,
bool is_array, bool is_shadow, bool is_buffer, bool is_indexed)
bool is_array, bool is_shadow, bool is_buffer)
: index{index}, offset{offset}, buffer{buffer}, type{type}, is_array{is_array},
is_shadow{is_shadow}, is_buffer{is_buffer}, is_bindless{true}, is_indexed{is_indexed} {}
is_shadow{is_shadow}, is_buffer{is_buffer}, is_bindless{true} {}
constexpr u32 GetIndex() const {
return index;
@@ -283,72 +276,16 @@ public:
return is_bindless;
}
constexpr bool IsIndexed() const {
return is_indexed;
}
constexpr u32 Size() const {
return size;
}
constexpr void SetSize(u32 new_size) {
size = new_size;
}
private:
u32 index{}; ///< Emulated index given for the this sampler.
u32 offset{}; ///< Offset in the const buffer from where the sampler is being read.
u32 buffer{}; ///< Buffer where the bindless sampler is being read (unused on bound samplers).
u32 size{}; ///< Size of the sampler if indexed.
Tegra::Shader::TextureType type{}; ///< The type used to sample this texture (Texture2D, etc)
bool is_array{}; ///< Whether the texture is being sampled as an array texture or not.
bool is_shadow{}; ///< Whether the texture is being sampled as a depth texture or not.
bool is_buffer{}; ///< Whether the texture is a texture buffer without sampler.
bool is_bindless{}; ///< Whether this sampler belongs to a bindless texture or not.
bool is_indexed{}; ///< Whether this sampler is an indexed array of textures.
};
/// Represents a tracked bindless sampler into a direct const buffer
class ArraySamplerNode final {
public:
explicit ArraySamplerNode(u32 index, u32 base_offset, u32 bindless_var)
: index{index}, base_offset{base_offset}, bindless_var{bindless_var} {}
constexpr u32 GetIndex() const {
return index;
}
constexpr u32 GetBaseOffset() const {
return base_offset;
}
constexpr u32 GetIndexVar() const {
return bindless_var;
}
private:
u32 index;
u32 base_offset;
u32 bindless_var;
};
/// Represents a tracked bindless sampler into a direct const buffer
class BindlessSamplerNode final {
public:
explicit BindlessSamplerNode(u32 index, u32 offset) : index{index}, offset{offset} {}
constexpr u32 GetIndex() const {
return index;
}
constexpr u32 GetOffset() const {
return offset;
}
private:
u32 index;
u32 offset;
};
class Image final {
@@ -443,9 +380,8 @@ struct MetaTexture {
std::vector<Node> derivates;
Node bias;
Node lod;
Node component;
Node component{};
u32 element{};
Node index;
};
struct MetaImage {
@@ -552,19 +488,6 @@ private:
Tegra::Shader::Register index{};
};
/// A custom variable
class CustomVarNode final {
public:
explicit constexpr CustomVarNode(u32 index) : index{index} {}
constexpr u32 GetIndex() const {
return index;
}
private:
u32 index{};
};
/// A 32-bits value that represents an immediate value
class ImmediateNode final {
public:
-6
View File
@@ -45,12 +45,6 @@ Node MakeNode(Args&&... args) {
return std::make_shared<NodeData>(T(std::forward<Args>(args)...));
}
template <typename T, typename... Args>
TrackSampler MakeTrackSampler(Args&&... args) {
static_assert(std::is_convertible_v<T, TrackSamplerData>);
return std::make_shared<TrackSamplerData>(T(std::forward<Args>(args)...));
}
template <typename... Args>
Node Operation(OperationCode code, Args&&... args) {
if constexpr (sizeof...(args) == 0) {
-9
View File
@@ -27,7 +27,6 @@ ShaderIR::ShaderIR(const ProgramCode& program_code, u32 main_offset, CompilerSet
ConstBufferLocker& locker)
: program_code{program_code}, main_offset{main_offset}, settings{settings}, locker{locker} {
Decode();
PostDecode();
}
ShaderIR::~ShaderIR() = default;
@@ -39,10 +38,6 @@ Node ShaderIR::GetRegister(Register reg) {
return MakeNode<GprNode>(reg);
}
Node ShaderIR::GetCustomVariable(u32 id) {
return MakeNode<CustomVarNode>(id);
}
Node ShaderIR::GetImmediate19(Instruction instr) {
return Immediate(instr.alu.GetImm20_19());
}
@@ -457,8 +452,4 @@ std::size_t ShaderIR::DeclareAmend(Node new_amend) {
return id;
}
u32 ShaderIR::NewCustomVariable() {
return num_custom_variables++;
}
} // namespace VideoCommon::Shader
+1 -15
View File
@@ -180,10 +180,6 @@ public:
return amend_code[index];
}
u32 GetNumCustomVariables() const {
return num_custom_variables;
}
private:
friend class ASTDecoder;
@@ -195,7 +191,6 @@ private:
};
void Decode();
void PostDecode();
NodeBlock DecodeRange(u32 begin, u32 end);
void DecodeRangeInner(NodeBlock& bb, u32 begin, u32 end);
@@ -240,8 +235,6 @@ private:
/// Generates a node for a passed register.
Node GetRegister(Tegra::Shader::Register reg);
/// Generates a node for a custom variable
Node GetCustomVariable(u32 id);
/// Generates a node representing a 19-bit immediate value
Node GetImmediate19(Tegra::Shader::Instruction instr);
/// Generates a node representing a 32-bit immediate value
@@ -328,7 +321,7 @@ private:
std::optional<SamplerInfo> sampler_info = std::nullopt);
/// Accesses a texture sampler for a bindless texture.
const Sampler* GetBindlessSampler(Tegra::Shader::Register reg, Node& index_var,
const Sampler* GetBindlessSampler(Tegra::Shader::Register reg,
std::optional<SamplerInfo> sampler_info = std::nullopt);
/// Accesses an image.
@@ -394,9 +387,6 @@ private:
std::tuple<Node, u32, u32> TrackCbuf(Node tracked, const NodeBlock& code, s64 cursor) const;
std::tuple<Node, TrackSampler> TrackBindlessSampler(Node tracked, const NodeBlock& code,
s64 cursor);
std::optional<u32> TrackImmediate(Node tracked, const NodeBlock& code, s64 cursor) const;
std::pair<Node, s64> TrackRegister(const GprNode* tracked, const NodeBlock& code,
@@ -409,8 +399,6 @@ private:
/// Register new amending code and obtain the reference id.
std::size_t DeclareAmend(Node new_amend);
u32 NewCustomVariable();
const ProgramCode& program_code;
const u32 main_offset;
const CompilerSettings settings;
@@ -426,7 +414,6 @@ private:
NodeBlock global_code;
ASTManager program_manager{true, true};
std::vector<Node> amend_code;
u32 num_custom_variables{};
std::set<u32> used_registers;
std::set<Tegra::Shader::Pred> used_predicates;
@@ -444,7 +431,6 @@ private:
bool uses_instance_id{};
bool uses_vertex_id{};
bool uses_warps{};
bool uses_indexed_samplers{};
Tegra::Shader::Header header;
};
-106
View File
@@ -8,7 +8,6 @@
#include "common/common_types.h"
#include "video_core/shader/node.h"
#include "video_core/shader/node_helper.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon::Shader {
@@ -36,113 +35,8 @@ std::pair<Node, s64> FindOperation(const NodeBlock& code, s64 cursor,
}
return {};
}
std::optional<std::pair<Node, Node>> DecoupleIndirectRead(const OperationNode& operation) {
if (operation.GetCode() != OperationCode::UAdd) {
return std::nullopt;
}
Node gpr;
Node offset;
ASSERT(operation.GetOperandsCount() == 2);
for (std::size_t i = 0; i < operation.GetOperandsCount(); i++) {
Node operand = operation[i];
if (std::holds_alternative<ImmediateNode>(*operand)) {
offset = operation[i];
} else if (std::holds_alternative<GprNode>(*operand)) {
gpr = operation[i];
}
}
if (offset && gpr) {
return std::make_pair(gpr, offset);
}
return std::nullopt;
}
bool AmendNodeCv(std::size_t amend_index, Node node) {
if (const auto operation = std::get_if<OperationNode>(&*node)) {
operation->SetAmendIndex(amend_index);
return true;
} else if (const auto conditional = std::get_if<ConditionalNode>(&*node)) {
conditional->SetAmendIndex(amend_index);
return true;
}
return false;
}
} // Anonymous namespace
std::tuple<Node, TrackSampler> ShaderIR::TrackBindlessSampler(Node tracked, const NodeBlock& code,
s64 cursor) {
if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) {
// Constant buffer found, test if it's an immediate
const auto offset = cbuf->GetOffset();
if (const auto immediate = std::get_if<ImmediateNode>(&*offset)) {
auto track =
MakeTrackSampler<BindlessSamplerNode>(cbuf->GetIndex(), immediate->GetValue());
return {tracked, track};
} else if (const auto operation = std::get_if<OperationNode>(&*offset)) {
auto bound_buffer = locker.ObtainBoundBuffer();
if (!bound_buffer) {
return {};
}
if (*bound_buffer != cbuf->GetIndex()) {
return {};
}
auto pair = DecoupleIndirectRead(*operation);
if (!pair) {
return {};
}
auto [gpr, base_offset] = *pair;
const auto offset_inm = std::get_if<ImmediateNode>(&*base_offset);
auto gpu_driver = locker.AccessGuestDriverProfile();
if (gpu_driver == nullptr) {
return {};
}
const u32 bindless_cv = NewCustomVariable();
const Node op = Operation(OperationCode::UDiv, NO_PRECISE, gpr,
Immediate(gpu_driver->GetTextureHandlerSize()));
const Node cv_node = GetCustomVariable(bindless_cv);
Node amend_op = Operation(OperationCode::Assign, cv_node, std::move(op));
const std::size_t amend_index = DeclareAmend(amend_op);
AmendNodeCv(amend_index, code[cursor]);
// TODO Implement Bindless Index custom variable
auto track = MakeTrackSampler<ArraySamplerNode>(cbuf->GetIndex(),
offset_inm->GetValue(), bindless_cv);
return {tracked, track};
}
return {};
}
if (const auto gpr = std::get_if<GprNode>(&*tracked)) {
if (gpr->GetIndex() == Tegra::Shader::Register::ZeroIndex) {
return {};
}
// Reduce the cursor in one to avoid infinite loops when the instruction sets the same
// register that it uses as operand
const auto [source, new_cursor] = TrackRegister(gpr, code, cursor - 1);
if (!source) {
return {};
}
return TrackBindlessSampler(source, code, new_cursor);
}
if (const auto operation = std::get_if<OperationNode>(&*tracked)) {
for (std::size_t i = operation->GetOperandsCount(); i > 0; --i) {
if (auto found = TrackBindlessSampler((*operation)[i - 1], code, cursor);
std::get<0>(found)) {
// Cbuf found in operand.
return found;
}
}
return {};
}
if (const auto conditional = std::get_if<ConditionalNode>(&*tracked)) {
const auto& conditional_code = conditional->GetCode();
return TrackBindlessSampler(tracked, conditional_code,
static_cast<s64>(conditional_code.size()));
}
return {};
}
std::tuple<Node, u32, u32> ShaderIR::TrackCbuf(Node tracked, const NodeBlock& code,
s64 cursor) const {
if (const auto cbuf = std::get_if<CbufNode>(&*tracked)) {
@@ -135,7 +135,7 @@ std::vector<CopyParams> SurfaceBaseImpl::BreakDownLayered(const SurfaceParams& i
for (u32 level = 0; level < mipmaps; level++) {
const u32 width = SurfaceParams::IntersectWidth(params, in_params, level, level);
const u32 height = SurfaceParams::IntersectHeight(params, in_params, level, level);
result.emplace_back(0, 0, layer, 0, 0, layer, level, level, width, height, 1);
result.emplace_back(width, height, layer, level);
}
}
return result;
@@ -236,8 +236,6 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
widget->setVisible(false);
analog_map_stick = {ui->buttonLStickAnalog, ui->buttonRStickAnalog};
analog_map_deadzone = {ui->sliderLStickDeadzone, ui->sliderRStickDeadzone};
analog_map_deadzone_label = {ui->labelLStickDeadzone, ui->labelRStickDeadzone};
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; button_id++) {
auto* const button = button_map[button_id];
@@ -328,11 +326,6 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
InputCommon::Polling::DeviceType::Analog);
}
});
connect(analog_map_deadzone[analog_id], &QSlider::valueChanged, [=] {
const float deadzone = analog_map_deadzone[analog_id]->value() / 100.0f;
analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1").arg(deadzone));
analogs_param[analog_id].Set("deadzone", deadzone);
});
}
connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
@@ -491,7 +484,7 @@ void ConfigureInputPlayer::ClearAll() {
continue;
}
analogs_param[analog_id].Clear();
analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]);
}
}
@@ -515,23 +508,6 @@ void ConfigureInputPlayer::UpdateButtonLabels() {
AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
}
analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
auto& param = analogs_param[analog_id];
auto* const analog_deadzone_slider = analog_map_deadzone[analog_id];
auto* const analog_deadzone_label = analog_map_deadzone_label[analog_id];
if (param.Has("engine") && param.Get("engine", "") == "sdl") {
if (!param.Has("deadzone")) {
param.Set("deadzone", 0.1f);
}
analog_deadzone_slider->setValue(static_cast<int>(param.Get("deadzone", 0.1f) * 100));
analog_deadzone_slider->setVisible(true);
analog_deadzone_label->setVisible(true);
} else {
analog_deadzone_slider->setVisible(false);
analog_deadzone_label->setVisible(false);
}
}
}
@@ -97,8 +97,6 @@ private:
/// Analog inputs are also represented each with a single button, used to configure with an
/// actual analog stick
std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick;
std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone;
std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> analog_map_deadzone_label;
static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
@@ -170,44 +170,6 @@
</item>
</layout>
</item>
<item row="4" column="0" colspan="2">
<layout class="QVBoxLayout" name="sliderRStickDeadzoneVerticalLayout">
<item>
<layout class="QHBoxLayout" name="sliderRStickDeadzoneHorizontalLayout">
<item>
<widget class="QLabel" name="labelRStickDeadzone">
<property name="text">
<string>Deadzone: 0</string>
</property>
<property name="alignment">
<enum>Qt::AlignHCenter</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QSlider" name="sliderRStickDeadzone">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<spacer name="RStick_verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
@@ -783,47 +745,6 @@
</item>
</layout>
</item>
<item row="5" column="1" colspan="2">
<layout class="QVBoxLayout" name="sliderLStickDeadzoneVerticalLayout">
<property name="sizeConstraint">
<enum>QLayout::SetDefaultConstraint</enum>
</property>
<item>
<layout class="QHBoxLayout" name="sliderLStickDeadzoneHorizontalLayout">
<item>
<widget class="QLabel" name="labelLStickDeadzone">
<property name="text">
<string>Deadzone: 0</string>
</property>
<property name="alignment">
<enum>Qt::AlignHCenter</enum>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QSlider" name="sliderLStickDeadzone">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
</layout>
</item>
<item row="6" column="1">
<spacer name="LStick_verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>