config: Add readbacks config option

This commit is contained in:
IndecisiveTurtle 2025-07-01 15:20:24 +03:00
parent 0b410a16ad
commit 53519aa8ca
7 changed files with 47 additions and 37 deletions

View File

@ -51,6 +51,7 @@ static bool isShowSplash = false;
static std::string isSideTrophy = "right";
static bool isNullGpu = false;
static bool shouldCopyGPUBuffers = false;
static bool readbacksEnabled = false;
static bool shouldDumpShaders = false;
static bool shouldPatchShaders = true;
static u32 vblankDivider = 1;
@ -240,6 +241,10 @@ bool copyGPUCmdBuffers() {
return shouldCopyGPUBuffers;
}
bool readbacks() {
return readbacksEnabled;
}
bool dumpShaders() {
return shouldDumpShaders;
}
@ -344,6 +349,10 @@ void setCopyGPUCmdBuffers(bool enable) {
shouldCopyGPUBuffers = enable;
}
void setReadbacks(bool enable) {
readbacksEnabled = enable;
}
void setDumpShaders(bool enable) {
shouldDumpShaders = enable;
}
@ -586,6 +595,7 @@ void load(const std::filesystem::path& path) {
screenHeight = toml::find_or<int>(gpu, "screenHeight", screenHeight);
isNullGpu = toml::find_or<bool>(gpu, "nullGpu", false);
shouldCopyGPUBuffers = toml::find_or<bool>(gpu, "copyGPUBuffers", false);
readbacksEnabled = toml::find_or<bool>(gpu, "readbacks", false);
shouldDumpShaders = toml::find_or<bool>(gpu, "dumpShaders", false);
shouldPatchShaders = toml::find_or<bool>(gpu, "patchShaders", true);
vblankDivider = toml::find_or<int>(gpu, "vblankDivider", 1);
@ -735,6 +745,7 @@ void save(const std::filesystem::path& path) {
data["GPU"]["screenHeight"] = screenHeight;
data["GPU"]["nullGpu"] = isNullGpu;
data["GPU"]["copyGPUBuffers"] = shouldCopyGPUBuffers;
data["GPU"]["readbacks"] = readbacksEnabled;
data["GPU"]["dumpShaders"] = shouldDumpShaders;
data["GPU"]["patchShaders"] = shouldPatchShaders;
data["GPU"]["vblankDivider"] = vblankDivider;

View File

@ -45,6 +45,8 @@ bool nullGpu();
void setNullGpu(bool enable);
bool copyGPUCmdBuffers();
void setCopyGPUCmdBuffers(bool enable);
bool readbacks();
void setReadbacks(bool enable);
bool dumpShaders();
void setDumpShaders(bool enable);
u32 vblankDiv();

View File

@ -77,7 +77,7 @@ void Liverpool::ProcessCommands() {
while (num_commands) {
Common::UniqueFunction<void> callback{};
{
std::unique_lock lk{submit_mutex};
std::scoped_lock lk{submit_mutex};
callback = std::move(command_queue.front());
command_queue.pop();
--num_commands;

View File

@ -8,6 +8,7 @@
#include <coroutine>
#include <exception>
#include <mutex>
#include <semaphore>
#include <span>
#include <thread>
#include <vector>
@ -1512,12 +1513,30 @@ public:
rasterizer = rasterizer_;
}
void SendCommand(Common::UniqueFunction<void>&& func) {
template <bool wait_done = false>
void SendCommand(auto&& func) {
if (std::this_thread::get_id() == gpu_id) {
return func();
}
if constexpr (wait_done) {
std::binary_semaphore sem{0};
{
std::scoped_lock lk{submit_mutex};
command_queue.emplace([&sem, &func] {
func();
sem.release();
});
++num_commands;
submit_cv.notify_one();
}
sem.acquire();
} else {
std::scoped_lock lk{submit_mutex};
command_queue.emplace(std::move(func));
++num_commands;
submit_cv.notify_one();
}
}
void ReserveCopyBufferSpace() {
GpuQueue& gfx_queue = mapped_queues[GfxQueueId];
@ -1542,7 +1561,6 @@ public:
u32 tmp_dwords;
};
Common::SlotVector<AscQueueInfo> asc_queues{};
std::thread::id gpu_id;
private:
struct Task {
@ -1628,6 +1646,7 @@ private:
std::mutex submit_mutex;
std::condition_variable_any submit_cv;
std::queue<Common::UniqueFunction<void>> command_queue{};
std::thread::id gpu_id;
int curr_qid{-1};
};

View File

@ -2,8 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <semaphore>
#include "common/alignment.h"
#include "common/config.h"
#include "common/debug.h"
#include "common/scope_exit.h"
#include "common/types.h"
@ -136,25 +136,17 @@ void BufferCache::InvalidateMemory(VAddr device_addr, u64 size) {
if (!IsRegionRegistered(device_addr, size)) {
return;
}
if (memory_tracker->IsRegionGpuModified(device_addr, size)) {
if (Config::readbacks() && memory_tracker->IsRegionGpuModified(device_addr, size)) {
ReadMemory(device_addr, size);
}
memory_tracker->MarkRegionAsCpuModified(device_addr, size);
}
void BufferCache::ReadMemory(VAddr device_addr, u64 size) {
if (std::this_thread::get_id() != liverpool->gpu_id) {
std::binary_semaphore command_wait{0};
liverpool->SendCommand([this, &command_wait, device_addr, size] {
liverpool->SendCommand<true>([this, device_addr, size] {
Buffer& buffer = slot_buffers[FindBuffer(device_addr, size)];
DownloadBufferMemory(buffer, device_addr, size);
command_wait.release();
});
command_wait.acquire();
} else {
Buffer& buffer = slot_buffers[FindBuffer(device_addr, size)];
DownloadBufferMemory(buffer, device_addr, size);
}
}
void BufferCache::DownloadBufferMemory(Buffer& buffer, VAddr device_addr, u64 size) {

View File

@ -3,7 +3,6 @@
#pragma once
#include <array>
#include "common/bit_array.h"
#include "common/types.h"
@ -20,7 +19,6 @@ constexpr u64 NUM_PAGES_PER_REGION = TRACKER_HIGHER_PAGE_SIZE / TRACKER_BYTES_PE
enum class Type {
CPU,
GPU,
Writeable,
};
using RegionBits = Common::BitArray<NUM_PAGES_PER_REGION>;

View File

@ -4,6 +4,7 @@
#pragma once
#include <mutex>
#include "common/config.h"
#include "common/div_ceil.h"
#ifdef __linux__
@ -47,29 +48,19 @@ public:
template <Type type>
RegionBits& GetRegionBits() noexcept {
static_assert(type != Type::Writeable);
if constexpr (type == Type::CPU) {
return cpu;
} else if constexpr (type == Type::GPU) {
return gpu;
} else if constexpr (type == Type::Writeable) {
return writeable;
} else {
static_assert(false, "Invalid type");
}
}
template <Type type>
const RegionBits& GetRegionBits() const noexcept {
static_assert(type != Type::Writeable);
if constexpr (type == Type::CPU) {
return cpu;
} else if constexpr (type == Type::GPU) {
return gpu;
} else if constexpr (type == Type::Writeable) {
return writeable;
} else {
static_assert(false, "Invalid type");
}
}
@ -90,7 +81,6 @@ public:
return;
}
std::scoped_lock lk{lock};
static_assert(type != Type::Writeable);
RegionBits& bits = GetRegionBits<type>();
if constexpr (enable) {
@ -100,7 +90,7 @@ public:
}
if constexpr (type == Type::CPU) {
UpdateProtection<!enable, false>();
} else {
} else if (Config::readbacks()) {
UpdateProtection<enable, true>();
}
}
@ -124,7 +114,6 @@ public:
return;
}
std::scoped_lock lk{lock};
static_assert(type != Type::Writeable);
RegionBits& bits = GetRegionBits<type>();
RegionBits mask(bits, start_page, end_page);
@ -137,7 +126,7 @@ public:
bits.UnsetRange(start_page, end_page);
if constexpr (type == Type::CPU) {
UpdateProtection<true, false>();
} else {
} else if (Config::readbacks()) {
UpdateProtection<false, true>();
}
}
@ -159,7 +148,6 @@ public:
return false;
}
std::scoped_lock lk{lock};
static_assert(type != Type::Writeable);
const RegionBits& bits = GetRegionBits<type>();
RegionBits test(bits, start_page, end_page);