1 /****************************************************************************
2 * Copyright (C) 2014-2019 without restriction, including without limitation
3 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
4 * and/or sell copies of the Software, and to permit persons to whom the
5 * Software is furnished to do so, subject to the following conditions:
6 *
7 * The above copyright notice and this permission notice (including the next
8 * paragraph) shall be included in all copies or substantial portions of the
9 * Software.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
14 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
16 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
17 * IN THE SOFTWARE.
18 *
19 * @file tessellator.h
20 *
21 * @brief Tessellator fixed function unit interface definition
22 *
23 ******************************************************************************/
24 #pragma once
25
26 #include "tessellator.hpp"
27
28 struct SWR_TS_TESSELLATED_DATA
29 {
30 uint32_t NumPrimitives;
31 uint32_t NumDomainPoints;
32
33 uint32_t* ppIndices[3];
34 float* pDomainPointsU;
35 float* pDomainPointsV;
36 // For Tri: pDomainPointsW[i] = 1.0f - pDomainPointsU[i] - pDomainPointsV[i]
37 };
38
39 namespace Tessellator
40 {
41 /// Wrapper class for the CHWTessellator reference tessellator from MSFT
42 /// This class will store data not originally stored in CHWTessellator
43 class SWR_TS : private CHWTessellator
44 {
45 private:
46 typedef CHWTessellator SUPER;
47 SWR_TS_DOMAIN Domain;
48 OSALIGNSIMD(float) DomainPointsU[MAX_POINT_COUNT];
49 OSALIGNSIMD(float) DomainPointsV[MAX_POINT_COUNT];
50 uint32_t NumDomainPoints;
51 OSALIGNSIMD(uint32_t) Indices[3][MAX_INDEX_COUNT / 3];
52 uint32_t NumIndices;
53
54 public:
Init(SWR_TS_DOMAIN tsDomain,SWR_TS_PARTITIONING tsPartitioning,SWR_TS_OUTPUT_TOPOLOGY tsOutputTopology)55 void Init(SWR_TS_DOMAIN tsDomain,
56 SWR_TS_PARTITIONING tsPartitioning,
57 SWR_TS_OUTPUT_TOPOLOGY tsOutputTopology)
58 {
59 static D3D11_TESSELLATOR_PARTITIONING CVT_TS_D3D_PARTITIONING[] = {
60 D3D11_TESSELLATOR_PARTITIONING_INTEGER, // SWR_TS_INTEGER
61 D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD, // SWR_TS_ODD_FRACTIONAL
62 D3D11_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN, // SWR_TS_EVEN_FRACTIONAL
63 D3D11_TESSELLATOR_PARTITIONING_POW2 // SWR_TS_POW2
64 };
65
66 static D3D11_TESSELLATOR_OUTPUT_PRIMITIVE CVT_TS_D3D_OUTPUT_TOPOLOGY[] = {
67 D3D11_TESSELLATOR_OUTPUT_POINT, // SWR_TS_OUTPUT_POINT
68 D3D11_TESSELLATOR_OUTPUT_LINE, // SWR_TS_OUTPUT_LINE
69 D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CCW, // SWR_TS_OUTPUT_TRI_CW - inverted logic, because DX
70 D3D11_TESSELLATOR_OUTPUT_TRIANGLE_CW // SWR_TS_OUTPUT_TRI_CCW - inverted logic, because DX
71 };
72
73 SUPER::Init(CVT_TS_D3D_PARTITIONING[tsPartitioning],
74 CVT_TS_D3D_OUTPUT_TOPOLOGY[tsOutputTopology]);
75
76 Domain = tsDomain;
77 NumDomainPoints = 0;
78 NumIndices = 0;
79 }
80
Tessellate(const SWR_TESSELLATION_FACTORS & tsTessFactors,SWR_TS_TESSELLATED_DATA & tsTessellatedData)81 void Tessellate(const SWR_TESSELLATION_FACTORS& tsTessFactors,
82 SWR_TS_TESSELLATED_DATA& tsTessellatedData)
83 {
84 uint32_t IndexDiv = 0;
85 switch (Domain)
86 {
87 case SWR_TS_QUAD:
88 IndexDiv = 3;
89 SUPER::TessellateQuadDomain(
90 tsTessFactors.OuterTessFactors[SWR_QUAD_U_EQ0_TRI_U_LINE_DETAIL],
91 tsTessFactors.OuterTessFactors[SWR_QUAD_V_EQ0_TRI_W],
92 tsTessFactors.OuterTessFactors[SWR_QUAD_U_EQ1_TRI_V_LINE_DENSITY],
93 tsTessFactors.OuterTessFactors[SWR_QUAD_V_EQ1],
94 tsTessFactors.InnerTessFactors[SWR_QUAD_U_TRI_INSIDE],
95 tsTessFactors.InnerTessFactors[SWR_QUAD_V_INSIDE]);
96 break;
97
98 case SWR_TS_TRI:
99 IndexDiv = 3;
100 SUPER::TessellateTriDomain(
101 tsTessFactors.OuterTessFactors[SWR_QUAD_U_EQ0_TRI_U_LINE_DETAIL],
102 tsTessFactors.OuterTessFactors[SWR_QUAD_U_EQ1_TRI_V_LINE_DENSITY],
103 tsTessFactors.OuterTessFactors[SWR_QUAD_V_EQ0_TRI_W],
104 tsTessFactors.InnerTessFactors[SWR_QUAD_U_TRI_INSIDE]);
105 break;
106
107 case SWR_TS_ISOLINE:
108 IndexDiv = 2;
109 SUPER::TessellateIsoLineDomain(
110 tsTessFactors.OuterTessFactors[SWR_QUAD_U_EQ1_TRI_V_LINE_DENSITY],
111 tsTessFactors.OuterTessFactors[SWR_QUAD_U_EQ0_TRI_U_LINE_DETAIL]);
112 break;
113
114 default:
115 SWR_INVALID("Invalid Tessellation Domain: %d", Domain);
116 assert(false);
117 }
118
119 NumDomainPoints = (uint32_t)SUPER::GetPointCount();
120
121 DOMAIN_POINT* pPoints = SUPER::GetPoints();
122 for (uint32_t i = 0; i < NumDomainPoints; i++) {
123 DomainPointsU[i] = pPoints[i].u;
124 DomainPointsV[i] = pPoints[i].v;
125 }
126 tsTessellatedData.NumDomainPoints = NumDomainPoints;
127 tsTessellatedData.pDomainPointsU = &DomainPointsU[0];
128 tsTessellatedData.pDomainPointsV = &DomainPointsV[0];
129
130 NumIndices = (uint32_t)SUPER::GetIndexCount();
131
132 assert(NumIndices % IndexDiv == 0);
133 tsTessellatedData.NumPrimitives = NumIndices / IndexDiv;
134
135 uint32_t* pIndices = (uint32_t*)SUPER::GetIndices();
136 for (uint32_t i = 0; i < NumIndices; i++) {
137 Indices[i % IndexDiv][i / IndexDiv] = pIndices[i];
138 }
139
140 tsTessellatedData.ppIndices[0] = &Indices[0][0];
141 tsTessellatedData.ppIndices[1] = &Indices[1][0];
142 tsTessellatedData.ppIndices[2] = &Indices[2][0];
143 }
144 };
145 } // namespace Tessellator
146
147 /// Allocate and initialize a new tessellation context
148 INLINE HANDLE SWR_API
TSInitCtx(SWR_TS_DOMAIN tsDomain,SWR_TS_PARTITIONING tsPartitioning,SWR_TS_OUTPUT_TOPOLOGY tsOutputTopology,void * pContextMem,size_t & memSize)149 TSInitCtx(SWR_TS_DOMAIN tsDomain, ///< [IN] Tessellation domain (isoline, quad, triangle)
150 SWR_TS_PARTITIONING tsPartitioning, ///< [IN] Tessellation partitioning algorithm
151 SWR_TS_OUTPUT_TOPOLOGY tsOutputTopology, ///< [IN] Tessellation output topology
152 void* pContextMem, ///< [IN] Memory to use for the context
153 size_t& memSize) ///< [INOUT] In: Amount of memory in pContextMem. Out: Mem required
154 {
155 using Tessellator::SWR_TS;
156 SWR_ASSERT(tsDomain < SWR_TS_DOMAIN_COUNT);
157 SWR_ASSERT(tsPartitioning < SWR_TS_PARTITIONING_COUNT);
158 SWR_ASSERT(tsOutputTopology < SWR_TS_OUTPUT_TOPOLOGY_COUNT);
159
160 size_t origMemSize = memSize;
161 memSize = AlignUp(sizeof(SWR_TS), 64);
162
163 if (nullptr == pContextMem || memSize > origMemSize)
164 {
165 return nullptr;
166 }
167
168 HANDLE tsCtx = pContextMem;
169
170 SWR_TS* pTessellator = new (tsCtx) SWR_TS();
171 SWR_ASSERT(pTessellator == tsCtx);
172
173 pTessellator->Init(tsDomain, tsPartitioning, tsOutputTopology);
174
175 return tsCtx;
176 }
177
178 /// Destroy & de-allocate tessellation context
TSDestroyCtx(HANDLE tsCtx)179 INLINE void SWR_API TSDestroyCtx(HANDLE tsCtx) ///< [IN] Tessellation context to be destroyed
180 {
181 using Tessellator::SWR_TS;
182 SWR_TS* pTessellator = (SWR_TS*)tsCtx;
183
184 if (pTessellator)
185 {
186 pTessellator->~SWR_TS();
187 }
188 }
189
190 /// Perform Tessellation
191 INLINE void SWR_API
TSTessellate(HANDLE tsCtx,const SWR_TESSELLATION_FACTORS & tsTessFactors,SWR_TS_TESSELLATED_DATA & tsTessellatedData)192 TSTessellate(HANDLE tsCtx, ///< [IN] Tessellation Context
193 const SWR_TESSELLATION_FACTORS& tsTessFactors, ///< [IN] Tessellation Factors
194 SWR_TS_TESSELLATED_DATA& tsTessellatedData) ///< [OUT] Tessellated Data
195 {
196 using Tessellator::SWR_TS;
197 SWR_TS* pTessellator = (SWR_TS*)tsCtx;
198 SWR_ASSERT(pTessellator);
199
200 pTessellator->Tessellate(tsTessFactors, tsTessellatedData);
201 }
202
203