gpu: preserve finite buffer descriptors across sparse PRT holes

This commit is contained in:
nmzik
2026-10-19 05:26:41 +02:00
parent 5f29374d5b
commit e5f0ee7fc2
2 changed files with 47 additions and 1 deletions
@@ -764,7 +764,10 @@ void RenderExecutor::FindBuffers(std::span<PreparedBindings* const> stages) {
size = std::min({size, uint64_t {256} * 1024 * 1024, limit});
}
}
size = Libs::LibKernel::Memory::ClampRangeSize(address, size);
// Finite GPU descriptors can span sparse PRT holes; clamp only oversized/sentinel ranges.
if (size >= (uint64_t {1} << 30u) || descriptor.NumRecords() == UINT32_MAX) {
size = Libs::LibKernel::Memory::ClampRangeSize(address, size);
}
source = {address, size, cache.FindBuffer(address, size)};
}
}
+43
View File
@@ -13474,6 +13474,49 @@ public:
return program;
};
{
constexpr uint64_t page = 0x10000;
constexpr uint64_t address = base - page;
constexpr u32 resident_value = 0x13572468u;
void *reservation = reinterpret_cast<void *>(address);
Require(name, "sparse descriptor reservation",
LibKernel::Memory::KernelReserveVirtualRange(&reservation, page, 0x10, page) == 0,
"leading sparse page reservation failed");
resources.MapMemory(address, page);
LibKernel::Memory::WriteBacking(base, &resident_value, sizeof(resident_value));
const auto program = make_buffer_program(ShaderType::Compute, {.read = true});
ShaderRecompiler::IR::ResourceSnapshot snapshot;
auto &value = snapshot.buffers.emplace_back();
value.dword_count = 4;
value.dwords = {static_cast<u32>(address), static_cast<u32>(address >> 32), 2u * page};
ShaderStageRuntime runtime{&program, &snapshot};
PreparedBindings bindings;
executor.PrepareBindings(runtime, bindings);
std::array<PreparedBindings *, 1> stages{&bindings};
executor.FindBuffers(stages);
executor.RebindBuffers(bindings);
const auto &source = bindings.buffer_sources[0];
const auto &owner = resources.GetBufferCache().GetBuffer(source.id);
Require(name, "finite sparse descriptor extent",
source.address == address && source.size == 2u * page &&
bindings.buffers[0].range == 2u * page,
"finite descriptor lost its leading hole or resident tail");
auto output = CreateHostBuffer(name, 2u * sizeof(u32), vk::BufferUsageFlagBits::eTransferDst, {});
const std::array<vk::BufferCopy, 2> copies{{
{owner.Offset(address), 0, sizeof(u32)},
{owner.Offset(base), sizeof(u32), sizeof(u32)}}};
scheduler.Current().Handle().copyBuffer(owner.Handle(), output.buffer, copies.size(), copies.data());
scheduler.Finish();
Require(name, "finite sparse descriptor upload",
ReadBuffer(name, output, 2) == std::vector<u32>{0u, resident_value},
"sparse descriptor upload lost zero-filled holes or resident bytes");
DestroyBuffer(&output);
resources.UnmapMemory(address, page);
Require(name, "sparse descriptor reservation release",
LibKernel::Memory::KernelMunmap(address, page) == 0,
"leading sparse page reservation release failed");
}
{
const auto buffer_program = make_buffer_program(ShaderType::Compute, {.read = true});