[Vulkan] Implement tiled_shared_memory for resolution scaling

Adds support for >3x resolution scaling to vulkan by implementing
sparse scaled resolve similar to the d3d12 implementation.
This commit is contained in:
Herman S.
2025-12-22 11:58:13 +09:00
parent a092551735
commit 5897de3eaf
10 changed files with 508 additions and 77 deletions

View File

@@ -12,17 +12,19 @@
#include "xenia/base/clock.h"
#include "xenia/base/cvar.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
#include "xenia/base/profiling.h"
#include "xenia/gpu/gpu_flags.h"
#include "xenia/gpu/shared_memory.h"
DEFINE_int32(
draw_resolution_scale_x, 1,
"Integer pixel width scale used for scaling the rendering resolution "
"opaquely to the game.\n"
"1, 2 and 3 may be supported, but support of anything above 1 depends on "
"the device properties, such as whether it supports sparse binding / tiled "
"resources, the number of virtual address bits per resource, and other "
"factors.\n"
"Values from 1 to 7 may be supported, depending on device capabilities. "
"Requires sparse binding (Vulkan) or tiled resources (D3D12) for scales "
"above 1x1. The emulator will automatically clamp to the maximum supported "
"scale if the requested value exceeds device limits.\n"
"Various effects and parts of game rendering pipelines may work "
"incorrectly as pixels become ambiguous from the game's perspective and "
"because half-pixel offset (which normally doesn't affect coverage when "
@@ -59,6 +61,10 @@ DEFINE_uint32(
"textures - so with 2x2 resolution scaling, the soft limit will be 360 + "
"96 MB, and with 3x3, it will be 360 + 216 MB.",
"GPU");
DEFINE_bool(tiled_shared_memory, true,
"Enable tiled/sparse resources for efficient large address space "
"support. Disable for graphics debugger compatibility.",
"GPU");
namespace xe {
namespace gpu {
@@ -187,6 +193,43 @@ bool TextureCache::GetConfigDrawResolutionScale(uint32_t& x_out,
return clamped_x == config_x && clamped_y == config_y;
}
bool TextureCache::ClampDrawResolutionScaleToMaxSupported(
uint32_t& scale_x, uint32_t& scale_y, bool sparse_bind_supported,
uint32_t virtual_address_bits_per_resource) {
// Without sparse/tiled resource support, resolution scaling is not possible
// because the scaled address space exceeds what simple buffers can handle.
if (!sparse_bind_supported) {
bool was_clamped = scale_x > 1 || scale_y > 1;
scale_x = 1;
scale_y = 1;
return !was_clamped;
}
// With sparse binding, limit based on virtual address space if specified.
bool was_clamped = false;
if (virtual_address_bits_per_resource > 0) {
while (scale_x > 1 || scale_y > 1) {
uint64_t highest_scaled_address =
uint64_t(SharedMemory::kBufferSize) * (scale_x * scale_y) - 1;
if (uint32_t(64) - xe::lzcnt(highest_scaled_address) <=
virtual_address_bits_per_resource) {
break;
}
// When reducing from a square size, prefer decreasing the horizontal
// resolution as vertical resolution difference is visible more clearly in
// perspective.
was_clamped = true;
if (scale_x >= scale_y) {
--scale_x;
} else {
--scale_y;
}
}
}
return !was_clamped;
}
void TextureCache::ClearCache() { DestroyAllTextures(); }
void TextureCache::CompletedSubmissionUpdated(