diff options
-rw-r--r-- | src/yuzu/configuration/configuration_shared.cpp | 177 | ||||
-rw-r--r-- | src/yuzu/configuration/configuration_shared.h | 14 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_general.cpp | 4 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_graphics.cpp | 71 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_graphics.h | 1 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_graphics.ui | 20 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_graphics_advanced.cpp | 2 | ||||
-rw-r--r-- | src/yuzu/configuration/configure_graphics_advanced.ui | 15 | ||||
-rw-r--r-- | src/yuzu/configuration/shared_translation.cpp | 3 |
9 files changed, 204 insertions, 103 deletions
diff --git a/src/yuzu/configuration/configuration_shared.cpp b/src/yuzu/configuration/configuration_shared.cpp index 8d5ab8b4c..45165c2e9 100644 --- a/src/yuzu/configuration/configuration_shared.cpp +++ b/src/yuzu/configuration/configuration_shared.cpp @@ -2,119 +2,151 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <memory> +#include <QBoxLayout> #include <QCheckBox> #include <QHBoxLayout> #include <QLabel> #include <QLineEdit> #include <QObject> +#include <QPushButton> #include <QString> +#include <QStyle> #include <QWidget> +#include <qabstractbutton.h> #include <qcheckbox.h> +#include <qcombobox.h> #include <qnamespace.h> +#include <qsizepolicy.h> #include "common/settings.h" #include "yuzu/configuration/configuration_shared.h" #include "yuzu/configuration/configure_per_game.h" #include "yuzu/configuration/shared_translation.h" namespace ConfigurationShared { + +static QPushButton* CreateClearGlobalButton(QWidget* parent, Settings::BasicSetting* setting) { + QStyle* style = parent->style(); + QIcon* icon = new QIcon(style->standardIcon(QStyle::SP_DialogResetButton)); + QPushButton* button = new QPushButton(*icon, QStringLiteral(""), parent); + button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Expanding); + + QSizePolicy sp_retain = button->sizePolicy(); + sp_retain.setRetainSizeWhenHidden(true); + button->setSizePolicy(sp_retain); + + button->setEnabled(!setting->UsingGlobal()); + button->setVisible(!setting->UsingGlobal()); + + return button; +} + static std::pair<QWidget*, std::function<void()>> CreateCheckBox(Settings::BasicSetting* setting, const QString& label, QWidget* parent, std::list<CheckState>& trackers) { + QWidget* widget = new QWidget(parent); + QHBoxLayout* layout = new QHBoxLayout(widget); + QCheckBox* checkbox = new QCheckBox(label, parent); checkbox->setObjectName(QString::fromStdString(setting->GetLabel())); checkbox->setCheckState(setting->ToString() == "true" ? Qt::CheckState::Checked : Qt::CheckState::Unchecked); - CheckState* tracker{}; - - // Per-game config highlight - if (setting->Switchable() && !Settings::IsConfiguringGlobal()) { - bool global_state = setting->ToStringGlobal() == "true"; - bool state = setting->ToString() == "true"; - bool global = setting->UsingGlobal(); - tracker = &trackers.emplace_front(CheckState{}); - SetColoredTristate(checkbox, global, state, global_state, *tracker); - } + std::function<void()> load_func; - auto load_func = [checkbox, setting, tracker]() { - if (Settings::IsConfiguringGlobal()) { + layout->addWidget(checkbox); + if (Settings::IsConfiguringGlobal()) { + load_func = [setting, checkbox]() { setting->LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); - } - - if (Settings::IsConfiguringGlobal() || !setting->Switchable()) { - return; - } + }; + } else { + auto* button = CreateClearGlobalButton(parent, setting); + layout->addWidget(button); + + QObject::connect(checkbox, &QCheckBox::stateChanged, [button](int) { + button->setVisible(true); + button->setEnabled(true); + }); + + QObject::connect(button, &QAbstractButton::clicked, [checkbox, setting, button](bool) { + checkbox->setCheckState(setting->ToStringGlobal() == "true" ? Qt::Checked + : Qt::Unchecked); + button->setEnabled(false); + button->setVisible(false); + }); + + load_func = [setting, checkbox, button]() { + bool using_global = !button->isEnabled(); + setting->SetGlobal(using_global); + if (!using_global) { + setting->LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); + } + }; + } - if (*tracker != CheckState::Global) { - setting->SetGlobal(false); - setting->LoadString(checkbox->checkState() == Qt::Checked ? "true" : "false"); - } else { - setting->SetGlobal(true); - } - }; + layout->setContentsMargins(0, 0, 0, 0); - return {checkbox, load_func}; + return {widget, load_func}; } -static std::tuple<QWidget*, void*, std::function<void()>> CreateCombobox( +static std::tuple<QWidget*, QComboBox*, QPushButton*, std::function<void()>> CreateCombobox( Settings::BasicSetting* setting, const QString& label, QWidget* parent, bool managed) { const auto type = setting->TypeId(); QWidget* group = new QWidget(parent); group->setObjectName(QString::fromStdString(setting->GetLabel())); - QLayout* combobox_layout = new QHBoxLayout(group); + QLayout* layout = new QHBoxLayout(group); QLabel* qt_label = new QLabel(label, parent); QComboBox* combobox = new QComboBox(parent); + QPushButton* button{nullptr}; + std::forward_list<QString> combobox_enumerations = ComboboxEnumeration(type, parent); for (const auto& item : combobox_enumerations) { combobox->addItem(item); } - combobox_layout->addWidget(qt_label); - combobox_layout->addWidget(combobox); + layout->addWidget(qt_label); + layout->addWidget(combobox); - combobox_layout->setSpacing(6); - combobox_layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(6); + layout->setContentsMargins(0, 0, 0, 0); - if (setting->Switchable() && !Settings::IsConfiguringGlobal() && managed) { - int current = std::stoi(setting->ToString()); - int global_value = std::stoi(setting->ToStringGlobal()); - SetColoredComboBox(combobox, group, global_value); - if (setting->UsingGlobal()) { - combobox->setCurrentIndex(USE_GLOBAL_INDEX); - } else { - SetHighlight(group, true); - combobox->setCurrentIndex(current + USE_GLOBAL_OFFSET); - } - } else { - combobox->setCurrentIndex(std::stoi(setting->ToString())); - } + combobox->setCurrentIndex(std::stoi(setting->ToString())); std::function<void()> load_func = []() {}; - if (managed) { - load_func = [combobox, setting]() { - if (Settings::IsConfiguringGlobal()) { - setting->LoadString(std::to_string(combobox->currentIndex())); - } - if (Settings::IsConfiguringGlobal() || !setting->Switchable()) { - return; - } + if (Settings::IsConfiguringGlobal() && managed) { + load_func = [setting, combobox]() { + setting->LoadString(std::to_string(combobox->currentIndex())); + }; + } else if (managed) { + button = CreateClearGlobalButton(parent, setting); + layout->addWidget(button); + + QObject::connect(button, &QAbstractButton::clicked, [button, combobox, setting](bool) { + button->setEnabled(false); + button->setVisible(false); + + combobox->setCurrentIndex(std::stoi(setting->ToStringGlobal())); + }); - bool using_global = combobox->currentIndex() == USE_GLOBAL_INDEX; - int index = combobox->currentIndex() - USE_GLOBAL_OFFSET; + QObject::connect(combobox, QOverload<int>::of(&QComboBox::activated), [=](int) { + button->setEnabled(true); + button->setVisible(true); + }); + load_func = [setting, combobox, button]() { + bool using_global = !button->isEnabled(); setting->SetGlobal(using_global); if (!using_global) { - setting->LoadString(std::to_string(index)); + setting->LoadString(std::to_string(combobox->currentIndex())); } }; } - return {group, combobox, load_func}; + return {group, combobox, button, load_func}; } static std::tuple<QWidget*, void*, std::function<void()>> CreateLineEdit( @@ -136,7 +168,7 @@ static std::tuple<QWidget*, void*, std::function<void()>> CreateLineEdit( q_label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); layout->addWidget(q_label); - load_func = [&]() { + load_func = [line_edit, setting]() { std::string load_text = line_edit->text().toStdString(); setting->LoadString(load_text); }; @@ -157,7 +189,7 @@ static std::tuple<QWidget*, void*, std::function<void()>> CreateLineEdit( checkbox->setCheckState(setting->UsingGlobal() ? Qt::Unchecked : Qt::Checked); highlight_func(checkbox->checkState()); - load_func = [&]() { + load_func = [checkbox, setting, line_edit]() { if (checkbox->checkState() == Qt::Checked) { setting->SetGlobal(false); @@ -176,12 +208,15 @@ static std::tuple<QWidget*, void*, std::function<void()>> CreateLineEdit( return {widget, line_edit, load_func}; } -std::pair<QWidget*, void*> CreateWidget(Settings::BasicSetting* setting, - const TranslationMap& translations, QWidget* parent, - bool runtime_lock, - std::forward_list<std::function<void(bool)>>& apply_funcs, - std::list<CheckState>& trackers, RequestType request, - bool managed) { +std::tuple<QWidget*, void*, QPushButton*> CreateWidget( + Settings::BasicSetting* setting, const TranslationMap& translations, QWidget* parent, + bool runtime_lock, std::forward_list<std::function<void(bool)>>& apply_funcs, + std::list<CheckState>& trackers, RequestType request, bool managed) { + if (!Settings::IsConfiguringGlobal() && !setting->Switchable()) { + LOG_DEBUG(Frontend, "\"{}\" is not switchable, skipping...", setting->GetLabel()); + return {nullptr, nullptr, nullptr}; + } + const auto type = setting->TypeId(); const int id = setting->Id(); QWidget* widget{nullptr}; @@ -201,9 +236,11 @@ std::pair<QWidget*, void*> CreateWidget(Settings::BasicSetting* setting, if (label == QStringLiteral("")) { LOG_DEBUG(Frontend, "Translation table has emtpy entry for \"{}\", skipping...", setting->GetLabel()); - return {nullptr, nullptr}; + return {nullptr, nullptr, nullptr}; } + QPushButton* button; + if (type == typeid(bool)) { auto pair = CreateCheckBox(setting, label, parent, trackers); widget = pair.first; @@ -212,7 +249,8 @@ std::pair<QWidget*, void*> CreateWidget(Settings::BasicSetting* setting, auto tuple = CreateCombobox(setting, label, parent, managed); widget = std::get<0>(tuple); extra = std::get<1>(tuple); - load_func = std::get<2>(tuple); + button = std::get<2>(tuple); + load_func = std::get<3>(tuple); } else if (type == typeid(u32) || type == typeid(int)) { switch (request) { case RequestType::Default: { @@ -226,7 +264,8 @@ std::pair<QWidget*, void*> CreateWidget(Settings::BasicSetting* setting, auto tuple = CreateCombobox(setting, label, parent, managed); widget = std::get<0>(tuple); extra = std::get<1>(tuple); - load_func = std::get<2>(tuple); + button = std::get<2>(tuple); + load_func = std::get<3>(tuple); break; } case RequestType::SpinBox: @@ -238,7 +277,7 @@ std::pair<QWidget*, void*> CreateWidget(Settings::BasicSetting* setting, if (widget == nullptr) { LOG_ERROR(Frontend, "No widget was created for \"{}\"", setting->GetLabel()); - return {nullptr, nullptr}; + return {nullptr, nullptr, nullptr}; } apply_funcs.push_front([load_func, setting](bool powered_on) { @@ -257,7 +296,7 @@ std::pair<QWidget*, void*> CreateWidget(Settings::BasicSetting* setting, widget->setToolTip(tooltip); - return {widget, extra}; + return {widget, extra, button}; } Tab::Tab(std::shared_ptr<std::forward_list<Tab*>> group_, QWidget* parent) diff --git a/src/yuzu/configuration/configuration_shared.h b/src/yuzu/configuration/configuration_shared.h index 942af0215..63df11d26 100644 --- a/src/yuzu/configuration/configuration_shared.h +++ b/src/yuzu/configuration/configuration_shared.h @@ -13,6 +13,8 @@ #include "common/settings.h" #include "yuzu/configuration/shared_translation.h" +class QPushButton; + namespace ConfigurationShared { class Tab : public QWidget { @@ -49,13 +51,11 @@ enum class RequestType { MaxEnum, }; -std::pair<QWidget*, void*> CreateWidget(Settings::BasicSetting* setting, - const TranslationMap& translations, QWidget* parent, - bool runtime_lock, - std::forward_list<std::function<void(bool)>>& apply_funcs, - std::list<CheckState>& trackers, - RequestType request = RequestType::Default, - bool managed = true); +std::tuple<QWidget*, void*, QPushButton*> CreateWidget( + Settings::BasicSetting* setting, const TranslationMap& translations, QWidget* parent, + bool runtime_lock, std::forward_list<std::function<void(bool)>>& apply_funcs, + std::list<CheckState>& trackers, RequestType request = RequestType::Default, + bool managed = true); // Global-aware apply and set functions diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 03261992a..8c6fee2a5 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp @@ -139,8 +139,8 @@ void ConfigureGeneral::SetupPerGameUI() { ui->button_reset_defaults->setVisible(false); - ConfigurationShared::SetColoredTristate(ui->toggle_speed_limit, - Settings::values.use_speed_limit, use_speed_limit); + // ConfigurationShared::SetColoredTristate(ui->toggle_speed_limit, + // Settings::values.use_speed_limit, use_speed_limit); ConfigurationShared::SetColoredTristate(ui->use_multi_core, Settings::values.use_multi_core, use_multi_core); diff --git a/src/yuzu/configuration/configure_graphics.cpp b/src/yuzu/configuration/configure_graphics.cpp index 37a10ac87..1145b6c43 100644 --- a/src/yuzu/configuration/configure_graphics.cpp +++ b/src/yuzu/configuration/configure_graphics.cpp @@ -20,8 +20,11 @@ #include <QSlider> #include <QStringLiteral> #include <QtCore/qobjectdefs.h> +#include <qabstractbutton.h> +#include <qboxlayout.h> #include <qcoreevent.h> #include <qglobal.h> +#include <qgridlayout.h> #include <vulkan/vulkan_core.h> #include "common/common_types.h" @@ -112,7 +115,7 @@ ConfigureGraphics::ConfigureGraphics( } } - connect(api_combobox, qOverload<int>(&QComboBox::currentIndexChanged), this, [this] { + connect(api_combobox, qOverload<int>(&QComboBox::activated), this, [this] { UpdateAPILayout(); PopulateVSyncModeSelection(); }); @@ -146,6 +149,10 @@ ConfigureGraphics::ConfigureGraphics( } void ConfigureGraphics::PopulateVSyncModeSelection() { + if (!Settings::IsConfiguringGlobal()) { + return; + } + const Settings::RendererBackend backend{GetCurrentGraphicsBackend()}; if (backend == Settings::RendererBackend::Null) { vsync_mode_combobox->setEnabled(false); @@ -204,7 +211,12 @@ ConfigureGraphics::~ConfigureGraphics() = default; void ConfigureGraphics::SetConfiguration() { const bool runtime_lock = !system.IsPoweredOn(); - QLayout& api_layout = *ui->api_widget->layout(); + QLayout* api_layout = ui->api_widget->layout(); + QWidget* api_grid_widget = new QWidget(this); + QVBoxLayout* api_grid_layout = new QVBoxLayout(api_grid_widget); + api_grid_layout->setContentsMargins(0, 0, 0, 0); + api_layout->addWidget(api_grid_widget); + QLayout& graphics_layout = *ui->graphics_widget->layout(); std::map<bool, std::map<std::string, QWidget*>> hold_graphics; @@ -213,7 +225,7 @@ void ConfigureGraphics::SetConfiguration() { for (const auto setting : Settings::values.linkage.by_category[Settings::Category::Renderer]) { const auto& setting_label = setting->GetLabel(); - auto [widget, extra] = [&]() { + auto [widget, extra, button] = [&]() { if (setting->Id() == Settings::values.vulkan_device.Id() || setting->Id() == Settings::values.shader_backend.Id() || setting->Id() == Settings::values.vsync_mode.Id()) { @@ -230,8 +242,20 @@ void ConfigureGraphics::SetConfiguration() { continue; } - if (setting->Id() == Settings::values.vulkan_device.Id()) { - api_layout.addWidget(widget); + if (setting->Id() == Settings::values.renderer_backend.Id()) { + api_grid_layout->addWidget(widget); + api_combobox = reinterpret_cast<QComboBox*>(extra); + api_restore_global_button = button; + + if (!Settings::IsConfiguringGlobal()) { + QObject::connect(api_restore_global_button, &QAbstractButton::clicked, + [=](bool) { UpdateAPILayout(); }); + + widget->layout()->removeWidget(api_restore_global_button); + api_layout->addWidget(api_restore_global_button); + } + } else if (setting->Id() == Settings::values.vulkan_device.Id()) { + api_layout->addWidget(widget); api_combobox = reinterpret_cast<QComboBox*>(extra); } else if (setting->Id() == Settings::values.vulkan_device.Id()) { hold_api.push_front(widget); @@ -256,7 +280,7 @@ void ConfigureGraphics::SetConfiguration() { } for (auto widget : hold_api) { - api_layout.addWidget(widget); + api_grid_layout->addWidget(widget); } } @@ -297,6 +321,25 @@ void ConfigureGraphics::ApplyConfiguration() { const auto vsync_mode = PresentModeToSetting(mode); Settings::values.vsync_mode.SetValue(vsync_mode); } + + Settings::values.shader_backend.SetGlobal(true); + Settings::values.vulkan_device.SetGlobal(true); + if (!Settings::IsConfiguringGlobal() && api_restore_global_button->isEnabled()) { + auto backend = static_cast<Settings::RendererBackend>(api_combobox->currentIndex()); + switch (backend) { + case Settings::RendererBackend::OpenGL: + Settings::values.shader_backend.SetGlobal(false); + Settings::values.shader_backend.SetValue( + static_cast<Settings::ShaderBackend>(shader_backend_combobox->currentIndex())); + break; + case Settings::RendererBackend::Vulkan: + Settings::values.vulkan_device.SetGlobal(false); + Settings::values.vulkan_device.SetValue(vulkan_device_combobox->currentIndex()); + break; + case Settings::RendererBackend::Null: + break; + } + } } void ConfigureGraphics::changeEvent(QEvent* event) { @@ -322,8 +365,7 @@ void ConfigureGraphics::UpdateBackgroundColorButton(QColor color) { } void ConfigureGraphics::UpdateAPILayout() { - if (!Settings::IsConfiguringGlobal() && - api_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { + if (!Settings::IsConfiguringGlobal() && !api_restore_global_button->isEnabled()) { vulkan_device = Settings::values.vulkan_device.GetValue(true); shader_backend = Settings::values.shader_backend.GetValue(true); vulkan_device_widget->setEnabled(false); @@ -371,15 +413,8 @@ void ConfigureGraphics::RetrieveVulkanDevices() { } Settings::RendererBackend ConfigureGraphics::GetCurrentGraphicsBackend() const { - if (Settings::IsConfiguringGlobal()) { - return static_cast<Settings::RendererBackend>(api_combobox->currentIndex()); - } - - if (api_combobox->currentIndex() == ConfigurationShared::USE_GLOBAL_INDEX) { - Settings::values.renderer_backend.SetGlobal(true); - return Settings::values.renderer_backend.GetValue(); + if (!Settings::IsConfiguringGlobal() && !api_restore_global_button->isEnabled()) { + return Settings::values.renderer_backend.GetValue(true); } - Settings::values.renderer_backend.SetGlobal(false); - return static_cast<Settings::RendererBackend>(api_combobox->currentIndex() - - ConfigurationShared::USE_GLOBAL_OFFSET); + return static_cast<Settings::RendererBackend>(api_combobox->currentIndex()); } diff --git a/src/yuzu/configuration/configure_graphics.h b/src/yuzu/configuration/configure_graphics.h index c226e825b..12a588127 100644 --- a/src/yuzu/configuration/configure_graphics.h +++ b/src/yuzu/configuration/configure_graphics.h @@ -85,6 +85,7 @@ private: const Core::System& system; const ConfigurationShared::TranslationMap& translations; + QPushButton* api_restore_global_button; QComboBox* vulkan_device_combobox; QComboBox* api_combobox; QComboBox* shader_backend_combobox; diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 565429c98..1f6ffea1a 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -27,7 +27,7 @@ <layout class="QVBoxLayout" name="verticalLayout_3"> <item> <widget class="QWidget" name="api_widget" native="true"> - <layout class="QGridLayout" name="gridLayout"> + <layout class="QHBoxLayout" name="horizontalLayout"> <property name="leftMargin"> <number>0</number> </property> @@ -40,9 +40,6 @@ <property name="bottomMargin"> <number>0</number> </property> - <property name="horizontalSpacing"> - <number>6</number> - </property> </layout> </widget> </item> @@ -63,7 +60,20 @@ <layout class="QVBoxLayout" name="verticalLayout_4"> <item> <widget class="QWidget" name="graphics_widget" native="true"> - <layout class="QVBoxLayout" name="verticalLayout"/> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + </layout> </widget> </item> </layout> diff --git a/src/yuzu/configuration/configure_graphics_advanced.cpp b/src/yuzu/configuration/configure_graphics_advanced.cpp index 3a207e2cd..8a53ad111 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.cpp +++ b/src/yuzu/configuration/configure_graphics_advanced.cpp @@ -32,7 +32,7 @@ void ConfigureGraphicsAdvanced::SetConfiguration() { for (auto setting : Settings::values.linkage.by_category[Settings::Category::RendererAdvanced]) { - auto [widget, extra] = ConfigurationShared::CreateWidget( + auto [widget, extra, button] = ConfigurationShared::CreateWidget( setting, translations, this, runtime_lock, apply_funcs, trackers); if (widget == nullptr) { diff --git a/src/yuzu/configuration/configure_graphics_advanced.ui b/src/yuzu/configuration/configure_graphics_advanced.ui index 113fbc010..37a854ca3 100644 --- a/src/yuzu/configuration/configure_graphics_advanced.ui +++ b/src/yuzu/configuration/configure_graphics_advanced.ui @@ -27,7 +27,20 @@ <layout class="QVBoxLayout" name="verticalLayout_3"> <item> <widget class="QWidget" name="populate_target" native="true"> - <layout class="QVBoxLayout" name="verticalLayout"/> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + </layout> </widget> </item> </layout> diff --git a/src/yuzu/configuration/shared_translation.cpp b/src/yuzu/configuration/shared_translation.cpp index 5a2071781..a13636af6 100644 --- a/src/yuzu/configuration/shared_translation.cpp +++ b/src/yuzu/configuration/shared_translation.cpp @@ -93,6 +93,9 @@ std::unique_ptr<TranslationMap> InitializeTranslations(QWidget* parent) { "Enable compute pipelines, required by some games.\nThis setting only exists for Intel " "proprietary drivers, and may crash if enabled.\nCompute pipelines are always enabled " "on all other drivers."); + INSERT(use_reactive_flushing, "Enable Reactive Flushing", + "Uses reactive flushing instead of predictive flushing, allowing more accurate memory " + "syncing."); // Renderer (Debug) |