1 // Copyright (c) 2013- PPSSPP Project. 2 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU General Public License as published by 5 // the Free Software Foundation, version 2.0 or later versions. 6 7 // This program is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 // GNU General Public License 2.0 for more details. 11 12 // A copy of the GPL 2.0 should have been included with the program. 13 // If not, see http://www.gnu.org/licenses/ 14 15 // Official git repository and contact information can be found at 16 // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. 17 18 #pragma once 19 #include <unordered_map> 20 21 #include "Common/CommonTypes.h" 22 #include "Common/Swap.h" 23 #include "GPU/Math3D.h" 24 #include "GPU/ge_constants.h" 25 #include "Core/Config.h" 26 27 #define HALF_CEIL(x) (x + 1) / 2 // Integer ceil = (int)ceil((float)x / 2.0f) 28 29 // PSP compatible format so we can use the end of the pipeline in beziers etc 30 struct SimpleVertex { 31 float uv[2]; 32 union { 33 u8 color[4]; 34 u32_le color_32; 35 }; 36 Vec3Packedf nrm; 37 Vec3Packedf pos; 38 }; 39 40 class SimpleBufferManager; 41 42 namespace Spline { 43 44 void BuildIndex(u16 *indices, int &count, int num_u, int num_v, GEPatchPrimType prim_type, int total = 0); 45 46 enum SplineQuality { 47 LOW_QUALITY = 0, 48 MEDIUM_QUALITY = 1, 49 HIGH_QUALITY = 2, 50 }; 51 52 class Bezier3DWeight; 53 class Spline3DWeight; 54 55 // We decode all vertices into a common format for easy interpolation and stuff. 56 // Not fast but can be optimized later. 57 58 struct SurfaceInfo { 59 int tess_u, tess_v; 60 int num_points_u, num_points_v; 61 int num_patches_u, num_patches_v; 62 int type_u, type_v; 63 GEPatchPrimType primType; 64 bool patchFacing; 65 66 void Init() { 67 // If specified as 0, uses 1. 68 if (tess_u < 1) tess_u = 1; 69 if (tess_v < 1) tess_v = 1; 70 71 switch (g_Config.iSplineBezierQuality) { 72 case LOW_QUALITY: 73 tess_u = 2; 74 tess_v = 2; 75 break; 76 case MEDIUM_QUALITY: 77 // Don't cut below 2, though. 78 if (tess_u > 2) tess_u = HALF_CEIL(tess_u); 79 if (tess_v > 2) tess_v = HALF_CEIL(tess_v); 80 break; 81 } 82 } 83 }; 84 85 struct BezierSurface : public SurfaceInfo { 86 using WeightType = Bezier3DWeight; 87 88 int num_verts_per_patch; 89 90 void Init(int maxVertices) { 91 SurfaceInfo::Init(); 92 // Downsample until it fits, in case crazy tessellation factors are sent. 93 while ((tess_u + 1) * (tess_v + 1) * num_patches_u * num_patches_v > maxVertices) { 94 tess_u--; 95 tess_v--; 96 } 97 num_verts_per_patch = (tess_u + 1) * (tess_v + 1); 98 } 99 100 int GetTessStart(int patch) const { return 0; } 101 102 int GetPointIndex(int patch_u, int patch_v) const { return patch_v * 3 * num_points_u + patch_u * 3; } 103 104 int GetIndexU(int patch_u, int tile_u) const { return tile_u; } 105 int GetIndexV(int patch_v, int tile_v) const { return tile_v; } 106 107 int GetIndex(int index_u, int index_v, int patch_u, int patch_v) const { 108 int patch_index = patch_v * num_patches_u + patch_u; 109 return index_v * (tess_u + 1) + index_u + num_verts_per_patch * patch_index; 110 } 111 112 void BuildIndex(u16 *indices, int &count) const { 113 for (int patch_u = 0; patch_u < num_patches_u; ++patch_u) { 114 for (int patch_v = 0; patch_v < num_patches_v; ++patch_v) { 115 int patch_index = patch_v * num_patches_u + patch_u; 116 int total = patch_index * num_verts_per_patch; 117 Spline::BuildIndex(indices + count, count, tess_u, tess_v, primType, total); 118 } 119 } 120 } 121 }; 122 123 struct SplineSurface : public SurfaceInfo { 124 using WeightType = Spline3DWeight; 125 126 int num_vertices_u; 127 128 void Init(int maxVertices) { 129 SurfaceInfo::Init(); 130 // Downsample until it fits, in case crazy tessellation factors are sent. 131 while ((num_patches_u * tess_u + 1) * (num_patches_v * tess_v + 1) > maxVertices) { 132 tess_u--; 133 tess_v--; 134 } 135 num_vertices_u = num_patches_u * tess_u + 1; 136 } 137 138 int GetTessStart(int patch) const { return (patch == 0) ? 0 : 1; } 139 140 int GetPointIndex(int patch_u, int patch_v) const { return patch_v * num_points_u + patch_u; } 141 142 int GetIndexU(int patch_u, int tile_u) const { return patch_u * tess_u + tile_u; } 143 int GetIndexV(int patch_v, int tile_v) const { return patch_v * tess_v + tile_v; } 144 145 int GetIndex(int index_u, int index_v, int patch_u, int patch_v) const { 146 return index_v * num_vertices_u + index_u; 147 } 148 149 void BuildIndex(u16 *indices, int &count) const { 150 Spline::BuildIndex(indices, count, num_patches_u * tess_u, num_patches_v * tess_v, primType); 151 } 152 }; 153 154 struct Weight { 155 float basis[4], deriv[4]; 156 }; 157 158 template<class T> 159 class WeightCache : public T { 160 private: 161 std::unordered_map<u32, Weight*> weightsCache; 162 public: 163 Weight* operator [] (u32 key) { 164 Weight *&weights = weightsCache[key]; 165 if (!weights) 166 weights = T::CalcWeightsAll(key); 167 return weights; 168 } 169 170 void Clear() { 171 for (auto it : weightsCache) 172 delete[] it.second; 173 weightsCache.clear(); 174 } 175 }; 176 177 struct Weight2D { 178 const Weight *u, *v; 179 int size_u, size_v; 180 181 template<class T> 182 Weight2D(WeightCache<T> &cache, u32 key_u, u32 key_v) { 183 u = cache[key_u]; 184 v = (key_u != key_v) ? cache[key_v] : u; // Use same weights if u == v 185 } 186 }; 187 188 struct ControlPoints { 189 Vec3f *pos; 190 Vec2f *tex; 191 Vec4f *col; 192 u32_le defcolor; 193 194 ControlPoints() {} 195 ControlPoints(const SimpleVertex *const *points, int size, SimpleBufferManager &managedBuf); 196 void Convert(const SimpleVertex *const *points, int size); 197 }; 198 199 struct OutputBuffers { 200 SimpleVertex *vertices; 201 u16 *indices; 202 int count; 203 }; 204 205 template<class Surface> 206 void SoftwareTessellation(OutputBuffers &output, const Surface &surface, u32 origVertType, const ControlPoints &points); 207 208 } // namespace Spline 209 210 // Define function object for TemplateParameterDispatcher 211 #define TEMPLATE_PARAMETER_DISPATCHER_FUNCTION(NAME, FUNCNAME, FUNCTYPE) \ 212 struct NAME { \ 213 template<bool ...Params> \ 214 static FUNCTYPE GetFunc() { \ 215 return &FUNCNAME<Params...>; \ 216 } \ 217 }; 218 219 template<typename Func, int NumParams, class Dispatcher> 220 class TemplateParameterDispatcher { 221 222 /* Store all combinations of template functions into an array */ 223 template<int LoopCount, int Index = 0, bool ...Params> 224 struct Initializer { 225 static void Init(Func funcs[]) { 226 Initializer<LoopCount - 1, (Index << 1) + 1, true, Params...>::Init(funcs); // true 227 Initializer<LoopCount - 1, (Index << 1) + 0, false, Params...>::Init(funcs); // false 228 } 229 }; 230 /* Specialized for terminates the recursive loop */ 231 template<int Index, bool ...Params> 232 struct Initializer<0, Index, Params...> { 233 static void Init(Func funcs[]) { 234 funcs[Index] = Dispatcher::template GetFunc<Params...>(); // Resolve the nested dependent name as template function. 235 } 236 }; 237 238 private: 239 Func funcs[1 << NumParams]; /* Function pointers array */ 240 public: 241 TemplateParameterDispatcher() { 242 Initializer<NumParams>::Init(funcs); 243 } 244 245 Func GetFunc(const bool params[]) const { 246 /* Convert bool parameters to index of the array */ 247 int index = 0; 248 for (int i = 0; i < NumParams; ++i) 249 index |= params[i] << i; 250 251 return funcs[index]; 252 } 253 }; 254