Fix centroid interpolation weights

PPSA03792
This commit is contained in:
nmzik
2026-09-15 19:51:30 +04:00
parent 9cf7963f44
commit 0d9e95d96a
8 changed files with 128 additions and 16 deletions
+41
View File
@@ -1219,6 +1219,8 @@ struct GraphicsCase {
bool pixel_position_w = false;
float vertex_clip_w = 1.0f;
bool pixel_depth_export = false;
u32 pixel_perspective_centroid_vgpr = UINT32_MAX;
u32 pixel_custom_interpolation_mask = 0;
};
struct CompiledShader {
@@ -1565,6 +1567,8 @@ CompiledShader CompileFragmentCase(const GraphicsCase &test) {
pixel_info.ps_pos_w = test.pixel_position_w;
pixel_info.ps_depth_export_enable = test.pixel_depth_export;
pixel_info.ps_system_input_base = 2;
pixel_info.ps_perspective_centroid_vgpr = test.pixel_perspective_centroid_vgpr;
pixel_info.custom_interpolation_mask = test.pixel_custom_interpolation_mask;
for (u32 i = 0; i < std::size(pixel_info.interpolator_settings); i++) {
pixel_info.interpolator_settings[i] = i;
}
@@ -25553,6 +25557,37 @@ GraphicsCase GraphicsPositionWExport() {
return test;
}
GraphicsCase GraphicsPackedHalfCentroid() {
GraphicsCase test;
test.name = "GraphicsPackedHalfCentroid";
test.pixel_perspective_centroid_vgpr = 0;
test.pixel_custom_interpolation_mask = 1;
test.pixel_interpolator_settings = {0x420u};
// Captured ab810715011baef3 interpolation, with attr3.x remapped to attr0.x.
test.fragment_code = {
0xc8120002u, 0xc80e0000u, // raw vertex0/vertex1 packed halves
0xcc204007u, 0x9c1206f2u, // low(vertex1) - low(vertex0)
0xcc207005u, 0x9c1206f2u, // high(vertex1) - high(vertex0)
0xc80a0001u, // raw vertex2
0xcc204006u, 0x9c1204f2u,
0xcc207003u, 0x9c1204f2u,
0xcc20400eu, 0x04120f00u, // low = I * delta10 + vertex0
0xcc20600fu, 0x04120b00u, // high = I * delta10 + vertex0
0x3e1c0306u, 0x3e1e0303u, // += J * delta20
EncodeExp0(0x00, 0xf), EncodeExp1(14, 15, 14, 15)};
AppendEnd(&test.fragment_code);
// At the pixel center the vertex weights are (5/8, 1/8, 1/4).
// Packed values are (0,1), (1,2), (3,3): expected result (0.875, 1.625).
test.vertices = {
0xbf800000u, 0xbf800000u, 0x3c000000u, 0, 0, 0,
0x40e00000u, 0xbf800000u, 0x40003c00u, 0, 0, 0,
0xbf800000u, 0x40400000u, 0x42004200u, 0, 0, 0};
test.expected_pixel = {0x3f600000u, 0x3fd00000u, 0x3f600000u, 0x3fd00000u};
test.opcodes = {ShaderOpcode::V_INTERP_MOV_F32, ShaderOpcode::V_FMA_F32, ShaderOpcode::V_MAC_F32,
ShaderOpcode::EXP, ShaderOpcode::S_ENDPGM};
return test;
}
GraphicsCase GraphicsAncillaryLayer(bool front_face) {
GraphicsCase test;
test.name = front_face ? "GraphicsAncillaryAfterFrontFace" : "GraphicsAncillaryLayer";
@@ -26196,6 +26231,7 @@ std::vector<GraphicsCase> MakeGraphicsCases() {
return {
GraphicsInterpolationExport(),
GraphicsPositionWExport(),
GraphicsPackedHalfCentroid(),
GraphicsAncillaryLayer(false),
GraphicsAncillaryLayer(true),
GraphicsAncillarySampleId(),
@@ -30665,6 +30701,11 @@ int main(int argc, char **argv) {
RunGraphicsCase(&vulkan, GraphicsPositionWExport());
return 0;
}
if (argc == 2 && std::strcmp(argv[1], "--centroid-only") == 0) {
VulkanHarness vulkan;
RunGraphicsCase(&vulkan, GraphicsPackedHalfCentroid());
return 0;
}
if (argc == 2 && std::strcmp(argv[1], "--clip-control-only") == 0) {
CheckClipControlDepthClipState();
return 0;
+48
View File
@@ -6103,6 +6103,53 @@ void TestCustomVintrpMovTranslation() {
CheckSpirvBinaryValidates(mixed_linear_result.spirv);
}
void TestPerspectiveCentroidInputs() {
constexpr std::array cases{std::array{4u, UINT32_MAX, 0u},
std::array{5u, UINT32_MAX, 2u},
std::array{6u, 0u, 2u}, std::array{7u, 2u, 4u}};
for (const auto &[inputs, center, centroid] : cases) {
const uint32_t other = center == UINT32_MAX ? centroid : center;
const std::vector<uint32_t> shader = {
EncodeExp0(0x00, 0xf), EncodeExp1(centroid, centroid + 1, other, other + 1),
EncodeSopp(0x01)};
HW::PixelShaderInfo regs{};
regs.ps_regs.data_addr = reinterpret_cast<uint64_t>(shader.data());
ShaderMappedData mapped{};
mapped.code_size_bytes = shader.size() * sizeof(uint32_t);
ShaderMapUserData(regs.ps_regs.data_addr, mapped);
HW::ShaderRegisters sh{};
sh.ps_input_ena = sh.ps_input_addr = inputs;
const std::array<Prospero::ColorComponentMapping, 8> mappings{};
ShaderPixelInputInfo pixel{};
(void)PrepareProgram(regs, sh, mappings, pixel);
Check(pixel.ps_perspective_centroid_vgpr == centroid &&
pixel.ps_perspective_center_vgpr == center &&
pixel.ps_system_input_base == centroid + 2,
"perspective-centroid pair did not follow enabled sample/center inputs");
const auto key = MakeStageStaticKey(pixel);
pixel.ps_perspective_centroid_vgpr = UINT32_MAX;
Check(key != MakeStageStaticKey(pixel), "centroid input is missing from shader key");
pixel.ps_perspective_centroid_vgpr = centroid;
auto options = MakeCompileOptions(ShaderType::Pixel);
options.input_info.pixel = &pixel;
const auto result = RecompileForTest(shader, options);
const auto source = DisassembleSpirvBinary(result.spirv);
Check(SpirvContainsCapability(result.spirv, 52u) &&
SpirvHasDecorationValue(result.spirv, 11u, 5286u) &&
Common::ContainsStr(source, "InterpolateAtCentroid %gl_BaryCoordKHR") &&
SpirvSourceHasInstructionUsing(source, "OpCompositeExtract", " 1") &&
SpirvSourceHasInstructionUsing(source, "OpCompositeExtract", " 2"),
"centroid I/J did not evaluate BaryCoordKHR Y/Z at the centroid");
Check(!SpirvHasDecorationValueWithDecoration(result.spirv, 11u, 5286u, 16u),
"centroid input changed the shared center builtin's interpolation location");
if (center != UINT32_MAX) {
Check(SpirvSourceHasInstructionUsing(source, "OpLoad", "%float "),
"center pair lost its ordinary barycentric loads when centroid was enabled");
}
CheckSpirvBinaryValidates(result.spirv);
}
}
void TestPsInputCountRegisterDecode() {
HW::Context context;
// NUM_INTERP is 3 while bit 14 is an independent control flag that must be
@@ -13444,6 +13491,7 @@ int main() {
TestNewShaderRecompilerNativeBindingPlan();
TestNewShaderRecompilerStageInputInfo();
TestCustomVintrpMovTranslation();
TestPerspectiveCentroidInputs();
TestGraphicsCreateInterpolantMapping();
TestNewShaderRecompilerPixelPipelineEntry();
TestComputeLdsAllocationIdentity();