mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 19:36:55 +02:00
graphics: do not arm a fast clear from a read-modify-write dispatch (#428)
* graphics: do not arm a fast clear from a read-modify-write dispatch * tests: cover compute metadata clear classification --------- Co-authored-by: nmzik <Nmzik@mail.ru>
This commit is contained in:
@@ -574,6 +574,8 @@ if(BUILD_TESTING)
|
|||||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --storage-sampled-only)
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --storage-sampled-only)
|
||||||
add_test(NAME texture_cache_depth_readback
|
add_test(NAME texture_cache_depth_readback
|
||||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --depth-readback-only)
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --depth-readback-only)
|
||||||
|
add_test(NAME compute_meta_clear_classification
|
||||||
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --compute-meta-clear-only)
|
||||||
add_test(NAME buffer_cache_dirty_gc
|
add_test(NAME buffer_cache_dirty_gc
|
||||||
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --buffer-cache-gc-only)
|
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --buffer-cache-gc-only)
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ bool RenderExecutor::TryConsumeComputeMetaClear(const ShaderComputeInputInfo& in
|
|||||||
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
|
for (uint32_t i = 0; i < program.info.buffers.size(); i++) {
|
||||||
const auto& resource = program.info.buffers[i];
|
const auto& resource = program.info.buffers[i];
|
||||||
const auto descriptor = DecodeNativeDescriptor<ShaderBufferResource>(resources.buffers[i]);
|
const auto descriptor = DecodeNativeDescriptor<ShaderBufferResource>(resources.buffers[i]);
|
||||||
if (!resource.written && cache.IsMeta(descriptor.Base48())) {
|
// A metadata resource that is also read is not proven to be a full overwrite. Execute it
|
||||||
|
// conservatively instead of replacing the dispatch with a coarse full-surface clear.
|
||||||
|
if (cache.IsMeta(descriptor.Base48()) && (!resource.written || resource.read)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -357,10 +357,23 @@ struct TextureCacheTestAccess {
|
|||||||
return cache.TryDownloadImage(id);
|
return cache.TryDownloadImage(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RegisterHtileMeta(TextureCache &cache, uint64_t address) {
|
||||||
|
std::lock_guard lock(cache.m_lock);
|
||||||
|
auto &metadata = cache.m_surface_metas[address];
|
||||||
|
metadata.type = TextureCache::MetaDataInfo::Type::HTile;
|
||||||
|
metadata.clear_mask = 0;
|
||||||
|
}
|
||||||
|
|
||||||
static TileManager &Tiler(TextureCache &cache) { return cache.m_tiler; }
|
static TileManager &Tiler(TextureCache &cache) { return cache.m_tiler; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RenderExecutorTestAccess {
|
struct RenderExecutorTestAccess {
|
||||||
|
static bool TryConsumeComputeMetaClear(RenderExecutor &executor,
|
||||||
|
const ShaderComputeInputInfo &input,
|
||||||
|
const CommandBuffer &buffer) {
|
||||||
|
return executor.TryConsumeComputeMetaClear(input, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
static TextureBinding
|
static TextureBinding
|
||||||
ResolveTexture(RenderExecutor &executor,
|
ResolveTexture(RenderExecutor &executor,
|
||||||
const ShaderRecompiler::IR::ImageResource &resource,
|
const ShaderRecompiler::IR::ImageResource &resource,
|
||||||
@@ -3778,6 +3791,92 @@ public:
|
|||||||
std::printf("[host] %-32s ok\n", name);
|
std::printf("[host] %-32s ok\n", name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CheckComputeMetaClearClassification() {
|
||||||
|
constexpr const char *name = "ComputeMetaClearClassification";
|
||||||
|
constexpr uint64_t read_only_meta = 0x0000000204201f00ull;
|
||||||
|
constexpr uint64_t read_write_meta = 0x0000000204202000ull;
|
||||||
|
constexpr uint64_t write_only_meta = 0x0000000204202100ull;
|
||||||
|
EnsureRuntimeContext();
|
||||||
|
RenderContext context(m_runtime_context);
|
||||||
|
auto &scheduler = context.GetCommandScheduler();
|
||||||
|
HW::Context registers{};
|
||||||
|
HW::UserConfig user_config{};
|
||||||
|
HW::Shader shaders{};
|
||||||
|
scheduler.Begin(registers, user_config, shaders);
|
||||||
|
auto &texture_cache = context.GetTextureCache();
|
||||||
|
TextureCacheTestAccess::RegisterHtileMeta(texture_cache, read_only_meta);
|
||||||
|
TextureCacheTestAccess::RegisterHtileMeta(texture_cache, read_write_meta);
|
||||||
|
TextureCacheTestAccess::RegisterHtileMeta(texture_cache, write_only_meta);
|
||||||
|
Require(name, "HTile fixture",
|
||||||
|
texture_cache.IsMeta(read_only_meta) &&
|
||||||
|
texture_cache.IsMeta(read_write_meta) &&
|
||||||
|
texture_cache.IsMeta(write_only_meta) &&
|
||||||
|
!texture_cache.IsMetaCleared(read_only_meta, 0) &&
|
||||||
|
!texture_cache.IsMetaCleared(read_write_meta, 0) &&
|
||||||
|
!texture_cache.IsMetaCleared(write_only_meta, 0),
|
||||||
|
"test HTile entries were not registered in their initial state");
|
||||||
|
|
||||||
|
const auto MakeInput = [](uint64_t address, bool read, bool written) {
|
||||||
|
auto program = std::make_shared<ShaderRecompiler::IR::Program>();
|
||||||
|
program->stage = ShaderType::Compute;
|
||||||
|
ShaderRecompiler::IR::BufferResource resource{};
|
||||||
|
resource.read = read;
|
||||||
|
resource.written = written;
|
||||||
|
resource.formatted = true;
|
||||||
|
program->info.buffers.push_back(resource);
|
||||||
|
|
||||||
|
ShaderBufferResource descriptor{};
|
||||||
|
descriptor.UpdateAddress48(address);
|
||||||
|
descriptor.fields[1] |= 16u << 16u;
|
||||||
|
descriptor.fields[2] = 8;
|
||||||
|
descriptor.fields[3] =
|
||||||
|
DstSel(4, 5, 6, 7) |
|
||||||
|
(static_cast<uint32_t>(Prospero::BufferFormat::k32_32_32_32UInt)
|
||||||
|
<< 12u);
|
||||||
|
ShaderRecompiler::IR::DescriptorValue value{};
|
||||||
|
value.dword_count = 4;
|
||||||
|
std::copy_n(descriptor.fields, value.dword_count, value.dwords.begin());
|
||||||
|
auto snapshot =
|
||||||
|
std::make_shared<ShaderRecompiler::IR::ResourceSnapshot>();
|
||||||
|
snapshot->buffers.push_back(value);
|
||||||
|
|
||||||
|
ShaderComputeInputInfo input{};
|
||||||
|
input.stage.program = std::move(program);
|
||||||
|
input.stage.resources = std::move(snapshot);
|
||||||
|
return input;
|
||||||
|
};
|
||||||
|
auto &executor = context.GetRenderExecutor();
|
||||||
|
auto &command = scheduler.Current();
|
||||||
|
const auto read_only_input = MakeInput(read_only_meta, true, false);
|
||||||
|
const bool read_only_consumed =
|
||||||
|
RenderExecutorTestAccess::TryConsumeComputeMetaClear(
|
||||||
|
executor, read_only_input, command);
|
||||||
|
Require(name, "read-only dispatch preserved",
|
||||||
|
!read_only_consumed &&
|
||||||
|
!texture_cache.IsMetaCleared(read_only_meta, 0),
|
||||||
|
"a metadata read-only dispatch changed logical clear state");
|
||||||
|
|
||||||
|
const auto read_write_input = MakeInput(read_write_meta, true, true);
|
||||||
|
const bool read_write_consumed =
|
||||||
|
RenderExecutorTestAccess::TryConsumeComputeMetaClear(
|
||||||
|
executor, read_write_input, command);
|
||||||
|
Require(name, "read/write dispatch preserved",
|
||||||
|
!read_write_consumed &&
|
||||||
|
!texture_cache.IsMetaCleared(read_write_meta, 0),
|
||||||
|
"a metadata read/modify/write dispatch was replaced by a clear");
|
||||||
|
|
||||||
|
const auto write_only_input = MakeInput(write_only_meta, false, true);
|
||||||
|
const bool write_only_consumed =
|
||||||
|
RenderExecutorTestAccess::TryConsumeComputeMetaClear(
|
||||||
|
executor, write_only_input, command);
|
||||||
|
Require(name, "write-only fill consumed",
|
||||||
|
write_only_consumed &&
|
||||||
|
texture_cache.IsMetaCleared(write_only_meta, 0),
|
||||||
|
"a metadata write-only fill was not consumed as a clear");
|
||||||
|
scheduler.Finish();
|
||||||
|
std::printf("[host] %-32s ok\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
void CheckUnifiedTextureCacheFlow() {
|
void CheckUnifiedTextureCacheFlow() {
|
||||||
constexpr const char *name = "UnifiedTextureCacheFlow";
|
constexpr const char *name = "UnifiedTextureCacheFlow";
|
||||||
constexpr uintptr_t base = 0x0000000200600000ull;
|
constexpr uintptr_t base = 0x0000000200600000ull;
|
||||||
@@ -25443,6 +25542,11 @@ int main(int argc, char **argv) {
|
|||||||
vulkan.CheckUnifiedTextureCacheFlow();
|
vulkan.CheckUnifiedTextureCacheFlow();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (argc == 2 && std::strcmp(argv[1], "--compute-meta-clear-only") == 0) {
|
||||||
|
VulkanHarness vulkan;
|
||||||
|
vulkan.CheckComputeMetaClearClassification();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--layered-image-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--layered-image-only") == 0) {
|
||||||
VulkanHarness vulkan;
|
VulkanHarness vulkan;
|
||||||
vulkan.CheckUnifiedImageViewCache();
|
vulkan.CheckUnifiedImageViewCache();
|
||||||
|
|||||||
Reference in New Issue
Block a user