mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01:00
Preserve vertex export locations for mixed pixel interpolation
This commit is contained in:
@@ -617,6 +617,13 @@ PipelineCache::GraphicsPrograms PipelineCache::GetGraphicsPrograms(
|
|||||||
ShaderParams pixel_params;
|
ShaderParams pixel_params;
|
||||||
if (pixel_active) {
|
if (pixel_active) {
|
||||||
pixel_params = PrepareProgram(pixel_regs, sh, target_export_mapping, pixel_info);
|
pixel_params = PrepareProgram(pixel_regs, sh, target_export_mapping, pixel_info);
|
||||||
|
if (!mesh_active && !tess_active && Prospero::IsRectList(user_config.GetPrimType())) {
|
||||||
|
pixel_info.parameter_mode = ShaderPixelParameterMode::Rectangle;
|
||||||
|
} else if (context.GetModeControl().provoking_vtx_last) {
|
||||||
|
pixel_info.parameter_mode = ShaderPixelParameterMode::LastVertex;
|
||||||
|
} else {
|
||||||
|
pixel_info.parameter_mode = ShaderPixelParameterMode::FirstVertex;
|
||||||
|
}
|
||||||
const auto& blend = context.GetBlendControl(0);
|
const auto& blend = context.GetBlendControl(0);
|
||||||
pixel_info.dual_source_blending =
|
pixel_info.dual_source_blending =
|
||||||
blend.enable && !context.GetRenderTarget(0).info.blend_bypass &&
|
blend.enable && !context.GetRenderTarget(0).info.blend_bypass &&
|
||||||
|
|||||||
@@ -177,6 +177,13 @@ uint32_t EmitAttribute(EmitterState& state, uint32_t attr, uint32_t chan) {
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
if (input->per_vertex) {
|
if (input->per_vertex) {
|
||||||
|
if (PixelParameterIsFlat(state, attr)) {
|
||||||
|
const auto value = load_per_vertex(
|
||||||
|
state.input_info.pixel->parameter_mode == ShaderPixelParameterMode::LastVertex ? 2u : 0u);
|
||||||
|
const auto bits = state.builder.AllocateId();
|
||||||
|
state.builder.AddFunction(spv::OpBitcast, TypeU32(state), bits, value);
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
const auto barycentric_kind = state.input_info.pixel->ps_no_perspective
|
const auto barycentric_kind = state.input_info.pixel->ps_no_perspective
|
||||||
? IR::StageInputKind::BaryCoordNoPerspective
|
? IR::StageInputKind::BaryCoordNoPerspective
|
||||||
: IR::StageInputKind::BaryCoordSmooth;
|
: IR::StageInputKind::BaryCoordSmooth;
|
||||||
@@ -231,8 +238,12 @@ uint32_t EmitInterpolationParameter(ValueEmitContext& ctx, uint32_t attr, uint32
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto selected_vertex = (mode + 1u) % 3u;
|
uint32_t selected_vertex = (mode + 1u) % 3u;
|
||||||
uint32_t value = load_vertex(selected_vertex);
|
if (mode == 2u && PixelParameterIsFlat(state, attr)) {
|
||||||
|
selected_vertex =
|
||||||
|
state.input_info.pixel->parameter_mode == ShaderPixelParameterMode::LastVertex ? 2u : 0u;
|
||||||
|
}
|
||||||
|
uint32_t value = load_vertex(selected_vertex);
|
||||||
if (!PixelParameterIsCustom(state, attr) && mode < 2u) {
|
if (!PixelParameterIsCustom(state, attr) && mode < 2u) {
|
||||||
const auto delta = state.builder.AllocateId();
|
const auto delta = state.builder.AllocateId();
|
||||||
state.builder.AddFunction(spv::OpFSub, TypeF32(state), delta, value, load_vertex(0));
|
state.builder.AddFunction(spv::OpFSub, TypeF32(state), delta, value, load_vertex(0));
|
||||||
|
|||||||
@@ -227,15 +227,16 @@ void CollectPixelInputs(const Program& program, const ShaderPixelInputInfo* pixe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Aliases of a vertex output share one SPIR-V interface variable. If any
|
// Mixed interpolation modes share raw vertices at their guest export slot.
|
||||||
// alias reads raw vertices, interpolate the other aliases from those too.
|
// Rectangle expansion alone supplies separate flat and smooth outputs.
|
||||||
for (uint32_t input = 0; input < pixel->input_num; input++) {
|
for (uint32_t input = 0; input < pixel->input_num; input++) {
|
||||||
for (uint32_t alias = 0; alias < pixel->input_num; alias++) {
|
for (uint32_t alias = 0; alias < pixel->input_num; alias++) {
|
||||||
|
const bool same_mode = ShaderPixelParameterIsFlat(*pixel, input) ==
|
||||||
|
ShaderPixelParameterIsFlat(*pixel, alias);
|
||||||
if (ShaderPixelParameterMappedLocation(*pixel, input) ==
|
if (ShaderPixelParameterMappedLocation(*pixel, input) ==
|
||||||
ShaderPixelParameterMappedLocation(*pixel, alias) &&
|
ShaderPixelParameterMappedLocation(*pixel, alias) &&
|
||||||
ShaderPixelParameterIsFlat(*pixel, input) ==
|
(pixel->parameter_mode != ShaderPixelParameterMode::Rectangle || same_mode)) {
|
||||||
ShaderPixelParameterIsFlat(*pixel, alias)) {
|
per_vertex[input] = per_vertex[input] || per_vertex[alias] || !same_mode;
|
||||||
per_vertex[input] = per_vertex[input] || per_vertex[alias];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,7 +245,8 @@ void CollectPixelInputs(const Program& program, const ShaderPixelInputInfo* pixe
|
|||||||
per_vertex[input]);
|
per_vertex[input]);
|
||||||
}
|
}
|
||||||
for (uint32_t input = 0; input < pixel->input_num; input++) {
|
for (uint32_t input = 0; input < pixel->input_num; input++) {
|
||||||
if (interpolated[input] && per_vertex[input]) {
|
if (interpolated[input] && per_vertex[input] &&
|
||||||
|
!ShaderPixelParameterIsFlat(*pixel, input)) {
|
||||||
const auto kind = pixel->ps_no_perspective ? StageInputKind::BaryCoordNoPerspective
|
const auto kind = pixel->ps_no_perspective ? StageInputKind::BaryCoordNoPerspective
|
||||||
: StageInputKind::BaryCoordSmooth;
|
: StageInputKind::BaryCoordSmooth;
|
||||||
AddInput(info, kind, 0, 3,
|
AddInput(info, kind, 0, 3,
|
||||||
|
|||||||
@@ -663,6 +663,7 @@ void BuildStageStaticKey(const ShaderPixelInputInfo& info, std::vector<uint32_t>
|
|||||||
key.push_back(static_cast<uint32_t>(info.ps_front_face));
|
key.push_back(static_cast<uint32_t>(info.ps_front_face));
|
||||||
key.push_back(static_cast<uint32_t>(info.ps_ancillary));
|
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.ps_no_perspective));
|
||||||
|
key.push_back(static_cast<uint32_t>(info.parameter_mode));
|
||||||
key.push_back(static_cast<uint32_t>(info.ps_pixel_kill_enable));
|
key.push_back(static_cast<uint32_t>(info.ps_pixel_kill_enable));
|
||||||
key.push_back(static_cast<uint32_t>(info.ps_depth_export_enable));
|
key.push_back(static_cast<uint32_t>(info.ps_depth_export_enable));
|
||||||
key.push_back(static_cast<uint32_t>(info.ps_sample_mask_export_enable));
|
key.push_back(static_cast<uint32_t>(info.ps_sample_mask_export_enable));
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ struct ShaderComputeInputInfo: ShaderWorkgroupInputInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
enum class ShaderAlphaBlendSource : uint8_t { None, SourceAlpha, SourceAlphaOne, SourceAlphaZero };
|
enum class ShaderAlphaBlendSource : uint8_t { None, SourceAlpha, SourceAlphaOne, SourceAlphaZero };
|
||||||
|
enum class ShaderPixelParameterMode : uint8_t { FirstVertex, LastVertex, Rectangle };
|
||||||
|
|
||||||
struct ShaderPixelInputInfo {
|
struct ShaderPixelInputInfo {
|
||||||
uint32_t interpolator_settings[32] = {0};
|
uint32_t interpolator_settings[32] = {0};
|
||||||
@@ -180,6 +181,7 @@ struct ShaderPixelInputInfo {
|
|||||||
bool ps_front_face = false;
|
bool ps_front_face = false;
|
||||||
bool ps_ancillary = false;
|
bool ps_ancillary = false;
|
||||||
bool ps_no_perspective = false;
|
bool ps_no_perspective = false;
|
||||||
|
ShaderPixelParameterMode parameter_mode = ShaderPixelParameterMode::FirstVertex;
|
||||||
bool ps_pixel_kill_enable = false;
|
bool ps_pixel_kill_enable = false;
|
||||||
bool ps_depth_export_enable = false;
|
bool ps_depth_export_enable = false;
|
||||||
bool ps_sample_mask_export_enable = false;
|
bool ps_sample_mask_export_enable = false;
|
||||||
|
|||||||
@@ -30,6 +30,9 @@ uint32_t ShaderPixelParameterMappedLocation(const ShaderPixelInputInfo& info, ui
|
|||||||
|
|
||||||
uint32_t ShaderPixelParameterLocation(const ShaderPixelInputInfo& info,
|
uint32_t ShaderPixelParameterLocation(const ShaderPixelInputInfo& info,
|
||||||
std::span<const uint32_t> active_inputs, uint32_t input) {
|
std::span<const uint32_t> active_inputs, uint32_t input) {
|
||||||
|
if (info.parameter_mode != ShaderPixelParameterMode::Rectangle) {
|
||||||
|
return ShaderPixelParameterMappedLocation(info, input);
|
||||||
|
}
|
||||||
std::array<bool, 32> used_locations {};
|
std::array<bool, 32> used_locations {};
|
||||||
for (const auto active_input: active_inputs) {
|
for (const auto active_input: active_inputs) {
|
||||||
used_locations[ShaderPixelParameterMappedLocation(info, active_input)] = true;
|
used_locations[ShaderPixelParameterMappedLocation(info, active_input)] = true;
|
||||||
@@ -42,8 +45,7 @@ uint32_t ShaderPixelParameterLocation(const ShaderPixelInputInfo& info,
|
|||||||
auto& location = group_locations[group];
|
auto& location = group_locations[group];
|
||||||
if (location == UINT32_MAX) {
|
if (location == UINT32_MAX) {
|
||||||
location = mapped;
|
location = mapped;
|
||||||
// Smooth and custom interpolation read the same vertex output. Only
|
// Rectangle expansion broadcasts flat aliases through separate outputs.
|
||||||
// differing flat/smooth rectangle outputs need separate locations.
|
|
||||||
if (group_locations[group ^ 1u] != UINT32_MAX) {
|
if (group_locations[group ^ 1u] != UINT32_MAX) {
|
||||||
location = 0;
|
location = 0;
|
||||||
while (location < used_locations.size() && used_locations[location]) {
|
while (location < used_locations.size() && used_locations[location]) {
|
||||||
|
|||||||
@@ -1353,6 +1353,7 @@ struct GraphicsCase {
|
|||||||
std::vector<u32> push_constants;
|
std::vector<u32> push_constants;
|
||||||
std::vector<u32> pixel_interpolator_settings;
|
std::vector<u32> pixel_interpolator_settings;
|
||||||
bool pixel_no_perspective = false;
|
bool pixel_no_perspective = false;
|
||||||
|
bool provoking_vtx_last = false;
|
||||||
std::vector<u32> vertices;
|
std::vector<u32> vertices;
|
||||||
bool pixel_ancillary = false;
|
bool pixel_ancillary = false;
|
||||||
bool pixel_front_face = false;
|
bool pixel_front_face = false;
|
||||||
@@ -1449,6 +1450,20 @@ void CheckPixelParameterAliases() {
|
|||||||
pixel.interpolator_settings[1] = 0u;
|
pixel.interpolator_settings[1] = 0u;
|
||||||
pixel.interpolator_settings[2] = 1u;
|
pixel.interpolator_settings[2] = 1u;
|
||||||
const std::array<uint32_t, 3> active = {0, 1, 2};
|
const std::array<uint32_t, 3> active = {0, 1, 2};
|
||||||
|
Require(name, "ordinary mixed aliases",
|
||||||
|
ShaderPixelParameterLocation(pixel, active, 0) == 0u &&
|
||||||
|
ShaderPixelParameterLocation(pixel, active, 1) == 0u &&
|
||||||
|
ShaderPixelParameterLocation(pixel, active, 2) == 1u,
|
||||||
|
"flat/smooth aliases must retain the real vertex export location");
|
||||||
|
std::vector<uint32_t> ordinary_key, rectangle_key, provoking_key;
|
||||||
|
BuildStageStaticKey(pixel, ordinary_key);
|
||||||
|
pixel.parameter_mode = ShaderPixelParameterMode::LastVertex;
|
||||||
|
BuildStageStaticKey(pixel, provoking_key);
|
||||||
|
pixel.parameter_mode = ShaderPixelParameterMode::Rectangle;
|
||||||
|
BuildStageStaticKey(pixel, rectangle_key);
|
||||||
|
Require(name, "interpolation specialization",
|
||||||
|
ordinary_key != rectangle_key && ordinary_key != provoking_key,
|
||||||
|
"rectangle and provoking-vertex modes must participate in the shader key");
|
||||||
Require(name, "reserved physical locations",
|
Require(name, "reserved physical locations",
|
||||||
ShaderPixelParameterLocation(pixel, active, 0) == 0u &&
|
ShaderPixelParameterLocation(pixel, active, 0) == 0u &&
|
||||||
ShaderPixelParameterLocation(pixel, active, 1) == 2u &&
|
ShaderPixelParameterLocation(pixel, active, 1) == 2u &&
|
||||||
@@ -1473,6 +1488,7 @@ void CheckRectListShaders() {
|
|||||||
vertex.stage.program = &vertex_program;
|
vertex.stage.program = &vertex_program;
|
||||||
vertex.stage.resources = &empty_snapshot;
|
vertex.stage.resources = &empty_snapshot;
|
||||||
ShaderPixelInputInfo pixel{};
|
ShaderPixelInputInfo pixel{};
|
||||||
|
pixel.parameter_mode = ShaderPixelParameterMode::Rectangle;
|
||||||
pixel.input_num = 2;
|
pixel.input_num = 2;
|
||||||
pixel.interpolator_settings[0] = 0x400u;
|
pixel.interpolator_settings[0] = 0x400u;
|
||||||
pixel.interpolator_settings[1] = 0;
|
pixel.interpolator_settings[1] = 0;
|
||||||
@@ -1774,6 +1790,8 @@ CompiledShader CompileFragmentCase(const GraphicsCase &test) {
|
|||||||
? 1u
|
? 1u
|
||||||
: static_cast<u32>(test.pixel_interpolator_settings.size());
|
: static_cast<u32>(test.pixel_interpolator_settings.size());
|
||||||
pixel_info.ps_no_perspective = test.pixel_no_perspective;
|
pixel_info.ps_no_perspective = test.pixel_no_perspective;
|
||||||
|
pixel_info.parameter_mode = test.provoking_vtx_last ? ShaderPixelParameterMode::LastVertex
|
||||||
|
: ShaderPixelParameterMode::FirstVertex;
|
||||||
pixel_info.ps_ancillary = test.pixel_ancillary;
|
pixel_info.ps_ancillary = test.pixel_ancillary;
|
||||||
pixel_info.ps_front_face = test.pixel_front_face;
|
pixel_info.ps_front_face = test.pixel_front_face;
|
||||||
pixel_info.ps_pos_w = test.pixel_position_w;
|
pixel_info.ps_pos_w = test.pixel_position_w;
|
||||||
@@ -16928,6 +16946,12 @@ public:
|
|||||||
raster.frontFace = vk::FrontFace::eCounterClockwise;
|
raster.frontFace = vk::FrontFace::eCounterClockwise;
|
||||||
raster.lineWidth = 1.0f;
|
raster.lineWidth = 1.0f;
|
||||||
|
|
||||||
|
vk::PipelineRasterizationProvokingVertexStateCreateInfoEXT provoking_vertex{};
|
||||||
|
if (test.provoking_vtx_last) {
|
||||||
|
provoking_vertex.provokingVertexMode = vk::ProvokingVertexModeEXT::eLastVertex;
|
||||||
|
raster.pNext = &provoking_vertex;
|
||||||
|
}
|
||||||
|
|
||||||
vk::PipelineMultisampleStateCreateInfo multisample{};
|
vk::PipelineMultisampleStateCreateInfo multisample{};
|
||||||
multisample.sType = vk::StructureType::ePipelineMultisampleStateCreateInfo;
|
multisample.sType = vk::StructureType::ePipelineMultisampleStateCreateInfo;
|
||||||
multisample.rasterizationSamples = test.samples;
|
multisample.rasterizationSamples = test.samples;
|
||||||
@@ -35871,6 +35895,38 @@ GraphicsCase GraphicsSmoothRawInputAlias() {
|
|||||||
return test;
|
return test;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GraphicsCase GraphicsSmoothFlatInputAlias(bool flat_first, bool provoking_last = false) {
|
||||||
|
auto test = GraphicsSmoothRawInputAlias();
|
||||||
|
test.name = provoking_last
|
||||||
|
? (flat_first ? "GraphicsFlatSmoothAliasLast" : "GraphicsSmoothFlatAliasLast")
|
||||||
|
: (flat_first ? "GraphicsFlatSmoothInputAlias" : "GraphicsSmoothFlatInputAlias");
|
||||||
|
test.pixel_custom_interpolation_mask = 0;
|
||||||
|
test.provoking_vtx_last = provoking_last;
|
||||||
|
test.pixel_interpolator_settings = flat_first ? std::vector<u32>{0x400u, 0u}
|
||||||
|
: std::vector<u32>{0u, 0x400u};
|
||||||
|
const u32 smooth = flat_first ? 1u : 0u;
|
||||||
|
const u32 flat = smooth ^ 1u;
|
||||||
|
// One export carries smooth values (2,4,8) and packed light IDs (5,7,11).
|
||||||
|
// Flat P0 preserves the ID bits; flat P1/P2 uses the same provoking vertex.
|
||||||
|
test.vertices[4] = 0x3f800005u;
|
||||||
|
test.vertices[10] = 0x3f800007u;
|
||||||
|
test.vertices[16] = 0x3f80000bu;
|
||||||
|
test.fragment_code = {EncodeVintrp(0x00, 0, smooth, 1, 0),
|
||||||
|
EncodeVintrp(0x01, 0, smooth, 1, 1),
|
||||||
|
EncodeVintrp(0x02, 1, flat, 2, 2),
|
||||||
|
EncodeVop2(0x1b, 1, InlineU32(63), 1),
|
||||||
|
EncodeVop1(0x06, 1, Vgpr(1)),
|
||||||
|
EncodeVintrp(0x00, 2, flat, 1, 0),
|
||||||
|
EncodeVintrp(0x01, 2, flat, 1, 1),
|
||||||
|
EncodeExp0(0x00, 0xf), EncodeExp1(0, 1, 2, 0)};
|
||||||
|
AppendEnd(&test.fragment_code);
|
||||||
|
test.expected_pixel = {0x40700000u, provoking_last ? 0x41300000u : 0x40a00000u,
|
||||||
|
provoking_last ? 0x41000000u : 0x40000000u, 0x40700000u};
|
||||||
|
test.opcodes.insert(test.opcodes.end(),
|
||||||
|
{ShaderOpcode::V_AND_B32, ShaderOpcode::V_CVT_F32_U32});
|
||||||
|
return test;
|
||||||
|
}
|
||||||
|
|
||||||
GraphicsCase GraphicsAncillaryLayer(bool front_face) {
|
GraphicsCase GraphicsAncillaryLayer(bool front_face) {
|
||||||
GraphicsCase test;
|
GraphicsCase test;
|
||||||
test.name = front_face ? "GraphicsAncillaryAfterFrontFace" : "GraphicsAncillaryLayer";
|
test.name = front_face ? "GraphicsAncillaryAfterFrontFace" : "GraphicsAncillaryLayer";
|
||||||
@@ -36714,6 +36770,10 @@ std::vector<GraphicsCase> MakeGraphicsCases() {
|
|||||||
GraphicsPackedHalfInputAlias(false),
|
GraphicsPackedHalfInputAlias(false),
|
||||||
GraphicsPackedHalfInputAlias(true),
|
GraphicsPackedHalfInputAlias(true),
|
||||||
GraphicsSmoothRawInputAlias(),
|
GraphicsSmoothRawInputAlias(),
|
||||||
|
GraphicsSmoothFlatInputAlias(false),
|
||||||
|
GraphicsSmoothFlatInputAlias(true),
|
||||||
|
GraphicsSmoothFlatInputAlias(false, true),
|
||||||
|
GraphicsSmoothFlatInputAlias(true, true),
|
||||||
GraphicsAncillaryLayer(false),
|
GraphicsAncillaryLayer(false),
|
||||||
GraphicsAncillaryLayer(true),
|
GraphicsAncillaryLayer(true),
|
||||||
GraphicsAncillarySampleId(),
|
GraphicsAncillarySampleId(),
|
||||||
@@ -42196,6 +42256,11 @@ int main(int argc, char **argv) {
|
|||||||
RunGraphicsCase(&vulkan, GraphicsPackedHalfInputAlias(false));
|
RunGraphicsCase(&vulkan, GraphicsPackedHalfInputAlias(false));
|
||||||
RunGraphicsCase(&vulkan, GraphicsPackedHalfInputAlias(true));
|
RunGraphicsCase(&vulkan, GraphicsPackedHalfInputAlias(true));
|
||||||
RunGraphicsCase(&vulkan, GraphicsSmoothRawInputAlias());
|
RunGraphicsCase(&vulkan, GraphicsSmoothRawInputAlias());
|
||||||
|
RunGraphicsCase(&vulkan, GraphicsSmoothFlatInputAlias(false));
|
||||||
|
RunGraphicsCase(&vulkan, GraphicsSmoothFlatInputAlias(true));
|
||||||
|
RunGraphicsCase(&vulkan, GraphicsSmoothFlatInputAlias(false, true));
|
||||||
|
RunGraphicsCase(&vulkan, GraphicsSmoothFlatInputAlias(true, true));
|
||||||
|
RunGraphicsCase(&vulkan, GraphicsFlatInterpolatorExport());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (argc == 2 && std::strcmp(argv[1], "--clip-control-only") == 0) {
|
if (argc == 2 && std::strcmp(argv[1], "--clip-control-only") == 0) {
|
||||||
|
|||||||
Reference in New Issue
Block a user