mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-19 18:36:53 +02:00
shader: honor front-face input format
This commit is contained in:
@@ -52,9 +52,12 @@ uint32_t EmitBuiltinU32(EmitterState& state, IR::StageInputKind kind, uint32_t c
|
||||
const auto value = state.builder.AllocateId();
|
||||
const auto bits = state.builder.AllocateId();
|
||||
state.builder.AddFunction(spv::OpLoad, TypeBool(state), value, variable);
|
||||
// PS5 initializes v_front_face with float +1.0/-1.0 bits.
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), bits, value,
|
||||
ConstantU32(state, 0x3f800000u), ConstantU32(state, 0xbf800000u));
|
||||
// SPI_BARYC_CNTL.FRONT_FACE_ALL_BITS selects uint masks or float +/-1.
|
||||
const bool all_bits =
|
||||
state.input_info.pixel != nullptr && state.input_info.pixel->ps_front_face_all_bits;
|
||||
const auto front = ConstantU32(state, all_bits ? 0xffffffffu : 0x3f800000u);
|
||||
const auto back = ConstantU32(state, all_bits ? 0u : 0xbf800000u);
|
||||
state.builder.AddFunction(spv::OpSelect, TypeU32(state), bits, value, front, back);
|
||||
return bits;
|
||||
}
|
||||
if (kind == IR::StageInputKind::VertexIndex || kind == IR::StageInputKind::InstanceIndex ||
|
||||
|
||||
@@ -344,6 +344,8 @@ static void ShaderGetStaticInputInfoPS(
|
||||
ps_info.ps_pos_z = (active_inputs & 0x00000400u) != 0;
|
||||
ps_info.ps_pos_w = (active_inputs & 0x00000800u) != 0;
|
||||
ps_info.ps_front_face = (active_inputs & 0x00001000u) != 0;
|
||||
// SPI_BARYC_CNTL.FRONT_FACE_ALL_BITS selects integer masks instead of float +/-1.
|
||||
ps_info.ps_front_face_all_bits = (sh.baryc_cntl & 0x01000000u) != 0;
|
||||
ps_info.ps_ancillary = (active_inputs & 0x00002000u) != 0;
|
||||
ps_info.ps_sample_shading = (active_inputs & 0x00000011u) != 0;
|
||||
ps_info.ps_no_perspective = (sh.ps_input_ena & sh.ps_input_addr & 0x00000020u) != 0;
|
||||
@@ -464,6 +466,7 @@ void BuildStageStaticKey(const ShaderPixelInputInfo& info, std::vector<uint32_t>
|
||||
key.push_back(static_cast<uint32_t>(info.ps_pos_z));
|
||||
key.push_back(static_cast<uint32_t>(info.ps_pos_w));
|
||||
key.push_back(static_cast<uint32_t>(info.ps_front_face));
|
||||
key.push_back(static_cast<uint32_t>(info.ps_front_face_all_bits));
|
||||
key.push_back(static_cast<uint32_t>(info.ps_ancillary));
|
||||
key.push_back(static_cast<uint32_t>(info.ps_no_perspective));
|
||||
key.push_back(static_cast<uint32_t>(info.parameter_mode));
|
||||
@@ -737,6 +740,7 @@ void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo& info) {
|
||||
"\t ps_pos_z = %s\n"
|
||||
"\t ps_pos_w = %s\n"
|
||||
"\t ps_front_face = %s\n"
|
||||
"\t ps_front_face_all_bits = %s\n"
|
||||
"\t ps_ancillary = %s\n"
|
||||
"\t ps_sample_shading = %s\n"
|
||||
"\t ps_no_perspective = %s\n"
|
||||
@@ -745,11 +749,10 @@ void ShaderDbgDumpInputInfo(const ShaderPixelInputInfo& info) {
|
||||
"\t ps_execute_on_noop = %s\n",
|
||||
info.input_num, info.ps_system_input_base, info.custom_interpolation_mask,
|
||||
info.ps_perspective_center_vgpr, info.ps_perspective_sample_vgpr,
|
||||
info.ps_perspective_centroid_vgpr,
|
||||
info.ps_pos_x ? "true" : "false",
|
||||
info.ps_perspective_centroid_vgpr, info.ps_pos_x ? "true" : "false",
|
||||
info.ps_pos_y ? "true" : "false", info.ps_pos_z ? "true" : "false",
|
||||
info.ps_pos_w ? "true" : "false", info.ps_front_face ? "true" : "false",
|
||||
info.ps_ancillary ? "true" : "false",
|
||||
info.ps_front_face_all_bits ? "true" : "false", info.ps_ancillary ? "true" : "false",
|
||||
info.ps_sample_shading ? "true" : "false", info.ps_no_perspective ? "true" : "false",
|
||||
info.ps_pixel_kill_enable ? "true" : "false", info.ps_early_z ? "true" : "false",
|
||||
info.ps_execute_on_noop ? "true" : "false");
|
||||
|
||||
@@ -196,6 +196,7 @@ struct ShaderPixelInputInfo {
|
||||
bool ps_pos_z = false;
|
||||
bool ps_pos_w = false;
|
||||
bool ps_front_face = false;
|
||||
bool ps_front_face_all_bits = false;
|
||||
bool ps_ancillary = false;
|
||||
bool ps_no_perspective = false;
|
||||
ShaderPixelParameterMode parameter_mode = ShaderPixelParameterMode::FirstVertex;
|
||||
|
||||
@@ -1383,6 +1383,7 @@ struct GraphicsCase {
|
||||
std::vector<u32> vertices;
|
||||
bool pixel_ancillary = false;
|
||||
bool pixel_front_face = false;
|
||||
bool pixel_front_face_all_bits = false;
|
||||
u32 layers = 1;
|
||||
vk::SampleCountFlagBits samples = vk::SampleCountFlagBits::e1;
|
||||
bool pixel_position_w = false;
|
||||
@@ -1834,6 +1835,7 @@ CompiledShader CompileFragmentCase(const GraphicsCase &test) {
|
||||
: ShaderPixelParameterMode::FirstVertex;
|
||||
pixel_info.ps_ancillary = test.pixel_ancillary;
|
||||
pixel_info.ps_front_face = test.pixel_front_face;
|
||||
pixel_info.ps_front_face_all_bits = test.pixel_front_face_all_bits;
|
||||
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;
|
||||
@@ -41299,6 +41301,83 @@ GraphicsCase GraphicsAncillarySampleId() {
|
||||
return test;
|
||||
}
|
||||
|
||||
// SPI_BARYC_CNTL[24] selects all-bits mode for uint/bool S_FRONT_FACE;
|
||||
// float S_FRONT_FACE and __getSpecialVgprFloat(__v_front_face) leave it clear.
|
||||
GraphicsCase GraphicsFrontFaceBits(bool reversed, bool all_bits) {
|
||||
GraphicsCase test;
|
||||
test.name = all_bits ? (reversed ? "GraphicsFrontFaceUintFront" : "GraphicsFrontFaceUintBack")
|
||||
: (reversed ? "GraphicsFrontFaceFloatFront" : "GraphicsFrontFaceFloatBack");
|
||||
test.pixel_front_face = true;
|
||||
test.pixel_front_face_all_bits = all_bits;
|
||||
// Preserve every raw bit as two finite, exactly representable integer-to-float
|
||||
// results. Directly exporting the integer front value would export a NaN.
|
||||
AppendVop3(&test.fragment_code, 0x148, 4, Vgpr(2), InlineU32(0), InlineU32(16));
|
||||
AppendVop3(&test.fragment_code, 0x148, 5, Vgpr(2), InlineU32(16), InlineU32(16));
|
||||
test.fragment_code.push_back(EncodeVop1(0x06, 0, Vgpr(4)));
|
||||
test.fragment_code.push_back(EncodeVop1(0x06, 1, Vgpr(5)));
|
||||
// Integer inputs test raw zero; float inputs test the sign.
|
||||
test.fragment_code.push_back(EncodeVopc(all_bits ? 0xc2 : 0x04, InlineU32(0), 2));
|
||||
AppendVMovLiteral(&test.fragment_code, 3, 0x3f800000u);
|
||||
test.fragment_code.push_back(EncodeVop2(0x01, 2, InlineU32(0), 3));
|
||||
test.fragment_code.push_back(EncodeExp0(0x00, 0xf));
|
||||
test.fragment_code.push_back(EncodeExp1(0, 1, 2, 3));
|
||||
AppendEnd(&test.fragment_code);
|
||||
test.opcodes = {ShaderOpcode::V_BFE_U32, ShaderOpcode::V_CVT_F32_U32,
|
||||
all_bits ? ShaderOpcode::V_CMP_EQ_U32 : ShaderOpcode::V_CMP_GT_F32,
|
||||
ShaderOpcode::V_CNDMASK_B32, ShaderOpcode::V_MOV_B32,
|
||||
ShaderOpcode::EXP, ShaderOpcode::S_ENDPGM};
|
||||
test.vertices = {
|
||||
0xbf800000u, 0xbf800000u, 0x3e800000u, 0x3f000000u, 0x3f400000u, 0x3f800000u,
|
||||
0x40400000u, 0xbf800000u, 0x3e800000u, 0x3f000000u, 0x3f400000u, 0x3f800000u,
|
||||
0xbf800000u, 0x40400000u, 0x3e800000u, 0x3f000000u, 0x3f400000u, 0x3f800000u};
|
||||
if (reversed) {
|
||||
std::swap_ranges(test.vertices.begin() + 6, test.vertices.begin() + 12,
|
||||
test.vertices.begin() + 12);
|
||||
}
|
||||
// With the harness's positive-height viewport, the default triangle faces back.
|
||||
const u32 bits = all_bits ? (reversed ? UINT32_MAX : 0u)
|
||||
: (reversed ? 0x3f800000u : 0xbf800000u);
|
||||
test.expected_pixel = {
|
||||
std::bit_cast<u32>(static_cast<float>(bits & 0xffffu)),
|
||||
std::bit_cast<u32>(static_cast<float>(bits >> 16u)),
|
||||
reversed ? 0u : 0x3f800000u, 0x3f800000u};
|
||||
return test;
|
||||
}
|
||||
|
||||
void CheckPixelFrontFaceModes() {
|
||||
constexpr const char *name = "PixelFrontFaceModes";
|
||||
static const std::array<u32, 1> code = {EncodeSopp(0x01)};
|
||||
HW::PixelShaderInfo regs{};
|
||||
regs.ps_regs.data_addr = reinterpret_cast<uint64_t>(code.data());
|
||||
ShaderMapUserData(regs.ps_regs.data_addr,
|
||||
{.type = Prospero::ShaderBinaryType::kPs,
|
||||
.code_size_bytes = static_cast<u32>(sizeof(code))});
|
||||
HW::ShaderRegisters sh{};
|
||||
sh.ps_input_ena = sh.ps_input_addr = 0x1002u;
|
||||
const std::array<Prospero::ColorComponentMapping, 8> export_mapping{};
|
||||
std::vector<u32> float_key;
|
||||
for (bool all_bits : {false, true}) {
|
||||
for (u32 other_bits : {0u, 0x120u}) {
|
||||
sh.baryc_cntl = (all_bits ? 0x01000000u : 0u) | other_bits;
|
||||
ShaderPixelInputInfo pixel{};
|
||||
(void)PrepareProgram(regs, sh, export_mapping, pixel);
|
||||
Require(name, "register format decoding",
|
||||
pixel.ps_front_face && pixel.ps_front_face_all_bits == all_bits &&
|
||||
pixel.ps_system_input_base == 2u,
|
||||
"SPI_BARYC_CNTL[24] did not select the front-face format");
|
||||
std::vector<u32> key;
|
||||
BuildStageStaticKey(pixel, key);
|
||||
if (!all_bits && other_bits == 0u) {
|
||||
float_key = key;
|
||||
}
|
||||
Require(name, "format specialization",
|
||||
(key != float_key) == all_bits,
|
||||
"front-face formats must have distinct shader keys and ignore unrelated bits");
|
||||
}
|
||||
}
|
||||
std::printf("[host] %-32s ok\n", name);
|
||||
}
|
||||
|
||||
GraphicsCase GraphicsFlatInterpolatorExport() {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
@@ -42179,6 +42258,10 @@ std::vector<GraphicsCase> MakeGraphicsCases() {
|
||||
GraphicsAncillaryLayer(false),
|
||||
GraphicsAncillaryLayer(true),
|
||||
GraphicsAncillarySampleId(),
|
||||
GraphicsFrontFaceBits(false, false),
|
||||
GraphicsFrontFaceBits(true, false),
|
||||
GraphicsFrontFaceBits(false, true),
|
||||
GraphicsFrontFaceBits(true, true),
|
||||
GraphicsFlatInterpolatorExport(),
|
||||
GraphicsDsAddtidScratchExport(),
|
||||
GraphicsDirectSgprPushConstantExport(),
|
||||
@@ -47959,6 +48042,17 @@ int main(int argc, char **argv) {
|
||||
RunCase(&vulkan, SiblingSharedExitKeepsCapturedConditions());
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--front-face-only") == 0) {
|
||||
CheckPixelFrontFaceModes();
|
||||
VulkanHarness vulkan;
|
||||
for (bool all_bits : {false, true}) {
|
||||
for (bool reversed : {false, true}) {
|
||||
RunGraphicsCase(&vulkan, GraphicsFrontFaceBits(reversed, all_bits));
|
||||
}
|
||||
}
|
||||
RunGraphicsCase(&vulkan, GraphicsAncillaryLayer(true));
|
||||
return 0;
|
||||
}
|
||||
if (argc == 2 && std::strcmp(argv[1], "--position-w-only") == 0) {
|
||||
VulkanHarness vulkan;
|
||||
RunGraphicsCase(&vulkan, GraphicsPositionWExport());
|
||||
@@ -48574,6 +48668,7 @@ int main(int argc, char **argv) {
|
||||
CheckEmbeddedFetchLaneSpill();
|
||||
CheckTessellationPrograms();
|
||||
CheckPixelParameterAliases();
|
||||
CheckPixelFrontFaceModes();
|
||||
CheckRectListShaders();
|
||||
CheckSigned16ImageStore(vulkan);
|
||||
CheckBoundedFormattedBufferCopy(vulkan);
|
||||
|
||||
Reference in New Issue
Block a user