Compare commits

...
9 Commits
Author SHA1 Message Date
TJnotJTandlightningterror fa50a11eac GS:HW: Add feedback flags for VK depth stencil creation.
VK does depth feedback with depth textures. Fixed regression with texture usage flag refactor.
2026-07-25 21:08:36 +02:00
PCSX2 Botandlightningterror ee4a83b0c9 [ci skip] Qt: Update Base Translation. 2026-07-25 02:30:33 +02:00
SternXDandTy 94ad591d4f FullscreenUI: Add icons to all ShowToasts 2026-07-24 07:40:03 -04:00
SternXDandTy bd0982ed4c FullscreenUI: Fix icon layout in toast notifications 2026-07-24 07:40:03 -04:00
SternXDandTy 8e9be7411c Qt: Fix incorrect setting keys 2026-07-24 07:40:03 -04:00
SternXDandTy 1528e962d2 FullscreenUI: Align Achievements settings layout with Qt
Also don't show the enable prompts until the login dialog is dismissed. Account row now also shows the RA avatar and opens the profile page.
2026-07-24 07:40:03 -04:00
SternXDandTy d9822b8ad8 FullscreenUI: Align setting names with Qt 2026-07-24 07:40:03 -04:00
SternXDandTy 2fc8ae44be FullscreenUI: Expose missing settings 2026-07-24 07:40:03 -04:00
SternXDandTy 66c0771d12 Qt: Fix Optimal Frame Pacing not inheriting from global 2026-07-21 17:31:17 -04:00
11 changed files with 1956 additions and 1623 deletions
+6 -12
View File
@@ -262,20 +262,14 @@ void EmulationSettingsWidget::onOptimalFramePacingChanged()
const QSignalBlocker sb(m_ui.maxFrameLatency);
std::optional<int> value;
bool optimal = false;
if (m_ui.optimalFramePacing->checkState() != Qt::PartiallyChecked)
{
optimal = m_ui.optimalFramePacing->isChecked();
value = optimal ? 0 : DEFAULT_FRAME_LATENCY;
}
else
{
value = dialog()->getEffectiveIntValue("EmuCore/GS", "VsyncQueueSize", DEFAULT_FRAME_LATENCY);
optimal = (value == 0);
}
value = m_ui.optimalFramePacing->isChecked() ? 0 : DEFAULT_FRAME_LATENCY;
const int latency = value.value_or(Host::GetBaseIntSettingValue("EmuCore/GS", "VsyncQueueSize", DEFAULT_FRAME_LATENCY));
const bool optimal = (latency == 0);
m_ui.maxFrameLatency->setMinimum(optimal ? 0 : 1);
m_ui.maxFrameLatency->setValue(optimal ? 0 : DEFAULT_FRAME_LATENCY);
m_ui.maxFrameLatency->setValue(latency);
m_ui.maxFrameLatency->setEnabled(!dialog()->isPerGameSettings() && !m_ui.optimalFramePacing->isChecked());
dialog()->setIntSettingValue("EmuCore/GS", "VsyncQueueSize", value);
@@ -300,7 +294,7 @@ void EmulationSettingsWidget::updateOptimalFramePacing()
}
m_ui.maxFrameLatency->setMinimum(optimal ? 0 : 1);
m_ui.maxFrameLatency->setValue(optimal ? 0 : value);
m_ui.maxFrameLatency->setValue(value);
}
void EmulationSettingsWidget::updateUseVSyncForTimingEnabled()
+1 -1
View File
@@ -19,7 +19,7 @@ FolderSettingsWidget::FolderSettingsWidget(SettingsWindow* settings_dialog, QWid
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.organizeSnapshotsByGame, "EmuCore/GS", "OrganizeScreenshotsByGame", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.organizeVideoDumpByGame, "EmuCore/GS", "OrganizeVideoCaptureByGame", false);
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.saveStates, m_ui.saveStatesBrowse, m_ui.saveStatesOpen, m_ui.saveStatesReset,
"Folders", "SaveStates", Path::Combine(EmuFolders::DataRoot, "sstates"));
"Folders", "Savestates", Path::Combine(EmuFolders::DataRoot, "sstates"));
SettingWidgetBinder::BindWidgetToFolderSetting(sif, m_ui.videoDumpingDirectory, m_ui.videoDumpingDirectoryBrowse, m_ui.videoDumpingDirectoryOpen, m_ui.videoDumpingDirectoryReset,
"Folders", "Videos", Path::Combine(EmuFolders::DataRoot, "videos"));
dialog()->registerWidgetHelp(m_ui.organizeSnapshotsByGame, tr("Save Snapshots in Game-Specific Folders"), tr("Unchecked"),
+1 -1
View File
@@ -173,7 +173,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* settings_dialog,
SettingWidgetBinder::BindWidgetToIntSetting(sif, m_upscaling.textureOffsetY, "EmuCore/GS", "UserHacks_TCOffsetY", 0);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_upscaling.alignSprite, "EmuCore/GS", "UserHacks_align_sprite_X", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_upscaling.mergeSprite, "EmuCore/GS", "UserHacks_merge_pp_sprite", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_upscaling.forceEvenSpritePosition, "EmuCore/GS", "UserHacks_forceEvenSpritePosition", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_upscaling.forceEvenSpritePosition, "EmuCore/GS", "UserHacks_ForceEvenSpritePosition", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_upscaling.nativePaletteDraw, "EmuCore/GS", "UserHacks_NativePaletteDraw", false);
//////////////////////////////////////////////////////////////////////////
+1 -1
View File
@@ -74,7 +74,7 @@ OSDSettingsWidget::OSDSettingsWidget(SettingsWindow* settings_dialog, QWidget* p
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showVideoCapture, "EmuCore/GS", "OsdShowVideoCapture", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showInputRec, "EmuCore/GS", "OsdShowInputRec", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.showTextureReplacements, "EmuCore/GS", "OsdShowTextureReplacements", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.warnAboutUnsafeSettings, "EmuCore", "OsdWarnAboutUnsafeSettings", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.warnAboutUnsafeSettings, "EmuCore", "WarnAboutUnsafeSettings", true);
#ifndef _WIN32
// Currently DX12 only
File diff suppressed because it is too large Load Diff
+7 -2
View File
@@ -791,14 +791,19 @@ GSTexture* GSDevice::CreateShaderWriteTarget(const GSVector2i& size, GSTexture::
return FetchSurface(GSTexture::ShaderWriteTarget, size.x, size.y, 1, format, clear, prefer_reuse);
}
GSTexture::Usage GSDevice::GetDepthStencilUsage() const
{
return m_features.depth_feedback ? GSTexture::FeedbackDepth : GSTexture::DepthStencil;
}
GSTexture* GSDevice::CreateDepthStencil(int w, int h, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::DepthStencil, w, h, 1, GSTexture::Format::DepthStencil, clear, prefer_reuse);
return FetchSurface(GetDepthStencilUsage(), w, h, 1, GSTexture::Format::DepthStencil, clear, prefer_reuse);
}
GSTexture* GSDevice::CreateDepthStencil(const GSVector2i& size, bool clear, bool prefer_reuse)
{
return FetchSurface(GSTexture::DepthStencil, size.x, size.y, 1, GSTexture::Format::DepthStencil, clear, prefer_reuse);
return FetchSurface(GetDepthStencilUsage(), size.x, size.y, 1, GSTexture::Format::DepthStencil, clear, prefer_reuse);
}
GSTexture* GSDevice::CreateTexture(int w, int h, int mipmap_levels, GSTexture::Format format, bool prefer_reuse)
+2
View File
@@ -1637,6 +1637,8 @@ public:
virtual void PopDebugGroup() = 0;
virtual void InsertDebugMessage(DebugMessageCategory category, const char* fmt, ...) = 0;
GSTexture::Usage GetDepthStencilUsage() const;
GSTexture* FetchSurface(GSTexture::Usage usage, int width, int height, int levels, GSTexture::Format format, bool clear, bool prefer_reuse);
GSTexture* FetchSurface(GSTexture::Usage usage, const GSVector2i& size, int levels, GSTexture::Format format, bool clear, bool prefer_reuse);
GSTexture* CreateRenderTarget(int w, int h, GSTexture::Format format, bool clear = true, bool prefer_reuse = true);
+1 -2
View File
@@ -7215,8 +7215,7 @@ GSTextureCache::Target* GSTextureCache::Target::Create(GIFRegTEX0 TEX0, int w, i
const int scaled_w = static_cast<int>(std::ceil(static_cast<float>(w) * scale));
const int scaled_h = static_cast<int>(std::ceil(static_cast<float>(h) * scale));
GSTexture::Usage usage = type == RenderTarget ? GSTexture::FeedbackTarget :
(g_gs_device->Features().depth_feedback ? GSTexture::FeedbackDepth : GSTexture::DepthStencil);
GSTexture::Usage usage = type == RenderTarget ? GSTexture::FeedbackTarget : g_gs_device->GetDepthStencilUsage();
GSTexture::Format format = type == RenderTarget ? GSTexture::Format::Color : GSTexture::Format::DepthStencil;
GSTexture* texture = g_gs_device->FetchSurface(usage, scaled_w, scaled_h, 1, format, clear, PreferReusedLabelledTexture());
if (!texture)
+13 -13
View File
@@ -893,8 +893,8 @@ void FullscreenUI::DoStartDisc()
std::vector<std::string> devices(GetOpticalDriveList());
if (devices.empty())
{
ShowToast(std::string(), FSUI_STR("Could not find any CD/DVD-ROM devices. Please ensure you have a drive connected and sufficient "
"permissions to access it."));
ShowToast(ICON_FA_COMPACT_DISC, FSUI_STR("Could not find any CD/DVD-ROM devices. Please ensure you have a drive connected and sufficient "
"permissions to access it."));
return;
}
@@ -978,7 +978,7 @@ void FullscreenUI::DoChangeDiscFromFile()
{
if (!VMManager::IsDiscFileName(path))
{
ShowToast({}, fmt::format(FSUI_FSTR("{} is not a valid disc image."), Path::GetFileName(path)));
ShowToast(ICON_FA_TRIANGLE_EXCLAMATION, fmt::format(FSUI_FSTR("{} is not a valid disc image."), Path::GetFileName(path)));
}
else
{
@@ -1949,7 +1949,7 @@ bool FullscreenUI::OpenLoadStateSelectorForGame(const std::string& game_path)
}
}
ShowToast({}, FSUI_STR("No save states found."), 5.0f);
ShowToast(ICON_FA_FLOPPY_DISK, FSUI_STR("No save states found."), 5.0f);
return false;
}
@@ -1964,7 +1964,7 @@ bool FullscreenUI::OpenSaveStateSelector(bool is_loading)
return true;
}
ShowToast({}, FSUI_STR("No save states found."), 5.0f);
ShowToast(ICON_FA_FLOPPY_DISK, FSUI_STR("No save states found."), 5.0f);
return false;
}
@@ -2120,12 +2120,12 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
{
if (!FileSystem::FileExists(entry.path.c_str()))
{
ShowToast({}, fmt::format(FSUI_FSTR("{} does not exist."), ImGuiFullscreen::RemoveHash(entry.title)));
ShowToast(ICON_FA_TRIANGLE_EXCLAMATION, fmt::format(FSUI_FSTR("{} does not exist."), ImGuiFullscreen::RemoveHash(entry.title)));
is_open = true;
}
else if (FileSystem::DeleteFilePath(entry.path.c_str()))
{
ShowToast({}, fmt::format(FSUI_FSTR("{} deleted."), ImGuiFullscreen::RemoveHash(entry.title)));
ShowToast(ICON_FA_TRASH, fmt::format(FSUI_FSTR("{} deleted."), ImGuiFullscreen::RemoveHash(entry.title)));
if (s_save_state_selector_loading)
s_save_state_selector_slots.erase(s_save_state_selector_slots.begin() + i);
else
@@ -2145,7 +2145,7 @@ void FullscreenUI::DrawSaveStateSelector(bool is_loading)
}
else
{
ShowToast({}, fmt::format(FSUI_FSTR("Failed to delete {}."), ImGuiFullscreen::RemoveHash(entry.title)));
ShowToast(ICON_FA_TRIANGLE_EXCLAMATION, fmt::format(FSUI_FSTR("Failed to delete {}."), ImGuiFullscreen::RemoveHash(entry.title)));
is_open = false;
}
}
@@ -2372,7 +2372,7 @@ void FullscreenUI::DrawResumeStateSelector()
}
else
{
ShowToast(std::string(), FSUI_STR("Failed to delete save state."));
ShowToast(ICON_FA_TRIANGLE_EXCLAMATION, FSUI_STR("Failed to delete save state."));
}
}
@@ -3388,9 +3388,9 @@ void FullscreenUI::ExitFullscreenAndOpenURL(const std::string_view url)
void FullscreenUI::CopyTextToClipboard(std::string title, const std::string_view text)
{
if (Host::CopyTextToClipboard(text))
ShowToast(std::string(), std::move(title));
ShowToast(ICON_FA_CLIPBOARD, std::move(title));
else
ShowToast(std::string(), FSUI_STR("Failed to copy text to clipboard."));
ShowToast(ICON_FA_TRIANGLE_EXCLAMATION, FSUI_STR("Failed to copy text to clipboard."));
}
void FullscreenUI::OpenAboutWindow()
@@ -3863,7 +3863,7 @@ void FullscreenUI::SwitchToAchievementsWindow()
if (!Achievements::HasAchievements())
{
ShowToast(std::string(), FSUI_STR("This game has no achievements."));
ShowToast(ICON_FA_TROPHY, FSUI_STR("This game has no achievements."));
return;
}
@@ -3907,7 +3907,7 @@ void FullscreenUI::SwitchToLeaderboardsWindow()
if (!Achievements::HasLeaderboards())
{
ShowToast(std::string(), FSUI_STR("This game has no leaderboards."));
ShowToast(ICON_FA_TROPHY, FSUI_STR("This game has no leaderboards."));
return;
}
File diff suppressed because it is too large Load Diff
+21 -16
View File
@@ -3162,8 +3162,6 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
const float badge_size = ImGuiFullscreen::LayoutScale(48.0f);
const float min_width = ImGuiFullscreen::LayoutScale(200.0f);
const float max_width = ImGuiFullscreen::LayoutScale(800.0f);
const float max_text_width = max_width - badge_size - (horizontal_padding * 2.0f) - horizontal_spacing;
const float min_height = (vertical_padding * 2.0f) + badge_size;
const float shadow_size = ImGuiFullscreen::LayoutScale(4.0f);
const float rounding = ImGuiFullscreen::LayoutScale(4.0f);
@@ -3185,13 +3183,19 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
continue;
}
const bool has_badge = !notif.badge_path.empty();
const float effective_badge_size = has_badge ? badge_size : 0.0f;
const float effective_badge_spacing = has_badge ? horizontal_spacing : 0.0f;
const float max_text_width = max_width - effective_badge_size - (horizontal_padding * 2.0f) - effective_badge_spacing;
const float min_height = (vertical_padding * 2.0f) + effective_badge_size;
const ImVec2 title_size(title_font.first->CalcTextSizeA(title_font.second, max_text_width, max_text_width,
notif.title.c_str(), notif.title.c_str() + notif.title.size()));
const ImVec2 text_size(text_font.first->CalcTextSizeA(text_font.second, max_text_width, max_text_width,
notif.text.c_str(), notif.text.c_str() + notif.text.size()));
const float box_width = std::max((horizontal_padding * 2.0f) + badge_size + horizontal_spacing +
const float box_width = std::max((horizontal_padding * 2.0f) + effective_badge_size + effective_badge_spacing +
ImCeil(std::max(title_size.x, text_size.x)),
min_width);
const float box_height =
@@ -3250,10 +3254,10 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
dl->AddRectFilled(box_min, box_max, background_color, rounding, ImDrawFlags_RoundCornersAll);
dl->AddRect(box_min, box_max, border_color, rounding, ImGuiFullscreen::LayoutScale(1.0f), ImDrawFlags_RoundCornersAll);
const ImVec2 badge_min(box_min.x + horizontal_padding, box_min.y + vertical_padding);
const ImVec2 badge_max(badge_min.x + badge_size, badge_min.y + badge_size);
if (!notif.badge_path.empty())
if (has_badge)
{
const ImVec2 badge_min(box_min.x + horizontal_padding, box_min.y + (box_height - badge_size) * 0.5f);
const ImVec2 badge_max(badge_min.x + badge_size, badge_min.y + badge_size);
GSTexture* tex = GetCachedTexture(notif.badge_path.c_str());
if (tex)
{
@@ -3262,14 +3266,14 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
}
}
const ImVec2 title_min(badge_max.x + horizontal_spacing, box_min.y + vertical_padding);
const ImVec2 title_min(box_min.x + horizontal_padding + effective_badge_size + effective_badge_spacing, box_min.y + vertical_padding);
const ImVec2 title_max(title_min.x + title_size.x, title_min.y + title_size.y);
const u32 title_col = (toast_title_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
const u32 text_shadow_col = IM_COL32(0, 0, 0, (64u * opacity) / 255u);
AddTextWithShadow(dl, title_font, title_min, title_col, notif.title.c_str(), notif.title.c_str() + notif.title.size(), max_text_width,
nullptr, text_shadow_col);
const ImVec2 text_min(badge_max.x + horizontal_spacing, title_max.y + vertical_spacing);
const ImVec2 text_min(title_min.x, title_max.y + vertical_spacing);
const ImVec2 text_max(text_min.x + text_size.x, text_min.y + text_size.y);
const u32 text_col = (toast_text_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
AddTextWithShadow(dl, text_font, text_min, text_col, notif.text.c_str(), notif.text.c_str() + notif.text.size(), max_text_width,
@@ -3318,15 +3322,17 @@ void ImGuiFullscreen::DrawToast()
const float padding = LayoutScale(20.0f);
const float total_padding = padding * 2.0f;
const float margin = LayoutScale(20.0f + (s_fullscreen_footer_text.empty() ? 0.0f : LAYOUT_FOOTER_HEIGHT));
const float spacing = s_toast_title.empty() ? 0.0f : LayoutScale(10.0f);
const float spacing = (s_toast_title.empty() || s_toast_message.empty()) ? 0.0f : LayoutScale(10.0f);
const ImVec2 display_size(ImGui::GetIO().DisplaySize);
const ImVec2 title_size(s_toast_title.empty() ? ImVec2(0.0f, 0.0f) :
title_font.first->CalcTextSizeA(title_font.second, FLT_MAX, max_width,
s_toast_title.c_str(), s_toast_title.c_str() + s_toast_title.length()));
const float max_message_width = std::max(LayoutScale(100.0f), max_width - (s_toast_title.empty() ? 0.0f : (title_size.x + spacing)));
const ImVec2 message_size(s_toast_message.empty() ? ImVec2(0.0f, 0.0f) :
message_font.first->CalcTextSizeA(message_font.second, FLT_MAX, max_width,
message_font.first->CalcTextSizeA(message_font.second, FLT_MAX, max_message_width,
s_toast_message.c_str(), s_toast_message.c_str() + s_toast_message.length()));
const ImVec2 comb_size(std::max(title_size.x, message_size.x), title_size.y + spacing + message_size.y);
const ImVec2 comb_size(s_toast_title.empty() ? message_size.x : (title_size.x + spacing + message_size.x),
std::max(title_size.y, message_size.y));
const ImVec2 box_size(comb_size.x + total_padding, comb_size.y + total_padding);
const ImVec2 box_pos((display_size.x - box_size.x) * 0.5f, (display_size.y - margin - box_size.y));
@@ -3336,19 +3342,18 @@ void ImGuiFullscreen::DrawToast()
const u32 shadow_col = IM_COL32(0, 0, 0, static_cast<int>(64.0f * alpha));
if (!s_toast_title.empty())
{
const float offset = (comb_size.x - title_size.x) * 0.5f;
const ImVec2 title_pos = box_pos + ImVec2(offset + padding, padding);
const ImVec2 title_pos = box_pos + ImVec2(padding, padding + (comb_size.y - title_size.y) * 0.5f);
AddTextWithShadow(dl, title_font, title_pos,
ImGui::GetColorU32(ModAlpha(UIPrimaryTextColor, alpha)), s_toast_title.c_str(), s_toast_title.c_str() + s_toast_title.length(),
max_width, nullptr, shadow_col);
}
if (!s_toast_message.empty())
{
const float offset = (comb_size.x - message_size.x) * 0.5f;
const ImVec2 message_pos = box_pos + ImVec2(offset + padding, padding + spacing + title_size.y);
const float title_offset = s_toast_title.empty() ? 0.0f : (title_size.x + spacing);
const ImVec2 message_pos = box_pos + ImVec2(padding + title_offset, padding + (comb_size.y - message_size.y) * 0.5f);
AddTextWithShadow(dl, message_font, message_pos,
ImGui::GetColorU32(ModAlpha(UIPrimaryTextColor, alpha)), s_toast_message.c_str(),
s_toast_message.c_str() + s_toast_message.length(), max_width, nullptr, shadow_col);
s_toast_message.c_str() + s_toast_message.length(), max_message_width, nullptr, shadow_col);
}
}