GPU: readback-window diagnostics + min_length floor
This commit is contained in:
parent
b8258670da
commit
065cade4d3
3 changed files with 65 additions and 1 deletions
|
|
@ -36,6 +36,7 @@ REXCVAR_DECLARE(int32_t, scaled_resolve_small_texture_readback_max_length);
|
||||||
REXCVAR_DECLARE(std::string, readback_resolve);
|
REXCVAR_DECLARE(std::string, readback_resolve);
|
||||||
REXCVAR_DECLARE(bool, readback_resolve_half_pixel_offset);
|
REXCVAR_DECLARE(bool, readback_resolve_half_pixel_offset);
|
||||||
REXCVAR_DECLARE(int32_t, native_render_force_resolve_readback_max_length);
|
REXCVAR_DECLARE(int32_t, native_render_force_resolve_readback_max_length);
|
||||||
|
REXCVAR_DECLARE(int32_t, native_render_force_resolve_readback_min_length);
|
||||||
REXCVAR_DECLARE(bool, readback_memexport);
|
REXCVAR_DECLARE(bool, readback_memexport);
|
||||||
REXCVAR_DECLARE(bool, readback_memexport_fast);
|
REXCVAR_DECLARE(bool, readback_memexport_fast);
|
||||||
REXCVAR_DECLARE(bool, occlusion_query_enable);
|
REXCVAR_DECLARE(bool, occlusion_query_enable);
|
||||||
|
|
|
||||||
|
|
@ -101,6 +101,18 @@ REXCVAR_DEFINE_INT32(native_render_force_resolve_readback_max_length, 0, "GPU",
|
||||||
.range(0, 16 * 1024 * 1024)
|
.range(0, 16 * 1024 * 1024)
|
||||||
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
||||||
|
|
||||||
|
REXCVAR_DEFINE_INT32(native_render_force_resolve_readback_min_length, 0, "GPU",
|
||||||
|
"Lower bound companion to "
|
||||||
|
"native_render_force_resolve_readback_max_length: when > 0, resolves "
|
||||||
|
"SHORTER than this skip the forced CPU copy (they still execute "
|
||||||
|
"GPU-side). Each forced copy is a synchronous GPU drain; the Skate 3 "
|
||||||
|
"photo-flow compose window uses this to skip the ~18 small per-frame "
|
||||||
|
"resolves (64 KB lightmap pages, postfx aux) that made the window a "
|
||||||
|
"stutter-fest, while still copying the display-card compose. 0 "
|
||||||
|
"disables (default).")
|
||||||
|
.range(0, 16 * 1024 * 1024)
|
||||||
|
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
||||||
|
|
||||||
REXCVAR_DEFINE_BOOL(readback_memexport, false, "GPU",
|
REXCVAR_DEFINE_BOOL(readback_memexport, false, "GPU",
|
||||||
"Enable CPU readback of shader memexport writes for guest memory "
|
"Enable CPU readback of shader memexport writes for guest memory "
|
||||||
"coherency (can reduce correctness issues, but may add GPU/CPU sync cost)")
|
"coherency (can reduce correctness issues, but may add GPU/CPU sync cost)")
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@
|
||||||
#include <rex/graphics/util/draw.h>
|
#include <rex/graphics/util/draw.h>
|
||||||
#include <rex/graphics/xenos.h>
|
#include <rex/graphics/xenos.h>
|
||||||
#include <rex/kernel/xboxkrnl/video.h>
|
#include <rex/kernel/xboxkrnl/video.h>
|
||||||
|
#include <rex/chrono/clock.h>
|
||||||
#include <rex/logging.h>
|
#include <rex/logging.h>
|
||||||
#include <rex/memory/utils.h>
|
#include <rex/memory/utils.h>
|
||||||
#include <rex/system/kernel_state.h>
|
#include <rex/system/kernel_state.h>
|
||||||
|
|
@ -2851,6 +2852,30 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, uint3
|
||||||
// composition, CAS composites) must keep their resolves: skipping
|
// composition, CAS composites) must keep their resolves: skipping
|
||||||
// lightpage composition left never-composed pages sampling garbage:
|
// lightpage composition left never-composed pages sampling garbage:
|
||||||
// the light/dark checkerboard ground.
|
// the light/dark checkerboard ground.
|
||||||
|
if (REXCVAR_GET(native_render_force_resolve_readback_max_length) > 0) {
|
||||||
|
// App-armed window diagnostics (Skate 3 photo flows): while the
|
||||||
|
// window is armed, show which resolves the suppression filter drops
|
||||||
|
// - pins passes (e.g. the photo display-card compose) whose output
|
||||||
|
// never reaches guest memory. Throttled.
|
||||||
|
static uint64_t s_drop_log_ms = 0;
|
||||||
|
static uint32_t s_drop_log_count = 0;
|
||||||
|
const uint64_t now_ms = rex::chrono::Clock::QueryHostUptimeMillis();
|
||||||
|
if (now_ms - s_drop_log_ms >= 1000) {
|
||||||
|
if (s_drop_log_count > 8) {
|
||||||
|
REXLOG_INFO("readback-window: (+{} more dropped resolves)",
|
||||||
|
s_drop_log_count - 8);
|
||||||
|
}
|
||||||
|
s_drop_log_ms = now_ms;
|
||||||
|
s_drop_log_count = 0;
|
||||||
|
}
|
||||||
|
if (++s_drop_log_count <= 8) {
|
||||||
|
REXLOG_INFO(
|
||||||
|
"readback-window: resolve DROPPED with suppressed pass "
|
||||||
|
"(surface_pitch={} copy_dest=0x{:08X})",
|
||||||
|
regs.Get<reg::RB_SURFACE_INFO>().surface_pitch,
|
||||||
|
uint32_t(regs[XE_GPU_REG_RB_COPY_DEST_BASE]));
|
||||||
|
}
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return IssueCopy();
|
return IssueCopy();
|
||||||
|
|
@ -3730,9 +3755,35 @@ bool D3D12CommandProcessor::IssueCopy_ReadbackResolvePath() {
|
||||||
// framebuffer-sized resolves stay excluded.
|
// framebuffer-sized resolves stay excluded.
|
||||||
const int32_t force_readback_max_length =
|
const int32_t force_readback_max_length =
|
||||||
REXCVAR_GET(native_render_force_resolve_readback_max_length);
|
REXCVAR_GET(native_render_force_resolve_readback_max_length);
|
||||||
|
const int32_t force_readback_min_length =
|
||||||
|
REXCVAR_GET(native_render_force_resolve_readback_min_length);
|
||||||
const bool force_window_cpu_copy =
|
const bool force_window_cpu_copy =
|
||||||
force_readback_max_length > 0 &&
|
force_readback_max_length > 0 &&
|
||||||
written_length <= uint32_t(force_readback_max_length);
|
written_length <= uint32_t(force_readback_max_length) &&
|
||||||
|
(force_readback_min_length <= 0 ||
|
||||||
|
written_length >= uint32_t(force_readback_min_length));
|
||||||
|
if (force_readback_max_length > 0) {
|
||||||
|
// App-armed window diagnostics (Skate 3 photo flows): every resolve
|
||||||
|
// that executes while the window is armed, and whether it takes the
|
||||||
|
// CPU-copy path. Throttled.
|
||||||
|
static uint64_t s_seen_log_ms = 0;
|
||||||
|
static uint32_t s_seen_log_count = 0;
|
||||||
|
const uint64_t now_ms = rex::chrono::Clock::QueryHostUptimeMillis();
|
||||||
|
if (now_ms - s_seen_log_ms >= 1000) {
|
||||||
|
if (s_seen_log_count > 8) {
|
||||||
|
REXLOG_INFO("readback-window: (+{} more resolves seen)",
|
||||||
|
s_seen_log_count - 8);
|
||||||
|
}
|
||||||
|
s_seen_log_ms = now_ms;
|
||||||
|
s_seen_log_count = 0;
|
||||||
|
}
|
||||||
|
if (++s_seen_log_count <= 8) {
|
||||||
|
REXLOG_INFO("readback-window: resolve dest=0x{:08X} len=0x{:X}{}",
|
||||||
|
written_address, written_length,
|
||||||
|
force_window_cpu_copy ? " -> CPU copy (kFull)"
|
||||||
|
: " (above window cap - GPU only)");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!force_scaled_resolve_cpu_copy && !force_window_cpu_copy) {
|
if (!force_scaled_resolve_cpu_copy && !force_window_cpu_copy) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue