diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp index 81f8d08d7..8b5e30a0d 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_context_get_set.cpp @@ -144,6 +144,25 @@ Id EmitGetAttribute(EmitContext& ctx, IR::Attribute attr, u32 comp, u32 index) { case IR::Attribute::BaryCoordNoPersp: return ctx.OpLoad(ctx.F32[1], ctx.OpAccessChain(ctx.input_f32, ctx.bary_coord_nopersp, ctx.ConstU32(comp))); + case IR::Attribute::BaryCoordPullModel: + if (ctx.profile.supports_amd_shader_explicit_vertex_parameter) { + return ctx.OpLoad(ctx.F32[1], ctx.OpAccessChain(ctx.input_f32, ctx.bary_coord_pullmodel, + ctx.ConstU32(comp))); + } else { + switch (comp) { + case 0: + return ctx.OpLoad( + ctx.F32[1], ctx.OpAccessChain(ctx.input_f32, ctx.frag_coord, ctx.ConstU32(3U))); + case 1: + case 2: + return ctx.OpFDiv( + ctx.F32[1], ctx.ConstF32(1.0f), + ctx.OpLoad(ctx.F32[1], ctx.OpAccessChain(ctx.input_f32, ctx.bary_coord_nopersp, + ctx.ConstU32(comp)))); + default: + UNREACHABLE_MSG("BaryCoordPullModel comp {}", comp); + } + } default: UNREACHABLE_MSG("Read attribute {}", attr); } diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp index 9ec342b59..5df1d812d 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.cpp @@ -418,6 +418,15 @@ void EmitContext::DefineInputs() { spv::StorageClass::Input); } } + if (info.loads.GetAny(IR::Attribute::BaryCoordPullModel)) { + if (profile.supports_amd_shader_explicit_vertex_parameter) { + bary_coord_pullmodel = DefineVariable(F32[3], spv::BuiltIn::BaryCoordPullModelAMD, + spv::StorageClass::Input); + } else if (profile.supports_fragment_shader_barycentric) { + bary_coord_nopersp = DefineVariable(F32[3], spv::BuiltIn::BaryCoordNoPerspKHR, + spv::StorageClass::Input); + } + } const bool has_clip_distance_inputs = runtime_info.fs_info.clip_distance_emulation; // Clip distances attribute vector is the last in inputs array diff --git a/src/shader_recompiler/backend/spirv/spirv_emit_context.h b/src/shader_recompiler/backend/spirv/spirv_emit_context.h index a9c6f0968..820a609a3 100644 --- a/src/shader_recompiler/backend/spirv/spirv_emit_context.h +++ b/src/shader_recompiler/backend/spirv/spirv_emit_context.h @@ -288,6 +288,7 @@ public: Id bary_coord_smooth_centroid{}; Id bary_coord_smooth_sample{}; Id bary_coord_nopersp{}; + Id bary_coord_pullmodel{}; struct TextureDefinition { const VectorIds* data_types; diff --git a/src/shader_recompiler/frontend/translate/vector_interpolation.cpp b/src/shader_recompiler/frontend/translate/vector_interpolation.cpp index f3da22845..24fef157e 100644 --- a/src/shader_recompiler/frontend/translate/vector_interpolation.cpp +++ b/src/shader_recompiler/frontend/translate/vector_interpolation.cpp @@ -98,14 +98,28 @@ void Translator::V_INTERP_MOV_F32(const GcnInst& inst) { const IR::Attribute attrib = IR::Attribute::Param0 + attr_index; const auto& attr = runtime_info.fs_info.inputs[attr_index]; auto& interp = info.fs_interpolation[attr_index]; - ASSERT(attr.is_flat || inst.src[0].code == 2); - if (profile.supports_amd_shader_explicit_vertex_parameter || - (profile.supports_fragment_shader_barycentric && - !profile.has_incomplete_fragment_shader_barycentric)) { + + if (!attr.is_flat && (profile.supports_amd_shader_explicit_vertex_parameter || + (profile.supports_fragment_shader_barycentric && + !profile.has_incomplete_fragment_shader_barycentric))) { // VSRC 0=P10, 1=P20, 2=P0 interp.primary = Qualifier::PerVertex; - SetDst(inst.dst[0], - ir.GetAttribute(attrib, inst.control.vintrp.chan, (inst.src[0].code + 1) % 3)); + switch (inst.src[0].code) { + case 0: { // P10 + const IR::F32 p0 = ir.GetAttribute(attrib, inst.control.vintrp.chan, 0); + const IR::F32 p1 = ir.GetAttribute(attrib, inst.control.vintrp.chan, 1); + return SetDst(inst.dst[0], ir.FPSub(p1, p0)); + } + case 1: { // P20 + const IR::F32 p0 = ir.GetAttribute(attrib, inst.control.vintrp.chan, 0); + const IR::F32 p2 = ir.GetAttribute(attrib, inst.control.vintrp.chan, 2); + return SetDst(inst.dst[0], ir.FPSub(p2, p0)); + } + case 2: // P0 + return SetDst(inst.dst[0], ir.GetAttribute(attrib, inst.control.vintrp.chan, 0)); + default: + UNREACHABLE(); + } } else { interp.primary = Qualifier::Flat; SetDst(inst.dst[0], ir.GetAttribute(attrib, inst.control.vintrp.chan));