Merge pull request #8554 from stenzek/present-duplicate-frames

Add an option to present duplicate frames
This commit is contained in:
Connor McLaughlin 2020-01-20 12:04:26 +10:00 committed by GitHub
commit a63510a55a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 60 additions and 17 deletions

View File

@ -585,6 +585,7 @@ public final class SettingsFragmentPresenter
Setting gpuTextureDecoding = gfxSection.getSetting(SettingsFile.KEY_GPU_TEXTURE_DECODING);
Setting xfbToTexture = hacksSection.getSetting(SettingsFile.KEY_XFB_TEXTURE);
Setting immediateXfb = hacksSection.getSetting(SettingsFile.KEY_IMMEDIATE_XFB);
Setting skipDuplicateXfbs = hacksSection.getSetting(SettingsFile.KEY_SKIP_DUPLICATE_XFBS);
Setting fastDepth = gfxSection.getSetting(SettingsFile.KEY_FAST_DEPTH);
sl.add(new HeaderSetting(null, null, R.string.embedded_frame_buffer, 0));
@ -613,6 +614,9 @@ public final class SettingsFragmentPresenter
R.string.xfb_copy_method, R.string.xfb_copy_method_description, true, xfbToTexture));
sl.add(new CheckBoxSetting(SettingsFile.KEY_IMMEDIATE_XFB, Settings.SECTION_GFX_HACKS,
R.string.immediate_xfb, R.string.immediate_xfb_description, false, immediateXfb));
sl.add(new CheckBoxSetting(SettingsFile.KEY_SKIP_DUPLICATE_XFBS, Settings.SECTION_GFX_HACKS,
R.string.skip_duplicate_xfbs, R.string.skip_duplicate_xfbs_description, true,
skipDuplicateXfbs));
sl.add(new HeaderSetting(null, null, R.string.other, 0));
sl.add(new CheckBoxSetting(SettingsFile.KEY_FAST_DEPTH, Settings.SECTION_GFX_SETTINGS,

View File

@ -89,6 +89,7 @@ public final class SettingsFile
public static final String KEY_GPU_TEXTURE_DECODING = "EnableGPUTextureDecoding";
public static final String KEY_XFB_TEXTURE = "XFBToTextureEnable";
public static final String KEY_IMMEDIATE_XFB = "ImmediateXFBEnable";
public static final String KEY_SKIP_DUPLICATE_XFBS = "SkipDuplicateXFBs";
public static final String KEY_FAST_DEPTH = "FastDepthCalc";
public static final String KEY_ASPECT_RATIO = "AspectRatio";
public static final String KEY_SHADER_COMPILATION_MODE = "ShaderCompilationMode";

View File

@ -232,6 +232,8 @@
<string name="xfb_copy_method_description">Stores XFB Copies exclusively on the GPU, bypassing system memory. Causes graphical defects in a small number of games that need to readback from memory. If unsure, leave this checked.</string>
<string name="immediate_xfb">Immediately Present XFB</string>
<string name="immediate_xfb_description">Displays the XFB copies as soon as they are created, without waiting for scanout. Causes graphical defects in some games but reduces latency. If unsure, leave this unchecked.</string>
<string name="skip_duplicate_xfbs">Immediately Present XFB</string>
<string name="skip_duplicate_xfbs_description">Skips presentation of duplicate frames. This may improve performance on low-end devices, while making frame pacing less consistent. If unsure, leave this checked.</string>
<string name="disable_destination_alpha">Disable Destination Alpha</string>
<string name="disable_destination_alpha_description">Disables emulation of a hardware feature called destination alpha, which is used in many games for various effects.</string>
<string name="fast_depth_calculation">Fast Depth Calculation</string>

View File

@ -154,6 +154,8 @@ const ConfigInfo<bool> GFX_HACK_DISABLE_COPY_TO_VRAM{{System::GFX, "Hacks", "Dis
false};
const ConfigInfo<bool> GFX_HACK_DEFER_EFB_COPIES{{System::GFX, "Hacks", "DeferEFBCopies"}, true};
const ConfigInfo<bool> GFX_HACK_IMMEDIATE_XFB{{System::GFX, "Hacks", "ImmediateXFBEnable"}, false};
const ConfigInfo<bool> GFX_HACK_SKIP_DUPLICATE_XFBS{{System::GFX, "Hacks", "SkipDuplicateXFBs"},
true};
const ConfigInfo<bool> GFX_HACK_COPY_EFB_SCALED{{System::GFX, "Hacks", "EFBScaledCopy"}, true};
const ConfigInfo<bool> GFX_HACK_EFB_EMULATE_FORMAT_CHANGES{
{System::GFX, "Hacks", "EFBEmulateFormatChanges"}, false};

View File

@ -111,6 +111,7 @@ extern const ConfigInfo<bool> GFX_HACK_SKIP_XFB_COPY_TO_RAM;
extern const ConfigInfo<bool> GFX_HACK_DISABLE_COPY_TO_VRAM;
extern const ConfigInfo<bool> GFX_HACK_DEFER_EFB_COPIES;
extern const ConfigInfo<bool> GFX_HACK_IMMEDIATE_XFB;
extern const ConfigInfo<bool> GFX_HACK_SKIP_DUPLICATE_XFBS;
extern const ConfigInfo<bool> GFX_HACK_COPY_EFB_SCALED;
extern const ConfigInfo<bool> GFX_HACK_EFB_EMULATE_FORMAT_CHANGES;
extern const ConfigInfo<bool> GFX_HACK_VERTEX_ROUDING;

View File

@ -28,7 +28,7 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
return true;
}
static constexpr std::array<const Config::ConfigLocation*, 92> s_setting_saveable = {
static constexpr std::array<const Config::ConfigLocation*, 93> s_setting_saveable = {
// Main.Core
&Config::MAIN_DEFAULT_ISO.location,
@ -136,6 +136,7 @@ bool IsSettingSaveable(const Config::ConfigLocation& config_location)
&Config::GFX_HACK_DISABLE_COPY_TO_VRAM.location,
&Config::GFX_HACK_DEFER_EFB_COPIES.location,
&Config::GFX_HACK_IMMEDIATE_XFB.location,
&Config::GFX_HACK_SKIP_DUPLICATE_XFBS.location,
&Config::GFX_HACK_COPY_EFB_SCALED.location,
&Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES.location,
&Config::GFX_HACK_VERTEX_ROUDING.location,

View File

@ -86,9 +86,12 @@ void HacksWidget::CreateWidgets()
m_store_xfb_copies = new GraphicsBool(tr("Store XFB Copies to Texture Only"),
Config::GFX_HACK_SKIP_XFB_COPY_TO_RAM);
m_immediate_xfb = new GraphicsBool(tr("Immediately Present XFB"), Config::GFX_HACK_IMMEDIATE_XFB);
m_skip_duplicate_xfbs = new GraphicsBool(tr("Skip Presenting Duplicate Frames"),
Config::GFX_HACK_SKIP_DUPLICATE_XFBS);
xfb_layout->addWidget(m_store_xfb_copies);
xfb_layout->addWidget(m_immediate_xfb);
xfb_layout->addWidget(m_skip_duplicate_xfbs);
// Other
auto* other_box = new QGroupBox(tr("Other"));
@ -117,6 +120,7 @@ void HacksWidget::CreateWidgets()
setLayout(main_layout);
UpdateDeferEFBCopiesEnabled();
UpdateSkipPresentingDuplicateFramesEnabled();
}
void HacksWidget::OnBackendChanged(const QString& backend_name)
@ -140,6 +144,8 @@ void HacksWidget::ConnectWidgets()
[this](int) { UpdateDeferEFBCopiesEnabled(); });
connect(m_store_xfb_copies, &QCheckBox::stateChanged,
[this](int) { UpdateDeferEFBCopiesEnabled(); });
connect(m_immediate_xfb, &QCheckBox::stateChanged,
[this](int) { UpdateSkipPresentingDuplicateFramesEnabled(); });
}
void HacksWidget::LoadSettings()
@ -235,6 +241,12 @@ void HacksWidget::AddDescriptions()
"expect all XFB copies to be displayed. However, turning this setting on reduces "
"latency.\n\nIf unsure, leave this unchecked.");
static const char TR_SKIP_DUPLICATE_XFBS_DESCRIPTION[] = QT_TR_NOOP(
"Skips presentation of duplicate frames (XFB copies) in 25fps/30fps games. This may improve "
"performance on low-end devices, while making frame pacing less consistent.\n\nDisable this "
"option as well as enabling V-Sync for optimal frame pacing.\n\nIf unsure, leave this "
"checked.");
static const char TR_GPU_DECODING_DESCRIPTION[] =
QT_TR_NOOP("Enables texture decoding using the GPU instead of the CPU.\n\nThis may result in "
"performance gains in some scenarios, or on systems where the CPU is the "
@ -263,6 +275,7 @@ void HacksWidget::AddDescriptions()
AddDescription(m_accuracy, TR_ACCUARCY_DESCRIPTION);
AddDescription(m_store_xfb_copies, TR_STORE_XFB_TO_TEXTURE_DESCRIPTION);
AddDescription(m_immediate_xfb, TR_IMMEDIATE_XFB_DESCRIPTION);
AddDescription(m_skip_duplicate_xfbs, TR_SKIP_DUPLICATE_XFBS_DESCRIPTION);
AddDescription(m_gpu_texture_decoding, TR_GPU_DECODING_DESCRIPTION);
AddDescription(m_fast_depth_calculation, TR_FAST_DEPTH_CALC_DESCRIPTION);
AddDescription(m_disable_bounding_box, TR_DISABLE_BOUNDINGBOX_DESCRIPTION);
@ -277,3 +290,10 @@ void HacksWidget::UpdateDeferEFBCopiesEnabled()
const bool can_defer = m_store_efb_copies->isChecked() && m_store_xfb_copies->isChecked();
m_defer_efb_copies->setEnabled(!can_defer);
}
void HacksWidget::UpdateSkipPresentingDuplicateFramesEnabled()
{
// If Immediate XFB is on, there's no point to skipping duplicate XFB copies as immediate presents
// when the XFB is created, therefore all XFB copies will be unique.
m_skip_duplicate_xfbs->setEnabled(!m_immediate_xfb->isChecked());
}

