diff options
| author | Tim Foley <tfoley@nvidia.com> | 2017-06-09 11:34:21 -0700 |
|---|---|---|
| committer | Tim Foley <tfoley@nvidia.com> | 2017-06-09 13:44:59 -0700 |
| commit | fcf83dbf9effab3bd98bad2b83b2468b7eb05cfd (patch) | |
| tree | 41047c94883b86ec085a81597391ce3ef557cd43 /tests/hlsl/dxsdk/AdaptiveTessellationCS40 | |
| parent | 52e8d4b9a27ab0060f874c3a63ab531847be35c0 (diff) | |
Initial import of code.
Diffstat (limited to 'tests/hlsl/dxsdk/AdaptiveTessellationCS40')
9 files changed, 1739 insertions, 0 deletions
diff --git a/tests/hlsl/dxsdk/AdaptiveTessellationCS40/Render.hlsl b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/Render.hlsl new file mode 100644 index 000000000..b98b870da --- /dev/null +++ b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/Render.hlsl @@ -0,0 +1,58 @@ +//TEST:COMPARE_HLSL: -profile vs_4_0 -entry RenderBaseVS -profile ps_4_0 -entry RenderPS -target dxbc-assembly +//-------------------------------------------------------------------------------------- +// File: Render.hlsl +// +// The shaders for rendering tessellated mesh and base mesh +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- +cbuffer cbPerObject : register( b0 ) +{ + row_major matrix g_mWorldViewProjection : packoffset( c0 ); +} + +// The tessellated vertex structure +struct TessedVertex +{ + uint BaseTriID; // Which triangle of the base mesh this tessellated vertex belongs to? + float2 bc; // Barycentric coordinates with regard to the base triangle +}; +Buffer<float4> g_base_vb_buffer : register(t0); // Base mesh vertex buffer +StructuredBuffer<TessedVertex> g_TessedVertices : register(t1); // Tessellated mesh vertex buffer + +float4 bary_centric(float4 v1, float4 v2, float4 v3, float2 bc) +{ + return (1 - bc.x - bc.y) * v1 + bc.x * v2 + bc.y * v3; +} + +float4 RenderVS( uint vertid : SV_VertexID ) : SV_POSITION +{ + TessedVertex input = g_TessedVertices[vertid]; + + // Get the positions of the three vertices of the base triangle + float4 v[3]; + [unroll] + for (int i = 0; i < 3; ++ i) + { + uint vert_id = input.BaseTriID * 3 + i; + v[i] = g_base_vb_buffer[vert_id]; + } + + // Calculate the position of this tessellated vertex from barycentric coordinates and then project it + return mul(bary_centric(v[0], v[1], v[2], input.bc), g_mWorldViewProjection); +} + +struct BaseVertex +{ + float4 pos : POSITION; +}; + +float4 RenderBaseVS( BaseVertex input ) : SV_POSITION +{ + return mul( input.pos, g_mWorldViewProjection ); +} + +float4 RenderPS() : SV_TARGET +{ + return float4( 1.0f, 1.0f, 0.0f, 1.0f ); +}
\ No newline at end of file diff --git a/tests/hlsl/dxsdk/AdaptiveTessellationCS40/ScanCS.hlsl b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/ScanCS.hlsl new file mode 100644 index 000000000..46cdc1ed9 --- /dev/null +++ b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/ScanCS.hlsl @@ -0,0 +1,109 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile cs_4_0 -entry CSScanInBucket -entry CSScanBucketResult -entry CSScanAddBucketResult +//-------------------------------------------------------------------------------------- +// File: ScanCS.hlsl +// +// A simple inclusive prefix sum(scan) implemented in CS4.0, +// using a typical up sweep and down sweep scheme +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- +StructuredBuffer<uint2> Input : register( t0 ); // Change uint2 here if scan other types, and +RWStructuredBuffer<uint2> Result : register( u0 ); // also here + +#define groupthreads 128 +groupshared uint4 bucket[groupthreads]; // Change uint4 to the "type x2" if scan other types, e.g. + // if scan uint2, then put uint4 here, + // if scan float, then put float2 here + +void CSScan( uint3 DTid, uint GI, uint2 x ) // Change the type of x here if scan other types +{ + // since CS40 can only support one shared memory for one shader, we use .xy and .zw as ping-ponging buffers + // if scan a single element type like int, search and replace all .xy to .x and .zw to .y below + bucket[GI].xy = x; + bucket[GI].zw = 0; + + // Up sweep + [unroll] + for ( uint stride = 2; stride <= groupthreads; stride <<= 1 ) + { + GroupMemoryBarrierWithGroupSync(); + + if ( (GI & (stride - 1)) == (stride - 1) ) + { + bucket[GI].xy += bucket[GI - stride/2].xy; + } + } + + if ( GI == (groupthreads - 1) ) + { + bucket[GI].xy = 0; + } + + // Down sweep + bool n = true; + [unroll] + for ( stride = groupthreads / 2; stride >= 1; stride >>= 1 ) + { + GroupMemoryBarrierWithGroupSync(); + + uint a = stride - 1; + uint b = stride | a; + + if ( n ) // ping-pong between passes + { + if ( ( GI & b) == b ) + { + bucket[GI].zw = bucket[GI-stride].xy + bucket[GI].xy; + } else + if ( (GI & a) == a ) + { + bucket[GI].zw = bucket[GI+stride].xy; + } else + { + bucket[GI].zw = bucket[GI].xy; + } + } else + { + if ( ( GI & b) == b ) + { + bucket[GI].xy = bucket[GI-stride].zw + bucket[GI].zw; + } else + if ( (GI & a) == a ) + { + bucket[GI].xy = bucket[GI+stride].zw; + } else + { + bucket[GI].xy = bucket[GI].zw; + } + } + + n = !n; + } + + Result[DTid.x] = bucket[GI].zw + x; +} + +// scan in each bucket +[numthreads( groupthreads, 1, 1 )] +void CSScanInBucket( uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI: SV_GroupIndex ) +{ + uint2 x = Input[DTid.x]; // Change the type of x here if scan other types + CSScan( DTid, GI, x ); +} + +// record and scan the sum of each bucket +[numthreads( groupthreads, 1, 1 )] +void CSScanBucketResult( uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI: SV_GroupIndex ) +{ + uint2 x = Input[DTid.x*groupthreads - 1]; // Change the type of x here if scan other types + CSScan( DTid, GI, x ); +} + +StructuredBuffer<uint2> Input1 : register( t1 ); + +// add the bucket scanned result to each bucket to get the final result +[numthreads( groupthreads, 1, 1 )] +void CSScanAddBucketResult( uint3 Gid : SV_GroupID, uint3 DTid : SV_DispatchThreadID, uint3 GTid : SV_GroupThreadID, uint GI: SV_GroupIndex ) +{ + Result[DTid.x] = Input[DTid.x] + Input1[Gid.x]; +} diff --git a/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_EdgeFactorCS.hlsl b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_EdgeFactorCS.hlsl new file mode 100644 index 000000000..91ebca777 --- /dev/null +++ b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_EdgeFactorCS.hlsl @@ -0,0 +1,217 @@ +//TEST_IGNORE_FILE: Currently failing due to Spire compiler issues. +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile cs_4_0 -entry CSEdgeFactor +//-------------------------------------------------------------------------------------- +// File: TessellatorCS40_EdgeFactorCS.hlsl +// +// The CS to compute edge tessellation factor acoording to current world, view, projection matrix +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +// http://jgt.akpeters.com/papers/akeninemoller01/tribox.html +bool planeBoxOverlap(float3 normal, float d, float3 maxbox) +{ + float3 vmin = maxbox, vmax = maxbox; + [unroll] + for (int q = 0;q <= 2; ++ q) + { + if (normal[q] > 0.0f) + { + vmin[q] *= -1; + } + else + { + vmax[q] *= -1; + } + } + if (dot(normal, vmin) + d > 0.0f) + { + return false; + } + if (dot(normal, vmax) + d >= 0.0f) + { + return true; + } + + return false; +} + +/*======================== X-tests ========================*/ +bool AXISTEST_X01(float3 v0, float3 v2, float3 boxhalfsize, float2 ab, float2 fab) +{ + float p0 = ab.x * v0.y - ab.y * v0.z; + float p2 = ab.x * v2.y - ab.y * v2.z; + float min_v = min(p0, p2); + float max_v = max(p0, p2); + float rad = dot(fab, boxhalfsize.yz); + return (min_v < rad) && (max_v > -rad); +} + +bool AXISTEST_X2(float3 v0, float3 v1, float3 boxhalfsize, float2 ab, float2 fab) +{ + float p0 = ab.x * v0.y - ab.y * v0.z; + float p1 = ab.x * v1.y - ab.y * v1.z; + float min_v = min(p0, p1); + float max_v = max(p0, p1); + float rad = dot(fab, boxhalfsize.yz); + return (min_v < rad) && (max_v > -rad); +} + +/*======================== Y-tests ========================*/ +bool AXISTEST_Y02(float3 v0, float3 v2, float3 boxhalfsize, float2 ab, float2 fab) +{ + float p0 = -ab.x * v0.x + ab.y * v0.z; + float p2 = -ab.x * v2.x + ab.y * v2.z; + float min_v = min(p0, p2); + float max_v = max(p0, p2); + float rad = dot(fab, boxhalfsize.xz); + return (min_v < rad) && (max_v > -rad); +} + +bool AXISTEST_Y1(float3 v0, float3 v1, float3 boxhalfsize, float2 ab, float2 fab) +{ + float p0 = -ab.x * v0.x + ab.y * v0.z; + float p1 = -ab.x * v1.x + ab.y * v1.z; + float min_v = min(p0, p1); + float max_v = max(p0, p1); + float rad = dot(fab, boxhalfsize.xz); + return (min_v < rad) && (max_v > -rad); +} + +/*======================== Z-tests ========================*/ +bool AXISTEST_Z12(float3 v1, float3 v2, float3 boxhalfsize, float2 ab, float2 fab) +{ + float p1 = ab.x * v1.x - ab.y * v1.y; + float p2 = ab.x * v2.x - ab.y * v2.y; + float min_v = min(p1, p2); + float max_v = max(p1, p2); + float rad = dot(fab, boxhalfsize.xy); + return (min_v < rad) && (max_v > -rad); +} + +bool AXISTEST_Z0(float3 v0, float3 v1, float3 boxhalfsize, float2 ab, float2 fab) +{ + float p0 = ab.x * v0.x - ab.y * v0.y; + float p1 = ab.x * v1.x - ab.y * v1.y; + float min_v = min(p0, p1); + float max_v = max(p0, p1); + float rad = dot(fab, boxhalfsize.xy); + return (min_v < rad) && (max_v > -rad); +} + +bool triBoxOverlap(float3 boxcenter,float3 boxhalfsize,float3 triverts0, float3 triverts1, float3 triverts2) +{ + /* use separating axis theorem to test overlap between triangle and box */ + /* need to test for overlap in these directions: */ + /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */ + /* we do not even need to test these) */ + /* 2) normal of the triangle */ + /* 3) crossproduct(edge from tri, {x,y,z}-directin) */ + /* this gives 3x3=9 more tests */ + + /* This is the fastest branch on Sun */ + /* move everything so that the boxcenter is in (0,0,0) */ + float3 v0 = triverts0 - boxcenter; + float3 v1 = triverts1 - boxcenter; + float3 v2 = triverts2 - boxcenter; + + /* compute triangle edges */ + float3 e0 = v1 - v0; /* tri edge 0 */ + float3 e1 = v2 - v1; /* tri edge 1 */ + float3 e2 = v0 - v2; /* tri edge 2 */ + + /* Bullet 3: */ + /* test the 9 tests first (this was faster) */ + float3 fe = abs(e0); + if (!AXISTEST_X01(v0, v2, boxhalfsize, e0.zy, fe.zy) + || !AXISTEST_Y02(v0, v2, boxhalfsize, e0.zx, fe.zx) + || !AXISTEST_Z12(v1, v2, boxhalfsize, e0.yx, fe.yx)) + { + return false; + } + + fe = abs(e1); + if (!AXISTEST_X01(v0, v2, boxhalfsize, e1.zy, fe.zy) + || !AXISTEST_Y02(v0, v2, boxhalfsize, e1.zx, fe.zx) + || !AXISTEST_Z0(v0, v1, boxhalfsize, e1.yx, fe.yx)) + { + return false; + } + + fe = abs(e2); + if (!AXISTEST_X2(v0, v1, boxhalfsize, e2.zy, fe.zy) + || !AXISTEST_Y1(v0, v1, boxhalfsize, e2.zx, fe.zx) + || !AXISTEST_Z12(v1, v2, boxhalfsize, e2.yx, fe.yx)) + { + return false; + } + + /* Bullet 1: */ + /* first test overlap in the {x,y,z}-directions */ + /* find min, max of the triangle each direction, and test for overlap in */ + /* that direction -- this is equivalent to testing a minimal AABB around */ + /* the triangle against the AABB */ + + float3 min_v = min(min(v0, v1), v2); + float3 max_v = max(max(v0, v1), v2); + if ((min_v.x > boxhalfsize.x || max_v.x < -boxhalfsize.x) + || (min_v.y > boxhalfsize.y || max_v.y < -boxhalfsize.y) + || (min_v.z > boxhalfsize.z || max_v.z < -boxhalfsize.z)) + { + return false; + } + + /* Bullet 2: */ + /* test if the box intersects the plane of the triangle */ + /* compute plane equation of triangle: normal*x+d=0 */ + float3 normal = cross(e0, e1); + float d = -dot(normal, v0); /* plane eq: normal.x+d=0 */ + if (!planeBoxOverlap(normal, d, boxhalfsize)) + { + return false; + } + + return true; /* box and triangle overlaps */ +} + + +Buffer<float4> InputVertices : register(t0); +RWStructuredBuffer<float4> EdgeFactorBufOut : register(u0); + +cbuffer cb +{ + row_major matrix g_matWVP; + float2 g_tess_edge_length_scale; + int num_triangles; + float dummy; +} + +[numthreads(128, 1, 1)] +void CSEdgeFactor( uint3 DTid : SV_DispatchThreadID ) +{ + if (DTid.x < num_triangles) + { + float4 p0 = mul(InputVertices[DTid.x*3+0], g_matWVP); + float4 p1 = mul(InputVertices[DTid.x*3+1], g_matWVP); + float4 p2 = mul(InputVertices[DTid.x*3+2], g_matWVP); + p0 = p0 / p0.w; + p1 = p1 / p1.w; + p2 = p2 / p2.w; + + float4 factor; + // Only triangles which are completely inside or intersect with the view frustum are taken into account + if ( triBoxOverlap( float3(0, 0, 0.5), float3(1.02, 1.02, 0.52), p0.xyz, p1.xyz, p2.xyz ) ) + { + factor.x = length((p0.xy - p2.xy) * g_tess_edge_length_scale); + factor.y = length((p1.xy - p0.xy) * g_tess_edge_length_scale); + factor.z = length((p2.xy - p1.xy) * g_tess_edge_length_scale); + factor.w = min(min(factor.x, factor.y), factor.z); + factor = clamp(factor, 0, 9); + } else + { + factor = 0; + } + + EdgeFactorBufOut[DTid.x] = factor; + } +} diff --git a/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_NumVerticesIndicesCS.hlsl b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_NumVerticesIndicesCS.hlsl new file mode 100644 index 000000000..4f2fb547b --- /dev/null +++ b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_NumVerticesIndicesCS.hlsl @@ -0,0 +1,56 @@ +//TEST_IGNORE_FILE: Currently failing due to Spire compiler issues. +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile cs_4_0 -entry CSNumVerticesIndices +//-------------------------------------------------------------------------------------- +// File: TessellatorCS40_NumVerticesIndicesCS.hlsl +// +// The CS to compute number of vertices and triangles to be generated from edge tessellation factor +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +#include "TessellatorCS40_common.hlsl" + +StructuredBuffer<float4> InputEdgeFactor : register(t0); +RWStructuredBuffer<uint2> NumVerticesIndicesOut : register(u0); + +cbuffer cbCS : register(b1) +{ + uint4 g_param; +} + +[numthreads(128, 1, 1)] +void CSNumVerticesIndices( uint3 DTid : SV_DispatchThreadID ) +{ + if (DTid.x < g_param.x) + { + float4 edge_factor = InputEdgeFactor[DTid.x]; + + PROCESSED_TESS_FACTORS_TRI processedTessFactors; + int num_points = TriProcessTessFactors(edge_factor, processedTessFactors, g_partitioning); + + int num_index; + if (0 == num_points) + { + num_index = 0; + } + else if (3 == num_points) + { + num_index = 4; + } + else + { + int numRings = ((processedTessFactors.numPointsForOutsideInside.w + 1) / 2); // +1 is so even tess includes the center point, which we want to now + + int4 outsideInsideHalfTessFactor = int4(ceil(processedTessFactors.outsideInsideHalfTessFactor)); + uint3 n = NumStitchTransition(outsideInsideHalfTessFactor, processedTessFactors.outsideInsideTessFactorParity); + num_index = n.x + n.y + n.z; + num_index += TotalNumStitchRegular(true, DIAGONALS_MIRRORED, processedTessFactors.numPointsForOutsideInside.w, numRings - 1) * 3; + if( processedTessFactors.outsideInsideTessFactorParity.w == TESSELLATOR_PARITY_ODD ) + { + num_index += 4; + } + } + + NumVerticesIndicesOut[DTid.x] = uint2(num_points, num_index); + } +} diff --git a/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_ScatterIDCS.hlsl b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_ScatterIDCS.hlsl new file mode 100644 index 000000000..17f003794 --- /dev/null +++ b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_ScatterIDCS.hlsl @@ -0,0 +1,45 @@ +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile cs_4_0 -entry CSScatterVertexTriIDIndexID -entry CSScatterIndexTriIDIndexID +//-------------------------------------------------------------------------------------- +// File: TessellatorCS40_ScatterIDCS.hlsl +// +// The CS to scatter vertex ID and triangle ID +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- +StructuredBuffer<uint2> InputScanned : register(t0); +RWStructuredBuffer<uint2> TriIDIndexIDOut : register(u0); + +cbuffer cbCS : register(b1) +{ + uint4 g_param; +} + +[numthreads(128, 1, 1)] +void CSScatterVertexTriIDIndexID( uint3 DTid : SV_DispatchThreadID ) +{ + if (DTid.x < g_param.x) + { + uint start = InputScanned[DTid.x-1].x; + uint end = InputScanned[DTid.x].x; + + for ( uint i = start; i < end; ++i ) + { + TriIDIndexIDOut[i] = uint2(DTid.x, i - start); + } + } +} + +[numthreads(128, 1, 1)] +void CSScatterIndexTriIDIndexID( uint3 DTid : SV_DispatchThreadID ) +{ + if (DTid.x < g_param.x) + { + uint start = InputScanned[DTid.x-1].y; + uint end = InputScanned[DTid.x].y; + + for ( uint i = start; i < end; ++i ) + { + TriIDIndexIDOut[i] = uint2(DTid.x, i - start); + } + } +} diff --git a/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_TessellateIndicesCS.hlsl b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_TessellateIndicesCS.hlsl new file mode 100644 index 000000000..756f99e58 --- /dev/null +++ b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_TessellateIndicesCS.hlsl @@ -0,0 +1,628 @@ +//TEST_IGNORE_FILE: Currently failing due to Spire compiler issues. +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile cs_4_0 -entry CSTessellationIndices +//-------------------------------------------------------------------------------------- +// File: TessellatorCS40_TessellateIndicesCS.hlsl +// +// The CS to tessellate indices +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +#include "TessellatorCS40_common.hlsl" + +StructuredBuffer<uint2> InputTriIDIndexID : register(t0); +StructuredBuffer<float4> InputEdgeFactor : register(t1); +StructuredBuffer<uint2> InputScanned : register(t2); + +RWByteAddressBuffer TessedIndicesOut : register(u0); + +cbuffer cbCS : register(b1) +{ + uint4 g_param; +} + + +int TransformIndex1(int index, int vertices_base) +{ + return vertices_base + index; +} + +int TransformIndex2(int index, int vertices_base, INDEX_PATCH_CONTEXT IndexPatchContext) +{ + if( index >= IndexPatchContext.outsidePointIndexPatchBase ) // assumed remapped outide indices are > remapped inside vertices + { + if( index == IndexPatchContext.outsidePointIndexBadValue ) + { + index = IndexPatchContext.outsidePointIndexReplacementValue; + } + else + { + index += IndexPatchContext.outsidePointIndexDeltaToRealValue; + } + } + else + { + if( index == IndexPatchContext.insidePointIndexBadValue ) + { + index = IndexPatchContext.insidePointIndexReplacementValue; + } + else + { + index += IndexPatchContext.insidePointIndexDeltaToRealValue; + } + } + + return vertices_base + index; +} + + +int AStitchRegular(bool bTrapezoid, int diagonals, + uint numInsideEdgePoints, + int2 outsideInsideEdgePointBaseOffset, + int i) +{ + if (bTrapezoid) + { + ++ outsideInsideEdgePointBaseOffset.x; + } + + int pt; + + if ((i < 4) && bTrapezoid) + { + if (i < 2) + { + pt = outsideInsideEdgePointBaseOffset.x - 1 + i; + } + else if (i == 2) + { + pt = outsideInsideEdgePointBaseOffset.y; + } + else + { + pt = -1; + } + } + + int index = i; + if (bTrapezoid) + { + index -= 4; + } + + if (index >= 0) + { + uint uindex = (uint)index; + + switch( diagonals ) + { + case DIAGONALS_INSIDE_TO_OUTSIDE: + if (uindex < 5 * numInsideEdgePoints - 5) + { + uint p = uindex / 5; + uint r = uindex - p * 5; + if (r < 2) + { + pt = outsideInsideEdgePointBaseOffset.x + p + r; + } + else if (r < 4) + { + pt = outsideInsideEdgePointBaseOffset.y + p + r; + } + else + { + pt = -1; + } + } + else + { + int r = i - (4 + 5 * numInsideEdgePoints - 5); + if (r < 2) + { + pt = outsideInsideEdgePointBaseOffset.x + numInsideEdgePoints - 1 + r; + } + else if (r == 2) + { + pt = outsideInsideEdgePointBaseOffset.y + numInsideEdgePoints - 1; + } + else + { + pt = -1; + } + } + break; + + case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE: // Assumes ODD tessellation + if (uindex < (numInsideEdgePoints / 2 - 1) * 5) + { + // First half + uint p = uindex / 5; + uint r = uindex - p * 5; + if (r < 2) + { + pt = outsideInsideEdgePointBaseOffset.x + p + r; + } + else if (r < 4) + { + pt = outsideInsideEdgePointBaseOffset.y + p; + } + else + { + pt = -1; + } + } + else if (uindex < (numInsideEdgePoints / 2 - 1) * 5 + 8) + { + // Middle + uint r = uindex - (numInsideEdgePoints / 2 - 1) * 5; + if (0 == r) + { + pt = outsideInsideEdgePointBaseOffset.x + numInsideEdgePoints / 2 - 1; + } + else if (r < 3) + { + pt = outsideInsideEdgePointBaseOffset.y + numInsideEdgePoints / 2 - 1 + (2 - r); + } + else if (r == 3) + { + pt = -1; + } + else if (r < 6) + { + pt = outsideInsideEdgePointBaseOffset.x + numInsideEdgePoints / 2 - 1 + (r - 4); + } + else if (r == 6) + { + pt = outsideInsideEdgePointBaseOffset.y + numInsideEdgePoints / 2 - 1 + 1; + } + else if (r == 7) + { + pt = -1; + } + } + //else if (uindex < (numInsideEdgePoints/2-1) * 5 + 8 + (numInsideEdgePoints - numInsideEdgePoints/2 - 1) * 5) + else if (uindex < numInsideEdgePoints * 5 - 2) + { + // Second half + uint p = (uindex - (numInsideEdgePoints / 2 - 1) * 5 + 8) / 5 + numInsideEdgePoints / 2 + 1; + uint r = uindex - (numInsideEdgePoints / 2 - 1) * 5 + 8 - (p - (numInsideEdgePoints / 2 + 1)) * 5; + if (r < 2) + { + pt = outsideInsideEdgePointBaseOffset.x + p - 1 + r; + } + else if (r < 4) + { + pt = outsideInsideEdgePointBaseOffset.y + p - 1 + r; + } + else + { + pt = -1; + } + } + else + { + //int r = i - (4 + (numInsideEdgePoints/2-1) * 5 + 8 + (numInsideEdgePoints - numInsideEdgePoints/2 - 1) * 5); + int r = i - (numInsideEdgePoints * 5 + 2); + if (r < 2) + { + pt = outsideInsideEdgePointBaseOffset.x + numInsideEdgePoints - 1 + r; + } + else if (r == 2) + { + pt = outsideInsideEdgePointBaseOffset.y + numInsideEdgePoints - 1; + } + else + { + pt = -1; + } + } + break; + + case DIAGONALS_MIRRORED: + if (uindex < (numInsideEdgePoints / 2 + 1) * 2) + { + uint p = uindex / 2; + uint r = uindex - p * 2; + if (0 == r) + { + pt = outsideInsideEdgePointBaseOffset.y + p; + } + else + { + pt = outsideInsideEdgePointBaseOffset.x + p; + } + } + else if (uindex == (numInsideEdgePoints / 2 + 1) * 2) + { + pt = -1; + } + else if (uindex == (numInsideEdgePoints / 2 + 1) * 2 + 1) + { + pt = outsideInsideEdgePointBaseOffset.x + numInsideEdgePoints / 2; + } + //else if (uindex < (numInsideEdgePoints / 2 + 1) * 2 + 2 + (numInsideEdgePoints - numInsideEdgePoints / 2) * 2) + else if (uindex < numInsideEdgePoints * 2 + 4) + { + uint p = (uindex - ((numInsideEdgePoints / 2 + 1) * 2 + 2)) / 2 + numInsideEdgePoints / 2; + uint r = uindex - ((numInsideEdgePoints / 2 + 1) * 2 + 2) - (p - numInsideEdgePoints / 2) * 2; + if (0 == r) + { + pt = outsideInsideEdgePointBaseOffset.x + p; + } + else + { + pt = outsideInsideEdgePointBaseOffset.y + p; + } + } + //else if (uindex == (numInsideEdgePoints / 2 + 1) * 2 + 2 + (numInsideEdgePoints - numInsideEdgePoints / 2) * 2) + else if (uindex == numInsideEdgePoints * 2 + 4) + { + pt = -1; + } + else + { + //int r = i - (4 + (numInsideEdgePoints / 2 + 1) * 2 + 2 + (numInsideEdgePoints - numInsideEdgePoints / 2) * 2 + 1); + uint r = i - (numInsideEdgePoints * 2 + 9); + if (r < 2) + { + pt = outsideInsideEdgePointBaseOffset.x + numInsideEdgePoints - 1 + r; + } + else if (r == 2) + { + pt = outsideInsideEdgePointBaseOffset.y + numInsideEdgePoints - 1; + } + else + { + pt = -1; + } + } + break; + } + } + + return pt; +} + +int AStitchTransition(int2 outsideInsideEdgePointBaseOffset, int2 outsideInsideNumHalfTessFactorPoints, + int2 outsideInsideEdgeTessFactorParity, + uint i) +{ + outsideInsideNumHalfTessFactorPoints -= (TESSELLATOR_PARITY_ODD == outsideInsideEdgeTessFactorParity); + + uint2 out_in_first_half = uint2(outsidePointIndex[outsideInsideNumHalfTessFactorPoints.x][MAX_FACTOR / 2 + 1].y, insidePointIndex[outsideInsideNumHalfTessFactorPoints.y][MAX_FACTOR / 2 + 1].y) * 4; + + uint3 out_in_middle = 0; + if ((outsideInsideEdgeTessFactorParity.y != outsideInsideEdgeTessFactorParity.x) || (outsideInsideEdgeTessFactorParity.y == TESSELLATOR_PARITY_ODD)) + { + if (outsideInsideEdgeTessFactorParity.y == outsideInsideEdgeTessFactorParity.x) + { + // Quad in the middle + out_in_middle.z = 5; + out_in_middle.xy = 1; + } + else if (TESSELLATOR_PARITY_EVEN == outsideInsideEdgeTessFactorParity.y) + { + // Triangle pointing inside + out_in_middle.z = 4; + out_in_middle.x = 1; + } + else + { + // Triangle pointing outside + out_in_middle.z = 4; + out_in_middle.y = 1; + } + } + + + int pt = -1; + + if (i < out_in_first_half.y) + { + // Advance inside + + uint p = i / 4; + uint r = i - p * 4; + p = insidePointIndex[outsideInsideNumHalfTessFactorPoints.y][p].z; + if ((0 == r) || (2 == r)) + { + pt = outsideInsideEdgePointBaseOffset.y + insidePointIndex[outsideInsideNumHalfTessFactorPoints.y][p].y + r / 2; + } + else if (1 == r) + { + pt = outsideInsideEdgePointBaseOffset.x + outsidePointIndex[outsideInsideNumHalfTessFactorPoints.x][p].y; + } + } + else + { + i -= out_in_first_half.y; + + if (i < out_in_first_half.x) + { + // Advance outside + + uint p = i / 4; + uint r = i - p * 4; + p = outsidePointIndex[outsideInsideNumHalfTessFactorPoints.x][p].z; + if (r < 2) + { + pt = outsideInsideEdgePointBaseOffset.x + outsidePointIndex[outsideInsideNumHalfTessFactorPoints.x][p].y + r; + } + else if (r == 2) + { + pt = outsideInsideEdgePointBaseOffset.y + insidePointIndex[outsideInsideNumHalfTessFactorPoints.y][p].y; + if (insidePointIndex[outsideInsideNumHalfTessFactorPoints.y][p].x) + { + ++ pt; + } + } + } + else + { + i -= out_in_first_half.x; + + if (i < out_in_middle.z) + { + uint r = i; + if (outsideInsideEdgeTessFactorParity.y == outsideInsideEdgeTessFactorParity.x) + { + // Quad in the middle + if ((0 == r) || (2 == r)) + { + pt = outsideInsideEdgePointBaseOffset.y + out_in_first_half.y / 4 + (2 == r);//r / 2; + } + else if ((1 == r) || (3 == r)) + { + pt = outsideInsideEdgePointBaseOffset.x + out_in_first_half.x / 4 + (3 == r);//(r - 1) / 2; + } + } + else if (TESSELLATOR_PARITY_EVEN == outsideInsideEdgeTessFactorParity.y) + { + // Triangle pointing inside + if (r == 0) + { + pt = outsideInsideEdgePointBaseOffset.y + out_in_first_half.y / 4; + } + else if (r < 3) + { + pt = outsideInsideEdgePointBaseOffset.x + out_in_first_half.x / 4 + r - 1; + } + } + else + { + // Triangle pointing outside + if ((0 == r) || (2 == r)) + { + pt = outsideInsideEdgePointBaseOffset.y + out_in_first_half.y / 4 + (2 == r);//r / 2; + } + else if (1 == r) + { + pt = outsideInsideEdgePointBaseOffset.x + out_in_first_half.x / 4; + } + } + } + else + { + i -= out_in_middle.z; + + if (i < out_in_first_half.x) + { + // Advance outside + + uint p = i / 4; + uint r = i - p * 4; + p = outsidePointIndex[outsideInsideNumHalfTessFactorPoints.x][p].z; + if (r < 2) + { + pt = outsideInsideEdgePointBaseOffset.x + out_in_first_half.x / 4 + out_in_middle.x + (outsidePointIndex[outsideInsideNumHalfTessFactorPoints.x][MAX_FACTOR / 2 + 1].y - outsidePointIndex[outsideInsideNumHalfTessFactorPoints.x][p + 1].y) + r; + } + else if (r == 2) + { + pt = outsideInsideEdgePointBaseOffset.y + out_in_first_half.y / 4 + out_in_middle.y + (insidePointIndex[outsideInsideNumHalfTessFactorPoints.y][MAX_FACTOR / 2 + 1].y - insidePointIndex[outsideInsideNumHalfTessFactorPoints.y][p + 1].y); + } + } + else + { + // Advance inside + + i -= out_in_first_half.x; + + uint p = i / 4; + uint r = i - p * 4; + p = insidePointIndex[outsideInsideNumHalfTessFactorPoints.y][p].w; + if ((0 == r) || (2 == r)) + { + pt = outsideInsideEdgePointBaseOffset.y + out_in_first_half.y / 4 + out_in_middle.y + + (insidePointIndex[outsideInsideNumHalfTessFactorPoints.y][MAX_FACTOR / 2 + 1].y - insidePointIndex[outsideInsideNumHalfTessFactorPoints.y][p + 1].y) + (2 == r);//r / 2; + } + else if (1 == r) + { + pt = outsideInsideEdgePointBaseOffset.x + out_in_first_half.x / 4 + out_in_middle.x + + (outsidePointIndex[outsideInsideNumHalfTessFactorPoints.x][MAX_FACTOR / 2 + 1].y - outsidePointIndex[outsideInsideNumHalfTessFactorPoints.x][p + 1].y); + if (outsidePointIndex[outsideInsideNumHalfTessFactorPoints.x][p].x) + { + ++ pt; + } + } + } + } + } + } + + return pt; +} + +[numthreads(128, 1, 1)] +void CSTessellationIndices( uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint GI : SV_GroupIndex ) +{ + uint id = DTid.x; + //uint id = Gid.x * 128 + GI; // Workaround for some CS4x preview drivers + + if ( id < g_param.x ) + { + uint tri_id = InputTriIDIndexID[id].x; + uint index_id = InputTriIDIndexID[id].y; + uint base_vertex = InputScanned[tri_id-1].x; + + float4 outside_inside_factor = InputEdgeFactor[tri_id]; + + PROCESSED_TESS_FACTORS_TRI processedTessFactors; + int num_points = TriProcessTessFactors(outside_inside_factor, processedTessFactors, g_partitioning); + + uint tessed_indices; + if (3 == num_points) + { + if (index_id < 3) + { + tessed_indices = TransformIndex1(index_id, base_vertex); + } + else + { + tessed_indices = -1; + } + } + else + { + // Generate primitives for all the concentric rings, one side at a time for each ring + static const int startRing = 1; + int numRings = ((processedTessFactors.numPointsForOutsideInside.w + 1) / 2); // +1 is so even tess includes the center point, which we want to now + + int4 outsideInsideHalfTessFactor = int4(ceil(processedTessFactors.outsideInsideHalfTessFactor)); + uint3 num = NumStitchTransition(outsideInsideHalfTessFactor, processedTessFactors.outsideInsideTessFactorParity); + num.y += num.x; + num.z += num.y; + uint num_index = num.z; + num_index += TotalNumStitchRegular(true, DIAGONALS_MIRRORED, processedTessFactors.numPointsForOutsideInside.w, numRings - 1) * 3; + if( processedTessFactors.outsideInsideTessFactorParity.w == TESSELLATOR_PARITY_ODD ) + { + num_index += 4; + } + + int pt; + + if (index_id < num.x) + { + int numPointsForInsideEdge = processedTessFactors.numPointsForOutsideInside.w - 2 * startRing; + + pt = AStitchTransition(int2(0, processedTessFactors.insideEdgePointBaseOffset), + outsideInsideHalfTessFactor.xw, + processedTessFactors.outsideInsideTessFactorParity.xw, + index_id); + if (pt != -1) + { + pt = TransformIndex1(pt, base_vertex); + } + } + else if (index_id < num.y) + { + int numPointsForInsideEdge = processedTessFactors.numPointsForOutsideInside.w - 2 * startRing; + + pt = AStitchTransition( + int2(processedTessFactors.numPointsForOutsideInside.x - 1, processedTessFactors.insideEdgePointBaseOffset + numPointsForInsideEdge - 1), + outsideInsideHalfTessFactor.yw, + processedTessFactors.outsideInsideTessFactorParity.yw, + index_id - num.x); + if (pt != -1) + { + pt = TransformIndex1(pt, base_vertex); + } + } + else if (index_id < num.z) + { + int numPointsForInsideEdge = processedTessFactors.numPointsForOutsideInside.w - 2 * startRing; + + INDEX_PATCH_CONTEXT IndexPatchContext; + IndexPatchContext.insidePointIndexDeltaToRealValue = processedTessFactors.insideEdgePointBaseOffset + 2 * (numPointsForInsideEdge - 1); + IndexPatchContext.insidePointIndexBadValue = numPointsForInsideEdge - 1; + IndexPatchContext.insidePointIndexReplacementValue = processedTessFactors.insideEdgePointBaseOffset; + IndexPatchContext.outsidePointIndexPatchBase = IndexPatchContext.insidePointIndexBadValue+1; // past inside patched index range + IndexPatchContext.outsidePointIndexDeltaToRealValue = processedTessFactors.numPointsForOutsideInside.x + processedTessFactors.numPointsForOutsideInside.y - 2 + - IndexPatchContext.outsidePointIndexPatchBase; + IndexPatchContext.outsidePointIndexBadValue = IndexPatchContext.outsidePointIndexPatchBase + + processedTessFactors.numPointsForOutsideInside.z - 1; + IndexPatchContext.outsidePointIndexReplacementValue = 0; + + pt = AStitchTransition(int2(numPointsForInsideEdge, 0), + outsideInsideHalfTessFactor.zw, + processedTessFactors.outsideInsideTessFactorParity.zw, + index_id - num.y); + if (pt != -1) + { + pt = TransformIndex2(pt, base_vertex, IndexPatchContext); + } + } + else + { + if ((processedTessFactors.outsideInsideTessFactorParity.w == TESSELLATOR_PARITY_ODD) && (index_id >= num_index - 4)) + { + int outsideEdgePointBaseOffset = processedTessFactors.insideEdgePointBaseOffset + + ((processedTessFactors.numPointsForOutsideInside.w + 1) - (numRings + startRing)) * (numRings - startRing - 1) * 3; + + if (index_id - (num_index - 4) != 3) + { + pt = TransformIndex1(outsideEdgePointBaseOffset + index_id - (num_index - 4), base_vertex); + } + else + { + pt = -1; + } + } + else + { + int ring = GetRingFromIndexStitchRegular(true, DIAGONALS_MIRRORED, processedTessFactors.numPointsForOutsideInside.w, index_id - num.z); + + int tn = TotalNumStitchRegular(true, DIAGONALS_MIRRORED, processedTessFactors.numPointsForOutsideInside.w, ring - 1) * 3; + int n = NumStitchRegular(true, DIAGONALS_MIRRORED, processedTessFactors.numPointsForOutsideInside.w - 2 * ring); + + int edge = (index_id - num.z - tn) / n; + int index = (index_id - num.z - tn) - edge * n; + + int2 outsideInsideEdgePointBaseOffset = processedTessFactors.insideEdgePointBaseOffset + + int2(0, 3 * (processedTessFactors.numPointsForOutsideInside.w - 3)) + + ((processedTessFactors.numPointsForOutsideInside.w - (ring + startRing)) + int2(1, -1)) * (ring - startRing - 1) * 3; + + int numPointsForInsideEdge = processedTessFactors.numPointsForOutsideInside.w - 2 * ring; + int numLastPointsForInsideEdge = numPointsForInsideEdge + 2; + + if (edge < 2) + { + pt = AStitchRegular(true, DIAGONALS_MIRRORED, + numPointsForInsideEdge, + outsideInsideEdgePointBaseOffset + (int2(numLastPointsForInsideEdge, numPointsForInsideEdge) - 1) * edge, + index); + if (pt != -1) + { + pt = TransformIndex1(pt, base_vertex); + } + } + else + { + INDEX_PATCH_CONTEXT IndexPatchContext; + IndexPatchContext.insidePointIndexDeltaToRealValue = outsideInsideEdgePointBaseOffset.y + (numPointsForInsideEdge - 1) * 2; + IndexPatchContext.insidePointIndexBadValue = numPointsForInsideEdge - 1; + IndexPatchContext.insidePointIndexReplacementValue = outsideInsideEdgePointBaseOffset.y; + IndexPatchContext.outsidePointIndexPatchBase = IndexPatchContext.insidePointIndexBadValue+1; // past inside patched index range + IndexPatchContext.outsidePointIndexDeltaToRealValue = outsideInsideEdgePointBaseOffset.x + (numLastPointsForInsideEdge - 1) * 2 + - IndexPatchContext.outsidePointIndexPatchBase; + IndexPatchContext.outsidePointIndexBadValue = IndexPatchContext.outsidePointIndexPatchBase + + numLastPointsForInsideEdge - 1; + IndexPatchContext.outsidePointIndexReplacementValue = outsideInsideEdgePointBaseOffset.x; + + pt = AStitchRegular(true, DIAGONALS_MIRRORED, + numPointsForInsideEdge, + int2(numPointsForInsideEdge, 0), + index); + if (pt != -1) + { + pt = TransformIndex2(pt, base_vertex, IndexPatchContext); + } + } + } + } + + tessed_indices = pt; + } + + TessedIndicesOut.Store(id*4, tessed_indices); + } +} diff --git a/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_TessellateVerticesCS.hlsl b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_TessellateVerticesCS.hlsl new file mode 100644 index 000000000..55bf1be87 --- /dev/null +++ b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_TessellateVerticesCS.hlsl @@ -0,0 +1,206 @@ +//TEST_IGNORE_FILE: Currently failing due to Spire compiler issues. +//TEST:COMPARE_HLSL: -target dxbc-assembly -profile cs_4_0 -entry CSTessellationVertices +//-------------------------------------------------------------------------------------- +// File: TessellatorCS40_TessellateVerticesCS.hlsl +// +// The CS to tessellate vertices +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +#include "TessellatorCS40_common.hlsl" + +StructuredBuffer<uint2> InputTriIDIndexID : register(t0); +StructuredBuffer<float4> InputEdgeFactor : register(t1); + +struct TessedVertex +{ + uint BaseTriID; + float2 bc; +}; +RWStructuredBuffer<TessedVertex> TessedVerticesOut : register(u0); + +cbuffer cbCS : register(b1) +{ + uint4 g_param; +} + +void PlacePointIn1D(PROCESSED_TESS_FACTORS_TRI processedTessFactors, int ctx_index, int pt, out float location, int parity) +{ + int numHalfTessFactorPoints = int(ceil(processedTessFactors.outsideInsideHalfTessFactor[ctx_index])); + + bool bFlip; + if( pt >= numHalfTessFactorPoints ) + { + pt = (numHalfTessFactorPoints << 1) - pt; + if( TESSELLATOR_PARITY_ODD == parity ) + { + pt -= 1; + } + bFlip = true; + } + else + { + bFlip = false; + } + + if( pt == numHalfTessFactorPoints ) + { + location = 0.5f; + } + else + { + unsigned int indexOnCeilHalfTessFactor = pt; + unsigned int indexOnFloorHalfTessFactor = indexOnCeilHalfTessFactor; + if( pt > processedTessFactors.outsideInsideSplitPointOnFloorHalfTessFactor[ctx_index] ) + { + indexOnFloorHalfTessFactor -= 1; + } + float locationOnFloorHalfTessFactor = indexOnFloorHalfTessFactor * processedTessFactors.outsideInsideInvNumSegmentsOnFloorTessFactor[ctx_index]; + float locationOnCeilHalfTessFactor = indexOnCeilHalfTessFactor * processedTessFactors.outsideInsideInvNumSegmentsOnCeilTessFactor[ctx_index]; + + location = lerp(locationOnFloorHalfTessFactor, locationOnCeilHalfTessFactor, frac(processedTessFactors.outsideInsideHalfTessFactor[ctx_index])); + + if( bFlip ) + { + location = 1.0f - location; + } + } +} + +[numthreads(128, 1, 1)] +void CSTessellationVertices( uint3 DTid : SV_DispatchThreadID, uint3 Gid : SV_GroupID, uint GI : SV_GroupIndex ) +{ + uint id = DTid.x; + //uint id = Gid.x * 128 + GI; // Workaround for some CS4x preview drivers + + if ( id < g_param.x ) + { + uint tri_id = InputTriIDIndexID[id].x; + uint vert_id = InputTriIDIndexID[id].y; + + float4 outside_inside_factor = InputEdgeFactor[tri_id]; + + PROCESSED_TESS_FACTORS_TRI processedTessFactors; + int num_points = TriProcessTessFactors(outside_inside_factor, processedTessFactors, g_partitioning); + + float2 uv; + if (3 == num_points) + { + if (0 == vert_id) + { + uv = float2(0, 1); + } + else if (1 == vert_id) + { + uv = float2(0, 0); + } + else + { + uv = float2(1, 0); + } + } + else + { + if (vert_id < processedTessFactors.insideEdgePointBaseOffset) + { + // Generate exterior ring edge points, clockwise starting from point V (VW, the U==0 edge) + + int edge; + if (vert_id < processedTessFactors.numPointsForOutsideInside.x - 1) + { + edge = 0; + } + else + { + vert_id -= processedTessFactors.numPointsForOutsideInside.x - 1; + if (vert_id < processedTessFactors.numPointsForOutsideInside.y - 1) + { + edge = 1; + } + else + { + vert_id -= processedTessFactors.numPointsForOutsideInside.y - 1; + edge = 2; + } + } + + int p = vert_id; + int endPoint = processedTessFactors.numPointsForOutsideInside[edge] - 1; + float param; + int q = (edge & 0x1) ? p : endPoint - p; // whether to reverse point order given we are defining V or U (W implicit): + // edge0, VW, has V decreasing, so reverse 1D points below + // edge1, WU, has U increasing, so don't reverse 1D points below + // edge2, UV, has U decreasing, so reverse 1D points below + PlacePointIn1D(processedTessFactors, edge,q,param, processedTessFactors.outsideInsideTessFactorParity[edge]); + if (0 == edge) + { + uv = float2(0, param); + } + else if (1 == edge) + { + uv = float2(param, 0); + } + else + { + uv = float2(param, 1 - param); + } + } + else + { + // Generate interior ring points, clockwise spiralling in + + uint index = vert_id - processedTessFactors.insideEdgePointBaseOffset; + uint ring = 1 + (((3 * processedTessFactors.numPointsForOutsideInside.w - 6) - sqrt(sqr(3 * processedTessFactors.numPointsForOutsideInside.w - 6) - 4 * 3 * index)) + 0.001f) / 6; + index -= 3 * (processedTessFactors.numPointsForOutsideInside.w - ring - 1) * (ring - 1); + + uint startPoint = ring; + uint endPoint = processedTessFactors.numPointsForOutsideInside.w - 1 - startPoint; + if (index < 3 * (endPoint - startPoint)) + { + uint edge = index / (endPoint - startPoint); + uint p = index - edge * (endPoint - startPoint) + startPoint; + + int perpendicularAxisPoint = startPoint; + float perpParam; + PlacePointIn1D(processedTessFactors, 3, perpendicularAxisPoint, perpParam, processedTessFactors.outsideInsideTessFactorParity.w); + perpParam = perpParam * 2 / 3; + + float param; + int q = (edge & 0x1) ? p : endPoint - (p - startPoint); // whether to reverse point given we are defining V or U (W implicit): + // edge0, VW, has V decreasing, so reverse 1D points below + // edge1, WU, has U increasing, so don't reverse 1D points below + // edge2, UV, has U decreasing, so reverse 1D points below + PlacePointIn1D(processedTessFactors, 3, q,param, processedTessFactors.outsideInsideTessFactorParity.w); + // edge0 VW, has perpendicular parameter U constant + // edge1 WU, has perpendicular parameter V constant + // edge2 UV, has perpendicular parameter W constant + const unsigned int deriv = 2; // reciprocal is the rate of change of edge-parallel parameters as they are pushed into the triangle + if (0 == edge) + { + uv = float2(perpParam, param - perpParam / deriv); + } + else if (1 == edge) + { + uv = float2(param - perpParam / deriv, perpParam); + } + else + { + uv = float2(param - perpParam / deriv, 1 - (param - perpParam / deriv + perpParam)); + } + } + else + { + if( processedTessFactors.outsideInsideTessFactorParity.w != TESSELLATOR_PARITY_ODD ) + { + // Last point is the point at the center. + uv = 1 / 3.0f; + } + } + } + } + + TessedVerticesOut[id].BaseTriID = tri_id; + TessedVerticesOut[id].bc = uv; + } +} diff --git a/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_common.hlsl b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_common.hlsl new file mode 100644 index 000000000..309044cdb --- /dev/null +++ b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_common.hlsl @@ -0,0 +1,411 @@ +//TEST_IGNORE_FILE: +//-------------------------------------------------------------------------------------- +// File: TessellatorCS40_common.hlsl +// +// The common utils included by other shaders in the sample +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +#include "TessellatorCS40_defines.h" + +cbuffer cbNeverChanges : register(b0) +{ + uint4 insidePointIndex[MAX_FACTOR / 2 + 1][MAX_FACTOR / 2 + 2]; + uint4 outsidePointIndex[MAX_FACTOR / 2 + 1][MAX_FACTOR / 2 + 2]; +} + +#define D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR ( 64 ) +#define D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR ( 63 ) +#define D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR ( 2 ) +#define D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR ( 1 ) + +#define D3D11_TESSELLATOR_PARTITIONING_INTEGER ( 0 ) +#define D3D11_TESSELLATOR_PARTITIONING_POW2 ( 1 ) +#define D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD ( 2 ) +#define D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN ( 3 ) + +#define TESSELLATOR_PARITY_EVEN ( 0 ) +#define TESSELLATOR_PARITY_ODD ( 1 ) + +#define EPSILON 1e-6f +#define MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON (D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON/2) + +#define DIAGONALS_INSIDE_TO_OUTSIDE ( 0 ) +#define DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE ( 1 ) +#define DIAGONALS_MIRRORED ( 2 ) + + +// This is moved to macro defines at shader compile time, so that the partitioning mode can be changed during runtime +//#define g_partitioning (D3D11_TESSELLATOR_PARTITIONING_POW2) + + +struct PROCESSED_TESS_FACTORS_TRI +{ + float4 outsideInsideTessFactor; + int4 outsideInsideTessFactorParity; + + float4 outsideInsideInvNumSegmentsOnFloorTessFactor; + float4 outsideInsideInvNumSegmentsOnCeilTessFactor; + float4 outsideInsideHalfTessFactor; + int4 outsideInsideSplitPointOnFloorHalfTessFactor; + + // Stuff below is specific to the traversal order + uint4 numPointsForOutsideInside; + uint insideEdgePointBaseOffset; +}; + +struct INDEX_PATCH_CONTEXT +{ + int insidePointIndexDeltaToRealValue; + int insidePointIndexBadValue; + int insidePointIndexReplacementValue; + int outsidePointIndexPatchBase; + int outsidePointIndexDeltaToRealValue; + int outsidePointIndexBadValue; + int outsidePointIndexReplacementValue; +}; + +bool4 isEven(float4 input) +{ + return (((uint4)input) & 1) ? false : true; +} + +uint RemoveMSB(uint val) +{ + int check; + if( val <= 0x0000ffff ) + { + check = ( val <= 0x000000ff ) ? 0x00000080 : 0x00008000; + } + else + { + check = ( val <= 0x00ffffff ) ? 0x00800000 : 0x80000000; + } + for (int i = 0; i < 8; i++, check >>= 1) + { + if( val & check ) + { + return (val & ~check); + } + } + return 0; +} + +uint4 NumPointsForTessFactor(float4 tessFactor, int4 parity) +{ + return TESSELLATOR_PARITY_ODD == parity ? uint4(ceil(0.5f + tessFactor / 2)) * 2 : uint4(ceil(tessFactor / 2)) * 2 + 1; +} + +void ComputeTessFactorContext(float4 tessFactor, int4 parity, + out float4 invNumSegmentsOnFloorTessFactor, + out float4 invNumSegmentsOnCeilTessFactor, + out float4 halfTessFactor, + out int4 splitPointOnFloorHalfTessFactor) +{ + halfTessFactor = tessFactor / 2; + + halfTessFactor += 0.5 * ((TESSELLATOR_PARITY_ODD == parity) | (0.5f == halfTessFactor)); + + float4 floorHalfTessFactor = floor(halfTessFactor); + float4 ceilHalfTessFactor = ceil(halfTessFactor); + int4 numHalfTessFactorPoints = int4(ceilHalfTessFactor); + + for (int index = 0; index < 4; ++ index) + { + if( ceilHalfTessFactor[index] == floorHalfTessFactor[index] ) + { + splitPointOnFloorHalfTessFactor[index] = /*pick value to cause this to be ignored*/ numHalfTessFactorPoints[index]+1; + } + else if( TESSELLATOR_PARITY_ODD == parity[index] ) + { + if( floorHalfTessFactor[index] == 1 ) + { + splitPointOnFloorHalfTessFactor[index] = 0; + } + else + { + splitPointOnFloorHalfTessFactor[index] = (RemoveMSB(int(floorHalfTessFactor[index]) - 1) << 1) + 1; + } + } + else + { + splitPointOnFloorHalfTessFactor[index] = (RemoveMSB(int(floorHalfTessFactor[index])) << 1) + 1; + } + } + + int4 numFloorSegments = int4(floorHalfTessFactor * 2); + int4 numCeilSegments = int4(ceilHalfTessFactor * 2); + int4 s = (TESSELLATOR_PARITY_ODD == parity); + numFloorSegments -= s; + numCeilSegments -= s; + invNumSegmentsOnFloorTessFactor = 1.0f / numFloorSegments; + invNumSegmentsOnCeilTessFactor = 1.0f / numCeilSegments; +} + +int TriProcessTessFactors( inout float4 tessFactor, + out PROCESSED_TESS_FACTORS_TRI processedTessFactors, + int partitioning ) +{ + processedTessFactors = (PROCESSED_TESS_FACTORS_TRI)0; + + int parity = TESSELLATOR_PARITY_EVEN; + switch( partitioning ) + { + case D3D11_TESSELLATOR_PARTITIONING_INTEGER: + default: + break; + case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD: + parity = TESSELLATOR_PARITY_ODD; + break; + case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN: + parity = TESSELLATOR_PARITY_EVEN; + break; + } + + // Is the patch culled? + if( !(tessFactor.x > 0) || // NaN will pass + !(tessFactor.y > 0) || + !(tessFactor.z > 0) ) + { + return 0; + } + + // Clamp edge TessFactors + float lowerBound, upperBound; + switch(partitioning) + { + case D3D11_TESSELLATOR_PARTITIONING_INTEGER: + case D3D11_TESSELLATOR_PARTITIONING_POW2: // don't care about pow2 distinction for validation, just treat as integer + default: + lowerBound = D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR; + upperBound = D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR; + break; + + case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN: + lowerBound = D3D11_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR; + upperBound = D3D11_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR; + break; + + case D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD: + lowerBound = D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR; + upperBound = D3D11_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR; + break; + } + + tessFactor.xyz = min( upperBound, max( lowerBound, tessFactor.xyz ) ); + + // Clamp inside TessFactors + if(D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD == partitioning) + { + if( (tessFactor.x > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) || + (tessFactor.y > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) || + (tessFactor.z > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON)) + // Don't need the same check for insideTessFactor for tri patches, + // since there is only one insideTessFactor, as opposed to quad + // patches which have 2 insideTessFactors. + { + // Force picture frame + lowerBound = D3D11_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON; + } + } + + tessFactor.w = min( upperBound, max( lowerBound, tessFactor.w ) ); + // Note the above clamps map NaN to lowerBound + + if (partitioning == D3D11_TESSELLATOR_PARTITIONING_INTEGER) + { + tessFactor = ceil(tessFactor); + } + else if (partitioning == D3D11_TESSELLATOR_PARTITIONING_POW2) + { + static const int exponentMask = 0x7f800000; + static const int mantissaMask = 0x007fffff; + static const int exponentLSB = 0x00800000; + + int4 bits = asint(tessFactor); + tessFactor = bits & mantissaMask ? asfloat((bits & exponentMask) + exponentLSB) : tessFactor; + } + + // Process tessFactors + if ((partitioning == D3D11_TESSELLATOR_PARTITIONING_INTEGER)|| (partitioning == D3D11_TESSELLATOR_PARTITIONING_POW2)) + { + bool4 e = isEven(tessFactor); + processedTessFactors.outsideInsideTessFactorParity.xyz = e.xyz ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD; + processedTessFactors.outsideInsideTessFactorParity.w = (e.w || (1 == tessFactor.w)) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD; + } + else + { + processedTessFactors.outsideInsideTessFactorParity = parity; + } + + processedTessFactors.outsideInsideTessFactor = tessFactor; + + if (((partitioning == D3D11_TESSELLATOR_PARTITIONING_INTEGER)|| (partitioning == D3D11_TESSELLATOR_PARTITIONING_POW2)) || (parity == TESSELLATOR_PARITY_ODD)) + { + // Special case if all TessFactors are 1 + if( (1 == processedTessFactors.outsideInsideTessFactor.x) && + (1 == processedTessFactors.outsideInsideTessFactor.y) && + (1 == processedTessFactors.outsideInsideTessFactor.z) && + (1 == processedTessFactors.outsideInsideTessFactor.w) ) + { + return 3; + } + } + + // Compute per-TessFactor metadata + ComputeTessFactorContext(processedTessFactors.outsideInsideTessFactor, processedTessFactors.outsideInsideTessFactorParity, + processedTessFactors.outsideInsideInvNumSegmentsOnFloorTessFactor, + processedTessFactors.outsideInsideInvNumSegmentsOnCeilTessFactor, + processedTessFactors.outsideInsideHalfTessFactor, + processedTessFactors.outsideInsideSplitPointOnFloorHalfTessFactor); + + // Compute some initial data. + + // outside edge offsets and storage + processedTessFactors.numPointsForOutsideInside = NumPointsForTessFactor(processedTessFactors.outsideInsideTessFactor, processedTessFactors.outsideInsideTessFactorParity); + int NumPoints = processedTessFactors.numPointsForOutsideInside.x + processedTessFactors.numPointsForOutsideInside.y + processedTessFactors.numPointsForOutsideInside.z - 3; + + // inside edge offsets + { + uint pointCountMin = (processedTessFactors.outsideInsideTessFactorParity.w == TESSELLATOR_PARITY_ODD) ? 4 : 3; + // max() allows degenerate transition regions when inside TessFactor == 1 + processedTessFactors.numPointsForOutsideInside.w = max(pointCountMin, processedTessFactors.numPointsForOutsideInside.w); + } + + processedTessFactors.insideEdgePointBaseOffset = NumPoints; + + // inside storage, including interior edges above + { + int numInteriorRings = (processedTessFactors.numPointsForOutsideInside.w >> 1) - 1; + int numInteriorPoints; + if( processedTessFactors.outsideInsideTessFactorParity.w == TESSELLATOR_PARITY_ODD ) + { + numInteriorPoints = 3*(numInteriorRings*(numInteriorRings+1) - numInteriorRings); + } + else + { + numInteriorPoints = 3*(numInteriorRings*(numInteriorRings+1)) + 1; + } + NumPoints += numInteriorPoints; + } + + return NumPoints; +} + +int NumStitchRegular(bool bTrapezoid, int diagonals, int numInsideEdgePoints) +{ + int num_index = 0; + + if( bTrapezoid ) + { + num_index += 8; + } + switch( diagonals ) + { + case DIAGONALS_INSIDE_TO_OUTSIDE: + // Diagonals pointing from inside edge forward towards outside edge + num_index += 5 * numInsideEdgePoints - 5; + break; + + case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE: // Assumes ODD tessellation + // Diagonals pointing from outside edge forward towards inside edge + num_index += 5 * numInsideEdgePoints - 2; + break; + + case DIAGONALS_MIRRORED: + num_index += 2 * numInsideEdgePoints + 5; + break; + } + + return num_index; +} + +uint TotalNumStitchRegular(bool bTrapezoid, int diagonals, + int numPointsForInsideTessFactor, int ring) +{ + uint num_index = 0; + + if( bTrapezoid ) + { + num_index += 8 * (ring - 1); + } + switch( diagonals ) + { + case DIAGONALS_INSIDE_TO_OUTSIDE: + // Diagonals pointing from inside edge forward towards outside edge + num_index += (5 * numPointsForInsideTessFactor - 35 - 5 * ring) * (ring - 1); + break; + + case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE: // Assumes ODD tessellation + // Diagonals pointing from outside edge forward towards inside edge + num_index += (5 * numPointsForInsideTessFactor - 12 - 5 * ring) * (ring - 1); + break; + + case DIAGONALS_MIRRORED: + num_index += (2 * numPointsForInsideTessFactor + 1 - 2 * ring) * (ring - 1); + break; + } + + return num_index; +} + +int sqr(int x) +{ + return x * x; +} + +int GetRingFromIndexStitchRegular(bool bTrapezoid, int diagonals, int numPointsForInsideTessFactor, int index) +{ + int t = 0; + if (bTrapezoid) + { + t = 8; + } + + switch( diagonals ) + { + case DIAGONALS_INSIDE_TO_OUTSIDE: + t = (5 * numPointsForInsideTessFactor - (35 - t)) * 3; + return 1 + uint((t + 15) - sqrt(sqr(t + 15) - 4 * 15 * (t + index)) + 0.001f) / 30; + + case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE: + t = (5 * numPointsForInsideTessFactor - (12 - t)) * 3; + return 1 + uint((t + 15) - sqrt(sqr(t + 15) - 4 * 15 * (t + index)) + 0.001f) / 30; + + case DIAGONALS_MIRRORED: + t = ((t + 1) + 2 * numPointsForInsideTessFactor) * 3; + return 1 + uint((t + 6) - sqrt(sqr(t + 6) - 4 * 6 * (t + index)) + 0.001f) / 12; + + default: + return -1; + } +} + +uint3 NumStitchTransition(int4 outsideInsideNumHalfTessFactorPoints, + int4 outsideInsideEdgeTessFactorParity) +{ + outsideInsideNumHalfTessFactorPoints -= (TESSELLATOR_PARITY_ODD == outsideInsideEdgeTessFactorParity); + + uint3 num_index = insidePointIndex[outsideInsideNumHalfTessFactorPoints.w][MAX_FACTOR / 2 + 1].y * 8; + + [unroll] + for (int edge = 0; edge < 3; ++ edge) + { + num_index[edge] += outsidePointIndex[outsideInsideNumHalfTessFactorPoints[edge]][MAX_FACTOR / 2 + 1].y * 8; + + if( (outsideInsideEdgeTessFactorParity.w != outsideInsideEdgeTessFactorParity[edge]) || (outsideInsideEdgeTessFactorParity.w == TESSELLATOR_PARITY_ODD)) + { + if( outsideInsideEdgeTessFactorParity.w == outsideInsideEdgeTessFactorParity[edge] ) + { + num_index[edge] += 5; + } + else + { + num_index[edge] += 4; + } + } + } + + return num_index; +} diff --git a/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_defines.h b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_defines.h new file mode 100644 index 000000000..6b4382393 --- /dev/null +++ b/tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_defines.h @@ -0,0 +1,9 @@ +//-------------------------------------------------------------------------------------- +// File: TessellatorCS40_defines.h +// +// This file defines common constants which are included by both CPU code and shader code +// +// Copyright (c) Microsoft Corporation. All rights reserved. +//-------------------------------------------------------------------------------------- + +#define MAX_FACTOR 16 |
