mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
shader: validate indirect image operands at each typed access
This commit is contained in:
@@ -61,10 +61,10 @@ uint32_t AddressF32(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::
|
||||
: Unary(ctx.state, spv::OpBitcast, TypeF32(ctx.state), value);
|
||||
}
|
||||
|
||||
ImageSampleLayout Layout(const IR::MemoryInfo& mem) {
|
||||
ImageSampleLayout Layout(const IR::MemoryInfo& mem, ImageDimension dimension) {
|
||||
ImageSampleLayout layout;
|
||||
uint32_t cursor = 0;
|
||||
const auto& info = ImageDimensionInfoFor(mem.image_dimension);
|
||||
const auto& info = ImageDimensionInfoFor(dimension);
|
||||
if (HasFlag(mem, Decoder::ImageSampleFlagOffset)) layout.offset = cursor++;
|
||||
if (HasFlag(mem, Decoder::ImageSampleFlagBias)) layout.bias = cursor++;
|
||||
if (HasFlag(mem, Decoder::ImageSampleFlagCompare)) layout.dref = cursor++;
|
||||
@@ -80,6 +80,48 @@ ImageSampleLayout Layout(const IR::MemoryInfo& mem) {
|
||||
return layout;
|
||||
}
|
||||
|
||||
void ValidateIndirectImageOperands(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto op = inst.GetOpcode();
|
||||
const auto& memory = ctx.Memory(inst);
|
||||
const auto& images = ctx.state.program.info.images;
|
||||
const auto& root = images.at(memory.resource);
|
||||
if (root.indirect_root != memory.resource) return;
|
||||
if (op != IR::ValueOpcode::ImageSampleRaw &&
|
||||
op != IR::ValueOpcode::ImageGatherRaw && op != IR::ValueOpcode::ImageRead) {
|
||||
ctx.Fail(inst, "requires an unsupported indirect image operation");
|
||||
}
|
||||
const auto& native = ImageDimensionInfoFor(memory.image_dimension);
|
||||
const auto native_layout = Layout(memory, memory.image_dimension);
|
||||
const bool sampling = op == IR::ValueOpcode::ImageSampleRaw ||
|
||||
op == IR::ValueOpcode::ImageGatherRaw;
|
||||
const auto validate = [&](const IR::ImageResource& image) {
|
||||
const auto& candidate = ImageDimensionInfoFor(image.dimension);
|
||||
// Sample/fetch ignore the native array slice for a non-array T# while
|
||||
// keeping the original positions of later operands.
|
||||
const bool projected_2d = memory.image_dimension == ImageDimension::Dim2DArray &&
|
||||
image.dimension == ImageDimension::Dim2D;
|
||||
bool compatible = projected_2d ||
|
||||
(candidate.coordinate_components == native.coordinate_components &&
|
||||
candidate.multisampled == native.multisampled);
|
||||
if (sampling) {
|
||||
compatible &= candidate.multisampled == 0u && native.multisampled == 0u;
|
||||
compatible &= projected_2d || Layout(memory, image.dimension) == native_layout;
|
||||
if (HasFlag(memory, Decoder::ImageSampleFlagDerivative)) {
|
||||
compatible &= candidate.spatial_components == native.spatial_components;
|
||||
}
|
||||
if (op == IR::ValueOpcode::ImageGatherRaw ||
|
||||
HasFlag(memory, Decoder::ImageSampleFlagCompare)) {
|
||||
compatible &= image.dimension != ImageDimension::Dim3D;
|
||||
}
|
||||
}
|
||||
if (!compatible) ctx.Fail(inst, "has incompatible image operand layout");
|
||||
};
|
||||
validate(root);
|
||||
for (const auto resource: root.indirect_resources) {
|
||||
if (resource != memory.resource) validate(images.at(resource));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t ZeroF32(EmitterState& state) {
|
||||
return ConstantF32(state, 0);
|
||||
}
|
||||
@@ -736,6 +778,7 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
const auto& mem = ctx.Memory(inst);
|
||||
const auto image_arg = inst.Arg(0);
|
||||
ctx.ResourceIndex(image_arg, IR::ValueOpcode::GetImageResource);
|
||||
ValidateIndirectImageOperands(ctx, inst);
|
||||
const auto& image = state.program.info.images.at(mem.resource);
|
||||
const auto* address = ctx.ImageAddress(inst.Arg(image_info.needs_sampler ? 2 : 1));
|
||||
if (op == IR::ValueOpcode::ImageQueryDimensions) {
|
||||
@@ -817,7 +860,7 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
||||
if (op == IR::ValueOpcode::ImageSampleRaw || op == IR::ValueOpcode::ImageGatherRaw) {
|
||||
const auto dimension = image.dimension;
|
||||
const auto& dimension_info = ImageDimensionInfoFor(dimension);
|
||||
const auto layout = Layout(mem);
|
||||
const auto layout = Layout(mem, mem.image_dimension);
|
||||
const auto numeric_class = image.numeric_class;
|
||||
const bool dref = HasFlag(mem, Decoder::ImageSampleFlagCompare);
|
||||
IR::Value offset_value;
|
||||
|
||||
@@ -272,6 +272,8 @@ struct ImageSampleLayout {
|
||||
uint32_t lod = NoImageComponent;
|
||||
uint32_t grad_x = NoImageComponent;
|
||||
uint32_t grad_y = NoImageComponent;
|
||||
|
||||
bool operator==(const ImageSampleLayout&) const = default;
|
||||
};
|
||||
|
||||
struct F32Class {
|
||||
|
||||
@@ -621,10 +621,6 @@ 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 is_2d = [](Decoder::ImageDimension dimension) {
|
||||
return dimension == Decoder::ImageDimension::Dim2D ||
|
||||
dimension == Decoder::ImageDimension::Dim2DArray;
|
||||
};
|
||||
for (uint32_t candidate = 0; candidate < specialization.images.size(); candidate++) {
|
||||
auto& image = specialization.images[candidate];
|
||||
if (image.indirect_root != root_index) {
|
||||
@@ -638,10 +634,7 @@ static bool BuildResourceSpecialization(const ResourcePlan& program, ResourceSna
|
||||
image.shader_swizzle = image_class.shader_swizzle;
|
||||
image.cube = image_class.cube;
|
||||
}
|
||||
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))) ||
|
||||
image.mip_count != image_class.mip_count ||
|
||||
if (image.mip_count != image_class.mip_count ||
|
||||
image.conversion_format != image_class.conversion_format ||
|
||||
image.shader_swizzle != image_class.shader_swizzle) {
|
||||
return SpecializationFail(
|
||||
@@ -1414,10 +1407,6 @@ void ApplyResourceSpecialization(Program& program, const ResourceSpecialization&
|
||||
memory.sampler = sampler_plan.mapping[memory.sampler][type];
|
||||
EXIT_IF(memory.sampler == UINT32_MAX);
|
||||
}
|
||||
EXIT_IF(image.indirect_root == memory.resource &&
|
||||
inst.GetOpcode() != ValueOpcode::ImageSampleRaw &&
|
||||
inst.GetOpcode() != ValueOpcode::ImageGatherRaw &&
|
||||
inst.GetOpcode() != ValueOpcode::ImageRead);
|
||||
}
|
||||
}
|
||||
for (auto& memory: memory_info) {
|
||||
|
||||
Reference in New Issue
Block a user