mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-29 22:36:52 +01:00
graphics: write small GPU-written tiled images back to guest memory behind --readback-tiled-images
Co-authored-by: Dimitar Vagalinski <275970482+overlordxrz-source@users.noreply.github.com> Co-authored-by: Mr. Big Britches <111622360+MrBigBritches@users.noreply.github.com>
This commit is contained in:
@@ -185,6 +185,10 @@ bool ReadbackLinearImagesEnabled() {
|
|||||||
return g_config->readback_linear_images;
|
return g_config->readback_linear_images;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ReadbackTiledImagesEnabled() {
|
||||||
|
return g_config->readback_tiled_images;
|
||||||
|
}
|
||||||
|
|
||||||
bool SyncRawImageBuffersEnabled() {
|
bool SyncRawImageBuffersEnabled() {
|
||||||
return g_config->sync_raw_image_buffers;
|
return g_config->sync_raw_image_buffers;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ struct ConfigOptions {
|
|||||||
bool gpu_assisted_validation_enabled = false;
|
bool gpu_assisted_validation_enabled = false;
|
||||||
bool renderdoc_enabled = false;
|
bool renderdoc_enabled = false;
|
||||||
bool readback_linear_images = false;
|
bool readback_linear_images = false;
|
||||||
|
bool readback_tiled_images = false;
|
||||||
bool sync_raw_image_buffers = false;
|
bool sync_raw_image_buffers = false;
|
||||||
bool tessellation_enabled = false;
|
bool tessellation_enabled = false;
|
||||||
bool trophy_enabled = true;
|
bool trophy_enabled = true;
|
||||||
@@ -150,6 +151,7 @@ bool GpuAssistedValidationEnabled();
|
|||||||
|
|
||||||
bool RenderDocEnabled();
|
bool RenderDocEnabled();
|
||||||
bool ReadbackLinearImagesEnabled();
|
bool ReadbackLinearImagesEnabled();
|
||||||
|
bool ReadbackTiledImagesEnabled();
|
||||||
bool SyncRawImageBuffersEnabled();
|
bool SyncRawImageBuffersEnabled();
|
||||||
bool TessellationEnabled();
|
bool TessellationEnabled();
|
||||||
bool TrophyEnabled();
|
bool TrophyEnabled();
|
||||||
|
|||||||
+13
-3
@@ -34,6 +34,8 @@ namespace Libs::Graphics {
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr uint64_t NumFramesBeforeRemoval = 32;
|
constexpr uint64_t NumFramesBeforeRemoval = 32;
|
||||||
|
// Largest GPU-written tiled image (in texels) that is written back to guest memory on submit.
|
||||||
|
constexpr uint64_t SmallTiledReadbackTexels = 64 * 64;
|
||||||
|
|
||||||
[[nodiscard]] bool DecodeColorClear(const TextureCache::ImageDesc& desc, uint8_t code,
|
[[nodiscard]] bool DecodeColorClear(const TextureCache::ImageDesc& desc, uint8_t code,
|
||||||
vk::ClearColorValue& clear) {
|
vk::ClearColorValue& clear) {
|
||||||
@@ -122,7 +124,8 @@ TextureCache::TextureCache(GraphicContext& graphics, CommandScheduler& scheduler
|
|||||||
m_blit_helper(graphics, scheduler),
|
m_blit_helper(graphics, scheduler),
|
||||||
m_tiler(graphics, scheduler, buffer_cache.GetUtilityBuffer(MemoryUsage::Stream)),
|
m_tiler(graphics, scheduler, buffer_cache.GetUtilityBuffer(MemoryUsage::Stream)),
|
||||||
m_buffer_cache(buffer_cache),
|
m_buffer_cache(buffer_cache),
|
||||||
m_readback_linear_images(Config::ReadbackLinearImagesEnabled()) {
|
m_readback_linear_images(Config::ReadbackLinearImagesEnabled()),
|
||||||
|
m_readback_tiled_images(Config::ReadbackTiledImagesEnabled()) {
|
||||||
if (m_graphics.CanReportMemoryUsage()) {
|
if (m_graphics.CanReportMemoryUsage()) {
|
||||||
constexpr int64_t GiB = 1024ll * 1024 * 1024;
|
constexpr int64_t GiB = 1024ll * 1024 * 1024;
|
||||||
const auto budget =
|
const auto budget =
|
||||||
@@ -401,7 +404,14 @@ void TextureCache::UntrackImageTail(ImageId id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextureCache::TrackImageDownload(ImageId id, Image& image) {
|
void TextureCache::TrackImageDownload(ImageId id, Image& image) {
|
||||||
if (m_readback_linear_images && !image.info.IsTiled()) {
|
// Small tiled targets are written back too: games read GPU results such as reductions and
|
||||||
|
// simulation state from them on the CPU (PPSA04263 keeps the origin of its ocean wave grid
|
||||||
|
// in a 1x1 R32G32 target, and its water physics read it to sample the wave heights).
|
||||||
|
const auto& info = image.info;
|
||||||
|
const auto texels = static_cast<uint64_t>(info.extent.width) * info.extent.height *
|
||||||
|
info.extent.depth * info.resources.layers;
|
||||||
|
if (info.IsTiled() ? m_readback_tiled_images && texels <= SmallTiledReadbackTexels
|
||||||
|
: m_readback_linear_images) {
|
||||||
if (!image.IsGpuModified()) {
|
if (!image.IsGpuModified()) {
|
||||||
EXIT("TextureCache: cannot enroll a non-GPU-owned image for download\n");
|
EXIT("TextureCache: cannot enroll a non-GPU-owned image for download\n");
|
||||||
}
|
}
|
||||||
@@ -1956,7 +1966,7 @@ void TextureCache::RunGarbageCollector() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextureCache::ProcessDownloadImages() {
|
void TextureCache::ProcessDownloadImages() {
|
||||||
if (!m_readback_linear_images) {
|
if (!m_readback_linear_images && !m_readback_tiled_images) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::scoped_lock lock {m_lock};
|
std::scoped_lock lock {m_lock};
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ private:
|
|||||||
uint64_t m_gc_tick = 0;
|
uint64_t m_gc_tick = 0;
|
||||||
mutable uint32_t m_image_query_epoch = 0;
|
mutable uint32_t m_image_query_epoch = 0;
|
||||||
bool m_readback_linear_images = false;
|
bool m_readback_linear_images = false;
|
||||||
|
bool m_readback_tiled_images = false;
|
||||||
|
|
||||||
friend struct TextureCacheTestAccess;
|
friend struct TextureCacheTestAccess;
|
||||||
friend class BufferCache;
|
friend class BufferCache;
|
||||||
|
|||||||
@@ -168,12 +168,18 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="6" column="1">
|
<item row="6" column="1">
|
||||||
|
<widget class="QCheckBox" name="checkBox_readback_tiled">
|
||||||
|
<property name="toolTip"><string>Read back small writable tiled images</string></property>
|
||||||
|
<property name="text"><string>Enable tiled readback</string></property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="7" column="1">
|
||||||
<widget class="QCheckBox" name="checkBox_tessellation">
|
<widget class="QCheckBox" name="checkBox_tessellation">
|
||||||
<property name="toolTip"><string>Draw tessellated geometry. Disabled by default; unsupported tessellation may cause crashes.</string></property>
|
<property name="toolTip"><string>Draw tessellated geometry. Disabled by default; unsupported tessellation may cause crashes.</string></property>
|
||||||
<property name="text"><string>Enable tessellation support (experimental)</string></property>
|
<property name="text"><string>Enable tessellation support (experimental)</string></property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="7" column="1">
|
<item row="8" column="1">
|
||||||
<widget class="QCheckBox" name="checkBox_hdr">
|
<widget class="QCheckBox" name="checkBox_hdr">
|
||||||
<property name="toolTip"><string>Enable HDR10 output for supported games. Requires HDR enabled on the host display.</string></property>
|
<property name="toolTip"><string>Enable HDR10 output for supported games. Requires HDR enabled on the host display.</string></property>
|
||||||
<property name="text"><string>Enable HDR display support</string></property>
|
<property name="text"><string>Enable HDR display support</string></property>
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ public:
|
|||||||
bool hdr_enabled = false;
|
bool hdr_enabled = false;
|
||||||
bool hide_cursor_enabled = false;
|
bool hide_cursor_enabled = false;
|
||||||
bool readback_linear_images = false;
|
bool readback_linear_images = false;
|
||||||
|
bool readback_tiled_images = false;
|
||||||
bool sync_raw_image_buffers = false;
|
bool sync_raw_image_buffers = false;
|
||||||
bool tessellation_enabled = false;
|
bool tessellation_enabled = false;
|
||||||
bool trophy_enabled = true;
|
bool trophy_enabled = true;
|
||||||
@@ -165,6 +166,7 @@ public:
|
|||||||
hdr_enabled = other.hdr_enabled;
|
hdr_enabled = other.hdr_enabled;
|
||||||
hide_cursor_enabled = other.hide_cursor_enabled;
|
hide_cursor_enabled = other.hide_cursor_enabled;
|
||||||
readback_linear_images = other.readback_linear_images;
|
readback_linear_images = other.readback_linear_images;
|
||||||
|
readback_tiled_images = other.readback_tiled_images;
|
||||||
sync_raw_image_buffers = other.sync_raw_image_buffers;
|
sync_raw_image_buffers = other.sync_raw_image_buffers;
|
||||||
tessellation_enabled = other.tessellation_enabled;
|
tessellation_enabled = other.tessellation_enabled;
|
||||||
trophy_enabled = other.trophy_enabled;
|
trophy_enabled = other.trophy_enabled;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ QVariantMap Configuration::GameSettings() const {
|
|||||||
KYTY_CFG_SET(hdr_enabled);
|
KYTY_CFG_SET(hdr_enabled);
|
||||||
KYTY_CFG_SET(hide_cursor_enabled);
|
KYTY_CFG_SET(hide_cursor_enabled);
|
||||||
KYTY_CFG_SET(readback_linear_images);
|
KYTY_CFG_SET(readback_linear_images);
|
||||||
|
KYTY_CFG_SET(readback_tiled_images);
|
||||||
KYTY_CFG_SET(sync_raw_image_buffers);
|
KYTY_CFG_SET(sync_raw_image_buffers);
|
||||||
KYTY_CFG_SET(tessellation_enabled);
|
KYTY_CFG_SET(tessellation_enabled);
|
||||||
KYTY_CFG_SET(trophy_enabled);
|
KYTY_CFG_SET(trophy_enabled);
|
||||||
@@ -62,6 +63,7 @@ void Configuration::ReadGameSettingsValues(const Settings& s) {
|
|||||||
KYTY_CFG_GET(hdr_enabled);
|
KYTY_CFG_GET(hdr_enabled);
|
||||||
KYTY_CFG_GET(hide_cursor_enabled);
|
KYTY_CFG_GET(hide_cursor_enabled);
|
||||||
KYTY_CFG_GET(readback_linear_images);
|
KYTY_CFG_GET(readback_linear_images);
|
||||||
|
KYTY_CFG_GET(readback_tiled_images);
|
||||||
KYTY_CFG_GET(sync_raw_image_buffers);
|
KYTY_CFG_GET(sync_raw_image_buffers);
|
||||||
KYTY_CFG_GET(tessellation_enabled);
|
KYTY_CFG_GET(tessellation_enabled);
|
||||||
trophy_enabled = s.value("trophy_enabled", trophy_enabled).toBool();
|
trophy_enabled = s.value("trophy_enabled", trophy_enabled).toBool();
|
||||||
|
|||||||
@@ -286,6 +286,7 @@ void ConfigurationEditDialog::Init(const Configuration& info) {
|
|||||||
m_ui->checkBox_hdr->setChecked(info.hdr_enabled);
|
m_ui->checkBox_hdr->setChecked(info.hdr_enabled);
|
||||||
m_ui->checkBox_hide_cursor->setChecked(info.hide_cursor_enabled);
|
m_ui->checkBox_hide_cursor->setChecked(info.hide_cursor_enabled);
|
||||||
m_ui->checkBox_readback->setChecked(info.readback_linear_images);
|
m_ui->checkBox_readback->setChecked(info.readback_linear_images);
|
||||||
|
m_ui->checkBox_readback_tiled->setChecked(info.readback_tiled_images);
|
||||||
m_ui->checkBox_sync_raw_image_buffers->setChecked(info.sync_raw_image_buffers);
|
m_ui->checkBox_sync_raw_image_buffers->setChecked(info.sync_raw_image_buffers);
|
||||||
m_ui->checkBox_tessellation->setChecked(info.tessellation_enabled);
|
m_ui->checkBox_tessellation->setChecked(info.tessellation_enabled);
|
||||||
m_ui->checkBox_skip_notice_screen->setChecked(info.skip_notice_screen);
|
m_ui->checkBox_skip_notice_screen->setChecked(info.skip_notice_screen);
|
||||||
@@ -479,6 +480,7 @@ static void UpdateInfo(Configuration& info, Ui::ConfigurationEditDialog& ui, boo
|
|||||||
info.hdr_enabled = ui.checkBox_hdr->isChecked();
|
info.hdr_enabled = ui.checkBox_hdr->isChecked();
|
||||||
info.hide_cursor_enabled = ui.checkBox_hide_cursor->isChecked();
|
info.hide_cursor_enabled = ui.checkBox_hide_cursor->isChecked();
|
||||||
info.readback_linear_images = ui.checkBox_readback->isChecked();
|
info.readback_linear_images = ui.checkBox_readback->isChecked();
|
||||||
|
info.readback_tiled_images = ui.checkBox_readback_tiled->isChecked();
|
||||||
info.sync_raw_image_buffers = ui.checkBox_sync_raw_image_buffers->isChecked();
|
info.sync_raw_image_buffers = ui.checkBox_sync_raw_image_buffers->isChecked();
|
||||||
info.tessellation_enabled = ui.checkBox_tessellation->isChecked();
|
info.tessellation_enabled = ui.checkBox_tessellation->isChecked();
|
||||||
info.skip_notice_screen = ui.checkBox_skip_notice_screen->isChecked();
|
info.skip_notice_screen = ui.checkBox_skip_notice_screen->isChecked();
|
||||||
|
|||||||
@@ -279,6 +279,7 @@ static QStringList CreateEmulatorArgs(const Configuration& info) {
|
|||||||
AddFlag(args, info.hdr_enabled, "--hdr");
|
AddFlag(args, info.hdr_enabled, "--hdr");
|
||||||
AddFlag(args, info.hide_cursor_enabled, "--hide-cursor");
|
AddFlag(args, info.hide_cursor_enabled, "--hide-cursor");
|
||||||
AddFlag(args, info.readback_linear_images, "--readback-linear-images");
|
AddFlag(args, info.readback_linear_images, "--readback-linear-images");
|
||||||
|
AddFlag(args, info.readback_tiled_images, "--readback-tiled-images");
|
||||||
AddFlag(args, info.sync_raw_image_buffers, "--sync-raw-image-buffers");
|
AddFlag(args, info.sync_raw_image_buffers, "--sync-raw-image-buffers");
|
||||||
AddFlag(args, !info.trophy_enabled, "--no-trophy-notifications");
|
AddFlag(args, !info.trophy_enabled, "--no-trophy-notifications");
|
||||||
args << "--trophy-duration" << QString::number(info.trophy_duration_seconds);
|
args << "--trophy-duration" << QString::number(info.trophy_duration_seconds);
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ static void PrintUsage() {
|
|||||||
::printf(" --profile Enable the Tracy profiler.\n");
|
::printf(" --profile Enable the Tracy profiler.\n");
|
||||||
::printf(" --spirv-debug-printf Enable SPIR-V debug printf.\n");
|
::printf(" --spirv-debug-printf Enable SPIR-V debug printf.\n");
|
||||||
::printf(" --readback-linear-images Read back writable linear images on submit.\n");
|
::printf(" --readback-linear-images Read back writable linear images on submit.\n");
|
||||||
|
::printf(" --readback-tiled-images Read back small writable tiled images on submit.\n");
|
||||||
::printf(" --sync-raw-image-buffers Synchronize raw reads of GPU images.\n");
|
::printf(" --sync-raw-image-buffers Synchronize raw reads of GPU images.\n");
|
||||||
::printf(" --no-trophy-notifications Disable trophy unlock toasts and their sound.\n");
|
::printf(" --no-trophy-notifications Disable trophy unlock toasts and their sound.\n");
|
||||||
::printf(
|
::printf(
|
||||||
@@ -206,6 +207,7 @@ static constexpr Flag FLAGS[] = {
|
|||||||
{"--profile", &ConfigOptions::profiler_enabled},
|
{"--profile", &ConfigOptions::profiler_enabled},
|
||||||
{"--spirv-debug-printf", &ConfigOptions::spirv_debug_printf_enabled},
|
{"--spirv-debug-printf", &ConfigOptions::spirv_debug_printf_enabled},
|
||||||
{"--readback-linear-images", &ConfigOptions::readback_linear_images},
|
{"--readback-linear-images", &ConfigOptions::readback_linear_images},
|
||||||
|
{"--readback-tiled-images", &ConfigOptions::readback_tiled_images},
|
||||||
{"--sync-raw-image-buffers", &ConfigOptions::sync_raw_image_buffers},
|
{"--sync-raw-image-buffers", &ConfigOptions::sync_raw_image_buffers},
|
||||||
{"--no-trophy-notifications", &ConfigOptions::trophy_enabled, false},
|
{"--no-trophy-notifications", &ConfigOptions::trophy_enabled, false},
|
||||||
{"--perf-overlay", &ConfigOptions::perf_overlay_enabled},
|
{"--perf-overlay", &ConfigOptions::perf_overlay_enabled},
|
||||||
|
|||||||
Reference in New Issue
Block a user