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

View File

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

View File

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

View File

@ -8,6 +8,7 @@
#include <coroutine> #include <coroutine>
#include <exception> #include <exception>
#include <mutex> #include <mutex>
#include <semaphore>
#include <span> #include <span>
#include <thread> #include <thread>
#include <vector> #include <vector>
@ -1512,11 +1513,29 @@ public:
rasterizer = rasterizer_; rasterizer = rasterizer_;
} }
void SendCommand(Common::UniqueFunction<void>&& func) { template <bool wait_done = false>
std::scoped_lock lk{submit_mutex}; void SendCommand(auto&& func) {
command_queue.emplace(std::move(func)); if (std::this_thread::get_id() == gpu_id) {
++num_commands; return func();
submit_cv.notify_one(); }
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() { void ReserveCopyBufferSpace() {
@ -1542,7 +1561,6 @@ public:
u32 tmp_dwords; u32 tmp_dwords;
}; };
Common::SlotVector<AscQueueInfo> asc_queues{}; Common::SlotVector<AscQueueInfo> asc_queues{};
std::thread::id gpu_id;
private: private:
struct Task { struct Task {
@ -1628,6 +1646,7 @@ private:
std::mutex submit_mutex; std::mutex submit_mutex;
std::condition_variable_any submit_cv; std::condition_variable_any submit_cv;
std::queue<Common::UniqueFunction<void>> command_queue{}; std::queue<Common::UniqueFunction<void>> command_queue{};
std::thread::id gpu_id;
int curr_qid{-1}; int curr_qid{-1};
}; };

View File

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

View File

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

View File

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