[D3D12] Pass adaptive tessellation factors via index buffer like on the guest

This commit is contained in:
Triang3l
2020-04-05 17:22:49 +03:00
parent 5d6fe38e6f
commit e82d05c687
41 changed files with 2071 additions and 1911 deletions

View File

@@ -1,49 +1,35 @@
#include "byte_swap.hlsli"
#include "xenos_draw.hlsli"
ByteAddressBuffer xe_shared_memory_srv : register(t0);
RWByteAddressBuffer xe_shared_memory_uav : register(u0);
struct XeHSControlPointOutput {};
struct XeHSConstantDataOutput {
float edges[3] : SV_TessFactor;
float inside : SV_InsideTessFactor;
};
XeHSConstantDataOutput XePatchConstant(uint xe_patch_id : SV_PrimitiveID) {
struct XeAdaptiveHSControlPointOutput {};
XeHSConstantDataOutput XePatchConstant(
InputPatch<XeHSControlPointInput, 3> xe_input_patch) {
XeHSConstantDataOutput output = (XeHSConstantDataOutput)0;
uint i;
// Factors for adaptive tessellation are taken from the index buffer.
// 1.0 added to the factors according to the images in
// https://www.slideshare.net/blackdevilvikas/next-generation-graphics-programming-on-xbox-360
// (fractional_even also requires a factor of at least 2.0), to the min/max it
// has already been added on the CPU.
// Due to usage of SV_PrimitiveID, and because the inside factor (join phase)
// depends only on the edge factors (fork phase), there will be no
// dcl_hs_fork_phase_instance_count set (all 3 edge factors will be set in the
// same hs_fork_phase instance), so it's okay to have data calculated only
// once for all edge factors.
uint edge_factor_address =
XeGetTessellationFactorAddress(xe_patch_id * 3u, 3u);
uint3 edge_factor_data;
[branch] if (xe_flags & XeSysFlag_SharedMemoryIsUAV) {
edge_factor_data = xe_shared_memory_uav.Load3(edge_factor_address);
} else {
edge_factor_data = xe_shared_memory_srv.Load3(edge_factor_address);
}
edge_factor_data =
XeByteSwap(edge_factor_data, xe_vertex_index_endian_and_edge_factors);
float3 edge_factors = clamp(asfloat(edge_factor_data) + 1.0,
xe_tessellation_factor_range.x,
xe_tessellation_factor_range.y);
// Fork phase.
// UVW are taken with ZYX swizzle (when r1.y is 0) in the vertex (domain)
// shader. Edge 0 is with U = 0, edge 1 is with V = 0, edge 2 is with W = 0.
// TODO(Triang3l): Verify this order. There are still cracks.
output.edges[0] = edge_factors.z;
output.edges[1] = edge_factors.y;
output.edges[2] = edge_factors.x;
// vpc0, vpc1, vpc2 taken as inputs to the join phase.
[unroll] for (i = 0u; i < 3u; ++i) {
output.edges[i] =
clamp(asfloat(xe_input_patch[2u - i].index_or_edge_factor) + 1.0f,
xe_tessellation_factor_range.x, xe_tessellation_factor_range.y);
}
// Join phase. vpc0, vpc1, vpc2 taken as inputs.
output.inside = min(min(output.edges[0], output.edges[1]), output.edges[2]);
return output;
@@ -54,4 +40,8 @@ XeHSConstantDataOutput XePatchConstant(uint xe_patch_id : SV_PrimitiveID) {
[outputtopology("triangle_cw")]
[outputcontrolpoints(3)]
[patchconstantfunc("XePatchConstant")]
void main(InputPatch<XeHSControlPointOutput, 3> input_patch) {}
XeAdaptiveHSControlPointOutput main(
InputPatch<XeHSControlPointInput, 3> xe_input_patch) {
XeAdaptiveHSControlPointOutput output;
return output;
}