mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
shader: legalize 1D level-zero gathers
This commit is contained in:
@@ -439,6 +439,49 @@ uint32_t UnpackImageGather(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uin
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t EmitOneDimensionalGatherLz(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32_t pc,
|
||||||
|
uint32_t coord, bool integer) {
|
||||||
|
auto& state = ctx.state;
|
||||||
|
state.builder.RequireCapability(CapabilityImageQuery);
|
||||||
|
const auto image = LoadSampledImageDescriptor(state, mem, pc, ImageViewKind::Dim1D);
|
||||||
|
const auto width = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction(
|
||||||
|
{OpImageQuerySizeLod, TypeU32(state), width, image, ConstantU32(state, 0)});
|
||||||
|
const auto width_f32 = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction({OpConvertUToF, TypeF32(state), width_f32, width});
|
||||||
|
const auto left = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction(
|
||||||
|
{OpExtInst, TypeF32(state), left, GlslStd450(state), GlslFloor,
|
||||||
|
Binary(state, OpFSub, TypeF32(state),
|
||||||
|
Binary(state, OpFMul, TypeF32(state), coord, width_f32),
|
||||||
|
ConstantF32(state, 0x3f000000u))});
|
||||||
|
|
||||||
|
const auto sampled = MakeSampledImage(state, mem, pc, ImageViewKind::Dim1D);
|
||||||
|
const auto vector_type = integer ? TypeU32Vector(state, 4) : TypeF32Vector(state, 4);
|
||||||
|
const auto scalar_type = integer ? TypeU32(state) : TypeF32(state);
|
||||||
|
const auto component = ImageConversionFormat(state, mem).format == Prospero::BufferFormat::kInvalid
|
||||||
|
? ImageGatherComponent(mem.dmask)
|
||||||
|
: 0u;
|
||||||
|
uint32_t values[2] {};
|
||||||
|
for (uint32_t index = 0; index < 2u; index++) {
|
||||||
|
const auto sample_coord = Binary(
|
||||||
|
state, OpFDiv, TypeF32(state),
|
||||||
|
Binary(state, OpFAdd, TypeF32(state), left,
|
||||||
|
ConstantF32(state, index == 0u ? 0x3f000000u : 0x3fc00000u)),
|
||||||
|
width_f32);
|
||||||
|
const auto texel = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction({OpImageSampleExplicitLod, vector_type, texel, sampled, sample_coord,
|
||||||
|
ImageOperandsLodMask, ZeroF32(state)});
|
||||||
|
values[index] = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction(
|
||||||
|
{OpCompositeExtract, scalar_type, values[index], texel, component});
|
||||||
|
}
|
||||||
|
const auto result = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction({OpCompositeConstruct, vector_type, result, values[0], values[1],
|
||||||
|
values[1], values[0]});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t PackImageTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32_t texel) {
|
uint32_t PackImageTexel(ValueEmitContext& ctx, const IR::MemoryInfo& mem, uint32_t texel) {
|
||||||
const auto info = ImageConversionFormat(ctx.state, mem);
|
const auto info = ImageConversionFormat(ctx.state, mem);
|
||||||
if (info.format == Prospero::BufferFormat::kInvalid) return texel;
|
if (info.format == Prospero::BufferFormat::kInvalid) return texel;
|
||||||
@@ -613,6 +656,22 @@ bool EmitValueImage(ValueEmitContext& ctx, const IR::Inst& inst) {
|
|||||||
const auto coord =
|
const auto coord =
|
||||||
CoordF32(ctx, mem, *address, layout.coord, ImageViewCoordinateComponents(view));
|
CoordF32(ctx, mem, *address, layout.coord, ImageViewCoordinateComponents(view));
|
||||||
if (op == IR::ValueOpcode::ImageGatherRaw) {
|
if (op == IR::ValueOpcode::ImageGatherRaw) {
|
||||||
|
if (view == ImageViewKind::Dim1D) {
|
||||||
|
if (dref || !HasFlag(mem, Decoder::ImageSampleFlagLevelZero) ||
|
||||||
|
HasFlag(mem, Decoder::ImageSampleFlagOffset) ||
|
||||||
|
HasFlag(mem, Decoder::ImageSampleFlagGatherHorizontal)) {
|
||||||
|
ctx.Fail(inst, "has an unsupported 1D gather variant");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const auto sample = EmitOneDimensionalGatherLz(ctx, mem, pc, coord, integer);
|
||||||
|
ctx.Define(inst, ResultVector(ctx, UnpackImageGather(ctx, mem, sample), integer,
|
||||||
|
false, mem, true));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (view == ImageViewKind::Dim1DArray) {
|
||||||
|
ctx.Fail(inst, "has an unsupported 1D-array gather");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
const auto sampled = MakeSampledImage(state, mem, pc, view);
|
const auto sampled = MakeSampledImage(state, mem, pc, view);
|
||||||
const auto sample = state.builder.AllocateId();
|
const auto sample = state.builder.AllocateId();
|
||||||
std::vector<uint32_t> words =
|
std::vector<uint32_t> words =
|
||||||
|
|||||||
@@ -19040,6 +19040,44 @@ TestCase ImageLoad1DUsesScalarCoordinate() {
|
|||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TestCase ImageGather2DInstructionWith1DDescriptor() {
|
||||||
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
|
std::vector<u32> code;
|
||||||
|
AppendVMovLiteral(&code, 20, 0x3f000000u);
|
||||||
|
AppendVMovLiteral(&code, 21, 0x3f000000u);
|
||||||
|
code.push_back(EncodeMimg0(0x47, 0x1));
|
||||||
|
code.push_back(EncodeMimg1(0, 20));
|
||||||
|
for (u32 i = 0; i < 4u; i++) {
|
||||||
|
AppendStoreVgpr(&code, i, i);
|
||||||
|
}
|
||||||
|
AppendEnd(&code);
|
||||||
|
|
||||||
|
auto image = MakeRgbaImage(4, 1);
|
||||||
|
SetRgbaPixel(&image, 4, 1, 0, 0x40000000u, 0, 0, 0);
|
||||||
|
SetRgbaPixel(&image, 4, 2, 0, 0x40400000u, 0, 0, 0);
|
||||||
|
|
||||||
|
TestCase test;
|
||||||
|
test.name = "ImageGather2DInstructionWith1DDescriptor";
|
||||||
|
test.code = code;
|
||||||
|
test.expected = {0x40000000u, 0x40400000u, 0x40400000u, 0x40000000u};
|
||||||
|
test.opcodes = {O::V_MOV_B32, O::IMAGE_GATHER4_LZ, O::BUFFER_STORE_DWORD,
|
||||||
|
O::S_ENDPGM};
|
||||||
|
test.image_width = 4;
|
||||||
|
test.image_height = 1;
|
||||||
|
test.sampled_image_rgba = image;
|
||||||
|
test.sampled_image_type = vk::ImageType::e1D;
|
||||||
|
test.sampled_image_view_type = vk::ImageViewType::e1D;
|
||||||
|
test.user_data = MakeSampledTextureData(Prospero::BufferFormat::k32Float);
|
||||||
|
test.user_data[3] = static_cast<uint32_t>(Prospero::ImageType::kColor1D)
|
||||||
|
<< 28u;
|
||||||
|
test.has_user_data = true;
|
||||||
|
test.required_spirv = {"sampled_1d", "OpImageQuerySizeLod",
|
||||||
|
"OpImageSampleExplicitLod", "Floor"};
|
||||||
|
test.forbidden_spirv = {"OpImageGather"};
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
|
||||||
TestCase ImageLoad1DArrayUsesLayerCoordinate() {
|
TestCase ImageLoad1DArrayUsesLayerCoordinate() {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
@@ -20643,6 +20681,7 @@ std::vector<TestCase> MakeCases() {
|
|||||||
AddCase(ImageSamplePackedUintConvertsSampleAndGather);
|
AddCase(ImageSamplePackedUintConvertsSampleAndGather);
|
||||||
AddCase(ImageLoadR128IgnoresAdjacentMaskSgprs);
|
AddCase(ImageLoadR128IgnoresAdjacentMaskSgprs);
|
||||||
AddCase(ImageLoad1DUsesScalarCoordinate);
|
AddCase(ImageLoad1DUsesScalarCoordinate);
|
||||||
|
AddCase(ImageGather2DInstructionWith1DDescriptor);
|
||||||
AddCase(ImageLoad1DArrayUsesLayerCoordinate);
|
AddCase(ImageLoad1DArrayUsesLayerCoordinate);
|
||||||
AddCase(ImageLoad1DArrayDescriptorUsesSelectedLayer);
|
AddCase(ImageLoad1DArrayDescriptorUsesSelectedLayer);
|
||||||
AddCase(ImageLoadMipUsesVaddr2Lod2D);
|
AddCase(ImageLoadMipUsesVaddr2Lod2D);
|
||||||
|
|||||||
@@ -5109,30 +5109,6 @@ void TestNewShaderRecompilerNullImageUsesCanonical2DView() {
|
|||||||
"null image retained the decoded 1D descriptor binding");
|
"null image retained the decoded 1D descriptor binding");
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestNewShaderRecompilerRejectsOneDimensionalGather() {
|
|
||||||
constexpr std::array cases{
|
|
||||||
std::pair{0u, Prospero::ImageType::kColor1D},
|
|
||||||
std::pair{4u, Prospero::ImageType::kColor1DArray},
|
|
||||||
};
|
|
||||||
for (const auto &[dimension, type] : cases) {
|
|
||||||
const uint32_t shader[] = {
|
|
||||||
EncodeMimg0(0x47, 0x1, false, dimension),
|
|
||||||
EncodeMimg1(0, 0, 1, 0),
|
|
||||||
0xbf810000u,
|
|
||||||
};
|
|
||||||
auto user_data = ImageTestUserData(type);
|
|
||||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
|
||||||
options.user_data = user_data.data();
|
|
||||||
|
|
||||||
ShaderRecompiler::CompileResult result;
|
|
||||||
std::string error;
|
|
||||||
Check(!ShaderRecompiler::TryRecompile(shader, options, result, &error) &&
|
|
||||||
Common::ContainsStr(error,
|
|
||||||
"1D image gather is not supported by SPIR-V"),
|
|
||||||
"1D image gather escaped as invalid SPIR-V");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TestNewShaderRecompilerImageGatherVariants() {
|
void TestNewShaderRecompilerImageGatherVariants() {
|
||||||
const uint32_t shader[] = {
|
const uint32_t shader[] = {
|
||||||
EncodeMimg0(0x47, 0x1),
|
EncodeMimg0(0x47, 0x1),
|
||||||
|
|||||||
Reference in New Issue
Block a user