mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 08:13:05 +00:00
shader: lower FMASK loads before binding images
This commit is contained in:
1 parent
cf0cbee02d
commit
ace877ce28
6 files changed
+200
-8
No files matched your search
@@ -825,6 +825,96 @@ void TestSampleAdjustSamplerScratch() {
|
||||
"SampleAdjust canonicalization discarded border-mode bits");
|
||||
}
|
||||
|
||||
void TestFmaskLoadSpecialization() {
|
||||
namespace Prospero = Libs::Graphics::Prospero;
|
||||
Fixture fixture;
|
||||
std::array<Value, 8> words;
|
||||
for (uint32_t i = 0; i < words.size(); i++) {
|
||||
words[i] = fixture.UserData(i);
|
||||
}
|
||||
const auto fmask = fixture.Image(words, 4);
|
||||
const auto active = fixture.Emit(ValueOpcode::IEqual32,
|
||||
{fixture.UserData(8), Value(0u)});
|
||||
MemoryInfo load;
|
||||
load.kind = ResourceKind::Image;
|
||||
load.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
load.image_address_components = 2;
|
||||
load.dmask = 1;
|
||||
const auto mapping = fixture.Emit(
|
||||
ValueOpcode::ImageRead, {fmask, fixture.ImageAddress(), active},
|
||||
fixture.AddMemory(load, 4));
|
||||
const auto ordinary = fixture.Image(
|
||||
{Value(0x2000u),
|
||||
Value(static_cast<uint32_t>(Prospero::BufferFormat::k8UInt) << 20u),
|
||||
Value(3u | (3u << 14u)),
|
||||
Value(Libs::Graphics::DstSel(4, 5, 6, 7) |
|
||||
(static_cast<uint32_t>(Prospero::ImageType::kColor2D) << 28u)),
|
||||
Value(0u), Value(0u), Value(0u), Value(0u)}, 8);
|
||||
const auto ordinary_flags = fixture.AddMemory(load, 8);
|
||||
const auto color = fixture.Emit(
|
||||
ValueOpcode::ImageRead, {ordinary, fixture.ImageAddress(), Value(true)},
|
||||
ordinary_flags);
|
||||
const auto output = fixture.Buffer(
|
||||
{Value(0x3000u), Value(0u), Value(12u), Value(0u)}, 12);
|
||||
MemoryInfo store;
|
||||
store.kind = ResourceKind::Buffer;
|
||||
Value result;
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
const auto value = fixture.Emit(
|
||||
ValueOpcode::CompositeExtractU32x4,
|
||||
{i == 0 ? mapping : color, Value(0u)});
|
||||
fixture.Emit(ValueOpcode::StoreBufferU32,
|
||||
{output, Value(0u), Value(i * 4u), Value(0u), value, Value(true)},
|
||||
fixture.AddMemory(store, 12 + i * 4u));
|
||||
if (i == 0) result = value;
|
||||
}
|
||||
fixture.PlanAndTrack();
|
||||
const auto plan = ExtractResourcePlan(fixture.program);
|
||||
std::array<uint32_t, 9> user_data{
|
||||
0x303ac300u, 0xca100000u, 0x021bc3bfu, 0x91800004u,
|
||||
0u, 0x00700000u, 0u, 0u};
|
||||
ResourceSnapshot snapshot;
|
||||
ResourceSpecialization specialization;
|
||||
Check(MaterializeResources(plan, {.user_data = user_data}, snapshot,
|
||||
specialization),
|
||||
"FMASK resources did not materialize");
|
||||
ApplyResourceSpecialization(fixture.program, specialization);
|
||||
RemoveIdentities(fixture.program.blocks);
|
||||
EliminateDeadCode(fixture.program.blocks);
|
||||
Check(fixture.program.info.images.size() == 1 && snapshot.images.size() == 1 &&
|
||||
snapshot.images[0].dwords[0] == 0x2000u &&
|
||||
ordinary.Instruction()->Flags<uint32_t>() == 0 &&
|
||||
fixture.program.memory_info[ordinary_flags.index].resource == 0,
|
||||
"FMASK removal did not preserve the remaining image and runtime descriptor");
|
||||
const auto *vector = result.Instruction()->Arg(0).Resolve().TryInstruction();
|
||||
Check(vector != nullptr &&
|
||||
vector->GetOpcode() == ValueOpcode::CompositeConstructU32x4,
|
||||
"FMASK load did not lower to a value vector");
|
||||
result = vector->Arg(0);
|
||||
uint32_t value = 0;
|
||||
Check(EvaluateUniformValues(plan, {&result, 1}, {.user_data = user_data}, {&value, 1}) &&
|
||||
value == 0x76543210u,
|
||||
"FMASK load did not return the native sample-to-fragment mapping");
|
||||
user_data[8] = 1;
|
||||
Check(EvaluateUniformValues(plan, {&result, 1}, {.user_data = user_data}, {&value, 1}) &&
|
||||
value == 0u,
|
||||
"inactive FMASK load did not preserve the execution mask");
|
||||
ShaderComputeInputInfo compute{};
|
||||
CollectShaderInfo(fixture.program, {.compute = &compute});
|
||||
AllocateBindings(fixture.program);
|
||||
const auto kind = DescriptorBindingForImage(fixture.program.info.images[0]);
|
||||
Check(kind.has_value() &&
|
||||
FindBinding(fixture.program.bindings, *kind)->resources ==
|
||||
std::vector<uint32_t>{0},
|
||||
"FMASK allocated an ordinary image descriptor");
|
||||
user_data[8] = 0;
|
||||
user_data[1] = static_cast<uint32_t>(Prospero::BufferFormat::k8UInt) << 20u;
|
||||
ResourceSpecialization rebound;
|
||||
Check(MaterializeResources(plan, {.user_data = user_data}, snapshot, rebound) &&
|
||||
rebound != specialization && snapshot.images.size() == 2,
|
||||
"rebinding FMASK as a texture reused the metadata specialization");
|
||||
}
|
||||
|
||||
void TestDynamicStorageMipTracking() {
|
||||
Fixture fixture;
|
||||
std::array<Value, 8> image_words;
|
||||
@@ -1760,6 +1850,7 @@ int main() {
|
||||
Run("runtime unsigned min", TestRuntimeUnsignedMinDescriptor);
|
||||
Run("images and samplers", TestImagesSamplersAndAliases);
|
||||
Run("SampleAdjust sampler scratch", TestSampleAdjustSamplerScratch);
|
||||
Run("FMASK load specialization", TestFmaskLoadSpecialization);
|
||||
Run("dynamic storage mips", TestDynamicStorageMipTracking);
|
||||
Run("invariant indirect images", TestInvariantIndirectImageMaterialization);
|
||||
Run("SRT runtime", TestSrtFlatteningAndRuntimeMemoization);
|
||||
|
||||
@@ -11597,8 +11597,7 @@ public:
|
||||
raw_format <= static_cast<uint32_t>(Prospero::BufferFormat::kBc7Srgb);
|
||||
++raw_format) {
|
||||
const auto format = static_cast<Prospero::BufferFormat>(raw_format);
|
||||
// FMASK is synthesized as identity metadata by TextureUploadFmask; it is
|
||||
// deliberately not a texel surface and must never enter the GPU tiler.
|
||||
// FMASK contains sample-to-fragment metadata, not texels for the GPU tiler.
|
||||
if (Prospero::IsFmaskTextureFormat(format)) {
|
||||
continue;
|
||||
}
|
||||
@@ -12729,10 +12728,10 @@ void CompareGraphicsWords(const GraphicsCase &test,
|
||||
|
||||
void RunCase(VulkanHarness *vulkan, const TestCase &test) {
|
||||
auto compiled = CompileCase(test, vulkan != nullptr ? vulkan->SubgroupSize() : 64u);
|
||||
if (test.image_descriptor_swizzle != DstSel(4, 5, 6, 7)) {
|
||||
if (test.image_descriptor_swizzle != DstSel(4, 5, 6, 7) &&
|
||||
!compiled.program.info.images.empty()) {
|
||||
Require(test.name, "resource specialization",
|
||||
!compiled.program.info.images.empty() &&
|
||||
compiled.program.info.images[0].shader_swizzle ==
|
||||
compiled.program.info.images[0].shader_swizzle ==
|
||||
test.image_descriptor_swizzle,
|
||||
"storage image descriptor swizzle did not reach the specialized "
|
||||
"program");
|
||||
@@ -21089,6 +21088,19 @@ TestCase ImageLoadR32UintUsesIntegerSampledImage() {
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase ImageLoadFmaskUsesNativeSampleMapping() {
|
||||
auto test = ImageLoadR32UintUsesIntegerSampledImage();
|
||||
test.name = "ImageLoadFmaskUsesNativeSampleMapping";
|
||||
test.expected = {0x76543210u};
|
||||
test.user_data = {0x303ac300u, 0xca100000u, 0x021bc3bfu, 0x91800004u,
|
||||
0u, 0x00700000u, 0u, 0u};
|
||||
test.image_descriptor_swizzle = DstSel(4, 0, 0, 0);
|
||||
test.sampled_image_rgba.clear();
|
||||
test.required_spirv = {"OpConstant %uint 1985229328"};
|
||||
test.forbidden_spirv = {"OpTypeImage", "OpImageFetch"};
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase ImageLoadR32SintUsesSignedSampledImage() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -22950,6 +22962,7 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(BufferAtomicFMaxContendedWorkgroup);
|
||||
AddCase(ImageLoadVariants);
|
||||
AddCase(ImageLoadR32UintUsesIntegerSampledImage);
|
||||
AddCase(ImageLoadFmaskUsesNativeSampleMapping);
|
||||
AddCase(ImageLoadR32SintUsesSignedSampledImage);
|
||||
AddCase(ImageLoadPackedUintUnpacksAndSwizzles);
|
||||
AddCase(ImageSamplePackedUintConvertsSampleAndGather);
|
||||
@@ -27251,6 +27264,12 @@ int main(int argc, char **argv) {
|
||||
std::setvbuf(stdout, nullptr, _IONBF, 0);
|
||||
EnsureConfigInitialized();
|
||||
CheckLeastRecentlyUsedCacheOrdering();
|
||||
if (argc == 2 && std::strcmp(argv[1], "--fmask-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, ImageLoadFmaskUsesNativeSampleMapping());
|
||||
RunCase(&vulkan, ImageLoadR32UintUsesIntegerSampledImage());
|
||||
return 0;
|
||||
}
|
||||
#if KYTY_PLATFORM != KYTY_PLATFORM_WINDOWS
|
||||
if (argc == 2 && std::strcmp(argv[1], "--shader-fatal-only") == 0) {
|
||||
CheckShaderRecompilerFatalContracts();
|
||||
|
||||
Reference in new issue
Block a user