shader: emit native texel offsets using sample execution context
Co-authored-by: netwarex <mail@pety.me>
This commit is contained in:
parent
df0412afb5
commit
984cfcebd1
|
|
@ -323,25 +323,25 @@ uint32_t QueryDimensions(ValueEmitContext& ctx, const IR::MemoryInfo& mem,
|
|||
return vector;
|
||||
}
|
||||
|
||||
uint32_t PackedOffset(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR::Inst& address,
|
||||
const ImageSampleLayout& layout, ImageDimension dimension) {
|
||||
uint32_t PackedOffset(ValueEmitContext& ctx, IR::Value value, ImageDimension dimension,
|
||||
uint32_t& mask) {
|
||||
const auto components = ImageDimensionInfoFor(dimension).spatial_components;
|
||||
const auto zero = ConstantI32(ctx.state, 0);
|
||||
if (layout.offset == NoImageComponent || mem.image_address_components <= layout.offset) {
|
||||
if (components == 1u) return zero;
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
if (components == 3u) {
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 3),
|
||||
result, zero, zero, zero);
|
||||
} else {
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 2),
|
||||
result, zero, zero);
|
||||
uint32_t values[3] {};
|
||||
if (value.IsImmediate()) {
|
||||
// RDNA2 packs signed six-bit texel offsets into the low bits of each byte.
|
||||
for (uint32_t index = 0; index < components; index++) {
|
||||
const auto bits = (value.U32() >> (index * 8u)) & 0x3fu;
|
||||
values[index] = ConstantI32(ctx.state, static_cast<int32_t>(bits ^ 0x20u) - 0x20);
|
||||
}
|
||||
return result;
|
||||
mask |= spv::ImageOperandsConstOffsetMask;
|
||||
return components == 1u
|
||||
? values[0]
|
||||
: ctx.state.builder.Constant(spv::OpConstantComposite,
|
||||
TypeI32Vector(ctx.state, components),
|
||||
std::span(values).first(components));
|
||||
}
|
||||
const auto packed = Unary(ctx.state, spv::OpBitcast, TypeI32(ctx.state),
|
||||
AddressU32(ctx, mem, address, layout.offset));
|
||||
uint32_t values[3] = {zero, zero, zero};
|
||||
mask |= spv::ImageOperandsOffsetMask;
|
||||
const auto packed = Unary(ctx.state, spv::OpBitcast, TypeI32(ctx.state), ctx.Def(value));
|
||||
for (uint32_t index = 0; index < components; index++) {
|
||||
values[index] = ctx.state.builder.AllocateId();
|
||||
ctx.state.builder.AddFunction(spv::OpBitFieldSExtract, TypeI32(ctx.state), values[index],
|
||||
|
|
@ -350,13 +350,8 @@ uint32_t PackedOffset(ValueEmitContext& ctx, const IR::MemoryInfo& mem, const IR
|
|||
}
|
||||
if (components == 1u) return values[0];
|
||||
const auto result = ctx.state.builder.AllocateId();
|
||||
if (components == 3u) {
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 3),
|
||||
result, values[0], values[1], values[2]);
|
||||
} else {
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeI32Vector(ctx.state, 2),
|
||||
result, values[0], values[1]);
|
||||
}
|
||||
ctx.state.builder.AddFunction(spv::OpCompositeConstruct, TypeI32Vector(ctx.state, components),
|
||||
result, std::span(values).first(components));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -794,6 +789,12 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||
const auto layout = Layout(mem);
|
||||
const auto numeric_class = image.numeric_class;
|
||||
const bool dref = HasFlag(mem, Decoder::ImageSampleFlagCompare);
|
||||
IR::Value offset_value;
|
||||
if (layout.offset != NoImageComponent) {
|
||||
const auto value = address->Arg(layout.offset).Resolve();
|
||||
offset_value = IR::ResolveActiveU32(value, inst.Arg(inst.NumArgs() - 1u).Resolve());
|
||||
if (offset_value.IsEmpty()) offset_value = value;
|
||||
}
|
||||
if (dref && state.program.info.images[mem.resource].conversion_format !=
|
||||
Prospero::BufferFormat::kInvalid) {
|
||||
ctx.Fail(inst, "uses depth comparison with a converted image");
|
||||
|
|
@ -843,8 +844,7 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||
operand_mask = spv::ImageOperandsConstOffsetsMask;
|
||||
offset = HorizontalOffsets(state, dimension);
|
||||
} else if (layout.offset != NoImageComponent) {
|
||||
operand_mask = spv::ImageOperandsOffsetMask;
|
||||
offset = PackedOffset(ctx, mem, *address, layout, dimension);
|
||||
offset = PackedOffset(ctx, offset_value, dimension, operand_mask);
|
||||
}
|
||||
const auto EmitMip = [&](uint32_t mip) {
|
||||
const auto sampled = MakeSampledImage(state, resource, sampler_id, mip, array_index);
|
||||
|
|
@ -886,7 +886,7 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||
dref_value = AddressF32(ctx, mem, *address, layout.dref);
|
||||
}
|
||||
}
|
||||
std::array<uint32_t, 3> operands {};
|
||||
std::array<uint32_t, 4> operands {};
|
||||
size_t operand_count = 0;
|
||||
if (HasFlag(mem, Decoder::ImageSampleFlagDerivative)) {
|
||||
operands[0] = spv::ImageOperandsGradMask;
|
||||
|
|
@ -916,9 +916,20 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||
state, ctx.Def(handle->Arg(0)), static_cast<uint32_t>(samplers.size()),
|
||||
TypeU32(state), [&](uint32_t ordinal) { return ConstantU32(state, samplers[ordinal]); });
|
||||
}
|
||||
if (layout.offset != NoImageComponent &&
|
||||
!offset_value.IsImmediate()) {
|
||||
ctx.Fail(inst, "has a nonconstant sample texel offset");
|
||||
}
|
||||
const auto sampler_id = LoadSamplerDescriptor(state, mem.sampler, sampler_index);
|
||||
const auto EmitSample = [&](uint32_t resource, uint32_t array_index) {
|
||||
const auto& candidate = state.program.info.images[resource];
|
||||
auto sample_operands = operands;
|
||||
auto sample_operand_count = operand_count;
|
||||
if (layout.offset != NoImageComponent) {
|
||||
sample_operand_count = std::max(size_t{1}, sample_operand_count);
|
||||
sample_operands[sample_operand_count++] = PackedOffset(
|
||||
ctx, offset_value, candidate.dimension, sample_operands[0]);
|
||||
}
|
||||
const auto coord =
|
||||
CoordF32(ctx, mem, *address, layout.coord,
|
||||
ImageDimensionInfoFor(candidate.dimension).coordinate_components,
|
||||
|
|
@ -928,7 +939,7 @@ void EmitImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||
const auto sample = state.builder.AllocateId();
|
||||
state.builder.AddFunction(opcode, result_type, sample, sampled, coord,
|
||||
std::span(&dref_value, dref ? 1u : 0u),
|
||||
std::span<const uint32_t>(operands).first(operand_count));
|
||||
std::span<const uint32_t>(sample_operands).first(sample_operand_count));
|
||||
return sample;
|
||||
};
|
||||
auto result = EmitImageAccess(ctx, inst, result_type, EmitSample);
|
||||
|
|
|
|||
|
|
@ -687,7 +687,8 @@ void Translator::IMAGE_SAMPLE(const Decoder::Instruction& inst) {
|
|||
const auto resource = GetImageResource(memory);
|
||||
const auto sampler = GetSamplerResource(memory);
|
||||
const auto address = MakeImageAddress(inst, MemorySourceAt(inst, 0));
|
||||
const auto result = ir.Emit(IR::ValueOpcode::ImageSampleRaw, {resource, sampler, address},
|
||||
const auto result = ir.Emit(IR::ValueOpcode::ImageSampleRaw,
|
||||
{resource, sampler, address, ir.GetExec()},
|
||||
AddMemoryInfo(memory, inst.pc));
|
||||
const bool dref = (memory.image_sample_flags & Decoder::ImageSampleFlagCompare) != 0u;
|
||||
if (dref && memory.data_bits != 16u) {
|
||||
|
|
@ -714,7 +715,7 @@ void Translator::IMAGE_GATHER(const Decoder::Instruction& inst) {
|
|||
has_lod ? resource.Instruction()->Arg(1) : IR::Value(0u),
|
||||
has_lod ? resource.Instruction()->Arg(3) : IR::Value(0u),
|
||||
has_lod ? sampler.Instruction()->Arg(1) : IR::Value(0u),
|
||||
has_lod ? sampler.Instruction()->Arg(2) : IR::Value(0u)},
|
||||
has_lod ? sampler.Instruction()->Arg(2) : IR::Value(0u), ir.GetExec()},
|
||||
AddMemoryInfo(memory, inst.pc));
|
||||
for (uint32_t index = 0; index < memory.data_dwords; index++) {
|
||||
WriteOperand(OffsetOperand(inst.dst, index),
|
||||
|
|
|
|||
|
|
@ -317,8 +317,8 @@ VALUE_OPCODE(BvhIntersect, U32x4, U32x4, ImageAddress, U1)
|
|||
VALUE_OPCODE(ImageQueryLod, U32x4, ImageResource, SamplerResource, ImageAddress)
|
||||
VALUE_OPCODE(ImageRead, U32x4, ImageResource, ImageAddress, U1)
|
||||
VALUE_OPCODE(ImageWrite, Void, ImageResource, ImageAddress, U32x4, U1)
|
||||
VALUE_OPCODE(ImageSampleRaw, U32x4, ImageResource, SamplerResource, ImageAddress)
|
||||
VALUE_OPCODE(ImageGatherRaw, U32x4, ImageResource, SamplerResource, ImageAddress, U32, U32, U32, U32)
|
||||
VALUE_OPCODE(ImageSampleRaw, U32x4, ImageResource, SamplerResource, ImageAddress, U1)
|
||||
VALUE_OPCODE(ImageGatherRaw, U32x4, ImageResource, SamplerResource, ImageAddress, U32, U32, U32, U32, U1)
|
||||
VALUE_OPCODE(ImageAtomicCompareSwap32, U32, ImageResource, ImageAddress, U32, U32, U1)
|
||||
VALUE_OPCODE(ImageAtomicSwap32, U32, ImageResource, ImageAddress, U32, U1)
|
||||
VALUE_OPCODE(ImageAtomicSwap64, U64, ImageResource, ImageAddress, U64, U1)
|
||||
|
|
|
|||
|
|
@ -270,7 +270,7 @@ MakeIndirectImageFixture(bool malformed, uint32_t table_stride = 32, uint32_t ta
|
|||
sample.kind = ResourceKind::Image;
|
||||
sample.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
const auto sampled = fixture->Emit(ValueOpcode::ImageSampleRaw,
|
||||
{image, sampler, fixture->ImageAddress()},
|
||||
{image, sampler, fixture->ImageAddress(), Value(true)},
|
||||
fixture->AddMemory(sample, 0x10f0));
|
||||
const auto sampled_x =
|
||||
fixture->Emit(ValueOpcode::CompositeExtractU32x4, {sampled, Value(0u)});
|
||||
|
|
@ -486,7 +486,8 @@ void TestWaterfallImageTable() {
|
|||
memory.kind = ResourceKind::Image;
|
||||
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
const auto value = fixture->Emit(ValueOpcode::ImageSampleRaw,
|
||||
{image, sampler, fixture->ImageAddress()}, fixture->AddMemory(memory, 0x92cu), block);
|
||||
{image, sampler, fixture->ImageAddress(), block == entry ? active : guard},
|
||||
fixture->AddMemory(memory, 0x92cu), block);
|
||||
fixture->Emit(ValueOpcode::ReferenceU32,
|
||||
{fixture->Emit(ValueOpcode::CompositeExtractU32x4, {value, Value(0u)}, 0, block)}, 0, block);
|
||||
};
|
||||
|
|
@ -641,7 +642,7 @@ void TestGuardedDirectImageTable() {
|
|||
MemoryInfo memory;
|
||||
memory.kind = ResourceKind::Image;
|
||||
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress()},
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress(), Value(true)},
|
||||
fixture.AddMemory(memory, 0x128));
|
||||
fixture.PlanAndTrack();
|
||||
const auto source = fixture.program.info.images[0].source;
|
||||
|
|
@ -989,7 +990,7 @@ void TestBoundedComputeImageLoop() {
|
|||
sample.kind = ResourceKind::Image;
|
||||
sample.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw,
|
||||
{image, sampler, fixture.ImageAddress()},
|
||||
{image, sampler, fixture.ImageAddress(), Value(true)},
|
||||
fixture.AddMemory(sample, 0x29c));
|
||||
fixture.PlanAndTrack();
|
||||
const auto source = fixture.program.info.images[0].source;
|
||||
|
|
@ -1325,7 +1326,9 @@ void TestUniformizedMaterialImageKeys() {
|
|||
MemoryInfo image_memory;
|
||||
image_memory.kind = ResourceKind::Image;
|
||||
image_memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
const auto sampled = fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, address},
|
||||
const auto sampled = fixture.Emit(ValueOpcode::ImageSampleRaw,
|
||||
{image, sampler, address,
|
||||
variant == Variant::EmptyFirstEntry ? material_guard : sample_guard},
|
||||
fixture.AddMemory(image_memory, 0x1aecu), sample);
|
||||
if (first_lane) {
|
||||
const auto component = fixture.Emit(
|
||||
|
|
@ -1477,7 +1480,7 @@ void TestImageDescriptorFields() {
|
|||
memory.kind = ResourceKind::Image;
|
||||
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
memory.image_r128 = r128;
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress()},
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress(), Value(true)},
|
||||
fixture.AddMemory(memory, 0x80));
|
||||
fixture.PlanAndTrack();
|
||||
auto plan = ExtractResourcePlan(fixture.program);
|
||||
|
|
@ -1571,7 +1574,7 @@ void TestUniformScalarBufferImage() {
|
|||
sample.kind = ResourceKind::Image;
|
||||
sample.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw,
|
||||
{image, sampler, fixture.ImageAddress()}, fixture.AddMemory(sample, 0x228));
|
||||
{image, sampler, fixture.ImageAddress(), Value(true)}, fixture.AddMemory(sample, 0x228));
|
||||
fixture.PlanAndTrack();
|
||||
const auto plan = ExtractResourcePlan(fixture.program);
|
||||
|
||||
|
|
@ -1866,7 +1869,7 @@ void TestImagesSamplersAndAliases() {
|
|||
memory.kind = ResourceKind::Image;
|
||||
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
memory.image_sample_flags = sample_flags;
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, image_address},
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, image_address, Value(true)},
|
||||
fixture.AddMemory(memory, pc));
|
||||
return std::pair{image, sampler};
|
||||
};
|
||||
|
|
@ -1938,14 +1941,14 @@ void TestSampleAdjustSamplerScratch() {
|
|||
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
memory.image_sample_flags = Decoder::ImageSampleFlagAdjust;
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw,
|
||||
{image, sampler, fixture.ImageAddress()},
|
||||
{image, sampler, fixture.ImageAddress(), Value(true)},
|
||||
fixture.AddMemory(memory, 0x1ec));
|
||||
// PPSA24156's zero border payload leaves the reserved scratch shift as
|
||||
// the entire DWORD after the frontend folds its OR with zero.
|
||||
const auto shift_sampler = fixture.Sampler(
|
||||
{Value(0x36u), Value(0xfff000u), Value(0x02500000u), scratch}, 0x200);
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw,
|
||||
{image, shift_sampler, fixture.ImageAddress()},
|
||||
{image, shift_sampler, fixture.ImageAddress(), Value(true)},
|
||||
fixture.AddMemory(memory, 0x200));
|
||||
fixture.PlanAndTrack();
|
||||
auto plan = ExtractResourcePlan(fixture.program);
|
||||
|
|
@ -1994,7 +1997,7 @@ void TestSampleAdjustSamplerScratch() {
|
|||
rejected_memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
rejected_memory.image_sample_flags = flags;
|
||||
rejected.Emit(ValueOpcode::ImageSampleRaw,
|
||||
{rejected_image, rejected_sampler, rejected.ImageAddress()},
|
||||
{rejected_image, rejected_sampler, rejected.ImageAddress(), Value(true)},
|
||||
rejected.AddMemory(rejected_memory, 0x200));
|
||||
|
||||
CheckFatal([&] { rejected.PlanAndTrack(); },
|
||||
|
|
@ -2112,7 +2115,7 @@ void TestGatherLodSamplerValidation() {
|
|||
fixture.Emit(ValueOpcode::ImageGatherRaw,
|
||||
{fixture.Image(image_words), fixture.Sampler(sampler_words),
|
||||
fixture.ImageAddress(), image_words[1], image_words[3],
|
||||
sampler_words[1], sampler_words[2]},
|
||||
sampler_words[1], sampler_words[2], Value(true)},
|
||||
fixture.AddMemory(memory, i * 4));
|
||||
}
|
||||
fixture.PlanAndTrack();
|
||||
|
|
@ -2514,7 +2517,7 @@ ResourcePlan ConditionalSamplerPlan(bool diamond, bool reverse, bool reverse_phi
|
|||
sample.kind = ResourceKind::Image;
|
||||
sample.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
const auto result =
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, address},
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, address, Value(true)},
|
||||
fixture.AddMemory(sample, 0x4d4));
|
||||
fixture.Emit(ValueOpcode::ReferenceU32,
|
||||
{fixture.Emit(ValueOpcode::CompositeExtractU32x4,
|
||||
|
|
@ -2619,7 +2622,7 @@ void TestFiniteImagePhiCycle() {
|
|||
MemoryInfo memory;
|
||||
memory.kind = ResourceKind::Image;
|
||||
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress()},
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress(), Value(true)},
|
||||
fixture.AddMemory(memory, 4));
|
||||
fixture.PlanAndTrack();
|
||||
auto plan = ExtractResourcePlan(fixture.program);
|
||||
|
|
@ -2685,12 +2688,12 @@ void TestFiniteInlineSampler() {
|
|||
memory.kind = ResourceKind::Image;
|
||||
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
if (format == F::k32Float)
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, previous, fixture.ImageAddress()},
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, previous, fixture.ImageAddress(), Value(true)},
|
||||
fixture.AddMemory(memory, 0x440u));
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress()},
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress(), Value(true)},
|
||||
fixture.AddMemory(memory, 0x1dd0u));
|
||||
if (format == F::k32Float)
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, direct, fixture.ImageAddress()},
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, direct, fixture.ImageAddress(), Value(true)},
|
||||
fixture.AddMemory(memory, 0x1dd8u));
|
||||
}
|
||||
fixture.PlanAndTrack();
|
||||
|
|
@ -2764,7 +2767,7 @@ void TestFiniteInlineSampler() {
|
|||
memory.kind = ResourceKind::Image;
|
||||
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
memory.image_sample_flags = flags;
|
||||
adjusted.Emit(ValueOpcode::ImageSampleRaw, {image, shared, adjusted.ImageAddress()},
|
||||
adjusted.Emit(ValueOpcode::ImageSampleRaw, {image, shared, adjusted.ImageAddress(), Value(true)},
|
||||
adjusted.AddMemory(memory, 0x1dd0u));
|
||||
}
|
||||
CheckFatal([&] { adjusted.PlanAndTrack(); }, "not a valid runtime value",
|
||||
|
|
@ -2817,7 +2820,7 @@ void TestFiniteImageBitScanSentinel() {
|
|||
MemoryInfo memory;
|
||||
memory.kind = ResourceKind::Image;
|
||||
memory.image_dimension = Decoder::ImageDimension::Dim2D;
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress()},
|
||||
fixture.Emit(ValueOpcode::ImageSampleRaw, {image, sampler, fixture.ImageAddress(), Value(true)},
|
||||
fixture.AddMemory(memory, 4));
|
||||
if (!nonzero) {
|
||||
CheckFatal([&] { fixture.PlanAndTrack(); }, "not a valid runtime value",
|
||||
|
|
|
|||
|
|
@ -34960,12 +34960,11 @@ TestCase ImageSampleOpcodeAliasUsesNormalCoords() {
|
|||
return test;
|
||||
}
|
||||
|
||||
TestCase ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu() {
|
||||
template <u32 wave_size> TestCase ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
std::vector<u32> code;
|
||||
AppendVMovU32(&code, 20,
|
||||
1); // Non-constant +1 X offset is not a SPIR-V ConstOffset.
|
||||
AppendVMovU32(&code, 20, 1); // +1 X remains a full dword with A16 coordinates.
|
||||
AppendVMovLiteral(&code, 21, 0x36003900u); // x=0.625, y=0.375 packed as f16.
|
||||
AppendVMovU32(&code, 22, 0);
|
||||
code.push_back(EncodeMimg0(0x30, 0xf));
|
||||
|
|
@ -34976,18 +34975,63 @@ TestCase ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu() {
|
|||
AppendEnd(&code);
|
||||
|
||||
auto image = MakeRgbaImage(4, 4);
|
||||
SetRgbaPixel(&image, 4, 2, 1, 0x3f800000u, 0x40000000u, 0x40400000u,
|
||||
SetRgbaPixel(&image, 4, 2, 1, 0x3f000000u, 0, 0, 0);
|
||||
SetRgbaPixel(&image, 4, 3, 1, 0x3f800000u, 0x40000000u, 0x40400000u,
|
||||
0x40800000u);
|
||||
|
||||
TestCase test;
|
||||
test.name = "ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu";
|
||||
test.name = wave_size == 32 ? "ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu32"
|
||||
: "ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu64";
|
||||
test.code = code;
|
||||
test.compute_info.wave_size = wave_size;
|
||||
test.has_compute_info = true;
|
||||
test.expected = {0x3f800000u, 0x40000000u, 0x40400000u, 0x40800000u};
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_SAMPLE, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
test.sampled_image_rgba = image;
|
||||
test.required_spirv = {"UnpackHalf2x16"};
|
||||
test.forbidden_spirv = {"OpBitFieldSExtract"};
|
||||
test.required_spirv = {"UnpackHalf2x16", "Lod|ConstOffset"};
|
||||
test.forbidden_spirv = {"OpBitFieldSExtract", "OpImageQuerySizeLod", "OpFDiv"};
|
||||
return test;
|
||||
}
|
||||
|
||||
template <u32 wave_size> TestCase ImageSampleOffsetsReadFourNeighbors() {
|
||||
using O = ShaderOpcode;
|
||||
TestCase test;
|
||||
test.name = wave_size == 32 ? "ImageSampleOffsetsReadFourNeighbors32"
|
||||
: "ImageSampleOffsetsReadFourNeighbors64";
|
||||
test.compute_info.wave_size = wave_size;
|
||||
test.has_compute_info = true;
|
||||
constexpr std::array offsets{0x01u, 0x3fu, 0x3f00u, 0x0100u};
|
||||
constexpr std::array opcodes{0x37u, 0x37u, 0x34u, 0x32u};
|
||||
for (u32 sample = 0; sample < offsets.size(); ++sample) {
|
||||
AppendVMovLiteral(&test.code, 20, offsets[sample]);
|
||||
u32 coordinate = 21;
|
||||
if (opcodes[sample] == 0x32u) {
|
||||
for (float gradient : {0.25f, 0.f, 0.f, 0.25f}) {
|
||||
AppendVMovLiteral(&test.code, coordinate++, std::bit_cast<u32>(gradient));
|
||||
}
|
||||
}
|
||||
// All instructions address the center of texel (2, 1) before applying the offset.
|
||||
AppendVMovLiteral(&test.code, coordinate, std::bit_cast<u32>(0.625f));
|
||||
AppendVMovLiteral(&test.code, coordinate + 1, std::bit_cast<u32>(0.375f));
|
||||
if (opcodes[sample] == 0x34u) AppendVMovU32(&test.code, coordinate + 2, 0);
|
||||
test.code.push_back(EncodeMimg0(opcodes[sample], 0x1));
|
||||
test.code.push_back(EncodeMimg1(sample, 20));
|
||||
AppendStoreVgpr(&test.code, sample, sample);
|
||||
}
|
||||
AppendEnd(&test.code);
|
||||
test.sampled_image_rgba = MakeRgbaImage(4, 4);
|
||||
SetRgbaPixel(&test.sampled_image_rgba, 4, 2, 1, std::bit_cast<u32>(16.f), 0, 0, 0);
|
||||
constexpr std::array<std::array<u32, 2>, 4> neighbors{{{3, 1}, {1, 1}, {2, 0}, {2, 2}}};
|
||||
for (u32 sample = 0; sample < neighbors.size(); ++sample) {
|
||||
const auto value = std::bit_cast<u32>(float(sample + 1));
|
||||
SetRgbaPixel(&test.sampled_image_rgba, 4, neighbors[sample][0], neighbors[sample][1],
|
||||
value, 0, 0, 0);
|
||||
test.expected.push_back(value);
|
||||
}
|
||||
test.opcodes = {O::V_MOV_B32, O::IMAGE_SAMPLE, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.required_spirv = {"Lod|ConstOffset", "Grad|ConstOffset"};
|
||||
test.forbidden_spirv = {"OpImageQuerySizeLod", "OpFDiv", "OpBitFieldSExtract", "OpSwitch"};
|
||||
return test;
|
||||
}
|
||||
|
||||
|
|
@ -35058,7 +35102,8 @@ TestCase ImageGatherCompareOpcodes() {
|
|||
O::V_MOV_B32, O::IMAGE_GATHER4_C, O::IMAGE_GATHER4_C_LZ,
|
||||
O::IMAGE_GATHER4_C_O, O::IMAGE_GATHER4_C_LZ_O, O::BUFFER_STORE_DWORD,
|
||||
O::S_ENDPGM};
|
||||
test.required_spirv = {"OpImageDrefGather", "OpBitFieldSExtract"};
|
||||
test.required_spirv = {"OpImageDrefGather", "ConstOffset"};
|
||||
test.forbidden_spirv = {"OpBitFieldSExtract"};
|
||||
test.compile_only = true;
|
||||
return test;
|
||||
}
|
||||
|
|
@ -35610,7 +35655,7 @@ void CheckIndirectImageKeySwitch(VulkanHarness &vulkan) {
|
|||
std::memcpy(&memory_flag_bits, &memory_flags, sizeof(memory_flags));
|
||||
auto &sample = block->AppendNewInst(
|
||||
ValueOpcode::ImageSampleRaw,
|
||||
{Value(&image), Value(&sampler), Value(&address)}, memory_flag_bits);
|
||||
{Value(&image), Value(&sampler), Value(&address), Value(true)}, memory_flag_bits);
|
||||
auto &sample_x = block->AppendNewInst(ValueOpcode::CompositeExtractU32x4,
|
||||
{Value(&sample), Value(0u)});
|
||||
block->AppendNewInst(ValueOpcode::ReferenceU32, {Value(&sample_x)});
|
||||
|
|
@ -35836,7 +35881,7 @@ void CheckIndirectImageKeySwitch(VulkanHarness &vulkan) {
|
|||
auto &read = *block->PrependNewInst(
|
||||
position, ValueOpcode::ImageGatherRaw,
|
||||
{Value(&image), Value(&sampler), Value(&address), Value(0u), Value(0u),
|
||||
Value(0u), Value(0u)}, memory_flag_bits);
|
||||
Value(0u), Value(0u), Value(true)}, memory_flag_bits);
|
||||
access->ReplaceUsesWith(Value(&read), false);
|
||||
access = &read;
|
||||
compiled.program.info.images[4].cube = false;
|
||||
|
|
@ -37772,7 +37817,10 @@ std::vector<TestCase> MakeCases() {
|
|||
AddCase(ImageD16GatherPacksHalfPairs);
|
||||
AddCase(ImageSampleA16SamplerCoordsOnGpu);
|
||||
AddCase(ImageSampleOpcodeAliasUsesNormalCoords);
|
||||
AddCase(ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu);
|
||||
AddCase(ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu<32>);
|
||||
AddCase(ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu<64>);
|
||||
AddCase(ImageSampleOffsetsReadFourNeighbors<32>);
|
||||
AddCase(ImageSampleOffsetsReadFourNeighbors<64>);
|
||||
AddCase(ImageSampleA16CompareBiasRdna2AddressOrder);
|
||||
AddCase(ImageGatherCompareOpcodes);
|
||||
AddCase(ImageStoreVariants);
|
||||
|
|
@ -40183,7 +40231,7 @@ void CheckImageSamplerSpecialization() {
|
|||
sizeof(signed_memory_flags));
|
||||
mixed_sampler_block->AppendNewInst(
|
||||
ValueOpcode::ImageSampleRaw,
|
||||
{Value(&image_handle), Value(&sampler_handle), Value(&image_address)},
|
||||
{Value(&image_handle), Value(&sampler_handle), Value(&image_address), Value(true)},
|
||||
signed_memory_flag_bits);
|
||||
|
||||
ShaderRecompiler::IR::DescriptorValue native_image_descriptor{};
|
||||
|
|
@ -43440,6 +43488,16 @@ int main(int argc, char **argv) {
|
|||
RunCase(&vulkan, FlatVirtualAddressRebasesGuestAllocation());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--image-sample-offset-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, ImageSampleOffsetsReadFourNeighbors<32>());
|
||||
RunCase(&vulkan, ImageSampleOffsetsReadFourNeighbors<64>());
|
||||
RunCase(&vulkan, ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu<32>());
|
||||
RunCase(&vulkan, ImageSampleA16OffsetKeepsTexelOffset32BitOnGpu<64>());
|
||||
RunCase(&vulkan, ImageSampleAndGather());
|
||||
RunCase(nullptr, ImageGatherCompareOpcodes());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--image-gather-lod-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunCase(&vulkan, ImageGatherExplicitLod());
|
||||
|
|
|
|||
|
|
@ -1316,7 +1316,7 @@ void TestShaderFeatureCollection() {
|
|||
{Value(0u), Value(0u), Value(0u)});
|
||||
block->AppendNewInst(ValueOpcode::ImageGatherRaw,
|
||||
{Value(0u), Value(0u), Value(0u), Value(0u),
|
||||
Value(0u), Value(0u), Value(0u)});
|
||||
Value(0u), Value(0u), Value(0u), Value(true)});
|
||||
auto &shared = block->AppendNewInst(ValueOpcode::LoadSharedU32,
|
||||
{Value(0u), Value(true)});
|
||||
shared.SetFlags(MemoryFlags{.index = 0});
|
||||
|
|
|
|||
Loading…
Reference in New Issue