gpu: compile RDNA2 tessellation through native LS HS and TES stages

This commit is contained in:
nmzik
2026-09-13 07:45:08 +04:00
parent 6d1ba5870a
commit 7516068662
26 changed files with 1035 additions and 161 deletions
+17 -1
View File
@@ -150,8 +150,20 @@ struct SampledResourcePair {
bool operator==(const SampledResourcePair& other) const = default;
};
enum class TessellationAttribute {
LocalOutput,
ControlInput,
ControlOutput,
EvaluationInput,
PatchOutput,
Factor
};
enum class StageInputKind {
VertexIndex,
InvocationId,
PrimitiveId,
TessCoord,
InstanceIndex,
FragCoord,
FrontFacing,
@@ -287,8 +299,12 @@ static_assert(sizeof(PushData) == 128);
constexpr uint32_t NativePushConstantSize = sizeof(PushData);
[[nodiscard]] constexpr uint32_t NativeBinding(ShaderType stage, DescriptorBindingKind kind) {
const uint32_t group = stage == ShaderType::Pixel ? 1u
: stage == ShaderType::TessellationControl ? 2u
: stage == ShaderType::TessellationEvaluation ? 3u
: 0u;
return static_cast<uint32_t>(kind) +
(stage == ShaderType::Pixel ? static_cast<uint32_t>(DescriptorBindingKind::Count) : 0u);
group * static_cast<uint32_t>(DescriptorBindingKind::Count);
}
[[nodiscard]] constexpr ImageResourceClass ImageBindingResourceClass(DescriptorBindingKind kind) {
@@ -90,6 +90,7 @@ bool HasSideEffects(ValueOpcode opcode) {
case ValueOpcode::Reference:
case ValueOpcode::ReferenceU32:
case ValueOpcode::SetAttribute:
case ValueOpcode::SetTessellationAttribute:
case ValueOpcode::MeshAllocate:
case ValueOpcode::Barrier: return true;
default: return false;
@@ -10,6 +10,9 @@ VALUE_OPCODE(GetUserData, U32, ScalarReg)
VALUE_OPCODE(GetShaderBase, U64)
VALUE_OPCODE(MeshDrawParameter, U32, U32)
VALUE_OPCODE(MeshAllocate, Void, U32)
VALUE_OPCODE(TessellationBase, U32, U32)
VALUE_OPCODE(GetTessellationAttribute, U32, U32, U32, U1)
VALUE_OPCODE(SetTessellationAttribute, Void, U32, U32, U32, U1)
VALUE_OPCODE(GetBuiltin, U32, U32, U32)
VALUE_OPCODE(GetThreadBitScalarRegister, U1, ScalarReg)
VALUE_OPCODE(SetThreadBitScalarRegister, Void, ScalarReg, U1)
@@ -228,6 +228,15 @@ void FoldInstruction(Block& block, Block::iterator instruction,
const auto offset = Arg(inst, 1);
const auto count = Arg(inst, 2);
auto* source = value.TryInstruction();
if (source != nullptr && source->GetOpcode() == ValueOpcode::ShiftLeftLogical32 &&
IsImmediate(offset, Type::U32) && IsImmediate(count, Type::U32)) {
const auto shift = Arg(*source, 1);
if (IsImmediate(shift, Type::U32) && shift.U32() < 32u &&
offset.U32() <= shift.U32() && count.U32() <= shift.U32() - offset.U32()) {
Replace(inst, Value(0u));
return;
}
}
if (source != nullptr && source->GetOpcode() == ValueOpcode::GetBuiltin &&
source->Arg(0) == Value(static_cast<uint32_t>(StageInputKind::PackedAncillary)) &&
IsImmediate(offset, Type::U32) && IsImmediate(count, Type::U32) && count.U32() != 0u) {
@@ -43,6 +43,9 @@ void AddOutput(ShaderInfo& info, StageOutputKind kind, uint32_t index, uint32_t
void ValidateOptions(const Program& program, ShaderStageInputInfo input_info) {
switch (program.stage) {
case ShaderType::Vertex:
case ShaderType::Local:
case ShaderType::TessellationControl:
case ShaderType::TessellationEvaluation:
case ShaderType::Mesh:
if (input_info.vertex == nullptr) {
return Fail("vertex shader has no input metadata");
@@ -81,7 +84,8 @@ void ValidateValueReferences(const Program& program, ShaderStageInputInfo input_
!inst.Arg(1).IsImmediate() || inst.Arg(1).GetType() != Type::U32) {
return Fail("typed attribute reference is not constant");
}
if (program.stage == ShaderType::Vertex &&
if ((program.stage == ShaderType::Vertex ||
program.stage == ShaderType::Local) &&
(inst.Arg(1).U32() >= 4u ||
inst.Arg(0).U32() >=
static_cast<uint32_t>(input_info.vertex->resources_num))) {
@@ -124,6 +128,8 @@ void ValidateValueReferences(const Program& program, ShaderStageInputInfo input_
}
break;
case StageInputKind::VertexIndex:
case StageInputKind::InvocationId:
case StageInputKind::PrimitiveId:
case StageInputKind::InstanceIndex:
case StageInputKind::FrontFacing:
case StageInputKind::LocalInvocationIndex:
@@ -142,6 +148,7 @@ void ValidateValueReferences(const Program& program, ShaderStageInputInfo input_
return Fail("typed barycentric component is out of range");
}
break;
case StageInputKind::TessCoord:
case StageInputKind::WorkgroupId:
case StageInputKind::LocalInvocationId:
case StageInputKind::GlobalInvocationId:
@@ -161,8 +168,10 @@ void ValidateValueReferences(const Program& program, ShaderStageInputInfo input_
}
const auto& exp = program.export_info[index];
if (exp.kind == ExportTargetKind::Position && exp.index != 0 && exp.en != 0 &&
program.stage != ShaderType::Vertex && program.stage != ShaderType::Mesh) {
return Fail("auxiliary position export requires the vertex or mesh stage");
program.stage != ShaderType::Vertex && program.stage != ShaderType::Mesh &&
program.stage != ShaderType::TessellationEvaluation) {
return Fail("auxiliary position export requires a vertex, mesh, or "
"tessellation evaluation shader");
}
break;
}
@@ -249,6 +258,10 @@ void CollectComputeInputs(const ShaderComputeInputInfo* compute, ShaderInfo& inf
void CollectBuiltinInputs(const Program& program, ShaderInfo& info) {
for (const auto* block: program.blocks) {
for (const auto& inst: *block) {
if (program.stage == ShaderType::TessellationControl &&
inst.GetOpcode() == ValueOpcode::LaneId) {
AddInput(info, StageInputKind::InvocationId, 0, 1, "gl_InvocationID");
}
if (inst.GetOpcode() != ValueOpcode::GetBuiltin) {
continue;
}
@@ -260,6 +273,13 @@ void CollectBuiltinInputs(const Program& program, ShaderInfo& info) {
case StageInputKind::InstanceIndex:
AddInput(info, kind, 0, 1, "gl_InstanceIndex");
break;
case StageInputKind::InvocationId:
AddInput(info, kind, 0, 1, "gl_InvocationID");
break;
case StageInputKind::PrimitiveId:
AddInput(info, kind, 0, 1, "gl_PrimitiveID");
break;
case StageInputKind::TessCoord: AddInput(info, kind, 0, 3, "gl_TessCoord"); break;
case StageInputKind::FragCoord: AddInput(info, kind, 0, 4, "gl_FragCoord"); break;
case StageInputKind::FrontFacing:
AddInput(info, kind, 0, 1, "gl_FrontFacing");
@@ -380,7 +400,10 @@ void CollectShaderInfo(Program& program, ShaderStageInputInfo input_info) {
});
});
switch (program.stage) {
case ShaderType::Vertex: CollectVertexInputs(program, input_info.vertex, next); break;
case ShaderType::Vertex:
case ShaderType::Local: CollectVertexInputs(program, input_info.vertex, next); break;
case ShaderType::TessellationControl:
case ShaderType::TessellationEvaluation:
case ShaderType::Mesh: break;
case ShaderType::Pixel: CollectPixelInputs(program, input_info.pixel, next); break;
case ShaderType::Compute: CollectComputeInputs(input_info.compute, next); break;