summaryrefslogtreecommitdiff
path: root/tests/hlsl/dxsdk/AdaptiveTessellationCS40
diff options
context:
space:
mode:
authorTim Foley <tfoley@nvidia.com>2017-06-09 11:34:21 -0700
committerTim Foley <tfoley@nvidia.com>2017-06-09 13:44:59 -0700
commitfcf83dbf9effab3bd98bad2b83b2468b7eb05cfd (patch)
tree41047c94883b86ec085a81597391ce3ef557cd43 /tests/hlsl/dxsdk/AdaptiveTessellationCS40
parent52e8d4b9a27ab0060f874c3a63ab531847be35c0 (diff)
Initial import of code.
Diffstat (limited to 'tests/hlsl/dxsdk/AdaptiveTessellationCS40')
-rw-r--r--tests/hlsl/dxsdk/AdaptiveTessellationCS40/Render.hlsl58
-rw-r--r--tests/hlsl/dxsdk/AdaptiveTessellationCS40/ScanCS.hlsl109
-rw-r--r--tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_EdgeFactorCS.hlsl217
-rw-r--r--tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_NumVerticesIndicesCS.hlsl56
-rw-r--r--tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_ScatterIDCS.hlsl45
-rw-r--r--tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_TessellateIndicesCS.hlsl628
-rw-r--r--tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_TessellateVerticesCS.hlsl206
-rw-r--r--tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_common.hlsl411
-rw-r--r--tests/hlsl/dxsdk/AdaptiveTessellationCS40/TessellatorCS40_defines.h9
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