pvr: auto frame skip to replace current and previous synchronous rendering
Restore previous synchronous rendering behaviour (normal auto frame skip) No frame skipping when disabled better cpu speed measure over 4 vblanks
This commit is contained in:
parent
b9d7c11936
commit
a00aad5fa7
|
@ -1,3 +1,4 @@
|
|||
#include <array>
|
||||
#include "spg.h"
|
||||
#include "hw/holly/holly_intc.h"
|
||||
#include "hw/holly/sb.h"
|
||||
|
@ -23,6 +24,11 @@ static u32 Frame_Cycles;
|
|||
int render_end_schid;
|
||||
int vblank_schid;
|
||||
|
||||
static std::array<double, 4> real_times;
|
||||
static std::array<u64, 4> cpu_cycles;
|
||||
static u32 cpu_time_idx;
|
||||
bool SH4FastEnough;
|
||||
|
||||
void CalculateSync()
|
||||
{
|
||||
u32 pixel_clock = PIXEL_CLOCK / (FB_R_CTRL.vclk_div ? 1 : 2);
|
||||
|
@ -127,13 +133,28 @@ int spg_line_sched(int tag, int cycl, int jit)
|
|||
else
|
||||
SPG_STATUS.fieldnum=0;
|
||||
|
||||
vblk_cnt++;
|
||||
rend_vblank();
|
||||
|
||||
double now = os_GetSeconds() * 1000000.0;
|
||||
cpu_time_idx = (cpu_time_idx + 1) % cpu_cycles.size();
|
||||
if (cpu_cycles[cpu_time_idx] != 0)
|
||||
{
|
||||
u32 cycle_span = (u32)(sh4_sched_now64() - cpu_cycles[cpu_time_idx]);
|
||||
double time_span = now - real_times[cpu_time_idx];
|
||||
double cpu_speed = ((double)cycle_span / time_span) / (SH4_MAIN_CLOCK / 100000000);
|
||||
SH4FastEnough = cpu_speed >= 85.0;
|
||||
}
|
||||
else
|
||||
SH4FastEnough = false;
|
||||
cpu_cycles[cpu_time_idx] = sh4_sched_now64();
|
||||
real_times[cpu_time_idx] = now;
|
||||
|
||||
#ifdef TEST_AUTOMATION
|
||||
replay_input();
|
||||
#endif
|
||||
|
||||
|
||||
#if !defined(NDEBUG) || defined(DEBUGFAST)
|
||||
vblk_cnt++;
|
||||
if ((os_GetSeconds()-last_fps)>2)
|
||||
{
|
||||
static int Last_FC;
|
||||
|
@ -190,6 +211,7 @@ int spg_line_sched(int tag, int cycl, int jit)
|
|||
fskip=0;
|
||||
last_fps=os_GetSeconds();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (lightgun_line != 0xffff && lightgun_line == prv_cur_scanline)
|
||||
{
|
||||
|
@ -273,6 +295,11 @@ void spg_Term()
|
|||
void spg_Reset(bool hard)
|
||||
{
|
||||
CalculateSync();
|
||||
|
||||
SH4FastEnough = false;
|
||||
cpu_time_idx = 0;
|
||||
cpu_cycles.fill(0);
|
||||
real_times.fill(0.0);
|
||||
}
|
||||
|
||||
void SetREP(TA_context* cntx)
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#pragma once
|
||||
#include "ta_ctx.h"
|
||||
|
||||
extern bool SH4FastEnough;
|
||||
|
||||
bool spg_Init();
|
||||
void spg_Term();
|
||||
void spg_Reset(bool Manual);
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#include "ta_ctx.h"
|
||||
#include "spg.h"
|
||||
#include "oslib/oslib.h"
|
||||
|
||||
extern u32 fskip;
|
||||
extern u32 FrameCount;
|
||||
static int RenderCount;
|
||||
|
||||
TA_context* ta_ctx;
|
||||
tad_context ta_tad;
|
||||
|
@ -73,13 +75,18 @@ bool QueueRender(TA_context* ctx)
|
|||
{
|
||||
verify(ctx != 0);
|
||||
|
||||
if (rqueue && settings.pvr.SynchronousRender)
|
||||
//wait for a frame if
|
||||
// we have another one queue'd
|
||||
// and SynchronousRender is enabled
|
||||
bool skipFrame = false;
|
||||
RenderCount++;
|
||||
if (RenderCount % (settings.pvr.ta_skip + 1) != 0)
|
||||
skipFrame = true;
|
||||
else if (rqueue && (settings.pvr.AutoSkipFrame == 0
|
||||
|| (settings.pvr.AutoSkipFrame == 1 && SH4FastEnough)))
|
||||
// The previous render hasn't completed yet so we wait.
|
||||
// If autoskipframe is enabled (normal level), we only do so if the CPU is running
|
||||
// fast enough over the last frames
|
||||
frame_finished.Wait();
|
||||
|
||||
if (rqueue)
|
||||
if (skipFrame || rqueue)
|
||||
{
|
||||
tactx_Recycle(ctx);
|
||||
fskip++;
|
||||
|
|
|
@ -1432,8 +1432,6 @@ static void getRegionTileClipping(u32& xmin, u32& xmax, u32& ymin, u32& ymax);
|
|||
|
||||
FifoSplitter<0> TAFifo0;
|
||||
|
||||
int ta_parse_cnt = 0;
|
||||
|
||||
//
|
||||
// Check if a vertex has huge x,y,z values or negative z
|
||||
//
|
||||
|
@ -1581,69 +1579,66 @@ bool ta_parse_vdrc(TA_context* ctx)
|
|||
vd_ctx = ctx;
|
||||
vd_rc = vd_ctx->rend;
|
||||
|
||||
ta_parse_cnt++;
|
||||
if (ctx->rend.isRTT || 0 == (ta_parse_cnt % ( settings.pvr.ta_skip + 1)))
|
||||
TAFifo0.vdec_init();
|
||||
|
||||
bool empty_context = true;
|
||||
int op_poly_count = 0;
|
||||
int pt_poly_count = 0;
|
||||
int tr_poly_count = 0;
|
||||
|
||||
PolyParam *bgpp = vd_rc.global_param_op.head();
|
||||
if (bgpp->pcw.Texture)
|
||||
{
|
||||
TAFifo0.vdec_init();
|
||||
|
||||
bool empty_context = true;
|
||||
int op_poly_count = 0;
|
||||
int pt_poly_count = 0;
|
||||
int tr_poly_count = 0;
|
||||
|
||||
PolyParam *bgpp = vd_rc.global_param_op.head();
|
||||
if (bgpp->pcw.Texture)
|
||||
{
|
||||
bgpp->texid = renderer->GetTexture(bgpp->tsp, bgpp->tcw);
|
||||
empty_context = false;
|
||||
}
|
||||
|
||||
for (u32 pass = 0; pass <= ctx->tad.render_pass_count; pass++)
|
||||
{
|
||||
ctx->MarkRend(pass);
|
||||
vd_rc.proc_start = ctx->rend.proc_start;
|
||||
vd_rc.proc_end = ctx->rend.proc_end;
|
||||
|
||||
Ta_Dma* ta_data=(Ta_Dma*)vd_rc.proc_start;
|
||||
Ta_Dma* ta_data_end=((Ta_Dma*)vd_rc.proc_end)-1;
|
||||
|
||||
do
|
||||
{
|
||||
ta_data =TaCmd(ta_data,ta_data_end);
|
||||
}
|
||||
while(ta_data<=ta_data_end);
|
||||
|
||||
if (ctx->rend.Overrun)
|
||||
break;
|
||||
|
||||
bool empty_pass = vd_rc.global_param_op.used() == (pass == 0 ? 0 : (int)vd_rc.render_passes.LastPtr()->op_count)
|
||||
&& vd_rc.global_param_pt.used() == (pass == 0 ? 0 : (int)vd_rc.render_passes.LastPtr()->pt_count)
|
||||
&& vd_rc.global_param_tr.used() == (pass == 0 ? 0 : (int)vd_rc.render_passes.LastPtr()->tr_count);
|
||||
empty_context = empty_context && empty_pass;
|
||||
|
||||
if (pass == 0 || !empty_pass)
|
||||
{
|
||||
RenderPass *render_pass = vd_rc.render_passes.Append();
|
||||
render_pass->op_count = vd_rc.global_param_op.used();
|
||||
make_index(&vd_rc.global_param_op, op_poly_count,
|
||||
render_pass->op_count, true, &vd_rc);
|
||||
op_poly_count = render_pass->op_count;
|
||||
render_pass->mvo_count = vd_rc.global_param_mvo.used();
|
||||
render_pass->pt_count = vd_rc.global_param_pt.used();
|
||||
make_index(&vd_rc.global_param_pt, pt_poly_count,
|
||||
render_pass->pt_count, true, &vd_rc);
|
||||
pt_poly_count = render_pass->pt_count;
|
||||
render_pass->tr_count = vd_rc.global_param_tr.used();
|
||||
make_index(&vd_rc.global_param_tr, tr_poly_count,
|
||||
render_pass->tr_count, false, &vd_rc);
|
||||
tr_poly_count = render_pass->tr_count;
|
||||
render_pass->mvo_tr_count = vd_rc.global_param_mvo_tr.used();
|
||||
render_pass->autosort = UsingAutoSort(pass);
|
||||
render_pass->z_clear = ClearZBeforePass(pass);
|
||||
}
|
||||
}
|
||||
rv = !empty_context;
|
||||
bgpp->texid = renderer->GetTexture(bgpp->tsp, bgpp->tcw);
|
||||
empty_context = false;
|
||||
}
|
||||
|
||||
for (u32 pass = 0; pass <= ctx->tad.render_pass_count; pass++)
|
||||
{
|
||||
ctx->MarkRend(pass);
|
||||
vd_rc.proc_start = ctx->rend.proc_start;
|
||||
vd_rc.proc_end = ctx->rend.proc_end;
|
||||
|
||||
Ta_Dma* ta_data=(Ta_Dma*)vd_rc.proc_start;
|
||||
Ta_Dma* ta_data_end=((Ta_Dma*)vd_rc.proc_end)-1;
|
||||
|
||||
do
|
||||
{
|
||||
ta_data =TaCmd(ta_data,ta_data_end);
|
||||
}
|
||||
while(ta_data<=ta_data_end);
|
||||
|
||||
if (ctx->rend.Overrun)
|
||||
break;
|
||||
|
||||
bool empty_pass = vd_rc.global_param_op.used() == (pass == 0 ? 0 : (int)vd_rc.render_passes.LastPtr()->op_count)
|
||||
&& vd_rc.global_param_pt.used() == (pass == 0 ? 0 : (int)vd_rc.render_passes.LastPtr()->pt_count)
|
||||
&& vd_rc.global_param_tr.used() == (pass == 0 ? 0 : (int)vd_rc.render_passes.LastPtr()->tr_count);
|
||||
empty_context = empty_context && empty_pass;
|
||||
|
||||
if (pass == 0 || !empty_pass)
|
||||
{
|
||||
RenderPass *render_pass = vd_rc.render_passes.Append();
|
||||
render_pass->op_count = vd_rc.global_param_op.used();
|
||||
make_index(&vd_rc.global_param_op, op_poly_count,
|
||||
render_pass->op_count, true, &vd_rc);
|
||||
op_poly_count = render_pass->op_count;
|
||||
render_pass->mvo_count = vd_rc.global_param_mvo.used();
|
||||
render_pass->pt_count = vd_rc.global_param_pt.used();
|
||||
make_index(&vd_rc.global_param_pt, pt_poly_count,
|
||||
render_pass->pt_count, true, &vd_rc);
|
||||
pt_poly_count = render_pass->pt_count;
|
||||
render_pass->tr_count = vd_rc.global_param_tr.used();
|
||||
make_index(&vd_rc.global_param_tr, tr_poly_count,
|
||||
render_pass->tr_count, false, &vd_rc);
|
||||
tr_poly_count = render_pass->tr_count;
|
||||
render_pass->mvo_tr_count = vd_rc.global_param_mvo_tr.used();
|
||||
render_pass->autosort = UsingAutoSort(pass);
|
||||
render_pass->z_clear = ClearZBeforePass(pass);
|
||||
}
|
||||
}
|
||||
rv = !empty_context;
|
||||
|
||||
bool overrun = ctx->rend.Overrun;
|
||||
if (overrun)
|
||||
WARN_LOG(PVR, "ERROR: TA context overrun");
|
||||
|
|
|
@ -760,7 +760,7 @@ void InitSettings()
|
|||
settings.pvr.ta_skip = 0;
|
||||
|
||||
settings.pvr.MaxThreads = 3;
|
||||
settings.pvr.SynchronousRender = true;
|
||||
settings.pvr.AutoSkipFrame = 0;
|
||||
|
||||
settings.debug.SerialConsole = false;
|
||||
settings.debug.SerialPTY = false;
|
||||
|
@ -860,7 +860,16 @@ void LoadSettings(bool game_specific)
|
|||
settings.pvr.ta_skip = cfgLoadInt(config_section, "ta.skip", settings.pvr.ta_skip);
|
||||
|
||||
settings.pvr.MaxThreads = cfgLoadInt(config_section, "pvr.MaxThreads", settings.pvr.MaxThreads);
|
||||
settings.pvr.SynchronousRender = cfgLoadBool(config_section, "pvr.SynchronousRendering", settings.pvr.SynchronousRender);
|
||||
if (game_specific)
|
||||
settings.pvr.AutoSkipFrame = cfgLoadInt(config_section, "pvr.AutoSkipFrame", settings.pvr.AutoSkipFrame);
|
||||
else
|
||||
{
|
||||
// compatibility with previous SynchronousRendering option
|
||||
int autoskip = cfgLoadInt(config_section, "pvr.AutoSkipFrame", 99);
|
||||
if (autoskip == 99)
|
||||
autoskip = cfgLoadBool(config_section, "pvr.SynchronousRendering", true) ? 1 : 2;
|
||||
settings.pvr.AutoSkipFrame = autoskip;
|
||||
}
|
||||
|
||||
settings.debug.SerialConsole = cfgLoadBool(config_section, "Debug.SerialConsoleEnabled", settings.debug.SerialConsole);
|
||||
settings.debug.SerialPTY = cfgLoadBool(config_section, "Debug.SerialPTY", settings.debug.SerialPTY);
|
||||
|
@ -1017,7 +1026,7 @@ void SaveSettings()
|
|||
cfgSaveBool("config", "rend.WidescreenGameHacks", settings.rend.WidescreenGameHacks);
|
||||
|
||||
cfgSaveInt("config", "pvr.MaxThreads", settings.pvr.MaxThreads);
|
||||
cfgSaveBool("config", "pvr.SynchronousRendering", settings.pvr.SynchronousRender);
|
||||
cfgSaveInt("config", "pvr.AutoSkipFrame", settings.pvr.AutoSkipFrame);
|
||||
|
||||
cfgSaveBool("config", "Debug.SerialConsoleEnabled", settings.debug.SerialConsole);
|
||||
cfgSaveBool("config", "Debug.SerialPTY", settings.debug.SerialPTY);
|
||||
|
|
|
@ -1151,9 +1151,21 @@ static void gui_display_settings()
|
|||
}
|
||||
if (ImGui::CollapsingHeader("Rendering Options", ImGuiTreeNodeFlags_DefaultOpen))
|
||||
{
|
||||
ImGui::Checkbox("Synchronous Rendering", &settings.pvr.SynchronousRender);
|
||||
ImGui::Text("Automatic Frame Skipping:");
|
||||
ImGui::Columns(3, "autoskip", false);
|
||||
ImGui::RadioButton("Disabled", &settings.pvr.AutoSkipFrame, 0);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Reduce frame skipping by pausing the CPU when possible. Recommended for most platforms");
|
||||
ShowHelpMarker("No frame skipping");
|
||||
ImGui::NextColumn();
|
||||
ImGui::RadioButton("Normal", &settings.pvr.AutoSkipFrame, 1);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Skip a frame when the GPU and CPU are both running slow");
|
||||
ImGui::NextColumn();
|
||||
ImGui::RadioButton("Maximum", &settings.pvr.AutoSkipFrame, 2);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Skip a frame when the GPU is running slow");
|
||||
ImGui::Columns(1, nullptr, false);
|
||||
|
||||
ImGui::Checkbox("Clipping", &settings.rend.Clipping);
|
||||
ImGui::SameLine();
|
||||
ShowHelpMarker("Enable clipping. May produce graphical errors when disabled");
|
||||
|
|
|
@ -475,7 +475,7 @@ struct settings_t
|
|||
RenderType rend;
|
||||
|
||||
u32 MaxThreads;
|
||||
bool SynchronousRender;
|
||||
int AutoSkipFrame; // 0: none, 1: some, 2: more
|
||||
|
||||
bool IsOpenGL() { return rend == RenderType::OpenGL || rend == RenderType::OpenGL_OIT; }
|
||||
} pvr;
|
||||
|
|
Loading…
Reference in New Issue