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