mirror of
https://github.com/izzy2lost/xenia-edge.git
synced 2026-07-06 00:20:26 -07:00
[GPU] Change readback_resolve values and default
Rename values to [none, some, fast, full], "fast" is still the default but is what was previously known as "slow". Also fixing the controller hotkey handling to update the cached value as well as persist the value in per-game config.
This commit is contained in:
@@ -2213,16 +2213,29 @@ void EmulatorWindow::ToggleGPUSetting(gpu::GPUSetting setting) {
|
||||
}
|
||||
|
||||
void EmulatorWindow::CycleReadbackResolve() {
|
||||
const std::string& current = cvars::readback_resolve;
|
||||
if (current == "fast") {
|
||||
gpu::SetReadbackResolveMode("slow");
|
||||
} else if (current == "slow") {
|
||||
gpu::SetReadbackResolveMode("full");
|
||||
} else if (current == "full") {
|
||||
gpu::SetReadbackResolveMode("none");
|
||||
} else {
|
||||
gpu::SetReadbackResolveMode("fast");
|
||||
auto* graphics_system = emulator_->graphics_system();
|
||||
if (!graphics_system) return;
|
||||
auto* command_processor = graphics_system->command_processor();
|
||||
if (!command_processor) return;
|
||||
|
||||
gpu::ReadbackResolveMode current =
|
||||
command_processor->GetReadbackResolveMode();
|
||||
gpu::ReadbackResolveMode next;
|
||||
switch (current) {
|
||||
case gpu::ReadbackResolveMode::kDisabled:
|
||||
next = gpu::ReadbackResolveMode::kSome;
|
||||
break;
|
||||
case gpu::ReadbackResolveMode::kSome:
|
||||
next = gpu::ReadbackResolveMode::kFast;
|
||||
break;
|
||||
case gpu::ReadbackResolveMode::kFast:
|
||||
next = gpu::ReadbackResolveMode::kFull;
|
||||
break;
|
||||
default:
|
||||
next = gpu::ReadbackResolveMode::kDisabled;
|
||||
break;
|
||||
}
|
||||
command_processor->SetReadbackResolveMode(next);
|
||||
}
|
||||
|
||||
void EmulatorWindow::DisplayHotKeysConfig() {
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "xenia/base/cvar.h"
|
||||
#include "xenia/base/logging.h"
|
||||
#include "xenia/base/profiling.h"
|
||||
#include "xenia/config.h"
|
||||
#include "xenia/gpu/gpu_flags.h"
|
||||
#include "xenia/gpu/graphics_system.h"
|
||||
#include "xenia/gpu/packet_disassembler.h"
|
||||
@@ -52,8 +53,8 @@ DEFINE_bool(clear_memory_page_state, true,
|
||||
DEFINE_string(
|
||||
readback_resolve, "fast",
|
||||
"Controls CPU readback of render-to-texture resolve results.\n"
|
||||
" fast: Read from previous frame, skip copy on cache hit (default)\n"
|
||||
" slow: Read from previous frame, copy every frame\n"
|
||||
" fast: Read from previous frame, copy every frame (default)\n"
|
||||
" some: Read from previous frame, skip copy on cache hit\n"
|
||||
" full: Wait for GPU to finish (accurate but slow, GPU-CPU sync stall)\n"
|
||||
" none: Disable readback completely (some games render better without it)",
|
||||
"GPU");
|
||||
@@ -104,8 +105,8 @@ static ReadbackResolveMode ParseReadbackResolveMode() {
|
||||
const std::string& mode = cvars::readback_resolve;
|
||||
if (mode == "full") {
|
||||
return ReadbackResolveMode::kFull;
|
||||
} else if (mode == "slow") {
|
||||
return ReadbackResolveMode::kSlow;
|
||||
} else if (mode == "some") {
|
||||
return ReadbackResolveMode::kSome;
|
||||
} else if (mode == "none") {
|
||||
return ReadbackResolveMode::kDisabled;
|
||||
} else {
|
||||
@@ -114,7 +115,7 @@ static ReadbackResolveMode ParseReadbackResolveMode() {
|
||||
}
|
||||
}
|
||||
|
||||
void SetReadbackResolveMode(const std::string& mode) {
|
||||
static void SetReadbackResolveCvar(const std::string& mode) {
|
||||
OVERRIDE_string(readback_resolve, mode);
|
||||
}
|
||||
|
||||
@@ -278,6 +279,47 @@ void CommandProcessor::InvalidateGpuMemory() {}
|
||||
|
||||
void CommandProcessor::ClearReadbackBuffers() {}
|
||||
|
||||
void CommandProcessor::SetReadbackResolveMode(ReadbackResolveMode mode) {
|
||||
if (cached_readback_resolve_mode_ == mode) {
|
||||
return;
|
||||
}
|
||||
// Update cached value
|
||||
cached_readback_resolve_mode_ = mode;
|
||||
// Update cvar string for UI display
|
||||
const char* mode_str = "fast";
|
||||
switch (mode) {
|
||||
case ReadbackResolveMode::kDisabled:
|
||||
mode_str = "none";
|
||||
break;
|
||||
case ReadbackResolveMode::kSome:
|
||||
mode_str = "some";
|
||||
break;
|
||||
case ReadbackResolveMode::kFull:
|
||||
mode_str = "full";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
SetReadbackResolveCvar(mode_str);
|
||||
|
||||
// Save to per-game config if a title is loaded
|
||||
uint32_t title_id = kernel_state_ ? kernel_state_->title_id() : 0;
|
||||
if (title_id != 0) {
|
||||
toml::table config_table = config::LoadGameConfig(title_id);
|
||||
|
||||
if (!config_table.contains("GPU")) {
|
||||
config_table.insert("GPU", toml::table{});
|
||||
}
|
||||
|
||||
auto* gpu_table = config_table["GPU"].as_table();
|
||||
if (gpu_table) {
|
||||
gpu_table->insert_or_assign("readback_resolve", mode_str);
|
||||
}
|
||||
|
||||
config::SaveGameConfig(title_id, config_table);
|
||||
}
|
||||
}
|
||||
|
||||
void CommandProcessor::SetDesiredSwapPostEffect(
|
||||
SwapPostEffect swap_post_effect) {
|
||||
if (swap_post_effect_desired_ == swap_post_effect) {
|
||||
|
||||
@@ -37,14 +37,13 @@ enum class GPUSetting { ClearMemoryPageState, ReadbackMemexport };
|
||||
|
||||
enum class ReadbackResolveMode {
|
||||
kDisabled, // No readback (none)
|
||||
kFast, // Delayed sync, skip copy on cache hit (fast)
|
||||
kSlow, // Delayed sync, copy every frame (slow)
|
||||
kSome, // Delayed sync, skip copy on cache hit (some)
|
||||
kFast, // Delayed sync, copy every frame (fast)
|
||||
kFull // Immediate sync with GPU stall (full)
|
||||
};
|
||||
|
||||
void SaveGPUSetting(GPUSetting setting, uint64_t value);
|
||||
bool GetGPUSetting(GPUSetting setting);
|
||||
void SetReadbackResolveMode(const std::string& mode);
|
||||
|
||||
// Occlusion query pool size for both D3D12 and Vulkan backends.
|
||||
// Queries complete synchronously with GPU stalls.
|
||||
@@ -117,6 +116,9 @@ class CommandProcessor {
|
||||
return cached_readback_resolve_mode_;
|
||||
}
|
||||
|
||||
// Set readback resolve mode (updates both cvar and cached value)
|
||||
void SetReadbackResolveMode(ReadbackResolveMode mode);
|
||||
|
||||
// "Desired" is for the external thread managing the post-processing effect.
|
||||
SwapPostEffect GetDesiredSwapPostEffect() const {
|
||||
return swap_post_effect_desired_;
|
||||
|
||||
@@ -3256,7 +3256,7 @@ bool D3D12CommandProcessor::IssueCopy_ReadbackResolvePath() {
|
||||
|
||||
ReadbackResolveMode readback_mode = GetReadbackResolveMode();
|
||||
bool use_delayed_sync = (readback_mode == ReadbackResolveMode::kFast ||
|
||||
readback_mode == ReadbackResolveMode::kSlow);
|
||||
readback_mode == ReadbackResolveMode::kSome);
|
||||
uint32_t read_index = write_index;
|
||||
|
||||
if (use_delayed_sync) {
|
||||
@@ -3286,11 +3286,11 @@ bool D3D12CommandProcessor::IssueCopy_ReadbackResolvePath() {
|
||||
}
|
||||
|
||||
// Copy to guest memory
|
||||
// "fast" mode: only copy on cache miss (saves CPU)
|
||||
// "slow" mode: always copy (1 frame behind, no GPU stall)
|
||||
// "some" mode: only copy on cache miss (saves CPU)
|
||||
// "fast" mode: always copy (1 frame behind, no GPU stall)
|
||||
// "full" mode: always copy (GPU sync already done above)
|
||||
bool should_copy =
|
||||
(readback_mode == ReadbackResolveMode::kFast) ? is_cache_miss : true;
|
||||
(readback_mode == ReadbackResolveMode::kSome) ? is_cache_miss : true;
|
||||
if (should_copy && read_source != nullptr &&
|
||||
written_length <= rb.sizes[read_index] &&
|
||||
rb.mapped_data[read_index] != nullptr) {
|
||||
|
||||
@@ -3274,7 +3274,7 @@ bool VulkanCommandProcessor::IssueCopy() {
|
||||
shared_memory_buffer, rb.buffers[write_index], 1, ©_region);
|
||||
|
||||
bool use_delayed_sync = (readback_mode == ReadbackResolveMode::kFast ||
|
||||
readback_mode == ReadbackResolveMode::kSlow);
|
||||
readback_mode == ReadbackResolveMode::kSome);
|
||||
uint32_t read_index = write_index;
|
||||
|
||||
if (use_delayed_sync) {
|
||||
@@ -3306,7 +3306,7 @@ bool VulkanCommandProcessor::IssueCopy() {
|
||||
}
|
||||
|
||||
bool should_copy =
|
||||
(readback_mode == ReadbackResolveMode::kFast) ? is_cache_miss : true;
|
||||
(readback_mode == ReadbackResolveMode::kSome) ? is_cache_miss : true;
|
||||
if (should_copy && rb.buffers[read_index] != VK_NULL_HANDLE &&
|
||||
written_length <= rb.sizes[read_index] &&
|
||||
rb.mapped_data[read_index] != nullptr) {
|
||||
|
||||
@@ -78,7 +78,7 @@ GetKnownEnumOptions() {
|
||||
#endif
|
||||
{"d3d12_readback_resolve",
|
||||
{"kCopy", "kComputeLuminance", "kComputeRGBA16"}},
|
||||
{"readback_resolve", {"fast", "slow", "full", "none"}},
|
||||
{"readback_resolve", {"fast", "some", "full", "none"}},
|
||||
{"render_target_path", {"performance", "accuracy"}},
|
||||
{"postprocess_antialiasing", {"off", "fxaa", "fxaa_extreme"}},
|
||||
{"postprocess_scaling_and_sharpening",
|
||||
|
||||
Reference in New Issue
Block a user