mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-27 16:02:37 +00:00
gpu: write end-of-pipe labels beside GPU-written bytes to the backing store
This commit is contained in:
1 parent
556538bed5
commit
2463e3aaf0
2 files changed
+70
-2
No files matched your search
@@ -976,16 +976,28 @@ void CommandProcessor::ReleaseMem(uint32_t data_sel, uint32_t interrupt_selector
|
|||||||
// Dumped occlusion counters are written before any end-of-pipe signal reaches the guest.
|
// Dumped occlusion counters are written before any end-of-pipe signal reaches the guest.
|
||||||
m_renderer.GetOcclusionQueries().Publish();
|
m_renderer.GetOcclusionQueries().Publish();
|
||||||
|
|
||||||
|
// A label beside GPU-written bytes goes to the backing store, so they are not downloaded.
|
||||||
|
// Other labels go through the guest mapping: its fault keeps a clean cached copy current and
|
||||||
|
// downloads GPU-written bytes under the label before the store.
|
||||||
|
const auto write_label = [this, address](const void* value, uint64_t size) {
|
||||||
|
const auto vaddr = reinterpret_cast<uint64_t>(address);
|
||||||
|
auto& buffers = m_renderer.GetBufferCache();
|
||||||
|
if (!GuestRange {vaddr, size}.Valid() || !buffers.IsRegionGpuModified(vaddr, size) ||
|
||||||
|
buffers.HasGpuDirtyBytes(vaddr, size) ||
|
||||||
|
!LibKernel::Memory::TryWriteBacking(vaddr, value, size)) {
|
||||||
|
std::memcpy(address, value, size);
|
||||||
|
}
|
||||||
|
};
|
||||||
// EndOfPipeData: kNone, kImmediate32b, kImmediate64b, kRefClk; 5 reads GDS.
|
// EndOfPipeData: kNone, kImmediate32b, kImmediate64b, kRefClk; 5 reads GDS.
|
||||||
switch (data_sel) {
|
switch (data_sel) {
|
||||||
case 0: break;
|
case 0: break;
|
||||||
case 1: {
|
case 1: {
|
||||||
const auto value = static_cast<uint32_t>(data);
|
const auto value = static_cast<uint32_t>(data);
|
||||||
std::memcpy(address, &value, sizeof(value));
|
write_label(&value, sizeof(value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 3: data = Sync::ReadReferenceClock(); [[fallthrough]];
|
case 3: data = Sync::ReadReferenceClock(); [[fallthrough]];
|
||||||
case 2: std::memcpy(address, &data, sizeof(data)); break;
|
case 2: write_label(&data, sizeof(data)); break;
|
||||||
case 5: {
|
case 5: {
|
||||||
GetScheduler().Finish();
|
GetScheduler().Finish();
|
||||||
const auto gds = static_cast<uint32_t>(data);
|
const auto gds = static_cast<uint32_t>(data);
|
||||||
|
|||||||
@@ -3942,6 +3942,62 @@ public:
|
|||||||
"write invalidation without a remaining copy did not establish CPU "
|
"write invalidation without a remaining copy did not establish CPU "
|
||||||
"ownership");
|
"ownership");
|
||||||
|
|
||||||
|
// A RELEASE_MEM label beside GPU-written bytes lands without downloading
|
||||||
|
// them; one over GPU-written bytes downloads them first, and one on a clean
|
||||||
|
// cached page leaves it CPU-modified for the next upload.
|
||||||
|
constexpr uint64_t label_gpu_address = fault_base + 0xf000;
|
||||||
|
constexpr uint64_t label_beside_address = fault_base + 0xf100;
|
||||||
|
constexpr uint64_t label_clean_address = memory_dst + 0x100;
|
||||||
|
constexpr uint32_t label_gpu_value = 0x7e57ab1eu;
|
||||||
|
constexpr uint64_t label_value = 0x0123456789abcdefull;
|
||||||
|
gpu.SendCommandSync([&] {
|
||||||
|
auto dirty = buffer_cache.ObtainBuffer(
|
||||||
|
label_gpu_address, sizeof(label_gpu_value), true, false);
|
||||||
|
Require("GpuCommandLane", "label page setup",
|
||||||
|
dirty.first != nullptr &&
|
||||||
|
buffer_cache.IsRegionRegistered(label_clean_address,
|
||||||
|
sizeof(label_value)) &&
|
||||||
|
!buffer_cache.IsRegionCpuModified(label_clean_address,
|
||||||
|
sizeof(label_value)) &&
|
||||||
|
!buffer_cache.IsRegionGpuModified(label_clean_address,
|
||||||
|
sizeof(label_value)),
|
||||||
|
"label test has no GPU-written page or clean cached page");
|
||||||
|
buffer_cache.FillBuffer(label_gpu_address, sizeof(label_gpu_value),
|
||||||
|
label_gpu_value, false);
|
||||||
|
});
|
||||||
|
const auto release_label = [&](uint64_t address) {
|
||||||
|
const auto packet = make_interrupt_packet(
|
||||||
|
2, 0, reinterpret_cast<void *>(address), label_value, 0);
|
||||||
|
gpu.Submit(packet);
|
||||||
|
gpu.WaitForIdle();
|
||||||
|
uint64_t label = 0;
|
||||||
|
return LibKernel::Memory::TryReadBacking(address, &label,
|
||||||
|
sizeof(label)) &&
|
||||||
|
label == label_value;
|
||||||
|
};
|
||||||
|
LibKernel::Memory::InstallGpuResources(&resources);
|
||||||
|
const bool label_beside_stored =
|
||||||
|
release_label(label_beside_address) &&
|
||||||
|
buffer_cache.HasGpuDirtyBytes(label_gpu_address,
|
||||||
|
sizeof(label_gpu_value));
|
||||||
|
const bool label_over_stored =
|
||||||
|
release_label(label_gpu_address) &&
|
||||||
|
!buffer_cache.HasGpuDirtyBytes(label_gpu_address, sizeof(label_value));
|
||||||
|
const bool label_clean_stored =
|
||||||
|
release_label(label_clean_address) &&
|
||||||
|
buffer_cache.IsRegionCpuModified(label_clean_address,
|
||||||
|
sizeof(label_value));
|
||||||
|
LibKernel::Memory::InstallGpuResources(nullptr);
|
||||||
|
Require("GpuCommandLane", "RELEASE_MEM label beside GPU-written bytes",
|
||||||
|
label_beside_stored,
|
||||||
|
"a label downloaded the GPU-written bytes beside it");
|
||||||
|
Require("GpuCommandLane", "RELEASE_MEM label over GPU-written bytes",
|
||||||
|
label_over_stored,
|
||||||
|
"a label over GPU-written bytes left them to a later download");
|
||||||
|
Require("GpuCommandLane", "RELEASE_MEM label on a clean cached page",
|
||||||
|
label_clean_stored,
|
||||||
|
"a label left a clean cached copy of its page stale");
|
||||||
|
|
||||||
resources.UnmapMemory(fault_base, fault_size);
|
resources.UnmapMemory(fault_base, fault_size);
|
||||||
Require("GpuCommandLane", "processor fault unmap",
|
Require("GpuCommandLane", "processor fault unmap",
|
||||||
Libs::LibKernel::Memory::KernelMunmap(fault_base, fault_size) == 0,
|
Libs::LibKernel::Memory::KernelMunmap(fault_base, fault_size) == 0,
|
||||||
|
|||||||
Reference in new issue
Block a user