shader: preserve typed candidates for unfiltered indirect image access

Co-authored-by: fxpw <fxpw@outlook.com>
This commit is contained in:
nmzik
2026-10-14 18:57:26 +02:00
parent 127cf8d46f
commit b6da068313
6 changed files with 249 additions and 65 deletions
@@ -712,6 +712,8 @@ auto EmitImageAccess(ValueEmitContext& ctx, const IR::Inst& inst, uint32_t resul
const auto next_slot = run.slot_bias + ordinal;
if (candidate.dimension == first.dimension && candidate.cube == first.cube &&
IR::DescriptorBindingForImage(first) == kind &&
(inst.GetOpcode() != IR::ValueOpcode::ImageWrite ||
candidate.shader_swizzle == first.shader_swizzle) &&
candidate.mip_count == 1u && first.mip_count == 1u &&
(ordinal == 1u || candidate.descriptor_index == next_slot)) {
// Native roots precede appended children; only the root may have a slot gap.
@@ -158,6 +158,7 @@ struct ImageResource {
bool written = false;
bool atomic = false;
bool atomic64 = false;
bool unfiltered_access_only = true;
bool depth_compare = false;
bool cube = false;
bool r128 = false;
@@ -829,10 +829,17 @@ static bool BuildResourceSpecialization(const ResourcePlan& program, ResourceSna
return SpecializationFail("indirect image specialization has no typed candidate");
}
const auto& image_class = specialization.images[exemplar];
const auto& base = program.info.images[root_index];
const bool storage_swizzle = base.unfiltered_access_only &&
base.resource_class == ImageResourceClass::Storage;
const auto is_2d = [](Decoder::ImageDimension dimension) {
return dimension == Decoder::ImageDimension::Dim2D ||
dimension == Decoder::ImageDimension::Dim2DArray;
};
const auto is_1d_or_2d = [](Decoder::ImageDimension dimension) {
return dimension == Decoder::ImageDimension::Dim1D ||
dimension == Decoder::ImageDimension::Dim2D;
};
for (uint32_t candidate = 0; candidate < specialization.images.size(); candidate++) {
auto& image = specialization.images[candidate];
if (image.indirect_root != root_index) {
@@ -848,10 +855,15 @@ static bool BuildResourceSpecialization(const ResourcePlan& program, ResourceSna
}
const bool same_coordinates = image.dimension == image_class.dimension &&
image.cube == image_class.cube;
if ((!same_coordinates && !(is_2d(image.dimension) && is_2d(image_class.dimension))) ||
const bool unfiltered_coordinates = base.unfiltered_access_only &&
base.dimension == Decoder::ImageDimension::Dim2D &&
!image.cube && !image_class.cube && is_1d_or_2d(image.dimension) &&
is_1d_or_2d(image_class.dimension);
if ((!same_coordinates && !(is_2d(image.dimension) && is_2d(image_class.dimension)) &&
!unfiltered_coordinates) ||
image.mip_count != image_class.mip_count ||
image.conversion_format != image_class.conversion_format ||
image.shader_swizzle != image_class.shader_swizzle) {
(!storage_swizzle && image.shader_swizzle != image_class.shader_swizzle)) {
return SpecializationFail(
fmt::format("indirect image table at pc 0x{:08x} has incompatible candidates",
program.info.images[root_index].first_use_pc));
@@ -1708,7 +1720,8 @@ void ApplyResourceSpecialization(Program& program, const ResourceSpecialization&
EXIT_IF(image.indirect_root == memory.resource &&
inst.GetOpcode() != ValueOpcode::ImageSampleRaw &&
inst.GetOpcode() != ValueOpcode::ImageGatherRaw &&
inst.GetOpcode() != ValueOpcode::ImageRead);
inst.GetOpcode() != ValueOpcode::ImageRead &&
inst.GetOpcode() != ValueOpcode::ImageWrite);
}
}
for (auto& memory: memory_info) {
@@ -3495,6 +3495,7 @@ private:
image.read = image.read || !write || atomic;
image.written = image.written || write;
image.atomic = image.atomic || atomic;
image.unfiltered_access_only &= op == ValueOpcode::ImageRead || op == ValueOpcode::ImageWrite;
}
uint32_t AddSampler(uint32_t source, uint32_t pc) {