mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-12-09 13:19:00 +00:00
config: Add present mode option. (#3502)
* config: Add present mode option. * settings_dialog: Add details for present modes.
This commit is contained in:
@@ -79,6 +79,7 @@ static bool shouldPatchShaders = false;
|
|||||||
static u32 vblankDivider = 1;
|
static u32 vblankDivider = 1;
|
||||||
static bool isFullscreen = false;
|
static bool isFullscreen = false;
|
||||||
static std::string fullscreenMode = "Windowed";
|
static std::string fullscreenMode = "Windowed";
|
||||||
|
static std::string presentMode = "Mailbox";
|
||||||
static bool isHDRAllowed = false;
|
static bool isHDRAllowed = false;
|
||||||
|
|
||||||
// Vulkan
|
// Vulkan
|
||||||
@@ -194,6 +195,10 @@ std::string getFullscreenMode() {
|
|||||||
return fullscreenMode;
|
return fullscreenMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string getPresentMode() {
|
||||||
|
return presentMode;
|
||||||
|
}
|
||||||
|
|
||||||
bool getisTrophyPopupDisabled() {
|
bool getisTrophyPopupDisabled() {
|
||||||
return isTrophyPopupDisabled;
|
return isTrophyPopupDisabled;
|
||||||
}
|
}
|
||||||
@@ -466,6 +471,10 @@ void setFullscreenMode(std::string mode) {
|
|||||||
fullscreenMode = mode;
|
fullscreenMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setPresentMode(std::string mode) {
|
||||||
|
presentMode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
void setisTrophyPopupDisabled(bool disable) {
|
void setisTrophyPopupDisabled(bool disable) {
|
||||||
isTrophyPopupDisabled = disable;
|
isTrophyPopupDisabled = disable;
|
||||||
}
|
}
|
||||||
@@ -726,6 +735,7 @@ void load(const std::filesystem::path& path) {
|
|||||||
vblankDivider = toml::find_or<int>(gpu, "vblankDivider", vblankDivider);
|
vblankDivider = toml::find_or<int>(gpu, "vblankDivider", vblankDivider);
|
||||||
isFullscreen = toml::find_or<bool>(gpu, "Fullscreen", isFullscreen);
|
isFullscreen = toml::find_or<bool>(gpu, "Fullscreen", isFullscreen);
|
||||||
fullscreenMode = toml::find_or<std::string>(gpu, "FullscreenMode", fullscreenMode);
|
fullscreenMode = toml::find_or<std::string>(gpu, "FullscreenMode", fullscreenMode);
|
||||||
|
presentMode = toml::find_or<std::string>(gpu, "presentMode", presentMode);
|
||||||
isHDRAllowed = toml::find_or<bool>(gpu, "allowHDR", isHDRAllowed);
|
isHDRAllowed = toml::find_or<bool>(gpu, "allowHDR", isHDRAllowed);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -894,6 +904,7 @@ void save(const std::filesystem::path& path) {
|
|||||||
data["GPU"]["vblankDivider"] = vblankDivider;
|
data["GPU"]["vblankDivider"] = vblankDivider;
|
||||||
data["GPU"]["Fullscreen"] = isFullscreen;
|
data["GPU"]["Fullscreen"] = isFullscreen;
|
||||||
data["GPU"]["FullscreenMode"] = fullscreenMode;
|
data["GPU"]["FullscreenMode"] = fullscreenMode;
|
||||||
|
data["GPU"]["presentMode"] = presentMode;
|
||||||
data["GPU"]["allowHDR"] = isHDRAllowed;
|
data["GPU"]["allowHDR"] = isHDRAllowed;
|
||||||
data["Vulkan"]["gpuId"] = gpuId;
|
data["Vulkan"]["gpuId"] = gpuId;
|
||||||
data["Vulkan"]["validation"] = vkValidation;
|
data["Vulkan"]["validation"] = vkValidation;
|
||||||
@@ -1003,6 +1014,7 @@ void setDefaultValues() {
|
|||||||
vblankDivider = 1;
|
vblankDivider = 1;
|
||||||
isFullscreen = false;
|
isFullscreen = false;
|
||||||
fullscreenMode = "Windowed";
|
fullscreenMode = "Windowed";
|
||||||
|
presentMode = "Mailbox";
|
||||||
isHDRAllowed = false;
|
isHDRAllowed = false;
|
||||||
|
|
||||||
// Vulkan
|
// Vulkan
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ bool getIsFullscreen();
|
|||||||
void setIsFullscreen(bool enable);
|
void setIsFullscreen(bool enable);
|
||||||
std::string getFullscreenMode();
|
std::string getFullscreenMode();
|
||||||
void setFullscreenMode(std::string mode);
|
void setFullscreenMode(std::string mode);
|
||||||
|
std::string getPresentMode();
|
||||||
|
void setPresentMode(std::string mode);
|
||||||
u32 getWindowWidth();
|
u32 getWindowWidth();
|
||||||
u32 getWindowHeight();
|
u32 getWindowHeight();
|
||||||
void setWindowWidth(u32 width);
|
void setWindowWidth(u32 width);
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ const QVector<int> languageIndexes = {21, 23, 14, 6, 18, 1, 12, 22, 2, 4, 25, 2
|
|||||||
QMap<QString, QString> channelMap;
|
QMap<QString, QString> channelMap;
|
||||||
QMap<QString, QString> logTypeMap;
|
QMap<QString, QString> logTypeMap;
|
||||||
QMap<QString, QString> screenModeMap;
|
QMap<QString, QString> screenModeMap;
|
||||||
|
QMap<QString, QString> presentModeMap;
|
||||||
QMap<QString, QString> chooseHomeTabMap;
|
QMap<QString, QString> chooseHomeTabMap;
|
||||||
QMap<QString, QString> micMap;
|
QMap<QString, QString> micMap;
|
||||||
|
|
||||||
@@ -93,6 +94,9 @@ SettingsDialog::SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
|
|||||||
screenModeMap = {{tr("Fullscreen (Borderless)"), "Fullscreen (Borderless)"},
|
screenModeMap = {{tr("Fullscreen (Borderless)"), "Fullscreen (Borderless)"},
|
||||||
{tr("Windowed"), "Windowed"},
|
{tr("Windowed"), "Windowed"},
|
||||||
{tr("Fullscreen"), "Fullscreen"}};
|
{tr("Fullscreen"), "Fullscreen"}};
|
||||||
|
presentModeMap = {{tr("Mailbox (Vsync)"), "Mailbox"},
|
||||||
|
{tr("Fifo (Vsync)"), "Fifo"},
|
||||||
|
{tr("Immediate (No Vsync)"), "Immediate"}};
|
||||||
chooseHomeTabMap = {{tr("General"), "General"}, {tr("GUI"), "GUI"},
|
chooseHomeTabMap = {{tr("General"), "General"}, {tr("GUI"), "GUI"},
|
||||||
{tr("Graphics"), "Graphics"}, {tr("User"), "User"},
|
{tr("Graphics"), "Graphics"}, {tr("User"), "User"},
|
||||||
{tr("Input"), "Input"}, {tr("Paths"), "Paths"},
|
{tr("Input"), "Input"}, {tr("Paths"), "Paths"},
|
||||||
@@ -414,6 +418,7 @@ SettingsDialog::SettingsDialog(std::shared_ptr<gui_settings> gui_settings,
|
|||||||
// Graphics
|
// Graphics
|
||||||
ui->graphicsAdapterGroupBox->installEventFilter(this);
|
ui->graphicsAdapterGroupBox->installEventFilter(this);
|
||||||
ui->windowSizeGroupBox->installEventFilter(this);
|
ui->windowSizeGroupBox->installEventFilter(this);
|
||||||
|
ui->presentModeGroupBox->installEventFilter(this);
|
||||||
ui->heightDivider->installEventFilter(this);
|
ui->heightDivider->installEventFilter(this);
|
||||||
ui->dumpShadersCheckBox->installEventFilter(this);
|
ui->dumpShadersCheckBox->installEventFilter(this);
|
||||||
ui->nullGpuCheckBox->installEventFilter(this);
|
ui->nullGpuCheckBox->installEventFilter(this);
|
||||||
@@ -540,6 +545,9 @@ void SettingsDialog::LoadValuesFromConfig() {
|
|||||||
QString translatedText_FullscreenMode =
|
QString translatedText_FullscreenMode =
|
||||||
screenModeMap.key(QString::fromStdString(Config::getFullscreenMode()));
|
screenModeMap.key(QString::fromStdString(Config::getFullscreenMode()));
|
||||||
ui->displayModeComboBox->setCurrentText(translatedText_FullscreenMode);
|
ui->displayModeComboBox->setCurrentText(translatedText_FullscreenMode);
|
||||||
|
QString translatedText_PresentMode =
|
||||||
|
presentModeMap.key(QString::fromStdString(Config::getPresentMode()));
|
||||||
|
ui->presentModeComboBox->setCurrentText(translatedText_PresentMode);
|
||||||
ui->gameSizeCheckBox->setChecked(toml::find_or<bool>(data, "GUI", "loadGameSizeEnabled", true));
|
ui->gameSizeCheckBox->setChecked(toml::find_or<bool>(data, "GUI", "loadGameSizeEnabled", true));
|
||||||
ui->showSplashCheckBox->setChecked(toml::find_or<bool>(data, "General", "showSplash", false));
|
ui->showSplashCheckBox->setChecked(toml::find_or<bool>(data, "General", "showSplash", false));
|
||||||
QString translatedText_logType = logTypeMap.key(QString::fromStdString(Config::getLogType()));
|
QString translatedText_logType = logTypeMap.key(QString::fromStdString(Config::getLogType()));
|
||||||
@@ -746,6 +754,11 @@ void SettingsDialog::updateNoteTextEdit(const QString& elementName) {
|
|||||||
// Graphics
|
// Graphics
|
||||||
if (elementName == "graphicsAdapterGroupBox") {
|
if (elementName == "graphicsAdapterGroupBox") {
|
||||||
text = tr("Graphics Device:\\nOn multiple GPU systems, select the GPU the emulator will use from the drop down list,\\nor select \"Auto Select\" to automatically determine it.");
|
text = tr("Graphics Device:\\nOn multiple GPU systems, select the GPU the emulator will use from the drop down list,\\nor select \"Auto Select\" to automatically determine it.");
|
||||||
|
} else if (elementName == "presentModeGroupBox") {
|
||||||
|
text = tr("Present Mode:\\nConfigures how video output will be presented to your screen.\\n\\n"
|
||||||
|
"Mailbox: Frames synchronize with your screen's refresh rate. New frames will replace any pending frames. Reduces latency but may skip frames if running behind.\\n"
|
||||||
|
"Fifo: Frames synchronize with your screen's refresh rate. New frames will be queued behind pending frames. Ensures all frames are presented but may increase latency.\\n"
|
||||||
|
"Immediate: Frames immediately present to your screen when ready. May result in tearing.");
|
||||||
} else if (elementName == "windowSizeGroupBox") {
|
} else if (elementName == "windowSizeGroupBox") {
|
||||||
text = tr("Width/Height:\\nSets the size of the emulator window at launch, which can be resized during gameplay.\\nThis is different from the in-game resolution.");
|
text = tr("Width/Height:\\nSets the size of the emulator window at launch, which can be resized during gameplay.\\nThis is different from the in-game resolution.");
|
||||||
} else if (elementName == "heightDivider") {
|
} else if (elementName == "heightDivider") {
|
||||||
@@ -834,6 +847,8 @@ void SettingsDialog::UpdateSettings() {
|
|||||||
"Windowed");
|
"Windowed");
|
||||||
Config::setFullscreenMode(
|
Config::setFullscreenMode(
|
||||||
screenModeMap.value(ui->displayModeComboBox->currentText()).toStdString());
|
screenModeMap.value(ui->displayModeComboBox->currentText()).toStdString());
|
||||||
|
Config::setPresentMode(
|
||||||
|
presentModeMap.value(ui->presentModeComboBox->currentText()).toStdString());
|
||||||
Config::setIsMotionControlsEnabled(ui->motionControlsCheckBox->isChecked());
|
Config::setIsMotionControlsEnabled(ui->motionControlsCheckBox->isChecked());
|
||||||
Config::setBackgroundControllerInput(ui->backgroundControllerCheckBox->isChecked());
|
Config::setBackgroundControllerInput(ui->backgroundControllerCheckBox->isChecked());
|
||||||
Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked());
|
Config::setisTrophyPopupDisabled(ui->disableTrophycheckBox->isChecked());
|
||||||
|
|||||||
@@ -1096,6 +1096,40 @@
|
|||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="presentModeGroupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Present Mode</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="presentModeLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="presentModeComboBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Mailbox (Vsync)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Fifo (Vsync)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Immediate (No Vsync)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="windowSizeLayout">
|
<layout class="QHBoxLayout" name="windowSizeLayout">
|
||||||
<item>
|
<item>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ static constexpr vk::SurfaceFormatKHR SURFACE_FORMAT_HDR = {
|
|||||||
Swapchain::Swapchain(const Instance& instance_, const Frontend::WindowSDL& window_)
|
Swapchain::Swapchain(const Instance& instance_, const Frontend::WindowSDL& window_)
|
||||||
: instance{instance_}, window{window_}, surface{CreateSurface(instance.GetInstance(), window)} {
|
: instance{instance_}, window{window_}, surface{CreateSurface(instance.GetInstance(), window)} {
|
||||||
FindPresentFormat();
|
FindPresentFormat();
|
||||||
|
FindPresentMode();
|
||||||
|
|
||||||
Create(window.GetWidth(), window.GetHeight());
|
Create(window.GetWidth(), window.GetHeight());
|
||||||
ImGui::Core::Initialize(instance, window, image_count, surface_format.format);
|
ImGui::Core::Initialize(instance, window, image_count, surface_format.format);
|
||||||
@@ -45,20 +46,6 @@ void Swapchain::Create(u32 width_, u32 height_) {
|
|||||||
instance.GetPresentQueueFamilyIndex(),
|
instance.GetPresentQueueFamilyIndex(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto [modes_result, modes] =
|
|
||||||
instance.GetPhysicalDevice().getSurfacePresentModesKHR(surface);
|
|
||||||
const auto find_mode = [&modes_result, &modes](vk::PresentModeKHR requested) {
|
|
||||||
if (modes_result != vk::Result::eSuccess) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const auto it =
|
|
||||||
std::find_if(modes.begin(), modes.end(),
|
|
||||||
[&requested](vk::PresentModeKHR mode) { return mode == requested; });
|
|
||||||
|
|
||||||
return it != modes.cend();
|
|
||||||
};
|
|
||||||
const bool has_mailbox = find_mode(vk::PresentModeKHR::eMailbox);
|
|
||||||
|
|
||||||
const bool exclusive = queue_family_indices[0] == queue_family_indices[1];
|
const bool exclusive = queue_family_indices[0] == queue_family_indices[1];
|
||||||
const u32 queue_family_indices_count = exclusive ? 1u : 2u;
|
const u32 queue_family_indices_count = exclusive ? 1u : 2u;
|
||||||
const vk::SharingMode sharing_mode =
|
const vk::SharingMode sharing_mode =
|
||||||
@@ -78,7 +65,7 @@ void Swapchain::Create(u32 width_, u32 height_) {
|
|||||||
.pQueueFamilyIndices = queue_family_indices.data(),
|
.pQueueFamilyIndices = queue_family_indices.data(),
|
||||||
.preTransform = transform,
|
.preTransform = transform,
|
||||||
.compositeAlpha = composite_alpha,
|
.compositeAlpha = composite_alpha,
|
||||||
.presentMode = has_mailbox ? vk::PresentModeKHR::eMailbox : vk::PresentModeKHR::eImmediate,
|
.presentMode = present_mode,
|
||||||
.clipped = true,
|
.clipped = true,
|
||||||
.oldSwapchain = nullptr,
|
.oldSwapchain = nullptr,
|
||||||
};
|
};
|
||||||
@@ -202,6 +189,38 @@ void Swapchain::FindPresentFormat() {
|
|||||||
UNREACHABLE_MSG("Unable to find required swapchain format!");
|
UNREACHABLE_MSG("Unable to find required swapchain format!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Swapchain::FindPresentMode() {
|
||||||
|
const auto [modes_result, modes] =
|
||||||
|
instance.GetPhysicalDevice().getSurfacePresentModesKHR(surface);
|
||||||
|
if (modes_result != vk::Result::eSuccess) {
|
||||||
|
LOG_ERROR(Render, "Failed to query available present modes, falling back to Fifo as "
|
||||||
|
"guaranteed supported option.");
|
||||||
|
present_mode = vk::PresentModeKHR::eFifo;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto requested_mode = Config::getPresentMode();
|
||||||
|
if (requested_mode == "Mailbox") {
|
||||||
|
present_mode = vk::PresentModeKHR::eMailbox;
|
||||||
|
} else if (requested_mode == "Fifo") {
|
||||||
|
present_mode = vk::PresentModeKHR::eFifo;
|
||||||
|
} else if (requested_mode == "Immediate") {
|
||||||
|
present_mode = vk::PresentModeKHR::eImmediate;
|
||||||
|
} else {
|
||||||
|
LOG_ERROR(Render_Vulkan, "Unknown present mode {}, defaulting to Mailbox.",
|
||||||
|
Config::getPresentMode());
|
||||||
|
present_mode = vk::PresentModeKHR::eMailbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::ranges::find(modes, present_mode) == modes.cend()) {
|
||||||
|
// FIFO is guaranteed to be supported by the Vulkan spec.
|
||||||
|
constexpr auto fallback = vk::PresentModeKHR::eFifo;
|
||||||
|
LOG_WARNING(Render, "Requested present mode {} is not supported, falling back to {}.",
|
||||||
|
vk::to_string(present_mode), vk::to_string(fallback));
|
||||||
|
present_mode = fallback;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Swapchain::SetSurfaceProperties() {
|
void Swapchain::SetSurfaceProperties() {
|
||||||
const auto [capabilities_result, capabilities] =
|
const auto [capabilities_result, capabilities] =
|
||||||
instance.GetPhysicalDevice().getSurfaceCapabilitiesKHR(surface);
|
instance.GetPhysicalDevice().getSurfaceCapabilitiesKHR(surface);
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ private:
|
|||||||
/// Selects the best available swapchain image format
|
/// Selects the best available swapchain image format
|
||||||
void FindPresentFormat();
|
void FindPresentFormat();
|
||||||
|
|
||||||
|
/// Selects the best available present mode
|
||||||
|
void FindPresentMode();
|
||||||
|
|
||||||
/// Sets the surface properties according to device capabilities
|
/// Sets the surface properties according to device capabilities
|
||||||
void SetSurfaceProperties();
|
void SetSurfaceProperties();
|
||||||
|
|
||||||
@@ -115,6 +118,7 @@ private:
|
|||||||
vk::SurfaceKHR surface{};
|
vk::SurfaceKHR surface{};
|
||||||
vk::SurfaceFormatKHR surface_format;
|
vk::SurfaceFormatKHR surface_format;
|
||||||
vk::Format view_format;
|
vk::Format view_format;
|
||||||
|
vk::PresentModeKHR present_mode;
|
||||||
vk::Extent2D extent;
|
vk::Extent2D extent;
|
||||||
vk::SurfaceTransformFlagBitsKHR transform;
|
vk::SurfaceTransformFlagBitsKHR transform;
|
||||||
vk::CompositeAlphaFlagBitsKHR composite_alpha;
|
vk::CompositeAlphaFlagBitsKHR composite_alpha;
|
||||||
|
|||||||
Reference in New Issue
Block a user