mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 19:07:01 +02:00
gpu: compile RDNA2 tessellation through native LS HS and TES stages
This commit is contained in:
@@ -290,7 +290,8 @@ uint32_t GlslStd450(EmitterState& state) {
|
||||
}
|
||||
|
||||
VertexInputScalarKind VertexParameterScalarKind(const EmitterState& state, uint32_t location) {
|
||||
if (state.program.stage != ShaderType::Vertex || location >= ShaderVertexInputInfo::RES_MAX ||
|
||||
if ((state.program.stage != ShaderType::Vertex && state.program.stage != ShaderType::Local) ||
|
||||
location >= ShaderVertexInputInfo::RES_MAX ||
|
||||
location >= static_cast<uint32_t>(state.input_info.vertex->resources_num)) {
|
||||
return VertexInputScalarKind::Float;
|
||||
}
|
||||
@@ -347,6 +348,9 @@ uint32_t DefineInterfaceVariable(EmitterState& state, uint32_t type, spv::Storag
|
||||
uint32_t BuiltInForInput(IR::StageInputKind kind) {
|
||||
switch (kind) {
|
||||
case IR::StageInputKind::VertexIndex: return spv::BuiltInVertexIndex;
|
||||
case IR::StageInputKind::InvocationId: return spv::BuiltInInvocationId;
|
||||
case IR::StageInputKind::PrimitiveId: return spv::BuiltInPrimitiveId;
|
||||
case IR::StageInputKind::TessCoord: return spv::BuiltInTessCoord;
|
||||
case IR::StageInputKind::InstanceIndex: return spv::BuiltInInstanceIndex;
|
||||
case IR::StageInputKind::FragCoord: return spv::BuiltInFragCoord;
|
||||
case IR::StageInputKind::FrontFacing: return spv::BuiltInFrontFacing;
|
||||
@@ -387,6 +391,8 @@ void DefineInputs(EmitterState& state) {
|
||||
uint32_t type = TypeU32(state);
|
||||
switch (input.kind) {
|
||||
case IR::StageInputKind::VertexIndex:
|
||||
case IR::StageInputKind::InvocationId:
|
||||
case IR::StageInputKind::PrimitiveId:
|
||||
case IR::StageInputKind::InstanceIndex:
|
||||
case IR::StageInputKind::Layer:
|
||||
case IR::StageInputKind::SampleId: type = TypeI32(state); break;
|
||||
@@ -394,11 +400,13 @@ void DefineInputs(EmitterState& state) {
|
||||
case IR::StageInputKind::LocalInvocationId:
|
||||
case IR::StageInputKind::GlobalInvocationId: type = TypeU32Vector(state, 3); break;
|
||||
case IR::StageInputKind::FragCoord: type = TypeF32Vector(state, 4); break;
|
||||
case IR::StageInputKind::TessCoord:
|
||||
case IR::StageInputKind::BaryCoordSmooth:
|
||||
case IR::StageInputKind::BaryCoordNoPerspective: type = TypeF32Vector(state, 3); break;
|
||||
case IR::StageInputKind::FrontFacing: type = TypeBool(state); break;
|
||||
case IR::StageInputKind::Parameter:
|
||||
if (state.program.stage == ShaderType::Vertex) {
|
||||
if (state.program.stage == ShaderType::Vertex ||
|
||||
state.program.stage == ShaderType::Local) {
|
||||
type = VertexParameterScalarType(
|
||||
state, VertexParameterScalarKind(state, input.location));
|
||||
const auto components = VertexParameterComponentCount(input);
|
||||
@@ -536,6 +544,70 @@ void DefineOutputs(EmitterState& state) {
|
||||
}
|
||||
}
|
||||
|
||||
void DefineTessellationInterfaces(EmitterState& state) {
|
||||
using Attribute = IR::TessellationAttribute;
|
||||
std::array<bool, 6> used {};
|
||||
uint32_t patch_begin = UINT32_MAX, patch_end = 0;
|
||||
for (const auto* block: state.program.blocks) {
|
||||
for (const auto& inst: *block) {
|
||||
if (inst.GetOpcode() != IR::ValueOpcode::GetTessellationAttribute &&
|
||||
inst.GetOpcode() != IR::ValueOpcode::SetTessellationAttribute)
|
||||
continue;
|
||||
const auto kind = inst.Arg(0).U32();
|
||||
used.at(kind) = true;
|
||||
if (kind == static_cast<uint32_t>(Attribute::PatchOutput)) {
|
||||
EXIT_NOT_IMPLEMENTED(!inst.Arg(1).IsImmediate());
|
||||
patch_begin = std::min(patch_begin, inst.Arg(1).U32());
|
||||
patch_end = std::max(patch_end, inst.Arg(1).U32() + 4u);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (std::ranges::none_of(used, [](bool value) { return value; })) return;
|
||||
const auto& tess = state.input_info.vertex->tess;
|
||||
const auto array = [&](uint32_t type, uint32_t count) {
|
||||
return state.builder.Type(spv::OpTypeArray, type, ConstantU32(state, count));
|
||||
};
|
||||
for (uint32_t index = 0; index < used.size(); index++) {
|
||||
if (!used[index]) continue;
|
||||
const auto kind = static_cast<Attribute>(index);
|
||||
const bool input = kind == Attribute::ControlInput || kind == Attribute::EvaluationInput;
|
||||
const auto storage = input ? spv::StorageClassInput : spv::StorageClassOutput;
|
||||
uint32_t type;
|
||||
if (kind == Attribute::Factor) {
|
||||
type = array(TypeF32(state), 4u);
|
||||
} else if (kind == Attribute::PatchOutput) {
|
||||
state.tess_patch_base = patch_begin;
|
||||
type = array(TypeU32Vector(state, 4), (patch_end - patch_begin + 15u) / 16u);
|
||||
} else {
|
||||
const bool local = kind == Attribute::LocalOutput || kind == Attribute::ControlInput;
|
||||
const auto stride = local ? tess.ls_stride : tess.hs_stride;
|
||||
type = array(TypeU32Vector(state, 4), (stride + 15u) / 16u);
|
||||
if (kind != Attribute::LocalOutput) {
|
||||
type = array(type, local ? tess.input_control_points : tess.output_control_points);
|
||||
}
|
||||
}
|
||||
auto& variable = state.tess_variables[index];
|
||||
variable = DefineInterfaceVariable(state, type, storage, "tess_attributes");
|
||||
if (kind == Attribute::Factor) {
|
||||
state.builder.AddAnnotation(spv::OpDecorate, variable, spv::DecorationBuiltIn,
|
||||
spv::BuiltInTessLevelOuter);
|
||||
state.tess_inner_variable =
|
||||
DefineInterfaceVariable(state, array(TypeF32(state), 2u), storage, "tess_inner");
|
||||
state.builder.AddAnnotation(spv::OpDecorate, state.tess_inner_variable,
|
||||
spv::DecorationBuiltIn, spv::BuiltInTessLevelInner);
|
||||
state.builder.AddAnnotation(spv::OpDecorate, state.tess_inner_variable,
|
||||
spv::DecorationPatch);
|
||||
} else {
|
||||
state.builder.AddAnnotation(
|
||||
spv::OpDecorate, variable, spv::DecorationLocation,
|
||||
kind == Attribute::PatchOutput ? (tess.hs_stride + 15u) / 16u : 0u);
|
||||
}
|
||||
if (kind == Attribute::Factor || kind == Attribute::PatchOutput) {
|
||||
state.builder.AddAnnotation(spv::OpDecorate, variable, spv::DecorationPatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void DefineModule(EmitterState& state) {
|
||||
@@ -543,6 +615,7 @@ void DefineModule(EmitterState& state) {
|
||||
state.program.info.outputs.size());
|
||||
DefineInputs(state);
|
||||
DefineOutputs(state);
|
||||
DefineTessellationInterfaces(state);
|
||||
DefineDescriptors(state);
|
||||
if (state.requirements.function_lds) {
|
||||
state.lds_variable = state.builder.AllocateId();
|
||||
@@ -564,6 +637,21 @@ void DefineModule(EmitterState& state) {
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeOutputPrimitivesEXT,
|
||||
state.input_info.vertex->mesh.max_primitives);
|
||||
}
|
||||
if (state.program.stage == ShaderType::TessellationControl ||
|
||||
state.program.stage == ShaderType::TessellationEvaluation) {
|
||||
const auto& tess = state.input_info.vertex->tess;
|
||||
EXIT_NOT_IMPLEMENTED(tess.domain != 1u || tess.partitioning != 2u ||
|
||||
tess.output_topology != 2u);
|
||||
state.builder.RequireCapability(spv::CapabilityTessellation);
|
||||
if (state.program.stage == ShaderType::TessellationControl) {
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeOutputVertices,
|
||||
tess.output_control_points);
|
||||
} else {
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeTriangles);
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeSpacingFractionalOdd);
|
||||
state.builder.AddExecutionMode(state.main_func, spv::ExecutionModeVertexOrderCw);
|
||||
}
|
||||
}
|
||||
state.entry_label = state.builder.AllocateId();
|
||||
|
||||
state.builder.RequireCapability(spv::CapabilityShader);
|
||||
|
||||
Reference in New Issue
Block a user