graphics: rate-limit the targeted preview-resolve readbacks
This commit is contained in:
parent
b4d018c405
commit
f8cbe94367
4 changed files with 56 additions and 1 deletions
|
|
@ -37,6 +37,7 @@ REXCVAR_DECLARE(std::string, readback_resolve);
|
|||
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_min_length);
|
||||
REXCVAR_DECLARE(int32_t, native_render_targeted_readback_min_interval_ms);
|
||||
REXCVAR_DECLARE(bool, readback_memexport);
|
||||
REXCVAR_DECLARE(bool, readback_memexport_fast);
|
||||
REXCVAR_DECLARE(bool, occlusion_query_enable);
|
||||
|
|
|
|||
|
|
@ -101,6 +101,19 @@ REXCVAR_DEFINE_INT32(native_render_force_resolve_readback_max_length, 0, "GPU",
|
|||
.range(0, 16 * 1024 * 1024)
|
||||
.lifecycle(rex::cvar::Lifecycle::kHotReload);
|
||||
|
||||
REXCVAR_DEFINE_INT32(native_render_targeted_readback_min_interval_ms, 33, "GPU",
|
||||
"Minimum interval between the targeted always-on resolve readbacks "
|
||||
"(the non-gameplay Import-Skater/preview target) in milliseconds. "
|
||||
"Each readback is a synchronous GPU drain plus a multi-megabyte CPU "
|
||||
"copy; menu flows that re-resolve the preview target every frame "
|
||||
"(trick guide demo pages) otherwise saturate the command processor "
|
||||
"with hundreds of drains per second. Skipped copies leave the "
|
||||
"previous CPU-visible contents in place (the consumer is a preview "
|
||||
"image). 0 disables the throttle. Does not affect the app-armed "
|
||||
"photo-grab window.")
|
||||
.range(0, 1000)
|
||||
.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 "
|
||||
|
|
|
|||
|
|
@ -3616,10 +3616,30 @@ bool D3D12CommandProcessor::IssueCopy_ReadbackResolvePath() {
|
|||
if (readback_mode == ReadbackResolveMode::kDisabled) {
|
||||
constexpr uint32_t kImportSkaterPreviewResolveAddress = UINT32_C(0x04911000);
|
||||
constexpr uint32_t kImportSkaterPreviewResolveLength = UINT32_C(0x2D0000);
|
||||
const bool force_scaled_resolve_cpu_copy =
|
||||
bool force_scaled_resolve_cpu_copy =
|
||||
!IsGameplayStateActive(kernel_state_) && is_scaled &&
|
||||
written_address == kImportSkaterPreviewResolveAddress &&
|
||||
written_length == kImportSkaterPreviewResolveLength;
|
||||
// Rate-limit the targeted copies: each one is a synchronous GPU drain
|
||||
// plus a multi-megabyte CPU copy, and menu flows that re-resolve the
|
||||
// preview target every frame (trick guide demo pages) issue hundreds
|
||||
// per second. A skipped copy leaves the previous CPU-visible contents
|
||||
// in place, which a preview consumer tolerates. The app-armed
|
||||
// photo-grab window below is deliberately NOT throttled (the display
|
||||
// card composes from exact frames). Mirrors the Vulkan gate.
|
||||
if (force_scaled_resolve_cpu_copy) {
|
||||
const int32_t min_interval_ms =
|
||||
REXCVAR_GET(native_render_targeted_readback_min_interval_ms);
|
||||
if (min_interval_ms > 0) {
|
||||
static uint64_t s_last_targeted_copy_ms = 0;
|
||||
const uint64_t now_ms = rex::chrono::Clock::QueryHostUptimeMillis();
|
||||
if (now_ms - s_last_targeted_copy_ms < uint64_t(min_interval_ms)) {
|
||||
force_scaled_resolve_cpu_copy = false;
|
||||
} else {
|
||||
s_last_targeted_copy_ms = now_ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
// App-armed readback window (Skate 3 photo grab): the game CPU-reads the
|
||||
// resolved 1152x640 PostFX screenshot target (also 0x04911000) while the
|
||||
// gameplay presence context is still 1 (photo missions), so the targeted
|
||||
|
|
|
|||
|
|
@ -5824,6 +5824,27 @@ bool VulkanCommandProcessor::IssueCopy_ReadbackResolvePath() {
|
|||
!IsGameplayStateActive(kernel_state_) && is_scaled &&
|
||||
written_address == kImportSkaterPreviewResolveAddress &&
|
||||
written_length == kImportSkaterPreviewResolveLength;
|
||||
// Rate-limit the targeted copies: each one is a synchronous GPU drain
|
||||
// plus a multi-megabyte CPU copy, and menu flows that re-resolve the
|
||||
// preview target every frame (trick guide demo pages) issue hundreds
|
||||
// per second, enough to halve the frame rate on their own. A skipped
|
||||
// copy leaves the previous CPU-visible contents in place, which a
|
||||
// preview consumer tolerates. The app-armed photo-grab window below is
|
||||
// deliberately NOT throttled (the display card composes from exact
|
||||
// frames).
|
||||
if (force_scaled_resolve_cpu_copy) {
|
||||
const int32_t min_interval_ms =
|
||||
REXCVAR_GET(native_render_targeted_readback_min_interval_ms);
|
||||
if (min_interval_ms > 0) {
|
||||
static uint64_t s_last_targeted_copy_ms = 0;
|
||||
const uint64_t now_ms = rex::chrono::Clock::QueryHostUptimeMillis();
|
||||
if (now_ms - s_last_targeted_copy_ms < uint64_t(min_interval_ms)) {
|
||||
force_scaled_resolve_cpu_copy = false;
|
||||
} else {
|
||||
s_last_targeted_copy_ms = now_ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
// App-armed readback window (Skate 3 photo grab): the game CPU-reads the
|
||||
// resolved 1152x640 PostFX screenshot target (also 0x04911000) while the
|
||||
// gameplay presence context is still 1 (photo missions), so the targeted
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue