mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-01 22:30:42 -07:00
graphics: address performance regression with Image Resize (#504)
## Link to GitHub Issue, if one exists Regressed by #401 ## Description of change Two things from testing SDVX Live2D - 1. ColorFill is almost always too expensive and will lead to drops 1. Scale factor of 0.5 causes GPU to sync and causes drops (ARGB/XRGB doesn't matter, linear filtering doesn't matter) 1 is fixed by removing ColorFill calls on every frame - instead only do this once when the user changes the duplicate option (on the next frame) 2 is fixed by updating the UI (limit the slider) though people can ctrl+click to override these slider limits. The warning label will be kept with slightly reworded text. ## Testing tested in sdvx eg final (sudden death) - on my RTX 4070, my FPS is rock solid 120 fps even with image resize on now.
This commit is contained in:
@@ -81,19 +81,8 @@ namespace cfg {
|
|||||||
|
|
||||||
load_bool_value(doc, root + "enable_screen_resize", this->enable_screen_resize);
|
load_bool_value(doc, root + "enable_screen_resize", this->enable_screen_resize);
|
||||||
if (this->enable_screen_resize) {
|
if (this->enable_screen_resize) {
|
||||||
if (avs::game::is_model("KFC")) {
|
|
||||||
log_warning(
|
|
||||||
"ScreenResize",
|
|
||||||
"Image Resize feature enabled for SDVX; enabling this is known to significantly "
|
|
||||||
"lower framerate for songs with Live2D!");
|
|
||||||
deferredlogs::defer_error_messages({
|
|
||||||
"Image Resize + SDVX Live2D performance warning",
|
|
||||||
" Enabling Image Resize feature is known to have significant impact",
|
|
||||||
" on Live2D performance; you should disable it"});
|
|
||||||
} else {
|
|
||||||
log_misc("ScreenResize", "enabled by config file");
|
log_misc("ScreenResize", "enabled by config file");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
load_bool_value(doc, root + "enable_linear_filter", this->enable_linear_filter);
|
load_bool_value(doc, root + "enable_linear_filter", this->enable_linear_filter);
|
||||||
for (size_t i = 0; i < std::size(this->scene_settings); i++) {
|
for (size_t i = 0; i < std::size(this->scene_settings); i++) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -51,6 +52,9 @@ namespace cfg {
|
|||||||
bool enable_linear_filter = true;
|
bool enable_linear_filter = true;
|
||||||
fullscreen_setting scene_settings[4];
|
fullscreen_setting scene_settings[4];
|
||||||
|
|
||||||
|
// state
|
||||||
|
std::atomic<bool> need_surface_clean = false;
|
||||||
|
|
||||||
// windowed mode sizing
|
// windowed mode sizing
|
||||||
// Windows terminology:
|
// Windows terminology:
|
||||||
// window = rectangle including the frame
|
// window = rectangle including the frame
|
||||||
|
|||||||
@@ -742,14 +742,12 @@ void SurfaceHook(IDirect3DDevice9 *pReal) {
|
|||||||
const int w = param.BackBufferWidth;
|
const int w = param.BackBufferWidth;
|
||||||
const int h = param.BackBufferHeight;
|
const int h = param.BackBufferHeight;
|
||||||
|
|
||||||
if (cfg::SCREENRESIZE->enable_screen_resize) {
|
// this code used to clear the surface using ColorFill on every call, but
|
||||||
RECT rect {
|
// this turned out to be very expensive, leading to major frame drops in
|
||||||
0,
|
// SDVX Live2D scenario
|
||||||
0,
|
if (cfg::SCREENRESIZE->need_surface_clean) {
|
||||||
(LONG)topSurface_width,
|
pReal->ColorFill(topSurface, nullptr, D3DCOLOR_XRGB(0, 0, 0));
|
||||||
(LONG)topSurface_height,
|
cfg::SCREENRESIZE->need_surface_clean = false;
|
||||||
};
|
|
||||||
pReal->ColorFill(topSurface, &rect, D3DCOLOR_XRGB(0, 0, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
D3DLOCKED_RECT rect;
|
D3DLOCKED_RECT rect;
|
||||||
|
|||||||
@@ -103,12 +103,16 @@ namespace overlay::windows {
|
|||||||
|
|
||||||
if (avs::game::is_model("KFC")) {
|
if (avs::game::is_model("KFC")) {
|
||||||
ImGui::TextColored(ImVec4(1, 0.5f, 0.5f, 1.f),
|
ImGui::TextColored(ImVec4(1, 0.5f, 0.5f, 1.f),
|
||||||
"Warning: Enabling Image Resize will significantly\n"
|
"Warning: Enabling Image Resize uses more GPU\n"
|
||||||
"lower framerate for songs with Live2D!");
|
"resources and may significantly lower framerate\n"
|
||||||
|
"for songs with Live2D! Results may vary, use at\n"
|
||||||
|
"your own risk.");
|
||||||
} else {
|
} else {
|
||||||
ImGui::TextColored(ImVec4(1, 0.5f, 0.5f, 1.f),
|
ImGui::TextColored(ImVec4(1, 0.5f, 0.5f, 1.f),
|
||||||
"Warning: Some games are known to have significant\n"
|
"Warning: Enabling Image Resize uses more GPU\n"
|
||||||
"performance issues when Image Resize is enabled.");
|
"resources and may significantly lower framerate\n"
|
||||||
|
"in some situations! Results may vary, use at\n"
|
||||||
|
"your own risk.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// enable checkbox
|
// enable checkbox
|
||||||
@@ -152,22 +156,27 @@ namespace overlay::windows {
|
|||||||
// aspect ratio
|
// aspect ratio
|
||||||
ImGui::Checkbox("Keep Aspect Ratio", &scene.keep_aspect_ratio);
|
ImGui::Checkbox("Keep Aspect Ratio", &scene.keep_aspect_ratio);
|
||||||
if (scene.keep_aspect_ratio) {
|
if (scene.keep_aspect_ratio) {
|
||||||
if (ImGui::SliderFloat("Scale", &scene.scale_x, 0.5f, 2.5f)) {
|
|
||||||
|
// we want to avoid zooming out below 0.6 as it will cause StretchRect calls to
|
||||||
|
// go on a slow sync path with the GPU, leading to frame drops in some situations
|
||||||
|
// (e.g., SDVX Live2D)
|
||||||
|
|
||||||
|
if (ImGui::SliderFloat("Scale", &scene.scale_x, 0.6f, 2.5f)) {
|
||||||
scene.scale_y = scene.scale_x;
|
scene.scale_y = scene.scale_x;
|
||||||
}
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
|
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
|
||||||
} else {
|
} else {
|
||||||
ImGui::SliderFloat("Width Scale", &scene.scale_x, 0.5f, 2.5f);
|
ImGui::SliderFloat("Width Scale", &scene.scale_x, 0.6f, 2.5f);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
|
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
|
||||||
ImGui::SliderFloat("Height Scale", &scene.scale_y, 0.5f, 2.5f);
|
ImGui::SliderFloat("Height Scale", &scene.scale_y, 0.6f, 2.5f);
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
|
ImGui::HelpMarker("Hint: ctrl + click on the slider to type in a numeric value.");
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* dupe_items[] = { "None", "Copy Left", "Copy Right" };
|
static const char* dupe_items[] = { "None", "Copy Left", "Copy Right" };
|
||||||
ImGui::Combo(
|
const bool duplicate_changed = ImGui::Combo(
|
||||||
"Duplicate",
|
"Duplicate",
|
||||||
reinterpret_cast<int *>(&scene.duplicate),
|
reinterpret_cast<int *>(&scene.duplicate),
|
||||||
dupe_items,
|
dupe_items,
|
||||||
@@ -178,6 +187,11 @@ namespace overlay::windows {
|
|||||||
"wrap-around effect when an offset is set.");
|
"wrap-around effect when an offset is set.");
|
||||||
|
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
|
||||||
|
// tell d3d9 device to clear surface to get rid of ghost image
|
||||||
|
if (duplicate_changed) {
|
||||||
|
cfg::SCREENRESIZE->need_surface_clean = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenResize::build_windowed_config() {
|
void ScreenResize::build_windowed_config() {
|
||||||
|
|||||||
Reference in New Issue
Block a user