mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
graphics: support RDNA2 custom pixel interpolation
Co-authored-by: Senaxx <Senaxx@users.noreply.github.com>
This commit is contained in:
@@ -866,9 +866,9 @@ bool LowerVInterpP1F32(const Decoder::Instruction& decoded, BasicBlock& block) {
|
||||
|
||||
bool LowerVInterpLoadF32(const Decoder::Instruction& decoded, BasicBlock& block,
|
||||
std::string* error) {
|
||||
if (decoded.opcode == Decoder::Opcode::V_INTERP_MOV_F32 && decoded.src0.value != 2u) {
|
||||
if (decoded.opcode == Decoder::Opcode::V_INTERP_MOV_F32 && decoded.src0.value >= 3u) {
|
||||
if (error != nullptr) {
|
||||
*error = fmt::format("v_interp_mov_f32 mode {} is not implemented at pc 0x{:08x}",
|
||||
*error = fmt::format("v_interp_mov_f32 mode {} is reserved at pc 0x{:08x}",
|
||||
decoded.src0.value, decoded.pc);
|
||||
}
|
||||
return false;
|
||||
@@ -879,6 +879,9 @@ bool LowerVInterpLoadF32(const Decoder::Instruction& decoded, BasicBlock& block,
|
||||
inst.op = Opcode::LoadInputF32;
|
||||
inst.input_info.attr = decoded.src1.value;
|
||||
inst.input_info.chan = decoded.src2.value;
|
||||
if (decoded.opcode == Decoder::Opcode::V_INTERP_MOV_F32) {
|
||||
inst.input_info.interpolation_mode = decoded.src0.value;
|
||||
}
|
||||
if (!LowerRegisterOperand(decoded.dst, inst.dst, error)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -144,9 +144,10 @@ struct ExportInfo {
|
||||
};
|
||||
|
||||
struct InputInfo {
|
||||
uint32_t attr = 0;
|
||||
uint32_t chan = 0;
|
||||
uint32_t component_count = 1;
|
||||
uint32_t attr = 0;
|
||||
uint32_t chan = 0;
|
||||
uint32_t component_count = 1;
|
||||
uint32_t interpolation_mode = 3;
|
||||
|
||||
bool operator==(const InputInfo& other) const = default;
|
||||
};
|
||||
@@ -272,6 +273,8 @@ enum class StageInputKind {
|
||||
InstanceIndex,
|
||||
FragCoord,
|
||||
FrontFacing,
|
||||
BaryCoordSmooth,
|
||||
BaryCoordNoPerspective,
|
||||
WorkgroupId,
|
||||
LocalInvocationId,
|
||||
LocalInvocationIndex,
|
||||
@@ -286,6 +289,7 @@ struct StageInput {
|
||||
uint32_t location = 0;
|
||||
uint32_t component_count = 1;
|
||||
std::string debug_name;
|
||||
bool per_vertex = false;
|
||||
|
||||
bool operator==(const StageInput& other) const = default;
|
||||
};
|
||||
|
||||
@@ -274,6 +274,7 @@ VALUE_OPCODE(ImageAtomicAnd32, U32, ImageResource, ImageAddress, U32, U1)
|
||||
VALUE_OPCODE(ImageAtomicOr32, U32, ImageResource, ImageAddress, U32, U1)
|
||||
VALUE_OPCODE(ImageAtomicXor32, U32, ImageResource, ImageAddress, U32, U1)
|
||||
VALUE_OPCODE(GetAttribute, U32, U32, U32)
|
||||
VALUE_OPCODE(GetInterpolationParameter, U32, U32, U32, U32)
|
||||
VALUE_OPCODE(SetAttribute, Void, U32x4, U1)
|
||||
|
||||
VALUE_OPCODE(ControlNop, Void)
|
||||
|
||||
@@ -9,14 +9,15 @@ namespace Libs::Graphics::ShaderRecompiler::IR {
|
||||
namespace {
|
||||
|
||||
void AddInput(ShaderInfo& info, StageInputKind kind, uint32_t location, uint32_t components,
|
||||
std::string name) {
|
||||
std::string name, bool per_vertex = false) {
|
||||
const auto input = std::find_if(info.inputs.begin(), info.inputs.end(), [=](const auto& value) {
|
||||
return value.kind == kind && value.location == location;
|
||||
});
|
||||
if (input == info.inputs.end()) {
|
||||
info.inputs.push_back({kind, location, components, std::move(name)});
|
||||
info.inputs.push_back({kind, location, components, std::move(name), per_vertex});
|
||||
} else {
|
||||
input->component_count = std::max(input->component_count, components);
|
||||
input->per_vertex = input->per_vertex || per_vertex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,6 +80,24 @@ bool ValidateValueReferences(const Program& program, const ShaderInfoOptions& op
|
||||
static_cast<uint32_t>(options.vertex->resources_num))) {
|
||||
return Fail("vertex input reference is out of range");
|
||||
}
|
||||
if (program.stage == ShaderType::Pixel &&
|
||||
(inst.Arg(1).U32() >= 4u ||
|
||||
inst.Arg(0).U32() >= options.pixel->input_num)) {
|
||||
return Fail("pixel input reference is out of range");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ValueOpcode::GetInterpolationParameter: {
|
||||
if (program.stage != ShaderType::Pixel || !inst.Arg(0).IsImmediate() ||
|
||||
inst.Arg(0).GetType() != Type::U32 || !inst.Arg(1).IsImmediate() ||
|
||||
inst.Arg(1).GetType() != Type::U32 || !inst.Arg(2).IsImmediate() ||
|
||||
inst.Arg(2).GetType() != Type::U32) {
|
||||
return Fail("interpolation parameter reference is invalid");
|
||||
}
|
||||
if (inst.Arg(0).U32() >= options.pixel->input_num || inst.Arg(1).U32() >= 4u ||
|
||||
inst.Arg(2).U32() >= 3u) {
|
||||
return Fail("interpolation parameter reference is out of range");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ValueOpcode::GetBuiltin: {
|
||||
@@ -102,6 +121,12 @@ bool ValidateValueReferences(const Program& program, const ShaderInfoOptions& op
|
||||
return Fail("typed fragment-coordinate component is out of range");
|
||||
}
|
||||
break;
|
||||
case StageInputKind::BaryCoordSmooth:
|
||||
case StageInputKind::BaryCoordNoPerspective:
|
||||
if (component >= 2u) {
|
||||
return Fail("typed barycentric component is out of range");
|
||||
}
|
||||
break;
|
||||
case StageInputKind::WorkgroupId:
|
||||
case StageInputKind::LocalInvocationId:
|
||||
case StageInputKind::GlobalInvocationId:
|
||||
@@ -150,15 +175,40 @@ void CollectVertexInputs(const Program& program, const ShaderVertexInputInfo* ve
|
||||
}
|
||||
}
|
||||
|
||||
void CollectPixelInputs(const ShaderPixelInputInfo* pixel, ShaderInfo& info) {
|
||||
void CollectPixelInputs(const Program& program, const ShaderPixelInputInfo* pixel,
|
||||
ShaderInfo& info) {
|
||||
if (pixel->HasPositionInput()) {
|
||||
AddInput(info, StageInputKind::FragCoord, 0, 4, "gl_FragCoord");
|
||||
}
|
||||
if (pixel->ps_front_face) {
|
||||
AddInput(info, StageInputKind::FrontFacing, 0, 1, "gl_FrontFacing");
|
||||
}
|
||||
std::array<bool, 32> per_vertex {};
|
||||
std::array<bool, 32> interpolated {};
|
||||
for (const auto* block: program.values->blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
if (inst.GetOpcode() == ValueOpcode::GetAttribute) {
|
||||
interpolated[inst.Arg(0).U32()] = true;
|
||||
} else if (inst.GetOpcode() == ValueOpcode::GetInterpolationParameter) {
|
||||
const auto input = inst.Arg(0).U32();
|
||||
const auto mode = inst.Arg(2).U32();
|
||||
per_vertex[input] =
|
||||
per_vertex[input] || mode < 2u || !ShaderPixelParameterIsFlat(*pixel, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (uint32_t input = 0; input < pixel->input_num; input++) {
|
||||
AddInput(info, StageInputKind::Parameter, input, 4, fmt::format("in_param_{}", input));
|
||||
AddInput(info, StageInputKind::Parameter, input, 4, fmt::format("in_param_{}", input),
|
||||
per_vertex[input]);
|
||||
}
|
||||
for (uint32_t input = 0; input < pixel->input_num; input++) {
|
||||
if (interpolated[input] && per_vertex[input]) {
|
||||
const auto kind = pixel->ps_no_perspective ? StageInputKind::BaryCoordNoPerspective
|
||||
: StageInputKind::BaryCoordSmooth;
|
||||
AddInput(info, kind, 0, 3,
|
||||
pixel->ps_no_perspective ? "gl_BaryCoordNoPerspKHR" : "gl_BaryCoordKHR");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,6 +245,12 @@ void CollectBuiltinInputs(const Program& program, ShaderInfo& info) {
|
||||
case StageInputKind::FrontFacing:
|
||||
AddInput(info, kind, 0, 1, "gl_FrontFacing");
|
||||
break;
|
||||
case StageInputKind::BaryCoordSmooth:
|
||||
AddInput(info, kind, 0, 3, "gl_BaryCoordKHR");
|
||||
break;
|
||||
case StageInputKind::BaryCoordNoPerspective:
|
||||
AddInput(info, kind, 0, 3, "gl_BaryCoordNoPerspKHR");
|
||||
break;
|
||||
case StageInputKind::WorkgroupId:
|
||||
AddInput(info, kind, 0, 3, "gl_WorkGroupID");
|
||||
break;
|
||||
@@ -287,7 +343,7 @@ bool CollectShaderInfo(Program& program, const ShaderInfoOptions& options, std::
|
||||
});
|
||||
switch (program.stage) {
|
||||
case ShaderType::Vertex: CollectVertexInputs(program, options.vertex, next); break;
|
||||
case ShaderType::Pixel: CollectPixelInputs(options.pixel, next); break;
|
||||
case ShaderType::Pixel: CollectPixelInputs(program, options.pixel, next); break;
|
||||
case ShaderType::Compute: CollectComputeInputs(options.compute, next); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user