View File

@ -37,6 +37,7 @@ private:
// External Framebuffer
QCheckBox* m_store_xfb_copies;
QCheckBox* m_immediate_xfb;
QCheckBox* m_skip_duplicate_xfbs;
// Other
QCheckBox* m_fast_depth_calculation;
@ -50,4 +51,5 @@ private:
void AddDescriptions();
void UpdateDeferEFBCopiesEnabled();
void UpdateSkipPresentingDuplicateFramesEnabled();
};

View File

@ -1190,8 +1190,10 @@ void Renderer::Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u6
MathUtil::Rectangle<int> xfb_rect;
const auto* xfb_entry =
g_texture_cache->GetXFBTexture(xfb_addr, fb_width, fb_height, fb_stride, &xfb_rect);
if (xfb_entry && xfb_entry->id != m_last_xfb_id)
if (xfb_entry &&
(!g_ActiveConfig.bSkipPresentingDuplicateXFBs || xfb_entry->id != m_last_xfb_id))
{
const bool is_duplicate_frame = xfb_entry->id == m_last_xfb_id;
m_last_xfb_id = xfb_entry->id;
// Since we use the common pipelines here and draw vertices if a batch is currently being
@ -1235,20 +1237,24 @@ void Renderer::Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u6
SetWindowSize(xfb_rect.GetWidth(), xfb_rect.GetHeight());
}
m_fps_counter.Update();
if (!is_duplicate_frame)
{
m_fps_counter.Update();
DolphinAnalytics::PerformanceSample perf_sample;
perf_sample.speed_ratio = SystemTimers::GetEstimatedEmulationPerformance();
perf_sample.num_prims = g_stats.this_frame.num_prims + g_stats.this_frame.num_dl_prims;
perf_sample.num_draw_calls = g_stats.this_frame.num_draw_calls;
DolphinAnalytics::Instance().ReportPerformanceInfo(std::move(perf_sample));
DolphinAnalytics::PerformanceSample perf_sample;
perf_sample.speed_ratio = SystemTimers::GetEstimatedEmulationPerformance();
perf_sample.num_prims = g_stats.this_frame.num_prims + g_stats.this_frame.num_dl_prims;
perf_sample.num_draw_calls = g_stats.this_frame.num_draw_calls;
DolphinAnalytics::Instance().ReportPerformanceInfo(std::move(perf_sample));
if (IsFrameDumping())
DumpCurrentFrame(xfb_entry->texture.get(), xfb_rect, ticks);
if (IsFrameDumping())
DumpCurrentFrame(xfb_entry->texture.get(), xfb_rect, ticks);
// Begin new frame
m_frame_count++;
g_stats.ResetFrame();
}
// Begin new frame
m_frame_count++;
g_stats.ResetFrame();
g_shader_cache->RetrieveAsyncShaders();
g_vertex_manager->OnEndFrame();
BeginImGuiFrame();
@ -1263,16 +1269,18 @@ void Renderer::Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u6
// rate and not waiting for vblank. Otherwise, we'd end up with a huge list of pending copies.
g_texture_cache->FlushEFBCopies();
// Remove stale EFB/XFB copies.
g_texture_cache->Cleanup(m_frame_count);
if (!is_duplicate_frame)
{
// Remove stale EFB/XFB copies.
g_texture_cache->Cleanup(m_frame_count);
Core::Callback_VideoCopiedToXFB(true);
}
// Handle any config changes, this gets propogated to the backend.
CheckForConfigChanges();
g_Config.iSaveTargetId = 0;
EndUtilityDrawing();
Core::Callback_VideoCopiedToXFB(true);
}
else
{

View File

@ -152,6 +152,7 @@ void VideoConfig::Refresh()
bDisableCopyToVRAM = Config::Get(Config::GFX_HACK_DISABLE_COPY_TO_VRAM);
bDeferEFBCopies = Config::Get(Config::GFX_HACK_DEFER_EFB_COPIES);
bImmediateXFB = Config::Get(Config::GFX_HACK_IMMEDIATE_XFB);
bSkipPresentingDuplicateXFBs = Config::Get(Config::GFX_HACK_SKIP_DUPLICATE_XFBS);
bCopyEFBScaled = Config::Get(Config::GFX_HACK_COPY_EFB_SCALED);
bEFBEmulateFormatChanges = Config::Get(Config::GFX_HACK_EFB_EMULATE_FORMAT_CHANGES);
bVertexRounding = Config::Get(Config::GFX_HACK_VERTEX_ROUDING);

View File

@ -124,6 +124,7 @@ struct VideoConfig final
bool bDisableCopyToVRAM;
bool bDeferEFBCopies;
bool bImmediateXFB;
bool bSkipPresentingDuplicateXFBs;
bool bCopyEFBScaled;
int iSafeTextureCache_ColorSamples;
float fAspectRatioHackW, fAspectRatioHackH;