mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-18 23:07:07 -05:00
Merge pull request #6486 from karanvora2599/perf/agc-stage-swept-raw-buffers
perf(agc): stage raw buffer elements a dispatch sweeps
This commit is contained in:
9 files changed
+41
-18
No files matched your search
@@ -1264,6 +1264,12 @@ if(BUILD_TESTING)
|
||||
set_tests_properties(agc_storage_baseline_settled PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test(NAME agc_read_written_staging COMMAND agc_driver_recorder_tests --read-written-staging-only)
|
||||
set_tests_properties(agc_read_written_staging PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 30)
|
||||
if(WIN32)
|
||||
set_tests_properties(agc_read_written_staging PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
|
||||
endif()
|
||||
add_test(NAME agc_storage_written_buffer_order COMMAND agc_driver_recorder_tests --written-buffer-order-only)
|
||||
set_tests_properties(agc_storage_written_buffer_order PROPERTIES SKIP_RETURN_CODE 77 TIMEOUT 30)
|
||||
if(WIN32)
|
||||
|
||||
@@ -422,7 +422,7 @@ private:
|
||||
// `written` is the element's DescriptorBinding::bufferWritten: a read-only element binds the
|
||||
// same way but is left out of the write set (no write-back, no pending-write note). `atomic`
|
||||
// is its bufferAtomic (see GuestBufferMemory::AddWritable).
|
||||
std::size_t addGuestBuffer(std::span<const std::uint32_t> words, const ColorTarget* target, std::uint64_t indexAddress, std::size_t indexBytes, bool written, bool atomic, bool read);
|
||||
std::size_t addGuestBuffer(std::span<const std::uint32_t> words, const ColorTarget* target, std::uint64_t indexAddress, std::size_t indexBytes, bool written, bool atomic, bool read, std::uint32_t extent);
|
||||
std::uint64_t guestBufferBytes(std::span<const std::uint32_t> words) const;
|
||||
std::size_t addDataBuffer(std::span<const std::uint32_t> words);
|
||||
// Stage A: the layout entry of an image binding (samplers are taken at once, the sampler cache
|
||||
|
||||
@@ -1832,7 +1832,8 @@ void ShaderResources::buildPrepare(std::span<const CompiledShader> shaders, cons
|
||||
const bool written = element >= binding.bufferWritten.size() || binding.bufferWritten[element];
|
||||
const bool atomic = element < binding.bufferAtomic.size() && binding.bufferAtomic[element];
|
||||
const bool read = element < binding.bufferRead.size() && binding.bufferRead[element];
|
||||
const auto index = addGuestBuffer(std::span<const std::uint32_t>(binding.guestDescriptor).subspan(static_cast<std::size_t>(element) * 4, 4), target, indexAddress, indexBytes, written, atomic, read);
|
||||
const std::uint32_t extent = element < binding.bufferExtent.size() ? binding.bufferExtent[element] : 0u;
|
||||
const auto index = addGuestBuffer(std::span<const std::uint32_t>(binding.guestDescriptor).subspan(static_cast<std::size_t>(element) * 4, 4), target, indexAddress, indexBytes, written, atomic, read, extent);
|
||||
const auto& push = shader.program->pushConstants;
|
||||
if (!push.empty()) {
|
||||
const auto position = shader.program->memoryOffsetDword * 4u + element;
|
||||
@@ -3962,7 +3963,7 @@ std::uint64_t ShaderResources::guestBufferBytes(std::span<const std::uint32_t> w
|
||||
return byteSize;
|
||||
}
|
||||
|
||||
std::size_t ShaderResources::addGuestBuffer(std::span<const std::uint32_t> words, const ColorTarget* target, std::uint64_t indexAddress, std::size_t indexBytes, bool written, bool atomic, bool read) {
|
||||
std::size_t ShaderResources::addGuestBuffer(std::span<const std::uint32_t> words, const ColorTarget* target, std::uint64_t indexAddress, std::size_t indexBytes, bool written, bool atomic, bool read, std::uint32_t extent) {
|
||||
Require(words.size() == 4, "buffer descriptor must contain four DWORDs");
|
||||
const ShaderRecompiler::ShaderBufferResource descriptor{{words[0], words[1] & ~0x40000000u, words[2], words[3]}};
|
||||
Require(descriptor.Type() == 0u, "buffer descriptor uses an unsupported type");
|
||||
@@ -3980,7 +3981,8 @@ std::size_t ShaderResources::addGuestBuffer(std::span<const std::uint32_t> words
|
||||
static const bool allWritten = std::getenv("APS5_ALL_BUFFERS_WRITTEN") != nullptr;
|
||||
Require(!written || !overlap(address, size, indexAddress, indexBytes), "writable shader buffer aliases the index buffer");
|
||||
written = written || allWritten;
|
||||
const bool swept = read && dispatchThreads != 0 && descriptor.Stride() != 0 && dispatchThreads * descriptor.Stride() * 2u >= byteSize;
|
||||
const std::uint64_t recordBytes = descriptor.Stride() != 0 ? descriptor.Stride() : extent;
|
||||
const bool swept = read && dispatchThreads != 0 && recordBytes != 0 && dispatchThreads * recordBytes * 2u >= byteSize;
|
||||
if (written) guestMemory.AddWritable(address, size, atomic, swept);
|
||||
else {
|
||||
guestMemory.AddReadable(address, size);
|
||||
|
||||
@@ -2593,11 +2593,11 @@ void resourceReadTests(const Device& device, Recorder& recorder) {
|
||||
HostImportFor(context, address, bytes);
|
||||
}
|
||||
|
||||
void readWrittenStagingTests(const Device& device, Recorder& recorder) {
|
||||
bool readWrittenStagingTests(const Device& device, Recorder& recorder) {
|
||||
const auto& context = device.GetContext();
|
||||
if (context.hostImportAlignment == 0) {
|
||||
std::cout << "host imports unavailable: read and written staging not tested\n";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
constexpr std::size_t bytes = 8u << 20u;
|
||||
#ifdef _WIN32
|
||||
@@ -2614,7 +2614,7 @@ void readWrittenStagingTests(const Device& device, Recorder& recorder) {
|
||||
}
|
||||
if (HostImportFor(context, address, bytes) == nullptr) {
|
||||
std::cout << "host import of the test block refused: read and written staging not tested\n";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
const auto boundInPlace = [&](std::uint64_t element, std::size_t elementBytes, bool read) {
|
||||
GuestBufferMemory memory(context);
|
||||
@@ -2631,10 +2631,10 @@ void readWrittenStagingTests(const Device& device, Recorder& recorder) {
|
||||
Require(!boundInPlace(address + 4096, 1u << 20u, false), "a written 1 MiB element was not staged");
|
||||
Require(boundInPlace(address + 4096, 4u << 20u, false), "a written-only 4 MiB element was staged past the written window");
|
||||
Require(!boundInPlace(address + 4096, 4u << 20u, true), "a read and written 4 MiB element was bound in place");
|
||||
const auto buildInPlace = [&](std::uint64_t dispatchThreads, bool read) {
|
||||
const auto buildInPlace = [&](std::uint64_t dispatchThreads, bool read, std::uint32_t stride, std::uint32_t extent) {
|
||||
const auto element = address + 4096;
|
||||
constexpr std::uint32_t stride = 16;
|
||||
constexpr std::uint32_t records = (4u << 20u) / stride;
|
||||
constexpr std::uint32_t elementBytes = 4u << 20u;
|
||||
const std::uint32_t records = stride != 0 ? elementBytes / stride : elementBytes;
|
||||
ShaderRecompiler::RecompileResult program;
|
||||
ShaderRecompiler::DescriptorBinding binding;
|
||||
binding.kind = ShaderRecompiler::DescriptorKind::StorageBuffer;
|
||||
@@ -2645,25 +2645,30 @@ void readWrittenStagingTests(const Device& device, Recorder& recorder) {
|
||||
binding.guestDescriptor = {static_cast<std::uint32_t>(element), (static_cast<std::uint32_t>(element >> 32u) & 0xffffu) | (stride << 16u), records, 0x31000000u};
|
||||
binding.bufferWritten = {true};
|
||||
binding.bufferRead = {read};
|
||||
binding.bufferExtent = {extent};
|
||||
program.bindings.push_back(binding);
|
||||
const CompiledShader compute{ShaderRecompiler::ShaderStage::Compute, &program, 0};
|
||||
ShaderResources resources(context, compute, {}, false, dispatchThreads);
|
||||
const auto reads = resources.InPlaceReads();
|
||||
const bool direct = std::any_of(reads.begin(), reads.end(), [&](const auto& range) { return range.first <= element && range.second >= element + records * stride; });
|
||||
const bool direct = std::any_of(reads.begin(), reads.end(), [&](const auto& range) { return range.first <= element && range.second >= element + elementBytes; });
|
||||
resources.MarkGpuWrites(recorder);
|
||||
recorder.Sync();
|
||||
return direct;
|
||||
};
|
||||
Require(!buildInPlace((4u << 20u) / 16u, true), "a dispatch sweeping a read and written 4 MiB element bound it in place");
|
||||
Require(buildInPlace(1024, true), "a dispatch touching 16 KiB of a read and written 4 MiB element staged all of it");
|
||||
Require(buildInPlace(0, true), "a dispatch of unknown size staged a read and written 4 MiB element");
|
||||
Require(buildInPlace((4u << 20u) / 16u, false), "a dispatch sweeping a written-only 4 MiB element staged it");
|
||||
Require(!buildInPlace((4u << 20u) / 16u, true, 16, 0), "a dispatch sweeping a read and written 4 MiB element bound it in place");
|
||||
Require(buildInPlace(1024, true, 16, 0), "a dispatch touching 16 KiB of a read and written 4 MiB element staged all of it");
|
||||
Require(buildInPlace(0, true, 16, 0), "a dispatch of unknown size staged a read and written 4 MiB element");
|
||||
Require(buildInPlace((4u << 20u) / 16u, false, 16, 0), "a dispatch sweeping a written-only 4 MiB element staged it");
|
||||
Require(!buildInPlace((4u << 20u) / 32u, true, 0, 32), "a dispatch sweeping a read and written 4 MiB raw element bound it in place");
|
||||
Require(buildInPlace(1024, true, 0, 32), "a dispatch touching 32 KiB of a read and written 4 MiB raw element staged all of it");
|
||||
Require(buildInPlace((4u << 20u) / 32u, true, 0, 0), "a raw element without an access extent was staged");
|
||||
Require(std::all_of(static_cast<const std::byte*>(block), static_cast<const std::byte*>(block) + bytes, [](std::byte value) { return value == std::byte{0x11}; }), "a staged copy-back changed the guest bytes");
|
||||
{
|
||||
GuestAllocations::Mutation mutation;
|
||||
mutation.Remove(block);
|
||||
}
|
||||
HostImportFor(context, address, bytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sparseRunImportTests(const Device& device, bool copied) {
|
||||
@@ -9086,6 +9091,11 @@ int main(int argc, char** argv) {
|
||||
std::cout << "Completion label storage and ordering tests passed\n";
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::string_view(argv[1]) == "--read-written-staging-only") {
|
||||
if (!readWrittenStagingTests(device, recorder)) return 77;
|
||||
std::cout << "read and written staging tests passed\n";
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::string_view(argv[1]) == "--written-buffer-order-only") {
|
||||
if (!writtenBufferOrderTests(device, recorder)) return 77;
|
||||
std::cout << "written buffer order tests passed\n";
|
||||
|
||||
@@ -84,7 +84,7 @@ void removeCacheDirectory(const std::filesystem::path& directory) {
|
||||
}
|
||||
|
||||
bool sameBinding(const DescriptorBinding& left, const DescriptorBinding& right) {
|
||||
return left.kind == right.kind && left.role == right.role && left.descriptorSet == right.descriptorSet && left.binding == right.binding && left.count == right.count && left.guestDescriptor == right.guestDescriptor && left.readOnly == right.readOnly && left.imageShape == right.imageShape && left.samplerDepthCompare == right.samplerDepthCompare && left.imageWritten == right.imageWritten && left.imageDepthCompare == right.imageDepthCompare && left.imageAtomic == right.imageAtomic && left.imageShapes == right.imageShapes && left.bufferAtomic == right.bufferAtomic && left.bufferWritten == right.bufferWritten && left.bufferRead == right.bufferRead && left.samplerUnnormalized == right.samplerUnnormalized && left.samplerIntegerBorder == right.samplerIntegerBorder && left.samplerCoordinatesIgnored == right.samplerCoordinatesIgnored && left.imageUnnormalized == right.imageUnnormalized && left.imageUnnormalizedBaseLevel == right.imageUnnormalizedBaseLevel && left.imageSamplers == right.imageSamplers;
|
||||
return left.kind == right.kind && left.role == right.role && left.descriptorSet == right.descriptorSet && left.binding == right.binding && left.count == right.count && left.guestDescriptor == right.guestDescriptor && left.readOnly == right.readOnly && left.imageShape == right.imageShape && left.samplerDepthCompare == right.samplerDepthCompare && left.imageWritten == right.imageWritten && left.imageDepthCompare == right.imageDepthCompare && left.imageAtomic == right.imageAtomic && left.imageShapes == right.imageShapes && left.bufferAtomic == right.bufferAtomic && left.bufferWritten == right.bufferWritten && left.bufferRead == right.bufferRead && left.bufferExtent == right.bufferExtent && left.samplerUnnormalized == right.samplerUnnormalized && left.samplerIntegerBorder == right.samplerIntegerBorder && left.samplerCoordinatesIgnored == right.samplerCoordinatesIgnored && left.imageUnnormalized == right.imageUnnormalized && left.imageUnnormalizedBaseLevel == right.imageUnnormalizedBaseLevel && left.imageSamplers == right.imageSamplers;
|
||||
}
|
||||
|
||||
bool sameBindings(const std::vector<DescriptorBinding>& left, const std::vector<DescriptorBinding>& right) {
|
||||
@@ -181,6 +181,7 @@ DescriptorBinding sampleBinding(std::uint32_t seed) {
|
||||
binding.imageUnnormalizedBaseLevel = {false, true, seed % 3 == 0};
|
||||
binding.imageSamplers = {0x5u, 0u, 0x80000000u};
|
||||
binding.bufferRead = {true, false, false, true, true, false};
|
||||
binding.bufferExtent = {32, 0, 16, 4096, 8, 0};
|
||||
return binding;
|
||||
}
|
||||
|
||||
|
||||
@@ -435,6 +435,7 @@ DescriptorBindingPlan DescriptorBindingBuilder::Prepare(const IrBindingLayout& l
|
||||
physical.bufferAtomic.push_back(buffer.atomic);
|
||||
physical.bufferWritten.push_back(buffer.written || buffer.atomic);
|
||||
physical.bufferRead.push_back(buffer.read);
|
||||
physical.bufferExtent.push_back(buffer.maxByteExtent);
|
||||
if (buffer.written || buffer.atomic) ++entry.writtenBuffers;
|
||||
else ++entry.readOnlyBuffers;
|
||||
}
|
||||
|
||||
@@ -450,6 +450,7 @@ struct DescriptorBinding {
|
||||
std::vector<bool> imageUnnormalizedBaseLevel;
|
||||
std::vector<std::uint32_t> imageSamplers;
|
||||
std::vector<bool> bufferRead;
|
||||
std::vector<std::uint32_t> bufferExtent;
|
||||
};
|
||||
|
||||
struct ImageTableEntryPoison {
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace ShaderRecompiler::ShaderDiskCache {
|
||||
static_assert(sizeof(CompiledShaderArtifact) == 240, "CompiledShaderArtifact changed: update the artifact encoder");
|
||||
static_assert(sizeof(ShaderInvocation) == 200, "ShaderInvocation changed: update the invocation encoder");
|
||||
static_assert(sizeof(RecompileResult) == 472, "RecompileResult changed: update EncodeResult and DecodeResult");
|
||||
static_assert(sizeof(DescriptorBinding) == 632, "DescriptorBinding changed: update the binding encoder");
|
||||
static_assert(sizeof(DescriptorBinding) == 656, "DescriptorBinding changed: update the binding encoder");
|
||||
static_assert(sizeof(VertexAttribute) == 32, "VertexAttribute changed: update the attribute encoder");
|
||||
static_assert(sizeof(VertexInput) == 16, "VertexInput changed: update the vertex input encoder");
|
||||
static_assert(sizeof(FragmentParameter) == 16, "FragmentParameter changed: update the parameter encoder");
|
||||
@@ -430,6 +430,7 @@ void encodeBinding(Writer& writer, const DescriptorBinding& binding) {
|
||||
writer.Flags(binding.samplerCoordinatesIgnored);
|
||||
writer.Values(std::span<const std::uint32_t>(binding.imageSamplers));
|
||||
writer.Flags(binding.bufferRead);
|
||||
writer.Values(std::span<const std::uint32_t>(binding.bufferExtent));
|
||||
}
|
||||
|
||||
void decodeBinding(Reader& reader, DescriptorBinding& binding) {
|
||||
@@ -458,6 +459,7 @@ void decodeBinding(Reader& reader, DescriptorBinding& binding) {
|
||||
reader.Flags(binding.samplerCoordinatesIgnored);
|
||||
reader.Values(binding.imageSamplers);
|
||||
reader.Flags(binding.bufferRead);
|
||||
reader.Values(binding.bufferExtent);
|
||||
}
|
||||
|
||||
void encodeArtifact(Writer& writer, const CompiledShaderArtifact& result) {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
namespace ShaderRecompiler::ShaderDiskCache {
|
||||
|
||||
inline constexpr std::uint32_t FormatVersion = 39;
|
||||
inline constexpr std::uint32_t FormatVersion = 40;
|
||||
|
||||
enum class LoadStatus {
|
||||
Loaded,
|
||||
|
||||
Reference in new issue
Block a user