Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/auxiliary/tessellator/tessellator.cpp
4565 views
1
/*
2
Copyright (c) Microsoft Corporation
3
4
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
5
associated documentation files (the "Software"), to deal in the Software without restriction,
6
including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
7
and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
8
subject to the following conditions:
9
10
The above copyright notice and this permission notice shall be included in all copies or substantial
11
portions of the Software.
12
13
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
14
NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
15
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
16
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
17
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18
*/
19
20
#include "tessellator.hpp"
21
#include "util/macros.h"
22
#if defined(_MSC_VER)
23
#include <math.h> // ceil
24
#else
25
#include <cmath>
26
#endif
27
#define min(x,y) (x < y ? x : y)
28
#define max(x,y) (x > y ? x : y)
29
30
//=================================================================================================================================
31
// Some D3D Compliant Float Math (reference rasterizer implements these in RefALU class)
32
//=================================================================================================================================
33
//
34
//---------------------------------------------------------------------------------------------------------------------------------
35
// isNaN
36
//---------------------------------------------------------------------------------------------------------------------------------
37
38
union fiu {
39
float f;
40
int i;
41
};
42
43
static bool tess_isNaN( float a )
44
{
45
static const int exponentMask = 0x7f800000;
46
static const int mantissaMask = 0x007fffff;
47
union fiu fiu;
48
fiu.f = a;
49
return ( ( ( fiu.i & exponentMask ) == exponentMask ) && ( fiu.i & mantissaMask ) ); // NaN
50
}
51
52
//---------------------------------------------------------------------------------------------------------------------------------
53
// flush (denorm)
54
//---------------------------------------------------------------------------------------------------------------------------------
55
static float tess_flush( float a )
56
{
57
static const int minNormalizedFloat = 0x00800000;
58
static const int signBit = 0x80000000;
59
static const int signBitComplement = 0x7fffffff;
60
union fiu fiu, uif;
61
fiu.f = a;
62
int b = fiu.i & signBitComplement; // fabs()
63
if( b < minNormalizedFloat ) // UINT comparison. NaN/INF do test false here
64
{
65
b = signBit & (fiu.i);
66
uif.i = b;
67
return uif.f;
68
}
69
return a;
70
}
71
72
//---------------------------------------------------------------------------------------------------------------------------------
73
// IEEE754R min
74
//---------------------------------------------------------------------------------------------------------------------------------
75
static float tess_fmin( float a, float b )
76
{
77
float _a = tess_flush( a );
78
float _b = tess_flush( b );
79
if( tess_isNaN( _b ) )
80
{
81
return a;
82
}
83
else if( ( _a == 0 ) && ( _b == 0 ) )
84
{
85
union fiu fiu;
86
fiu.f = _a;
87
return ( fiu.i & 0x80000000 ) ? a : b;
88
}
89
return _a < _b ? a : b;
90
}
91
92
//---------------------------------------------------------------------------------------------------------------------------------
93
// IEEE754R max
94
//---------------------------------------------------------------------------------------------------------------------------------
95
static float tess_fmax( float a, float b )
96
{
97
float _a = tess_flush( a );
98
float _b = tess_flush( b );
99
100
if( tess_isNaN( _b ) )
101
{
102
return a;
103
}
104
else if( ( _a == 0 ) && ( _b == 0 ) )
105
{
106
union fiu fiu;
107
fiu.f = _b;
108
return ( fiu.i & 0x80000000 ) ? a : b;
109
}
110
return _a >= _b ? a : b;
111
}
112
113
//=================================================================================================================================
114
// Fixed Point Math
115
//=================================================================================================================================
116
117
//-----------------------------------------------------------------------------------------------------------------------------
118
// floatToFixedPoint
119
//
120
// Convert 32-bit float to 32-bit fixed point integer, using only
121
// integer arithmetic + bitwise operations.
122
//
123
// c_uIBits: UINT8 : Width of i (aka. integer bits)
124
// c_uFBits: UINT8 : Width of f (aka. fractional bits)
125
// c_bSigned: bool : Whether the integer bits are a 2's complement signed value
126
// input: float : All values valid.
127
// output: INT32 : At most 24 bits from LSB are meaningful, depending
128
// on the fixed point bit representation chosen (see
129
// below). Extra bits are sign extended from the most
130
// meaningful bit.
131
//
132
//-----------------------------------------------------------------------------------------------------------------------------
133
134
typedef unsigned char UINT8;
135
typedef int INT32;
136
template< const UINT8 c_uIBits, const UINT8 c_uFBits, const bool c_bSigned >
137
INT32 floatToIDotF( const float& input )
138
{
139
// ------------------------------------------------------------------------
140
// output fixed point format
141
// 32-bit result:
142
//
143
// [sign-extend]i.f
144
// | |
145
// MSB(31)...LSB(0)
146
//
147
// f fractional part of the number, an unsigned
148
// value with _fxpFracBitCount bits (defined below)
149
//
150
// . implied decimal
151
//
152
// i integer part of the number, a 2's complement
153
// value with _fxpIntBitCount bits (defined below)
154
//
155
// [sign-extend] MSB of i conditionally replicated
156
//
157
// ------------------------------------------------------------------------
158
// Define fixed point bit counts
159
//
160
161
// Commenting out C_ASSERT below to minimise #includes:
162
// C_ASSERT( 2 <= c_uIBits && c_uIBits <= 32 && c_uFBits <= 32 && c_uIBits + c_uFBits <= 32 );
163
164
// Define most negative and most positive fixed point values
165
const INT32 c_iMinResult = (c_bSigned ? INT32( -1 ) << (c_uIBits + c_uFBits - 1) : 0);
166
const INT32 c_iMaxResult = ~c_iMinResult;
167
168
// ------------------------------------------------------------------------
169
// constant float properties
170
// ------------------------------------------------------------------------
171
const UINT8 _fltMantissaBitCount = 23;
172
const UINT8 _fltExponentBitCount = 8;
173
const INT32 _fltExponentBias = (INT32( 1 ) << (_fltExponentBitCount - 1)) - 1;
174
const INT32 _fltHiddenBit = INT32( 1 ) << _fltMantissaBitCount;
175
const INT32 _fltMantissaMask = _fltHiddenBit - 1;
176
const INT32 _fltExponentMask = ((INT32( 1 ) << _fltExponentBitCount) - 1) << _fltMantissaBitCount;
177
const INT32 _fltSignBit = INT32( 1 ) << (_fltExponentBitCount + _fltMantissaBitCount);
178
179
// ------------------------------------------------------------------------
180
// define min and max values as floats (clamp to these bounds)
181
// ------------------------------------------------------------------------
182
INT32 _fxpMaxPosValueFloat;
183
INT32 _fxpMaxNegValueFloat;
184
185
if (c_bSigned)
186
{
187
// The maximum positive fixed point value is 2^(i-1) - 2^(-f).
188
// The following constructs the floating point bit pattern for this value,
189
// as long as i >= 2.
190
_fxpMaxPosValueFloat = (_fltExponentBias + c_uIBits - 1) <<_fltMantissaBitCount;
191
const INT32 iShift = _fltMantissaBitCount + 2 - c_uIBits - c_uFBits;
192
if (iShift >= 0)
193
{
194
// assert( iShift < 32 );
195
#if defined(_MSC_VER)
196
#pragma warning( push )
197
#pragma warning( disable : 4293 26452 )
198
#endif
199
_fxpMaxPosValueFloat -= INT32( 1 ) << iShift;
200
#if defined(_MSC_VER)
201
#pragma warning( pop )
202
#endif
203
}
204
205
// The maximum negative fixed point value is -2^(i-1).
206
// The following constructs the floating point bit pattern for this value,
207
// as long as i >= 2.
208
// We need this number without the sign bit
209
_fxpMaxNegValueFloat = (_fltExponentBias + c_uIBits - 1) << _fltMantissaBitCount;
210
}
211
else
212
{
213
// The maximum positive fixed point value is 2^(i) - 2^(-f).
214
// The following constructs the floating point bit pattern for this value,
215
// as long as i >= 2.
216
_fxpMaxPosValueFloat = (_fltExponentBias + c_uIBits) <<_fltMantissaBitCount;
217
const INT32 iShift = _fltMantissaBitCount + 1 - c_uIBits - c_uFBits;
218
if (iShift >= 0)
219
{
220
// assert( iShift < 32 );
221
#if defined(_MSC_VER)
222
#pragma warning( push )
223
#pragma warning( disable : 4293 26452 )
224
#endif
225
_fxpMaxPosValueFloat -= INT32( 1 ) << iShift;
226
#if defined(_MSC_VER)
227
#pragma warning( pop )
228
#endif
229
}
230
231
// The maximum negative fixed point value is 0.
232
_fxpMaxNegValueFloat = 0;
233
}
234
235
// ------------------------------------------------------------------------
236
// float -> fixed conversion
237
// ------------------------------------------------------------------------
238
239
// ------------------------------------------------------------------------
240
// examine input float
241
// ------------------------------------------------------------------------
242
INT32 output = *(INT32*)&input;
243
INT32 unbiasedExponent = ((output & _fltExponentMask) >> _fltMantissaBitCount) - _fltExponentBias;
244
INT32 isNegative = output & _fltSignBit;
245
246
// ------------------------------------------------------------------------
247
// nan
248
// ------------------------------------------------------------------------
249
if (unbiasedExponent == (_fltExponentBias + 1) && (output & _fltMantissaMask))
250
{
251
// nan converts to 0
252
output = 0;
253
}
254
// ------------------------------------------------------------------------
255
// too large positive
256
// ------------------------------------------------------------------------
257
else if (!isNegative && output >= _fxpMaxPosValueFloat) // integer compare
258
{
259
output = c_iMaxResult;
260
}
261
// ------------------------------------------------------------------------
262
// too large negative
263
// ------------------------------------------------------------------------
264
// integer compare
265
else if (isNegative && (output & ~_fltSignBit) >= _fxpMaxNegValueFloat)
266
{
267
output = c_iMinResult;
268
}
269
// ------------------------------------------------------------------------
270
// too small
271
// ------------------------------------------------------------------------
272
else if (unbiasedExponent < -c_uFBits - 1)
273
{
274
// clamp to 0
275
output = 0;
276
}
277
// ------------------------------------------------------------------------
278
// within range
279
// ------------------------------------------------------------------------
280
else
281
{
282
// copy mantissa, add hidden bit
283
output = (output & _fltMantissaMask) | _fltHiddenBit;
284
285
INT32 extraBits = _fltMantissaBitCount - c_uFBits - unbiasedExponent;
286
if (extraBits >= 0)
287
{
288
// 2's complement if negative
289
if (isNegative)
290
{
291
output = ~output + 1;
292
}
293
294
// From the range checks that led here, it is known that
295
// unbiasedExponent < c_uIBits. So, at most:
296
// (a) unbiasedExponent == c_uIBits - 1.
297
//
298
// From compile validation above, it is known that
299
// c_uIBits + c_uFBits <= _fltMantissaBitCount + 1).
300
// So, at minimum:
301
// (b) _fltMantissaBitCount == _fxtIntBitCount + c_uFBits - 1
302
//
303
// Substituting (a) and (b) into extraBits calculation above:
304
// extraBits >= (_fxtIntBitCount + c_uFBits - 1)
305
// - c_uFBits - (c_uIBits - 1)
306
// extraBits >= 0
307
//
308
// Thus we only have to worry about shifting right by 0 or more
309
// bits to get the decimal to the right place, and never have
310
// to shift left.
311
312
INT32 LSB = 1 << extraBits; // last bit being kept
313
INT32 extraBitsMask = LSB - 1;
314
INT32 half = LSB >> 1; // round bias
315
316
// round to nearest-even at LSB
317
if ((output & LSB) || (output & extraBitsMask) > half)
318
{
319
output += half;
320
}
321
322
// shift off the extra bits (sign extending)
323
output >>= extraBits;
324
}
325
else
326
{
327
output <<= -extraBits;
328
329
// 2's complement if negative
330
if (isNegative)
331
{
332
output = ~output + 1;
333
}
334
}
335
}
336
return output;
337
}
338
//-----------------------------------------------------------------------------------------------------------------------------
339
340
#define FXP_INTEGER_BITS 15
341
#define FXP_FRACTION_BITS 16
342
#define FXP_FRACTION_MASK 0x0000ffff
343
#define FXP_INTEGER_MASK 0x7fff0000
344
#define FXP_THREE (3<<FXP_FRACTION_BITS)
345
#define FXP_ONE (1<<FXP_FRACTION_BITS)
346
#define FXP_ONE_THIRD 0x00005555
347
#define FXP_TWO_THIRDS 0x0000aaaa
348
#define FXP_ONE_HALF 0x00008000
349
350
#define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_TRIPLE_AVERAGE 0x55540000 // 1/3 of max fixed point number - 1. Numbers less than
351
// or equal to this allows avg. reduction on a tri patch
352
// including rounding.
353
354
#define FXP_MAX_INPUT_TESS_FACTOR_BEFORE_PAIR_AVERAGE 0x7FFF0000 // 1/2 of max fixed point number - 1. Numbers less than
355
// or equal to this allows avg. reduction on a quad patch
356
// including rounding.
357
358
static const FXP s_fixedReciprocal[PIPE_TESSELLATOR_MAX_TESSELLATION_FACTOR+1] =
359
{
360
0xffffffff, // 1/0 is the first entry (unused)
361
0x10000, 0x8000, 0x5555, 0x4000,
362
0x3333, 0x2aab, 0x2492, 0x2000,
363
0x1c72, 0x199a, 0x1746, 0x1555,
364
0x13b1, 0x1249, 0x1111, 0x1000,
365
0xf0f, 0xe39, 0xd79, 0xccd,
366
0xc31, 0xba3, 0xb21, 0xaab,
367
0xa3d, 0x9d9, 0x97b, 0x925,
368
0x8d4, 0x889, 0x842, 0x800,
369
0x7c2, 0x788, 0x750, 0x71c,
370
0x6eb, 0x6bd, 0x690, 0x666,
371
0x63e, 0x618, 0x5f4, 0x5d1,
372
0x5b0, 0x591, 0x572, 0x555,
373
0x539, 0x51f, 0x505, 0x4ec,
374
0x4d5, 0x4be, 0x4a8, 0x492,
375
0x47e, 0x46a, 0x457, 0x444,
376
0x432, 0x421, 0x410, 0x400, // 1/64 is the last entry
377
};
378
379
#define FLOAT_THREE 3.0f
380
#define FLOAT_ONE 1.0f
381
382
//---------------------------------------------------------------------------------------------------------------------------------
383
// floatToFixed
384
//---------------------------------------------------------------------------------------------------------------------------------
385
FXP floatToFixed(const float& input)
386
{
387
return floatToIDotF< FXP_INTEGER_BITS, FXP_FRACTION_BITS, /*bSigned*/false >( input );
388
}
389
390
//---------------------------------------------------------------------------------------------------------------------------------
391
// fixedToFloat
392
//---------------------------------------------------------------------------------------------------------------------------------
393
float fixedToFloat(const FXP& input)
394
{
395
// not worrying about denorm flushing the float operations (the DX spec behavior for div), since the numbers will not be that small during tessellation.
396
return ((float)(input>>FXP_FRACTION_BITS) + (float)(input&FXP_FRACTION_MASK)/(1<<FXP_FRACTION_BITS));
397
}
398
399
//---------------------------------------------------------------------------------------------------------------------------------
400
// isEven
401
//---------------------------------------------------------------------------------------------------------------------------------
402
bool isEven(const float& input)
403
{
404
return (((int)input) & 1) ? false : true;
405
}
406
407
//---------------------------------------------------------------------------------------------------------------------------------
408
// fxpCeil
409
//---------------------------------------------------------------------------------------------------------------------------------
410
FXP fxpCeil(const FXP& input)
411
{
412
if( input & FXP_FRACTION_MASK )
413
{
414
return (input & FXP_INTEGER_MASK) + FXP_ONE;
415
}
416
return input;
417
}
418
419
//---------------------------------------------------------------------------------------------------------------------------------
420
// fxpFloor
421
//---------------------------------------------------------------------------------------------------------------------------------
422
FXP fxpFloor(const FXP& input)
423
{
424
return (input & FXP_INTEGER_MASK);
425
}
426
427
//=================================================================================================================================
428
// CHWTessellator
429
//=================================================================================================================================
430
431
//---------------------------------------------------------------------------------------------------------------------------------
432
// CHWTessellator::CHWTessellator
433
//---------------------------------------------------------------------------------------------------------------------------------
434
CHWTessellator::CHWTessellator()
435
{
436
m_Point = 0;
437
m_Index = 0;
438
m_NumPoints = 0;
439
m_NumIndices = 0;
440
m_bUsingPatchedIndices = false;
441
m_bUsingPatchedIndices2 = false;
442
}
443
//---------------------------------------------------------------------------------------------------------------------------------
444
// CHWTessellator::~CHWTessellator
445
//---------------------------------------------------------------------------------------------------------------------------------
446
CHWTessellator::~CHWTessellator()
447
{
448
delete [] m_Point;
449
delete [] m_Index;
450
}
451
452
//---------------------------------------------------------------------------------------------------------------------------------
453
// CHWTessellator::Init
454
// User calls this.
455
//---------------------------------------------------------------------------------------------------------------------------------
456
void CHWTessellator::Init(
457
PIPE_TESSELLATOR_PARTITIONING partitioning,
458
PIPE_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive)
459
{
460
if( 0 == m_Point )
461
{
462
m_Point = new DOMAIN_POINT[MAX_POINT_COUNT];
463
}
464
if( 0 == m_Index )
465
{
466
m_Index = new int[MAX_INDEX_COUNT];
467
}
468
m_partitioning = partitioning;
469
m_originalPartitioning = partitioning;
470
switch( partitioning )
471
{
472
case PIPE_TESSELLATOR_PARTITIONING_INTEGER:
473
default:
474
break;
475
case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
476
m_parity = TESSELLATOR_PARITY_ODD;
477
break;
478
case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
479
m_parity = TESSELLATOR_PARITY_EVEN;
480
break;
481
}
482
m_originalParity = m_parity;
483
m_outputPrimitive = outputPrimitive;
484
m_NumPoints = 0;
485
m_NumIndices = 0;
486
}
487
//---------------------------------------------------------------------------------------------------------------------------------
488
// CHWTessellator::TessellateQuadDomain
489
// User calls this
490
//---------------------------------------------------------------------------------------------------------------------------------
491
void CHWTessellator::TessellateQuadDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,
492
float insideTessFactor_U, float insideTessFactor_V )
493
{
494
PROCESSED_TESS_FACTORS_QUAD processedTessFactors;
495
QuadProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Ueq1,tessFactor_Veq1,insideTessFactor_U,insideTessFactor_V,processedTessFactors);
496
497
if( processedTessFactors.bPatchCulled )
498
{
499
m_NumPoints = 0;
500
m_NumIndices = 0;
501
return;
502
}
503
else if( processedTessFactors.bJustDoMinimumTessFactor )
504
{
505
DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/0);
506
DefinePoint(/*U*/FXP_ONE,/*V*/0,/*pointStorageOffset*/1);
507
DefinePoint(/*U*/FXP_ONE,/*V*/FXP_ONE,/*pointStorageOffset*/2);
508
DefinePoint(/*U*/0,/*V*/FXP_ONE,/*pointStorageOffset*/3);
509
m_NumPoints = 4;
510
511
switch(m_outputPrimitive)
512
{
513
case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CW:
514
case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CCW:
515
// function orients them CCW if needed
516
DefineClockwiseTriangle(0,1,3,/*indexStorageOffset*/0);
517
DefineClockwiseTriangle(1,2,3,/*indexStorageOffset*/3);
518
m_NumIndices = 6;
519
break;
520
case PIPE_TESSELLATOR_OUTPUT_POINT:
521
DumpAllPoints();
522
break;
523
case PIPE_TESSELLATOR_OUTPUT_LINE:
524
DumpAllPointsAsInOrderLineList();
525
break;
526
}
527
return;
528
}
529
530
QuadGeneratePoints(processedTessFactors);
531
532
if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )
533
{
534
DumpAllPoints();
535
return;
536
}
537
if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_LINE )
538
{
539
DumpAllPointsAsInOrderLineList();
540
return;
541
}
542
543
QuadGenerateConnectivity(processedTessFactors); // can be done in parallel to QuadGeneratePoints()
544
}
545
546
//---------------------------------------------------------------------------------------------------------------------------------
547
// CHWTessellator::QuadProcessTessFactors
548
//---------------------------------------------------------------------------------------------------------------------------------
549
void CHWTessellator::QuadProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,
550
float insideTessFactor_U, float insideTessFactor_V, PROCESSED_TESS_FACTORS_QUAD& processedTessFactors )
551
{
552
// Is the patch culled?
553
if( !(tessFactor_Ueq0 > 0) || // NaN will pass
554
!(tessFactor_Veq0 > 0) ||
555
!(tessFactor_Ueq1 > 0) ||
556
!(tessFactor_Veq1 > 0) )
557
{
558
processedTessFactors.bPatchCulled = true;
559
return;
560
}
561
else
562
{
563
processedTessFactors.bPatchCulled = false;
564
}
565
566
// Clamp edge TessFactors
567
float lowerBound = 0.0, upperBound = 0.0;
568
switch(m_originalPartitioning)
569
{
570
case PIPE_TESSELLATOR_PARTITIONING_INTEGER:
571
case PIPE_TESSELLATOR_PARTITIONING_POW2: // don�t care about pow2 distinction for validation, just treat as integer
572
lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
573
upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
574
break;
575
576
case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
577
lowerBound = PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR;
578
upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
579
break;
580
581
case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
582
lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
583
upperBound = PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR;
584
break;
585
}
586
587
tessFactor_Ueq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Ueq0 ) );
588
tessFactor_Veq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Veq0 ) );
589
tessFactor_Ueq1 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Ueq1 ) );
590
tessFactor_Veq1 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Veq1 ) );
591
592
if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
593
{
594
tessFactor_Ueq0 = ceil(tessFactor_Ueq0);
595
tessFactor_Veq0 = ceil(tessFactor_Veq0);
596
tessFactor_Ueq1 = ceil(tessFactor_Ueq1);
597
tessFactor_Veq1 = ceil(tessFactor_Veq1);
598
}
599
600
// Clamp inside TessFactors
601
if(PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD == m_originalPartitioning)
602
{
603
#define EPSILON 0.0000152587890625f // 2^(-16), min positive fixed point fraction
604
#define MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON (PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON/2)
605
// If any TessFactor will end up > 1 after floatToFixed conversion later,
606
// then force the inside TessFactors to be > 1 so there is a picture frame.
607
if( (tessFactor_Ueq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
608
(tessFactor_Veq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
609
(tessFactor_Ueq1 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
610
(tessFactor_Veq1 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
611
(insideTessFactor_U > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
612
(insideTessFactor_V > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) )
613
{
614
// Force picture frame
615
lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON;
616
}
617
}
618
619
insideTessFactor_U = tess_fmin( upperBound, tess_fmax( lowerBound, insideTessFactor_U ) );
620
insideTessFactor_V = tess_fmin( upperBound, tess_fmax( lowerBound, insideTessFactor_V ) );
621
// Note the above clamps map NaN to lowerBound
622
623
624
if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
625
{
626
insideTessFactor_U = ceil(insideTessFactor_U);
627
insideTessFactor_V = ceil(insideTessFactor_V);
628
}
629
630
// Reset our vertex and index buffers. We have enough storage for the max tessFactor.
631
m_NumPoints = 0;
632
m_NumIndices = 0;
633
634
// Process tessFactors
635
float outsideTessFactor[QUAD_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Ueq1, tessFactor_Veq1};
636
float insideTessFactor[QUAD_AXES] = {insideTessFactor_U,insideTessFactor_V};
637
int edge, axis;
638
if( HWIntegerPartitioning() )
639
{
640
for( edge = 0; edge < QUAD_EDGES; edge++ )
641
{
642
int edgeEven = isEven(outsideTessFactor[edge]);
643
processedTessFactors.outsideTessFactorParity[edge] = edgeEven ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
644
}
645
for( axis = 0; axis < QUAD_AXES; axis++ )
646
{
647
processedTessFactors.insideTessFactorParity[axis] =
648
(isEven(insideTessFactor[axis]) || (FLOAT_ONE == insideTessFactor[axis]) )
649
? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
650
}
651
}
652
else
653
{
654
for( edge = 0; edge < QUAD_EDGES; edge++ )
655
{
656
processedTessFactors.outsideTessFactorParity[edge] = m_originalParity;
657
}
658
processedTessFactors.insideTessFactorParity[U] = processedTessFactors.insideTessFactorParity[V] = m_originalParity;
659
}
660
661
// Save fixed point TessFactors
662
for( edge = 0; edge < QUAD_EDGES; edge++ )
663
{
664
processedTessFactors.outsideTessFactor[edge] = floatToFixed(outsideTessFactor[edge]);
665
}
666
for( axis = 0; axis < QUAD_AXES; axis++ )
667
{
668
processedTessFactors.insideTessFactor[axis] = floatToFixed(insideTessFactor[axis]);
669
}
670
671
if( HWIntegerPartitioning() || Odd() )
672
{
673
// Special case if all TessFactors are 1
674
if( (FXP_ONE == processedTessFactors.insideTessFactor[U]) &&
675
(FXP_ONE == processedTessFactors.insideTessFactor[V]) &&
676
(FXP_ONE == processedTessFactors.outsideTessFactor[Ueq0]) &&
677
(FXP_ONE == processedTessFactors.outsideTessFactor[Veq0]) &&
678
(FXP_ONE == processedTessFactors.outsideTessFactor[Ueq1]) &&
679
(FXP_ONE == processedTessFactors.outsideTessFactor[Veq1]) )
680
{
681
processedTessFactors.bJustDoMinimumTessFactor = true;
682
return;
683
}
684
}
685
processedTessFactors.bJustDoMinimumTessFactor = false;
686
687
// Compute TessFactor-specific metadata
688
for(int edge = 0; edge < QUAD_EDGES; edge++ )
689
{
690
SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
691
ComputeTessFactorContext(processedTessFactors.outsideTessFactor[edge], processedTessFactors.outsideTessFactorCtx[edge]);
692
}
693
694
for(int axis = 0; axis < QUAD_AXES; axis++)
695
{
696
SetTessellationParity(processedTessFactors.insideTessFactorParity[axis]);
697
ComputeTessFactorContext(processedTessFactors.insideTessFactor[axis], processedTessFactors.insideTessFactorCtx[axis]);
698
}
699
700
// Compute some initial data.
701
702
// outside edge offsets and storage
703
for(int edge = 0; edge < QUAD_EDGES; edge++ )
704
{
705
SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
706
processedTessFactors.numPointsForOutsideEdge[edge] = NumPointsForTessFactor(processedTessFactors.outsideTessFactor[edge]);
707
m_NumPoints += processedTessFactors.numPointsForOutsideEdge[edge];
708
}
709
m_NumPoints -= 4;
710
711
// inside edge offsets
712
for(int axis = 0; axis < QUAD_AXES; axis++)
713
{
714
SetTessellationParity(processedTessFactors.insideTessFactorParity[axis]);
715
processedTessFactors.numPointsForInsideTessFactor[axis] = NumPointsForTessFactor(processedTessFactors.insideTessFactor[axis]);
716
int pointCountMin = ( TESSELLATOR_PARITY_ODD == processedTessFactors.insideTessFactorParity[axis] ) ? 4 : 3;
717
// max() allows degenerate transition regions when inside TessFactor == 1
718
processedTessFactors.numPointsForInsideTessFactor[axis] = max(pointCountMin,processedTessFactors.numPointsForInsideTessFactor[axis]);
719
}
720
721
processedTessFactors.insideEdgePointBaseOffset = m_NumPoints;
722
723
// inside storage, including interior edges above
724
int numInteriorPoints = (processedTessFactors.numPointsForInsideTessFactor[U] - 2)*(processedTessFactors.numPointsForInsideTessFactor[V]-2);
725
m_NumPoints += numInteriorPoints;
726
}
727
728
//---------------------------------------------------------------------------------------------------------------------------------
729
// CHWTessellator::QuadGeneratePoints
730
//---------------------------------------------------------------------------------------------------------------------------------
731
void CHWTessellator::QuadGeneratePoints( const PROCESSED_TESS_FACTORS_QUAD& processedTessFactors )
732
{
733
// Generate exterior ring edge points, clockwise from top-left
734
int pointOffset = 0;
735
int edge;
736
for(edge = 0; edge < QUAD_EDGES; edge++ )
737
{
738
int parity = edge&0x1;
739
int startPoint = 0;
740
int endPoint = processedTessFactors.numPointsForOutsideEdge[edge] - 1;
741
for(int p = startPoint; p < endPoint; p++,pointOffset++) // don't include end, since next edge starts with it.
742
{
743
FXP fxpParam;
744
int q = ((edge==1)||(edge==2)) ? p : endPoint - p; // reverse order
745
SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
746
PlacePointIn1D(processedTessFactors.outsideTessFactorCtx[edge],q,fxpParam);
747
if( parity )
748
{
749
DefinePoint(/*U*/fxpParam,
750
/*V*/(edge == 3) ? FXP_ONE : 0,
751
/*pointStorageOffset*/pointOffset);
752
}
753
else
754
{
755
DefinePoint(/*U*/(edge == 2) ? FXP_ONE : 0,
756
/*V*/fxpParam,
757
/*pointStorageOffset*/pointOffset);
758
}
759
}
760
}
761
762
// Generate interior ring points, clockwise from (U==0,V==1) (bottom-left) spiralling toward center
763
static const int startRing = 1;
764
int minNumPointsForTessFactor = min(processedTessFactors.numPointsForInsideTessFactor[U],processedTessFactors.numPointsForInsideTessFactor[V]);
765
int numRings = (minNumPointsForTessFactor >> 1); // note for even tess we aren't counting center point here.
766
for(int ring = startRing; ring < numRings; ring++)
767
{
768
int startPoint = ring;
769
int endPoint[QUAD_AXES] = {processedTessFactors.numPointsForInsideTessFactor[U] - 1 - startPoint,
770
processedTessFactors.numPointsForInsideTessFactor[V] - 1 - startPoint};
771
772
for(edge = 0; edge < QUAD_EDGES; edge++ )
773
{
774
int parity[QUAD_AXES] = {edge&0x1,((edge+1)&0x1)};
775
int perpendicularAxisPoint = (edge < 2) ? startPoint : endPoint[parity[0]];
776
FXP fxpPerpParam;
777
SetTessellationParity(processedTessFactors.insideTessFactorParity[parity[0]]);
778
PlacePointIn1D(processedTessFactors.insideTessFactorCtx[parity[0]],perpendicularAxisPoint,fxpPerpParam);
779
SetTessellationParity(processedTessFactors.insideTessFactorParity[parity[1]]);
780
for(int p = startPoint; p < endPoint[parity[1]]; p++, pointOffset++) // don't include end: next edge starts with it.
781
{
782
FXP fxpParam;
783
int q = ((edge == 1)||(edge==2)) ? p : endPoint[parity[1]] - (p - startPoint);
784
PlacePointIn1D(processedTessFactors.insideTessFactorCtx[parity[1]],q,fxpParam);
785
if( parity[1] )
786
{
787
DefinePoint(/*U*/fxpPerpParam,
788
/*V*/fxpParam,
789
/*pointStorageOffset*/pointOffset);
790
}
791
else
792
{
793
DefinePoint(/*U*/fxpParam,
794
/*V*/fxpPerpParam,
795
/*pointStorageOffset*/pointOffset);
796
}
797
}
798
}
799
}
800
// For even tessellation, the inner "ring" is degenerate - a row of points
801
if( (processedTessFactors.numPointsForInsideTessFactor[U] > processedTessFactors.numPointsForInsideTessFactor[V]) &&
802
(TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V]) )
803
{
804
int startPoint = numRings;
805
int endPoint = processedTessFactors.numPointsForInsideTessFactor[U] - 1 - startPoint;
806
SetTessellationParity(processedTessFactors.insideTessFactorParity[U]);
807
for( int p = startPoint; p <= endPoint; p++, pointOffset++ )
808
{
809
FXP fxpParam;
810
PlacePointIn1D(processedTessFactors.insideTessFactorCtx[U],p,fxpParam);
811
DefinePoint(/*U*/fxpParam,
812
/*V*/FXP_ONE_HALF, // middle
813
/*pointStorageOffset*/pointOffset);
814
}
815
}
816
else if( (processedTessFactors.numPointsForInsideTessFactor[V] >= processedTessFactors.numPointsForInsideTessFactor[U]) &&
817
(TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[U]) )
818
{
819
int startPoint = numRings;
820
int endPoint;
821
FXP fxpParam;
822
endPoint = processedTessFactors.numPointsForInsideTessFactor[V] - 1 - startPoint;
823
SetTessellationParity(processedTessFactors.insideTessFactorParity[V]);
824
for( int p = endPoint; p >= startPoint; p--, pointOffset++ )
825
{
826
PlacePointIn1D(processedTessFactors.insideTessFactorCtx[V],p,fxpParam);
827
DefinePoint(/*U*/FXP_ONE_HALF, // middle
828
/*V*/fxpParam,
829
/*pointStorageOffset*/pointOffset);
830
}
831
}
832
}
833
//---------------------------------------------------------------------------------------------------------------------------------
834
// CHWTessellator::QuadGenerateConnectivity
835
//---------------------------------------------------------------------------------------------------------------------------------
836
void CHWTessellator::QuadGenerateConnectivity( const PROCESSED_TESS_FACTORS_QUAD& processedTessFactors )
837
{
838
// Generate primitives for all the concentric rings, one side at a time for each ring
839
static const int startRing = 1;
840
int numPointRowsToCenter[QUAD_AXES] = {((processedTessFactors.numPointsForInsideTessFactor[U]+1) >> 1),
841
((processedTessFactors.numPointsForInsideTessFactor[V]+1) >> 1)}; // +1 is so even tess includes the center point
842
int numRings = min(numPointRowsToCenter[U],numPointRowsToCenter[V]);
843
int degeneratePointRing[QUAD_AXES] = { // Even partitioning causes degenerate row of points,
844
// which results in exceptions to the point ordering conventions
845
// when travelling around the rings counterclockwise.
846
(TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V]) ? numPointRowsToCenter[V] - 1 : -1,
847
(TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[U]) ? numPointRowsToCenter[U] - 1 : -1 };
848
849
const TESS_FACTOR_CONTEXT* outsideTessFactorCtx[QUAD_EDGES] = {&processedTessFactors.outsideTessFactorCtx[Ueq0],
850
&processedTessFactors.outsideTessFactorCtx[Veq0],
851
&processedTessFactors.outsideTessFactorCtx[Ueq1],
852
&processedTessFactors.outsideTessFactorCtx[Veq1]};
853
TESSELLATOR_PARITY outsideTessFactorParity[QUAD_EDGES] = {processedTessFactors.outsideTessFactorParity[Ueq0],
854
processedTessFactors.outsideTessFactorParity[Veq0],
855
processedTessFactors.outsideTessFactorParity[Ueq1],
856
processedTessFactors.outsideTessFactorParity[Veq1]};
857
int numPointsForOutsideEdge[QUAD_EDGES] = {processedTessFactors.numPointsForOutsideEdge[Ueq0],
858
processedTessFactors.numPointsForOutsideEdge[Veq0],
859
processedTessFactors.numPointsForOutsideEdge[Ueq1],
860
processedTessFactors.numPointsForOutsideEdge[Veq1]};
861
862
int insideEdgePointBaseOffset = processedTessFactors.insideEdgePointBaseOffset;
863
int outsideEdgePointBaseOffset = 0;
864
int edge;
865
for(int ring = startRing; ring < numRings; ring++)
866
{
867
int numPointsForInsideEdge[QUAD_AXES] = {processedTessFactors.numPointsForInsideTessFactor[U] - 2*ring,
868
processedTessFactors.numPointsForInsideTessFactor[V] - 2*ring};
869
870
int edge0InsidePointBaseOffset = insideEdgePointBaseOffset;
871
int edge0OutsidePointBaseOffset = outsideEdgePointBaseOffset;
872
873
for(edge = 0; edge < QUAD_EDGES; edge++ )
874
{
875
int parity = (edge+1)&0x1;
876
877
int numTriangles = numPointsForInsideEdge[parity] + numPointsForOutsideEdge[edge] - 2;
878
int insideBaseOffset;
879
int outsideBaseOffset;
880
if( edge == 3 ) // We need to patch the indexing so Stitch() can think it sees
881
// 2 sequentially increasing rows of points, even though we have wrapped around
882
// to the end of the inner and outer ring's points, so the last point is really
883
// the first point for the ring.
884
// We make it so that when Stitch() calls AddIndex(), that function
885
// will do any necessary index adjustment.
886
{
887
if( ring == degeneratePointRing[parity] )
888
{
889
m_IndexPatchContext2.baseIndexToInvert = insideEdgePointBaseOffset + 1;
890
m_IndexPatchContext2.cornerCaseBadValue = outsideEdgePointBaseOffset + numPointsForOutsideEdge[edge] - 1;
891
m_IndexPatchContext2.cornerCaseReplacementValue = edge0OutsidePointBaseOffset;
892
m_IndexPatchContext2.indexInversionEndPoint = (m_IndexPatchContext2.baseIndexToInvert << 1) - 1;
893
insideBaseOffset = m_IndexPatchContext2.baseIndexToInvert;
894
outsideBaseOffset = outsideEdgePointBaseOffset;
895
SetUsingPatchedIndices2(true);
896
}
897
else
898
{
899
m_IndexPatchContext.insidePointIndexDeltaToRealValue = insideEdgePointBaseOffset;
900
m_IndexPatchContext.insidePointIndexBadValue = numPointsForInsideEdge[parity] - 1;
901
m_IndexPatchContext.insidePointIndexReplacementValue = edge0InsidePointBaseOffset;
902
m_IndexPatchContext.outsidePointIndexPatchBase = m_IndexPatchContext.insidePointIndexBadValue+1; // past inside patched index range
903
m_IndexPatchContext.outsidePointIndexDeltaToRealValue = outsideEdgePointBaseOffset
904
- m_IndexPatchContext.outsidePointIndexPatchBase;
905
m_IndexPatchContext.outsidePointIndexBadValue = m_IndexPatchContext.outsidePointIndexPatchBase
906
+ numPointsForOutsideEdge[edge] - 1;
907
m_IndexPatchContext.outsidePointIndexReplacementValue = edge0OutsidePointBaseOffset;
908
909
insideBaseOffset = 0;
910
outsideBaseOffset = m_IndexPatchContext.outsidePointIndexPatchBase;
911
SetUsingPatchedIndices(true);
912
}
913
}
914
else if( (edge == 2) && (ring == degeneratePointRing[parity]) )
915
{
916
m_IndexPatchContext2.baseIndexToInvert = insideEdgePointBaseOffset;
917
m_IndexPatchContext2.cornerCaseBadValue = -1; // unused
918
m_IndexPatchContext2.cornerCaseReplacementValue = -1; // unused
919
m_IndexPatchContext2.indexInversionEndPoint = m_IndexPatchContext2.baseIndexToInvert << 1;
920
insideBaseOffset = m_IndexPatchContext2.baseIndexToInvert;
921
outsideBaseOffset = outsideEdgePointBaseOffset;
922
SetUsingPatchedIndices2(true);
923
}
924
else
925
{
926
insideBaseOffset = insideEdgePointBaseOffset;
927
outsideBaseOffset = outsideEdgePointBaseOffset;
928
}
929
if( ring == startRing )
930
{
931
StitchTransition(/*baseIndexOffset: */m_NumIndices,
932
insideBaseOffset,processedTessFactors.insideTessFactorCtx[parity].numHalfTessFactorPoints,processedTessFactors.insideTessFactorParity[parity],
933
outsideBaseOffset,outsideTessFactorCtx[edge]->numHalfTessFactorPoints,outsideTessFactorParity[edge]);
934
}
935
else
936
{
937
StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED,
938
/*baseIndexOffset: */m_NumIndices,
939
numPointsForInsideEdge[parity],
940
insideBaseOffset,outsideBaseOffset);
941
}
942
SetUsingPatchedIndices(false);
943
SetUsingPatchedIndices2(false);
944
m_NumIndices += numTriangles*3;
945
outsideEdgePointBaseOffset += numPointsForOutsideEdge[edge] - 1;
946
if( (edge == 2) && (ring == degeneratePointRing[parity]) )
947
{
948
insideEdgePointBaseOffset -= numPointsForInsideEdge[parity] - 1;
949
}
950
else
951
{
952
insideEdgePointBaseOffset += numPointsForInsideEdge[parity] - 1;
953
}
954
numPointsForOutsideEdge[edge] = numPointsForInsideEdge[parity];
955
}
956
if( startRing == ring )
957
{
958
for(edge = 0; edge < QUAD_EDGES; edge++ )
959
{
960
outsideTessFactorCtx[edge] = &processedTessFactors.insideTessFactorCtx[edge&1];
961
outsideTessFactorParity[edge] = processedTessFactors.insideTessFactorParity[edge&1];
962
}
963
}
964
}
965
966
// Triangulate center - a row of quads if odd
967
// This triangulation may be producing diagonals that are asymmetric about
968
// the center of the patch in this region.
969
if( (processedTessFactors.numPointsForInsideTessFactor[U] > processedTessFactors.numPointsForInsideTessFactor[V]) &&
970
(TESSELLATOR_PARITY_ODD == processedTessFactors.insideTessFactorParity[V] ) )
971
{
972
SetUsingPatchedIndices2(true);
973
int stripNumQuads = (((processedTessFactors.numPointsForInsideTessFactor[U]>>1) - (processedTessFactors.numPointsForInsideTessFactor[V]>>1))<<1)+
974
((TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[U] ) ? 2 : 1);
975
m_IndexPatchContext2.baseIndexToInvert = outsideEdgePointBaseOffset + stripNumQuads + 2;
976
m_IndexPatchContext2.cornerCaseBadValue = m_IndexPatchContext2.baseIndexToInvert;
977
m_IndexPatchContext2.cornerCaseReplacementValue = outsideEdgePointBaseOffset;
978
m_IndexPatchContext2.indexInversionEndPoint = m_IndexPatchContext2.baseIndexToInvert +
979
m_IndexPatchContext2.baseIndexToInvert + stripNumQuads;
980
StitchRegular(/*bTrapezoid*/false,DIAGONALS_INSIDE_TO_OUTSIDE,
981
/*baseIndexOffset: */m_NumIndices, /*numInsideEdgePoints:*/stripNumQuads+1,
982
/*insideEdgePointBaseOffset*/m_IndexPatchContext2.baseIndexToInvert,
983
outsideEdgePointBaseOffset+1);
984
SetUsingPatchedIndices2(false);
985
m_NumIndices += stripNumQuads*6;
986
}
987
else if((processedTessFactors.numPointsForInsideTessFactor[V] >= processedTessFactors.numPointsForInsideTessFactor[U]) &&
988
(TESSELLATOR_PARITY_ODD == processedTessFactors.insideTessFactorParity[U]) )
989
{
990
SetUsingPatchedIndices2(true);
991
int stripNumQuads = (((processedTessFactors.numPointsForInsideTessFactor[V]>>1) - (processedTessFactors.numPointsForInsideTessFactor[U]>>1))<<1)+
992
((TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V] ) ? 2 : 1);
993
m_IndexPatchContext2.baseIndexToInvert = outsideEdgePointBaseOffset + stripNumQuads + 1;
994
m_IndexPatchContext2.cornerCaseBadValue = -1; // unused
995
m_IndexPatchContext2.indexInversionEndPoint = m_IndexPatchContext2.baseIndexToInvert +
996
m_IndexPatchContext2.baseIndexToInvert + stripNumQuads;
997
DIAGONALS diag = (TESSELLATOR_PARITY_EVEN == processedTessFactors.insideTessFactorParity[V]) ?
998
DIAGONALS_INSIDE_TO_OUTSIDE : DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE;
999
StitchRegular(/*bTrapezoid*/false,diag,
1000
/*baseIndexOffset: */m_NumIndices, /*numInsideEdgePoints:*/stripNumQuads+1,
1001
/*insideEdgePointBaseOffset*/m_IndexPatchContext2.baseIndexToInvert,
1002
outsideEdgePointBaseOffset);
1003
SetUsingPatchedIndices2(false);
1004
m_NumIndices += stripNumQuads*6;
1005
}
1006
}
1007
1008
//---------------------------------------------------------------------------------------------------------------------------------
1009
// CHWTessellator::TessellateTriDomain
1010
// User calls this
1011
//---------------------------------------------------------------------------------------------------------------------------------
1012
void CHWTessellator::TessellateTriDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,
1013
float insideTessFactor )
1014
{
1015
PROCESSED_TESS_FACTORS_TRI processedTessFactors;
1016
TriProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Weq0,insideTessFactor,processedTessFactors);
1017
1018
if( processedTessFactors.bPatchCulled )
1019
{
1020
m_NumPoints = 0;
1021
m_NumIndices = 0;
1022
return;
1023
}
1024
else if( processedTessFactors.bJustDoMinimumTessFactor )
1025
{
1026
DefinePoint(/*U*/0,/*V*/FXP_ONE,/*pointStorageOffset*/0); //V=1 (beginning of Ueq0 edge VW)
1027
DefinePoint(/*U*/0,/*V*/0,/*pointStorageOffset*/1); //W=1 (beginning of Veq0 edge WU)
1028
DefinePoint(/*U*/FXP_ONE,/*V*/0,/*pointStorageOffset*/2); //U=1 (beginning of Weq0 edge UV)
1029
m_NumPoints = 3;
1030
1031
switch(m_outputPrimitive)
1032
{
1033
case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CW:
1034
case PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CCW:
1035
// function orients them CCW if needed
1036
DefineClockwiseTriangle(0,1,2,/*indexStorageBaseOffset*/m_NumIndices);
1037
m_NumIndices = 3;
1038
break;
1039
case PIPE_TESSELLATOR_OUTPUT_POINT:
1040
DumpAllPoints();
1041
break;
1042
case PIPE_TESSELLATOR_OUTPUT_LINE:
1043
DumpAllPointsAsInOrderLineList();
1044
break;
1045
}
1046
return;
1047
}
1048
1049
TriGeneratePoints(processedTessFactors);
1050
1051
if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )
1052
{
1053
DumpAllPoints();
1054
return;
1055
}
1056
if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_LINE )
1057
{
1058
DumpAllPointsAsInOrderLineList();
1059
return;
1060
}
1061
1062
TriGenerateConnectivity(processedTessFactors); // can be done in parallel to TriGeneratePoints()
1063
}
1064
1065
//---------------------------------------------------------------------------------------------------------------------------------
1066
// CHWTessellator::TriProcessTessFactors
1067
//---------------------------------------------------------------------------------------------------------------------------------
1068
void CHWTessellator::TriProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,
1069
float insideTessFactor, PROCESSED_TESS_FACTORS_TRI& processedTessFactors )
1070
{
1071
// Is the patch culled?
1072
if( !(tessFactor_Ueq0 > 0) || // NaN will pass
1073
!(tessFactor_Veq0 > 0) ||
1074
!(tessFactor_Weq0 > 0) )
1075
{
1076
processedTessFactors.bPatchCulled = true;
1077
return;
1078
}
1079
else
1080
{
1081
processedTessFactors.bPatchCulled = false;
1082
}
1083
1084
// Clamp edge TessFactors
1085
float lowerBound = 0.0, upperBound = 0.0;
1086
switch(m_originalPartitioning)
1087
{
1088
case PIPE_TESSELLATOR_PARTITIONING_INTEGER:
1089
case PIPE_TESSELLATOR_PARTITIONING_POW2: // don�t care about pow2 distinction for validation, just treat as integer
1090
lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
1091
upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
1092
break;
1093
1094
case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
1095
lowerBound = PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR;
1096
upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
1097
break;
1098
1099
case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
1100
lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
1101
upperBound = PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR;
1102
break;
1103
}
1104
1105
tessFactor_Ueq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Ueq0 ) );
1106
tessFactor_Veq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Veq0 ) );
1107
tessFactor_Weq0 = tess_fmin( upperBound, tess_fmax( lowerBound, tessFactor_Weq0 ) );
1108
1109
if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1110
{
1111
tessFactor_Ueq0 = ceil(tessFactor_Ueq0);
1112
tessFactor_Veq0 = ceil(tessFactor_Veq0);
1113
tessFactor_Weq0 = ceil(tessFactor_Weq0);
1114
}
1115
1116
// Clamp inside TessFactors
1117
if(PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD == m_originalPartitioning)
1118
{
1119
if( (tessFactor_Ueq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
1120
(tessFactor_Veq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON) ||
1121
(tessFactor_Weq0 > MIN_ODD_TESSFACTOR_PLUS_HALF_EPSILON))
1122
// Don't need the same check for insideTessFactor for tri patches,
1123
// since there is only one insideTessFactor, as opposed to quad
1124
// patches which have 2 insideTessFactors.
1125
{
1126
// Force picture frame
1127
lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR + EPSILON;
1128
}
1129
}
1130
1131
insideTessFactor = tess_fmin( upperBound, tess_fmax( lowerBound, insideTessFactor ) );
1132
// Note the above clamps map NaN to lowerBound
1133
1134
if( HWIntegerPartitioning()) // pow2 or integer, round to next int (hw doesn't care about pow2 distinction)
1135
{
1136
insideTessFactor = ceil(insideTessFactor);
1137
}
1138
1139
// Reset our vertex and index buffers. We have enough storage for the max tessFactor.
1140
m_NumPoints = 0;
1141
m_NumIndices = 0;
1142
1143
// Process tessFactors
1144
float outsideTessFactor[TRI_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Weq0};
1145
int edge;
1146
if( HWIntegerPartitioning() )
1147
{
1148
for( edge = 0; edge < TRI_EDGES; edge++ )
1149
{
1150
int edgeEven = isEven(outsideTessFactor[edge]);
1151
processedTessFactors.outsideTessFactorParity[edge] = edgeEven ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
1152
}
1153
processedTessFactors.insideTessFactorParity = (isEven(insideTessFactor) || (FLOAT_ONE == insideTessFactor))
1154
? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
1155
}
1156
else
1157
{
1158
for( edge = 0; edge < TRI_EDGES; edge++ )
1159
{
1160
processedTessFactors.outsideTessFactorParity[edge] = m_originalParity;
1161
}
1162
processedTessFactors.insideTessFactorParity = m_originalParity;
1163
}
1164
1165
// Save fixed point TessFactors
1166
for( edge = 0; edge < TRI_EDGES; edge++ )
1167
{
1168
processedTessFactors.outsideTessFactor[edge] = floatToFixed(outsideTessFactor[edge]);
1169
}
1170
processedTessFactors.insideTessFactor = floatToFixed(insideTessFactor);
1171
1172
if( HWIntegerPartitioning() || Odd() )
1173
{
1174
// Special case if all TessFactors are 1
1175
if( (FXP_ONE == processedTessFactors.insideTessFactor) &&
1176
(FXP_ONE == processedTessFactors.outsideTessFactor[Ueq0]) &&
1177
(FXP_ONE == processedTessFactors.outsideTessFactor[Veq0]) &&
1178
(FXP_ONE == processedTessFactors.outsideTessFactor[Weq0]) )
1179
{
1180
processedTessFactors.bJustDoMinimumTessFactor = true;
1181
return;
1182
}
1183
}
1184
processedTessFactors.bJustDoMinimumTessFactor = false;
1185
1186
// Compute per-TessFactor metadata
1187
for(edge = 0; edge < TRI_EDGES; edge++ )
1188
{
1189
SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
1190
ComputeTessFactorContext(processedTessFactors.outsideTessFactor[edge], processedTessFactors.outsideTessFactorCtx[edge]);
1191
}
1192
SetTessellationParity(processedTessFactors.insideTessFactorParity);
1193
ComputeTessFactorContext(processedTessFactors.insideTessFactor, processedTessFactors.insideTessFactorCtx);
1194
1195
// Compute some initial data.
1196
1197
// outside edge offsets and storage
1198
for(edge = 0; edge < TRI_EDGES; edge++ )
1199
{
1200
SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
1201
processedTessFactors.numPointsForOutsideEdge[edge] = NumPointsForTessFactor(processedTessFactors.outsideTessFactor[edge]);
1202
m_NumPoints += processedTessFactors.numPointsForOutsideEdge[edge];
1203
}
1204
m_NumPoints -= 3;
1205
1206
// inside edge offsets
1207
SetTessellationParity(processedTessFactors.insideTessFactorParity);
1208
processedTessFactors.numPointsForInsideTessFactor = NumPointsForTessFactor(processedTessFactors.insideTessFactor);
1209
{
1210
int pointCountMin = Odd() ? 4 : 3;
1211
// max() allows degenerate transition regions when inside TessFactor == 1
1212
processedTessFactors.numPointsForInsideTessFactor = max(pointCountMin,processedTessFactors.numPointsForInsideTessFactor);
1213
}
1214
1215
processedTessFactors.insideEdgePointBaseOffset = m_NumPoints;
1216
1217
// inside storage, including interior edges above
1218
{
1219
int numInteriorRings = (processedTessFactors.numPointsForInsideTessFactor >> 1) - 1;
1220
int numInteriorPoints;
1221
if( Odd() )
1222
{
1223
numInteriorPoints = TRI_EDGES*(numInteriorRings*(numInteriorRings+1) - numInteriorRings);
1224
}
1225
else
1226
{
1227
numInteriorPoints = TRI_EDGES*(numInteriorRings*(numInteriorRings+1)) + 1;
1228
}
1229
m_NumPoints += numInteriorPoints;
1230
}
1231
1232
}
1233
1234
//---------------------------------------------------------------------------------------------------------------------------------
1235
// CHWTessellator::TriGeneratePoints
1236
//---------------------------------------------------------------------------------------------------------------------------------
1237
void CHWTessellator::TriGeneratePoints( const PROCESSED_TESS_FACTORS_TRI& processedTessFactors )
1238
{
1239
// Generate exterior ring edge points, clockwise starting from point V (VW, the U==0 edge)
1240
int pointOffset = 0;
1241
int edge;
1242
for(edge = 0; edge < TRI_EDGES; edge++ )
1243
{
1244
int parity = edge&0x1;
1245
int startPoint = 0;
1246
int endPoint = processedTessFactors.numPointsForOutsideEdge[edge] - 1;
1247
for(int p = startPoint; p < endPoint; p++, pointOffset++) // don't include end, since next edge starts with it.
1248
{
1249
FXP fxpParam;
1250
int q = (parity) ? p : endPoint - p; // whether to reverse point order given we are defining V or U (W implicit):
1251
// edge0, VW, has V decreasing, so reverse 1D points below
1252
// edge1, WU, has U increasing, so don't reverse 1D points below
1253
// edge2, UV, has U decreasing, so reverse 1D points below
1254
SetTessellationParity(processedTessFactors.outsideTessFactorParity[edge]);
1255
PlacePointIn1D(processedTessFactors.outsideTessFactorCtx[edge],q,fxpParam);
1256
if( edge == 0 )
1257
{
1258
DefinePoint(/*U*/0,
1259
/*V*/fxpParam,
1260
/*pointStorageOffset*/pointOffset);
1261
}
1262
else
1263
{
1264
DefinePoint(/*U*/fxpParam,
1265
/*V*/(edge == 2) ? FXP_ONE - fxpParam : 0,
1266
/*pointStorageOffset*/pointOffset);
1267
}
1268
}
1269
}
1270
1271
// Generate interior ring points, clockwise spiralling in
1272
SetTessellationParity(processedTessFactors.insideTessFactorParity);
1273
static const int startRing = 1;
1274
int numRings = (processedTessFactors.numPointsForInsideTessFactor >> 1);
1275
for(int ring = startRing; ring < numRings; ring++)
1276
{
1277
int startPoint = ring;
1278
int endPoint = processedTessFactors.numPointsForInsideTessFactor - 1 - startPoint;
1279
1280
for(edge = 0; edge < TRI_EDGES; edge++ )
1281
{
1282
int parity = edge&0x1;
1283
int perpendicularAxisPoint = startPoint;
1284
FXP fxpPerpParam;
1285
PlacePointIn1D(processedTessFactors.insideTessFactorCtx,perpendicularAxisPoint,fxpPerpParam);
1286
fxpPerpParam *= FXP_TWO_THIRDS; // Map location to the right size in barycentric space.
1287
// I (amarp) can draw a picture to explain.
1288
// We know this fixed point math won't over/underflow
1289
fxpPerpParam = (fxpPerpParam+FXP_ONE_HALF/*round*/)>>FXP_FRACTION_BITS; // get back to n.16
1290
for(int p = startPoint; p < endPoint; p++, pointOffset++) // don't include end: next edge starts with it.
1291
{
1292
FXP fxpParam;
1293
int q = (parity) ? p : endPoint - (p - startPoint); // whether to reverse point given we are defining V or U (W implicit):
1294
// edge0, VW, has V decreasing, so reverse 1D points below
1295
// edge1, WU, has U increasing, so don't reverse 1D points below
1296
// edge2, UV, has U decreasing, so reverse 1D points below
1297
PlacePointIn1D(processedTessFactors.insideTessFactorCtx,q,fxpParam);
1298
// edge0 VW, has perpendicular parameter U constant
1299
// edge1 WU, has perpendicular parameter V constant
1300
// edge2 UV, has perpendicular parameter W constant
1301
const unsigned int deriv = 2; // reciprocal is the rate of change of edge-parallel parameters as they are pushed into the triangle
1302
switch(edge)
1303
{
1304
case 0:
1305
DefinePoint(/*U*/fxpPerpParam,
1306
/*V*/fxpParam - (fxpPerpParam+1/*round*/)/deriv, // we know this fixed point math won't over/underflow
1307
/*pointStorageOffset*/pointOffset);
1308
break;
1309
case 1:
1310
DefinePoint(/*U*/fxpParam - (fxpPerpParam+1/*round*/)/deriv,// we know this fixed point math won't over/underflow
1311
/*V*/fxpPerpParam,
1312
/*pointStorageOffset*/pointOffset);
1313
break;
1314
case 2:
1315
DefinePoint(/*U*/fxpParam - (fxpPerpParam+1/*round*/)/deriv,// we know this fixed point math won't over/underflow
1316
/*V*/FXP_ONE - (fxpParam - (fxpPerpParam+1/*round*/)/deriv) - fxpPerpParam,// we know this fixed point math won't over/underflow
1317
/*pointStorageOffset*/pointOffset);
1318
break;
1319
}
1320
}
1321
}
1322
}
1323
if( !Odd() )
1324
{
1325
// Last point is the point at the center.
1326
DefinePoint(/*U*/FXP_ONE_THIRD,
1327
/*V*/FXP_ONE_THIRD,
1328
/*pointStorageOffset*/pointOffset);
1329
}
1330
}
1331
//---------------------------------------------------------------------------------------------------------------------------------
1332
// CHWTessellator::TriGenerateConnectivity
1333
//---------------------------------------------------------------------------------------------------------------------------------
1334
void CHWTessellator::TriGenerateConnectivity( const PROCESSED_TESS_FACTORS_TRI& processedTessFactors )
1335
{
1336
// Generate primitives for all the concentric rings, one side at a time for each ring
1337
static const int startRing = 1;
1338
int numRings = ((processedTessFactors.numPointsForInsideTessFactor+1) >> 1); // +1 is so even tess includes the center point, which we want to now
1339
const TESS_FACTOR_CONTEXT* outsideTessFactorCtx[TRI_EDGES] = {&processedTessFactors.outsideTessFactorCtx[Ueq0],
1340
&processedTessFactors.outsideTessFactorCtx[Veq0],
1341
&processedTessFactors.outsideTessFactorCtx[Weq0]};
1342
TESSELLATOR_PARITY outsideTessFactorParity[TRI_EDGES] = {processedTessFactors.outsideTessFactorParity[Ueq0],
1343
processedTessFactors.outsideTessFactorParity[Veq0],
1344
processedTessFactors.outsideTessFactorParity[Weq0]};
1345
int numPointsForOutsideEdge[TRI_EDGES] = {processedTessFactors.numPointsForOutsideEdge[Ueq0],
1346
processedTessFactors.numPointsForOutsideEdge[Veq0],
1347
processedTessFactors.numPointsForOutsideEdge[Weq0]};
1348
1349
int insideEdgePointBaseOffset = processedTessFactors.insideEdgePointBaseOffset;
1350
int outsideEdgePointBaseOffset = 0;
1351
int edge;
1352
for(int ring = startRing; ring < numRings; ring++)
1353
{
1354
int numPointsForInsideEdge = processedTessFactors.numPointsForInsideTessFactor - 2*ring;
1355
int edge0InsidePointBaseOffset = insideEdgePointBaseOffset;
1356
int edge0OutsidePointBaseOffset = outsideEdgePointBaseOffset;
1357
for(edge = 0; edge < TRI_EDGES; edge++ )
1358
{
1359
int numTriangles = numPointsForInsideEdge + numPointsForOutsideEdge[edge] - 2;
1360
1361
int insideBaseOffset;
1362
int outsideBaseOffset;
1363
if( edge == 2 )
1364
{
1365
m_IndexPatchContext.insidePointIndexDeltaToRealValue = insideEdgePointBaseOffset;
1366
m_IndexPatchContext.insidePointIndexBadValue = numPointsForInsideEdge - 1;
1367
m_IndexPatchContext.insidePointIndexReplacementValue = edge0InsidePointBaseOffset;
1368
m_IndexPatchContext.outsidePointIndexPatchBase = m_IndexPatchContext.insidePointIndexBadValue+1; // past inside patched index range
1369
m_IndexPatchContext.outsidePointIndexDeltaToRealValue = outsideEdgePointBaseOffset
1370
- m_IndexPatchContext.outsidePointIndexPatchBase;
1371
m_IndexPatchContext.outsidePointIndexBadValue = m_IndexPatchContext.outsidePointIndexPatchBase
1372
+ numPointsForOutsideEdge[edge] - 1;
1373
m_IndexPatchContext.outsidePointIndexReplacementValue = edge0OutsidePointBaseOffset;
1374
SetUsingPatchedIndices(true);
1375
insideBaseOffset = 0;
1376
outsideBaseOffset = m_IndexPatchContext.outsidePointIndexPatchBase;
1377
}
1378
else
1379
{
1380
insideBaseOffset = insideEdgePointBaseOffset;
1381
outsideBaseOffset = outsideEdgePointBaseOffset;
1382
}
1383
if( ring == startRing )
1384
{
1385
StitchTransition(/*baseIndexOffset: */m_NumIndices,
1386
insideBaseOffset,processedTessFactors.insideTessFactorCtx.numHalfTessFactorPoints,processedTessFactors.insideTessFactorParity,
1387
outsideBaseOffset,outsideTessFactorCtx[edge]->numHalfTessFactorPoints,outsideTessFactorParity[edge]);
1388
}
1389
else
1390
{
1391
StitchRegular(/*bTrapezoid*/true, DIAGONALS_MIRRORED,
1392
/*baseIndexOffset: */m_NumIndices,
1393
numPointsForInsideEdge,
1394
insideBaseOffset,outsideBaseOffset);
1395
}
1396
if( 2 == edge )
1397
{
1398
SetUsingPatchedIndices(false);
1399
}
1400
m_NumIndices += numTriangles*3;
1401
outsideEdgePointBaseOffset += numPointsForOutsideEdge[edge] - 1;
1402
insideEdgePointBaseOffset += numPointsForInsideEdge - 1;
1403
numPointsForOutsideEdge[edge] = numPointsForInsideEdge;
1404
}
1405
if( startRing == ring )
1406
{
1407
for(edge = 0; edge < TRI_EDGES; edge++ )
1408
{
1409
outsideTessFactorCtx[edge] = &processedTessFactors.insideTessFactorCtx;
1410
outsideTessFactorParity[edge] = processedTessFactors.insideTessFactorParity;
1411
}
1412
}
1413
}
1414
if( Odd() )
1415
{
1416
// Triangulate center (a single triangle)
1417
DefineClockwiseTriangle(outsideEdgePointBaseOffset, outsideEdgePointBaseOffset+1, outsideEdgePointBaseOffset+2,
1418
m_NumIndices);
1419
m_NumIndices += 3;
1420
}
1421
}
1422
1423
//---------------------------------------------------------------------------------------------------------------------------------
1424
// CHWTessellator::TessellateIsoLineDomain
1425
// User calls this.
1426
//---------------------------------------------------------------------------------------------------------------------------------
1427
void CHWTessellator::TessellateIsoLineDomain( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail )
1428
{
1429
PROCESSED_TESS_FACTORS_ISOLINE processedTessFactors;
1430
IsoLineProcessTessFactors(TessFactor_V_LineDensity,TessFactor_U_LineDetail,processedTessFactors);
1431
if( processedTessFactors.bPatchCulled )
1432
{
1433
m_NumPoints = 0;
1434
m_NumIndices = 0;
1435
return;
1436
}
1437
IsoLineGeneratePoints(processedTessFactors);
1438
IsoLineGenerateConnectivity(processedTessFactors); // can be done in parallel to IsoLineGeneratePoints
1439
}
1440
1441
//---------------------------------------------------------------------------------------------------------------------------------
1442
// CHWTessellator::IsoLineProcessTessFactors
1443
//---------------------------------------------------------------------------------------------------------------------------------
1444
void CHWTessellator::IsoLineProcessTessFactors( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail,
1445
PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors )
1446
{
1447
// Is the patch culled?
1448
if( !(TessFactor_V_LineDensity > 0) || // NaN will pass
1449
!(TessFactor_U_LineDetail > 0) )
1450
{
1451
processedTessFactors.bPatchCulled = true;
1452
return;
1453
}
1454
else
1455
{
1456
processedTessFactors.bPatchCulled = false;
1457
}
1458
1459
// Clamp edge TessFactors
1460
float lowerBound = 0.0, upperBound = 0.0;
1461
switch(m_originalPartitioning)
1462
{
1463
case PIPE_TESSELLATOR_PARTITIONING_INTEGER:
1464
case PIPE_TESSELLATOR_PARTITIONING_POW2: // don�t care about pow2 distinction for validation, just treat as integer
1465
lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
1466
upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
1467
break;
1468
1469
case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
1470
lowerBound = PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR;
1471
upperBound = PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR;
1472
break;
1473
1474
case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
1475
lowerBound = PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR;
1476
upperBound = PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR;
1477
break;
1478
}
1479
1480
TessFactor_V_LineDensity = tess_fmin( PIPE_TESSELLATOR_MAX_ISOLINE_DENSITY_TESSELLATION_FACTOR,
1481
tess_fmax( PIPE_TESSELLATOR_MIN_ISOLINE_DENSITY_TESSELLATION_FACTOR, TessFactor_V_LineDensity ) );
1482
TessFactor_U_LineDetail = tess_fmin( upperBound, tess_fmax( lowerBound, TessFactor_U_LineDetail ) );
1483
1484
// Reset our vertex and index buffers. We have enough storage for the max tessFactor.
1485
m_NumPoints = 0;
1486
m_NumIndices = 0;
1487
1488
// Process tessFactors
1489
if( HWIntegerPartitioning() )
1490
{
1491
TessFactor_U_LineDetail = ceil(TessFactor_U_LineDetail);
1492
processedTessFactors.lineDetailParity = isEven(TessFactor_U_LineDetail) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
1493
}
1494
else
1495
{
1496
processedTessFactors.lineDetailParity = m_originalParity;
1497
}
1498
1499
FXP fxpTessFactor_U_LineDetail = floatToFixed(TessFactor_U_LineDetail);
1500
1501
SetTessellationParity(processedTessFactors.lineDetailParity);
1502
1503
ComputeTessFactorContext(fxpTessFactor_U_LineDetail, processedTessFactors.lineDetailTessFactorCtx);
1504
processedTessFactors.numPointsPerLine = NumPointsForTessFactor(fxpTessFactor_U_LineDetail);
1505
1506
OverridePartitioning(PIPE_TESSELLATOR_PARTITIONING_INTEGER);
1507
1508
TessFactor_V_LineDensity = ceil(TessFactor_V_LineDensity);
1509
processedTessFactors.lineDensityParity = isEven(TessFactor_V_LineDensity) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
1510
SetTessellationParity(processedTessFactors.lineDensityParity);
1511
FXP fxpTessFactor_V_LineDensity = floatToFixed(TessFactor_V_LineDensity);
1512
ComputeTessFactorContext(fxpTessFactor_V_LineDensity, processedTessFactors.lineDensityTessFactorCtx);
1513
1514
processedTessFactors.numLines = NumPointsForTessFactor(fxpTessFactor_V_LineDensity) - 1; // don't draw last line at V == 1.
1515
1516
RestorePartitioning();
1517
1518
// Compute some initial data.
1519
1520
// outside edge offsets
1521
m_NumPoints = processedTessFactors.numPointsPerLine * processedTessFactors.numLines;
1522
if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )
1523
{
1524
m_NumIndices = m_NumPoints;
1525
}
1526
else // line
1527
{
1528
m_NumIndices = processedTessFactors.numLines*(processedTessFactors.numPointsPerLine-1)*2;
1529
}
1530
}
1531
1532
//---------------------------------------------------------------------------------------------------------------------------------
1533
// CHWTessellator::IsoLineGeneratePoints
1534
//---------------------------------------------------------------------------------------------------------------------------------
1535
void CHWTessellator::IsoLineGeneratePoints( const PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors )
1536
{
1537
int line, pointOffset;
1538
for(line = 0, pointOffset = 0; line < processedTessFactors.numLines; line++)
1539
{
1540
for(int point = 0; point < processedTessFactors.numPointsPerLine; point++)
1541
{
1542
FXP fxpU,fxpV;
1543
SetTessellationParity(processedTessFactors.lineDensityParity);
1544
PlacePointIn1D(processedTessFactors.lineDensityTessFactorCtx,line,fxpV);
1545
1546
SetTessellationParity(processedTessFactors.lineDetailParity);
1547
PlacePointIn1D(processedTessFactors.lineDetailTessFactorCtx,point,fxpU);
1548
1549
DefinePoint(fxpU,fxpV,pointOffset++);
1550
}
1551
}
1552
}
1553
1554
//---------------------------------------------------------------------------------------------------------------------------------
1555
// CHWTessellator::IsoLineGenerateConnectivity
1556
//---------------------------------------------------------------------------------------------------------------------------------
1557
void CHWTessellator::IsoLineGenerateConnectivity( const PROCESSED_TESS_FACTORS_ISOLINE& processedTessFactors )
1558
{
1559
int line, pointOffset, indexOffset;
1560
if( m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_POINT )
1561
{
1562
for(line = 0, pointOffset = 0, indexOffset = 0; line < processedTessFactors.numLines; line++)
1563
{
1564
for(int point = 0; point < processedTessFactors.numPointsPerLine; point++)
1565
{
1566
DefineIndex(pointOffset++,indexOffset++);
1567
}
1568
}
1569
}
1570
else // line
1571
{
1572
for(line = 0, pointOffset = 0, indexOffset = 0; line < processedTessFactors.numLines; line++)
1573
{
1574
for(int point = 0; point < processedTessFactors.numPointsPerLine; point++)
1575
{
1576
if( point > 0 )
1577
{
1578
DefineIndex(pointOffset-1,indexOffset++);
1579
DefineIndex(pointOffset,indexOffset++);
1580
}
1581
pointOffset++;
1582
}
1583
}
1584
}
1585
}
1586
1587
//---------------------------------------------------------------------------------------------------------------------------------
1588
// CHWTessellator::GetPointCount
1589
// User calls this.
1590
//---------------------------------------------------------------------------------------------------------------------------------
1591
int CHWTessellator::GetPointCount()
1592
{
1593
return m_NumPoints;
1594
}
1595
1596
//---------------------------------------------------------------------------------------------------------------------------------
1597
// CHWTessellator::GetIndexCount()
1598
// User calls this.
1599
//---------------------------------------------------------------------------------------------------------------------------------
1600
int CHWTessellator::GetIndexCount()
1601
{
1602
return m_NumIndices;
1603
}
1604
1605
//---------------------------------------------------------------------------------------------------------------------------------
1606
// CHWTessellator::GetPoints()
1607
// User calls this.
1608
//---------------------------------------------------------------------------------------------------------------------------------
1609
DOMAIN_POINT* CHWTessellator::GetPoints()
1610
{
1611
return m_Point;
1612
}
1613
//---------------------------------------------------------------------------------------------------------------------------------
1614
// CHWTessellator::GetIndices()
1615
// User calls this.
1616
//---------------------------------------------------------------------------------------------------------------------------------
1617
int* CHWTessellator::GetIndices()
1618
{
1619
return m_Index;
1620
}
1621
1622
//---------------------------------------------------------------------------------------------------------------------------------
1623
// CHWTessellator::DefinePoint()
1624
//---------------------------------------------------------------------------------------------------------------------------------
1625
int CHWTessellator::DefinePoint(FXP fxpU, FXP fxpV, int pointStorageOffset)
1626
{
1627
// WCHAR foo[80];
1628
// StringCchPrintf(foo,80,L"off:%d, uv=(%f,%f)\n",pointStorageOffset,fixedToFloat(fxpU),fixedToFloat(fxpV));
1629
// OutputDebugString(foo);
1630
m_Point[pointStorageOffset].u = fixedToFloat(fxpU);
1631
m_Point[pointStorageOffset].v = fixedToFloat(fxpV);
1632
return pointStorageOffset;
1633
}
1634
1635
//---------------------------------------------------------------------------------------------------------------------------------
1636
// CHWTessellator::DefineIndex()
1637
//--------------------------------------------------------------------------------------------------------------------------------
1638
void CHWTessellator::DefineIndex(int index, int indexStorageOffset)
1639
{
1640
index = PatchIndexValue(index);
1641
// WCHAR foo[80];
1642
// StringCchPrintf(foo,80,L"off:%d, idx=%d, uv=(%f,%f)\n",indexStorageOffset,index,m_Point[index].u,m_Point[index].v);
1643
// OutputDebugString(foo);
1644
m_Index[indexStorageOffset] = index;
1645
}
1646
1647
//---------------------------------------------------------------------------------------------------------------------------------
1648
// CHWTessellator::DefineClockwiseTriangle()
1649
//---------------------------------------------------------------------------------------------------------------------------------
1650
void CHWTessellator::DefineClockwiseTriangle(int index0, int index1, int index2, int indexStorageBaseOffset)
1651
{
1652
// inputs a clockwise triangle, stores a CW or CCW triangle depending on the state
1653
DefineIndex(index0,indexStorageBaseOffset);
1654
bool bWantClockwise = (m_outputPrimitive == PIPE_TESSELLATOR_OUTPUT_TRIANGLE_CW) ? true : false;
1655
if( bWantClockwise )
1656
{
1657
DefineIndex(index1,indexStorageBaseOffset+1);
1658
DefineIndex(index2,indexStorageBaseOffset+2);
1659
}
1660
else
1661
{
1662
DefineIndex(index2,indexStorageBaseOffset+1);
1663
DefineIndex(index1,indexStorageBaseOffset+2);
1664
}
1665
}
1666
1667
//---------------------------------------------------------------------------------------------------------------------------------
1668
// CHWTessellator::DumpAllPoints()
1669
//---------------------------------------------------------------------------------------------------------------------------------
1670
void CHWTessellator::DumpAllPoints()
1671
{
1672
for( int p = 0; p < m_NumPoints; p++ )
1673
{
1674
DefineIndex(p,m_NumIndices++);
1675
}
1676
}
1677
1678
//---------------------------------------------------------------------------------------------------------------------------------
1679
// CHWTessellator::DumpAllPointsAsInOrderLineList()
1680
//---------------------------------------------------------------------------------------------------------------------------------
1681
void CHWTessellator::DumpAllPointsAsInOrderLineList()
1682
{
1683
for( int p = 1; p < m_NumPoints; p++ )
1684
{
1685
DefineIndex(p-1,m_NumIndices++);
1686
DefineIndex(p,m_NumIndices++);
1687
}
1688
}
1689
1690
//---------------------------------------------------------------------------------------------------------------------------------
1691
// RemoveMSB
1692
//---------------------------------------------------------------------------------------------------------------------------------
1693
int RemoveMSB(int val)
1694
{
1695
int check;
1696
if( val <= 0x0000ffff ) { check = ( val <= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1697
else { check = ( val <= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1698
for( int i = 0; i < 8; i++, check >>= 1 ) { if( val & check ) return (val & ~check); }
1699
return 0;
1700
}
1701
//---------------------------------------------------------------------------------------------------------------------------------
1702
// GetMSB
1703
//---------------------------------------------------------------------------------------------------------------------------------
1704
int GetMSB(int val)
1705
{
1706
int check;
1707
if( val <= 0x0000ffff ) { check = ( val <= 0x000000ff ) ? 0x00000080 : 0x00008000; }
1708
else { check = ( val <= 0x00ffffff ) ? 0x00800000 : 0x80000000; }
1709
for( int i = 0; i < 8; i++, check >>= 1 ) { if( val & check ) return check; }
1710
return 0;
1711
}
1712
1713
//---------------------------------------------------------------------------------------------------------------------------------
1714
// CHWTessellator::CleanseParameter()
1715
//---------------------------------------------------------------------------------------------------------------------------------
1716
/* NOTHING TO DO FOR FIXED POINT ARITHMETIC!
1717
void CHWTessellator::CleanseParameter(float& parameter)
1718
{
1719
// Clean up [0..1] parameter to guarantee that (1 - (1 - parameter)) == parameter.
1720
parameter = 1.0f - parameter;
1721
parameter = 1.0f - parameter;
1722
1723
}
1724
*/
1725
//---------------------------------------------------------------------------------------------------------------------------------
1726
// CHWTessellator::NumPointsForTessFactor()
1727
//---------------------------------------------------------------------------------------------------------------------------------
1728
int CHWTessellator::NumPointsForTessFactor( FXP fxpTessFactor )
1729
{
1730
int numPoints;
1731
if( Odd() )
1732
{
1733
numPoints = (fxpCeil(FXP_ONE_HALF + (fxpTessFactor+1/*round*/)/2)*2)>>FXP_FRACTION_BITS;
1734
}
1735
else
1736
{
1737
numPoints = ((fxpCeil((fxpTessFactor+1/*round*/)/2)*2)>>FXP_FRACTION_BITS)+1;
1738
}
1739
return numPoints;
1740
}
1741
1742
//---------------------------------------------------------------------------------------------------------------------------------
1743
// CHWTessellator::ComputeTessFactorContext()
1744
//---------------------------------------------------------------------------------------------------------------------------------
1745
void CHWTessellator::ComputeTessFactorContext( FXP fxpTessFactor, TESS_FACTOR_CONTEXT& TessFactorCtx )
1746
{
1747
FXP fxpHalfTessFactor = (fxpTessFactor+1/*round*/)/2;
1748
if( Odd() || (fxpHalfTessFactor == FXP_ONE_HALF)) // fxpHalfTessFactor == 1/2 if TessFactor is 1, but we're pretending we are even.
1749
{
1750
fxpHalfTessFactor += FXP_ONE_HALF;
1751
}
1752
FXP fxpFloorHalfTessFactor = fxpFloor(fxpHalfTessFactor);
1753
FXP fxpCeilHalfTessFactor = fxpCeil(fxpHalfTessFactor);
1754
TessFactorCtx.fxpHalfTessFactorFraction = fxpHalfTessFactor - fxpFloorHalfTessFactor;
1755
//CleanseParameter(TessFactorCtx.fxpHalfTessFactorFraction);
1756
TessFactorCtx.numHalfTessFactorPoints = (fxpCeilHalfTessFactor>>FXP_FRACTION_BITS); // for EVEN, we don't include the point always fixed at the midpoint of the TessFactor
1757
if( fxpCeilHalfTessFactor == fxpFloorHalfTessFactor )
1758
{
1759
TessFactorCtx.splitPointOnFloorHalfTessFactor = /*pick value to cause this to be ignored*/ TessFactorCtx.numHalfTessFactorPoints+1;
1760
}
1761
else if( Odd() )
1762
{
1763
if( fxpFloorHalfTessFactor == FXP_ONE )
1764
{
1765
TessFactorCtx.splitPointOnFloorHalfTessFactor = 0;
1766
}
1767
else
1768
{
1769
TessFactorCtx.splitPointOnFloorHalfTessFactor = (RemoveMSB((fxpFloorHalfTessFactor>>FXP_FRACTION_BITS)-1)<<1) + 1;
1770
}
1771
}
1772
else
1773
{
1774
TessFactorCtx.splitPointOnFloorHalfTessFactor = (RemoveMSB(fxpFloorHalfTessFactor>>FXP_FRACTION_BITS)<<1) + 1;
1775
}
1776
int numFloorSegments = (fxpFloorHalfTessFactor * 2)>>FXP_FRACTION_BITS;
1777
int numCeilSegments = (fxpCeilHalfTessFactor * 2)>>FXP_FRACTION_BITS;
1778
if( Odd() )
1779
{
1780
numFloorSegments -= 1;
1781
numCeilSegments -= 1;
1782
}
1783
TessFactorCtx.fxpInvNumSegmentsOnFloorTessFactor = s_fixedReciprocal[numFloorSegments];
1784
TessFactorCtx.fxpInvNumSegmentsOnCeilTessFactor = s_fixedReciprocal[numCeilSegments];
1785
}
1786
1787
//---------------------------------------------------------------------------------------------------------------------------------
1788
// CHWTessellator::PlacePointIn1D()
1789
//---------------------------------------------------------------------------------------------------------------------------------
1790
void CHWTessellator::PlacePointIn1D( const TESS_FACTOR_CONTEXT& TessFactorCtx, int point, FXP& fxpLocation )
1791
{
1792
bool bFlip;
1793
if( point >= TessFactorCtx.numHalfTessFactorPoints )
1794
{
1795
point = (TessFactorCtx.numHalfTessFactorPoints << 1) - point;
1796
if( Odd() )
1797
{
1798
point -= 1;
1799
}
1800
bFlip = true;
1801
}
1802
else
1803
{
1804
bFlip = false;
1805
}
1806
if( point == TessFactorCtx.numHalfTessFactorPoints )
1807
{
1808
fxpLocation = FXP_ONE_HALF; // special casing middle since 16 bit fixed math below can't reproduce 0.5 exactly
1809
return;
1810
}
1811
unsigned int indexOnCeilHalfTessFactor = point;
1812
unsigned int indexOnFloorHalfTessFactor = indexOnCeilHalfTessFactor;
1813
if( point > TessFactorCtx.splitPointOnFloorHalfTessFactor )
1814
{
1815
indexOnFloorHalfTessFactor -= 1;
1816
}
1817
// For the fixed point multiplies below, we know the results are <= 16 bits because
1818
// the locations on the halfTessFactor are <= half the number of segments for the total TessFactor.
1819
// So a number divided by a number that is at least twice as big will give
1820
// a result no bigger than 0.5 (which in fixed point is 16 bits in our case)
1821
FXP fxpLocationOnFloorHalfTessFactor = indexOnFloorHalfTessFactor * TessFactorCtx.fxpInvNumSegmentsOnFloorTessFactor;
1822
FXP fxpLocationOnCeilHalfTessFactor = indexOnCeilHalfTessFactor * TessFactorCtx.fxpInvNumSegmentsOnCeilTessFactor;
1823
1824
// Since we know the numbers calculated above are <= fixed point 0.5, and the equation
1825
// below is just lerping between two values <= fixed point 0.5 (0x00008000), then we know
1826
// that the final result before shifting by 16 bits is no larger than 0x80000000. Once we
1827
// shift that down by 16, we get the result of lerping 2 numbers <= 0.5, which is obviously
1828
// at most 0.5 (0x00008000)
1829
fxpLocation = fxpLocationOnFloorHalfTessFactor * (FXP_ONE - TessFactorCtx.fxpHalfTessFactorFraction) +
1830
fxpLocationOnCeilHalfTessFactor * (TessFactorCtx.fxpHalfTessFactorFraction);
1831
fxpLocation = (fxpLocation + FXP_ONE_HALF/*round*/) >> FXP_FRACTION_BITS; // get back to n.16
1832
/* Commenting out floating point version. Note the parameter cleansing it does is not needed in fixed point.
1833
if( bFlip )
1834
location = 1.0f - location; // complement produces cleansed result.
1835
else
1836
CleanseParameter(location);
1837
*/
1838
if( bFlip )
1839
{
1840
fxpLocation = FXP_ONE - fxpLocation;
1841
}
1842
}
1843
1844
//---------------------------------------------------------------------------------------------------------------------------------
1845
// CHWTessellator::StitchRegular
1846
//---------------------------------------------------------------------------------------------------------------------------------
1847
void CHWTessellator::StitchRegular(bool bTrapezoid,DIAGONALS diagonals,
1848
int baseIndexOffset, int numInsideEdgePoints,
1849
int insideEdgePointBaseOffset, int outsideEdgePointBaseOffset)
1850
{
1851
int insidePoint = insideEdgePointBaseOffset;
1852
int outsidePoint = outsideEdgePointBaseOffset;
1853
if( bTrapezoid )
1854
{
1855
DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
1856
baseIndexOffset += 3; outsidePoint++;
1857
}
1858
int p;
1859
switch( diagonals )
1860
{
1861
case DIAGONALS_INSIDE_TO_OUTSIDE:
1862
// Diagonals pointing from inside edge forward towards outside edge
1863
for( p = 0; p < numInsideEdgePoints-1; p++ )
1864
{
1865
DefineClockwiseTriangle(insidePoint,outsidePoint,outsidePoint+1,baseIndexOffset);
1866
baseIndexOffset += 3;
1867
1868
DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1869
baseIndexOffset += 3;
1870
insidePoint++; outsidePoint++;
1871
}
1872
break;
1873
case DIAGONALS_INSIDE_TO_OUTSIDE_EXCEPT_MIDDLE: // Assumes ODD tessellation
1874
// Diagonals pointing from outside edge forward towards inside edge
1875
1876
// First half
1877
for( p = 0; p < numInsideEdgePoints/2-1; p++ )
1878
{
1879
DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
1880
baseIndexOffset += 3;
1881
DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1882
baseIndexOffset += 3;
1883
insidePoint++; outsidePoint++;
1884
}
1885
1886
// Middle
1887
DefineClockwiseTriangle(outsidePoint,insidePoint+1,insidePoint,baseIndexOffset);
1888
baseIndexOffset += 3;
1889
DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1890
baseIndexOffset += 3;
1891
insidePoint++; outsidePoint++; p+=2;
1892
1893
// Second half
1894
for( ; p < numInsideEdgePoints; p++ )
1895
{
1896
DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
1897
baseIndexOffset += 3;
1898
DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1899
baseIndexOffset += 3;
1900
insidePoint++; outsidePoint++;
1901
}
1902
break;
1903
case DIAGONALS_MIRRORED:
1904
// First half, diagonals pointing from outside of outside edge to inside of inside edge
1905
for( p = 0; p < numInsideEdgePoints/2; p++ )
1906
{
1907
DefineClockwiseTriangle(outsidePoint,insidePoint+1,insidePoint,baseIndexOffset);
1908
baseIndexOffset += 3;
1909
DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1910
baseIndexOffset += 3;
1911
insidePoint++; outsidePoint++;
1912
}
1913
// Second half, diagonals pointing from inside of inside edge to outside of outside edge
1914
for( ; p < numInsideEdgePoints-1; p++ )
1915
{
1916
DefineClockwiseTriangle(insidePoint,outsidePoint,outsidePoint+1,baseIndexOffset);
1917
baseIndexOffset += 3;
1918
DefineClockwiseTriangle(insidePoint,outsidePoint+1,insidePoint+1,baseIndexOffset);
1919
baseIndexOffset += 3;
1920
insidePoint++; outsidePoint++;
1921
}
1922
break;
1923
}
1924
if( bTrapezoid )
1925
{
1926
DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
1927
baseIndexOffset += 3;
1928
}
1929
}
1930
1931
//---------------------------------------------------------------------------------------------------------------------------------
1932
// CHWTessellator::StitchTransition()
1933
//---------------------------------------------------------------------------------------------------------------------------------
1934
void CHWTessellator::StitchTransition(int baseIndexOffset,
1935
int insideEdgePointBaseOffset, int insideNumHalfTessFactorPoints,
1936
TESSELLATOR_PARITY insideEdgeTessFactorParity,
1937
int outsideEdgePointBaseOffset, int outsideNumHalfTessFactorPoints,
1938
TESSELLATOR_PARITY outsideTessFactorParity
1939
)
1940
{
1941
// Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
1942
// The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
1943
//
1944
// The contents of the finalPointPositionTable are where vertex i [0..33] ends up on the half-edge
1945
// at the max tessellation amount given ruler-function split order.
1946
// Recall the other half of an edge is mirrored, so we only need to deal with one half.
1947
// This table is used to decide when to advance a point on the interior or exterior.
1948
// It supports odd TessFactor up to 65 and even TessFactor up to 64.
1949
static const int finalPointPositionTable[33] =
1950
{ 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
1951
1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
1952
1953
// The loopStart and loopEnd tables below just provide optimal loop bounds for the
1954
// stitching algorithm further below, for any given halfTssFactor.
1955
// There is probably a better way to encode this...
1956
1957
// loopStart[halfTessFactor] encodes the FIRST entry in finalPointPositionTable[] above which is
1958
// less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1959
static const int loopStart[33] =
1960
{1,1,17,9,9,5,5,5,5,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
1961
// loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
1962
// less than halfTessFactor. Exceptions are entry 0 and 1, which are set up to skip the loop.
1963
static const int loopEnd[33] =
1964
{0,0,17,17,25,25,25,25,29,29,29,29,29,29,29,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,32};
1965
1966
if( TESSELLATOR_PARITY_ODD == insideEdgeTessFactorParity )
1967
{
1968
insideNumHalfTessFactorPoints -= 1;
1969
}
1970
if( TESSELLATOR_PARITY_ODD == outsideTessFactorParity )
1971
{
1972
outsideNumHalfTessFactorPoints -= 1;
1973
}
1974
// Walk first half
1975
int outsidePoint = outsideEdgePointBaseOffset;
1976
int insidePoint = insideEdgePointBaseOffset;
1977
1978
// iStart,iEnd are a small optimization so the loop below doesn't have to go from 0 up to 31
1979
int iStart = min(loopStart[insideNumHalfTessFactorPoints],loopStart[outsideNumHalfTessFactorPoints]);
1980
int iEnd = max(loopEnd[insideNumHalfTessFactorPoints],loopEnd[outsideNumHalfTessFactorPoints]);
1981
1982
if( finalPointPositionTable[0] < outsideNumHalfTessFactorPoints ) // since we dont' start the loop at 0 below, we need a special case.
1983
{
1984
// Advance outside
1985
DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
1986
baseIndexOffset += 3; outsidePoint++;
1987
}
1988
1989
for(int i = iStart; i <= iEnd; i++)
1990
{
1991
if( /*(i>0) && <-- not needed since iStart is never 0*/(finalPointPositionTable[i] < insideNumHalfTessFactorPoints))
1992
{
1993
// Advance inside
1994
DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
1995
baseIndexOffset += 3; insidePoint++;
1996
}
1997
if((finalPointPositionTable[i] < outsideNumHalfTessFactorPoints))
1998
{
1999
// Advance outside
2000
DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
2001
baseIndexOffset += 3; outsidePoint++;
2002
}
2003
}
2004
2005
if( (insideEdgeTessFactorParity != outsideTessFactorParity) || (insideEdgeTessFactorParity == TESSELLATOR_PARITY_ODD))
2006
{
2007
if( insideEdgeTessFactorParity == outsideTessFactorParity )
2008
{
2009
// Quad in the middle
2010
DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
2011
baseIndexOffset += 3;
2012
DefineClockwiseTriangle(insidePoint+1,outsidePoint,outsidePoint+1,baseIndexOffset);
2013
baseIndexOffset += 3;
2014
insidePoint++;
2015
outsidePoint++;
2016
}
2017
else if( TESSELLATOR_PARITY_EVEN == insideEdgeTessFactorParity )
2018
{
2019
// Triangle pointing inside
2020
DefineClockwiseTriangle(insidePoint,outsidePoint,outsidePoint+1,baseIndexOffset);
2021
baseIndexOffset += 3;
2022
outsidePoint++;
2023
}
2024
else
2025
{
2026
// Triangle pointing outside
2027
DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
2028
baseIndexOffset += 3;
2029
insidePoint++;
2030
}
2031
}
2032
2033
// Walk second half.
2034
for(int i = iEnd; i >= iStart; i--)
2035
{
2036
if((finalPointPositionTable[i] < outsideNumHalfTessFactorPoints))
2037
{
2038
// Advance outside
2039
DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
2040
baseIndexOffset += 3; outsidePoint++;
2041
}
2042
if( /*(i>0) && <-- not needed since iStart is never 0*/ (finalPointPositionTable[i] < insideNumHalfTessFactorPoints))
2043
{
2044
// Advance inside
2045
DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
2046
baseIndexOffset += 3; insidePoint++;
2047
}
2048
}
2049
// Below case is not needed if we didn't optimize loop above and made it run from 31 down to 0.
2050
if((finalPointPositionTable[0] < outsideNumHalfTessFactorPoints))
2051
{
2052
DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
2053
baseIndexOffset += 3; outsidePoint++;
2054
}
2055
}
2056
2057
//---------------------------------------------------------------------------------------------------------------------------------
2058
// CHWTessellator::PatchIndexValue()
2059
//--------------------------------------------------------------------------------------------------------------------------------
2060
int CHWTessellator::PatchIndexValue(int index)
2061
{
2062
if( m_bUsingPatchedIndices )
2063
{
2064
if( index >= m_IndexPatchContext.outsidePointIndexPatchBase ) // assumed remapped outide indices are > remapped inside vertices
2065
{
2066
if( index == m_IndexPatchContext.outsidePointIndexBadValue )
2067
index = m_IndexPatchContext.outsidePointIndexReplacementValue;
2068
else
2069
index += m_IndexPatchContext.outsidePointIndexDeltaToRealValue;
2070
}
2071
else
2072
{
2073
if( index == m_IndexPatchContext.insidePointIndexBadValue )
2074
index = m_IndexPatchContext.insidePointIndexReplacementValue;
2075
else
2076
index += m_IndexPatchContext.insidePointIndexDeltaToRealValue;
2077
}
2078
}
2079
else if( m_bUsingPatchedIndices2 )
2080
{
2081
if( index >= m_IndexPatchContext2.baseIndexToInvert )
2082
{
2083
if( index == m_IndexPatchContext2.cornerCaseBadValue )
2084
{
2085
index = m_IndexPatchContext2.cornerCaseReplacementValue;
2086
}
2087
else
2088
{
2089
index = m_IndexPatchContext2.indexInversionEndPoint - index;
2090
}
2091
}
2092
else if( index == m_IndexPatchContext2.cornerCaseBadValue )
2093
{
2094
index = m_IndexPatchContext2.cornerCaseReplacementValue;
2095
}
2096
}
2097
return index;
2098
}
2099
2100
2101
//=================================================================================================================================
2102
// CHLSLTessellator
2103
//=================================================================================================================================
2104
2105
//---------------------------------------------------------------------------------------------------------------------------------
2106
// CHLSLTessellator::CHLSLTessellator
2107
//---------------------------------------------------------------------------------------------------------------------------------
2108
CHLSLTessellator::CHLSLTessellator()
2109
{
2110
m_LastComputedTessFactors[0] = m_LastComputedTessFactors[1] = m_LastComputedTessFactors[2] =
2111
m_LastComputedTessFactors[3] = m_LastComputedTessFactors[4] = m_LastComputedTessFactors[5] = 0;
2112
}
2113
2114
//---------------------------------------------------------------------------------------------------------------------------------
2115
// CHLSLTessellator::Init
2116
// User calls this.
2117
//---------------------------------------------------------------------------------------------------------------------------------
2118
void CHLSLTessellator::Init(
2119
PIPE_TESSELLATOR_PARTITIONING partitioning,
2120
PIPE_TESSELLATOR_REDUCTION insideTessFactorReduction,
2121
PIPE_TESSELLATOR_QUAD_REDUCTION_AXIS quadInsideTessFactorReductionAxis,
2122
PIPE_TESSELLATOR_OUTPUT_PRIMITIVE outputPrimitive)
2123
{
2124
CHWTessellator::Init(partitioning,outputPrimitive);
2125
m_LastComputedTessFactors[0] = m_LastComputedTessFactors[1] = m_LastComputedTessFactors[2] =
2126
m_LastComputedTessFactors[3] = m_LastComputedTessFactors[4] = m_LastComputedTessFactors[5] = 0;
2127
m_partitioning = partitioning;
2128
m_originalPartitioning = partitioning;
2129
switch( partitioning )
2130
{
2131
case PIPE_TESSELLATOR_PARTITIONING_INTEGER:
2132
default:
2133
break;
2134
case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_ODD:
2135
m_parity = TESSELLATOR_PARITY_ODD;
2136
break;
2137
case PIPE_TESSELLATOR_PARTITIONING_FRACTIONAL_EVEN:
2138
m_parity = TESSELLATOR_PARITY_EVEN;
2139
break;
2140
}
2141
m_originalParity = m_parity;
2142
m_outputPrimitive = outputPrimitive;
2143
m_insideTessFactorReduction = insideTessFactorReduction;
2144
m_quadInsideTessFactorReductionAxis = quadInsideTessFactorReductionAxis;
2145
}
2146
//---------------------------------------------------------------------------------------------------------------------------------
2147
// CHLSLTessellator::TessellateQuadDomain
2148
// User calls this
2149
//---------------------------------------------------------------------------------------------------------------------------------
2150
void CHLSLTessellator::TessellateQuadDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,
2151
float insideTessFactorScaleU, float insideTessFactorScaleV )
2152
{
2153
QuadHLSLProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Ueq1,tessFactor_Veq1,insideTessFactorScaleU,insideTessFactorScaleV);
2154
2155
CHWTessellator::TessellateQuadDomain(m_LastComputedTessFactors[0],m_LastComputedTessFactors[1],m_LastComputedTessFactors[2],m_LastComputedTessFactors[3],
2156
m_LastComputedTessFactors[4],m_LastComputedTessFactors[5]);
2157
}
2158
2159
//---------------------------------------------------------------------------------------------------------------------------------
2160
// CHLSLTessellator::QuadHLSLProcessTessFactors
2161
//---------------------------------------------------------------------------------------------------------------------------------
2162
void CHLSLTessellator::QuadHLSLProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Ueq1, float tessFactor_Veq1,
2163
float insideTessFactorScaleU, float insideTessFactorScaleV )
2164
{
2165
if( !(tessFactor_Ueq0 > 0) ||// NaN will pass
2166
!(tessFactor_Veq0 > 0) ||
2167
!(tessFactor_Ueq1 > 0) ||
2168
!(tessFactor_Veq1 > 0) )
2169
{
2170
m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;
2171
m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;
2172
m_LastUnRoundedComputedTessFactors[2] = tessFactor_Ueq1;
2173
m_LastUnRoundedComputedTessFactors[3] = tessFactor_Veq1;
2174
m_LastUnRoundedComputedTessFactors[4] = 0;
2175
m_LastUnRoundedComputedTessFactors[5] = 0;
2176
m_LastComputedTessFactors[0] =
2177
m_LastComputedTessFactors[1] =
2178
m_LastComputedTessFactors[2] =
2179
m_LastComputedTessFactors[3] =
2180
m_LastComputedTessFactors[4] =
2181
m_LastComputedTessFactors[5] = 0;
2182
return;
2183
}
2184
2185
CleanupFloatTessFactor(tessFactor_Ueq0);// clamp to [1.0f..INF], NaN->1.0f
2186
CleanupFloatTessFactor(tessFactor_Veq0);
2187
CleanupFloatTessFactor(tessFactor_Ueq1);
2188
CleanupFloatTessFactor(tessFactor_Veq1);
2189
2190
// Save off tessFactors so they can be returned to app
2191
m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;
2192
m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;
2193
m_LastUnRoundedComputedTessFactors[2] = tessFactor_Ueq1;
2194
m_LastUnRoundedComputedTessFactors[3] = tessFactor_Veq1;
2195
2196
// Process outside tessFactors
2197
float outsideTessFactor[QUAD_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Ueq1, tessFactor_Veq1};
2198
int edge, axis;
2199
TESSELLATOR_PARITY insideTessFactorParity[QUAD_AXES];
2200
if( Pow2Partitioning() || IntegerPartitioning() )
2201
{
2202
for( edge = 0; edge < QUAD_EDGES; edge++ )
2203
{
2204
RoundUpTessFactor(outsideTessFactor[edge]);
2205
ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode
2206
}
2207
}
2208
else
2209
{
2210
SetTessellationParity(m_originalParity); // ClampTessFactor needs it
2211
for( edge = 0; edge < QUAD_EDGES; edge++ )
2212
{
2213
ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode
2214
}
2215
}
2216
2217
// Compute inside TessFactors
2218
float insideTessFactor[QUAD_AXES];
2219
if( m_quadInsideTessFactorReductionAxis == PIPE_TESSELLATOR_QUAD_REDUCTION_1_AXIS )
2220
{
2221
switch( m_insideTessFactorReduction )
2222
{
2223
case PIPE_TESSELLATOR_REDUCTION_MIN:
2224
insideTessFactor[U] = tess_fmin(tess_fmin(tessFactor_Veq0,tessFactor_Veq1),tess_fmin(tessFactor_Ueq0,tessFactor_Ueq1));
2225
break;
2226
case PIPE_TESSELLATOR_REDUCTION_MAX:
2227
insideTessFactor[U] = tess_fmax(tess_fmax(tessFactor_Veq0,tessFactor_Veq1),tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1));
2228
break;
2229
case PIPE_TESSELLATOR_REDUCTION_AVERAGE:
2230
insideTessFactor[U] = (tessFactor_Veq0 + tessFactor_Veq1 + tessFactor_Ueq0 + tessFactor_Ueq1) / 4;
2231
break;
2232
default:
2233
unreachable("impossible m_insideTessFactorReduction");
2234
}
2235
// Scale inside tessFactor based on user scale factor.
2236
2237
ClampFloatTessFactorScale(insideTessFactorScaleU); // clamp scale value to [0..1], NaN->0
2238
insideTessFactor[U] = insideTessFactor[U]*insideTessFactorScaleU;
2239
2240
// Compute inside parity
2241
if( Pow2Partitioning() || IntegerPartitioning() )
2242
{
2243
ClampTessFactor(insideTessFactor[U]); // clamp reduction + scale result that is based on unbounded user input
2244
m_LastUnRoundedComputedTessFactors[4] = m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app
2245
RoundUpTessFactor(insideTessFactor[U]);
2246
insideTessFactorParity[U] =
2247
insideTessFactorParity[V] =
2248
(isEven(insideTessFactor[U]) || (FLOAT_ONE == insideTessFactor[U]) )
2249
? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2250
}
2251
else
2252
{
2253
ClampTessFactor(insideTessFactor[U]); // clamp reduction + scale result that is based on unbounded user input
2254
m_LastUnRoundedComputedTessFactors[4] = m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app
2255
// no parity changes for fractional tessellation - just use what the user requested
2256
insideTessFactorParity[U] = insideTessFactorParity[V] = m_originalParity;
2257
}
2258
2259
// To prevent snapping on edges, the "picture frame" comes
2260
// in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2261
if( (TESSELLATOR_PARITY_ODD == insideTessFactorParity[U]) &&
2262
(insideTessFactor[U] < FLOAT_THREE) )
2263
{
2264
if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)
2265
{
2266
insideTessFactor[U] = tess_fmin(FLOAT_THREE,tess_fmax(tess_fmax(tessFactor_Veq0,tessFactor_Veq1),tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1)));
2267
}
2268
else
2269
{
2270
insideTessFactor[U] = tess_fmin(FLOAT_THREE,(tessFactor_Veq0 + tessFactor_Veq1 + tessFactor_Ueq0 + tessFactor_Ueq1) / 4);
2271
}
2272
ClampTessFactor(insideTessFactor[U]); // clamp reduction result that is based on unbounded user input
2273
m_LastUnRoundedComputedTessFactors[4] = m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app
2274
if( IntegerPartitioning())
2275
{
2276
RoundUpTessFactor(insideTessFactor[U]);
2277
insideTessFactorParity[U] =
2278
insideTessFactorParity[V] = isEven(insideTessFactor[U]) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2279
}
2280
}
2281
insideTessFactor[V] = insideTessFactor[U];
2282
}
2283
else
2284
{
2285
switch( m_insideTessFactorReduction )
2286
{
2287
case PIPE_TESSELLATOR_REDUCTION_MIN:
2288
insideTessFactor[U] = tess_fmin(tessFactor_Veq0,tessFactor_Veq1);
2289
insideTessFactor[V] = tess_fmin(tessFactor_Ueq0,tessFactor_Ueq1);
2290
break;
2291
case PIPE_TESSELLATOR_REDUCTION_MAX:
2292
insideTessFactor[U] = tess_fmax(tessFactor_Veq0,tessFactor_Veq1);
2293
insideTessFactor[V] = tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1);
2294
break;
2295
case PIPE_TESSELLATOR_REDUCTION_AVERAGE:
2296
insideTessFactor[U] = (tessFactor_Veq0 + tessFactor_Veq1) / 2;
2297
insideTessFactor[V] = (tessFactor_Ueq0 + tessFactor_Ueq1) / 2;
2298
break;
2299
default:
2300
unreachable("impossible m_insideTessFactorReduction");
2301
}
2302
// Scale inside tessFactors based on user scale factor.
2303
2304
ClampFloatTessFactorScale(insideTessFactorScaleU); // clamp scale value to [0..1], NaN->0
2305
ClampFloatTessFactorScale(insideTessFactorScaleV);
2306
insideTessFactor[U] = insideTessFactor[U]*insideTessFactorScaleU;
2307
insideTessFactor[V] = insideTessFactor[V]*insideTessFactorScaleV;
2308
2309
// Compute inside parity
2310
if( Pow2Partitioning() || IntegerPartitioning() )
2311
{
2312
for( axis = 0; axis < QUAD_AXES; axis++ )
2313
{
2314
ClampTessFactor(insideTessFactor[axis]); // clamp reduction + scale result that is based on unbounded user input
2315
m_LastUnRoundedComputedTessFactors[4+axis] = insideTessFactor[axis]; // Save off TessFactors so they can be returned to app
2316
RoundUpTessFactor(insideTessFactor[axis]);
2317
insideTessFactorParity[axis] =
2318
(isEven(insideTessFactor[axis]) || (FLOAT_ONE == insideTessFactor[axis]) )
2319
? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2320
}
2321
}
2322
else
2323
{
2324
ClampTessFactor(insideTessFactor[U]); // clamp reduction + scale result that is based on unbounded user input
2325
ClampTessFactor(insideTessFactor[V]); // clamp reduction + scale result that is based on unbounded user input
2326
m_LastUnRoundedComputedTessFactors[4] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app
2327
m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[V]; // Save off TessFactors so they can be returned to app
2328
// no parity changes for fractional tessellation - just use what the user requested
2329
insideTessFactorParity[U] = insideTessFactorParity[V] = m_originalParity;
2330
}
2331
2332
// To prevent snapping on edges, the "picture frame" comes
2333
// in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2334
if( (TESSELLATOR_PARITY_ODD == insideTessFactorParity[U]) &&
2335
(insideTessFactor[U] < FLOAT_THREE) )
2336
{
2337
if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)
2338
{
2339
insideTessFactor[U] = tess_fmin(FLOAT_THREE,tess_fmax(tessFactor_Veq0,tessFactor_Veq1));
2340
}
2341
else
2342
{
2343
insideTessFactor[U] = tess_fmin(FLOAT_THREE,(tessFactor_Veq0 + tessFactor_Veq1) / 2);
2344
}
2345
ClampTessFactor(insideTessFactor[U]); // clamp reduction result that is based on unbounded user input
2346
m_LastUnRoundedComputedTessFactors[4] = insideTessFactor[U]; // Save off TessFactors so they can be returned to app
2347
if( IntegerPartitioning())
2348
{
2349
RoundUpTessFactor(insideTessFactor[U]);
2350
insideTessFactorParity[U] = isEven(insideTessFactor[U]) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2351
}
2352
}
2353
2354
if( (TESSELLATOR_PARITY_ODD == insideTessFactorParity[V]) &&
2355
(insideTessFactor[V] < FLOAT_THREE) )
2356
{
2357
if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)
2358
{
2359
insideTessFactor[V] = tess_fmin(FLOAT_THREE,tess_fmax(tessFactor_Ueq0,tessFactor_Ueq1));
2360
}
2361
else
2362
{
2363
insideTessFactor[V] = tess_fmin(FLOAT_THREE,(tessFactor_Ueq0 + tessFactor_Ueq1) / 2);
2364
}
2365
ClampTessFactor(insideTessFactor[V]);// clamp reduction result that is based on unbounded user input
2366
m_LastUnRoundedComputedTessFactors[5] = insideTessFactor[V]; // Save off TessFactors so they can be returned to app
2367
if( IntegerPartitioning())
2368
{
2369
RoundUpTessFactor(insideTessFactor[V]);
2370
insideTessFactorParity[V] = isEven(insideTessFactor[V]) ? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2371
}
2372
}
2373
2374
for( axis = 0; axis < QUAD_AXES; axis++ )
2375
{
2376
if( TESSELLATOR_PARITY_ODD == insideTessFactorParity[axis] )
2377
{
2378
// Ensure the first ring ("picture frame") interpolates in on all sides
2379
// as much as the side with the minimum TessFactor. Prevents snapping to edge.
2380
if( (insideTessFactor[axis] < FLOAT_THREE) && (insideTessFactor[axis] < insideTessFactor[(axis+1)&0x1]))
2381
{
2382
insideTessFactor[axis] = tess_fmin(insideTessFactor[(axis+1)&0x1],FLOAT_THREE);
2383
m_LastUnRoundedComputedTessFactors[4+axis] = insideTessFactor[axis]; // Save off TessFactors so they can be returned to app
2384
}
2385
}
2386
}
2387
}
2388
2389
// Save off TessFactors so they can be returned to app
2390
m_LastComputedTessFactors[0] = outsideTessFactor[Ueq0];
2391
m_LastComputedTessFactors[1] = outsideTessFactor[Veq0];
2392
m_LastComputedTessFactors[2] = outsideTessFactor[Ueq1];
2393
m_LastComputedTessFactors[3] = outsideTessFactor[Veq1];
2394
m_LastComputedTessFactors[4] = insideTessFactor[U];
2395
m_LastComputedTessFactors[5] = insideTessFactor[V];
2396
}
2397
2398
//---------------------------------------------------------------------------------------------------------------------------------
2399
// CHLSLTessellator::TessellateTriDomain
2400
// User calls this
2401
//---------------------------------------------------------------------------------------------------------------------------------
2402
void CHLSLTessellator::TessellateTriDomain( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,
2403
float insideTessFactorScale )
2404
{
2405
TriHLSLProcessTessFactors(tessFactor_Ueq0,tessFactor_Veq0,tessFactor_Weq0,insideTessFactorScale);
2406
2407
CHWTessellator::TessellateTriDomain(m_LastComputedTessFactors[0],m_LastComputedTessFactors[1],m_LastComputedTessFactors[2],m_LastComputedTessFactors[3]);
2408
}
2409
2410
//---------------------------------------------------------------------------------------------------------------------------------
2411
// CHLSLTessellator::TriHLSLProcessTessFactors
2412
//---------------------------------------------------------------------------------------------------------------------------------
2413
void CHLSLTessellator::TriHLSLProcessTessFactors( float tessFactor_Ueq0, float tessFactor_Veq0, float tessFactor_Weq0,
2414
float insideTessFactorScale )
2415
{
2416
if( !(tessFactor_Ueq0 > 0) || // NaN will pass
2417
!(tessFactor_Veq0 > 0) ||
2418
!(tessFactor_Weq0 > 0) )
2419
{
2420
m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;
2421
m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;
2422
m_LastUnRoundedComputedTessFactors[2] = tessFactor_Weq0;
2423
m_LastUnRoundedComputedTessFactors[3] =
2424
m_LastComputedTessFactors[0] =
2425
m_LastComputedTessFactors[1] =
2426
m_LastComputedTessFactors[2] =
2427
m_LastComputedTessFactors[3] = 0;
2428
return;
2429
}
2430
2431
CleanupFloatTessFactor(tessFactor_Ueq0); // clamp to [1.0f..INF], NaN->1.0f
2432
CleanupFloatTessFactor(tessFactor_Veq0);
2433
CleanupFloatTessFactor(tessFactor_Weq0);
2434
2435
// Save off TessFactors so they can be returned to app
2436
m_LastUnRoundedComputedTessFactors[0] = tessFactor_Ueq0;
2437
m_LastUnRoundedComputedTessFactors[1] = tessFactor_Veq0;
2438
m_LastUnRoundedComputedTessFactors[2] = tessFactor_Weq0;
2439
2440
// Process outside TessFactors
2441
float outsideTessFactor[TRI_EDGES] = {tessFactor_Ueq0, tessFactor_Veq0, tessFactor_Weq0};
2442
int edge;
2443
if( Pow2Partitioning() || IntegerPartitioning() )
2444
{
2445
for( edge = 0; edge < TRI_EDGES; edge++ )
2446
{
2447
RoundUpTessFactor(outsideTessFactor[edge]); // for pow2 this rounds to pow2
2448
ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode
2449
}
2450
}
2451
else
2452
{
2453
for( edge = 0; edge < TRI_EDGES; edge++ )
2454
{
2455
ClampTessFactor(outsideTessFactor[edge]); // clamp unbounded user input based on tessellation mode
2456
}
2457
}
2458
2459
// Compute inside TessFactor
2460
float insideTessFactor;
2461
switch( m_insideTessFactorReduction )
2462
{
2463
case PIPE_TESSELLATOR_REDUCTION_MIN:
2464
insideTessFactor = tess_fmin(tess_fmin(tessFactor_Ueq0,tessFactor_Veq0),tessFactor_Weq0);
2465
break;
2466
case PIPE_TESSELLATOR_REDUCTION_MAX:
2467
insideTessFactor = tess_fmax(tess_fmax(tessFactor_Ueq0,tessFactor_Veq0),tessFactor_Weq0);
2468
break;
2469
case PIPE_TESSELLATOR_REDUCTION_AVERAGE:
2470
insideTessFactor = (tessFactor_Ueq0 + tessFactor_Veq0 + tessFactor_Weq0) / 3;
2471
break;
2472
default:
2473
unreachable("impossible m_insideTessFactorReduction");
2474
}
2475
2476
// Scale inside TessFactor based on user scale factor.
2477
ClampFloatTessFactorScale(insideTessFactorScale); // clamp scale value to [0..1], NaN->0
2478
insideTessFactor = insideTessFactor*tess_fmin(FLOAT_ONE,insideTessFactorScale);
2479
2480
ClampTessFactor(insideTessFactor); // clamp reduction + scale result that is based on unbounded user input
2481
m_LastUnRoundedComputedTessFactors[3] = insideTessFactor;// Save off TessFactors so they can be returned to app
2482
TESSELLATOR_PARITY parity;
2483
if( Pow2Partitioning() || IntegerPartitioning() )
2484
{
2485
RoundUpTessFactor(insideTessFactor);
2486
parity = (isEven(insideTessFactor) || (FLOAT_ONE == insideTessFactor))
2487
? TESSELLATOR_PARITY_EVEN : TESSELLATOR_PARITY_ODD;
2488
}
2489
else
2490
{
2491
parity = m_originalParity;
2492
}
2493
2494
if( (TESSELLATOR_PARITY_ODD == parity) &&
2495
(insideTessFactor < FLOAT_THREE))
2496
{
2497
// To prevent snapping on edges, the "picture frame" comes
2498
// in using avg or max (and ignore inside TessFactor scaling) until it is at least 3.
2499
if(PIPE_TESSELLATOR_REDUCTION_MAX == m_insideTessFactorReduction)
2500
{
2501
insideTessFactor = tess_fmin(FLOAT_THREE,tess_fmax(tessFactor_Ueq0,tess_fmax(tessFactor_Veq0,tessFactor_Weq0)));
2502
}
2503
else
2504
{
2505
insideTessFactor = tess_fmin(FLOAT_THREE,(tessFactor_Ueq0 + tessFactor_Veq0 + tessFactor_Weq0) / 3);
2506
}
2507
ClampTessFactor(insideTessFactor); // clamp reduction result that is based on unbounded user input
2508
m_LastUnRoundedComputedTessFactors[3] = insideTessFactor;// Save off TessFactors so they can be returned to app
2509
if( IntegerPartitioning())
2510
{
2511
RoundUpTessFactor(insideTessFactor);
2512
}
2513
}
2514
2515
// Save off TessFactors so they can be returned to app
2516
m_LastComputedTessFactors[0] = outsideTessFactor[Ueq0];
2517
m_LastComputedTessFactors[1] = outsideTessFactor[Veq0];
2518
m_LastComputedTessFactors[2] = outsideTessFactor[Weq0];
2519
m_LastComputedTessFactors[3] = insideTessFactor;
2520
}
2521
2522
//---------------------------------------------------------------------------------------------------------------------------------
2523
// CHLSLTessellator::TessellateIsoLineDomain
2524
// User calls this.
2525
//---------------------------------------------------------------------------------------------------------------------------------
2526
void CHLSLTessellator::TessellateIsoLineDomain( float TessFactor_U_LineDetail, float TessFactor_V_LineDensity )
2527
{
2528
IsoLineHLSLProcessTessFactors(TessFactor_V_LineDensity,TessFactor_U_LineDetail);
2529
CHWTessellator::TessellateIsoLineDomain(m_LastComputedTessFactors[0],m_LastComputedTessFactors[1]);
2530
}
2531
2532
//---------------------------------------------------------------------------------------------------------------------------------
2533
// CHLSLTessellator::IsoLineHLSLProcessTessFactors
2534
//---------------------------------------------------------------------------------------------------------------------------------
2535
void CHLSLTessellator::IsoLineHLSLProcessTessFactors( float TessFactor_V_LineDensity, float TessFactor_U_LineDetail )
2536
{
2537
if( !(TessFactor_V_LineDensity > 0) || // NaN will pass
2538
!(TessFactor_U_LineDetail > 0) )
2539
{
2540
m_LastUnRoundedComputedTessFactors[0] = TessFactor_V_LineDensity;
2541
m_LastUnRoundedComputedTessFactors[1] = TessFactor_U_LineDetail;
2542
m_LastComputedTessFactors[0] =
2543
m_LastComputedTessFactors[1] = 0;
2544
return;
2545
}
2546
2547
CleanupFloatTessFactor(TessFactor_V_LineDensity); // clamp to [1.0f..INF], NaN->1.0f
2548
CleanupFloatTessFactor(TessFactor_U_LineDetail); // clamp to [1.0f..INF], NaN->1.0f
2549
2550
ClampTessFactor(TessFactor_U_LineDetail); // clamp unbounded user input based on tessellation mode
2551
2552
m_LastUnRoundedComputedTessFactors[1] = TessFactor_U_LineDetail; // Save off TessFactors so they can be returned to app
2553
2554
if(Pow2Partitioning()||IntegerPartitioning())
2555
{
2556
RoundUpTessFactor(TessFactor_U_LineDetail);
2557
}
2558
2559
OverridePartitioning(PIPE_TESSELLATOR_PARTITIONING_INTEGER);
2560
2561
ClampTessFactor(TessFactor_V_LineDensity); // Clamp unbounded user input to integer
2562
m_LastUnRoundedComputedTessFactors[0] = TessFactor_V_LineDensity; // Save off TessFactors so they can be returned to app
2563
2564
RoundUpTessFactor(TessFactor_V_LineDensity);
2565
2566
RestorePartitioning();
2567
2568
// Save off TessFactors so they can be returned to app
2569
m_LastComputedTessFactors[0] = TessFactor_V_LineDensity;
2570
m_LastComputedTessFactors[1] = TessFactor_U_LineDetail;
2571
}
2572
2573
//---------------------------------------------------------------------------------------------------------------------------------
2574
// CHLSLTessellator::ClampTessFactor()
2575
//---------------------------------------------------------------------------------------------------------------------------------
2576
void CHLSLTessellator::ClampTessFactor(float& TessFactor)
2577
{
2578
if( Pow2Partitioning() )
2579
{
2580
TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR) );
2581
}
2582
else if( IntegerPartitioning() )
2583
{
2584
TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR) );
2585
}
2586
else if( Odd() )
2587
{
2588
TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_ODD_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_ODD_TESSELLATION_FACTOR) );
2589
}
2590
else // even
2591
{
2592
TessFactor = tess_fmin( PIPE_TESSELLATOR_MAX_EVEN_TESSELLATION_FACTOR, tess_fmax( TessFactor, PIPE_TESSELLATOR_MIN_EVEN_TESSELLATION_FACTOR) );
2593
}
2594
}
2595
2596
//---------------------------------------------------------------------------------------------------------------------------------
2597
// CHLSLTessellator::CleanupFloatTessFactor()
2598
//---------------------------------------------------------------------------------------------------------------------------------
2599
static const int exponentMask = 0x7f800000;
2600
static const int mantissaMask = 0x007fffff;
2601
void CHLSLTessellator::CleanupFloatTessFactor(float& input)
2602
{
2603
// If input is < 1.0f or NaN, clamp to 1.0f.
2604
// In other words, clamp input to [1.0f...+INF]
2605
int bits = *(int*)&input;
2606
if( ( ( ( bits & exponentMask ) == exponentMask ) && ( bits & mantissaMask ) ) ||// nan?
2607
(input < 1.0f) )
2608
{
2609
input = 1;
2610
}
2611
}
2612
2613
//---------------------------------------------------------------------------------------------------------------------------------
2614
// CHLSLTessellator::ClampFloatTessFactorScale()
2615
//---------------------------------------------------------------------------------------------------------------------------------
2616
void CHLSLTessellator::ClampFloatTessFactorScale(float& input)
2617
{
2618
// If input is < 0.0f or NaN, clamp to 0.0f. > 1 clamps to 1.
2619
// In other words, clamp input to [0.0f...1.0f]
2620
int bits = *(int*)&input;
2621
if( ( ( ( bits & exponentMask ) == exponentMask ) && ( bits & mantissaMask ) ) ||// nan?
2622
(input < 0.0f) )
2623
{
2624
input = 0;
2625
}
2626
else if( input > 1 )
2627
{
2628
input = 1;
2629
}
2630
}
2631
2632
//---------------------------------------------------------------------------------------------------------------------------------
2633
// CHLSLTessellator::RoundUpTessFactor()
2634
//---------------------------------------------------------------------------------------------------------------------------------
2635
static const int exponentLSB = 0x00800000;
2636
void CHLSLTessellator::RoundUpTessFactor(float& TessFactor)
2637
{
2638
// Assume TessFactor is in [1.0f..+INF]
2639
if( Pow2Partitioning() )
2640
{
2641
int bits = *(int*)&TessFactor;
2642
if( bits & mantissaMask )
2643
{
2644
*(int*)&TessFactor = (bits & exponentMask) + exponentLSB;
2645
}
2646
}
2647
else if( IntegerPartitioning() )
2648
{
2649
TessFactor = ceil(TessFactor);
2650
}
2651
}
2652
2653