1/**************************************************************************
2 *
3 * Copyright 2020 Red Hat.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 *
24 **************************************************************************/
25
26#include "util/u_math.h"
27#include "util/u_memory.h"
28#include "pipe/p_defines.h"
29#include "p_tessellator.h"
30#include "tessellator.hpp"
31
32#include <new>
33
34namespace pipe_tessellator_wrap
35{
36   /// Wrapper class for the CHWTessellator reference tessellator from MSFT
37   /// This class will store data not originally stored in CHWTessellator
38   class pipe_ts : private CHWTessellator
39   {
40   private:
41      typedef CHWTessellator SUPER;
42      enum pipe_prim_type    prim_mode;
43      PIPE_ALIGN_VAR(32) float     domain_points_u[MAX_POINT_COUNT];
44      PIPE_ALIGN_VAR(32) float     domain_points_v[MAX_POINT_COUNT];
45      uint32_t               num_domain_points;
46
47   public:
48      void Init(enum pipe_prim_type tes_prim_mode,
49                enum pipe_tess_spacing ts_spacing,
50                bool tes_vertex_order_cw, bool tes_point_mode)
51      {
52         static PIPE_TESSELLATOR_PARTITIONING CVT_TS_D3D_PARTITIONING[] = {
53                                                                            PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD,  // PIPE_TESS_SPACING_ODD
54                                                                            PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN, // PIPE_TESS_SPACING_EVEN
55                                                                            PIPE_TESSELLATOR_PARTITIONING_INTEGER,         // PIPE_TESS_SPACING_EQUAL
56         };
57
58         PIPE_TESSELLATOR_OUTPUT_PRIMITIVE out_prim;
59         if (tes_point_mode)
60            out_prim = PIPE_TESSELLATOR_OUTPUT_POINT;
61         else if (tes_prim_mode == PIPE_PRIM_LINES)
62            out_prim = PIPE_TESSELLATOR_OUTPUT_LINE;
63         else if (tes_vertex_order_cw)
64            out_prim = PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CW;
65         else
66            out_prim = PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CCW;
67
68         SUPER::Init(CVT_TS_D3D_PARTITIONING[ts_spacing],
69                     out_prim);
70
71         prim_mode          = tes_prim_mode;
72         num_domain_points = 0;
73      }
74
75      void Tessellate(const struct pipe_tessellation_factors *tess_factors,
76                      struct pipe_tessellator_data *tess_data)
77      {
78         switch (prim_mode)
79            {
80            case PIPE_PRIM_QUADS:
81               SUPER::TessellateQuadDomain(
82                                           tess_factors->outer_tf[0],
83                                           tess_factors->outer_tf[1],
84                                           tess_factors->outer_tf[2],
85                                           tess_factors->outer_tf[3],
86                                           tess_factors->inner_tf[0],
87                                           tess_factors->inner_tf[1]);
88               break;
89
90            case PIPE_PRIM_TRIANGLES:
91               SUPER::TessellateTriDomain(
92                                          tess_factors->outer_tf[0],
93                                          tess_factors->outer_tf[1],
94                                          tess_factors->outer_tf[2],
95                                          tess_factors->inner_tf[0]);
96               break;
97
98            case PIPE_PRIM_LINES:
99               SUPER::TessellateIsoLineDomain(
100                                              tess_factors->outer_tf[0],
101                                              tess_factors->outer_tf[1]);
102               break;
103
104            default:
105               assert(0);
106               return;
107            }
108
109         num_domain_points = (uint32_t)SUPER::GetPointCount();
110
111         DOMAIN_POINT *points = SUPER::GetPoints();
112         for (uint32_t i = 0; i < num_domain_points; i++) {
113            domain_points_u[i] = points[i].u;
114            domain_points_v[i] = points[i].v;
115         }
116         tess_data->num_domain_points = num_domain_points;
117         tess_data->domain_points_u = &domain_points_u[0];
118         tess_data->domain_points_v = &domain_points_v[0];
119
120         tess_data->num_indices = (uint32_t)SUPER::GetIndexCount();
121
122         tess_data->indices = (uint32_t*)SUPER::GetIndices();
123      }
124   };
125} // namespace Tessellator
126
127/* allocate tessellator */
128struct pipe_tessellator *
129p_tess_init(enum pipe_prim_type tes_prim_mode,
130            enum pipe_tess_spacing spacing,
131            bool tes_vertex_order_cw, bool tes_point_mode)
132{
133   void *mem;
134   using pipe_tessellator_wrap::pipe_ts;
135
136   mem = align_malloc(sizeof(pipe_ts), 256);
137
138   pipe_ts* tessellator = new (mem) pipe_ts();
139
140   tessellator->Init(tes_prim_mode, spacing, tes_vertex_order_cw, tes_point_mode);
141
142   return (struct pipe_tessellator *)tessellator;
143}
144
145/* destroy tessellator */
146void p_tess_destroy(struct pipe_tessellator *pipe_tess)
147{
148   using pipe_tessellator_wrap::pipe_ts;
149   pipe_ts *tessellator = (pipe_ts*)pipe_tess;
150
151   tessellator->~pipe_ts();
152   align_free(tessellator);
153}
154
155/* perform tessellation */
156void p_tessellate(struct pipe_tessellator *pipe_tess,
157                  const struct pipe_tessellation_factors *tess_factors,
158                  struct pipe_tessellator_data *tess_data)
159{
160   using pipe_tessellator_wrap::pipe_ts;
161   pipe_ts *tessellator = (pipe_ts*)pipe_tess;
162
163   tessellator->Tessellate(tess_factors, tess_data);
164}
165
166